Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - a driver for SGI IOC3 PS/2 controller - updates to driver for FocalTech FT5x06 series touch screen controllers - other assorted fixes * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: synaptics-rmi4 - switch to reduced reporting mode dt-bindings: touchscreen: Convert Goodix touchscreen to json-schema dt-bindings: touchscreen: Add touchscreen schema Input: add IOC3 serio driver Input: axp20x-pek - enable wakeup for all AXP variants Input: axp20x-pek - respect userspace wakeup configuration Input: ads7846 - use new `delay` structure for SPI transfer delays Input: edt-ft5x06 - use pm core to enable/disable the wake irq Input: edt-ft5x06 - make wakeup-source switchable Input: edt-ft5x06 - document wakeup-source capability Input: edt-ft5x06 - alphabetical include reorder Input: edt-ft5x06 - work around first register access error Input: apbps2 - add __iomem to register struct Input: axp20x-pek - make device attributes static Input: elants_i2c - check Remark ID when attempting firmware update
This commit is contained in:
@@ -36,6 +36,8 @@ Optional properties:
|
|||||||
- pinctrl-0: a phandle pointing to the pin settings for the
|
- pinctrl-0: a phandle pointing to the pin settings for the
|
||||||
control gpios
|
control gpios
|
||||||
|
|
||||||
|
- wakeup-source: If present the device will act as wakeup-source
|
||||||
|
|
||||||
- threshold: allows setting the "click"-threshold in the range
|
- threshold: allows setting the "click"-threshold in the range
|
||||||
from 0 to 80.
|
from 0 to 80.
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
Device tree bindings for Goodix GT9xx series touchscreen controller
|
|
||||||
|
|
||||||
Required properties:
|
|
||||||
|
|
||||||
- compatible : Should be "goodix,gt1151"
|
|
||||||
or "goodix,gt5663"
|
|
||||||
or "goodix,gt5688"
|
|
||||||
or "goodix,gt911"
|
|
||||||
or "goodix,gt9110"
|
|
||||||
or "goodix,gt912"
|
|
||||||
or "goodix,gt927"
|
|
||||||
or "goodix,gt9271"
|
|
||||||
or "goodix,gt928"
|
|
||||||
or "goodix,gt967"
|
|
||||||
- reg : I2C address of the chip. Should be 0x5d or 0x14
|
|
||||||
- interrupts : Interrupt to which the chip is connected
|
|
||||||
|
|
||||||
Optional properties:
|
|
||||||
|
|
||||||
- irq-gpios : GPIO pin used for IRQ. The driver uses the
|
|
||||||
interrupt gpio pin as output to reset the device.
|
|
||||||
- reset-gpios : GPIO pin used for reset
|
|
||||||
- AVDD28-supply : Analog power supply regulator on AVDD28 pin
|
|
||||||
- VDDIO-supply : GPIO power supply regulator on VDDIO pin
|
|
||||||
- touchscreen-inverted-x
|
|
||||||
- touchscreen-inverted-y
|
|
||||||
- touchscreen-size-x
|
|
||||||
- touchscreen-size-y
|
|
||||||
- touchscreen-swapped-x-y
|
|
||||||
|
|
||||||
The touchscreen-* properties are documented in touchscreen.txt in this
|
|
||||||
directory.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
i2c@00000000 {
|
|
||||||
/* ... */
|
|
||||||
|
|
||||||
gt928@5d {
|
|
||||||
compatible = "goodix,gt928";
|
|
||||||
reg = <0x5d>;
|
|
||||||
interrupt-parent = <&gpio>;
|
|
||||||
interrupts = <0 0>;
|
|
||||||
|
|
||||||
irq-gpios = <&gpio1 0 0>;
|
|
||||||
reset-gpios = <&gpio1 1 0>;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* ... */
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/touchscreen/goodix.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Goodix GT9xx series touchscreen controller Bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||||
|
|
||||||
|
allOf:
|
||||||
|
- $ref: touchscreen.yaml#
|
||||||
|
|
||||||
|
properties:
|
||||||
|
compatible:
|
||||||
|
enum:
|
||||||
|
- goodix,gt1151
|
||||||
|
- goodix,gt5663
|
||||||
|
- goodix,gt5688
|
||||||
|
- goodix,gt911
|
||||||
|
- goodix,gt9110
|
||||||
|
- goodix,gt912
|
||||||
|
- goodix,gt927
|
||||||
|
- goodix,gt9271
|
||||||
|
- goodix,gt928
|
||||||
|
- goodix,gt967
|
||||||
|
|
||||||
|
reg:
|
||||||
|
enum: [ 0x5d, 0x14 ]
|
||||||
|
|
||||||
|
interrupts:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
irq-gpios:
|
||||||
|
description: GPIO pin used for IRQ.
|
||||||
|
The driver uses the interrupt gpio pin as
|
||||||
|
output to reset the device.
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
reset-gpios:
|
||||||
|
maxItems: 1
|
||||||
|
|
||||||
|
AVDD28-supply:
|
||||||
|
description: Analog power supply regulator on AVDD28 pin
|
||||||
|
|
||||||
|
VDDIO-supply:
|
||||||
|
description: GPIO power supply regulator on VDDIO pin
|
||||||
|
|
||||||
|
touchscreen-inverted-x: true
|
||||||
|
touchscreen-inverted-y: true
|
||||||
|
touchscreen-size-x: true
|
||||||
|
touchscreen-size-y: true
|
||||||
|
touchscreen-swapped-x-y: true
|
||||||
|
|
||||||
|
additionalProperties: false
|
||||||
|
|
||||||
|
required:
|
||||||
|
- compatible
|
||||||
|
- reg
|
||||||
|
- interrupts
|
||||||
|
|
||||||
|
examples:
|
||||||
|
- |
|
||||||
|
i2c@00000000 {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
gt928@5d {
|
||||||
|
compatible = "goodix,gt928";
|
||||||
|
reg = <0x5d>;
|
||||||
|
interrupt-parent = <&gpio>;
|
||||||
|
interrupts = <0 0>;
|
||||||
|
irq-gpios = <&gpio1 0 0>;
|
||||||
|
reset-gpios = <&gpio1 1 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
...
|
||||||
@@ -1,39 +1 @@
|
|||||||
General Touchscreen Properties:
|
See touchscreen.yaml
|
||||||
|
|
||||||
Optional properties for Touchscreens:
|
|
||||||
- touchscreen-min-x : minimum x coordinate reported (0 if not set)
|
|
||||||
- touchscreen-min-y : minimum y coordinate reported (0 if not set)
|
|
||||||
- touchscreen-size-x : horizontal resolution of touchscreen
|
|
||||||
(maximum x coordinate reported + 1)
|
|
||||||
- touchscreen-size-y : vertical resolution of touchscreen
|
|
||||||
(maximum y coordinate reported + 1)
|
|
||||||
- touchscreen-max-pressure : maximum reported pressure (arbitrary range
|
|
||||||
dependent on the controller)
|
|
||||||
- touchscreen-min-pressure : minimum pressure on the touchscreen to be
|
|
||||||
achieved in order for the touchscreen
|
|
||||||
driver to report a touch event.
|
|
||||||
- touchscreen-fuzz-x : horizontal noise value of the absolute input
|
|
||||||
device (in pixels)
|
|
||||||
- touchscreen-fuzz-y : vertical noise value of the absolute input
|
|
||||||
device (in pixels)
|
|
||||||
- touchscreen-fuzz-pressure : pressure noise value of the absolute input
|
|
||||||
device (arbitrary range dependent on the
|
|
||||||
controller)
|
|
||||||
- touchscreen-average-samples : Number of data samples which are averaged
|
|
||||||
for each read (valid values dependent on the
|
|
||||||
controller)
|
|
||||||
- touchscreen-inverted-x : X axis is inverted (boolean)
|
|
||||||
- touchscreen-inverted-y : Y axis is inverted (boolean)
|
|
||||||
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
|
|
||||||
Swapping is done after inverting the axis
|
|
||||||
- touchscreen-x-mm : horizontal length in mm of the touchscreen
|
|
||||||
- touchscreen-y-mm : vertical length in mm of the touchscreen
|
|
||||||
|
|
||||||
Deprecated properties for Touchscreens:
|
|
||||||
- x-size : deprecated name for touchscreen-size-x
|
|
||||||
- y-size : deprecated name for touchscreen-size-y
|
|
||||||
- moving-threshold : deprecated name for a combination of
|
|
||||||
touchscreen-fuzz-x and touchscreen-fuzz-y
|
|
||||||
- contact-threshold : deprecated name for touchscreen-fuzz-pressure
|
|
||||||
- x-invert : deprecated name for touchscreen-inverted-x
|
|
||||||
- y-invert : deprecated name for touchscreen-inverted-y
|
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
%YAML 1.2
|
||||||
|
---
|
||||||
|
$id: http://devicetree.org/schemas/input/touchscreen/touchscreen.yaml#
|
||||||
|
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||||
|
|
||||||
|
title: Common touchscreen Bindings
|
||||||
|
|
||||||
|
maintainers:
|
||||||
|
- Dmitry Torokhov <dmitry.torokhov@gmail.com>
|
||||||
|
|
||||||
|
properties:
|
||||||
|
touchscreen-min-x:
|
||||||
|
description: minimum x coordinate reported
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
touchscreen-min-y:
|
||||||
|
description: minimum y coordinate reported
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
default: 0
|
||||||
|
|
||||||
|
touchscreen-size-x:
|
||||||
|
description: horizontal resolution of touchscreen (maximum x coordinate reported + 1)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-size-y:
|
||||||
|
description: vertical resolution of touchscreen (maximum y coordinate reported + 1)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-max-pressure:
|
||||||
|
description: maximum reported pressure (arbitrary range dependent on the controller)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-min-pressure:
|
||||||
|
description: minimum pressure on the touchscreen to be achieved in order for the
|
||||||
|
touchscreen driver to report a touch event.
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-fuzz-x:
|
||||||
|
description: horizontal noise value of the absolute input device (in pixels)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-fuzz-y:
|
||||||
|
description: vertical noise value of the absolute input device (in pixels)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-fuzz-pressure:
|
||||||
|
description: pressure noise value of the absolute input device (arbitrary range
|
||||||
|
dependent on the controller)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-average-samples:
|
||||||
|
description: Number of data samples which are averaged for each read (valid values
|
||||||
|
dependent on the controller)
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-inverted-x:
|
||||||
|
description: X axis is inverted
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
touchscreen-inverted-y:
|
||||||
|
description: Y axis is inverted
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
touchscreen-swapped-x-y:
|
||||||
|
description: X and Y axis are swapped
|
||||||
|
Swapping is done after inverting the axis
|
||||||
|
type: boolean
|
||||||
|
|
||||||
|
touchscreen-x-mm:
|
||||||
|
description: horizontal length in mm of the touchscreen
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
touchscreen-y-mm:
|
||||||
|
description: vertical length in mm of the touchscreen
|
||||||
|
$ref: /schemas/types.yaml#/definitions/uint32
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
touchscreen-size-x: [ touchscreen-size-y ]
|
||||||
|
touchscreen-size-y: [ touchscreen-size-x ]
|
||||||
|
touchscreen-x-mm: [ touchscreen-y-mm ]
|
||||||
|
touchscreen-y-mm: [ touchscreen-x-mm ]
|
||||||
@@ -191,9 +191,10 @@ static ssize_t axp20x_store_attr_shutdown(struct device *dev,
|
|||||||
axp20x_pek->info->shutdown_mask, buf, count);
|
axp20x_pek->info->shutdown_mask, buf, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEVICE_ATTR(startup, 0644, axp20x_show_attr_startup, axp20x_store_attr_startup);
|
static DEVICE_ATTR(startup, 0644, axp20x_show_attr_startup,
|
||||||
DEVICE_ATTR(shutdown, 0644, axp20x_show_attr_shutdown,
|
axp20x_store_attr_startup);
|
||||||
axp20x_store_attr_shutdown);
|
static DEVICE_ATTR(shutdown, 0644, axp20x_show_attr_shutdown,
|
||||||
|
axp20x_store_attr_shutdown);
|
||||||
|
|
||||||
static struct attribute *axp20x_attrs[] = {
|
static struct attribute *axp20x_attrs[] = {
|
||||||
&dev_attr_startup.attr,
|
&dev_attr_startup.attr,
|
||||||
@@ -279,8 +280,7 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (axp20x_pek->axp20x->variant == AXP288_ID)
|
device_init_wakeup(&pdev->dev, true);
|
||||||
enable_irq_wake(axp20x_pek->irq_dbr);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -352,6 +352,40 @@ static int axp20x_pek_probe(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused axp20x_pek_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As nested threaded IRQs are not automatically disabled during
|
||||||
|
* suspend, we must explicitly disable non-wakeup IRQs.
|
||||||
|
*/
|
||||||
|
if (device_may_wakeup(dev)) {
|
||||||
|
enable_irq_wake(axp20x_pek->irq_dbf);
|
||||||
|
enable_irq_wake(axp20x_pek->irq_dbr);
|
||||||
|
} else {
|
||||||
|
disable_irq(axp20x_pek->irq_dbf);
|
||||||
|
disable_irq(axp20x_pek->irq_dbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __maybe_unused axp20x_pek_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
|
||||||
|
|
||||||
|
if (device_may_wakeup(dev)) {
|
||||||
|
disable_irq_wake(axp20x_pek->irq_dbf);
|
||||||
|
disable_irq_wake(axp20x_pek->irq_dbr);
|
||||||
|
} else {
|
||||||
|
enable_irq(axp20x_pek->irq_dbf);
|
||||||
|
enable_irq(axp20x_pek->irq_dbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
|
static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
|
||||||
{
|
{
|
||||||
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
|
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
|
||||||
@@ -371,6 +405,7 @@ static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct dev_pm_ops axp20x_pek_pm_ops = {
|
static const struct dev_pm_ops axp20x_pek_pm_ops = {
|
||||||
|
SET_SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
|
||||||
#ifdef CONFIG_PM_SLEEP
|
#ifdef CONFIG_PM_SLEEP
|
||||||
.resume_noirq = axp20x_pek_resume_noirq,
|
.resume_noirq = axp20x_pek_resume_noirq,
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -412,6 +412,10 @@ struct f11_2d_sensor_queries {
|
|||||||
|
|
||||||
/* Defs for Ctrl0. */
|
/* Defs for Ctrl0. */
|
||||||
#define RMI_F11_REPORT_MODE_MASK 0x07
|
#define RMI_F11_REPORT_MODE_MASK 0x07
|
||||||
|
#define RMI_F11_REPORT_MODE_CONTINUOUS (0 << 0)
|
||||||
|
#define RMI_F11_REPORT_MODE_REDUCED (1 << 0)
|
||||||
|
#define RMI_F11_REPORT_MODE_FS_CHANGE (2 << 0)
|
||||||
|
#define RMI_F11_REPORT_MODE_FP_CHANGE (3 << 0)
|
||||||
#define RMI_F11_ABS_POS_FILT (1 << 3)
|
#define RMI_F11_ABS_POS_FILT (1 << 3)
|
||||||
#define RMI_F11_REL_POS_FILT (1 << 4)
|
#define RMI_F11_REL_POS_FILT (1 << 4)
|
||||||
#define RMI_F11_REL_BALLISTICS (1 << 5)
|
#define RMI_F11_REL_BALLISTICS (1 << 5)
|
||||||
@@ -1195,6 +1199,16 @@ static int rmi_f11_initialize(struct rmi_function *fn)
|
|||||||
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
|
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] =
|
||||||
sensor->axis_align.delta_y_threshold;
|
sensor->axis_align.delta_y_threshold;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If distance threshold values are set, switch to reduced reporting
|
||||||
|
* mode so they actually get used by the controller.
|
||||||
|
*/
|
||||||
|
if (ctrl->ctrl0_11[RMI_F11_DELTA_X_THRESHOLD] ||
|
||||||
|
ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD]) {
|
||||||
|
ctrl->ctrl0_11[0] &= ~RMI_F11_REPORT_MODE_MASK;
|
||||||
|
ctrl->ctrl0_11[0] |= RMI_F11_REPORT_MODE_REDUCED;
|
||||||
|
}
|
||||||
|
|
||||||
if (f11->sens_query.has_dribble) {
|
if (f11->sens_query.has_dribble) {
|
||||||
switch (sensor->dribble) {
|
switch (sensor->dribble) {
|
||||||
case RMI_REG_STATE_OFF:
|
case RMI_REG_STATE_OFF:
|
||||||
|
|||||||
@@ -165,6 +165,16 @@ config SERIO_MACEPS2
|
|||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called maceps2.
|
module will be called maceps2.
|
||||||
|
|
||||||
|
config SERIO_SGI_IOC3
|
||||||
|
tristate "SGI IOC3 PS/2 controller"
|
||||||
|
depends on SGI_MFD_IOC3
|
||||||
|
help
|
||||||
|
Say Y here if you have an SGI Onyx2, SGI Octane or IOC3 PCI card
|
||||||
|
and you want to attach and use a keyboard, mouse, or both.
|
||||||
|
|
||||||
|
To compile this driver as a module, choose M here: the
|
||||||
|
module will be called ioc3kbd.
|
||||||
|
|
||||||
config SERIO_LIBPS2
|
config SERIO_LIBPS2
|
||||||
tristate "PS/2 driver library"
|
tristate "PS/2 driver library"
|
||||||
depends on SERIO_I8042 || SERIO_I8042=n
|
depends on SERIO_I8042 || SERIO_I8042=n
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o
|
|||||||
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
|
obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o
|
||||||
obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o
|
obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o
|
||||||
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
|
obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o
|
||||||
|
obj-$(CONFIG_SERIO_SGI_IOC3) += ioc3kbd.o
|
||||||
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
|
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
|
||||||
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
|
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
|
||||||
obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o
|
obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ struct apbps2_regs {
|
|||||||
|
|
||||||
struct apbps2_priv {
|
struct apbps2_priv {
|
||||||
struct serio *io;
|
struct serio *io;
|
||||||
struct apbps2_regs *regs;
|
struct apbps2_regs __iomem *regs;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int apbps2_idx;
|
static int apbps2_idx;
|
||||||
|
|||||||
216
drivers/input/serio/ioc3kbd.c
Normal file
216
drivers/input/serio/ioc3kbd.c
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* SGI IOC3 PS/2 controller driver for linux
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Thomas Bogendoerfer <tbogendoerfer@suse.de>
|
||||||
|
*
|
||||||
|
* Based on code Copyright (C) 2005 Stanislaw Skowronek <skylark@unaligned.org>
|
||||||
|
* Copyright (C) 2009 Johannes Dickgreber <tanzy@gmx.de>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <linux/serio.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
|
||||||
|
#include <asm/sn/ioc3.h>
|
||||||
|
|
||||||
|
struct ioc3kbd_data {
|
||||||
|
struct ioc3_serioregs __iomem *regs;
|
||||||
|
struct serio *kbd, *aux;
|
||||||
|
bool kbd_exists, aux_exists;
|
||||||
|
int irq;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int ioc3kbd_wait(struct ioc3_serioregs __iomem *regs, u32 mask)
|
||||||
|
{
|
||||||
|
unsigned long timeout = 0;
|
||||||
|
|
||||||
|
while ((readl(®s->km_csr) & mask) && (timeout < 250)) {
|
||||||
|
udelay(50);
|
||||||
|
timeout++;
|
||||||
|
}
|
||||||
|
return (timeout >= 250) ? -ETIMEDOUT : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioc3kbd_write(struct serio *dev, u8 val)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev->port_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ioc3kbd_wait(d->regs, KM_CSR_K_WRT_PEND);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
writel(val, &d->regs->k_wd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioc3kbd_start(struct serio *dev)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev->port_data;
|
||||||
|
|
||||||
|
d->kbd_exists = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ioc3kbd_stop(struct serio *dev)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev->port_data;
|
||||||
|
|
||||||
|
d->kbd_exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioc3aux_write(struct serio *dev, u8 val)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev->port_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = ioc3kbd_wait(d->regs, KM_CSR_M_WRT_PEND);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
writel(val, &d->regs->m_wd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioc3aux_start(struct serio *dev)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev->port_data;
|
||||||
|
|
||||||
|
d->aux_exists = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ioc3aux_stop(struct serio *dev)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev->port_data;
|
||||||
|
|
||||||
|
d->aux_exists = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ioc3kbd_process_data(struct serio *dev, u32 data)
|
||||||
|
{
|
||||||
|
if (data & KM_RD_VALID_0)
|
||||||
|
serio_interrupt(dev, (data >> KM_RD_DATA_0_SHIFT) & 0xff, 0);
|
||||||
|
if (data & KM_RD_VALID_1)
|
||||||
|
serio_interrupt(dev, (data >> KM_RD_DATA_1_SHIFT) & 0xff, 0);
|
||||||
|
if (data & KM_RD_VALID_2)
|
||||||
|
serio_interrupt(dev, (data >> KM_RD_DATA_2_SHIFT) & 0xff, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t ioc3kbd_intr(int itq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = dev_id;
|
||||||
|
u32 data_k, data_m;
|
||||||
|
|
||||||
|
data_k = readl(&d->regs->k_rd);
|
||||||
|
if (d->kbd_exists)
|
||||||
|
ioc3kbd_process_data(d->kbd, data_k);
|
||||||
|
|
||||||
|
data_m = readl(&d->regs->m_rd);
|
||||||
|
if (d->aux_exists)
|
||||||
|
ioc3kbd_process_data(d->aux, data_m);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioc3kbd_probe(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct ioc3_serioregs __iomem *regs;
|
||||||
|
struct device *dev = &pdev->dev;
|
||||||
|
struct ioc3kbd_data *d;
|
||||||
|
struct serio *sk, *sa;
|
||||||
|
int irq, ret;
|
||||||
|
|
||||||
|
regs = devm_platform_ioremap_resource(pdev, 0);
|
||||||
|
if (IS_ERR(regs))
|
||||||
|
return PTR_ERR(regs);
|
||||||
|
|
||||||
|
irq = platform_get_irq(pdev, 0);
|
||||||
|
if (irq < 0)
|
||||||
|
return -ENXIO;
|
||||||
|
|
||||||
|
d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
|
||||||
|
if (!d)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sk = kzalloc(sizeof(*sk), GFP_KERNEL);
|
||||||
|
if (!sk)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
sa = kzalloc(sizeof(*sa), GFP_KERNEL);
|
||||||
|
if (!sa) {
|
||||||
|
kfree(sk);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
sk->id.type = SERIO_8042;
|
||||||
|
sk->write = ioc3kbd_write;
|
||||||
|
sk->start = ioc3kbd_start;
|
||||||
|
sk->stop = ioc3kbd_stop;
|
||||||
|
snprintf(sk->name, sizeof(sk->name), "IOC3 keyboard %d", pdev->id);
|
||||||
|
snprintf(sk->phys, sizeof(sk->phys), "ioc3/serio%dkbd", pdev->id);
|
||||||
|
sk->port_data = d;
|
||||||
|
sk->dev.parent = dev;
|
||||||
|
|
||||||
|
sa->id.type = SERIO_8042;
|
||||||
|
sa->write = ioc3aux_write;
|
||||||
|
sa->start = ioc3aux_start;
|
||||||
|
sa->stop = ioc3aux_stop;
|
||||||
|
snprintf(sa->name, sizeof(sa->name), "IOC3 auxiliary %d", pdev->id);
|
||||||
|
snprintf(sa->phys, sizeof(sa->phys), "ioc3/serio%daux", pdev->id);
|
||||||
|
sa->port_data = d;
|
||||||
|
sa->dev.parent = dev;
|
||||||
|
|
||||||
|
d->regs = regs;
|
||||||
|
d->kbd = sk;
|
||||||
|
d->aux = sa;
|
||||||
|
d->irq = irq;
|
||||||
|
|
||||||
|
platform_set_drvdata(pdev, d);
|
||||||
|
serio_register_port(d->kbd);
|
||||||
|
serio_register_port(d->aux);
|
||||||
|
|
||||||
|
ret = request_irq(irq, ioc3kbd_intr, IRQF_SHARED, "ioc3-kbd", d);
|
||||||
|
if (ret) {
|
||||||
|
dev_err(dev, "could not request IRQ %d\n", irq);
|
||||||
|
serio_unregister_port(d->kbd);
|
||||||
|
serio_unregister_port(d->aux);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enable ports */
|
||||||
|
writel(KM_CSR_K_CLAMP_3 | KM_CSR_M_CLAMP_3, ®s->km_csr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ioc3kbd_remove(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct ioc3kbd_data *d = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
|
free_irq(d->irq, d);
|
||||||
|
|
||||||
|
serio_unregister_port(d->kbd);
|
||||||
|
serio_unregister_port(d->aux);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct platform_driver ioc3kbd_driver = {
|
||||||
|
.probe = ioc3kbd_probe,
|
||||||
|
.remove = ioc3kbd_remove,
|
||||||
|
.driver = {
|
||||||
|
.name = "ioc3-kbd",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
module_platform_driver(ioc3kbd_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Thomas Bogendoerfer <tbogendoerfer@suse.de>");
|
||||||
|
MODULE_DESCRIPTION("SGI IOC3 serio driver");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
@@ -333,7 +333,8 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
|
|||||||
req->xfer[1].len = 2;
|
req->xfer[1].len = 2;
|
||||||
|
|
||||||
/* for 1uF, settle for 800 usec; no cap, 100 usec. */
|
/* for 1uF, settle for 800 usec; no cap, 100 usec. */
|
||||||
req->xfer[1].delay_usecs = ts->vref_delay_usecs;
|
req->xfer[1].delay.value = ts->vref_delay_usecs;
|
||||||
|
req->xfer[1].delay.unit = SPI_DELAY_UNIT_USECS;
|
||||||
spi_message_add_tail(&req->xfer[1], &req->msg);
|
spi_message_add_tail(&req->xfer[1], &req->msg);
|
||||||
|
|
||||||
/* Enable reference voltage */
|
/* Enable reference voltage */
|
||||||
@@ -1018,7 +1019,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
|
|||||||
* have had enough time to stabilize.
|
* have had enough time to stabilize.
|
||||||
*/
|
*/
|
||||||
if (pdata->settle_delay_usecs) {
|
if (pdata->settle_delay_usecs) {
|
||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay.value = pdata->settle_delay_usecs;
|
||||||
|
x->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &packet->read_y;
|
x->tx_buf = &packet->read_y;
|
||||||
@@ -1061,7 +1063,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
|
|||||||
|
|
||||||
/* ... maybe discard first sample ... */
|
/* ... maybe discard first sample ... */
|
||||||
if (pdata->settle_delay_usecs) {
|
if (pdata->settle_delay_usecs) {
|
||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay.value = pdata->settle_delay_usecs;
|
||||||
|
x->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &packet->read_x;
|
x->tx_buf = &packet->read_x;
|
||||||
@@ -1094,7 +1097,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
|
|||||||
|
|
||||||
/* ... maybe discard first sample ... */
|
/* ... maybe discard first sample ... */
|
||||||
if (pdata->settle_delay_usecs) {
|
if (pdata->settle_delay_usecs) {
|
||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay.value = pdata->settle_delay_usecs;
|
||||||
|
x->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &packet->read_z1;
|
x->tx_buf = &packet->read_z1;
|
||||||
@@ -1125,7 +1129,8 @@ static void ads7846_setup_spi_msg(struct ads7846 *ts,
|
|||||||
|
|
||||||
/* ... maybe discard first sample ... */
|
/* ... maybe discard first sample ... */
|
||||||
if (pdata->settle_delay_usecs) {
|
if (pdata->settle_delay_usecs) {
|
||||||
x->delay_usecs = pdata->settle_delay_usecs;
|
x->delay.value = pdata->settle_delay_usecs;
|
||||||
|
x->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||||
|
|
||||||
x++;
|
x++;
|
||||||
x->tx_buf = &packet->read_z2;
|
x->tx_buf = &packet->read_z2;
|
||||||
|
|||||||
@@ -13,22 +13,23 @@
|
|||||||
* http://www.glyn.com/Products/Displays
|
* http://www.glyn.com/Products/Displays
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/debugfs.h>
|
||||||
#include <linux/ratelimit.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/irq.h>
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/input.h>
|
#include <linux/input.h>
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/uaccess.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/debugfs.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/gpio/consumer.h>
|
|
||||||
#include <linux/input/mt.h>
|
#include <linux/input/mt.h>
|
||||||
#include <linux/input/touchscreen.h>
|
#include <linux/input/touchscreen.h>
|
||||||
#include <asm/unaligned.h>
|
#include <linux/irq.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/ratelimit.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
#include <asm/unaligned.h>
|
||||||
|
|
||||||
#define WORK_REGISTER_THRESHOLD 0x00
|
#define WORK_REGISTER_THRESHOLD 0x00
|
||||||
#define WORK_REGISTER_REPORT_RATE 0x08
|
#define WORK_REGISTER_REPORT_RATE 0x08
|
||||||
@@ -1050,6 +1051,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
|||||||
{
|
{
|
||||||
const struct edt_i2c_chip_data *chip_data;
|
const struct edt_i2c_chip_data *chip_data;
|
||||||
struct edt_ft5x06_ts_data *tsdata;
|
struct edt_ft5x06_ts_data *tsdata;
|
||||||
|
u8 buf[2] = { 0xfc, 0x00 };
|
||||||
struct input_dev *input;
|
struct input_dev *input;
|
||||||
unsigned long irq_flags;
|
unsigned long irq_flags;
|
||||||
int error;
|
int error;
|
||||||
@@ -1140,6 +1142,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dummy read access. EP0700MLP1 returns bogus data on the first
|
||||||
|
* register read access and ignores writes.
|
||||||
|
*/
|
||||||
|
edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf);
|
||||||
|
|
||||||
edt_ft5x06_ts_set_regs(tsdata);
|
edt_ft5x06_ts_set_regs(tsdata);
|
||||||
edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
|
edt_ft5x06_ts_get_defaults(&client->dev, tsdata);
|
||||||
edt_ft5x06_ts_get_parameters(tsdata);
|
edt_ft5x06_ts_get_parameters(tsdata);
|
||||||
@@ -1200,7 +1208,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
|
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
|
||||||
device_init_wakeup(&client->dev, 1);
|
|
||||||
|
|
||||||
dev_dbg(&client->dev,
|
dev_dbg(&client->dev,
|
||||||
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
|
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
|
||||||
@@ -1220,29 +1227,6 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
|
||||||
|
|
||||||
if (device_may_wakeup(dev))
|
|
||||||
enable_irq_wake(client->irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
|
|
||||||
{
|
|
||||||
struct i2c_client *client = to_i2c_client(dev);
|
|
||||||
|
|
||||||
if (device_may_wakeup(dev))
|
|
||||||
disable_irq_wake(client->irq);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static SIMPLE_DEV_PM_OPS(edt_ft5x06_ts_pm_ops,
|
|
||||||
edt_ft5x06_ts_suspend, edt_ft5x06_ts_resume);
|
|
||||||
|
|
||||||
static const struct edt_i2c_chip_data edt_ft5x06_data = {
|
static const struct edt_i2c_chip_data edt_ft5x06_data = {
|
||||||
.max_support_points = 5,
|
.max_support_points = 5,
|
||||||
};
|
};
|
||||||
@@ -1281,7 +1265,6 @@ static struct i2c_driver edt_ft5x06_ts_driver = {
|
|||||||
.driver = {
|
.driver = {
|
||||||
.name = "edt_ft5x06",
|
.name = "edt_ft5x06",
|
||||||
.of_match_table = edt_ft5x06_of_match,
|
.of_match_table = edt_ft5x06_of_match,
|
||||||
.pm = &edt_ft5x06_ts_pm_ops,
|
|
||||||
},
|
},
|
||||||
.id_table = edt_ft5x06_ts_id,
|
.id_table = edt_ft5x06_ts_id,
|
||||||
.probe = edt_ft5x06_ts_probe,
|
.probe = edt_ft5x06_ts_probe,
|
||||||
|
|||||||
@@ -59,8 +59,10 @@
|
|||||||
#define CMD_HEADER_WRITE 0x54
|
#define CMD_HEADER_WRITE 0x54
|
||||||
#define CMD_HEADER_READ 0x53
|
#define CMD_HEADER_READ 0x53
|
||||||
#define CMD_HEADER_6B_READ 0x5B
|
#define CMD_HEADER_6B_READ 0x5B
|
||||||
|
#define CMD_HEADER_ROM_READ 0x96
|
||||||
#define CMD_HEADER_RESP 0x52
|
#define CMD_HEADER_RESP 0x52
|
||||||
#define CMD_HEADER_6B_RESP 0x9B
|
#define CMD_HEADER_6B_RESP 0x9B
|
||||||
|
#define CMD_HEADER_ROM_RESP 0x95
|
||||||
#define CMD_HEADER_HELLO 0x55
|
#define CMD_HEADER_HELLO 0x55
|
||||||
#define CMD_HEADER_REK 0x66
|
#define CMD_HEADER_REK 0x66
|
||||||
|
|
||||||
@@ -200,6 +202,10 @@ static int elants_i2c_execute_command(struct i2c_client *client,
|
|||||||
expected_response = CMD_HEADER_6B_RESP;
|
expected_response = CMD_HEADER_6B_RESP;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case CMD_HEADER_ROM_READ:
|
||||||
|
expected_response = CMD_HEADER_ROM_RESP;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dev_err(&client->dev, "%s: invalid command %*ph\n",
|
dev_err(&client->dev, "%s: invalid command %*ph\n",
|
||||||
__func__, (int)cmd_size, cmd);
|
__func__, (int)cmd_size, cmd);
|
||||||
@@ -556,6 +562,8 @@ static int elants_i2c_initialize(struct elants_data *ts)
|
|||||||
|
|
||||||
/* hw version is available even if device in recovery state */
|
/* hw version is available even if device in recovery state */
|
||||||
error2 = elants_i2c_query_hw_version(ts);
|
error2 = elants_i2c_query_hw_version(ts);
|
||||||
|
if (!error2)
|
||||||
|
error2 = elants_i2c_query_bc_version(ts);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = error2;
|
error = error2;
|
||||||
|
|
||||||
@@ -563,8 +571,6 @@ static int elants_i2c_initialize(struct elants_data *ts)
|
|||||||
error = elants_i2c_query_fw_version(ts);
|
error = elants_i2c_query_fw_version(ts);
|
||||||
if (!error)
|
if (!error)
|
||||||
error = elants_i2c_query_test_version(ts);
|
error = elants_i2c_query_test_version(ts);
|
||||||
if (!error)
|
|
||||||
error = elants_i2c_query_bc_version(ts);
|
|
||||||
if (!error)
|
if (!error)
|
||||||
error = elants_i2c_query_ts_info(ts);
|
error = elants_i2c_query_ts_info(ts);
|
||||||
|
|
||||||
@@ -613,39 +619,94 @@ static int elants_i2c_fw_write_page(struct i2c_client *client,
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int elants_i2c_validate_remark_id(struct elants_data *ts,
|
||||||
|
const struct firmware *fw)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = ts->client;
|
||||||
|
int error;
|
||||||
|
const u8 cmd[] = { CMD_HEADER_ROM_READ, 0x80, 0x1F, 0x00, 0x00, 0x21 };
|
||||||
|
u8 resp[6] = { 0 };
|
||||||
|
u16 ts_remark_id = 0;
|
||||||
|
u16 fw_remark_id = 0;
|
||||||
|
|
||||||
|
/* Compare TS Remark ID and FW Remark ID */
|
||||||
|
error = elants_i2c_execute_command(client, cmd, sizeof(cmd),
|
||||||
|
resp, sizeof(resp));
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "failed to query Remark ID: %d\n", error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ts_remark_id = get_unaligned_be16(&resp[3]);
|
||||||
|
|
||||||
|
fw_remark_id = get_unaligned_le16(&fw->data[fw->size - 4]);
|
||||||
|
|
||||||
|
if (fw_remark_id != ts_remark_id) {
|
||||||
|
dev_err(&client->dev,
|
||||||
|
"Remark ID Mismatched: ts_remark_id=0x%04x, fw_remark_id=0x%04x.\n",
|
||||||
|
ts_remark_id, fw_remark_id);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int elants_i2c_do_update_firmware(struct i2c_client *client,
|
static int elants_i2c_do_update_firmware(struct i2c_client *client,
|
||||||
const struct firmware *fw,
|
const struct firmware *fw,
|
||||||
bool force)
|
bool force)
|
||||||
{
|
{
|
||||||
|
struct elants_data *ts = i2c_get_clientdata(client);
|
||||||
const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 };
|
const u8 enter_iap[] = { 0x45, 0x49, 0x41, 0x50 };
|
||||||
const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 };
|
const u8 enter_iap2[] = { 0x54, 0x00, 0x12, 0x34 };
|
||||||
const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc };
|
const u8 iap_ack[] = { 0x55, 0xaa, 0x33, 0xcc };
|
||||||
const u8 close_idle[] = {0x54, 0x2c, 0x01, 0x01};
|
const u8 close_idle[] = { 0x54, 0x2c, 0x01, 0x01 };
|
||||||
u8 buf[HEADER_SIZE];
|
u8 buf[HEADER_SIZE];
|
||||||
u16 send_id;
|
u16 send_id;
|
||||||
int page, n_fw_pages;
|
int page, n_fw_pages;
|
||||||
int error;
|
int error;
|
||||||
|
bool check_remark_id = ts->iap_version >= 0x60;
|
||||||
|
|
||||||
/* Recovery mode detection! */
|
/* Recovery mode detection! */
|
||||||
if (force) {
|
if (force) {
|
||||||
dev_dbg(&client->dev, "Recovery mode procedure\n");
|
dev_dbg(&client->dev, "Recovery mode procedure\n");
|
||||||
|
|
||||||
|
if (check_remark_id) {
|
||||||
|
error = elants_i2c_validate_remark_id(ts, fw);
|
||||||
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2));
|
error = elants_i2c_send(client, enter_iap2, sizeof(enter_iap2));
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "failed to enter IAP mode: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Start IAP Procedure */
|
/* Start IAP Procedure */
|
||||||
dev_dbg(&client->dev, "Normal IAP procedure\n");
|
dev_dbg(&client->dev, "Normal IAP procedure\n");
|
||||||
|
|
||||||
/* Close idle mode */
|
/* Close idle mode */
|
||||||
error = elants_i2c_send(client, close_idle, sizeof(close_idle));
|
error = elants_i2c_send(client, close_idle, sizeof(close_idle));
|
||||||
if (error)
|
if (error)
|
||||||
dev_err(&client->dev, "Failed close idle: %d\n", error);
|
dev_err(&client->dev, "Failed close idle: %d\n", error);
|
||||||
msleep(60);
|
msleep(60);
|
||||||
|
|
||||||
elants_i2c_sw_reset(client);
|
elants_i2c_sw_reset(client);
|
||||||
msleep(20);
|
msleep(20);
|
||||||
error = elants_i2c_send(client, enter_iap, sizeof(enter_iap));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (error) {
|
if (check_remark_id) {
|
||||||
dev_err(&client->dev, "failed to enter IAP mode: %d\n", error);
|
error = elants_i2c_validate_remark_id(ts, fw);
|
||||||
return error;
|
if (error)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
error = elants_i2c_send(client, enter_iap, sizeof(enter_iap));
|
||||||
|
if (error) {
|
||||||
|
dev_err(&client->dev, "failed to enter IAP mode: %d\n",
|
||||||
|
error);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msleep(20);
|
msleep(20);
|
||||||
|
|||||||
Reference in New Issue
Block a user