diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-08-03 21:16:10 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2016-08-03 21:16:10 -0400 |
commit | 326a50f5734c228873eb33c6db6c5240c44f2ecc (patch) | |
tree | f954bb63fc74d44e327c578f3114d62ff9d04b86 | |
parent | 0808882863774ab69066d83f49f511606be024e0 (diff) | |
parent | a485cb037fe64367ec14813f018edb87799c5eb1 (diff) |
Merge branch 'next' into for-linus
Prepare second round of input updates for 4.8 merge window.
-rw-r--r-- | Documentation/devicetree/bindings/input/rotary-encoder.txt | 4 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt | 36 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt | 33 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/vendor-prefixes.txt | 1 | ||||
-rw-r--r-- | drivers/input/joystick/xpad.c | 43 | ||||
-rw-r--r-- | drivers/input/keyboard/cros_ec_keyb.c | 19 | ||||
-rw-r--r-- | drivers/input/misc/rotary_encoder.c | 23 | ||||
-rw-r--r-- | drivers/input/mouse/elan_i2c_core.c | 79 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.c | 8 | ||||
-rw-r--r-- | drivers/input/rmi4/rmi_bus.c | 5 | ||||
-rw-r--r-- | drivers/input/serio/i8042.c | 16 | ||||
-rw-r--r-- | drivers/input/serio/libps2.c | 10 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 24 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/ili210x.c | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/silead.c | 568 | ||||
-rw-r--r-- | drivers/input/touchscreen/sis_i2c.c | 413 | ||||
-rw-r--r-- | include/linux/i8042.h | 6 | ||||
-rw-r--r-- | include/linux/serio.h | 24 |
19 files changed, 1246 insertions, 70 deletions
diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt index 6c9f0c8a846c..e85ce3dea480 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt | |||
@@ -20,6 +20,8 @@ Optional properties: | |||
20 | 2: Half-period mode | 20 | 2: Half-period mode |
21 | 4: Quarter-period mode | 21 | 4: Quarter-period mode |
22 | - wakeup-source: Boolean, rotary encoder can wake up the system. | 22 | - wakeup-source: Boolean, rotary encoder can wake up the system. |
23 | - rotary-encoder,encoding: String, the method used to encode steps. | ||
24 | Supported are "gray" (the default and more common) and "binary". | ||
23 | 25 | ||
24 | Deprecated properties: | 26 | Deprecated properties: |
25 | - rotary-encoder,half-period: Makes the driver work on half-period mode. | 27 | - rotary-encoder,half-period: Makes the driver work on half-period mode. |
@@ -34,6 +36,7 @@ Example: | |||
34 | compatible = "rotary-encoder"; | 36 | compatible = "rotary-encoder"; |
35 | gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */ | 37 | gpios = <&gpio 19 1>, <&gpio 20 0>; /* GPIO19 is inverted */ |
36 | linux,axis = <0>; /* REL_X */ | 38 | linux,axis = <0>; /* REL_X */ |
39 | rotary-encoder,encoding = "gray"; | ||
37 | rotary-encoder,relative-axis; | 40 | rotary-encoder,relative-axis; |
38 | }; | 41 | }; |
39 | 42 | ||
@@ -42,5 +45,6 @@ Example: | |||
42 | gpios = <&gpio 21 0>, <&gpio 22 0>; | 45 | gpios = <&gpio 21 0>, <&gpio 22 0>; |
43 | linux,axis = <1>; /* ABS_Y */ | 46 | linux,axis = <1>; /* ABS_Y */ |
44 | rotary-encoder,steps = <24>; | 47 | rotary-encoder,steps = <24>; |
48 | rotary-encoder,encoding = "binary"; | ||
45 | rotary-encoder,rollover; | 49 | rotary-encoder,rollover; |
46 | }; | 50 | }; |
diff --git a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt new file mode 100644 index 000000000000..1112e0d794e1 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt | |||
@@ -0,0 +1,36 @@ | |||
1 | * GSL 1680 touchscreen controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "silead,gsl1680" | ||
5 | - reg : I2C slave address of the chip (0x40) | ||
6 | - interrupt-parent : a phandle pointing to the interrupt controller | ||
7 | serving the interrupt for this chip | ||
8 | - interrupts : interrupt specification for the gsl1680 interrupt | ||
9 | - power-gpios : Specification for the pin connected to the gsl1680's | ||
10 | shutdown input. This needs to be driven high to take the | ||
11 | gsl1680 out of its low power state | ||
12 | - touchscreen-size-x : See touchscreen.txt | ||
13 | - touchscreen-size-y : See touchscreen.txt | ||
14 | |||
15 | Optional properties: | ||
16 | - touchscreen-inverted-x : See touchscreen.txt | ||
17 | - touchscreen-inverted-y : See touchscreen.txt | ||
18 | - touchscreen-swapped-x-y : See touchscreen.txt | ||
19 | - silead,max-fingers : maximum number of fingers the touchscreen can detect | ||
20 | |||
21 | Example: | ||
22 | |||
23 | i2c@00000000 { | ||
24 | gsl1680: touchscreen@40 { | ||
25 | compatible = "silead,gsl1680"; | ||
26 | reg = <0x40>; | ||
27 | interrupt-parent = <&pio>; | ||
28 | interrupts = <6 11 IRQ_TYPE_EDGE_FALLING>; | ||
29 | power-gpios = <&pio 1 3 GPIO_ACTIVE_HIGH>; | ||
30 | touchscreen-size-x = <480>; | ||
31 | touchscreen-size-y = <800>; | ||
32 | touchscreen-inverted-x; | ||
33 | touchscreen-swapped-x-y; | ||
34 | silead,max-fingers = <5>; | ||
35 | }; | ||
36 | }; | ||
diff --git a/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt b/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt new file mode 100644 index 000000000000..d87ad14f1efe --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt | |||
@@ -0,0 +1,33 @@ | |||
1 | * SiS I2C Multiple Touch Controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: must be "sis,9200-ts" | ||
5 | - reg: i2c slave address | ||
6 | - interrupt-parent: the phandle for the interrupt controller | ||
7 | (see interrupt binding [0]) | ||
8 | - interrupts: touch controller interrupt (see interrupt | ||
9 | binding [0]) | ||
10 | |||
11 | Optional properties: | ||
12 | - pinctrl-names: should be "default" (see pinctrl binding [1]). | ||
13 | - pinctrl-0: a phandle pointing to the pin settings for the | ||
14 | device (see pinctrl binding [1]). | ||
15 | - attn-gpios: the gpio pin used as attention line | ||
16 | - reset-gpios: the gpio pin used to reset the controller | ||
17 | - wakeup-source: touchscreen can be used as a wakeup source | ||
18 | |||
19 | [0]: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt | ||
20 | [1]: Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | ||
21 | |||
22 | Example: | ||
23 | |||
24 | sis9255@5c { | ||
25 | compatible = "sis,9200-ts"; | ||
26 | reg = <0x5c>; | ||
27 | pinctrl-names = "default"; | ||
28 | pinctrl-0 = <&pinctrl_sis>; | ||
29 | interrupt-parent = <&gpio3>; | ||
30 | interrupts = <19 IRQ_TYPE_EDGE_FALLING>; | ||
31 | irq-gpios = <&gpio3 19 GPIO_ACTIVE_LOW>; | ||
32 | reset-gpios = <&gpio2 30 GPIO_ACTIVE_LOW>; | ||
33 | }; | ||
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 80fdbe2ce088..99029cfed459 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt | |||
@@ -221,6 +221,7 @@ simtek | |||
221 | sii Seiko Instruments, Inc. | 221 | sii Seiko Instruments, Inc. |
222 | silergy Silergy Corp. | 222 | silergy Silergy Corp. |
223 | sirf SiRF Technology, Inc. | 223 | sirf SiRF Technology, Inc. |
224 | sis Silicon Integrated Systems Corp. | ||
224 | sitronix Sitronix Technology Corporation | 225 | sitronix Sitronix Technology Corporation |
225 | skyworks Skyworks Solutions, Inc. | 226 | skyworks Skyworks Solutions, Inc. |
226 | smsc Standard Microsystems Corporation | 227 | smsc Standard Microsystems Corporation |
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index a529a4535457..83af17ad0f1f 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -115,6 +115,10 @@ static bool sticks_to_null; | |||
115 | module_param(sticks_to_null, bool, S_IRUGO); | 115 | module_param(sticks_to_null, bool, S_IRUGO); |
116 | MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads"); | 116 | MODULE_PARM_DESC(sticks_to_null, "Do not map sticks at all for unknown pads"); |
117 | 117 | ||
118 | static bool auto_poweroff = true; | ||
119 | module_param(auto_poweroff, bool, S_IWUSR | S_IRUGO); | ||
120 | MODULE_PARM_DESC(auto_poweroff, "Power off wireless controllers on suspend"); | ||
121 | |||
118 | static const struct xpad_device { | 122 | static const struct xpad_device { |
119 | u16 idVendor; | 123 | u16 idVendor; |
120 | u16 idProduct; | 124 | u16 idProduct; |
@@ -1248,6 +1252,36 @@ static void xpad_stop_input(struct usb_xpad *xpad) | |||
1248 | usb_kill_urb(xpad->irq_in); | 1252 | usb_kill_urb(xpad->irq_in); |
1249 | } | 1253 | } |
1250 | 1254 | ||
1255 | static void xpad360w_poweroff_controller(struct usb_xpad *xpad) | ||
1256 | { | ||
1257 | unsigned long flags; | ||
1258 | struct xpad_output_packet *packet = | ||
1259 | &xpad->out_packets[XPAD_OUT_CMD_IDX]; | ||
1260 | |||
1261 | spin_lock_irqsave(&xpad->odata_lock, flags); | ||
1262 | |||
1263 | packet->data[0] = 0x00; | ||
1264 | packet->data[1] = 0x00; | ||
1265 | packet->data[2] = 0x08; | ||
1266 | packet->data[3] = 0xC0; | ||
1267 | packet->data[4] = 0x00; | ||
1268 | packet->data[5] = 0x00; | ||
1269 | packet->data[6] = 0x00; | ||
1270 | packet->data[7] = 0x00; | ||
1271 | packet->data[8] = 0x00; | ||
1272 | packet->data[9] = 0x00; | ||
1273 | packet->data[10] = 0x00; | ||
1274 | packet->data[11] = 0x00; | ||
1275 | packet->len = 12; | ||
1276 | packet->pending = true; | ||
1277 | |||
1278 | /* Reset the sequence so we send out poweroff now */ | ||
1279 | xpad->last_out_packet = -1; | ||
1280 | xpad_try_sending_next_out_packet(xpad); | ||
1281 | |||
1282 | spin_unlock_irqrestore(&xpad->odata_lock, flags); | ||
1283 | } | ||
1284 | |||
1251 | static int xpad360w_start_input(struct usb_xpad *xpad) | 1285 | static int xpad360w_start_input(struct usb_xpad *xpad) |
1252 | { | 1286 | { |
1253 | int error; | 1287 | int error; |
@@ -1590,6 +1624,15 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message) | |||
1590 | * or goes away. | 1624 | * or goes away. |
1591 | */ | 1625 | */ |
1592 | xpad360w_stop_input(xpad); | 1626 | xpad360w_stop_input(xpad); |
1627 | |||
1628 | /* | ||
1629 | * The wireless adapter is going off now, so the | ||
1630 | * gamepads are going to become disconnected. | ||
1631 | * Unless explicitly disabled, power them down | ||
1632 | * so they don't just sit there flashing. | ||
1633 | */ | ||
1634 | if (auto_poweroff && xpad->pad_present) | ||
1635 | xpad360w_poweroff_controller(xpad); | ||
1593 | } else { | 1636 | } else { |
1594 | mutex_lock(&input->mutex); | 1637 | mutex_lock(&input->mutex); |
1595 | if (input->users) | 1638 | if (input->users) |
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index b01966dc7eb3..4b0878f35471 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c | |||
@@ -186,7 +186,7 @@ static irqreturn_t cros_ec_keyb_irq(int irq, void *data) | |||
186 | if (ret >= 0) | 186 | if (ret >= 0) |
187 | cros_ec_keyb_process(ckdev, kb_state, ret); | 187 | cros_ec_keyb_process(ckdev, kb_state, ret); |
188 | else | 188 | else |
189 | dev_err(ec->dev, "failed to get keyboard state: %d\n", ret); | 189 | dev_err(ckdev->dev, "failed to get keyboard state: %d\n", ret); |
190 | 190 | ||
191 | return IRQ_HANDLED; | 191 | return IRQ_HANDLED; |
192 | } | 192 | } |
@@ -236,7 +236,7 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev) | |||
236 | static int cros_ec_keyb_probe(struct platform_device *pdev) | 236 | static int cros_ec_keyb_probe(struct platform_device *pdev) |
237 | { | 237 | { |
238 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); | 238 | struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); |
239 | struct device *dev = ec->dev; | 239 | struct device *dev = &pdev->dev; |
240 | struct cros_ec_keyb *ckdev; | 240 | struct cros_ec_keyb *ckdev; |
241 | struct input_dev *idev; | 241 | struct input_dev *idev; |
242 | struct device_node *np; | 242 | struct device_node *np; |
@@ -246,23 +246,22 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
246 | if (!np) | 246 | if (!np) |
247 | return -ENODEV; | 247 | return -ENODEV; |
248 | 248 | ||
249 | ckdev = devm_kzalloc(&pdev->dev, sizeof(*ckdev), GFP_KERNEL); | 249 | ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL); |
250 | if (!ckdev) | 250 | if (!ckdev) |
251 | return -ENOMEM; | 251 | return -ENOMEM; |
252 | err = matrix_keypad_parse_of_params(&pdev->dev, &ckdev->rows, | 252 | err = matrix_keypad_parse_of_params(dev, &ckdev->rows, &ckdev->cols); |
253 | &ckdev->cols); | ||
254 | if (err) | 253 | if (err) |
255 | return err; | 254 | return err; |
256 | 255 | ||
257 | ckdev->valid_keys = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); | 256 | ckdev->valid_keys = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); |
258 | if (!ckdev->valid_keys) | 257 | if (!ckdev->valid_keys) |
259 | return -ENOMEM; | 258 | return -ENOMEM; |
260 | 259 | ||
261 | ckdev->old_kb_state = devm_kzalloc(&pdev->dev, ckdev->cols, GFP_KERNEL); | 260 | ckdev->old_kb_state = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); |
262 | if (!ckdev->old_kb_state) | 261 | if (!ckdev->old_kb_state) |
263 | return -ENOMEM; | 262 | return -ENOMEM; |
264 | 263 | ||
265 | idev = devm_input_allocate_device(&pdev->dev); | 264 | idev = devm_input_allocate_device(dev); |
266 | if (!idev) | 265 | if (!idev) |
267 | return -ENOMEM; | 266 | return -ENOMEM; |
268 | 267 | ||
@@ -273,7 +272,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
273 | 272 | ||
274 | ckdev->ec = ec; | 273 | ckdev->ec = ec; |
275 | ckdev->dev = dev; | 274 | ckdev->dev = dev; |
276 | dev_set_drvdata(&pdev->dev, ckdev); | 275 | dev_set_drvdata(dev, ckdev); |
277 | 276 | ||
278 | idev->name = CROS_EC_DEV_NAME; | 277 | idev->name = CROS_EC_DEV_NAME; |
279 | idev->phys = ec->phys_name; | 278 | idev->phys = ec->phys_name; |
@@ -282,7 +281,7 @@ static int cros_ec_keyb_probe(struct platform_device *pdev) | |||
282 | idev->id.bustype = BUS_VIRTUAL; | 281 | idev->id.bustype = BUS_VIRTUAL; |
283 | idev->id.version = 1; | 282 | idev->id.version = 1; |
284 | idev->id.product = 0; | 283 | idev->id.product = 0; |
285 | idev->dev.parent = &pdev->dev; | 284 | idev->dev.parent = dev; |
286 | idev->open = cros_ec_keyb_open; | 285 | idev->open = cros_ec_keyb_open; |
287 | idev->close = cros_ec_keyb_close; | 286 | idev->close = cros_ec_keyb_close; |
288 | 287 | ||
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index c7fc8d4fb080..1588aecafff7 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c | |||
@@ -28,6 +28,11 @@ | |||
28 | 28 | ||
29 | #define DRV_NAME "rotary-encoder" | 29 | #define DRV_NAME "rotary-encoder" |
30 | 30 | ||
31 | enum rotary_encoder_encoding { | ||
32 | ROTENC_GRAY, | ||
33 | ROTENC_BINARY, | ||
34 | }; | ||
35 | |||
31 | struct rotary_encoder { | 36 | struct rotary_encoder { |
32 | struct input_dev *input; | 37 | struct input_dev *input; |
33 | 38 | ||
@@ -37,6 +42,7 @@ struct rotary_encoder { | |||
37 | u32 axis; | 42 | u32 axis; |
38 | bool relative_axis; | 43 | bool relative_axis; |
39 | bool rollover; | 44 | bool rollover; |
45 | enum rotary_encoder_encoding encoding; | ||
40 | 46 | ||
41 | unsigned int pos; | 47 | unsigned int pos; |
42 | 48 | ||
@@ -57,8 +63,9 @@ static unsigned int rotary_encoder_get_state(struct rotary_encoder *encoder) | |||
57 | 63 | ||
58 | for (i = 0; i < encoder->gpios->ndescs; ++i) { | 64 | for (i = 0; i < encoder->gpios->ndescs; ++i) { |
59 | int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]); | 65 | int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]); |
66 | |||
60 | /* convert from gray encoding to normal */ | 67 | /* convert from gray encoding to normal */ |
61 | if (ret & 1) | 68 | if (encoder->encoding == ROTENC_GRAY && ret & 1) |
62 | val = !val; | 69 | val = !val; |
63 | 70 | ||
64 | ret = ret << 1 | val; | 71 | ret = ret << 1 | val; |
@@ -213,6 +220,20 @@ static int rotary_encoder_probe(struct platform_device *pdev) | |||
213 | encoder->rollover = | 220 | encoder->rollover = |
214 | device_property_read_bool(dev, "rotary-encoder,rollover"); | 221 | device_property_read_bool(dev, "rotary-encoder,rollover"); |
215 | 222 | ||
223 | if (!device_property_present(dev, "rotary-encoder,encoding") || | ||
224 | !device_property_match_string(dev, "rotary-encoder,encoding", | ||
225 | "gray")) { | ||
226 | dev_info(dev, "gray"); | ||
227 | encoder->encoding = ROTENC_GRAY; | ||
228 | } else if (!device_property_match_string(dev, "rotary-encoder,encoding", | ||
229 | "binary")) { | ||
230 | dev_info(dev, "binary"); | ||
231 | encoder->encoding = ROTENC_BINARY; | ||
232 | } else { | ||
233 | dev_err(dev, "unknown encoding setting\n"); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | |||
216 | device_property_read_u32(dev, "linux,axis", &encoder->axis); | 237 | device_property_read_u32(dev, "linux,axis", &encoder->axis); |
217 | encoder->relative_axis = | 238 | encoder->relative_axis = |
218 | device_property_read_bool(dev, "rotary-encoder,relative-axis"); | 239 | device_property_read_bool(dev, "rotary-encoder,relative-axis"); |
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 2f589857a039..d15b33813021 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c | |||
@@ -4,7 +4,8 @@ | |||
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.6.0 | 7 | * Author: KT Liao <kt.liao@emc.com.tw> |
8 | * Version: 1.6.2 | ||
8 | * | 9 | * |
9 | * Based on cyapa driver: | 10 | * Based on cyapa driver: |
10 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. | 11 | * copyright (c) 2011-2012 Cypress Semiconductor, Inc. |
@@ -40,7 +41,7 @@ | |||
40 | #include "elan_i2c.h" | 41 | #include "elan_i2c.h" |
41 | 42 | ||
42 | #define DRIVER_NAME "elan_i2c" | 43 | #define DRIVER_NAME "elan_i2c" |
43 | #define ELAN_DRIVER_VERSION "1.6.1" | 44 | #define ELAN_DRIVER_VERSION "1.6.2" |
44 | #define ELAN_VENDOR_ID 0x04f3 | 45 | #define ELAN_VENDOR_ID 0x04f3 |
45 | #define ETP_MAX_PRESSURE 255 | 46 | #define ETP_MAX_PRESSURE 255 |
46 | #define ETP_FWIDTH_REDUCE 90 | 47 | #define ETP_FWIDTH_REDUCE 90 |
@@ -199,9 +200,41 @@ static int elan_sleep(struct elan_tp_data *data) | |||
199 | return error; | 200 | return error; |
200 | } | 201 | } |
201 | 202 | ||
203 | static int elan_query_product(struct elan_tp_data *data) | ||
204 | { | ||
205 | int error; | ||
206 | |||
207 | error = data->ops->get_product_id(data->client, &data->product_id); | ||
208 | if (error) | ||
209 | return error; | ||
210 | |||
211 | error = data->ops->get_sm_version(data->client, &data->ic_type, | ||
212 | &data->sm_version); | ||
213 | if (error) | ||
214 | return error; | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int elan_check_ASUS_special_fw(struct elan_tp_data *data) | ||
220 | { | ||
221 | if (data->ic_type != 0x0E) | ||
222 | return false; | ||
223 | |||
224 | switch (data->product_id) { | ||
225 | case 0x05 ... 0x07: | ||
226 | case 0x09: | ||
227 | case 0x13: | ||
228 | return true; | ||
229 | default: | ||
230 | return false; | ||
231 | } | ||
232 | } | ||
233 | |||
202 | static int __elan_initialize(struct elan_tp_data *data) | 234 | static int __elan_initialize(struct elan_tp_data *data) |
203 | { | 235 | { |
204 | struct i2c_client *client = data->client; | 236 | struct i2c_client *client = data->client; |
237 | bool woken_up = false; | ||
205 | int error; | 238 | int error; |
206 | 239 | ||
207 | error = data->ops->initialize(client); | 240 | error = data->ops->initialize(client); |
@@ -210,6 +243,27 @@ static int __elan_initialize(struct elan_tp_data *data) | |||
210 | return error; | 243 | return error; |
211 | } | 244 | } |
212 | 245 | ||
246 | error = elan_query_product(data); | ||
247 | if (error) | ||
248 | return error; | ||
249 | |||
250 | /* | ||
251 | * Some ASUS devices were shipped with firmware that requires | ||
252 | * touchpads to be woken up first, before attempting to switch | ||
253 | * them into absolute reporting mode. | ||
254 | */ | ||
255 | if (elan_check_ASUS_special_fw(data)) { | ||
256 | error = data->ops->sleep_control(client, false); | ||
257 | if (error) { | ||
258 | dev_err(&client->dev, | ||
259 | "failed to wake device up: %d\n", error); | ||
260 | return error; | ||
261 | } | ||
262 | |||
263 | msleep(200); | ||
264 | woken_up = true; | ||
265 | } | ||
266 | |||
213 | data->mode |= ETP_ENABLE_ABS; | 267 | data->mode |= ETP_ENABLE_ABS; |
214 | error = data->ops->set_mode(client, data->mode); | 268 | error = data->ops->set_mode(client, data->mode); |
215 | if (error) { | 269 | if (error) { |
@@ -218,11 +272,13 @@ static int __elan_initialize(struct elan_tp_data *data) | |||
218 | return error; | 272 | return error; |
219 | } | 273 | } |
220 | 274 | ||
221 | error = data->ops->sleep_control(client, false); | 275 | if (!woken_up) { |
222 | if (error) { | 276 | error = data->ops->sleep_control(client, false); |
223 | dev_err(&client->dev, | 277 | if (error) { |
224 | "failed to wake device up: %d\n", error); | 278 | dev_err(&client->dev, |
225 | return error; | 279 | "failed to wake device up: %d\n", error); |
280 | return error; | ||
281 | } | ||
226 | } | 282 | } |
227 | 283 | ||
228 | return 0; | 284 | return 0; |
@@ -248,10 +304,6 @@ static int elan_query_device_info(struct elan_tp_data *data) | |||
248 | { | 304 | { |
249 | int error; | 305 | int error; |
250 | 306 | ||
251 | error = data->ops->get_product_id(data->client, &data->product_id); | ||
252 | if (error) | ||
253 | return error; | ||
254 | |||
255 | error = data->ops->get_version(data->client, false, &data->fw_version); | 307 | error = data->ops->get_version(data->client, false, &data->fw_version); |
256 | if (error) | 308 | if (error) |
257 | return error; | 309 | return error; |
@@ -261,11 +313,6 @@ static int elan_query_device_info(struct elan_tp_data *data) | |||
261 | if (error) | 313 | if (error) |
262 | return error; | 314 | return error; |
263 | 315 | ||
264 | error = data->ops->get_sm_version(data->client, &data->ic_type, | ||
265 | &data->sm_version); | ||
266 | if (error) | ||
267 | return error; | ||
268 | |||
269 | error = data->ops->get_version(data->client, true, &data->iap_version); | 316 | error = data->ops->get_version(data->client, true, &data->iap_version); |
270 | if (error) | 317 | if (error) |
271 | return error; | 318 | return error; |
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 615d23ec0d8e..08e252a42480 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c | |||
@@ -222,12 +222,8 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, | |||
222 | */ | 222 | */ |
223 | static void elantech_packet_dump(struct psmouse *psmouse) | 223 | static void elantech_packet_dump(struct psmouse *psmouse) |
224 | { | 224 | { |
225 | int i; | 225 | psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet [%*ph]\n", |
226 | 226 | psmouse->pktsize, psmouse->packet); | |
227 | psmouse_printk(KERN_DEBUG, psmouse, "PS/2 packet ["); | ||
228 | for (i = 0; i < psmouse->pktsize; i++) | ||
229 | printk("%s0x%02x ", i ? ", " : " ", psmouse->packet[i]); | ||
230 | printk("]\n"); | ||
231 | } | 227 | } |
232 | 228 | ||
233 | /* | 229 | /* |
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 253df96be427..a73580654c6b 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c | |||
@@ -232,10 +232,7 @@ err_put_device: | |||
232 | void rmi_unregister_function(struct rmi_function *fn) | 232 | void rmi_unregister_function(struct rmi_function *fn) |
233 | { | 233 | { |
234 | device_del(&fn->dev); | 234 | device_del(&fn->dev); |
235 | 235 | of_node_put(fn->dev.of_node); | |
236 | if (fn->dev.of_node) | ||
237 | of_node_put(fn->dev.of_node); | ||
238 | |||
239 | put_device(&fn->dev); | 236 | put_device(&fn->dev); |
240 | } | 237 | } |
241 | 238 | ||
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 454195709a82..b4d34086e73f 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c | |||
@@ -1277,6 +1277,7 @@ static int __init i8042_create_kbd_port(void) | |||
1277 | serio->start = i8042_start; | 1277 | serio->start = i8042_start; |
1278 | serio->stop = i8042_stop; | 1278 | serio->stop = i8042_stop; |
1279 | serio->close = i8042_port_close; | 1279 | serio->close = i8042_port_close; |
1280 | serio->ps2_cmd_mutex = &i8042_mutex; | ||
1280 | serio->port_data = port; | 1281 | serio->port_data = port; |
1281 | serio->dev.parent = &i8042_platform_device->dev; | 1282 | serio->dev.parent = &i8042_platform_device->dev; |
1282 | strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); | 1283 | strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name)); |
@@ -1373,21 +1374,6 @@ static void i8042_unregister_ports(void) | |||
1373 | } | 1374 | } |
1374 | } | 1375 | } |
1375 | 1376 | ||
1376 | /* | ||
1377 | * Checks whether port belongs to i8042 controller. | ||
1378 | */ | ||
1379 | bool i8042_check_port_owner(const struct serio *port) | ||
1380 | { | ||
1381 | int i; | ||
1382 | |||
1383 | for (i = 0; i < I8042_NUM_PORTS; i++) | ||
1384 | if (i8042_ports[i].serio == port) | ||
1385 | return true; | ||
1386 | |||
1387 | return false; | ||
1388 | } | ||
1389 | EXPORT_SYMBOL(i8042_check_port_owner); | ||
1390 | |||
1391 | static void i8042_free_irqs(void) | 1377 | static void i8042_free_irqs(void) |
1392 | { | 1378 | { |
1393 | if (i8042_aux_irq_registered) | 1379 | if (i8042_aux_irq_registered) |
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 316f2c897101..83e9c663aa67 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c | |||
@@ -56,19 +56,17 @@ EXPORT_SYMBOL(ps2_sendbyte); | |||
56 | 56 | ||
57 | void ps2_begin_command(struct ps2dev *ps2dev) | 57 | void ps2_begin_command(struct ps2dev *ps2dev) |
58 | { | 58 | { |
59 | mutex_lock(&ps2dev->cmd_mutex); | 59 | struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; |
60 | 60 | ||
61 | if (i8042_check_port_owner(ps2dev->serio)) | 61 | mutex_lock(m); |
62 | i8042_lock_chip(); | ||
63 | } | 62 | } |
64 | EXPORT_SYMBOL(ps2_begin_command); | 63 | EXPORT_SYMBOL(ps2_begin_command); |
65 | 64 | ||
66 | void ps2_end_command(struct ps2dev *ps2dev) | 65 | void ps2_end_command(struct ps2dev *ps2dev) |
67 | { | 66 | { |
68 | if (i8042_check_port_owner(ps2dev->serio)) | 67 | struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; |
69 | i8042_unlock_chip(); | ||
70 | 68 | ||
71 | mutex_unlock(&ps2dev->cmd_mutex); | 69 | mutex_unlock(m); |
72 | } | 70 | } |
73 | EXPORT_SYMBOL(ps2_end_command); | 71 | EXPORT_SYMBOL(ps2_end_command); |
74 | 72 | ||
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index ee02dc7422bd..8d893cefb0e3 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -1059,6 +1059,30 @@ config TOUCHSCREEN_RM_TS | |||
1059 | To compile this driver as a module, choose M here: the | 1059 | To compile this driver as a module, choose M here: the |
1060 | module will be called raydium_i2c_ts. | 1060 | module will be called raydium_i2c_ts. |
1061 | 1061 | ||
1062 | config TOUCHSCREEN_SILEAD | ||
1063 | tristate "Silead I2C touchscreen" | ||
1064 | depends on I2C | ||
1065 | help | ||
1066 | Say Y here if you have the Silead touchscreen connected to | ||
1067 | your system. | ||
1068 | |||
1069 | If unsure, say N. | ||
1070 | |||
1071 | To compile this driver as a module, choose M here: the | ||
1072 | module will be called silead. | ||
1073 | |||
1074 | config TOUCHSCREEN_SIS_I2C | ||
1075 | tristate "SiS 9200 family I2C touchscreen" | ||
1076 | depends on I2C | ||
1077 | depends on GPIOLIB || COMPILE_TEST | ||
1078 | help | ||
1079 | This enables support for SiS 9200 family over I2C based touchscreens. | ||
1080 | |||
1081 | If unsure, say N. | ||
1082 | |||
1083 | To compile this driver as a module, choose M here: the | ||
1084 | module will be called sis_i2c. | ||
1085 | |||
1062 | config TOUCHSCREEN_ST1232 | 1086 | config TOUCHSCREEN_ST1232 |
1063 | tristate "Sitronix ST1232 touchscreen controllers" | 1087 | tristate "Sitronix ST1232 touchscreen controllers" |
1064 | depends on I2C | 1088 | depends on I2C |
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 3315882905f7..b4373d6be402 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile | |||
@@ -64,6 +64,8 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o | |||
64 | obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o | 64 | obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o |
65 | obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o | 65 | obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o |
66 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o | 66 | obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o |
67 | obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o | ||
68 | obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o | ||
67 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o | 69 | obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o |
68 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o | 70 | obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o |
69 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o | 71 | obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o |
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index ddf694b9fffc..fe4848bd1f4c 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c | |||
@@ -169,7 +169,7 @@ static ssize_t ili210x_calibrate(struct device *dev, | |||
169 | 169 | ||
170 | return count; | 170 | return count; |
171 | } | 171 | } |
172 | static DEVICE_ATTR(calibrate, 0644, NULL, ili210x_calibrate); | 172 | static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate); |
173 | 173 | ||
174 | static struct attribute *ili210x_attributes[] = { | 174 | static struct attribute *ili210x_attributes[] = { |
175 | &dev_attr_calibrate.attr, | 175 | &dev_attr_calibrate.attr, |
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c new file mode 100644 index 000000000000..5f55167855d3 --- /dev/null +++ b/drivers/input/touchscreen/silead.c | |||
@@ -0,0 +1,568 @@ | |||
1 | /* ------------------------------------------------------------------------- | ||
2 | * Copyright (C) 2014-2015, Intel Corporation | ||
3 | * | ||
4 | * Derived from: | ||
5 | * gslX68X.c | ||
6 | * Copyright (C) 2010-2015, Shanghai Sileadinc Co.Ltd | ||
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 as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * ------------------------------------------------------------------------- | ||
18 | */ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/acpi.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/gpio/consumer.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/firmware.h> | ||
27 | #include <linux/input.h> | ||
28 | #include <linux/input/mt.h> | ||
29 | #include <linux/input/touchscreen.h> | ||
30 | #include <linux/pm.h> | ||
31 | #include <linux/irq.h> | ||
32 | |||
33 | #include <asm/unaligned.h> | ||
34 | |||
35 | #define SILEAD_TS_NAME "silead_ts" | ||
36 | |||
37 | #define SILEAD_REG_RESET 0xE0 | ||
38 | #define SILEAD_REG_DATA 0x80 | ||
39 | #define SILEAD_REG_TOUCH_NR 0x80 | ||
40 | #define SILEAD_REG_POWER 0xBC | ||
41 | #define SILEAD_REG_CLOCK 0xE4 | ||
42 | #define SILEAD_REG_STATUS 0xB0 | ||
43 | #define SILEAD_REG_ID 0xFC | ||
44 | #define SILEAD_REG_MEM_CHECK 0xB0 | ||
45 | |||
46 | #define SILEAD_STATUS_OK 0x5A5A5A5A | ||
47 | #define SILEAD_TS_DATA_LEN 44 | ||
48 | #define SILEAD_CLOCK 0x04 | ||
49 | |||
50 | #define SILEAD_CMD_RESET 0x88 | ||
51 | #define SILEAD_CMD_START 0x00 | ||
52 | |||
53 | #define SILEAD_POINT_DATA_LEN 0x04 | ||
54 | #define SILEAD_POINT_Y_OFF 0x00 | ||
55 | #define SILEAD_POINT_Y_MSB_OFF 0x01 | ||
56 | #define SILEAD_POINT_X_OFF 0x02 | ||
57 | #define SILEAD_POINT_X_MSB_OFF 0x03 | ||
58 | #define SILEAD_TOUCH_ID_MASK 0xF0 | ||
59 | |||
60 | #define SILEAD_CMD_SLEEP_MIN 10000 | ||
61 | #define SILEAD_CMD_SLEEP_MAX 20000 | ||
62 | #define SILEAD_POWER_SLEEP 20 | ||
63 | #define SILEAD_STARTUP_SLEEP 30 | ||
64 | |||
65 | #define SILEAD_MAX_FINGERS 10 | ||
66 | |||
67 | enum silead_ts_power { | ||
68 | SILEAD_POWER_ON = 1, | ||
69 | SILEAD_POWER_OFF = 0 | ||
70 | }; | ||
71 | |||
72 | struct silead_ts_data { | ||
73 | struct i2c_client *client; | ||
74 | struct gpio_desc *gpio_power; | ||
75 | struct input_dev *input; | ||
76 | char fw_name[64]; | ||
77 | struct touchscreen_properties prop; | ||
78 | u32 max_fingers; | ||
79 | u32 chip_id; | ||
80 | struct input_mt_pos pos[SILEAD_MAX_FINGERS]; | ||
81 | int slots[SILEAD_MAX_FINGERS]; | ||
82 | int id[SILEAD_MAX_FINGERS]; | ||
83 | }; | ||
84 | |||
85 | struct silead_fw_data { | ||
86 | u32 offset; | ||
87 | u32 val; | ||
88 | }; | ||
89 | |||
90 | static int silead_ts_request_input_dev(struct silead_ts_data *data) | ||
91 | { | ||
92 | struct device *dev = &data->client->dev; | ||
93 | int error; | ||
94 | |||
95 | data->input = devm_input_allocate_device(dev); | ||
96 | if (!data->input) { | ||
97 | dev_err(dev, | ||
98 | "Failed to allocate input device\n"); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | |||
102 | input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0); | ||
103 | input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0); | ||
104 | touchscreen_parse_properties(data->input, true, &data->prop); | ||
105 | |||
106 | input_mt_init_slots(data->input, data->max_fingers, | ||
107 | INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED | | ||
108 | INPUT_MT_TRACK); | ||
109 | |||
110 | data->input->name = SILEAD_TS_NAME; | ||
111 | data->input->phys = "input/ts"; | ||
112 | data->input->id.bustype = BUS_I2C; | ||
113 | |||
114 | error = input_register_device(data->input); | ||
115 | if (error) { | ||
116 | dev_err(dev, "Failed to register input device: %d\n", error); | ||
117 | return error; | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static void silead_ts_set_power(struct i2c_client *client, | ||
124 | enum silead_ts_power state) | ||
125 | { | ||
126 | struct silead_ts_data *data = i2c_get_clientdata(client); | ||
127 | |||
128 | if (data->gpio_power) { | ||
129 | gpiod_set_value_cansleep(data->gpio_power, state); | ||
130 | msleep(SILEAD_POWER_SLEEP); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static void silead_ts_read_data(struct i2c_client *client) | ||
135 | { | ||
136 | struct silead_ts_data *data = i2c_get_clientdata(client); | ||
137 | struct input_dev *input = data->input; | ||
138 | struct device *dev = &client->dev; | ||
139 | u8 *bufp, buf[SILEAD_TS_DATA_LEN]; | ||
140 | int touch_nr, error, i; | ||
141 | |||
142 | error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_DATA, | ||
143 | SILEAD_TS_DATA_LEN, buf); | ||
144 | if (error < 0) { | ||
145 | dev_err(dev, "Data read error %d\n", error); | ||
146 | return; | ||
147 | } | ||
148 | |||
149 | touch_nr = buf[0]; | ||
150 | if (touch_nr < 0) | ||
151 | return; | ||
152 | |||
153 | if (touch_nr > data->max_fingers) { | ||
154 | dev_warn(dev, "More touches reported then supported %d > %d\n", | ||
155 | touch_nr, data->max_fingers); | ||
156 | touch_nr = data->max_fingers; | ||
157 | } | ||
158 | |||
159 | bufp = buf + SILEAD_POINT_DATA_LEN; | ||
160 | for (i = 0; i < touch_nr; i++, bufp += SILEAD_POINT_DATA_LEN) { | ||
161 | /* Bits 4-7 are the touch id */ | ||
162 | data->id[i] = (bufp[SILEAD_POINT_X_MSB_OFF] & | ||
163 | SILEAD_TOUCH_ID_MASK) >> 4; | ||
164 | touchscreen_set_mt_pos(&data->pos[i], &data->prop, | ||
165 | get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff, | ||
166 | get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff); | ||
167 | } | ||
168 | |||
169 | input_mt_assign_slots(input, data->slots, data->pos, touch_nr, 0); | ||
170 | |||
171 | for (i = 0; i < touch_nr; i++) { | ||
172 | input_mt_slot(input, data->slots[i]); | ||
173 | input_mt_report_slot_state(input, MT_TOOL_FINGER, true); | ||
174 | input_report_abs(input, ABS_MT_POSITION_X, data->pos[i].x); | ||
175 | input_report_abs(input, ABS_MT_POSITION_Y, data->pos[i].y); | ||
176 | |||
177 | dev_dbg(dev, "x=%d y=%d hw_id=%d sw_id=%d\n", data->pos[i].x, | ||
178 | data->pos[i].y, data->id[i], data->slots[i]); | ||
179 | } | ||
180 | |||
181 | input_mt_sync_frame(input); | ||
182 | input_sync(input); | ||
183 | } | ||
184 | |||
185 | static int silead_ts_init(struct i2c_client *client) | ||
186 | { | ||
187 | struct silead_ts_data *data = i2c_get_clientdata(client); | ||
188 | int error; | ||
189 | |||
190 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, | ||
191 | SILEAD_CMD_RESET); | ||
192 | if (error) | ||
193 | goto i2c_write_err; | ||
194 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
195 | |||
196 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_TOUCH_NR, | ||
197 | data->max_fingers); | ||
198 | if (error) | ||
199 | goto i2c_write_err; | ||
200 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
201 | |||
202 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK, | ||
203 | SILEAD_CLOCK); | ||
204 | if (error) | ||
205 | goto i2c_write_err; | ||
206 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
207 | |||
208 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, | ||
209 | SILEAD_CMD_START); | ||
210 | if (error) | ||
211 | goto i2c_write_err; | ||
212 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
213 | |||
214 | return 0; | ||
215 | |||
216 | i2c_write_err: | ||
217 | dev_err(&client->dev, "Registers clear error %d\n", error); | ||
218 | return error; | ||
219 | } | ||
220 | |||
221 | static int silead_ts_reset(struct i2c_client *client) | ||
222 | { | ||
223 | int error; | ||
224 | |||
225 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, | ||
226 | SILEAD_CMD_RESET); | ||
227 | if (error) | ||
228 | goto i2c_write_err; | ||
229 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
230 | |||
231 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_CLOCK, | ||
232 | SILEAD_CLOCK); | ||
233 | if (error) | ||
234 | goto i2c_write_err; | ||
235 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
236 | |||
237 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_POWER, | ||
238 | SILEAD_CMD_START); | ||
239 | if (error) | ||
240 | goto i2c_write_err; | ||
241 | usleep_range(SILEAD_CMD_SLEEP_MIN, SILEAD_CMD_SLEEP_MAX); | ||
242 | |||
243 | return 0; | ||
244 | |||
245 | i2c_write_err: | ||
246 | dev_err(&client->dev, "Chip reset error %d\n", error); | ||
247 | return error; | ||
248 | } | ||
249 | |||
250 | static int silead_ts_startup(struct i2c_client *client) | ||
251 | { | ||
252 | int error; | ||
253 | |||
254 | error = i2c_smbus_write_byte_data(client, SILEAD_REG_RESET, 0x00); | ||
255 | if (error) { | ||
256 | dev_err(&client->dev, "Startup error %d\n", error); | ||
257 | return error; | ||
258 | } | ||
259 | |||
260 | msleep(SILEAD_STARTUP_SLEEP); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int silead_ts_load_fw(struct i2c_client *client) | ||
266 | { | ||
267 | struct device *dev = &client->dev; | ||
268 | struct silead_ts_data *data = i2c_get_clientdata(client); | ||
269 | unsigned int fw_size, i; | ||
270 | const struct firmware *fw; | ||
271 | struct silead_fw_data *fw_data; | ||
272 | int error; | ||
273 | |||
274 | dev_dbg(dev, "Firmware file name: %s", data->fw_name); | ||
275 | |||
276 | error = request_firmware(&fw, data->fw_name, dev); | ||
277 | if (error) { | ||
278 | dev_err(dev, "Firmware request error %d\n", error); | ||
279 | return error; | ||
280 | } | ||
281 | |||
282 | fw_size = fw->size / sizeof(*fw_data); | ||
283 | fw_data = (struct silead_fw_data *)fw->data; | ||
284 | |||
285 | for (i = 0; i < fw_size; i++) { | ||
286 | error = i2c_smbus_write_i2c_block_data(client, | ||
287 | fw_data[i].offset, | ||
288 | 4, | ||
289 | (u8 *)&fw_data[i].val); | ||
290 | if (error) { | ||
291 | dev_err(dev, "Firmware load error %d\n", error); | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | release_firmware(fw); | ||
297 | return error ?: 0; | ||
298 | } | ||
299 | |||
300 | static u32 silead_ts_get_status(struct i2c_client *client) | ||
301 | { | ||
302 | int error; | ||
303 | __le32 status; | ||
304 | |||
305 | error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_STATUS, | ||
306 | sizeof(status), (u8 *)&status); | ||
307 | if (error < 0) { | ||
308 | dev_err(&client->dev, "Status read error %d\n", error); | ||
309 | return error; | ||
310 | } | ||
311 | |||
312 | return le32_to_cpu(status); | ||
313 | } | ||
314 | |||
315 | static int silead_ts_get_id(struct i2c_client *client) | ||
316 | { | ||
317 | struct silead_ts_data *data = i2c_get_clientdata(client); | ||
318 | __le32 chip_id; | ||
319 | int error; | ||
320 | |||
321 | error = i2c_smbus_read_i2c_block_data(client, SILEAD_REG_ID, | ||
322 | sizeof(chip_id), (u8 *)&chip_id); | ||
323 | if (error < 0) { | ||
324 | dev_err(&client->dev, "Chip ID read error %d\n", error); | ||
325 | return error; | ||
326 | } | ||
327 | |||
328 | data->chip_id = le32_to_cpu(chip_id); | ||
329 | dev_info(&client->dev, "Silead chip ID: 0x%8X", data->chip_id); | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static int silead_ts_setup(struct i2c_client *client) | ||
335 | { | ||
336 | int error; | ||
337 | u32 status; | ||
338 | |||
339 | silead_ts_set_power(client, SILEAD_POWER_OFF); | ||
340 | silead_ts_set_power(client, SILEAD_POWER_ON); | ||
341 | |||
342 | error = silead_ts_get_id(client); | ||
343 | if (error) | ||
344 | return error; | ||
345 | |||
346 | error = silead_ts_init(client); | ||
347 | if (error) | ||
348 | return error; | ||
349 | |||
350 | error = silead_ts_reset(client); | ||
351 | if (error) | ||
352 | return error; | ||
353 | |||
354 | error = silead_ts_load_fw(client); | ||
355 | if (error) | ||
356 | return error; | ||
357 | |||
358 | error = silead_ts_startup(client); | ||
359 | if (error) | ||
360 | return error; | ||
361 | |||
362 | status = silead_ts_get_status(client); | ||
363 | if (status != SILEAD_STATUS_OK) { | ||
364 | dev_err(&client->dev, | ||
365 | "Initialization error, status: 0x%X\n", status); | ||
366 | return -ENODEV; | ||
367 | } | ||
368 | |||
369 | return 0; | ||
370 | } | ||
371 | |||
372 | static irqreturn_t silead_ts_threaded_irq_handler(int irq, void *id) | ||
373 | { | ||
374 | struct silead_ts_data *data = id; | ||
375 | struct i2c_client *client = data->client; | ||
376 | |||
377 | silead_ts_read_data(client); | ||
378 | |||
379 | return IRQ_HANDLED; | ||
380 | } | ||
381 | |||
382 | static void silead_ts_read_props(struct i2c_client *client) | ||
383 | { | ||
384 | struct silead_ts_data *data = i2c_get_clientdata(client); | ||
385 | struct device *dev = &client->dev; | ||
386 | const char *str; | ||
387 | int error; | ||
388 | |||
389 | error = device_property_read_u32(dev, "silead,max-fingers", | ||
390 | &data->max_fingers); | ||
391 | if (error) { | ||
392 | dev_dbg(dev, "Max fingers read error %d\n", error); | ||
393 | data->max_fingers = 5; /* Most devices handle up-to 5 fingers */ | ||
394 | } | ||
395 | |||
396 | error = device_property_read_string(dev, "touchscreen-fw-name", &str); | ||
397 | if (!error) | ||
398 | snprintf(data->fw_name, sizeof(data->fw_name), "%s", str); | ||
399 | else | ||
400 | dev_dbg(dev, "Firmware file name read error. Using default."); | ||
401 | } | ||
402 | |||
403 | #ifdef CONFIG_ACPI | ||
404 | static int silead_ts_set_default_fw_name(struct silead_ts_data *data, | ||
405 | const struct i2c_device_id *id) | ||
406 | { | ||
407 | const struct acpi_device_id *acpi_id; | ||
408 | struct device *dev = &data->client->dev; | ||
409 | int i; | ||
410 | |||
411 | if (ACPI_HANDLE(dev)) { | ||
412 | acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
413 | if (!acpi_id) | ||
414 | return -ENODEV; | ||
415 | |||
416 | snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw", | ||
417 | acpi_id->id); | ||
418 | |||
419 | for (i = 0; i < strlen(data->fw_name); i++) | ||
420 | data->fw_name[i] = tolower(data->fw_name[i]); | ||
421 | } else { | ||
422 | snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw", | ||
423 | id->name); | ||
424 | } | ||
425 | |||
426 | return 0; | ||
427 | } | ||
428 | #else | ||
429 | static int silead_ts_set_default_fw_name(struct silead_ts_data *data, | ||
430 | const struct i2c_device_id *id) | ||
431 | { | ||
432 | snprintf(data->fw_name, sizeof(data->fw_name), "%s.fw", id->name); | ||
433 | return 0; | ||
434 | } | ||
435 | #endif | ||
436 | |||
437 | static int silead_ts_probe(struct i2c_client *client, | ||
438 | const struct i2c_device_id *id) | ||
439 | { | ||
440 | struct silead_ts_data *data; | ||
441 | struct device *dev = &client->dev; | ||
442 | int error; | ||
443 | |||
444 | if (!i2c_check_functionality(client->adapter, | ||
445 | I2C_FUNC_I2C | | ||
446 | I2C_FUNC_SMBUS_READ_I2C_BLOCK | | ||
447 | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) { | ||
448 | dev_err(dev, "I2C functionality check failed\n"); | ||
449 | return -ENXIO; | ||
450 | } | ||
451 | |||
452 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | ||
453 | if (!data) | ||
454 | return -ENOMEM; | ||
455 | |||
456 | i2c_set_clientdata(client, data); | ||
457 | data->client = client; | ||
458 | |||
459 | error = silead_ts_set_default_fw_name(data, id); | ||
460 | if (error) | ||
461 | return error; | ||
462 | |||
463 | silead_ts_read_props(client); | ||
464 | |||
465 | /* We must have the IRQ provided by DT or ACPI subsytem */ | ||
466 | if (client->irq <= 0) | ||
467 | return -ENODEV; | ||
468 | |||
469 | /* Power GPIO pin */ | ||
470 | data->gpio_power = gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); | ||
471 | if (IS_ERR(data->gpio_power)) { | ||
472 | if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER) | ||
473 | dev_err(dev, "Shutdown GPIO request failed\n"); | ||
474 | return PTR_ERR(data->gpio_power); | ||
475 | } | ||
476 | |||
477 | error = silead_ts_setup(client); | ||
478 | if (error) | ||
479 | return error; | ||
480 | |||
481 | error = silead_ts_request_input_dev(data); | ||
482 | if (error) | ||
483 | return error; | ||
484 | |||
485 | error = devm_request_threaded_irq(dev, client->irq, | ||
486 | NULL, silead_ts_threaded_irq_handler, | ||
487 | IRQF_ONESHOT, client->name, data); | ||
488 | if (error) { | ||
489 | if (error != -EPROBE_DEFER) | ||
490 | dev_err(dev, "IRQ request failed %d\n", error); | ||
491 | return error; | ||
492 | } | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int __maybe_unused silead_ts_suspend(struct device *dev) | ||
498 | { | ||
499 | struct i2c_client *client = to_i2c_client(dev); | ||
500 | |||
501 | silead_ts_set_power(client, SILEAD_POWER_OFF); | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int __maybe_unused silead_ts_resume(struct device *dev) | ||
506 | { | ||
507 | struct i2c_client *client = to_i2c_client(dev); | ||
508 | int error, status; | ||
509 | |||
510 | silead_ts_set_power(client, SILEAD_POWER_ON); | ||
511 | |||
512 | error = silead_ts_reset(client); | ||
513 | if (error) | ||
514 | return error; | ||
515 | |||
516 | error = silead_ts_startup(client); | ||
517 | if (error) | ||
518 | return error; | ||
519 | |||
520 | status = silead_ts_get_status(client); | ||
521 | if (status != SILEAD_STATUS_OK) { | ||
522 | dev_err(dev, "Resume error, status: 0x%02x\n", status); | ||
523 | return -ENODEV; | ||
524 | } | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume); | ||
530 | |||
531 | static const struct i2c_device_id silead_ts_id[] = { | ||
532 | { "gsl1680", 0 }, | ||
533 | { "gsl1688", 0 }, | ||
534 | { "gsl3670", 0 }, | ||
535 | { "gsl3675", 0 }, | ||
536 | { "gsl3692", 0 }, | ||
537 | { "mssl1680", 0 }, | ||
538 | { } | ||
539 | }; | ||
540 | MODULE_DEVICE_TABLE(i2c, silead_ts_id); | ||
541 | |||
542 | #ifdef CONFIG_ACPI | ||
543 | static const struct acpi_device_id silead_ts_acpi_match[] = { | ||
544 | { "GSL1680", 0 }, | ||
545 | { "GSL1688", 0 }, | ||
546 | { "GSL3670", 0 }, | ||
547 | { "GSL3675", 0 }, | ||
548 | { "GSL3692", 0 }, | ||
549 | { "MSSL1680", 0 }, | ||
550 | { } | ||
551 | }; | ||
552 | MODULE_DEVICE_TABLE(acpi, silead_ts_acpi_match); | ||
553 | #endif | ||
554 | |||
555 | static struct i2c_driver silead_ts_driver = { | ||
556 | .probe = silead_ts_probe, | ||
557 | .id_table = silead_ts_id, | ||
558 | .driver = { | ||
559 | .name = SILEAD_TS_NAME, | ||
560 | .acpi_match_table = ACPI_PTR(silead_ts_acpi_match), | ||
561 | .pm = &silead_ts_pm, | ||
562 | }, | ||
563 | }; | ||
564 | module_i2c_driver(silead_ts_driver); | ||
565 | |||
566 | MODULE_AUTHOR("Robert Dolca <robert.dolca@intel.com>"); | ||
567 | MODULE_DESCRIPTION("Silead I2C touchscreen driver"); | ||
568 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c new file mode 100644 index 000000000000..8d93f8c9a403 --- /dev/null +++ b/drivers/input/touchscreen/sis_i2c.c | |||
@@ -0,0 +1,413 @@ | |||
1 | /* | ||
2 | * Touch Screen driver for SiS 9200 family I2C Touch panels | ||
3 | * | ||
4 | * Copyright (C) 2015 SiS, Inc. | ||
5 | * Copyright (C) 2016 Nextfour Group | ||
6 | * | ||
7 | * This software is licensed under the terms of the GNU General Public | ||
8 | * License version 2, as published by the Free Software Foundation, and | ||
9 | * may be copied, distributed, and modified under those terms. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/crc-itu-t.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/input.h> | ||
21 | #include <linux/input/mt.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/gpio/consumer.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <asm/unaligned.h> | ||
27 | |||
28 | #define SIS_I2C_NAME "sis_i2c_ts" | ||
29 | |||
30 | /* | ||
31 | * The I2C packet format: | ||
32 | * le16 byte count | ||
33 | * u8 Report ID | ||
34 | * <contact data - variable length> | ||
35 | * u8 Number of contacts | ||
36 | * le16 Scan Time (optional) | ||
37 | * le16 CRC | ||
38 | * | ||
39 | * One touch point information consists of 6+ bytes, the order is: | ||
40 | * u8 contact state | ||
41 | * u8 finger id | ||
42 | * le16 x axis | ||
43 | * le16 y axis | ||
44 | * u8 contact width (optional) | ||
45 | * u8 contact height (optional) | ||
46 | * u8 pressure (optional) | ||
47 | * | ||
48 | * Maximum amount of data transmitted in one shot is 64 bytes, if controller | ||
49 | * needs to report more contacts than fit in one packet it will send true | ||
50 | * number of contacts in first packet and 0 as number of contacts in second | ||
51 | * packet. | ||
52 | */ | ||
53 | |||
54 | #define SIS_MAX_PACKET_SIZE 64 | ||
55 | |||
56 | #define SIS_PKT_LEN_OFFSET 0 | ||
57 | #define SIS_PKT_REPORT_OFFSET 2 /* Report ID/type */ | ||
58 | #define SIS_PKT_CONTACT_OFFSET 3 /* First contact */ | ||
59 | |||
60 | #define SIS_SCAN_TIME_LEN 2 | ||
61 | |||
62 | /* Supported report types */ | ||
63 | #define SIS_ALL_IN_ONE_PACKAGE 0x10 | ||
64 | #define SIS_PKT_IS_TOUCH(x) (((x) & 0x0f) == 0x01) | ||
65 | #define SIS_PKT_IS_HIDI2C(x) (((x) & 0x0f) == 0x06) | ||
66 | |||
67 | /* Contact properties within report */ | ||
68 | #define SIS_PKT_HAS_AREA(x) ((x) & BIT(4)) | ||
69 | #define SIS_PKT_HAS_PRESSURE(x) ((x) & BIT(5)) | ||
70 | #define SIS_PKT_HAS_SCANTIME(x) ((x) & BIT(6)) | ||
71 | |||
72 | /* Contact size */ | ||
73 | #define SIS_BASE_LEN_PER_CONTACT 6 | ||
74 | #define SIS_AREA_LEN_PER_CONTACT 2 | ||
75 | #define SIS_PRESSURE_LEN_PER_CONTACT 1 | ||
76 | |||
77 | /* Offsets within contact data */ | ||
78 | #define SIS_CONTACT_STATUS_OFFSET 0 | ||
79 | #define SIS_CONTACT_ID_OFFSET 1 /* Contact ID */ | ||
80 | #define SIS_CONTACT_X_OFFSET 2 | ||
81 | #define SIS_CONTACT_Y_OFFSET 4 | ||
82 | #define SIS_CONTACT_WIDTH_OFFSET 6 | ||
83 | #define SIS_CONTACT_HEIGHT_OFFSET 7 | ||
84 | #define SIS_CONTACT_PRESSURE_OFFSET(id) (SIS_PKT_HAS_AREA(id) ? 8 : 6) | ||
85 | |||
86 | /* Individual contact state */ | ||
87 | #define SIS_STATUS_UP 0x0 | ||
88 | #define SIS_STATUS_DOWN 0x3 | ||
89 | |||
90 | /* Touchscreen parameters */ | ||
91 | #define SIS_MAX_FINGERS 10 | ||
92 | #define SIS_MAX_X 4095 | ||
93 | #define SIS_MAX_Y 4095 | ||
94 | #define SIS_MAX_PRESSURE 255 | ||
95 | |||
96 | /* Resolution diagonal */ | ||
97 | #define SIS_AREA_LENGTH_LONGER 5792 | ||
98 | /*((SIS_MAX_X^2) + (SIS_MAX_Y^2))^0.5*/ | ||
99 | #define SIS_AREA_LENGTH_SHORT 5792 | ||
100 | #define SIS_AREA_UNIT (5792 / 32) | ||
101 | |||
102 | struct sis_ts_data { | ||
103 | struct i2c_client *client; | ||
104 | struct input_dev *input; | ||
105 | |||
106 | struct gpio_desc *attn_gpio; | ||
107 | struct gpio_desc *reset_gpio; | ||
108 | |||
109 | u8 packet[SIS_MAX_PACKET_SIZE]; | ||
110 | }; | ||
111 | |||
112 | static int sis_read_packet(struct i2c_client *client, u8 *buf, | ||
113 | unsigned int *num_contacts, | ||
114 | unsigned int *contact_size) | ||
115 | { | ||
116 | int count_idx; | ||
117 | int ret; | ||
118 | u16 len; | ||
119 | u16 crc, pkg_crc; | ||
120 | u8 report_id; | ||
121 | |||
122 | ret = i2c_master_recv(client, buf, SIS_MAX_PACKET_SIZE); | ||
123 | if (ret <= 0) | ||
124 | return -EIO; | ||
125 | |||
126 | len = get_unaligned_le16(&buf[SIS_PKT_LEN_OFFSET]); | ||
127 | if (len > SIS_MAX_PACKET_SIZE) { | ||
128 | dev_err(&client->dev, | ||
129 | "%s: invalid packet length (%d vs %d)\n", | ||
130 | __func__, len, SIS_MAX_PACKET_SIZE); | ||
131 | return -E2BIG; | ||
132 | } | ||
133 | |||
134 | if (len < 10) | ||
135 | return -EINVAL; | ||
136 | |||
137 | report_id = buf[SIS_PKT_REPORT_OFFSET]; | ||
138 | count_idx = len - 1; | ||
139 | *contact_size = SIS_BASE_LEN_PER_CONTACT; | ||
140 | |||
141 | if (report_id != SIS_ALL_IN_ONE_PACKAGE) { | ||
142 | if (SIS_PKT_IS_TOUCH(report_id)) { | ||
143 | /* | ||
144 | * Calculate CRC ignoring packet length | ||
145 | * in the beginning and CRC transmitted | ||
146 | * at the end of the packet. | ||
147 | */ | ||
148 | crc = crc_itu_t(0, buf + 2, len - 2 - 2); | ||
149 | pkg_crc = get_unaligned_le16(&buf[len - 2]); | ||
150 | |||
151 | if (crc != pkg_crc) { | ||
152 | dev_err(&client->dev, | ||
153 | "%s: CRC Error (%d vs %d)\n", | ||
154 | __func__, crc, pkg_crc); | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | |||
158 | count_idx -= 2; | ||
159 | |||
160 | } else if (!SIS_PKT_IS_HIDI2C(report_id)) { | ||
161 | dev_err(&client->dev, | ||
162 | "%s: invalid packet ID %#02x\n", | ||
163 | __func__, report_id); | ||
164 | return -EINVAL; | ||
165 | } | ||
166 | |||
167 | if (SIS_PKT_HAS_SCANTIME(report_id)) | ||
168 | count_idx -= SIS_SCAN_TIME_LEN; | ||
169 | |||
170 | if (SIS_PKT_HAS_AREA(report_id)) | ||
171 | *contact_size += SIS_AREA_LEN_PER_CONTACT; | ||
172 | if (SIS_PKT_HAS_PRESSURE(report_id)) | ||
173 | *contact_size += SIS_PRESSURE_LEN_PER_CONTACT; | ||
174 | } | ||
175 | |||
176 | *num_contacts = buf[count_idx]; | ||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int sis_ts_report_contact(struct sis_ts_data *ts, const u8 *data, u8 id) | ||
181 | { | ||
182 | struct input_dev *input = ts->input; | ||
183 | int slot; | ||
184 | u8 status = data[SIS_CONTACT_STATUS_OFFSET]; | ||
185 | u8 pressure; | ||
186 | u8 height, width; | ||
187 | u16 x, y; | ||
188 | |||
189 | if (status != SIS_STATUS_DOWN && status != SIS_STATUS_UP) { | ||
190 | dev_err(&ts->client->dev, "Unexpected touch status: %#02x\n", | ||
191 | data[SIS_CONTACT_STATUS_OFFSET]); | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | slot = input_mt_get_slot_by_key(input, data[SIS_CONTACT_ID_OFFSET]); | ||
196 | if (slot < 0) | ||
197 | return -ENOENT; | ||
198 | |||
199 | input_mt_slot(input, slot); | ||
200 | input_mt_report_slot_state(input, MT_TOOL_FINGER, | ||
201 | status == SIS_STATUS_DOWN); | ||
202 | |||
203 | if (status == SIS_STATUS_DOWN) { | ||
204 | pressure = height = width = 1; | ||
205 | if (id != SIS_ALL_IN_ONE_PACKAGE) { | ||
206 | if (SIS_PKT_HAS_AREA(id)) { | ||
207 | width = data[SIS_CONTACT_WIDTH_OFFSET]; | ||
208 | height = data[SIS_CONTACT_HEIGHT_OFFSET]; | ||
209 | } | ||
210 | |||
211 | if (SIS_PKT_HAS_PRESSURE(id)) | ||
212 | pressure = | ||
213 | data[SIS_CONTACT_PRESSURE_OFFSET(id)]; | ||
214 | } | ||
215 | |||
216 | x = get_unaligned_le16(&data[SIS_CONTACT_X_OFFSET]); | ||
217 | y = get_unaligned_le16(&data[SIS_CONTACT_Y_OFFSET]); | ||
218 | |||
219 | input_report_abs(input, ABS_MT_TOUCH_MAJOR, | ||
220 | width * SIS_AREA_UNIT); | ||
221 | input_report_abs(input, ABS_MT_TOUCH_MINOR, | ||
222 | height * SIS_AREA_UNIT); | ||
223 | input_report_abs(input, ABS_MT_PRESSURE, pressure); | ||
224 | input_report_abs(input, ABS_MT_POSITION_X, x); | ||
225 | input_report_abs(input, ABS_MT_POSITION_Y, y); | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void sis_ts_handle_packet(struct sis_ts_data *ts) | ||
232 | { | ||
233 | const u8 *contact; | ||
234 | unsigned int num_to_report = 0; | ||
235 | unsigned int num_contacts; | ||
236 | unsigned int num_reported; | ||
237 | unsigned int contact_size; | ||
238 | int error; | ||
239 | u8 report_id; | ||
240 | |||
241 | do { | ||
242 | error = sis_read_packet(ts->client, ts->packet, | ||
243 | &num_contacts, &contact_size); | ||
244 | if (error) | ||
245 | break; | ||
246 | |||
247 | if (num_to_report == 0) { | ||
248 | num_to_report = num_contacts; | ||
249 | } else if (num_contacts != 0) { | ||
250 | dev_err(&ts->client->dev, | ||
251 | "%s: nonzero (%d) point count in tail packet\n", | ||
252 | __func__, num_contacts); | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | report_id = ts->packet[SIS_PKT_REPORT_OFFSET]; | ||
257 | contact = &ts->packet[SIS_PKT_CONTACT_OFFSET]; | ||
258 | num_reported = 0; | ||
259 | |||
260 | while (num_to_report > 0) { | ||
261 | error = sis_ts_report_contact(ts, contact, report_id); | ||
262 | if (error) | ||
263 | break; | ||
264 | |||
265 | contact += contact_size; | ||
266 | num_to_report--; | ||
267 | num_reported++; | ||
268 | |||
269 | if (report_id != SIS_ALL_IN_ONE_PACKAGE && | ||
270 | num_reported >= 5) { | ||
271 | /* | ||
272 | * The remainder of contacts is sent | ||
273 | * in the 2nd packet. | ||
274 | */ | ||
275 | break; | ||
276 | } | ||
277 | } | ||
278 | } while (num_to_report > 0); | ||
279 | |||
280 | input_mt_sync_frame(ts->input); | ||
281 | input_sync(ts->input); | ||
282 | } | ||
283 | |||
284 | static irqreturn_t sis_ts_irq_handler(int irq, void *dev_id) | ||
285 | { | ||
286 | struct sis_ts_data *ts = dev_id; | ||
287 | |||
288 | do { | ||
289 | sis_ts_handle_packet(ts); | ||
290 | } while (ts->attn_gpio && gpiod_get_value_cansleep(ts->attn_gpio)); | ||
291 | |||
292 | return IRQ_HANDLED; | ||
293 | } | ||
294 | |||
295 | static void sis_ts_reset(struct sis_ts_data *ts) | ||
296 | { | ||
297 | if (ts->reset_gpio) { | ||
298 | /* Get out of reset */ | ||
299 | usleep_range(1000, 2000); | ||
300 | gpiod_set_value(ts->reset_gpio, 1); | ||
301 | usleep_range(1000, 2000); | ||
302 | gpiod_set_value(ts->reset_gpio, 0); | ||
303 | msleep(100); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | static int sis_ts_probe(struct i2c_client *client, | ||
308 | const struct i2c_device_id *id) | ||
309 | { | ||
310 | struct sis_ts_data *ts; | ||
311 | struct input_dev *input; | ||
312 | int error; | ||
313 | |||
314 | ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); | ||
315 | if (!ts) | ||
316 | return -ENOMEM; | ||
317 | |||
318 | ts->client = client; | ||
319 | i2c_set_clientdata(client, ts); | ||
320 | |||
321 | ts->attn_gpio = devm_gpiod_get_optional(&client->dev, | ||
322 | "attn", GPIOD_IN); | ||
323 | if (IS_ERR(ts->attn_gpio)) { | ||
324 | error = PTR_ERR(ts->attn_gpio); | ||
325 | if (error != -EPROBE_DEFER) | ||
326 | dev_err(&client->dev, | ||
327 | "Failed to get attention GPIO: %d\n", error); | ||
328 | return error; | ||
329 | } | ||
330 | |||
331 | ts->reset_gpio = devm_gpiod_get_optional(&client->dev, | ||
332 | "reset", GPIOD_OUT_LOW); | ||
333 | if (IS_ERR(ts->reset_gpio)) { | ||
334 | error = PTR_ERR(ts->reset_gpio); | ||
335 | if (error != -EPROBE_DEFER) | ||
336 | dev_err(&client->dev, | ||
337 | "Failed to get reset GPIO: %d\n", error); | ||
338 | return error; | ||
339 | } | ||
340 | |||
341 | sis_ts_reset(ts); | ||
342 | |||
343 | ts->input = input = devm_input_allocate_device(&client->dev); | ||
344 | if (!input) { | ||
345 | dev_err(&client->dev, "Failed to allocate input device\n"); | ||
346 | return -ENOMEM; | ||
347 | } | ||
348 | |||
349 | input->name = "SiS Touchscreen"; | ||
350 | input->id.bustype = BUS_I2C; | ||
351 | |||
352 | input_set_abs_params(input, ABS_MT_POSITION_X, 0, SIS_MAX_X, 0, 0); | ||
353 | input_set_abs_params(input, ABS_MT_POSITION_Y, 0, SIS_MAX_Y, 0, 0); | ||
354 | input_set_abs_params(input, ABS_MT_PRESSURE, 0, SIS_MAX_PRESSURE, 0, 0); | ||
355 | input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, | ||
356 | 0, SIS_AREA_LENGTH_LONGER, 0, 0); | ||
357 | input_set_abs_params(input, ABS_MT_TOUCH_MINOR, | ||
358 | 0, SIS_AREA_LENGTH_SHORT, 0, 0); | ||
359 | |||
360 | error = input_mt_init_slots(input, SIS_MAX_FINGERS, INPUT_MT_DIRECT); | ||
361 | if (error) { | ||
362 | dev_err(&client->dev, | ||
363 | "Failed to initialize MT slots: %d\n", error); | ||
364 | return error; | ||
365 | } | ||
366 | |||
367 | error = devm_request_threaded_irq(&client->dev, client->irq, | ||
368 | NULL, sis_ts_irq_handler, | ||
369 | IRQF_ONESHOT, | ||
370 | client->name, ts); | ||
371 | if (error) { | ||
372 | dev_err(&client->dev, "Failed to request IRQ: %d\n", error); | ||
373 | return error; | ||
374 | } | ||
375 | |||
376 | error = input_register_device(ts->input); | ||
377 | if (error) { | ||
378 | dev_err(&client->dev, | ||
379 | "Failed to register input device: %d\n", error); | ||
380 | return error; | ||
381 | } | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | #ifdef CONFIG_OF | ||
387 | static const struct of_device_id sis_ts_dt_ids[] = { | ||
388 | { .compatible = "sis,9200-ts" }, | ||
389 | { /* sentinel */ } | ||
390 | }; | ||
391 | MODULE_DEVICE_TABLE(of, sis_ts_dt_ids); | ||
392 | #endif | ||
393 | |||
394 | static const struct i2c_device_id sis_ts_id[] = { | ||
395 | { SIS_I2C_NAME, 0 }, | ||
396 | { "9200-ts", 0 }, | ||
397 | { /* sentinel */ } | ||
398 | }; | ||
399 | MODULE_DEVICE_TABLE(i2c, sis_ts_id); | ||
400 | |||
401 | static struct i2c_driver sis_ts_driver = { | ||
402 | .driver = { | ||
403 | .name = SIS_I2C_NAME, | ||
404 | .of_match_table = of_match_ptr(sis_ts_dt_ids), | ||
405 | }, | ||
406 | .probe = sis_ts_probe, | ||
407 | .id_table = sis_ts_id, | ||
408 | }; | ||
409 | module_i2c_driver(sis_ts_driver); | ||
410 | |||
411 | MODULE_DESCRIPTION("SiS 9200 Family Touchscreen Driver"); | ||
412 | MODULE_LICENSE("GPL v2"); | ||
413 | MODULE_AUTHOR("Mika Penttilä <mika.penttila@nextfour.com>"); | ||
diff --git a/include/linux/i8042.h b/include/linux/i8042.h index 0f9bafa17a02..d98780ca9604 100644 --- a/include/linux/i8042.h +++ b/include/linux/i8042.h | |||
@@ -62,7 +62,6 @@ struct serio; | |||
62 | void i8042_lock_chip(void); | 62 | void i8042_lock_chip(void); |
63 | void i8042_unlock_chip(void); | 63 | void i8042_unlock_chip(void); |
64 | int i8042_command(unsigned char *param, int command); | 64 | int i8042_command(unsigned char *param, int command); |
65 | bool i8042_check_port_owner(const struct serio *); | ||
66 | int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, | 65 | int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, |
67 | struct serio *serio)); | 66 | struct serio *serio)); |
68 | int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, | 67 | int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, |
@@ -83,11 +82,6 @@ static inline int i8042_command(unsigned char *param, int command) | |||
83 | return -ENODEV; | 82 | return -ENODEV; |
84 | } | 83 | } |
85 | 84 | ||
86 | static inline bool i8042_check_port_owner(const struct serio *serio) | ||
87 | { | ||
88 | return false; | ||
89 | } | ||
90 | |||
91 | static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, | 85 | static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, |
92 | struct serio *serio)) | 86 | struct serio *serio)) |
93 | { | 87 | { |
diff --git a/include/linux/serio.h b/include/linux/serio.h index df4ab5de1586..c733cff44e18 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h | |||
@@ -31,7 +31,8 @@ struct serio { | |||
31 | 31 | ||
32 | struct serio_device_id id; | 32 | struct serio_device_id id; |
33 | 33 | ||
34 | spinlock_t lock; /* protects critical sections from port's interrupt handler */ | 34 | /* Protects critical sections from port's interrupt handler */ |
35 | spinlock_t lock; | ||
35 | 36 | ||
36 | int (*write)(struct serio *, unsigned char); | 37 | int (*write)(struct serio *, unsigned char); |
37 | int (*open)(struct serio *); | 38 | int (*open)(struct serio *); |
@@ -40,16 +41,29 @@ struct serio { | |||
40 | void (*stop)(struct serio *); | 41 | void (*stop)(struct serio *); |
41 | 42 | ||
42 | struct serio *parent; | 43 | struct serio *parent; |
43 | struct list_head child_node; /* Entry in parent->children list */ | 44 | /* Entry in parent->children list */ |
45 | struct list_head child_node; | ||
44 | struct list_head children; | 46 | struct list_head children; |
45 | unsigned int depth; /* level of nesting in serio hierarchy */ | 47 | /* Level of nesting in serio hierarchy */ |
48 | unsigned int depth; | ||
46 | 49 | ||
47 | struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ | 50 | /* |
48 | struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */ | 51 | * serio->drv is accessed from interrupt handlers; when modifying |
52 | * caller should acquire serio->drv_mutex and serio->lock. | ||
53 | */ | ||
54 | struct serio_driver *drv; | ||
55 | /* Protects serio->drv so attributes can pin current driver */ | ||
56 | struct mutex drv_mutex; | ||
49 | 57 | ||
50 | struct device dev; | 58 | struct device dev; |
51 | 59 | ||
52 | struct list_head node; | 60 | struct list_head node; |
61 | |||
62 | /* | ||
63 | * For use by PS/2 layer when several ports share hardware and | ||
64 | * may get indigestion when exposed to concurrent access (i8042). | ||
65 | */ | ||
66 | struct mutex *ps2_cmd_mutex; | ||
53 | }; | 67 | }; |
54 | #define to_serio_port(d) container_of(d, struct serio, dev) | 68 | #define to_serio_port(d) container_of(d, struct serio, dev) |
55 | 69 | ||