Browse Source

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:

 - three new touchscreen drivers: EETI EXC3000, HiDeep, and Samsung
   S6SY761

 - the timer API conversion (setup_timer() -> timer_setup())

 - a few drivers swiytched to using managed API for creating custom
   device attributes

 - other assorted fixed and cleanups.

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (50 commits)
  Input: gamecon - mark expected switch fall-throughs
  Input: sidewinder - mark expected switch fall-throughs
  Input: spaceball - mark expected switch fall-throughs
  Input: uinput - unlock on allocation failure in ioctl
  Input: add support for the Samsung S6SY761 touchscreen
  Input: add support for HiDeep touchscreen
  Input: st1232 - remove obsolete platform device support
  Input: convert autorepeat timer to use timer_setup()
  media: ttpci: remove autorepeat handling and use timer_setup
  Input: cyttsp4 - avoid overflows when calculating memory sizes
  Input: mxs-lradc - remove redundant assignment to pointer input
  Input: add I2C attached EETI EXC3000 multi touch driver
  Input: goodix - support gt1151 touchpanel
  Input: ps2-gpio - actually abort probe when connected to sleeping GPIOs
  Input: hil_mlc - convert to using timer_setup()
  Input: hp_sdc - convert to using timer_setup()
  Input: touchsceen - convert timers to use timer_setup()
  Input: keyboard - convert timers to use timer_setup()
  Input: uinput - fold header into the driver proper
  Input: uinput - remove uinput_allocate_device()
  ...
Linus Torvalds 7 years ago
parent
commit
9f7a9b1191
55 changed files with 2776 additions and 731 deletions
  1. 32 0
      Documentation/devicetree/bindings/input/gpio-mouse.txt
  2. 27 0
      Documentation/devicetree/bindings/input/touchscreen/exc3000.txt
  3. 2 1
      Documentation/devicetree/bindings/input/touchscreen/goodix.txt
  4. 42 0
      Documentation/devicetree/bindings/input/touchscreen/hideep.txt
  5. 34 0
      Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.txt
  6. 1 0
      Documentation/devicetree/bindings/vendor-prefixes.txt
  7. 4 4
      drivers/input/ff-memless.c
  8. 5 6
      drivers/input/input.c
  9. 3 0
      drivers/input/joystick/gamecon.c
  10. 5 5
      drivers/input/joystick/sidewinder.c
  11. 4 0
      drivers/input/joystick/spaceball.c
  12. 3 4
      drivers/input/keyboard/bf54x-keys.c
  13. 3 4
      drivers/input/keyboard/gpio_keys.c
  14. 4 4
      drivers/input/keyboard/imx_keypad.c
  15. 3 4
      drivers/input/keyboard/locomokbd.c
  16. 3 3
      drivers/input/keyboard/omap-keypad.c
  17. 3 4
      drivers/input/keyboard/snvs_pwrkey.c
  18. 3 3
      drivers/input/keyboard/tegra-kbc.c
  19. 1 1
      drivers/input/misc/adxl34x.c
  20. 170 135
      drivers/input/misc/uinput.c
  21. 4 4
      drivers/input/mouse/alps.c
  22. 6 4
      drivers/input/mouse/byd.c
  23. 7 4
      drivers/input/mouse/elan_i2c_core.c
  24. 101 105
      drivers/input/mouse/gpio_mouse.c
  25. 1 1
      drivers/input/rmi4/rmi_f54.c
  26. 2 2
      drivers/input/serio/hil_mlc.c
  27. 2 3
      drivers/input/serio/hp_sdc.c
  28. 1 0
      drivers/input/serio/ps2-gpio.c
  29. 41 28
      drivers/input/serio/sa1111ps2.c
  30. 33 1
      drivers/input/touchscreen/Kconfig
  31. 3 0
      drivers/input/touchscreen/Makefile
  32. 3 3
      drivers/input/touchscreen/ad7877.c
  33. 4 15
      drivers/input/touchscreen/ad7879.c
  34. 6 4
      drivers/input/touchscreen/atmel-wm97xx.c
  35. 43 16
      drivers/input/touchscreen/cyttsp4_core.c
  36. 130 43
      drivers/input/touchscreen/edt-ft5x06.c
  37. 1 18
      drivers/input/touchscreen/elants_i2c.c
  38. 223 0
      drivers/input/touchscreen/exc3000.c
  39. 98 27
      drivers/input/touchscreen/goodix.c
  40. 1120 0
      drivers/input/touchscreen/hideep.c
  41. 1 16
      drivers/input/touchscreen/melfas_mip4.c
  42. 1 1
      drivers/input/touchscreen/mxs-lradc-ts.c
  43. 1 17
      drivers/input/touchscreen/raydium_i2c_ts.c
  44. 1 16
      drivers/input/touchscreen/rohm_bu21023.c
  45. 559 0
      drivers/input/touchscreen/s6sy761.c
  46. 3 13
      drivers/input/touchscreen/st1232.c
  47. 1 3
      drivers/input/touchscreen/stmfts.c
  48. 3 3
      drivers/input/touchscreen/tsc200x-core.c
  49. 3 4
      drivers/input/touchscreen/w90p910_ts.c
  50. 1 9
      drivers/input/touchscreen/wdt87xx_i2c.c
  51. 1 1
      drivers/media/pci/ttpci/av7110.h
  52. 20 36
      drivers/media/pci/ttpci/av7110_ir.c
  53. 0 61
      include/linux/gpio_mouse.h
  54. 0 14
      include/linux/platform_data/st1232_pdata.h
  55. 0 81
      include/linux/uinput.h

+ 32 - 0
Documentation/devicetree/bindings/input/gpio-mouse.txt

@@ -0,0 +1,32 @@
+Device-Tree bindings for GPIO attached mice
+
+This simply uses standard GPIO handles to define a simple mouse connected
+to 5-7 GPIO lines.
+
+Required properties:
+	- compatible: must be "gpio-mouse"
+	- scan-interval-ms: The scanning interval in milliseconds
+	- up-gpios: GPIO line phandle to the line indicating "up"
+	- down-gpios: GPIO line phandle to the line indicating "down"
+	- left-gpios: GPIO line phandle to the line indicating "left"
+	- right-gpios: GPIO line phandle to the line indicating "right"
+
+Optional properties:
+	- button-left-gpios: GPIO line handle to the left mouse button
+	- button-middle-gpios: GPIO line handle to the middle mouse button
+	- button-right-gpios: GPIO line handle to the right mouse button
+Example:
+
+#include <dt-bindings/gpio/gpio.h>
+
+gpio-mouse {
+	compatible = "gpio-mouse";
+	scan-interval-ms = <50>;
+	up-gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
+	down-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
+	left-gpios = <&gpio0 2 GPIO_ACTIVE_LOW>;
+	right-gpios = <&gpio0 3 GPIO_ACTIVE_LOW>;
+	button-left-gpios = <&gpio0 4 GPIO_ACTIVE_LOW>;
+	button-middle-gpios = <&gpio0 5 GPIO_ACTIVE_LOW>;
+	button-right-gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
+};

+ 27 - 0
Documentation/devicetree/bindings/input/touchscreen/exc3000.txt

@@ -0,0 +1,27 @@
+* EETI EXC3000 Multiple Touch Controller
+
+Required properties:
+- compatible: must be "eeti,exc3000"
+- reg: i2c slave address
+- interrupt-parent: the phandle for the interrupt controller
+- interrupts: touch controller interrupt
+- touchscreen-size-x: See touchscreen.txt
+- touchscreen-size-y: See touchscreen.txt
+
+Optional properties:
+- touchscreen-inverted-x: See touchscreen.txt
+- touchscreen-inverted-y: See touchscreen.txt
+- touchscreen-swapped-x-y: See touchscreen.txt
+
+Example:
+
+	touchscreen@2a {
+		compatible = "eeti,exc3000";
+		reg = <0x2a>;
+		interrupt-parent = <&gpio1>;
+		interrupts = <9 IRQ_TYPE_LEVEL_LOW>;
+		touchscreen-size-x = <4096>;
+		touchscreen-size-y = <4096>;
+		touchscreen-inverted-x;
+		touchscreen-swapped-x-y;
+	};

+ 2 - 1
Documentation/devicetree/bindings/input/touchscreen/goodix.txt

@@ -2,7 +2,8 @@ Device tree bindings for Goodix GT9xx series touchscreen controller
 
 
 Required properties:
 Required properties:
 
 
- - compatible		: Should be "goodix,gt911"
+ - compatible		: Should be "goodix,gt1151"
+				 or "goodix,gt911"
 				 or "goodix,gt9110"
 				 or "goodix,gt9110"
 				 or "goodix,gt912"
 				 or "goodix,gt912"
 				 or "goodix,gt927"
 				 or "goodix,gt927"

+ 42 - 0
Documentation/devicetree/bindings/input/touchscreen/hideep.txt

@@ -0,0 +1,42 @@
+* HiDeep Finger and Stylus touchscreen controller
+
+Required properties:
+- compatible		: must be "hideep,hideep-ts"
+- reg			: I2C slave address, (e.g. 0x6C).
+- interrupt-parent : Interrupt controller to which the chip is connected.
+- interrupts : Interrupt to which the chip is connected.
+
+Optional properties:
+- vdd-supply	: It is the controller supply for controlling
+					 main voltage(3.3V) through the regulator.
+- vid-supply	: It is the controller supply for controlling
+					IO voltage(1.8V) through the regulator.
+- reset-gpios	: Define for reset gpio pin.
+						It is to use for reset IC.
+- touchscreen-size-x	: X axis size of touchscreen
+- touchscreen-size-y	: Y axis size of touchscreen
+- linux,keycodes	: Specifies an array of numeric keycode values to
+			be used for reporting button presses. The array can
+			contain up to 3 entries.
+
+Example:
+
+#include "dt-bindings/input/input.h"
+
+i2c@00000000 {
+
+	/* ... */
+
+	touchscreen@6c {
+		compatible = "hideep,hideep-ts";
+		reg = <0x6c>;
+		interrupt-parent = <&gpx1>;
+		interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+		vdd-supply = <&ldo15_reg>";
+		vid-supply = <&ldo18_reg>;
+		reset-gpios = <&gpx1 5 0>;
+		touchscreen-size-x = <1080>;
+		touchscreen-size-y = <1920>;
+		linux,keycodes = <KEY_HOME>, <KEY_MENU>, <KEY_BACK>;
+	};
+};

+ 34 - 0
Documentation/devicetree/bindings/input/touchscreen/samsung,s6sy761.txt

@@ -0,0 +1,34 @@
+* Samsung S6SY761 touchscreen controller
+
+Required properties:
+- compatible		: must be "samsung,s6sy761"
+- reg			: I2C slave address, (e.g. 0x48)
+- interrupt-parent	: the phandle to the interrupt controller which provides
+			  the interrupt
+- interrupts		: interrupt specification
+- avdd-supply		: analogic power supply
+- vdd-supply		: power supply
+
+Optional properties:
+- touchscreen-size-x	: see touchscreen.txt. This property is embedded in the
+			  device. If defined it forces a different x resolution.
+- touchscreen-size-y	: see touchscreen.txt. This property is embedded in the
+			  device. If defined it forces a different y resolution.
+
+Example:
+
+i2c@00000000 {
+
+	/* ... */
+
+	touchscreen@48 {
+		compatible = "samsung,s6sy761";
+		reg = <0x48>;
+		interrupt-parent = <&gpa1>;
+		interrupts = <1 IRQ_TYPE_NONE>;
+		avdd-supply = <&ldo30_reg>;
+		vdd-supply = <&ldo31_reg>;
+		touchscreen-size-x = <4096>;
+		touchscreen-size-y = <4096>;
+	};
+};

+ 1 - 0
Documentation/devicetree/bindings/vendor-prefixes.txt

@@ -137,6 +137,7 @@ gw	Gateworks Corporation
 hannstar	HannStar Display Corporation
 hannstar	HannStar Display Corporation
 haoyu	Haoyu Microelectronic Co. Ltd.
 haoyu	Haoyu Microelectronic Co. Ltd.
 hardkernel	Hardkernel Co., Ltd
 hardkernel	Hardkernel Co., Ltd
+hideep	HiDeep Inc.
 himax	Himax Technologies, Inc.
 himax	Himax Technologies, Inc.
 hisilicon	Hisilicon Limited.
 hisilicon	Hisilicon Limited.
 hit	Hitachi Ltd.
 hit	Hitachi Ltd.

+ 4 - 4
drivers/input/ff-memless.c

@@ -412,10 +412,10 @@ static void ml_play_effects(struct ml_device *ml)
 	ml_schedule_timer(ml);
 	ml_schedule_timer(ml);
 }
 }
 
 
-static void ml_effect_timer(unsigned long timer_data)
+static void ml_effect_timer(struct timer_list *t)
 {
 {
-	struct input_dev *dev = (struct input_dev *)timer_data;
-	struct ml_device *ml = dev->ff->private;
+	struct ml_device *ml = from_timer(ml, t, timer);
+	struct input_dev *dev = ml->dev;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	pr_debug("timer: updating effects\n");
 	pr_debug("timer: updating effects\n");
@@ -526,7 +526,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
 	ml->private = data;
 	ml->private = data;
 	ml->play_effect = play_effect;
 	ml->play_effect = play_effect;
 	ml->gain = 0xffff;
 	ml->gain = 0xffff;
-	setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
+	timer_setup(&ml->timer, ml_effect_timer, 0);
 
 
 	set_bit(FF_GAIN, dev->ffbit);
 	set_bit(FF_GAIN, dev->ffbit);
 
 

+ 5 - 6
drivers/input/input.c

@@ -76,7 +76,7 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
 {
 {
 	if (test_bit(EV_REP, dev->evbit) &&
 	if (test_bit(EV_REP, dev->evbit) &&
 	    dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
 	    dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] &&
-	    dev->timer.data) {
+	    dev->timer.function) {
 		dev->repeat_key = code;
 		dev->repeat_key = code;
 		mod_timer(&dev->timer,
 		mod_timer(&dev->timer,
 			  jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
 			  jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]));
@@ -179,9 +179,9 @@ static void input_pass_event(struct input_dev *dev,
  * dev->event_lock here to avoid racing with input_event
  * dev->event_lock here to avoid racing with input_event
  * which may cause keys get "stuck".
  * which may cause keys get "stuck".
  */
  */
-static void input_repeat_key(unsigned long data)
+static void input_repeat_key(struct timer_list *t)
 {
 {
-	struct input_dev *dev = (void *) data;
+	struct input_dev *dev = from_timer(dev, t, timer);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&dev->event_lock, flags);
 	spin_lock_irqsave(&dev->event_lock, flags);
@@ -1784,7 +1784,7 @@ struct input_dev *input_allocate_device(void)
 		device_initialize(&dev->dev);
 		device_initialize(&dev->dev);
 		mutex_init(&dev->mutex);
 		mutex_init(&dev->mutex);
 		spin_lock_init(&dev->event_lock);
 		spin_lock_init(&dev->event_lock);
-		init_timer(&dev->timer);
+		timer_setup(&dev->timer, NULL, 0);
 		INIT_LIST_HEAD(&dev->h_list);
 		INIT_LIST_HEAD(&dev->h_list);
 		INIT_LIST_HEAD(&dev->node);
 		INIT_LIST_HEAD(&dev->node);
 
 
@@ -2047,8 +2047,7 @@ static void devm_input_device_unregister(struct device *dev, void *res)
  */
  */
 void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
 void input_enable_softrepeat(struct input_dev *dev, int delay, int period)
 {
 {
-	dev->timer.data = (unsigned long) dev;
-	dev->timer.function = input_repeat_key;
+	dev->timer.function = (TIMER_FUNC_TYPE)input_repeat_key;
 	dev->rep[REP_DELAY] = delay;
 	dev->rep[REP_DELAY] = delay;
 	dev->rep[REP_PERIOD] = period;
 	dev->rep[REP_PERIOD] = period;
 }
 }

+ 3 - 0
drivers/input/joystick/gamecon.c

@@ -654,6 +654,7 @@ static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
 
 
 		input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
 		input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
 		input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
 		input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
+		/* fall through */
 
 
 	case GC_PSX_NEGCON:
 	case GC_PSX_NEGCON:
 	case GC_PSX_ANALOG:
 	case GC_PSX_ANALOG:
@@ -887,6 +888,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
 	case GC_SNES:
 	case GC_SNES:
 		for (i = 4; i < 8; i++)
 		for (i = 4; i < 8; i++)
 			__set_bit(gc_snes_btn[i], input_dev->keybit);
 			__set_bit(gc_snes_btn[i], input_dev->keybit);
+		/* fall through */
 	case GC_NES:
 	case GC_NES:
 		for (i = 0; i < 4; i++)
 		for (i = 0; i < 4; i++)
 			__set_bit(gc_snes_btn[i], input_dev->keybit);
 			__set_bit(gc_snes_btn[i], input_dev->keybit);
@@ -894,6 +896,7 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
 
 
 	case GC_MULTI2:
 	case GC_MULTI2:
 		__set_bit(BTN_THUMB, input_dev->keybit);
 		__set_bit(BTN_THUMB, input_dev->keybit);
+		/* fall through */
 	case GC_MULTI:
 	case GC_MULTI:
 		__set_bit(BTN_TRIGGER, input_dev->keybit);
 		__set_bit(BTN_TRIGGER, input_dev->keybit);
 		break;
 		break;

+ 5 - 5
drivers/input/joystick/sidewinder.c

@@ -672,16 +672,16 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
 
 
 			switch (i * m) {
 			switch (i * m) {
 				case 60:
 				case 60:
-					sw->number++;
+					sw->number++;			/* fall through */
 				case 45:				/* Ambiguous packet length */
 				case 45:				/* Ambiguous packet length */
 					if (j <= 40) {			/* ID length less or eq 40 -> FSP */
 					if (j <= 40) {			/* ID length less or eq 40 -> FSP */
 				case 43:
 				case 43:
 						sw->type = SW_ID_FSP;
 						sw->type = SW_ID_FSP;
 						break;
 						break;
 					}
 					}
-					sw->number++;
+					sw->number++;			/* fall through */
 				case 30:
 				case 30:
-					sw->number++;
+					sw->number++;			/* fall through */
 				case 15:
 				case 15:
 					sw->type = SW_ID_GP;
 					sw->type = SW_ID_GP;
 					break;
 					break;
@@ -697,9 +697,9 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
 						sw->type = SW_ID_PP;
 						sw->type = SW_ID_PP;
 					break;
 					break;
 				case 66:
 				case 66:
-					sw->bits = 3;
+					sw->bits = 3;			/* fall through */
 				case 198:
 				case 198:
-					sw->length = 22;
+					sw->length = 22;		/* fall through */
 				case 64:
 				case 64:
 					sw->type = SW_ID_3DP;
 					sw->type = SW_ID_3DP;
 					if (j == 160)
 					if (j == 160)

+ 4 - 0
drivers/input/joystick/spaceball.c

@@ -162,6 +162,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
 				break;
 				break;
 			}
 			}
 			spaceball->escape = 0;
 			spaceball->escape = 0;
+			/* fall through */
 		case 'M':
 		case 'M':
 		case 'Q':
 		case 'Q':
 		case 'S':
 		case 'S':
@@ -169,6 +170,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
 				spaceball->escape = 0;
 				spaceball->escape = 0;
 				data &= 0x1f;
 				data &= 0x1f;
 			}
 			}
+			/* fall through */
 		default:
 		default:
 			if (spaceball->escape)
 			if (spaceball->escape)
 				spaceball->escape = 0;
 				spaceball->escape = 0;
@@ -234,11 +236,13 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
 			input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
 			input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
 				BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
 				BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
 				BIT_MASK(BTN_MODE);
 				BIT_MASK(BTN_MODE);
+			/* fall through */
 		default:
 		default:
 			input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
 			input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
 				BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
 				BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
 				BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
 				BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
 				BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
 				BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
+			/* fall through */
 		case SPACEBALL_3003C:
 		case SPACEBALL_3003C:
 			input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
 			input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
 				BIT_MASK(BTN_8);
 				BIT_MASK(BTN_8);

+ 3 - 4
drivers/input/keyboard/bf54x-keys.c

@@ -127,10 +127,9 @@ static inline void bfin_kpad_clear_irq(void)
 	bfin_write_KPAD_ROWCOL(0xFFFF);
 	bfin_write_KPAD_ROWCOL(0xFFFF);
 }
 }
 
 
-static void bfin_kpad_timer(unsigned long data)
+static void bfin_kpad_timer(struct timer_list *t)
 {
 {
-	struct platform_device *pdev =  (struct platform_device *) data;
-	struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
+	struct bf54x_kpad *bf54x_kpad = from_timer(bf54x_kpad, t, timer);
 
 
 	if (bfin_kpad_get_keypressed(bf54x_kpad)) {
 	if (bfin_kpad_get_keypressed(bf54x_kpad)) {
 		/* Try again later */
 		/* Try again later */
@@ -298,7 +297,7 @@ static int bfin_kpad_probe(struct platform_device *pdev)
 
 
 	/* Init Keypad Key Up/Release test timer */
 	/* Init Keypad Key Up/Release test timer */
 
 
-	setup_timer(&bf54x_kpad->timer, bfin_kpad_timer, (unsigned long) pdev);
+	timer_setup(&bf54x_kpad->timer, bfin_kpad_timer, 0);
 
 
 	bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
 	bfin_write_KPAD_PRESCALE(bfin_kpad_get_prescale(TIME_SCALE));
 
 

+ 3 - 4
drivers/input/keyboard/gpio_keys.c

@@ -419,9 +419,9 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static void gpio_keys_irq_timer(unsigned long _data)
+static void gpio_keys_irq_timer(struct timer_list *t)
 {
 {
-	struct gpio_button_data *bdata = (struct gpio_button_data *)_data;
+	struct gpio_button_data *bdata = from_timer(bdata, t, release_timer);
 	struct input_dev *input = bdata->input;
 	struct input_dev *input = bdata->input;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -582,8 +582,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
 		}
 		}
 
 
 		bdata->release_delay = button->debounce_interval;
 		bdata->release_delay = button->debounce_interval;
-		setup_timer(&bdata->release_timer,
-			    gpio_keys_irq_timer, (unsigned long)bdata);
+		timer_setup(&bdata->release_timer, gpio_keys_irq_timer, 0);
 
 
 		isr = gpio_keys_irq_isr;
 		isr = gpio_keys_irq_isr;
 		irqflags = 0;
 		irqflags = 0;

+ 4 - 4
drivers/input/keyboard/imx_keypad.c

@@ -184,9 +184,9 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad,
 /*
 /*
  * imx_keypad_check_for_events is the timer handler.
  * imx_keypad_check_for_events is the timer handler.
  */
  */
-static void imx_keypad_check_for_events(unsigned long data)
+static void imx_keypad_check_for_events(struct timer_list *t)
 {
 {
-	struct imx_keypad *keypad = (struct imx_keypad *) data;
+	struct imx_keypad *keypad = from_timer(keypad, t, check_matrix_timer);
 	unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
 	unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
 	unsigned short reg_val;
 	unsigned short reg_val;
 	bool state_changed, is_zero_matrix;
 	bool state_changed, is_zero_matrix;
@@ -456,8 +456,8 @@ static int imx_keypad_probe(struct platform_device *pdev)
 	keypad->irq = irq;
 	keypad->irq = irq;
 	keypad->stable_count = 0;
 	keypad->stable_count = 0;
 
 
-	setup_timer(&keypad->check_matrix_timer,
-		    imx_keypad_check_for_events, (unsigned long) keypad);
+	timer_setup(&keypad->check_matrix_timer,
+		    imx_keypad_check_for_events, 0);
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);
 	keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res);

+ 3 - 4
drivers/input/keyboard/locomokbd.c

@@ -210,9 +210,9 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
 /*
 /*
  * LoCoMo timer checking for released keys
  * LoCoMo timer checking for released keys
  */
  */
-static void locomokbd_timer_callback(unsigned long data)
+static void locomokbd_timer_callback(struct timer_list *t)
 {
 {
-	struct locomokbd *locomokbd = (struct locomokbd *) data;
+	struct locomokbd *locomokbd = from_timer(locomokbd, t, timer);
 
 
 	locomokbd_scankeyboard(locomokbd);
 	locomokbd_scankeyboard(locomokbd);
 }
 }
@@ -264,8 +264,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
 
 
 	spin_lock_init(&locomokbd->lock);
 	spin_lock_init(&locomokbd->lock);
 
 
-	setup_timer(&locomokbd->timer, locomokbd_timer_callback,
-		    (unsigned long)locomokbd);
+	timer_setup(&locomokbd->timer, locomokbd_timer_callback, 0);
 
 
 	locomokbd->suspend_jiffies = jiffies;
 	locomokbd->suspend_jiffies = jiffies;
 
 

+ 3 - 3
drivers/input/keyboard/omap-keypad.c

@@ -41,7 +41,7 @@
 #undef NEW_BOARD_LEARNING_MODE
 #undef NEW_BOARD_LEARNING_MODE
 
 
 static void omap_kp_tasklet(unsigned long);
 static void omap_kp_tasklet(unsigned long);
-static void omap_kp_timer(unsigned long);
+static void omap_kp_timer(struct timer_list *);
 
 
 static unsigned char keypad_state[8];
 static unsigned char keypad_state[8];
 static DEFINE_MUTEX(kp_enable_mutex);
 static DEFINE_MUTEX(kp_enable_mutex);
@@ -74,7 +74,7 @@ static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static void omap_kp_timer(unsigned long data)
+static void omap_kp_timer(struct timer_list *unused)
 {
 {
 	tasklet_schedule(&kp_tasklet);
 	tasklet_schedule(&kp_tasklet);
 }
 }
@@ -233,7 +233,7 @@ static int omap_kp_probe(struct platform_device *pdev)
 	col_idx = 0;
 	col_idx = 0;
 	row_idx = 0;
 	row_idx = 0;
 
 
-	setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
+	timer_setup(&omap_kp->timer, omap_kp_timer, 0);
 
 
 	/* get the irq and init timer*/
 	/* get the irq and init timer*/
 	kp_tasklet.data = (unsigned long) omap_kp;
 	kp_tasklet.data = (unsigned long) omap_kp;

+ 3 - 4
drivers/input/keyboard/snvs_pwrkey.c

@@ -45,9 +45,9 @@ struct pwrkey_drv_data {
 	struct input_dev *input;
 	struct input_dev *input;
 };
 };
 
 
-static void imx_imx_snvs_check_for_events(unsigned long data)
+static void imx_imx_snvs_check_for_events(struct timer_list *t)
 {
 {
-	struct pwrkey_drv_data *pdata = (struct pwrkey_drv_data *) data;
+	struct pwrkey_drv_data *pdata = from_timer(pdata, t, check_timer);
 	struct input_dev *input = pdata->input;
 	struct input_dev *input = pdata->input;
 	u32 state;
 	u32 state;
 
 
@@ -134,8 +134,7 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
 	/* clear the unexpected interrupt before driver ready */
 	/* clear the unexpected interrupt before driver ready */
 	regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
 	regmap_write(pdata->snvs, SNVS_LPSR_REG, SNVS_LPSR_SPO);
 
 
-	setup_timer(&pdata->check_timer,
-		    imx_imx_snvs_check_for_events, (unsigned long) pdata);
+	timer_setup(&pdata->check_timer, imx_imx_snvs_check_for_events, 0);
 
 
 	input = devm_input_allocate_device(&pdev->dev);
 	input = devm_input_allocate_device(&pdev->dev);
 	if (!input) {
 	if (!input) {

+ 3 - 3
drivers/input/keyboard/tegra-kbc.c

@@ -251,9 +251,9 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
 	writel(val, kbc->mmio + KBC_CONTROL_0);
 	writel(val, kbc->mmio + KBC_CONTROL_0);
 }
 }
 
 
-static void tegra_kbc_keypress_timer(unsigned long data)
+static void tegra_kbc_keypress_timer(struct timer_list *t)
 {
 {
-	struct tegra_kbc *kbc = (struct tegra_kbc *)data;
+	struct tegra_kbc *kbc = from_timer(kbc, t, timer);
 	unsigned long flags;
 	unsigned long flags;
 	u32 val;
 	u32 val;
 	unsigned int i;
 	unsigned int i;
@@ -655,7 +655,7 @@ static int tegra_kbc_probe(struct platform_device *pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
+	timer_setup(&kbc->timer, tegra_kbc_keypress_timer, 0);
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	kbc->mmio = devm_ioremap_resource(&pdev->dev, res);
 	kbc->mmio = devm_ioremap_resource(&pdev->dev, res);

+ 1 - 1
drivers/input/misc/adxl34x.c

@@ -796,7 +796,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 
 
 	if (pdata->watermark) {
 	if (pdata->watermark) {
 		ac->int_mask |= WATERMARK;
 		ac->int_mask |= WATERMARK;
-		if (!FIFO_MODE(pdata->fifo_mode))
+		if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
 			ac->pdata.fifo_mode |= FIFO_STREAM;
 			ac->pdata.fifo_mode |= FIFO_STREAM;
 	} else {
 	} else {
 		ac->int_mask |= DATA_READY;
 		ac->int_mask |= DATA_READY;

+ 170 - 135
drivers/input/misc/uinput.c

@@ -31,6 +31,7 @@
  *	0.1	20/06/2002
  *	0.1	20/06/2002
  *		- first public version
  *		- first public version
  */
  */
+#include <uapi/linux/uinput.h>
 #include <linux/poll.h>
 #include <linux/poll.h>
 #include <linux/sched.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
@@ -38,10 +39,47 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <linux/miscdevice.h>
-#include <linux/uinput.h>
 #include <linux/input/mt.h>
 #include <linux/input/mt.h>
 #include "../input-compat.h"
 #include "../input-compat.h"
 
 
+#define UINPUT_NAME		"uinput"
+#define UINPUT_BUFFER_SIZE	16
+#define UINPUT_NUM_REQUESTS	16
+
+enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
+
+struct uinput_request {
+	unsigned int		id;
+	unsigned int		code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
+
+	int			retval;
+	struct completion	done;
+
+	union {
+		unsigned int	effect_id;
+		struct {
+			struct ff_effect *effect;
+			struct ff_effect *old;
+		} upload;
+	} u;
+};
+
+struct uinput_device {
+	struct input_dev	*dev;
+	struct mutex		mutex;
+	enum uinput_state	state;
+	wait_queue_head_t	waitq;
+	unsigned char		ready;
+	unsigned char		head;
+	unsigned char		tail;
+	struct input_event	buff[UINPUT_BUFFER_SIZE];
+	unsigned int		ff_effects_max;
+
+	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
+	wait_queue_head_t	requests_waitq;
+	spinlock_t		requests_lock;
+};
+
 static int uinput_dev_event(struct input_dev *dev,
 static int uinput_dev_event(struct input_dev *dev,
 			    unsigned int type, unsigned int code, int value)
 			    unsigned int type, unsigned int code, int value)
 {
 {
@@ -149,7 +187,11 @@ static int uinput_request_submit(struct uinput_device *udev,
 	if (retval)
 	if (retval)
 		goto out;
 		goto out;
 
 
-	wait_for_completion(&request->done);
+	if (!wait_for_completion_timeout(&request->done, 30 * HZ)) {
+		retval = -ETIMEDOUT;
+		goto out;
+	}
+
 	retval = request->retval;
 	retval = request->retval;
 
 
  out:
  out:
@@ -320,6 +362,10 @@ static int uinput_create_device(struct uinput_device *udev)
 		dev->flush = uinput_dev_flush;
 		dev->flush = uinput_dev_flush;
 	}
 	}
 
 
+	dev->event = uinput_dev_event;
+
+	input_set_drvdata(udev->dev, udev);
+
 	error = input_register_device(udev->dev);
 	error = input_register_device(udev->dev);
 	if (error)
 	if (error)
 		goto fail2;
 		goto fail2;
@@ -402,18 +448,6 @@ static int uinput_validate_absbits(struct input_dev *dev)
 	return 0;
 	return 0;
 }
 }
 
 
-static int uinput_allocate_device(struct uinput_device *udev)
-{
-	udev->dev = input_allocate_device();
-	if (!udev->dev)
-		return -ENOMEM;
-
-	udev->dev->event = uinput_dev_event;
-	input_set_drvdata(udev->dev, udev);
-
-	return 0;
-}
-
 static int uinput_dev_setup(struct uinput_device *udev,
 static int uinput_dev_setup(struct uinput_device *udev,
 			    struct uinput_setup __user *arg)
 			    struct uinput_setup __user *arg)
 {
 {
@@ -489,9 +523,9 @@ static int uinput_setup_device_legacy(struct uinput_device *udev,
 		return -EINVAL;
 		return -EINVAL;
 
 
 	if (!udev->dev) {
 	if (!udev->dev) {
-		retval = uinput_allocate_device(udev);
-		if (retval)
-			return retval;
+		udev->dev = input_allocate_device();
+		if (!udev->dev)
+			return -ENOMEM;
 	}
 	}
 
 
 	dev = udev->dev;
 	dev = udev->dev;
@@ -822,162 +856,163 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
 		return retval;
 		return retval;
 
 
 	if (!udev->dev) {
 	if (!udev->dev) {
-		retval = uinput_allocate_device(udev);
-		if (retval)
+		udev->dev = input_allocate_device();
+		if (!udev->dev) {
+			retval = -ENOMEM;
 			goto out;
 			goto out;
+		}
 	}
 	}
 
 
 	switch (cmd) {
 	switch (cmd) {
-		case UI_GET_VERSION:
-			if (put_user(UINPUT_VERSION,
-				     (unsigned int __user *)p))
-				retval = -EFAULT;
-			goto out;
+	case UI_GET_VERSION:
+		if (put_user(UINPUT_VERSION, (unsigned int __user *)p))
+			retval = -EFAULT;
+		goto out;
 
 
-		case UI_DEV_CREATE:
-			retval = uinput_create_device(udev);
-			goto out;
+	case UI_DEV_CREATE:
+		retval = uinput_create_device(udev);
+		goto out;
 
 
-		case UI_DEV_DESTROY:
-			uinput_destroy_device(udev);
-			goto out;
+	case UI_DEV_DESTROY:
+		uinput_destroy_device(udev);
+		goto out;
 
 
-		case UI_DEV_SETUP:
-			retval = uinput_dev_setup(udev, p);
-			goto out;
+	case UI_DEV_SETUP:
+		retval = uinput_dev_setup(udev, p);
+		goto out;
 
 
-		/* UI_ABS_SETUP is handled in the variable size ioctls */
+	/* UI_ABS_SETUP is handled in the variable size ioctls */
 
 
-		case UI_SET_EVBIT:
-			retval = uinput_set_bit(arg, evbit, EV_MAX);
-			goto out;
+	case UI_SET_EVBIT:
+		retval = uinput_set_bit(arg, evbit, EV_MAX);
+		goto out;
 
 
-		case UI_SET_KEYBIT:
-			retval = uinput_set_bit(arg, keybit, KEY_MAX);
-			goto out;
+	case UI_SET_KEYBIT:
+		retval = uinput_set_bit(arg, keybit, KEY_MAX);
+		goto out;
 
 
-		case UI_SET_RELBIT:
-			retval = uinput_set_bit(arg, relbit, REL_MAX);
-			goto out;
+	case UI_SET_RELBIT:
+		retval = uinput_set_bit(arg, relbit, REL_MAX);
+		goto out;
 
 
-		case UI_SET_ABSBIT:
-			retval = uinput_set_bit(arg, absbit, ABS_MAX);
-			goto out;
+	case UI_SET_ABSBIT:
+		retval = uinput_set_bit(arg, absbit, ABS_MAX);
+		goto out;
 
 
-		case UI_SET_MSCBIT:
-			retval = uinput_set_bit(arg, mscbit, MSC_MAX);
-			goto out;
+	case UI_SET_MSCBIT:
+		retval = uinput_set_bit(arg, mscbit, MSC_MAX);
+		goto out;
 
 
-		case UI_SET_LEDBIT:
-			retval = uinput_set_bit(arg, ledbit, LED_MAX);
-			goto out;
+	case UI_SET_LEDBIT:
+		retval = uinput_set_bit(arg, ledbit, LED_MAX);
+		goto out;
+
+	case UI_SET_SNDBIT:
+		retval = uinput_set_bit(arg, sndbit, SND_MAX);
+		goto out;
 
 
-		case UI_SET_SNDBIT:
-			retval = uinput_set_bit(arg, sndbit, SND_MAX);
+	case UI_SET_FFBIT:
+		retval = uinput_set_bit(arg, ffbit, FF_MAX);
+		goto out;
+
+	case UI_SET_SWBIT:
+		retval = uinput_set_bit(arg, swbit, SW_MAX);
+		goto out;
+
+	case UI_SET_PROPBIT:
+		retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
+		goto out;
+
+	case UI_SET_PHYS:
+		if (udev->state == UIST_CREATED) {
+			retval = -EINVAL;
 			goto out;
 			goto out;
+		}
 
 
-		case UI_SET_FFBIT:
-			retval = uinput_set_bit(arg, ffbit, FF_MAX);
+		phys = strndup_user(p, 1024);
+		if (IS_ERR(phys)) {
+			retval = PTR_ERR(phys);
 			goto out;
 			goto out;
+		}
+
+		kfree(udev->dev->phys);
+		udev->dev->phys = phys;
+		goto out;
 
 
-		case UI_SET_SWBIT:
-			retval = uinput_set_bit(arg, swbit, SW_MAX);
+	case UI_BEGIN_FF_UPLOAD:
+		retval = uinput_ff_upload_from_user(p, &ff_up);
+		if (retval)
 			goto out;
 			goto out;
 
 
-		case UI_SET_PROPBIT:
-			retval = uinput_set_bit(arg, propbit, INPUT_PROP_MAX);
+		req = uinput_request_find(udev, ff_up.request_id);
+		if (!req || req->code != UI_FF_UPLOAD ||
+		    !req->u.upload.effect) {
+			retval = -EINVAL;
 			goto out;
 			goto out;
+		}
 
 
-		case UI_SET_PHYS:
-			if (udev->state == UIST_CREATED) {
-				retval = -EINVAL;
-				goto out;
-			}
+		ff_up.retval = 0;
+		ff_up.effect = *req->u.upload.effect;
+		if (req->u.upload.old)
+			ff_up.old = *req->u.upload.old;
+		else
+			memset(&ff_up.old, 0, sizeof(struct ff_effect));
 
 
-			phys = strndup_user(p, 1024);
-			if (IS_ERR(phys)) {
-				retval = PTR_ERR(phys);
-				goto out;
-			}
+		retval = uinput_ff_upload_to_user(p, &ff_up);
+		goto out;
 
 
-			kfree(udev->dev->phys);
-			udev->dev->phys = phys;
+	case UI_BEGIN_FF_ERASE:
+		if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+			retval = -EFAULT;
 			goto out;
 			goto out;
+		}
 
 
-		case UI_BEGIN_FF_UPLOAD:
-			retval = uinput_ff_upload_from_user(p, &ff_up);
-			if (retval)
-				goto out;
-
-			req = uinput_request_find(udev, ff_up.request_id);
-			if (!req || req->code != UI_FF_UPLOAD ||
-			    !req->u.upload.effect) {
-				retval = -EINVAL;
-				goto out;
-			}
-
-			ff_up.retval = 0;
-			ff_up.effect = *req->u.upload.effect;
-			if (req->u.upload.old)
-				ff_up.old = *req->u.upload.old;
-			else
-				memset(&ff_up.old, 0, sizeof(struct ff_effect));
-
-			retval = uinput_ff_upload_to_user(p, &ff_up);
+		req = uinput_request_find(udev, ff_erase.request_id);
+		if (!req || req->code != UI_FF_ERASE) {
+			retval = -EINVAL;
 			goto out;
 			goto out;
+		}
 
 
-		case UI_BEGIN_FF_ERASE:
-			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
-				retval = -EFAULT;
-				goto out;
-			}
-
-			req = uinput_request_find(udev, ff_erase.request_id);
-			if (!req || req->code != UI_FF_ERASE) {
-				retval = -EINVAL;
-				goto out;
-			}
-
-			ff_erase.retval = 0;
-			ff_erase.effect_id = req->u.effect_id;
-			if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
-				retval = -EFAULT;
-				goto out;
-			}
-
+		ff_erase.retval = 0;
+		ff_erase.effect_id = req->u.effect_id;
+		if (copy_to_user(p, &ff_erase, sizeof(ff_erase))) {
+			retval = -EFAULT;
 			goto out;
 			goto out;
+		}
 
 
-		case UI_END_FF_UPLOAD:
-			retval = uinput_ff_upload_from_user(p, &ff_up);
-			if (retval)
-				goto out;
+		goto out;
 
 
-			req = uinput_request_find(udev, ff_up.request_id);
-			if (!req || req->code != UI_FF_UPLOAD ||
-			    !req->u.upload.effect) {
-				retval = -EINVAL;
-				goto out;
-			}
+	case UI_END_FF_UPLOAD:
+		retval = uinput_ff_upload_from_user(p, &ff_up);
+		if (retval)
+			goto out;
 
 
-			req->retval = ff_up.retval;
-			complete(&req->done);
+		req = uinput_request_find(udev, ff_up.request_id);
+		if (!req || req->code != UI_FF_UPLOAD ||
+		    !req->u.upload.effect) {
+			retval = -EINVAL;
 			goto out;
 			goto out;
+		}
 
 
-		case UI_END_FF_ERASE:
-			if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
-				retval = -EFAULT;
-				goto out;
-			}
+		req->retval = ff_up.retval;
+		complete(&req->done);
+		goto out;
 
 
-			req = uinput_request_find(udev, ff_erase.request_id);
-			if (!req || req->code != UI_FF_ERASE) {
-				retval = -EINVAL;
-				goto out;
-			}
+	case UI_END_FF_ERASE:
+		if (copy_from_user(&ff_erase, p, sizeof(ff_erase))) {
+			retval = -EFAULT;
+			goto out;
+		}
 
 
-			req->retval = ff_erase.retval;
-			complete(&req->done);
+		req = uinput_request_find(udev, ff_erase.request_id);
+		if (!req || req->code != UI_FF_ERASE) {
+			retval = -EINVAL;
 			goto out;
 			goto out;
+		}
+
+		req->retval = ff_erase.retval;
+		complete(&req->done);
+		goto out;
 	}
 	}
 
 
 	size = _IOC_SIZE(cmd);
 	size = _IOC_SIZE(cmd);

+ 4 - 4
drivers/input/mouse/alps.c

@@ -1587,10 +1587,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
 	return PSMOUSE_GOOD_DATA;
 	return PSMOUSE_GOOD_DATA;
 }
 }
 
 
-static void alps_flush_packet(unsigned long data)
+static void alps_flush_packet(struct timer_list *t)
 {
 {
-	struct psmouse *psmouse = (struct psmouse *)data;
-	struct alps_data *priv = psmouse->private;
+	struct alps_data *priv = from_timer(priv, t, timer);
+	struct psmouse *psmouse = priv->psmouse;
 
 
 	serio_pause_rx(psmouse->ps2dev.serio);
 	serio_pause_rx(psmouse->ps2dev.serio);
 
 
@@ -2702,7 +2702,7 @@ static int alps_set_protocol(struct psmouse *psmouse,
 {
 {
 	psmouse->private = priv;
 	psmouse->private = priv;
 
 
-	setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
+	timer_setup(&priv->timer, alps_flush_packet, 0);
 
 
 	priv->proto_version = protocol->version;
 	priv->proto_version = protocol->version;
 	priv->byte0 = protocol->byte0;
 	priv->byte0 = protocol->byte0;

+ 6 - 4
drivers/input/mouse/byd.c

@@ -227,6 +227,7 @@
 
 
 struct byd_data {
 struct byd_data {
 	struct timer_list timer;
 	struct timer_list timer;
+	struct psmouse *psmouse;
 	s32 abs_x;
 	s32 abs_x;
 	s32 abs_y;
 	s32 abs_y;
 	typeof(jiffies) last_touch_time;
 	typeof(jiffies) last_touch_time;
@@ -251,10 +252,10 @@ static void byd_report_input(struct psmouse *psmouse)
 	input_sync(dev);
 	input_sync(dev);
 }
 }
 
 
-static void byd_clear_touch(unsigned long data)
+static void byd_clear_touch(struct timer_list *t)
 {
 {
-	struct psmouse *psmouse = (struct psmouse *)data;
-	struct byd_data *priv = psmouse->private;
+	struct byd_data *priv = from_timer(priv, t, timer);
+	struct psmouse *psmouse = priv->psmouse;
 
 
 	serio_pause_rx(psmouse->ps2dev.serio);
 	serio_pause_rx(psmouse->ps2dev.serio);
 	priv->touch = false;
 	priv->touch = false;
@@ -478,7 +479,8 @@ int byd_init(struct psmouse *psmouse)
 	if (!priv)
 	if (!priv)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse);
+	priv->psmouse = psmouse;
+	timer_setup(&priv->timer, byd_clear_touch, 0);
 
 
 	psmouse->private = priv;
 	psmouse->private = priv;
 	psmouse->disconnect = byd_disconnect;
 	psmouse->disconnect = byd_disconnect;

+ 7 - 4
drivers/input/mouse/elan_i2c_core.c

@@ -26,6 +26,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/input/mt.h>
 #include <linux/input/mt.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
+#include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -1141,10 +1142,13 @@ static int elan_probe(struct i2c_client *client,
 		return error;
 		return error;
 
 
 	/*
 	/*
-	 * Systems using device tree should set up interrupt via DTS,
-	 * the rest will use the default falling edge interrupts.
+	 * Platform code (ACPI, DTS) should normally set up interrupt
+	 * for us, but in case it did not let's fall back to using falling
+	 * edge to be compatible with older Chromebooks.
 	 */
 	 */
-	irqflags = dev->of_node ? 0 : IRQF_TRIGGER_FALLING;
+	irqflags = irq_get_trigger_type(client->irq);
+	if (!irqflags)
+		irqflags = IRQF_TRIGGER_FALLING;
 
 
 	error = devm_request_threaded_irq(dev, client->irq, NULL, elan_isr,
 	error = devm_request_threaded_irq(dev, client->irq, NULL, elan_isr,
 					  irqflags | IRQF_ONESHOT,
 					  irqflags | IRQF_ONESHOT,
@@ -1255,7 +1259,6 @@ static const struct acpi_device_id elan_acpi_id[] = {
 	{ "ELAN0602", 0 },
 	{ "ELAN0602", 0 },
 	{ "ELAN0605", 0 },
 	{ "ELAN0605", 0 },
 	{ "ELAN0608", 0 },
 	{ "ELAN0608", 0 },
-	{ "ELAN0605", 0 },
 	{ "ELAN0609", 0 },
 	{ "ELAN0609", 0 },
 	{ "ELAN060B", 0 },
 	{ "ELAN060B", 0 },
 	{ "ELAN060C", 0 },
 	{ "ELAN060C", 0 },

+ 101 - 105
drivers/input/mouse/gpio_mouse.c

@@ -2,6 +2,7 @@
  * Driver for simulating a mouse on GPIO lines.
  * Driver for simulating a mouse on GPIO lines.
  *
  *
  * Copyright (C) 2007 Atmel Corporation
  * Copyright (C) 2007 Atmel Corporation
+ * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
  * it under the terms of the GNU General Public License version 2 as
@@ -11,9 +12,35 @@
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/input-polldev.h>
 #include <linux/input-polldev.h>
-#include <linux/gpio.h>
-#include <linux/gpio_mouse.h>
-
+#include <linux/gpio/consumer.h>
+#include <linux/property.h>
+#include <linux/of.h>
+
+/**
+ * struct gpio_mouse
+ * @scan_ms: the scan interval in milliseconds.
+ * @up: GPIO line for up value.
+ * @down: GPIO line for down value.
+ * @left: GPIO line for left value.
+ * @right: GPIO line for right value.
+ * @bleft: GPIO line for left button.
+ * @bmiddle: GPIO line for middle button.
+ * @bright: GPIO line for right button.
+ *
+ * This struct must be added to the platform_device in the board code.
+ * It is used by the gpio_mouse driver to setup GPIO lines and to
+ * calculate mouse movement.
+ */
+struct gpio_mouse {
+	u32 scan_ms;
+	struct gpio_desc *up;
+	struct gpio_desc *down;
+	struct gpio_desc *left;
+	struct gpio_desc *right;
+	struct gpio_desc *bleft;
+	struct gpio_desc *bmiddle;
+	struct gpio_desc *bright;
+};
 
 
 /*
 /*
  * Timer function which is run every scan_ms ms when the device is opened.
  * Timer function which is run every scan_ms ms when the device is opened.
@@ -21,24 +48,22 @@
  */
  */
 static void gpio_mouse_scan(struct input_polled_dev *dev)
 static void gpio_mouse_scan(struct input_polled_dev *dev)
 {
 {
-	struct gpio_mouse_platform_data *gpio = dev->private;
+	struct gpio_mouse *gpio = dev->private;
 	struct input_dev *input = dev->input;
 	struct input_dev *input = dev->input;
 	int x, y;
 	int x, y;
 
 
-	if (gpio->bleft >= 0)
+	if (gpio->bleft)
 		input_report_key(input, BTN_LEFT,
 		input_report_key(input, BTN_LEFT,
-				gpio_get_value(gpio->bleft) ^ gpio->polarity);
-	if (gpio->bmiddle >= 0)
+				 gpiod_get_value(gpio->bleft));
+	if (gpio->bmiddle)
 		input_report_key(input, BTN_MIDDLE,
 		input_report_key(input, BTN_MIDDLE,
-				gpio_get_value(gpio->bmiddle) ^ gpio->polarity);
-	if (gpio->bright >= 0)
+				 gpiod_get_value(gpio->bmiddle));
+	if (gpio->bright)
 		input_report_key(input, BTN_RIGHT,
 		input_report_key(input, BTN_RIGHT,
-				gpio_get_value(gpio->bright) ^ gpio->polarity);
+				 gpiod_get_value(gpio->bright));
 
 
-	x = (gpio_get_value(gpio->right) ^ gpio->polarity)
-		- (gpio_get_value(gpio->left) ^ gpio->polarity);
-	y = (gpio_get_value(gpio->down) ^ gpio->polarity)
-		- (gpio_get_value(gpio->up) ^ gpio->polarity);
+	x = gpiod_get_value(gpio->right) - gpiod_get_value(gpio->left);
+	y = gpiod_get_value(gpio->down) - gpiod_get_value(gpio->up);
 
 
 	input_report_rel(input, REL_X, x);
 	input_report_rel(input, REL_X, x);
 	input_report_rel(input, REL_Y, y);
 	input_report_rel(input, REL_Y, y);
@@ -47,65 +72,61 @@ static void gpio_mouse_scan(struct input_polled_dev *dev)
 
 
 static int gpio_mouse_probe(struct platform_device *pdev)
 static int gpio_mouse_probe(struct platform_device *pdev)
 {
 {
-	struct gpio_mouse_platform_data *pdata = dev_get_platdata(&pdev->dev);
+	struct device *dev = &pdev->dev;
+	struct gpio_mouse *gmouse;
 	struct input_polled_dev *input_poll;
 	struct input_polled_dev *input_poll;
 	struct input_dev *input;
 	struct input_dev *input;
-	int pin, i;
-	int error;
-
-	if (!pdata) {
-		dev_err(&pdev->dev, "no platform data\n");
-		error = -ENXIO;
-		goto out;
-	}
-
-	if (pdata->scan_ms < 0) {
-		dev_err(&pdev->dev, "invalid scan time\n");
-		error = -EINVAL;
-		goto out;
-	}
-
-	for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
-		pin = pdata->pins[i];
-
-		if (pin < 0) {
-
-			if (i <= GPIO_MOUSE_PIN_RIGHT) {
-				/* Mouse direction is required. */
-				dev_err(&pdev->dev,
-					"missing GPIO for directions\n");
-				error = -EINVAL;
-				goto out_free_gpios;
-			}
-
-			if (i == GPIO_MOUSE_PIN_BLEFT)
-				dev_dbg(&pdev->dev, "no left button defined\n");
-
-		} else {
-			error = gpio_request(pin, "gpio_mouse");
-			if (error) {
-				dev_err(&pdev->dev, "fail %d pin (%d idx)\n",
-					pin, i);
-				goto out_free_gpios;
-			}
-
-			gpio_direction_input(pin);
-		}
+	int ret;
+
+	gmouse = devm_kzalloc(dev, sizeof(*gmouse), GFP_KERNEL);
+	if (!gmouse)
+		return -ENOMEM;
+
+	/* Assign some default scanning time */
+	ret = device_property_read_u32(dev, "scan-interval-ms",
+				       &gmouse->scan_ms);
+	if (ret || gmouse->scan_ms == 0) {
+		dev_warn(dev, "invalid scan time, set to 50 ms\n");
+		gmouse->scan_ms = 50;
 	}
 	}
 
 
-	input_poll = input_allocate_polled_device();
+	gmouse->up = devm_gpiod_get(dev, "up", GPIOD_IN);
+	if (IS_ERR(gmouse->up))
+		return PTR_ERR(gmouse->up);
+	gmouse->down = devm_gpiod_get(dev, "down", GPIOD_IN);
+	if (IS_ERR(gmouse->down))
+		return PTR_ERR(gmouse->down);
+	gmouse->left = devm_gpiod_get(dev, "left", GPIOD_IN);
+	if (IS_ERR(gmouse->left))
+		return PTR_ERR(gmouse->left);
+	gmouse->right = devm_gpiod_get(dev, "right", GPIOD_IN);
+	if (IS_ERR(gmouse->right))
+		return PTR_ERR(gmouse->right);
+
+	gmouse->bleft = devm_gpiod_get_optional(dev, "button-left", GPIOD_IN);
+	if (IS_ERR(gmouse->bleft))
+		return PTR_ERR(gmouse->bleft);
+	gmouse->bmiddle = devm_gpiod_get_optional(dev, "button-middle",
+						  GPIOD_IN);
+	if (IS_ERR(gmouse->bmiddle))
+		return PTR_ERR(gmouse->bmiddle);
+	gmouse->bright = devm_gpiod_get_optional(dev, "button-right",
+						 GPIOD_IN);
+	if (IS_ERR(gmouse->bright))
+		return PTR_ERR(gmouse->bright);
+
+	input_poll = devm_input_allocate_polled_device(dev);
 	if (!input_poll) {
 	if (!input_poll) {
-		dev_err(&pdev->dev, "not enough memory for input device\n");
-		error = -ENOMEM;
-		goto out_free_gpios;
+		dev_err(dev, "not enough memory for input device\n");
+		return -ENOMEM;
 	}
 	}
 
 
 	platform_set_drvdata(pdev, input_poll);
 	platform_set_drvdata(pdev, input_poll);
 
 
 	/* set input-polldev handlers */
 	/* set input-polldev handlers */
-	input_poll->private = pdata;
+	input_poll->private = gmouse;
 	input_poll->poll = gpio_mouse_scan;
 	input_poll->poll = gpio_mouse_scan;
-	input_poll->poll_interval = pdata->scan_ms;
+	input_poll->poll_interval = gmouse->scan_ms;
 
 
 	input = input_poll->input;
 	input = input_poll->input;
 	input->name = pdev->name;
 	input->name = pdev->name;
@@ -114,63 +135,39 @@ static int gpio_mouse_probe(struct platform_device *pdev)
 
 
 	input_set_capability(input, EV_REL, REL_X);
 	input_set_capability(input, EV_REL, REL_X);
 	input_set_capability(input, EV_REL, REL_Y);
 	input_set_capability(input, EV_REL, REL_Y);
-	if (pdata->bleft >= 0)
+	if (gmouse->bleft)
 		input_set_capability(input, EV_KEY, BTN_LEFT);
 		input_set_capability(input, EV_KEY, BTN_LEFT);
-	if (pdata->bmiddle >= 0)
+	if (gmouse->bmiddle)
 		input_set_capability(input, EV_KEY, BTN_MIDDLE);
 		input_set_capability(input, EV_KEY, BTN_MIDDLE);
-	if (pdata->bright >= 0)
+	if (gmouse->bright)
 		input_set_capability(input, EV_KEY, BTN_RIGHT);
 		input_set_capability(input, EV_KEY, BTN_RIGHT);
 
 
-	error = input_register_polled_device(input_poll);
-	if (error) {
-		dev_err(&pdev->dev, "could not register input device\n");
-		goto out_free_polldev;
+	ret = input_register_polled_device(input_poll);
+	if (ret) {
+		dev_err(dev, "could not register input device\n");
+		return ret;
 	}
 	}
 
 
-	dev_dbg(&pdev->dev, "%d ms scan time, buttons: %s%s%s\n",
-			pdata->scan_ms,
-			pdata->bleft < 0 ? "" : "left ",
-			pdata->bmiddle < 0 ? "" : "middle ",
-			pdata->bright < 0 ? "" : "right");
+	dev_dbg(dev, "%d ms scan time, buttons: %s%s%s\n",
+		gmouse->scan_ms,
+		gmouse->bleft ? "" : "left ",
+		gmouse->bmiddle ? "" : "middle ",
+		gmouse->bright ? "" : "right");
 
 
 	return 0;
 	return 0;
-
- out_free_polldev:
-	input_free_polled_device(input_poll);
-
- out_free_gpios:
-	while (--i >= 0) {
-		pin = pdata->pins[i];
-		if (pin)
-			gpio_free(pin);
-	}
- out:
-	return error;
 }
 }
 
 
-static int gpio_mouse_remove(struct platform_device *pdev)
-{
-	struct input_polled_dev *input = platform_get_drvdata(pdev);
-	struct gpio_mouse_platform_data *pdata = input->private;
-	int pin, i;
-
-	input_unregister_polled_device(input);
-	input_free_polled_device(input);
-
-	for (i = 0; i < GPIO_MOUSE_PIN_MAX; i++) {
-		pin = pdata->pins[i];
-		if (pin >= 0)
-			gpio_free(pin);
-	}
-
-	return 0;
-}
+static const struct of_device_id gpio_mouse_of_match[] = {
+	{ .compatible = "gpio-mouse", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, gpio_mouse_of_match);
 
 
 static struct platform_driver gpio_mouse_device_driver = {
 static struct platform_driver gpio_mouse_device_driver = {
 	.probe		= gpio_mouse_probe,
 	.probe		= gpio_mouse_probe,
-	.remove		= gpio_mouse_remove,
 	.driver		= {
 	.driver		= {
 		.name	= "gpio_mouse",
 		.name	= "gpio_mouse",
+		.of_match_table = gpio_mouse_of_match,
 	}
 	}
 };
 };
 module_platform_driver(gpio_mouse_device_driver);
 module_platform_driver(gpio_mouse_device_driver);
@@ -179,4 +176,3 @@ MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");
 MODULE_DESCRIPTION("GPIO mouse driver");
 MODULE_DESCRIPTION("GPIO mouse driver");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
 MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */
-

+ 1 - 1
drivers/input/rmi4/rmi_f54.c

@@ -73,7 +73,7 @@ enum rmi_f54_report_type {
 	F54_MAX_REPORT_TYPE,
 	F54_MAX_REPORT_TYPE,
 };
 };
 
 
-const char *rmi_f54_report_type_names[] = {
+static const char * const rmi_f54_report_type_names[] = {
 	[F54_REPORT_NONE]		= "Unknown",
 	[F54_REPORT_NONE]		= "Unknown",
 	[F54_8BIT_IMAGE]		= "Normalized 8-Bit Image",
 	[F54_8BIT_IMAGE]		= "Normalized 8-Bit Image",
 	[F54_16BIT_IMAGE]		= "Normalized 16-Bit Image",
 	[F54_16BIT_IMAGE]		= "Normalized 16-Bit Image",

+ 2 - 2
drivers/input/serio/hil_mlc.c

@@ -784,7 +784,7 @@ static void hil_mlcs_process(unsigned long unused)
 
 
 /************************* Keepalive timer task *********************/
 /************************* Keepalive timer task *********************/
 
 
-static void hil_mlcs_timer(unsigned long data)
+static void hil_mlcs_timer(struct timer_list *unused)
 {
 {
 	hil_mlcs_probe = 1;
 	hil_mlcs_probe = 1;
 	tasklet_schedule(&hil_mlcs_tasklet);
 	tasklet_schedule(&hil_mlcs_tasklet);
@@ -998,7 +998,7 @@ int hil_mlc_unregister(hil_mlc *mlc)
 
 
 static int __init hil_mlc_init(void)
 static int __init hil_mlc_init(void)
 {
 {
-	setup_timer(&hil_mlcs_kicker, &hil_mlcs_timer, 0);
+	timer_setup(&hil_mlcs_kicker, &hil_mlcs_timer, 0);
 	mod_timer(&hil_mlcs_kicker, jiffies + HZ);
 	mod_timer(&hil_mlcs_kicker, jiffies + HZ);
 
 
 	tasklet_enable(&hil_mlcs_tasklet);
 	tasklet_enable(&hil_mlcs_tasklet);

+ 2 - 3
drivers/input/serio/hp_sdc.c

@@ -794,7 +794,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback)
 
 
 /************************* Keepalive timer task *********************/
 /************************* Keepalive timer task *********************/
 
 
-static void hp_sdc_kicker(unsigned long data)
+static void hp_sdc_kicker(struct timer_list *unused)
 {
 {
 	tasklet_schedule(&hp_sdc.task);
 	tasklet_schedule(&hp_sdc.task);
 	/* Re-insert the periodic task. */
 	/* Re-insert the periodic task. */
@@ -909,9 +909,8 @@ static int __init hp_sdc_init(void)
 	down(&s_sync); /* Wait for t_sync to complete */
 	down(&s_sync); /* Wait for t_sync to complete */
 
 
 	/* Create the keepalive task */
 	/* Create the keepalive task */
-	init_timer(&hp_sdc.kicker);
+	timer_setup(&hp_sdc.kicker, hp_sdc_kicker, 0);
 	hp_sdc.kicker.expires = jiffies + HZ;
 	hp_sdc.kicker.expires = jiffies + HZ;
-	hp_sdc.kicker.function = &hp_sdc_kicker;
 	add_timer(&hp_sdc.kicker);
 	add_timer(&hp_sdc.kicker);
 
 
 	hp_sdc.dev_err = 0;
 	hp_sdc.dev_err = 0;

+ 1 - 0
drivers/input/serio/ps2-gpio.c

@@ -366,6 +366,7 @@ static int ps2_gpio_probe(struct platform_device *pdev)
 	    gpiod_cansleep(drvdata->gpio_clk)) {
 	    gpiod_cansleep(drvdata->gpio_clk)) {
 		dev_err(dev, "GPIO data or clk are connected via slow bus\n");
 		dev_err(dev, "GPIO data or clk are connected via slow bus\n");
 		error = -EINVAL;
 		error = -EINVAL;
+		goto err_free_serio;
 	}
 	}
 
 
 	drvdata->irq = platform_get_irq(pdev, 0);
 	drvdata->irq = platform_get_irq(pdev, 0);

+ 41 - 28
drivers/input/serio/sa1111ps2.c

@@ -47,6 +47,8 @@ struct ps2if {
 	struct serio		*io;
 	struct serio		*io;
 	struct sa1111_dev	*dev;
 	struct sa1111_dev	*dev;
 	void __iomem		*base;
 	void __iomem		*base;
+	int			rx_irq;
+	int			tx_irq;
 	unsigned int		open;
 	unsigned int		open;
 	spinlock_t		lock;
 	spinlock_t		lock;
 	unsigned int		head;
 	unsigned int		head;
@@ -64,22 +66,22 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id)
 	struct ps2if *ps2if = dev_id;
 	struct ps2if *ps2if = dev_id;
 	unsigned int scancode, flag, status;
 	unsigned int scancode, flag, status;
 
 
-	status = sa1111_readl(ps2if->base + PS2STAT);
+	status = readl_relaxed(ps2if->base + PS2STAT);
 	while (status & PS2STAT_RXF) {
 	while (status & PS2STAT_RXF) {
 		if (status & PS2STAT_STP)
 		if (status & PS2STAT_STP)
-			sa1111_writel(PS2STAT_STP, ps2if->base + PS2STAT);
+			writel_relaxed(PS2STAT_STP, ps2if->base + PS2STAT);
 
 
 		flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
 		flag = (status & PS2STAT_STP ? SERIO_FRAME : 0) |
 		       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 		       (status & PS2STAT_RXP ? 0 : SERIO_PARITY);
 
 
-		scancode = sa1111_readl(ps2if->base + PS2DATA) & 0xff;
+		scancode = readl_relaxed(ps2if->base + PS2DATA) & 0xff;
 
 
 		if (hweight8(scancode) & 1)
 		if (hweight8(scancode) & 1)
 			flag ^= SERIO_PARITY;
 			flag ^= SERIO_PARITY;
 
 
 		serio_interrupt(ps2if->io, scancode, flag);
 		serio_interrupt(ps2if->io, scancode, flag);
 
 
-		status = sa1111_readl(ps2if->base + PS2STAT);
+		status = readl_relaxed(ps2if->base + PS2STAT);
         }
         }
 
 
         return IRQ_HANDLED;
         return IRQ_HANDLED;
@@ -94,12 +96,12 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
 	unsigned int status;
 	unsigned int status;
 
 
 	spin_lock(&ps2if->lock);
 	spin_lock(&ps2if->lock);
-	status = sa1111_readl(ps2if->base + PS2STAT);
+	status = readl_relaxed(ps2if->base + PS2STAT);
 	if (ps2if->head == ps2if->tail) {
 	if (ps2if->head == ps2if->tail) {
 		disable_irq_nosync(irq);
 		disable_irq_nosync(irq);
 		/* done */
 		/* done */
 	} else if (status & PS2STAT_TXE) {
 	} else if (status & PS2STAT_TXE) {
-		sa1111_writel(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
+		writel_relaxed(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
 		ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
 		ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
 	}
 	}
 	spin_unlock(&ps2if->lock);
 	spin_unlock(&ps2if->lock);
@@ -122,11 +124,11 @@ static int ps2_write(struct serio *io, unsigned char val)
 	/*
 	/*
 	 * If the TX register is empty, we can go straight out.
 	 * If the TX register is empty, we can go straight out.
 	 */
 	 */
-	if (sa1111_readl(ps2if->base + PS2STAT) & PS2STAT_TXE) {
-		sa1111_writel(val, ps2if->base + PS2DATA);
+	if (readl_relaxed(ps2if->base + PS2STAT) & PS2STAT_TXE) {
+		writel_relaxed(val, ps2if->base + PS2DATA);
 	} else {
 	} else {
 		if (ps2if->head == ps2if->tail)
 		if (ps2if->head == ps2if->tail)
-			enable_irq(ps2if->dev->irq[1]);
+			enable_irq(ps2if->tx_irq);
 		head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
 		head = (ps2if->head + 1) & (sizeof(ps2if->buf) - 1);
 		if (head != ps2if->tail) {
 		if (head != ps2if->tail) {
 			ps2if->buf[ps2if->head] = val;
 			ps2if->buf[ps2if->head] = val;
@@ -147,30 +149,30 @@ static int ps2_open(struct serio *io)
 	if (ret)
 	if (ret)
 		return ret;
 		return ret;
 
 
-	ret = request_irq(ps2if->dev->irq[0], ps2_rxint, 0,
+	ret = request_irq(ps2if->rx_irq, ps2_rxint, 0,
 			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
 			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
 	if (ret) {
 	if (ret) {
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
-			ps2if->dev->irq[0], ret);
+			ps2if->rx_irq, ret);
 		sa1111_disable_device(ps2if->dev);
 		sa1111_disable_device(ps2if->dev);
 		return ret;
 		return ret;
 	}
 	}
 
 
-	ret = request_irq(ps2if->dev->irq[1], ps2_txint, 0,
+	ret = request_irq(ps2if->tx_irq, ps2_txint, 0,
 			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
 			  SA1111_DRIVER_NAME(ps2if->dev), ps2if);
 	if (ret) {
 	if (ret) {
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
 		printk(KERN_ERR "sa1111ps2: could not allocate IRQ%d: %d\n",
-			ps2if->dev->irq[1], ret);
-		free_irq(ps2if->dev->irq[0], ps2if);
+			ps2if->tx_irq, ret);
+		free_irq(ps2if->rx_irq, ps2if);
 		sa1111_disable_device(ps2if->dev);
 		sa1111_disable_device(ps2if->dev);
 		return ret;
 		return ret;
 	}
 	}
 
 
 	ps2if->open = 1;
 	ps2if->open = 1;
 
 
-	enable_irq_wake(ps2if->dev->irq[0]);
+	enable_irq_wake(ps2if->rx_irq);
 
 
-	sa1111_writel(PS2CR_ENA, ps2if->base + PS2CR);
+	writel_relaxed(PS2CR_ENA, ps2if->base + PS2CR);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -178,14 +180,14 @@ static void ps2_close(struct serio *io)
 {
 {
 	struct ps2if *ps2if = io->port_data;
 	struct ps2if *ps2if = io->port_data;
 
 
-	sa1111_writel(0, ps2if->base + PS2CR);
+	writel_relaxed(0, ps2if->base + PS2CR);
 
 
-	disable_irq_wake(ps2if->dev->irq[0]);
+	disable_irq_wake(ps2if->rx_irq);
 
 
 	ps2if->open = 0;
 	ps2if->open = 0;
 
 
-	free_irq(ps2if->dev->irq[1], ps2if);
-	free_irq(ps2if->dev->irq[0], ps2if);
+	free_irq(ps2if->tx_irq, ps2if);
+	free_irq(ps2if->rx_irq, ps2if);
 
 
 	sa1111_disable_device(ps2if->dev);
 	sa1111_disable_device(ps2if->dev);
 }
 }
@@ -198,7 +200,7 @@ static void ps2_clear_input(struct ps2if *ps2if)
 	int maxread = 100;
 	int maxread = 100;
 
 
 	while (maxread--) {
 	while (maxread--) {
-		if ((sa1111_readl(ps2if->base + PS2DATA) & 0xff) == 0xff)
+		if ((readl_relaxed(ps2if->base + PS2DATA) & 0xff) == 0xff)
 			break;
 			break;
 	}
 	}
 }
 }
@@ -208,11 +210,11 @@ static unsigned int ps2_test_one(struct ps2if *ps2if,
 {
 {
 	unsigned int val;
 	unsigned int val;
 
 
-	sa1111_writel(PS2CR_ENA | mask, ps2if->base + PS2CR);
+	writel_relaxed(PS2CR_ENA | mask, ps2if->base + PS2CR);
 
 
-	udelay(2);
+	udelay(10);
 
 
-	val = sa1111_readl(ps2if->base + PS2STAT);
+	val = readl_relaxed(ps2if->base + PS2STAT);
 	return val & (PS2STAT_KBC | PS2STAT_KBD);
 	return val & (PS2STAT_KBC | PS2STAT_KBD);
 }
 }
 
 
@@ -243,7 +245,7 @@ static int ps2_test(struct ps2if *ps2if)
 		ret = -ENODEV;
 		ret = -ENODEV;
 	}
 	}
 
 
-	sa1111_writel(0, ps2if->base + PS2CR);
+	writel_relaxed(0, ps2if->base + PS2CR);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -264,7 +266,6 @@ static int ps2_probe(struct sa1111_dev *dev)
 		goto free;
 		goto free;
 	}
 	}
 
 
-
 	serio->id.type		= SERIO_8042;
 	serio->id.type		= SERIO_8042;
 	serio->write		= ps2_write;
 	serio->write		= ps2_write;
 	serio->open		= ps2_open;
 	serio->open		= ps2_open;
@@ -279,6 +280,18 @@ static int ps2_probe(struct sa1111_dev *dev)
 
 
 	spin_lock_init(&ps2if->lock);
 	spin_lock_init(&ps2if->lock);
 
 
+	ps2if->rx_irq = sa1111_get_irq(dev, 0);
+	if (ps2if->rx_irq <= 0) {
+		ret = ps2if->rx_irq ? : -ENXIO;
+		goto free;
+	}
+
+	ps2if->tx_irq = sa1111_get_irq(dev, 1);
+	if (ps2if->tx_irq <= 0) {
+		ret = ps2if->tx_irq ? : -ENXIO;
+		goto free;
+	}
+
 	/*
 	/*
 	 * Request the physical region for this PS2 port.
 	 * Request the physical region for this PS2 port.
 	 */
 	 */
@@ -297,8 +310,8 @@ static int ps2_probe(struct sa1111_dev *dev)
 	sa1111_enable_device(ps2if->dev);
 	sa1111_enable_device(ps2if->dev);
 
 
 	/* Incoming clock is 8MHz */
 	/* Incoming clock is 8MHz */
-	sa1111_writel(0, ps2if->base + PS2CLKDIV);
-	sa1111_writel(127, ps2if->base + PS2PRECNT);
+	writel_relaxed(0, ps2if->base + PS2CLKDIV);
+	writel_relaxed(127, ps2if->base + PS2PRECNT);
 
 
 	/*
 	/*
 	 * Flush any pending input.
 	 * Flush any pending input.

+ 33 - 1
drivers/input/touchscreen/Kconfig

@@ -316,6 +316,16 @@ config TOUCHSCREEN_EGALAX_SERIAL
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called egalax_ts_serial.
 	  module will be called egalax_ts_serial.
 
 
+config TOUCHSCREEN_EXC3000
+	tristate "EETI EXC3000 multi-touch panel support"
+	depends on I2C
+	help
+	  Say Y here to enable support for I2C connected EETI
+	  EXC3000 multi-touch panels.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called exc3000.
+
 config TOUCHSCREEN_FUJITSU
 config TOUCHSCREEN_FUJITSU
 	tristate "Fujitsu serial touchscreen"
 	tristate "Fujitsu serial touchscreen"
 	select SERIO
 	select SERIO
@@ -344,6 +354,17 @@ config TOUCHSCREEN_GOODIX
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called goodix.
 	  module will be called goodix.
 
 
+config TOUCHSCREEN_HIDEEP
+	tristate "HiDeep Touch IC"
+	depends on I2C
+	help
+	  Say Y here if you have a touchscreen using HiDeep.
+
+	  If unsure, say N.
+
+	  To compile this driver as a moudle, choose M here : the
+	  module will be called hideep_ts.
+
 config TOUCHSCREEN_ILI210X
 config TOUCHSCREEN_ILI210X
 	tristate "Ilitek ILI210X based touchscreen"
 	tristate "Ilitek ILI210X based touchscreen"
 	depends on I2C
 	depends on I2C
@@ -383,6 +404,17 @@ config TOUCHSCREEN_S3C2410
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called s3c2410_ts.
 	  module will be called s3c2410_ts.
 
 
+config TOUCHSCREEN_S6SY761
+	tristate "Samsung S6SY761 Touchscreen driver"
+	depends on I2C
+	help
+	  Say Y if you have the Samsung S6SY761 driver
+
+	  If unsure, say N
+
+	  To compile this driver as module, choose M here: the
+	  module will be called s6sy761.
+
 config TOUCHSCREEN_GUNZE
 config TOUCHSCREEN_GUNZE
 	tristate "Gunze AHL-51S touchscreen"
 	tristate "Gunze AHL-51S touchscreen"
 	select SERIO
 	select SERIO
@@ -949,7 +981,7 @@ config TOUCHSCREEN_USB_NEXIO
 
 
 config TOUCHSCREEN_USB_EASYTOUCH
 config TOUCHSCREEN_USB_EASYTOUCH
 	default y
 	default y
-	bool "EasyTouch USB Touch controller device support" if EMBEDDED
+	bool "EasyTouch USB Touch controller device support" if EXPERT
 	depends on TOUCHSCREEN_USB_COMPOSITE
 	depends on TOUCHSCREEN_USB_COMPOSITE
 	help
 	help
 	  Say Y here if you have an EasyTouch USB Touch controller.
 	  Say Y here if you have an EasyTouch USB Touch controller.

+ 3 - 0
drivers/input/touchscreen/Makefile

@@ -38,8 +38,10 @@ obj-$(CONFIG_TOUCHSCREEN_ELAN)		+= elants_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_ELO)		+= elo.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX)	+= egalax_ts.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)	+= egalax_ts_serial.o
 obj-$(CONFIG_TOUCHSCREEN_EGALAX_SERIAL)	+= egalax_ts_serial.o
+obj-$(CONFIG_TOUCHSCREEN_EXC3000)	+= exc3000.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_FUJITSU)	+= fujitsu_ts.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
 obj-$(CONFIG_TOUCHSCREEN_GOODIX)	+= goodix.o
+obj-$(CONFIG_TOUCHSCREEN_HIDEEP)	+= hideep.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_ILI210X)	+= ili210x.o
 obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC)	+= imx6ul_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC)	+= imx6ul_tsc.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
 obj-$(CONFIG_TOUCHSCREEN_INEXIO)	+= inexio.o
@@ -65,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)	+= penmount.o
 obj-$(CONFIG_TOUCHSCREEN_PIXCIR)	+= pixcir_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_PIXCIR)	+= pixcir_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_RM_TS)		+= raydium_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_RM_TS)		+= raydium_i2c_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
 obj-$(CONFIG_TOUCHSCREEN_S3C2410)	+= s3c2410_ts.o
+obj-$(CONFIG_TOUCHSCREEN_S6SY761)	+= s6sy761.o
 obj-$(CONFIG_TOUCHSCREEN_SILEAD)	+= silead.o
 obj-$(CONFIG_TOUCHSCREEN_SILEAD)	+= silead.o
 obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)	+= sis_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_SIS_I2C)	+= sis_i2c.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o
 obj-$(CONFIG_TOUCHSCREEN_ST1232)	+= st1232.o

+ 3 - 3
drivers/input/touchscreen/ad7877.c

@@ -385,9 +385,9 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
 	input_sync(input_dev);
 	input_sync(input_dev);
 }
 }
 
 
-static void ad7877_timer(unsigned long handle)
+static void ad7877_timer(struct timer_list *t)
 {
 {
-	struct ad7877 *ts = (void *)handle;
+	struct ad7877 *ts = from_timer(ts, t, timer);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&ts->lock, flags);
 	spin_lock_irqsave(&ts->lock, flags);
@@ -718,7 +718,7 @@ static int ad7877_probe(struct spi_device *spi)
 	ts->spi = spi;
 	ts->spi = spi;
 	ts->input = input_dev;
 	ts->input = input_dev;
 
 
-	setup_timer(&ts->timer, ad7877_timer, (unsigned long) ts);
+	timer_setup(&ts->timer, ad7877_timer, 0);
 	mutex_init(&ts->mutex);
 	mutex_init(&ts->mutex);
 	spin_lock_init(&ts->lock);
 	spin_lock_init(&ts->lock);
 
 

+ 4 - 15
drivers/input/touchscreen/ad7879.c

@@ -237,9 +237,9 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
 	input_sync(input_dev);
 	input_sync(input_dev);
 }
 }
 
 
-static void ad7879_timer(unsigned long handle)
+static void ad7879_timer(struct timer_list *t)
 {
 {
-	struct ad7879 *ts = (void *)handle;
+	struct ad7879 *ts = from_timer(ts, t, timer);
 
 
 	ad7879_ts_event_release(ts);
 	ad7879_ts_event_release(ts);
 }
 }
@@ -524,13 +524,6 @@ static int ad7879_parse_dt(struct device *dev, struct ad7879 *ts)
 	return 0;
 	return 0;
 }
 }
 
 
-static void ad7879_cleanup_sysfs(void *_ts)
-{
-	struct ad7879 *ts = _ts;
-
-	sysfs_remove_group(&ts->dev->kobj, &ad7879_attr_group);
-}
-
 int ad7879_probe(struct device *dev, struct regmap *regmap,
 int ad7879_probe(struct device *dev, struct regmap *regmap,
 		 int irq, u16 bustype, u8 devid)
 		 int irq, u16 bustype, u8 devid)
 {
 {
@@ -577,7 +570,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
 	ts->irq = irq;
 	ts->irq = irq;
 	ts->regmap = regmap;
 	ts->regmap = regmap;
 
 
-	setup_timer(&ts->timer, ad7879_timer, (unsigned long) ts);
+	timer_setup(&ts->timer, ad7879_timer, 0);
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
 
 
 	input_dev->name = "AD7879 Touchscreen";
 	input_dev->name = "AD7879 Touchscreen";
@@ -658,11 +651,7 @@ int ad7879_probe(struct device *dev, struct regmap *regmap,
 
 
 	__ad7879_disable(ts);
 	__ad7879_disable(ts);
 
 
-	err = sysfs_create_group(&dev->kobj, &ad7879_attr_group);
-	if (err)
-		return err;
-
-	err = devm_add_action_or_reset(dev, ad7879_cleanup_sysfs, ts);
+	err = devm_device_add_group(dev, &ad7879_attr_group);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 

+ 6 - 4
drivers/input/touchscreen/atmel-wm97xx.c

@@ -208,9 +208,12 @@ static void atmel_wm97xx_acc_pen_up(struct wm97xx *wm)
 	}
 	}
 }
 }
 
 
-static void atmel_wm97xx_pen_timer(unsigned long data)
+static void atmel_wm97xx_pen_timer(struct timer_list *t)
 {
 {
-	atmel_wm97xx_acc_pen_up((struct wm97xx *)data);
+	struct atmel_wm97xx *atmel_wm97xx = from_timer(atmel_wm97xx, t,
+						       pen_timer);
+
+	atmel_wm97xx_acc_pen_up(atmel_wm97xx->wm);
 }
 }
 
 
 static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
 static int atmel_wm97xx_acc_startup(struct wm97xx *wm)
@@ -348,8 +351,7 @@ static int __init atmel_wm97xx_probe(struct platform_device *pdev)
 	atmel_wm97xx->gpio_pen	= atmel_gpio_line;
 	atmel_wm97xx->gpio_pen	= atmel_gpio_line;
 	atmel_wm97xx->gpio_irq	= gpio_to_irq(atmel_wm97xx->gpio_pen);
 	atmel_wm97xx->gpio_irq	= gpio_to_irq(atmel_wm97xx->gpio_pen);
 
 
-	setup_timer(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer,
-			(unsigned long)wm);
+	timer_setup(&atmel_wm97xx->pen_timer, atmel_wm97xx_pen_timer, 0);
 
 
 	ret = request_irq(atmel_wm97xx->ac97c_irq,
 	ret = request_irq(atmel_wm97xx->ac97c_irq,
 			  atmel_wm97xx_channel_b_interrupt,
 			  atmel_wm97xx_channel_b_interrupt,

+ 43 - 16
drivers/input/touchscreen/cyttsp4_core.c

@@ -201,13 +201,21 @@ static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
 	void *p;
 	void *p;
 	int rc;
 	int rc;
 
 
+	if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) {
+		dev_err(cd->dev,
+			"%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n",
+			__func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs);
+		return -EINVAL;
+	}
+
 	si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
 	si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
 	dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
 	dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
 			si->si_ofs.cydata_size);
 			si->si_ofs.cydata_size);
 
 
 	p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
 	p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
 	if (p == NULL) {
 	if (p == NULL) {
-		dev_err(cd->dev, "%s: fail alloc cydata memory\n", __func__);
+		dev_err(cd->dev, "%s: failed to allocate cydata memory\n",
+			__func__);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 	si->si_ptrs.cydata = p;
 	si->si_ptrs.cydata = p;
@@ -270,11 +278,19 @@ static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
 	void *p;
 	void *p;
 	int rc;
 	int rc;
 
 
+	if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) {
+		dev_err(cd->dev,
+			"%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n",
+			__func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs);
+		return -EINVAL;
+	}
+
 	si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
 	si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
 
 
 	p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
 	p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
 	if (p == NULL) {
 	if (p == NULL) {
-		dev_err(cd->dev, "%s: fail alloc test memory\n", __func__);
+		dev_err(cd->dev, "%s: failed to allocate test memory\n",
+			__func__);
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 	si->si_ptrs.test = p;
 	si->si_ptrs.test = p;
@@ -321,14 +337,20 @@ static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
 	void *p;
 	void *p;
 	int rc;
 	int rc;
 
 
+	if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) {
+		dev_err(cd->dev,
+			"%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n",
+			__func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs);
+		return -EINVAL;
+	}
+
 	si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
 	si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
 
 
 	p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
 	p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
 	if (p == NULL) {
 	if (p == NULL) {
-		rc = -ENOMEM;
-		dev_err(cd->dev, "%s: fail alloc pcfg memory r=%d\n",
-			__func__, rc);
-		return rc;
+		dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
+			__func__);
+		return -ENOMEM;
 	}
 	}
 	si->si_ptrs.pcfg = p;
 	si->si_ptrs.pcfg = p;
 
 
@@ -367,13 +389,20 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
 	void *p;
 	void *p;
 	int rc;
 	int rc;
 
 
+	if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) {
+		dev_err(cd->dev,
+			"%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n",
+			__func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs);
+		return -EINVAL;
+	}
+
 	si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
 	si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
 
 
 	p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
 	p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
 	if (p == NULL) {
 	if (p == NULL) {
-		dev_err(cd->dev, "%s: fail alloc opcfg memory\n", __func__);
-		rc = -ENOMEM;
-		goto cyttsp4_si_get_opcfg_data_exit;
+		dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
+			__func__);
+		return -ENOMEM;
 	}
 	}
 	si->si_ptrs.opcfg = p;
 	si->si_ptrs.opcfg = p;
 
 
@@ -382,7 +411,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
 	if (rc < 0) {
 	if (rc < 0) {
 		dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
 		dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
 			__func__, rc);
 			__func__, rc);
-		goto cyttsp4_si_get_opcfg_data_exit;
+		return rc;
 	}
 	}
 	si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
 	si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
 	si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
 	si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
@@ -447,8 +476,7 @@ static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
 	cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
 	cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
 		si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
 		si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
 
 
-cyttsp4_si_get_opcfg_data_exit:
-	return rc;
+	return 0;
 }
 }
 
 
 static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
 static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
@@ -1237,9 +1265,9 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
 	del_timer_sync(&cd->watchdog_timer);
 	del_timer_sync(&cd->watchdog_timer);
 }
 }
 
 
-static void cyttsp4_watchdog_timer(unsigned long handle)
+static void cyttsp4_watchdog_timer(struct timer_list *t)
 {
 {
-	struct cyttsp4 *cd = (struct cyttsp4 *)handle;
+	struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer);
 
 
 	dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
 	dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
 
 
@@ -2074,8 +2102,7 @@ struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
 	}
 	}
 
 
 	/* Setup watchdog timer */
 	/* Setup watchdog timer */
-	setup_timer(&cd->watchdog_timer, cyttsp4_watchdog_timer,
-		(unsigned long)cd);
+	timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
 
 
 	/*
 	/*
 	 * call startup directly to ensure that the device
 	 * call startup directly to ensure that the device

+ 130 - 43
drivers/input/touchscreen/edt-ft5x06.c

@@ -70,8 +70,10 @@
 #define EDT_RAW_DATA_DELAY		1000 /* usec */
 #define EDT_RAW_DATA_DELAY		1000 /* usec */
 
 
 enum edt_ver {
 enum edt_ver {
-	M06,
-	M09,
+	EDT_M06,
+	EDT_M09,
+	EDT_M12,
+	GENERIC_FT,
 };
 };
 
 
 struct edt_reg_addr {
 struct edt_reg_addr {
@@ -179,14 +181,16 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
 	int error;
 	int error;
 
 
 	switch (tsdata->version) {
 	switch (tsdata->version) {
-	case M06:
+	case EDT_M06:
 		cmd = 0xf9; /* tell the controller to send touch data */
 		cmd = 0xf9; /* tell the controller to send touch data */
 		offset = 5; /* where the actual touch data starts */
 		offset = 5; /* where the actual touch data starts */
 		tplen = 4;  /* data comes in so called frames */
 		tplen = 4;  /* data comes in so called frames */
 		crclen = 1; /* length of the crc data */
 		crclen = 1; /* length of the crc data */
 		break;
 		break;
 
 
-	case M09:
+	case EDT_M09:
+	case EDT_M12:
+	case GENERIC_FT:
 		cmd = 0x0;
 		cmd = 0x0;
 		offset = 3;
 		offset = 3;
 		tplen = 6;
 		tplen = 6;
@@ -209,8 +213,8 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	/* M09 does not send header or CRC */
-	if (tsdata->version == M06) {
+	/* M09/M12 does not send header or CRC */
+	if (tsdata->version == EDT_M06) {
 		if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
 		if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa ||
 			rdbuf[2] != datalen) {
 			rdbuf[2] != datalen) {
 			dev_err_ratelimited(dev,
 			dev_err_ratelimited(dev,
@@ -233,7 +237,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
 			continue;
 			continue;
 
 
 		/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
 		/* M06 sometimes sends bogus coordinates in TOUCH_DOWN */
-		if (tsdata->version == M06 && type == TOUCH_EVENT_DOWN)
+		if (tsdata->version == EDT_M06 && type == TOUCH_EVENT_DOWN)
 			continue;
 			continue;
 
 
 		x = ((buf[0] << 8) | buf[1]) & 0x0fff;
 		x = ((buf[0] << 8) | buf[1]) & 0x0fff;
@@ -264,14 +268,16 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
 	u8 wrbuf[4];
 	u8 wrbuf[4];
 
 
 	switch (tsdata->version) {
 	switch (tsdata->version) {
-	case M06:
+	case EDT_M06:
 		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
 		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
 		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
 		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
 		wrbuf[2] = value;
 		wrbuf[2] = value;
 		wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
 		wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
 		return edt_ft5x06_ts_readwrite(tsdata->client, 4,
 		return edt_ft5x06_ts_readwrite(tsdata->client, 4,
 					wrbuf, 0, NULL);
 					wrbuf, 0, NULL);
-	case M09:
+	case EDT_M09:
+	case EDT_M12:
+	case GENERIC_FT:
 		wrbuf[0] = addr;
 		wrbuf[0] = addr;
 		wrbuf[1] = value;
 		wrbuf[1] = value;
 
 
@@ -290,7 +296,7 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
 	int error;
 	int error;
 
 
 	switch (tsdata->version) {
 	switch (tsdata->version) {
-	case M06:
+	case EDT_M06:
 		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
 		wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc;
 		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
 		wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f;
 		wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
 		wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40;
@@ -309,7 +315,9 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
 		}
 		}
 		break;
 		break;
 
 
-	case M09:
+	case EDT_M09:
+	case EDT_M12:
+	case GENERIC_FT:
 		wrbuf[0] = addr;
 		wrbuf[0] = addr;
 		error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
 		error = edt_ft5x06_ts_readwrite(tsdata->client, 1,
 						wrbuf, 1, rdbuf);
 						wrbuf, 1, rdbuf);
@@ -368,11 +376,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
 	}
 	}
 
 
 	switch (tsdata->version) {
 	switch (tsdata->version) {
-	case M06:
+	case EDT_M06:
 		addr = attr->addr_m06;
 		addr = attr->addr_m06;
 		break;
 		break;
 
 
-	case M09:
+	case EDT_M09:
+	case EDT_M12:
+	case GENERIC_FT:
 		addr = attr->addr_m09;
 		addr = attr->addr_m09;
 		break;
 		break;
 
 
@@ -437,11 +447,13 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
 	}
 	}
 
 
 	switch (tsdata->version) {
 	switch (tsdata->version) {
-	case M06:
+	case EDT_M06:
 		addr = attr->addr_m06;
 		addr = attr->addr_m06;
 		break;
 		break;
 
 
-	case M09:
+	case EDT_M09:
+	case EDT_M12:
+	case GENERIC_FT:
 		addr = attr->addr_m09;
 		addr = attr->addr_m09;
 		break;
 		break;
 
 
@@ -466,14 +478,18 @@ out:
 	return error ?: count;
 	return error ?: count;
 }
 }
 
 
+/* m06, m09: range 0-31, m12: range 0-5 */
 static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
 static EDT_ATTR(gain, S_IWUSR | S_IRUGO, WORK_REGISTER_GAIN,
 		M09_REGISTER_GAIN, 0, 31);
 		M09_REGISTER_GAIN, 0, 31);
+/* m06, m09: range 0-31, m12: range 0-16 */
 static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
 static EDT_ATTR(offset, S_IWUSR | S_IRUGO, WORK_REGISTER_OFFSET,
 		M09_REGISTER_OFFSET, 0, 31);
 		M09_REGISTER_OFFSET, 0, 31);
+/* m06: range 20 to 80, m09: range 0 to 30, m12: range 1 to 255... */
 static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
 static EDT_ATTR(threshold, S_IWUSR | S_IRUGO, WORK_REGISTER_THRESHOLD,
-		M09_REGISTER_THRESHOLD, 0, 80);
+		M09_REGISTER_THRESHOLD, 0, 255);
+/* m06: range 3 to 14, m12: (0x64: 100Hz) */
 static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
 static EDT_ATTR(report_rate, S_IWUSR | S_IRUGO, WORK_REGISTER_REPORT_RATE,
-		NO_REGISTER, 3, 14);
+		NO_REGISTER, 0, 255);
 
 
 static struct attribute *edt_ft5x06_attrs[] = {
 static struct attribute *edt_ft5x06_attrs[] = {
 	&edt_ft5x06_attr_gain.dattr.attr,
 	&edt_ft5x06_attr_gain.dattr.attr,
@@ -508,7 +524,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
 	}
 	}
 
 
 	/* mode register is 0x3c when in the work mode */
 	/* mode register is 0x3c when in the work mode */
-	if (tsdata->version == M09)
+	if (tsdata->version != EDT_M06)
 		goto m09_out;
 		goto m09_out;
 
 
 	error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
 	error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03);
@@ -545,7 +561,7 @@ err_out:
 	return error;
 	return error;
 
 
 m09_out:
 m09_out:
-	dev_err(&client->dev, "No factory mode support for M09\n");
+	dev_err(&client->dev, "No factory mode support for M09/M12/GENERIC_FT\n");
 	return -EINVAL;
 	return -EINVAL;
 
 
 }
 }
@@ -770,16 +786,17 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
 	 * to have garbage in there
 	 * to have garbage in there
 	 */
 	 */
 	memset(rdbuf, 0, sizeof(rdbuf));
 	memset(rdbuf, 0, sizeof(rdbuf));
-	error = edt_ft5x06_ts_readwrite(client, 1, "\xbb",
+	error = edt_ft5x06_ts_readwrite(client, 1, "\xBB",
 					EDT_NAME_LEN - 1, rdbuf);
 					EDT_NAME_LEN - 1, rdbuf);
 	if (error)
 	if (error)
 		return error;
 		return error;
 
 
-	/* if we find something consistent, stay with that assumption
-	 * at least M09 won't send 3 bytes here
+	/* Probe content for something consistent.
+	 * M06 starts with a response byte, M12 gives the data directly.
+	 * M09/Generic does not provide model number information.
 	 */
 	 */
-	if (!(strncasecmp(rdbuf + 1, "EP0", 3))) {
-		tsdata->version = M06;
+	if (!strncasecmp(rdbuf + 1, "EP0", 3)) {
+		tsdata->version = EDT_M06;
 
 
 		/* remove last '$' end marker */
 		/* remove last '$' end marker */
 		rdbuf[EDT_NAME_LEN - 1] = '\0';
 		rdbuf[EDT_NAME_LEN - 1] = '\0';
@@ -792,9 +809,31 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
 			*p++ = '\0';
 			*p++ = '\0';
 		strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
 		strlcpy(model_name, rdbuf + 1, EDT_NAME_LEN);
 		strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
 		strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
+	} else if (!strncasecmp(rdbuf, "EP0", 3)) {
+		tsdata->version = EDT_M12;
+
+		/* remove last '$' end marker */
+		rdbuf[EDT_NAME_LEN - 2] = '\0';
+		if (rdbuf[EDT_NAME_LEN - 3] == '$')
+			rdbuf[EDT_NAME_LEN - 3] = '\0';
+
+		/* look for Model/Version separator */
+		p = strchr(rdbuf, '*');
+		if (p)
+			*p++ = '\0';
+		strlcpy(model_name, rdbuf, EDT_NAME_LEN);
+		strlcpy(fw_version, p ? p : "", EDT_NAME_LEN);
 	} else {
 	} else {
-		/* since there are only two versions around (M06, M09) */
-		tsdata->version = M09;
+		/* If it is not an EDT M06/M12 touchscreen, then the model
+		 * detection is a bit hairy. The different ft5x06
+		 * firmares around don't reliably implement the
+		 * identification registers. Well, we'll take a shot.
+		 *
+		 * The main difference between generic focaltec based
+		 * touches and EDT M09 is that we know how to retrieve
+		 * the max coordinates for the latter.
+		 */
+		tsdata->version = GENERIC_FT;
 
 
 		error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
 		error = edt_ft5x06_ts_readwrite(client, 1, "\xA6",
 						2, rdbuf);
 						2, rdbuf);
@@ -808,8 +847,34 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
 		if (error)
 		if (error)
 			return error;
 			return error;
 
 
-		snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
-			rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+		/* This "model identification" is not exact. Unfortunately
+		 * not all firmwares for the ft5x06 put useful values in
+		 * the identification registers.
+		 */
+		switch (rdbuf[0]) {
+		case 0x35:   /* EDT EP0350M09 */
+		case 0x43:   /* EDT EP0430M09 */
+		case 0x50:   /* EDT EP0500M09 */
+		case 0x57:   /* EDT EP0570M09 */
+		case 0x70:   /* EDT EP0700M09 */
+			tsdata->version = EDT_M09;
+			snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09",
+				rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+			break;
+		case 0xa1:   /* EDT EP1010ML00 */
+			tsdata->version = EDT_M09;
+			snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00",
+				rdbuf[0] >> 4, rdbuf[0] & 0x0F);
+			break;
+		case 0x5a:   /* Solomon Goldentek Display */
+			snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0");
+			break;
+		default:
+			snprintf(model_name, EDT_NAME_LEN,
+				 "generic ft5x06 (%02x)",
+				 rdbuf[0]);
+			break;
+		}
 	}
 	}
 
 
 	return 0;
 	return 0;
@@ -853,8 +918,17 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
 	if (reg_addr->reg_report_rate != NO_REGISTER)
 	if (reg_addr->reg_report_rate != NO_REGISTER)
 		tsdata->report_rate = edt_ft5x06_register_read(tsdata,
 		tsdata->report_rate = edt_ft5x06_register_read(tsdata,
 						reg_addr->reg_report_rate);
 						reg_addr->reg_report_rate);
-	tsdata->num_x = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_x);
-	tsdata->num_y = edt_ft5x06_register_read(tsdata, reg_addr->reg_num_y);
+	if (tsdata->version == EDT_M06 ||
+	    tsdata->version == EDT_M09 ||
+	    tsdata->version == EDT_M12) {
+		tsdata->num_x = edt_ft5x06_register_read(tsdata,
+							 reg_addr->reg_num_x);
+		tsdata->num_y = edt_ft5x06_register_read(tsdata,
+							 reg_addr->reg_num_y);
+	} else {
+		tsdata->num_x = -1;
+		tsdata->num_y = -1;
+	}
 }
 }
 
 
 static void
 static void
@@ -863,7 +937,7 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
 	struct edt_reg_addr *reg_addr = &tsdata->reg_addr;
 
 
 	switch (tsdata->version) {
 	switch (tsdata->version) {
-	case M06:
+	case EDT_M06:
 		reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
 		reg_addr->reg_threshold = WORK_REGISTER_THRESHOLD;
 		reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
 		reg_addr->reg_report_rate = WORK_REGISTER_REPORT_RATE;
 		reg_addr->reg_gain = WORK_REGISTER_GAIN;
 		reg_addr->reg_gain = WORK_REGISTER_GAIN;
@@ -872,7 +946,8 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
 		reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
 		reg_addr->reg_num_y = WORK_REGISTER_NUM_Y;
 		break;
 		break;
 
 
-	case M09:
+	case EDT_M09:
+	case EDT_M12:
 		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
 		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
 		reg_addr->reg_report_rate = NO_REGISTER;
 		reg_addr->reg_report_rate = NO_REGISTER;
 		reg_addr->reg_gain = M09_REGISTER_GAIN;
 		reg_addr->reg_gain = M09_REGISTER_GAIN;
@@ -880,6 +955,13 @@ edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
 		reg_addr->reg_num_x = M09_REGISTER_NUM_X;
 		reg_addr->reg_num_x = M09_REGISTER_NUM_X;
 		reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
 		reg_addr->reg_num_y = M09_REGISTER_NUM_Y;
 		break;
 		break;
+
+	case GENERIC_FT:
+		/* this is a guesswork */
+		reg_addr->reg_threshold = M09_REGISTER_THRESHOLD;
+		reg_addr->reg_gain = M09_REGISTER_GAIN;
+		reg_addr->reg_offset = M09_REGISTER_OFFSET;
+		break;
 	}
 	}
 }
 }
 
 
@@ -969,10 +1051,20 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 	input->id.bustype = BUS_I2C;
 	input->id.bustype = BUS_I2C;
 	input->dev.parent = &client->dev;
 	input->dev.parent = &client->dev;
 
 
-	input_set_abs_params(input, ABS_MT_POSITION_X,
-			     0, tsdata->num_x * 64 - 1, 0, 0);
-	input_set_abs_params(input, ABS_MT_POSITION_Y,
-			     0, tsdata->num_y * 64 - 1, 0, 0);
+	if (tsdata->version == EDT_M06 ||
+	    tsdata->version == EDT_M09 ||
+	    tsdata->version == EDT_M12) {
+		input_set_abs_params(input, ABS_MT_POSITION_X,
+				     0, tsdata->num_x * 64 - 1, 0, 0);
+		input_set_abs_params(input, ABS_MT_POSITION_Y,
+				     0, tsdata->num_y * 64 - 1, 0, 0);
+	} else {
+		/* Unknown maximum values. Specify via devicetree */
+		input_set_abs_params(input, ABS_MT_POSITION_X,
+				     0, 65535, 0, 0);
+		input_set_abs_params(input, ABS_MT_POSITION_Y,
+				     0, 65535, 0, 0);
+	}
 
 
 	touchscreen_parse_properties(input, true, &tsdata->prop);
 	touchscreen_parse_properties(input, true, &tsdata->prop);
 
 
@@ -998,13 +1090,13 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 		return error;
 		return error;
 	}
 	}
 
 
-	error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+	error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
 	if (error)
 	if (error)
 		return error;
 		return error;
 
 
 	error = input_register_device(input);
 	error = input_register_device(input);
 	if (error)
 	if (error)
-		goto err_remove_attrs;
+		return error;
 
 
 	edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
 	edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
 	device_init_wakeup(&client->dev, 1);
 	device_init_wakeup(&client->dev, 1);
@@ -1016,10 +1108,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
 		tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
 		tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
 
 
 	return 0;
 	return 0;
-
-err_remove_attrs:
-	sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
-	return error;
 }
 }
 
 
 static int edt_ft5x06_ts_remove(struct i2c_client *client)
 static int edt_ft5x06_ts_remove(struct i2c_client *client)
@@ -1027,7 +1115,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
 
 
 	edt_ft5x06_ts_teardown_debugfs(tsdata);
 	edt_ft5x06_ts_teardown_debugfs(tsdata);
-	sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
 
 
 	return 0;
 	return 0;
 }
 }

+ 1 - 18
drivers/input/touchscreen/elants_i2c.c

@@ -1070,13 +1070,6 @@ static const struct attribute_group elants_attribute_group = {
 	.attrs = elants_attributes,
 	.attrs = elants_attributes,
 };
 };
 
 
-static void elants_i2c_remove_sysfs_group(void *_data)
-{
-	struct elants_data *ts = _data;
-
-	sysfs_remove_group(&ts->client->dev.kobj, &elants_attribute_group);
-}
-
 static int elants_i2c_power_on(struct elants_data *ts)
 static int elants_i2c_power_on(struct elants_data *ts)
 {
 {
 	int error;
 	int error;
@@ -1289,23 +1282,13 @@ static int elants_i2c_probe(struct i2c_client *client,
 	if (!client->dev.of_node)
 	if (!client->dev.of_node)
 		device_init_wakeup(&client->dev, true);
 		device_init_wakeup(&client->dev, true);
 
 
-	error = sysfs_create_group(&client->dev.kobj, &elants_attribute_group);
+	error = devm_device_add_group(&client->dev, &elants_attribute_group);
 	if (error) {
 	if (error) {
 		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
 		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
 			error);
 			error);
 		return error;
 		return error;
 	}
 	}
 
 
-	error = devm_add_action(&client->dev,
-				elants_i2c_remove_sysfs_group, ts);
-	if (error) {
-		elants_i2c_remove_sysfs_group(ts);
-		dev_err(&client->dev,
-			"Failed to add sysfs cleanup action: %d\n",
-			error);
-		return error;
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 223 - 0
drivers/input/touchscreen/exc3000.c

@@ -0,0 +1,223 @@
+/*
+ * Driver for I2C connected EETI EXC3000 multiple touch controller
+ *
+ * Copyright (C) 2017 Ahmet Inan <inan@distec.de>
+ *
+ * minimal implementation based on egalax_ts.c and egalax_i2c.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/timer.h>
+#include <asm/unaligned.h>
+
+#define EXC3000_NUM_SLOTS		10
+#define EXC3000_SLOTS_PER_FRAME		5
+#define EXC3000_LEN_FRAME		66
+#define EXC3000_LEN_POINT		10
+#define EXC3000_MT_EVENT		6
+#define EXC3000_TIMEOUT_MS		100
+
+struct exc3000_data {
+	struct i2c_client *client;
+	struct input_dev *input;
+	struct touchscreen_properties prop;
+	struct timer_list timer;
+	u8 buf[2 * EXC3000_LEN_FRAME];
+};
+
+static void exc3000_report_slots(struct input_dev *input,
+				 struct touchscreen_properties *prop,
+				 const u8 *buf, int num)
+{
+	for (; num--; buf += EXC3000_LEN_POINT) {
+		if (buf[0] & BIT(0)) {
+			input_mt_slot(input, buf[1]);
+			input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+			touchscreen_report_pos(input, prop,
+					       get_unaligned_le16(buf + 2),
+					       get_unaligned_le16(buf + 4),
+					       true);
+		}
+	}
+}
+
+static void exc3000_timer(struct timer_list *t)
+{
+	struct exc3000_data *data = from_timer(data, t, timer);
+
+	input_mt_sync_frame(data->input);
+	input_sync(data->input);
+}
+
+static int exc3000_read_frame(struct i2c_client *client, u8 *buf)
+{
+	int ret;
+
+	ret = i2c_master_send(client, "'", 2);
+	if (ret < 0)
+		return ret;
+
+	if (ret != 2)
+		return -EIO;
+
+	ret = i2c_master_recv(client, buf, EXC3000_LEN_FRAME);
+	if (ret < 0)
+		return ret;
+
+	if (ret != EXC3000_LEN_FRAME)
+		return -EIO;
+
+	if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME ||
+			buf[2] != EXC3000_MT_EVENT)
+		return -EINVAL;
+
+	return 0;
+}
+
+static int exc3000_read_data(struct i2c_client *client,
+			     u8 *buf, int *n_slots)
+{
+	int error;
+
+	error = exc3000_read_frame(client, buf);
+	if (error)
+		return error;
+
+	*n_slots = buf[3];
+	if (!*n_slots || *n_slots > EXC3000_NUM_SLOTS)
+		return -EINVAL;
+
+	if (*n_slots > EXC3000_SLOTS_PER_FRAME) {
+		/* Read 2nd frame to get the rest of the contacts. */
+		error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME);
+		if (error)
+			return error;
+
+		/* 2nd chunk must have number of contacts set to 0. */
+		if (buf[EXC3000_LEN_FRAME + 3] != 0)
+			return -EINVAL;
+	}
+
+	return 0;
+}
+
+static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
+{
+	struct exc3000_data *data = dev_id;
+	struct input_dev *input = data->input;
+	u8 *buf = data->buf;
+	int slots, total_slots;
+	int error;
+
+	error = exc3000_read_data(data->client, buf, &total_slots);
+	if (error) {
+		/* Schedule a timer to release "stuck" contacts */
+		mod_timer(&data->timer,
+			  jiffies + msecs_to_jiffies(EXC3000_TIMEOUT_MS));
+		goto out;
+	}
+
+	/*
+	 * We read full state successfully, no contacts will be "stuck".
+	 */
+	del_timer_sync(&data->timer);
+
+	while (total_slots > 0) {
+		slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
+		exc3000_report_slots(input, &data->prop, buf + 4, slots);
+		total_slots -= slots;
+		buf += EXC3000_LEN_FRAME;
+	}
+
+	input_mt_sync_frame(input);
+	input_sync(input);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int exc3000_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct exc3000_data *data;
+	struct input_dev *input;
+	int error;
+
+	data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	timer_setup(&data->timer, exc3000_timer, 0);
+
+	input = devm_input_allocate_device(&client->dev);
+	if (!input)
+		return -ENOMEM;
+
+	data->input = input;
+
+	input->name = "EETI EXC3000 Touch Screen";
+	input->id.bustype = BUS_I2C;
+
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
+	touchscreen_parse_properties(input, true, &data->prop);
+
+	error = input_mt_init_slots(input, EXC3000_NUM_SLOTS,
+				    INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+	if (error)
+		return error;
+
+	error = input_register_device(input);
+	if (error)
+		return error;
+
+	error = devm_request_threaded_irq(&client->dev, client->irq,
+					  NULL, exc3000_interrupt, IRQF_ONESHOT,
+					  client->name, data);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static const struct i2c_device_id exc3000_id[] = {
+	{ "exc3000", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, exc3000_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id exc3000_of_match[] = {
+	{ .compatible = "eeti,exc3000" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, exc3000_of_match);
+#endif
+
+static struct i2c_driver exc3000_driver = {
+	.driver = {
+		.name	= "exc3000",
+		.of_match_table = of_match_ptr(exc3000_of_match),
+	},
+	.id_table	= exc3000_id,
+	.probe		= exc3000_probe,
+};
+
+module_i2c_driver(exc3000_driver);
+
+MODULE_AUTHOR("Ahmet Inan <inan@distec.de>");
+MODULE_DESCRIPTION("I2C connected EETI EXC3000 multiple touch controller driver");
+MODULE_LICENSE("GPL v2");

+ 98 - 27
drivers/input/touchscreen/goodix.c

@@ -31,9 +31,18 @@
 #include <linux/of.h>
 #include <linux/of.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 
+struct goodix_ts_data;
+
+struct goodix_chip_data {
+	u16 config_addr;
+	int config_len;
+	int (*check_config)(struct goodix_ts_data *, const struct firmware *);
+};
+
 struct goodix_ts_data {
 struct goodix_ts_data {
 	struct i2c_client *client;
 	struct i2c_client *client;
 	struct input_dev *input_dev;
 	struct input_dev *input_dev;
+	const struct goodix_chip_data *chip;
 	int abs_x_max;
 	int abs_x_max;
 	int abs_y_max;
 	int abs_y_max;
 	bool swapped_x_y;
 	bool swapped_x_y;
@@ -41,7 +50,6 @@ struct goodix_ts_data {
 	bool inverted_y;
 	bool inverted_y;
 	unsigned int max_touch_num;
 	unsigned int max_touch_num;
 	unsigned int int_trigger_type;
 	unsigned int int_trigger_type;
-	int cfg_len;
 	struct gpio_desc *gpiod_int;
 	struct gpio_desc *gpiod_int;
 	struct gpio_desc *gpiod_rst;
 	struct gpio_desc *gpiod_rst;
 	u16 id;
 	u16 id;
@@ -69,7 +77,8 @@ struct goodix_ts_data {
 #define GOODIX_CMD_SCREEN_OFF		0x05
 #define GOODIX_CMD_SCREEN_OFF		0x05
 
 
 #define GOODIX_READ_COOR_ADDR		0x814E
 #define GOODIX_READ_COOR_ADDR		0x814E
-#define GOODIX_REG_CONFIG_DATA		0x8047
+#define GOODIX_GT1X_REG_CONFIG_DATA	0x8050
+#define GOODIX_GT9X_REG_CONFIG_DATA	0x8047
 #define GOODIX_REG_ID			0x8140
 #define GOODIX_REG_ID			0x8140
 
 
 #define GOODIX_BUFFER_STATUS_READY	BIT(7)
 #define GOODIX_BUFFER_STATUS_READY	BIT(7)
@@ -79,6 +88,35 @@ struct goodix_ts_data {
 #define MAX_CONTACTS_LOC	5
 #define MAX_CONTACTS_LOC	5
 #define TRIGGER_LOC		6
 #define TRIGGER_LOC		6
 
 
+static int goodix_check_cfg_8(struct goodix_ts_data *ts,
+			const struct firmware *cfg);
+static int goodix_check_cfg_16(struct goodix_ts_data *ts,
+			const struct firmware *cfg);
+
+static const struct goodix_chip_data gt1x_chip_data = {
+	.config_addr		= GOODIX_GT1X_REG_CONFIG_DATA,
+	.config_len		= GOODIX_CONFIG_MAX_LENGTH,
+	.check_config		= goodix_check_cfg_16,
+};
+
+static const struct goodix_chip_data gt911_chip_data = {
+	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
+	.config_len		= GOODIX_CONFIG_911_LENGTH,
+	.check_config		= goodix_check_cfg_8,
+};
+
+static const struct goodix_chip_data gt967_chip_data = {
+	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
+	.config_len		= GOODIX_CONFIG_967_LENGTH,
+	.check_config		= goodix_check_cfg_8,
+};
+
+static const struct goodix_chip_data gt9x_chip_data = {
+	.config_addr		= GOODIX_GT9X_REG_CONFIG_DATA,
+	.config_len		= GOODIX_CONFIG_MAX_LENGTH,
+	.check_config		= goodix_check_cfg_8,
+};
+
 static const unsigned long goodix_irq_flags[] = {
 static const unsigned long goodix_irq_flags[] = {
 	IRQ_TYPE_EDGE_RISING,
 	IRQ_TYPE_EDGE_RISING,
 	IRQ_TYPE_EDGE_FALLING,
 	IRQ_TYPE_EDGE_FALLING,
@@ -177,22 +215,25 @@ static int goodix_i2c_write_u8(struct i2c_client *client, u16 reg, u8 value)
 	return goodix_i2c_write(client, reg, &value, sizeof(value));
 	return goodix_i2c_write(client, reg, &value, sizeof(value));
 }
 }
 
 
-static int goodix_get_cfg_len(u16 id)
+static const struct goodix_chip_data *goodix_get_chip_data(u16 id)
 {
 {
 	switch (id) {
 	switch (id) {
+	case 1151:
+		return &gt1x_chip_data;
+
 	case 911:
 	case 911:
 	case 9271:
 	case 9271:
 	case 9110:
 	case 9110:
 	case 927:
 	case 927:
 	case 928:
 	case 928:
-		return GOODIX_CONFIG_911_LENGTH;
+		return &gt911_chip_data;
 
 
 	case 912:
 	case 912:
 	case 967:
 	case 967:
-		return GOODIX_CONFIG_967_LENGTH;
+		return &gt967_chip_data;
 
 
 	default:
 	default:
-		return GOODIX_CONFIG_MAX_LENGTH;
+		return &gt9x_chip_data;
 	}
 	}
 }
 }
 
 
@@ -332,25 +373,12 @@ static int goodix_request_irq(struct goodix_ts_data *ts)
 					 ts->irq_flags, ts->client->name, ts);
 					 ts->irq_flags, ts->client->name, ts);
 }
 }
 
 
-/**
- * goodix_check_cfg - Checks if config fw is valid
- *
- * @ts: goodix_ts_data pointer
- * @cfg: firmware config data
- */
-static int goodix_check_cfg(struct goodix_ts_data *ts,
-			    const struct firmware *cfg)
+static int goodix_check_cfg_8(struct goodix_ts_data *ts,
+			const struct firmware *cfg)
 {
 {
-	int i, raw_cfg_len;
+	int i, raw_cfg_len = cfg->size - 2;
 	u8 check_sum = 0;
 	u8 check_sum = 0;
 
 
-	if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
-		dev_err(&ts->client->dev,
-			"The length of the config fw is not correct");
-		return -EINVAL;
-	}
-
-	raw_cfg_len = cfg->size - 2;
 	for (i = 0; i < raw_cfg_len; i++)
 	for (i = 0; i < raw_cfg_len; i++)
 		check_sum += cfg->data[i];
 		check_sum += cfg->data[i];
 	check_sum = (~check_sum) + 1;
 	check_sum = (~check_sum) + 1;
@@ -369,6 +397,48 @@ static int goodix_check_cfg(struct goodix_ts_data *ts,
 	return 0;
 	return 0;
 }
 }
 
 
+static int goodix_check_cfg_16(struct goodix_ts_data *ts,
+			const struct firmware *cfg)
+{
+	int i, raw_cfg_len = cfg->size - 3;
+	u16 check_sum = 0;
+
+	for (i = 0; i < raw_cfg_len; i += 2)
+		check_sum += get_unaligned_be16(&cfg->data[i]);
+	check_sum = (~check_sum) + 1;
+	if (check_sum != get_unaligned_be16(&cfg->data[raw_cfg_len])) {
+		dev_err(&ts->client->dev,
+			"The checksum of the config fw is not correct");
+		return -EINVAL;
+	}
+
+	if (cfg->data[raw_cfg_len + 2] != 1) {
+		dev_err(&ts->client->dev,
+			"Config fw must have Config_Fresh register set");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/**
+ * goodix_check_cfg - Checks if config fw is valid
+ *
+ * @ts: goodix_ts_data pointer
+ * @cfg: firmware config data
+ */
+static int goodix_check_cfg(struct goodix_ts_data *ts,
+			    const struct firmware *cfg)
+{
+	if (cfg->size > GOODIX_CONFIG_MAX_LENGTH) {
+		dev_err(&ts->client->dev,
+			"The length of the config fw is not correct");
+		return -EINVAL;
+	}
+
+	return ts->chip->check_config(ts, cfg);
+}
+
 /**
 /**
  * goodix_send_cfg - Write fw config to device
  * goodix_send_cfg - Write fw config to device
  *
  *
@@ -384,7 +454,7 @@ static int goodix_send_cfg(struct goodix_ts_data *ts,
 	if (error)
 	if (error)
 		return error;
 		return error;
 
 
-	error = goodix_i2c_write(ts->client, GOODIX_REG_CONFIG_DATA, cfg->data,
+	error = goodix_i2c_write(ts->client, ts->chip->config_addr, cfg->data,
 				 cfg->size);
 				 cfg->size);
 	if (error) {
 	if (error) {
 		dev_err(&ts->client->dev, "Failed to write config data: %d",
 		dev_err(&ts->client->dev, "Failed to write config data: %d",
@@ -511,8 +581,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
 	u8 config[GOODIX_CONFIG_MAX_LENGTH];
 	u8 config[GOODIX_CONFIG_MAX_LENGTH];
 	int error;
 	int error;
 
 
-	error = goodix_i2c_read(ts->client, GOODIX_REG_CONFIG_DATA,
-				config, ts->cfg_len);
+	error = goodix_i2c_read(ts->client, ts->chip->config_addr,
+				config, ts->chip->config_len);
 	if (error) {
 	if (error) {
 		dev_warn(&ts->client->dev,
 		dev_warn(&ts->client->dev,
 			 "Error reading config (%d), using defaults\n",
 			 "Error reading config (%d), using defaults\n",
@@ -592,7 +662,7 @@ static int goodix_i2c_test(struct i2c_client *client)
 	u8 test;
 	u8 test;
 
 
 	while (retry++ < 2) {
 	while (retry++ < 2) {
-		error = goodix_i2c_read(client, GOODIX_REG_CONFIG_DATA,
+		error = goodix_i2c_read(client, GOODIX_REG_ID,
 					&test, 1);
 					&test, 1);
 		if (!error)
 		if (!error)
 			return 0;
 			return 0;
@@ -762,7 +832,7 @@ static int goodix_ts_probe(struct i2c_client *client,
 		return error;
 		return error;
 	}
 	}
 
 
-	ts->cfg_len = goodix_get_cfg_len(ts->id);
+	ts->chip = goodix_get_chip_data(ts->id);
 
 
 	if (ts->gpiod_int && ts->gpiod_rst) {
 	if (ts->gpiod_int && ts->gpiod_rst) {
 		/* update device config */
 		/* update device config */
@@ -891,6 +961,7 @@ MODULE_DEVICE_TABLE(acpi, goodix_acpi_match);
 
 
 #ifdef CONFIG_OF
 #ifdef CONFIG_OF
 static const struct of_device_id goodix_of_match[] = {
 static const struct of_device_id goodix_of_match[] = {
+	{ .compatible = "goodix,gt1151" },
 	{ .compatible = "goodix,gt911" },
 	{ .compatible = "goodix,gt911" },
 	{ .compatible = "goodix,gt9110" },
 	{ .compatible = "goodix,gt9110" },
 	{ .compatible = "goodix,gt912" },
 	{ .compatible = "goodix,gt912" },

+ 1120 - 0
drivers/input/touchscreen/hideep.c

@@ -0,0 +1,1120 @@
+/*
+ * Copyright (C) 2012-2017 Hideep, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foudation.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/gpio/machine.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/sysfs.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/regulator/consumer.h>
+#include <asm/unaligned.h>
+
+#define HIDEEP_TS_NAME			"HiDeep Touchscreen"
+#define HIDEEP_I2C_NAME			"hideep_ts"
+
+#define HIDEEP_MT_MAX			10
+#define HIDEEP_KEY_MAX			3
+
+/* count(2) + touch data(100) + key data(6) */
+#define HIDEEP_MAX_EVENT		108UL
+
+#define HIDEEP_TOUCH_EVENT_INDEX	2
+#define HIDEEP_KEY_EVENT_INDEX		102
+
+/* Touch & key event */
+#define HIDEEP_EVENT_ADDR		0x240
+
+/* command list */
+#define HIDEEP_RESET_CMD		0x9800
+
+/* event bit */
+#define HIDEEP_MT_RELEASED		BIT(4)
+#define HIDEEP_KEY_PRESSED		BIT(7)
+#define HIDEEP_KEY_FIRST_PRESSED	BIT(8)
+#define HIDEEP_KEY_PRESSED_MASK		(HIDEEP_KEY_PRESSED | \
+					 HIDEEP_KEY_FIRST_PRESSED)
+
+#define HIDEEP_KEY_IDX_MASK		0x0f
+
+/* For NVM */
+#define HIDEEP_YRAM_BASE		0x40000000
+#define HIDEEP_PERIPHERAL_BASE		0x50000000
+#define HIDEEP_ESI_BASE			(HIDEEP_PERIPHERAL_BASE + 0x00000000)
+#define HIDEEP_FLASH_BASE		(HIDEEP_PERIPHERAL_BASE + 0x01000000)
+#define HIDEEP_SYSCON_BASE		(HIDEEP_PERIPHERAL_BASE + 0x02000000)
+
+#define HIDEEP_SYSCON_MOD_CON		(HIDEEP_SYSCON_BASE + 0x0000)
+#define HIDEEP_SYSCON_SPC_CON		(HIDEEP_SYSCON_BASE + 0x0004)
+#define HIDEEP_SYSCON_CLK_CON		(HIDEEP_SYSCON_BASE + 0x0008)
+#define HIDEEP_SYSCON_CLK_ENA		(HIDEEP_SYSCON_BASE + 0x000C)
+#define HIDEEP_SYSCON_RST_CON		(HIDEEP_SYSCON_BASE + 0x0010)
+#define HIDEEP_SYSCON_WDT_CON		(HIDEEP_SYSCON_BASE + 0x0014)
+#define HIDEEP_SYSCON_WDT_CNT		(HIDEEP_SYSCON_BASE + 0x0018)
+#define HIDEEP_SYSCON_PWR_CON		(HIDEEP_SYSCON_BASE + 0x0020)
+#define HIDEEP_SYSCON_PGM_ID		(HIDEEP_SYSCON_BASE + 0x00F4)
+
+#define HIDEEP_FLASH_CON		(HIDEEP_FLASH_BASE + 0x0000)
+#define HIDEEP_FLASH_STA		(HIDEEP_FLASH_BASE + 0x0004)
+#define HIDEEP_FLASH_CFG		(HIDEEP_FLASH_BASE + 0x0008)
+#define HIDEEP_FLASH_TIM		(HIDEEP_FLASH_BASE + 0x000C)
+#define HIDEEP_FLASH_CACHE_CFG		(HIDEEP_FLASH_BASE + 0x0010)
+#define HIDEEP_FLASH_PIO_SIG		(HIDEEP_FLASH_BASE + 0x400000)
+
+#define HIDEEP_ESI_TX_INVALID		(HIDEEP_ESI_BASE + 0x0008)
+
+#define HIDEEP_PERASE			0x00040000
+#define HIDEEP_WRONLY			0x00100000
+
+#define HIDEEP_NVM_MASK_OFS		0x0000000C
+#define HIDEEP_NVM_DEFAULT_PAGE		0
+#define HIDEEP_NVM_SFR_WPAGE		1
+#define HIDEEP_NVM_SFR_RPAGE		2
+
+#define HIDEEP_PIO_SIG			0x00400000
+#define HIDEEP_PROT_MODE		0x03400000
+
+#define HIDEEP_NVM_PAGE_SIZE		128
+
+#define HIDEEP_DWZ_INFO			0x000002C0
+
+struct hideep_event {
+	__le16 x;
+	__le16 y;
+	__le16 z;
+	u8 w;
+	u8 flag;
+	u8 type;
+	u8 index;
+};
+
+struct dwz_info {
+	__be32 code_start;
+	u8 code_crc[12];
+
+	__be32 c_code_start;
+	__be16 gen_ver;
+	__be16 c_code_len;
+
+	__be32 vr_start;
+	__be16 rsv0;
+	__be16 vr_len;
+
+	__be32 ft_start;
+	__be16 vr_version;
+	__be16 ft_len;
+
+	__be16 core_ver;
+	__be16 boot_ver;
+
+	__be16 release_ver;
+	__be16 custom_ver;
+
+	u8 factory_id;
+	u8 panel_type;
+	u8 model_name[6];
+
+	__be16 extra_option;
+	__be16 product_code;
+
+	__be16 vendor_id;
+	__be16 product_id;
+};
+
+struct pgm_packet {
+	struct {
+		u8 unused[3];
+		u8 len;
+		__be32 addr;
+	} header;
+	__be32 payload[HIDEEP_NVM_PAGE_SIZE / sizeof(__be32)];
+};
+
+#define HIDEEP_XFER_BUF_SIZE	sizeof(struct pgm_packet)
+
+struct hideep_ts {
+	struct i2c_client *client;
+	struct input_dev *input_dev;
+	struct regmap *reg;
+
+	struct touchscreen_properties prop;
+
+	struct gpio_desc *reset_gpio;
+
+	struct regulator *vcc_vdd;
+	struct regulator *vcc_vid;
+
+	struct mutex dev_mutex;
+
+	u32 tch_count;
+	u32 lpm_count;
+
+	/*
+	 * Data buffer to read packet from the device (contacts and key
+	 * states). We align it on double-word boundary to keep word-sized
+	 * fields in contact data and double-word-sized fields in program
+	 * packet aligned.
+	 */
+	u8 xfer_buf[HIDEEP_XFER_BUF_SIZE] __aligned(4);
+
+	int key_num;
+	u32 key_codes[HIDEEP_KEY_MAX];
+
+	struct dwz_info dwz_info;
+
+	unsigned int fw_size;
+	u32 nvm_mask;
+};
+
+static int hideep_pgm_w_mem(struct hideep_ts *ts, u32 addr,
+			    const __be32 *data, size_t count)
+{
+	struct pgm_packet *packet = (void *)ts->xfer_buf;
+	size_t len = count * sizeof(*data);
+	struct i2c_msg msg = {
+		.addr	= ts->client->addr,
+		.len	= len + sizeof(packet->header.len) +
+				sizeof(packet->header.addr),
+		.buf	= &packet->header.len,
+	};
+	int ret;
+
+	if (len > HIDEEP_NVM_PAGE_SIZE)
+		return -EINVAL;
+
+	packet->header.len = 0x80 | (count - 1);
+	packet->header.addr = cpu_to_be32(addr);
+	memcpy(packet->payload, data, len);
+
+	ret = i2c_transfer(ts->client->adapter, &msg, 1);
+	if (ret != 1)
+		return ret < 0 ? ret : -EIO;
+
+	return 0;
+}
+
+static int hideep_pgm_r_mem(struct hideep_ts *ts, u32 addr,
+			    __be32 *data, size_t count)
+{
+	struct pgm_packet *packet = (void *)ts->xfer_buf;
+	size_t len = count * sizeof(*data);
+	struct i2c_msg msg[] = {
+		{
+			.addr	= ts->client->addr,
+			.len	= sizeof(packet->header.len) +
+					sizeof(packet->header.addr),
+			.buf	= &packet->header.len,
+		},
+		{
+			.addr	= ts->client->addr,
+			.flags	= I2C_M_RD,
+			.len	= len,
+			.buf	= (u8 *)data,
+		},
+	};
+	int ret;
+
+	if (len > HIDEEP_NVM_PAGE_SIZE)
+		return -EINVAL;
+
+	packet->header.len = count - 1;
+	packet->header.addr = cpu_to_be32(addr);
+
+	ret = i2c_transfer(ts->client->adapter, msg, ARRAY_SIZE(msg));
+	if (ret != ARRAY_SIZE(msg))
+		return ret < 0 ? ret : -EIO;
+
+	return 0;
+}
+
+static int hideep_pgm_r_reg(struct hideep_ts *ts, u32 addr, u32 *val)
+{
+	__be32 data;
+	int error;
+
+	error = hideep_pgm_r_mem(ts, addr, &data, 1);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"read of register %#08x failed: %d\n",
+			addr, error);
+		return error;
+	}
+
+	*val = be32_to_cpu(data);
+	return 0;
+}
+
+static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val)
+{
+	__be32 data = cpu_to_be32(val);
+	int error;
+
+	error = hideep_pgm_w_mem(ts, addr, &data, 1);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"write to register %#08x (%#08x) failed: %d\n",
+			addr, val, error);
+		return error;
+	}
+
+	return 0;
+}
+
+#define SW_RESET_IN_PGM(clk)					\
+{								\
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk));	\
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03);	\
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x01);	\
+}
+
+#define SET_FLASH_PIO(ce)					\
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CON,			\
+			 0x01 | ((ce) << 1))
+
+#define SET_PIO_SIG(x, y)					\
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_PIO_SIG + (x), (y))
+
+#define SET_FLASH_HWCONTROL()					\
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CON, 0x00)
+
+#define NVM_W_SFR(x, y)						\
+{								\
+	SET_FLASH_PIO(1);					\
+	SET_PIO_SIG(x, y);					\
+	SET_FLASH_PIO(0);					\
+}
+
+static void hideep_pgm_set(struct hideep_ts *ts)
+{
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x00);
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_SPC_CON, 0x00);
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_CLK_ENA, 0xFF);
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_CLK_CON, 0x01);
+	hideep_pgm_w_reg(ts, HIDEEP_SYSCON_PWR_CON, 0x01);
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_TIM, 0x03);
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CACHE_CFG, 0x00);
+}
+
+static int hideep_pgm_get_pattern(struct hideep_ts *ts, u32 *pattern)
+{
+	u16 p1 = 0xAF39;
+	u16 p2 = 0xDF9D;
+	int error;
+
+	error = regmap_bulk_write(ts->reg, p1, &p2, 1);
+	if (error) {
+		dev_err(&ts->client->dev,
+			"%s: regmap_bulk_write() failed with %d\n",
+			__func__, error);
+		return error;
+	}
+
+	usleep_range(1000, 1100);
+
+	/* flush invalid Tx load register */
+	error = hideep_pgm_w_reg(ts, HIDEEP_ESI_TX_INVALID, 0x01);
+	if (error)
+		return error;
+
+	error = hideep_pgm_r_reg(ts, HIDEEP_SYSCON_PGM_ID, pattern);
+	if (error)
+		return error;
+
+	return 0;
+}
+
+static int hideep_enter_pgm(struct hideep_ts *ts)
+{
+	int retry_count = 10;
+	u32 pattern;
+	int error;
+
+	while (retry_count--) {
+		error = hideep_pgm_get_pattern(ts, &pattern);
+		if (error) {
+			dev_err(&ts->client->dev,
+				"hideep_pgm_get_pattern failed: %d\n", error);
+		} else if (pattern != 0x39AF9DDF) {
+			dev_err(&ts->client->dev, "%s: bad pattern: %#08x\n",
+				__func__, pattern);
+		} else {
+			dev_dbg(&ts->client->dev, "found magic code");
+
+			hideep_pgm_set(ts);
+			usleep_range(1000, 1100);
+
+			return 0;
+		}
+	}
+
+	dev_err(&ts->client->dev, "failed to  enter pgm mode\n");
+	SW_RESET_IN_PGM(1000);
+	return -EIO;
+}
+
+static void hideep_nvm_unlock(struct hideep_ts *ts)
+{
+	u32 unmask_code;
+
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_RPAGE);
+	hideep_pgm_r_reg(ts, 0x0000000C, &unmask_code);
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE);
+
+	/* make it unprotected code */
+	unmask_code &= ~HIDEEP_PROT_MODE;
+
+	/* compare unmask code */
+	if (unmask_code != ts->nvm_mask)
+		dev_warn(&ts->client->dev,
+			 "read mask code different %#08x vs %#08x",
+			 unmask_code, ts->nvm_mask);
+
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_SFR_WPAGE);
+	SET_FLASH_PIO(0);
+
+	NVM_W_SFR(HIDEEP_NVM_MASK_OFS, ts->nvm_mask);
+	SET_FLASH_HWCONTROL();
+	hideep_pgm_w_reg(ts, HIDEEP_FLASH_CFG, HIDEEP_NVM_DEFAULT_PAGE);
+}
+
+static int hideep_check_status(struct hideep_ts *ts)
+{
+	int time_out = 100;
+	int status;
+	int error;
+
+	while (time_out--) {
+		error = hideep_pgm_r_reg(ts, HIDEEP_FLASH_STA, &status);
+		if (!error && status)
+			return 0;
+
+		usleep_range(1000, 1100);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int hideep_program_page(struct hideep_ts *ts, u32 addr,
+			       const __be32 *ucode, size_t xfer_count)
+{
+	u32 val;
+	int error;
+
+	error = hideep_check_status(ts);
+	if (error)
+		return -EBUSY;
+
+	addr &= ~(HIDEEP_NVM_PAGE_SIZE - 1);
+
+	SET_FLASH_PIO(0);
+	SET_FLASH_PIO(1);
+
+	/* erase page */
+	SET_PIO_SIG(HIDEEP_PERASE | addr, 0xFFFFFFFF);
+
+	SET_FLASH_PIO(0);
+
+	error = hideep_check_status(ts);
+	if (error)
+		return -EBUSY;
+
+	/* write page */
+	SET_FLASH_PIO(1);
+
+	val = be32_to_cpu(ucode[0]);
+	SET_PIO_SIG(HIDEEP_WRONLY | addr, val);
+
+	hideep_pgm_w_mem(ts, HIDEEP_FLASH_PIO_SIG | HIDEEP_WRONLY,
+			 ucode, xfer_count);
+
+	val = be32_to_cpu(ucode[xfer_count - 1]);
+	SET_PIO_SIG(124, val);
+
+	SET_FLASH_PIO(0);
+
+	usleep_range(1000, 1100);
+
+	error = hideep_check_status(ts);
+	if (error)
+		return -EBUSY;
+
+	SET_FLASH_HWCONTROL();
+
+	return 0;
+}
+
+static int hideep_program_nvm(struct hideep_ts *ts,
+			      const __be32 *ucode, size_t ucode_len)
+{
+	struct pgm_packet *packet_r = (void *)ts->xfer_buf;
+	__be32 *current_ucode = packet_r->payload;
+	size_t xfer_len;
+	size_t xfer_count;
+	u32 addr = 0;
+	int error;
+
+	hideep_nvm_unlock(ts);
+
+	while (ucode_len > 0) {
+		xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE);
+		xfer_count = xfer_len / sizeof(*ucode);
+
+		error = hideep_pgm_r_mem(ts, 0x00000000 + addr,
+					 current_ucode, xfer_count);
+		if (error) {
+			dev_err(&ts->client->dev,
+				"%s: failed to read page at offset %#08x: %d\n",
+				__func__, addr, error);
+			return error;
+		}
+
+		/* See if the page needs updating */
+		if (memcmp(ucode, current_ucode, xfer_len)) {
+			error = hideep_program_page(ts, addr,
+						    ucode, xfer_count);
+			if (error) {
+				dev_err(&ts->client->dev,
+					"%s: iwrite failure @%#08x: %d\n",
+					__func__, addr, error);
+				return error;
+			}
+
+			usleep_range(1000, 1100);
+		}
+
+		ucode += xfer_count;
+		addr += xfer_len;
+		ucode_len -= xfer_len;
+	}
+
+	return 0;
+}
+
+static int hideep_verify_nvm(struct hideep_ts *ts,
+			     const __be32 *ucode, size_t ucode_len)
+{
+	struct pgm_packet *packet_r = (void *)ts->xfer_buf;
+	__be32 *current_ucode = packet_r->payload;
+	size_t xfer_len;
+	size_t xfer_count;
+	u32 addr = 0;
+	int i;
+	int error;
+
+	while (ucode_len > 0) {
+		xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE);
+		xfer_count = xfer_len / sizeof(*ucode);
+
+		error = hideep_pgm_r_mem(ts, 0x00000000 + addr,
+					 current_ucode, xfer_count);
+		if (error) {
+			dev_err(&ts->client->dev,
+				"%s: failed to read page at offset %#08x: %d\n",
+				__func__, addr, error);
+			return error;
+		}
+
+		if (memcmp(ucode, current_ucode, xfer_len)) {
+			const u8 *ucode_bytes = (const u8 *)ucode;
+			const u8 *current_bytes = (const u8 *)current_ucode;
+
+			for (i = 0; i < xfer_len; i++)
+				if (ucode_bytes[i] != current_bytes[i])
+					dev_err(&ts->client->dev,
+						"%s: mismatch @%#08x: (%#02x vs %#02x)\n",
+						__func__, addr + i,
+						ucode_bytes[i],
+						current_bytes[i]);
+
+			return -EIO;
+		}
+
+		ucode += xfer_count;
+		addr += xfer_len;
+		ucode_len -= xfer_len;
+	}
+
+	return 0;
+}
+
+static int hideep_load_dwz(struct hideep_ts *ts)
+{
+	u16 product_code;
+	int error;
+
+	error = hideep_enter_pgm(ts);
+	if (error)
+		return error;
+
+	msleep(50);
+
+	error = hideep_pgm_r_mem(ts, HIDEEP_DWZ_INFO,
+				 (void *)&ts->dwz_info,
+				 sizeof(ts->dwz_info) / sizeof(__be32));
+
+	SW_RESET_IN_PGM(10);
+	msleep(50);
+
+	if (error) {
+		dev_err(&ts->client->dev,
+			"failed to fetch DWZ data: %d\n", error);
+		return error;
+	}
+
+	product_code = be16_to_cpu(ts->dwz_info.product_code);
+
+	switch (product_code & 0xF0) {
+	case 0x40:
+		dev_dbg(&ts->client->dev, "used crimson IC");
+		ts->fw_size = 1024 * 48;
+		ts->nvm_mask = 0x00310000;
+		break;
+	case 0x60:
+		dev_dbg(&ts->client->dev, "used lime IC");
+		ts->fw_size = 1024 * 64;
+		ts->nvm_mask = 0x0030027B;
+		break;
+	default:
+		dev_err(&ts->client->dev, "product code is wrong: %#04x",
+			product_code);
+		return -EINVAL;
+	}
+
+	dev_dbg(&ts->client->dev, "firmware release version: %#04x",
+		be16_to_cpu(ts->dwz_info.release_ver));
+
+	return 0;
+}
+
+static int hideep_flash_firmware(struct hideep_ts *ts,
+				 const __be32 *ucode, size_t ucode_len)
+{
+	int retry_cnt = 3;
+	int error;
+
+	while (retry_cnt--) {
+		error = hideep_program_nvm(ts, ucode, ucode_len);
+		if (!error) {
+			error = hideep_verify_nvm(ts, ucode, ucode_len);
+			if (!error)
+				return 0;
+		}
+	}
+
+	return error;
+}
+
+static int hideep_update_firmware(struct hideep_ts *ts,
+				  const __be32 *ucode, size_t ucode_len)
+{
+	int error, error2;
+
+	dev_dbg(&ts->client->dev, "starting firmware update");
+
+	/* enter program mode */
+	error = hideep_enter_pgm(ts);
+	if (error)
+		return error;
+
+	error = hideep_flash_firmware(ts, ucode, ucode_len);
+	if (error)
+		dev_err(&ts->client->dev,
+			"firmware update failed: %d\n", error);
+	else
+		dev_dbg(&ts->client->dev, "firmware updated successfully\n");
+
+	SW_RESET_IN_PGM(1000);
+
+	error2 = hideep_load_dwz(ts);
+	if (error2)
+		dev_err(&ts->client->dev,
+			"failed to load dwz after firmware update: %d\n",
+			error2);
+
+	return error ?: error2;
+}
+
+static int hideep_power_on(struct hideep_ts *ts)
+{
+	int error = 0;
+
+	error = regulator_enable(ts->vcc_vdd);
+	if (error)
+		dev_err(&ts->client->dev,
+			"failed to enable 'vdd' regulator: %d", error);
+
+	usleep_range(999, 1000);
+
+	error = regulator_enable(ts->vcc_vid);
+	if (error)
+		dev_err(&ts->client->dev,
+			"failed to enable 'vcc_vid' regulator: %d",
+			error);
+
+	msleep(30);
+
+	if (ts->reset_gpio) {
+		gpiod_set_value_cansleep(ts->reset_gpio, 0);
+	} else {
+		error = regmap_write(ts->reg, HIDEEP_RESET_CMD, 0x01);
+		if (error)
+			dev_err(&ts->client->dev,
+				"failed to send 'reset' command: %d\n", error);
+	}
+
+	msleep(50);
+
+	return error;
+}
+
+static void hideep_power_off(void *data)
+{
+	struct hideep_ts *ts = data;
+
+	if (ts->reset_gpio)
+		gpiod_set_value(ts->reset_gpio, 1);
+
+	regulator_disable(ts->vcc_vid);
+	regulator_disable(ts->vcc_vdd);
+}
+
+#define __GET_MT_TOOL_TYPE(type) ((type) == 0x01 ? MT_TOOL_FINGER : MT_TOOL_PEN)
+
+static void hideep_report_slot(struct input_dev *input,
+			       const struct hideep_event *event)
+{
+	input_mt_slot(input, event->index & 0x0f);
+	input_mt_report_slot_state(input,
+				   __GET_MT_TOOL_TYPE(event->type),
+				   !(event->flag & HIDEEP_MT_RELEASED));
+	if (!(event->flag & HIDEEP_MT_RELEASED)) {
+		input_report_abs(input, ABS_MT_POSITION_X,
+				 le16_to_cpup(&event->x));
+		input_report_abs(input, ABS_MT_POSITION_Y,
+				 le16_to_cpup(&event->y));
+		input_report_abs(input, ABS_MT_PRESSURE,
+				 le16_to_cpup(&event->z));
+		input_report_abs(input, ABS_MT_TOUCH_MAJOR, event->w);
+	}
+}
+
+static void hideep_parse_and_report(struct hideep_ts *ts)
+{
+	const struct hideep_event *events =
+			(void *)&ts->xfer_buf[HIDEEP_TOUCH_EVENT_INDEX];
+	const u8 *keys = &ts->xfer_buf[HIDEEP_KEY_EVENT_INDEX];
+	int touch_count = ts->xfer_buf[0];
+	int key_count = ts->xfer_buf[1] & 0x0f;
+	int lpm_count = ts->xfer_buf[1] & 0xf0;
+	int i;
+
+	/* get touch event count */
+	dev_dbg(&ts->client->dev, "mt = %d, key = %d, lpm = %02x",
+		touch_count, key_count, lpm_count);
+
+	touch_count = min(touch_count, HIDEEP_MT_MAX);
+	for (i = 0; i < touch_count; i++)
+		hideep_report_slot(ts->input_dev, events + i);
+
+	key_count = min(key_count, HIDEEP_KEY_MAX);
+	for (i = 0; i < key_count; i++) {
+		u8 key_data = keys[i * 2];
+
+		input_report_key(ts->input_dev,
+				 ts->key_codes[key_data & HIDEEP_KEY_IDX_MASK],
+				 key_data & HIDEEP_KEY_PRESSED_MASK);
+	}
+
+	input_mt_sync_frame(ts->input_dev);
+	input_sync(ts->input_dev);
+}
+
+static irqreturn_t hideep_irq(int irq, void *handle)
+{
+	struct hideep_ts *ts = handle;
+	int error;
+
+	BUILD_BUG_ON(HIDEEP_MAX_EVENT > HIDEEP_XFER_BUF_SIZE);
+
+	error = regmap_bulk_read(ts->reg, HIDEEP_EVENT_ADDR,
+				 ts->xfer_buf, HIDEEP_MAX_EVENT / 2);
+	if (error) {
+		dev_err(&ts->client->dev, "failed to read events: %d\n", error);
+		goto out;
+	}
+
+	hideep_parse_and_report(ts);
+
+out:
+	return IRQ_HANDLED;
+}
+
+static int hideep_get_axis_info(struct hideep_ts *ts)
+{
+	__le16 val[2];
+	int error;
+
+	error = regmap_bulk_read(ts->reg, 0x28, val, ARRAY_SIZE(val));
+	if (error)
+		return error;
+
+	ts->prop.max_x = le16_to_cpup(val);
+	ts->prop.max_y = le16_to_cpup(val + 1);
+
+	dev_dbg(&ts->client->dev, "X: %d, Y: %d",
+		ts->prop.max_x, ts->prop.max_y);
+
+	return 0;
+}
+
+static int hideep_init_input(struct hideep_ts *ts)
+{
+	struct device *dev = &ts->client->dev;
+	int i;
+	int error;
+
+	ts->input_dev = devm_input_allocate_device(dev);
+	if (!ts->input_dev) {
+		dev_err(dev, "failed to allocate input device\n");
+		return -ENOMEM;
+	}
+
+	ts->input_dev->name = HIDEEP_TS_NAME;
+	ts->input_dev->id.bustype = BUS_I2C;
+	input_set_drvdata(ts->input_dev, ts);
+
+	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_X);
+	input_set_capability(ts->input_dev, EV_ABS, ABS_MT_POSITION_Y);
+	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE, 0, 65535, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(ts->input_dev, ABS_MT_TOOL_TYPE,
+			     0, MT_TOOL_MAX, 0, 0);
+	touchscreen_parse_properties(ts->input_dev, true, &ts->prop);
+
+	if (ts->prop.max_x == 0 || ts->prop.max_y == 0) {
+		error = hideep_get_axis_info(ts);
+		if (error)
+			return error;
+	}
+
+	error = input_mt_init_slots(ts->input_dev, HIDEEP_MT_MAX,
+				    INPUT_MT_DIRECT);
+	if (error)
+		return error;
+
+	ts->key_num = device_property_read_u32_array(dev, "linux,keycodes",
+						     NULL, 0);
+	if (ts->key_num > HIDEEP_KEY_MAX) {
+		dev_err(dev, "too many keys defined: %d\n",
+			ts->key_num);
+		return -EINVAL;
+	}
+
+	if (ts->key_num <= 0) {
+		dev_dbg(dev,
+			"missing or malformed 'linux,keycodes' property\n");
+	} else {
+		error = device_property_read_u32_array(dev, "linux,keycodes",
+						       ts->key_codes,
+						       ts->key_num);
+		if (error) {
+			dev_dbg(dev, "failed to read keymap: %d", error);
+			return error;
+		}
+
+		if (ts->key_num) {
+			ts->input_dev->keycode = ts->key_codes;
+			ts->input_dev->keycodesize = sizeof(ts->key_codes[0]);
+			ts->input_dev->keycodemax = ts->key_num;
+
+			for (i = 0; i < ts->key_num; i++)
+				input_set_capability(ts->input_dev, EV_KEY,
+					ts->key_codes[i]);
+		}
+	}
+
+	error = input_register_device(ts->input_dev);
+	if (error) {
+		dev_err(dev, "failed to register input device: %d", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static ssize_t hideep_update_fw(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct hideep_ts *ts = i2c_get_clientdata(client);
+	const struct firmware *fw_entry;
+	char *fw_name;
+	int mode;
+	int error;
+
+	error = kstrtoint(buf, 0, &mode);
+	if (error)
+		return error;
+
+	fw_name = kasprintf(GFP_KERNEL, "hideep_ts_%04x.bin",
+			    be16_to_cpu(ts->dwz_info.product_id));
+	if (!fw_name)
+		return -ENOMEM;
+
+	error = request_firmware(&fw_entry, fw_name, dev);
+	if (error) {
+		dev_err(dev, "failed to request firmware %s: %d",
+			fw_name, error);
+		goto out_free_fw_name;
+	}
+
+	if (fw_entry->size % sizeof(__be32)) {
+		dev_err(dev, "invalid firmware size %zu\n", fw_entry->size);
+		error = -EINVAL;
+		goto out_release_fw;
+	}
+
+	if (fw_entry->size > ts->fw_size) {
+		dev_err(dev, "fw size (%zu) is too big (memory size %d)\n",
+			fw_entry->size, ts->fw_size);
+		error = -EFBIG;
+		goto out_release_fw;
+	}
+
+	mutex_lock(&ts->dev_mutex);
+	disable_irq(client->irq);
+
+	error = hideep_update_firmware(ts, (const __be32 *)fw_entry->data,
+				       fw_entry->size);
+
+	enable_irq(client->irq);
+	mutex_unlock(&ts->dev_mutex);
+
+out_release_fw:
+	release_firmware(fw_entry);
+out_free_fw_name:
+	kfree(fw_name);
+
+	return error ?: count;
+}
+
+static ssize_t hideep_fw_version_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct hideep_ts *ts = i2c_get_clientdata(client);
+	ssize_t len;
+
+	mutex_lock(&ts->dev_mutex);
+	len = scnprintf(buf, PAGE_SIZE, "%04x\n",
+			be16_to_cpu(ts->dwz_info.release_ver));
+	mutex_unlock(&ts->dev_mutex);
+
+	return len;
+}
+
+static ssize_t hideep_product_id_show(struct device *dev,
+				      struct device_attribute *attr, char *buf)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct hideep_ts *ts = i2c_get_clientdata(client);
+	ssize_t len;
+
+	mutex_lock(&ts->dev_mutex);
+	len = scnprintf(buf, PAGE_SIZE, "%04x\n",
+			be16_to_cpu(ts->dwz_info.product_id));
+	mutex_unlock(&ts->dev_mutex);
+
+	return len;
+}
+
+static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL);
+static DEVICE_ATTR(product_id, 0664, hideep_product_id_show, NULL);
+static DEVICE_ATTR(update_fw, 0664, NULL, hideep_update_fw);
+
+static struct attribute *hideep_ts_sysfs_entries[] = {
+	&dev_attr_version.attr,
+	&dev_attr_product_id.attr,
+	&dev_attr_update_fw.attr,
+	NULL,
+};
+
+static const struct attribute_group hideep_ts_attr_group = {
+	.attrs = hideep_ts_sysfs_entries,
+};
+
+static int __maybe_unused hideep_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct hideep_ts *ts = i2c_get_clientdata(client);
+
+	disable_irq(client->irq);
+	hideep_power_off(ts);
+
+	return 0;
+}
+
+static int __maybe_unused hideep_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct hideep_ts *ts = i2c_get_clientdata(client);
+	int error;
+
+	error = hideep_power_on(ts);
+	if (error) {
+		dev_err(&client->dev, "power on failed");
+		return error;
+	}
+
+	enable_irq(client->irq);
+
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(hideep_pm_ops, hideep_suspend, hideep_resume);
+
+static const struct regmap_config hideep_regmap_config = {
+	.reg_bits = 16,
+	.reg_format_endian = REGMAP_ENDIAN_LITTLE,
+	.val_bits = 16,
+	.val_format_endian = REGMAP_ENDIAN_LITTLE,
+	.max_register = 0xffff,
+};
+
+static int hideep_probe(struct i2c_client *client,
+			const struct i2c_device_id *id)
+{
+	struct hideep_ts *ts;
+	int error;
+
+	/* check i2c bus */
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+		dev_err(&client->dev, "check i2c device error");
+		return -ENODEV;
+	}
+
+	if (client->irq <= 0) {
+		dev_err(&client->dev, "missing irq: %d\n", client->irq);
+		return -EINVAL;
+	}
+
+	ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL);
+	if (!ts)
+		return -ENOMEM;
+
+	ts->client = client;
+	i2c_set_clientdata(client, ts);
+	mutex_init(&ts->dev_mutex);
+
+	ts->reg = devm_regmap_init_i2c(client, &hideep_regmap_config);
+	if (IS_ERR(ts->reg)) {
+		error = PTR_ERR(ts->reg);
+		dev_err(&client->dev,
+			"failed to initialize regmap: %d\n", error);
+		return error;
+	}
+
+	ts->vcc_vdd = devm_regulator_get(&client->dev, "vdd");
+	if (IS_ERR(ts->vcc_vdd))
+		return PTR_ERR(ts->vcc_vdd);
+
+	ts->vcc_vid = devm_regulator_get(&client->dev, "vid");
+	if (IS_ERR(ts->vcc_vid))
+		return PTR_ERR(ts->vcc_vid);
+
+	ts->reset_gpio = devm_gpiod_get_optional(&client->dev,
+						 "reset", GPIOD_OUT_HIGH);
+	if (IS_ERR(ts->reset_gpio))
+		return PTR_ERR(ts->reset_gpio);
+
+	error = hideep_power_on(ts);
+	if (error) {
+		dev_err(&client->dev, "power on failed: %d\n", error);
+		return error;
+	}
+
+	error = devm_add_action_or_reset(&client->dev, hideep_power_off, ts);
+	if (error)
+		return error;
+
+	error = hideep_load_dwz(ts);
+	if (error) {
+		dev_err(&client->dev, "failed to load dwz: %d", error);
+		return error;
+	}
+
+	error = hideep_init_input(ts);
+	if (error)
+		return error;
+
+	error = devm_request_threaded_irq(&client->dev, client->irq,
+					  NULL, hideep_irq, IRQF_ONESHOT,
+					  client->name, ts);
+	if (error) {
+		dev_err(&client->dev, "failed to request irq %d: %d\n",
+			client->irq, error);
+		return error;
+	}
+
+	error = devm_device_add_group(&client->dev, &hideep_ts_attr_group);
+	if (error) {
+		dev_err(&client->dev,
+			"failed to add sysfs attributes: %d\n", error);
+		return error;
+	}
+
+	return 0;
+}
+
+static const struct i2c_device_id hideep_i2c_id[] = {
+	{ HIDEEP_I2C_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, hideep_i2c_id);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id hideep_acpi_id[] = {
+	{ "HIDP0001", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(acpi, hideep_acpi_id);
+#endif
+
+#ifdef CONFIG_OF
+static const struct of_device_id hideep_match_table[] = {
+	{ .compatible = "hideep,hideep-ts" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, hideep_match_table);
+#endif
+
+static struct i2c_driver hideep_driver = {
+	.driver = {
+		.name			= HIDEEP_I2C_NAME,
+		.of_match_table		= of_match_ptr(hideep_match_table),
+		.acpi_match_table	= ACPI_PTR(hideep_acpi_id),
+		.pm			= &hideep_pm_ops,
+	},
+	.id_table	= hideep_i2c_id,
+	.probe		= hideep_probe,
+};
+
+module_i2c_driver(hideep_driver);
+
+MODULE_DESCRIPTION("Driver for HiDeep Touchscreen Controller");
+MODULE_AUTHOR("anthony.kim@hideep.com");
+MODULE_LICENSE("GPL v2");

+ 1 - 16
drivers/input/touchscreen/melfas_mip4.c

@@ -1433,13 +1433,6 @@ static const struct attribute_group mip4_attr_group = {
 	.attrs = mip4_attrs,
 	.attrs = mip4_attrs,
 };
 };
 
 
-static void mip4_sysfs_remove(void *_data)
-{
-	struct mip4_ts *ts = _data;
-
-	sysfs_remove_group(&ts->client->dev.kobj, &mip4_attr_group);
-}
-
 static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
 static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 {
 	struct mip4_ts *ts;
 	struct mip4_ts *ts;
@@ -1535,21 +1528,13 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		return error;
 		return error;
 	}
 	}
 
 
-	error = sysfs_create_group(&client->dev.kobj, &mip4_attr_group);
+	error = devm_device_add_group(&client->dev, &mip4_attr_group);
 	if (error) {
 	if (error) {
 		dev_err(&client->dev,
 		dev_err(&client->dev,
 			"Failed to create sysfs attribute group: %d\n", error);
 			"Failed to create sysfs attribute group: %d\n", error);
 		return error;
 		return error;
 	}
 	}
 
 
-	error = devm_add_action(&client->dev, mip4_sysfs_remove, ts);
-	if (error) {
-		mip4_sysfs_remove(ts);
-		dev_err(&client->dev,
-			"Failed to install sysfs remoce action: %d\n", error);
-		return error;
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
drivers/input/touchscreen/mxs-lradc-ts.c

@@ -584,7 +584,7 @@ static void mxs_lradc_ts_hw_init(struct mxs_lradc_ts *ts)
 
 
 static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
 static int mxs_lradc_ts_register(struct mxs_lradc_ts *ts)
 {
 {
-	struct input_dev *input = ts->ts_input;
+	struct input_dev *input;
 	struct device *dev = ts->dev;
 	struct device *dev = ts->dev;
 
 
 	input = devm_input_allocate_device(dev);
 	input = devm_input_allocate_device(dev);

+ 1 - 17
drivers/input/touchscreen/raydium_i2c_ts.c

@@ -943,13 +943,6 @@ static const struct attribute_group raydium_i2c_attribute_group = {
 	.attrs = raydium_i2c_attributes,
 	.attrs = raydium_i2c_attributes,
 };
 };
 
 
-static void raydium_i2c_remove_sysfs_group(void *_data)
-{
-	struct raydium_data *ts = _data;
-
-	sysfs_remove_group(&ts->client->dev.kobj, &raydium_i2c_attribute_group);
-}
-
 static int raydium_i2c_power_on(struct raydium_data *ts)
 static int raydium_i2c_power_on(struct raydium_data *ts)
 {
 {
 	int error;
 	int error;
@@ -1120,7 +1113,7 @@ static int raydium_i2c_probe(struct i2c_client *client,
 		return error;
 		return error;
 	}
 	}
 
 
-	error = sysfs_create_group(&client->dev.kobj,
+	error = devm_device_add_group(&client->dev,
 				   &raydium_i2c_attribute_group);
 				   &raydium_i2c_attribute_group);
 	if (error) {
 	if (error) {
 		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
 		dev_err(&client->dev, "failed to create sysfs attributes: %d\n",
@@ -1128,15 +1121,6 @@ static int raydium_i2c_probe(struct i2c_client *client,
 		return error;
 		return error;
 	}
 	}
 
 
-	error = devm_add_action(&client->dev,
-				raydium_i2c_remove_sysfs_group, ts);
-	if (error) {
-		raydium_i2c_remove_sysfs_group(ts);
-		dev_err(&client->dev,
-			"Failed to add sysfs cleanup action: %d\n", error);
-		return error;
-	}
-
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 16
drivers/input/touchscreen/rohm_bu21023.c

@@ -1103,13 +1103,6 @@ static void rohm_ts_close(struct input_dev *input_dev)
 	ts->initialized = false;
 	ts->initialized = false;
 }
 }
 
 
-static void rohm_ts_remove_sysfs_group(void *_dev)
-{
-	struct device *dev = _dev;
-
-	sysfs_remove_group(&dev->kobj, &rohm_ts_attr_group);
-}
-
 static int rohm_bu21023_i2c_probe(struct i2c_client *client,
 static int rohm_bu21023_i2c_probe(struct i2c_client *client,
 				  const struct i2c_device_id *id)
 				  const struct i2c_device_id *id)
 {
 {
@@ -1180,20 +1173,12 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client,
 		return error;
 		return error;
 	}
 	}
 
 
-	error = sysfs_create_group(&dev->kobj, &rohm_ts_attr_group);
+	error = devm_device_add_group(dev, &rohm_ts_attr_group);
 	if (error) {
 	if (error) {
 		dev_err(dev, "failed to create sysfs group: %d\n", error);
 		dev_err(dev, "failed to create sysfs group: %d\n", error);
 		return error;
 		return error;
 	}
 	}
 
 
-	error = devm_add_action(dev, rohm_ts_remove_sysfs_group, dev);
-	if (error) {
-		rohm_ts_remove_sysfs_group(dev);
-		dev_err(dev, "Failed to add sysfs cleanup action: %d\n",
-			error);
-		return error;
-	}
-
 	return error;
 	return error;
 }
 }
 
 

+ 559 - 0
drivers/input/touchscreen/s6sy761.c

@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ * Author: Andi Shyti <andi.shyti@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Samsung S6SY761 Touchscreen device driver
+ */
+
+#include <asm/unaligned.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+
+/* commands */
+#define S6SY761_SENSE_ON		0x10
+#define S6SY761_SENSE_OFF		0x11
+#define S6SY761_TOUCH_FUNCTION		0x30 /* R/W for get/set */
+#define S6SY761_FIRMWARE_INTEGRITY	0x21
+#define S6SY761_PANEL_INFO		0x23
+#define S6SY761_DEVICE_ID		0x52
+#define S6SY761_BOOT_STATUS		0x55
+#define S6SY761_READ_ONE_EVENT		0x60
+#define S6SY761_READ_ALL_EVENT		0x61
+#define S6SY761_CLEAR_EVENT_STACK	0x62
+#define S6SY761_APPLICATION_MODE	0xe4
+
+/* events */
+#define S6SY761_EVENT_INFO		0x02
+#define S6SY761_EVENT_VENDOR_INFO	0x07
+
+/* info */
+#define S6SY761_INFO_BOOT_COMPLETE	0x00
+
+/* firmware status */
+#define S6SY761_FW_OK			0x80
+
+/*
+ * the functionalities are put as a reference
+ * as in the device I am using none of them
+ * works therefore not used in this driver yet.
+ */
+/* touchscreen functionalities */
+#define S6SY761_MASK_TOUCH		BIT(0)
+#define S6SY761_MASK_HOVER		BIT(1)
+#define S6SY761_MASK_COVER		BIT(2)
+#define S6SY761_MASK_GLOVE		BIT(3)
+#define S6SY761_MASK_STYLUS		BIT(4)
+#define S6SY761_MASK_PALM		BIT(5)
+#define S6SY761_MASK_WET		BIT(6)
+#define S6SY761_MASK_PROXIMITY		BIT(7)
+
+/* boot status (BS) */
+#define S6SY761_BS_BOOT_LOADER		0x10
+#define S6SY761_BS_APPLICATION		0x20
+
+/* event id */
+#define S6SY761_EVENT_ID_COORDINATE	0x00
+#define S6SY761_EVENT_ID_STATUS		0x01
+
+/* event register masks */
+#define S6SY761_MASK_TOUCH_STATE	0xc0 /* byte 0 */
+#define S6SY761_MASK_TID		0x3c
+#define S6SY761_MASK_EID		0x03
+#define S6SY761_MASK_X			0xf0 /* byte 3 */
+#define S6SY761_MASK_Y			0x0f
+#define S6SY761_MASK_Z			0x3f /* byte 6 */
+#define S6SY761_MASK_LEFT_EVENTS	0x3f /* byte 7 */
+#define S6SY761_MASK_TOUCH_TYPE		0xc0 /* MSB in byte 6, LSB in byte 7 */
+
+/* event touch state values */
+#define S6SY761_TS_NONE			0x00
+#define S6SY761_TS_PRESS		0x01
+#define S6SY761_TS_MOVE			0x02
+#define S6SY761_TS_RELEASE		0x03
+
+/* application modes */
+#define S6SY761_APP_NORMAL		0x0
+#define S6SY761_APP_LOW_POWER		0x1
+#define S6SY761_APP_TEST		0x2
+#define S6SY761_APP_FLASH		0x3
+#define S6SY761_APP_SLEEP		0x4
+
+#define S6SY761_EVENT_SIZE		8
+#define S6SY761_EVENT_COUNT		32
+#define S6SY761_DEVID_SIZE		3
+#define S6SY761_PANEL_ID_SIZE		11
+#define S6SY761_TS_STATUS_SIZE		5
+#define S6SY761_MAX_FINGERS		10
+
+#define S6SY761_DEV_NAME	"s6sy761"
+
+enum s6sy761_regulators {
+	S6SY761_REGULATOR_VDD,
+	S6SY761_REGULATOR_AVDD,
+};
+
+struct s6sy761_data {
+	struct i2c_client *client;
+	struct regulator_bulk_data regulators[2];
+	struct input_dev *input;
+	struct touchscreen_properties prop;
+
+	u8 data[S6SY761_EVENT_SIZE * S6SY761_EVENT_COUNT];
+
+	u16 devid;
+	u8 tx_channel;
+};
+
+/*
+ * We can't simply use i2c_smbus_read_i2c_block_data because we
+ * need to read more than 255 bytes
+ */
+static int s6sy761_read_events(struct s6sy761_data *sdata, u16 n_events)
+{
+	u8 cmd = S6SY761_READ_ALL_EVENT;
+	struct i2c_msg msgs[2] = {
+		{
+			.addr	= sdata->client->addr,
+			.len	= 1,
+			.buf	= &cmd,
+		},
+		{
+			.addr	= sdata->client->addr,
+			.flags	= I2C_M_RD,
+			.len	= (n_events * S6SY761_EVENT_SIZE),
+			.buf	= sdata->data + S6SY761_EVENT_SIZE,
+		},
+	};
+	int ret;
+
+	ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs));
+	if (ret < 0)
+		return ret;
+
+	return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
+}
+
+static void s6sy761_report_coordinates(struct s6sy761_data *sdata,
+				       u8 *event, u8 tid)
+{
+	u8 major = event[4];
+	u8 minor = event[5];
+	u8 z = event[6] & S6SY761_MASK_Z;
+	u16 x = (event[1] << 3) | ((event[3] & S6SY761_MASK_X) >> 4);
+	u16 y = (event[2] << 3) | (event[3] & S6SY761_MASK_Y);
+
+	input_mt_slot(sdata->input, tid);
+
+	input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
+	input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
+	input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
+	input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, major);
+	input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, minor);
+	input_report_abs(sdata->input, ABS_MT_PRESSURE, z);
+
+	input_sync(sdata->input);
+}
+
+static void s6sy761_report_release(struct s6sy761_data *sdata,
+				   u8 *event, u8 tid)
+{
+	input_mt_slot(sdata->input, tid);
+	input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, false);
+
+	input_sync(sdata->input);
+}
+
+static void s6sy761_handle_coordinates(struct s6sy761_data *sdata, u8 *event)
+{
+	u8 tid;
+	u8 touch_state;
+
+	if (unlikely(!(event[0] & S6SY761_MASK_TID)))
+		return;
+
+	tid = ((event[0] & S6SY761_MASK_TID) >> 2) - 1;
+	touch_state = (event[0] & S6SY761_MASK_TOUCH_STATE) >> 6;
+
+	switch (touch_state) {
+
+	case S6SY761_TS_NONE:
+		break;
+	case S6SY761_TS_RELEASE:
+		s6sy761_report_release(sdata, event, tid);
+		break;
+	case S6SY761_TS_PRESS:
+	case S6SY761_TS_MOVE:
+		s6sy761_report_coordinates(sdata, event, tid);
+		break;
+	}
+}
+
+static void s6sy761_handle_events(struct s6sy761_data *sdata, u8 n_events)
+{
+	int i;
+
+	for (i = 0; i < n_events; i++) {
+		u8 *event = &sdata->data[i * S6SY761_EVENT_SIZE];
+		u8 event_id = event[0] & S6SY761_MASK_EID;
+
+		if (!event[0])
+			return;
+
+		switch (event_id) {
+
+		case S6SY761_EVENT_ID_COORDINATE:
+			s6sy761_handle_coordinates(sdata, event);
+			break;
+
+		case S6SY761_EVENT_ID_STATUS:
+			break;
+
+		default:
+			break;
+		}
+	}
+}
+
+static irqreturn_t s6sy761_irq_handler(int irq, void *dev)
+{
+	struct s6sy761_data *sdata = dev;
+	int ret;
+	u8 n_events;
+
+	ret = i2c_smbus_read_i2c_block_data(sdata->client,
+					    S6SY761_READ_ONE_EVENT,
+					    S6SY761_EVENT_SIZE,
+					    sdata->data);
+	if (ret < 0) {
+		dev_err(&sdata->client->dev, "failed to read events\n");
+		return IRQ_HANDLED;
+	}
+
+	if (!sdata->data[0])
+		return IRQ_HANDLED;
+
+	n_events = sdata->data[7] & S6SY761_MASK_LEFT_EVENTS;
+	if (unlikely(n_events > S6SY761_EVENT_COUNT - 1))
+		return IRQ_HANDLED;
+
+	if (n_events) {
+		ret = s6sy761_read_events(sdata, n_events);
+		if (ret < 0) {
+			dev_err(&sdata->client->dev, "failed to read events\n");
+			return IRQ_HANDLED;
+		}
+	}
+
+	s6sy761_handle_events(sdata, n_events +  1);
+
+	return IRQ_HANDLED;
+}
+
+static int s6sy761_input_open(struct input_dev *dev)
+{
+	struct s6sy761_data *sdata = input_get_drvdata(dev);
+
+	return i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_ON);
+}
+
+static void s6sy761_input_close(struct input_dev *dev)
+{
+	struct s6sy761_data *sdata = input_get_drvdata(dev);
+	int ret;
+
+	ret = i2c_smbus_write_byte(sdata->client, S6SY761_SENSE_OFF);
+	if (ret)
+		dev_err(&sdata->client->dev, "failed to turn off sensing\n");
+}
+
+static ssize_t s6sy761_sysfs_devid(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct s6sy761_data *sdata = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%#x\n", sdata->devid);
+}
+
+static DEVICE_ATTR(devid, 0444, s6sy761_sysfs_devid, NULL);
+
+static struct attribute *s6sy761_sysfs_attrs[] = {
+	&dev_attr_devid.attr,
+	NULL
+};
+
+static struct attribute_group s6sy761_attribute_group = {
+	.attrs = s6sy761_sysfs_attrs
+};
+
+static int s6sy761_power_on(struct s6sy761_data *sdata)
+{
+	u8 buffer[S6SY761_EVENT_SIZE];
+	u8 event;
+	int ret;
+
+	ret = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
+				    sdata->regulators);
+	if (ret)
+		return ret;
+
+	msleep(140);
+
+	/* double check whether the touch is functional */
+	ret = i2c_smbus_read_i2c_block_data(sdata->client,
+					    S6SY761_READ_ONE_EVENT,
+					    S6SY761_EVENT_SIZE,
+					    buffer);
+	if (ret < 0)
+		return ret;
+
+	event = (buffer[0] >> 2) & 0xf;
+
+	if ((event != S6SY761_EVENT_INFO &&
+	     event != S6SY761_EVENT_VENDOR_INFO) ||
+	    buffer[1] != S6SY761_INFO_BOOT_COMPLETE) {
+		return -ENODEV;
+	}
+
+	ret = i2c_smbus_read_byte_data(sdata->client, S6SY761_BOOT_STATUS);
+	if (ret < 0)
+		return ret;
+
+	/* for some reasons the device might be stuck in the bootloader */
+	if (ret != S6SY761_BS_APPLICATION)
+		return -ENODEV;
+
+	/* enable touch functionality */
+	ret = i2c_smbus_write_word_data(sdata->client,
+					S6SY761_TOUCH_FUNCTION,
+					S6SY761_MASK_TOUCH);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int s6sy761_hw_init(struct s6sy761_data *sdata,
+			   unsigned int *max_x, unsigned int *max_y)
+{
+	u8 buffer[S6SY761_PANEL_ID_SIZE]; /* larger read size */
+	int ret;
+
+	ret = s6sy761_power_on(sdata);
+	if (ret)
+		return ret;
+
+	ret = i2c_smbus_read_i2c_block_data(sdata->client,
+					    S6SY761_DEVICE_ID,
+					    S6SY761_DEVID_SIZE,
+					    buffer);
+	if (ret < 0)
+		return ret;
+
+	sdata->devid = get_unaligned_be16(buffer + 1);
+
+	ret = i2c_smbus_read_i2c_block_data(sdata->client,
+					    S6SY761_PANEL_INFO,
+					    S6SY761_PANEL_ID_SIZE,
+					    buffer);
+	if (ret < 0)
+		return ret;
+
+	*max_x = get_unaligned_be16(buffer);
+	*max_y = get_unaligned_be16(buffer + 2);
+
+	/* if no tx channels defined, at least keep one */
+	sdata->tx_channel = max_t(u8, buffer[8], 1);
+
+	ret = i2c_smbus_read_byte_data(sdata->client,
+				       S6SY761_FIRMWARE_INTEGRITY);
+	if (ret < 0)
+		return ret;
+	else if (ret != S6SY761_FW_OK)
+		return -ENODEV;
+
+	return 0;
+}
+
+static void s6sy761_power_off(void *data)
+{
+	struct s6sy761_data *sdata = data;
+
+	disable_irq(sdata->client->irq);
+	regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
+						sdata->regulators);
+}
+
+static int s6sy761_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct s6sy761_data *sdata;
+	unsigned int max_x, max_y;
+	int err;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+						I2C_FUNC_SMBUS_BYTE_DATA |
+						I2C_FUNC_SMBUS_I2C_BLOCK))
+		return -ENODEV;
+
+	sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
+	if (!sdata)
+		return -ENOMEM;
+
+	i2c_set_clientdata(client, sdata);
+	sdata->client = client;
+
+	sdata->regulators[S6SY761_REGULATOR_VDD].supply = "vdd";
+	sdata->regulators[S6SY761_REGULATOR_AVDD].supply = "avdd";
+	err = devm_regulator_bulk_get(&client->dev,
+				      ARRAY_SIZE(sdata->regulators),
+				      sdata->regulators);
+	if (err)
+		return err;
+
+	err = devm_add_action_or_reset(&client->dev, s6sy761_power_off, sdata);
+	if (err)
+		return err;
+
+	err = s6sy761_hw_init(sdata, &max_x, &max_y);
+	if (err)
+		return err;
+
+	sdata->input = devm_input_allocate_device(&client->dev);
+	if (!sdata->input)
+		return -ENOMEM;
+
+	sdata->input->name = S6SY761_DEV_NAME;
+	sdata->input->id.bustype = BUS_I2C;
+	sdata->input->open = s6sy761_input_open;
+	sdata->input->close = s6sy761_input_close;
+
+	input_set_abs_params(sdata->input, ABS_MT_POSITION_X, 0, max_x, 0, 0);
+	input_set_abs_params(sdata->input, ABS_MT_POSITION_Y, 0, max_y, 0, 0);
+	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
+	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+	input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
+	input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+
+	touchscreen_parse_properties(sdata->input, true, &sdata->prop);
+
+	if (!input_abs_get_max(sdata->input, ABS_X) ||
+	    !input_abs_get_max(sdata->input, ABS_Y)) {
+		dev_warn(&client->dev, "the axis have not been set\n");
+	}
+
+	err = input_mt_init_slots(sdata->input, sdata->tx_channel,
+				  INPUT_MT_DIRECT);
+	if (err)
+		return err;
+
+	input_set_drvdata(sdata->input, sdata);
+
+	err = input_register_device(sdata->input);
+	if (err)
+		return err;
+
+	err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+					s6sy761_irq_handler,
+					IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+					"s6sy761_irq", sdata);
+	if (err)
+		return err;
+
+	err = devm_device_add_group(&client->dev, &s6sy761_attribute_group);
+	if (err)
+		return err;
+
+	pm_runtime_enable(&client->dev);
+
+	return 0;
+}
+
+static int s6sy761_remove(struct i2c_client *client)
+{
+	pm_runtime_disable(&client->dev);
+
+	return 0;
+}
+
+static int __maybe_unused s6sy761_runtime_suspend(struct device *dev)
+{
+	struct s6sy761_data *sdata = dev_get_drvdata(dev);
+
+	return i2c_smbus_write_byte_data(sdata->client,
+				S6SY761_APPLICATION_MODE, S6SY761_APP_SLEEP);
+}
+
+static int __maybe_unused s6sy761_runtime_resume(struct device *dev)
+{
+	struct s6sy761_data *sdata = dev_get_drvdata(dev);
+
+	return i2c_smbus_write_byte_data(sdata->client,
+				S6SY761_APPLICATION_MODE, S6SY761_APP_NORMAL);
+}
+
+static int __maybe_unused s6sy761_suspend(struct device *dev)
+{
+	struct s6sy761_data *sdata = dev_get_drvdata(dev);
+
+	s6sy761_power_off(sdata);
+
+	return 0;
+}
+
+static int __maybe_unused s6sy761_resume(struct device *dev)
+{
+	struct s6sy761_data *sdata = dev_get_drvdata(dev);
+
+	enable_irq(sdata->client->irq);
+
+	return s6sy761_power_on(sdata);
+}
+
+static const struct dev_pm_ops s6sy761_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(s6sy761_suspend, s6sy761_resume)
+	SET_RUNTIME_PM_OPS(s6sy761_runtime_suspend,
+				s6sy761_runtime_resume, NULL)
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id s6sy761_of_match[] = {
+	{ .compatible = "samsung,s6sy761", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, s6sy761_of_match);
+#endif
+
+static const struct i2c_device_id s6sy761_id[] = {
+	{ "s6sy761", 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, s6sy761_id);
+
+static struct i2c_driver s6sy761_driver = {
+	.driver = {
+		.name = S6SY761_DEV_NAME,
+		.of_match_table = of_match_ptr(s6sy761_of_match),
+		.pm = &s6sy761_pm_ops,
+	},
+	.probe = s6sy761_probe,
+	.remove = s6sy761_remove,
+	.id_table = s6sy761_id,
+};
+
+module_i2c_driver(s6sy761_driver);
+
+MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
+MODULE_DESCRIPTION("Samsung S6SY761 Touch Screen");
+MODULE_LICENSE("GPL v2");

+ 3 - 13
drivers/input/touchscreen/st1232.c

@@ -29,7 +29,6 @@
 #include <linux/pm_qos.h>
 #include <linux/pm_qos.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/types.h>
-#include <linux/platform_data/st1232_pdata.h>
 
 
 #define ST1232_TS_NAME	"st1232-ts"
 #define ST1232_TS_NAME	"st1232-ts"
 
 
@@ -152,10 +151,9 @@ static void st1232_ts_power(struct st1232_ts_data *ts, bool poweron)
 }
 }
 
 
 static int st1232_ts_probe(struct i2c_client *client,
 static int st1232_ts_probe(struct i2c_client *client,
-					const struct i2c_device_id *id)
+			   const struct i2c_device_id *id)
 {
 {
 	struct st1232_ts_data *ts;
 	struct st1232_ts_data *ts;
-	struct st1232_pdata *pdata = dev_get_platdata(&client->dev);
 	struct input_dev *input_dev;
 	struct input_dev *input_dev;
 	int error;
 	int error;
 
 
@@ -180,13 +178,7 @@ static int st1232_ts_probe(struct i2c_client *client,
 	ts->client = client;
 	ts->client = client;
 	ts->input_dev = input_dev;
 	ts->input_dev = input_dev;
 
 
-	if (pdata)
-		ts->reset_gpio = pdata->reset_gpio;
-	else if (client->dev.of_node)
-		ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
-	else
-		ts->reset_gpio = -ENODEV;
-
+	ts->reset_gpio = of_get_gpio(client->dev.of_node, 0);
 	if (gpio_is_valid(ts->reset_gpio)) {
 	if (gpio_is_valid(ts->reset_gpio)) {
 		error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
 		error = devm_gpio_request(&client->dev, ts->reset_gpio, NULL);
 		if (error) {
 		if (error) {
@@ -281,13 +273,11 @@ static const struct i2c_device_id st1232_ts_id[] = {
 };
 };
 MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
 MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
 
 
-#ifdef CONFIG_OF
 static const struct of_device_id st1232_ts_dt_ids[] = {
 static const struct of_device_id st1232_ts_dt_ids[] = {
 	{ .compatible = "sitronix,st1232", },
 	{ .compatible = "sitronix,st1232", },
 	{ }
 	{ }
 };
 };
 MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
 MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids);
-#endif
 
 
 static struct i2c_driver st1232_ts_driver = {
 static struct i2c_driver st1232_ts_driver = {
 	.probe		= st1232_ts_probe,
 	.probe		= st1232_ts_probe,
@@ -295,7 +285,7 @@ static struct i2c_driver st1232_ts_driver = {
 	.id_table	= st1232_ts_id,
 	.id_table	= st1232_ts_id,
 	.driver = {
 	.driver = {
 		.name	= ST1232_TS_NAME,
 		.name	= ST1232_TS_NAME,
-		.of_match_table = of_match_ptr(st1232_ts_dt_ids),
+		.of_match_table = st1232_ts_dt_ids,
 		.pm	= &st1232_ts_pm_ops,
 		.pm	= &st1232_ts_pm_ops,
 	},
 	},
 };
 };

+ 1 - 3
drivers/input/touchscreen/stmfts.c

@@ -725,8 +725,7 @@ static int stmfts_probe(struct i2c_client *client,
 		}
 		}
 	}
 	}
 
 
-	err = sysfs_create_group(&sdata->client->dev.kobj,
-				 &stmfts_attribute_group);
+	err = devm_device_add_group(&client->dev, &stmfts_attribute_group);
 	if (err)
 	if (err)
 		return err;
 		return err;
 
 
@@ -738,7 +737,6 @@ static int stmfts_probe(struct i2c_client *client,
 static int stmfts_remove(struct i2c_client *client)
 static int stmfts_remove(struct i2c_client *client)
 {
 {
 	pm_runtime_disable(&client->dev);
 	pm_runtime_disable(&client->dev);
-	sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group);
 
 
 	return 0;
 	return 0;
 }
 }

+ 3 - 3
drivers/input/touchscreen/tsc200x-core.c

@@ -202,9 +202,9 @@ out:
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static void tsc200x_penup_timer(unsigned long data)
+static void tsc200x_penup_timer(struct timer_list *t)
 {
 {
-	struct tsc200x *ts = (struct tsc200x *)data;
+	struct tsc200x *ts = from_timer(ts, t, penup_timer);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&ts->lock, flags);
 	spin_lock_irqsave(&ts->lock, flags);
@@ -506,7 +506,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
 	mutex_init(&ts->mutex);
 	mutex_init(&ts->mutex);
 
 
 	spin_lock_init(&ts->lock);
 	spin_lock_init(&ts->lock);
-	setup_timer(&ts->penup_timer, tsc200x_penup_timer, (unsigned long)ts);
+	timer_setup(&ts->penup_timer, tsc200x_penup_timer, 0);
 
 
 	INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);
 	INIT_DELAYED_WORK(&ts->esd_work, tsc200x_esd_work);
 
 

+ 3 - 4
drivers/input/touchscreen/w90p910_ts.c

@@ -146,9 +146,9 @@ static irqreturn_t w90p910_ts_interrupt(int irq, void *dev_id)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-static void w90p910_check_pen_up(unsigned long data)
+static void w90p910_check_pen_up(struct timer_list *t)
 {
 {
-	struct w90p910_ts *w90p910_ts = (struct w90p910_ts *) data;
+	struct w90p910_ts *w90p910_ts = from_timer(w90p910_ts, t, timer);
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&w90p910_ts->lock, flags);
 	spin_lock_irqsave(&w90p910_ts->lock, flags);
@@ -232,8 +232,7 @@ static int w90x900ts_probe(struct platform_device *pdev)
 	w90p910_ts->input = input_dev;
 	w90p910_ts->input = input_dev;
 	w90p910_ts->state = TS_IDLE;
 	w90p910_ts->state = TS_IDLE;
 	spin_lock_init(&w90p910_ts->lock);
 	spin_lock_init(&w90p910_ts->lock);
-	setup_timer(&w90p910_ts->timer, w90p910_check_pen_up,
-		    (unsigned long)w90p910_ts);
+	timer_setup(&w90p910_ts->timer, w90p910_check_pen_up, 0);
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 	if (!res) {

+ 1 - 9
drivers/input/touchscreen/wdt87xx_i2c.c

@@ -1106,7 +1106,7 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
 		return error;
 		return error;
 	}
 	}
 
 
-	error = sysfs_create_group(&client->dev.kobj, &wdt87xx_attr_group);
+	error = devm_device_add_group(&client->dev, &wdt87xx_attr_group);
 	if (error) {
 	if (error) {
 		dev_err(&client->dev, "create sysfs failed: %d\n", error);
 		dev_err(&client->dev, "create sysfs failed: %d\n", error);
 		return error;
 		return error;
@@ -1115,13 +1115,6 @@ static int wdt87xx_ts_probe(struct i2c_client *client,
 	return 0;
 	return 0;
 }
 }
 
 
-static int wdt87xx_ts_remove(struct i2c_client *client)
-{
-	sysfs_remove_group(&client->dev.kobj, &wdt87xx_attr_group);
-
-	return 0;
-}
-
 static int __maybe_unused wdt87xx_suspend(struct device *dev)
 static int __maybe_unused wdt87xx_suspend(struct device *dev)
 {
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct i2c_client *client = to_i2c_client(dev);
@@ -1179,7 +1172,6 @@ MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
 
 
 static struct i2c_driver wdt87xx_driver = {
 static struct i2c_driver wdt87xx_driver = {
 	.probe		= wdt87xx_ts_probe,
 	.probe		= wdt87xx_ts_probe,
-	.remove		= wdt87xx_ts_remove,
 	.id_table	= wdt87xx_dev_id,
 	.id_table	= wdt87xx_dev_id,
 	.driver	= {
 	.driver	= {
 		.name	= WDT87XX_NAME,
 		.name	= WDT87XX_NAME,

+ 1 - 1
drivers/media/pci/ttpci/av7110.h

@@ -94,7 +94,7 @@ struct infrared {
 	u8			inversion;
 	u8			inversion;
 	u16			last_key;
 	u16			last_key;
 	u16			last_toggle;
 	u16			last_toggle;
-	u8			delay_timer_finished;
+	bool			keypressed;
 };
 };
 
 
 
 

+ 20 - 36
drivers/media/pci/ttpci/av7110_ir.c

@@ -84,15 +84,16 @@ static u16 default_key_map [256] = {
 
 
 
 
 /* key-up timer */
 /* key-up timer */
-static void av7110_emit_keyup(unsigned long parm)
+static void av7110_emit_keyup(struct timer_list *t)
 {
 {
-	struct infrared *ir = (struct infrared *) parm;
+	struct infrared *ir = from_timer(ir, t, keyup_timer);
 
 
-	if (!ir || !test_bit(ir->last_key, ir->input_dev->key))
+	if (!ir || !ir->keypressed)
 		return;
 		return;
 
 
 	input_report_key(ir->input_dev, ir->last_key, 0);
 	input_report_key(ir->input_dev, ir->last_key, 0);
 	input_sync(ir->input_dev);
 	input_sync(ir->input_dev);
+	ir->keypressed = false;
 }
 }
 
 
 
 
@@ -152,29 +153,18 @@ static void av7110_emit_key(unsigned long parm)
 		return;
 		return;
 	}
 	}
 
 
-	if (timer_pending(&ir->keyup_timer)) {
-		del_timer(&ir->keyup_timer);
-		if (ir->last_key != keycode || toggle != ir->last_toggle) {
-			ir->delay_timer_finished = 0;
-			input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
-			input_event(ir->input_dev, EV_KEY, keycode, 1);
-			input_sync(ir->input_dev);
-		} else if (ir->delay_timer_finished) {
-			input_event(ir->input_dev, EV_KEY, keycode, 2);
-			input_sync(ir->input_dev);
-		}
-	} else {
-		ir->delay_timer_finished = 0;
-		input_event(ir->input_dev, EV_KEY, keycode, 1);
-		input_sync(ir->input_dev);
-	}
+	if (ir->keypressed &&
+	    (ir->last_key != keycode || toggle != ir->last_toggle))
+		input_event(ir->input_dev, EV_KEY, ir->last_key, 0);
 
 
+	input_event(ir->input_dev, EV_KEY, keycode, 1);
+	input_sync(ir->input_dev);
+
+	ir->keypressed = true;
 	ir->last_key = keycode;
 	ir->last_key = keycode;
 	ir->last_toggle = toggle;
 	ir->last_toggle = toggle;
 
 
-	ir->keyup_timer.expires = jiffies + UP_TIMEOUT;
-	add_timer(&ir->keyup_timer);
-
+	mod_timer(&ir->keyup_timer, jiffies + UP_TIMEOUT);
 }
 }
 
 
 
 
@@ -204,16 +194,6 @@ static void input_register_keys(struct infrared *ir)
 	ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
 	ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map);
 }
 }
 
 
-
-/* called by the input driver after rep[REP_DELAY] ms */
-static void input_repeat_key(unsigned long parm)
-{
-	struct infrared *ir = (struct infrared *) parm;
-
-	ir->delay_timer_finished = 1;
-}
-
-
 /* check for configuration changes */
 /* check for configuration changes */
 int av7110_check_ir_config(struct av7110 *av7110, int force)
 int av7110_check_ir_config(struct av7110 *av7110, int force)
 {
 {
@@ -333,8 +313,7 @@ int av7110_ir_init(struct av7110 *av7110)
 	av_list[av_cnt++] = av7110;
 	av_list[av_cnt++] = av7110;
 	av7110_check_ir_config(av7110, true);
 	av7110_check_ir_config(av7110, true);
 
 
-	setup_timer(&av7110->ir.keyup_timer, av7110_emit_keyup,
-		    (unsigned long)&av7110->ir);
+	timer_setup(&av7110->ir.keyup_timer, av7110_emit_keyup, 0);
 
 
 	input_dev = input_allocate_device();
 	input_dev = input_allocate_device();
 	if (!input_dev)
 	if (!input_dev)
@@ -365,8 +344,13 @@ int av7110_ir_init(struct av7110 *av7110)
 		input_free_device(input_dev);
 		input_free_device(input_dev);
 		return err;
 		return err;
 	}
 	}
-	input_dev->timer.function = input_repeat_key;
-	input_dev->timer.data = (unsigned long) &av7110->ir;
+
+	/*
+	 * Input core's default autorepeat is 33 cps with 250 msec
+	 * delay, let's adjust to numbers more suitable for remote
+	 * control.
+	 */
+	input_enable_softrepeat(input_dev, 250, 125);
 
 
 	if (av_cnt == 1) {
 	if (av_cnt == 1) {
 		e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);
 		e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops);

+ 0 - 61
include/linux/gpio_mouse.h

@@ -1,61 +0,0 @@
-/*
- * Driver for simulating a mouse on GPIO lines.
- *
- * Copyright (C) 2007 Atmel Corporation
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#ifndef _GPIO_MOUSE_H
-#define _GPIO_MOUSE_H
-
-#define GPIO_MOUSE_POLARITY_ACT_HIGH	0x00
-#define GPIO_MOUSE_POLARITY_ACT_LOW	0x01
-
-#define GPIO_MOUSE_PIN_UP	0
-#define GPIO_MOUSE_PIN_DOWN	1
-#define GPIO_MOUSE_PIN_LEFT	2
-#define GPIO_MOUSE_PIN_RIGHT	3
-#define GPIO_MOUSE_PIN_BLEFT	4
-#define GPIO_MOUSE_PIN_BMIDDLE	5
-#define GPIO_MOUSE_PIN_BRIGHT	6
-#define GPIO_MOUSE_PIN_MAX	7
-
-/**
- * struct gpio_mouse_platform_data
- * @scan_ms: integer in ms specifying the scan periode.
- * @polarity: Pin polarity, active high or low.
- * @up: GPIO line for up value.
- * @down: GPIO line for down value.
- * @left: GPIO line for left value.
- * @right: GPIO line for right value.
- * @bleft: GPIO line for left button.
- * @bmiddle: GPIO line for middle button.
- * @bright: GPIO line for right button.
- *
- * This struct must be added to the platform_device in the board code.
- * It is used by the gpio_mouse driver to setup GPIO lines and to
- * calculate mouse movement.
- */
-struct gpio_mouse_platform_data {
-	int scan_ms;
-	int polarity;
-
-	union {
-		struct {
-			int up;
-			int down;
-			int left;
-			int right;
-
-			int bleft;
-			int bmiddle;
-			int bright;
-		};
-		int pins[GPIO_MOUSE_PIN_MAX];
-	};
-};
-
-#endif /* _GPIO_MOUSE_H */

+ 0 - 14
include/linux/platform_data/st1232_pdata.h

@@ -1,14 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _LINUX_ST1232_PDATA_H
-#define _LINUX_ST1232_PDATA_H
-
-/*
- * Optional platform data
- *
- * Use this if you want the driver to drive the reset pin.
- */
-struct st1232_pdata {
-	int reset_gpio;
-};
-
-#endif

+ 0 - 81
include/linux/uinput.h

@@ -1,81 +0,0 @@
-/*
- *  User level driver support for input subsystem
- *
- * Heavily based on evdev.c by Vojtech Pavlik
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
- *
- * Changes/Revisions:
- *	0.5	08/13/2015 (David Herrmann <dh.herrmann@gmail.com> &
- *			    Benjamin Tissoires <benjamin.tissoires@redhat.com>)
- *		- add UI_DEV_SETUP ioctl
- *		- add UI_ABS_SETUP ioctl
- *		- add UI_GET_VERSION ioctl
- *	0.4	01/09/2014 (Benjamin Tissoires <benjamin.tissoires@redhat.com>)
- *		- add UI_GET_SYSNAME ioctl
- *	0.3	24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
- *		- update ff support for the changes in kernel interface
- *		- add UINPUT_VERSION
- *	0.2	16/10/2004 (Micah Dowty <micah@navi.cx>)
- *		- added force feedback support
- *             - added UI_SET_PHYS
- *	0.1	20/06/2002
- *		- first public version
- */
-#ifndef __UINPUT_H_
-#define __UINPUT_H_
-
-#include <uapi/linux/uinput.h>
-
-#define UINPUT_NAME		"uinput"
-#define UINPUT_BUFFER_SIZE	16
-#define UINPUT_NUM_REQUESTS	16
-
-enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
-
-struct uinput_request {
-	unsigned int		id;
-	unsigned int		code;	/* UI_FF_UPLOAD, UI_FF_ERASE */
-
-	int			retval;
-	struct completion	done;
-
-	union {
-		unsigned int	effect_id;
-		struct {
-			struct ff_effect *effect;
-			struct ff_effect *old;
-		} upload;
-	} u;
-};
-
-struct uinput_device {
-	struct input_dev	*dev;
-	struct mutex		mutex;
-	enum uinput_state	state;
-	wait_queue_head_t	waitq;
-	unsigned char		ready;
-	unsigned char		head;
-	unsigned char		tail;
-	struct input_event	buff[UINPUT_BUFFER_SIZE];
-	unsigned int		ff_effects_max;
-
-	struct uinput_request	*requests[UINPUT_NUM_REQUESTS];
-	wait_queue_head_t	requests_waitq;
-	spinlock_t		requests_lock;
-};
-#endif	/* __UINPUT_H_ */