summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-08-11 01:35:57 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2020-08-11 01:35:57 +0200
commit4bcf69e57063c9b1b15df1a293c969e80a1c97e6 (patch)
treeaacea8bf1ca4260d3064665ecc946ab78857b3a3 /drivers
parentMerge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid... (diff)
parentMerge branch 'next' into for-linus (diff)
downloadlinux-4bcf69e57063c9b1b15df1a293c969e80a1c97e6.tar.xz
linux-4bcf69e57063c9b1b15df1a293c969e80a1c97e6.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - an update to Elan touchpad controller driver supporting newer ICs with enhanced precision reports and a new firmware update process - an update to EXC3000 touch controller supporting additional parts - assorted driver fixups * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (27 commits) Input: exc3000 - add support to query model and fw_version Input: exc3000 - add reset gpio support Input: exc3000 - add EXC80H60 and EXC80H84 support dt-bindings: touchscreen: Convert EETI EXC3000 touchscreen to json-schema Input: sentelic - fix error return when fsp_reg_write fails Input: alps - remove redundant assignment to variable ret Input: ims-pcu - return error code rather than -ENOMEM Input: elan_i2c - add ic type 0x15 Input: atmel_mxt_ts - only read messages in mxt_acquire_irq() when necessary Input: uinput - fix typo in function name documentation Input: ati_remote2 - add missing newlines when printing module parameters Input: psmouse - add a newline when printing 'proto' by sysfs Input: synaptics-rmi4 - drop a duplicated word Input: elan_i2c - add support for high resolution reports Input: elan_i2c - do not constantly re-query pattern ID Input: elan_i2c - add firmware update info for ICs 0x11, 0x13, 0x14 Input: elan_i2c - handle firmware updated on newer ICs Input: elan_i2c - add support for different firmware page sizes Input: elan_i2c - fix detecting IAP version on older controllers Input: elan_i2c - handle devices with patterns above 1 ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/input-mt.c2
-rw-r--r--drivers/input/joystick/db9.c10
-rw-r--r--drivers/input/joystick/gamecon.c10
-rw-r--r--drivers/input/joystick/sidewinder.c15
-rw-r--r--drivers/input/joystick/spaceball.c8
-rw-r--r--drivers/input/keyboard/adp5589-keys.c2
-rw-r--r--drivers/input/keyboard/atkbd.c2
-rw-r--r--drivers/input/keyboard/gpio_keys.c1
-rw-r--r--drivers/input/misc/ati_remote2.c4
-rw-r--r--drivers/input/misc/cm109.c8
-rw-r--r--drivers/input/misc/ims-pcu.c2
-rw-r--r--drivers/input/misc/iqs269a.c21
-rw-r--r--drivers/input/misc/pwm-vibra.c2
-rw-r--r--drivers/input/misc/xen-kbdfront.c4
-rw-r--r--drivers/input/mouse/alps.c2
-rw-r--r--drivers/input/mouse/appletouch.c2
-rw-r--r--drivers/input/mouse/cyapa_gen3.c4
-rw-r--r--drivers/input/mouse/cyapa_gen5.c2
-rw-r--r--drivers/input/mouse/cyapa_gen6.c2
-rw-r--r--drivers/input/mouse/elan_i2c.h20
-rw-r--r--drivers/input/mouse/elan_i2c_core.c195
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c165
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c35
-rw-r--r--drivers/input/mouse/elantech.c12
-rw-r--r--drivers/input/mouse/hgpk.c4
-rw-r--r--drivers/input/mouse/navpoint.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c2
-rw-r--r--drivers/input/mouse/sentelic.c4
-rw-r--r--drivers/input/mouse/sermouse.c4
-rw-r--r--drivers/input/serio/i8042.c2
-rw-r--r--drivers/input/serio/libps2.c2
-rw-r--r--drivers/input/sparse-keymap.c2
-rw-r--r--drivers/input/tablet/gtco.c6
-rw-r--r--drivers/input/tablet/pegasus_notetaker.c2
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c56
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c3
-rw-r--r--drivers/input/touchscreen/elants_i2c.c2
-rw-r--r--drivers/input/touchscreen/elo.c2
-rw-r--r--drivers/input/touchscreen/exc3000.c248
-rw-r--r--drivers/input/touchscreen/iqs5xx.c2
-rw-r--r--drivers/input/touchscreen/max11801_ts.c1
-rw-r--r--drivers/input/touchscreen/stmfts.c2
42 files changed, 641 insertions, 235 deletions
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index a81e14148407..f699538bdac4 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -16,7 +16,7 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
if (dev->absinfo && test_bit(src, dev->absbit)) {
dev->absinfo[dst] = dev->absinfo[src];
dev->absinfo[dst].fuzz = 0;
- dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst);
+ __set_bit(dst, dev->absbit);
}
}
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index a7bc576eb342..434d265fa2e8 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -247,7 +247,7 @@ static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char
db9_saturn_write_sub(port, type, 3, powered, 0);
return data[0] = 0xe3;
}
- /* fall through */
+ fallthrough;
default:
return data[0];
}
@@ -267,14 +267,14 @@ static int db9_saturn_report(unsigned char id, unsigned char data[60], struct in
switch (data[j]) {
case 0x16: /* multi controller (analog 4 axis) */
input_report_abs(dev, db9_abs[5], data[j + 6]);
- /* fall through */
+ fallthrough;
case 0x15: /* mission stick (analog 3 axis) */
input_report_abs(dev, db9_abs[3], data[j + 4]);
input_report_abs(dev, db9_abs[4], data[j + 5]);
- /* fall through */
+ fallthrough;
case 0x13: /* racing controller (analog 1 axis) */
input_report_abs(dev, db9_abs[2], data[j + 3]);
- /* fall through */
+ fallthrough;
case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
case 0x02: /* digital pad (digital 2 axis + buttons) */
input_report_abs(dev, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
@@ -368,7 +368,7 @@ static void db9_timer(struct timer_list *t)
input_report_abs(dev2, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
input_report_abs(dev2, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
input_report_key(dev2, BTN_TRIGGER, ~data & DB9_FIRE1);
- /* fall through */
+ fallthrough;
case DB9_MULTI_0802:
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index e0a362be5812..88df68cc4ac6 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -485,7 +485,7 @@ static void gc_multi_process_packet(struct gc *gc)
switch (pad->type) {
case GC_MULTI2:
input_report_key(dev, BTN_THUMB, s & data[5]);
- /* fall through */
+ fallthrough;
case GC_MULTI:
input_report_abs(dev, ABS_X,
@@ -638,7 +638,7 @@ static void gc_psx_report_one(struct gc_pad *pad, unsigned char psx_type,
input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04);
input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02);
- /* fall through */
+ fallthrough;
case GC_PSX_NEGCON:
case GC_PSX_ANALOG:
@@ -872,7 +872,8 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
case GC_SNES:
for (i = 4; i < 8; i++)
input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]);
- /* fall through */
+ fallthrough;
+
case GC_NES:
for (i = 0; i < 4; i++)
input_set_capability(input_dev, EV_KEY, gc_snes_btn[i]);
@@ -880,7 +881,8 @@ static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
case GC_MULTI2:
input_set_capability(input_dev, EV_KEY, BTN_THUMB);
- /* fall through */
+ fallthrough;
+
case GC_MULTI:
input_set_capability(input_dev, EV_KEY, BTN_TRIGGER);
/* fall through */
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 1777e68c9f02..fac91ea14f17 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -656,16 +656,19 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
switch (i * m) {
case 60:
- sw->number++; /* fall through */
+ sw->number++;
+ fallthrough;
case 45: /* Ambiguous packet length */
if (j <= 40) { /* ID length less or eq 40 -> FSP */
case 43:
sw->type = SW_ID_FSP;
break;
}
- sw->number++; /* fall through */
+ sw->number++;
+ fallthrough;
case 30:
- sw->number++; /* fall through */
+ sw->number++;
+ fallthrough;
case 15:
sw->type = SW_ID_GP;
break;
@@ -681,9 +684,11 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
sw->type = SW_ID_PP;
break;
case 66:
- sw->bits = 3; /* fall through */
+ sw->bits = 3;
+ fallthrough;
case 198:
- sw->length = 22; /* fall through */
+ sw->length = 22;
+ fallthrough;
case 64:
sw->type = SW_ID_3DP;
if (j == 160)
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index cf7cbcd0c29d..429411c6c0a8 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -146,7 +146,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
break;
}
spaceball->escape = 0;
- /* fall through */
+ fallthrough;
case 'M':
case 'Q':
case 'S':
@@ -154,7 +154,7 @@ static irqreturn_t spaceball_interrupt(struct serio *serio,
spaceball->escape = 0;
data &= 0x1f;
}
- /* fall through */
+ fallthrough;
default:
if (spaceball->escape)
spaceball->escape = 0;
@@ -220,13 +220,13 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
input_dev->keybit[BIT_WORD(BTN_A)] |= BIT_MASK(BTN_A) |
BIT_MASK(BTN_B) | BIT_MASK(BTN_C) |
BIT_MASK(BTN_MODE);
- /* fall through */
+ fallthrough;
default:
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_2) |
BIT_MASK(BTN_3) | BIT_MASK(BTN_4) |
BIT_MASK(BTN_5) | BIT_MASK(BTN_6) |
BIT_MASK(BTN_7) | BIT_MASK(BTN_8);
- /* fall through */
+ fallthrough;
case SPACEBALL_3003C:
input_dev->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_1) |
BIT_MASK(BTN_8);
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
index e7d58e7f0257..eb0e9cd66bcb 100644
--- a/drivers/input/keyboard/adp5589-keys.c
+++ b/drivers/input/keyboard/adp5589-keys.c
@@ -1016,7 +1016,7 @@ static int adp5589_probe(struct i2c_client *client,
switch (id->driver_data) {
case ADP5585_02:
kpad->support_row5 = true;
- /* fall through */
+ fallthrough;
case ADP5585_01:
kpad->is_adp5585 = true;
kpad->var = &const_adp5585;
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 6ec28265771d..edc613efc158 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1241,7 +1241,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
case SERIO_8042_XL:
atkbd->translated = true;
- /* Fall through */
+ fallthrough;
case SERIO_8042:
if (serio->write)
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 53c9ff338dea..f2d4e4daa818 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -574,7 +574,6 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
IRQ_TYPE_EDGE_RISING : IRQ_TYPE_EDGE_FALLING;
break;
case EV_ACT_ANY:
- /* fall through */
default:
/*
* For other cases, we are OK letting suspend/resume
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 305f0160506a..8a36d78fed63 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -68,7 +68,7 @@ static int ati_remote2_get_channel_mask(char *buffer,
{
pr_debug("%s()\n", __func__);
- return sprintf(buffer, "0x%04x", *(unsigned int *)kp->arg);
+ return sprintf(buffer, "0x%04x\n", *(unsigned int *)kp->arg);
}
static int ati_remote2_set_mode_mask(const char *val,
@@ -84,7 +84,7 @@ static int ati_remote2_get_mode_mask(char *buffer,
{
pr_debug("%s()\n", __func__);
- return sprintf(buffer, "0x%02x", *(unsigned int *)kp->arg);
+ return sprintf(buffer, "0x%02x\n", *(unsigned int *)kp->arg);
}
static unsigned int channel_mask = ATI_REMOTE2_MAX_CHANNEL_MASK;
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index c09b9628ad34..e413801f0491 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -663,12 +663,8 @@ static const struct usb_device_id cm109_usb_table[] = {
static void cm109_usb_cleanup(struct cm109_dev *dev)
{
kfree(dev->ctl_req);
- if (dev->ctl_data)
- usb_free_coherent(dev->udev, USB_PKT_LEN,
- dev->ctl_data, dev->ctl_dma);
- if (dev->irq_data)
- usb_free_coherent(dev->udev, USB_PKT_LEN,
- dev->irq_data, dev->irq_dma);
+ usb_free_coherent(dev->udev, USB_PKT_LEN, dev->ctl_data, dev->ctl_dma);
+ usb_free_coherent(dev->udev, USB_PKT_LEN, dev->irq_data, dev->irq_dma);
usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */
usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index d8dbfc030d0f..08b9b5cdb943 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -335,7 +335,7 @@ static int ims_pcu_setup_gamepad(struct ims_pcu *pcu)
err_free_mem:
input_free_device(input);
kfree(gamepad);
- return -ENOMEM;
+ return error;
}
static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c
index 6699eb160a0f..a348247d3d38 100644
--- a/drivers/input/misc/iqs269a.c
+++ b/drivers/input/misc/iqs269a.c
@@ -575,8 +575,7 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
case IQS269_LOCAL_CAP_SIZE_GLOBAL_0pF5:
engine_a |= IQS269_CHx_ENG_A_LOCAL_CAP_SIZE;
-
- /* fall through */
+ fallthrough;
case IQS269_LOCAL_CAP_SIZE_GLOBAL_ONLY:
engine_b |= IQS269_CHx_ENG_B_LOCAL_CAP_ENABLE;
@@ -731,14 +730,12 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
iqs269->switches[i].code = val;
iqs269->switches[i].enabled = true;
}
-
- /* fall through */
+ fallthrough;
case IQS269_CHx_HALL_INACTIVE:
if (iqs269->hall_enable)
break;
-
- /* fall through */
+ fallthrough;
default:
iqs269->keycode[i * IQS269_NUM_CH + reg] = val;
@@ -1143,14 +1140,12 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
sw_code,
state & BIT(j));
}
-
- /* fall through */
+ fallthrough;
case IQS269_CHx_HALL_INACTIVE:
if (iqs269->hall_enable)
continue;
-
- /* fall through */
+ fallthrough;
default:
if (keycode != KEY_RESERVED)
@@ -1273,14 +1268,12 @@ static int iqs269_report(struct iqs269_private *iqs269)
input_report_switch(iqs269->keypad,
sw_code,
state & BIT(j));
-
- /* fall through */
+ fallthrough;
case IQS269_CHx_HALL_INACTIVE:
if (iqs269->hall_enable)
continue;
-
- /* fall through */
+ fallthrough;
default:
input_report_key(iqs269->keypad, keycode,
diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
index 8ceaf7db2882..81e777a04b88 100644
--- a/drivers/input/misc/pwm-vibra.c
+++ b/drivers/input/misc/pwm-vibra.c
@@ -190,7 +190,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
default:
dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
- /* Fall through */
+ fallthrough;
case -EPROBE_DEFER:
return err;
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
index a1bba722b234..4ff5cd2a6d8d 100644
--- a/drivers/input/misc/xen-kbdfront.c
+++ b/drivers/input/misc/xen-kbdfront.c
@@ -124,7 +124,7 @@ static void xenkbd_handle_mt_event(struct xenkbd_info *info,
switch (mtouch->event_type) {
case XENKBD_MT_EV_DOWN:
input_mt_report_slot_state(info->mtouch, MT_TOOL_FINGER, true);
- /* fall through */
+ fallthrough;
case XENKBD_MT_EV_MOTION:
input_report_abs(info->mtouch, ABS_MT_POSITION_X,
@@ -524,7 +524,7 @@ static void xenkbd_backend_changed(struct xenbus_device *dev,
case XenbusStateClosed:
if (dev->state == XenbusStateClosed)
break;
- /* fall through - Missed the backend's CLOSING state */
+ fallthrough; /* Missed the backend's CLOSING state */
case XenbusStateClosing:
xenbus_frontend_closed(dev);
break;
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 34700eda0429..b067bfd2699c 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1929,7 +1929,7 @@ static int alps_monitor_mode(struct psmouse *psmouse, bool enable)
static int alps_absolute_mode_v6(struct psmouse *psmouse)
{
u16 reg_val = 0x181;
- int ret = -1;
+ int ret;
/* enter monitor mode, to write the register */
if (alps_monitor_mode(psmouse, true))
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 3f06e8a495d8..bfa26651c0be 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -458,7 +458,7 @@ static int atp_status_check(struct urb *urb)
dev->info->datalen, dev->urb->actual_length);
dev->overflow_warned = true;
}
- /* fall through */
+ fallthrough;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 00e395dfc3d5..a0361f9325f8 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -1067,7 +1067,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
return error;
}
- /* Fall through */
+ fallthrough;
case CYAPA_STATE_BL_IDLE:
/* Try to get firmware version in bootloader mode. */
cyapa_gen3_bl_query_data(cyapa);
@@ -1078,7 +1078,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
return error;
}
- /* Fall through */
+ fallthrough;
case CYAPA_STATE_OP:
/*
* Reading query data before going back to the full mode
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 7f012bfa2658..bb3a63d1268d 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -2554,7 +2554,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
}
cyapa->state = CYAPA_STATE_GEN5_APP;
- /* fall through */
+ fallthrough;
case CYAPA_STATE_GEN5_APP:
/*
diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c
index c1b524ab4623..7eba66fbef58 100644
--- a/drivers/input/mouse/cyapa_gen6.c
+++ b/drivers/input/mouse/cyapa_gen6.c
@@ -680,7 +680,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa)
}
cyapa->state = CYAPA_STATE_GEN6_APP;
- /* fall through */
+ fallthrough;
case CYAPA_STATE_GEN6_APP:
/*
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index a9074ac9364f..c75b00c45d75 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -26,6 +26,8 @@
#define ETP_CALIBRATE_MAX_LEN 3
+#define ETP_FEATURE_REPORT_MK BIT(0)
+
/* IAP Firmware handling */
#define ETP_PRODUCT_ID_FORMAT_STRING "%d.0"
#define ETP_FW_NAME "elan_i2c_" ETP_PRODUCT_ID_FORMAT_STRING ".bin"
@@ -33,6 +35,8 @@
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
#define ETP_FW_IAP_INTF_ERR (1 << 4)
#define ETP_FW_PAGE_SIZE 64
+#define ETP_FW_PAGE_SIZE_128 128
+#define ETP_FW_PAGE_SIZE_512 512
#define ETP_FW_SIGNATURE_SIZE 6
struct i2c_client;
@@ -55,8 +59,9 @@ struct elan_transport_ops {
int (*get_baseline_data)(struct i2c_client *client,
bool max_baseliune, u8 *value);
- int (*get_version)(struct i2c_client *client, bool iap, u8 *version);
- int (*get_sm_version)(struct i2c_client *client,
+ int (*get_version)(struct i2c_client *client, u8 pattern, bool iap,
+ u8 *version);
+ int (*get_sm_version)(struct i2c_client *client, u8 pattern,
u16 *ic_type, u8 *version, u8 *clickpad);
int (*get_checksum)(struct i2c_client *client, bool iap, u16 *csum);
int (*get_product_id)(struct i2c_client *client, u16 *id);
@@ -72,13 +77,18 @@ struct elan_transport_ops {
int (*iap_get_mode)(struct i2c_client *client, enum tp_mode *mode);
int (*iap_reset)(struct i2c_client *client);
- int (*prepare_fw_update)(struct i2c_client *client);
- int (*write_fw_block)(struct i2c_client *client,
+ int (*prepare_fw_update)(struct i2c_client *client, u16 ic_type,
+ u8 iap_version);
+ int (*write_fw_block)(struct i2c_client *client, u16 fw_page_size,
const u8 *page, u16 checksum, int idx);
int (*finish_fw_update)(struct i2c_client *client,
struct completion *reset_done);
- int (*get_report)(struct i2c_client *client, u8 *report);
+ int (*get_report_features)(struct i2c_client *client, u8 pattern,
+ unsigned int *features,
+ unsigned int *report_len);
+ int (*get_report)(struct i2c_client *client, u8 *report,
+ unsigned int report_len);
int (*get_pressure_adjustment)(struct i2c_client *client,
int *adjustment);
int (*get_pattern)(struct i2c_client *client, u8 *pattern);
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 6291fb5fa015..c599e21a8478 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -50,12 +50,14 @@
#define ETP_MAX_FINGERS 5
#define ETP_FINGER_DATA_LEN 5
#define ETP_REPORT_ID 0x5D
+#define ETP_REPORT_ID2 0x60 /* High precision report */
#define ETP_TP_REPORT_ID 0x5E
#define ETP_REPORT_ID_OFFSET 2
#define ETP_TOUCH_INFO_OFFSET 3
#define ETP_FINGER_DATA_OFFSET 4
#define ETP_HOVER_INFO_OFFSET 30
-#define ETP_MAX_REPORT_LEN 34
+#define ETP_MK_DATA_OFFSET 33 /* For high precision reports */
+#define ETP_MAX_REPORT_LEN 39
/* The main device structure */
struct elan_tp_data {
@@ -85,11 +87,14 @@ struct elan_tp_data {
u8 sm_version;
u8 iap_version;
u16 fw_checksum;
+ unsigned int report_features;
+ unsigned int report_len;
int pressure_adjustment;
u8 mode;
u16 ic_type;
u16 fw_validpage_count;
- u16 fw_signature_address;
+ u16 fw_page_size;
+ u32 fw_signature_address;
bool irq_wake;
@@ -100,8 +105,8 @@ struct elan_tp_data {
bool middle_button;
};
-static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
- u16 *signature_address)
+static int elan_get_fwinfo(u16 ic_type, u8 iap_version, u16 *validpage_count,
+ u32 *signature_address, u16 *page_size)
{
switch (ic_type) {
case 0x00:
@@ -126,16 +131,37 @@ static int elan_get_fwinfo(u16 ic_type, u16 *validpage_count,
case 0x10:
*validpage_count = 1024;
break;
+ case 0x11:
+ *validpage_count = 1280;
+ break;
+ case 0x13:
+ *validpage_count = 2048;
+ break;
+ case 0x14:
+ case 0x15:
+ *validpage_count = 1024;
+ break;
default:
/* unknown ic type clear value */
*validpage_count = 0;
*signature_address = 0;
+ *page_size = 0;
return -ENXIO;
}
*signature_address =
(*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE;
+ if ((ic_type == 0x14 || ic_type == 0x15) && iap_version >= 2) {
+ *validpage_count /= 8;
+ *page_size = ETP_FW_PAGE_SIZE_512;
+ } else if (ic_type >= 0x0D && iap_version >= 1) {
+ *validpage_count /= 2;
+ *page_size = ETP_FW_PAGE_SIZE_128;
+ } else {
+ *page_size = ETP_FW_PAGE_SIZE;
+ }
+
return 0;
}
@@ -215,8 +241,13 @@ static int elan_query_product(struct elan_tp_data *data)
if (error)
return error;
- error = data->ops->get_sm_version(data->client, &data->ic_type,
- &data->sm_version, &data->clickpad);
+ error = data->ops->get_pattern(data->client, &data->pattern);
+ if (error)
+ return error;
+
+ error = data->ops->get_sm_version(data->client, data->pattern,
+ &data->ic_type, &data->sm_version,
+ &data->clickpad);
if (error)
return error;
@@ -312,9 +343,9 @@ static int elan_initialize(struct elan_tp_data *data)
static int elan_query_device_info(struct elan_tp_data *data)
{
int error;
- u16 ic_type;
- error = data->ops->get_version(data->client, false, &data->fw_version);
+ error = data->ops->get_version(data->client, data->pattern, false,
+ &data->fw_version);
if (error)
return error;
@@ -323,7 +354,8 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;
- error = data->ops->get_version(data->client, true, &data->iap_version);
+ error = data->ops->get_version(data->client, data->pattern,
+ true, &data->iap_version);
if (error)
return error;
@@ -332,17 +364,16 @@ static int elan_query_device_info(struct elan_tp_data *data)
if (error)
return error;
- error = data->ops->get_pattern(data->client, &data->pattern);
+ error = data->ops->get_report_features(data->client, data->pattern,
+ &data->report_features,
+ &data->report_len);
if (error)
return error;
- if (data->pattern == 0x01)
- ic_type = data->ic_type;
- else
- ic_type = data->iap_version;
-
- error = elan_get_fwinfo(ic_type, &data->fw_validpage_count,
- &data->fw_signature_address);
+ error = elan_get_fwinfo(data->ic_type, data->iap_version,
+ &data->fw_validpage_count,
+ &data->fw_signature_address,
+ &data->fw_page_size);
if (error)
dev_warn(&data->client->dev,
"unexpected iap version %#04x (ic type: %#04x), firmware update will not work\n",
@@ -351,16 +382,21 @@ static int elan_query_device_info(struct elan_tp_data *data)
return 0;
}
-static unsigned int elan_convert_resolution(u8 val)
+static unsigned int elan_convert_resolution(u8 val, u8 pattern)
{
/*
- * (value from firmware) * 10 + 790 = dpi
- *
+ * pattern <= 0x01:
+ * (value from firmware) * 10 + 790 = dpi
+ * else
+ * ((value from firmware) + 3) * 100 = dpi
+ */
+ int res = pattern <= 0x01 ?
+ (int)(char)val * 10 + 790 : ((int)(char)val + 3) * 100;
+ /*
* We also have to convert dpi to dots/mm (*10/254 to avoid floating
* point).
*/
-
- return ((int)(char)val * 10 + 790) * 10 / 254;
+ return res * 10 / 254;
}
static int elan_query_device_parameters(struct elan_tp_data *data)
@@ -409,8 +445,8 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
if (error)
return error;
- data->x_res = elan_convert_resolution(hw_x_res);
- data->y_res = elan_convert_resolution(hw_y_res);
+ data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
+ data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
} else {
data->x_res = (data->max_x + 1) / x_mm;
data->y_res = (data->max_y + 1) / y_mm;
@@ -430,14 +466,14 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
* IAP firmware updater related routines
**********************************************************
*/
-static int elan_write_fw_block(struct elan_tp_data *data,
+static int elan_write_fw_block(struct elan_tp_data *data, u16 page_size,
const u8 *page, u16 checksum, int idx)
{
int retry = ETP_RETRY_COUNT;
int error;
do {
- error = data->ops->write_fw_block(data->client,
+ error = data->ops->write_fw_block(data->client, page_size,
page, checksum, idx);
if (!error)
return 0;
@@ -460,21 +496,23 @@ static int __elan_update_firmware(struct elan_tp_data *data,
u16 boot_page_count;
u16 sw_checksum = 0, fw_checksum = 0;
- error = data->ops->prepare_fw_update(client);
+ error = data->ops->prepare_fw_update(client, data->ic_type,
+ data->iap_version);
if (error)
return error;
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
- boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
+ boot_page_count = (iap_start_addr * 2) / data->fw_page_size;
for (i = boot_page_count; i < data->fw_validpage_count; i++) {
u16 checksum = 0;
- const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
+ const u8 *page = &fw->data[i * data->fw_page_size];
- for (j = 0; j < ETP_FW_PAGE_SIZE; j += 2)
+ for (j = 0; j < data->fw_page_size; j += 2)
checksum += ((page[j + 1] << 8) | page[j]);
- error = elan_write_fw_block(data, page, checksum, i);
+ error = elan_write_fw_block(data, data->fw_page_size,
+ page, checksum, i);
if (error) {
dev_err(dev, "write page %d fail: %d\n", i, error);
return error;
@@ -886,24 +924,22 @@ static const struct attribute_group *elan_sysfs_groups[] = {
* Elan isr functions
******************************************************************
*/
-static void elan_report_contact(struct elan_tp_data *data,
- int contact_num, bool contact_valid,
- u8 *finger_data)
+static void elan_report_contact(struct elan_tp_data *data, int contact_num,
+ bool contact_valid, bool high_precision,
+ u8 *packet, u8 *finger_data)
{
struct input_dev *input = data->input;
unsigned int pos_x, pos_y;
- unsigned int pressure, mk_x, mk_y;
- unsigned int area_x, area_y, major, minor;
- unsigned int scaled_pressure;
+ unsigned int pressure, scaled_pressure;
if (contact_valid) {
- pos_x = ((finger_data[0] & 0xf0) << 4) |
- finger_data[1];
- pos_y = ((finger_data[0] & 0x0f) << 8) |
- finger_data[2];
- mk_x = (finger_data[3] & 0x0f);
- mk_y = (finger_data[3] >> 4);
- pressure = finger_data[4];
+ if (high_precision) {
+ pos_x = get_unaligned_be16(&finger_data[0]);
+ pos_y = get_unaligned_be16(&finger_data[2]);
+ } else {
+ pos_x = ((finger_data[0] & 0xf0) << 4) | finger_data[1];
+ pos_y = ((finger_data[0] & 0x0f) << 8) | finger_data[2];
+ }
if (pos_x > data->max_x || pos_y > data->max_y) {
dev_dbg(input->dev.parent,
@@ -913,18 +949,8 @@ static void elan_report_contact(struct elan_tp_data *data,
return;
}
- /*
- * To avoid treating large finger as palm, let's reduce the
- * width x and y per trace.
- */
- area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
- area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
-
- major = max(area_x, area_y);
- minor = min(area_x, area_y);
-
+ pressure = finger_data[4];
scaled_pressure = pressure + data->pressure_adjustment;
-
if (scaled_pressure > ETP_MAX_PRESSURE)
scaled_pressure = ETP_MAX_PRESSURE;
@@ -933,16 +959,37 @@ static void elan_report_contact(struct elan_tp_data *data,
input_report_abs(input, ABS_MT_POSITION_X, pos_x);
input_report_abs(input, ABS_MT_POSITION_Y, data->max_y - pos_y);
input_report_abs(input, ABS_MT_PRESSURE, scaled_pressure);
- input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
- input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
- input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
+
+ if (data->report_features & ETP_FEATURE_REPORT_MK) {
+ unsigned int mk_x, mk_y, area_x, area_y;
+ u8 mk_data = high_precision ?
+ packet[ETP_MK_DATA_OFFSET + contact_num] :
+ finger_data[3];
+
+ mk_x = mk_data & 0x0f;
+ mk_y = mk_data >> 4;
+
+ /*
+ * To avoid treating large finger as palm, let's reduce
+ * the width x and y per trace.
+ */
+ area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
+ area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
+
+ input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+ max(area_x, area_y));
+ input_report_abs(input, ABS_MT_TOUCH_MINOR,
+ min(area_x, area_y));
+ }
} else {
input_mt_slot(input, contact_num);
input_mt_report_slot_inactive(input);
}
}
-static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
+static void elan_report_absolute(struct elan_tp_data *data, u8 *packet,
+ bool high_precision)
{
struct input_dev *input = data->input;
u8 *finger_data = &packet[ETP_FINGER_DATA_OFFSET];
@@ -953,11 +1000,12 @@ static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
pm_wakeup_event(&data->client->dev, 0);
- hover_event = hover_info & 0x40;
- for (i = 0; i < ETP_MAX_FINGERS; i++) {
- contact_valid = tp_info & (1U << (3 + i));
- elan_report_contact(data, i, contact_valid, finger_data);
+ hover_event = hover_info & BIT(6);
+ for (i = 0; i < ETP_MAX_FINGERS; i++) {
+ contact_valid = tp_info & BIT(3 + i);
+ elan_report_contact(data, i, contact_valid, high_precision,
+ packet, finger_data);
if (contact_valid)
finger_data += ETP_FINGER_DATA_LEN;
}
@@ -1015,13 +1063,16 @@ static irqreturn_t elan_isr(int irq, void *dev_id)
goto out;
}
- error = data->ops->get_report(data->client, report);
+ error = data->ops->get_report(data->client, report, data->report_len);
if (error)
goto out;
switch (report[ETP_REPORT_ID_OFFSET]) {
case ETP_REPORT_ID:
- elan_report_absolute(data, report);
+ elan_report_absolute(data, report, false);
+ break;
+ case ETP_REPORT_ID2:
+ elan_report_absolute(data, report, true);
break;
case ETP_TP_REPORT_ID:
elan_report_trackpoint(data, report);
@@ -1112,7 +1163,9 @@ static int elan_setup_input_device(struct elan_tp_data *data)
input_abs_set_res(input, ABS_X, data->x_res);
input_abs_set_res(input, ABS_Y, data->y_res);
input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
- input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
+ if (data->report_features & ETP_FEATURE_REPORT_MK)
+ input_set_abs_params(input, ABS_TOOL_WIDTH,
+ 0, ETP_FINGER_WIDTH, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0);
/* And MT parameters */
@@ -1122,10 +1175,12 @@ static int elan_setup_input_device(struct elan_tp_data *data)
input_abs_set_res(input, ABS_MT_POSITION_Y, data->y_res);
input_set_abs_params(input, ABS_MT_PRESSURE, 0,
ETP_MAX_PRESSURE, 0, 0);
- input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
- ETP_FINGER_WIDTH * max_width, 0, 0);
- input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
- ETP_FINGER_WIDTH * min_width, 0, 0);
+ if (data->report_features & ETP_FEATURE_REPORT_MK) {
+ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR,
+ 0, ETP_FINGER_WIDTH * max_width, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MINOR,
+ 0, ETP_FINGER_WIDTH * min_width, 0, 0);
+ }
data->input = input;
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index 058b35b1f9a9..5a496d4ffa49 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
+#include <linux/slab.h>
#include <linux/sched.h>
#include <asm/unaligned.h>
@@ -43,6 +44,8 @@
#define ETP_I2C_RESOLUTION_CMD 0x0108
#define ETP_I2C_PRESSURE_CMD 0x010A
#define ETP_I2C_IAP_VERSION_CMD 0x0110
+#define ETP_I2C_IC_TYPE_P0_CMD 0x0110
+#define ETP_I2C_IAP_VERSION_P0_CMD 0x0111
#define ETP_I2C_SET_CMD 0x0300
#define ETP_I2C_POWER_CMD 0x0307
#define ETP_I2C_FW_CHECKSUM_CMD 0x030F
@@ -53,8 +56,12 @@
#define ETP_I2C_CALIBRATE_CMD 0x0316
#define ETP_I2C_MAX_BASELINE_CMD 0x0317
#define ETP_I2C_MIN_BASELINE_CMD 0x0318
+#define ETP_I2C_IAP_TYPE_REG 0x0040
+#define ETP_I2C_IAP_TYPE_CMD 0x0304
#define ETP_I2C_REPORT_LEN 34
+#define ETP_I2C_REPORT_LEN_ID2 39
+#define ETP_I2C_REPORT_MAX_LEN 39
#define ETP_I2C_DESC_LENGTH 30
#define ETP_I2C_REPORT_DESC_LENGTH 158
#define ETP_I2C_INF_LENGTH 2
@@ -249,56 +256,52 @@ static int elan_i2c_get_pattern(struct i2c_client *client, u8 *pattern)
dev_err(&client->dev, "failed to get pattern: %d\n", error);
return error;
}
- *pattern = val[1];
+
+ /*
+ * Not all versions of firmware implement "get pattern" command.
+ * When this command is not implemented the device will respond
+ * with 0xFF 0xFF, which we will treat as "old" pattern 0.
+ */
+ *pattern = val[0] == 0xFF && val[1] == 0xFF ? 0 : val[1];
return 0;
}
static int elan_i2c_get_version(struct i2c_client *client,
- bool iap, u8 *version)
+ u8 pattern, bool iap, u8 *version)
{
int error;
- u8 pattern_ver;
+ u16 cmd;
u8 val[3];
- error = elan_i2c_get_pattern(client, &pattern_ver);
- if (error) {
- dev_err(&client->dev, "failed to get pattern version\n");
- return error;
- }
+ if (!iap)
+ cmd = ETP_I2C_FW_VERSION_CMD;
+ else if (pattern == 0)
+ cmd = ETP_I2C_IAP_VERSION_P0_CMD;
+ else
+ cmd = ETP_I2C_IAP_VERSION_CMD;
- error = elan_i2c_read_cmd(client,
- iap ? ETP_I2C_IAP_VERSION_CMD :
- ETP_I2C_FW_VERSION_CMD,
- val);
+ error = elan_i2c_read_cmd(client, cmd, val);
if (error) {
dev_err(&client->dev, "failed to get %s version: %d\n",
iap ? "IAP" : "FW", error);
return error;
}
- if (pattern_ver == 0x01)
+ if (pattern >= 0x01)
*version = iap ? val[1] : val[0];
else
*version = val[0];
return 0;
}
-static int elan_i2c_get_sm_version(struct i2c_client *client,
- u16 *ic_type, u8 *version,
- u8 *clickpad)
+static int elan_i2c_get_sm_version(struct i2c_client *client, u8 pattern,
+ u16 *ic_type, u8 *version, u8 *clickpad)
{
int error;
- u8 pattern_ver;
u8 val[3];
- error = elan_i2c_get_pattern(client, &pattern_ver);
- if (error) {
- dev_err(&client->dev, "failed to get pattern version\n");
- return error;
- }
-
- if (pattern_ver == 0x01) {
+ if (pattern >= 0x01) {
error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_CMD, val);
if (error) {
dev_err(&client->dev, "failed to get ic type: %d\n",
@@ -324,7 +327,14 @@ static int elan_i2c_get_sm_version(struct i2c_client *client,
return error;
}
*version = val[0];
- *ic_type = val[1];
+
+ error = elan_i2c_read_cmd(client, ETP_I2C_IC_TYPE_P0_CMD, val);
+ if (error) {
+ dev_err(&client->dev, "failed to get ic type: %d\n",
+ error);
+ return error;
+ }
+ *ic_type = val[0];
error = elan_i2c_read_cmd(client, ETP_I2C_NSM_VERSION_CMD,
val);
@@ -386,7 +396,7 @@ static int elan_i2c_get_max(struct i2c_client *client,
return error;
}
- *max_x = le16_to_cpup((__le16 *)val) & 0x0fff;
+ *max_x = le16_to_cpup((__le16 *)val);
error = elan_i2c_read_cmd(client, ETP_I2C_MAX_Y_AXIS_CMD, val);
if (error) {
@@ -394,7 +404,7 @@ static int elan_i2c_get_max(struct i2c_client *client,
return error;
}
- *max_y = le16_to_cpup((__le16 *)val) & 0x0fff;
+ *max_y = le16_to_cpup((__le16 *)val);
return 0;
}
@@ -507,7 +517,43 @@ static int elan_i2c_set_flash_key(struct i2c_client *client)
return 0;
}
-static int elan_i2c_prepare_fw_update(struct i2c_client *client)
+static int elan_read_write_iap_type(struct i2c_client *client)
+{
+ int error;
+ u16 constant;
+ u8 val[3];
+ int retry = 3;
+
+ do {
+ error = elan_i2c_write_cmd(client, ETP_I2C_IAP_TYPE_CMD,
+ ETP_I2C_IAP_TYPE_REG);
+ if (error) {
+ dev_err(&client->dev,
+ "cannot write iap type: %d\n", error);
+ return error;
+ }
+
+ error = elan_i2c_read_cmd(client, ETP_I2C_IAP_TYPE_CMD, val);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to read iap type register: %d\n",
+ error);
+ return error;
+ }
+ constant = le16_to_cpup((__le16 *)val);
+ dev_dbg(&client->dev, "iap type reg: 0x%04x\n", constant);
+
+ if (constant == ETP_I2C_IAP_TYPE_REG)
+ return 0;
+
+ } while (--retry > 0);
+
+ dev_err(&client->dev, "cannot set iap type\n");
+ return -EIO;
+}
+
+static int elan_i2c_prepare_fw_update(struct i2c_client *client, u16 ic_type,
+ u8 iap_version)
{
struct device *dev = &client->dev;
int error;
@@ -547,6 +593,12 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client)
return -EIO;
}
+ if (ic_type >= 0x0D && iap_version >= 1) {
+ error = elan_read_write_iap_type(client);
+ if (error)
+ return error;
+ }
+
/* Set flash key again */
error = elan_i2c_set_flash_key(client);
if (error)
@@ -572,57 +624,64 @@ static int elan_i2c_prepare_fw_update(struct i2c_client *client)
return 0;
}
-static int elan_i2c_write_fw_block(struct i2c_client *client,
+static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size,
const u8 *page, u16 checksum, int idx)
{
struct device *dev = &client->dev;
- u8 page_store[ETP_FW_PAGE_SIZE + 4];
+ u8 *page_store;
u8 val[3];
u16 result;
int ret, error;
+ page_store = kmalloc(fw_page_size + 4, GFP_KERNEL);
+ if (!page_store)
+ return -ENOMEM;
+
page_store[0] = ETP_I2C_IAP_REG_L;
page_store[1] = ETP_I2C_IAP_REG_H;
- memcpy(&page_store[2], page, ETP_FW_PAGE_SIZE);
+ memcpy(&page_store[2], page, fw_page_size);
/* recode checksum at last two bytes */
- put_unaligned_le16(checksum, &page_store[ETP_FW_PAGE_SIZE + 2]);
+ put_unaligned_le16(checksum, &page_store[fw_page_size + 2]);
- ret = i2c_master_send(client, page_store, sizeof(page_store));
- if (ret != sizeof(page_store)) {
+ ret = i2c_master_send(client, page_store, fw_page_size + 4);
+ if (ret != fw_page_size + 4) {
error = ret < 0 ? ret : -EIO;
dev_err(dev, "Failed to write page %d: %d\n", idx, error);
- return error;
+ goto exit;
}
/* Wait for F/W to update one page ROM data. */
- msleep(35);
+ msleep(fw_page_size == ETP_FW_PAGE_SIZE_512 ? 50 : 35);
error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val);
if (error) {
dev_err(dev, "Failed to read IAP write result: %d\n", error);
- return error;
+ goto exit;
}
result = le16_to_cpup((__le16 *)val);
if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) {
dev_err(dev, "IAP reports failed write: %04hx\n",
result);
- return -EIO;
+ error = -EIO;
+ goto exit;
}
- return 0;
+exit:
+ kfree(page_store);
+ return error;
}
static int elan_i2c_finish_fw_update(struct i2c_client *client,
struct completion *completion)
{
struct device *dev = &client->dev;
- int error;
+ int error = 0;
int len;
- u8 buffer[ETP_I2C_REPORT_LEN];
+ u8 buffer[ETP_I2C_REPORT_MAX_LEN];
- len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_LEN);
- if (len != ETP_I2C_REPORT_LEN) {
+ len = i2c_master_recv(client, buffer, ETP_I2C_REPORT_MAX_LEN);
+ if (len <= 0) {
error = len < 0 ? len : -EIO;
dev_warn(dev, "failed to read I2C data after FW WDT reset: %d (%d)\n",
error, len);
@@ -656,20 +715,31 @@ static int elan_i2c_finish_fw_update(struct i2c_client *client,
return 0;
}
-static int elan_i2c_get_report(struct i2c_client *client, u8 *report)
+static int elan_i2c_get_report_features(struct i2c_client *client, u8 pattern,
+ unsigned int *features,
+ unsigned int *report_len)
+{
+ *features = ETP_FEATURE_REPORT_MK;
+ *report_len = pattern <= 0x01 ?
+ ETP_I2C_REPORT_LEN : ETP_I2C_REPORT_LEN_ID2;
+ return 0;
+}
+
+static int elan_i2c_get_report(struct i2c_client *client,
+ u8 *report, unsigned int report_len)
{
int len;
- len = i2c_master_recv(client, report, ETP_I2C_REPORT_LEN);
+ len = i2c_master_recv(client, report, report_len);
if (len < 0) {
dev_err(&client->dev, "failed to read report data: %d\n", len);
return len;
}
- if (len != ETP_I2C_REPORT_LEN) {
+ if (len != report_len) {
dev_err(&client->dev,
"wrong report length (%d vs %d expected)\n",
- len, ETP_I2C_REPORT_LEN);
+ len, report_len);
return -EIO;
}
@@ -706,5 +776,6 @@ const struct elan_transport_ops elan_i2c_ops = {
.get_pattern = elan_i2c_get_pattern,
+ .get_report_features = elan_i2c_get_report_features,
.get_report = elan_i2c_get_report,
};
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 8c3185d54c73..8ff823751f3b 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -147,7 +147,7 @@ static int elan_smbus_get_baseline_data(struct i2c_client *client,
}
static int elan_smbus_get_version(struct i2c_client *client,
- bool iap, u8 *version)
+ u8 pattern, bool iap, u8 *version)
{
int error;
u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
@@ -166,9 +166,8 @@ static int elan_smbus_get_version(struct i2c_client *client,
return 0;
}
-static int elan_smbus_get_sm_version(struct i2c_client *client,
- u16 *ic_type, u8 *version,
- u8 *clickpad)
+static int elan_smbus_get_sm_version(struct i2c_client *client, u8 pattern,
+ u16 *ic_type, u8 *version, u8 *clickpad)
{
int error;
u8 val[I2C_SMBUS_BLOCK_MAX] = {0};
@@ -340,7 +339,8 @@ static int elan_smbus_set_flash_key(struct i2c_client *client)
return 0;
}
-static int elan_smbus_prepare_fw_update(struct i2c_client *client)
+static int elan_smbus_prepare_fw_update(struct i2c_client *client, u16 ic_type,
+ u8 iap_version)
{
struct device *dev = &client->dev;
int len;
@@ -414,7 +414,7 @@ static int elan_smbus_prepare_fw_update(struct i2c_client *client)
}
-static int elan_smbus_write_fw_block(struct i2c_client *client,
+static int elan_smbus_write_fw_block(struct i2c_client *client, u16 fw_page_size,
const u8 *page, u16 checksum, int idx)
{
struct device *dev = &client->dev;
@@ -429,7 +429,7 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
*/
error = i2c_smbus_write_block_data(client,
ETP_SMBUS_WRITE_FW_BLOCK,
- ETP_FW_PAGE_SIZE / 2,
+ fw_page_size / 2,
page);
if (error) {
dev_err(dev, "Failed to write page %d (part %d): %d\n",
@@ -439,8 +439,8 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
error = i2c_smbus_write_block_data(client,
ETP_SMBUS_WRITE_FW_BLOCK,
- ETP_FW_PAGE_SIZE / 2,
- page + ETP_FW_PAGE_SIZE / 2);
+ fw_page_size / 2,
+ page + fw_page_size / 2);
if (error) {
dev_err(dev, "Failed to write page %d (part %d): %d\n",
idx, 2, error);
@@ -469,7 +469,21 @@ static int elan_smbus_write_fw_block(struct i2c_client *client,
return 0;
}
-static int elan_smbus_get_report(struct i2c_client *client, u8 *report)
+static int elan_smbus_get_report_features(struct i2c_client *client, u8 pattern,
+ unsigned int *features,
+ unsigned int *report_len)
+{
+ /*
+ * SMBus controllers with pattern 2 lack area info, as newer
+ * high-precision packets use that space for coordinates.
+ */
+ *features = pattern <= 0x01 ? ETP_FEATURE_REPORT_MK : 0;
+ *report_len = ETP_SMBUS_REPORT_LEN;
+ return 0;
+}
+
+static int elan_smbus_get_report(struct i2c_client *client,
+ u8 *report, unsigned int report_len)
{
int len;
@@ -534,6 +548,7 @@ const struct elan_transport_ops elan_smbus_ops = {
.write_fw_block = elan_smbus_write_fw_block,
.finish_fw_update = elan_smbus_finish_fw_update,
+ .get_report_features = elan_smbus_get_report_features,
.get_report = elan_smbus_get_report,
.get_pattern = elan_smbus_get_pattern,
};
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 2d8434b7b623..90f8765f9efc 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -383,7 +383,7 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
*/
if (packet[3] & 0x80)
fingers = 4;
- /* fall through */
+ fallthrough;
case 1:
/*
* byte 1: . . . . x11 x10 x9 x8
@@ -1146,7 +1146,7 @@ static int elantech_set_input_params(struct psmouse *psmouse)
case 2:
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
__set_bit(INPUT_PROP_SEMI_MT, dev->propbit);
- /* fall through */
+ fallthrough;
case 3:
if (info->hw_version == 3)
elantech_set_buttonpad_prop(psmouse);
@@ -1877,12 +1877,10 @@ static bool elantech_use_host_notify(struct psmouse *psmouse,
/* expected case */
break;
case ETP_BUS_SMB_ALERT_ONLY:
- /* fall-through */
case ETP_BUS_PS2_SMB_ALERT:
psmouse_dbg(psmouse, "Ignoring SMBus provider through alert protocol.\n");
break;
case ETP_BUS_SMB_HST_NTFY_ONLY:
- /* fall-through */
case ETP_BUS_PS2_SMB_HST_NTFY:
return true;
default:
@@ -1897,7 +1895,7 @@ static bool elantech_use_host_notify(struct psmouse *psmouse,
int elantech_init_smbus(struct psmouse *psmouse)
{
struct elantech_device_info info;
- int error = -EINVAL;
+ int error;
psmouse_reset(psmouse);
@@ -2015,7 +2013,7 @@ static int elantech_setup_ps2(struct psmouse *psmouse,
int elantech_init_ps2(struct psmouse *psmouse)
{
struct elantech_device_info info;
- int error = -EINVAL;
+ int error;
psmouse_reset(psmouse);
@@ -2036,7 +2034,7 @@ int elantech_init_ps2(struct psmouse *psmouse)
int elantech_init(struct psmouse *psmouse)
{
struct elantech_device_info info;
- int error = -EINVAL;
+ int error;
psmouse_reset(psmouse);
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 72a083f3fc4a..4dc441309aac 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -238,7 +238,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
/* we're not spewing, but this packet might be the start */
priv->spew_flag = MAYBE_SPEWING;
- /* fall-through */
+ fallthrough;
case MAYBE_SPEWING:
priv->spew_count++;
@@ -249,7 +249,7 @@ static void hgpk_spewing_hack(struct psmouse *psmouse,
/* excessive spew detected, request recalibration */
priv->spew_flag = SPEW_DETECTED;
- /* fall-through */
+ fallthrough;
case SPEW_DETECTED:
/* only recalibrate when the overall delta to the cursor
diff --git a/drivers/input/mouse/navpoint.c b/drivers/input/mouse/navpoint.c
index 0b75248c8380..c112980c2341 100644
--- a/drivers/input/mouse/navpoint.c
+++ b/drivers/input/mouse/navpoint.c
@@ -105,7 +105,7 @@ static void navpoint_packet(struct navpoint *navpoint)
case 0x19: /* Module 0, Hello packet */
if ((navpoint->data[1] & 0xf0) == 0x10)
break;
- /* FALLTHROUGH */
+ fallthrough;
default:
dev_warn(navpoint->dev,
"spurious packet: data=0x%02x,0x%02x,...\n",
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 527ae0b9a191..0b4a3039f312 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -2042,7 +2042,7 @@ static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp)
{
int type = *((unsigned int *)kp->arg);
- return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name);
+ return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
}
static int __init psmouse_init(void)
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index e99d9bf1a267..2716d2ba386a 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -441,7 +441,7 @@ static ssize_t fsp_attr_set_setreg(struct psmouse *psmouse, void *data,
fsp_reg_write_enable(psmouse, false);
- return count;
+ return retval;
}
PSMOUSE_DEFINE_WO_ATTR(setreg, S_IWUSR, NULL, fsp_attr_set_setreg);
@@ -794,7 +794,7 @@ static psmouse_ret_t fsp_process_byte(struct psmouse *psmouse)
/* on-pad click, filter it if necessary */
if ((ad->flags & FSPDRV_FLAG_EN_OPC) != FSPDRV_FLAG_EN_OPC)
packet[0] &= ~FSP_PB0_LBTN;
- /* fall through */
+ fallthrough;
case FSP_PKT_TYPE_NORMAL:
/* normal packet */
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index ea9242d53899..caa79c177c55 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -128,7 +128,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
case SERIO_MS:
sermouse->type = SERIO_MP;
- /* fall through */
+ fallthrough;
case SERIO_MP:
if ((data >> 2) & 3) break; /* M++ Wireless Extension packet. */
@@ -139,7 +139,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
case SERIO_MZP:
case SERIO_MZPP:
input_report_key(dev, BTN_SIDE, (data >> 5) & 1);
- /* fall through */
+ fallthrough;
case SERIO_MZ:
input_report_key(dev, BTN_MIDDLE, (data >> 4) & 1);
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 0dddf273afd9..d3eda48032e3 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -562,7 +562,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
str = last_str;
break;
}
- /* fall through - report timeout */
+ fallthrough; /* report timeout */
case 0xfc:
case 0xfd:
case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index a8c94a940a79..8a16e41f7b7f 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -418,7 +418,7 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data)
ps2dev->nak = 0;
break;
}
- /* Fall through */
+ fallthrough;
default:
/*
* Do not signal errors if we get unexpected reply while
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 530fd15eaeca..25bf8be6e711 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -247,7 +247,7 @@ void sparse_keymap_report_entry(struct input_dev *dev, const struct key_entry *k
case KE_SW:
value = ke->sw.value;
- /* fall through */
+ fallthrough;
case KE_VSW:
input_report_switch(dev, ke->sw.code, value);
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 96d65575f75a..44bb1f69b4b2 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -676,8 +676,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* Mask out the Y tilt value used for pressure */
device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+ fallthrough;
- /* Fall thru */
case 4:
/* Tilt */
input_report_abs(inputdev, ABS_TILT_X,
@@ -685,8 +685,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
input_report_abs(inputdev, ABS_TILT_Y,
sign_extend32(device->buffer[7], 6));
+ fallthrough;
- /* Fall thru */
case 2:
case 3:
/* Convert buttons, only 5 bits possible */
@@ -695,8 +695,8 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* We don't apply any meaning to the bitmask,
just report */
input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+ fallthrough;
- /* Fall thru */
case 1:
/* All reports have X and Y coords in the same place */
val = get_unaligned_le16(&device->buffer[1]);
diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c
index 38f087404f7a..749edbdb7ffa 100644
--- a/drivers/input/tablet/pegasus_notetaker.c
+++ b/drivers/input/tablet/pegasus_notetaker.c
@@ -146,7 +146,7 @@ static void pegasus_parse_packet(struct pegasus *pegasus)
/* xy data */
case BATTERY_LOW:
dev_warn_once(&dev->dev, "Pen battery low\n");
- /* fall through */
+ fallthrough;
case BATTERY_NO_REPORT:
case BATTERY_GOOD:
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index a2189739e30f..6b71b0aff115 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -20,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/input/mt.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -129,6 +130,7 @@ struct t9_range {
/* MXT_SPT_COMMSCONFIG_T18 */
#define MXT_COMMS_CTRL 0
#define MXT_COMMS_CMD 1
+#define MXT_COMMS_RETRIGEN BIT(6)
/* MXT_DEBUG_DIAGNOSTIC_T37 */
#define MXT_DIAGNOSTIC_PAGEUP 0x01
@@ -308,6 +310,7 @@ struct mxt_data {
struct t7_config t7_cfg;
struct mxt_dbg dbg;
struct gpio_desc *reset_gpio;
+ bool use_retrigen_workaround;
/* Cached parameters from object table */
u16 T5_address;
@@ -318,6 +321,7 @@ struct mxt_data {
u16 T71_address;
u8 T9_reportid_min;
u8 T9_reportid_max;
+ u16 T18_address;
u8 T19_reportid;
u16 T44_address;
u8 T100_reportid_min;
@@ -1190,9 +1194,11 @@ static int mxt_acquire_irq(struct mxt_data *data)
enable_irq(data->irq);
- error = mxt_process_messages_until_invalid(data);
- if (error)
- return error;
+ if (data->use_retrigen_workaround) {
+ error = mxt_process_messages_until_invalid(data);
+ if (error)
+ return error;
+ }
return 0;
}
@@ -1282,6 +1288,38 @@ static u32 mxt_calculate_crc(u8 *base, off_t start_off, off_t end_off)
return crc;
}
+static int mxt_check_retrigen(struct mxt_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+ int val;
+ struct irq_data *irqd;
+
+ data->use_retrigen_workaround = false;
+
+ irqd = irq_get_irq_data(data->irq);
+ if (!irqd)
+ return -EINVAL;
+
+ if (irqd_is_level_type(irqd))
+ return 0;
+
+ if (data->T18_address) {
+ error = __mxt_read_reg(client,
+ data->T18_address + MXT_COMMS_CTRL,
+ 1, &val);
+ if (error)
+ return error;
+
+ if (val & MXT_COMMS_RETRIGEN)
+ return 0;
+ }
+
+ dev_warn(&client->dev, "Enabling RETRIGEN workaround\n");
+ data->use_retrigen_workaround = true;
+ return 0;
+}
+
static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
{
struct device *dev = &data->client->dev;
@@ -1561,6 +1599,10 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
+ ret = mxt_check_retrigen(data);
+ if (ret)
+ goto release_mem;
+
ret = mxt_soft_reset(data);
if (ret)
goto release_mem;
@@ -1604,6 +1646,7 @@ static void mxt_free_object_table(struct mxt_data *data)
data->T71_address = 0;
data->T9_reportid_min = 0;
data->T9_reportid_max = 0;
+ data->T18_address = 0;
data->T19_reportid = 0;
data->T44_address = 0;
data->T100_reportid_min = 0;
@@ -1678,6 +1721,9 @@ static int mxt_parse_object_table(struct mxt_data *data,
object->num_report_ids - 1;
data->num_touchids = object->num_report_ids;
break;
+ case MXT_SPT_COMMSCONFIG_T18:
+ data->T18_address = object->start_address;
+ break;
case MXT_SPT_MESSAGECOUNT_T44:
data->T44_address = object->start_address;
break;
@@ -2141,6 +2187,10 @@ static int mxt_initialize(struct mxt_data *data)
if (error)
return error;
+ error = mxt_check_retrigen(data);
+ if (error)
+ return error;
+
error = request_firmware_nowait(THIS_MODULE, true, MXT_CFG_NAME,
&client->dev, GFP_KERNEL, data,
mxt_config_cb);
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 3a4f18d3450d..6ff81d48da86 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -288,7 +288,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata,
wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2];
return edt_ft5x06_ts_readwrite(tsdata->client, 4,
wrbuf, 0, NULL);
- /* fallthrough */
+
case EDT_M09:
case EDT_M12:
case EV_FT:
@@ -330,7 +330,6 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata,
}
break;
- /* fallthrough */
case EDT_M09:
case EDT_M12:
case EV_FT:
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 5477a5718202..b0bd5bb079be 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -955,7 +955,7 @@ static irqreturn_t elants_i2c_irq(int irq, void *_dev)
break;
ts->state = ELAN_STATE_NORMAL;
- /* fall through */
+ fallthrough;
case ELAN_STATE_NORMAL:
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index d6772a2c2d09..e0bacd34866a 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -348,7 +348,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
case 1: /* 6-byte protocol */
input_set_abs_params(input_dev, ABS_PRESSURE, 0, 15, 0, 0);
- /* fall through */
+ fallthrough;
case 2: /* 4-byte protocol */
input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index e007e2e8f626..a6597f026980 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -8,7 +8,9 @@
*/
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
@@ -16,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/sizes.h>
#include <linux/timer.h>
#include <asm/unaligned.h>
@@ -23,15 +26,59 @@
#define EXC3000_SLOTS_PER_FRAME 5
#define EXC3000_LEN_FRAME 66
#define EXC3000_LEN_POINT 10
-#define EXC3000_MT_EVENT 6
+
+#define EXC3000_LEN_MODEL_NAME 16
+#define EXC3000_LEN_FW_VERSION 16
+
+#define EXC3000_MT1_EVENT 0x06
+#define EXC3000_MT2_EVENT 0x18
+
#define EXC3000_TIMEOUT_MS 100
+#define EXC3000_RESET_MS 10
+#define EXC3000_READY_MS 100
+
+static const struct i2c_device_id exc3000_id[];
+
+struct eeti_dev_info {
+ const char *name;
+ int max_xy;
+};
+
+enum eeti_dev_id {
+ EETI_EXC3000,
+ EETI_EXC80H60,
+ EETI_EXC80H84,
+};
+
+static struct eeti_dev_info exc3000_info[] = {
+ [EETI_EXC3000] = {
+ .name = "EETI EXC3000 Touch Screen",
+ .max_xy = SZ_4K - 1,
+ },
+ [EETI_EXC80H60] = {
+ .name = "EETI EXC80H60 Touch Screen",
+ .max_xy = SZ_16K - 1,
+ },
+ [EETI_EXC80H84] = {
+ .name = "EETI EXC80H84 Touch Screen",
+ .max_xy = SZ_16K - 1,
+ },
+};
+
struct exc3000_data {
struct i2c_client *client;
+ const struct eeti_dev_info *info;
struct input_dev *input;
struct touchscreen_properties prop;
+ struct gpio_desc *reset;
struct timer_list timer;
u8 buf[2 * EXC3000_LEN_FRAME];
+ struct completion wait_event;
+ struct mutex query_lock;
+ int query_result;
+ char model[EXC3000_LEN_MODEL_NAME];
+ char fw_version[EXC3000_LEN_FW_VERSION];
};
static void exc3000_report_slots(struct input_dev *input,
@@ -58,10 +105,15 @@ static void exc3000_timer(struct timer_list *t)
input_sync(data->input);
}
-static int exc3000_read_frame(struct i2c_client *client, u8 *buf)
+static int exc3000_read_frame(struct exc3000_data *data, u8 *buf)
{
+ struct i2c_client *client = data->client;
+ u8 expected_event = EXC3000_MT1_EVENT;
int ret;
+ if (data->info->max_xy == SZ_16K - 1)
+ expected_event = EXC3000_MT2_EVENT;
+
ret = i2c_master_send(client, "'", 2);
if (ret < 0)
return ret;
@@ -76,19 +128,21 @@ static int exc3000_read_frame(struct i2c_client *client, u8 *buf)
if (ret != EXC3000_LEN_FRAME)
return -EIO;
- if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME ||
- buf[2] != EXC3000_MT_EVENT)
+ if (get_unaligned_le16(buf) != EXC3000_LEN_FRAME)
+ return -EINVAL;
+
+ if (buf[2] != expected_event)
return -EINVAL;
return 0;
}
-static int exc3000_read_data(struct i2c_client *client,
+static int exc3000_read_data(struct exc3000_data *data,
u8 *buf, int *n_slots)
{
int error;
- error = exc3000_read_frame(client, buf);
+ error = exc3000_read_frame(data, buf);
if (error)
return error;
@@ -98,7 +152,7 @@ static int exc3000_read_data(struct i2c_client *client,
if (*n_slots > EXC3000_SLOTS_PER_FRAME) {
/* Read 2nd frame to get the rest of the contacts. */
- error = exc3000_read_frame(client, buf + EXC3000_LEN_FRAME);
+ error = exc3000_read_frame(data, buf + EXC3000_LEN_FRAME);
if (error)
return error;
@@ -110,6 +164,28 @@ static int exc3000_read_data(struct i2c_client *client,
return 0;
}
+static int exc3000_query_interrupt(struct exc3000_data *data)
+{
+ u8 *buf = data->buf;
+ int error;
+
+ error = i2c_master_recv(data->client, buf, EXC3000_LEN_FRAME);
+ if (error < 0)
+ return error;
+
+ if (buf[0] != 'B')
+ return -EPROTO;
+
+ if (buf[4] == 'E')
+ strlcpy(data->model, buf + 5, sizeof(data->model));
+ else if (buf[4] == 'D')
+ strlcpy(data->fw_version, buf + 5, sizeof(data->fw_version));
+ else
+ return -EPROTO;
+
+ return 0;
+}
+
static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
{
struct exc3000_data *data = dev_id;
@@ -118,7 +194,13 @@ static irqreturn_t exc3000_interrupt(int irq, void *dev_id)
int slots, total_slots;
int error;
- error = exc3000_read_data(data->client, buf, &total_slots);
+ if (mutex_is_locked(&data->query_lock)) {
+ data->query_result = exc3000_query_interrupt(data);
+ complete(&data->wait_event);
+ goto out;
+ }
+
+ error = exc3000_read_data(data, buf, &total_slots);
if (error) {
/* Schedule a timer to release "stuck" contacts */
mod_timer(&data->timer,
@@ -145,31 +227,132 @@ out:
return IRQ_HANDLED;
}
-static int exc3000_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static ssize_t fw_version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct exc3000_data *data = i2c_get_clientdata(client);
+ static const u8 request[68] = {
+ 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'D', 0x00
+ };
+ int error;
+
+ mutex_lock(&data->query_lock);
+
+ data->query_result = -ETIMEDOUT;
+ reinit_completion(&data->wait_event);
+
+ error = i2c_master_send(client, request, sizeof(request));
+ if (error < 0) {
+ mutex_unlock(&data->query_lock);
+ return error;
+ }
+
+ wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ);
+ mutex_unlock(&data->query_lock);
+
+ if (data->query_result < 0)
+ return data->query_result;
+
+ return sprintf(buf, "%s\n", data->fw_version);
+}
+static DEVICE_ATTR_RO(fw_version);
+
+static ssize_t exc3000_get_model(struct exc3000_data *data)
+{
+ static const u8 request[68] = {
+ 0x67, 0x00, 0x42, 0x00, 0x03, 0x01, 'E', 0x00
+ };
+ struct i2c_client *client = data->client;
+ int error;
+
+ mutex_lock(&data->query_lock);
+ data->query_result = -ETIMEDOUT;
+ reinit_completion(&data->wait_event);
+
+ error = i2c_master_send(client, request, sizeof(request));
+ if (error < 0) {
+ mutex_unlock(&data->query_lock);
+ return error;
+ }
+
+ wait_for_completion_interruptible_timeout(&data->wait_event, 1 * HZ);
+ mutex_unlock(&data->query_lock);
+
+ return data->query_result;
+}
+
+static ssize_t model_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct exc3000_data *data = i2c_get_clientdata(client);
+ int error;
+
+ error = exc3000_get_model(data);
+ if (error < 0)
+ return error;
+
+ return sprintf(buf, "%s\n", data->model);
+}
+static DEVICE_ATTR_RO(model);
+
+static struct attribute *sysfs_attrs[] = {
+ &dev_attr_fw_version.attr,
+ &dev_attr_model.attr,
+ NULL
+};
+
+static struct attribute_group exc3000_attribute_group = {
+ .attrs = sysfs_attrs
+};
+
+static int exc3000_probe(struct i2c_client *client)
{
struct exc3000_data *data;
struct input_dev *input;
- int error;
+ int error, max_xy, retry;
data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
data->client = client;
+ data->info = device_get_match_data(&client->dev);
+ if (!data->info) {
+ enum eeti_dev_id eeti_dev_id =
+ i2c_match_id(exc3000_id, client)->driver_data;
+ data->info = &exc3000_info[eeti_dev_id];
+ }
timer_setup(&data->timer, exc3000_timer, 0);
+ init_completion(&data->wait_event);
+ mutex_init(&data->query_lock);
+
+ data->reset = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(data->reset))
+ return PTR_ERR(data->reset);
+
+ if (data->reset) {
+ msleep(EXC3000_RESET_MS);
+ gpiod_set_value_cansleep(data->reset, 0);
+ msleep(EXC3000_READY_MS);
+ }
input = devm_input_allocate_device(&client->dev);
if (!input)
return -ENOMEM;
data->input = input;
+ input_set_drvdata(input, data);
- input->name = "EETI EXC3000 Touch Screen";
+ input->name = data->info->name;
input->id.bustype = BUS_I2C;
- input_set_abs_params(input, ABS_MT_POSITION_X, 0, 4095, 0, 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, 0, 4095, 0, 0);
+ max_xy = data->info->max_xy;
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, max_xy, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, max_xy, 0, 0);
+
touchscreen_parse_properties(input, true, &data->prop);
error = input_mt_init_slots(input, EXC3000_NUM_SLOTS,
@@ -187,18 +370,49 @@ static int exc3000_probe(struct i2c_client *client,
if (error)
return error;
+ /*
+ * I²C does not have built-in recovery, so retry on failure. This
+ * ensures, that the device probe will not fail for temporary issues
+ * on the bus. This is not needed for the sysfs calls (userspace
+ * will receive the error code and can start another query) and
+ * cannot be done for touch events (but that only means loosing one
+ * or two touch events anyways).
+ */
+ for (retry = 0; retry < 3; retry++) {
+ error = exc3000_get_model(data);
+ if (!error)
+ break;
+ dev_warn(&client->dev, "Retry %d get EETI EXC3000 model: %d\n",
+ retry + 1, error);
+ }
+
+ if (error)
+ return error;
+
+ dev_dbg(&client->dev, "TS Model: %s", data->model);
+
+ i2c_set_clientdata(client, data);
+
+ error = devm_device_add_group(&client->dev, &exc3000_attribute_group);
+ if (error)
+ return error;
+
return 0;
}
static const struct i2c_device_id exc3000_id[] = {
- { "exc3000", 0 },
+ { "exc3000", EETI_EXC3000 },
+ { "exc80h60", EETI_EXC80H60 },
+ { "exc80h84", EETI_EXC80H84 },
{ }
};
MODULE_DEVICE_TABLE(i2c, exc3000_id);
#ifdef CONFIG_OF
static const struct of_device_id exc3000_of_match[] = {
- { .compatible = "eeti,exc3000" },
+ { .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] },
+ { .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] },
+ { .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] },
{ }
};
MODULE_DEVICE_TABLE(of, exc3000_of_match);
@@ -210,7 +424,7 @@ static struct i2c_driver exc3000_driver = {
.of_match_table = of_match_ptr(exc3000_of_match),
},
.id_table = exc3000_id,
- .probe = exc3000_probe,
+ .probe_new = exc3000_probe,
};
module_i2c_driver(exc3000_driver);
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index 5875bb1099a8..3162b68f7374 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -289,7 +289,7 @@ static int iqs5xx_bl_cmd(struct i2c_client *client, u8 bl_cmd, u16 bl_addr)
break;
case IQS5XX_BL_CMD_EXEC:
usleep_range(10000, 10100);
- /* fall through */
+ fallthrough;
default:
return 0;
}
diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c
index 1af08d3dfaf7..f15713aaebc2 100644
--- a/drivers/input/touchscreen/max11801_ts.c
+++ b/drivers/input/touchscreen/max11801_ts.c
@@ -130,7 +130,6 @@ static irqreturn_t max11801_ts_interrupt(int irq, void *dev_id)
switch (buf[1] & EVENT_TAG_MASK) {
case EVENT_INIT:
- /* fall through */
case EVENT_MIDDLE:
input_report_abs(data->input_dev, ABS_X, x);
input_report_abs(data->input_dev, ABS_Y, y);
diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c
index b54cc64e4ea6..df946869d4cd 100644
--- a/drivers/input/touchscreen/stmfts.c
+++ b/drivers/input/touchscreen/stmfts.c
@@ -255,7 +255,7 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
case STMFTS_EV_STATUS:
complete(&sdata->cmd_done);
- /* fall through */
+ fallthrough;
case STMFTS_EV_NO_EVENT:
case STMFTS_EV_DEBUG: