Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov:
 "Two new touchpad drivers - Cypress APA I2C Trackpad and Cypress PS/2
  touchpad and a big update to ALPS driver from Kevin Cernekee that adds
  support for "Rushmore" touchpads and paves way for adding support for
  "Dolphin" touchpads.
  There is also a new input driver for Goldfish emulator and also
  Android keyreset driver was folded into SysRq code.
  A few more drivers were updated with device tree bindings and others
  got some small cleanups and fixes."
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (55 commits)
  Input: cyttsp-spi - remove duplicate MODULE_ALIAS()
  Input: tsc2005 - add MODULE_ALIAS
  Input: tegra-kbc - require CONFIG_OF, remove platform data
  Input: synaptics - initialize pointer emulation usage
  Input: MT - do not apply filtering on emulated events
  Input: bma150 - make some defines public and fix some comments
  Input: bma150 - fix checking pm_runtime_get_sync() return value
  Input: ALPS - enable trackstick on Rushmore touchpads
  Input: ALPS - add support for "Rushmore" touchpads
  Input: ALPS - make the V3 packet field decoder "pluggable"
  Input: ALPS - move pixel and bitmap info into alps_data struct
  Input: ALPS - fix command mode check
  Input: ALPS - rework detection of Pinnacle AGx touchpads
  Input: ALPS - move {addr,nibble}_command settings into alps_set_defaults()
  Input: ALPS - use function pointers for different protocol handlers
  Input: ALPS - rework detection sequence
  Input: ALPS - introduce helper function for repeated commands
  Input: ALPS - move alps_get_model() down below hw_init code
  Input: ALPS - copy "model" info into alps_data struct
  Input: ALPS - document the alps.h data structures
  ...
	
	
This commit is contained in:
		
				commit
				
					
						c6699b58f4
					
				
			
		
					 41 changed files with 3627 additions and 1201 deletions
				
			
		
							
								
								
									
										53
									
								
								Documentation/devicetree/bindings/input/imx-keypad.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Documentation/devicetree/bindings/input/imx-keypad.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,53 @@
 | 
			
		|||
* Freescale i.MX Keypad Port(KPP) device tree bindings
 | 
			
		||||
 | 
			
		||||
The KPP is designed to interface with a keypad matrix with 2-point contact
 | 
			
		||||
or 3-point contact keys. The KPP is designed to simplify the software task
 | 
			
		||||
of scanning a keypad matrix. The KPP is capable of detecting, debouncing,
 | 
			
		||||
and decoding one or multiple keys pressed simultaneously on a keypad.
 | 
			
		||||
 | 
			
		||||
Required SoC Specific Properties:
 | 
			
		||||
- compatible: Should be "fsl,<soc>-kpp".
 | 
			
		||||
 | 
			
		||||
- reg: Physical base address of the KPP and length of memory mapped
 | 
			
		||||
  region.
 | 
			
		||||
 | 
			
		||||
- interrupts: The KPP interrupt number to the CPU(s).
 | 
			
		||||
 | 
			
		||||
- clocks: The clock provided by the SoC to the KPP. Some SoCs use dummy
 | 
			
		||||
clock(The clock for the KPP is provided by the SoCs automatically).
 | 
			
		||||
 | 
			
		||||
Required Board Specific Properties:
 | 
			
		||||
- pinctrl-names: The definition can be found at
 | 
			
		||||
pinctrl/pinctrl-bindings.txt.
 | 
			
		||||
 | 
			
		||||
- pinctrl-0: The definition can be found at
 | 
			
		||||
pinctrl/pinctrl-bindings.txt.
 | 
			
		||||
 | 
			
		||||
- linux,keymap: The definition can be found at
 | 
			
		||||
bindings/input/matrix-keymap.txt.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
kpp: kpp@73f94000 {
 | 
			
		||||
	compatible = "fsl,imx51-kpp", "fsl,imx21-kpp";
 | 
			
		||||
	reg = <0x73f94000 0x4000>;
 | 
			
		||||
	interrupts = <60>;
 | 
			
		||||
	clocks = <&clks 0>;
 | 
			
		||||
	pinctrl-names = "default";
 | 
			
		||||
	pinctrl-0 = <&pinctrl_kpp_1>;
 | 
			
		||||
	linux,keymap = <0x00000067	/* KEY_UP */
 | 
			
		||||
			0x0001006c	/* KEY_DOWN */
 | 
			
		||||
			0x00020072	/* KEY_VOLUMEDOWN */
 | 
			
		||||
			0x00030066	/* KEY_HOME */
 | 
			
		||||
			0x0100006a	/* KEY_RIGHT */
 | 
			
		||||
			0x01010069	/* KEY_LEFT */
 | 
			
		||||
			0x0102001c	/* KEY_ENTER */
 | 
			
		||||
			0x01030073	/* KEY_VOLUMEUP */
 | 
			
		||||
			0x02000040	/* KEY_F6 */
 | 
			
		||||
			0x02010042	/* KEY_F8 */
 | 
			
		||||
			0x02020043	/* KEY_F9 */
 | 
			
		||||
			0x02030044	/* KEY_F10 */
 | 
			
		||||
			0x0300003b	/* KEY_F1 */
 | 
			
		||||
			0x0301003c	/* KEY_F2 */
 | 
			
		||||
			0x0302003d	/* KEY_F3 */
 | 
			
		||||
			0x03030074>;	/* KEY_POWER */
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +1,18 @@
 | 
			
		|||
* Tegra keyboard controller
 | 
			
		||||
The key controller has maximum 24 pins to make matrix keypad. Any pin
 | 
			
		||||
can be configured as row or column. The maximum column pin can be 8
 | 
			
		||||
and maximum row pins can be 16 for Tegra20/Tegra30.
 | 
			
		||||
 | 
			
		||||
Required properties:
 | 
			
		||||
- compatible: "nvidia,tegra20-kbc"
 | 
			
		||||
- reg: Register base address of KBC.
 | 
			
		||||
- interrupts: Interrupt number for the KBC.
 | 
			
		||||
- nvidia,kbc-row-pins: The KBC pins which are configured as row. This is an
 | 
			
		||||
  array of pin numbers which is used as rows.
 | 
			
		||||
- nvidia,kbc-col-pins: The KBC pins which are configured as column. This is an
 | 
			
		||||
  array of pin numbers which is used as column.
 | 
			
		||||
- linux,keymap: The keymap for keys as described in the binding document
 | 
			
		||||
  devicetree/bindings/input/matrix-keymap.txt.
 | 
			
		||||
 | 
			
		||||
Optional properties, in addition to those specified by the shared
 | 
			
		||||
matrix-keyboard bindings:
 | 
			
		||||
| 
						 | 
				
			
			@ -19,5 +30,16 @@ Example:
 | 
			
		|||
keyboard: keyboard {
 | 
			
		||||
	compatible = "nvidia,tegra20-kbc";
 | 
			
		||||
	reg = <0x7000e200 0x100>;
 | 
			
		||||
	interrupts = <0 85 0x04>;
 | 
			
		||||
	nvidia,ghost-filter;
 | 
			
		||||
	nvidia,debounce-delay-ms = <640>;
 | 
			
		||||
	nvidia,kbc-row-pins = <0 1 2>;    /* pin 0, 1, 2 as rows */
 | 
			
		||||
	nvidia,kbc-col-pins = <11 12 13>; /* pin 11, 12, 13 as columns */
 | 
			
		||||
	linux,keymap = <0x00000074
 | 
			
		||||
			0x00010067
 | 
			
		||||
			0x00020066
 | 
			
		||||
			0x01010068
 | 
			
		||||
			0x02000069
 | 
			
		||||
			0x02010070
 | 
			
		||||
			0x02020071>;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,7 +3,7 @@
 | 
			
		|||
#
 | 
			
		||||
 | 
			
		||||
menu "Input device support"
 | 
			
		||||
	depends on !S390 && !UML
 | 
			
		||||
	depends on !UML
 | 
			
		||||
 | 
			
		||||
config INPUT
 | 
			
		||||
	tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,6 +18,7 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
 | 
			
		|||
{
 | 
			
		||||
	if (dev->absinfo && test_bit(src, dev->absbit)) {
 | 
			
		||||
		dev->absinfo[dst] = dev->absinfo[src];
 | 
			
		||||
		dev->absinfo[dst].fuzz = 0;
 | 
			
		||||
		dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@
 | 
			
		|||
 * the Free Software Foundation.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
/* #define WK0701_DEBUG */
 | 
			
		||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 | 
			
		||||
 | 
			
		||||
#define RESERVE 20000
 | 
			
		||||
#define SYNC_PULSE 1306000
 | 
			
		||||
| 
						 | 
				
			
			@ -67,6 +67,7 @@ static inline void walkera0701_parse_frame(struct walkera_dev *w)
 | 
			
		|||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int val1, val2, val3, val4, val5, val6, val7, val8;
 | 
			
		||||
	int magic, magic_bit;
 | 
			
		||||
	int crc1, crc2;
 | 
			
		||||
 | 
			
		||||
	for (crc1 = crc2 = i = 0; i < 10; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -102,17 +103,12 @@ static inline void walkera0701_parse_frame(struct walkera_dev *w)
 | 
			
		|||
	val8 = (w->buf[18] & 1) << 8 | (w->buf[19] << 4) | w->buf[20];
 | 
			
		||||
	val8 *= (w->buf[18] & 2) - 1;	/*sign */
 | 
			
		||||
 | 
			
		||||
#ifdef WK0701_DEBUG
 | 
			
		||||
	{
 | 
			
		||||
		int magic, magic_bit;
 | 
			
		||||
	magic = (w->buf[21] << 4) | w->buf[22];
 | 
			
		||||
	magic_bit = (w->buf[24] & 8) >> 3;
 | 
			
		||||
		printk(KERN_DEBUG
 | 
			
		||||
		       "walkera0701: %4d %4d %4d %4d  %4d %4d %4d %4d (magic %2x %d)\n",
 | 
			
		||||
		       val1, val2, val3, val4, val5, val6, val7, val8, magic,
 | 
			
		||||
		       magic_bit);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
	pr_debug("%4d %4d %4d %4d  %4d %4d %4d %4d (magic %2x %d)\n",
 | 
			
		||||
		 val1, val2, val3, val4, val5, val6, val7, val8,
 | 
			
		||||
		 magic, magic_bit);
 | 
			
		||||
 | 
			
		||||
	input_report_abs(w->input_dev, ABS_X, val2);
 | 
			
		||||
	input_report_abs(w->input_dev, ABS_Y, val1);
 | 
			
		||||
	input_report_abs(w->input_dev, ABS_Z, val6);
 | 
			
		||||
| 
						 | 
				
			
			@ -187,6 +183,9 @@ static int walkera0701_open(struct input_dev *dev)
 | 
			
		|||
{
 | 
			
		||||
	struct walkera_dev *w = input_get_drvdata(dev);
 | 
			
		||||
 | 
			
		||||
	if (parport_claim(w->pardevice))
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	parport_enable_irq(w->parport);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -197,40 +196,51 @@ static void walkera0701_close(struct input_dev *dev)
 | 
			
		|||
 | 
			
		||||
	parport_disable_irq(w->parport);
 | 
			
		||||
	hrtimer_cancel(&w->timer);
 | 
			
		||||
 | 
			
		||||
	parport_release(w->pardevice);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int walkera0701_connect(struct walkera_dev *w, int parport)
 | 
			
		||||
{
 | 
			
		||||
	int err = -ENODEV;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	w->parport = parport_find_number(parport);
 | 
			
		||||
	if (w->parport == NULL)
 | 
			
		||||
	if (!w->parport) {
 | 
			
		||||
		pr_err("parport %d does not exist\n", parport);
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (w->parport->irq == -1) {
 | 
			
		||||
		printk(KERN_ERR "walkera0701: parport without interrupt\n");
 | 
			
		||||
		goto init_err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err = -EBUSY;
 | 
			
		||||
	if (w->parport->irq == -1) {
 | 
			
		||||
		pr_err("parport %d does not have interrupt assigned\n",
 | 
			
		||||
			parport);
 | 
			
		||||
		error = -EINVAL;
 | 
			
		||||
		goto err_put_parport;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	w->pardevice = parport_register_device(w->parport, "walkera0701",
 | 
			
		||||
				    NULL, NULL, walkera0701_irq_handler,
 | 
			
		||||
				    PARPORT_DEV_EXCL, w);
 | 
			
		||||
	if (!w->pardevice)
 | 
			
		||||
		goto init_err;
 | 
			
		||||
	if (!w->pardevice) {
 | 
			
		||||
		pr_err("failed to register parport device\n");
 | 
			
		||||
		error = -EIO;
 | 
			
		||||
		goto err_put_parport;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT))
 | 
			
		||||
		goto init_err1;
 | 
			
		||||
 | 
			
		||||
	if (parport_claim(w->pardevice))
 | 
			
		||||
		goto init_err1;
 | 
			
		||||
	if (parport_negotiate(w->pardevice->port, IEEE1284_MODE_COMPAT)) {
 | 
			
		||||
		pr_err("failed to negotiate parport mode\n");
 | 
			
		||||
		error = -EIO;
 | 
			
		||||
		goto err_unregister_device;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
 | 
			
		||||
	w->timer.function = timer_handler;
 | 
			
		||||
 | 
			
		||||
	w->input_dev = input_allocate_device();
 | 
			
		||||
	if (!w->input_dev)
 | 
			
		||||
		goto init_err2;
 | 
			
		||||
	if (!w->input_dev) {
 | 
			
		||||
		pr_err("failed to allocate input device\n");
 | 
			
		||||
		error = -ENOMEM;
 | 
			
		||||
		goto err_unregister_device;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_set_drvdata(w->input_dev, w);
 | 
			
		||||
	w->input_dev->name = "Walkera WK-0701 TX";
 | 
			
		||||
| 
						 | 
				
			
			@ -241,6 +251,7 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
 | 
			
		|||
	w->input_dev->id.vendor = 0x0001;
 | 
			
		||||
	w->input_dev->id.product = 0x0001;
 | 
			
		||||
	w->input_dev->id.version = 0x0100;
 | 
			
		||||
	w->input_dev->dev.parent = w->parport->dev;
 | 
			
		||||
	w->input_dev->open = walkera0701_open;
 | 
			
		||||
	w->input_dev->close = walkera0701_close;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -254,27 +265,26 @@ static int walkera0701_connect(struct walkera_dev *w, int parport)
 | 
			
		|||
	input_set_abs_params(w->input_dev, ABS_RUDDER, -512, 512, 0, 0);
 | 
			
		||||
	input_set_abs_params(w->input_dev, ABS_MISC, -512, 512, 0, 0);
 | 
			
		||||
 | 
			
		||||
	err = input_register_device(w->input_dev);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto init_err3;
 | 
			
		||||
	error = input_register_device(w->input_dev);
 | 
			
		||||
	if (error) {
 | 
			
		||||
		pr_err("failed to register input device\n");
 | 
			
		||||
		goto err_free_input_dev;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
 init_err3:
 | 
			
		||||
err_free_input_dev:
 | 
			
		||||
	input_free_device(w->input_dev);
 | 
			
		||||
 init_err2:
 | 
			
		||||
	parport_release(w->pardevice);
 | 
			
		||||
 init_err1:
 | 
			
		||||
err_unregister_device:
 | 
			
		||||
	parport_unregister_device(w->pardevice);
 | 
			
		||||
 init_err:
 | 
			
		||||
err_put_parport:
 | 
			
		||||
	parport_put_port(w->parport);
 | 
			
		||||
	return err;
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void walkera0701_disconnect(struct walkera_dev *w)
 | 
			
		||||
{
 | 
			
		||||
	input_unregister_device(w->input_dev);
 | 
			
		||||
	parport_release(w->pardevice);
 | 
			
		||||
	parport_unregister_device(w->pardevice);
 | 
			
		||||
	parport_put_port(w->parport);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -224,7 +224,7 @@ config KEYBOARD_TCA6416
 | 
			
		|||
 | 
			
		||||
config KEYBOARD_TCA8418
 | 
			
		||||
	tristate "TCA8418 Keypad Support"
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	depends on I2C && GENERIC_HARDIRQS
 | 
			
		||||
	select INPUT_MATRIXKMAP
 | 
			
		||||
	help
 | 
			
		||||
	  This driver implements basic keypad functionality
 | 
			
		||||
| 
						 | 
				
			
			@ -303,7 +303,7 @@ config KEYBOARD_HP7XX
 | 
			
		|||
 | 
			
		||||
config KEYBOARD_LM8323
 | 
			
		||||
	tristate "LM8323 keypad chip"
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	depends on I2C && GENERIC_HARDIRQS
 | 
			
		||||
	depends on LEDS_CLASS
 | 
			
		||||
	help
 | 
			
		||||
	  If you say yes here you get support for the National Semiconductor
 | 
			
		||||
| 
						 | 
				
			
			@ -420,7 +420,7 @@ config KEYBOARD_NOMADIK
 | 
			
		|||
 | 
			
		||||
config KEYBOARD_TEGRA
 | 
			
		||||
	tristate "NVIDIA Tegra internal matrix keyboard controller support"
 | 
			
		||||
	depends on ARCH_TEGRA
 | 
			
		||||
	depends on ARCH_TEGRA && OF
 | 
			
		||||
	select INPUT_MATRIXKMAP
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here if you want to use a matrix keyboard connected directly
 | 
			
		||||
| 
						 | 
				
			
			@ -479,6 +479,16 @@ config KEYBOARD_SAMSUNG
 | 
			
		|||
	  To compile this driver as a module, choose M here: the
 | 
			
		||||
	  module will be called samsung-keypad.
 | 
			
		||||
 | 
			
		||||
config KEYBOARD_GOLDFISH_EVENTS
 | 
			
		||||
	depends on GOLDFISH
 | 
			
		||||
	tristate "Generic Input Event device for Goldfish"
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here to get an input event device for the Goldfish virtual
 | 
			
		||||
	  device emulator.
 | 
			
		||||
 | 
			
		||||
	  To compile this driver as a module, choose M here: the
 | 
			
		||||
	  module will be called goldfish-events.
 | 
			
		||||
 | 
			
		||||
config KEYBOARD_STOWAWAY
 | 
			
		||||
	tristate "Stowaway keyboard"
 | 
			
		||||
	select SERIO
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_ATKBD)		+= atkbd.o
 | 
			
		|||
obj-$(CONFIG_KEYBOARD_BFIN)		+= bf54x-keys.o
 | 
			
		||||
obj-$(CONFIG_KEYBOARD_DAVINCI)		+= davinci_keyscan.o
 | 
			
		||||
obj-$(CONFIG_KEYBOARD_EP93XX)		+= ep93xx_keypad.o
 | 
			
		||||
obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS)	+= goldfish_events.o
 | 
			
		||||
obj-$(CONFIG_KEYBOARD_GPIO)		+= gpio_keys.o
 | 
			
		||||
obj-$(CONFIG_KEYBOARD_GPIO_POLLED)	+= gpio_keys_polled.o
 | 
			
		||||
obj-$(CONFIG_KEYBOARD_TCA6416)		+= tca6416-keypad.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -676,6 +676,39 @@ static inline void atkbd_disable(struct atkbd *atkbd)
 | 
			
		|||
	serio_continue_rx(atkbd->ps2dev.serio);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int atkbd_activate(struct atkbd *atkbd)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &atkbd->ps2dev;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Enable the keyboard to receive keystrokes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
 | 
			
		||||
		dev_err(&ps2dev->serio->dev,
 | 
			
		||||
			"Failed to enable keyboard on %s\n",
 | 
			
		||||
			ps2dev->serio->phys);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * atkbd_deactivate() resets and disables the keyboard from sending
 | 
			
		||||
 * keystrokes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
static void atkbd_deactivate(struct atkbd *atkbd)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &atkbd->ps2dev;
 | 
			
		||||
 | 
			
		||||
	if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS))
 | 
			
		||||
		dev_err(&ps2dev->serio->dev,
 | 
			
		||||
			"Failed to deactivate keyboard on %s\n",
 | 
			
		||||
			ps2dev->serio->phys);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * atkbd_probe() probes for an AT keyboard on a serio port.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -726,11 +759,17 @@ static int atkbd_probe(struct atkbd *atkbd)
 | 
			
		|||
 | 
			
		||||
	if (atkbd->id == 0xaca1 && atkbd->translated) {
 | 
			
		||||
		dev_err(&ps2dev->serio->dev,
 | 
			
		||||
			"NCD terminal keyboards are only supported on non-translating controlelrs. "
 | 
			
		||||
			"NCD terminal keyboards are only supported on non-translating controllers. "
 | 
			
		||||
			"Use i8042.direct=1 to disable translation.\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Make sure nothing is coming from the keyboard and disturbs our
 | 
			
		||||
 * internal state.
 | 
			
		||||
 */
 | 
			
		||||
	atkbd_deactivate(atkbd);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -825,24 +864,6 @@ static int atkbd_reset_state(struct atkbd *atkbd)
 | 
			
		|||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int atkbd_activate(struct atkbd *atkbd)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &atkbd->ps2dev;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Enable the keyboard to receive keystrokes.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
	if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) {
 | 
			
		||||
		dev_err(&ps2dev->serio->dev,
 | 
			
		||||
			"Failed to enable keyboard on %s\n",
 | 
			
		||||
			ps2dev->serio->phys);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
 | 
			
		||||
 * reboot.
 | 
			
		||||
| 
						 | 
				
			
			@ -1150,7 +1171,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
 | 
			
		||||
		atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra);
 | 
			
		||||
		atkbd_reset_state(atkbd);
 | 
			
		||||
		atkbd_activate(atkbd);
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		atkbd->set = 2;
 | 
			
		||||
| 
						 | 
				
			
			@ -1165,6 +1185,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
 | 
			
		|||
		goto fail3;
 | 
			
		||||
 | 
			
		||||
	atkbd_enable(atkbd);
 | 
			
		||||
	if (serio->write)
 | 
			
		||||
		atkbd_activate(atkbd);
 | 
			
		||||
 | 
			
		||||
	err = input_register_device(atkbd->dev);
 | 
			
		||||
	if (err)
 | 
			
		||||
| 
						 | 
				
			
			@ -1208,8 +1230,6 @@ static int atkbd_reconnect(struct serio *serio)
 | 
			
		|||
		if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
 | 
			
		||||
			goto out;
 | 
			
		||||
 | 
			
		||||
		atkbd_activate(atkbd);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Restore LED state and repeat rate. While input core
 | 
			
		||||
		 * will do this for us at resume time reconnect may happen
 | 
			
		||||
| 
						 | 
				
			
			@ -1223,7 +1243,17 @@ static int atkbd_reconnect(struct serio *serio)
 | 
			
		|||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Reset our state machine in case reconnect happened in the middle
 | 
			
		||||
	 * of multi-byte scancode.
 | 
			
		||||
	 */
 | 
			
		||||
	atkbd->xl_bit = 0;
 | 
			
		||||
	atkbd->emul = 0;
 | 
			
		||||
 | 
			
		||||
	atkbd_enable(atkbd);
 | 
			
		||||
	if (atkbd->write)
 | 
			
		||||
		atkbd_activate(atkbd);
 | 
			
		||||
 | 
			
		||||
	retval = 0;
 | 
			
		||||
 | 
			
		||||
 out:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										194
									
								
								drivers/input/keyboard/goldfish_events.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								drivers/input/keyboard/goldfish_events.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,194 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Copyright (C) 2007 Google, Inc.
 | 
			
		||||
 * Copyright (C) 2012 Intel, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This software is licensed under the terms of the GNU General Public
 | 
			
		||||
 * License version 2, as published by the Free Software Foundation, and
 | 
			
		||||
 * may be copied, distributed, and modified under those terms.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/irq.h>
 | 
			
		||||
#include <linux/io.h>
 | 
			
		||||
 | 
			
		||||
enum {
 | 
			
		||||
	REG_READ        = 0x00,
 | 
			
		||||
	REG_SET_PAGE    = 0x00,
 | 
			
		||||
	REG_LEN         = 0x04,
 | 
			
		||||
	REG_DATA        = 0x08,
 | 
			
		||||
 | 
			
		||||
	PAGE_NAME       = 0x00000,
 | 
			
		||||
	PAGE_EVBITS     = 0x10000,
 | 
			
		||||
	PAGE_ABSDATA    = 0x20000 | EV_ABS,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct event_dev {
 | 
			
		||||
	struct input_dev *input;
 | 
			
		||||
	int irq;
 | 
			
		||||
	void __iomem *addr;
 | 
			
		||||
	char name[0];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static irqreturn_t events_interrupt(int irq, void *dev_id)
 | 
			
		||||
{
 | 
			
		||||
	struct event_dev *edev = dev_id;
 | 
			
		||||
	unsigned type, code, value;
 | 
			
		||||
 | 
			
		||||
	type = __raw_readl(edev->addr + REG_READ);
 | 
			
		||||
	code = __raw_readl(edev->addr + REG_READ);
 | 
			
		||||
	value = __raw_readl(edev->addr + REG_READ);
 | 
			
		||||
 | 
			
		||||
	input_event(edev->input, type, code, value);
 | 
			
		||||
	input_sync(edev->input);
 | 
			
		||||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void events_import_bits(struct event_dev *edev,
 | 
			
		||||
			unsigned long bits[], unsigned type, size_t count)
 | 
			
		||||
{
 | 
			
		||||
	void __iomem *addr = edev->addr;
 | 
			
		||||
	int i, j;
 | 
			
		||||
	size_t size;
 | 
			
		||||
	uint8_t val;
 | 
			
		||||
 | 
			
		||||
	__raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE);
 | 
			
		||||
 | 
			
		||||
	size = __raw_readl(addr + REG_LEN) * 8;
 | 
			
		||||
	if (size < count)
 | 
			
		||||
		count = size;
 | 
			
		||||
 | 
			
		||||
	addr += REG_DATA;
 | 
			
		||||
	for (i = 0; i < count; i += 8) {
 | 
			
		||||
		val = __raw_readb(addr++);
 | 
			
		||||
		for (j = 0; j < 8; j++)
 | 
			
		||||
			if (val & 1 << j)
 | 
			
		||||
				set_bit(i + j, bits);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void events_import_abs_params(struct event_dev *edev)
 | 
			
		||||
{
 | 
			
		||||
	struct input_dev *input_dev = edev->input;
 | 
			
		||||
	void __iomem *addr = edev->addr;
 | 
			
		||||
	u32 val[4];
 | 
			
		||||
	int count;
 | 
			
		||||
	int i, j;
 | 
			
		||||
 | 
			
		||||
	__raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE);
 | 
			
		||||
 | 
			
		||||
	count = __raw_readl(addr + REG_LEN) / sizeof(val);
 | 
			
		||||
	if (count > ABS_MAX)
 | 
			
		||||
		count = ABS_MAX;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < count; i++) {
 | 
			
		||||
		if (!test_bit(i, input_dev->absbit))
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		for (j = 0; j < ARRAY_SIZE(val); j++) {
 | 
			
		||||
			int offset = (i * ARRAY_SIZE(val) + j) * sizeof(u32);
 | 
			
		||||
			val[j] = __raw_readl(edev->addr + REG_DATA + offset);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		input_set_abs_params(input_dev, i,
 | 
			
		||||
				     val[0], val[1], val[2], val[3]);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int events_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct input_dev *input_dev;
 | 
			
		||||
	struct event_dev *edev;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	unsigned keymapnamelen;
 | 
			
		||||
	void __iomem *addr;
 | 
			
		||||
	int irq;
 | 
			
		||||
	int i;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	if (irq < 0)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (!res)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	addr = devm_ioremap(&pdev->dev, res->start, 4096);
 | 
			
		||||
	if (!addr)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	__raw_writel(PAGE_NAME, addr + REG_SET_PAGE);
 | 
			
		||||
	keymapnamelen = __raw_readl(addr + REG_LEN);
 | 
			
		||||
 | 
			
		||||
	edev = devm_kzalloc(&pdev->dev,
 | 
			
		||||
			    sizeof(struct event_dev) + keymapnamelen + 1,
 | 
			
		||||
			    GFP_KERNEL);
 | 
			
		||||
	if (!edev)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	input_dev = devm_input_allocate_device(&pdev->dev);
 | 
			
		||||
	if (!input_dev)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	edev->input = input_dev;
 | 
			
		||||
	edev->addr = addr;
 | 
			
		||||
	edev->irq = irq;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < keymapnamelen; i++)
 | 
			
		||||
		edev->name[i] = __raw_readb(edev->addr + REG_DATA + i);
 | 
			
		||||
 | 
			
		||||
	pr_debug("events_probe() keymap=%s\n", edev->name);
 | 
			
		||||
 | 
			
		||||
	input_dev->name = edev->name;
 | 
			
		||||
	input_dev->id.bustype = BUS_HOST;
 | 
			
		||||
 | 
			
		||||
	events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX);
 | 
			
		||||
	events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX);
 | 
			
		||||
 | 
			
		||||
	events_import_abs_params(edev);
 | 
			
		||||
 | 
			
		||||
	error = devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0,
 | 
			
		||||
				 "goldfish-events-keypad", edev);
 | 
			
		||||
	if (error)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	error = input_register_device(input_dev);
 | 
			
		||||
	if (error)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver events_driver = {
 | 
			
		||||
	.probe	= events_probe,
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
		.name	= "goldfish_events",
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_platform_driver(events_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_AUTHOR("Brian Swetland");
 | 
			
		||||
MODULE_DESCRIPTION("Goldfish Event Device");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
#include <linux/jiffies.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/of.h>
 | 
			
		||||
#include <linux/platform_device.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/timer.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -414,15 +415,23 @@ open_err:
 | 
			
		|||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OF
 | 
			
		||||
static struct of_device_id imx_keypad_of_match[] = {
 | 
			
		||||
	{ .compatible = "fsl,imx21-kpp", },
 | 
			
		||||
	{ /* sentinel */ }
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(of, imx_keypad_of_match);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static int imx_keypad_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	const struct matrix_keymap_data *keymap_data = pdev->dev.platform_data;
 | 
			
		||||
	struct imx_keypad *keypad;
 | 
			
		||||
	struct input_dev *input_dev;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	int irq, error, i;
 | 
			
		||||
	int irq, error, i, row, col;
 | 
			
		||||
 | 
			
		||||
	if (keymap_data == NULL) {
 | 
			
		||||
	if (!keymap_data && !pdev->dev.of_node) {
 | 
			
		||||
		dev_err(&pdev->dev, "no keymap defined\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -480,22 +489,6 @@ static int imx_keypad_probe(struct platform_device *pdev)
 | 
			
		|||
		goto failed_unmap;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Search for rows and cols enabled */
 | 
			
		||||
	for (i = 0; i < keymap_data->keymap_size; i++) {
 | 
			
		||||
		keypad->rows_en_mask |= 1 << KEY_ROW(keymap_data->keymap[i]);
 | 
			
		||||
		keypad->cols_en_mask |= 1 << KEY_COL(keymap_data->keymap[i]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (keypad->rows_en_mask > ((1 << MAX_MATRIX_KEY_ROWS) - 1) ||
 | 
			
		||||
	    keypad->cols_en_mask > ((1 << MAX_MATRIX_KEY_COLS) - 1)) {
 | 
			
		||||
		dev_err(&pdev->dev,
 | 
			
		||||
			"invalid key data (too many rows or colums)\n");
 | 
			
		||||
		error = -EINVAL;
 | 
			
		||||
		goto failed_clock_put;
 | 
			
		||||
	}
 | 
			
		||||
	dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
 | 
			
		||||
	dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
 | 
			
		||||
 | 
			
		||||
	/* Init the Input device */
 | 
			
		||||
	input_dev->name = pdev->name;
 | 
			
		||||
	input_dev->id.bustype = BUS_HOST;
 | 
			
		||||
| 
						 | 
				
			
			@ -512,6 +505,19 @@ static int imx_keypad_probe(struct platform_device *pdev)
 | 
			
		|||
		goto failed_clock_put;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Search for rows and cols enabled */
 | 
			
		||||
	for (row = 0; row < MAX_MATRIX_KEY_ROWS; row++) {
 | 
			
		||||
		for (col = 0; col < MAX_MATRIX_KEY_COLS; col++) {
 | 
			
		||||
			i = MATRIX_SCAN_CODE(row, col, MATRIX_ROW_SHIFT);
 | 
			
		||||
			if (keypad->keycodes[i] != KEY_RESERVED) {
 | 
			
		||||
				keypad->rows_en_mask |= 1 << row;
 | 
			
		||||
				keypad->cols_en_mask |= 1 << col;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	dev_dbg(&pdev->dev, "enabled rows mask: %x\n", keypad->rows_en_mask);
 | 
			
		||||
	dev_dbg(&pdev->dev, "enabled cols mask: %x\n", keypad->cols_en_mask);
 | 
			
		||||
 | 
			
		||||
	__set_bit(EV_REP, input_dev->evbit);
 | 
			
		||||
	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 | 
			
		||||
	input_set_drvdata(input_dev, keypad);
 | 
			
		||||
| 
						 | 
				
			
			@ -631,6 +637,7 @@ static struct platform_driver imx_keypad_driver = {
 | 
			
		|||
		.name	= "imx-keypad",
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
		.pm	= &imx_kbd_pm_ops,
 | 
			
		||||
		.of_match_table = of_match_ptr(imx_keypad_of_match),
 | 
			
		||||
	},
 | 
			
		||||
	.probe		= imx_keypad_probe,
 | 
			
		||||
	.remove		= imx_keypad_remove,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,6 +20,7 @@
 | 
			
		|||
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/leds.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/jiffies.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -39,6 +40,11 @@
 | 
			
		|||
#define QT2160_CMD_GPIOS      6
 | 
			
		||||
#define QT2160_CMD_SUBVER     7
 | 
			
		||||
#define QT2160_CMD_CALIBRATE  10
 | 
			
		||||
#define QT2160_CMD_DRIVE_X    70
 | 
			
		||||
#define QT2160_CMD_PWMEN_X    74
 | 
			
		||||
#define QT2160_CMD_PWM_DUTY   76
 | 
			
		||||
 | 
			
		||||
#define QT2160_NUM_LEDS_X	8
 | 
			
		||||
 | 
			
		||||
#define QT2160_CYCLE_INTERVAL	(2*HZ)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +55,17 @@ static unsigned char qt2160_key2code[] = {
 | 
			
		|||
	KEY_C, KEY_D, KEY_E, KEY_F,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LEDS_CLASS
 | 
			
		||||
struct qt2160_led {
 | 
			
		||||
	struct qt2160_data *qt2160;
 | 
			
		||||
	struct led_classdev cdev;
 | 
			
		||||
	struct work_struct work;
 | 
			
		||||
	char name[32];
 | 
			
		||||
	int id;
 | 
			
		||||
	enum led_brightness new_brightness;
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct qt2160_data {
 | 
			
		||||
	struct i2c_client *client;
 | 
			
		||||
	struct input_dev *input;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,8 +73,61 @@ struct qt2160_data {
 | 
			
		|||
	spinlock_t lock;        /* Protects canceling/rescheduling of dwork */
 | 
			
		||||
	unsigned short keycodes[ARRAY_SIZE(qt2160_key2code)];
 | 
			
		||||
	u16 key_matrix;
 | 
			
		||||
#ifdef CONFIG_LEDS_CLASS
 | 
			
		||||
	struct qt2160_led leds[QT2160_NUM_LEDS_X];
 | 
			
		||||
	struct mutex led_lock;
 | 
			
		||||
#endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static int qt2160_read(struct i2c_client *client, u8 reg);
 | 
			
		||||
static int qt2160_write(struct i2c_client *client, u8 reg, u8 data);
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LEDS_CLASS
 | 
			
		||||
 | 
			
		||||
static void qt2160_led_work(struct work_struct *work)
 | 
			
		||||
{
 | 
			
		||||
	struct qt2160_led *led = container_of(work, struct qt2160_led, work);
 | 
			
		||||
	struct qt2160_data *qt2160 = led->qt2160;
 | 
			
		||||
	struct i2c_client *client = qt2160->client;
 | 
			
		||||
	int value = led->new_brightness;
 | 
			
		||||
	u32 drive, pwmen;
 | 
			
		||||
 | 
			
		||||
	mutex_lock(&qt2160->led_lock);
 | 
			
		||||
 | 
			
		||||
	drive = qt2160_read(client, QT2160_CMD_DRIVE_X);
 | 
			
		||||
	pwmen = qt2160_read(client, QT2160_CMD_PWMEN_X);
 | 
			
		||||
	if (value != LED_OFF) {
 | 
			
		||||
		drive |= (1 << led->id);
 | 
			
		||||
		pwmen |= (1 << led->id);
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		drive &= ~(1 << led->id);
 | 
			
		||||
		pwmen &= ~(1 << led->id);
 | 
			
		||||
	}
 | 
			
		||||
	qt2160_write(client, QT2160_CMD_DRIVE_X, drive);
 | 
			
		||||
	qt2160_write(client, QT2160_CMD_PWMEN_X, pwmen);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Changing this register will change the brightness
 | 
			
		||||
	 * of every LED in the qt2160. It's a HW limitation.
 | 
			
		||||
	 */
 | 
			
		||||
	if (value != LED_OFF)
 | 
			
		||||
		qt2160_write(client, QT2160_CMD_PWM_DUTY, value);
 | 
			
		||||
 | 
			
		||||
	mutex_unlock(&qt2160->led_lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qt2160_led_set(struct led_classdev *cdev,
 | 
			
		||||
			   enum led_brightness value)
 | 
			
		||||
{
 | 
			
		||||
	struct qt2160_led *led = container_of(cdev, struct qt2160_led, cdev);
 | 
			
		||||
 | 
			
		||||
	led->new_brightness = value;
 | 
			
		||||
	schedule_work(&led->work);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif /* CONFIG_LEDS_CLASS */
 | 
			
		||||
 | 
			
		||||
static int qt2160_read_block(struct i2c_client *client,
 | 
			
		||||
			     u8 inireg, u8 *buffer, unsigned int count)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -216,6 +286,63 @@ static int qt2160_write(struct i2c_client *client, u8 reg, u8 data)
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_LEDS_CLASS
 | 
			
		||||
 | 
			
		||||
static int qt2160_register_leds(struct qt2160_data *qt2160)
 | 
			
		||||
{
 | 
			
		||||
	struct i2c_client *client = qt2160->client;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	mutex_init(&qt2160->led_lock);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
 | 
			
		||||
		struct qt2160_led *led = &qt2160->leds[i];
 | 
			
		||||
 | 
			
		||||
		snprintf(led->name, sizeof(led->name), "qt2160:x%d", i);
 | 
			
		||||
		led->cdev.name = led->name;
 | 
			
		||||
		led->cdev.brightness_set = qt2160_led_set;
 | 
			
		||||
		led->cdev.brightness = LED_OFF;
 | 
			
		||||
		led->id = i;
 | 
			
		||||
		led->qt2160 = qt2160;
 | 
			
		||||
 | 
			
		||||
		INIT_WORK(&led->work, qt2160_led_work);
 | 
			
		||||
 | 
			
		||||
		ret = led_classdev_register(&client->dev, &led->cdev);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Tur off LEDs */
 | 
			
		||||
	qt2160_write(client, QT2160_CMD_DRIVE_X, 0);
 | 
			
		||||
	qt2160_write(client, QT2160_CMD_PWMEN_X, 0);
 | 
			
		||||
	qt2160_write(client, QT2160_CMD_PWM_DUTY, 0);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void qt2160_unregister_leds(struct qt2160_data *qt2160)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < QT2160_NUM_LEDS_X; i++) {
 | 
			
		||||
		led_classdev_unregister(&qt2160->leds[i].cdev);
 | 
			
		||||
		cancel_work_sync(&qt2160->leds[i].work);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline int qt2160_register_leds(struct qt2160_data *qt2160)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void qt2160_unregister_leds(struct qt2160_data *qt2160)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static bool qt2160_identify(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -314,11 +441,17 @@ static int qt2160_probe(struct i2c_client *client,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = qt2160_register_leds(qt2160);
 | 
			
		||||
	if (error) {
 | 
			
		||||
		dev_err(&client->dev, "Failed to register leds\n");
 | 
			
		||||
		goto err_free_irq;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = input_register_device(qt2160->input);
 | 
			
		||||
	if (error) {
 | 
			
		||||
		dev_err(&client->dev,
 | 
			
		||||
			"Failed to register input device\n");
 | 
			
		||||
		goto err_free_irq;
 | 
			
		||||
		goto err_unregister_leds;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	i2c_set_clientdata(client, qt2160);
 | 
			
		||||
| 
						 | 
				
			
			@ -326,6 +459,8 @@ static int qt2160_probe(struct i2c_client *client,
 | 
			
		|||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_unregister_leds:
 | 
			
		||||
	qt2160_unregister_leds(qt2160);
 | 
			
		||||
err_free_irq:
 | 
			
		||||
	if (client->irq)
 | 
			
		||||
		free_irq(client->irq, qt2160);
 | 
			
		||||
| 
						 | 
				
			
			@ -339,6 +474,8 @@ static int qt2160_remove(struct i2c_client *client)
 | 
			
		|||
{
 | 
			
		||||
	struct qt2160_data *qt2160 = i2c_get_clientdata(client);
 | 
			
		||||
 | 
			
		||||
	qt2160_unregister_leds(qt2160);
 | 
			
		||||
 | 
			
		||||
	/* Release IRQ so no queue will be scheduled */
 | 
			
		||||
	if (client->irq)
 | 
			
		||||
		free_irq(client->irq, qt2160);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,9 +29,16 @@
 | 
			
		|||
#include <linux/of.h>
 | 
			
		||||
#include <linux/clk.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/input/tegra_kbc.h>
 | 
			
		||||
#include <linux/input/matrix_keypad.h>
 | 
			
		||||
#include <mach/clk.h>
 | 
			
		||||
 | 
			
		||||
#define KBC_MAX_GPIO	24
 | 
			
		||||
#define KBC_MAX_KPENT	8
 | 
			
		||||
 | 
			
		||||
#define KBC_MAX_ROW	16
 | 
			
		||||
#define KBC_MAX_COL	8
 | 
			
		||||
#define KBC_MAX_KEY	(KBC_MAX_ROW * KBC_MAX_COL)
 | 
			
		||||
 | 
			
		||||
#define KBC_MAX_DEBOUNCE_CNT	0x3ffu
 | 
			
		||||
 | 
			
		||||
/* KBC row scan time and delay for beginning the row scan. */
 | 
			
		||||
| 
						 | 
				
			
			@ -67,10 +74,27 @@
 | 
			
		|||
 | 
			
		||||
#define KBC_ROW_SHIFT	3
 | 
			
		||||
 | 
			
		||||
enum tegra_pin_type {
 | 
			
		||||
	PIN_CFG_IGNORE,
 | 
			
		||||
	PIN_CFG_COL,
 | 
			
		||||
	PIN_CFG_ROW,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct tegra_kbc_pin_cfg {
 | 
			
		||||
	enum tegra_pin_type type;
 | 
			
		||||
	unsigned char num;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct tegra_kbc {
 | 
			
		||||
	struct device *dev;
 | 
			
		||||
	unsigned int debounce_cnt;
 | 
			
		||||
	unsigned int repeat_cnt;
 | 
			
		||||
	struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
 | 
			
		||||
	const struct matrix_keymap_data *keymap_data;
 | 
			
		||||
	bool wakeup;
 | 
			
		||||
	void __iomem *mmio;
 | 
			
		||||
	struct input_dev *idev;
 | 
			
		||||
	unsigned int irq;
 | 
			
		||||
	int irq;
 | 
			
		||||
	spinlock_t lock;
 | 
			
		||||
	unsigned int repoll_dly;
 | 
			
		||||
	unsigned long cp_dly_jiffies;
 | 
			
		||||
| 
						 | 
				
			
			@ -78,7 +102,6 @@ struct tegra_kbc {
 | 
			
		|||
	bool use_fn_map;
 | 
			
		||||
	bool use_ghost_filter;
 | 
			
		||||
	bool keypress_caused_wake;
 | 
			
		||||
	const struct tegra_kbc_platform_data *pdata;
 | 
			
		||||
	unsigned short keycode[KBC_MAX_KEY * 2];
 | 
			
		||||
	unsigned short current_keys[KBC_MAX_KPENT];
 | 
			
		||||
	unsigned int num_pressed_keys;
 | 
			
		||||
| 
						 | 
				
			
			@ -87,147 +110,6 @@ struct tegra_kbc {
 | 
			
		|||
	struct clk *clk;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const u32 tegra_kbc_default_keymap[] = {
 | 
			
		||||
	KEY(0, 2, KEY_W),
 | 
			
		||||
	KEY(0, 3, KEY_S),
 | 
			
		||||
	KEY(0, 4, KEY_A),
 | 
			
		||||
	KEY(0, 5, KEY_Z),
 | 
			
		||||
	KEY(0, 7, KEY_FN),
 | 
			
		||||
 | 
			
		||||
	KEY(1, 7, KEY_LEFTMETA),
 | 
			
		||||
 | 
			
		||||
	KEY(2, 6, KEY_RIGHTALT),
 | 
			
		||||
	KEY(2, 7, KEY_LEFTALT),
 | 
			
		||||
 | 
			
		||||
	KEY(3, 0, KEY_5),
 | 
			
		||||
	KEY(3, 1, KEY_4),
 | 
			
		||||
	KEY(3, 2, KEY_R),
 | 
			
		||||
	KEY(3, 3, KEY_E),
 | 
			
		||||
	KEY(3, 4, KEY_F),
 | 
			
		||||
	KEY(3, 5, KEY_D),
 | 
			
		||||
	KEY(3, 6, KEY_X),
 | 
			
		||||
 | 
			
		||||
	KEY(4, 0, KEY_7),
 | 
			
		||||
	KEY(4, 1, KEY_6),
 | 
			
		||||
	KEY(4, 2, KEY_T),
 | 
			
		||||
	KEY(4, 3, KEY_H),
 | 
			
		||||
	KEY(4, 4, KEY_G),
 | 
			
		||||
	KEY(4, 5, KEY_V),
 | 
			
		||||
	KEY(4, 6, KEY_C),
 | 
			
		||||
	KEY(4, 7, KEY_SPACE),
 | 
			
		||||
 | 
			
		||||
	KEY(5, 0, KEY_9),
 | 
			
		||||
	KEY(5, 1, KEY_8),
 | 
			
		||||
	KEY(5, 2, KEY_U),
 | 
			
		||||
	KEY(5, 3, KEY_Y),
 | 
			
		||||
	KEY(5, 4, KEY_J),
 | 
			
		||||
	KEY(5, 5, KEY_N),
 | 
			
		||||
	KEY(5, 6, KEY_B),
 | 
			
		||||
	KEY(5, 7, KEY_BACKSLASH),
 | 
			
		||||
 | 
			
		||||
	KEY(6, 0, KEY_MINUS),
 | 
			
		||||
	KEY(6, 1, KEY_0),
 | 
			
		||||
	KEY(6, 2, KEY_O),
 | 
			
		||||
	KEY(6, 3, KEY_I),
 | 
			
		||||
	KEY(6, 4, KEY_L),
 | 
			
		||||
	KEY(6, 5, KEY_K),
 | 
			
		||||
	KEY(6, 6, KEY_COMMA),
 | 
			
		||||
	KEY(6, 7, KEY_M),
 | 
			
		||||
 | 
			
		||||
	KEY(7, 1, KEY_EQUAL),
 | 
			
		||||
	KEY(7, 2, KEY_RIGHTBRACE),
 | 
			
		||||
	KEY(7, 3, KEY_ENTER),
 | 
			
		||||
	KEY(7, 7, KEY_MENU),
 | 
			
		||||
 | 
			
		||||
	KEY(8, 4, KEY_RIGHTSHIFT),
 | 
			
		||||
	KEY(8, 5, KEY_LEFTSHIFT),
 | 
			
		||||
 | 
			
		||||
	KEY(9, 5, KEY_RIGHTCTRL),
 | 
			
		||||
	KEY(9, 7, KEY_LEFTCTRL),
 | 
			
		||||
 | 
			
		||||
	KEY(11, 0, KEY_LEFTBRACE),
 | 
			
		||||
	KEY(11, 1, KEY_P),
 | 
			
		||||
	KEY(11, 2, KEY_APOSTROPHE),
 | 
			
		||||
	KEY(11, 3, KEY_SEMICOLON),
 | 
			
		||||
	KEY(11, 4, KEY_SLASH),
 | 
			
		||||
	KEY(11, 5, KEY_DOT),
 | 
			
		||||
 | 
			
		||||
	KEY(12, 0, KEY_F10),
 | 
			
		||||
	KEY(12, 1, KEY_F9),
 | 
			
		||||
	KEY(12, 2, KEY_BACKSPACE),
 | 
			
		||||
	KEY(12, 3, KEY_3),
 | 
			
		||||
	KEY(12, 4, KEY_2),
 | 
			
		||||
	KEY(12, 5, KEY_UP),
 | 
			
		||||
	KEY(12, 6, KEY_PRINT),
 | 
			
		||||
	KEY(12, 7, KEY_PAUSE),
 | 
			
		||||
 | 
			
		||||
	KEY(13, 0, KEY_INSERT),
 | 
			
		||||
	KEY(13, 1, KEY_DELETE),
 | 
			
		||||
	KEY(13, 3, KEY_PAGEUP),
 | 
			
		||||
	KEY(13, 4, KEY_PAGEDOWN),
 | 
			
		||||
	KEY(13, 5, KEY_RIGHT),
 | 
			
		||||
	KEY(13, 6, KEY_DOWN),
 | 
			
		||||
	KEY(13, 7, KEY_LEFT),
 | 
			
		||||
 | 
			
		||||
	KEY(14, 0, KEY_F11),
 | 
			
		||||
	KEY(14, 1, KEY_F12),
 | 
			
		||||
	KEY(14, 2, KEY_F8),
 | 
			
		||||
	KEY(14, 3, KEY_Q),
 | 
			
		||||
	KEY(14, 4, KEY_F4),
 | 
			
		||||
	KEY(14, 5, KEY_F3),
 | 
			
		||||
	KEY(14, 6, KEY_1),
 | 
			
		||||
	KEY(14, 7, KEY_F7),
 | 
			
		||||
 | 
			
		||||
	KEY(15, 0, KEY_ESC),
 | 
			
		||||
	KEY(15, 1, KEY_GRAVE),
 | 
			
		||||
	KEY(15, 2, KEY_F5),
 | 
			
		||||
	KEY(15, 3, KEY_TAB),
 | 
			
		||||
	KEY(15, 4, KEY_F1),
 | 
			
		||||
	KEY(15, 5, KEY_F2),
 | 
			
		||||
	KEY(15, 6, KEY_CAPSLOCK),
 | 
			
		||||
	KEY(15, 7, KEY_F6),
 | 
			
		||||
 | 
			
		||||
	/* Software Handled Function Keys */
 | 
			
		||||
	KEY(20, 0, KEY_KP7),
 | 
			
		||||
 | 
			
		||||
	KEY(21, 0, KEY_KP9),
 | 
			
		||||
	KEY(21, 1, KEY_KP8),
 | 
			
		||||
	KEY(21, 2, KEY_KP4),
 | 
			
		||||
	KEY(21, 4, KEY_KP1),
 | 
			
		||||
 | 
			
		||||
	KEY(22, 1, KEY_KPSLASH),
 | 
			
		||||
	KEY(22, 2, KEY_KP6),
 | 
			
		||||
	KEY(22, 3, KEY_KP5),
 | 
			
		||||
	KEY(22, 4, KEY_KP3),
 | 
			
		||||
	KEY(22, 5, KEY_KP2),
 | 
			
		||||
	KEY(22, 7, KEY_KP0),
 | 
			
		||||
 | 
			
		||||
	KEY(27, 1, KEY_KPASTERISK),
 | 
			
		||||
	KEY(27, 3, KEY_KPMINUS),
 | 
			
		||||
	KEY(27, 4, KEY_KPPLUS),
 | 
			
		||||
	KEY(27, 5, KEY_KPDOT),
 | 
			
		||||
 | 
			
		||||
	KEY(28, 5, KEY_VOLUMEUP),
 | 
			
		||||
 | 
			
		||||
	KEY(29, 3, KEY_HOME),
 | 
			
		||||
	KEY(29, 4, KEY_END),
 | 
			
		||||
	KEY(29, 5, KEY_BRIGHTNESSDOWN),
 | 
			
		||||
	KEY(29, 6, KEY_VOLUMEDOWN),
 | 
			
		||||
	KEY(29, 7, KEY_BRIGHTNESSUP),
 | 
			
		||||
 | 
			
		||||
	KEY(30, 0, KEY_NUMLOCK),
 | 
			
		||||
	KEY(30, 1, KEY_SCROLLLOCK),
 | 
			
		||||
	KEY(30, 2, KEY_MUTE),
 | 
			
		||||
 | 
			
		||||
	KEY(31, 4, KEY_HELP),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const
 | 
			
		||||
struct matrix_keymap_data tegra_kbc_default_keymap_data = {
 | 
			
		||||
	.keymap		= tegra_kbc_default_keymap,
 | 
			
		||||
	.keymap_size	= ARRAY_SIZE(tegra_kbc_default_keymap),
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void tegra_kbc_report_released_keys(struct input_dev *input,
 | 
			
		||||
					   unsigned short old_keycodes[],
 | 
			
		||||
					   unsigned int old_num_keys,
 | 
			
		||||
| 
						 | 
				
			
			@ -357,18 +239,6 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
 | 
			
		|||
	writel(val, kbc->mmio + KBC_CONTROL_0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
 | 
			
		||||
{
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	val = readl(kbc->mmio + KBC_CONTROL_0);
 | 
			
		||||
	if (enable)
 | 
			
		||||
		val |= KBC_CONTROL_KEYPRESS_INT_EN;
 | 
			
		||||
	else
 | 
			
		||||
		val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
 | 
			
		||||
	writel(val, kbc->mmio + KBC_CONTROL_0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void tegra_kbc_keypress_timer(unsigned long data)
 | 
			
		||||
{
 | 
			
		||||
	struct tegra_kbc *kbc = (struct tegra_kbc *)data;
 | 
			
		||||
| 
						 | 
				
			
			@ -439,12 +309,11 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
 | 
			
		|||
 | 
			
		||||
static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
 | 
			
		||||
{
 | 
			
		||||
	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 | 
			
		||||
	int i;
 | 
			
		||||
	unsigned int rst_val;
 | 
			
		||||
 | 
			
		||||
	/* Either mask all keys or none. */
 | 
			
		||||
	rst_val = (filter && !pdata->wakeup) ? ~0 : 0;
 | 
			
		||||
	rst_val = (filter && !kbc->wakeup) ? ~0 : 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < KBC_MAX_ROW; i++)
 | 
			
		||||
		writel(rst_val, kbc->mmio + KBC_ROW0_MASK_0 + i * 4);
 | 
			
		||||
| 
						 | 
				
			
			@ -452,7 +321,6 @@ static void tegra_kbc_setup_wakekeys(struct tegra_kbc *kbc, bool filter)
 | 
			
		|||
 | 
			
		||||
static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
 | 
			
		||||
{
 | 
			
		||||
	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < KBC_MAX_GPIO; i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -468,13 +336,13 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
 | 
			
		|||
		row_cfg &= ~r_mask;
 | 
			
		||||
		col_cfg &= ~c_mask;
 | 
			
		||||
 | 
			
		||||
		switch (pdata->pin_cfg[i].type) {
 | 
			
		||||
		switch (kbc->pin_cfg[i].type) {
 | 
			
		||||
		case PIN_CFG_ROW:
 | 
			
		||||
			row_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << r_shft;
 | 
			
		||||
			row_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << r_shft;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case PIN_CFG_COL:
 | 
			
		||||
			col_cfg |= ((pdata->pin_cfg[i].num << 1) | 1) << c_shft;
 | 
			
		||||
			col_cfg |= ((kbc->pin_cfg[i].num << 1) | 1) << c_shft;
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		case PIN_CFG_IGNORE:
 | 
			
		||||
| 
						 | 
				
			
			@ -488,7 +356,6 @@ static void tegra_kbc_config_pins(struct tegra_kbc *kbc)
 | 
			
		|||
 | 
			
		||||
static int tegra_kbc_start(struct tegra_kbc *kbc)
 | 
			
		||||
{
 | 
			
		||||
	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 | 
			
		||||
	unsigned int debounce_cnt;
 | 
			
		||||
	u32 val = 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -503,10 +370,10 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
 | 
			
		|||
	tegra_kbc_config_pins(kbc);
 | 
			
		||||
	tegra_kbc_setup_wakekeys(kbc, false);
 | 
			
		||||
 | 
			
		||||
	writel(pdata->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
 | 
			
		||||
	writel(kbc->repeat_cnt, kbc->mmio + KBC_RPT_DLY_0);
 | 
			
		||||
 | 
			
		||||
	/* Keyboard debounce count is maximum of 12 bits. */
 | 
			
		||||
	debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
 | 
			
		||||
	debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
 | 
			
		||||
	val = KBC_DEBOUNCE_CNT_SHIFT(debounce_cnt);
 | 
			
		||||
	val |= KBC_FIFO_TH_CNT_SHIFT(1); /* set fifo interrupt threshold to 1 */
 | 
			
		||||
	val |= KBC_CONTROL_FIFO_CNT_INT_EN;  /* interrupt on FIFO threshold */
 | 
			
		||||
| 
						 | 
				
			
			@ -573,21 +440,20 @@ static void tegra_kbc_close(struct input_dev *dev)
 | 
			
		|||
	return tegra_kbc_stop(kbc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
 | 
			
		||||
			struct device *dev, unsigned int *num_rows)
 | 
			
		||||
static bool tegra_kbc_check_pin_cfg(const struct tegra_kbc *kbc,
 | 
			
		||||
					unsigned int *num_rows)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	*num_rows = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < KBC_MAX_GPIO; i++) {
 | 
			
		||||
		const struct tegra_kbc_pin_cfg *pin_cfg = &pdata->pin_cfg[i];
 | 
			
		||||
		const struct tegra_kbc_pin_cfg *pin_cfg = &kbc->pin_cfg[i];
 | 
			
		||||
 | 
			
		||||
		switch (pin_cfg->type) {
 | 
			
		||||
		case PIN_CFG_ROW:
 | 
			
		||||
			if (pin_cfg->num >= KBC_MAX_ROW) {
 | 
			
		||||
				dev_err(dev,
 | 
			
		||||
				dev_err(kbc->dev,
 | 
			
		||||
					"pin_cfg[%d]: invalid row number %d\n",
 | 
			
		||||
					i, pin_cfg->num);
 | 
			
		||||
				return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -597,7 +463,7 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
 | 
			
		|||
 | 
			
		||||
		case PIN_CFG_COL:
 | 
			
		||||
			if (pin_cfg->num >= KBC_MAX_COL) {
 | 
			
		||||
				dev_err(dev,
 | 
			
		||||
				dev_err(kbc->dev,
 | 
			
		||||
					"pin_cfg[%d]: invalid column number %d\n",
 | 
			
		||||
					i, pin_cfg->num);
 | 
			
		||||
				return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -608,7 +474,7 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
 | 
			
		|||
			break;
 | 
			
		||||
 | 
			
		||||
		default:
 | 
			
		||||
			dev_err(dev,
 | 
			
		||||
			dev_err(kbc->dev,
 | 
			
		||||
				"pin_cfg[%d]: invalid entry type %d\n",
 | 
			
		||||
				pin_cfg->type, pin_cfg->num);
 | 
			
		||||
			return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -618,154 +484,140 @@ tegra_kbc_check_pin_cfg(const struct tegra_kbc_platform_data *pdata,
 | 
			
		|||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_OF
 | 
			
		||||
static struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
 | 
			
		||||
	struct platform_device *pdev)
 | 
			
		||||
static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
 | 
			
		||||
{
 | 
			
		||||
	struct tegra_kbc_platform_data *pdata;
 | 
			
		||||
	struct device_node *np = pdev->dev.of_node;
 | 
			
		||||
	struct device_node *np = kbc->dev->of_node;
 | 
			
		||||
	u32 prop;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!np)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
 | 
			
		||||
	if (!pdata)
 | 
			
		||||
		return NULL;
 | 
			
		||||
	u32 num_rows = 0;
 | 
			
		||||
	u32 num_cols = 0;
 | 
			
		||||
	u32 cols_cfg[KBC_MAX_GPIO];
 | 
			
		||||
	u32 rows_cfg[KBC_MAX_GPIO];
 | 
			
		||||
	int proplen;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
 | 
			
		||||
		pdata->debounce_cnt = prop;
 | 
			
		||||
		kbc->debounce_cnt = prop;
 | 
			
		||||
 | 
			
		||||
	if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop))
 | 
			
		||||
		pdata->repeat_cnt = prop;
 | 
			
		||||
		kbc->repeat_cnt = prop;
 | 
			
		||||
 | 
			
		||||
	if (of_find_property(np, "nvidia,needs-ghost-filter", NULL))
 | 
			
		||||
		pdata->use_ghost_filter = true;
 | 
			
		||||
		kbc->use_ghost_filter = true;
 | 
			
		||||
 | 
			
		||||
	if (of_find_property(np, "nvidia,wakeup-source", NULL))
 | 
			
		||||
		pdata->wakeup = true;
 | 
			
		||||
		kbc->wakeup = true;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * All currently known keymaps with device tree support use the same
 | 
			
		||||
	 * pin_cfg, so set it up here.
 | 
			
		||||
	 */
 | 
			
		||||
	for (i = 0; i < KBC_MAX_ROW; i++) {
 | 
			
		||||
		pdata->pin_cfg[i].num = i;
 | 
			
		||||
		pdata->pin_cfg[i].type = PIN_CFG_ROW;
 | 
			
		||||
	if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) {
 | 
			
		||||
		dev_err(kbc->dev, "property nvidia,kbc-row-pins not found\n");
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
	num_rows = proplen / sizeof(u32);
 | 
			
		||||
 | 
			
		||||
	if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) {
 | 
			
		||||
		dev_err(kbc->dev, "property nvidia,kbc-col-pins not found\n");
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
	num_cols = proplen / sizeof(u32);
 | 
			
		||||
 | 
			
		||||
	if (!of_get_property(np, "linux,keymap", &proplen)) {
 | 
			
		||||
		dev_err(kbc->dev, "property linux,keymap not found\n");
 | 
			
		||||
		return -ENOENT;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < KBC_MAX_COL; i++) {
 | 
			
		||||
		pdata->pin_cfg[KBC_MAX_ROW + i].num = i;
 | 
			
		||||
		pdata->pin_cfg[KBC_MAX_ROW + i].type = PIN_CFG_COL;
 | 
			
		||||
	if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
 | 
			
		||||
		dev_err(kbc->dev,
 | 
			
		||||
			"keypad rows/columns not porperly specified\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return pdata;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static inline struct tegra_kbc_platform_data *tegra_kbc_dt_parse_pdata(
 | 
			
		||||
	struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
	/* Set all pins as non-configured */
 | 
			
		||||
	for (i = 0; i < KBC_MAX_GPIO; i++)
 | 
			
		||||
		kbc->pin_cfg[i].type = PIN_CFG_IGNORE;
 | 
			
		||||
 | 
			
		||||
static int tegra_kbd_setup_keymap(struct tegra_kbc *kbc)
 | 
			
		||||
{
 | 
			
		||||
	const struct tegra_kbc_platform_data *pdata = kbc->pdata;
 | 
			
		||||
	const struct matrix_keymap_data *keymap_data = pdata->keymap_data;
 | 
			
		||||
	unsigned int keymap_rows = KBC_MAX_KEY;
 | 
			
		||||
	int retval;
 | 
			
		||||
 | 
			
		||||
	if (keymap_data && pdata->use_fn_map)
 | 
			
		||||
		keymap_rows *= 2;
 | 
			
		||||
 | 
			
		||||
	retval = matrix_keypad_build_keymap(keymap_data, NULL,
 | 
			
		||||
					    keymap_rows, KBC_MAX_COL,
 | 
			
		||||
					    kbc->keycode, kbc->idev);
 | 
			
		||||
	if (retval == -ENOSYS || retval == -ENOENT) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * If there is no OF support in kernel or keymap
 | 
			
		||||
		 * property is missing, use default keymap.
 | 
			
		||||
		 */
 | 
			
		||||
		retval = matrix_keypad_build_keymap(
 | 
			
		||||
					&tegra_kbc_default_keymap_data, NULL,
 | 
			
		||||
					keymap_rows, KBC_MAX_COL,
 | 
			
		||||
					kbc->keycode, kbc->idev);
 | 
			
		||||
	ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
 | 
			
		||||
				rows_cfg, num_rows);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		dev_err(kbc->dev, "Rows configurations are not proper\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return retval;
 | 
			
		||||
	ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins",
 | 
			
		||||
				cols_cfg, num_cols);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		dev_err(kbc->dev, "Cols configurations are not proper\n");
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_rows; i++) {
 | 
			
		||||
		kbc->pin_cfg[rows_cfg[i]].type = PIN_CFG_ROW;
 | 
			
		||||
		kbc->pin_cfg[rows_cfg[i]].num = i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < num_cols; i++) {
 | 
			
		||||
		kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL;
 | 
			
		||||
		kbc->pin_cfg[cols_cfg[i]].num = i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int tegra_kbc_probe(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	const struct tegra_kbc_platform_data *pdata = pdev->dev.platform_data;
 | 
			
		||||
	struct tegra_kbc *kbc;
 | 
			
		||||
	struct input_dev *input_dev;
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
	int irq;
 | 
			
		||||
	int err;
 | 
			
		||||
	int num_rows = 0;
 | 
			
		||||
	unsigned int debounce_cnt;
 | 
			
		||||
	unsigned int scan_time_rows;
 | 
			
		||||
	unsigned int keymap_rows = KBC_MAX_KEY;
 | 
			
		||||
 | 
			
		||||
	if (!pdata)
 | 
			
		||||
		pdata = tegra_kbc_dt_parse_pdata(pdev);
 | 
			
		||||
 | 
			
		||||
	if (!pdata)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (!tegra_kbc_check_pin_cfg(pdata, &pdev->dev, &num_rows)) {
 | 
			
		||||
		err = -EINVAL;
 | 
			
		||||
		goto err_free_pdata;
 | 
			
		||||
	kbc = devm_kzalloc(&pdev->dev, sizeof(*kbc), GFP_KERNEL);
 | 
			
		||||
	if (!kbc) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to alloc memory for kbc\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kbc->dev = &pdev->dev;
 | 
			
		||||
	spin_lock_init(&kbc->lock);
 | 
			
		||||
 | 
			
		||||
	err = tegra_kbc_parse_dt(kbc);
 | 
			
		||||
	if (err)
 | 
			
		||||
		return err;
 | 
			
		||||
 | 
			
		||||
	if (!tegra_kbc_check_pin_cfg(kbc, &num_rows))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to get I/O memory\n");
 | 
			
		||||
		err = -ENXIO;
 | 
			
		||||
		goto err_free_pdata;
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	if (irq < 0) {
 | 
			
		||||
	kbc->irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	if (kbc->irq < 0) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to get keyboard IRQ\n");
 | 
			
		||||
		err = -ENXIO;
 | 
			
		||||
		goto err_free_pdata;
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kbc = kzalloc(sizeof(*kbc), GFP_KERNEL);
 | 
			
		||||
	input_dev = input_allocate_device();
 | 
			
		||||
	if (!kbc || !input_dev) {
 | 
			
		||||
		err = -ENOMEM;
 | 
			
		||||
		goto err_free_mem;
 | 
			
		||||
	kbc->idev = devm_input_allocate_device(&pdev->dev);
 | 
			
		||||
	if (!kbc->idev) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to allocate input device\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kbc->pdata = pdata;
 | 
			
		||||
	kbc->idev = input_dev;
 | 
			
		||||
	kbc->irq = irq;
 | 
			
		||||
	spin_lock_init(&kbc->lock);
 | 
			
		||||
	setup_timer(&kbc->timer, tegra_kbc_keypress_timer, (unsigned long)kbc);
 | 
			
		||||
 | 
			
		||||
	res = request_mem_region(res->start, resource_size(res), pdev->name);
 | 
			
		||||
	if (!res) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to request I/O memory\n");
 | 
			
		||||
		err = -EBUSY;
 | 
			
		||||
		goto err_free_mem;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kbc->mmio = ioremap(res->start, resource_size(res));
 | 
			
		||||
	kbc->mmio = devm_request_and_ioremap(&pdev->dev, res);
 | 
			
		||||
	if (!kbc->mmio) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to remap I/O memory\n");
 | 
			
		||||
		err = -ENXIO;
 | 
			
		||||
		goto err_free_mem_region;
 | 
			
		||||
		dev_err(&pdev->dev, "Cannot request memregion/iomap address\n");
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	kbc->clk = clk_get(&pdev->dev, NULL);
 | 
			
		||||
	kbc->clk = devm_clk_get(&pdev->dev, NULL);
 | 
			
		||||
	if (IS_ERR(kbc->clk)) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to get keyboard clock\n");
 | 
			
		||||
		err = PTR_ERR(kbc->clk);
 | 
			
		||||
		goto err_iounmap;
 | 
			
		||||
		return PTR_ERR(kbc->clk);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -774,37 +626,38 @@ static int tegra_kbc_probe(struct platform_device *pdev)
 | 
			
		|||
	 * the rows. There is an additional delay before the row scanning
 | 
			
		||||
	 * starts. The repoll delay is computed in milliseconds.
 | 
			
		||||
	 */
 | 
			
		||||
	debounce_cnt = min(pdata->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
 | 
			
		||||
	debounce_cnt = min(kbc->debounce_cnt, KBC_MAX_DEBOUNCE_CNT);
 | 
			
		||||
	scan_time_rows = (KBC_ROW_SCAN_TIME + debounce_cnt) * num_rows;
 | 
			
		||||
	kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + pdata->repeat_cnt;
 | 
			
		||||
	kbc->repoll_dly = KBC_ROW_SCAN_DLY + scan_time_rows + kbc->repeat_cnt;
 | 
			
		||||
	kbc->repoll_dly = DIV_ROUND_UP(kbc->repoll_dly, KBC_CYCLE_MS);
 | 
			
		||||
 | 
			
		||||
	kbc->wakeup_key = pdata->wakeup_key;
 | 
			
		||||
	kbc->use_fn_map = pdata->use_fn_map;
 | 
			
		||||
	kbc->use_ghost_filter = pdata->use_ghost_filter;
 | 
			
		||||
	kbc->idev->name = pdev->name;
 | 
			
		||||
	kbc->idev->id.bustype = BUS_HOST;
 | 
			
		||||
	kbc->idev->dev.parent = &pdev->dev;
 | 
			
		||||
	kbc->idev->open = tegra_kbc_open;
 | 
			
		||||
	kbc->idev->close = tegra_kbc_close;
 | 
			
		||||
 | 
			
		||||
	input_dev->name = pdev->name;
 | 
			
		||||
	input_dev->id.bustype = BUS_HOST;
 | 
			
		||||
	input_dev->dev.parent = &pdev->dev;
 | 
			
		||||
	input_dev->open = tegra_kbc_open;
 | 
			
		||||
	input_dev->close = tegra_kbc_close;
 | 
			
		||||
	if (kbc->keymap_data && kbc->use_fn_map)
 | 
			
		||||
		keymap_rows *= 2;
 | 
			
		||||
 | 
			
		||||
	err = tegra_kbd_setup_keymap(kbc);
 | 
			
		||||
	err = matrix_keypad_build_keymap(kbc->keymap_data, NULL,
 | 
			
		||||
					 keymap_rows, KBC_MAX_COL,
 | 
			
		||||
					 kbc->keycode, kbc->idev);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to setup keymap\n");
 | 
			
		||||
		goto err_put_clk;
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__set_bit(EV_REP, input_dev->evbit);
 | 
			
		||||
	input_set_capability(input_dev, EV_MSC, MSC_SCAN);
 | 
			
		||||
	__set_bit(EV_REP, kbc->idev->evbit);
 | 
			
		||||
	input_set_capability(kbc->idev, EV_MSC, MSC_SCAN);
 | 
			
		||||
 | 
			
		||||
	input_set_drvdata(input_dev, kbc);
 | 
			
		||||
	input_set_drvdata(kbc->idev, kbc);
 | 
			
		||||
 | 
			
		||||
	err = request_irq(kbc->irq, tegra_kbc_isr,
 | 
			
		||||
	err = devm_request_irq(&pdev->dev, kbc->irq, tegra_kbc_isr,
 | 
			
		||||
			  IRQF_NO_SUSPEND | IRQF_TRIGGER_HIGH, pdev->name, kbc);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to request keyboard IRQ\n");
 | 
			
		||||
		goto err_put_clk;
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	disable_irq(kbc->irq);
 | 
			
		||||
| 
						 | 
				
			
			@ -812,60 +665,28 @@ static int tegra_kbc_probe(struct platform_device *pdev)
 | 
			
		|||
	err = input_register_device(kbc->idev);
 | 
			
		||||
	if (err) {
 | 
			
		||||
		dev_err(&pdev->dev, "failed to register input device\n");
 | 
			
		||||
		goto err_free_irq;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, kbc);
 | 
			
		||||
	device_init_wakeup(&pdev->dev, pdata->wakeup);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_free_irq:
 | 
			
		||||
	free_irq(kbc->irq, pdev);
 | 
			
		||||
err_put_clk:
 | 
			
		||||
	clk_put(kbc->clk);
 | 
			
		||||
err_iounmap:
 | 
			
		||||
	iounmap(kbc->mmio);
 | 
			
		||||
err_free_mem_region:
 | 
			
		||||
	release_mem_region(res->start, resource_size(res));
 | 
			
		||||
err_free_mem:
 | 
			
		||||
	input_free_device(input_dev);
 | 
			
		||||
	kfree(kbc);
 | 
			
		||||
err_free_pdata:
 | 
			
		||||
	if (!pdev->dev.platform_data)
 | 
			
		||||
		kfree(pdata);
 | 
			
		||||
 | 
			
		||||
		return err;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
static int tegra_kbc_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct tegra_kbc *kbc = platform_get_drvdata(pdev);
 | 
			
		||||
	struct resource *res;
 | 
			
		||||
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
 | 
			
		||||
	free_irq(kbc->irq, pdev);
 | 
			
		||||
	clk_put(kbc->clk);
 | 
			
		||||
 | 
			
		||||
	input_unregister_device(kbc->idev);
 | 
			
		||||
	iounmap(kbc->mmio);
 | 
			
		||||
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 | 
			
		||||
	release_mem_region(res->start, resource_size(res));
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we do not have platform data attached to the device we
 | 
			
		||||
	 * allocated it ourselves and thus need to free it.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!pdev->dev.platform_data)
 | 
			
		||||
		kfree(kbc->pdata);
 | 
			
		||||
 | 
			
		||||
	kfree(kbc);
 | 
			
		||||
	platform_set_drvdata(pdev, kbc);
 | 
			
		||||
	device_init_wakeup(&pdev->dev, kbc->wakeup);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM_SLEEP
 | 
			
		||||
static void tegra_kbc_set_keypress_interrupt(struct tegra_kbc *kbc, bool enable)
 | 
			
		||||
{
 | 
			
		||||
	u32 val;
 | 
			
		||||
 | 
			
		||||
	val = readl(kbc->mmio + KBC_CONTROL_0);
 | 
			
		||||
	if (enable)
 | 
			
		||||
		val |= KBC_CONTROL_KEYPRESS_INT_EN;
 | 
			
		||||
	else
 | 
			
		||||
		val &= ~KBC_CONTROL_KEYPRESS_INT_EN;
 | 
			
		||||
	writel(val, kbc->mmio + KBC_CONTROL_0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int tegra_kbc_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	struct platform_device *pdev = to_platform_device(dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -954,7 +775,6 @@ MODULE_DEVICE_TABLE(of, tegra_kbc_of_match);
 | 
			
		|||
 | 
			
		||||
static struct platform_driver tegra_kbc_driver = {
 | 
			
		||||
	.probe		= tegra_kbc_probe,
 | 
			
		||||
	.remove		= tegra_kbc_remove,
 | 
			
		||||
	.driver	= {
 | 
			
		||||
		.name	= "tegra-kbc",
 | 
			
		||||
		.owner  = THIS_MODULE,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,7 +232,7 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
 | 
			
		|||
 | 
			
		||||
	.ev_code_tap = {BTN_TOUCH, BTN_TOUCH, BTN_TOUCH}, /* EV_KEY {x,y,z} */
 | 
			
		||||
	.power_mode = ADXL_AUTO_SLEEP | ADXL_LINK,
 | 
			
		||||
	.fifo_mode = FIFO_STREAM,
 | 
			
		||||
	.fifo_mode = ADXL_FIFO_STREAM,
 | 
			
		||||
	.watermark = 0,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -732,7 +732,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 | 
			
		|||
	mutex_init(&ac->mutex);
 | 
			
		||||
 | 
			
		||||
	input_dev->name = "ADXL34x accelerometer";
 | 
			
		||||
	revid = ac->bops->read(dev, DEVID);
 | 
			
		||||
	revid = AC_READ(ac, DEVID);
 | 
			
		||||
 | 
			
		||||
	switch (revid) {
 | 
			
		||||
	case ID_ADXL345:
 | 
			
		||||
| 
						 | 
				
			
			@ -809,7 +809,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 | 
			
		|||
	if (FIFO_MODE(pdata->fifo_mode) == FIFO_BYPASS)
 | 
			
		||||
		ac->fifo_delay = false;
 | 
			
		||||
 | 
			
		||||
	ac->bops->write(dev, POWER_CTL, 0);
 | 
			
		||||
	AC_WRITE(ac, POWER_CTL, 0);
 | 
			
		||||
 | 
			
		||||
	err = request_threaded_irq(ac->irq, NULL, adxl34x_irq,
 | 
			
		||||
				   IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
 | 
			
		||||
| 
						 | 
				
			
			@ -827,7 +827,6 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
 | 
			
		|||
	if (err)
 | 
			
		||||
		goto err_remove_attr;
 | 
			
		||||
 | 
			
		||||
	AC_WRITE(ac, THRESH_TAP, pdata->tap_threshold);
 | 
			
		||||
	AC_WRITE(ac, OFSX, pdata->x_axis_offset);
 | 
			
		||||
	ac->hwcal.x = pdata->x_axis_offset;
 | 
			
		||||
	AC_WRITE(ac, OFSY, pdata->y_axis_offset);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -46,18 +46,6 @@
 | 
			
		|||
#define BMA150_POLL_MAX		200
 | 
			
		||||
#define BMA150_POLL_MIN		0
 | 
			
		||||
 | 
			
		||||
#define BMA150_BW_25HZ		0
 | 
			
		||||
#define BMA150_BW_50HZ		1
 | 
			
		||||
#define BMA150_BW_100HZ		2
 | 
			
		||||
#define BMA150_BW_190HZ		3
 | 
			
		||||
#define BMA150_BW_375HZ		4
 | 
			
		||||
#define BMA150_BW_750HZ		5
 | 
			
		||||
#define BMA150_BW_1500HZ	6
 | 
			
		||||
 | 
			
		||||
#define BMA150_RANGE_2G		0
 | 
			
		||||
#define BMA150_RANGE_4G		1
 | 
			
		||||
#define BMA150_RANGE_8G		2
 | 
			
		||||
 | 
			
		||||
#define BMA150_MODE_NORMAL	0
 | 
			
		||||
#define BMA150_MODE_SLEEP	2
 | 
			
		||||
#define BMA150_MODE_WAKE_UP	3
 | 
			
		||||
| 
						 | 
				
			
			@ -372,7 +360,7 @@ static int bma150_open(struct bma150_data *bma150)
 | 
			
		|||
	int error;
 | 
			
		||||
 | 
			
		||||
	error = pm_runtime_get_sync(&bma150->client->dev);
 | 
			
		||||
	if (error && error != -ENOSYS)
 | 
			
		||||
	if (error < 0 && error != -ENOSYS)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -43,7 +43,6 @@ struct vibra_info {
 | 
			
		|||
	struct device		*dev;
 | 
			
		||||
	struct input_dev	*input_dev;
 | 
			
		||||
 | 
			
		||||
	struct workqueue_struct *workqueue;
 | 
			
		||||
	struct work_struct	play_work;
 | 
			
		||||
 | 
			
		||||
	bool			enabled;
 | 
			
		||||
| 
						 | 
				
			
			@ -143,19 +142,7 @@ static int vibra_play(struct input_dev *input, void *data,
 | 
			
		|||
	if (!info->speed)
 | 
			
		||||
		info->speed = effect->u.rumble.weak_magnitude >> 9;
 | 
			
		||||
	info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
 | 
			
		||||
	queue_work(info->workqueue, &info->play_work);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int twl4030_vibra_open(struct input_dev *input)
 | 
			
		||||
{
 | 
			
		||||
	struct vibra_info *info = input_get_drvdata(input);
 | 
			
		||||
 | 
			
		||||
	info->workqueue = create_singlethread_workqueue("vibra");
 | 
			
		||||
	if (info->workqueue == NULL) {
 | 
			
		||||
		dev_err(&input->dev, "couldn't create workqueue\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
	schedule_work(&info->play_work);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -164,9 +151,6 @@ static void twl4030_vibra_close(struct input_dev *input)
 | 
			
		|||
	struct vibra_info *info = input_get_drvdata(input);
 | 
			
		||||
 | 
			
		||||
	cancel_work_sync(&info->play_work);
 | 
			
		||||
	INIT_WORK(&info->play_work, vibra_play_work); /* cleanup */
 | 
			
		||||
	destroy_workqueue(info->workqueue);
 | 
			
		||||
	info->workqueue = NULL;
 | 
			
		||||
 | 
			
		||||
	if (info->enabled)
 | 
			
		||||
		vibra_disable(info);
 | 
			
		||||
| 
						 | 
				
			
			@ -219,7 +203,7 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info = kzalloc(sizeof(*info), GFP_KERNEL);
 | 
			
		||||
	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 | 
			
		||||
	if (!info)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -227,11 +211,10 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
	info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
 | 
			
		||||
	INIT_WORK(&info->play_work, vibra_play_work);
 | 
			
		||||
 | 
			
		||||
	info->input_dev = input_allocate_device();
 | 
			
		||||
	info->input_dev = devm_input_allocate_device(&pdev->dev);
 | 
			
		||||
	if (info->input_dev == NULL) {
 | 
			
		||||
		dev_err(&pdev->dev, "couldn't allocate input device\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto err_kzalloc;
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_set_drvdata(info->input_dev, info);
 | 
			
		||||
| 
						 | 
				
			
			@ -239,14 +222,13 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
	info->input_dev->name = "twl4030:vibrator";
 | 
			
		||||
	info->input_dev->id.version = 1;
 | 
			
		||||
	info->input_dev->dev.parent = pdev->dev.parent;
 | 
			
		||||
	info->input_dev->open = twl4030_vibra_open;
 | 
			
		||||
	info->input_dev->close = twl4030_vibra_close;
 | 
			
		||||
	__set_bit(FF_RUMBLE, info->input_dev->ffbit);
 | 
			
		||||
 | 
			
		||||
	ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
 | 
			
		||||
	if (ret < 0) {
 | 
			
		||||
		dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
 | 
			
		||||
		goto err_ialloc;
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = input_register_device(info->input_dev);
 | 
			
		||||
| 
						 | 
				
			
			@ -262,28 +244,11 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
err_iff:
 | 
			
		||||
	input_ff_destroy(info->input_dev);
 | 
			
		||||
err_ialloc:
 | 
			
		||||
	input_free_device(info->input_dev);
 | 
			
		||||
err_kzalloc:
 | 
			
		||||
	kfree(info);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int twl4030_vibra_remove(struct platform_device *pdev)
 | 
			
		||||
{
 | 
			
		||||
	struct vibra_info *info = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	/* this also free ff-memless and calls close if needed */
 | 
			
		||||
	input_unregister_device(info->input_dev);
 | 
			
		||||
	kfree(info);
 | 
			
		||||
	platform_set_drvdata(pdev, NULL);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct platform_driver twl4030_vibra_driver = {
 | 
			
		||||
	.probe		= twl4030_vibra_probe,
 | 
			
		||||
	.remove		= twl4030_vibra_remove,
 | 
			
		||||
	.driver		= {
 | 
			
		||||
		.name	= "twl4030-vibra",
 | 
			
		||||
		.owner	= THIS_MODULE,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -275,7 +275,7 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info = kzalloc(sizeof(*info), GFP_KERNEL);
 | 
			
		||||
	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 | 
			
		||||
	if (!info) {
 | 
			
		||||
		dev_err(&pdev->dev, "couldn't allocate memory\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
| 
						 | 
				
			
			@ -309,24 +309,65 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
	if ((!info->vibldrv_res && !info->viblmotor_res) ||
 | 
			
		||||
	    (!info->vibrdrv_res && !info->vibrmotor_res)) {
 | 
			
		||||
		dev_err(info->dev, "invalid vibra driver/motor resistance\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto err_kzalloc;
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->irq = platform_get_irq(pdev, 0);
 | 
			
		||||
	if (info->irq < 0) {
 | 
			
		||||
		dev_err(info->dev, "invalid irq\n");
 | 
			
		||||
		ret = -EINVAL;
 | 
			
		||||
		goto err_kzalloc;
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mutex_init(&info->mutex);
 | 
			
		||||
 | 
			
		||||
	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
 | 
			
		||||
					twl6040_vib_irq_handler, 0,
 | 
			
		||||
					"twl6040_irq_vib", info);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->supplies[0].supply = "vddvibl";
 | 
			
		||||
	info->supplies[1].supply = "vddvibr";
 | 
			
		||||
	/*
 | 
			
		||||
	 * When booted with Device tree the regulators are attached to the
 | 
			
		||||
	 * parent device (twl6040 MFD core)
 | 
			
		||||
	 */
 | 
			
		||||
	ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev,
 | 
			
		||||
				 ARRAY_SIZE(info->supplies), info->supplies);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(info->dev, "couldn't get regulators %d\n", ret);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vddvibl_uV) {
 | 
			
		||||
		ret = regulator_set_voltage(info->supplies[0].consumer,
 | 
			
		||||
					    vddvibl_uV, vddvibl_uV);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
 | 
			
		||||
				ret);
 | 
			
		||||
			goto err_regulator;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vddvibr_uV) {
 | 
			
		||||
		ret = regulator_set_voltage(info->supplies[1].consumer,
 | 
			
		||||
					    vddvibr_uV, vddvibr_uV);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
 | 
			
		||||
				ret);
 | 
			
		||||
			goto err_regulator;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	INIT_WORK(&info->play_work, vibra_play_work);
 | 
			
		||||
 | 
			
		||||
	info->input_dev = input_allocate_device();
 | 
			
		||||
	if (info->input_dev == NULL) {
 | 
			
		||||
		dev_err(info->dev, "couldn't allocate input device\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto err_kzalloc;
 | 
			
		||||
		goto err_regulator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_set_drvdata(info->input_dev, info);
 | 
			
		||||
| 
						 | 
				
			
			@ -351,70 +392,14 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	platform_set_drvdata(pdev, info);
 | 
			
		||||
 | 
			
		||||
	ret = request_threaded_irq(info->irq, NULL, twl6040_vib_irq_handler, 0,
 | 
			
		||||
				   "twl6040_irq_vib", info);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(info->dev, "VIB IRQ request failed: %d\n", ret);
 | 
			
		||||
		goto err_irq;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->supplies[0].supply = "vddvibl";
 | 
			
		||||
	info->supplies[1].supply = "vddvibr";
 | 
			
		||||
	/*
 | 
			
		||||
	 * When booted with Device tree the regulators are attached to the
 | 
			
		||||
	 * parent device (twl6040 MFD core)
 | 
			
		||||
	 */
 | 
			
		||||
	ret = regulator_bulk_get(pdata ? info->dev : twl6040_core_dev,
 | 
			
		||||
				 ARRAY_SIZE(info->supplies), info->supplies);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(info->dev, "couldn't get regulators %d\n", ret);
 | 
			
		||||
		goto err_regulator;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vddvibl_uV) {
 | 
			
		||||
		ret = regulator_set_voltage(info->supplies[0].consumer,
 | 
			
		||||
					    vddvibl_uV, vddvibl_uV);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
 | 
			
		||||
				ret);
 | 
			
		||||
			goto err_voltage;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (vddvibr_uV) {
 | 
			
		||||
		ret = regulator_set_voltage(info->supplies[1].consumer,
 | 
			
		||||
					    vddvibr_uV, vddvibr_uV);
 | 
			
		||||
		if (ret) {
 | 
			
		||||
			dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
 | 
			
		||||
				ret);
 | 
			
		||||
			goto err_voltage;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	info->workqueue = alloc_workqueue("twl6040-vibra", 0, 0);
 | 
			
		||||
	if (info->workqueue == NULL) {
 | 
			
		||||
		dev_err(info->dev, "couldn't create workqueue\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
		goto err_voltage;
 | 
			
		||||
	}
 | 
			
		||||
	INIT_WORK(&info->play_work, vibra_play_work);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_voltage:
 | 
			
		||||
	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
 | 
			
		||||
err_regulator:
 | 
			
		||||
	free_irq(info->irq, info);
 | 
			
		||||
err_irq:
 | 
			
		||||
	input_unregister_device(info->input_dev);
 | 
			
		||||
	info->input_dev = NULL;
 | 
			
		||||
err_iff:
 | 
			
		||||
	if (info->input_dev)
 | 
			
		||||
	input_ff_destroy(info->input_dev);
 | 
			
		||||
err_ialloc:
 | 
			
		||||
	input_free_device(info->input_dev);
 | 
			
		||||
err_kzalloc:
 | 
			
		||||
	kfree(info);
 | 
			
		||||
err_regulator:
 | 
			
		||||
	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -423,10 +408,7 @@ static int twl6040_vibra_remove(struct platform_device *pdev)
 | 
			
		|||
	struct vibra_info *info = platform_get_drvdata(pdev);
 | 
			
		||||
 | 
			
		||||
	input_unregister_device(info->input_dev);
 | 
			
		||||
	free_irq(info->irq, info);
 | 
			
		||||
	regulator_bulk_free(ARRAY_SIZE(info->supplies), info->supplies);
 | 
			
		||||
	destroy_workqueue(info->workqueue);
 | 
			
		||||
	kfree(info);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -86,7 +86,7 @@ static int wm831x_on_probe(struct platform_device *pdev)
 | 
			
		|||
	wm831x_on->wm831x = wm831x;
 | 
			
		||||
	INIT_DELAYED_WORK(&wm831x_on->work, wm831x_poll_on);
 | 
			
		||||
 | 
			
		||||
	wm831x_on->dev = input_allocate_device();
 | 
			
		||||
	wm831x_on->dev = devm_input_allocate_device(&pdev->dev);
 | 
			
		||||
	if (!wm831x_on->dev) {
 | 
			
		||||
		dev_err(&pdev->dev, "Can't allocate input dev\n");
 | 
			
		||||
		ret = -ENOMEM;
 | 
			
		||||
| 
						 | 
				
			
			@ -119,7 +119,6 @@ static int wm831x_on_probe(struct platform_device *pdev)
 | 
			
		|||
err_irq:
 | 
			
		||||
	free_irq(irq, wm831x_on);
 | 
			
		||||
err_input_dev:
 | 
			
		||||
	input_free_device(wm831x_on->dev);
 | 
			
		||||
err:
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -131,7 +130,6 @@ static int wm831x_on_remove(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	free_irq(irq, wm831x_on);
 | 
			
		||||
	cancel_delayed_work_sync(&wm831x_on->work);
 | 
			
		||||
	input_unregister_device(wm831x_on->dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -68,6 +68,16 @@ config MOUSE_PS2_SYNAPTICS
 | 
			
		|||
 | 
			
		||||
	  If unsure, say Y.
 | 
			
		||||
 | 
			
		||||
config MOUSE_PS2_CYPRESS
 | 
			
		||||
       bool "Cypress PS/2 mouse protocol extension" if EXPERT
 | 
			
		||||
       default y
 | 
			
		||||
       depends on MOUSE_PS2
 | 
			
		||||
       help
 | 
			
		||||
         Say Y here if you have a Cypress PS/2 Trackpad connected to
 | 
			
		||||
         your system.
 | 
			
		||||
 | 
			
		||||
         If unsure, say Y.
 | 
			
		||||
 | 
			
		||||
config MOUSE_PS2_LIFEBOOK
 | 
			
		||||
	bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT
 | 
			
		||||
	default y
 | 
			
		||||
| 
						 | 
				
			
			@ -193,6 +203,18 @@ config MOUSE_BCM5974
 | 
			
		|||
	  To compile this driver as a module, choose M here: the
 | 
			
		||||
	  module will be called bcm5974.
 | 
			
		||||
 | 
			
		||||
config MOUSE_CYAPA
 | 
			
		||||
	tristate "Cypress APA I2C Trackpad support"
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	help
 | 
			
		||||
	  This driver adds support for Cypress All Points Addressable (APA)
 | 
			
		||||
	  I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
 | 
			
		||||
 | 
			
		||||
	  Say Y here if you have a Cypress APA I2C Trackpad.
 | 
			
		||||
 | 
			
		||||
	  To compile this driver as a module, choose M here: the module will be
 | 
			
		||||
	  called cyapa.
 | 
			
		||||
 | 
			
		||||
config MOUSE_INPORT
 | 
			
		||||
	tristate "InPort/MS/ATIXL busmouse"
 | 
			
		||||
	depends on ISA
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA)		+= amimouse.o
 | 
			
		|||
obj-$(CONFIG_MOUSE_APPLETOUCH)		+= appletouch.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 | 
			
		||||
obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
 | 
			
		||||
| 
						 | 
				
			
			@ -32,3 +33,4 @@ psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK)	+= lifebook.o
 | 
			
		|||
psmouse-$(CONFIG_MOUSE_PS2_SENTELIC)	+= sentelic.o
 | 
			
		||||
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT)	+= trackpoint.o
 | 
			
		||||
psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT)	+= touchkit_ps2.o
 | 
			
		||||
psmouse-$(CONFIG_MOUSE_PS2_CYPRESS)	+= cypress_ps2.o
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -12,35 +12,146 @@
 | 
			
		|||
#ifndef _ALPS_H
 | 
			
		||||
#define _ALPS_H
 | 
			
		||||
 | 
			
		||||
#define ALPS_PROTO_V1	0
 | 
			
		||||
#define ALPS_PROTO_V2	1
 | 
			
		||||
#define ALPS_PROTO_V3	2
 | 
			
		||||
#define ALPS_PROTO_V4	3
 | 
			
		||||
#define ALPS_PROTO_V1	1
 | 
			
		||||
#define ALPS_PROTO_V2	2
 | 
			
		||||
#define ALPS_PROTO_V3	3
 | 
			
		||||
#define ALPS_PROTO_V4	4
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct alps_model_info - touchpad ID table
 | 
			
		||||
 * @signature: E7 response string to match.
 | 
			
		||||
 * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response
 | 
			
		||||
 *   (aka command mode response) identifies the firmware minor version.  This
 | 
			
		||||
 *   can be used to distinguish different hardware models which are not
 | 
			
		||||
 *   uniquely identifiable through their E7 responses.
 | 
			
		||||
 * @proto_version: Indicates V1/V2/V3/...
 | 
			
		||||
 * @byte0: Helps figure out whether a position report packet matches the
 | 
			
		||||
 *   known format for this model.  The first byte of the report, ANDed with
 | 
			
		||||
 *   mask0, should match byte0.
 | 
			
		||||
 * @mask0: The mask used to check the first byte of the report.
 | 
			
		||||
 * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
 | 
			
		||||
 *
 | 
			
		||||
 * Many (but not all) ALPS touchpads can be identified by looking at the
 | 
			
		||||
 * values returned in the "E7 report" and/or the "EC report."  This table
 | 
			
		||||
 * lists a number of such touchpads.
 | 
			
		||||
 */
 | 
			
		||||
struct alps_model_info {
 | 
			
		||||
	unsigned char signature[3];
 | 
			
		||||
	unsigned char command_mode_resp; /* v3/v4 only */
 | 
			
		||||
	unsigned char command_mode_resp;
 | 
			
		||||
	unsigned char proto_version;
 | 
			
		||||
	unsigned char byte0, mask0;
 | 
			
		||||
	unsigned char flags;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct alps_nibble_commands - encodings for register accesses
 | 
			
		||||
 * @command: PS/2 command used for the nibble
 | 
			
		||||
 * @data: Data supplied as an argument to the PS/2 command, if applicable
 | 
			
		||||
 *
 | 
			
		||||
 * The ALPS protocol uses magic sequences to transmit binary data to the
 | 
			
		||||
 * touchpad, as it is generally not OK to send arbitrary bytes out the
 | 
			
		||||
 * PS/2 port.  Each of the sequences in this table sends one nibble of the
 | 
			
		||||
 * register address or (write) data.  Different versions of the ALPS protocol
 | 
			
		||||
 * use slightly different encodings.
 | 
			
		||||
 */
 | 
			
		||||
struct alps_nibble_commands {
 | 
			
		||||
	int command;
 | 
			
		||||
	unsigned char data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct alps_fields - decoded version of the report packet
 | 
			
		||||
 * @x_map: Bitmap of active X positions for MT.
 | 
			
		||||
 * @y_map: Bitmap of active Y positions for MT.
 | 
			
		||||
 * @fingers: Number of fingers for MT.
 | 
			
		||||
 * @x: X position for ST.
 | 
			
		||||
 * @y: Y position for ST.
 | 
			
		||||
 * @z: Z position for ST.
 | 
			
		||||
 * @first_mp: Packet is the first of a multi-packet report.
 | 
			
		||||
 * @is_mp: Packet is part of a multi-packet report.
 | 
			
		||||
 * @left: Left touchpad button is active.
 | 
			
		||||
 * @right: Right touchpad button is active.
 | 
			
		||||
 * @middle: Middle touchpad button is active.
 | 
			
		||||
 * @ts_left: Left trackstick button is active.
 | 
			
		||||
 * @ts_right: Right trackstick button is active.
 | 
			
		||||
 * @ts_middle: Middle trackstick button is active.
 | 
			
		||||
 */
 | 
			
		||||
struct alps_fields {
 | 
			
		||||
	unsigned int x_map;
 | 
			
		||||
	unsigned int y_map;
 | 
			
		||||
	unsigned int fingers;
 | 
			
		||||
	unsigned int x;
 | 
			
		||||
	unsigned int y;
 | 
			
		||||
	unsigned int z;
 | 
			
		||||
	unsigned int first_mp:1;
 | 
			
		||||
	unsigned int is_mp:1;
 | 
			
		||||
 | 
			
		||||
	unsigned int left:1;
 | 
			
		||||
	unsigned int right:1;
 | 
			
		||||
	unsigned int middle:1;
 | 
			
		||||
 | 
			
		||||
	unsigned int ts_left:1;
 | 
			
		||||
	unsigned int ts_right:1;
 | 
			
		||||
	unsigned int ts_middle:1;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * struct alps_data - private data structure for the ALPS driver
 | 
			
		||||
 * @dev2: "Relative" device used to report trackstick or mouse activity.
 | 
			
		||||
 * @phys: Physical path for the relative device.
 | 
			
		||||
 * @nibble_commands: Command mapping used for touchpad register accesses.
 | 
			
		||||
 * @addr_command: Command used to tell the touchpad that a register address
 | 
			
		||||
 *   follows.
 | 
			
		||||
 * @proto_version: Indicates V1/V2/V3/...
 | 
			
		||||
 * @byte0: Helps figure out whether a position report packet matches the
 | 
			
		||||
 *   known format for this model.  The first byte of the report, ANDed with
 | 
			
		||||
 *   mask0, should match byte0.
 | 
			
		||||
 * @mask0: The mask used to check the first byte of the report.
 | 
			
		||||
 * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
 | 
			
		||||
 * @x_max: Largest possible X position value.
 | 
			
		||||
 * @y_max: Largest possible Y position value.
 | 
			
		||||
 * @x_bits: Number of X bits in the MT bitmap.
 | 
			
		||||
 * @y_bits: Number of Y bits in the MT bitmap.
 | 
			
		||||
 * @hw_init: Protocol-specific hardware init function.
 | 
			
		||||
 * @process_packet: Protocol-specific function to process a report packet.
 | 
			
		||||
 * @decode_fields: Protocol-specific function to read packet bitfields.
 | 
			
		||||
 * @set_abs_params: Protocol-specific function to configure the input_dev.
 | 
			
		||||
 * @prev_fin: Finger bit from previous packet.
 | 
			
		||||
 * @multi_packet: Multi-packet data in progress.
 | 
			
		||||
 * @multi_data: Saved multi-packet data.
 | 
			
		||||
 * @x1: First X coordinate from last MT report.
 | 
			
		||||
 * @x2: Second X coordinate from last MT report.
 | 
			
		||||
 * @y1: First Y coordinate from last MT report.
 | 
			
		||||
 * @y2: Second Y coordinate from last MT report.
 | 
			
		||||
 * @fingers: Number of fingers from last MT report.
 | 
			
		||||
 * @quirks: Bitmap of ALPS_QUIRK_*.
 | 
			
		||||
 * @timer: Timer for flushing out the final report packet in the stream.
 | 
			
		||||
 */
 | 
			
		||||
struct alps_data {
 | 
			
		||||
	struct input_dev *dev2;		/* Relative device */
 | 
			
		||||
	char phys[32];			/* Phys */
 | 
			
		||||
	const struct alps_model_info *i;/* Info */
 | 
			
		||||
	struct input_dev *dev2;
 | 
			
		||||
	char phys[32];
 | 
			
		||||
 | 
			
		||||
	/* these are autodetected when the device is identified */
 | 
			
		||||
	const struct alps_nibble_commands *nibble_commands;
 | 
			
		||||
	int addr_command;		/* Command to set register address */
 | 
			
		||||
	int prev_fin;			/* Finger bit from previous packet */
 | 
			
		||||
	int multi_packet;		/* Multi-packet data in progress */
 | 
			
		||||
	unsigned char multi_data[6];	/* Saved multi-packet data */
 | 
			
		||||
	int x1, x2, y1, y2;		/* Coordinates from last MT report */
 | 
			
		||||
	int fingers;			/* Number of fingers from MT report */
 | 
			
		||||
	int addr_command;
 | 
			
		||||
	unsigned char proto_version;
 | 
			
		||||
	unsigned char byte0, mask0;
 | 
			
		||||
	unsigned char flags;
 | 
			
		||||
	int x_max;
 | 
			
		||||
	int y_max;
 | 
			
		||||
	int x_bits;
 | 
			
		||||
	int y_bits;
 | 
			
		||||
 | 
			
		||||
	int (*hw_init)(struct psmouse *psmouse);
 | 
			
		||||
	void (*process_packet)(struct psmouse *psmouse);
 | 
			
		||||
	void (*decode_fields)(struct alps_fields *f, unsigned char *p);
 | 
			
		||||
	void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
 | 
			
		||||
 | 
			
		||||
	int prev_fin;
 | 
			
		||||
	int multi_packet;
 | 
			
		||||
	unsigned char multi_data[6];
 | 
			
		||||
	int x1, x2, y1, y2;
 | 
			
		||||
	int fingers;
 | 
			
		||||
	u8 quirks;
 | 
			
		||||
	struct timer_list timer;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										973
									
								
								drivers/input/mouse/cyapa.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										973
									
								
								drivers/input/mouse/cyapa.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,973 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Cypress APA trackpad with I2C interface
 | 
			
		||||
 *
 | 
			
		||||
 * Author: Dudley Du <dudl@cypress.com>
 | 
			
		||||
 * Further cleanup and restructuring by:
 | 
			
		||||
 *   Daniel Kurtz <djkurtz@chromium.org>
 | 
			
		||||
 *   Benson Leung <bleung@chromium.org>
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2011-2012 Cypress Semiconductor, Inc.
 | 
			
		||||
 * Copyright (C) 2011-2012 Google, Inc.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is subject to the terms and conditions of the GNU General Public
 | 
			
		||||
 * License.  See the file COPYING in the main directory of this archive for
 | 
			
		||||
 * more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/delay.h>
 | 
			
		||||
#include <linux/i2c.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <linux/input/mt.h>
 | 
			
		||||
#include <linux/interrupt.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
 | 
			
		||||
/* APA trackpad firmware generation */
 | 
			
		||||
#define CYAPA_GEN3   0x03   /* support MT-protocol B with tracking ID. */
 | 
			
		||||
 | 
			
		||||
#define CYAPA_NAME   "Cypress APA Trackpad (cyapa)"
 | 
			
		||||
 | 
			
		||||
/* commands for read/write registers of Cypress trackpad */
 | 
			
		||||
#define CYAPA_CMD_SOFT_RESET       0x00
 | 
			
		||||
#define CYAPA_CMD_POWER_MODE       0x01
 | 
			
		||||
#define CYAPA_CMD_DEV_STATUS       0x02
 | 
			
		||||
#define CYAPA_CMD_GROUP_DATA       0x03
 | 
			
		||||
#define CYAPA_CMD_GROUP_CMD        0x04
 | 
			
		||||
#define CYAPA_CMD_GROUP_QUERY      0x05
 | 
			
		||||
#define CYAPA_CMD_BL_STATUS        0x06
 | 
			
		||||
#define CYAPA_CMD_BL_HEAD          0x07
 | 
			
		||||
#define CYAPA_CMD_BL_CMD           0x08
 | 
			
		||||
#define CYAPA_CMD_BL_DATA          0x09
 | 
			
		||||
#define CYAPA_CMD_BL_ALL           0x0a
 | 
			
		||||
#define CYAPA_CMD_BLK_PRODUCT_ID   0x0b
 | 
			
		||||
#define CYAPA_CMD_BLK_HEAD         0x0c
 | 
			
		||||
 | 
			
		||||
/* report data start reg offset address. */
 | 
			
		||||
#define DATA_REG_START_OFFSET  0x0000
 | 
			
		||||
 | 
			
		||||
#define BL_HEAD_OFFSET 0x00
 | 
			
		||||
#define BL_DATA_OFFSET 0x10
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Operational Device Status Register
 | 
			
		||||
 *
 | 
			
		||||
 * bit 7: Valid interrupt source
 | 
			
		||||
 * bit 6 - 4: Reserved
 | 
			
		||||
 * bit 3 - 2: Power status
 | 
			
		||||
 * bit 1 - 0: Device status
 | 
			
		||||
 */
 | 
			
		||||
#define REG_OP_STATUS     0x00
 | 
			
		||||
#define OP_STATUS_SRC     0x80
 | 
			
		||||
#define OP_STATUS_POWER   0x0c
 | 
			
		||||
#define OP_STATUS_DEV     0x03
 | 
			
		||||
#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Operational Finger Count/Button Flags Register
 | 
			
		||||
 *
 | 
			
		||||
 * bit 7 - 4: Number of touched finger
 | 
			
		||||
 * bit 3: Valid data
 | 
			
		||||
 * bit 2: Middle Physical Button
 | 
			
		||||
 * bit 1: Right Physical Button
 | 
			
		||||
 * bit 0: Left physical Button
 | 
			
		||||
 */
 | 
			
		||||
#define REG_OP_DATA1       0x01
 | 
			
		||||
#define OP_DATA_VALID      0x08
 | 
			
		||||
#define OP_DATA_MIDDLE_BTN 0x04
 | 
			
		||||
#define OP_DATA_RIGHT_BTN  0x02
 | 
			
		||||
#define OP_DATA_LEFT_BTN   0x01
 | 
			
		||||
#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
 | 
			
		||||
			  OP_DATA_LEFT_BTN)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Bootloader Status Register
 | 
			
		||||
 *
 | 
			
		||||
 * bit 7: Busy
 | 
			
		||||
 * bit 6 - 5: Reserved
 | 
			
		||||
 * bit 4: Bootloader running
 | 
			
		||||
 * bit 3 - 1: Reserved
 | 
			
		||||
 * bit 0: Checksum valid
 | 
			
		||||
 */
 | 
			
		||||
#define REG_BL_STATUS        0x01
 | 
			
		||||
#define BL_STATUS_BUSY       0x80
 | 
			
		||||
#define BL_STATUS_RUNNING    0x10
 | 
			
		||||
#define BL_STATUS_DATA_VALID 0x08
 | 
			
		||||
#define BL_STATUS_CSUM_VALID 0x01
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Bootloader Error Register
 | 
			
		||||
 *
 | 
			
		||||
 * bit 7: Invalid
 | 
			
		||||
 * bit 6: Invalid security key
 | 
			
		||||
 * bit 5: Bootloading
 | 
			
		||||
 * bit 4: Command checksum
 | 
			
		||||
 * bit 3: Flash protection error
 | 
			
		||||
 * bit 2: Flash checksum error
 | 
			
		||||
 * bit 1 - 0: Reserved
 | 
			
		||||
 */
 | 
			
		||||
#define REG_BL_ERROR         0x02
 | 
			
		||||
#define BL_ERROR_INVALID     0x80
 | 
			
		||||
#define BL_ERROR_INVALID_KEY 0x40
 | 
			
		||||
#define BL_ERROR_BOOTLOADING 0x20
 | 
			
		||||
#define BL_ERROR_CMD_CSUM    0x10
 | 
			
		||||
#define BL_ERROR_FLASH_PROT  0x08
 | 
			
		||||
#define BL_ERROR_FLASH_CSUM  0x04
 | 
			
		||||
 | 
			
		||||
#define BL_STATUS_SIZE  3  /* length of bootloader status registers */
 | 
			
		||||
#define BLK_HEAD_BYTES 32
 | 
			
		||||
 | 
			
		||||
#define PRODUCT_ID_SIZE  16
 | 
			
		||||
#define QUERY_DATA_SIZE  27
 | 
			
		||||
#define REG_PROTOCOL_GEN_QUERY_OFFSET  20
 | 
			
		||||
 | 
			
		||||
#define REG_OFFSET_DATA_BASE     0x0000
 | 
			
		||||
#define REG_OFFSET_COMMAND_BASE  0x0028
 | 
			
		||||
#define REG_OFFSET_QUERY_BASE    0x002a
 | 
			
		||||
 | 
			
		||||
#define CAPABILITY_LEFT_BTN_MASK	(0x01 << 3)
 | 
			
		||||
#define CAPABILITY_RIGHT_BTN_MASK	(0x01 << 4)
 | 
			
		||||
#define CAPABILITY_MIDDLE_BTN_MASK	(0x01 << 5)
 | 
			
		||||
#define CAPABILITY_BTN_MASK  (CAPABILITY_LEFT_BTN_MASK | \
 | 
			
		||||
			      CAPABILITY_RIGHT_BTN_MASK | \
 | 
			
		||||
			      CAPABILITY_MIDDLE_BTN_MASK)
 | 
			
		||||
 | 
			
		||||
#define CYAPA_OFFSET_SOFT_RESET  REG_OFFSET_COMMAND_BASE
 | 
			
		||||
 | 
			
		||||
#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1)
 | 
			
		||||
 | 
			
		||||
#define PWR_MODE_MASK   0xfc
 | 
			
		||||
#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
 | 
			
		||||
#define PWR_MODE_IDLE        (0x05 << 2) /* default sleep time is 50 ms. */
 | 
			
		||||
#define PWR_MODE_OFF         (0x00 << 2)
 | 
			
		||||
 | 
			
		||||
#define PWR_STATUS_MASK      0x0c
 | 
			
		||||
#define PWR_STATUS_ACTIVE    (0x03 << 2)
 | 
			
		||||
#define PWR_STATUS_IDLE      (0x02 << 2)
 | 
			
		||||
#define PWR_STATUS_OFF       (0x00 << 2)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * CYAPA trackpad device states.
 | 
			
		||||
 * Used in register 0x00, bit1-0, DeviceStatus field.
 | 
			
		||||
 * Other values indicate device is in an abnormal state and must be reset.
 | 
			
		||||
 */
 | 
			
		||||
#define CYAPA_DEV_NORMAL  0x03
 | 
			
		||||
#define CYAPA_DEV_BUSY    0x01
 | 
			
		||||
 | 
			
		||||
enum cyapa_state {
 | 
			
		||||
	CYAPA_STATE_OP,
 | 
			
		||||
	CYAPA_STATE_BL_IDLE,
 | 
			
		||||
	CYAPA_STATE_BL_ACTIVE,
 | 
			
		||||
	CYAPA_STATE_BL_BUSY,
 | 
			
		||||
	CYAPA_STATE_NO_DEVICE,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
struct cyapa_touch {
 | 
			
		||||
	/*
 | 
			
		||||
	 * high bits or x/y position value
 | 
			
		||||
	 * bit 7 - 4: high 4 bits of x position value
 | 
			
		||||
	 * bit 3 - 0: high 4 bits of y position value
 | 
			
		||||
	 */
 | 
			
		||||
	u8 xy_hi;
 | 
			
		||||
	u8 x_lo;  /* low 8 bits of x position value. */
 | 
			
		||||
	u8 y_lo;  /* low 8 bits of y position value. */
 | 
			
		||||
	u8 pressure;
 | 
			
		||||
	/* id range is 1 - 15.  It is incremented with every new touch. */
 | 
			
		||||
	u8 id;
 | 
			
		||||
} __packed;
 | 
			
		||||
 | 
			
		||||
/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
 | 
			
		||||
#define CYAPA_MAX_MT_SLOTS  15
 | 
			
		||||
 | 
			
		||||
struct cyapa_reg_data {
 | 
			
		||||
	/*
 | 
			
		||||
	 * bit 0 - 1: device status
 | 
			
		||||
	 * bit 3 - 2: power mode
 | 
			
		||||
	 * bit 6 - 4: reserved
 | 
			
		||||
	 * bit 7: interrupt valid bit
 | 
			
		||||
	 */
 | 
			
		||||
	u8 device_status;
 | 
			
		||||
	/*
 | 
			
		||||
	 * bit 7 - 4: number of fingers currently touching pad
 | 
			
		||||
	 * bit 3: valid data check bit
 | 
			
		||||
	 * bit 2: middle mechanism button state if exists
 | 
			
		||||
	 * bit 1: right mechanism button state if exists
 | 
			
		||||
	 * bit 0: left mechanism button state if exists
 | 
			
		||||
	 */
 | 
			
		||||
	u8 finger_btn;
 | 
			
		||||
	/* CYAPA reports up to 5 touches per packet. */
 | 
			
		||||
	struct cyapa_touch touches[5];
 | 
			
		||||
} __packed;
 | 
			
		||||
 | 
			
		||||
/* The main device structure */
 | 
			
		||||
struct cyapa {
 | 
			
		||||
	enum cyapa_state state;
 | 
			
		||||
 | 
			
		||||
	struct i2c_client *client;
 | 
			
		||||
	struct input_dev *input;
 | 
			
		||||
	char phys[32];	/* device physical location */
 | 
			
		||||
	int irq;
 | 
			
		||||
	bool irq_wake;  /* irq wake is enabled */
 | 
			
		||||
	bool smbus;
 | 
			
		||||
 | 
			
		||||
	/* read from query data region. */
 | 
			
		||||
	char product_id[16];
 | 
			
		||||
	u8 btn_capability;
 | 
			
		||||
	u8 gen;
 | 
			
		||||
	int max_abs_x;
 | 
			
		||||
	int max_abs_y;
 | 
			
		||||
	int physical_size_x;
 | 
			
		||||
	int physical_size_y;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03,
 | 
			
		||||
		0x04, 0x05, 0x06, 0x07 };
 | 
			
		||||
static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
 | 
			
		||||
		0x05, 0x06, 0x07 };
 | 
			
		||||
 | 
			
		||||
struct cyapa_cmd_len {
 | 
			
		||||
	u8 cmd;
 | 
			
		||||
	u8 len;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define CYAPA_ADAPTER_FUNC_NONE   0
 | 
			
		||||
#define CYAPA_ADAPTER_FUNC_I2C    1
 | 
			
		||||
#define CYAPA_ADAPTER_FUNC_SMBUS  2
 | 
			
		||||
#define CYAPA_ADAPTER_FUNC_BOTH   3
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * macros for SMBus communication
 | 
			
		||||
 */
 | 
			
		||||
#define SMBUS_READ   0x01
 | 
			
		||||
#define SMBUS_WRITE 0x00
 | 
			
		||||
#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
 | 
			
		||||
#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
 | 
			
		||||
#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
 | 
			
		||||
#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
 | 
			
		||||
 | 
			
		||||
 /* for byte read/write command */
 | 
			
		||||
#define CMD_RESET 0
 | 
			
		||||
#define CMD_POWER_MODE 1
 | 
			
		||||
#define CMD_DEV_STATUS 2
 | 
			
		||||
#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
 | 
			
		||||
#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
 | 
			
		||||
#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
 | 
			
		||||
#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
 | 
			
		||||
 | 
			
		||||
 /* for group registers read/write command */
 | 
			
		||||
#define REG_GROUP_DATA 0
 | 
			
		||||
#define REG_GROUP_CMD 2
 | 
			
		||||
#define REG_GROUP_QUERY 3
 | 
			
		||||
#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
 | 
			
		||||
#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
 | 
			
		||||
#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
 | 
			
		||||
#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
 | 
			
		||||
 | 
			
		||||
 /* for register block read/write command */
 | 
			
		||||
#define CMD_BL_STATUS 0
 | 
			
		||||
#define CMD_BL_HEAD 1
 | 
			
		||||
#define CMD_BL_CMD 2
 | 
			
		||||
#define CMD_BL_DATA 3
 | 
			
		||||
#define CMD_BL_ALL 4
 | 
			
		||||
#define CMD_BLK_PRODUCT_ID 5
 | 
			
		||||
#define CMD_BLK_HEAD 6
 | 
			
		||||
#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
 | 
			
		||||
 | 
			
		||||
/* register block read/write command in bootloader mode */
 | 
			
		||||
#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
 | 
			
		||||
#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
 | 
			
		||||
#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
 | 
			
		||||
#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
 | 
			
		||||
#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
 | 
			
		||||
 | 
			
		||||
/* register block read/write command in operational mode */
 | 
			
		||||
#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
 | 
			
		||||
#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
 | 
			
		||||
 | 
			
		||||
static const struct cyapa_cmd_len cyapa_i2c_cmds[] = {
 | 
			
		||||
	{ CYAPA_OFFSET_SOFT_RESET, 1 },
 | 
			
		||||
	{ REG_OFFSET_COMMAND_BASE + 1, 1 },
 | 
			
		||||
	{ REG_OFFSET_DATA_BASE, 1 },
 | 
			
		||||
	{ REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) },
 | 
			
		||||
	{ REG_OFFSET_COMMAND_BASE, 0 },
 | 
			
		||||
	{ REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE },
 | 
			
		||||
	{ BL_HEAD_OFFSET, 3 },
 | 
			
		||||
	{ BL_HEAD_OFFSET, 16 },
 | 
			
		||||
	{ BL_HEAD_OFFSET, 16 },
 | 
			
		||||
	{ BL_DATA_OFFSET, 16 },
 | 
			
		||||
	{ BL_HEAD_OFFSET, 32 },
 | 
			
		||||
	{ REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE },
 | 
			
		||||
	{ REG_OFFSET_DATA_BASE, 32 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
 | 
			
		||||
	{ CYAPA_SMBUS_RESET, 1 },
 | 
			
		||||
	{ CYAPA_SMBUS_POWER_MODE, 1 },
 | 
			
		||||
	{ CYAPA_SMBUS_DEV_STATUS, 1 },
 | 
			
		||||
	{ CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) },
 | 
			
		||||
	{ CYAPA_SMBUS_GROUP_CMD, 2 },
 | 
			
		||||
	{ CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE },
 | 
			
		||||
	{ CYAPA_SMBUS_BL_STATUS, 3 },
 | 
			
		||||
	{ CYAPA_SMBUS_BL_HEAD, 16 },
 | 
			
		||||
	{ CYAPA_SMBUS_BL_CMD, 16 },
 | 
			
		||||
	{ CYAPA_SMBUS_BL_DATA, 16 },
 | 
			
		||||
	{ CYAPA_SMBUS_BL_ALL, 32 },
 | 
			
		||||
	{ CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE },
 | 
			
		||||
	{ CYAPA_SMBUS_BLK_HEAD, 16 },
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
 | 
			
		||||
					u8 *values)
 | 
			
		||||
{
 | 
			
		||||
	return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
 | 
			
		||||
					 size_t len, const u8 *values)
 | 
			
		||||
{
 | 
			
		||||
	return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * cyapa_smbus_read_block - perform smbus block read command
 | 
			
		||||
 * @cyapa  - private data structure of the driver
 | 
			
		||||
 * @cmd    - the properly encoded smbus command
 | 
			
		||||
 * @len    - expected length of smbus command result
 | 
			
		||||
 * @values - buffer to store smbus command result
 | 
			
		||||
 *
 | 
			
		||||
 * Returns negative errno, else the number of bytes written.
 | 
			
		||||
 *
 | 
			
		||||
 * Note:
 | 
			
		||||
 * In trackpad device, the memory block allocated for I2C register map
 | 
			
		||||
 * is 256 bytes, so the max read block for I2C bus is 256 bytes.
 | 
			
		||||
 */
 | 
			
		||||
static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
 | 
			
		||||
				      u8 *values)
 | 
			
		||||
{
 | 
			
		||||
	ssize_t ret;
 | 
			
		||||
	u8 index;
 | 
			
		||||
	u8 smbus_cmd;
 | 
			
		||||
	u8 *buf;
 | 
			
		||||
	struct i2c_client *client = cyapa->client;
 | 
			
		||||
 | 
			
		||||
	if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd))
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) {
 | 
			
		||||
		/* read specific block registers command. */
 | 
			
		||||
		smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
 | 
			
		||||
		ret = i2c_smbus_read_block_data(client, smbus_cmd, values);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = 0;
 | 
			
		||||
	for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
 | 
			
		||||
		smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
 | 
			
		||||
		smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
 | 
			
		||||
		buf = values + I2C_SMBUS_BLOCK_MAX * index;
 | 
			
		||||
		ret = i2c_smbus_read_block_data(client, smbus_cmd, buf);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return ret > 0 ? len : ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx)
 | 
			
		||||
{
 | 
			
		||||
	u8 cmd;
 | 
			
		||||
 | 
			
		||||
	if (cyapa->smbus) {
 | 
			
		||||
		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
 | 
			
		||||
		cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
 | 
			
		||||
	}
 | 
			
		||||
	return i2c_smbus_read_byte_data(cyapa->client, cmd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value)
 | 
			
		||||
{
 | 
			
		||||
	u8 cmd;
 | 
			
		||||
 | 
			
		||||
	if (cyapa->smbus) {
 | 
			
		||||
		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
 | 
			
		||||
		cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE);
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
 | 
			
		||||
	}
 | 
			
		||||
	return i2c_smbus_write_byte_data(cyapa->client, cmd, value);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
 | 
			
		||||
{
 | 
			
		||||
	u8 cmd;
 | 
			
		||||
	size_t len;
 | 
			
		||||
 | 
			
		||||
	if (cyapa->smbus) {
 | 
			
		||||
		cmd = cyapa_smbus_cmds[cmd_idx].cmd;
 | 
			
		||||
		len = cyapa_smbus_cmds[cmd_idx].len;
 | 
			
		||||
		return cyapa_smbus_read_block(cyapa, cmd, len, values);
 | 
			
		||||
	} else {
 | 
			
		||||
		cmd = cyapa_i2c_cmds[cmd_idx].cmd;
 | 
			
		||||
		len = cyapa_i2c_cmds[cmd_idx].len;
 | 
			
		||||
		return cyapa_i2c_reg_read_block(cyapa, cmd, len, values);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Query device for its current operating state.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int cyapa_get_state(struct cyapa *cyapa)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 status[BL_STATUS_SIZE];
 | 
			
		||||
 | 
			
		||||
	cyapa->state = CYAPA_STATE_NO_DEVICE;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Get trackpad status by reading 3 registers starting from 0.
 | 
			
		||||
	 * If the device is in the bootloader, this will be BL_HEAD.
 | 
			
		||||
	 * If the device is in operation mode, this will be the DATA regs.
 | 
			
		||||
	 *
 | 
			
		||||
	 */
 | 
			
		||||
	ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
 | 
			
		||||
				       status);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * On smbus systems in OP mode, the i2c_reg_read will fail with
 | 
			
		||||
	 * -ETIMEDOUT.  In this case, try again using the smbus equivalent
 | 
			
		||||
	 * command.  This should return a BL_HEAD indicating CYAPA_STATE_OP.
 | 
			
		||||
	 */
 | 
			
		||||
	if (cyapa->smbus && (ret == -ETIMEDOUT || ret == -ENXIO))
 | 
			
		||||
		ret = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status);
 | 
			
		||||
 | 
			
		||||
	if (ret != BL_STATUS_SIZE)
 | 
			
		||||
		goto error;
 | 
			
		||||
 | 
			
		||||
	if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) {
 | 
			
		||||
		switch (status[REG_OP_STATUS] & OP_STATUS_DEV) {
 | 
			
		||||
		case CYAPA_DEV_NORMAL:
 | 
			
		||||
		case CYAPA_DEV_BUSY:
 | 
			
		||||
			cyapa->state = CYAPA_STATE_OP;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			ret = -EAGAIN;
 | 
			
		||||
			goto error;
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if (status[REG_BL_STATUS] & BL_STATUS_BUSY)
 | 
			
		||||
			cyapa->state = CYAPA_STATE_BL_BUSY;
 | 
			
		||||
		else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING)
 | 
			
		||||
			cyapa->state = CYAPA_STATE_BL_ACTIVE;
 | 
			
		||||
		else
 | 
			
		||||
			cyapa->state = CYAPA_STATE_BL_IDLE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
error:
 | 
			
		||||
	return (ret < 0) ? ret : -EAGAIN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Poll device for its status in a loop, waiting up to timeout for a response.
 | 
			
		||||
 *
 | 
			
		||||
 * When the device switches state, it usually takes ~300 ms.
 | 
			
		||||
 * However, when running a new firmware image, the device must calibrate its
 | 
			
		||||
 * sensors, which can take as long as 2 seconds.
 | 
			
		||||
 *
 | 
			
		||||
 * Note: The timeout has granularity of the polling rate, which is 100 ms.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *   0 when the device eventually responds with a valid non-busy state.
 | 
			
		||||
 *   -ETIMEDOUT if device never responds (too many -EAGAIN)
 | 
			
		||||
 *   < 0    other errors
 | 
			
		||||
 */
 | 
			
		||||
static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	int tries = timeout / 100;
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_get_state(cyapa);
 | 
			
		||||
	while ((ret || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
 | 
			
		||||
		msleep(100);
 | 
			
		||||
		ret = cyapa_get_state(cyapa);
 | 
			
		||||
	}
 | 
			
		||||
	return (ret == -EAGAIN || ret == -ETIMEDOUT) ? -ETIMEDOUT : ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cyapa_bl_deactivate(struct cyapa *cyapa)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
 | 
			
		||||
					bl_deactivate);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/* wait for bootloader to switch to idle state; should take < 100ms */
 | 
			
		||||
	msleep(100);
 | 
			
		||||
	ret = cyapa_poll_state(cyapa, 500);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
	if (cyapa->state != CYAPA_STATE_BL_IDLE)
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Exit bootloader
 | 
			
		||||
 *
 | 
			
		||||
 * Send bl_exit command, then wait 50 - 100 ms to let device transition to
 | 
			
		||||
 * operational mode.  If this is the first time the device's firmware is
 | 
			
		||||
 * running, it can take up to 2 seconds to calibrate its sensors.  So, poll
 | 
			
		||||
 * the device's new state for up to 2 seconds.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *   -EIO    failure while reading from device
 | 
			
		||||
 *   -EAGAIN device is stuck in bootloader, b/c it has invalid firmware
 | 
			
		||||
 *   0       device is supported and in operational mode
 | 
			
		||||
 */
 | 
			
		||||
static int cyapa_bl_exit(struct cyapa *cyapa)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Wait for bootloader to exit, and operation mode to start.
 | 
			
		||||
	 * Normally, this takes at least 50 ms.
 | 
			
		||||
	 */
 | 
			
		||||
	usleep_range(50000, 100000);
 | 
			
		||||
	/*
 | 
			
		||||
	 * In addition, when a device boots for the first time after being
 | 
			
		||||
	 * updated to new firmware, it must first calibrate its sensors, which
 | 
			
		||||
	 * can take up to an additional 2 seconds.
 | 
			
		||||
	 */
 | 
			
		||||
	ret = cyapa_poll_state(cyapa, 2000);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
	if (cyapa->state != CYAPA_STATE_OP)
 | 
			
		||||
		return -EAGAIN;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set device power mode
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &cyapa->client->dev;
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 power;
 | 
			
		||||
 | 
			
		||||
	if (cyapa->state != CYAPA_STATE_OP)
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	power = ret & ~PWR_MODE_MASK;
 | 
			
		||||
	power |= power_mode & PWR_MODE_MASK;
 | 
			
		||||
	ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
 | 
			
		||||
			power_mode, ret);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cyapa_get_query_data(struct cyapa *cyapa)
 | 
			
		||||
{
 | 
			
		||||
	u8 query_data[QUERY_DATA_SIZE];
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (cyapa->state != CYAPA_STATE_OP)
 | 
			
		||||
		return -EBUSY;
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
	if (ret != QUERY_DATA_SIZE)
 | 
			
		||||
		return -EIO;
 | 
			
		||||
 | 
			
		||||
	memcpy(&cyapa->product_id[0], &query_data[0], 5);
 | 
			
		||||
	cyapa->product_id[5] = '-';
 | 
			
		||||
	memcpy(&cyapa->product_id[6], &query_data[5], 6);
 | 
			
		||||
	cyapa->product_id[12] = '-';
 | 
			
		||||
	memcpy(&cyapa->product_id[13], &query_data[11], 2);
 | 
			
		||||
	cyapa->product_id[15] = '\0';
 | 
			
		||||
 | 
			
		||||
	cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK;
 | 
			
		||||
 | 
			
		||||
	cyapa->gen = query_data[20] & 0x0f;
 | 
			
		||||
 | 
			
		||||
	cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22];
 | 
			
		||||
	cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23];
 | 
			
		||||
 | 
			
		||||
	cyapa->physical_size_x =
 | 
			
		||||
		((query_data[24] & 0xf0) << 4) | query_data[25];
 | 
			
		||||
	cyapa->physical_size_y =
 | 
			
		||||
		((query_data[24] & 0x0f) << 8) | query_data[26];
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Check if device is operational.
 | 
			
		||||
 *
 | 
			
		||||
 * An operational device is responding, has exited bootloader, and has
 | 
			
		||||
 * firmware supported by this driver.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns:
 | 
			
		||||
 *   -EBUSY  no device or in bootloader
 | 
			
		||||
 *   -EIO    failure while reading from device
 | 
			
		||||
 *   -EAGAIN device is still in bootloader
 | 
			
		||||
 *           if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
 | 
			
		||||
 *   -EINVAL device is in operational mode, but not supported by this driver
 | 
			
		||||
 *   0       device is supported
 | 
			
		||||
 */
 | 
			
		||||
static int cyapa_check_is_operational(struct cyapa *cyapa)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &cyapa->client->dev;
 | 
			
		||||
	static const char unique_str[] = "CYTRA";
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_poll_state(cyapa, 2000);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
	switch (cyapa->state) {
 | 
			
		||||
	case CYAPA_STATE_BL_ACTIVE:
 | 
			
		||||
		ret = cyapa_bl_deactivate(cyapa);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
	/* Fallthrough state */
 | 
			
		||||
	case CYAPA_STATE_BL_IDLE:
 | 
			
		||||
		ret = cyapa_bl_exit(cyapa);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
	/* Fallthrough state */
 | 
			
		||||
	case CYAPA_STATE_OP:
 | 
			
		||||
		ret = cyapa_get_query_data(cyapa);
 | 
			
		||||
		if (ret < 0)
 | 
			
		||||
			return ret;
 | 
			
		||||
 | 
			
		||||
		/* only support firmware protocol gen3 */
 | 
			
		||||
		if (cyapa->gen != CYAPA_GEN3) {
 | 
			
		||||
			dev_err(dev, "unsupported protocol version (%d)",
 | 
			
		||||
				cyapa->gen);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/* only support product ID starting with CYTRA */
 | 
			
		||||
		if (memcmp(cyapa->product_id, unique_str,
 | 
			
		||||
			   sizeof(unique_str) - 1) != 0) {
 | 
			
		||||
			dev_err(dev, "unsupported product ID (%s)\n",
 | 
			
		||||
				cyapa->product_id);
 | 
			
		||||
			return -EINVAL;
 | 
			
		||||
		}
 | 
			
		||||
		return 0;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static irqreturn_t cyapa_irq(int irq, void *dev_id)
 | 
			
		||||
{
 | 
			
		||||
	struct cyapa *cyapa = dev_id;
 | 
			
		||||
	struct device *dev = &cyapa->client->dev;
 | 
			
		||||
	struct input_dev *input = cyapa->input;
 | 
			
		||||
	struct cyapa_reg_data data;
 | 
			
		||||
	int i;
 | 
			
		||||
	int ret;
 | 
			
		||||
	int num_fingers;
 | 
			
		||||
 | 
			
		||||
	if (device_may_wakeup(dev))
 | 
			
		||||
		pm_wakeup_event(dev, 0);
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
 | 
			
		||||
	if (ret != sizeof(data))
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
 | 
			
		||||
	    (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
 | 
			
		||||
	    (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	num_fingers = (data.finger_btn >> 4) & 0x0f;
 | 
			
		||||
	for (i = 0; i < num_fingers; i++) {
 | 
			
		||||
		const struct cyapa_touch *touch = &data.touches[i];
 | 
			
		||||
		/* Note: touch->id range is 1 to 15; slots are 0 to 14. */
 | 
			
		||||
		int slot = touch->id - 1;
 | 
			
		||||
 | 
			
		||||
		input_mt_slot(input, slot);
 | 
			
		||||
		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
 | 
			
		||||
		input_report_abs(input, ABS_MT_POSITION_X,
 | 
			
		||||
				 ((touch->xy_hi & 0xf0) << 4) | touch->x_lo);
 | 
			
		||||
		input_report_abs(input, ABS_MT_POSITION_Y,
 | 
			
		||||
				 ((touch->xy_hi & 0x0f) << 8) | touch->y_lo);
 | 
			
		||||
		input_report_abs(input, ABS_MT_PRESSURE, touch->pressure);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_mt_sync_frame(input);
 | 
			
		||||
 | 
			
		||||
	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
 | 
			
		||||
		input_report_key(input, BTN_LEFT,
 | 
			
		||||
				 data.finger_btn & OP_DATA_LEFT_BTN);
 | 
			
		||||
 | 
			
		||||
	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
 | 
			
		||||
		input_report_key(input, BTN_MIDDLE,
 | 
			
		||||
				 data.finger_btn & OP_DATA_MIDDLE_BTN);
 | 
			
		||||
 | 
			
		||||
	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
 | 
			
		||||
		input_report_key(input, BTN_RIGHT,
 | 
			
		||||
				 data.finger_btn & OP_DATA_RIGHT_BTN);
 | 
			
		||||
 | 
			
		||||
	input_sync(input);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	return IRQ_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
	u8 ret = CYAPA_ADAPTER_FUNC_NONE;
 | 
			
		||||
 | 
			
		||||
	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
 | 
			
		||||
		ret |= CYAPA_ADAPTER_FUNC_I2C;
 | 
			
		||||
	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
 | 
			
		||||
				     I2C_FUNC_SMBUS_BLOCK_DATA |
 | 
			
		||||
				     I2C_FUNC_SMBUS_I2C_BLOCK))
 | 
			
		||||
		ret |= CYAPA_ADAPTER_FUNC_SMBUS;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cyapa_create_input_dev(struct cyapa *cyapa)
 | 
			
		||||
{
 | 
			
		||||
	struct device *dev = &cyapa->client->dev;
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct input_dev *input;
 | 
			
		||||
 | 
			
		||||
	if (!cyapa->physical_size_x || !cyapa->physical_size_y)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	input = cyapa->input = input_allocate_device();
 | 
			
		||||
	if (!input) {
 | 
			
		||||
		dev_err(dev, "allocate memory for input device failed\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input->name = CYAPA_NAME;
 | 
			
		||||
	input->phys = cyapa->phys;
 | 
			
		||||
	input->id.bustype = BUS_I2C;
 | 
			
		||||
	input->id.version = 1;
 | 
			
		||||
	input->id.product = 0;  /* means any product in eventcomm. */
 | 
			
		||||
	input->dev.parent = &cyapa->client->dev;
 | 
			
		||||
 | 
			
		||||
	input_set_drvdata(input, cyapa);
 | 
			
		||||
 | 
			
		||||
	__set_bit(EV_ABS, input->evbit);
 | 
			
		||||
 | 
			
		||||
	/* finger position */
 | 
			
		||||
	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
 | 
			
		||||
			     0);
 | 
			
		||||
	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
 | 
			
		||||
			     0);
 | 
			
		||||
	input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
 | 
			
		||||
 | 
			
		||||
	input_abs_set_res(input, ABS_MT_POSITION_X,
 | 
			
		||||
			  cyapa->max_abs_x / cyapa->physical_size_x);
 | 
			
		||||
	input_abs_set_res(input, ABS_MT_POSITION_Y,
 | 
			
		||||
			  cyapa->max_abs_y / cyapa->physical_size_y);
 | 
			
		||||
 | 
			
		||||
	if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
 | 
			
		||||
		__set_bit(BTN_LEFT, input->keybit);
 | 
			
		||||
	if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
 | 
			
		||||
		__set_bit(BTN_MIDDLE, input->keybit);
 | 
			
		||||
	if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
 | 
			
		||||
		__set_bit(BTN_RIGHT, input->keybit);
 | 
			
		||||
 | 
			
		||||
	if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
 | 
			
		||||
		__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 | 
			
		||||
 | 
			
		||||
	/* handle pointer emulation and unused slots in core */
 | 
			
		||||
	ret = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
 | 
			
		||||
				  INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "allocate memory for MT slots failed, %d\n", ret);
 | 
			
		||||
		goto err_free_device;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Register the device in input subsystem */
 | 
			
		||||
	ret = input_register_device(input);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "input device register failed, %d\n", ret);
 | 
			
		||||
		goto err_free_device;
 | 
			
		||||
	}
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_free_device:
 | 
			
		||||
	input_free_device(input);
 | 
			
		||||
	cyapa->input = NULL;
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cyapa_probe(struct i2c_client *client,
 | 
			
		||||
		       const struct i2c_device_id *dev_id)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 adapter_func;
 | 
			
		||||
	struct cyapa *cyapa;
 | 
			
		||||
	struct device *dev = &client->dev;
 | 
			
		||||
 | 
			
		||||
	adapter_func = cyapa_check_adapter_functionality(client);
 | 
			
		||||
	if (adapter_func == CYAPA_ADAPTER_FUNC_NONE) {
 | 
			
		||||
		dev_err(dev, "not a supported I2C/SMBus adapter\n");
 | 
			
		||||
		return -EIO;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cyapa = kzalloc(sizeof(struct cyapa), GFP_KERNEL);
 | 
			
		||||
	if (!cyapa) {
 | 
			
		||||
		dev_err(dev, "allocate memory for cyapa failed\n");
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cyapa->gen = CYAPA_GEN3;
 | 
			
		||||
	cyapa->client = client;
 | 
			
		||||
	i2c_set_clientdata(client, cyapa);
 | 
			
		||||
	sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
 | 
			
		||||
		client->addr);
 | 
			
		||||
 | 
			
		||||
	/* i2c isn't supported, use smbus */
 | 
			
		||||
	if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
 | 
			
		||||
		cyapa->smbus = true;
 | 
			
		||||
	cyapa->state = CYAPA_STATE_NO_DEVICE;
 | 
			
		||||
	ret = cyapa_check_is_operational(cyapa);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "device not operational, %d\n", ret);
 | 
			
		||||
		goto err_mem_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_create_input_dev(cyapa);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "create input_dev instance failed, %d\n", ret);
 | 
			
		||||
		goto err_mem_free;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "set active power failed, %d\n", ret);
 | 
			
		||||
		goto err_unregister_device;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cyapa->irq = client->irq;
 | 
			
		||||
	ret = request_threaded_irq(cyapa->irq,
 | 
			
		||||
				   NULL,
 | 
			
		||||
				   cyapa_irq,
 | 
			
		||||
				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 | 
			
		||||
				   "cyapa",
 | 
			
		||||
				   cyapa);
 | 
			
		||||
	if (ret) {
 | 
			
		||||
		dev_err(dev, "IRQ request failed: %d\n, ", ret);
 | 
			
		||||
		goto err_unregister_device;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_unregister_device:
 | 
			
		||||
	input_unregister_device(cyapa->input);
 | 
			
		||||
err_mem_free:
 | 
			
		||||
	kfree(cyapa);
 | 
			
		||||
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cyapa_remove(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct cyapa *cyapa = i2c_get_clientdata(client);
 | 
			
		||||
 | 
			
		||||
	free_irq(cyapa->irq, cyapa);
 | 
			
		||||
	input_unregister_device(cyapa->input);
 | 
			
		||||
	cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
 | 
			
		||||
	kfree(cyapa);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_PM_SLEEP
 | 
			
		||||
static int cyapa_suspend(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	u8 power_mode;
 | 
			
		||||
	struct cyapa *cyapa = dev_get_drvdata(dev);
 | 
			
		||||
 | 
			
		||||
	disable_irq(cyapa->irq);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Set trackpad device to idle mode if wakeup is allowed,
 | 
			
		||||
	 * otherwise turn off.
 | 
			
		||||
	 */
 | 
			
		||||
	power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE
 | 
			
		||||
					    : PWR_MODE_OFF;
 | 
			
		||||
	ret = cyapa_set_power_mode(cyapa, power_mode);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		dev_err(dev, "set power mode failed, %d\n", ret);
 | 
			
		||||
 | 
			
		||||
	if (device_may_wakeup(dev))
 | 
			
		||||
		cyapa->irq_wake = (enable_irq_wake(cyapa->irq) == 0);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cyapa_resume(struct device *dev)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
	struct cyapa *cyapa = dev_get_drvdata(dev);
 | 
			
		||||
 | 
			
		||||
	if (device_may_wakeup(dev) && cyapa->irq_wake)
 | 
			
		||||
		disable_irq_wake(cyapa->irq);
 | 
			
		||||
 | 
			
		||||
	ret = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		dev_warn(dev, "resume active power failed, %d\n", ret);
 | 
			
		||||
 | 
			
		||||
	enable_irq(cyapa->irq);
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_PM_SLEEP */
 | 
			
		||||
 | 
			
		||||
static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume);
 | 
			
		||||
 | 
			
		||||
static const struct i2c_device_id cyapa_id_table[] = {
 | 
			
		||||
	{ "cyapa", 0 },
 | 
			
		||||
	{ },
 | 
			
		||||
};
 | 
			
		||||
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
 | 
			
		||||
 | 
			
		||||
static struct i2c_driver cyapa_driver = {
 | 
			
		||||
	.driver = {
 | 
			
		||||
		.name = "cyapa",
 | 
			
		||||
		.owner = THIS_MODULE,
 | 
			
		||||
		.pm = &cyapa_pm_ops,
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	.probe = cyapa_probe,
 | 
			
		||||
	.remove = cyapa_remove,
 | 
			
		||||
	.id_table = cyapa_id_table,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module_i2c_driver(cyapa_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_DESCRIPTION("Cypress APA I2C Trackpad Driver");
 | 
			
		||||
MODULE_AUTHOR("Dudley Du <dudl@cypress.com>");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
							
								
								
									
										725
									
								
								drivers/input/mouse/cypress_ps2.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										725
									
								
								drivers/input/mouse/cypress_ps2.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,725 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Cypress Trackpad PS/2 mouse driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2012 Cypress Semiconductor Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Author:
 | 
			
		||||
 *   Dudley Du <dudl@cypress.com>
 | 
			
		||||
 *
 | 
			
		||||
 * Additional contributors include:
 | 
			
		||||
 *   Kamal Mostafa <kamal@canonical.com>
 | 
			
		||||
 *   Kyle Fazzari <git@status.e4ward.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.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include <linux/init.h>
 | 
			
		||||
#include <linux/module.h>
 | 
			
		||||
#include <linux/kernel.h>
 | 
			
		||||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/serio.h>
 | 
			
		||||
#include <linux/libps2.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <linux/input/mt.h>
 | 
			
		||||
#include <linux/sched.h>
 | 
			
		||||
#include <linux/wait.h>
 | 
			
		||||
 | 
			
		||||
#include "cypress_ps2.h"
 | 
			
		||||
 | 
			
		||||
#undef CYTP_DEBUG_VERBOSE  /* define this and DEBUG for more verbose dump */
 | 
			
		||||
 | 
			
		||||
static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
	cytp->pkt_size = n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
 | 
			
		||||
static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
 | 
			
		||||
 | 
			
		||||
static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
			
		||||
 | 
			
		||||
	if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
 | 
			
		||||
		psmouse_dbg(psmouse,
 | 
			
		||||
				"sending command 0x%02x failed, resp 0x%02x\n",
 | 
			
		||||
				value & 0xff, ps2dev->nak);
 | 
			
		||||
		if (ps2dev->nak == CYTP_PS2_RETRY)
 | 
			
		||||
			return CYTP_PS2_RETRY;
 | 
			
		||||
		else
 | 
			
		||||
			return CYTP_PS2_ERROR;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
#ifdef CYTP_DEBUG_VERBOSE
 | 
			
		||||
	psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
 | 
			
		||||
			value & 0xff);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
 | 
			
		||||
			       unsigned char data)
 | 
			
		||||
{
 | 
			
		||||
	struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
			
		||||
	int tries = CYTP_PS2_CMD_TRIES;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	ps2_begin_command(ps2dev);
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Send extension command byte (0xE8 or 0xF3).
 | 
			
		||||
		 * If sending the command fails, send recovery command
 | 
			
		||||
		 * to make the device return to the ready state.
 | 
			
		||||
		 */
 | 
			
		||||
		rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
 | 
			
		||||
		if (rc == CYTP_PS2_RETRY) {
 | 
			
		||||
			rc = cypress_ps2_sendbyte(psmouse, 0x00);
 | 
			
		||||
			if (rc == CYTP_PS2_RETRY)
 | 
			
		||||
				rc = cypress_ps2_sendbyte(psmouse, 0x0a);
 | 
			
		||||
		}
 | 
			
		||||
		if (rc == CYTP_PS2_ERROR)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		rc = cypress_ps2_sendbyte(psmouse, data);
 | 
			
		||||
		if (rc == CYTP_PS2_RETRY)
 | 
			
		||||
			rc = cypress_ps2_sendbyte(psmouse, data);
 | 
			
		||||
		if (rc == CYTP_PS2_ERROR)
 | 
			
		||||
			continue;
 | 
			
		||||
		else
 | 
			
		||||
			break;
 | 
			
		||||
	} while (--tries > 0);
 | 
			
		||||
 | 
			
		||||
	ps2_end_command(ps2dev);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
 | 
			
		||||
				       unsigned char cmd,
 | 
			
		||||
				       unsigned char *param)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct ps2dev *ps2dev = &psmouse->ps2dev;
 | 
			
		||||
	enum psmouse_state old_state;
 | 
			
		||||
	int pktsize;
 | 
			
		||||
 | 
			
		||||
	ps2_begin_command(&psmouse->ps2dev);
 | 
			
		||||
 | 
			
		||||
	old_state = psmouse->state;
 | 
			
		||||
	psmouse->state = PSMOUSE_CMD_MODE;
 | 
			
		||||
	psmouse->pktcnt = 0;
 | 
			
		||||
 | 
			
		||||
	pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
 | 
			
		||||
	memset(param, 0, pktsize);
 | 
			
		||||
 | 
			
		||||
	rc = cypress_ps2_sendbyte(psmouse, 0xe9);
 | 
			
		||||
	if (rc < 0)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	wait_event_timeout(ps2dev->wait,
 | 
			
		||||
			(psmouse->pktcnt >= pktsize),
 | 
			
		||||
			msecs_to_jiffies(CYTP_CMD_TIMEOUT));
 | 
			
		||||
 | 
			
		||||
	memcpy(param, psmouse->packet, pktsize);
 | 
			
		||||
 | 
			
		||||
	psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
 | 
			
		||||
			cmd, pktsize, param);
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	psmouse->state = old_state;
 | 
			
		||||
	psmouse->pktcnt = 0;
 | 
			
		||||
 | 
			
		||||
	ps2_end_command(&psmouse->ps2dev);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool cypress_verify_cmd_state(struct psmouse *psmouse,
 | 
			
		||||
				     unsigned char cmd, unsigned char *param)
 | 
			
		||||
{
 | 
			
		||||
	bool rate_match = false;
 | 
			
		||||
	bool resolution_match = false;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	/* callers will do further checking. */
 | 
			
		||||
	if (cmd == CYTP_CMD_READ_CYPRESS_ID ||
 | 
			
		||||
	    cmd == CYTP_CMD_STANDARD_MODE ||
 | 
			
		||||
	    cmd == CYTP_CMD_READ_TP_METRICS)
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID &&
 | 
			
		||||
	    (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) {
 | 
			
		||||
		for (i = 0; i < sizeof(cytp_resolution); i++)
 | 
			
		||||
			if (cytp_resolution[i] == param[1])
 | 
			
		||||
				resolution_match = true;
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < sizeof(cytp_rate); i++)
 | 
			
		||||
			if (cytp_rate[i] == param[2])
 | 
			
		||||
				rate_match = true;
 | 
			
		||||
 | 
			
		||||
		if (resolution_match && rate_match)
 | 
			
		||||
			return true;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	psmouse_dbg(psmouse, "verify cmd state failed.\n");
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
 | 
			
		||||
				unsigned char *param)
 | 
			
		||||
{
 | 
			
		||||
	int tries = CYTP_PS2_CMD_TRIES;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
 | 
			
		||||
		 cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
 | 
			
		||||
		 DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		cypress_ps2_ext_cmd(psmouse,
 | 
			
		||||
				    PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
 | 
			
		||||
		cypress_ps2_ext_cmd(psmouse,
 | 
			
		||||
				    PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
 | 
			
		||||
		cypress_ps2_ext_cmd(psmouse,
 | 
			
		||||
				    PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
 | 
			
		||||
		cypress_ps2_ext_cmd(psmouse,
 | 
			
		||||
				    PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
 | 
			
		||||
 | 
			
		||||
		rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			continue;
 | 
			
		||||
 | 
			
		||||
		if (cypress_verify_cmd_state(psmouse, cmd, param))
 | 
			
		||||
			return 0;
 | 
			
		||||
 | 
			
		||||
	} while (--tries > 0);
 | 
			
		||||
 | 
			
		||||
	return -EIO;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cypress_detect(struct psmouse *psmouse, bool set_properties)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char param[3];
 | 
			
		||||
 | 
			
		||||
	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	/* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
 | 
			
		||||
	if (param[0] != 0x33 || param[1] != 0xCC)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	if (set_properties) {
 | 
			
		||||
		psmouse->vendor = "Cypress";
 | 
			
		||||
		psmouse->name = "Trackpad";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_read_fw_version(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
	unsigned char param[3];
 | 
			
		||||
 | 
			
		||||
	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	/* Check for Cypress Trackpad signature bytes: 0x33 0xCC */
 | 
			
		||||
	if (param[0] != 0x33 || param[1] != 0xCC)
 | 
			
		||||
		return -ENODEV;
 | 
			
		||||
 | 
			
		||||
	cytp->fw_version = param[2] & FW_VERSION_MASX;
 | 
			
		||||
	cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n",
 | 
			
		||||
		 cytp->tp_metrics_supported);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_read_tp_metrics(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
	unsigned char param[8];
 | 
			
		||||
 | 
			
		||||
	/* set default values for tp metrics. */
 | 
			
		||||
	cytp->tp_width = CYTP_DEFAULT_WIDTH;
 | 
			
		||||
	cytp->tp_high = CYTP_DEFAULT_HIGH;
 | 
			
		||||
	cytp->tp_max_abs_x = CYTP_ABS_MAX_X;
 | 
			
		||||
	cytp->tp_max_abs_y = CYTP_ABS_MAX_Y;
 | 
			
		||||
	cytp->tp_min_pressure = CYTP_MIN_PRESSURE;
 | 
			
		||||
	cytp->tp_max_pressure = CYTP_MAX_PRESSURE;
 | 
			
		||||
	cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
 | 
			
		||||
	cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
 | 
			
		||||
 | 
			
		||||
	memset(param, 0, sizeof(param));
 | 
			
		||||
	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) {
 | 
			
		||||
		/* Update trackpad parameters. */
 | 
			
		||||
		cytp->tp_max_abs_x = (param[1] << 8) | param[0];
 | 
			
		||||
		cytp->tp_max_abs_y = (param[3] << 8) | param[2];
 | 
			
		||||
		cytp->tp_min_pressure = param[4];
 | 
			
		||||
		cytp->tp_max_pressure = param[5];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!cytp->tp_max_pressure ||
 | 
			
		||||
	    cytp->tp_max_pressure < cytp->tp_min_pressure ||
 | 
			
		||||
	    !cytp->tp_width || !cytp->tp_high ||
 | 
			
		||||
	    !cytp->tp_max_abs_x ||
 | 
			
		||||
	    cytp->tp_max_abs_x < cytp->tp_width ||
 | 
			
		||||
	    !cytp->tp_max_abs_y ||
 | 
			
		||||
	    cytp->tp_max_abs_y < cytp->tp_high)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width;
 | 
			
		||||
	cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high;
 | 
			
		||||
 | 
			
		||||
#ifdef CYTP_DEBUG_VERBOSE
 | 
			
		||||
	psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n");
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x);
 | 
			
		||||
	psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y);
 | 
			
		||||
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_type_APA = %d\n",
 | 
			
		||||
			(param[6] & TP_METRICS_BIT_APA) ? 1 : 0);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_type_MTG = %d\n",
 | 
			
		||||
			(param[6] & TP_METRICS_BIT_MTG) ? 1 : 0);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_palm = %d\n",
 | 
			
		||||
			(param[6] & TP_METRICS_BIT_PALM) ? 1 : 0);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_stubborn = %d\n",
 | 
			
		||||
			(param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_1f_jitter = %d\n",
 | 
			
		||||
			(param[6] & TP_METRICS_BIT_1F_JITTER) >> 2);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_2f_jitter = %d\n",
 | 
			
		||||
			(param[6] & TP_METRICS_BIT_2F_JITTER) >> 4);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_1f_spike = %d\n",
 | 
			
		||||
			param[7] & TP_METRICS_BIT_1F_SPIKE);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_2f_spike = %d\n",
 | 
			
		||||
			(param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2);
 | 
			
		||||
	psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n",
 | 
			
		||||
			(param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_query_hardware(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	ret = cypress_read_fw_version(psmouse);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	if (cytp->tp_metrics_supported) {
 | 
			
		||||
		ret = cypress_read_tp_metrics(psmouse);
 | 
			
		||||
		if (ret)
 | 
			
		||||
			return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_set_absolute_mode(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
	unsigned char param[3];
 | 
			
		||||
 | 
			
		||||
	if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
 | 
			
		||||
			| CYTP_BIT_ABS_PRESSURE;
 | 
			
		||||
	cypress_set_packet_size(psmouse, 5);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Reset trackpad device.
 | 
			
		||||
 * This is also the default mode when trackpad powered on.
 | 
			
		||||
 */
 | 
			
		||||
static void cypress_reset(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
 | 
			
		||||
	cytp->mode = 0;
 | 
			
		||||
 | 
			
		||||
	psmouse_reset(psmouse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_set_input_params(struct input_dev *input,
 | 
			
		||||
				    struct cytp_data *cytp)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!cytp->tp_res_x || !cytp->tp_res_y)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	__set_bit(EV_ABS, input->evbit);
 | 
			
		||||
	input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0);
 | 
			
		||||
	input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0);
 | 
			
		||||
	input_set_abs_params(input, ABS_PRESSURE,
 | 
			
		||||
			     cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0);
 | 
			
		||||
	input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0);
 | 
			
		||||
 | 
			
		||||
	/* finger position */
 | 
			
		||||
	input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0);
 | 
			
		||||
	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
 | 
			
		||||
	input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
 | 
			
		||||
 | 
			
		||||
	ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
 | 
			
		||||
			INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
 | 
			
		||||
	if (ret < 0)
 | 
			
		||||
		return ret;
 | 
			
		||||
 | 
			
		||||
	__set_bit(INPUT_PROP_SEMI_MT, input->propbit);
 | 
			
		||||
 | 
			
		||||
	input_abs_set_res(input, ABS_X, cytp->tp_res_x);
 | 
			
		||||
	input_abs_set_res(input, ABS_Y, cytp->tp_res_y);
 | 
			
		||||
 | 
			
		||||
	input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x);
 | 
			
		||||
	input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y);
 | 
			
		||||
 | 
			
		||||
	__set_bit(BTN_TOUCH, input->keybit);
 | 
			
		||||
	__set_bit(BTN_TOOL_FINGER, input->keybit);
 | 
			
		||||
	__set_bit(BTN_TOOL_DOUBLETAP, input->keybit);
 | 
			
		||||
	__set_bit(BTN_TOOL_TRIPLETAP, input->keybit);
 | 
			
		||||
	__set_bit(BTN_TOOL_QUADTAP, input->keybit);
 | 
			
		||||
	__set_bit(BTN_TOOL_QUINTTAP, input->keybit);
 | 
			
		||||
 | 
			
		||||
	__clear_bit(EV_REL, input->evbit);
 | 
			
		||||
	__clear_bit(REL_X, input->relbit);
 | 
			
		||||
	__clear_bit(REL_Y, input->relbit);
 | 
			
		||||
 | 
			
		||||
	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 | 
			
		||||
	__set_bit(EV_KEY, input->evbit);
 | 
			
		||||
	__set_bit(BTN_LEFT, input->keybit);
 | 
			
		||||
	__set_bit(BTN_RIGHT, input->keybit);
 | 
			
		||||
	__set_bit(BTN_MIDDLE, input->keybit);
 | 
			
		||||
 | 
			
		||||
	input_set_drvdata(input, cytp);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_get_finger_count(unsigned char header_byte)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char bits6_7;
 | 
			
		||||
	int finger_count;
 | 
			
		||||
 | 
			
		||||
	bits6_7 = header_byte >> 6;
 | 
			
		||||
	finger_count = bits6_7 & 0x03;
 | 
			
		||||
 | 
			
		||||
	if (finger_count == 1)
 | 
			
		||||
		return 1;
 | 
			
		||||
 | 
			
		||||
	if (header_byte & ABS_HSCROLL_BIT) {
 | 
			
		||||
		/* HSCROLL gets added on to 0 finger count. */
 | 
			
		||||
		switch (finger_count) {
 | 
			
		||||
			case 0:	return 4;
 | 
			
		||||
			case 2: return 5;
 | 
			
		||||
			default:
 | 
			
		||||
				/* Invalid contact (e.g. palm). Ignore it. */
 | 
			
		||||
				return -1;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return finger_count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int cypress_parse_packet(struct psmouse *psmouse,
 | 
			
		||||
				struct cytp_data *cytp, struct cytp_report_data *report_data)
 | 
			
		||||
{
 | 
			
		||||
	unsigned char *packet = psmouse->packet;
 | 
			
		||||
	unsigned char header_byte = packet[0];
 | 
			
		||||
	int contact_cnt;
 | 
			
		||||
 | 
			
		||||
	memset(report_data, 0, sizeof(struct cytp_report_data));
 | 
			
		||||
 | 
			
		||||
	contact_cnt = cypress_get_finger_count(header_byte);
 | 
			
		||||
 | 
			
		||||
	if (contact_cnt < 0) /* e.g. palm detect */
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	report_data->contact_cnt = contact_cnt;
 | 
			
		||||
 | 
			
		||||
	report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	if (report_data->contact_cnt == 1) {
 | 
			
		||||
		report_data->contacts[0].x =
 | 
			
		||||
			((packet[1] & 0x70) << 4) | packet[2];
 | 
			
		||||
		report_data->contacts[0].y =
 | 
			
		||||
			((packet[1] & 0x07) << 8) | packet[3];
 | 
			
		||||
		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 | 
			
		||||
			report_data->contacts[0].z = packet[4];
 | 
			
		||||
 | 
			
		||||
	} else if (report_data->contact_cnt >= 2) {
 | 
			
		||||
		report_data->contacts[0].x =
 | 
			
		||||
			((packet[1] & 0x70) << 4) | packet[2];
 | 
			
		||||
		report_data->contacts[0].y =
 | 
			
		||||
			((packet[1] & 0x07) << 8) | packet[3];
 | 
			
		||||
		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 | 
			
		||||
			report_data->contacts[0].z = packet[4];
 | 
			
		||||
 | 
			
		||||
		report_data->contacts[1].x =
 | 
			
		||||
			((packet[5] & 0xf0) << 4) | packet[6];
 | 
			
		||||
		report_data->contacts[1].y =
 | 
			
		||||
			((packet[5] & 0x0f) << 8) | packet[7];
 | 
			
		||||
		if (cytp->mode & CYTP_BIT_ABS_PRESSURE)
 | 
			
		||||
			report_data->contacts[1].z = report_data->contacts[0].z;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0;
 | 
			
		||||
	report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * This is only true if one of the mouse buttons were tapped.  Make
 | 
			
		||||
	 * sure it doesn't turn into a click. The regular tap-to-click
 | 
			
		||||
	 * functionality will handle that on its own. If we don't do this,
 | 
			
		||||
	 * disabling tap-to-click won't affect the mouse button zones.
 | 
			
		||||
	 */
 | 
			
		||||
	if (report_data->tap)
 | 
			
		||||
		report_data->left = 0;
 | 
			
		||||
 | 
			
		||||
#ifdef CYTP_DEBUG_VERBOSE
 | 
			
		||||
	{
 | 
			
		||||
		int i;
 | 
			
		||||
		int n = report_data->contact_cnt;
 | 
			
		||||
		psmouse_dbg(psmouse, "Dump parsed report data as below:\n");
 | 
			
		||||
		psmouse_dbg(psmouse, "contact_cnt = %d\n",
 | 
			
		||||
			report_data->contact_cnt);
 | 
			
		||||
		if (n > CYTP_MAX_MT_SLOTS)
 | 
			
		||||
		    n = CYTP_MAX_MT_SLOTS;
 | 
			
		||||
		for (i = 0; i < n; i++)
 | 
			
		||||
			psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i,
 | 
			
		||||
					report_data->contacts[i].x,
 | 
			
		||||
					report_data->contacts[i].y,
 | 
			
		||||
					report_data->contacts[i].z);
 | 
			
		||||
		psmouse_dbg(psmouse, "left = %d\n", report_data->left);
 | 
			
		||||
		psmouse_dbg(psmouse, "right = %d\n", report_data->right);
 | 
			
		||||
		psmouse_dbg(psmouse, "middle = %d\n", report_data->middle);
 | 
			
		||||
	}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	struct input_dev *input = psmouse->dev;
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
	struct cytp_report_data report_data;
 | 
			
		||||
	struct cytp_contact *contact;
 | 
			
		||||
	struct input_mt_pos pos[CYTP_MAX_MT_SLOTS];
 | 
			
		||||
	int slots[CYTP_MAX_MT_SLOTS];
 | 
			
		||||
	int n;
 | 
			
		||||
 | 
			
		||||
	if (cypress_parse_packet(psmouse, cytp, &report_data))
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	n = report_data.contact_cnt;
 | 
			
		||||
 | 
			
		||||
	if (n > CYTP_MAX_MT_SLOTS)
 | 
			
		||||
		n = CYTP_MAX_MT_SLOTS;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < n; i++) {
 | 
			
		||||
		contact = &report_data.contacts[i];
 | 
			
		||||
		pos[i].x = contact->x;
 | 
			
		||||
		pos[i].y = contact->y;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_mt_assign_slots(input, slots, pos, n);
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < n; i++) {
 | 
			
		||||
		contact = &report_data.contacts[i];
 | 
			
		||||
		input_mt_slot(input, slots[i]);
 | 
			
		||||
		input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
 | 
			
		||||
		input_report_abs(input, ABS_MT_POSITION_X, contact->x);
 | 
			
		||||
		input_report_abs(input, ABS_MT_POSITION_Y, contact->y);
 | 
			
		||||
		input_report_abs(input, ABS_MT_PRESSURE, contact->z);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_mt_sync_frame(input);
 | 
			
		||||
 | 
			
		||||
	input_mt_report_finger_count(input, report_data.contact_cnt);
 | 
			
		||||
 | 
			
		||||
	input_report_key(input, BTN_LEFT, report_data.left);
 | 
			
		||||
	input_report_key(input, BTN_RIGHT, report_data.right);
 | 
			
		||||
	input_report_key(input, BTN_MIDDLE, report_data.middle);
 | 
			
		||||
 | 
			
		||||
	input_sync(input);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	int contact_cnt;
 | 
			
		||||
	int index = psmouse->pktcnt - 1;
 | 
			
		||||
	unsigned char *packet = psmouse->packet;
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
 | 
			
		||||
	if (index < 0 || index > cytp->pkt_size)
 | 
			
		||||
		return PSMOUSE_BAD_DATA;
 | 
			
		||||
 | 
			
		||||
	if (index == 0 && (packet[0] & 0xfc) == 0) {
 | 
			
		||||
		/* call packet process for reporting finger leave. */
 | 
			
		||||
		cypress_process_packet(psmouse, 1);
 | 
			
		||||
		return PSMOUSE_FULL_PACKET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Perform validation (and adjust packet size) based only on the
 | 
			
		||||
	 * first byte; allow all further bytes through.
 | 
			
		||||
	 */
 | 
			
		||||
	if (index != 0)
 | 
			
		||||
		return PSMOUSE_GOOD_DATA;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If absolute/relative mode bit has not been set yet, just pass
 | 
			
		||||
	 * the byte through.
 | 
			
		||||
	 */
 | 
			
		||||
	if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0)
 | 
			
		||||
		return PSMOUSE_GOOD_DATA;
 | 
			
		||||
 | 
			
		||||
	if ((packet[0] & 0x08) == 0x08)
 | 
			
		||||
		return PSMOUSE_BAD_DATA;
 | 
			
		||||
 | 
			
		||||
	contact_cnt = cypress_get_finger_count(packet[0]);
 | 
			
		||||
 | 
			
		||||
	if (contact_cnt < 0)
 | 
			
		||||
		return PSMOUSE_BAD_DATA;
 | 
			
		||||
 | 
			
		||||
	if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE)
 | 
			
		||||
		cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4);
 | 
			
		||||
	else
 | 
			
		||||
		cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5);
 | 
			
		||||
 | 
			
		||||
	return PSMOUSE_GOOD_DATA;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
 | 
			
		||||
	if (psmouse->pktcnt >= cytp->pkt_size) {
 | 
			
		||||
		cypress_process_packet(psmouse, 0);
 | 
			
		||||
		return PSMOUSE_FULL_PACKET;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cypress_validate_byte(psmouse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp = psmouse->private;
 | 
			
		||||
 | 
			
		||||
	if (rate >= 80) {
 | 
			
		||||
		psmouse->rate = 80;
 | 
			
		||||
		cytp->mode |= CYTP_BIT_HIGH_RATE;
 | 
			
		||||
	} else {
 | 
			
		||||
		psmouse->rate = 40;
 | 
			
		||||
		cytp->mode &= ~CYTP_BIT_HIGH_RATE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
 | 
			
		||||
		    PSMOUSE_CMD_SETRATE);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void cypress_disconnect(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	cypress_reset(psmouse);
 | 
			
		||||
	kfree(psmouse->private);
 | 
			
		||||
	psmouse->private = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int cypress_reconnect(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	int tries = CYTP_PS2_CMD_TRIES;
 | 
			
		||||
	int rc;
 | 
			
		||||
 | 
			
		||||
	do {
 | 
			
		||||
		cypress_reset(psmouse);
 | 
			
		||||
		rc = cypress_detect(psmouse, false);
 | 
			
		||||
	} while (rc && (--tries > 0));
 | 
			
		||||
 | 
			
		||||
	if (rc) {
 | 
			
		||||
		psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cypress_set_absolute_mode(psmouse)) {
 | 
			
		||||
		psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int cypress_init(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	struct cytp_data *cytp;
 | 
			
		||||
 | 
			
		||||
	cytp = (struct cytp_data *)kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
 | 
			
		||||
	psmouse->private = (void *)cytp;
 | 
			
		||||
	if (cytp == NULL)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	cypress_reset(psmouse);
 | 
			
		||||
 | 
			
		||||
	psmouse->pktsize = 8;
 | 
			
		||||
 | 
			
		||||
	if (cypress_query_hardware(psmouse)) {
 | 
			
		||||
		psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
 | 
			
		||||
		goto err_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cypress_set_absolute_mode(psmouse)) {
 | 
			
		||||
		psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
 | 
			
		||||
		goto err_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
 | 
			
		||||
		psmouse_err(psmouse, "init: Unable to set input params.\n");
 | 
			
		||||
		goto err_exit;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	psmouse->model = 1;
 | 
			
		||||
	psmouse->protocol_handler = cypress_protocol_handler;
 | 
			
		||||
	psmouse->set_rate = cypress_set_rate;
 | 
			
		||||
	psmouse->disconnect = cypress_disconnect;
 | 
			
		||||
	psmouse->reconnect = cypress_reconnect;
 | 
			
		||||
	psmouse->cleanup = cypress_reset;
 | 
			
		||||
	psmouse->resync_time = 0;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_exit:
 | 
			
		||||
	/*
 | 
			
		||||
	 * Reset Cypress Trackpad as a standard mouse. Then
 | 
			
		||||
	 * let psmouse driver commmunicating with it as default PS2 mouse.
 | 
			
		||||
	 */
 | 
			
		||||
	cypress_reset(psmouse);
 | 
			
		||||
 | 
			
		||||
	psmouse->private = NULL;
 | 
			
		||||
	kfree(cytp);
 | 
			
		||||
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool cypress_supported(void)
 | 
			
		||||
{
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										191
									
								
								drivers/input/mouse/cypress_ps2.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								drivers/input/mouse/cypress_ps2.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,191 @@
 | 
			
		|||
#ifndef _CYPRESS_PS2_H
 | 
			
		||||
#define _CYPRESS_PS2_H
 | 
			
		||||
 | 
			
		||||
#include "psmouse.h"
 | 
			
		||||
 | 
			
		||||
#define CMD_BITS_MASK 0x03
 | 
			
		||||
#define COMPOSIT(x, s) (((x) & CMD_BITS_MASK) << (s))
 | 
			
		||||
 | 
			
		||||
#define ENCODE_CMD(aa, bb, cc, dd) \
 | 
			
		||||
	(COMPOSIT((aa), 6) | COMPOSIT((bb), 4) | COMPOSIT((cc), 2) | COMPOSIT((dd), 0))
 | 
			
		||||
#define CYTP_CMD_ABS_NO_PRESSURE_MODE       ENCODE_CMD(0, 1, 0, 0)
 | 
			
		||||
#define CYTP_CMD_ABS_WITH_PRESSURE_MODE     ENCODE_CMD(0, 1, 0, 1)
 | 
			
		||||
#define CYTP_CMD_SMBUS_MODE                 ENCODE_CMD(0, 1, 1, 0)
 | 
			
		||||
#define CYTP_CMD_STANDARD_MODE              ENCODE_CMD(0, 2, 0, 0)  /* not implemented yet. */
 | 
			
		||||
#define CYTP_CMD_CYPRESS_REL_MODE           ENCODE_CMD(1, 1, 1, 1)  /* not implemented yet. */
 | 
			
		||||
#define CYTP_CMD_READ_CYPRESS_ID            ENCODE_CMD(0, 0, 0, 0)
 | 
			
		||||
#define CYTP_CMD_READ_TP_METRICS            ENCODE_CMD(0, 0, 0, 1)
 | 
			
		||||
#define CYTP_CMD_SET_HSCROLL_WIDTH(w)       ENCODE_CMD(1, 1, 0, (w))
 | 
			
		||||
#define     CYTP_CMD_SET_HSCROLL_MASK       ENCODE_CMD(1, 1, 0, 0)
 | 
			
		||||
#define CYTP_CMD_SET_VSCROLL_WIDTH(w)       ENCODE_CMD(1, 2, 0, (w))
 | 
			
		||||
#define     CYTP_CMD_SET_VSCROLL_MASK       ENCODE_CMD(1, 2, 0, 0)
 | 
			
		||||
#define CYTP_CMD_SET_PALM_GEOMETRY(e)       ENCODE_CMD(1, 2, 1, (e))
 | 
			
		||||
#define     CYTP_CMD_PALM_GEMMETRY_MASK     ENCODE_CMD(1, 2, 1, 0)
 | 
			
		||||
#define CYTP_CMD_SET_PALM_SENSITIVITY(s)    ENCODE_CMD(1, 2, 2, (s))
 | 
			
		||||
#define     CYTP_CMD_PALM_SENSITIVITY_MASK  ENCODE_CMD(1, 2, 2, 0)
 | 
			
		||||
#define CYTP_CMD_SET_MOUSE_SENSITIVITY(s)   ENCODE_CMD(1, 3, ((s) >> 2), (s))
 | 
			
		||||
#define     CYTP_CMD_MOUSE_SENSITIVITY_MASK ENCODE_CMD(1, 3, 0, 0)
 | 
			
		||||
#define CYTP_CMD_REQUEST_BASELINE_STATUS    ENCODE_CMD(2, 0, 0, 1)
 | 
			
		||||
#define CYTP_CMD_REQUEST_RECALIBRATION      ENCODE_CMD(2, 0, 0, 3)
 | 
			
		||||
 | 
			
		||||
#define DECODE_CMD_AA(x) (((x) >> 6) & CMD_BITS_MASK)
 | 
			
		||||
#define DECODE_CMD_BB(x) (((x) >> 4) & CMD_BITS_MASK)
 | 
			
		||||
#define DECODE_CMD_CC(x) (((x) >> 2) & CMD_BITS_MASK)
 | 
			
		||||
#define DECODE_CMD_DD(x) ((x) & CMD_BITS_MASK)
 | 
			
		||||
 | 
			
		||||
/* Cypress trackpad working mode. */
 | 
			
		||||
#define CYTP_BIT_ABS_PRESSURE    (1 << 3)
 | 
			
		||||
#define CYTP_BIT_ABS_NO_PRESSURE (1 << 2)
 | 
			
		||||
#define CYTP_BIT_CYPRESS_REL     (1 << 1)
 | 
			
		||||
#define CYTP_BIT_STANDARD_REL    (1 << 0)
 | 
			
		||||
#define CYTP_BIT_REL_MASK (CYTP_BIT_CYPRESS_REL | CYTP_BIT_STANDARD_REL)
 | 
			
		||||
#define CYTP_BIT_ABS_MASK (CYTP_BIT_ABS_PRESSURE | CYTP_BIT_ABS_NO_PRESSURE)
 | 
			
		||||
#define CYTP_BIT_ABS_REL_MASK (CYTP_BIT_ABS_MASK | CYTP_BIT_REL_MASK)
 | 
			
		||||
 | 
			
		||||
#define CYTP_BIT_HIGH_RATE       (1 << 4)
 | 
			
		||||
/*
 | 
			
		||||
 * report mode bit is set, firmware working in Remote Mode.
 | 
			
		||||
 * report mode bit is cleared, firmware working in Stream Mode.
 | 
			
		||||
 */
 | 
			
		||||
#define CYTP_BIT_REPORT_MODE     (1 << 5)
 | 
			
		||||
 | 
			
		||||
/* scrolling width values for set HSCROLL and VSCROLL width command. */
 | 
			
		||||
#define SCROLL_WIDTH_NARROW 1
 | 
			
		||||
#define SCROLL_WIDTH_NORMAL 2
 | 
			
		||||
#define SCROLL_WIDTH_WIDE   3
 | 
			
		||||
 | 
			
		||||
#define PALM_GEOMETRY_ENABLE  1
 | 
			
		||||
#define PALM_GEOMETRY_DISABLE 0
 | 
			
		||||
 | 
			
		||||
#define TP_METRICS_MASK  0x80
 | 
			
		||||
#define FW_VERSION_MASX    0x7f
 | 
			
		||||
#define FW_VER_HIGH_MASK 0x70
 | 
			
		||||
#define FW_VER_LOW_MASK  0x0f
 | 
			
		||||
 | 
			
		||||
/* Times to retry a ps2_command and millisecond delay between tries. */
 | 
			
		||||
#define CYTP_PS2_CMD_TRIES 3
 | 
			
		||||
#define CYTP_PS2_CMD_DELAY 500
 | 
			
		||||
 | 
			
		||||
/* time out for PS/2 command only in milliseconds. */
 | 
			
		||||
#define CYTP_CMD_TIMEOUT  200
 | 
			
		||||
#define CYTP_DATA_TIMEOUT 30
 | 
			
		||||
 | 
			
		||||
#define CYTP_EXT_CMD   0xe8
 | 
			
		||||
#define CYTP_PS2_RETRY 0xfe
 | 
			
		||||
#define CYTP_PS2_ERROR 0xfc
 | 
			
		||||
 | 
			
		||||
#define CYTP_RESP_RETRY 0x01
 | 
			
		||||
#define CYTP_RESP_ERROR 0xfe
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#define CYTP_105001_WIDTH  97   /* Dell XPS 13 */
 | 
			
		||||
#define CYTP_105001_HIGH   59
 | 
			
		||||
#define CYTP_DEFAULT_WIDTH (CYTP_105001_WIDTH)
 | 
			
		||||
#define CYTP_DEFAULT_HIGH  (CYTP_105001_HIGH)
 | 
			
		||||
 | 
			
		||||
#define CYTP_ABS_MAX_X     1600
 | 
			
		||||
#define CYTP_ABS_MAX_Y     900
 | 
			
		||||
#define CYTP_MAX_PRESSURE  255
 | 
			
		||||
#define CYTP_MIN_PRESSURE  0
 | 
			
		||||
 | 
			
		||||
/* header byte bits of relative package. */
 | 
			
		||||
#define BTN_LEFT_BIT   0x01
 | 
			
		||||
#define BTN_RIGHT_BIT  0x02
 | 
			
		||||
#define BTN_MIDDLE_BIT 0x04
 | 
			
		||||
#define REL_X_SIGN_BIT 0x10
 | 
			
		||||
#define REL_Y_SIGN_BIT 0x20
 | 
			
		||||
 | 
			
		||||
/* header byte bits of absolute package. */
 | 
			
		||||
#define ABS_VSCROLL_BIT 0x10
 | 
			
		||||
#define ABS_HSCROLL_BIT 0x20
 | 
			
		||||
#define ABS_MULTIFINGER_TAP 0x04
 | 
			
		||||
#define ABS_EDGE_MOTION_MASK 0x80
 | 
			
		||||
 | 
			
		||||
#define DFLT_RESP_BITS_VALID     0x88  /* SMBus bit should not be set. */
 | 
			
		||||
#define DFLT_RESP_SMBUS_BIT      0x80
 | 
			
		||||
#define   DFLT_SMBUS_MODE        0x80
 | 
			
		||||
#define   DFLT_PS2_MODE          0x00
 | 
			
		||||
#define DFLT_RESP_BIT_MODE       0x40
 | 
			
		||||
#define   DFLT_RESP_REMOTE_MODE  0x40
 | 
			
		||||
#define   DFLT_RESP_STREAM_MODE  0x00
 | 
			
		||||
#define DFLT_RESP_BIT_REPORTING  0x20
 | 
			
		||||
#define DFLT_RESP_BIT_SCALING    0x10
 | 
			
		||||
 | 
			
		||||
#define TP_METRICS_BIT_PALM               0x80
 | 
			
		||||
#define TP_METRICS_BIT_STUBBORN           0x40
 | 
			
		||||
#define TP_METRICS_BIT_2F_JITTER          0x30
 | 
			
		||||
#define TP_METRICS_BIT_1F_JITTER          0x0c
 | 
			
		||||
#define TP_METRICS_BIT_APA                0x02
 | 
			
		||||
#define TP_METRICS_BIT_MTG                0x01
 | 
			
		||||
#define TP_METRICS_BIT_ABS_PKT_FORMAT_SET 0xf0
 | 
			
		||||
#define TP_METRICS_BIT_2F_SPIKE           0x0c
 | 
			
		||||
#define TP_METRICS_BIT_1F_SPIKE           0x03
 | 
			
		||||
 | 
			
		||||
/* bits of first byte response of E9h-Status Request command. */
 | 
			
		||||
#define RESP_BTN_RIGHT_BIT  0x01
 | 
			
		||||
#define RESP_BTN_MIDDLE_BIT 0x02
 | 
			
		||||
#define RESP_BTN_LEFT_BIT   0x04
 | 
			
		||||
#define RESP_SCALING_BIT    0x10
 | 
			
		||||
#define RESP_ENABLE_BIT     0x20
 | 
			
		||||
#define RESP_REMOTE_BIT     0x40
 | 
			
		||||
#define RESP_SMBUS_BIT      0x80
 | 
			
		||||
 | 
			
		||||
#define CYTP_MAX_MT_SLOTS 2
 | 
			
		||||
 | 
			
		||||
struct cytp_contact {
 | 
			
		||||
	int x;
 | 
			
		||||
	int y;
 | 
			
		||||
	int z;  /* also named as touch pressure. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* The structure of Cypress Trackpad event data. */
 | 
			
		||||
struct cytp_report_data {
 | 
			
		||||
	int contact_cnt;
 | 
			
		||||
	struct cytp_contact contacts[CYTP_MAX_MT_SLOTS];
 | 
			
		||||
	unsigned int left:1;
 | 
			
		||||
	unsigned int right:1;
 | 
			
		||||
	unsigned int middle:1;
 | 
			
		||||
	unsigned int tap:1;  /* multi-finger tap detected. */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* The structure of Cypress Trackpad device private data. */
 | 
			
		||||
struct cytp_data {
 | 
			
		||||
	int fw_version;
 | 
			
		||||
 | 
			
		||||
	int pkt_size;
 | 
			
		||||
	int mode;
 | 
			
		||||
 | 
			
		||||
	int tp_min_pressure;
 | 
			
		||||
	int tp_max_pressure;
 | 
			
		||||
	int tp_width;  /* X direction physical size in mm. */
 | 
			
		||||
	int tp_high;  /* Y direction physical size in mm. */
 | 
			
		||||
	int tp_max_abs_x;  /* Max X absolute units that can be reported. */
 | 
			
		||||
	int tp_max_abs_y;  /* Max Y absolute units that can be reported. */
 | 
			
		||||
 | 
			
		||||
	int tp_res_x;  /* X resolution in units/mm. */
 | 
			
		||||
	int tp_res_y;  /* Y resolution in units/mm. */
 | 
			
		||||
 | 
			
		||||
	int tp_metrics_supported;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_MOUSE_PS2_CYPRESS
 | 
			
		||||
int cypress_detect(struct psmouse *psmouse, bool set_properties);
 | 
			
		||||
int cypress_init(struct psmouse *psmouse);
 | 
			
		||||
bool cypress_supported(void);
 | 
			
		||||
#else
 | 
			
		||||
inline int cypress_detect(struct psmouse *psmouse, bool set_properties)
 | 
			
		||||
{
 | 
			
		||||
	return -ENOSYS;
 | 
			
		||||
}
 | 
			
		||||
inline int cypress_init(struct psmouse *psmouse)
 | 
			
		||||
{
 | 
			
		||||
	return -ENOSYS;
 | 
			
		||||
}
 | 
			
		||||
inline bool cypress_supported(void)
 | 
			
		||||
{
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
#endif /* CONFIG_MOUSE_PS2_CYPRESS */
 | 
			
		||||
 | 
			
		||||
#endif  /* _CYPRESS_PS2_H */
 | 
			
		||||
| 
						 | 
				
			
			@ -34,6 +34,7 @@
 | 
			
		|||
#include "touchkit_ps2.h"
 | 
			
		||||
#include "elantech.h"
 | 
			
		||||
#include "sentelic.h"
 | 
			
		||||
#include "cypress_ps2.h"
 | 
			
		||||
 | 
			
		||||
#define DRIVER_DESC	"PS/2 mouse driver"
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -758,6 +759,28 @@ static int psmouse_extensions(struct psmouse *psmouse,
 | 
			
		|||
		synaptics_reset(psmouse);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Try Cypress Trackpad.
 | 
			
		||||
 * Must try it before Finger Sensing Pad because Finger Sensing Pad probe
 | 
			
		||||
 * upsets some modules of Cypress Trackpads.
 | 
			
		||||
 */
 | 
			
		||||
	if (max_proto > PSMOUSE_IMEX &&
 | 
			
		||||
			cypress_detect(psmouse, set_properties) == 0) {
 | 
			
		||||
		if (cypress_supported()) {
 | 
			
		||||
			if (cypress_init(psmouse) == 0)
 | 
			
		||||
				return PSMOUSE_CYPRESS;
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * Finger Sensing Pad probe upsets some modules of
 | 
			
		||||
			 * Cypress Trackpad, must avoid Finger Sensing Pad
 | 
			
		||||
			 * probe if Cypress Trackpad device detected.
 | 
			
		||||
			 */
 | 
			
		||||
			return PSMOUSE_PS2;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		max_proto = PSMOUSE_IMEX;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Try ALPS TouchPad
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -896,6 +919,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
 | 
			
		|||
		.alias		= "thinkps",
 | 
			
		||||
		.detect		= thinking_detect,
 | 
			
		||||
	},
 | 
			
		||||
#ifdef CONFIG_MOUSE_PS2_CYPRESS
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_CYPRESS,
 | 
			
		||||
		.name		= "CyPS/2",
 | 
			
		||||
		.alias		= "cypress",
 | 
			
		||||
		.detect		= cypress_detect,
 | 
			
		||||
		.init		= cypress_init,
 | 
			
		||||
	},
 | 
			
		||||
#endif
 | 
			
		||||
	{
 | 
			
		||||
		.type		= PSMOUSE_GENPS,
 | 
			
		||||
		.name		= "GenPS/2",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,6 +95,7 @@ enum psmouse_type {
 | 
			
		|||
	PSMOUSE_ELANTECH,
 | 
			
		||||
	PSMOUSE_FSP,
 | 
			
		||||
	PSMOUSE_SYNAPTICS_RELATIVE,
 | 
			
		||||
	PSMOUSE_CYPRESS,
 | 
			
		||||
	PSMOUSE_AUTO		/* This one should always be last */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -722,11 +722,13 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
 | 
			
		|||
	default:
 | 
			
		||||
		/*
 | 
			
		||||
		 * If the finger slot contained in SGM is valid, and either
 | 
			
		||||
		 * hasn't changed, or is new, then report SGM in MTB slot 0.
 | 
			
		||||
		 * hasn't changed, or is new, or the old SGM has now moved to
 | 
			
		||||
		 * AGM, then report SGM in MTB slot 0.
 | 
			
		||||
		 * Otherwise, empty MTB slot 0.
 | 
			
		||||
		 */
 | 
			
		||||
		if (mt_state->sgm != -1 &&
 | 
			
		||||
		    (mt_state->sgm == old->sgm || old->sgm == -1))
 | 
			
		||||
		    (mt_state->sgm == old->sgm ||
 | 
			
		||||
		     old->sgm == -1 || mt_state->agm == old->sgm))
 | 
			
		||||
			synaptics_report_slot(dev, 0, sgm);
 | 
			
		||||
		else
 | 
			
		||||
			synaptics_report_slot(dev, 0, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -735,9 +737,31 @@ static void synaptics_report_mt_data(struct psmouse *psmouse,
 | 
			
		|||
		 * If the finger slot contained in AGM is valid, and either
 | 
			
		||||
		 * hasn't changed, or is new, then report AGM in MTB slot 1.
 | 
			
		||||
		 * Otherwise, empty MTB slot 1.
 | 
			
		||||
		 *
 | 
			
		||||
		 * However, in the case where the AGM is new, make sure that
 | 
			
		||||
		 * that it is either the same as the old SGM, or there was no
 | 
			
		||||
		 * SGM.
 | 
			
		||||
		 *
 | 
			
		||||
		 * Otherwise, if the SGM was just 1, and the new AGM is 2, then
 | 
			
		||||
		 * the new AGM will keep the old SGM's tracking ID, which can
 | 
			
		||||
		 * cause apparent drumroll.  This happens if in the following
 | 
			
		||||
		 * valid finger sequence:
 | 
			
		||||
		 *
 | 
			
		||||
		 *  Action                 SGM  AGM (MTB slot:Contact)
 | 
			
		||||
		 *  1. Touch contact 0    (0:0)
 | 
			
		||||
		 *  2. Touch contact 1    (0:0, 1:1)
 | 
			
		||||
		 *  3. Lift  contact 0    (1:1)
 | 
			
		||||
		 *  4. Touch contacts 2,3 (0:2, 1:3)
 | 
			
		||||
		 *
 | 
			
		||||
		 * In step 4, contact 3, in AGM must not be given the same
 | 
			
		||||
		 * tracking ID as contact 1 had in step 3.  To avoid this,
 | 
			
		||||
		 * the first agm with contact 3 is dropped and slot 1 is
 | 
			
		||||
		 * invalidated (tracking ID = -1).
 | 
			
		||||
		 */
 | 
			
		||||
		if (mt_state->agm != -1 &&
 | 
			
		||||
		    (mt_state->agm == old->agm || old->agm == -1))
 | 
			
		||||
		    (mt_state->agm == old->agm ||
 | 
			
		||||
		     (old->agm == -1 &&
 | 
			
		||||
		      (old->sgm == -1 || mt_state->agm == old->sgm))))
 | 
			
		||||
			synaptics_report_slot(dev, 1, agm);
 | 
			
		||||
		else
 | 
			
		||||
			synaptics_report_slot(dev, 1, NULL);
 | 
			
		||||
| 
						 | 
				
			
			@ -1247,11 +1271,11 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv)
 | 
			
		|||
	input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
 | 
			
		||||
 | 
			
		||||
	if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) {
 | 
			
		||||
		input_mt_init_slots(dev, 2, 0);
 | 
			
		||||
		set_abs_position_params(dev, priv, ABS_MT_POSITION_X,
 | 
			
		||||
					ABS_MT_POSITION_Y);
 | 
			
		||||
		/* Image sensors can report per-contact pressure */
 | 
			
		||||
		input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
 | 
			
		||||
		input_mt_init_slots(dev, 2, INPUT_MT_POINTER);
 | 
			
		||||
 | 
			
		||||
		/* Image sensors can signal 4 and 5 finger clicks */
 | 
			
		||||
		__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -236,6 +236,7 @@ config SERIO_PS2MULT
 | 
			
		|||
 | 
			
		||||
config SERIO_ARC_PS2
 | 
			
		||||
	tristate "ARC PS/2 support"
 | 
			
		||||
	depends on GENERIC_HARDIRQS
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here if you have an ARC FPGA platform with a PS/2
 | 
			
		||||
	  controller in it.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -359,6 +359,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
 | 
			
		|||
		case 0x802: /* Intuos4 General Pen */
 | 
			
		||||
		case 0x804: /* Intuos4 Marker Pen */
 | 
			
		||||
		case 0x40802: /* Intuos4 Classic Pen */
 | 
			
		||||
		case 0x18803: /* DTH2242 Grip Pen */
 | 
			
		||||
		case 0x022:
 | 
			
		||||
			wacom->tool[idx] = BTN_TOOL_PEN;
 | 
			
		||||
			break;
 | 
			
		||||
| 
						 | 
				
			
			@ -538,6 +539,13 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 | 
			
		|||
				input_report_key(input, wacom->tool[1], 0);
 | 
			
		||||
				input_report_abs(input, ABS_MISC, 0);
 | 
			
		||||
			}
 | 
			
		||||
		} else if (features->type == DTK) {
 | 
			
		||||
			input_report_key(input, BTN_0, (data[6] & 0x01));
 | 
			
		||||
			input_report_key(input, BTN_1, (data[6] & 0x02));
 | 
			
		||||
			input_report_key(input, BTN_2, (data[6] & 0x04));
 | 
			
		||||
			input_report_key(input, BTN_3, (data[6] & 0x08));
 | 
			
		||||
			input_report_key(input, BTN_4, (data[6] & 0x10));
 | 
			
		||||
			input_report_key(input, BTN_5, (data[6] & 0x20));
 | 
			
		||||
		} else if (features->type == WACOM_24HD) {
 | 
			
		||||
			input_report_key(input, BTN_0, (data[6] & 0x01));
 | 
			
		||||
			input_report_key(input, BTN_1, (data[6] & 0x02));
 | 
			
		||||
| 
						 | 
				
			
			@ -785,25 +793,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
 | 
			
		|||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int find_slot_from_contactid(struct wacom_wac *wacom, int contactid)
 | 
			
		||||
{
 | 
			
		||||
	int touch_max = wacom->features.touch_max;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (!wacom->slots)
 | 
			
		||||
		return -1;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < touch_max; ++i) {
 | 
			
		||||
		if (wacom->slots[i] == contactid)
 | 
			
		||||
			return i;
 | 
			
		||||
	}
 | 
			
		||||
	for (i = 0; i < touch_max; ++i) {
 | 
			
		||||
		if (wacom->slots[i] == -1)
 | 
			
		||||
			return i;
 | 
			
		||||
	}
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int int_dist(int x1, int y1, int x2, int y2)
 | 
			
		||||
{
 | 
			
		||||
	int x = x2 - x1;
 | 
			
		||||
| 
						 | 
				
			
			@ -833,8 +822,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
 | 
			
		|||
	for (i = 0; i < contacts_to_send; i++) {
 | 
			
		||||
		int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
 | 
			
		||||
		bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
 | 
			
		||||
		int id = data[offset + 1];
 | 
			
		||||
		int slot = find_slot_from_contactid(wacom, id);
 | 
			
		||||
		int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
 | 
			
		||||
 | 
			
		||||
		if (slot < 0)
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -856,9 +844,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
 | 
			
		|||
			input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
 | 
			
		||||
			input_report_abs(input, ABS_MT_ORIENTATION, w > h);
 | 
			
		||||
		}
 | 
			
		||||
		wacom->slots[slot] = touch ? id : -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_mt_report_pointer_emulation(input, true);
 | 
			
		||||
 | 
			
		||||
	wacom->num_contacts_left -= contacts_to_send;
 | 
			
		||||
| 
						 | 
				
			
			@ -895,7 +881,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
 | 
			
		|||
		int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
 | 
			
		||||
		bool touch = data[offset] & 0x1;
 | 
			
		||||
		int id = le16_to_cpup((__le16 *)&data[offset + 1]);
 | 
			
		||||
		int slot = find_slot_from_contactid(wacom, id);
 | 
			
		||||
		int slot = input_mt_get_slot_by_key(input, id);
 | 
			
		||||
 | 
			
		||||
		if (slot < 0)
 | 
			
		||||
			continue;
 | 
			
		||||
| 
						 | 
				
			
			@ -908,9 +894,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
 | 
			
		|||
			input_report_abs(input, ABS_MT_POSITION_X, x);
 | 
			
		||||
			input_report_abs(input, ABS_MT_POSITION_Y, y);
 | 
			
		||||
		}
 | 
			
		||||
		wacom->slots[slot] = touch ? id : -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_mt_report_pointer_emulation(input, true);
 | 
			
		||||
 | 
			
		||||
	wacom->num_contacts_left -= contacts_to_send;
 | 
			
		||||
| 
						 | 
				
			
			@ -942,12 +926,11 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom)
 | 
			
		|||
			contact_with_no_pen_down_count++;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	input_mt_report_pointer_emulation(input, true);
 | 
			
		||||
 | 
			
		||||
	/* keep touch state for pen event */
 | 
			
		||||
	wacom->shared->touch_down = (contact_with_no_pen_down_count > 0);
 | 
			
		||||
 | 
			
		||||
	input_mt_report_pointer_emulation(input, true);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1104,12 +1087,15 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
 | 
			
		|||
static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data)
 | 
			
		||||
{
 | 
			
		||||
	struct input_dev *input = wacom->input;
 | 
			
		||||
	int slot_id = data[0] - 2;  /* data[0] is between 2 and 17 */
 | 
			
		||||
	bool touch = data[1] & 0x80;
 | 
			
		||||
	int slot = input_mt_get_slot_by_key(input, data[0]);
 | 
			
		||||
 | 
			
		||||
	if (slot < 0)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	touch = touch && !wacom->shared->stylus_in_proximity;
 | 
			
		||||
 | 
			
		||||
	input_mt_slot(input, slot_id);
 | 
			
		||||
	input_mt_slot(input, slot);
 | 
			
		||||
	input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
 | 
			
		||||
 | 
			
		||||
	if (touch) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1162,7 +1148,6 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom)
 | 
			
		|||
			wacom_bpt3_button_msg(wacom, data + offset);
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	input_mt_report_pointer_emulation(input, true);
 | 
			
		||||
 | 
			
		||||
	input_sync(input);
 | 
			
		||||
| 
						 | 
				
			
			@ -1319,6 +1304,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
 | 
			
		|||
	case WACOM_21UX2:
 | 
			
		||||
	case WACOM_22HD:
 | 
			
		||||
	case WACOM_24HD:
 | 
			
		||||
	case DTK:
 | 
			
		||||
		sync = wacom_intuos_irq(wacom_wac);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1444,6 +1430,51 @@ static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
 | 
			
		|||
       return (logical_max * 100) / physical_max;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void wacom_abs_set_axis(struct input_dev *input_dev,
 | 
			
		||||
			       struct wacom_wac *wacom_wac)
 | 
			
		||||
{
 | 
			
		||||
	struct wacom_features *features = &wacom_wac->features;
 | 
			
		||||
 | 
			
		||||
	if (features->device_type == BTN_TOOL_PEN) {
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
 | 
			
		||||
				     features->x_fuzz, 0);
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
 | 
			
		||||
				     features->y_fuzz, 0);
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_PRESSURE, 0,
 | 
			
		||||
			features->pressure_max, features->pressure_fuzz, 0);
 | 
			
		||||
 | 
			
		||||
		/* penabled devices have fixed resolution for each model */
 | 
			
		||||
		input_abs_set_res(input_dev, ABS_X, features->x_resolution);
 | 
			
		||||
		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (features->touch_max <= 2) {
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_X, 0,
 | 
			
		||||
				features->x_max, features->x_fuzz, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_Y, 0,
 | 
			
		||||
				features->y_max, features->y_fuzz, 0);
 | 
			
		||||
			input_abs_set_res(input_dev, ABS_X,
 | 
			
		||||
				wacom_calculate_touch_res(features->x_max,
 | 
			
		||||
							features->x_phy));
 | 
			
		||||
			input_abs_set_res(input_dev, ABS_Y,
 | 
			
		||||
				wacom_calculate_touch_res(features->y_max,
 | 
			
		||||
							features->y_phy));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (features->touch_max > 1) {
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
 | 
			
		||||
				features->x_max, features->x_fuzz, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
 | 
			
		||||
				features->y_max, features->y_fuzz, 0);
 | 
			
		||||
			input_abs_set_res(input_dev, ABS_MT_POSITION_X,
 | 
			
		||||
				wacom_calculate_touch_res(features->x_max,
 | 
			
		||||
							features->x_phy));
 | 
			
		||||
			input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
 | 
			
		||||
				wacom_calculate_touch_res(features->y_max,
 | 
			
		||||
							features->y_phy));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
			
		||||
				   struct wacom_wac *wacom_wac)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -1453,30 +1484,10 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
			
		|||
	input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
 | 
			
		||||
 | 
			
		||||
	__set_bit(BTN_TOUCH, input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
	input_set_abs_params(input_dev, ABS_X, 0, features->x_max,
 | 
			
		||||
			     features->x_fuzz, 0);
 | 
			
		||||
	input_set_abs_params(input_dev, ABS_Y, 0, features->y_max,
 | 
			
		||||
			     features->y_fuzz, 0);
 | 
			
		||||
 | 
			
		||||
	if (features->device_type == BTN_TOOL_PEN) {
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_PRESSURE, 0, features->pressure_max,
 | 
			
		||||
			     features->pressure_fuzz, 0);
 | 
			
		||||
 | 
			
		||||
		/* penabled devices have fixed resolution for each model */
 | 
			
		||||
		input_abs_set_res(input_dev, ABS_X, features->x_resolution);
 | 
			
		||||
		input_abs_set_res(input_dev, ABS_Y, features->y_resolution);
 | 
			
		||||
	} else {
 | 
			
		||||
		input_abs_set_res(input_dev, ABS_X,
 | 
			
		||||
			wacom_calculate_touch_res(features->x_max,
 | 
			
		||||
						features->x_phy));
 | 
			
		||||
		input_abs_set_res(input_dev, ABS_Y,
 | 
			
		||||
			wacom_calculate_touch_res(features->y_max,
 | 
			
		||||
						features->y_phy));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__set_bit(ABS_MISC, input_dev->absbit);
 | 
			
		||||
 | 
			
		||||
	wacom_abs_set_axis(input_dev, wacom_wac);
 | 
			
		||||
 | 
			
		||||
	switch (wacom_wac->features.type) {
 | 
			
		||||
	case WACOM_MO:
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -1513,12 +1524,17 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
			
		|||
		__set_bit(BTN_Y, input_dev->keybit);
 | 
			
		||||
		__set_bit(BTN_Z, input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
		for (i = 0; i < 10; i++)
 | 
			
		||||
		for (i = 6; i < 10; i++)
 | 
			
		||||
			__set_bit(BTN_0 + i, input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
		__set_bit(KEY_PROG1, input_dev->keybit);
 | 
			
		||||
		__set_bit(KEY_PROG2, input_dev->keybit);
 | 
			
		||||
		__set_bit(KEY_PROG3, input_dev->keybit);
 | 
			
		||||
		/* fall through */
 | 
			
		||||
 | 
			
		||||
	case DTK:
 | 
			
		||||
		for (i = 0; i < 6; i++)
 | 
			
		||||
			__set_bit(BTN_0 + i, input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
 | 
			
		||||
		input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -1614,24 +1630,11 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
			
		|||
		} else if (features->device_type == BTN_TOOL_FINGER) {
 | 
			
		||||
			__clear_bit(ABS_MISC, input_dev->absbit);
 | 
			
		||||
 | 
			
		||||
			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_TOOL_QUADTAP, input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
			input_mt_init_slots(input_dev, features->touch_max, 0);
 | 
			
		||||
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR,
 | 
			
		||||
			                     0, features->x_max, 0, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR,
 | 
			
		||||
			                     0, features->y_max, 0, 0);
 | 
			
		||||
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
 | 
			
		||||
					     0, features->x_max,
 | 
			
		||||
					     features->x_fuzz, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
 | 
			
		||||
					     0, features->y_max,
 | 
			
		||||
					     features->y_fuzz, 0);
 | 
			
		||||
			input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER);
 | 
			
		||||
		}
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1662,27 +1665,14 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
			
		|||
 | 
			
		||||
	case MTSCREEN:
 | 
			
		||||
	case MTTPC:
 | 
			
		||||
		if (features->device_type == BTN_TOOL_FINGER) {
 | 
			
		||||
			wacom_wac->slots = kmalloc(features->touch_max *
 | 
			
		||||
							sizeof(int),
 | 
			
		||||
						   GFP_KERNEL);
 | 
			
		||||
			if (!wacom_wac->slots)
 | 
			
		||||
				return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < features->touch_max; i++)
 | 
			
		||||
				wacom_wac->slots[i] = -1;
 | 
			
		||||
		}
 | 
			
		||||
		/* fall through */
 | 
			
		||||
 | 
			
		||||
	case TABLETPC2FG:
 | 
			
		||||
		if (features->device_type == BTN_TOOL_FINGER) {
 | 
			
		||||
			input_mt_init_slots(input_dev, features->touch_max, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_TOOL_TYPE,
 | 
			
		||||
					0, MT_TOOL_MAX, 0, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
 | 
			
		||||
					0, features->x_max, 0, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
 | 
			
		||||
					0, features->y_max, 0, 0);
 | 
			
		||||
			unsigned int flags = INPUT_MT_DIRECT;
 | 
			
		||||
 | 
			
		||||
			if (wacom_wac->features.type == TABLETPC2FG)
 | 
			
		||||
				flags = 0;
 | 
			
		||||
 | 
			
		||||
			input_mt_init_slots(input_dev, features->touch_max, flags);
 | 
			
		||||
		}
 | 
			
		||||
		/* fall through */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1725,35 +1715,26 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
 | 
			
		|||
		__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
 | 
			
		||||
 | 
			
		||||
		if (features->device_type == BTN_TOOL_FINGER) {
 | 
			
		||||
			unsigned int flags = INPUT_MT_POINTER;
 | 
			
		||||
 | 
			
		||||
			__set_bit(BTN_LEFT, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_FORWARD, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_BACK, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_RIGHT, input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
			__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
 | 
			
		||||
			input_mt_init_slots(input_dev, features->touch_max, 0);
 | 
			
		||||
 | 
			
		||||
			if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
 | 
			
		||||
				__set_bit(BTN_TOOL_TRIPLETAP,
 | 
			
		||||
					  input_dev->keybit);
 | 
			
		||||
				__set_bit(BTN_TOOL_QUADTAP,
 | 
			
		||||
					  input_dev->keybit);
 | 
			
		||||
 | 
			
		||||
				input_set_abs_params(input_dev,
 | 
			
		||||
						     ABS_MT_TOUCH_MAJOR,
 | 
			
		||||
						     0, features->x_max, 0, 0);
 | 
			
		||||
				input_set_abs_params(input_dev,
 | 
			
		||||
						     ABS_MT_TOUCH_MINOR,
 | 
			
		||||
						     0, features->y_max, 0, 0);
 | 
			
		||||
			} else {
 | 
			
		||||
				__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
 | 
			
		||||
				__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
 | 
			
		||||
				flags = 0;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_X,
 | 
			
		||||
					     0, features->x_max,
 | 
			
		||||
					     features->x_fuzz, 0);
 | 
			
		||||
			input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
 | 
			
		||||
					     0, features->y_max,
 | 
			
		||||
					     features->y_fuzz, 0);
 | 
			
		||||
			input_mt_init_slots(input_dev, features->touch_max, flags);
 | 
			
		||||
		} else if (features->device_type == BTN_TOOL_PEN) {
 | 
			
		||||
			__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
 | 
			
		||||
			__set_bit(BTN_TOOL_PEN, input_dev->keybit);
 | 
			
		||||
| 
						 | 
				
			
			@ -1978,6 +1959,13 @@ static const struct wacom_features wacom_features_0xCE =
 | 
			
		|||
static const struct wacom_features wacom_features_0xF0 =
 | 
			
		||||
	{ "Wacom DTU1631",        WACOM_PKGLEN_GRAPHIRE,  34623, 19553,  511,
 | 
			
		||||
	  0, DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES };
 | 
			
		||||
static const struct wacom_features wacom_features_0x59 = /* Pen */
 | 
			
		||||
	{ "Wacom DTH2242",        WACOM_PKGLEN_INTUOS,    95840, 54260, 2047,
 | 
			
		||||
	  63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
 | 
			
		||||
	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D };
 | 
			
		||||
static const struct wacom_features wacom_features_0x5D = /* Touch */
 | 
			
		||||
	{ "Wacom DTH2242",       .type = WACOM_24HDT,
 | 
			
		||||
	  .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x59, .touch_max = 10 };
 | 
			
		||||
static const struct wacom_features wacom_features_0xCC =
 | 
			
		||||
	{ "Wacom Cintiq 21UX2",   WACOM_PKGLEN_INTUOS,    87200, 65600, 2047,
 | 
			
		||||
	  63, WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
 | 
			
		||||
| 
						 | 
				
			
			@ -2152,6 +2140,8 @@ const struct usb_device_id wacom_ids[] = {
 | 
			
		|||
	{ USB_DEVICE_WACOM(0x43) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0x44) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0x45) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0x59) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0x5D) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0xB0) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0xB1) },
 | 
			
		||||
	{ USB_DEVICE_WACOM(0xB2) },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,6 +78,7 @@ enum {
 | 
			
		|||
	INTUOS5L,
 | 
			
		||||
	WACOM_21UX2,
 | 
			
		||||
	WACOM_22HD,
 | 
			
		||||
	DTK,
 | 
			
		||||
	WACOM_24HD,
 | 
			
		||||
	CINTIQ,
 | 
			
		||||
	WACOM_BEE,
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +136,6 @@ struct wacom_wac {
 | 
			
		|||
	int pid;
 | 
			
		||||
	int battery_capacity;
 | 
			
		||||
	int num_contacts_left;
 | 
			
		||||
	int *slots;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -359,7 +359,7 @@ config TOUCHSCREEN_MCS5000
 | 
			
		|||
 | 
			
		||||
config TOUCHSCREEN_MMS114
 | 
			
		||||
	tristate "MELFAS MMS114 touchscreen"
 | 
			
		||||
	depends on I2C
 | 
			
		||||
	depends on I2C && GENERIC_HARDIRQS
 | 
			
		||||
	help
 | 
			
		||||
	  Say Y here if you have the MELFAS MMS114 touchscreen controller
 | 
			
		||||
	  chip in your system.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -193,7 +193,6 @@ static struct spi_driver cyttsp_spi_driver = {
 | 
			
		|||
 | 
			
		||||
module_spi_driver(cyttsp_spi_driver);
 | 
			
		||||
 | 
			
		||||
MODULE_ALIAS("spi:cyttsp");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
 | 
			
		||||
MODULE_AUTHOR("Cypress");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -429,12 +429,12 @@ static int mms114_probe(struct i2c_client *client,
 | 
			
		|||
		return -ENODEV;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data = kzalloc(sizeof(struct mms114_data), GFP_KERNEL);
 | 
			
		||||
	input_dev = input_allocate_device();
 | 
			
		||||
	data = devm_kzalloc(&client->dev, sizeof(struct mms114_data),
 | 
			
		||||
			    GFP_KERNEL);
 | 
			
		||||
	input_dev = devm_input_allocate_device(&client->dev);
 | 
			
		||||
	if (!data || !input_dev) {
 | 
			
		||||
		dev_err(&client->dev, "Failed to allocate memory\n");
 | 
			
		||||
		error = -ENOMEM;
 | 
			
		||||
		goto err_free_mem;
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data->client = client;
 | 
			
		||||
| 
						 | 
				
			
			@ -466,58 +466,37 @@ static int mms114_probe(struct i2c_client *client,
 | 
			
		|||
	input_set_drvdata(input_dev, data);
 | 
			
		||||
	i2c_set_clientdata(client, data);
 | 
			
		||||
 | 
			
		||||
	data->core_reg = regulator_get(&client->dev, "avdd");
 | 
			
		||||
	data->core_reg = devm_regulator_get(&client->dev, "avdd");
 | 
			
		||||
	if (IS_ERR(data->core_reg)) {
 | 
			
		||||
		error = PTR_ERR(data->core_reg);
 | 
			
		||||
		dev_err(&client->dev,
 | 
			
		||||
			"Unable to get the Core regulator (%d)\n", error);
 | 
			
		||||
		goto err_free_mem;
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	data->io_reg = regulator_get(&client->dev, "vdd");
 | 
			
		||||
	data->io_reg = devm_regulator_get(&client->dev, "vdd");
 | 
			
		||||
	if (IS_ERR(data->io_reg)) {
 | 
			
		||||
		error = PTR_ERR(data->io_reg);
 | 
			
		||||
		dev_err(&client->dev,
 | 
			
		||||
			"Unable to get the IO regulator (%d)\n", error);
 | 
			
		||||
		goto err_core_reg;
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = request_threaded_irq(client->irq, NULL, mms114_interrupt,
 | 
			
		||||
			IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "mms114", data);
 | 
			
		||||
	error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
 | 
			
		||||
			mms114_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 | 
			
		||||
			dev_name(&client->dev), data);
 | 
			
		||||
	if (error) {
 | 
			
		||||
		dev_err(&client->dev, "Failed to register interrupt\n");
 | 
			
		||||
		goto err_io_reg;
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
	disable_irq(client->irq);
 | 
			
		||||
 | 
			
		||||
	error = input_register_device(data->input_dev);
 | 
			
		||||
	if (error)
 | 
			
		||||
		goto err_free_irq;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
err_free_irq:
 | 
			
		||||
	free_irq(client->irq, data);
 | 
			
		||||
err_io_reg:
 | 
			
		||||
	regulator_put(data->io_reg);
 | 
			
		||||
err_core_reg:
 | 
			
		||||
	regulator_put(data->core_reg);
 | 
			
		||||
err_free_mem:
 | 
			
		||||
	input_free_device(input_dev);
 | 
			
		||||
	kfree(data);
 | 
			
		||||
	if (error) {
 | 
			
		||||
		dev_err(&client->dev, "Failed to register input device\n");
 | 
			
		||||
		return error;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
static int mms114_remove(struct i2c_client *client)
 | 
			
		||||
{
 | 
			
		||||
	struct mms114_data *data = i2c_get_clientdata(client);
 | 
			
		||||
 | 
			
		||||
	free_irq(client->irq, data);
 | 
			
		||||
	regulator_put(data->io_reg);
 | 
			
		||||
	regulator_put(data->core_reg);
 | 
			
		||||
	input_unregister_device(data->input_dev);
 | 
			
		||||
	kfree(data);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -590,7 +569,6 @@ static struct i2c_driver mms114_driver = {
 | 
			
		|||
		.of_match_table = of_match_ptr(mms114_dt_match),
 | 
			
		||||
	},
 | 
			
		||||
	.probe		= mms114_probe,
 | 
			
		||||
	.remove		= mms114_remove,
 | 
			
		||||
	.id_table	= mms114_id,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -120,6 +120,7 @@ static void stmpe_work(struct work_struct *work)
 | 
			
		|||
	__stmpe_reset_fifo(ts->stmpe);
 | 
			
		||||
 | 
			
		||||
	input_report_abs(ts->idev, ABS_PRESSURE, 0);
 | 
			
		||||
	input_report_key(ts->idev, BTN_TOUCH, 0);
 | 
			
		||||
	input_sync(ts->idev);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -153,6 +154,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
 | 
			
		|||
	input_report_abs(ts->idev, ABS_X, x);
 | 
			
		||||
	input_report_abs(ts->idev, ABS_Y, y);
 | 
			
		||||
	input_report_abs(ts->idev, ABS_PRESSURE, z);
 | 
			
		||||
	input_report_key(ts->idev, BTN_TOUCH, 1);
 | 
			
		||||
	input_sync(ts->idev);
 | 
			
		||||
 | 
			
		||||
       /* flush the FIFO after we have read out our values. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -753,3 +753,4 @@ module_spi_driver(tsc2005_driver);
 | 
			
		|||
MODULE_AUTHOR("Lauri Leukkunen <lauri.leukkunen@nokia.com>");
 | 
			
		||||
MODULE_DESCRIPTION("TSC2005 Touchscreen Driver");
 | 
			
		||||
MODULE_LICENSE("GPL");
 | 
			
		||||
MODULE_ALIAS("spi:tsc2005");
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -247,7 +247,7 @@ static int wm831x_ts_probe(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	wm831x_ts = devm_kzalloc(&pdev->dev, sizeof(struct wm831x_ts),
 | 
			
		||||
				 GFP_KERNEL);
 | 
			
		||||
	input_dev = input_allocate_device();
 | 
			
		||||
	input_dev = devm_input_allocate_device(&pdev->dev);
 | 
			
		||||
	if (!wm831x_ts || !input_dev) {
 | 
			
		||||
		error = -ENOMEM;
 | 
			
		||||
		goto err_alloc;
 | 
			
		||||
| 
						 | 
				
			
			@ -376,7 +376,6 @@ err_pd_irq:
 | 
			
		|||
err_data_irq:
 | 
			
		||||
	free_irq(wm831x_ts->data_irq, wm831x_ts);
 | 
			
		||||
err_alloc:
 | 
			
		||||
	input_free_device(input_dev);
 | 
			
		||||
 | 
			
		||||
	return error;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -387,7 +386,6 @@ static int wm831x_ts_remove(struct platform_device *pdev)
 | 
			
		|||
 | 
			
		||||
	free_irq(wm831x_ts->pd_irq, wm831x_ts);
 | 
			
		||||
	free_irq(wm831x_ts->data_irq, wm831x_ts);
 | 
			
		||||
	input_unregister_device(wm831x_ts->input_dev);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,6 +42,7 @@
 | 
			
		|||
#include <linux/slab.h>
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
#include <linux/uaccess.h>
 | 
			
		||||
#include <linux/moduleparam.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/ptrace.h>
 | 
			
		||||
#include <asm/irq_regs.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -578,8 +579,71 @@ struct sysrq_state {
 | 
			
		|||
	bool active;
 | 
			
		||||
	bool need_reinject;
 | 
			
		||||
	bool reinjecting;
 | 
			
		||||
 | 
			
		||||
	/* reset sequence handling */
 | 
			
		||||
	bool reset_canceled;
 | 
			
		||||
	unsigned long reset_keybit[BITS_TO_LONGS(KEY_CNT)];
 | 
			
		||||
	int reset_seq_len;
 | 
			
		||||
	int reset_seq_cnt;
 | 
			
		||||
	int reset_seq_version;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define SYSRQ_KEY_RESET_MAX	20 /* Should be plenty */
 | 
			
		||||
static unsigned short sysrq_reset_seq[SYSRQ_KEY_RESET_MAX];
 | 
			
		||||
static unsigned int sysrq_reset_seq_len;
 | 
			
		||||
static unsigned int sysrq_reset_seq_version = 1;
 | 
			
		||||
 | 
			
		||||
static void sysrq_parse_reset_sequence(struct sysrq_state *state)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	unsigned short key;
 | 
			
		||||
 | 
			
		||||
	state->reset_seq_cnt = 0;
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < sysrq_reset_seq_len; i++) {
 | 
			
		||||
		key = sysrq_reset_seq[i];
 | 
			
		||||
 | 
			
		||||
		if (key == KEY_RESERVED || key > KEY_MAX)
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
		__set_bit(key, state->reset_keybit);
 | 
			
		||||
		state->reset_seq_len++;
 | 
			
		||||
 | 
			
		||||
		if (test_bit(key, state->key_down))
 | 
			
		||||
			state->reset_seq_cnt++;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Disable reset until old keys are not released */
 | 
			
		||||
	state->reset_canceled = state->reset_seq_cnt != 0;
 | 
			
		||||
 | 
			
		||||
	state->reset_seq_version = sysrq_reset_seq_version;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool sysrq_detect_reset_sequence(struct sysrq_state *state,
 | 
			
		||||
					unsigned int code, int value)
 | 
			
		||||
{
 | 
			
		||||
	if (!test_bit(code, state->reset_keybit)) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Pressing any key _not_ in reset sequence cancels
 | 
			
		||||
		 * the reset sequence.
 | 
			
		||||
		 */
 | 
			
		||||
		if (value && state->reset_seq_cnt)
 | 
			
		||||
			state->reset_canceled = true;
 | 
			
		||||
	} else if (value == 0) {
 | 
			
		||||
		/* key release */
 | 
			
		||||
		if (--state->reset_seq_cnt == 0)
 | 
			
		||||
			state->reset_canceled = false;
 | 
			
		||||
	} else if (value == 1) {
 | 
			
		||||
		/* key press, not autorepeat */
 | 
			
		||||
		if (++state->reset_seq_cnt == state->reset_seq_len &&
 | 
			
		||||
		    !state->reset_canceled) {
 | 
			
		||||
			return true;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void sysrq_reinject_alt_sysrq(struct work_struct *work)
 | 
			
		||||
{
 | 
			
		||||
	struct sysrq_state *sysrq =
 | 
			
		||||
| 
						 | 
				
			
			@ -606,27 +670,12 @@ static void sysrq_reinject_alt_sysrq(struct work_struct *work)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool sysrq_filter(struct input_handle *handle,
 | 
			
		||||
			 unsigned int type, unsigned int code, int value)
 | 
			
		||||
static bool sysrq_handle_keypress(struct sysrq_state *sysrq,
 | 
			
		||||
				  unsigned int code, int value)
 | 
			
		||||
{
 | 
			
		||||
	struct sysrq_state *sysrq = handle->private;
 | 
			
		||||
	bool was_active = sysrq->active;
 | 
			
		||||
	bool suppress;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Do not filter anything if we are in the process of re-injecting
 | 
			
		||||
	 * Alt+SysRq combination.
 | 
			
		||||
	 */
 | 
			
		||||
	if (sysrq->reinjecting)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	switch (type) {
 | 
			
		||||
 | 
			
		||||
	case EV_SYN:
 | 
			
		||||
		suppress = false;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case EV_KEY:
 | 
			
		||||
	switch (code) {
 | 
			
		||||
 | 
			
		||||
	case KEY_LEFTALT:
 | 
			
		||||
| 
						 | 
				
			
			@ -664,7 +713,7 @@ static bool sysrq_filter(struct input_handle *handle,
 | 
			
		|||
		 * triggering print screen function.
 | 
			
		||||
		 */
 | 
			
		||||
		if (sysrq->active)
 | 
			
		||||
				clear_bit(KEY_SYSRQ, handle->dev->key);
 | 
			
		||||
			clear_bit(KEY_SYSRQ, sysrq->handle.dev->key);
 | 
			
		||||
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -679,6 +728,13 @@ static bool sysrq_filter(struct input_handle *handle,
 | 
			
		|||
	suppress = sysrq->active;
 | 
			
		||||
 | 
			
		||||
	if (!sysrq->active) {
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * See if reset sequence has changed since the last time.
 | 
			
		||||
		 */
 | 
			
		||||
		if (sysrq->reset_seq_version != sysrq_reset_seq_version)
 | 
			
		||||
			sysrq_parse_reset_sequence(sysrq);
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * If we are not suppressing key presses keep track of
 | 
			
		||||
		 * keyboard state so we can release keys that have been
 | 
			
		||||
| 
						 | 
				
			
			@ -692,14 +748,43 @@ static bool sysrq_filter(struct input_handle *handle,
 | 
			
		|||
		if (was_active)
 | 
			
		||||
			schedule_work(&sysrq->reinject_work);
 | 
			
		||||
 | 
			
		||||
		} else if (value == 0 &&
 | 
			
		||||
			   test_and_clear_bit(code, sysrq->key_down)) {
 | 
			
		||||
		if (sysrq_detect_reset_sequence(sysrq, code, value)) {
 | 
			
		||||
			/* Force emergency reboot */
 | 
			
		||||
			__handle_sysrq(sysrq_xlate[KEY_B], false);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else if (value == 0 && test_and_clear_bit(code, sysrq->key_down)) {
 | 
			
		||||
		/*
 | 
			
		||||
		 * Pass on release events for keys that was pressed before
 | 
			
		||||
		 * entering SysRq mode.
 | 
			
		||||
		 */
 | 
			
		||||
		suppress = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return suppress;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool sysrq_filter(struct input_handle *handle,
 | 
			
		||||
			 unsigned int type, unsigned int code, int value)
 | 
			
		||||
{
 | 
			
		||||
	struct sysrq_state *sysrq = handle->private;
 | 
			
		||||
	bool suppress;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Do not filter anything if we are in the process of re-injecting
 | 
			
		||||
	 * Alt+SysRq combination.
 | 
			
		||||
	 */
 | 
			
		||||
	if (sysrq->reinjecting)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	switch (type) {
 | 
			
		||||
 | 
			
		||||
	case EV_SYN:
 | 
			
		||||
		suppress = false;
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	case EV_KEY:
 | 
			
		||||
		suppress = sysrq_handle_keypress(sysrq, code, value);
 | 
			
		||||
		break;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
| 
						 | 
				
			
			@ -787,7 +872,20 @@ static bool sysrq_handler_registered;
 | 
			
		|||
 | 
			
		||||
static inline void sysrq_register_handler(void)
 | 
			
		||||
{
 | 
			
		||||
	extern unsigned short platform_sysrq_reset_seq[] __weak;
 | 
			
		||||
	unsigned short key;
 | 
			
		||||
	int error;
 | 
			
		||||
	int i;
 | 
			
		||||
 | 
			
		||||
	if (platform_sysrq_reset_seq) {
 | 
			
		||||
		for (i = 0; i < ARRAY_SIZE(sysrq_reset_seq); i++) {
 | 
			
		||||
			key = platform_sysrq_reset_seq[i];
 | 
			
		||||
			if (key == KEY_RESERVED || key > KEY_MAX)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			sysrq_reset_seq[sysrq_reset_seq_len++] = key;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	error = input_register_handler(&sysrq_handler);
 | 
			
		||||
	if (error)
 | 
			
		||||
| 
						 | 
				
			
			@ -804,6 +902,36 @@ static inline void sysrq_unregister_handler(void)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int sysrq_reset_seq_param_set(const char *buffer,
 | 
			
		||||
				     const struct kernel_param *kp)
 | 
			
		||||
{
 | 
			
		||||
	unsigned long val;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	error = strict_strtoul(buffer, 0, &val);
 | 
			
		||||
	if (error < 0)
 | 
			
		||||
		return error;
 | 
			
		||||
 | 
			
		||||
	if (val > KEY_MAX)
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
 | 
			
		||||
	*((unsigned short *)kp->arg) = val;
 | 
			
		||||
	sysrq_reset_seq_version++;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct kernel_param_ops param_ops_sysrq_reset_seq = {
 | 
			
		||||
	.get	= param_get_ushort,
 | 
			
		||||
	.set	= sysrq_reset_seq_param_set,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define param_check_sysrq_reset_seq(name, p)	\
 | 
			
		||||
	__param_check(name, p, unsigned short)
 | 
			
		||||
 | 
			
		||||
module_param_array_named(reset_seq, sysrq_reset_seq, sysrq_reset_seq,
 | 
			
		||||
			 &sysrq_reset_seq_len, 0644);
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
static inline void sysrq_register_handler(void)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,6 +22,18 @@
 | 
			
		|||
 | 
			
		||||
#define BMA150_DRIVER		"bma150"
 | 
			
		||||
 | 
			
		||||
#define BMA150_RANGE_2G		0
 | 
			
		||||
#define BMA150_RANGE_4G		1
 | 
			
		||||
#define BMA150_RANGE_8G		2
 | 
			
		||||
 | 
			
		||||
#define BMA150_BW_25HZ		0
 | 
			
		||||
#define BMA150_BW_50HZ		1
 | 
			
		||||
#define BMA150_BW_100HZ		2
 | 
			
		||||
#define BMA150_BW_190HZ		3
 | 
			
		||||
#define BMA150_BW_375HZ		4
 | 
			
		||||
#define BMA150_BW_750HZ		5
 | 
			
		||||
#define BMA150_BW_1500HZ	6
 | 
			
		||||
 | 
			
		||||
struct bma150_cfg {
 | 
			
		||||
	bool any_motion_int;		/* Set to enable any-motion interrupt */
 | 
			
		||||
	bool hg_int;			/* Set to enable high-G interrupt */
 | 
			
		||||
| 
						 | 
				
			
			@ -34,8 +46,8 @@ struct bma150_cfg {
 | 
			
		|||
	unsigned char lg_hyst;		/* Low-G hysterisis */
 | 
			
		||||
	unsigned char lg_dur;		/* Low-G duration */
 | 
			
		||||
	unsigned char lg_thres;		/* Low-G threshold */
 | 
			
		||||
	unsigned char range;		/* BMA0150_RANGE_xxx (in G) */
 | 
			
		||||
	unsigned char bandwidth;	/* BMA0150_BW_xxx (in Hz) */
 | 
			
		||||
	unsigned char range;		/* one of BMA0150_RANGE_xxx */
 | 
			
		||||
	unsigned char bandwidth;	/* one of BMA0150_BW_xxx */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct bma150_platform_data {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -13,6 +13,8 @@
 | 
			
		|||
#ifndef __LINUX_INPUT_ADXL34X_H__
 | 
			
		||||
#define __LINUX_INPUT_ADXL34X_H__
 | 
			
		||||
 | 
			
		||||
#include <linux/input.h>
 | 
			
		||||
 | 
			
		||||
struct adxl34x_platform_data {
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,62 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
 * Platform definitions for tegra-kbc keyboard input driver
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (c) 2010-2011, NVIDIA Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.,
 | 
			
		||||
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef ASMARM_ARCH_TEGRA_KBC_H
 | 
			
		||||
#define ASMARM_ARCH_TEGRA_KBC_H
 | 
			
		||||
 | 
			
		||||
#include <linux/types.h>
 | 
			
		||||
#include <linux/input/matrix_keypad.h>
 | 
			
		||||
 | 
			
		||||
#define KBC_MAX_GPIO	24
 | 
			
		||||
#define KBC_MAX_KPENT	8
 | 
			
		||||
 | 
			
		||||
#define KBC_MAX_ROW	16
 | 
			
		||||
#define KBC_MAX_COL	8
 | 
			
		||||
#define KBC_MAX_KEY	(KBC_MAX_ROW * KBC_MAX_COL)
 | 
			
		||||
 | 
			
		||||
enum tegra_pin_type {
 | 
			
		||||
	PIN_CFG_IGNORE,
 | 
			
		||||
	PIN_CFG_COL,
 | 
			
		||||
	PIN_CFG_ROW,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct tegra_kbc_pin_cfg {
 | 
			
		||||
	enum tegra_pin_type type;
 | 
			
		||||
	unsigned char num;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct tegra_kbc_wake_key {
 | 
			
		||||
	u8 row:4;
 | 
			
		||||
	u8 col:4;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct tegra_kbc_platform_data {
 | 
			
		||||
	unsigned int debounce_cnt;
 | 
			
		||||
	unsigned int repeat_cnt;
 | 
			
		||||
 | 
			
		||||
	struct tegra_kbc_pin_cfg pin_cfg[KBC_MAX_GPIO];
 | 
			
		||||
	const struct matrix_keymap_data *keymap_data;
 | 
			
		||||
 | 
			
		||||
	u32 wakeup_key;
 | 
			
		||||
	bool wakeup;
 | 
			
		||||
	bool use_fn_map;
 | 
			
		||||
	bool use_ghost_filter;
 | 
			
		||||
};
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -36,7 +36,7 @@ struct ps2dev {
 | 
			
		|||
	wait_queue_head_t wait;
 | 
			
		||||
 | 
			
		||||
	unsigned long flags;
 | 
			
		||||
	unsigned char cmdbuf[6];
 | 
			
		||||
	unsigned char cmdbuf[8];
 | 
			
		||||
	unsigned char cmdcnt;
 | 
			
		||||
	unsigned char nak;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue