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

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

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

View File

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

View File

@ -31,6 +31,17 @@ properties:
if the EC does not have its own logic or hardware for this.
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:
- compatible
@ -38,11 +49,24 @@ unevaluatedProperties: false
examples:
- |
#include <dt-bindings/input/input.h>
cros-ec-keyb {
compatible = "google,cros-ec-keyb";
keypad,num-rows = <8>;
keypad,num-columns = <13>;
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
* RR=Row CC=Column KKKK=Key Code

View File

@ -6,103 +6,18 @@
*/
#include <dt-bindings/input/input.h>
#include <dt-bindings/input/cros-ec-keyboard.h>
&cros_ec {
keyboard-controller {
keyboard_controller: keyboard-controller {
compatible = "google,cros-ec-keyb";
keypad,num-rows = <8>;
keypad,num-columns = <13>;
google,needs-ghost-filter;
linux,keymap = <
MATRIX_KEY(0x00, 0x01, KEY_LEFTMETA)
MATRIX_KEY(0x00, 0x02, KEY_F1)
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)
CROS_STD_TOP_ROW_KEYMAP
CROS_STD_MAIN_KEYMAP
>;
};
};

View File

@ -456,7 +456,7 @@ static int joydev_handle_JSIOCSAXMAP(struct joydev *joydev,
if (IS_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) {
retval = -EINVAL;
goto out;
@ -480,6 +480,9 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
int i;
int retval = 0;
if (len % sizeof(*keypam))
return -EINVAL;
len = min(len, sizeof(joydev->keypam));
/* Validate the map. */
@ -487,7 +490,7 @@ static int joydev_handle_JSIOCSBTNMAP(struct joydev *joydev,
if (IS_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) {
retval = -EINVAL;
goto out;

View File

@ -382,4 +382,11 @@ config JOYSTICK_FSIA6B
To compile this driver as a module, choose M here: the
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

View File

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

View File

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

View File

@ -305,6 +305,7 @@ static const struct xpad_device {
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
{ 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 },
{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },

View File

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

View File

@ -48,6 +48,7 @@
#include <linux/efi.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/ktime.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@ -409,7 +410,7 @@ struct applespi_data {
unsigned int cmd_msg_cntr;
/* lock to protect the above parameters and flags below */
spinlock_t cmd_msg_lock;
bool cmd_msg_queued;
ktime_t cmd_msg_queued;
enum applespi_evt_type cmd_evt_type;
struct led_classdev backlight_info;
@ -729,7 +730,7 @@ static void applespi_msg_complete(struct applespi_data *applespi,
wake_up_all(&applespi->drain_complete);
if (is_write_msg) {
applespi->cmd_msg_queued = false;
applespi->cmd_msg_queued = 0;
applespi_send_cmd_msg(applespi);
}
@ -748,6 +749,8 @@ static void applespi_async_write_complete(void *context)
applespi->tx_status,
APPLESPI_STATUS_SIZE);
udelay(SPI_RW_CHG_DELAY_US);
if (!applespi_check_write_status(applespi, applespi->wr_m.status)) {
/*
* 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)
return 0;
/* check whether send is in progress */
if (applespi->cmd_msg_queued)
return 0;
if (applespi->cmd_msg_queued) {
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 */
memset(packet, 0, APPLESPI_PACKET_SIZE);
@ -869,7 +880,7 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
return sts;
}
applespi->cmd_msg_queued = true;
applespi->cmd_msg_queued = ktime_get_coarse();
applespi->write_active = true;
return 0;
@ -1921,7 +1932,7 @@ static int __maybe_unused applespi_resume(struct device *dev)
applespi->drain = false;
applespi->have_cl_led_on = false;
applespi->have_bl_level = 0;
applespi->cmd_msg_queued = false;
applespi->cmd_msg_queued = 0;
applespi->read_active = false;
applespi->write_active = false;

View File

@ -27,6 +27,8 @@
#include <asm/unaligned.h>
#define MAX_NUM_TOP_ROW_KEYS 15
/**
* struct cros_ec_keyb - Structure representing EC keyboard device
*
@ -42,6 +44,9 @@
* @idev: The input device for the matrix keys.
* @bs_idev: The input device for non-matrix buttons and switches (or NULL).
* @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 {
unsigned int rows;
@ -58,6 +63,9 @@ struct cros_ec_keyb {
struct input_dev *idev;
struct input_dev *bs_idev;
struct notifier_block notifier;
u16 function_row_physmap[MAX_NUM_TOP_ROW_KEYS];
size_t num_function_row_keys;
};
/**
@ -527,6 +535,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
struct input_dev *idev;
const char *phys;
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);
if (err)
@ -578,6 +591,21 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
ckdev->idev = idev;
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);
if (err) {
dev_err(dev, "cannot register input device\n");
@ -587,6 +615,51 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
return 0;
}
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)
{
struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
@ -617,6 +690,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
return err;
}
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;
err = blocking_notifier_chain_register(&ckdev->ec->event_notifier,
&ckdev->notifier);

View File

@ -60,6 +60,8 @@
((((dbms) * 1000) / ((1 << ((ptv) + 1)) * (1000000 / 32768))) - 1)
#define OMAP4_VAL_DEBOUNCINGTIME_16MS \
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 {
KBD_REVISION_OMAP4 = 0,
@ -71,6 +73,7 @@ struct omap4_keypad {
void __iomem *base;
unsigned int irq;
struct mutex lock; /* for key scan */
unsigned int rows;
unsigned int cols;
@ -78,7 +81,7 @@ struct omap4_keypad {
u32 irqreg_offset;
unsigned int row_shift;
bool no_autorepeat;
unsigned char key_state[8];
u64 keys;
unsigned short *keymap;
};
@ -107,6 +110,55 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
keypad_data->base + keypad_data->irqreg_offset + offset);
}
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 */
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)
{
struct omap4_keypad *keypad_data = dev_id;
struct input_dev *input_dev = keypad_data->input;
unsigned char key_state[ARRAY_SIZE(keypad_data->key_state)];
unsigned int col, row, code, changed;
u32 *new_state = (u32 *) key_state;
struct device *dev = keypad_data->input->dev.parent;
u32 low, high;
int error;
u64 keys;
*new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
*(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
for (row = 0; row < keypad_data->rows; row++) {
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));
}
}
error = pm_runtime_get_sync(dev);
if (error < 0) {
pm_runtime_put_noidle(dev);
return IRQ_NONE;
}
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,
sizeof(keypad_data->key_state));
omap4_keypad_scan_keys(keypad_data, keys);
/* clear pending interrupts */
kbd_write_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;
}
static int omap4_keypad_open(struct input_dev *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);
@ -176,13 +224,15 @@ static int omap4_keypad_open(struct input_dev *input)
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
OMAP4_DEF_IRQENABLE_EVENTEN |
OMAP4_DEF_IRQENABLE_LONGKEY);
OMAP4_DEF_IRQENABLE_EVENTEN);
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);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return 0;
}
@ -200,14 +250,20 @@ static void omap4_keypad_stop(struct omap4_keypad *keypad_data)
static void omap4_keypad_close(struct input_dev *input)
{
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);
omap4_keypad_stop(keypad_data);
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,
@ -252,8 +308,41 @@ static int omap4_keypad_check_revision(struct device *dev,
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)
{
struct device *dev = &pdev->dev;
struct omap4_keypad *keypad_data;
struct input_dev *input_dev;
struct resource *res;
@ -271,63 +360,62 @@ static int omap4_keypad_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
keypad_data = devm_kzalloc(dev, sizeof(*keypad_data), GFP_KERNEL);
if (!keypad_data) {
dev_err(&pdev->dev, "keypad_data memory allocation failed\n");
dev_err(dev, "keypad_data memory allocation failed\n");
return -ENOMEM;
}
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)
goto err_free_keypad;
return error;
res = request_mem_region(res->start, resource_size(res), pdev->name);
if (!res) {
dev_err(&pdev->dev, "can't request mem region\n");
error = -EBUSY;
goto err_free_keypad;
keypad_data->base = devm_ioremap_resource(dev, res);
if (IS_ERR(keypad_data->base))
return PTR_ERR(keypad_data->base);
pm_runtime_use_autosuspend(dev);
pm_runtime_set_autosuspend_delay(dev, OMAP4_KEYPAD_IDLE_CHECK_MS);
pm_runtime_enable(dev);
error = devm_add_action_or_reset(dev, omap4_disable_pm, dev);
if (error) {
dev_err(dev, "unable to register cleanup action\n");
return error;
}
keypad_data->base = ioremap(res->start, resource_size(res));
if (!keypad_data->base) {
dev_err(&pdev->dev, "can't ioremap mem resource\n");
error = -ENOMEM;
goto err_release_mem;
}
pm_runtime_enable(&pdev->dev);
/*
* Enable clocks for the keypad module so that we can read
* revision register.
*/
error = pm_runtime_get_sync(&pdev->dev);
error = pm_runtime_get_sync(dev);
if (error) {
dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
pm_runtime_put_noidle(&pdev->dev);
} else {
error = omap4_keypad_check_revision(&pdev->dev,
keypad_data);
if (!error) {
/* Ensure device does not raise interrupts */
omap4_keypad_stop(keypad_data);
}
pm_runtime_put_sync(&pdev->dev);
dev_err(dev, "pm_runtime_get_sync() failed\n");
pm_runtime_put_noidle(dev);
return error;
}
error = omap4_keypad_check_revision(dev, keypad_data);
if (!error) {
/* Ensure device does not raise interrupts */
omap4_keypad_stop(keypad_data);
}
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
if (error)
goto err_pm_disable;
return error;
/* input device allocation */
keypad_data->input = input_dev = input_allocate_device();
if (!input_dev) {
error = -ENOMEM;
goto err_pm_disable;
}
keypad_data->input = input_dev = devm_input_allocate_device(dev);
if (!input_dev)
return -ENOMEM;
input_dev->name = pdev->name;
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
@ -344,84 +432,51 @@ static int omap4_keypad_probe(struct platform_device *pdev)
keypad_data->row_shift = get_count_order(keypad_data->cols);
max_keys = keypad_data->rows << keypad_data->row_shift;
keypad_data->keymap = kcalloc(max_keys,
sizeof(keypad_data->keymap[0]),
GFP_KERNEL);
keypad_data->keymap = devm_kcalloc(dev,
max_keys,
sizeof(keypad_data->keymap[0]),
GFP_KERNEL);
if (!keypad_data->keymap) {
dev_err(&pdev->dev, "Not enough memory for keymap\n");
error = -ENOMEM;
goto err_free_input;
dev_err(dev, "Not enough memory for keymap\n");
return -ENOMEM;
}
error = matrix_keypad_build_keymap(NULL, NULL,
keypad_data->rows, keypad_data->cols,
keypad_data->keymap, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
goto err_free_keymap;
dev_err(dev, "failed to build keymap\n");
return error;
}
error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
omap4_keypad_irq_thread_fn, IRQF_ONESHOT,
"omap4-keypad", keypad_data);
error = devm_request_threaded_irq(dev, keypad_data->irq,
omap4_keypad_irq_handler,
omap4_keypad_irq_thread_fn,
IRQF_ONESHOT,
"omap4-keypad", keypad_data);
if (error) {
dev_err(&pdev->dev, "failed to register interrupt\n");
goto err_free_keymap;
dev_err(dev, "failed to register interrupt\n");
return error;
}
error = input_register_device(keypad_data->input);
if (error < 0) {
dev_err(&pdev->dev, "failed to register input device\n");
goto err_free_irq;
if (error) {
dev_err(dev, "failed to register input device\n");
return error;
}
device_init_wakeup(&pdev->dev, true);
error = dev_pm_set_wake_irq(&pdev->dev, keypad_data->irq);
device_init_wakeup(dev, true);
error = dev_pm_set_wake_irq(dev, keypad_data->irq);
if (error)
dev_warn(&pdev->dev,
"failed to set up wakeup irq: %d\n", error);
platform_set_drvdata(pdev, keypad_data);
dev_warn(dev, "failed to set up wakeup irq: %d\n", error);
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)
{
struct omap4_keypad *keypad_data = platform_get_drvdata(pdev);
struct resource *res;
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;
}
@ -437,6 +492,7 @@ static struct platform_driver omap4_keypad_driver = {
.driver = {
.name = "omap4-keypad",
.of_match_table = omap_keypad_dt_match,
.pm = &omap4_keypad_pm_ops,
},
};
module_platform_driver(omap4_keypad_driver);

View File

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

View File

@ -986,7 +986,7 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
case V7_PACKET_ID_TWO:
mt[1].x &= ~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) {
mt[1].x = 0;
/* y gets set to 0 at the end of this function */

View File

@ -1106,8 +1106,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
num_fingers = hw.w + 2;
break;
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;
case 4 ... 15:
if (SYN_CAP_PALMDETECT(info->capabilities))

View File

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

View File

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

View File

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

View File

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

View File

@ -64,24 +64,13 @@
struct ads7846_buf {
u8 cmd;
/*
* 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;
};
__be16 data;
} __packed;
struct ts_event {
bool ignore;
struct ads7846_buf x;
struct ads7846_buf y;
struct ads7846_buf z1;
struct ads7846_buf z2;
struct ads7846_buf_layout {
unsigned int offset;
unsigned int count;
unsigned int skip;
};
/*
@ -90,12 +79,18 @@ struct ts_event {
* systems where main memory is not DMA-coherent (most non-x86 boards).
*/
struct ads7846_packet {
struct ts_event tc;
struct ads7846_buf read_x_cmd;
struct ads7846_buf read_y_cmd;
struct ads7846_buf read_z1_cmd;
struct ads7846_buf read_z2_cmd;
unsigned int count;
unsigned int count_skip;
unsigned int cmds;
unsigned int last_cmd_idx;
struct ads7846_buf_layout l[5];
struct ads7846_buf *rx;
struct ads7846_buf *tx;
struct ads7846_buf pwrdown_cmd;
bool ignore;
u16 x, y, z1, z2;
};
struct ads7846 {
@ -194,7 +189,6 @@ struct ads7846 {
#define READ_Y(vref) (READ_12BIT_DFR(y, 1, vref))
#define READ_Z1(vref) (READ_12BIT_DFR(z1, 1, vref))
#define READ_Z2(vref) (READ_12BIT_DFR(z2, 1, vref))
#define READ_X(vref) (READ_12BIT_DFR(x, 1, vref))
#define PWRDOWN (READ_12BIT_DFR(y, 0, 0)) /* LAST */
@ -207,6 +201,21 @@ struct ads7846 {
#define REF_ON (READ_12BIT_DFR(x, 1, 1))
#define REF_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)
{
if (ts->get_pendown_state)
@ -689,26 +698,109 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
return ADS7846_FILTER_OK;
}
static int ads7846_get_value(struct ads7846 *ts, struct spi_message *m)
static int ads7846_get_value(struct ads7846_buf *buf)
{
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 */
return (value >> 3) & 0xfff;
}
static void ads7846_update_value(struct spi_message *m, int val)
static void ads7846_set_cmd_val(struct ads7846 *ts, enum ads7846_cmds cmd_idx,
u16 val)
{
struct spi_transfer *t =
list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
struct ads7846_buf *buf = t->rx_buf;
struct ads7846_packet *packet = ts->packet;
buf->data = val;
switch (cmd_idx) {
case ADS7846_Y:
packet->y = val;
break;
case ADS7846_X:
packet->x = val;
break;
case ADS7846_Z1:
packet->z1 = val;
break;
case ADS7846_Z2:
packet->z2 = val;
break;
default:
WARN_ON_ONCE(1);
}
}
static u8 ads7846_get_cmd(enum ads7846_cmds cmd_idx, int vref)
{
switch (cmd_idx) {
case ADS7846_Y:
return READ_Y(vref);
case ADS7846_X:
return READ_X(vref);
/* 7846 specific commands */
case ADS7846_Z1:
return READ_Z1(vref);
case ADS7846_Z2:
return READ_Z2(vref);
case ADS7846_PWDOWN:
return PWRDOWN;
default:
WARN_ON_ONCE(1);
}
return 0;
}
static bool ads7846_cmd_need_settle(enum ads7846_cmds cmd_idx)
{
switch (cmd_idx) {
case ADS7846_X:
case ADS7846_Y:
case ADS7846_Z1:
case ADS7846_Z2:
return true;
case ADS7846_PWDOWN:
return false;
default:
WARN_ON_ONCE(1);
}
return false;
}
static int ads7846_filter(struct ads7846 *ts)
{
struct ads7846_packet *packet = ts->packet;
int action;
int val;
unsigned int cmd_idx, b;
packet->ignore = false;
for (cmd_idx = packet->last_cmd_idx; cmd_idx < packet->cmds - 1; cmd_idx++) {
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
packet->last_cmd_idx = cmd_idx;
for (b = l->skip; b < l->count; b++) {
val = ads7846_get_value(&packet->rx[l->offset + b]);
action = ts->filter(ts->filter_data, cmd_idx, &val);
if (action == ADS7846_FILTER_REPEAT) {
if (b == l->count - 1)
return -EAGAIN;
} else if (action == ADS7846_FILTER_OK) {
ads7846_set_cmd_val(ts, cmd_idx, val);
break;
} else {
packet->ignore = true;
return 0;
}
}
}
return 0;
}
static void ads7846_read_state(struct ads7846 *ts)
@ -716,52 +808,26 @@ static void ads7846_read_state(struct ads7846 *ts)
struct ads7846_packet *packet = ts->packet;
struct spi_message *m;
int msg_idx = 0;
int val;
int action;
int error;
while (msg_idx < ts->msg_count) {
packet->last_cmd_idx = 0;
while (true) {
ts->wait_for_sync();
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
packet->tc.ignore = true;
packet->ignore = true;
return;
}
/*
* Last message is power down request, no need to convert
* or filter the value.
*/
if (msg_idx < ts->msg_count - 1) {
error = ads7846_filter(ts);
if (error)
continue;
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:
BUG();
}
} else {
msg_idx++;
}
return;
}
}
@ -771,19 +837,14 @@ static void ads7846_report_state(struct ads7846 *ts)
unsigned int Rt;
u16 x, y, z1, z2;
/*
* ads7846_get_value() does in-place conversion (including byte swap)
* from on-the-wire format as part of debouncing to get stable
* readings.
*/
x = packet->tc.x.data;
y = packet->tc.y.data;
x = packet->x;
y = packet->y;
if (ts->model == 7845) {
z1 = 0;
z2 = 0;
} else {
z1 = packet->tc.z1.data;
z2 = packet->tc.z2.data;
z1 = packet->z1;
z2 = packet->z2;
}
/* range filtering */
@ -816,9 +877,9 @@ static void ads7846_report_state(struct ads7846 *ts)
* the maximum. Don't report it to user space, repeat at least
* 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",
packet->tc.ignore, Rt);
packet->ignore, Rt);
return;
}
@ -979,13 +1040,59 @@ static int ads7846_setup_pendown(struct spi_device *spi,
* Set up the transfers to read touchscreen state; this assumes we
* 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)
{
struct spi_message *m = &ts->msg[0];
struct spi_transfer *x = ts->xfer;
struct ads7846_packet *packet = ts->packet;
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) {
/*
@ -1001,117 +1108,20 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
spi_message_init(m);
m->context = ts;
packet->read_y_cmd.cmd = READ_Y(vref);
x->tx_buf = &packet->read_y_cmd;
x->rx_buf = &packet->tc.y;
x->len = 3;
spi_message_add_tail(x, m);
for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
u8 cmd = ads7846_get_cmd(cmd_idx, vref);
/*
* The first sample after switching drivers can be low quality;
* 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);
for (b = 0; b < l->count; b++)
packet->tx[l->offset + b].cmd = cmd;
}
ts->msg_count++;
m++;
spi_message_init(m);
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;
x->tx_buf = packet->tx;
x->rx_buf = packet->rx;
x->len = size;
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_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);
return 0;
}
#ifdef CONFIG_OF

View File

@ -56,6 +56,7 @@
#define QUEUE_HEADER_SINGLE 0x62
#define QUEUE_HEADER_NORMAL 0X63
#define QUEUE_HEADER_WAIT 0x64
#define QUEUE_HEADER_NORMAL2 0x66
/* Command header definition */
#define CMD_HEADER_WRITE 0x54
@ -69,6 +70,7 @@
#define CMD_HEADER_REK 0x66
/* FW position data */
#define PACKET_SIZE_OLD 40
#define PACKET_SIZE 55
#define MAX_CONTACT_NUM 10
#define FW_POS_HEADER 0
@ -90,6 +92,8 @@
/* FW read command, 0x53 0x?? 0x0, 0x01 */
#define E_ELAN_INFO_FW_VER 0x00
#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_TEST_VER 0xE0
#define E_ELAN_INFO_FW_ID 0xF0
@ -112,6 +116,11 @@
#define ELAN_POWERON_DELAY_USEC 500
#define ELAN_RESET_DELAY_MSEC 20
enum elants_chip_id {
EKTH3500,
EKTF3624,
};
enum elants_state {
ELAN_STATE_NORMAL,
ELAN_WAIT_QUEUE_HEADER,
@ -143,9 +152,12 @@ struct elants_data {
unsigned int y_res;
unsigned int x_max;
unsigned int y_max;
unsigned int phy_x;
unsigned int phy_y;
struct touchscreen_properties prop;
enum elants_state state;
enum elants_chip_id chip_id;
enum elants_iap_mode iap_mode;
/* Guards against concurrent access to the device via sysfs */
@ -433,7 +445,51 @@ static int elants_i2c_query_bc_version(struct elants_data *ts)
return 0;
}
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;
int error;
@ -508,6 +564,8 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
ts->x_res = DIV_ROUND_CLOSEST(ts->x_max, phy_x);
ts->y_max = ELAN_TS_RESOLUTION(cols, osr);
ts->y_res = DIV_ROUND_CLOSEST(ts->y_max, phy_y);
ts->phy_x = phy_x;
ts->phy_y = phy_y;
}
return 0;
@ -587,8 +645,19 @@ static int elants_i2c_initialize(struct elants_data *ts)
error = elants_i2c_query_fw_version(ts);
if (!error)
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)
ts->iap_mode = ELAN_IAP_RECOVERY;
@ -853,7 +922,8 @@ out:
* 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;
unsigned int n_fingers;
@ -880,8 +950,24 @@ static void elants_i2c_mt_event(struct elants_data *ts, u8 *buf)
pos = &buf[FW_POS_XY + i * 3];
x = (((u16)pos[0] & 0xf0) << 4) | pos[1];
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",
i, x, y, p, w);
@ -913,7 +999,8 @@ static u8 elants_i2c_calculate_checksum(u8 *buf)
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);
@ -927,7 +1014,7 @@ static void elants_i2c_event(struct elants_data *ts, u8 *buf)
"%s: unknown packet type: %02x\n",
__func__, buf[FW_POS_HEADER]);
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)
@ -970,7 +1057,6 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
switch (ts->buf[FW_HDR_TYPE]) {
case CMD_HEADER_HELLO:
case CMD_HEADER_RESP:
case CMD_HEADER_REK:
break;
case QUEUE_HEADER_WAIT:
@ -985,9 +1071,24 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
break;
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;
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:
report_count = ts->buf[FW_HDR_COUNT];
if (report_count == 0 || report_count > 3) {
@ -998,7 +1099,12 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
}
report_len = ts->buf[FW_HDR_LENGTH] / report_count;
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,
"mismatching report length: %*ph\n",
HEADER_SIZE, ts->buf);
@ -1007,8 +1113,8 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
for (i = 0; i < report_count; i++) {
u8 *buf = ts->buf + HEADER_SIZE +
i * PACKET_SIZE;
elants_i2c_event(ts, buf);
i * report_len;
elants_i2c_event(ts, buf, report_len);
}
break;
@ -1250,6 +1356,7 @@ static int elants_i2c_probe(struct i2c_client *client,
init_completion(&ts->cmd_done);
ts->client = client;
ts->chip_id = (enum elants_chip_id)id->driver_data;
i2c_set_clientdata(client, ts);
ts->vcc33 = devm_regulator_get(&client->dev, "vcc33");
@ -1331,13 +1438,20 @@ static int elants_i2c_probe(struct i2c_client *client,
input_set_abs_params(ts->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
input_set_abs_params(ts->input, ABS_MT_TOOL_TYPE,
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_Y, ts->y_res);
if (ts->major_res > 0)
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,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) {
@ -1466,14 +1580,16 @@ static SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
elants_i2c_suspend, elants_i2c_resume);
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);
#ifdef CONFIG_ACPI
static const struct acpi_device_id elants_acpi_id[] = {
{ "ELAN0001", 0 },
{ "ELAN0001", EKTH3500 },
{ }
};
MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
@ -1482,6 +1598,7 @@ MODULE_DEVICE_TABLE(acpi, elants_acpi_id);
#ifdef CONFIG_OF
static const struct of_device_id elants_of_match[] = {
{ .compatible = "elan,ekth3500" },
{ .compatible = "elan,ektf3624" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, elants_of_match);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1044,6 +1044,7 @@ static void nexio_exit(struct usbtouch_usb *usbtouch)
static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
{
struct device *dev = &usbtouch->interface->dev;
struct nexio_touch_packet *packet = (void *) pkt;
struct nexio_priv *priv = usbtouch->priv;
unsigned int data_len = be16_to_cpu(packet->data_len);
@ -1062,6 +1063,8 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
/* send ACK */
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) {
usbtouch->type->max_xc = 2 * x_len;

View File

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

View File

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