Commit 43d01209 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:

 - a new driver for STM FingerTip touchscreen

 - a new driver for D-Link DIR-685 touch keys

 - updated list of supported devices in xpad driver

 - other assorted updates and fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (23 commits)
  MAINTAINERS: update input subsystem patterns
  Input: introduce KEY_ASSISTANT
  Input: xpad - sync supported devices with XBCD
  Input: xpad - sync supported devices with 360Controller
  Input: xen-kbdfront - use string constants from PV protocol
  Input: stmfts - mark all PM functions as __maybe_unused
  Input: add support for the STMicroelectronics FingerTip touchscreen
  Input: add D-Link DIR-685 touchkeys driver
  Input: s3c2410_ts - handle return value of clk_prepare_enable
  Input: axp20x-pek - add wakeup support
  Input: synaptics-rmi4 - use %phN to form F34 configuration ID
  Input: synaptics-rmi4 - change a char type to u8
  Input: sparse-keymap - remove sparse_keymap_free()
  Input: tsc2007 - move header file out of I2C realm
  Input: mms114 - move header file out of I2C realm
  Input: mcs - move header file out of I2C realm
  Input: lm8323 - move header file out of I2C realm
  Input: elantech - force relative mode on a certain module
  Input: elan_i2c - add support for fetching chip type on newer hardware
  Input: elan_i2c - check if device is there before really probing
  ...
parents 2ceedf97 ede2e7cd
* D-Link DIR-685 Touchkeys
This is a I2C one-off touchkey controller based on the Cypress Semiconductor
CY8C214 MCU with some firmware in its internal 8KB flash. The circuit
board inside the router is named E119921.
The touchkey device node should be placed inside an I2C bus node.
Required properties:
- compatible: must be "dlink,dir685-touchkeys"
- reg: the I2C address of the touchkeys
- interrupts: reference to the interrupt number
Example:
touchkeys@26 {
compatible = "dlink,dir685-touchkeys";
reg = <0x26>;
interrupt-parent = <&gpio0>;
interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
};
* ST-Microelectronics FingerTip touchscreen controller
The ST-Microelectronics FingerTip device provides a basic touchscreen
functionality. Along with it the user can enable the touchkey which can work as
a basic HOME and BACK key for phones.
The driver supports also hovering as an absolute single touch event with x, y, z
coordinates.
Required properties:
- compatible : must be "st,stmfts"
- reg : I2C slave address, (e.g. 0x49)
- interrupt-parent : the phandle to the interrupt controller which provides
the interrupt
- interrupts : interrupt specification
- avdd-supply : analogic power supply
- vdd-supply : power supply
- touchscreen-size-x : see touchscreen.txt
- touchscreen-size-y : see touchscreen.txt
Optional properties:
- touch-key-connected : specifies whether the touchkey feature is connected
- ledvdd-supply : power supply to the touch key leds
Example:
i2c@00000000 {
/* ... */
touchscreen@49 {
compatible = "st,stmfts";
reg = <0x49>;
interrupt-parent = <&gpa1>;
interrupts = <1 IRQ_TYPE_NONE>;
touchscreen-size-x = <1599>;
touchscreen-size-y = <2559>;
touch-key-connected;
avdd-supply = <&ldo30_reg>;
vdd-supply = <&ldo31_reg>;
ledvdd-supply = <&ldo33_reg>;
};
};
...@@ -3846,6 +3846,12 @@ S: Supported ...@@ -3846,6 +3846,12 @@ S: Supported
F: drivers/input/touchscreen/cyttsp* F: drivers/input/touchscreen/cyttsp*
F: include/linux/input/cyttsp.h F: include/linux/input/cyttsp.h
D-LINK DIR-685 TOUCHKEYS DRIVER
M: Linus Walleij <linus.walleij@linaro.org>
L: linux-input@vger.kernel.org
S: Supported
F: drivers/input/dlink-dir685-touchkeys.c
DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK DALLAS/MAXIM DS1685-FAMILY REAL TIME CLOCK
M: Joshua Kinard <kumba@gentoo.org> M: Joshua Kinard <kumba@gentoo.org>
S: Maintained S: Maintained
...@@ -6689,8 +6695,10 @@ S: Maintained ...@@ -6689,8 +6695,10 @@ S: Maintained
F: drivers/input/ F: drivers/input/
F: include/linux/input.h F: include/linux/input.h
F: include/uapi/linux/input.h F: include/uapi/linux/input.h
F: include/uapi/linux/input-event-codes.h
F: include/linux/input/ F: include/linux/input/
F: Documentation/devicetree/bindings/input/ F: Documentation/devicetree/bindings/input/
F: Documentation/input/
INPUT MULTITOUCH (MT) PROTOCOL INPUT MULTITOUCH (MT) PROTOCOL
M: Henrik Rydberg <rydberg@bitmath.org> M: Henrik Rydberg <rydberg@bitmath.org>
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <linux/usb/r8a66597.h> #include <linux/usb/r8a66597.h>
#include <linux/usb/renesas_usbhs.h> #include <linux/usb/renesas_usbhs.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/tsc2007.h> #include <linux/platform_data/tsc2007.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/sh_msiof.h> #include <linux/spi/sh_msiof.h>
#include <linux/spi/mmc_spi.h> #include <linux/spi/mmc_spi.h>
......
...@@ -481,7 +481,7 @@ EXPORT_SYMBOL(input_inject_event); ...@@ -481,7 +481,7 @@ EXPORT_SYMBOL(input_inject_event);
void input_alloc_absinfo(struct input_dev *dev) void input_alloc_absinfo(struct input_dev *dev)
{ {
if (!dev->absinfo) if (!dev->absinfo)
dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo), dev->absinfo = kcalloc(ABS_CNT, sizeof(*dev->absinfo),
GFP_KERNEL); GFP_KERNEL);
WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__); WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__);
...@@ -1126,7 +1126,7 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name, ...@@ -1126,7 +1126,7 @@ static void input_seq_print_bitmap(struct seq_file *seq, const char *name,
* If no output was produced print a single 0. * If no output was produced print a single 0.
*/ */
if (skip_empty) if (skip_empty)
seq_puts(seq, "0"); seq_putc(seq, '0');
seq_putc(seq, '\n'); seq_putc(seq, '\n');
} }
...@@ -1144,7 +1144,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v) ...@@ -1144,7 +1144,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : "");
seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); seq_printf(seq, "S: Sysfs=%s\n", path ? path : "");
seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : ""); seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : "");
seq_printf(seq, "H: Handlers="); seq_puts(seq, "H: Handlers=");
list_for_each_entry(handle, &dev->h_list, d_node) list_for_each_entry(handle, &dev->h_list, d_node)
seq_printf(seq, "%s ", handle->name); seq_printf(seq, "%s ", handle->name);
...@@ -1783,7 +1783,7 @@ struct input_dev *input_allocate_device(void) ...@@ -1783,7 +1783,7 @@ struct input_dev *input_allocate_device(void)
static atomic_t input_no = ATOMIC_INIT(-1); static atomic_t input_no = ATOMIC_INIT(-1);
struct input_dev *dev; struct input_dev *dev;
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev) { if (dev) {
dev->dev.type = &input_dev_type; dev->dev.type = &input_dev_type;
dev->dev.class = &input_class; dev->dev.class = &input_class;
...@@ -1849,7 +1849,7 @@ struct input_dev *devm_input_allocate_device(struct device *dev) ...@@ -1849,7 +1849,7 @@ struct input_dev *devm_input_allocate_device(struct device *dev)
struct input_devres *devres; struct input_devres *devres;
devres = devres_alloc(devm_input_device_release, devres = devres_alloc(devm_input_device_release,
sizeof(struct input_devres), GFP_KERNEL); sizeof(*devres), GFP_KERNEL);
if (!devres) if (!devres)
return NULL; return NULL;
...@@ -2099,7 +2099,7 @@ int input_register_device(struct input_dev *dev) ...@@ -2099,7 +2099,7 @@ int input_register_device(struct input_dev *dev)
if (dev->devres_managed) { if (dev->devres_managed) {
devres = devres_alloc(devm_input_device_unregister, devres = devres_alloc(devm_input_device_unregister,
sizeof(struct input_devres), GFP_KERNEL); sizeof(*devres), GFP_KERNEL);
if (!devres) if (!devres)
return -ENOMEM; return -ENOMEM;
......
...@@ -126,13 +126,18 @@ static const struct xpad_device { ...@@ -126,13 +126,18 @@ static const struct xpad_device {
u8 mapping; u8 mapping;
u8 xtype; u8 xtype;
} xpad_device[] = { } xpad_device[] = {
{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
{ 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
{ 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX },
{ 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 }, { 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 },
{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX }, { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX }, { 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
{ 0x045e, 0x0288, "Microsoft Xbox Controller S v2", 0, XTYPE_XBOX },
{ 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX }, { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
...@@ -145,28 +150,52 @@ static const struct xpad_device { ...@@ -145,28 +150,52 @@ static const struct xpad_device {
{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 }, { 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX }, { 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX }, { 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
{ 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX },
{ 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 },
{ 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 }, { 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 },
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX }, { 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX }, { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
{ 0x05fe, 0x3030, "Chic Controller", 0, XTYPE_XBOX },
{ 0x05fe, 0x3031, "Chic Controller", 0, XTYPE_XBOX },
{ 0x062a, 0x0020, "Logic3 Xbox GamePad", 0, XTYPE_XBOX },
{ 0x062a, 0x0033, "Competition Pro Steering Wheel", 0, XTYPE_XBOX },
{ 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX },
{ 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX },
{ 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 },
{ 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX },
{ 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX }, { 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
{ 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
{ 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX }, { 0x0738, 0x4522, "Mad Catz LumiCON", 0, XTYPE_XBOX },
{ 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX }, { 0x0738, 0x4526, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
{ 0x0738, 0x4530, "Mad Catz Universal MC2 Racing Wheel and Pedals", 0, XTYPE_XBOX },
{ 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX }, { 0x0738, 0x4536, "Mad Catz MicroCON", 0, XTYPE_XBOX },
{ 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x4540, "Mad Catz Beat Pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX }, { 0x0738, 0x4556, "Mad Catz Lynx Wireless Controller", 0, XTYPE_XBOX },
{ 0x0738, 0x4586, "Mad Catz MicroCon Wireless Controller", 0, XTYPE_XBOX },
{ 0x0738, 0x4588, "Mad Catz Blaster", 0, XTYPE_XBOX },
{ 0x0738, 0x45ff, "Mad Catz Beat Pad (w/ Handle)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 }, { 0x0738, 0x4718, "Mad Catz Street Fighter IV FightStick SE", 0, XTYPE_XBOX360 },
{ 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0738, 0x4726, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4728, "Mad Catz Street Fighter IV FightPad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0738, 0x4736, "Mad Catz MicroCon Gamepad", 0, XTYPE_XBOX360 },
{ 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0738, 0x4738, "Mad Catz Wired Xbox 360 Controller (SFIV)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 }, { 0x0738, 0x4740, "Mad Catz Beat Pad", 0, XTYPE_XBOX360 },
{ 0x0738, 0x4743, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0738, 0x4758, "Mad Catz Arcade Game Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0738, 0x4a01, "Mad Catz FightStick TE 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 },
{ 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 }, { 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 },
{ 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 }, { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
{ 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 }, { 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 },
{ 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 }, { 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 },
{ 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 },
{ 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX },
{ 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX },
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
{ 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX }, { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", DANCEPAD_MAP_CONFIG, XTYPE_XBOX },
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX }, { 0x0c12, 0x880a, "Pelican Eclipse PL-2023", 0, XTYPE_XBOX },
...@@ -174,37 +203,63 @@ static const struct xpad_device { ...@@ -174,37 +203,63 @@ static const struct xpad_device {
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX }, { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
{ 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX }, { 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
{ 0x0e4c, 0x1103, "Radica Gamester Reflex", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX },
{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX }, { 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
{ 0x0e4c, 0x3510, "Radica Gamester", 0, XTYPE_XBOX },
{ 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0003, "Logic3 Freebird wireless Controller", 0, XTYPE_XBOX },
{ 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0005, "Eclipse wireless Controller", 0, XTYPE_XBOX },
{ 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX }, { 0x0e6f, 0x0006, "Edge wireless Controller", 0, XTYPE_XBOX },
{ 0x0e6f, 0x0008, "After Glow Pro Controller", 0, XTYPE_XBOX },
{ 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0113, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x011f, "Rock Candy Gamepad Wired Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0131, "PDP EA Sports Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0133, "Xbox 360 Wired Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0139, "Afterglow Prismatic Wired Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x013a, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE }, { 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0164, "PDP Battlefield One", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0165, "PDP Titanfall 2", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0201, "Pelican PL-3601 'TSZ' Wired Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0213, "Afterglow Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x021f, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0246, "Rock Candy Gamepad for Xbox One 2015", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0301, "Logic3 Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0346, "Rock Candy Gamepad for Xbox One 2016", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0401, "Logic3 Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 }, { 0x0e6f, 0x0413, "Afterglow AX.1 Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0x0501, "PDP Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x0e6f, 0xf900, "PDP Afterglow AX.1", 0, XTYPE_XBOX360 },
{ 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX }, { 0x0e8f, 0x0201, "SmartJoy Frag Xpad/PS2 adaptor", 0, XTYPE_XBOX },
{ 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX }, { 0x0e8f, 0x3008, "Generic xbox control (dealextreme)", 0, XTYPE_XBOX },
{ 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 }, { 0x0f0d, 0x000a, "Hori Co. DOA4 FightStick", 0, XTYPE_XBOX360 },
{ 0x0f0d, 0x000c, "Hori PadEX Turbo", 0, XTYPE_XBOX360 },
{ 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0f0d, 0x001b, "Hori Real Arcade Pro VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x0f0d, 0x0063, "Hori Real Arcade Pro Hayabusa (USA) Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE },
{ 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX },
{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
{ 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 }, { 0x12ab, 0x0301, "PDP AFTERGLOW AX.1", 0, XTYPE_XBOX360 },
{ 0x12ab, 0x0303, "Mortal Kombat Klassic FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 },
{ 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x1430, 0xf801, "RedOctane Controller", 0, XTYPE_XBOX360 },
{ 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x1532, 0x0037, "Razer Sabertooth", 0, XTYPE_XBOX360 },
{ 0x1532, 0x0a00, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
{ 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE }, { 0x1532, 0x0a03, "Razer Wildcat", 0, XTYPE_XBOXONE },
{ 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f00, "Power A Mini Pro Elite", 0, XTYPE_XBOX360 },
{ 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x15e4, 0x3f0a, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
...@@ -215,22 +270,44 @@ static const struct xpad_device { ...@@ -215,22 +270,44 @@ static const struct xpad_device {
{ 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf016, "Mad Catz Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf018, "Mad Catz Street Fighter IV SE Fighting Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf019, "Mad Catz Brawlstick for Xbox 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf021, "Mad Cats Ghost Recon FS GamePad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf023, "MLG Pro Circuit Controller (Xbox)", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf025, "Mad Catz Call Of Duty", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf027, "Mad Catz FPS Pro", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf028, "Street Fighter IV FightPad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf02e, "Mad Catz Fightpad", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf030, "Mad Catz Xbox 360 MC2 MicroCon Racing Wheel", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf036, "Mad Catz MicroCon GamePad Pro", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf038, "Street Fighter IV FightStick TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf039, "Mad Catz MvC2 TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1bad, 0xf03a, "Mad Catz SFxT Fightstick Pro", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf03d, "Street Fighter IV Arcade Stick TE - Chun Li", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf03e, "Mad Catz MLG FightStick TE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf03f, "Mad Catz FightStick SoulCaliber", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf042, "Mad Catz FightStick TES+", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf080, "Mad Catz FightStick TE2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf501, "HoriPad EX2 Turbo", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf502, "Hori Real Arcade Pro.VX SA", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf503, "Hori Fighting Stick VX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf504, "Hori Real Arcade Pro. EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf505, "Hori Fighting Stick EX2B", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xf506, "Hori Real Arcade Pro.EX Premium VLX", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf900, "Harmonix Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf901, "Gamestop Xbox 360 Controller", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 }, { 0x1bad, 0xf903, "Tron Xbox 360 controller", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf904, "PDP Versus Fighting Pad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xf906, "MortalKombat FightStick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 }, { 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5303, "Xbox Airflo wired controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x530a, "Xbox 360 Pro EX Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x531a, "PowerA Pro Ex", 0, XTYPE_XBOX360 }, { 0x24c6, 0x531a, "PowerA Pro Ex", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5397, "FUS1ON Tournament Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5397, "FUS1ON Tournament Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x541a, "PowerA Xbox One Mini Wired Controller", 0, XTYPE_XBOXONE },
...@@ -238,12 +315,19 @@ static const struct xpad_device { ...@@ -238,12 +315,19 @@ static const struct xpad_device {
{ 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE }, { 0x24c6, 0x543a, "PowerA Xbox One wired controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5500, "Hori XBOX 360 EX 2 with Turbo", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5501, "Hori Real Arcade Pro VX-SA", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5502, "Hori Fighting Stick VX Alt", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5503, "Hori Fighting Edge", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5506, "Hori SOULCALIBUR V Stick", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x550d, "Hori GEM Xbox controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x550e, "Hori Real Arcade Pro V Kai 360", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 }, { 0x24c6, 0x5d04, "Razer Sabertooth", 0, XTYPE_XBOX360 },
{ 0x24c6, 0xfafe, "Rock Candy Gamepad for Xbox 360", 0, XTYPE_XBOX360 },
{ 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
}; };
...@@ -331,13 +415,16 @@ static struct usb_device_id xpad_table[] = { ...@@ -331,13 +415,16 @@ static struct usb_device_id xpad_table[] = {
XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */
XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */
XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */ XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */
XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
{ USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */
XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */
XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz GamePad */
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */ XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */
XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */
XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */
XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */
XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */
......
...@@ -178,6 +178,17 @@ config KEYBOARD_CLPS711X ...@@ -178,6 +178,17 @@ config KEYBOARD_CLPS711X
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called clps711x-keypad. module will be called clps711x-keypad.
config KEYBOARD_DLINK_DIR685
tristate "D-Link DIR-685 touchkeys support"
depends on I2C
default ARCH_GEMINI
help
If you say yes here you get support for the D-Link DIR-685
touchkeys.
To compile this driver as a module, choose M here: the
module will be called dlink-dir685-touchkeys.
config KEYBOARD_LKKBD config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard" tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO select SERIO
......
...@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o ...@@ -17,6 +17,7 @@ obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_DLINK_DIR685) += dlink-dir685-touchkeys.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
......
/*
* D-Link DIR-685 router I2C-based Touchkeys input driver
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
*
* This is a one-off touchkey controller based on the Cypress Semiconductor
* CY8C214 MCU with some firmware in its internal 8KB flash. The circuit
* board inside the router is named E119921
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/bitops.h>
struct dir685_touchkeys {
struct device *dev;
struct i2c_client *client;
struct input_dev *input;
unsigned long cur_key;
u16 codes[7];
};
static irqreturn_t dir685_tk_irq_thread(int irq, void *data)
{
struct dir685_touchkeys *tk = data;
const int num_bits = min_t(int, ARRAY_SIZE(tk->codes), 16);
unsigned long changed;
u8 buf[6];
unsigned long key;
int i;
int err;
memset(buf, 0, sizeof(buf));
err = i2c_master_recv(tk->client, buf, sizeof(buf));
if (err != sizeof(buf)) {
dev_err(tk->dev, "short read %d\n", err);
return IRQ_HANDLED;
}
dev_dbg(tk->dev, "IN: %*ph\n", (int)sizeof(buf), buf);
key = be16_to_cpup((__be16 *) &buf[4]);
/* Figure out if any bits went high or low since last message */
changed = tk->cur_key ^ key;
for_each_set_bit(i, &changed, num_bits) {
dev_dbg(tk->dev, "key %d is %s\n", i,
test_bit(i, &key) ? "down" : "up");
input_report_key(tk->input, tk->codes[i], test_bit(i, &key));
}
/* Store currently down keys */
tk->cur_key = key;
input_sync(tk->input);
return IRQ_HANDLED;
}
static int dir685_tk_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct dir685_touchkeys *tk;
struct device *dev = &client->dev;
u8 bl_data[] = { 0xa7, 0x40 };
int err;
int i;
tk = devm_kzalloc(&client->dev, sizeof(*tk), GFP_KERNEL);
if (!tk)
return -ENOMEM;
tk->input = devm_input_allocate_device(dev);
if (!tk->input)
return -ENOMEM;
tk->client = client;
tk->dev = dev;
tk->input->keycodesize = sizeof(u16);
tk->input->keycodemax = ARRAY_SIZE(tk->codes);
tk->input->keycode = tk->codes;
tk->codes[0] = KEY_UP;
tk->codes[1] = KEY_DOWN;
tk->codes[2] = KEY_LEFT;
tk->codes[3] = KEY_RIGHT;
tk->codes[4] = KEY_ENTER;
tk->codes[5] = KEY_WPS_BUTTON;
/*
* This key appears in the vendor driver, but I have
* not been able to activate it.
*/
tk->codes[6] = KEY_RESERVED;
__set_bit(EV_KEY, tk->input->evbit);
for (i = 0; i < ARRAY_SIZE(tk->codes); i++)
__set_bit(tk->codes[i], tk->input->keybit);
__clear_bit(KEY_RESERVED, tk->input->keybit);
tk->input->name = "D-Link DIR-685 touchkeys";
tk->input->id.bustype = BUS_I2C;
err = input_register_device(tk->input);
if (err)
return err;
/* Set the brightness to max level */
err = i2c_master_send(client, bl_data, sizeof(bl_data));
if (err != sizeof(bl_data))
dev_warn(tk->dev, "error setting brightness level\n");
if (!client->irq) {
dev_err(dev, "no IRQ on the I2C device\n");
return -ENODEV;
}
err = devm_request_threaded_irq(dev, client->irq,
NULL, dir685_tk_irq_thread,
IRQF_ONESHOT,
"dir685-tk", tk);
if (err) {
dev_err(dev, "can't request IRQ\n");
return err;
}
return 0;
}
static const struct i2c_device_id dir685_tk_id[] = {
{ "dir685tk", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, dir685_tk_id);
#ifdef CONFIG_OF
static const struct of_device_id dir685_tk_of_match[] = {
{ .compatible = "dlink,dir685-touchkeys" },
{},
};
MODULE_DEVICE_TABLE(of, dir685_tk_of_match);
#endif
static struct i2c_driver dir685_tk_i2c_driver = {
.driver = {
.name = "dlin-dir685-touchkeys",
.of_match_table = of_match_ptr(dir685_tk_of_match),
},
.probe = dir685_tk_probe,
.id_table = dir685_tk_id,
};
module_i2c_driver(dir685_tk_i2c_driver);
MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
MODULE_DESCRIPTION("D-Link DIR-685 touchkeys driver");
MODULE_LICENSE("GPL");
...@@ -30,8 +30,8 @@ ...@@ -30,8 +30,8 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/platform_data/lm8323.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/i2c/lm8323.h>
#include <linux/slab.h> #include <linux/slab.h>
/* Commands to send to the chip. */ /* Commands to send to the chip. */
......
...@@ -13,11 +13,11 @@ ...@@ -13,11 +13,11 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/mcs.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/platform_data/mcs.h>
#include <linux/pm.h> #include <linux/pm.h>
/* MCS5000 Touchkey */ /* MCS5000 Touchkey */
......
...@@ -253,6 +253,9 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, ...@@ -253,6 +253,9 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
return error; return error;
} }
if (axp20x_pek->axp20x->variant == AXP288_ID)
enable_irq_wake(axp20x_pek->irq_dbr);
return 0; return 0;
} }
...@@ -331,10 +334,35 @@ static int axp20x_pek_probe(struct platform_device *pdev) ...@@ -331,10 +334,35 @@ static int axp20x_pek_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
if (axp20x_pek->axp20x->variant != AXP288_ID)
return 0;
/*
* Clear interrupts from button presses during suspend, to avoid
* a wakeup power-button press getting reported to userspace.
*/
regmap_write(axp20x_pek->axp20x->regmap,
AXP20X_IRQ1_STATE + AXP288_IRQ_POKN / 8,
BIT(AXP288_IRQ_POKN % 8));
return 0;
}
static const struct dev_pm_ops axp20x_pek_pm_ops = {
#ifdef CONFIG_PM_SLEEP
.resume_noirq = axp20x_pek_resume_noirq,
#endif
};
static struct platform_driver axp20x_pek_driver = { static struct platform_driver axp20x_pek_driver = {
.probe = axp20x_pek_probe, .probe = axp20x_pek_probe,
.driver = { .driver = {
.name = "axp20x-pek", .name = "axp20x-pek",
.pm = &axp20x_pek_pm_ops,
}, },
}; };
module_platform_driver(axp20x_pek_driver); module_platform_driver(axp20x_pek_driver);
......
...@@ -135,14 +135,17 @@ static int xenkbd_probe(struct xenbus_device *dev, ...@@ -135,14 +135,17 @@ static int xenkbd_probe(struct xenbus_device *dev,
goto error_nomem; goto error_nomem;
/* Set input abs params to match backend screen res */ /* Set input abs params to match backend screen res */
abs = xenbus_read_unsigned(dev->otherend, "feature-abs-pointer", 0); abs = xenbus_read_unsigned(dev->otherend,
ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend, "width", XENKBD_FIELD_FEAT_ABS_POINTER, 0);
ptr_size[KPARAM_X] = xenbus_read_unsigned(dev->otherend,
XENKBD_FIELD_WIDTH,
ptr_size[KPARAM_X]); ptr_size[KPARAM_X]);
ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend, "height", ptr_size[KPARAM_Y] = xenbus_read_unsigned(dev->otherend,
XENKBD_FIELD_HEIGHT,
ptr_size[KPARAM_Y]); ptr_size[KPARAM_Y]);
if (abs) { if (abs) {
ret = xenbus_write(XBT_NIL, dev->nodename, ret = xenbus_write(XBT_NIL, dev->nodename,
"request-abs-pointer", "1"); XENKBD_FIELD_REQ_ABS_POINTER, "1");
if (ret) { if (ret) {
pr_warn("xenkbd: can't request abs-pointer\n"); pr_warn("xenkbd: can't request abs-pointer\n");
abs = 0; abs = 0;
...@@ -271,14 +274,15 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, ...@@ -271,14 +274,15 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
xenbus_dev_fatal(dev, ret, "starting transaction"); xenbus_dev_fatal(dev, ret, "starting transaction");
goto error_irqh; goto error_irqh;
} }
ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_REF, "%lu",
virt_to_gfn(info->page)); virt_to_gfn(info->page));
if (ret) if (ret)
goto error_xenbus; goto error_xenbus;
ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_RING_GREF,
"%u", info->gref);
if (ret) if (ret)
goto error_xenbus; goto error_xenbus;
ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", ret = xenbus_printf(xbt, dev->nodename, XENKBD_FIELD_EVT_CHANNEL, "%u",
evtchn); evtchn);
if (ret) if (ret)
goto error_xenbus; goto error_xenbus;
...@@ -353,7 +357,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev, ...@@ -353,7 +357,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
} }
static const struct xenbus_device_id xenkbd_ids[] = { static const struct xenbus_device_id xenkbd_ids[] = {
{ "vkbd" }, { XENKBD_DRIVER_NAME },
{ "" } { "" }
}; };
...@@ -390,4 +394,4 @@ module_exit(xenkbd_cleanup); ...@@ -390,4 +394,4 @@ module_exit(xenkbd_cleanup);
MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend"); MODULE_DESCRIPTION("Xen virtual keyboard/pointer device frontend");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("xen:vkbd"); MODULE_ALIAS("xen:" XENKBD_DRIVER_NAME);
...@@ -58,7 +58,7 @@ struct elan_transport_ops { ...@@ -58,7 +58,7 @@ struct elan_transport_ops {
int (*get_version)(struct i2c_client *client, bool iap, u8 *version); int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
int (*get_sm_version)(struct i2c_client *client, int (*get_sm_version)(struct i2c_client *client,
u8* ic_type, u8 *version); u16 *ic_type, u8 *version);
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum); int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
int (*get_product_id)(struct i2c_client *client, u16 *id); int (*get_product_id)(struct i2c_client *client, u16 *id);
...@@ -82,6 +82,7 @@ struct elan_transport_ops { ...@@ -82,6 +82,7 @@ struct elan_transport_ops {
int (*get_report)(struct i2c_client *client, u8 *report); int (*get_report)(struct i2c_client *client, u8 *report);
int (*get_pressure_adjustment)(struct i2c_client *client, int (*get_pressure_adjustment)(struct i2c_client *client,
int *adjustment); int *adjustment);
int (*get_pattern)(struct i2c_client *client, u8 *pattern);
}; };
extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops; extern const struct elan_transport_ops elan_smbus_ops, elan_i2c_ops;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* *
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw> * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
* Author: KT Liao <kt.liao@emc.com.tw> * Author: KT Liao <kt.liao@emc.com.tw>
* Version: 1.6.2 * Version: 1.6.3
* *
* Based on cyapa driver: * Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc. * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
#include "elan_i2c.h" #include "elan_i2c.h"
#define DRIVER_NAME "elan_i2c" #define DRIVER_NAME "elan_i2c"
#define ELAN_DRIVER_VERSION "1.6.2" #define ELAN_DRIVER_VERSION "1.6.3"
#define ELAN_VENDOR_ID 0x04f3 #define ELAN_VENDOR_ID 0x04f3
#define ETP_MAX_PRESSURE 255 #define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90 #define ETP_FWIDTH_REDUCE 90
...@@ -78,6 +78,7 @@ struct elan_tp_data { ...@@ -78,6 +78,7 @@ struct elan_tp_data {
unsigned int x_res; unsigned int x_res;
unsigned int y_res; unsigned int y_res;
u8 pattern;
u16 product_id; u16 product_id;
u8 fw_version; u8 fw_version;
u8 sm_version; u8 sm_version;
...@@ -85,7 +86,7 @@ struct elan_tp_data { ...@@ -85,7 +86,7 @@ struct elan_tp_data {
u16 fw_checksum; u16 fw_checksum;
int pressure_adjustment; int pressure_adjustment;
u8 mode; u8 mode;
u8 ic_type; u16 ic_type;
u16 fw_validpage_count; u16 fw_validpage_count;
u16 fw_signature_address; u16 fw_signature_address;
...@@ -96,10 +97,10 @@ struct elan_tp_data { ...@@ -96,10 +97,10 @@ struct elan_tp_data {
bool baseline_ready; bool baseline_ready;
}; };
static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
u16 *signature_address) u16 *signature_address)
{ {
switch (iap_version) { switch (ic_type) {
case 0x00: case 0x00:
case 0x06: case 0x06:
case 0x08: case 0x08:
...@@ -119,6 +120,9 @@ static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, ...@@ -119,6 +120,9 @@ static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count,
case 0x0E: case 0x0E:
*validpage_count = 640; *validpage_count = 640;
break; break;
case 0x10:
*validpage_count = 1024;
break;
default: default:
/* unknown ic type clear value */ /* unknown ic type clear value */
*validpage_count = 0; *validpage_count = 0;
...@@ -305,6 +309,7 @@ static int elan_initialize(struct elan_tp_data *data) ...@@ -305,6 +309,7 @@ static int elan_initialize(struct elan_tp_data *data)
static int elan_query_device_info(struct elan_tp_data *data) static int elan_query_device_info(struct elan_tp_data *data)
{ {
int error; int error;
u16 ic_type;
error = data->ops->get_version(data->client, false, &data->fw_version); error = data->ops->get_version(data->client, false, &data->fw_version);
if (error) if (error)
...@@ -324,7 +329,16 @@ static int elan_query_device_info(struct elan_tp_data *data) ...@@ -324,7 +329,16 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error) if (error)
return error; return error;
error = elan_get_fwinfo(data->iap_version, &data->fw_validpage_count, error = data->ops->get_pattern(data->client, &data->pattern);
if (error)
return error;
if (data->pattern == 0x01)
ic_type = data->ic_type;
else
ic_type = data->iap_version;
error = elan_get_fwinfo(ic_type, &data->fw_validpage_count,
&data->fw_signature_address); &data->fw_signature_address);
if (error) if (error)
dev_warn(&data->client->dev, dev_warn(&data->client->dev,
...@@ -1077,6 +1091,13 @@ static int elan_probe(struct i2c_client *client, ...@@ -1077,6 +1091,13 @@ static int elan_probe(struct i2c_client *client,
return error; return error;
} }
/* Make sure there is something at this address */
error = i2c_smbus_read_byte(client);
if (error < 0) {
dev_dbg(&client->dev, "nothing at this address: %d\n", error);
return -ENXIO;
}
/* Initialize the touchpad. */ /* Initialize the touchpad. */
error = elan_initialize(data); error = elan_initialize(data);
if (error) if (error)
...@@ -1101,10 +1122,13 @@ static int elan_probe(struct i2c_client *client, ...@@ -1101,10 +1122,13 @@ static int elan_probe(struct i2c_client *client,
"Elan Touchpad Extra Information:\n" "Elan Touchpad Extra Information:\n"
" Max ABS X,Y: %d,%d\n" " Max ABS X,Y: %d,%d\n"
" Width X,Y: %d,%d\n" " Width X,Y: %d,%d\n"
" Resolution X,Y: %d,%d (dots/mm)\n", " Resolution X,Y: %d,%d (dots/mm)\n"
" ic type: 0x%x\n"
" info pattern: 0x%x\n",
data->max_x, data->max_y, data->max_x, data->max_y,
data->width_x, data->width_y, data->width_x, data->width_y,
data->x_res, data->y_res); data->x_res, data->y_res,
data->ic_type, data->pattern);
/* Set up input device properties based on queried parameters. */ /* Set up input device properties based on queried parameters. */
error = elan_setup_input_device(data); error = elan_setup_input_device(data);
......
...@@ -34,9 +34,12 @@ ...@@ -34,9 +34,12 @@
#define ETP_I2C_DESC_CMD 0x0001 #define ETP_I2C_DESC_CMD 0x0001
#define ETP_I2C_REPORT_DESC_CMD 0x0002 #define ETP_I2C_REPORT_DESC_CMD 0x0002
#define ETP_I2C_STAND_CMD 0x0005 #define ETP_I2C_STAND_CMD 0x0005
#define ETP_I2C_PATTERN_CMD 0x0100
#define ETP_I2C_UNIQUEID_CMD 0x0101 #define ETP_I2C_UNIQUEID_CMD 0x0101
#define ETP_I2C_FW_VERSION_CMD 0x0102 #define ETP_I2C_FW_VERSION_CMD 0x0102
#define ETP_I2C_SM_VERSION_CMD 0x0103 #define ETP_I2C_IC_TYPE_CMD 0x0103
#define ETP_I2C_OSM_VERSION_CMD 0x0103
#define ETP_I2C_NSM_VERSION_CMD 0x0104
#define ETP_I2C_XY_TRACENUM_CMD 0x0105 #define ETP_I2C_XY_TRACENUM_CMD 0x0105
#define ETP_I2C_MAX_X_AXIS_CMD 0x0106 #define ETP_I2C_MAX_X_AXIS_CMD 0x0106
#define ETP_I2C_MAX_Y_AXIS_CMD 0x0107 #define ETP_I2C_MAX_Y_AXIS_CMD 0x0107
...@@ -239,12 +242,34 @@ static int elan_i2c_get_baseline_data(struct i2c_client *client, ...@@ -239,12 +242,34 @@ static int elan_i2c_get_baseline_data(struct i2c_client *client,
return 0; return 0;
} }
static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern)
{
int error;
u8 val[3];
error = elan_i2c_read_cmd(client, ETP_I2C_PATTERN_CMD, val);
if (error) {
dev_err(&client->dev, "failed to get pattern: %d\n", error);
return error;
}
*pattern = val[1];
return 0;
}
static int elan_i2c_get_version(struct i2c_client *client, static int elan_i2c_get_version(struct i2c_client *client,
bool iap, u8 *version) bool iap, u8 *version)
{ {
int error; int error;
u8 pattern_ver;
u8 val[3]; u8 val[3];
error = elan_i2c_get_pattern(client, &pattern_ver);
if (error) {
dev_err(&client->dev, "failed to get pattern version\n");
return error;
}
error = elan_i2c_read_cmd(client, error = elan_i2c_read_cmd(client,
iap ? ETP_I2C_IAP_VERSION_CMD : iap ? ETP_I2C_IAP_VERSION_CMD :
ETP_I2C_FW_VERSION_CMD, ETP_I2C_FW_VERSION_CMD,
...@@ -255,24 +280,54 @@ static int elan_i2c_get_version(struct i2c_client *client, ...@@ -255,24 +280,54 @@ static int elan_i2c_get_version(struct i2c_client *client,
return error; return error;
} }
if (pattern_ver == 0x01)
*version = iap ? val[1] : val[0];
else
*version = val[0]; *version = val[0];
return 0; return 0;
} }
static int elan_i2c_get_sm_version(struct i2c_client *client, static int elan_i2c_get_sm_version(struct i2c_client *client,
u8 *ic_type, u8 *version) u16 *ic_type, u8 *version)
{ {
int error; int error;
u8 pattern_ver;
u8 val[3]; u8 val[3];
error = elan_i2c_read_cmd(client, ETP_I2C_SM_VERSION_CMD, val); error = elan_i2c_get_pattern(client, &pattern_ver);
if (error) { if (error) {
dev_err(&client->dev, "failed to get SM version: %d\n", error); dev_err(&client->dev, "failed to get pattern version\n");
return error; return error;
} }
if (pattern_ver == 0x01) {
error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val);
if (error) {
dev_err(&client->dev, "failed to get ic type: %d\n",
error);
return error;
}
*ic_type = be16_to_cpup((__be16 *)val);
error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD,
val);
if (error) {
dev_err(&client->dev, "failed to get SM version: %d\n",
error);
return error;
}
*version = val[1];
} else {
error = elan_i2c_read_cmd(client, ETP_I2C_OSM_VERSION_CMD, val);
if (error) {
dev_err(&client->dev, "failed to get SM version: %d\n",
error);
return error;
}
*version = val[0]; *version = val[0];
*ic_type = val[1]; *ic_type = val[1];
}
return 0; return 0;
} }
...@@ -641,5 +696,7 @@ const struct elan_transport_ops elan_i2c_ops = { ...@@ -641,5 +696,7 @@ const struct elan_transport_ops elan_i2c_ops = {
.write_fw_block = elan_i2c_write_fw_block, .write_fw_block = elan_i2c_write_fw_block,
.finish_fw_update = elan_i2c_finish_fw_update, .finish_fw_update = elan_i2c_finish_fw_update,
.get_pattern = elan_i2c_get_pattern,
.get_report = elan_i2c_get_report, .get_report = elan_i2c_get_report,
}; };
...@@ -166,7 +166,7 @@ static int elan_smbus_get_version(struct i2c_client *client, ...@@ -166,7 +166,7 @@ static int elan_smbus_get_version(struct i2c_client *client,
} }
static int elan_smbus_get_sm_version(struct i2c_client *client, static int elan_smbus_get_sm_version(struct i2c_client *client,
u8 *ic_type, u8 *version) u16 *ic_type, u8 *version)
{ {
int error; int error;
u8 val[3]; u8 val[3];
...@@ -495,6 +495,12 @@ static int elan_smbus_finish_fw_update(struct i2c_client *client, ...@@ -495,6 +495,12 @@ static int elan_smbus_finish_fw_update(struct i2c_client *client,
return 0; return 0;
} }
static int elan_smbus_get_pattern(struct i2c_client *client, u8 *pattern)
{
*pattern = 0;
return 0;
}
const struct elan_transport_ops elan_smbus_ops = { const struct elan_transport_ops elan_smbus_ops = {
.initialize = elan_smbus_initialize, .initialize = elan_smbus_initialize,
.sleep_control = elan_smbus_sleep_control, .sleep_control = elan_smbus_sleep_control,
...@@ -524,4 +530,5 @@ const struct elan_transport_ops elan_smbus_ops = { ...@@ -524,4 +530,5 @@ const struct elan_transport_ops elan_smbus_ops = {
.finish_fw_update = elan_smbus_finish_fw_update, .finish_fw_update = elan_smbus_finish_fw_update,
.get_report = elan_smbus_get_report, .get_report = elan_smbus_get_report,
.get_pattern = elan_smbus_get_pattern,
}; };
...@@ -1711,6 +1711,17 @@ int elantech_init(struct psmouse *psmouse) ...@@ -1711,6 +1711,17 @@ int elantech_init(struct psmouse *psmouse)
etd->samples[0], etd->samples[1], etd->samples[2]); etd->samples[0], etd->samples[1], etd->samples[2]);
} }
if (etd->samples[1] == 0x74 && etd->hw_version == 0x03) {
/*
* This module has a bug which makes absolute mode
* unusable, so let's abort so we'll be using standard
* PS/2 protocol.
*/
psmouse_info(psmouse,
"absolute mode broken, forcing standard PS/2 protocol\n");
goto init_fail;
}
if (elantech_set_absolute_mode(psmouse)) { if (elantech_set_absolute_mode(psmouse)) {
psmouse_err(psmouse, psmouse_err(psmouse,
"failed to put touchpad into absolute mode.\n"); "failed to put touchpad into absolute mode.\n");
......
...@@ -9,13 +9,14 @@ ...@@ -9,13 +9,14 @@
* the Free Software Foundation. * the Free Software Foundation.
*/ */
#include <linux/bitops.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/rmi.h> #include <linux/rmi.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <asm/unaligned.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <asm/unaligned.h>
#include "rmi_driver.h" #include "rmi_driver.h"
#include "rmi_f34.h" #include "rmi_f34.h"
...@@ -464,7 +465,7 @@ static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34) ...@@ -464,7 +465,7 @@ static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34)
static int rmi_f34v7_read_queries(struct f34_data *f34) static int rmi_f34v7_read_queries(struct f34_data *f34)
{ {
int ret; int ret;
int i, j; int i;
u8 base; u8 base;
int offset; int offset;
u8 *ptable; u8 *ptable;
...@@ -518,10 +519,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) ...@@ -518,10 +519,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34)
query_1_7.partition_support[1] & HAS_GUEST_CODE; query_1_7.partition_support[1] & HAS_GUEST_CODE;
if (query_0 & HAS_CONFIG_ID) { if (query_0 & HAS_CONFIG_ID) {
char f34_ctrl[CONFIG_ID_SIZE]; u8 f34_ctrl[CONFIG_ID_SIZE];
int i = 0;
u8 *p = f34->configuration_id;
*p = '\0';
ret = rmi_read_block(f34->fn->rmi_dev, ret = rmi_read_block(f34->fn->rmi_dev,
f34->fn->fd.control_base_addr, f34->fn->fd.control_base_addr,
...@@ -531,13 +529,11 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) ...@@ -531,13 +529,11 @@ static int rmi_f34v7_read_queries(struct f34_data *f34)
return ret; return ret;
/* Eat leading zeros */ /* Eat leading zeros */
while (i < sizeof(f34_ctrl) && !f34_ctrl[i]) for (i = 0; i < sizeof(f34_ctrl) - 1 && !f34_ctrl[i]; i++)
i++; /* Empty */;
for (; i < sizeof(f34_ctrl); i++) snprintf(f34->configuration_id, sizeof(f34->configuration_id),
p += snprintf(p, f34->configuration_id "%*phN", (int)sizeof(f34_ctrl) - i, f34_ctrl + i);
+ sizeof(f34->configuration_id) - p,
"%02X", f34_ctrl[i]);
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n", rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n",
f34->configuration_id); f34->configuration_id);
...@@ -545,9 +541,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34) ...@@ -545,9 +541,7 @@ static int rmi_f34v7_read_queries(struct f34_data *f34)
f34->v7.partitions = 0; f34->v7.partitions = 0;
for (i = 0; i < sizeof(query_1_7.partition_support); i++) for (i = 0; i < sizeof(query_1_7.partition_support); i++)
for (j = 0; j < 8; j++) f34->v7.partitions += hweight8(query_1_7.partition_support[i]);
if (query_1_7.partition_support[i] & (1 << j))
f34->v7.partitions++;
rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n", rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n",
__func__, sizeof(query_1_7.partition_support), __func__, sizeof(query_1_7.partition_support),
......
...@@ -223,20 +223,6 @@ int sparse_keymap_setup(struct input_dev *dev, ...@@ -223,20 +223,6 @@ int sparse_keymap_setup(struct input_dev *dev,
} }
EXPORT_SYMBOL(sparse_keymap_setup); EXPORT_SYMBOL(sparse_keymap_setup);
/**
* sparse_keymap_free - free memory allocated for sparse keymap
* @dev: Input device using sparse keymap
*
* This function used to free memory allocated by sparse keymap
* in an input device that was set up by sparse_keymap_setup().
* Since sparse_keymap_setup() now uses a managed allocation for the
* keymap copy, use of this function is deprecated.
*/
void sparse_keymap_free(struct input_dev *dev)
{
}
EXPORT_SYMBOL(sparse_keymap_free);
/** /**
* sparse_keymap_report_entry - report event corresponding to given key entry * sparse_keymap_report_entry - report event corresponding to given key entry
* @dev: Input device for which event should be reported * @dev: Input device for which event should be reported
......
...@@ -1114,6 +1114,17 @@ config TOUCHSCREEN_ST1232 ...@@ -1114,6 +1114,17 @@ config TOUCHSCREEN_ST1232
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called st1232_ts. module will be called st1232_ts.
config TOUCHSCREEN_STMFTS
tristate "STMicroelectronics STMFTS touchscreen"
depends on I2C
depends on LEDS_CLASS
help
Say Y here if you want support for STMicroelectronics
STMFTS touchscreen.
To compile this driver as a module, choose M here: the
module will be called stmfts.
config TOUCHSCREEN_STMPE config TOUCHSCREEN_STMPE
tristate "STMicroelectronics STMPE touchscreens" tristate "STMicroelectronics STMPE touchscreens"
depends on MFD_STMPE depends on MFD_STMPE
......
...@@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o ...@@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_S3C2410) += s3c2410_ts.o
obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o obj-$(CONFIG_TOUCHSCREEN_SILEAD) += silead.o
obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o obj-$(CONFIG_TOUCHSCREEN_SIS_I2C) += sis_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o obj-$(CONFIG_TOUCHSCREEN_ST1232) += st1232.o
obj-$(CONFIG_TOUCHSCREEN_STMFTS) += stmfts.o
obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
......
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/mcs.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/irq.h> #include <linux/irq.h>
#include <linux/platform_data/mcs.h>
#include <linux/slab.h> #include <linux/slab.h>
/* Registers */ /* Registers */
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/mms114.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_data/mms114.h>
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/slab.h> #include <linux/slab.h>
......
...@@ -264,7 +264,11 @@ static int s3c2410ts_probe(struct platform_device *pdev) ...@@ -264,7 +264,11 @@ static int s3c2410ts_probe(struct platform_device *pdev)
return -ENOENT; return -ENOENT;
} }
clk_prepare_enable(ts.clock); ret = clk_prepare_enable(ts.clock);
if (ret) {
dev_err(dev, "Failed! to enabled clocks\n");
goto err_clk_get;
}
dev_dbg(dev, "got and enabled clocks\n"); dev_dbg(dev, "got and enabled clocks\n");
ts.irq_tc = ret = platform_get_irq(pdev, 0); ts.irq_tc = ret = platform_get_irq(pdev, 0);
...@@ -353,7 +357,9 @@ static int s3c2410ts_probe(struct platform_device *pdev) ...@@ -353,7 +357,9 @@ static int s3c2410ts_probe(struct platform_device *pdev)
err_iomap: err_iomap:
iounmap(ts.io); iounmap(ts.io);
err_clk: err_clk:
clk_disable_unprepare(ts.clock);
del_timer_sync(&touch_timer); del_timer_sync(&touch_timer);
err_clk_get:
clk_put(ts.clock); clk_put(ts.clock);
return ret; return ret;
} }
......
/*
* Copyright (c) 2017 Samsung Electronics Co., Ltd.
* Author: Andi Shyti <andi.shyti@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* STMicroelectronics FTS Touchscreen device driver
*/
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
/* I2C commands */
#define STMFTS_READ_INFO 0x80
#define STMFTS_READ_STATUS 0x84
#define STMFTS_READ_ONE_EVENT 0x85
#define STMFTS_READ_ALL_EVENT 0x86
#define STMFTS_LATEST_EVENT 0x87
#define STMFTS_SLEEP_IN 0x90
#define STMFTS_SLEEP_OUT 0x91
#define STMFTS_MS_MT_SENSE_OFF 0x92
#define STMFTS_MS_MT_SENSE_ON 0x93
#define STMFTS_SS_HOVER_SENSE_OFF 0x94
#define STMFTS_SS_HOVER_SENSE_ON 0x95
#define STMFTS_MS_KEY_SENSE_OFF 0x9a
#define STMFTS_MS_KEY_SENSE_ON 0x9b
#define STMFTS_SYSTEM_RESET 0xa0
#define STMFTS_CLEAR_EVENT_STACK 0xa1
#define STMFTS_FULL_FORCE_CALIBRATION 0xa2
#define STMFTS_MS_CX_TUNING 0xa3
#define STMFTS_SS_CX_TUNING 0xa4
/* events */
#define STMFTS_EV_NO_EVENT 0x00
#define STMFTS_EV_MULTI_TOUCH_DETECTED 0x02
#define STMFTS_EV_MULTI_TOUCH_ENTER 0x03
#define STMFTS_EV_MULTI_TOUCH_LEAVE 0x04
#define STMFTS_EV_MULTI_TOUCH_MOTION 0x05
#define STMFTS_EV_HOVER_ENTER 0x07
#define STMFTS_EV_HOVER_LEAVE 0x08
#define STMFTS_EV_HOVER_MOTION 0x09
#define STMFTS_EV_KEY_STATUS 0x0e
#define STMFTS_EV_ERROR 0x0f
#define STMFTS_EV_CONTROLLER_READY 0x10
#define STMFTS_EV_SLEEP_OUT_CONTROLLER_READY 0x11
#define STMFTS_EV_STATUS 0x16
#define STMFTS_EV_DEBUG 0xdb
/* multi touch related event masks */
#define STMFTS_MASK_EVENT_ID 0x0f
#define STMFTS_MASK_TOUCH_ID 0xf0
#define STMFTS_MASK_LEFT_EVENT 0x0f
#define STMFTS_MASK_X_MSB 0x0f
#define STMFTS_MASK_Y_LSB 0xf0
/* key related event masks */
#define STMFTS_MASK_KEY_NO_TOUCH 0x00
#define STMFTS_MASK_KEY_MENU 0x01
#define STMFTS_MASK_KEY_BACK 0x02
#define STMFTS_EVENT_SIZE 8
#define STMFTS_STACK_DEPTH 32
#define STMFTS_DATA_MAX_SIZE (STMFTS_EVENT_SIZE * STMFTS_STACK_DEPTH)
#define STMFTS_MAX_FINGERS 10
#define STMFTS_DEV_NAME "stmfts"
enum stmfts_regulators {
STMFTS_REGULATOR_VDD,
STMFTS_REGULATOR_AVDD,
};
struct stmfts_data {
struct i2c_client *client;
struct input_dev *input;
struct led_classdev led_cdev;
struct mutex mutex;
struct touchscreen_properties prop;
struct regulator_bulk_data regulators[2];
/*
* Presence of ledvdd will be used also to check
* whether the LED is supported.
*/
struct regulator *ledvdd;
u16 chip_id;
u8 chip_ver;
u16 fw_ver;
u8 config_id;
u8 config_ver;
u8 data[STMFTS_DATA_MAX_SIZE];
struct completion cmd_done;
bool use_key;
bool led_status;
bool hover_enabled;
bool running;
};
static void stmfts_brightness_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
struct stmfts_data *sdata = container_of(led_cdev,
struct stmfts_data, led_cdev);
int err;
if (value == sdata->led_status || !sdata->ledvdd)
return;
if (!value) {
regulator_disable(sdata->ledvdd);
} else {
err = regulator_enable(sdata->ledvdd);
if (err)
dev_warn(&sdata->client->dev,
"failed to disable ledvdd regulator: %d\n",
err);
}
sdata->led_status = value;
}
static enum led_brightness stmfts_brightness_get(struct led_classdev *led_cdev)
{
struct stmfts_data *sdata = container_of(led_cdev,
struct stmfts_data, led_cdev);
return !!regulator_is_enabled(sdata->ledvdd);
}
/*
* We can't simply use i2c_smbus_read_i2c_block_data because we
* need to read more than 255 bytes (
*/
static int stmfts_read_events(struct stmfts_data *sdata)
{
u8 cmd = STMFTS_READ_ALL_EVENT;
struct i2c_msg msgs[2] = {
{
.addr = sdata->client->addr,
.len = 1,
.buf = &cmd,
},
{
.addr = sdata->client->addr,
.flags = I2C_M_RD,
.len = STMFTS_DATA_MAX_SIZE,
.buf = sdata->data,
},
};
int ret;
ret = i2c_transfer(sdata->client->adapter, msgs, ARRAY_SIZE(msgs));
if (ret < 0)
return ret;
return ret == ARRAY_SIZE(msgs) ? 0 : -EIO;
}
static void stmfts_report_contact_event(struct stmfts_data *sdata,
const u8 event[])
{
u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
u16 x = event[1] | ((event[2] & STMFTS_MASK_X_MSB) << 8);
u16 y = (event[2] >> 4) | (event[3] << 4);
u8 maj = event[4];
u8 min = event[5];
u8 orientation = event[6];
u8 area = event[7];
input_mt_slot(sdata->input, slot_id);
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, true);
input_report_abs(sdata->input, ABS_MT_POSITION_X, x);
input_report_abs(sdata->input, ABS_MT_POSITION_Y, y);
input_report_abs(sdata->input, ABS_MT_TOUCH_MAJOR, maj);
input_report_abs(sdata->input, ABS_MT_TOUCH_MINOR, min);
input_report_abs(sdata->input, ABS_MT_PRESSURE, area);
input_report_abs(sdata->input, ABS_MT_ORIENTATION, orientation);
input_sync(sdata->input);
}
static void stmfts_report_contact_release(struct stmfts_data *sdata,
const u8 event[])
{
u8 slot_id = (event[0] & STMFTS_MASK_TOUCH_ID) >> 4;
input_mt_slot(sdata->input, slot_id);
input_mt_report_slot_state(sdata->input, MT_TOOL_FINGER, false);
input_sync(sdata->input);
}
static void stmfts_report_hover_event(struct stmfts_data *sdata,
const u8 event[])
{
u16 x = (event[2] << 4) | (event[4] >> 4);
u16 y = (event[3] << 4) | (event[4] & STMFTS_MASK_Y_LSB);
u8 z = event[5];
input_report_abs(sdata->input, ABS_X, x);
input_report_abs(sdata->input, ABS_Y, y);
input_report_abs(sdata->input, ABS_DISTANCE, z);
input_sync(sdata->input);
}
static void stmfts_report_key_event(struct stmfts_data *sdata, const u8 event[])
{
switch (event[2]) {
case 0:
input_report_key(sdata->input, KEY_BACK, 0);
input_report_key(sdata->input, KEY_MENU, 0);
break;
case STMFTS_MASK_KEY_BACK:
input_report_key(sdata->input, KEY_BACK, 1);
break;
case STMFTS_MASK_KEY_MENU:
input_report_key(sdata->input, KEY_MENU, 1);
break;
default:
dev_warn(&sdata->client->dev,
"unknown key event: %#02x\n", event[2]);
break;
}
input_sync(sdata->input);
}
static void stmfts_parse_events(struct stmfts_data *sdata)
{
int i;
for (i = 0; i < STMFTS_STACK_DEPTH; i++) {
u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE];
switch (event[0]) {
case STMFTS_EV_CONTROLLER_READY:
case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
case STMFTS_EV_STATUS:
complete(&sdata->cmd_done);
/* fall through */
case STMFTS_EV_NO_EVENT:
case STMFTS_EV_DEBUG:
return;
}
switch (event[0] & STMFTS_MASK_EVENT_ID) {
case STMFTS_EV_MULTI_TOUCH_ENTER:
case STMFTS_EV_MULTI_TOUCH_MOTION:
stmfts_report_contact_event(sdata, event);
break;
case STMFTS_EV_MULTI_TOUCH_LEAVE:
stmfts_report_contact_release(sdata, event);
break;
case STMFTS_EV_HOVER_ENTER:
case STMFTS_EV_HOVER_LEAVE:
case STMFTS_EV_HOVER_MOTION:
stmfts_report_hover_event(sdata, event);
break;
case STMFTS_EV_KEY_STATUS:
stmfts_report_key_event(sdata, event);
break;
case STMFTS_EV_ERROR:
dev_warn(&sdata->client->dev,
"error code: 0x%x%x%x%x%x%x",
event[6], event[5], event[4],
event[3], event[2], event[1]);
break;
default:
dev_err(&sdata->client->dev,
"unknown event %#02x\n", event[0]);
}
}
}
static irqreturn_t stmfts_irq_handler(int irq, void *dev)
{
struct stmfts_data *sdata = dev;
int err;
mutex_lock(&sdata->mutex);
err = stmfts_read_events(sdata);
if (unlikely(err))
dev_err(&sdata->client->dev,
"failed to read events: %d\n", err);
else
stmfts_parse_events(sdata);
mutex_unlock(&sdata->mutex);
return IRQ_HANDLED;
}
static int stmfts_command(struct stmfts_data *sdata, const u8 cmd)
{
int err;
reinit_completion(&sdata->cmd_done);
err = i2c_smbus_write_byte(sdata->client, cmd);
if (err)
return err;
if (!wait_for_completion_timeout(&sdata->cmd_done,
msecs_to_jiffies(1000)))
return -ETIMEDOUT;
return 0;
}
static int stmfts_input_open(struct input_dev *dev)
{
struct stmfts_data *sdata = input_get_drvdata(dev);
int err;
err = pm_runtime_get_sync(&sdata->client->dev);
if (err < 0)
return err;
err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_ON);
if (err)
return err;
mutex_lock(&sdata->mutex);
sdata->running = true;
if (sdata->hover_enabled) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_SS_HOVER_SENSE_ON);
if (err)
dev_warn(&sdata->client->dev,
"failed to enable hover\n");
}
mutex_unlock(&sdata->mutex);
if (sdata->use_key) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_MS_KEY_SENSE_ON);
if (err)
/* I can still use only the touch screen */
dev_warn(&sdata->client->dev,
"failed to enable touchkey\n");
}
return 0;
}
static void stmfts_input_close(struct input_dev *dev)
{
struct stmfts_data *sdata = input_get_drvdata(dev);
int err;
err = i2c_smbus_write_byte(sdata->client, STMFTS_MS_MT_SENSE_OFF);
if (err)
dev_warn(&sdata->client->dev,
"failed to disable touchscreen: %d\n", err);
mutex_lock(&sdata->mutex);
sdata->running = false;
if (sdata->hover_enabled) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_SS_HOVER_SENSE_OFF);
if (err)
dev_warn(&sdata->client->dev,
"failed to disable hover: %d\n", err);
}
mutex_unlock(&sdata->mutex);
if (sdata->use_key) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_MS_KEY_SENSE_OFF);
if (err)
dev_warn(&sdata->client->dev,
"failed to disable touchkey: %d\n", err);
}
pm_runtime_put_sync(&sdata->client->dev);
}
static ssize_t stmfts_sysfs_chip_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%#x\n", sdata->chip_id);
}
static ssize_t stmfts_sysfs_chip_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", sdata->chip_ver);
}
static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", sdata->fw_ver);
}
static ssize_t stmfts_sysfs_config_id(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%#x\n", sdata->config_id);
}
static ssize_t stmfts_sysfs_config_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", sdata->config_ver);
}
static ssize_t stmfts_sysfs_read_status(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
u8 status[4];
int err;
err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_STATUS,
sizeof(status), status);
if (err)
return err;
return sprintf(buf, "%#02x\n", status[0]);
}
static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return sprintf(buf, "%u\n", sdata->hover_enabled);
}
static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t len)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
unsigned long value;
int err = 0;
if (kstrtoul(buf, 0, &value))
return -EINVAL;
mutex_lock(&sdata->mutex);
if (value & sdata->hover_enabled)
goto out;
if (sdata->running)
err = i2c_smbus_write_byte(sdata->client,
value ? STMFTS_SS_HOVER_SENSE_ON :
STMFTS_SS_HOVER_SENSE_OFF);
if (!err)
sdata->hover_enabled = !!value;
out:
mutex_unlock(&sdata->mutex);
return len;
}
static DEVICE_ATTR(chip_id, 0444, stmfts_sysfs_chip_id, NULL);
static DEVICE_ATTR(chip_version, 0444, stmfts_sysfs_chip_version, NULL);
static DEVICE_ATTR(fw_ver, 0444, stmfts_sysfs_fw_ver, NULL);
static DEVICE_ATTR(config_id, 0444, stmfts_sysfs_config_id, NULL);
static DEVICE_ATTR(config_version, 0444, stmfts_sysfs_config_version, NULL);
static DEVICE_ATTR(status, 0444, stmfts_sysfs_read_status, NULL);
static DEVICE_ATTR(hover_enable, 0644, stmfts_sysfs_hover_enable_read,
stmfts_sysfs_hover_enable_write);
static struct attribute *stmfts_sysfs_attrs[] = {
&dev_attr_chip_id.attr,
&dev_attr_chip_version.attr,
&dev_attr_fw_ver.attr,
&dev_attr_config_id.attr,
&dev_attr_config_version.attr,
&dev_attr_status.attr,
&dev_attr_hover_enable.attr,
NULL
};
static struct attribute_group stmfts_attribute_group = {
.attrs = stmfts_sysfs_attrs
};
static int stmfts_power_on(struct stmfts_data *sdata)
{
int err;
u8 reg[8];
err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
sdata->regulators);
if (err)
return err;
/*
* The datasheet does not specify the power on time, but considering
* that the reset time is < 10ms, I sleep 20ms to be sure
*/
msleep(20);
err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO,
sizeof(reg), reg);
if (err < 0)
return err;
if (err != sizeof(reg))
return -EIO;
sdata->chip_id = be16_to_cpup((__be16 *)&reg[6]);
sdata->chip_ver = reg[0];
sdata->fw_ver = be16_to_cpup((__be16 *)&reg[2]);
sdata->config_id = reg[4];
sdata->config_ver = reg[5];
enable_irq(sdata->client->irq);
msleep(50);
err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
if (err)
return err;
err = stmfts_command(sdata, STMFTS_SLEEP_OUT);
if (err)
return err;
/* optional tuning */
err = stmfts_command(sdata, STMFTS_MS_CX_TUNING);
if (err)
dev_warn(&sdata->client->dev,
"failed to perform mutual auto tune: %d\n", err);
/* optional tuning */
err = stmfts_command(sdata, STMFTS_SS_CX_TUNING);
if (err)
dev_warn(&sdata->client->dev,
"failed to perform self auto tune: %d\n", err);
err = stmfts_command(sdata, STMFTS_FULL_FORCE_CALIBRATION);
if (err)
return err;
/*
* At this point no one is using the touchscreen
* and I don't really care about the return value
*/
(void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
return 0;
}
static void stmfts_power_off(void *data)
{
struct stmfts_data *sdata = data;
disable_irq(sdata->client->irq);
regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
sdata->regulators);
}
/* This function is void because I don't want to prevent using the touch key
* only because the LEDs don't get registered
*/
static int stmfts_enable_led(struct stmfts_data *sdata)
{
int err;
/* get the regulator for powering the leds on */
sdata->ledvdd = devm_regulator_get(&sdata->client->dev, "ledvdd");
if (IS_ERR(sdata->ledvdd))
return PTR_ERR(sdata->ledvdd);
sdata->led_cdev.name = STMFTS_DEV_NAME;
sdata->led_cdev.max_brightness = LED_ON;
sdata->led_cdev.brightness = LED_OFF;
sdata->led_cdev.brightness_set = stmfts_brightness_set;
sdata->led_cdev.brightness_get = stmfts_brightness_get;
err = devm_led_classdev_register(&sdata->client->dev, &sdata->led_cdev);
if (err) {
devm_regulator_put(sdata->ledvdd);
return err;
}
return 0;
}
static int stmfts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err;
struct stmfts_data *sdata;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK))
return -ENODEV;
sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
if (!sdata)
return -ENOMEM;
i2c_set_clientdata(client, sdata);
sdata->client = client;
mutex_init(&sdata->mutex);
init_completion(&sdata->cmd_done);
sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
err = devm_regulator_bulk_get(&client->dev,
ARRAY_SIZE(sdata->regulators),
sdata->regulators);
if (err)
return err;
sdata->input = devm_input_allocate_device(&client->dev);
if (!sdata->input)
return -ENOMEM;
sdata->input->name = STMFTS_DEV_NAME;
sdata->input->id.bustype = BUS_I2C;
sdata->input->open = stmfts_input_open;
sdata->input->close = stmfts_input_close;
touchscreen_parse_properties(sdata->input, true, &sdata->prop);
input_set_abs_params(sdata->input, ABS_MT_POSITION_X, 0,
sdata->prop.max_x, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_POSITION_Y, 0,
sdata->prop.max_y, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
sdata->use_key = device_property_read_bool(&client->dev,
"touch-key-connected");
if (sdata->use_key) {
input_set_capability(sdata->input, EV_KEY, KEY_MENU);
input_set_capability(sdata->input, EV_KEY, KEY_BACK);
}
err = input_mt_init_slots(sdata->input,
STMFTS_MAX_FINGERS, INPUT_MT_DIRECT);
if (err)
return err;
input_set_drvdata(sdata->input, sdata);
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, stmfts_irq_handler,
IRQF_ONESHOT,
"stmfts_irq", sdata);
if (err)
return err;
/* stmfts_power_on expects interrupt to be disabled */
disable_irq(client->irq);
dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
err = stmfts_power_on(sdata);
if (err)
return err;
err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
if (err)
return err;
err = input_register_device(sdata->input);
if (err)
return err;
if (sdata->use_key) {
err = stmfts_enable_led(sdata);
if (err) {
/*
* Even if the LEDs have failed to be initialized and
* used in the driver, I can still use the device even
* without LEDs. The ledvdd regulator pointer will be
* used as a flag.
*/
dev_warn(&client->dev, "unable to use touchkey leds\n");
sdata->ledvdd = NULL;
}
}
err = sysfs_create_group(&sdata->client->dev.kobj,
&stmfts_attribute_group);
if (err)
return err;
pm_runtime_enable(&client->dev);
return 0;
}
static int stmfts_remove(struct i2c_client *client)
{
pm_runtime_disable(&client->dev);
sysfs_remove_group(&client->dev.kobj, &stmfts_attribute_group);
return 0;
}
static int __maybe_unused stmfts_runtime_suspend(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
int ret;
ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
if (ret)
dev_warn(dev, "failed to suspend device: %d\n", ret);
return ret;
}
static int __maybe_unused stmfts_runtime_resume(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
int ret;
ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
if (ret)
dev_err(dev, "failed to resume device: %d\n", ret);
return ret;
}
static int __maybe_unused stmfts_suspend(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
stmfts_power_off(sdata);
return 0;
}
static int __maybe_unused stmfts_resume(struct device *dev)
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
return stmfts_power_on(sdata);
}
static const struct dev_pm_ops stmfts_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(stmfts_suspend, stmfts_resume)
SET_RUNTIME_PM_OPS(stmfts_runtime_suspend, stmfts_runtime_resume, NULL)
};
#ifdef CONFIG_OF
static const struct of_device_id stmfts_of_match[] = {
{ .compatible = "st,stmfts", },
{ },
};
MODULE_DEVICE_TABLE(of, stmfts_of_match);
#endif
static const struct i2c_device_id stmfts_id[] = {
{ "stmfts", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, stmfts_id);
static struct i2c_driver stmfts_driver = {
.driver = {
.name = STMFTS_DEV_NAME,
.of_match_table = of_match_ptr(stmfts_of_match),
.pm = &stmfts_pm_ops,
},
.probe = stmfts_probe,
.remove = stmfts_remove,
.id_table = stmfts_id,
};
module_i2c_driver(stmfts_driver);
MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
MODULE_LICENSE("GPL v2");
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c/tsc2007.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/platform_data/tsc2007.h>
#include "tsc2007.h" #include "tsc2007.h"
int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd) int tsc2007_xfer(struct tsc2007 *tsc, u8 cmd)
......
...@@ -32,13 +32,13 @@ ...@@ -32,13 +32,13 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-ocores.h> #include <linux/i2c-ocores.h>
#include <linux/i2c-xiic.h> #include <linux/i2c-xiic.h>
#include <linux/i2c/tsc2007.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/xilinx_spi.h> #include <linux/spi/xilinx_spi.h>
#include <linux/spi/max7301.h> #include <linux/spi/max7301.h>
#include <linux/spi/mc33880.h> #include <linux/spi/mc33880.h>
#include <linux/platform_data/tsc2007.h>
#include <linux/platform_data/media/timb_radio.h> #include <linux/platform_data/media/timb_radio.h>
#include <linux/platform_data/media/timb_video.h> #include <linux/platform_data/media/timb_video.h>
......
...@@ -51,7 +51,6 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev, ...@@ -51,7 +51,6 @@ struct key_entry *sparse_keymap_entry_from_keycode(struct input_dev *dev,
int sparse_keymap_setup(struct input_dev *dev, int sparse_keymap_setup(struct input_dev *dev,
const struct key_entry *keymap, const struct key_entry *keymap,
int (*setup)(struct input_dev *, struct key_entry *)); int (*setup)(struct input_dev *, struct key_entry *));
void sparse_keymap_free(struct input_dev *dev);
void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke, void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *ke,
unsigned int value, bool autorelease); unsigned int value, bool autorelease);
......
#ifndef __LINUX_I2C_TSC2007_H #ifndef __LINUX_I2C_TSC2007_H
#define __LINUX_I2C_TSC2007_H #define __LINUX_I2C_TSC2007_H
/* linux/i2c/tsc2007.h */ /* linux/platform_data/tsc2007.h */
struct tsc2007_platform_data { struct tsc2007_platform_data {
u16 model; /* 2007. */ u16 model; /* 2007. */
......
...@@ -600,6 +600,7 @@ ...@@ -600,6 +600,7 @@
#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ #define KEY_APPSELECT 0x244 /* AL Select Task/Application */
#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ #define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ #define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment