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

Pull input updates from Dmitry Torokhov:
 "Mostly existing driver fixes plus a new driver for game controllers
  directly connected to Nintendo 64, and an enhancement for keyboards
  driven by Chrome OS EC to communicate layout of the top row to
  userspace"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (47 commits)
  Input: st1232 - fix NORMAL vs. IDLE state handling
  Input: aiptek - convert sysfs sprintf/snprintf family to sysfs_emit
  Input: alps - fix spelling of "positive"
  ARM: dts: cros-ec-keyboard: Use keymap macros
  dt-bindings: input: Fix the keymap for LOCK key
  dt-bindings: input: Create macros for cros-ec keymap
  Input: cros-ec-keyb - expose function row physical map to userspace
  dt-bindings: input: cros-ec-keyb: Add a new property describing top row
  Input: applespi - fix occasional crc errors under load.
  Input: applespi - don't wait for responses to commands indefinitely.
  Input: st1232 - add IDLE state as ready condition
  Input: zinitix - fix return type of zinitix_init_touch()
  Input: i8042 - add ASUS Zenbook Flip to noselftest list
  Input: add missing dependencies on CONFIG_HAS_IOMEM
  Input: joydev - prevent potential read overflow in ioctl
  Input: elo - fix an error code in elo_connect()
  Input: xpad - add support for PowerA Enhanced Wired Controller for Xbox Series X|S
  Input: sur40 - fix an error code in sur40_probe()
  Input: elants_i2c - detect enum overflow
  Input: zinitix - remove unneeded semicolon
  ...
This commit is contained in:
Linus Torvalds 2021-02-23 14:56:23 -08:00
commit e0fbd25bb3
32 changed files with 1265 additions and 608 deletions

View File

@ -0,0 +1,6 @@
What: /sys/class/input/input(x)/device/function_row_physmap
Date: January 2021
Contact: Philip Chen <philipchen@chromium.org>
Description: A space separated list of scancodes for the top row keys,
ordered by the physical positions of the keys, from left
to right.

View File

@ -31,6 +31,17 @@ properties:
if the EC does not have its own logic or hardware for this. if the EC does not have its own logic or hardware for this.
type: boolean type: boolean
function-row-physmap:
minItems: 1
maxItems: 15
description: |
An ordered u32 array describing the rows/columns (in the scan matrix)
of top row keys from physical left (KEY_F1) to right. Each entry
encodes the row/column as:
(((row) & 0xFF) << 24) | (((column) & 0xFF) << 16)
where the lower 16 bits are reserved. This property is specified only
when the keyboard has a custom design for the top row keys.
required: required:
- compatible - compatible
@ -38,11 +49,24 @@ unevaluatedProperties: false
examples: examples:
- | - |
#include <dt-bindings/input/input.h>
cros-ec-keyb { cros-ec-keyb {
compatible = "google,cros-ec-keyb"; compatible = "google,cros-ec-keyb";
keypad,num-rows = <8>; keypad,num-rows = <8>;
keypad,num-columns = <13>; keypad,num-columns = <13>;
google,needs-ghost-filter; google,needs-ghost-filter;
function-row-physmap = <
MATRIX_KEY(0x00, 0x02, 0) /* T1 */
MATRIX_KEY(0x03, 0x02, 0) /* T2 */
MATRIX_KEY(0x02, 0x02, 0) /* T3 */
MATRIX_KEY(0x01, 0x02, 0) /* T4 */
MATRIX_KEY(0x03, 0x04, 0) /* T5 */
MATRIX_KEY(0x02, 0x04, 0) /* T6 */
MATRIX_KEY(0x01, 0x04, 0) /* T7 */
MATRIX_KEY(0x02, 0x09, 0) /* T8 */
MATRIX_KEY(0x01, 0x09, 0) /* T9 */
MATRIX_KEY(0x00, 0x04, 0) /* T10 */
>;
/* /*
* Keymap entries take the form of 0xRRCCKKKK where * Keymap entries take the form of 0xRRCCKKKK where
* RR=Row CC=Column KKKK=Key Code * RR=Row CC=Column KKKK=Key Code

View File

@ -6,103 +6,18 @@
*/ */
#include <dt-bindings/input/input.h> #include <dt-bindings/input/input.h>
#include <dt-bindings/input/cros-ec-keyboard.h>
&cros_ec { &cros_ec {
keyboard-controller { keyboard_controller: keyboard-controller {
compatible = "google,cros-ec-keyb"; compatible = "google,cros-ec-keyb";
keypad,num-rows = <8>; keypad,num-rows = <8>;
keypad,num-columns = <13>; keypad,num-columns = <13>;
google,needs-ghost-filter; google,needs-ghost-filter;
linux,keymap = < linux,keymap = <
MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA) CROS_STD_TOP_ROW_KEYMAP
MATRIX_KEY(0x00, 0x02, KEY_F1) CROS_STD_MAIN_KEYMAP
MATRIX_KEY(0x00, 0x03, KEY_B)
MATRIX_KEY(0x00, 0x04, KEY_F10)
MATRIX_KEY(0x00, 0x05, KEY_RO)
MATRIX_KEY(0x00, 0x06, KEY_N)
MATRIX_KEY(0x00, 0x08, KEY_EQUAL)
MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT)
MATRIX_KEY(0x01, 0x01, KEY_ESC)
MATRIX_KEY(0x01, 0x02, KEY_F4)
MATRIX_KEY(0x01, 0x03, KEY_G)
MATRIX_KEY(0x01, 0x04, KEY_F7)
MATRIX_KEY(0x01, 0x06, KEY_H)
MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE)
MATRIX_KEY(0x01, 0x09, KEY_F9)
MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE)
MATRIX_KEY(0x01, 0x0c, KEY_HENKAN)
MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL)
MATRIX_KEY(0x02, 0x01, KEY_TAB)
MATRIX_KEY(0x02, 0x02, KEY_F3)
MATRIX_KEY(0x02, 0x03, KEY_T)
MATRIX_KEY(0x02, 0x04, KEY_F6)
MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE)
MATRIX_KEY(0x02, 0x06, KEY_Y)
MATRIX_KEY(0x02, 0x07, KEY_102ND)
MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE)
MATRIX_KEY(0x02, 0x09, KEY_F8)
MATRIX_KEY(0x02, 0x0a, KEY_YEN)
MATRIX_KEY(0x03, 0x00, KEY_LEFTMETA)
MATRIX_KEY(0x03, 0x01, KEY_GRAVE)
MATRIX_KEY(0x03, 0x02, KEY_F2)
MATRIX_KEY(0x03, 0x03, KEY_5)
MATRIX_KEY(0x03, 0x04, KEY_F5)
MATRIX_KEY(0x03, 0x06, KEY_6)
MATRIX_KEY(0x03, 0x08, KEY_MINUS)
MATRIX_KEY(0x03, 0x09, KEY_F13)
MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH)
MATRIX_KEY(0x03, 0x0c, KEY_MUHENKAN)
MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL)
MATRIX_KEY(0x04, 0x01, KEY_A)
MATRIX_KEY(0x04, 0x02, KEY_D)
MATRIX_KEY(0x04, 0x03, KEY_F)
MATRIX_KEY(0x04, 0x04, KEY_S)
MATRIX_KEY(0x04, 0x05, KEY_K)
MATRIX_KEY(0x04, 0x06, KEY_J)
MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON)
MATRIX_KEY(0x04, 0x09, KEY_L)
MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH)
MATRIX_KEY(0x04, 0x0b, KEY_ENTER)
MATRIX_KEY(0x05, 0x01, KEY_Z)
MATRIX_KEY(0x05, 0x02, KEY_C)
MATRIX_KEY(0x05, 0x03, KEY_V)
MATRIX_KEY(0x05, 0x04, KEY_X)
MATRIX_KEY(0x05, 0x05, KEY_COMMA)
MATRIX_KEY(0x05, 0x06, KEY_M)
MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT)
MATRIX_KEY(0x05, 0x08, KEY_SLASH)
MATRIX_KEY(0x05, 0x09, KEY_DOT)
MATRIX_KEY(0x05, 0x0b, KEY_SPACE)
MATRIX_KEY(0x06, 0x01, KEY_1)
MATRIX_KEY(0x06, 0x02, KEY_3)
MATRIX_KEY(0x06, 0x03, KEY_4)
MATRIX_KEY(0x06, 0x04, KEY_2)
MATRIX_KEY(0x06, 0x05, KEY_8)
MATRIX_KEY(0x06, 0x06, KEY_7)
MATRIX_KEY(0x06, 0x08, KEY_0)
MATRIX_KEY(0x06, 0x09, KEY_9)
MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT)
MATRIX_KEY(0x06, 0x0b, KEY_DOWN)
MATRIX_KEY(0x06, 0x0c, KEY_RIGHT)
MATRIX_KEY(0x07, 0x01, KEY_Q)
MATRIX_KEY(0x07, 0x02, KEY_E)
MATRIX_KEY(0x07, 0x03, KEY_R)
MATRIX_KEY(0x07, 0x04, KEY_W)
MATRIX_KEY(0x07, 0x05, KEY_I)
MATRIX_KEY(0x07, 0x06, KEY_U)
MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT)
MATRIX_KEY(0x07, 0x08, KEY_P)
MATRIX_KEY(0x07, 0x09, KEY_O)
MATRIX_KEY(0x07, 0x0b, KEY_UP)
MATRIX_KEY(0x07, 0x0c, KEY_LEFT)
>; >;
}; };
}; };

View File

@ -456,7 +456,7 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
if (IS_ERR(abspam)) if (IS_ERR(abspam))
return PTR_ERR(abspam); return PTR_ERR(abspam);
for (i = 0; i < joydev->nabs; i++) { for (i = 0; i < len && i < joydev->nabs; i++) {
if (abspam[i] > ABS_MAX) { if (abspam[i] > ABS_MAX) {
retval = -EINVAL; retval = -EINVAL;
goto out; goto out;
@ -480,6 +480,9 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
int i; int i;
int retval = 0; int retval = 0;
if (len % sizeof(*keypam))
return -EINVAL;
len = min(len, sizeof(joydev->keypam)); len = min(len, sizeof(joydev->keypam));
/* Validate the map. */ /* Validate the map. */
@ -487,7 +490,7 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
if (IS_ERR(keypam)) if (IS_ERR(keypam))
return PTR_ERR(keypam); return PTR_ERR(keypam);
for (i = 0; i < joydev->nkey; i++) { for (i = 0; i < (len / 2) && i < joydev->nkey; i++) {
if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) { if (keypam[i] > KEY_MAX || keypam[i] < BTN_MISC) {
retval = -EINVAL; retval = -EINVAL;
goto out; goto out;

View File

@ -382,4 +382,11 @@ config JOYSTICK_FSIA6B
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 fsia6b. module will be called fsia6b.
config JOYSTICK_N64
bool "N64 controller"
depends on MACH_NINTENDO64
help
Say Y here if you want enable support for the four
built-in controller ports on the Nintendo 64 console.
endif endif

View File

@ -24,6 +24,7 @@ obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o
obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o obj-$(CONFIG_JOYSTICK_JOYDUMP) += joydump.o
obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
obj-$(CONFIG_JOYSTICK_MAPLE) += maplecontrol.o obj-$(CONFIG_JOYSTICK_MAPLE) += maplecontrol.o
obj-$(CONFIG_JOYSTICK_N64) += n64joy.o
obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o obj-$(CONFIG_JOYSTICK_PSXPAD_SPI) += psxpad-spi.o
obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o obj-$(CONFIG_JOYSTICK_PXRC) += pxrc.o
obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
@ -37,4 +38,3 @@ obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o obj-$(CONFIG_JOYSTICK_WALKERA0701) += walkera0701.o
obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o obj-$(CONFIG_JOYSTICK_XPAD) += xpad.o
obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o obj-$(CONFIG_JOYSTICK_ZHENHUA) += zhenhua.o

View File

@ -0,0 +1,345 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Support for the four N64 controllers.
*
* Copyright (c) 2021 Lauri Kasanen
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/limits.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/timer.h>
MODULE_AUTHOR("Lauri Kasanen <cand@gmx.com>");
MODULE_DESCRIPTION("Driver for N64 controllers");
MODULE_LICENSE("GPL");
#define PIF_RAM 0x1fc007c0
#define SI_DRAM_REG 0
#define SI_READ_REG 1
#define SI_WRITE_REG 4
#define SI_STATUS_REG 6
#define SI_STATUS_DMA_BUSY BIT(0)
#define SI_STATUS_IO_BUSY BIT(1)
#define N64_CONTROLLER_ID 0x0500
#define MAX_CONTROLLERS 4
static const char *n64joy_phys[MAX_CONTROLLERS] = {
"n64joy/port0",
"n64joy/port1",
"n64joy/port2",
"n64joy/port3",
};
struct n64joy_priv {
u64 si_buf[8] ____cacheline_aligned;
struct timer_list timer;
struct mutex n64joy_mutex;
struct input_dev *n64joy_dev[MAX_CONTROLLERS];
u32 __iomem *reg_base;
u8 n64joy_opened;
};
struct joydata {
unsigned int: 16; /* unused */
unsigned int err: 2;
unsigned int: 14; /* unused */
union {
u32 data;
struct {
unsigned int a: 1;
unsigned int b: 1;
unsigned int z: 1;
unsigned int start: 1;
unsigned int up: 1;
unsigned int down: 1;
unsigned int left: 1;
unsigned int right: 1;
unsigned int: 2; /* unused */
unsigned int l: 1;
unsigned int r: 1;
unsigned int c_up: 1;
unsigned int c_down: 1;
unsigned int c_left: 1;
unsigned int c_right: 1;
signed int x: 8;
signed int y: 8;
};
};
};
static void n64joy_write_reg(u32 __iomem *reg_base, const u8 reg, const u32 value)
{
writel(value, reg_base + reg);
}
static u32 n64joy_read_reg(u32 __iomem *reg_base, const u8 reg)
{
return readl(reg_base + reg);
}
static void n64joy_wait_si_dma(u32 __iomem *reg_base)
{
while (n64joy_read_reg(reg_base, SI_STATUS_REG) &
(SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY))
cpu_relax();
}
static void n64joy_exec_pif(struct n64joy_priv *priv, const u64 in[8])
{
unsigned long flags;
dma_cache_wback_inv((unsigned long) in, 8 * 8);
dma_cache_inv((unsigned long) priv->si_buf, 8 * 8);
local_irq_save(flags);
n64joy_wait_si_dma(priv->reg_base);
barrier();
n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(in));
barrier();
n64joy_write_reg(priv->reg_base, SI_WRITE_REG, PIF_RAM);
barrier();
n64joy_wait_si_dma(priv->reg_base);
barrier();
n64joy_write_reg(priv->reg_base, SI_DRAM_REG, virt_to_phys(priv->si_buf));
barrier();
n64joy_write_reg(priv->reg_base, SI_READ_REG, PIF_RAM);
barrier();
n64joy_wait_si_dma(priv->reg_base);
local_irq_restore(flags);
}
static const u64 polldata[] ____cacheline_aligned = {
0xff010401ffffffff,
0xff010401ffffffff,
0xff010401ffffffff,
0xff010401ffffffff,
0xfe00000000000000,
0,
0,
1
};
static void n64joy_poll(struct timer_list *t)
{
const struct joydata *data;
struct n64joy_priv *priv = container_of(t, struct n64joy_priv, timer);
struct input_dev *dev;
u32 i;
n64joy_exec_pif(priv, polldata);
data = (struct joydata *) priv->si_buf;
for (i = 0; i < MAX_CONTROLLERS; i++) {
if (!priv->n64joy_dev[i])
continue;
dev = priv->n64joy_dev[i];
/* d-pad */
input_report_key(dev, BTN_DPAD_UP, data[i].up);
input_report_key(dev, BTN_DPAD_DOWN, data[i].down);
input_report_key(dev, BTN_DPAD_LEFT, data[i].left);
input_report_key(dev, BTN_DPAD_RIGHT, data[i].right);
/* c buttons */
input_report_key(dev, BTN_FORWARD, data[i].c_up);
input_report_key(dev, BTN_BACK, data[i].c_down);
input_report_key(dev, BTN_LEFT, data[i].c_left);
input_report_key(dev, BTN_RIGHT, data[i].c_right);
/* matching buttons */
input_report_key(dev, BTN_START, data[i].start);
input_report_key(dev, BTN_Z, data[i].z);
/* remaining ones: a, b, l, r */
input_report_key(dev, BTN_0, data[i].a);
input_report_key(dev, BTN_1, data[i].b);
input_report_key(dev, BTN_2, data[i].l);
input_report_key(dev, BTN_3, data[i].r);
input_report_abs(dev, ABS_X, data[i].x);
input_report_abs(dev, ABS_Y, data[i].y);
input_sync(dev);
}
mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
}
static int n64joy_open(struct input_dev *dev)
{
struct n64joy_priv *priv = input_get_drvdata(dev);
int err;
err = mutex_lock_interruptible(&priv->n64joy_mutex);
if (err)
return err;
if (!priv->n64joy_opened) {
/*
* We could use the vblank irq, but it's not important if
* the poll point slightly changes.
*/
timer_setup(&priv->timer, n64joy_poll, 0);
mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
}
priv->n64joy_opened++;
mutex_unlock(&priv->n64joy_mutex);
return err;
}
static void n64joy_close(struct input_dev *dev)
{
struct n64joy_priv *priv = input_get_drvdata(dev);
mutex_lock(&priv->n64joy_mutex);
if (!--priv->n64joy_opened)
del_timer_sync(&priv->timer);
mutex_unlock(&priv->n64joy_mutex);
}
static const u64 __initconst scandata[] ____cacheline_aligned = {
0xff010300ffffffff,
0xff010300ffffffff,
0xff010300ffffffff,
0xff010300ffffffff,
0xfe00000000000000,
0,
0,
1
};
/*
* The target device is embedded and RAM-constrained. We save RAM
* by initializing in __init code that gets dropped late in boot.
* For the same reason there is no module or unloading support.
*/
static int __init n64joy_probe(struct platform_device *pdev)
{
const struct joydata *data;
struct n64joy_priv *priv;
struct input_dev *dev;
int err = 0;
u32 i, j, found = 0;
priv = kzalloc(sizeof(struct n64joy_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
mutex_init(&priv->n64joy_mutex);
priv->reg_base = devm_platform_ioremap_resource(pdev, 0);
if (!priv->reg_base) {
err = -EINVAL;
goto fail;
}
/* The controllers are not hotpluggable, so we can scan in init */
n64joy_exec_pif(priv, scandata);
data = (struct joydata *) priv->si_buf;
for (i = 0; i < MAX_CONTROLLERS; i++) {
if (!data[i].err && data[i].data >> 16 == N64_CONTROLLER_ID) {
found++;
dev = priv->n64joy_dev[i] = input_allocate_device();
if (!priv->n64joy_dev[i]) {
err = -ENOMEM;
goto fail;
}
input_set_drvdata(dev, priv);
dev->name = "N64 controller";
dev->phys = n64joy_phys[i];
dev->id.bustype = BUS_HOST;
dev->id.vendor = 0;
dev->id.product = data[i].data >> 16;
dev->id.version = 0;
dev->dev.parent = &pdev->dev;
dev->open = n64joy_open;
dev->close = n64joy_close;
/* d-pad */
input_set_capability(dev, EV_KEY, BTN_DPAD_UP);
input_set_capability(dev, EV_KEY, BTN_DPAD_DOWN);
input_set_capability(dev, EV_KEY, BTN_DPAD_LEFT);
input_set_capability(dev, EV_KEY, BTN_DPAD_RIGHT);
/* c buttons */
input_set_capability(dev, EV_KEY, BTN_LEFT);
input_set_capability(dev, EV_KEY, BTN_RIGHT);
input_set_capability(dev, EV_KEY, BTN_FORWARD);
input_set_capability(dev, EV_KEY, BTN_BACK);
/* matching buttons */
input_set_capability(dev, EV_KEY, BTN_START);
input_set_capability(dev, EV_KEY, BTN_Z);
/* remaining ones: a, b, l, r */
input_set_capability(dev, EV_KEY, BTN_0);
input_set_capability(dev, EV_KEY, BTN_1);
input_set_capability(dev, EV_KEY, BTN_2);
input_set_capability(dev, EV_KEY, BTN_3);
for (j = 0; j < 2; j++)
input_set_abs_params(dev, ABS_X + j,
S8_MIN, S8_MAX, 0, 0);
err = input_register_device(dev);
if (err) {
input_free_device(dev);
goto fail;
}
}
}
pr_info("%u controller(s) connected\n", found);
if (!found)
return -ENODEV;
return 0;
fail:
for (i = 0; i < MAX_CONTROLLERS; i++) {
if (!priv->n64joy_dev[i])
continue;
input_unregister_device(priv->n64joy_dev[i]);
}
return err;
}
static struct platform_driver n64joy_driver = {
.driver = {
.name = "n64joy",
},
};
static int __init n64joy_init(void)
{
return platform_driver_probe(&n64joy_driver, n64joy_probe);
}
module_init(n64joy_init);

View File

@ -305,6 +305,7 @@ static const struct xpad_device {
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 }, { 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 }, { 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE }, { 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 }, { 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE }, { 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },

View File

@ -446,7 +446,7 @@ config KEYBOARD_MPR121
config KEYBOARD_SNVS_PWRKEY config KEYBOARD_SNVS_PWRKEY
tristate "IMX SNVS Power Key Driver" tristate "IMX SNVS Power Key Driver"
depends on ARCH_MXC || COMPILE_TEST depends on ARCH_MXC || (COMPILE_TEST && HAS_IOMEM)
depends on OF depends on OF
help help
This is the snvs powerkey driver for the Freescale i.MX application This is the snvs powerkey driver for the Freescale i.MX application
@ -685,7 +685,7 @@ config KEYBOARD_OMAP
config KEYBOARD_OMAP4 config KEYBOARD_OMAP4
tristate "TI OMAP4+ keypad support" tristate "TI OMAP4+ keypad support"
depends on OF || ARCH_OMAP2PLUS depends on (OF && HAS_IOMEM) || ARCH_OMAP2PLUS
select INPUT_MATRIXKMAP select INPUT_MATRIXKMAP
help help
Say Y here if you want to use the OMAP4+ keypad. Say Y here if you want to use the OMAP4+ keypad.
@ -773,7 +773,7 @@ config KEYBOARD_CAP11XX
config KEYBOARD_BCM config KEYBOARD_BCM
tristate "Broadcom keypad driver" tristate "Broadcom keypad driver"
depends on OF && HAVE_CLK depends on OF && HAVE_CLK && HAS_IOMEM
select INPUT_MATRIXKMAP select INPUT_MATRIXKMAP
default ARCH_BCM_CYGNUS default ARCH_BCM_CYGNUS
help help

View File

@ -48,6 +48,7 @@
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/ktime.h>
#include <linux/leds.h> #include <linux/leds.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
@ -409,7 +410,7 @@ struct applespi_data {
unsigned int cmd_msg_cntr; unsigned int cmd_msg_cntr;
/* lock to protect the above parameters and flags below */ /* lock to protect the above parameters and flags below */
spinlock_t cmd_msg_lock; spinlock_t cmd_msg_lock;
bool cmd_msg_queued; ktime_t cmd_msg_queued;
enum applespi_evt_type cmd_evt_type; enum applespi_evt_type cmd_evt_type;
struct led_classdev backlight_info; struct led_classdev backlight_info;
@ -729,7 +730,7 @@ static void applespi_msg_complete(struct applespi_data *applespi,
wake_up_all(&applespi->drain_complete); wake_up_all(&applespi->drain_complete);
if (is_write_msg) { if (is_write_msg) {
applespi->cmd_msg_queued = false; applespi->cmd_msg_queued = 0;
applespi_send_cmd_msg(applespi); applespi_send_cmd_msg(applespi);
} }
@ -748,6 +749,8 @@ static void applespi_async_write_complete(void *context)
applespi->tx_status, applespi->tx_status,
APPLESPI_STATUS_SIZE); APPLESPI_STATUS_SIZE);
udelay(SPI_RW_CHG_DELAY_US);
if (!applespi_check_write_status(applespi, applespi->wr_m.status)) { if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
/* /*
* If we got an error, we presumably won't get the expected * If we got an error, we presumably won't get the expected
@ -771,9 +774,17 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
return 0; return 0;
/* check whether send is in progress */ /* check whether send is in progress */
if (applespi->cmd_msg_queued) if (applespi->cmd_msg_queued) {
if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000)
return 0; return 0;
dev_warn(&applespi->spi->dev, "Command %d timed out\n",
applespi->cmd_evt_type);
applespi->cmd_msg_queued = 0;
applespi->write_active = false;
}
/* set up packet */ /* set up packet */
memset(packet, 0, APPLESPI_PACKET_SIZE); memset(packet, 0, APPLESPI_PACKET_SIZE);
@ -869,7 +880,7 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
return sts; return sts;
} }
applespi->cmd_msg_queued = true; applespi->cmd_msg_queued = ktime_get_coarse();
applespi->write_active = true; applespi->write_active = true;
return 0; return 0;
@ -1921,7 +1932,7 @@ static int __maybe_unused applespi_resume(struct device *dev)
applespi->drain = false; applespi->drain = false;
applespi->have_cl_led_on = false; applespi->have_cl_led_on = false;
applespi->have_bl_level = 0; applespi->have_bl_level = 0;
applespi->cmd_msg_queued = false; applespi->cmd_msg_queued = 0;
applespi->read_active = false; applespi->read_active = false;
applespi->write_active = false; applespi->write_active = false;

View File

@ -27,6 +27,8 @@
#include <asm/unaligned.h> #include <asm/unaligned.h>
#define MAX_NUM_TOP_ROW_KEYS 15
/** /**
* struct cros_ec_keyb - Structure representing EC keyboard device * struct cros_ec_keyb - Structure representing EC keyboard device
* *
@ -42,6 +44,9 @@
* @idev: The input device for the matrix keys. * @idev: The input device for the matrix keys.
* @bs_idev: The input device for non-matrix buttons and switches (or NULL). * @bs_idev: The input device for non-matrix buttons and switches (or NULL).
* @notifier: interrupt event notifier for transport devices * @notifier: interrupt event notifier for transport devices
* @function_row_physmap: An array of the encoded rows/columns for the top
* row function keys, in an order from left to right
* @num_function_row_keys: The number of top row keys in a custom keyboard
*/ */
struct cros_ec_keyb { struct cros_ec_keyb {
unsigned int rows; unsigned int rows;
@ -58,6 +63,9 @@ struct cros_ec_keyb {
struct input_dev *idev; struct input_dev *idev;
struct input_dev *bs_idev; struct input_dev *bs_idev;
struct notifier_block notifier; struct notifier_block notifier;
u16 function_row_physmap[MAX_NUM_TOP_ROW_KEYS];
size_t num_function_row_keys;
}; };
/** /**
@ -527,6 +535,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
struct input_dev *idev; struct input_dev *idev;
const char *phys; const char *phys;
int err; int err;
struct property *prop;
const __be32 *p;
u16 *physmap;
u32 key_pos;
int row, col;
err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols); err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols);
if (err) if (err)
@ -578,6 +591,21 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
ckdev->idev = idev; ckdev->idev = idev;
cros_ec_keyb_compute_valid_keys(ckdev); cros_ec_keyb_compute_valid_keys(ckdev);
physmap = ckdev->function_row_physmap;
of_property_for_each_u32(dev->of_node, "function-row-physmap",
prop, p, key_pos) {
if (ckdev->num_function_row_keys == MAX_NUM_TOP_ROW_KEYS) {
dev_warn(dev, "Only support up to %d top row keys\n",
MAX_NUM_TOP_ROW_KEYS);
break;
}
row = KEY_ROW(key_pos);
col = KEY_COL(key_pos);
*physmap = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
physmap++;
ckdev->num_function_row_keys++;
}
err = input_register_device(ckdev->idev); err = input_register_device(ckdev->idev);
if (err) { if (err) {
dev_err(dev, "cannot register input device\n"); dev_err(dev, "cannot register input device\n");
@ -587,6 +615,51 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
return 0; return 0;
} }
static ssize_t function_row_physmap_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
ssize_t size = 0;
int i;
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
u16 *physmap = ckdev->function_row_physmap;
for (i = 0; i < ckdev->num_function_row_keys; i++)
size += scnprintf(buf + size, PAGE_SIZE - size,
"%s%02X", size ? " " : "", physmap[i]);
if (size)
size += scnprintf(buf + size, PAGE_SIZE - size, "\n");
return size;
}
static DEVICE_ATTR_RO(function_row_physmap);
static struct attribute *cros_ec_keyb_attrs[] = {
&dev_attr_function_row_physmap.attr,
NULL,
};
static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj,
struct attribute *attr,
int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct cros_ec_keyb *ckdev = dev_get_drvdata(dev);
if (attr == &dev_attr_function_row_physmap.attr &&
!ckdev->num_function_row_keys)
return 0;
return attr->mode;
}
static const struct attribute_group cros_ec_keyb_attr_group = {
.is_visible = cros_ec_keyb_attr_is_visible,
.attrs = cros_ec_keyb_attrs,
};
static int cros_ec_keyb_probe(struct platform_device *pdev) static int cros_ec_keyb_probe(struct platform_device *pdev)
{ {
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent); struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@ -617,6 +690,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
return err; return err;
} }
err = devm_device_add_group(dev, &cros_ec_keyb_attr_group);
if (err) {
dev_err(dev, "failed to create attributes. err=%d\n", err);
return err;
}
ckdev->notifier.notifier_call = cros_ec_keyb_work; ckdev->notifier.notifier_call = cros_ec_keyb_work;
err = blocking_notifier_chain_register(&ckdev->ec->event_notifier, err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
&ckdev->notifier); &ckdev->notifier);

View File

@ -60,6 +60,8 @@
((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1) ((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1)
#define OMAP4_VAL_DEBOUNCINGTIME_16MS \ #define OMAP4_VAL_DEBOUNCINGTIME_16MS \
OMAP4_KEYPAD_DEBOUNCINGTIME_MS(16, OMAP4_KEYPAD_PTV_DIV_128) OMAP4_KEYPAD_DEBOUNCINGTIME_MS(16, OMAP4_KEYPAD_PTV_DIV_128)
#define OMAP4_KEYPAD_AUTOIDLE_MS 50 /* Approximate measured time */
#define OMAP4_KEYPAD_IDLE_CHECK_MS (OMAP4_KEYPAD_AUTOIDLE_MS / 2)
enum { enum {
KBD_REVISION_OMAP4 = 0, KBD_REVISION_OMAP4 = 0,
@ -71,6 +73,7 @@ struct omap4_keypad {
void __iomem *base; void __iomem *base;
unsigned int irq; unsigned int irq;
struct mutex lock; /* for key scan */
unsigned int rows; unsigned int rows;
unsigned int cols; unsigned int cols;
@ -78,7 +81,7 @@ struct omap4_keypad {
u32 irqreg_offset; u32 irqreg_offset;
unsigned int row_shift; unsigned int row_shift;
bool no_autorepeat; bool no_autorepeat;
unsigned char key_state[8]; u64 keys;
unsigned short *keymap; unsigned short *keymap;
}; };
@ -107,6 +110,55 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
keypad_data->base + keypad_data->irqreg_offset + offset); keypad_data->base + keypad_data->irqreg_offset + offset);
} }
static int omap4_keypad_report_keys(struct omap4_keypad *keypad_data,
u64 keys, bool down)
{
struct input_dev *input_dev = keypad_data->input;
unsigned int col, row, code;
DECLARE_BITMAP(mask, 64);
unsigned long bit;
int events = 0;
bitmap_from_u64(mask, keys);
for_each_set_bit(bit, mask, keypad_data->rows * BITS_PER_BYTE) {
row = bit / BITS_PER_BYTE;
col = bit % BITS_PER_BYTE;
code = MATRIX_SCAN_CODE(row, col, keypad_data->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keypad_data->keymap[code], down);
events++;
}
if (events)
input_sync(input_dev);
return events;
}
static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys)
{
u64 changed;
mutex_lock(&keypad_data->lock);
changed = keys ^ keypad_data->keys;
/*
* Report key up events separately and first. This matters in case we
* lost key-up interrupt and just now catching up.
*/
omap4_keypad_report_keys(keypad_data, changed & ~keys, false);
/* Report key down events */
omap4_keypad_report_keys(keypad_data, changed & keys, true);
keypad_data->keys = keys;
mutex_unlock(&keypad_data->lock);
}
/* Interrupt handlers */ /* Interrupt handlers */
static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id) static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
@ -122,48 +174,44 @@ static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id) static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
{ {
struct omap4_keypad *keypad_data = dev_id; struct omap4_keypad *keypad_data = dev_id;
struct input_dev *input_dev = keypad_data->input; struct device *dev = keypad_data->input->dev.parent;
unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)]; u32 low, high;
unsigned int col, row, code, changed; int error;
u32 *new_state = (u32 *) key_state; u64 keys;
*new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0); error = pm_runtime_get_sync(dev);
*(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32); if (error < 0) {
pm_runtime_put_noidle(dev);
for (row = 0; row < keypad_data->rows; row++) { return IRQ_NONE;
changed = key_state[row] ^ keypad_data->key_state[row];
if (!changed)
continue;
for (col = 0; col < keypad_data->cols; col++) {
if (changed & (1 << col)) {
code = MATRIX_SCAN_CODE(row, col,
keypad_data->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev,
keypad_data->keymap[code],
key_state[row] & (1 << col));
}
}
} }
input_sync(input_dev); low = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
high = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
keys = low | (u64)high << 32;
memcpy(keypad_data->key_state, key_state, omap4_keypad_scan_keys(keypad_data, keys);
sizeof(keypad_data->key_state));
/* clear pending interrupts */ /* clear pending interrupts */
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int omap4_keypad_open(struct input_dev *input) static int omap4_keypad_open(struct input_dev *input)
{ {
struct omap4_keypad *keypad_data = input_get_drvdata(input); struct omap4_keypad *keypad_data = input_get_drvdata(input);
struct device *dev = input->dev.parent;
int error;
pm_runtime_get_sync(input->dev.parent); error = pm_runtime_get_sync(dev);
if (error < 0) {
pm_runtime_put_noidle(dev);
return error;
}
disable_irq(keypad_data->irq); disable_irq(keypad_data->irq);
@ -176,13 +224,15 @@ static int omap4_keypad_open(struct input_dev *input)
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS, kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)); kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE, kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_DEF_IRQENABLE_EVENTEN | OMAP4_DEF_IRQENABLE_EVENTEN);
OMAP4_DEF_IRQENABLE_LONGKEY);
kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE, kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA); OMAP4_DEF_WUP_EVENT_ENA);
enable_irq(keypad_data->irq); enable_irq(keypad_data->irq);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0; return 0;
} }
@ -200,14 +250,20 @@ static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
static void omap4_keypad_close(struct input_dev *input) static void omap4_keypad_close(struct input_dev *input)
{ {
struct omap4_keypad *keypad_data; struct omap4_keypad *keypad_data = input_get_drvdata(input);
struct device *dev = input->dev.parent;
int error;
error = pm_runtime_get_sync(dev);
if (error < 0)
pm_runtime_put_noidle(dev);
keypad_data = input_get_drvdata(input);
disable_irq(keypad_data->irq); disable_irq(keypad_data->irq);
omap4_keypad_stop(keypad_data); omap4_keypad_stop(keypad_data);
enable_irq(keypad_data->irq); enable_irq(keypad_data->irq);
pm_runtime_put_sync(input->dev.parent); pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
} }
static int omap4_keypad_parse_dt(struct device *dev, static int omap4_keypad_parse_dt(struct device *dev,
@ -252,8 +308,41 @@ static int omap4_keypad_check_revision(struct device *dev,
return 0; return 0;
} }
/*
* Errata ID i689 "1.32 Keyboard Key Up Event Can Be Missed".
* Interrupt may not happen for key-up events. We must clear stuck
* key-up events after the keyboard hardware has auto-idled.
*/
static int __maybe_unused omap4_keypad_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
u32 active;
active = kbd_readl(keypad_data, OMAP4_KBD_STATEMACHINE);
if (active) {
pm_runtime_mark_last_busy(dev);
return -EBUSY;
}
omap4_keypad_scan_keys(keypad_data, 0);
return 0;
}
static const struct dev_pm_ops omap4_keypad_pm_ops = {
SET_RUNTIME_PM_OPS(omap4_keypad_runtime_suspend, NULL, NULL)
};
static void omap4_disable_pm(void *d)
{
pm_runtime_dont_use_autosuspend(d);
pm_runtime_disable(d);
}
static int omap4_keypad_probe(struct platform_device *pdev) static int omap4_keypad_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev;
struct omap4_keypad *keypad_data; struct omap4_keypad *keypad_data;
struct input_dev *input_dev; struct input_dev *input_dev;
struct resource *res; struct resource *res;
@ -271,63 +360,62 @@ static int omap4_keypad_probe(struct platform_device *pdev)
if (irq < 0) if (irq < 0)
return irq; return irq;
keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL); keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
if (!keypad_data) { if (!keypad_data) {
dev_err(&pdev->dev, "keypad_data memory allocation failed\n"); dev_err(dev, "keypad_data memory allocation failed\n");
return -ENOMEM; return -ENOMEM;
} }
keypad_data->irq = irq; keypad_data->irq = irq;
mutex_init(&keypad_data->lock);
platform_set_drvdata(pdev, keypad_data);
error = omap4_keypad_parse_dt(&pdev->dev, keypad_data); error = omap4_keypad_parse_dt(dev, keypad_data);
if (error) if (error)
goto err_free_keypad; return error;
res = request_mem_region(res->start, resource_size(res), pdev->name); keypad_data->base = devm_ioremap_resource(dev, res);
if (!res) { if (IS_ERR(keypad_data->base))
dev_err(&pdev->dev, "can't request mem region\n"); return PTR_ERR(keypad_data->base);
error = -EBUSY;
goto err_free_keypad; pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, OMAP4_KEYPAD_IDLE_CHECK_MS);
pm_runtime_enable(dev);
error = devm_add_action_or_reset(dev, omap4_disable_pm, dev);
if (error) {
dev_err(dev, "unable to register cleanup action\n");
return error;
} }
keypad_data->base = ioremap(res->start, resource_size(res));
if (!keypad_data->base) {
dev_err(&pdev->dev, "can't ioremap mem resource\n");
error = -ENOMEM;
goto err_release_mem;
}
pm_runtime_enable(&pdev->dev);
/* /*
* Enable clocks for the keypad module so that we can read * Enable clocks for the keypad module so that we can read
* revision register. * revision register.
*/ */
error = pm_runtime_get_sync(&pdev->dev); error = pm_runtime_get_sync(dev);
if (error) { if (error) {
dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); dev_err(dev, "pm_runtime_get_sync() failed\n");
pm_runtime_put_noidle(&pdev->dev); pm_runtime_put_noidle(dev);
} else { return error;
error = omap4_keypad_check_revision(&pdev->dev, }
keypad_data);
error = omap4_keypad_check_revision(dev, keypad_data);
if (!error) { if (!error) {
/* Ensure device does not raise interrupts */ /* Ensure device does not raise interrupts */
omap4_keypad_stop(keypad_data); omap4_keypad_stop(keypad_data);
} }
pm_runtime_put_sync(&pdev->dev);
} pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (error) if (error)
goto err_pm_disable; return error;
/* input device allocation */ /* input device allocation */
keypad_data->input = input_dev = input_allocate_device(); keypad_data->input = input_dev = devm_input_allocate_device(dev);
if (!input_dev) { if (!input_dev)
error = -ENOMEM; return -ENOMEM;
goto err_pm_disable;
}
input_dev->name = pdev->name; input_dev->name = pdev->name;
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST; input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001; input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001; input_dev->id.product = 0x0001;
@ -344,84 +432,51 @@ static int omap4_keypad_probe(struct platform_device *pdev)
keypad_data->row_shift = get_count_order(keypad_data->cols); keypad_data->row_shift = get_count_order(keypad_data->cols);
max_keys = keypad_data->rows << keypad_data->row_shift; max_keys = keypad_data->rows << keypad_data->row_shift;
keypad_data->keymap = kcalloc(max_keys, keypad_data->keymap = devm_kcalloc(dev,
max_keys,
sizeof(keypad_data->keymap[0]), sizeof(keypad_data->keymap[0]),
GFP_KERNEL); GFP_KERNEL);
if (!keypad_data->keymap) { if (!keypad_data->keymap) {
dev_err(&pdev->dev, "Not enough memory for keymap\n"); dev_err(dev, "Not enough memory for keymap\n");
error = -ENOMEM; return -ENOMEM;
goto err_free_input;
} }
error = matrix_keypad_build_keymap(NULL, NULL, error = matrix_keypad_build_keymap(NULL, NULL,
keypad_data->rows, keypad_data->cols, keypad_data->rows, keypad_data->cols,
keypad_data->keymap, input_dev); keypad_data->keymap, input_dev);
if (error) { if (error) {
dev_err(&pdev->dev, "failed to build keymap\n"); dev_err(dev, "failed to build keymap\n");
goto err_free_keymap; return error;
} }
error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler, error = devm_request_threaded_irq(dev, keypad_data->irq,
omap4_keypad_irq_thread_fn, IRQF_ONESHOT, omap4_keypad_irq_handler,
omap4_keypad_irq_thread_fn,
IRQF_ONESHOT,
"omap4-keypad", keypad_data); "omap4-keypad", keypad_data);
if (error) { if (error) {
dev_err(&pdev->dev, "failed to register interrupt\n"); dev_err(dev, "failed to register interrupt\n");
goto err_free_keymap; return error;
} }
error = input_register_device(keypad_data->input); error = input_register_device(keypad_data->input);
if (error < 0) { if (error) {
dev_err(&pdev->dev, "failed to register input device\n"); dev_err(dev, "failed to register input device\n");
goto err_free_irq; return error;
} }
device_init_wakeup(&pdev->dev, true); device_init_wakeup(dev, true);
error = dev_pm_set_wake_irq(&pdev->dev, keypad_data->irq); error = dev_pm_set_wake_irq(dev, keypad_data->irq);
if (error) if (error)
dev_warn(&pdev->dev, dev_warn(dev, "failed to set up wakeup irq: %d\n", error);
"failed to set up wakeup irq: %d\n", error);
platform_set_drvdata(pdev, keypad_data);
return 0; return 0;
err_free_irq:
free_irq(keypad_data->irq, keypad_data);
err_free_keymap:
kfree(keypad_data->keymap);
err_free_input:
input_free_device(input_dev);
err_pm_disable:
pm_runtime_disable(&pdev->dev);
iounmap(keypad_data->base);
err_release_mem:
release_mem_region(res->start, resource_size(res));
err_free_keypad:
kfree(keypad_data);
return error;
} }
static int omap4_keypad_remove(struct platform_device *pdev) static int omap4_keypad_remove(struct platform_device *pdev)
{ {
struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
struct resource *res;
dev_pm_clear_wake_irq(&pdev->dev); dev_pm_clear_wake_irq(&pdev->dev);
free_irq(keypad_data->irq, keypad_data);
pm_runtime_disable(&pdev->dev);
input_unregister_device(keypad_data->input);
iounmap(keypad_data->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, resource_size(res));
kfree(keypad_data->keymap);
kfree(keypad_data);
return 0; return 0;
} }
@ -437,6 +492,7 @@ static struct platform_driver omap4_keypad_driver = {
.driver = { .driver = {
.name = "omap4-keypad", .name = "omap4-keypad",
.of_match_table = omap_keypad_dt_match, .of_match_table = omap_keypad_dt_match,
.pm = &omap4_keypad_pm_ops,
}, },
}; };
module_platform_driver(omap4_keypad_driver); module_platform_driver(omap4_keypad_driver);

View File

@ -863,6 +863,7 @@ static void da7280_parse_properties(struct device *dev,
gpi_str3[7] = '0' + i; gpi_str3[7] = '0' + i;
haptics->gpi_ctl[i].polarity = 0; haptics->gpi_ctl[i].polarity = 0;
error = device_property_read_string(dev, gpi_str3, &str); error = device_property_read_string(dev, gpi_str3, &str);
if (!error)
haptics->gpi_ctl[i].polarity = haptics->gpi_ctl[i].polarity =
da7280_haptic_of_gpi_pol_str(dev, str); da7280_haptic_of_gpi_pol_str(dev, str);
} }
@ -1299,11 +1300,13 @@ static int __maybe_unused da7280_resume(struct device *dev)
return retval; return retval;
} }
#ifdef CONFIG_OF
static const struct of_device_id da7280_of_match[] = { static const struct of_device_id da7280_of_match[] = {
{ .compatible = "dlg,da7280", }, { .compatible = "dlg,da7280", },
{ } { }
}; };
MODULE_DEVICE_TABLE(of, da7280_of_match); MODULE_DEVICE_TABLE(of, da7280_of_match);
#endif
static const struct i2c_device_id da7280_i2c_id[] = { static const struct i2c_device_id da7280_i2c_id[] = {
{ "da7280", }, { "da7280", },

View File

@ -986,7 +986,7 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
case V7_PACKET_ID_TWO: case V7_PACKET_ID_TWO:
mt[1].x &= ~0x000F; mt[1].x &= ~0x000F;
mt[1].y |= 0x000F; mt[1].y |= 0x000F;
/* Detect false-postive touches where x & y report max value */ /* Detect false-positive touches where x & y report max value */
if (mt[1].y == 0x7ff && mt[1].x == 0xff0) { if (mt[1].y == 0x7ff && mt[1].x == 0xff0) {
mt[1].x = 0; mt[1].x = 0;
/* y gets set to 0 at the end of this function */ /* y gets set to 0 at the end of this function */

View File

@ -1106,8 +1106,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
num_fingers = hw.w + 2; num_fingers = hw.w + 2;
break; break;
case 2: case 2:
if (SYN_MODEL_PEN(info->model_id)) /*
; /* Nothing, treat a pen as a single finger */ * SYN_MODEL_PEN(info->model_id): even if
* the device supports pen, we treat it as
* a single finger.
*/
break; break;
case 4 ... 15: case 4 ... 15:
if (SYN_CAP_PALMDETECT(info->capabilities)) if (SYN_CAP_PALMDETECT(info->capabilities))

View File

@ -255,7 +255,7 @@ config SERIO_ARC_PS2
config SERIO_APBPS2 config SERIO_APBPS2
tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller" tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller"
depends on OF depends on OF && HAS_IOMEM
help help
Say Y here if you want support for GRLIB APBPS2 peripherals used Say Y here if you want support for GRLIB APBPS2 peripherals used
to connect to PS/2 keyboard and/or mouse. to connect to PS/2 keyboard and/or mouse.

View File

@ -588,6 +588,10 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
}, },
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
DMI_MATCH(DMI_CHASSIS_TYPE, "31"), /* Convertible Notebook */
},
}, },
{ } { }
}; };

View File

@ -1036,7 +1036,7 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%dx%d\n", return sysfs_emit(buf, "%dx%d\n",
input_abs_get_max(aiptek->inputdev, ABS_X) + 1, input_abs_get_max(aiptek->inputdev, ABS_X) + 1,
input_abs_get_max(aiptek->inputdev, ABS_Y) + 1); input_abs_get_max(aiptek->inputdev, ABS_Y) + 1);
} }
@ -1064,8 +1064,7 @@ static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribut
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(pointer_mode_map,
map_val_to_str(pointer_mode_map,
aiptek->curSetting.pointerMode)); aiptek->curSetting.pointerMode));
} }
@ -1101,8 +1100,7 @@ static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attri
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(coordinate_mode_map,
map_val_to_str(coordinate_mode_map,
aiptek->curSetting.coordinateMode)); aiptek->curSetting.coordinateMode));
} }
@ -1143,8 +1141,7 @@ static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute *
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(tool_mode_map,
map_val_to_str(tool_mode_map,
aiptek->curSetting.toolMode)); aiptek->curSetting.toolMode));
} }
@ -1174,10 +1171,9 @@ static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *att
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) { if (aiptek->curSetting.xTilt == AIPTEK_TILT_DISABLE) {
return snprintf(buf, PAGE_SIZE, "disable\n"); return sysfs_emit(buf, "disable\n");
} else { } else {
return snprintf(buf, PAGE_SIZE, "%d\n", return sysfs_emit(buf, "%d\n", aiptek->curSetting.xTilt);
aiptek->curSetting.xTilt);
} }
} }
@ -1216,10 +1212,9 @@ static ssize_t show_tabletYtilt(struct device *dev, struct device_attribute *att
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) { if (aiptek->curSetting.yTilt == AIPTEK_TILT_DISABLE) {
return snprintf(buf, PAGE_SIZE, "disable\n"); return sysfs_emit(buf, "disable\n");
} else { } else {
return snprintf(buf, PAGE_SIZE, "%d\n", return sysfs_emit(buf, "%d\n", aiptek->curSetting.yTilt);
aiptek->curSetting.yTilt);
} }
} }
@ -1257,7 +1252,7 @@ static ssize_t show_tabletJitterDelay(struct device *dev, struct device_attribut
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.jitterDelay); return sysfs_emit(buf, "%d\n", aiptek->curSetting.jitterDelay);
} }
static ssize_t static ssize_t
@ -1286,8 +1281,7 @@ static ssize_t show_tabletProgrammableDelay(struct device *dev, struct device_at
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%d\n", return sysfs_emit(buf, "%d\n", aiptek->curSetting.programmableDelay);
aiptek->curSetting.programmableDelay);
} }
static ssize_t static ssize_t
@ -1316,7 +1310,7 @@ static ssize_t show_tabletEventsReceived(struct device *dev, struct device_attri
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%ld\n", aiptek->eventCount); return sysfs_emit(buf, "%ld\n", aiptek->eventCount);
} }
static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL); static DEVICE_ATTR(event_count, S_IRUGO, show_tabletEventsReceived, NULL);
@ -1355,7 +1349,7 @@ static ssize_t show_tabletDiagnosticMessage(struct device *dev, struct device_at
default: default:
return 0; return 0;
} }
return snprintf(buf, PAGE_SIZE, retMsg); return sysfs_emit(buf, retMsg);
} }
static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL); static DEVICE_ATTR(diagnostic, S_IRUGO, show_tabletDiagnosticMessage, NULL);
@ -1375,8 +1369,7 @@ static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribut
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(stylus_button_map,
map_val_to_str(stylus_button_map,
aiptek->curSetting.stylusButtonUpper)); aiptek->curSetting.stylusButtonUpper));
} }
@ -1406,8 +1399,7 @@ static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribut
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(stylus_button_map,
map_val_to_str(stylus_button_map,
aiptek->curSetting.stylusButtonLower)); aiptek->curSetting.stylusButtonLower));
} }
@ -1444,8 +1436,7 @@ static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
map_val_to_str(mouse_button_map,
aiptek->curSetting.mouseButtonLeft)); aiptek->curSetting.mouseButtonLeft));
} }
@ -1474,8 +1465,7 @@ static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribut
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
map_val_to_str(mouse_button_map,
aiptek->curSetting.mouseButtonMiddle)); aiptek->curSetting.mouseButtonMiddle));
} }
@ -1504,8 +1494,7 @@ static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%s\n", return sysfs_emit(buf, "%s\n", map_val_to_str(mouse_button_map,
map_val_to_str(mouse_button_map,
aiptek->curSetting.mouseButtonRight)); aiptek->curSetting.mouseButtonRight));
} }
@ -1535,10 +1524,9 @@ static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *att
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) { if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) {
return snprintf(buf, PAGE_SIZE, "disable\n"); return sysfs_emit(buf, "disable\n");
} else { } else {
return snprintf(buf, PAGE_SIZE, "%d\n", return sysfs_emit(buf, "%d\n", aiptek->curSetting.wheel);
aiptek->curSetting.wheel);
} }
} }
@ -1568,8 +1556,7 @@ static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *a
/* There is nothing useful to display, so a one-line manual /* There is nothing useful to display, so a one-line manual
* is in order... * is in order...
*/ */
return snprintf(buf, PAGE_SIZE, return sysfs_emit(buf, "Write anything to this file to program your tablet.\n");
"Write anything to this file to program your tablet.\n");
} }
static ssize_t static ssize_t
@ -1600,7 +1587,7 @@ static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *a
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode); return sysfs_emit(buf, "0x%04x\n", aiptek->features.odmCode);
} }
static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL); static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);
@ -1613,7 +1600,7 @@ static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode); return sysfs_emit(buf, "0x%04x\n", aiptek->features.modelCode);
} }
static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL); static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);
@ -1626,8 +1613,7 @@ static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *at
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%04x\n", return sysfs_emit(buf, "%04x\n", aiptek->features.firmwareCode);
aiptek->features.firmwareCode);
} }
static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL); static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);

View File

@ -608,7 +608,7 @@ config TOUCHSCREEN_MTOUCH
config TOUCHSCREEN_IMX6UL_TSC config TOUCHSCREEN_IMX6UL_TSC
tristate "Freescale i.MX6UL touchscreen controller" tristate "Freescale i.MX6UL touchscreen controller"
depends on (OF && GPIOLIB) || COMPILE_TEST depends on ((OF && GPIOLIB) || COMPILE_TEST) && HAS_IOMEM
help help
Say Y here if you have a Freescale i.MX6UL, and want to Say Y here if you have a Freescale i.MX6UL, and want to
use the internal touchscreen controller. use the internal touchscreen controller.

View File

@ -64,24 +64,13 @@
struct ads7846_buf { struct ads7846_buf {
u8 cmd; u8 cmd;
/* __be16 data;
* This union is a temporary hack. The driver does an in-place
* endianness conversion. This will be cleaned up in the next
* patch.
*/
union {
__be16 data_be16;
u16 data;
};
} __packed; } __packed;
struct ads7846_buf_layout {
struct ts_event { unsigned int offset;
bool ignore; unsigned int count;
struct ads7846_buf x; unsigned int skip;
struct ads7846_buf y;
struct ads7846_buf z1;
struct ads7846_buf z2;
}; };
/* /*
@ -90,12 +79,18 @@ struct ts_event {
* systems where main memory is not DMA-coherent (most non-x86 boards). * systems where main memory is not DMA-coherent (most non-x86 boards).
*/ */
struct ads7846_packet { struct ads7846_packet {
struct ts_event tc; unsigned int count;
struct ads7846_buf read_x_cmd; unsigned int count_skip;
struct ads7846_buf read_y_cmd; unsigned int cmds;
struct ads7846_buf read_z1_cmd; unsigned int last_cmd_idx;
struct ads7846_buf read_z2_cmd; struct ads7846_buf_layout l[5];
struct ads7846_buf *rx;
struct ads7846_buf *tx;
struct ads7846_buf pwrdown_cmd; struct ads7846_buf pwrdown_cmd;
bool ignore;
u16 x, y, z1, z2;
}; };
struct ads7846 { struct ads7846 {
@ -194,7 +189,6 @@ struct ads7846 {
#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref)) #define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref)) #define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref)) #define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref)) #define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */ #define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
@ -207,6 +201,21 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1)) #define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_OFF (READ_12BIT_DFR(y, 0, 0)) #define REF_OFF (READ_12BIT_DFR(y, 0, 0))
/* Order commands in the most optimal way to reduce Vref switching and
* settling time:
* Measure: X; Vref: X+, X-; IN: Y+
* Measure: Y; Vref: Y+, Y-; IN: X+
* Measure: Z1; Vref: Y+, X-; IN: X+
* Measure: Z2; Vref: Y+, X-; IN: Y-
*/
enum ads7846_cmds {
ADS7846_X,
ADS7846_Y,
ADS7846_Z1,
ADS7846_Z2,
ADS7846_PWDOWN,
};
static int get_pendown_state(struct ads7846 *ts) static int get_pendown_state(struct ads7846 *ts)
{ {
if (ts->get_pendown_state) if (ts->get_pendown_state)
@ -689,26 +698,109 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
return ADS7846_FILTER_OK; return ADS7846_FILTER_OK;
} }
static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m) static int ads7846_get_value(struct ads7846_buf *buf)
{ {
int value; int value;
struct spi_transfer *t =
list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
struct ads7846_buf *buf = t->rx_buf;
value = be16_to_cpup(&buf->data_be16); value = be16_to_cpup(&buf->data);
/* enforce ADC output is 12 bits width */ /* enforce ADC output is 12 bits width */
return (value >> 3) & 0xfff; return (value >> 3) & 0xfff;
} }
static void ads7846_update_value(struct spi_message *m, int val) static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx,
u16 val)
{ {
struct spi_transfer *t = struct ads7846_packet *packet = ts->packet;
list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
struct ads7846_buf *buf = t->rx_buf;
buf->data = val; switch (cmd_idx) {
case ADS7846_Y:
packet->y = val;
break;
case ADS7846_X:
packet->x = val;
break;
case ADS7846_Z1:
packet->z1 = val;
break;
case ADS7846_Z2:
packet->z2 = val;
break;
default:
WARN_ON_ONCE(1);
}
}
static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref)
{
switch (cmd_idx) {
case ADS7846_Y:
return READ_Y(vref);
case ADS7846_X:
return READ_X(vref);
/* 7846 specific commands */
case ADS7846_Z1:
return READ_Z1(vref);
case ADS7846_Z2:
return READ_Z2(vref);
case ADS7846_PWDOWN:
return PWRDOWN;
default:
WARN_ON_ONCE(1);
}
return 0;
}
static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)
{
switch (cmd_idx) {
case ADS7846_X:
case ADS7846_Y:
case ADS7846_Z1:
case ADS7846_Z2:
return true;
case ADS7846_PWDOWN:
return false;
default:
WARN_ON_ONCE(1);
}
return false;
}
static int ads7846_filter(struct ads7846 *ts)
{
struct ads7846_packet *packet = ts->packet;
int action;
int val;
unsigned int cmd_idx, b;
packet->ignore = false;
for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) {
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
packet->last_cmd_idx = cmd_idx;
for (b = l->skip; b < l->count; b++) {
val = ads7846_get_value(&packet->rx[l->offset + b]);
action = ts->filter(ts->filter_data, cmd_idx, &val);
if (action == ADS7846_FILTER_REPEAT) {
if (b == l->count - 1)
return -EAGAIN;
} else if (action == ADS7846_FILTER_OK) {
ads7846_set_cmd_val(ts, cmd_idx, val);
break;
} else {
packet->ignore = true;
return 0;
}
}
}
return 0;
} }
static void ads7846_read_state(struct ads7846 *ts) static void ads7846_read_state(struct ads7846 *ts)
@ -716,52 +808,26 @@ static void ads7846_read_state(struct ads7846 *ts)
struct ads7846_packet *packet = ts->packet; struct ads7846_packet *packet = ts->packet;
struct spi_message *m; struct spi_message *m;
int msg_idx = 0; int msg_idx = 0;
int val;
int action;
int error; int error;
while (msg_idx < ts->msg_count) { packet->last_cmd_idx = 0;
while (true) {
ts->wait_for_sync(); ts->wait_for_sync();
m = &ts->msg[msg_idx]; m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m); error = spi_sync(ts->spi, m);
if (error) { if (error) {
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error); dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
packet->tc.ignore = true; packet->ignore = true;
return; return;
} }
/* error = ads7846_filter(ts);
* Last message is power down request, no need to convert if (error)
* or filter the value.
*/
if (msg_idx < ts->msg_count - 1) {
val = ads7846_get_value(ts, m);
action = ts->filter(ts->filter_data, msg_idx, &val);
switch (action) {
case ADS7846_FILTER_REPEAT:
continue; continue;
case ADS7846_FILTER_IGNORE: return;
packet->tc.ignore = true;
msg_idx = ts->msg_count - 1;
continue;
case ADS7846_FILTER_OK:
ads7846_update_value(m, val);
packet->tc.ignore = false;
msg_idx++;
break;
default:
BUG();
}
} else {
msg_idx++;
}
} }
} }
@ -771,19 +837,14 @@ static void ads7846_report_state(struct ads7846 *ts)
unsigned int Rt; unsigned int Rt;
u16 x, y, z1, z2; u16 x, y, z1, z2;
/* x = packet->x;
* ads7846_get_value() does in-place conversion (including byte swap) y = packet->y;
* from on-the-wire format as part of debouncing to get stable
* readings.
*/
x = packet->tc.x.data;
y = packet->tc.y.data;
if (ts->model == 7845) { if (ts->model == 7845) {
z1 = 0; z1 = 0;
z2 = 0; z2 = 0;
} else { } else {
z1 = packet->tc.z1.data; z1 = packet->z1;
z2 = packet->tc.z2.data; z2 = packet->z2;
} }
/* range filtering */ /* range filtering */
@ -816,9 +877,9 @@ static void ads7846_report_state(struct ads7846 *ts)
* the maximum. Don't report it to user space, repeat at least * the maximum. Don't report it to user space, repeat at least
* once more the measurement * once more the measurement
*/ */
if (packet->tc.ignore || Rt > ts->pressure_max) { if (packet->ignore || Rt > ts->pressure_max) {
dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n", dev_vdbg(&ts->spi->dev, "ignored %d pressure %d\n",
packet->tc.ignore, Rt); packet->ignore, Rt);
return; return;
} }
@ -979,13 +1040,59 @@ static int ads7846_setup_pendown(struct spi_device *spi,
* Set up the transfers to read touchscreen state; this assumes we * Set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3. * use formula #2 for pressure, not #3.
*/ */
static void ads7846_setup_spi_msg(struct ads7846 *ts, static int ads7846_setup_spi_msg(struct ads7846 *ts,
const struct ads7846_platform_data *pdata) const struct ads7846_platform_data *pdata)
{ {
struct spi_message *m = &ts->msg[0]; struct spi_message *m = &ts->msg[0];
struct spi_transfer *x = ts->xfer; struct spi_transfer *x = ts->xfer;
struct ads7846_packet *packet = ts->packet; struct ads7846_packet *packet = ts->packet;
int vref = pdata->keep_vref_on; int vref = pdata->keep_vref_on;
unsigned int count, offset = 0;
unsigned int cmd_idx, b;
unsigned long time;
size_t size = 0;
/* time per bit */
time = NSEC_PER_SEC / ts->spi->max_speed_hz;
count = pdata->settle_delay_usecs * NSEC_PER_USEC / time;
packet->count_skip = DIV_ROUND_UP(count, 24);
if (ts->debounce_max && ts->debounce_rep)
/* ads7846_debounce_filter() is making ts->debounce_rep + 2
* reads. So we need to get all samples for normal case. */
packet->count = ts->debounce_rep + 2;
else
packet->count = 1;
if (ts->model == 7846)
packet->cmds = 5; /* x, y, z1, z2, pwdown */
else
packet->cmds = 3; /* x, y, pwdown */
for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
unsigned int max_count;
if (ads7846_cmd_need_settle(cmd_idx))
max_count = packet->count + packet->count_skip;
else
max_count = packet->count;
l->offset = offset;
offset += max_count;
l->count = max_count;
l->skip = packet->count_skip;
size += sizeof(*packet->tx) * max_count;
}
packet->tx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
if (!packet->tx)
return -ENOMEM;
packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
if (!packet->rx)
return -ENOMEM;
if (ts->model == 7873) { if (ts->model == 7873) {
/* /*
@ -1001,117 +1108,20 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
spi_message_init(m); spi_message_init(m);
m->context = ts; m->context = ts;
packet->read_y_cmd.cmd = READ_Y(vref); for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
x->tx_buf = &packet->read_y_cmd; struct ads7846_buf_layout *l = &packet->l[cmd_idx];
x->rx_buf = &packet->tc.y; u8 cmd = ads7846_get_cmd(cmd_idx, vref);
x->len = 3;
spi_message_add_tail(x, m);
/* for (b = 0; b < l->count; b++)
* The first sample after switching drivers can be low quality; packet->tx[l->offset + b].cmd = cmd;
* optionally discard it, using a second one after the signals
* have had enough time to stabilize.
*/
if (pdata->settle_delay_usecs) {
x->delay.value = pdata->settle_delay_usecs;
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
x->tx_buf = &packet->read_y_cmd;
x->rx_buf = &packet->tc.y;
x->len = 3;
spi_message_add_tail(x, m);
} }
ts->msg_count++; x->tx_buf = packet->tx;
m++; x->rx_buf = packet->rx;
spi_message_init(m); x->len = size;
m->context = ts;
/* turn y- off, x+ on, then leave in lowpower */
x++;
packet->read_x_cmd.cmd = READ_X(vref);
x->tx_buf = &packet->read_x_cmd;
x->rx_buf = &packet->tc.x;
x->len = 3;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
/* ... maybe discard first sample ... */ return 0;
if (pdata->settle_delay_usecs) {
x->delay.value = pdata->settle_delay_usecs;
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
x->tx_buf = &packet->read_x_cmd;
x->rx_buf = &packet->tc.x;
x->len = 3;
spi_message_add_tail(x, m);
}
/* turn y+ off, x- on; we'll use formula #2 */
if (ts->model == 7846) {
ts->msg_count++;
m++;
spi_message_init(m);
m->context = ts;
x++;
packet->read_z1_cmd.cmd = READ_Z1(vref);
x->tx_buf = &packet->read_z1_cmd;
x->rx_buf = &packet->tc.z1;
x->len = 3;
spi_message_add_tail(x, m);
/* ... maybe discard first sample ... */
if (pdata->settle_delay_usecs) {
x->delay.value = pdata->settle_delay_usecs;
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
x->tx_buf = &packet->read_z1_cmd;
x->rx_buf = &packet->tc.z1;
x->len = 3;
spi_message_add_tail(x, m);
}
ts->msg_count++;
m++;
spi_message_init(m);
m->context = ts;
x++;
packet->read_z2_cmd.cmd = READ_Z2(vref);
x->tx_buf = &packet->read_z2_cmd;
x->rx_buf = &packet->tc.z2;
x->len = 3;
spi_message_add_tail(x, m);
/* ... maybe discard first sample ... */
if (pdata->settle_delay_usecs) {
x->delay.value = pdata->settle_delay_usecs;
x->delay.unit = SPI_DELAY_UNIT_USECS;
x++;
x->tx_buf = &packet->read_z2_cmd;
x->rx_buf = &packet->tc.z2;
x->len = 3;
spi_message_add_tail(x, m);
}
}
/* power down */
ts->msg_count++;
m++;
spi_message_init(m);
m->context = ts;
x++;
packet->pwrdown_cmd.cmd = PWRDOWN;
x->tx_buf = &packet->pwrdown_cmd;
x->len = 3;
CS_CHANGE(*x);
spi_message_add_tail(x, m);
} }
#ifdef CONFIG_OF #ifdef CONFIG_OF

View File

@ -56,6 +56,7 @@
#define QUEUE_HEADER_SINGLE 0x62 #define QUEUE_HEADER_SINGLE 0x62
#define QUEUE_HEADER_NORMAL 0X63 #define QUEUE_HEADER_NORMAL 0X63
#define QUEUE_HEADER_WAIT 0x64 #define QUEUE_HEADER_WAIT 0x64
#define QUEUE_HEADER_NORMAL2 0x66
/* Command header definition */ /* Command header definition */
#define CMD_HEADER_WRITE 0x54 #define CMD_HEADER_WRITE 0x54
@ -69,6 +70,7 @@
#define CMD_HEADER_REK 0x66 #define CMD_HEADER_REK 0x66
/* FW position data */ /* FW position data */
#define PACKET_SIZE_OLD 40
#define PACKET_SIZE 55 #define PACKET_SIZE 55
#define MAX_CONTACT_NUM 10 #define MAX_CONTACT_NUM 10
#define FW_POS_HEADER 0 #define FW_POS_HEADER 0
@ -90,6 +92,8 @@
/* FW read command, 0x53 0x?? 0x0, 0x01 */ /* FW read command, 0x53 0x?? 0x0, 0x01 */
#define E_ELAN_INFO_FW_VER 0x00 #define E_ELAN_INFO_FW_VER 0x00
#define E_ELAN_INFO_BC_VER 0x10 #define E_ELAN_INFO_BC_VER 0x10
#define E_ELAN_INFO_X_RES 0x60
#define E_ELAN_INFO_Y_RES 0x63
#define E_ELAN_INFO_REK 0xD0 #define E_ELAN_INFO_REK 0xD0
#define E_ELAN_INFO_TEST_VER 0xE0 #define E_ELAN_INFO_TEST_VER 0xE0
#define E_ELAN_INFO_FW_ID 0xF0 #define E_ELAN_INFO_FW_ID 0xF0
@ -112,6 +116,11 @@
#define ELAN_POWERON_DELAY_USEC 500 #define ELAN_POWERON_DELAY_USEC 500
#define ELAN_RESET_DELAY_MSEC 20 #define ELAN_RESET_DELAY_MSEC 20
enum elants_chip_id {
EKTH3500,
EKTF3624,
};
enum elants_state { enum elants_state {
ELAN_STATE_NORMAL, ELAN_STATE_NORMAL,
ELAN_WAIT_QUEUE_HEADER, ELAN_WAIT_QUEUE_HEADER,
@ -143,9 +152,12 @@ struct elants_data {
unsigned int y_res; unsigned int y_res;
unsigned int x_max; unsigned int x_max;
unsigned int y_max; unsigned int y_max;
unsigned int phy_x;
unsigned int phy_y;
struct touchscreen_properties prop; struct touchscreen_properties prop;
enum elants_state state; enum elants_state state;
enum elants_chip_id chip_id;
enum elants_iap_mode iap_mode; enum elants_iap_mode iap_mode;
/* Guards against concurrent access to the device via sysfs */ /* Guards against concurrent access to the device via sysfs */
@ -433,7 +445,51 @@ static int elants_i2c_query_bc_version(struct elants_data *ts)
return 0; return 0;
} }
static int elants_i2c_query_ts_info(struct elants_data *ts) static int elants_i2c_query_ts_info_ektf(struct elants_data *ts)
{
struct i2c_client *client = ts->client;
int error;
u8 resp[4];
u16 phy_x, phy_y;
const u8 get_xres_cmd[] = {
CMD_HEADER_READ, E_ELAN_INFO_X_RES, 0x00, 0x00
};
const u8 get_yres_cmd[] = {
CMD_HEADER_READ, E_ELAN_INFO_Y_RES, 0x00, 0x00
};
/* Get X/Y size in mm */
error = elants_i2c_execute_command(client, get_xres_cmd,
sizeof(get_xres_cmd),
resp, sizeof(resp), 1,
"get X size");
if (error)
return error;
phy_x = resp[2] | ((resp[3] & 0xF0) << 4);
error = elants_i2c_execute_command(client, get_yres_cmd,
sizeof(get_yres_cmd),
resp, sizeof(resp), 1,
"get Y size");
if (error)
return error;
phy_y = resp[2] | ((resp[3] & 0xF0) << 4);
dev_dbg(&client->dev, "phy_x=%d, phy_y=%d\n", phy_x, phy_y);
ts->phy_x = phy_x;
ts->phy_y = phy_y;
/* eKTF doesn't report max size, set it to default values */
ts->x_max = 2240 - 1;
ts->y_max = 1408 - 1;
return 0;
}
static int elants_i2c_query_ts_info_ekth(struct elants_data *ts)
{ {
struct i2c_client *client = ts->client; struct i2c_client *client = ts->client;
int error; int error;
@ -508,6 +564,8 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x); ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x);
ts->y_max = ELAN_TS_RESOLUTION(cols, osr); ts->y_max = ELAN_TS_RESOLUTION(cols, osr);
ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y); ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y);
ts->phy_x = phy_x;
ts->phy_y = phy_y;
} }
return 0; return 0;
@ -587,8 +645,19 @@ static int elants_i2c_initialize(struct elants_data *ts)
error = elants_i2c_query_fw_version(ts); error = elants_i2c_query_fw_version(ts);
if (!error) if (!error)
error = elants_i2c_query_test_version(ts); error = elants_i2c_query_test_version(ts);
switch (ts->chip_id) {
case EKTH3500:
if (!error) if (!error)
error = elants_i2c_query_ts_info(ts); error = elants_i2c_query_ts_info_ekth(ts);
break;
case EKTF3624:
if (!error)
error = elants_i2c_query_ts_info_ektf(ts);
break;
default:
BUG();
}
if (error) if (error)
ts->iap_mode = ELAN_IAP_RECOVERY; ts->iap_mode = ELAN_IAP_RECOVERY;
@ -853,7 +922,8 @@ out:
* Event reporting. * Event reporting.
*/ */
static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf) static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf,
size_t packet_size)
{ {
struct input_dev *input = ts->input; struct input_dev *input = ts->input;
unsigned int n_fingers; unsigned int n_fingers;
@ -880,8 +950,24 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
pos = &buf[FW_POS_XY + i * 3]; pos = &buf[FW_POS_XY + i * 3];
x = (((u16)pos[0] & 0xf0) << 4) | pos[1]; x = (((u16)pos[0] & 0xf0) << 4) | pos[1];
y = (((u16)pos[0] & 0x0f) << 8) | pos[2]; y = (((u16)pos[0] & 0x0f) << 8) | pos[2];
/*
* eKTF3624 may have use "old" touch-report format,
* depending on a device and TS firmware version.
* For example, ASUS Transformer devices use the "old"
* format, while ASUS Nexus 7 uses the "new" formant.
*/
if (packet_size == PACKET_SIZE_OLD &&
ts->chip_id == EKTF3624) {
w = buf[FW_POS_WIDTH + i / 2];
w >>= 4 * (~i & 1);
w |= w << 4;
w |= !w;
p = w;
} else {
p = buf[FW_POS_PRESSURE + i]; p = buf[FW_POS_PRESSURE + i];
w = buf[FW_POS_WIDTH + i]; w = buf[FW_POS_WIDTH + i];
}
dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n", dev_dbg(&ts->client->dev, "i=%d x=%d y=%d p=%d w=%d\n",
i, x, y, p, w); i, x, y, p, w);
@ -913,7 +999,8 @@ static u8 elants_i2c_calculate_checksum(u8 *buf)
return checksum; return checksum;
} }
static void elants_i2c_event(struct elants_data *ts, u8 *buf) static void elants_i2c_event(struct elants_data *ts, u8 *buf,
size_t packet_size)
{ {
u8 checksum = elants_i2c_calculate_checksum(buf); u8 checksum = elants_i2c_calculate_checksum(buf);
@ -927,7 +1014,7 @@ static void elants_i2c_event(struct elants_data *ts, u8 *buf)
"%s: unknown packet type: %02x\n", "%s: unknown packet type: %02x\n",
__func__, buf[FW_POS_HEADER]); __func__, buf[FW_POS_HEADER]);
else else
elants_i2c_mt_event(ts, buf); elants_i2c_mt_event(ts, buf, packet_size);
} }
static irqreturn_t elants_i2c_irq(int irq, void *_dev) static irqreturn_t elants_i2c_irq(int irq, void *_dev)
@ -970,7 +1057,6 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
switch (ts->buf[FW_HDR_TYPE]) { switch (ts->buf[FW_HDR_TYPE]) {
case CMD_HEADER_HELLO: case CMD_HEADER_HELLO:
case CMD_HEADER_RESP: case CMD_HEADER_RESP:
case CMD_HEADER_REK:
break; break;
case QUEUE_HEADER_WAIT: case QUEUE_HEADER_WAIT:
@ -985,9 +1071,24 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
break; break;
case QUEUE_HEADER_SINGLE: case QUEUE_HEADER_SINGLE:
elants_i2c_event(ts, &ts->buf[HEADER_SIZE]); elants_i2c_event(ts, &ts->buf[HEADER_SIZE],
ts->buf[FW_HDR_LENGTH]);
break; break;
case QUEUE_HEADER_NORMAL2: /* CMD_HEADER_REK */
/*
* Depending on firmware version, eKTF3624 touchscreens
* may utilize one of these opcodes for the touch events:
* 0x63 (NORMAL) and 0x66 (NORMAL2). The 0x63 is used by
* older firmware version and differs from 0x66 such that
* touch pressure value needs to be adjusted. The 0x66
* opcode of newer firmware is equal to 0x63 of eKTH3500.
*/
if (ts->chip_id != EKTF3624)
break;
fallthrough;
case QUEUE_HEADER_NORMAL: case QUEUE_HEADER_NORMAL:
report_count = ts->buf[FW_HDR_COUNT]; report_count = ts->buf[FW_HDR_COUNT];
if (report_count == 0 || report_count > 3) { if (report_count == 0 || report_count > 3) {
@ -998,7 +1099,12 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
} }
report_len = ts->buf[FW_HDR_LENGTH] / report_count; report_len = ts->buf[FW_HDR_LENGTH] / report_count;
if (report_len != PACKET_SIZE) {
if (report_len == PACKET_SIZE_OLD &&
ts->chip_id == EKTF3624) {
dev_dbg_once(&client->dev,
"using old report format\n");
} else if (report_len != PACKET_SIZE) {
dev_err(&client->dev, dev_err(&client->dev,
"mismatching report length: %*ph\n", "mismatching report length: %*ph\n",
HEADER_SIZE, ts->buf); HEADER_SIZE, ts->buf);
@ -1007,8 +1113,8 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
for (i = 0; i < report_count; i++) { for (i = 0; i < report_count; i++) {
u8 *buf = ts->buf + HEADER_SIZE + u8 *buf = ts->buf + HEADER_SIZE +
i * PACKET_SIZE; i * report_len;
elants_i2c_event(ts, buf); elants_i2c_event(ts, buf, report_len);
} }
break; break;
@ -1250,6 +1356,7 @@ static int elants_i2c_probe(struct i2c_client *client,
init_completion(&ts->cmd_done); init_completion(&ts->cmd_done);
ts->client = client; ts->client = client;
ts->chip_id = (enum elants_chip_id)id->driver_data;
i2c_set_clientdata(client, ts); i2c_set_clientdata(client, ts);
ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
@ -1331,13 +1438,20 @@ static int elants_i2c_probe(struct i2c_client *client,
input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0); input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE, input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE,
0, MT_TOOL_PALM, 0, 0); 0, MT_TOOL_PALM, 0, 0);
touchscreen_parse_properties(ts->input, true, &ts->prop);
if (ts->chip_id == EKTF3624) {
/* calculate resolution from size */
ts->x_res = DIV_ROUND_CLOSEST(ts->prop.max_x, ts->phy_x);
ts->y_res = DIV_ROUND_CLOSEST(ts->prop.max_y, ts->phy_y);
}
input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res);
input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
if (ts->major_res > 0) if (ts->major_res > 0)
input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res); input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res);
touchscreen_parse_properties(ts->input, true, &ts->prop);
error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM, error = input_mt_init_slots(ts->input, MAX_CONTACT_NUM,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) { if (error) {
@ -1466,14 +1580,16 @@ static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
elants_i2c_suspend, elants_i2c_resume); elants_i2c_suspend, elants_i2c_resume);
static const struct i2c_device_id elants_i2c_id[] = { static const struct i2c_device_id elants_i2c_id[] = {
{ DEVICE_NAME, 0 }, { DEVICE_NAME, EKTH3500 },
{ "ekth3500", EKTH3500 },
{ "ektf3624", EKTF3624 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, elants_i2c_id); MODULE_DEVICE_TABLE(i2c, elants_i2c_id);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id elants_acpi_id[] = { static const struct acpi_device_id elants_acpi_id[] = {
{ "ELAN0001", 0 }, { "ELAN0001", EKTH3500 },
{ } { }
}; };
MODULE_DEVICE_TABLE(acpi, elants_acpi_id); MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
@ -1482,6 +1598,7 @@ MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id elants_of_match[] = { static const struct of_device_id elants_of_match[] = {
{ .compatible = "elan,ekth3500" }, { .compatible = "elan,ekth3500" },
{ .compatible = "elan,ektf3624" },
{ /* sentinel */ } { /* sentinel */ }
}; };
MODULE_DEVICE_TABLE(of, elants_of_match); MODULE_DEVICE_TABLE(of, elants_of_match);

View File

@ -341,8 +341,10 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
switch (elo->id) { switch (elo->id) {
case 0: /* 10-byte protocol */ case 0: /* 10-byte protocol */
if (elo_setup_10(elo)) if (elo_setup_10(elo)) {
err = -EIO;
goto fail3; goto fail3;
}
break; break;

View File

@ -2,8 +2,7 @@
/* /*
* Azoteq IQS550/572/525 Trackpad/Touchscreen Controller * Azoteq IQS550/572/525 Trackpad/Touchscreen Controller
* *
* Copyright (C) 2018 * Copyright (C) 2018 Jeff LaBundy <jeff@labundy.com>
* Author: Jeff LaBundy <jeff@labundy.com>
* *
* These devices require firmware exported from a PC-based configuration tool * These devices require firmware exported from a PC-based configuration tool
* made available by the vendor. Firmware files may be pushed to the device's * made available by the vendor. Firmware files may be pushed to the device's
@ -12,6 +11,7 @@
* Link to PC-based configuration tool and data sheet: http://www.azoteq.com/ * Link to PC-based configuration tool and data sheet: http://www.azoteq.com/
*/ */
#include <linux/bits.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/err.h> #include <linux/err.h>
@ -30,9 +30,9 @@
#define IQS5XX_FW_FILE_LEN 64 #define IQS5XX_FW_FILE_LEN 64
#define IQS5XX_NUM_RETRIES 10 #define IQS5XX_NUM_RETRIES 10
#define IQS5XX_NUM_POINTS 256
#define IQS5XX_NUM_CONTACTS 5 #define IQS5XX_NUM_CONTACTS 5
#define IQS5XX_WR_BYTES_MAX 2 #define IQS5XX_WR_BYTES_MAX 2
#define IQS5XX_XY_RES_MAX 0xFFFE
#define IQS5XX_PROD_NUM_IQS550 40 #define IQS5XX_PROD_NUM_IQS550 40
#define IQS5XX_PROD_NUM_IQS572 58 #define IQS5XX_PROD_NUM_IQS572 58
@ -41,28 +41,27 @@
#define IQS5XX_PROJ_NUM_B000 15 #define IQS5XX_PROJ_NUM_B000 15
#define IQS5XX_MAJOR_VER_MIN 2 #define IQS5XX_MAJOR_VER_MIN 2
#define IQS5XX_RESUME 0x00 #define IQS5XX_SHOW_RESET BIT(7)
#define IQS5XX_SUSPEND 0x01 #define IQS5XX_ACK_RESET BIT(7)
#define IQS5XX_SW_INPUT_EVENT 0x10 #define IQS5XX_SUSPEND BIT(0)
#define IQS5XX_SETUP_COMPLETE 0x40 #define IQS5XX_RESUME 0
#define IQS5XX_EVENT_MODE 0x01
#define IQS5XX_TP_EVENT 0x04
#define IQS5XX_FLIP_X 0x01 #define IQS5XX_SETUP_COMPLETE BIT(6)
#define IQS5XX_FLIP_Y 0x02 #define IQS5XX_WDT BIT(5)
#define IQS5XX_SWITCH_XY_AXIS 0x04 #define IQS5XX_ALP_REATI BIT(3)
#define IQS5XX_REATI BIT(2)
#define IQS5XX_TP_EVENT BIT(2)
#define IQS5XX_EVENT_MODE BIT(0)
#define IQS5XX_PROD_NUM 0x0000 #define IQS5XX_PROD_NUM 0x0000
#define IQS5XX_ABS_X 0x0016 #define IQS5XX_SYS_INFO0 0x000F
#define IQS5XX_ABS_Y 0x0018 #define IQS5XX_SYS_INFO1 0x0010
#define IQS5XX_SYS_CTRL0 0x0431 #define IQS5XX_SYS_CTRL0 0x0431
#define IQS5XX_SYS_CTRL1 0x0432 #define IQS5XX_SYS_CTRL1 0x0432
#define IQS5XX_SYS_CFG0 0x058E #define IQS5XX_SYS_CFG0 0x058E
#define IQS5XX_SYS_CFG1 0x058F #define IQS5XX_SYS_CFG1 0x058F
#define IQS5XX_TOTAL_RX 0x063D
#define IQS5XX_TOTAL_TX 0x063E
#define IQS5XX_XY_CFG0 0x0669
#define IQS5XX_X_RES 0x066E #define IQS5XX_X_RES 0x066E
#define IQS5XX_Y_RES 0x0670 #define IQS5XX_Y_RES 0x0670
#define IQS5XX_CHKSM 0x83C0 #define IQS5XX_CHKSM 0x83C0
@ -99,6 +98,7 @@ struct iqs5xx_private {
struct i2c_client *client; struct i2c_client *client;
struct input_dev *input; struct input_dev *input;
struct gpio_desc *reset_gpio; struct gpio_desc *reset_gpio;
struct touchscreen_properties prop;
struct mutex lock; struct mutex lock;
u8 bl_status; u8 bl_status;
}; };
@ -126,6 +126,14 @@ struct iqs5xx_touch_data {
u8 area; u8 area;
} __packed; } __packed;
struct iqs5xx_status {
u8 sys_info[2];
u8 num_active;
__be16 rel_x;
__be16 rel_y;
struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS];
} __packed;
static int iqs5xx_read_burst(struct i2c_client *client, static int iqs5xx_read_burst(struct i2c_client *client,
u16 reg, void *val, u16 len) u16 reg, void *val, u16 len)
{ {
@ -182,11 +190,6 @@ static int iqs5xx_read_word(struct i2c_client *client, u16 reg, u16 *val)
return 0; return 0;
} }
static int iqs5xx_read_byte(struct i2c_client *client, u16 reg, u8 *val)
{
return iqs5xx_read_burst(client, reg, val, sizeof(*val));
}
static int iqs5xx_write_burst(struct i2c_client *client, static int iqs5xx_write_burst(struct i2c_client *client,
u16 reg, const void *val, u16 len) u16 reg, const void *val, u16 len)
{ {
@ -337,10 +340,15 @@ static int iqs5xx_bl_open(struct i2c_client *client)
*/ */
for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) { for (i = 0; i < IQS5XX_BL_ATTEMPTS; i++) {
iqs5xx_reset(client); iqs5xx_reset(client);
usleep_range(350, 400);
for (j = 0; j < IQS5XX_NUM_RETRIES; j++) { for (j = 0; j < IQS5XX_NUM_RETRIES; j++) {
error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0); error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_VER, 0);
if (!error || error == -EINVAL) if (!error)
usleep_range(10000, 10100);
else if (error != -EINVAL)
continue;
return error; return error;
} }
} }
@ -481,12 +489,10 @@ static void iqs5xx_close(struct input_dev *input)
static int iqs5xx_axis_init(struct i2c_client *client) static int iqs5xx_axis_init(struct i2c_client *client)
{ {
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
struct touchscreen_properties prop; struct touchscreen_properties *prop = &iqs5xx->prop;
struct input_dev *input; struct input_dev *input;
u16 max_x, max_y;
int error; int error;
u16 max_x, max_x_hw;
u16 max_y, max_y_hw;
u8 val;
if (!iqs5xx->input) { if (!iqs5xx->input) {
input = devm_input_allocate_device(&client->dev); input = devm_input_allocate_device(&client->dev);
@ -506,88 +512,38 @@ static int iqs5xx_axis_init(struct i2c_client *client)
iqs5xx->input = input; iqs5xx->input = input;
} }
touchscreen_parse_properties(iqs5xx->input, true, &prop);
error = iqs5xx_read_byte(client, IQS5XX_TOTAL_RX, &val);
if (error)
return error;
max_x_hw = (val - 1) * IQS5XX_NUM_POINTS;
error = iqs5xx_read_byte(client, IQS5XX_TOTAL_TX, &val);
if (error)
return error;
max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val);
if (error)
return error;
if (val & IQS5XX_SWITCH_XY_AXIS)
swap(max_x_hw, max_y_hw);
if (prop.swap_x_y)
val ^= IQS5XX_SWITCH_XY_AXIS;
if (prop.invert_x)
val ^= prop.swap_x_y ? IQS5XX_FLIP_Y : IQS5XX_FLIP_X;
if (prop.invert_y)
val ^= prop.swap_x_y ? IQS5XX_FLIP_X : IQS5XX_FLIP_Y;
error = iqs5xx_write_byte(client, IQS5XX_XY_CFG0, val);
if (error)
return error;
if (prop.max_x > max_x_hw) {
dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
prop.max_x, max_x_hw);
return -EINVAL;
} else if (prop.max_x == 0) {
error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x); error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x);
if (error) if (error)
return error; return error;
input_abs_set_max(iqs5xx->input,
prop.swap_x_y ? ABS_MT_POSITION_Y :
ABS_MT_POSITION_X,
max_x);
} else {
max_x = (u16)prop.max_x;
}
if (prop.max_y > max_y_hw) {
dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
prop.max_y, max_y_hw);
return -EINVAL;
} else if (prop.max_y == 0) {
error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y); error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
if (error) if (error)
return error; return error;
input_abs_set_max(iqs5xx->input, input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_X, max_x);
prop.swap_x_y ? ABS_MT_POSITION_X : input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_Y, max_y);
ABS_MT_POSITION_Y,
max_y); touchscreen_parse_properties(iqs5xx->input, true, prop);
} else {
max_y = (u16)prop.max_y; if (prop->max_x > IQS5XX_XY_RES_MAX) {
dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
prop->max_x, IQS5XX_XY_RES_MAX);
return -EINVAL;
} else if (prop->max_x != max_x) {
error = iqs5xx_write_word(client, IQS5XX_X_RES, prop->max_x);
if (error)
return error;
} }
/* if (prop->max_y > IQS5XX_XY_RES_MAX) {
* Write horizontal and vertical resolution to the device in case its dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
* original defaults were overridden or swapped as per the properties prop->max_y, IQS5XX_XY_RES_MAX);
* specified in the device tree. return -EINVAL;
*/ } else if (prop->max_y != max_y) {
error = iqs5xx_write_word(client, error = iqs5xx_write_word(client, IQS5XX_Y_RES, prop->max_y);
prop.swap_x_y ? IQS5XX_Y_RES : IQS5XX_X_RES,
max_x);
if (error)
return error;
error = iqs5xx_write_word(client,
prop.swap_x_y ? IQS5XX_X_RES : IQS5XX_Y_RES,
max_y);
if (error) if (error)
return error; return error;
}
error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS, error = input_mt_init_slots(iqs5xx->input, IQS5XX_NUM_CONTACTS,
INPUT_MT_DIRECT); INPUT_MT_DIRECT);
@ -603,7 +559,6 @@ static int iqs5xx_dev_init(struct i2c_client *client)
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
struct iqs5xx_dev_id_info *dev_id_info; struct iqs5xx_dev_id_info *dev_id_info;
int error; int error;
u8 val;
u8 buf[sizeof(*dev_id_info) + 1]; u8 buf[sizeof(*dev_id_info) + 1];
error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM, error = iqs5xx_read_burst(client, IQS5XX_PROD_NUM,
@ -666,18 +621,18 @@ static int iqs5xx_dev_init(struct i2c_client *client)
if (error) if (error)
return error; return error;
error = iqs5xx_read_byte(client, IQS5XX_SYS_CFG0, &val); error = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL0, IQS5XX_ACK_RESET);
if (error) if (error)
return error; return error;
val |= IQS5XX_SETUP_COMPLETE; error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0,
val &= ~IQS5XX_SW_INPUT_EVENT; IQS5XX_SETUP_COMPLETE | IQS5XX_WDT |
error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG0, val); IQS5XX_ALP_REATI | IQS5XX_REATI);
if (error) if (error)
return error; return error;
val = IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE; error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1,
error = iqs5xx_write_byte(client, IQS5XX_SYS_CFG1, val); IQS5XX_TP_EVENT | IQS5XX_EVENT_MODE);
if (error) if (error)
return error; return error;
@ -688,13 +643,12 @@ static int iqs5xx_dev_init(struct i2c_client *client)
iqs5xx->bl_status = dev_id_info->bl_status; iqs5xx->bl_status = dev_id_info->bl_status;
/* /*
* Closure of the first communication window that appears following the * The following delay allows ATI to complete before the open and close
* release of reset appears to kick off an initialization period during * callbacks are free to elicit I2C communication. Any attempts to read
* which further communication is met with clock stretching. The return * from or write to the device during this time may face extended clock
* from this function is delayed so that further communication attempts * stretching and prompt the I2C controller to report an error.
* avoid this period.
*/ */
msleep(100); msleep(250);
return 0; return 0;
} }
@ -702,7 +656,7 @@ static int iqs5xx_dev_init(struct i2c_client *client)
static irqreturn_t iqs5xx_irq(int irq, void *data) static irqreturn_t iqs5xx_irq(int irq, void *data)
{ {
struct iqs5xx_private *iqs5xx = data; struct iqs5xx_private *iqs5xx = data;
struct iqs5xx_touch_data touch_data[IQS5XX_NUM_CONTACTS]; struct iqs5xx_status status;
struct i2c_client *client = iqs5xx->client; struct i2c_client *client = iqs5xx->client;
struct input_dev *input = iqs5xx->input; struct input_dev *input = iqs5xx->input;
int error, i; int error, i;
@ -715,21 +669,35 @@ static irqreturn_t iqs5xx_irq(int irq, void *data)
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET) if (iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
return IRQ_NONE; return IRQ_NONE;
error = iqs5xx_read_burst(client, IQS5XX_ABS_X, error = iqs5xx_read_burst(client, IQS5XX_SYS_INFO0,
touch_data, sizeof(touch_data)); &status, sizeof(status));
if (error) if (error)
return IRQ_NONE; return IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(touch_data); i++) { if (status.sys_info[0] & IQS5XX_SHOW_RESET) {
u16 pressure = be16_to_cpu(touch_data[i].strength); dev_err(&client->dev, "Unexpected device reset\n");
error = iqs5xx_dev_init(client);
if (error) {
dev_err(&client->dev,
"Failed to re-initialize device: %d\n", error);
return IRQ_NONE;
}
return IRQ_HANDLED;
}
for (i = 0; i < ARRAY_SIZE(status.touch_data); i++) {
struct iqs5xx_touch_data *touch_data = &status.touch_data[i];
u16 pressure = be16_to_cpu(touch_data->strength);
input_mt_slot(input, i); input_mt_slot(input, i);
if (input_mt_report_slot_state(input, MT_TOOL_FINGER, if (input_mt_report_slot_state(input, MT_TOOL_FINGER,
pressure != 0)) { pressure != 0)) {
input_report_abs(input, ABS_MT_POSITION_X, touchscreen_report_pos(iqs5xx->input, &iqs5xx->prop,
be16_to_cpu(touch_data[i].abs_x)); be16_to_cpu(touch_data->abs_x),
input_report_abs(input, ABS_MT_POSITION_Y, be16_to_cpu(touch_data->abs_y),
be16_to_cpu(touch_data[i].abs_y)); true);
input_report_abs(input, ABS_MT_PRESSURE, pressure); input_report_abs(input, ABS_MT_PRESSURE, pressure);
} }
} }
@ -884,7 +852,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
{ {
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client); struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
int error; int error, error_bl = 0;
u8 *pmap; u8 *pmap;
if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE) if (iqs5xx->bl_status == IQS5XX_BL_STATUS_NONE)
@ -938,6 +906,7 @@ err_reset:
usleep_range(10000, 10100); usleep_range(10000, 10100);
} }
error_bl = error;
error = iqs5xx_dev_init(client); error = iqs5xx_dev_init(client);
if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET) if (!error && iqs5xx->bl_status == IQS5XX_BL_STATUS_RESET)
error = -EINVAL; error = -EINVAL;
@ -949,11 +918,15 @@ err_reset:
err_kfree: err_kfree:
kfree(pmap); kfree(pmap);
if (error_bl)
return error_bl;
return error; return error;
} }
static ssize_t fw_file_store(struct device *dev, struct device_attribute *attr, static ssize_t fw_file_store(struct device *dev,
const char *buf, size_t count) struct device_attribute *attr, const char *buf,
size_t count)
{ {
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev); struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct i2c_client *client = iqs5xx->client; struct i2c_client *client = iqs5xx->client;
@ -1012,7 +985,7 @@ static int __maybe_unused iqs5xx_suspend(struct device *dev)
struct input_dev *input = iqs5xx->input; struct input_dev *input = iqs5xx->input;
int error = 0; int error = 0;
if (!input) if (!input || device_may_wakeup(dev))
return error; return error;
mutex_lock(&input->mutex); mutex_lock(&input->mutex);
@ -1031,7 +1004,7 @@ static int __maybe_unused iqs5xx_resume(struct device *dev)
struct input_dev *input = iqs5xx->input; struct input_dev *input = iqs5xx->input;
int error = 0; int error = 0;
if (!input) if (!input || device_may_wakeup(dev))
return error; return error;
mutex_lock(&input->mutex); mutex_lock(&input->mutex);

View File

@ -465,13 +465,13 @@ static void mip4_report_keys(struct mip4_ts *ts, u8 *packet)
static void mip4_report_touch(struct mip4_ts *ts, u8 *packet) static void mip4_report_touch(struct mip4_ts *ts, u8 *packet)
{ {
int id; int id;
bool hover; bool __always_unused hover;
bool palm; bool __always_unused palm;
bool state; bool state;
u16 x, y; u16 x, y;
u8 pressure_stage = 0; u8 __always_unused pressure_stage = 0;
u8 pressure; u8 pressure;
u8 size; u8 __always_unused size;
u8 touch_major; u8 touch_major;
u8 touch_minor; u8 touch_minor;

View File

@ -445,6 +445,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
enum raydium_bl_ack state) enum raydium_bl_ack state)
{ {
int error; int error;
static const u8 cmd[] = { 0xFF, 0x39 };
error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len); error = raydium_i2c_send(client, RM_CMD_BOOT_WRT, data, len);
if (error) { if (error) {
@ -453,7 +454,7 @@ static int raydium_i2c_write_object(struct i2c_client *client,
return error; return error;
} }
error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, NULL, 0); error = raydium_i2c_send(client, RM_CMD_BOOT_ACK, cmd, sizeof(cmd));
if (error) { if (error) {
dev_err(&client->dev, "Ack obj command failed: %d\n", error); dev_err(&client->dev, "Ack obj command failed: %d\n", error);
return error; return error;

View File

@ -94,8 +94,13 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
for (retries = 10; retries; retries--) { for (retries = 10; retries; retries--) {
error = st1232_ts_read_data(ts, REG_STATUS, 1); error = st1232_ts_read_data(ts, REG_STATUS, 1);
if (!error && ts->read_buf[0] == (STATUS_NORMAL | ERROR_NONE)) if (!error) {
switch (ts->read_buf[0]) {
case STATUS_NORMAL | ERROR_NONE:
case STATUS_IDLE | ERROR_NONE:
return 0; return 0;
}
}
usleep_range(1000, 2000); usleep_range(1000, 2000);
} }

View File

@ -52,6 +52,7 @@
* @idev: registered input device * @idev: registered input device
* @work: a work item used to scan the device * @work: a work item used to scan the device
* @dev: a pointer back to the MFD cell struct device* * @dev: a pointer back to the MFD cell struct device*
* @prop: Touchscreen properties
* @ave_ctrl: Sample average control * @ave_ctrl: Sample average control
* (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples) * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples)
* @touch_det_delay: Touch detect interrupt delay * @touch_det_delay: Touch detect interrupt delay

View File

@ -787,6 +787,7 @@ static int sur40_probe(struct usb_interface *interface,
dev_err(&interface->dev, dev_err(&interface->dev,
"Unable to register video controls."); "Unable to register video controls.");
v4l2_ctrl_handler_free(&sur40->hdl); v4l2_ctrl_handler_free(&sur40->hdl);
error = sur40->hdl.error;
goto err_unreg_v4l2; goto err_unreg_v4l2;
} }

View File

@ -94,9 +94,7 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data,
static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data) static void surface3_spi_process_touch(struct surface3_ts_data *ts_data, u8 *data)
{ {
u16 timestamp;
unsigned int i; unsigned int i;
timestamp = get_unaligned_le16(&data[15]);
for (i = 0; i < 13; i++) { for (i = 0; i < 13; i++) {
struct surface3_ts_data_finger *finger; struct surface3_ts_data_finger *finger;

View File

@ -1044,6 +1044,7 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt) static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
{ {
struct device *dev = &usbtouch->interface->dev;
struct nexio_touch_packet *packet = (void *) pkt; struct nexio_touch_packet *packet = (void *) pkt;
struct nexio_priv *priv = usbtouch->priv; struct nexio_priv *priv = usbtouch->priv;
unsigned int data_len = be16_to_cpu(packet->data_len); unsigned int data_len = be16_to_cpu(packet->data_len);
@ -1062,6 +1063,8 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
/* send ACK */ /* send ACK */
ret = usb_submit_urb(priv->ack, GFP_ATOMIC); ret = usb_submit_urb(priv->ack, GFP_ATOMIC);
if (ret)
dev_warn(dev, "Failed to submit ACK URB: %d\n", ret);
if (!usbtouch->type->max_xc) { if (!usbtouch->type->max_xc) {
usbtouch->type->max_xc = 2 * x_len; usbtouch->type->max_xc = 2 * x_len;

View File

@ -161,7 +161,7 @@ static int zinitix_read_data(struct i2c_client *client,
ret = i2c_master_recv(client, (u8 *)values, length); ret = i2c_master_recv(client, (u8 *)values, length);
if (ret != length) if (ret != length)
return ret < 0 ? ret : -EIO; ; return ret < 0 ? ret : -EIO;
return 0; return 0;
} }
@ -190,7 +190,7 @@ static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
return 0; return 0;
} }
static bool zinitix_init_touch(struct bt541_ts_data *bt541) static int zinitix_init_touch(struct bt541_ts_data *bt541)
{ {
struct i2c_client *client = bt541->client; struct i2c_client *client = bt541->client;
int i; int i;

View File

@ -0,0 +1,103 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This header provides the constants of the standard Chrome OS key matrix
* for cros-ec keyboard-controller bindings.
*
* Copyright (c) 2021 Google, Inc
*/
#ifndef _CROS_EC_KEYBOARD_H
#define _CROS_EC_KEYBOARD_H
#define CROS_STD_TOP_ROW_KEYMAP \
MATRIX_KEY(0x00, 0x02, KEY_F1) \
MATRIX_KEY(0x03, 0x02, KEY_F2) \
MATRIX_KEY(0x02, 0x02, KEY_F3) \
MATRIX_KEY(0x01, 0x02, KEY_F4) \
MATRIX_KEY(0x03, 0x04, KEY_F5) \
MATRIX_KEY(0x02, 0x04, KEY_F6) \
MATRIX_KEY(0x01, 0x04, KEY_F7) \
MATRIX_KEY(0x02, 0x09, KEY_F8) \
MATRIX_KEY(0x01, 0x09, KEY_F9) \
MATRIX_KEY(0x00, 0x04, KEY_F10)
#define CROS_STD_MAIN_KEYMAP \
MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA) \
MATRIX_KEY(0x00, 0x03, KEY_B) \
MATRIX_KEY(0x00, 0x05, KEY_RO) \
MATRIX_KEY(0x00, 0x06, KEY_N) \
MATRIX_KEY(0x00, 0x08, KEY_EQUAL) \
MATRIX_KEY(0x00, 0x0a, KEY_RIGHTALT) \
MATRIX_KEY(0x01, 0x01, KEY_ESC) \
MATRIX_KEY(0x01, 0x03, KEY_G) \
MATRIX_KEY(0x01, 0x06, KEY_H) \
MATRIX_KEY(0x01, 0x08, KEY_APOSTROPHE) \
MATRIX_KEY(0x01, 0x0b, KEY_BACKSPACE) \
MATRIX_KEY(0x01, 0x0c, KEY_HENKAN) \
\
MATRIX_KEY(0x02, 0x00, KEY_LEFTCTRL) \
MATRIX_KEY(0x02, 0x01, KEY_TAB) \
MATRIX_KEY(0x02, 0x03, KEY_T) \
MATRIX_KEY(0x02, 0x05, KEY_RIGHTBRACE) \
MATRIX_KEY(0x02, 0x06, KEY_Y) \
MATRIX_KEY(0x02, 0x07, KEY_102ND) \
MATRIX_KEY(0x02, 0x08, KEY_LEFTBRACE) \
MATRIX_KEY(0x02, 0x0a, KEY_YEN) \
\
MATRIX_KEY(0x03, 0x00, KEY_LEFTMETA) \
MATRIX_KEY(0x03, 0x01, KEY_GRAVE) \
MATRIX_KEY(0x03, 0x03, KEY_5) \
MATRIX_KEY(0x03, 0x06, KEY_6) \
MATRIX_KEY(0x03, 0x08, KEY_MINUS) \
MATRIX_KEY(0x03, 0x09, KEY_SLEEP) \
MATRIX_KEY(0x03, 0x0b, KEY_BACKSLASH) \
MATRIX_KEY(0x03, 0x0c, KEY_MUHENKAN) \
\
MATRIX_KEY(0x04, 0x00, KEY_RIGHTCTRL) \
MATRIX_KEY(0x04, 0x01, KEY_A) \
MATRIX_KEY(0x04, 0x02, KEY_D) \
MATRIX_KEY(0x04, 0x03, KEY_F) \
MATRIX_KEY(0x04, 0x04, KEY_S) \
MATRIX_KEY(0x04, 0x05, KEY_K) \
MATRIX_KEY(0x04, 0x06, KEY_J) \
MATRIX_KEY(0x04, 0x08, KEY_SEMICOLON) \
MATRIX_KEY(0x04, 0x09, KEY_L) \
MATRIX_KEY(0x04, 0x0a, KEY_BACKSLASH) \
MATRIX_KEY(0x04, 0x0b, KEY_ENTER) \
\
MATRIX_KEY(0x05, 0x01, KEY_Z) \
MATRIX_KEY(0x05, 0x02, KEY_C) \
MATRIX_KEY(0x05, 0x03, KEY_V) \
MATRIX_KEY(0x05, 0x04, KEY_X) \
MATRIX_KEY(0x05, 0x05, KEY_COMMA) \
MATRIX_KEY(0x05, 0x06, KEY_M) \
MATRIX_KEY(0x05, 0x07, KEY_LEFTSHIFT) \
MATRIX_KEY(0x05, 0x08, KEY_SLASH) \
MATRIX_KEY(0x05, 0x09, KEY_DOT) \
MATRIX_KEY(0x05, 0x0b, KEY_SPACE) \
\
MATRIX_KEY(0x06, 0x01, KEY_1) \
MATRIX_KEY(0x06, 0x02, KEY_3) \
MATRIX_KEY(0x06, 0x03, KEY_4) \
MATRIX_KEY(0x06, 0x04, KEY_2) \
MATRIX_KEY(0x06, 0x05, KEY_8) \
MATRIX_KEY(0x06, 0x06, KEY_7) \
MATRIX_KEY(0x06, 0x08, KEY_0) \
MATRIX_KEY(0x06, 0x09, KEY_9) \
MATRIX_KEY(0x06, 0x0a, KEY_LEFTALT) \
MATRIX_KEY(0x06, 0x0b, KEY_DOWN) \
MATRIX_KEY(0x06, 0x0c, KEY_RIGHT) \
\
MATRIX_KEY(0x07, 0x01, KEY_Q) \
MATRIX_KEY(0x07, 0x02, KEY_E) \
MATRIX_KEY(0x07, 0x03, KEY_R) \
MATRIX_KEY(0x07, 0x04, KEY_W) \
MATRIX_KEY(0x07, 0x05, KEY_I) \
MATRIX_KEY(0x07, 0x06, KEY_U) \
MATRIX_KEY(0x07, 0x07, KEY_RIGHTSHIFT) \
MATRIX_KEY(0x07, 0x08, KEY_P) \
MATRIX_KEY(0x07, 0x09, KEY_O) \
MATRIX_KEY(0x07, 0x0b, KEY_UP) \
MATRIX_KEY(0x07, 0x0c, KEY_LEFT)
#endif /* _CROS_EC_KEYBOARD_H */