Commit e0fbd25b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:
 "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
  ...
parents 69aea9d2 1bff77f4
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.
...@@ -31,6 +31,17 @@ properties: ...@@ -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 ...@@ -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
......
...@@ -6,103 +6,18 @@ ...@@ -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)
>; >;
}; };
}; };
...@@ -456,7 +456,7 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev, ...@@ -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, ...@@ -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, ...@@ -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;
......
...@@ -382,4 +382,11 @@ config JOYSTICK_FSIA6B ...@@ -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
...@@ -24,6 +24,7 @@ obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o ...@@ -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 ...@@ -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
// 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);
...@@ -305,6 +305,7 @@ static const struct xpad_device { ...@@ -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 },
......
...@@ -446,7 +446,7 @@ config KEYBOARD_MPR121 ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -48,6 +48,7 @@ ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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,8 +774,16 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi) ...@@ -771,8 +774,16 @@ 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) {
return 0; if (ktime_ms_delta(ktime_get(), applespi->cmd_msg_queued) < 1000)
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) ...@@ -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) ...@@ -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;
......
...@@ -27,6 +27,8 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
......
...@@ -60,6 +60,8 @@ ...@@ -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 { ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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;
}
keypad_data->base = ioremap(res->start, resource_size(res)); pm_runtime_use_autosuspend(dev);
if (!keypad_data->base) { pm_runtime_set_autosuspend_delay(dev, OMAP4_KEYPAD_IDLE_CHECK_MS);
dev_err(&pdev->dev, "can't ioremap mem resource\n"); pm_runtime_enable(dev);
error = -ENOMEM;
goto err_release_mem;
}
pm_runtime_enable(&pdev->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;
}
/* /*
* 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);
if (!error) { error = omap4_keypad_check_revision(dev, keypad_data);
/* Ensure device does not raise interrupts */ if (!error) {
omap4_keypad_stop(keypad_data); /* Ensure device does not raise interrupts */
} 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) ...@@ -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,
sizeof(keypad_data->keymap[0]), max_keys,
GFP_KERNEL); sizeof(keypad_data->keymap[0]),
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", keypad_data); omap4_keypad_irq_thread_fn,
IRQF_ONESHOT,
"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 = { ...@@ -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);
......
...@@ -863,6 +863,7 @@ static void da7280_parse_properties(struct device *dev, ...@@ -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) ...@@ -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", },
......
...@@ -986,7 +986,7 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt, ...@@ -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 */
......
...@@ -1106,8 +1106,11 @@ static void synaptics_process_packet(struct psmouse *psmouse) ...@@ -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))
......
...@@ -255,7 +255,7 @@ config SERIO_ARC_PS2 ...@@ -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.
......
...@@ -588,6 +588,10 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = { ...@@ -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 */
},
}, },
{ } { }
}; };
......
...@@ -1036,9 +1036,9 @@ static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr ...@@ -1036,9 +1036,9 @@ 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);
} }
/* These structs define the sysfs files, param #1 is the name of the /* These structs define the sysfs files, param #1 is the name of the
...@@ -1064,9 +1064,8 @@ static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribut ...@@ -1064,9 +1064,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1101,9 +1100,8 @@ static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attri ...@@ -1101,9 +1100,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1143,9 +1141,8 @@ static ssize_t show_tabletToolMode(struct device *dev, struct device_attribute * ...@@ -1143,9 +1141,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1174,10 +1171,9 @@ static ssize_t show_tabletXtilt(struct device *dev, struct device_attribute *att ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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,9 +1369,8 @@ static ssize_t show_tabletStylusUpper(struct device *dev, struct device_attribut ...@@ -1375,9 +1369,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1406,9 +1399,8 @@ static ssize_t show_tabletStylusLower(struct device *dev, struct device_attribut ...@@ -1406,9 +1399,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1444,9 +1436,8 @@ static ssize_t show_tabletMouseLeft(struct device *dev, struct device_attribute ...@@ -1444,9 +1436,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1474,9 +1465,8 @@ static ssize_t show_tabletMouseMiddle(struct device *dev, struct device_attribut ...@@ -1474,9 +1465,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1504,9 +1494,8 @@ static ssize_t show_tabletMouseRight(struct device *dev, struct device_attribute ...@@ -1504,9 +1494,8 @@ 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));
} }
static ssize_t static ssize_t
...@@ -1535,10 +1524,9 @@ static ssize_t show_tabletWheel(struct device *dev, struct device_attribute *att ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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);
......
...@@ -608,7 +608,7 @@ config TOUCHSCREEN_MTOUCH ...@@ -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.
......
...@@ -64,24 +64,13 @@ ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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 ads7846_packet *packet = ts->packet;
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 spi_transfer *t = struct ads7846_packet *packet = ts->packet;
list_entry(m->transfers.prev, struct spi_transfer, transfer_list); int action;
struct ads7846_buf *buf = t->rx_buf; int val;
unsigned int cmd_idx, b;
buf->data = val; 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) ...@@ -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. continue;
*/
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;
case ADS7846_FILTER_IGNORE:
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: return;
BUG();
}
} else {
msg_idx++;
}
} }
} }
...@@ -771,19 +837,14 @@ static void ads7846_report_state(struct ads7846 *ts) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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
......
...@@ -56,6 +56,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
if (!error)
error = elants_i2c_query_ts_info(ts); switch (ts->chip_id) {
case EKTH3500:
if (!error)
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 @@ static int elants_i2c_fw_update(struct elants_data *ts) ...@@ -853,7 +922,8 @@ static int elants_i2c_fw_update(struct elants_data *ts)
* 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) ...@@ -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];
p = buf[FW_POS_PRESSURE + i];
w = buf[FW_POS_WIDTH + i]; /*
* 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];
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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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); ...@@ -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);
......
...@@ -341,8 +341,10 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv) ...@@ -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;
......
...@@ -2,8 +2,7 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 { ...@@ -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 { ...@@ -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) ...@@ -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,11 +340,16 @@ static int iqs5xx_bl_open(struct i2c_client *client) ...@@ -337,11 +340,16 @@ 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)
return error; usleep_range(10000, 10100);
else if (error != -EINVAL)
continue;
return error;
} }
} }
...@@ -481,12 +489,10 @@ static void iqs5xx_close(struct input_dev *input) ...@@ -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,89 +512,39 @@ static int iqs5xx_axis_init(struct i2c_client *client) ...@@ -506,89 +512,39 @@ 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_word(client, IQS5XX_X_RES, &max_x);
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) if (error)
return error; return error;
max_y_hw = (val - 1) * IQS5XX_NUM_POINTS;
error = iqs5xx_read_byte(client, IQS5XX_XY_CFG0, &val); error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y);
if (error) if (error)
return error; return error;
if (val & IQS5XX_SWITCH_XY_AXIS) input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_X, max_x);
swap(max_x_hw, max_y_hw); input_abs_set_max(iqs5xx->input, ABS_MT_POSITION_Y, max_y);
if (prop.swap_x_y) touchscreen_parse_properties(iqs5xx->input, true, prop);
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) { if (prop->max_x > IQS5XX_XY_RES_MAX) {
dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n", dev_err(&client->dev, "Invalid maximum x-coordinate: %u > %u\n",
prop.max_x, max_x_hw); prop->max_x, IQS5XX_XY_RES_MAX);
return -EINVAL; return -EINVAL;
} else if (prop.max_x == 0) { } else if (prop->max_x != max_x) {
error = iqs5xx_read_word(client, IQS5XX_X_RES, &max_x); error = iqs5xx_write_word(client, IQS5XX_X_RES, prop->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) { if (prop->max_y > IQS5XX_XY_RES_MAX) {
dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n", dev_err(&client->dev, "Invalid maximum y-coordinate: %u > %u\n",
prop.max_y, max_y_hw); prop->max_y, IQS5XX_XY_RES_MAX);
return -EINVAL; return -EINVAL;
} else if (prop.max_y == 0) { } else if (prop->max_y != max_y) {
error = iqs5xx_read_word(client, IQS5XX_Y_RES, &max_y); error = iqs5xx_write_word(client, IQS5XX_Y_RES, prop->max_y);
if (error) if (error)
return error; return error;
input_abs_set_max(iqs5xx->input,
prop.swap_x_y ? ABS_MT_POSITION_X :
ABS_MT_POSITION_Y,
max_y);
} else {
max_y = (u16)prop.max_y;
} }
/*
* Write horizontal and vertical resolution to the device in case its
* original defaults were overridden or swapped as per the properties
* specified in the device tree.
*/
error = iqs5xx_write_word(client,
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)
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);
if (error) if (error)
...@@ -603,7 +559,6 @@ static int iqs5xx_dev_init(struct i2c_client *client) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) ...@@ -938,6 +906,7 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
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 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file) ...@@ -949,11 +918,15 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
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) ...@@ -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) ...@@ -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);
......
...@@ -465,13 +465,13 @@ static void mip4_report_keys(struct mip4_ts *ts, u8 *packet) ...@@ -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;
......
...@@ -445,6 +445,7 @@ static int raydium_i2c_write_object(struct i2c_client *client, ...@@ -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, ...@@ -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;
......
...@@ -94,8 +94,13 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts) ...@@ -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) {
return 0; switch (ts->read_buf[0]) {
case STATUS_NORMAL | ERROR_NONE:
case STATUS_IDLE | ERROR_NONE:
return 0;
}
}
usleep_range(1000, 2000); usleep_range(1000, 2000);
} }
......
...@@ -52,6 +52,7 @@ ...@@ -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
......
...@@ -787,6 +787,7 @@ static int sur40_probe(struct usb_interface *interface, ...@@ -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;
} }
......
...@@ -94,9 +94,7 @@ static void surface3_spi_report_touch(struct surface3_ts_data *ts_data, ...@@ -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;
......
...@@ -1044,6 +1044,7 @@ static void nexio_exit(struct usbtouch_usb *usbtouch) ...@@ -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) ...@@ -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;
......
...@@ -161,7 +161,7 @@ static int zinitix_read_data(struct i2c_client *client, ...@@ -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) ...@@ -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;
......
/* 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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment