Merge tag 'input-for-v7.1-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

Pull input updates from Dmitry Torokhov:

 - a new charlieplex GPIO keypad driver

 - an update to aw86927 driver to support 86938 chip

 - an update for Chrome OS EC keyboard driver to support Fn-<key> keymap
   extension

 - an UAF fix in debugfs teardown in EDT touchscreen driver

 - a number of conversions for input drivers to use guard() and __free()
   cleanup primitives

 - several drivers for bus mice (inport, logibm) and other very old
   devices have been removed

 - OLPC HGPK PS/2 protocol has been removed as it's been broken and
   inactive for 10 something years

 - dedicated kpsmoused has been removed from psmouse driver

 - other assorted cleanups and fixups

* tag 'input-for-v7.1-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (101 commits)
  Input: charlieplex_keypad - add GPIO charlieplex keypad
  dt-bindings: input: add GPIO charlieplex keypad
  dt-bindings: input: add settling-time-us common property
  dt-bindings: input: add debounce-delay-ms common property
  Input: imx_keypad - fix spelling mistake "Colums" -> "Columns"
  Input: edt-ft5x06 - fix use-after-free in debugfs teardown
  Input: ims-pcu - fix heap-buffer-overflow in ims_pcu_process_data()
  Input: ct82c710 - remove driver
  Input: mk712 - remove driver
  Input: logibm - remove driver
  Input: inport - remove driver
  Input: qt1070 - inline i2c_check_functionality check
  Input: qt1050 - inline i2c_check_functionality check
  Input: aiptek - validate raw macro indices before updating state
  Input: gf2k - skip invalid hat lookup values
  Input: xpad - add RedOctane Games vendor id
  Input: xpad - remove stale TODO and changelog header
  Input: usbtouchscreen - refactor endpoint lookup
  Input: aw86927 - add support for Awinic AW86938
  dt-bindings: input: awinic,aw86927: Add Awinic AW86938
  ...
This commit is contained in:
Linus Torvalds
2026-04-22 18:36:40 -07:00
98 changed files with 1815 additions and 3374 deletions

View File

@@ -10,6 +10,7 @@ maintainers:
- Robin van der Gracht <robin@protonic.nl>
allOf:
- $ref: /schemas/input/input.yaml#
- $ref: /schemas/input/matrix-keymap.yaml#
properties:
@@ -33,9 +34,7 @@ properties:
interrupts:
maxItems: 1
debounce-delay-ms:
maxItems: 1
description: Debouncing interval time in milliseconds
debounce-delay-ms: true
linux,keymap: true

View File

@@ -11,7 +11,12 @@ maintainers:
properties:
compatible:
const: awinic,aw86927
oneOf:
- const: awinic,aw86927
- items:
- enum:
- awinic,aw86938
- const: awinic,aw86927
reg:
maxItems: 1

View File

@@ -10,6 +10,7 @@ maintainers:
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
allOf:
- $ref: input.yaml#
- $ref: /schemas/input/matrix-keymap.yaml#
description:
@@ -37,10 +38,8 @@ properties:
clocks:
maxItems: 1
debounce-delay-ms:
description: |
Time in microseconds that key must be pressed or
released for state change interrupt to trigger.
# Time for state change interrupt to trigger
debounce-delay-ms: true
cirrus,prescale:
description: row/column counter pre-scaler load value

View File

@@ -0,0 +1,108 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/gpio-charlieplex-keypad.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: GPIO charlieplex keypad
maintainers:
- Hugo Villeneuve <hvilleneuve@dimonoff.com>
description: |
The charlieplex keypad supports N^2)-N different key combinations (where N is
the number of I/O lines). Key presses and releases are detected by configuring
only one line as output at a time, and reading other line states. This process
is repeated for each line. Diodes are required to ensure current flows in only
one direction between any pair of pins, as well as pull-up or pull-down
resistors on all I/O lines.
This mechanism doesn't allow to detect simultaneous key presses.
Wiring example for 3 lines keyboard with 6 switches and 3 diodes (pull-up/down
resistors not shown but needed on L0, L1 and L2):
L0 --+---------------------+----------------------+
| | |
L1 -------+-----------+---------------------+ |
| | | | | |
L2 -------------+----------------+-----+ | |
| | | | | | | | |
| | | | | | | | |
| S1 \ S2 \ | S3 \ S4 \ | S5 \ S6 \
| | | | | | | | |
| +--+--+ | +--+--+ | +--+--+
| | | | | |
| D1 v | D2 v | D3 v
| - (k) | - (k) | - (k)
| | | | | |
+-------+ +-------+ +-------+
L: GPIO line
S: switch
D: diode (k indicates cathode)
allOf:
- $ref: input.yaml#
- $ref: /schemas/input/matrix-keymap.yaml#
properties:
compatible:
const: gpio-charlieplex-keypad
autorepeat: true
debounce-delay-ms:
default: 5
line-gpios:
description:
List of GPIOs used as lines. The gpio specifier for this property
depends on the gpio controller to which these lines are connected.
linux,keymap: true
poll-interval: true
settling-time-us: true
wakeup-source: true
required:
- compatible
- line-gpios
- linux,keymap
- poll-interval
additionalProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
keyboard {
compatible = "gpio-charlieplex-keypad";
debounce-delay-ms = <20>;
poll-interval = <5>;
settling-time-us = <2>;
line-gpios = <&gpio2 25 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)
&gpio2 26 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)
&gpio2 27 (GPIO_ACTIVE_HIGH | GPIO_PULL_DOWN)>;
/* MATRIX_KEY(output, input, key-code) */
linux,keymap = <
/*
* According to wiring diagram above, if L1 is configured as
* output and HIGH, and we detect a HIGH level on input L0,
* then it means S1 is pressed: MATRIX_KEY(L1, L0, KEY...)
*/
MATRIX_KEY(1, 0, KEY_F1) /* S1 */
MATRIX_KEY(2, 0, KEY_F2) /* S2 */
MATRIX_KEY(0, 1, KEY_F3) /* S3 */
MATRIX_KEY(2, 1, KEY_F4) /* S4 */
MATRIX_KEY(1, 2, KEY_F5) /* S5 */
MATRIX_KEY(0, 2, KEY_F6) /* S6 */
>;
};

View File

@@ -18,6 +18,7 @@ description:
report the event using GPIO interrupts to the cpu.
allOf:
- $ref: input.yaml#
- $ref: /schemas/input/matrix-keymap.yaml#
properties:
@@ -46,9 +47,7 @@ properties:
Force GPIO polarity to active low.
In the absence of this property GPIOs are treated as active high.
debounce-delay-ms:
description: Debounce interval in milliseconds.
default: 0
debounce-delay-ms: true
col-scan-delay-us:
description:

View File

@@ -14,6 +14,14 @@ properties:
description: Enable autorepeat when key is pressed and held down.
type: boolean
debounce-delay-ms:
description:
Debounce delay in milliseconds. This is the time during which the key
press or release signal must remain stable before it is considered valid.
minimum: 0
maximum: 999
default: 0
linux,keycodes:
description:
Specifies an array of numeric keycode values to be used for reporting
@@ -58,6 +66,14 @@ properties:
reset automatically. Device with key pressed reset feature can specify
this property.
settling-time-us:
description:
Delay, in microseconds, when activating an output line/col/row before
we can reliably read other input lines that maybe affected by this
output. This can be the case for an output with a RC circuit that affects
ramp-up/down times.
default: 0
dependencies:
linux,input-type: [ "linux,code" ]

View File

@@ -4,13 +4,13 @@
$id: http://devicetree.org/schemas/input/matrix-keymap.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Common Key Matrices on Matrix-connected Key Boards
title: Common Key Matrices on Matrix-connected Keyboards
maintainers:
- Olof Johansson <olof@lixom.net>
description: |
A simple common binding for matrix-connected key boards. Currently targeted at
A simple common binding for matrix-connected keyboards. Currently targeted at
defining the keys in the scope of linux key codes since that is a stable and
standardized interface at this time.

View File

@@ -10,6 +10,7 @@ maintainers:
- Mattijs Korpershoek <mkorpershoek@kernel.org>
allOf:
- $ref: input.yaml#
- $ref: /schemas/input/matrix-keymap.yaml#
description: |

View File

@@ -0,0 +1,68 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/parade,tc3408.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Parade TC3408 touchscreen controller
maintainers:
- Langyan Ye <yelangyan@huaqin.corp-partner.google.com>
description: |
Parade TC3408 is a touchscreen controller supporting the I2C-HID protocol.
It requires a reset GPIO and two power supplies (3.3V and 1.8V).
allOf:
- $ref: /schemas/input/touchscreen/touchscreen.yaml#
properties:
compatible:
const: parade,tc3408
reg:
maxItems: 1
interrupts:
maxItems: 1
reset-gpios:
maxItems: 1
vcc33-supply:
description: The 3.3V supply to the touchscreen.
vccio-supply:
description: The 1.8V supply to the touchscreen.
required:
- compatible
- reg
- interrupts
- reset-gpios
- vcc33-supply
- vccio-supply
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
touchscreen: touchscreen@24 {
compatible = "parade,tc3408";
reg = <0x24>;
interrupt-parent = <&pio>;
interrupts = <15 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&pio 126 GPIO_ACTIVE_LOW>;
vcc33-supply = <&pp3300_tchscr_x>;
vccio-supply = <&pp1800_tchscr_report_disable>;
};
};

View File

@@ -33,19 +33,23 @@ allOf:
properties:
compatible:
enum:
- edt,edt-ft5206
- edt,edt-ft5306
- edt,edt-ft5406
- edt,edt-ft5506
- evervision,ev-ft5726
- focaltech,ft3518
- focaltech,ft5426
- focaltech,ft5452
- focaltech,ft6236
- focaltech,ft8201
- focaltech,ft8716
- focaltech,ft8719
oneOf:
- enum:
- edt,edt-ft5206
- edt,edt-ft5306
- edt,edt-ft5406
- edt,edt-ft5506
- evervision,ev-ft5726
- focaltech,ft3518
- focaltech,ft5426
- focaltech,ft5452
- focaltech,ft6236
- focaltech,ft8201
- focaltech,ft8716
- focaltech,ft8719
- items:
- const: focaltech,ft3519
- const: focaltech,ft3518
reg:
maxItems: 1

View File

@@ -32,6 +32,9 @@ properties:
description: A phandle to the reset GPIO
maxItems: 1
wakeup-source:
type: boolean
required:
- compatible
- reg
@@ -51,6 +54,7 @@ examples:
reg = <0x55>;
interrupts = <2 0>;
gpios = <&gpio1 166 0>;
wakeup-source;
touch-overlay {
segment-0 {

View File

@@ -0,0 +1,42 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/input/touchscreen/technologic,ts4800-ts.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: TS-4800 Touchscreen
maintainers:
- Eduard Bostina <egbostina@gmail.com>
properties:
compatible:
const: technologic,ts4800-ts
reg:
maxItems: 1
syscon:
$ref: /schemas/types.yaml#/definitions/phandle-array
items:
- items:
- description: Phandle to the FPGA's syscon
- description: Offset to the touchscreen register
- description: Offset to the touchscreen enable bit
description: Phandle / integers array that points to the syscon node which
describes the FPGA's syscon registers.
required:
- compatible
- reg
- syscon
additionalProperties: false
examples:
- |
touchscreen@1000 {
compatible = "technologic,ts4800-ts";
reg = <0x1000 0x100>;
syscon = <&fpga_syscon 0x20 3>;
};

View File

@@ -53,14 +53,14 @@ properties:
wakeup-source: true
allOf:
- $ref: touchscreen.yaml
required:
- compatible
- reg
- interrupts
allOf:
- $ref: touchscreen.yaml
unevaluatedProperties: false
examples:

View File

@@ -1,11 +0,0 @@
* TS-4800 Touchscreen bindings
Required properties:
- compatible: must be "technologic,ts4800-ts"
- reg: physical base address of the controller and length of memory mapped
region.
- syscon: phandle / integers array that points to the syscon node which
describes the FPGA's syscon registers.
- phandle to FPGA's syscon
- offset to the touchscreen register
- offset to the touchscreen enable bit

View File

@@ -76,8 +76,6 @@ properties:
debounce-delay-ms:
enum: [0, 30, 150, 750]
default: 30
description:
Sets the debouncing delay in milliseconds.
active-low:
description: Set active when pin is pulled low.

View File

@@ -5959,6 +5959,13 @@ S: Maintained
F: Documentation/hwmon/powerz.rst
F: drivers/hwmon/powerz.c
CHARLIEPLEX KEYPAD DRIVER
M: Hugo Villeneuve <hvilleneuve@dimonoff.com>
S: Supported
W: http://www.mosaic-industries.com/embedded-systems/microcontroller-projects/electronic-circuits/matrix-keypad-scan-decode
F: Documentation/devicetree/bindings/input/gpio-charlieplex-keypad.yaml
F: drivers/input/keyboard/charlieplex_keypad.c
CHECKPATCH
M: Andy Whitcroft <apw@canonical.com>
M: Joe Perches <joe@perches.com>

View File

@@ -195,12 +195,20 @@ static const struct elan_i2c_hid_chip_data ilitek_ili2901_chip_data = {
.main_supply_name = "vcc33",
};
static const struct elan_i2c_hid_chip_data parade_tc3408_chip_data = {
.post_power_delay_ms = 10,
.post_gpio_reset_on_delay_ms = 300,
.hid_descriptor_address = 0x0001,
.main_supply_name = "vcc33",
};
static const struct of_device_id elan_i2c_hid_of_match[] = {
{ .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
{ .compatible = "elan,ekth6a12nay", .data = &elan_ekth6a12nay_chip_data },
{ .compatible = "focaltech,ft8112", .data = &focaltech_ft8112_chip_data },
{ .compatible = "ilitek,ili9882t", .data = &ilitek_ili9882t_chip_data },
{ .compatible = "ilitek,ili2901", .data = &ilitek_ili2901_chip_data },
{ .compatible = "parade,tc3408", .data = &parade_tc3408_chip_data },
{ }
};
MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);

View File

@@ -800,14 +800,30 @@ static int input_default_getkeycode(struct input_dev *dev,
return 0;
}
static int input_default_setkeycode(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode)
/**
* input_default_setkeycode - default setkeycode method
* @dev: input device which keymap is being updated.
* @ke: new keymap entry.
* @old_keycode: pointer to the location where old keycode should be stored.
*
* This function is the default implementation of &input_dev.setkeycode()
* method. It is typically used when a driver does not provide its own
* implementation, but it is also exported so drivers can extend it.
*
* The function must be called with &input_dev.event_lock held.
*
* Return: 0 on success, or a negative error code on failure.
*/
int input_default_setkeycode(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode)
{
unsigned int index;
int error;
int i;
lockdep_assert_held(&dev->event_lock);
if (!dev->keycodesize)
return -EINVAL;
@@ -861,6 +877,7 @@ static int input_default_setkeycode(struct input_dev *dev,
__set_bit(ke->keycode, dev->keybit);
return 0;
}
EXPORT_SYMBOL(input_default_setkeycode);
/**
* input_get_keycode - retrieve keycode currently mapped to a given scancode

View File

@@ -165,8 +165,10 @@ static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
t = GB(40,4,0);
for (i = 0; i < gf2k_hats[gf2k->id]; i++)
input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
if (t < ARRAY_SIZE(gf2k_hat_to_axis))
for (i = 0; i < gf2k_hats[gf2k->id]; i++)
input_report_abs(dev, ABS_HAT0X + i,
gf2k_hat_to_axis[t][i]);
t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);

View File

@@ -25,40 +25,6 @@
* - Greg Kroah-Hartman - usb-skeleton driver
* - Xbox Linux project - extra USB IDs
* - Pekka Pöyry (quantus) - Xbox One controller reverse-engineering
*
* TODO:
* - fine tune axes (especially trigger axes)
* - fix "analog" buttons (reported as digital now)
* - get rumble working
* - need USB IDs for other dance pads
*
* History:
*
* 2002-06-27 - 0.0.1 : first version, just said "XBOX HID controller"
*
* 2002-07-02 - 0.0.2 : basic working version
* - all axes and 9 of the 10 buttons work (german InterAct device)
* - the black button does not work
*
* 2002-07-14 - 0.0.3 : rework by Vojtech Pavlik
* - indentation fixes
* - usb + input init sequence fixes
*
* 2002-07-16 - 0.0.4 : minor changes, merge with Vojtech's v0.0.3
* - verified the lack of HID and report descriptors
* - verified that ALL buttons WORK
* - fixed d-pad to axes mapping
*
* 2002-07-17 - 0.0.5 : simplified d-pad handling
*
* 2004-10-02 - 0.0.6 : DDR pad support
* - borrowed from the Xbox Linux kernel
* - USB id's for commonly used dance pads are present
* - dance pads will map D-PAD to buttons, not axes
* - pass the module paramater 'dpad_to_buttons' to force
* the D-PAD to map to buttons if your pad is not detected
*
* Later changes can be tracked in SCM.
*/
#include <linux/bits.h>
@@ -590,6 +556,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x3651), /* CRKD Controllers */
XPAD_XBOXONE_VENDOR(0x366c), /* ByoWave controllers */
XPAD_XBOX360_VENDOR(0x37d7), /* Flydigi Controllers */
XPAD_XBOX360_VENDOR(0x3958), /* RedOctane Games Controllers */
XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */
{ }
};

View File

@@ -289,6 +289,20 @@ config KEYBOARD_MATRIX
To compile this driver as a module, choose M here: the
module will be called matrix_keypad.
config KEYBOARD_CHARLIEPLEX
tristate "GPIO driven charlieplex keypad support"
depends on GPIOLIB || COMPILE_TEST
select INPUT_MATRIXKMAP
help
Enable support for GPIO driven charlieplex keypad. A charlieplex
keypad allows to use fewer GPIO lines to interface to key switches.
For example, an N lines charlieplex keypad can be used to interface
to N^2-N different key switches. However, this type of keypad
cannot detect more than one key press at a time.
To compile this driver as a module, choose M here: the
module will be called charlieplex_keypad.
config KEYBOARD_HIL_OLD
tristate "HP HIL keyboard support (simple driver)"
depends on GSC || HP300

View File

@@ -15,6 +15,7 @@ obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o
obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o
obj-$(CONFIG_KEYBOARD_CHARLIEPLEX) += charlieplex_keypad.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o

View File

@@ -3,10 +3,7 @@
* AT and PS/2 keyboard driver
*
* Copyright (c) 1999-2002 Vojtech Pavlik
*/
/*
*
* This driver can handle standard AT keyboards and PS/2 keyboards in
* Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb
* input-only controllers and AT keyboards connected over a one way RS232
@@ -65,8 +62,8 @@ static bool atkbd_terminal;
module_param_named(terminal, atkbd_terminal, bool, 0);
MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2");
#define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF)
#define KEYCODE(keymap) (keymap & 0xFFFF)
#define SCANCODE(keymap) (((keymap) >> 16) & 0xFFFF)
#define KEYCODE(keymap) ((keymap) & 0xFFFF)
/*
* Scancode to keycode tables. These are just the default setting, and
@@ -76,7 +73,6 @@ MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard conne
#define ATKBD_KEYMAP_SIZE 512
static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES
/* XXX: need a more general approach */
@@ -107,7 +103,6 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
};
static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60,
131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62,
134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64,
@@ -122,15 +117,15 @@ static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = {
148,149,147,140
};
static const unsigned short atkbd_unxlate_table[128] = {
0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
static const u8 atkbd_unxlate_table[128] = {
0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
};
#define ATKBD_CMD_SETLEDS 0x10ed
@@ -184,7 +179,7 @@ static const unsigned short atkbd_unxlate_table[128] = {
static const struct {
unsigned short keycode;
unsigned char set2;
u8 set2;
} atkbd_scroll_keys[] = {
{ ATKBD_SCR_1, 0xc5 },
{ ATKBD_SCR_2, 0x9d },
@@ -200,7 +195,6 @@ static const struct {
*/
struct atkbd {
struct ps2dev ps2dev;
struct input_dev *dev;
@@ -211,7 +205,7 @@ struct atkbd {
unsigned short id;
unsigned short keycode[ATKBD_KEYMAP_SIZE];
DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE);
unsigned char set;
u8 set;
bool translated;
bool extra;
bool write;
@@ -221,7 +215,7 @@ struct atkbd {
bool enabled;
/* Accessed only from interrupt */
unsigned char emul;
u8 emul;
bool resend;
bool release;
unsigned long xl_bit;
@@ -253,9 +247,9 @@ static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned in
static bool atkbd_skip_deactivate;
static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *));
ssize_t (*handler)(struct atkbd *, char *));
static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
ssize_t (*handler)(struct atkbd *, const char *, size_t));
ssize_t (*handler)(struct atkbd *, const char *, size_t));
#define ATKBD_DEFINE_ATTR(_name) \
static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
@@ -270,7 +264,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, \
return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
} \
static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name)
ATKBD_DEFINE_ATTR(extra);
ATKBD_DEFINE_ATTR(force_release);
@@ -287,7 +281,7 @@ static ssize_t atkbd_do_show_##_name(struct device *d, \
return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
} \
static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
__ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL)
ATKBD_DEFINE_RO_ATTR(err_count);
ATKBD_DEFINE_RO_ATTR(function_row_physmap);
@@ -317,7 +311,7 @@ static struct atkbd *atkbd_from_serio(struct serio *serio)
}
static umode_t atkbd_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int i)
struct attribute *attr, int i)
{
struct device *dev = kobj_to_dev(kobj);
struct serio *serio = to_serio_port(dev);
@@ -337,7 +331,7 @@ static const struct attribute_group atkbd_attribute_group = {
__ATTRIBUTE_GROUPS(atkbd_attribute);
static const unsigned int xl_table[] = {
static const u8 xl_table[] = {
ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
};
@@ -346,7 +340,7 @@ static const unsigned int xl_table[] = {
* Checks if we should mangle the scancode to extract 'release' bit
* in translated mode.
*/
static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
static bool atkbd_need_xlate(unsigned long xl_bit, u8 code)
{
int i;
@@ -365,7 +359,7 @@ static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code)
* between make/break pair of scancodes for select keys and PS/2
* protocol responses.
*/
static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code)
static void atkbd_calculate_xl_bit(struct atkbd *atkbd, u8 code)
{
int i;
@@ -389,7 +383,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
if (atkbd->set == 3) {
if (atkbd->emul == 1)
code |= 0x100;
} else {
} else {
code = (code & 0x7f) | ((code & 0x80) << 1);
if (atkbd->emul == 1)
code |= 0x80;
@@ -431,7 +425,7 @@ static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev,
dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags);
#if !defined(__i386__) && !defined (__x86_64__)
#if !defined(__i386__) && !defined(__x86_64__)
if (atkbd_handle_frame_error(ps2dev, data, flags))
return PS2_IGNORE;
#endif
@@ -460,7 +454,6 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
code = atkbd_platform_scancode_fixup(atkbd, code);
if (atkbd->translated) {
if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) {
atkbd->release = code >> 7;
code &= 0x7f;
@@ -486,11 +479,9 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
return;
case ATKBD_RET_ACK:
case ATKBD_RET_NAK:
if (printk_ratelimit())
dev_warn(&serio->dev,
"Spurious %s on %s. "
"Some program might be trying to access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
dev_warn_ratelimited(&serio->dev,
"Spurious %s on %s. Some program might be trying to access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
return;
case ATKBD_RET_ERR:
atkbd->err_count++;
@@ -582,14 +573,14 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data)
static int atkbd_set_repeat_rate(struct atkbd *atkbd)
{
const short period[32] =
{ 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 };
const short delay[4] =
{ 250, 500, 750, 1000 };
const short period[32] = {
33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125,
133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500
};
const short delay[4] = { 250, 500, 750, 1000 };
struct input_dev *dev = atkbd->dev;
unsigned char param;
u8 param;
int i = 0, j = 0;
while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD])
@@ -607,7 +598,7 @@ static int atkbd_set_repeat_rate(struct atkbd *atkbd)
static int atkbd_set_leds(struct atkbd *atkbd)
{
struct input_dev *dev = atkbd->dev;
unsigned char param[2];
u8 param[2];
param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0)
| (test_bit(LED_NUML, dev->led) ? 2 : 0)
@@ -648,8 +639,7 @@ static void atkbd_event_work(struct work_struct *work)
* it may not be ready yet. In this case we need to keep
* rescheduling till reconnect completes.
*/
schedule_delayed_work(&atkbd->event_work,
msecs_to_jiffies(100));
schedule_delayed_work(&atkbd->event_work, msecs_to_jiffies(100));
} else {
if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask))
atkbd_set_leds(atkbd);
@@ -683,7 +673,7 @@ static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit)
*/
static int atkbd_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
unsigned int type, unsigned int code, int value)
{
struct atkbd *atkbd = input_get_drvdata(dev);
@@ -691,7 +681,6 @@ static int atkbd_event(struct input_dev *dev,
return -1;
switch (type) {
case EV_LED:
atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT);
return 0;
@@ -808,7 +797,7 @@ static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; }
static int atkbd_probe(struct atkbd *atkbd)
{
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
u8 param[2];
/*
* Some systems, where the bit-twiddling when testing the io-lines of the
@@ -836,7 +825,6 @@ static int atkbd_probe(struct atkbd *atkbd)
param[0] = param[1] = 0xa5; /* initialize with invalid values */
if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) {
/*
* If the get ID command failed, we check if we can at least set
* the LEDs on the keyboard. This should work on every keyboard out there.
@@ -856,8 +844,7 @@ static int atkbd_probe(struct atkbd *atkbd)
if (atkbd->id == 0xaca1 && atkbd->translated) {
dev_err(&ps2dev->serio->dev,
"NCD terminal keyboards are only supported on non-translating controllers. "
"Use i8042.direct=1 to disable translation.\n");
"NCD terminal keyboards are only supported on non-translating controllers. Use i8042.direct=1 to disable translation.\n");
return -1;
}
@@ -881,7 +868,7 @@ static int atkbd_probe(struct atkbd *atkbd)
static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra)
{
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[2];
u8 param[2];
atkbd->extra = false;
/*
@@ -941,8 +928,8 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra
static int atkbd_reset_state(struct atkbd *atkbd)
{
struct ps2dev *ps2dev = &atkbd->ps2dev;
unsigned char param[1];
struct ps2dev *ps2dev = &atkbd->ps2dev;
u8 param[1];
/*
* Set the LEDs to a predefined state (all off).
@@ -967,7 +954,6 @@ static int atkbd_reset_state(struct atkbd *atkbd)
* atkbd_cleanup() restores the keyboard state so that BIOS is happy after a
* reboot.
*/
static void atkbd_cleanup(struct serio *serio)
{
struct atkbd *atkbd = atkbd_from_serio(serio);
@@ -976,11 +962,9 @@ static void atkbd_cleanup(struct serio *serio)
ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF);
}
/*
* atkbd_disconnect() closes and frees.
*/
static void atkbd_disconnect(struct serio *serio)
{
struct atkbd *atkbd = atkbd_from_serio(serio);
@@ -1005,8 +989,7 @@ static void atkbd_disconnect(struct serio *serio)
/*
* generate release events for the keycodes given in data
*/
static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd,
const void *data)
static void atkbd_apply_forced_release_keylist(struct atkbd *atkbd, const void *data)
{
const unsigned int *keys = data;
unsigned int i;
@@ -1088,7 +1071,6 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
{
struct device *dev = &atkbd->ps2dev.serio->dev;
int i, n;
u32 *ptr;
u16 scancode, keycode;
/* Parse "linux,keymap" property */
@@ -1096,13 +1078,12 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
if (n <= 0 || n > ATKBD_KEYMAP_SIZE)
return -ENXIO;
ptr = kcalloc(n, sizeof(u32), GFP_KERNEL);
u32 *ptr __free(kfree) = kcalloc(n, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) {
dev_err(dev, "problem parsing FW keymap property\n");
kfree(ptr);
return -EINVAL;
}
@@ -1110,10 +1091,14 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd)
for (i = 0; i < n; i++) {
scancode = SCANCODE(ptr[i]);
keycode = KEYCODE(ptr[i]);
if (scancode >= ATKBD_KEYMAP_SIZE) {
dev_warn(dev, "invalid scancode %#x in FW keymap entry %d\n",
scancode, i);
return -EINVAL;
}
atkbd->keycode[scancode] = keycode;
}
kfree(ptr);
return 0;
}
@@ -1235,7 +1220,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
}
input_dev->keycode = atkbd->keycode;
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodesize = sizeof(atkbd->keycode[0]);
input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode);
for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) {
@@ -1289,7 +1274,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
mutex_init(&atkbd->mutex);
switch (serio->id.type) {
case SERIO_8042_XL:
atkbd->translated = true;
fallthrough;
@@ -1314,7 +1298,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
goto fail2;
if (atkbd->write) {
if (atkbd_probe(atkbd)) {
err = -ENODEV;
goto fail3;
@@ -1354,7 +1337,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
* atkbd_reconnect() tries to restore keyboard into a sane state and is
* most likely called on resume.
*/
static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = atkbd_from_serio(serio);
@@ -1389,7 +1371,6 @@ static int atkbd_reconnect(struct serio *serio)
atkbd_set_leds(atkbd);
if (!atkbd->softrepeat)
atkbd_set_repeat_rate(atkbd);
}
/*
@@ -1445,7 +1426,7 @@ static struct serio_driver atkbd_drv = {
};
static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *))
ssize_t (*handler)(struct atkbd *, char *))
{
struct serio *serio = to_serio_port(dev);
struct atkbd *atkbd = atkbd_from_serio(serio);
@@ -1454,7 +1435,7 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
}
static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
ssize_t (*handler)(struct atkbd *, const char *, size_t))
ssize_t (*handler)(struct atkbd *, const char *, size_t))
{
struct serio *serio = to_serio_port(dev);
struct atkbd *atkbd = atkbd_from_serio(serio);
@@ -1482,7 +1463,7 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
unsigned int value;
int err;
bool old_extra;
unsigned char old_set;
u8 old_set;
if (!atkbd->write)
return -EIO;
@@ -1527,8 +1508,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
return err;
}
input_unregister_device(old_dev);
}
return count;
}
@@ -1544,7 +1525,7 @@ static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
}
static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
const char *buf, size_t count)
const char *buf, size_t count)
{
/* 64 bytes on stack should be acceptable */
DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE);
@@ -1558,7 +1539,6 @@ static ssize_t atkbd_set_force_release(struct atkbd *atkbd,
return count;
}
static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf)
{
return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0);
@@ -1617,7 +1597,7 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
struct input_dev *old_dev, *new_dev;
unsigned int value;
int err;
unsigned char old_set;
u8 old_set;
bool old_extra;
if (!atkbd->write)
@@ -1715,7 +1695,6 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
return count;
}
static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf)
{
return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0);

View File

@@ -0,0 +1,232 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* GPIO driven charlieplex keypad driver
*
* Copyright (c) 2026 Hugo Villeneuve <hvilleneuve@dimonoff.com>
*
* Based on matrix_keyboard.c
*/
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/dev_printk.h>
#include <linux/device/devres.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/input/matrix_keypad.h>
#include <linux/math.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/string_helpers.h>
#include <linux/types.h>
struct charlieplex_keypad {
struct input_dev *input_dev;
struct gpio_descs *line_gpios;
unsigned int nlines;
unsigned int settling_time_us;
unsigned int debounce_threshold;
unsigned int debounce_count;
int debounce_code;
int current_code;
};
static void charlieplex_keypad_report_key(struct input_dev *input)
{
struct charlieplex_keypad *keypad = input_get_drvdata(input);
const unsigned short *keycodes = input->keycode;
if (keypad->current_code > 0) {
input_event(input, EV_MSC, MSC_SCAN, keypad->current_code);
input_report_key(input, keycodes[keypad->current_code], 0);
input_sync(input);
}
if (keypad->debounce_code) {
input_event(input, EV_MSC, MSC_SCAN, keypad->debounce_code);
input_report_key(input, keycodes[keypad->debounce_code], 1);
input_sync(input);
}
keypad->current_code = keypad->debounce_code;
}
static void charlieplex_keypad_check_switch_change(struct input_dev *input,
unsigned int code)
{
struct charlieplex_keypad *keypad = input_get_drvdata(input);
if (code != keypad->debounce_code) {
keypad->debounce_count = 0;
keypad->debounce_code = code;
}
if (keypad->debounce_code != keypad->current_code) {
if (keypad->debounce_count++ >= keypad->debounce_threshold)
charlieplex_keypad_report_key(input);
}
}
static int charlieplex_keypad_scan_line(struct charlieplex_keypad *keypad,
unsigned int oline)
{
struct gpio_descs *line_gpios = keypad->line_gpios;
DECLARE_BITMAP(values, MATRIX_MAX_ROWS);
int err;
/* Activate only one line as output at a time. */
gpiod_direction_output(line_gpios->desc[oline], 1);
if (keypad->settling_time_us)
fsleep(keypad->settling_time_us);
/* Read input on all other lines. */
err = gpiod_get_array_value_cansleep(line_gpios->ndescs, line_gpios->desc,
line_gpios->info, values);
gpiod_direction_input(line_gpios->desc[oline]);
if (err)
return err;
for (unsigned int iline = 0; iline < keypad->nlines; iline++) {
if (iline == oline)
continue; /* Do not read active output line. */
/* Check if GPIO is asserted. */
if (test_bit(iline, values))
return MATRIX_SCAN_CODE(oline, iline,
get_count_order(keypad->nlines));
}
return 0;
}
static void charlieplex_keypad_poll(struct input_dev *input)
{
struct charlieplex_keypad *keypad = input_get_drvdata(input);
int code = 0;
for (unsigned int oline = 0; oline < keypad->nlines; oline++) {
code = charlieplex_keypad_scan_line(keypad, oline);
if (code != 0)
break;
}
if (code >= 0)
charlieplex_keypad_check_switch_change(input, code);
}
static int charlieplex_keypad_init_gpio(struct platform_device *pdev,
struct charlieplex_keypad *keypad)
{
char **pin_names;
char label[32];
snprintf(label, sizeof(label), "%s-pin", pdev->name);
keypad->line_gpios = devm_gpiod_get_array(&pdev->dev, "line", GPIOD_IN);
if (IS_ERR(keypad->line_gpios))
return PTR_ERR(keypad->line_gpios);
keypad->nlines = keypad->line_gpios->ndescs;
if (keypad->nlines > MATRIX_MAX_ROWS)
return -EINVAL;
pin_names = devm_kasprintf_strarray(&pdev->dev, label, keypad->nlines);
if (IS_ERR(pin_names))
return PTR_ERR(pin_names);
for (unsigned int i = 0; i < keypad->line_gpios->ndescs; i++)
gpiod_set_consumer_name(keypad->line_gpios->desc[i], pin_names[i]);
return 0;
}
static int charlieplex_keypad_probe(struct platform_device *pdev)
{
struct charlieplex_keypad *keypad;
struct input_dev *input_dev;
unsigned int debounce_interval_ms = 5;
unsigned int poll_interval_ms;
int err;
keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad)
return -ENOMEM;
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
keypad->input_dev = input_dev;
err = device_property_read_u32(&pdev->dev, "poll-interval", &poll_interval_ms);
if (err)
return dev_err_probe(&pdev->dev, err,
"failed to parse 'poll-interval' property\n");
if (poll_interval_ms == 0)
return dev_err_probe(&pdev->dev, -EINVAL, "invalid 'poll-interval' value\n");
device_property_read_u32(&pdev->dev, "debounce-delay-ms", &debounce_interval_ms);
device_property_read_u32(&pdev->dev, "settling-time-us", &keypad->settling_time_us);
keypad->current_code = -1;
keypad->debounce_code = -1;
keypad->debounce_threshold = DIV_ROUND_UP(debounce_interval_ms, poll_interval_ms);
err = charlieplex_keypad_init_gpio(pdev, keypad);
if (err)
return err;
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
err = matrix_keypad_build_keymap(NULL, NULL, keypad->nlines,
keypad->nlines, NULL, input_dev);
if (err)
return dev_err_probe(&pdev->dev, err, "failed to build keymap\n");
if (device_property_read_bool(&pdev->dev, "autorepeat"))
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
err = input_setup_polling(input_dev, charlieplex_keypad_poll);
if (err)
return dev_err_probe(&pdev->dev, err, "unable to set up polling\n");
input_set_poll_interval(input_dev, poll_interval_ms);
input_set_drvdata(input_dev, keypad);
err = input_register_device(keypad->input_dev);
if (err)
return err;
return 0;
}
static const struct of_device_id charlieplex_keypad_dt_match[] = {
{ .compatible = "gpio-charlieplex-keypad" },
{ }
};
MODULE_DEVICE_TABLE(of, charlieplex_keypad_dt_match);
static struct platform_driver charlieplex_keypad_driver = {
.probe = charlieplex_keypad_probe,
.driver = {
.name = "charlieplex-keypad",
.of_match_table = charlieplex_keypad_dt_match,
},
};
module_platform_driver(charlieplex_keypad_driver);
MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>");
MODULE_DESCRIPTION("GPIO driven charlieplex keypad driver");
MODULE_LICENSE("GPL");

View File

@@ -29,6 +29,12 @@
#include <linux/unaligned.h>
/*
* Maximum size of the normal key matrix, this is limited by the host command
* key_matrix field defined in ec_response_get_next_data_v3
*/
#define CROS_EC_KEYBOARD_COLS_MAX 18
/**
* struct cros_ec_keyb - Structure representing EC keyboard device
*
@@ -44,14 +50,17 @@
* @bs_idev: The input device for non-matrix buttons and switches (or NULL).
* @notifier: interrupt event notifier for transport devices
* @vdata: vivaldi function row data
* @has_fn_map: whether the driver uses an fn function-map layer
* @fn_active: tracks whether the function key is currently pressed
* @fn_combo_active: tracks whether another key was pressed while fn is active
*/
struct cros_ec_keyb {
unsigned int rows;
unsigned int cols;
int row_shift;
bool ghost_filter;
uint8_t *valid_keys;
uint8_t *old_kb_state;
u8 valid_keys[CROS_EC_KEYBOARD_COLS_MAX];
u8 old_kb_state[CROS_EC_KEYBOARD_COLS_MAX];
struct device *dev;
struct cros_ec_device *ec;
@@ -61,6 +70,10 @@ struct cros_ec_keyb {
struct notifier_block notifier;
struct vivaldi_data vdata;
bool has_fn_map;
bool fn_active;
bool fn_combo_active;
};
/**
@@ -132,11 +145,11 @@ static const struct cros_ec_bs_map cros_ec_keyb_bs[] = {
* Returns true when there is at least one combination of pressed keys that
* results in ghosting.
*/
static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf)
static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, u8 *buf)
{
int col1, col2, buf1, buf2;
struct device *dev = ckdev->dev;
uint8_t *valid_keys = ckdev->valid_keys;
u8 *valid_keys = ckdev->valid_keys;
/*
* Ghosting happens if for any pressed key X there are other keys
@@ -166,20 +179,108 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf)
return false;
}
static void cros_ec_emit_fn_key(struct input_dev *input, unsigned int pos)
{
input_event(input, EV_MSC, MSC_SCAN, pos);
input_report_key(input, KEY_FN, true);
input_sync(input);
input_event(input, EV_MSC, MSC_SCAN, pos);
input_report_key(input, KEY_FN, false);
}
static void cros_ec_keyb_process_key_plain(struct cros_ec_keyb *ckdev,
int row, int col, bool state)
{
struct input_dev *idev = ckdev->idev;
const unsigned short *keycodes = idev->keycode;
int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
input_event(idev, EV_MSC, MSC_SCAN, pos);
input_report_key(idev, keycodes[pos], state);
}
static void cros_ec_keyb_process_key_fn_map(struct cros_ec_keyb *ckdev,
int row, int col, bool state)
{
struct input_dev *idev = ckdev->idev;
const unsigned short *keycodes = idev->keycode;
unsigned int pos, fn_pos;
unsigned int code, fn_code;
pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
code = keycodes[pos];
if (code == KEY_FN) {
ckdev->fn_active = state;
if (state) {
ckdev->fn_combo_active = false;
} else if (!ckdev->fn_combo_active) {
/*
* Send both Fn press and release events if nothing
* else has been pressed together with Fn.
*/
cros_ec_emit_fn_key(idev, pos);
}
return;
}
fn_pos = MATRIX_SCAN_CODE(row + ckdev->rows, col, ckdev->row_shift);
fn_code = keycodes[fn_pos];
if (state) {
if (ckdev->fn_active) {
ckdev->fn_combo_active = true;
if (!fn_code)
return; /* Discard if no Fn mapping exists */
pos = fn_pos;
code = fn_code;
}
} else {
/*
* If the Fn-remapped code is currently pressed, release it.
* Otherwise, release the standard code (if it was pressed).
*/
if (fn_code && test_bit(fn_code, idev->key)) {
pos = fn_pos;
code = fn_code;
} else if (!test_bit(code, idev->key)) {
return; /* Discard, key press code was not sent */
}
}
input_event(idev, EV_MSC, MSC_SCAN, pos);
input_report_key(idev, code, state);
}
static void cros_ec_keyb_process_col(struct cros_ec_keyb *ckdev, int col,
u8 col_state, u8 changed)
{
for (int row = 0; row < ckdev->rows; row++) {
if (changed & BIT(row)) {
u8 key_state = col_state & BIT(row);
dev_dbg(ckdev->dev, "changed: [r%d c%d]: byte %02x\n",
row, col, key_state);
if (ckdev->has_fn_map)
cros_ec_keyb_process_key_fn_map(ckdev, row, col,
key_state);
else
cros_ec_keyb_process_key_plain(ckdev, row, col,
key_state);
}
}
}
/*
* Compares the new keyboard state to the old one and produces key
* press/release events accordingly. The keyboard state is 13 bytes (one byte
* per column)
* press/release events accordingly. The keyboard state is one byte
* per column.
*/
static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
uint8_t *kb_state, int len)
static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, u8 *kb_state, int len)
{
struct input_dev *idev = ckdev->idev;
int col, row;
int new_state;
int old_state;
if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) {
/*
* Simple-minded solution: ignore this state. The obvious
@@ -190,25 +291,15 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev,
return;
}
for (col = 0; col < ckdev->cols; col++) {
for (row = 0; row < ckdev->rows; row++) {
int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift);
const unsigned short *keycodes = idev->keycode;
for (int col = 0; col < ckdev->cols; col++) {
u8 changed = kb_state[col] ^ ckdev->old_kb_state[col];
new_state = kb_state[col] & (1 << row);
old_state = ckdev->old_kb_state[col] & (1 << row);
if (new_state != old_state) {
dev_dbg(ckdev->dev,
"changed: [r%d c%d]: byte %02x\n",
row, col, new_state);
input_event(idev, EV_MSC, MSC_SCAN, pos);
input_report_key(idev, keycodes[pos],
new_state);
}
}
ckdev->old_kb_state[col] = kb_state[col];
if (changed)
cros_ec_keyb_process_col(ckdev, col, kb_state[col],
changed);
}
memcpy(ckdev->old_kb_state, kb_state, sizeof(ckdev->old_kb_state));
input_sync(ckdev->idev);
}
@@ -246,8 +337,10 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
{
struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb,
notifier);
u32 val;
struct ec_response_get_next_event_v3 *event_data;
unsigned int event_size;
unsigned int ev_type;
u32 val;
/*
* If not wake enabled, discard key state changes during
@@ -257,32 +350,32 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
if (queued_during_suspend && !device_may_wakeup(ckdev->dev))
return NOTIFY_OK;
switch (ckdev->ec->event_data.event_type) {
event_data = &ckdev->ec->event_data;
event_size = ckdev->ec->event_size;
switch (event_data->event_type) {
case EC_MKBP_EVENT_KEY_MATRIX:
pm_wakeup_event(ckdev->dev, 0);
if (!ckdev->idev) {
dev_warn_once(ckdev->dev,
"Unexpected key matrix event\n");
dev_warn_once(ckdev->dev, "Unexpected key matrix event\n");
return NOTIFY_OK;
}
if (ckdev->ec->event_size != ckdev->cols) {
if (event_size != ckdev->cols) {
dev_err(ckdev->dev,
"Discarded key matrix event, unexpected length: %d != %d\n",
ckdev->ec->event_size, ckdev->cols);
return NOTIFY_OK;
}
cros_ec_keyb_process(ckdev,
ckdev->ec->event_data.data.key_matrix,
ckdev->ec->event_size);
cros_ec_keyb_process(ckdev, event_data->data.key_matrix, event_size);
break;
case EC_MKBP_EVENT_SYSRQ:
pm_wakeup_event(ckdev->dev, 0);
val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq);
val = get_unaligned_le32(&event_data->data.sysrq);
dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val);
handle_sysrq(val);
break;
@@ -291,13 +384,11 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
case EC_MKBP_EVENT_SWITCH:
pm_wakeup_event(ckdev->dev, 0);
if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) {
val = get_unaligned_le32(
&ckdev->ec->event_data.data.buttons);
if (event_data->event_type == EC_MKBP_EVENT_BUTTON) {
val = get_unaligned_le32(&event_data->data.buttons);
ev_type = EV_KEY;
} else {
val = get_unaligned_le32(
&ckdev->ec->event_data.data.switches);
val = get_unaligned_le32(&event_data->data.switches);
ev_type = EV_SW;
}
cros_ec_keyb_report_bs(ckdev, ev_type, val);
@@ -326,8 +417,8 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev)
for (col = 0; col < ckdev->cols; col++) {
for (row = 0; row < ckdev->rows; row++) {
code = keymap[MATRIX_SCAN_CODE(row, col, row_shift)];
if (code && (code != KEY_BATTERY))
ckdev->valid_keys[col] |= 1 << row;
if (code != KEY_RESERVED && code != KEY_BATTERY)
ckdev->valid_keys[col] |= BIT(row);
}
dev_dbg(ckdev->dev, "valid_keys[%02d] = 0x%02x\n",
col, ckdev->valid_keys[col]);
@@ -583,6 +674,62 @@ static void cros_ec_keyb_parse_vivaldi_physmap(struct cros_ec_keyb *ckdev)
ckdev->vdata.num_function_row_keys = n_physmap;
}
/* Returns true if there is a KEY_FN code defined in the normal keymap */
static bool cros_ec_keyb_has_fn_key(struct cros_ec_keyb *ckdev)
{
const unsigned short *keycodes = ckdev->idev->keycode;
int i;
for (i = 0; i < MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); i++) {
if (keycodes[i] == KEY_FN)
return true;
}
return false;
}
/*
* Returns true if there is a KEY_FN defined and at least one key in the fn
* layer keymap
*/
static bool cros_ec_keyb_has_fn_map(struct cros_ec_keyb *ckdev)
{
struct input_dev *idev = ckdev->idev;
const unsigned short *keycodes = ckdev->idev->keycode;
int i;
if (!cros_ec_keyb_has_fn_key(ckdev))
return false;
for (i = MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift);
i < idev->keycodemax; i++) {
if (keycodes[i] != KEY_RESERVED)
return true;
}
return false;
}
/*
* Custom handler for the set keycode ioctl, calls the default handler and
* recomputes has_fn_map.
*/
static int cros_ec_keyb_setkeycode(struct input_dev *idev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode)
{
struct cros_ec_keyb *ckdev = input_get_drvdata(idev);
int ret;
ret = input_default_setkeycode(idev, ke, old_keycode);
if (ret)
return ret;
ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev);
return 0;
}
/**
* cros_ec_keyb_register_matrix - Register matrix keys
*
@@ -604,13 +751,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
if (err)
return err;
ckdev->valid_keys = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL);
if (!ckdev->valid_keys)
return -ENOMEM;
ckdev->old_kb_state = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL);
if (!ckdev->old_kb_state)
return -ENOMEM;
if (ckdev->cols > CROS_EC_KEYBOARD_COLS_MAX) {
dev_err(dev, "keypad,num-columns too large: %d (max: %d)\n",
ckdev->cols, CROS_EC_KEYBOARD_COLS_MAX);
return -EINVAL;
}
/*
* We call the keyboard matrix 'input0'. Allocate phys before input
@@ -632,11 +777,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
idev->id.version = 1;
idev->id.product = 0;
idev->dev.parent = dev;
idev->setkeycode = cros_ec_keyb_setkeycode;
ckdev->ghost_filter = device_property_read_bool(dev,
"google,needs-ghost-filter");
ckdev->ghost_filter = device_property_read_bool(dev, "google,needs-ghost-filter");
err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols,
err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows * 2, ckdev->cols,
NULL, idev);
if (err) {
dev_err(dev, "cannot build key matrix\n");
@@ -651,6 +796,8 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev)
cros_ec_keyb_compute_valid_keys(ckdev);
cros_ec_keyb_parse_vivaldi_physmap(ckdev);
ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev);
err = input_register_device(ckdev->idev);
if (err) {
dev_err(dev, "cannot register input device\n");

View File

@@ -324,7 +324,7 @@ static void imx_keypad_config(struct imx_keypad *keypad)
reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */
writew(reg_val, keypad->mmio_base + KPCR);
/* Write 0's to KPDR[15:8] (Colums) */
/* Write 0's to KPDR[15:8] (Columns) */
reg_val = readw(keypad->mmio_base + KPDR);
reg_val &= 0x00ff;
writew(reg_val, keypad->mmio_base + KPDR);
@@ -357,7 +357,7 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad)
reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD;
writew(reg_val, keypad->mmio_base + KPSR);
/* Colums as open drain and disable all rows */
/* Columns as open drain and disable all rows */
reg_val = (keypad->cols_en_mask & 0xff) << 8;
writew(reg_val, keypad->mmio_base + KPCR);
}

View File

@@ -295,8 +295,6 @@ static int mpr_touchkey_probe(struct i2c_client *client)
return error;
i2c_set_clientdata(client, mpr121);
device_init_wakeup(dev,
device_property_read_bool(dev, "wakeup-source"));
return 0;
}
@@ -305,9 +303,6 @@ static int mpr_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00);
return 0;
@@ -318,9 +313,6 @@ static int mpr_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client);
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR,
mpr121->keycount);

View File

@@ -435,8 +435,7 @@ static int qt1050_probe(struct i2c_client *client)
int err;
/* Check basic functionality */
err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
if (!err) {
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
dev_err(&client->dev, "%s adapter not supported\n",
dev_driver_string(&client->adapter->dev));
return -ENODEV;

View File

@@ -133,8 +133,7 @@ static int qt1070_probe(struct i2c_client *client)
int i;
int err;
err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE);
if (!err) {
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
dev_err(&client->dev, "%s adapter not supported\n",
dev_driver_string(&client->adapter->dev));
return -ENODEV;

View File

@@ -77,11 +77,8 @@ static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
static int adxl34x_i2c_probe(struct i2c_client *client)
{
struct adxl34x *ac;
int error;
error = i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA);
if (!error) {
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
return -EIO;
}

View File

@@ -14,6 +14,7 @@
#include <linux/input.h>
#include <linux/types.h>
#include <linux/acpi.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#define ACPI_ATLAS_NAME "Atlas ACPI"
@@ -57,8 +58,9 @@ static acpi_status acpi_atlas_button_handler(u32 function,
return status;
}
static int atlas_acpi_button_add(struct acpi_device *device)
static int atlas_acpi_button_probe(struct platform_device *pdev)
{
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
acpi_status status;
int i;
int err;
@@ -106,8 +108,9 @@ static int atlas_acpi_button_add(struct acpi_device *device)
return err;
}
static void atlas_acpi_button_remove(struct acpi_device *device)
static void atlas_acpi_button_remove(struct platform_device *pdev)
{
struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
acpi_status status;
status = acpi_remove_address_space_handler(device->handle,
@@ -124,16 +127,15 @@ static const struct acpi_device_id atlas_device_ids[] = {
};
MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
static struct acpi_driver atlas_acpi_driver = {
.name = ACPI_ATLAS_NAME,
.class = ACPI_ATLAS_CLASS,
.ids = atlas_device_ids,
.ops = {
.add = atlas_acpi_button_add,
.remove = atlas_acpi_button_remove,
static struct platform_driver atlas_acpi_driver = {
.probe = atlas_acpi_button_probe,
.remove = atlas_acpi_button_remove,
.driver = {
.name = ACPI_ATLAS_NAME,
.acpi_match_table = atlas_device_ids,
},
};
module_acpi_driver(atlas_acpi_driver);
module_platform_driver(atlas_acpi_driver);
MODULE_AUTHOR("Jaya Kumar");
MODULE_LICENSE("GPL");

View File

@@ -43,6 +43,12 @@
#define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(6, 0)
#define AW86927_PLAYCFG1_BST_8500MV 0x50
#define AW86938_PLAYCFG1_REG 0x06
#define AW86938_PLAYCFG1_BST_MODE_MASK GENMASK(5, 5)
#define AW86938_PLAYCFG1_BST_MODE_BYPASS 0
#define AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(4, 0)
#define AW86938_PLAYCFG1_BST_7000MV 0x11
#define AW86927_PLAYCFG2_REG 0x07
#define AW86927_PLAYCFG3_REG 0x08
@@ -140,6 +146,7 @@
#define AW86927_CHIPIDH_REG 0x57
#define AW86927_CHIPIDL_REG 0x58
#define AW86927_CHIPID 0x9270
#define AW86938_CHIPID 0x9380
#define AW86927_TMCFG_REG 0x5b
#define AW86927_TMCFG_UNLOCK 0x7d
@@ -173,14 +180,20 @@ enum aw86927_work_mode {
AW86927_RAM_MODE,
};
enum aw86927_model {
AW86927,
AW86938,
};
struct aw86927_data {
enum aw86927_model model;
struct work_struct play_work;
struct device *dev;
struct input_dev *input_dev;
struct i2c_client *client;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
bool running;
u16 level;
};
static const struct regmap_config aw86927_regmap_config = {
@@ -325,11 +338,12 @@ static int aw86927_haptics_play(struct input_dev *dev, void *data, struct ff_eff
if (!level)
level = effect->u.rumble.weak_magnitude;
/* If already running, don't restart playback */
if (haptics->running && level)
/* If level does not change, don't restart playback */
if (haptics->level == level)
return 0;
haptics->running = level;
haptics->level = level;
schedule_work(&haptics->play_work);
return 0;
@@ -376,8 +390,7 @@ static int aw86927_play_sine(struct aw86927_data *haptics)
if (err)
return err;
/* set gain to value lower than 0x80 to avoid distorted playback */
err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c);
err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, haptics->level * 0x80 / 0xffff);
if (err)
return err;
@@ -409,7 +422,7 @@ static void aw86927_haptics_play_work(struct work_struct *work)
struct device *dev = &haptics->client->dev;
int err;
if (haptics->running)
if (haptics->level)
err = aw86927_play_sine(haptics);
else
err = aw86927_stop(haptics);
@@ -565,13 +578,26 @@ static int aw86927_haptic_init(struct aw86927_data *haptics)
if (err)
return err;
err = regmap_update_bits(haptics->regmap,
AW86927_PLAYCFG1_REG,
AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
AW86927_PLAYCFG1_BST_8500MV));
if (err)
return err;
switch (haptics->model) {
case AW86927:
err = regmap_update_bits(haptics->regmap,
AW86927_PLAYCFG1_REG,
AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
AW86927_PLAYCFG1_BST_8500MV));
if (err)
return err;
break;
case AW86938:
err = regmap_update_bits(haptics->regmap,
AW86938_PLAYCFG1_REG,
AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK,
FIELD_PREP(AW86938_PLAYCFG1_BST_VOUT_VREFSET_MASK,
AW86938_PLAYCFG1_BST_7000MV));
if (err)
return err;
break;
}
err = regmap_update_bits(haptics->regmap,
AW86927_PLAYCFG3_REG,
@@ -599,6 +625,9 @@ static int aw86927_ram_init(struct aw86927_data *haptics)
FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
AW86927_SYSCTRL3_EN_RAMINIT_ON));
/* AW86938 wants a 1ms delay here */
usleep_range(1000, 1500);
/* Set base address for the start of the SRAM waveforms */
err = regmap_write(haptics->regmap,
AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL);
@@ -717,7 +746,14 @@ static int aw86927_detect(struct aw86927_data *haptics)
chip_id = be16_to_cpu(read_buf);
if (chip_id != AW86927_CHIPID) {
switch (chip_id) {
case AW86927_CHIPID:
haptics->model = AW86927;
break;
case AW86938_CHIPID:
haptics->model = AW86938;
break;
default:
dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
return -ENODEV;
}

View File

@@ -7,14 +7,16 @@
* Copyright: (C) 2014 Texas Instruments, Inc.
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/device/devres.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <dt-bindings/input/ti-drv260x.h>
@@ -165,6 +167,12 @@
#define DRV260X_AUTOCAL_TIME_500MS (2 << 4)
#define DRV260X_AUTOCAL_TIME_1000MS (3 << 4)
/*
* Timeout for waiting for the GO status bit, in seconds. Should be reasonably
* large to wait for a auto-calibration cycle completion.
*/
#define DRV260X_GO_TIMEOUT_S 5
/**
* struct drv260x_data -
* @input_dev: Pointer to the input device
@@ -308,6 +316,7 @@ static int drv260x_init(struct drv260x_data *haptics)
{
int error;
unsigned int cal_buf;
unsigned long timeout;
error = regmap_write(haptics->regmap,
DRV260X_RATED_VOLT, haptics->rated_voltage);
@@ -397,6 +406,7 @@ static int drv260x_init(struct drv260x_data *haptics)
return error;
}
timeout = jiffies + DRV260X_GO_TIMEOUT_S * HZ;
do {
usleep_range(15000, 15500);
error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
@@ -406,6 +416,11 @@ static int drv260x_init(struct drv260x_data *haptics)
error);
return error;
}
if (time_after(jiffies, timeout)) {
dev_err(&haptics->client->dev,
"Calibration timeout. The device cannot be used.\n");
return -ETIMEDOUT;
}
} while (cal_buf == DRV260X_GO_BIT);
return 0;
@@ -419,6 +434,13 @@ static const struct regmap_config drv260x_regmap_config = {
.cache_type = REGCACHE_NONE,
};
static void drv260x_power_off(void *data)
{
struct drv260x_data *haptics = data;
regulator_disable(haptics->regulator);
}
static int drv260x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
@@ -484,6 +506,16 @@ static int drv260x_probe(struct i2c_client *client)
return error;
}
error = regulator_enable(haptics->regulator);
if (error) {
dev_err(dev, "Failed to enable regulator: %d\n", error);
return error;
}
error = devm_add_action_or_reset(dev, drv260x_power_off, haptics);
if (error)
return error;
haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable",
GPIOD_OUT_HIGH);
if (IS_ERR(haptics->enable_gpio))
@@ -598,11 +630,22 @@ static int drv260x_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
static const struct i2c_device_id drv260x_id[] = {
{ "drv2604" },
{ "drv2604l" },
{ "drv2605" },
{ "drv2605l" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv260x_id);
#ifdef CONFIG_ACPI
static const struct acpi_device_id drv260x_acpi_match[] = {
{ "DRV2604" },
{ }
};
MODULE_DEVICE_TABLE(acpi, drv260x_acpi_match);
#endif
static const struct of_device_id drv260x_of_match[] = {
{ .compatible = "ti,drv2604", },
{ .compatible = "ti,drv2604l", },
@@ -616,6 +659,7 @@ static struct i2c_driver drv260x_driver = {
.probe = drv260x_probe,
.driver = {
.name = "drv260x-haptics",
.acpi_match_table = ACPI_PTR(drv260x_acpi_match),
.of_match_table = drv260x_of_match,
.pm = pm_sleep_ptr(&drv260x_pm_ops),
},

View File

@@ -438,6 +438,14 @@ static void ims_pcu_handle_response(struct ims_pcu *pcu)
}
}
static void ims_pcu_reset_packet(struct ims_pcu *pcu)
{
pcu->have_stx = true;
pcu->have_dle = false;
pcu->read_pos = 0;
pcu->check_sum = 0;
}
static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
{
int i;
@@ -450,6 +458,14 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
continue;
if (pcu->have_dle) {
if (pcu->read_pos >= IMS_PCU_BUF_SIZE) {
dev_warn(pcu->dev,
"Packet too long (%d bytes), discarding\n",
pcu->read_pos);
ims_pcu_reset_packet(pcu);
continue;
}
pcu->have_dle = false;
pcu->read_buf[pcu->read_pos++] = data;
pcu->check_sum += data;
@@ -462,10 +478,8 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
dev_warn(pcu->dev,
"Unexpected STX at byte %d, discarding old data\n",
pcu->read_pos);
ims_pcu_reset_packet(pcu);
pcu->have_stx = true;
pcu->have_dle = false;
pcu->read_pos = 0;
pcu->check_sum = 0;
break;
case IMS_PCU_PROTOCOL_DLE:
@@ -485,12 +499,18 @@ static void ims_pcu_process_data(struct ims_pcu *pcu, struct urb *urb)
ims_pcu_handle_response(pcu);
}
pcu->have_stx = false;
pcu->have_dle = false;
pcu->read_pos = 0;
ims_pcu_reset_packet(pcu);
break;
default:
if (pcu->read_pos >= IMS_PCU_BUF_SIZE) {
dev_warn(pcu->dev,
"Packet too long (%d bytes), discarding\n",
pcu->read_pos);
ims_pcu_reset_packet(pcu);
continue;
}
pcu->read_buf[pcu->read_pos++] = data;
pcu->check_sum += data;
break;

View File

@@ -420,24 +420,6 @@ static void keyspan_close(struct input_dev *dev)
usb_kill_urb(remote->irq_urb);
}
static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_interface *iface)
{
struct usb_endpoint_descriptor *endpoint;
int i;
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
endpoint = &iface->endpoint[i].desc;
if (usb_endpoint_is_int_in(endpoint)) {
/* we found our interrupt in endpoint */
return endpoint;
}
}
return NULL;
}
/*
* Routine that sets up the driver to handle a specific USB device detected on the bus.
*/
@@ -449,8 +431,8 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
struct input_dev *input_dev;
int i, error;
endpoint = keyspan_get_in_endpoint(interface->cur_altsetting);
if (!endpoint)
error = usb_find_int_in_endpoint(interface->cur_altsetting, &endpoint);
if (error)
return -ENODEV;
remote = kzalloc_obj(*remote);

View File

@@ -164,16 +164,6 @@ config MOUSE_PS2_TOUCHKIT
If unsure, say N.
config MOUSE_PS2_OLPC
bool "OLPC PS/2 mouse protocol extension"
depends on MOUSE_PS2 && OLPC
help
Say Y here if you have an OLPC XO-1 laptop (with built-in
PS/2 touchpad/tablet device). The manufacturer calls the
touchpad an HGPK.
If unsure, say N.
config MOUSE_PS2_FOCALTECH
bool "FocalTech PS/2 mouse protocol extension" if EXPERT
default y
@@ -300,32 +290,6 @@ config MOUSE_ELAN_I2C_SMBUS
If unsure, say Y.
config MOUSE_INPORT
tristate "InPort/MS/ATIXL busmouse"
depends on ISA
help
Say Y here if you have an InPort, Microsoft or ATI XL busmouse.
They are rather rare these days.
To compile this driver as a module, choose M here: the
module will be called inport.
config MOUSE_ATIXL
bool "ATI XL variant"
depends on MOUSE_INPORT
help
Say Y here if your mouse is of the ATI XL variety.
config MOUSE_LOGIBM
tristate "Logitech busmouse"
depends on ISA
help
Say Y here if you have a Logitech busmouse.
They are rather rare these days.
To compile this driver as a module, choose M here: the
module will be called logibm.
config MOUSE_AMIGA
tristate "Amiga mouse"
depends on AMIGA

View File

@@ -12,8 +12,6 @@ obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o
obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o
obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o
obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o
obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o
obj-$(CONFIG_MOUSE_PS2) += psmouse.o
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
@@ -28,7 +26,6 @@ psmouse-objs := psmouse-base.o synaptics.o focaltech.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o
psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o
psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o

View File

@@ -12,6 +12,7 @@
* tpconfig utility (by C. Scott Ananian and Bruce Kall).
*/
#include "linux/workqueue.h"
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
@@ -1452,7 +1453,7 @@ static int alps_do_register_bare_ps2_mouse(struct alps_data *priv)
static void alps_register_bare_ps2_mouse(struct work_struct *work)
{
struct alps_data *priv = container_of(work, struct alps_data,
dev3_register_work.work);
dev3_register_work);
int error;
guard(mutex)(&alps_mutex);
@@ -1485,8 +1486,7 @@ static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
} else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
/* Register dev3 mouse if we received PS/2 packet first time */
if (!IS_ERR(priv->dev3))
psmouse_queue_work(psmouse, &priv->dev3_register_work,
0);
schedule_work(&priv->dev3_register_work);
return;
} else {
dev = priv->dev3;
@@ -2975,7 +2975,7 @@ static void alps_disconnect(struct psmouse *psmouse)
psmouse_reset(psmouse);
timer_shutdown_sync(&priv->timer);
disable_delayed_work_sync(&priv->dev3_register_work);
disable_work_sync(&priv->dev3_register_work);
if (priv->dev2)
input_unregister_device(priv->dev2);
if (!IS_ERR_OR_NULL(priv->dev3))
@@ -3147,8 +3147,7 @@ int alps_init(struct psmouse *psmouse)
priv->psmouse = psmouse;
INIT_DELAYED_WORK(&priv->dev3_register_work,
alps_register_bare_ps2_mouse);
INIT_WORK(&priv->dev3_register_work, alps_register_bare_ps2_mouse);
psmouse->protocol_handler = alps_process_byte;
psmouse->poll = alps_poll;

View File

@@ -257,7 +257,7 @@ struct alps_fields {
* @dev3: Generic PS/2 mouse (can be NULL, delayed registering).
* @phys2: Physical path for the trackstick device.
* @phys3: Physical path for the generic PS/2 mouse.
* @dev3_register_work: Delayed work for registering PS/2 mouse.
* @dev3_register_work: A work instance for registering PS/2 mouse.
* @nibble_commands: Command mapping used for touchpad register accesses.
* @addr_command: Command used to tell the touchpad that a register address
* follows.
@@ -289,7 +289,7 @@ struct alps_data {
struct input_dev *dev3;
char phys2[32];
char phys3[32];
struct delayed_work dev3_register_work;
struct work_struct dev3_register_work;
/* these are autodetected when the device is identified */
const struct alps_nibble_commands *nibble_commands;

View File

@@ -829,29 +829,20 @@ static int atp_probe(struct usb_interface *iface,
struct atp *dev;
struct input_dev *input_dev;
struct usb_device *udev = interface_to_usbdev(iface);
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
int int_in_endpointAddr = 0;
int i, error = -ENOMEM;
struct usb_endpoint_descriptor *ep;
int error;
const struct atp_info *info = (const struct atp_info *)id->driver_info;
/* set up the endpoint information */
/* use only the first interrupt-in endpoint */
iface_desc = iface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
/* we found an interrupt in endpoint */
int_in_endpointAddr = endpoint->bEndpointAddress;
break;
}
}
if (!int_in_endpointAddr) {
error = usb_find_int_in_endpoint(iface->cur_altsetting, &ep);
if (error) {
dev_err(&iface->dev, "Could not find int-in endpoint\n");
return -EIO;
}
/* allocate memory for our device state and initialize it */
error = -ENOMEM;
dev = kzalloc_obj(*dev);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
@@ -875,7 +866,7 @@ static int atp_probe(struct usb_interface *iface,
goto err_free_urb;
usb_fill_int_urb(dev->urb, udev,
usb_rcvintpipe(udev, int_in_endpointAddr),
usb_rcvintpipe(udev, usb_endpoint_num(ep)),
dev->data, dev->info->datalen,
dev->info->callback, dev, 1);

File diff suppressed because it is too large Load Diff

View File

@@ -1,61 +0,0 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* OLPC HGPK (XO-1) touchpad PS/2 mouse driver
*/
#ifndef _HGPK_H
#define _HGPK_H
#define HGPK_GS 0xff /* The GlideSensor */
#define HGPK_PT 0xcf /* The PenTablet */
enum hgpk_model_t {
HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */
HGPK_MODEL_C = 0x3c,
HGPK_MODEL_D = 0x50, /* C1, mass production */
};
enum hgpk_spew_flag {
NO_SPEW,
MAYBE_SPEWING,
SPEW_DETECTED,
RECALIBRATING,
};
#define SPEW_WATCH_COUNT 42 /* at 12ms/packet, this is 1/2 second */
enum hgpk_mode {
HGPK_MODE_MOUSE,
HGPK_MODE_GLIDESENSOR,
HGPK_MODE_PENTABLET,
HGPK_MODE_INVALID
};
struct hgpk_data {
struct psmouse *psmouse;
enum hgpk_mode mode;
bool powered;
enum hgpk_spew_flag spew_flag;
int spew_count, x_tally, y_tally; /* spew detection */
unsigned long recalib_window;
struct delayed_work recalib_wq;
int abs_x, abs_y;
int dupe_count;
int xbigj, ybigj, xlast, ylast; /* jumpiness detection */
int xsaw_secondary, ysaw_secondary; /* jumpiness detection */
};
int hgpk_detect(struct psmouse *psmouse, bool set_properties);
int hgpk_init(struct psmouse *psmouse);
#ifdef CONFIG_MOUSE_PS2_OLPC
void hgpk_module_init(void);
#else
static inline void hgpk_module_init(void)
{
}
#endif
#endif

View File

@@ -1,177 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
* Teemu Rantanen Derrick Cole
* Peter Cervasio Christoph Niemann
* Philip Blundell Russell King
* Bob Harris
*/
/*
* Inport (ATI XL and Microsoft) busmouse driver for Linux
*/
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <asm/io.h>
#include <asm/irq.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Inport (ATI XL and Microsoft) busmouse driver");
MODULE_LICENSE("GPL");
#define INPORT_BASE 0x23c
#define INPORT_EXTENT 4
#define INPORT_CONTROL_PORT INPORT_BASE + 0
#define INPORT_DATA_PORT INPORT_BASE + 1
#define INPORT_SIGNATURE_PORT INPORT_BASE + 2
#define INPORT_REG_BTNS 0x00
#define INPORT_REG_X 0x01
#define INPORT_REG_Y 0x02
#define INPORT_REG_MODE 0x07
#define INPORT_RESET 0x80
#ifdef CONFIG_MOUSE_ATIXL
#define INPORT_NAME "ATI XL Mouse"
#define INPORT_VENDOR 0x0002
#define INPORT_SPEED_30HZ 0x01
#define INPORT_SPEED_50HZ 0x02
#define INPORT_SPEED_100HZ 0x03
#define INPORT_SPEED_200HZ 0x04
#define INPORT_MODE_BASE INPORT_SPEED_100HZ
#define INPORT_MODE_IRQ 0x08
#else
#define INPORT_NAME "Microsoft InPort Mouse"
#define INPORT_VENDOR 0x0001
#define INPORT_MODE_BASE 0x10
#define INPORT_MODE_IRQ 0x01
#endif
#define INPORT_MODE_HOLD 0x20
#define INPORT_IRQ 5
static int inport_irq = INPORT_IRQ;
module_param_hw_named(irq, inport_irq, uint, irq, 0);
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
static struct input_dev *inport_dev;
static irqreturn_t inport_interrupt(int irq, void *dev_id)
{
unsigned char buttons;
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
outb(INPORT_REG_X, INPORT_CONTROL_PORT);
input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
outb(INPORT_REG_Y, INPORT_CONTROL_PORT);
input_report_rel(inport_dev, REL_Y, inb(INPORT_DATA_PORT));
outb(INPORT_REG_BTNS, INPORT_CONTROL_PORT);
buttons = inb(INPORT_DATA_PORT);
input_report_key(inport_dev, BTN_MIDDLE, buttons & 1);
input_report_key(inport_dev, BTN_LEFT, buttons & 2);
input_report_key(inport_dev, BTN_RIGHT, buttons & 4);
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
input_sync(inport_dev);
return IRQ_HANDLED;
}
static int inport_open(struct input_dev *dev)
{
if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
return -EBUSY;
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
return 0;
}
static void inport_close(struct input_dev *dev)
{
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
free_irq(inport_irq, NULL);
}
static int __init inport_init(void)
{
unsigned char a, b, c;
int err;
if (!request_region(INPORT_BASE, INPORT_EXTENT, "inport")) {
printk(KERN_ERR "inport.c: Can't allocate ports at %#x\n", INPORT_BASE);
return -EBUSY;
}
a = inb(INPORT_SIGNATURE_PORT);
b = inb(INPORT_SIGNATURE_PORT);
c = inb(INPORT_SIGNATURE_PORT);
if (a == b || a != c) {
printk(KERN_INFO "inport.c: Didn't find InPort mouse at %#x\n", INPORT_BASE);
err = -ENODEV;
goto err_release_region;
}
inport_dev = input_allocate_device();
if (!inport_dev) {
printk(KERN_ERR "inport.c: Not enough memory for input device\n");
err = -ENOMEM;
goto err_release_region;
}
inport_dev->name = INPORT_NAME;
inport_dev->phys = "isa023c/input0";
inport_dev->id.bustype = BUS_ISA;
inport_dev->id.vendor = INPORT_VENDOR;
inport_dev->id.product = 0x0001;
inport_dev->id.version = 0x0100;
inport_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
inport_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
inport_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
inport_dev->open = inport_open;
inport_dev->close = inport_close;
outb(INPORT_RESET, INPORT_CONTROL_PORT);
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
err = input_register_device(inport_dev);
if (err)
goto err_free_dev;
return 0;
err_free_dev:
input_free_device(inport_dev);
err_release_region:
release_region(INPORT_BASE, INPORT_EXTENT);
return err;
}
static void __exit inport_exit(void)
{
input_unregister_device(inport_dev);
release_region(INPORT_BASE, INPORT_EXTENT);
}
module_init(inport_init);
module_exit(inport_exit);

View File

@@ -1,166 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
* James Banks Matthew Dillon
* David Giller Nathan Laredo
* Linus Torvalds Johan Myreen
* Cliff Matthews Philip Blundell
* Russell King
*/
/*
* Logitech Bus Mouse Driver for Linux
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/irq.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Logitech busmouse driver");
MODULE_LICENSE("GPL");
#define LOGIBM_BASE 0x23c
#define LOGIBM_EXTENT 4
#define LOGIBM_DATA_PORT LOGIBM_BASE + 0
#define LOGIBM_SIGNATURE_PORT LOGIBM_BASE + 1
#define LOGIBM_CONTROL_PORT LOGIBM_BASE + 2
#define LOGIBM_CONFIG_PORT LOGIBM_BASE + 3
#define LOGIBM_ENABLE_IRQ 0x00
#define LOGIBM_DISABLE_IRQ 0x10
#define LOGIBM_READ_X_LOW 0x80
#define LOGIBM_READ_X_HIGH 0xa0
#define LOGIBM_READ_Y_LOW 0xc0
#define LOGIBM_READ_Y_HIGH 0xe0
#define LOGIBM_DEFAULT_MODE 0x90
#define LOGIBM_CONFIG_BYTE 0x91
#define LOGIBM_SIGNATURE_BYTE 0xa5
#define LOGIBM_IRQ 5
static int logibm_irq = LOGIBM_IRQ;
module_param_hw_named(irq, logibm_irq, uint, irq, 0);
MODULE_PARM_DESC(irq, "IRQ number (5=default)");
static struct input_dev *logibm_dev;
static irqreturn_t logibm_interrupt(int irq, void *dev_id)
{
char dx, dy;
unsigned char buttons;
outb(LOGIBM_READ_X_LOW, LOGIBM_CONTROL_PORT);
dx = (inb(LOGIBM_DATA_PORT) & 0xf);
outb(LOGIBM_READ_X_HIGH, LOGIBM_CONTROL_PORT);
dx |= (inb(LOGIBM_DATA_PORT) & 0xf) << 4;
outb(LOGIBM_READ_Y_LOW, LOGIBM_CONTROL_PORT);
dy = (inb(LOGIBM_DATA_PORT) & 0xf);
outb(LOGIBM_READ_Y_HIGH, LOGIBM_CONTROL_PORT);
buttons = inb(LOGIBM_DATA_PORT);
dy |= (buttons & 0xf) << 4;
buttons = ~buttons >> 5;
input_report_rel(logibm_dev, REL_X, dx);
input_report_rel(logibm_dev, REL_Y, dy);
input_report_key(logibm_dev, BTN_RIGHT, buttons & 1);
input_report_key(logibm_dev, BTN_MIDDLE, buttons & 2);
input_report_key(logibm_dev, BTN_LEFT, buttons & 4);
input_sync(logibm_dev);
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
return IRQ_HANDLED;
}
static int logibm_open(struct input_dev *dev)
{
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
return -EBUSY;
}
outb(LOGIBM_ENABLE_IRQ, LOGIBM_CONTROL_PORT);
return 0;
}
static void logibm_close(struct input_dev *dev)
{
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
free_irq(logibm_irq, NULL);
}
static int __init logibm_init(void)
{
int err;
if (!request_region(LOGIBM_BASE, LOGIBM_EXTENT, "logibm")) {
printk(KERN_ERR "logibm.c: Can't allocate ports at %#x\n", LOGIBM_BASE);
return -EBUSY;
}
outb(LOGIBM_CONFIG_BYTE, LOGIBM_CONFIG_PORT);
outb(LOGIBM_SIGNATURE_BYTE, LOGIBM_SIGNATURE_PORT);
udelay(100);
if (inb(LOGIBM_SIGNATURE_PORT) != LOGIBM_SIGNATURE_BYTE) {
printk(KERN_INFO "logibm.c: Didn't find Logitech busmouse at %#x\n", LOGIBM_BASE);
err = -ENODEV;
goto err_release_region;
}
outb(LOGIBM_DEFAULT_MODE, LOGIBM_CONFIG_PORT);
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
logibm_dev = input_allocate_device();
if (!logibm_dev) {
printk(KERN_ERR "logibm.c: Not enough memory for input device\n");
err = -ENOMEM;
goto err_release_region;
}
logibm_dev->name = "Logitech bus mouse";
logibm_dev->phys = "isa023c/input0";
logibm_dev->id.bustype = BUS_ISA;
logibm_dev->id.vendor = 0x0003;
logibm_dev->id.product = 0x0001;
logibm_dev->id.version = 0x0100;
logibm_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
logibm_dev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
logibm_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
logibm_dev->open = logibm_open;
logibm_dev->close = logibm_close;
err = input_register_device(logibm_dev);
if (err)
goto err_free_dev;
return 0;
err_free_dev:
input_free_device(logibm_dev);
err_release_region:
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
return err;
}
static void __exit logibm_exit(void)
{
input_unregister_device(logibm_dev);
release_region(LOGIBM_BASE, LOGIBM_EXTENT);
}
module_init(logibm_init);
module_exit(logibm_exit);

View File

@@ -26,7 +26,6 @@
#include "synaptics.h"
#include "logips2pp.h"
#include "alps.h"
#include "hgpk.h"
#include "lifebook.h"
#include "trackpoint.h"
#include "touchkit_ps2.h"
@@ -114,8 +113,6 @@ ATTRIBUTE_GROUPS(psmouse_dev);
*/
static DEFINE_MUTEX(psmouse_mutex);
static struct workqueue_struct *kpsmoused_wq;
struct psmouse *psmouse_from_serio(struct serio *serio)
{
struct ps2dev *ps2dev = serio_get_drvdata(serio);
@@ -241,12 +238,6 @@ psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET;
}
void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
unsigned long delay)
{
queue_delayed_work(kpsmoused_wq, work, delay);
}
/*
* __psmouse_set_state() sets new psmouse state and resets all flags.
*/
@@ -380,7 +371,7 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data)
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
schedule_work(&psmouse->resync_work);
return;
}
@@ -393,9 +384,7 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data)
return;
}
if (psmouse->packet[1] == PSMOUSE_RET_ID ||
(psmouse->protocol->type == PSMOUSE_HGPK &&
psmouse->packet[1] == PSMOUSE_RET_BAT)) {
if (psmouse->packet[1] == PSMOUSE_RET_ID) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE);
serio_reconnect(ps2dev->serio);
return;
@@ -418,7 +407,7 @@ static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data)
time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
schedule_work(&psmouse->resync_work);
return;
}
@@ -837,14 +826,6 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.detect = touchkit_ps2_detect,
},
#endif
#ifdef CONFIG_MOUSE_PS2_OLPC
{
.type = PSMOUSE_HGPK,
.name = "OLPC HGPK",
.alias = "hgpk",
.detect = hgpk_detect,
},
#endif
#ifdef CONFIG_MOUSE_PS2_ELANTECH
{
.type = PSMOUSE_ELANTECH,
@@ -1153,13 +1134,6 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_ALPS;
}
/* Try OLPC HGPK touchpad */
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto,
set_properties, true)) {
return PSMOUSE_HGPK;
}
/* Try Elantech touchpad */
if (max_proto > PSMOUSE_IMEX &&
psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH,
@@ -1331,7 +1305,7 @@ int psmouse_deactivate(struct psmouse *psmouse)
static void psmouse_resync(struct work_struct *work)
{
struct psmouse *parent = NULL, *psmouse =
container_of(work, struct psmouse, resync_work.work);
container_of(work, struct psmouse, resync_work);
struct serio *serio = psmouse->ps2dev.serio;
psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
bool failed = false, enabled = false;
@@ -1484,7 +1458,7 @@ static void psmouse_disconnect(struct serio *serio)
/* make sure we don't have a resync in progress */
mutex_unlock(&psmouse_mutex);
flush_workqueue(kpsmoused_wq);
disable_work_sync(&psmouse->resync_work);
mutex_lock(&psmouse_mutex);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
@@ -1598,7 +1572,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
ps2_init(&psmouse->ps2dev, serio,
psmouse_pre_receive_byte, psmouse_receive_byte);
INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
INIT_WORK(&psmouse->resync_work, psmouse_resync);
psmouse->dev = input_dev;
scnprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
@@ -2035,27 +2009,17 @@ static int __init psmouse_init(void)
lifebook_module_init();
synaptics_module_init();
hgpk_module_init();
err = psmouse_smbus_module_init();
if (err)
return err;
kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0);
if (!kpsmoused_wq) {
pr_err("failed to create kpsmoused workqueue\n");
err = -ENOMEM;
goto err_smbus_exit;
}
err = serio_register_driver(&psmouse_drv);
if (err)
goto err_destroy_wq;
goto err_smbus_exit;
return 0;
err_destroy_wq:
destroy_workqueue(kpsmoused_wq);
err_smbus_exit:
psmouse_smbus_module_exit();
return err;
@@ -2064,7 +2028,6 @@ static int __init psmouse_init(void)
static void __exit psmouse_exit(void)
{
serio_unregister_driver(&psmouse_drv);
destroy_workqueue(kpsmoused_wq);
psmouse_smbus_module_exit();
}

View File

@@ -59,7 +59,7 @@ enum psmouse_type {
PSMOUSE_TRACKPOINT,
PSMOUSE_TOUCHKIT_PS2,
PSMOUSE_CORTRON,
PSMOUSE_HGPK,
PSMOUSE_HGPK, /* No longer used */
PSMOUSE_ELANTECH,
PSMOUSE_FSP,
PSMOUSE_SYNAPTICS_RELATIVE,
@@ -90,7 +90,7 @@ struct psmouse {
void *private;
struct input_dev *dev;
struct ps2dev ps2dev;
struct delayed_work resync_work;
struct work_struct resync_work;
const char *vendor;
const char *name;
const struct psmouse_protocol *protocol;
@@ -132,8 +132,6 @@ struct psmouse {
struct psmouse *psmouse_from_serio(struct serio *serio);
void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
unsigned long delay);
int psmouse_reset(struct psmouse *psmouse);
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);

View File

@@ -220,25 +220,6 @@ static void synusb_irq(struct urb *urb)
__func__, error);
}
static struct usb_endpoint_descriptor *
synusb_get_in_endpoint(struct usb_host_interface *iface)
{
struct usb_endpoint_descriptor *endpoint;
int i;
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
endpoint = &iface->endpoint[i].desc;
if (usb_endpoint_is_int_in(endpoint)) {
/* we found our interrupt in endpoint */
return endpoint;
}
}
return NULL;
}
static int synusb_open(struct input_dev *dev)
{
struct synusb *synusb = input_get_drvdata(dev);
@@ -307,8 +288,8 @@ static int synusb_probe(struct usb_interface *intf,
return error;
}
ep = synusb_get_in_endpoint(intf->cur_altsetting);
if (!ep)
error = usb_find_int_in_endpoint(intf->cur_altsetting, &ep);
if (error)
return -ENODEV;
synusb = kzalloc_obj(*synusb);

View File

@@ -55,19 +55,6 @@ config SERIO_SERPORT
To compile this driver as a module, choose M here: the
module will be called serport.
config SERIO_CT82C710
tristate "ct82c710 Aux port controller"
depends on X86
help
Say Y here if you have a Texas Instruments TravelMate notebook
equipped with the ct82c710 chip and want to use a mouse connected
to the "QuickPort".
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called ct82c710.
config SERIO_Q40KBD
tristate "Q40 keyboard controller"
depends on Q40

View File

@@ -9,7 +9,6 @@ obj-$(CONFIG_SERIO) += serio.o
obj-$(CONFIG_SERIO_I8042) += i8042.o
obj-$(CONFIG_SERIO_PARKBD) += parkbd.o
obj-$(CONFIG_SERIO_SERPORT) += serport.o
obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o
obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o
obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o
obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o

View File

@@ -1,239 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 1999-2001 Vojtech Pavlik
*/
/*
* 82C710 C&T mouse port chip driver for Linux
*/
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/io.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("82C710 C&T mouse port chip driver");
MODULE_LICENSE("GPL");
/*
* ct82c710 interface
*/
#define CT82C710_DEV_IDLE 0x01 /* Device Idle */
#define CT82C710_RX_FULL 0x02 /* Device Char received */
#define CT82C710_TX_IDLE 0x04 /* Device XMIT Idle */
#define CT82C710_RESET 0x08 /* Device Reset */
#define CT82C710_INTS_ON 0x10 /* Device Interrupt On */
#define CT82C710_ERROR_FLAG 0x20 /* Device Error */
#define CT82C710_CLEAR 0x40 /* Device Clear */
#define CT82C710_ENABLE 0x80 /* Device Enable */
#define CT82C710_IRQ 12
#define CT82C710_DATA ct82c710_iores.start
#define CT82C710_STATUS (ct82c710_iores.start + 1)
static struct serio *ct82c710_port;
static struct platform_device *ct82c710_device;
static struct resource ct82c710_iores;
/*
* Interrupt handler for the 82C710 mouse port. A character
* is waiting in the 82C710.
*/
static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id)
{
return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0);
}
/*
* Wait for device to send output char and flush any input char.
*/
static int ct82c170_wait(void)
{
int timeout = 60000;
while ((inb(CT82C710_STATUS) & (CT82C710_RX_FULL | CT82C710_TX_IDLE | CT82C710_DEV_IDLE))
!= (CT82C710_DEV_IDLE | CT82C710_TX_IDLE) && timeout) {
if (inb_p(CT82C710_STATUS) & CT82C710_RX_FULL) inb_p(CT82C710_DATA);
udelay(1);
timeout--;
}
return !timeout;
}
static void ct82c710_close(struct serio *serio)
{
if (ct82c170_wait())
printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
outb_p(inb_p(CT82C710_STATUS) & ~(CT82C710_ENABLE | CT82C710_INTS_ON), CT82C710_STATUS);
if (ct82c170_wait())
printk(KERN_WARNING "ct82c710.c: Device busy in close()\n");
free_irq(CT82C710_IRQ, NULL);
}
static int ct82c710_open(struct serio *serio)
{
unsigned char status;
int err;
err = request_irq(CT82C710_IRQ, ct82c710_interrupt, 0, "ct82c710", NULL);
if (err)
return err;
status = inb_p(CT82C710_STATUS);
status |= (CT82C710_ENABLE | CT82C710_RESET);
outb_p(status, CT82C710_STATUS);
status &= ~(CT82C710_RESET);
outb_p(status, CT82C710_STATUS);
status |= CT82C710_INTS_ON;
outb_p(status, CT82C710_STATUS); /* Enable interrupts */
while (ct82c170_wait()) {
printk(KERN_ERR "ct82c710: Device busy in open()\n");
status &= ~(CT82C710_ENABLE | CT82C710_INTS_ON);
outb_p(status, CT82C710_STATUS);
free_irq(CT82C710_IRQ, NULL);
return -EBUSY;
}
return 0;
}
/*
* Write to the 82C710 mouse device.
*/
static int ct82c710_write(struct serio *port, unsigned char c)
{
if (ct82c170_wait()) return -1;
outb_p(c, CT82C710_DATA);
return 0;
}
/*
* See if we can find a 82C710 device. Read mouse address.
*/
static int __init ct82c710_detect(void)
{
outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */
outb_p(0xaa, 0x3fa); /* Inverse of 55 */
outb_p(0x36, 0x3fa); /* Address the chip */
outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */
outb_p(0x1b, 0x2fa); /* Inverse of e4 */
outb_p(0x0f, 0x390); /* Write index */
if (inb_p(0x391) != 0xe4) /* Config address found? */
return -ENODEV; /* No: no 82C710 here */
outb_p(0x0d, 0x390); /* Write index */
ct82c710_iores.start = inb_p(0x391) << 2; /* Get mouse I/O address */
ct82c710_iores.end = ct82c710_iores.start + 1;
ct82c710_iores.flags = IORESOURCE_IO;
outb_p(0x0f, 0x390);
outb_p(0x0f, 0x391); /* Close config mode */
return 0;
}
static int ct82c710_probe(struct platform_device *dev)
{
ct82c710_port = kzalloc_obj(*ct82c710_port);
if (!ct82c710_port)
return -ENOMEM;
ct82c710_port->id.type = SERIO_8042;
ct82c710_port->dev.parent = &dev->dev;
ct82c710_port->open = ct82c710_open;
ct82c710_port->close = ct82c710_close;
ct82c710_port->write = ct82c710_write;
strscpy(ct82c710_port->name, "C&T 82c710 mouse port",
sizeof(ct82c710_port->name));
snprintf(ct82c710_port->phys, sizeof(ct82c710_port->phys),
"isa%16llx/serio0", (unsigned long long)CT82C710_DATA);
serio_register_port(ct82c710_port);
printk(KERN_INFO "serio: C&T 82c710 mouse port at %#llx irq %d\n",
(unsigned long long)CT82C710_DATA, CT82C710_IRQ);
return 0;
}
static void ct82c710_remove(struct platform_device *dev)
{
serio_unregister_port(ct82c710_port);
}
static struct platform_driver ct82c710_driver = {
.driver = {
.name = "ct82c710",
},
.probe = ct82c710_probe,
.remove = ct82c710_remove,
};
static int __init ct82c710_init(void)
{
int error;
error = ct82c710_detect();
if (error)
return error;
error = platform_driver_register(&ct82c710_driver);
if (error)
return error;
ct82c710_device = platform_device_alloc("ct82c710", -1);
if (!ct82c710_device) {
error = -ENOMEM;
goto err_unregister_driver;
}
error = platform_device_add_resources(ct82c710_device, &ct82c710_iores, 1);
if (error)
goto err_free_device;
error = platform_device_add(ct82c710_device);
if (error)
goto err_free_device;
return 0;
err_free_device:
platform_device_put(ct82c710_device);
err_unregister_driver:
platform_driver_unregister(&ct82c710_driver);
return error;
}
static void __exit ct82c710_exit(void)
{
platform_device_unregister(ct82c710_device);
platform_driver_unregister(&ct82c710_driver);
}
module_init(ct82c710_init);
module_exit(ct82c710_exit);

View File

@@ -154,10 +154,8 @@ EXPORT_SYMBOL(ps2_end_command);
*/
void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
{
if (maxbytes > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1);
if (WARN_ON(maxbytes > sizeof(ps2dev->cmdbuf)))
maxbytes = sizeof(ps2dev->cmdbuf);
}
ps2_begin_command(ps2dev);
@@ -270,15 +268,11 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
int i;
u8 send_param[16];
if (receive > sizeof(ps2dev->cmdbuf)) {
WARN_ON(1);
if (WARN_ON(receive > sizeof(ps2dev->cmdbuf)))
return -EINVAL;
}
if (send && !param) {
WARN_ON(1);
if (WARN_ON(send && !param))
return -EINVAL;
}
memcpy(send_param, param, send);

View File

@@ -57,6 +57,7 @@
* http://aiptektablet.sourceforge.net.
*/
#include <linux/hid.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/slab.h>
@@ -164,8 +165,6 @@
#define USB_VENDOR_ID_AIPTEK 0x08ca
#define USB_VENDOR_ID_KYE 0x0458
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
/* PointerMode codes
*/
@@ -658,6 +657,8 @@ static void aiptek_irq(struct urb *urb)
pck = (data[1] & aiptek->curSetting.stylusButtonUpper) != 0 ? 1 : 0;
macro = dv && p && tip && !(data[3] & 1) ? (data[3] >> 1) : -1;
if (macro >= ARRAY_SIZE(macroKeyEvents))
macro = -1;
z = get_unaligned_le16(data + 4);
if (dv) {
@@ -699,7 +700,9 @@ static void aiptek_irq(struct urb *urb)
left = (data[1]& aiptek->curSetting.mouseButtonLeft) != 0 ? 1 : 0;
right = (data[1] & aiptek->curSetting.mouseButtonRight) != 0 ? 1 : 0;
middle = (data[1] & aiptek->curSetting.mouseButtonMiddle) != 0 ? 1 : 0;
macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : 0;
macro = dv && p && left && !(data[3] & 1) ? (data[3] >> 1) : -1;
if (macro >= ARRAY_SIZE(macroKeyEvents))
macro = -1;
if (dv) {
/* If the selected tool changed, reset the old
@@ -737,11 +740,11 @@ static void aiptek_irq(struct urb *urb)
*/
else if (data[0] == 6) {
macro = get_unaligned_le16(data + 1);
if (macro > 0) {
if (macro > 0 && macro - 1 < ARRAY_SIZE(macroKeyEvents)) {
input_report_key(inputdev, macroKeyEvents[macro - 1],
0);
}
if (macro < 25) {
if (macro + 1 < ARRAY_SIZE(macroKeyEvents)) {
input_report_key(inputdev, macroKeyEvents[macro + 1],
0);
}
@@ -760,7 +763,8 @@ static void aiptek_irq(struct urb *urb)
aiptek->curSetting.toolMode;
}
input_report_key(inputdev, macroKeyEvents[macro], 1);
if (macro < ARRAY_SIZE(macroKeyEvents))
input_report_key(inputdev, macroKeyEvents[macro], 1);
input_report_abs(inputdev, ABS_MISC,
1 | AIPTEK_REPORT_TOOL_UNKNOWN);
input_sync(inputdev);
@@ -856,7 +860,7 @@ aiptek_set_report(struct aiptek *aiptek,
return usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
USB_REQ_SET_REPORT,
HID_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE |
USB_DIR_OUT, (report_type << 8) + report_id,
aiptek->ifnum, buffer, size, 5000);
@@ -871,7 +875,7 @@ aiptek_get_report(struct aiptek *aiptek,
return usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
USB_REQ_GET_REPORT,
HID_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE |
USB_DIR_IN, (report_type << 8) + report_id,
aiptek->ifnum, buffer, size, 5000);

View File

@@ -36,6 +36,7 @@
* T Tip
*/
#include <linux/hid.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
@@ -44,10 +45,6 @@
#include <linux/workqueue.h>
#include <linux/mutex.h>
/* USB HID defines */
#define USB_REQ_GET_REPORT 0x01
#define USB_REQ_SET_REPORT 0x09
#define USB_VENDOR_ID_PEGASUSTECH 0x0e20
#define USB_DEVICE_ID_PEGASUS_NOTETAKER_EN100 0x0101
@@ -108,7 +105,7 @@ static int pegasus_control_msg(struct pegasus *pegasus, u8 *data, int len)
result = usb_control_msg(pegasus->usbdev,
usb_sndctrlpipe(pegasus->usbdev, 0),
USB_REQ_SET_REPORT,
HID_REQ_SET_REPORT,
USB_TYPE_VENDOR | USB_DIR_OUT,
0, 0, cmd_buf, sizeof_buf,
USB_CTRL_SET_TIMEOUT);

View File

@@ -723,18 +723,6 @@ config TOUCHSCREEN_INEXIO
To compile this driver as a module, choose M here: the
module will be called inexio.
config TOUCHSCREEN_MK712
tristate "ICS MicroClock MK712 touchscreen"
depends on ISA
help
Say Y here if you have the ICS MicroClock MK712 touchscreen
controller chip in your system.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called mk712.
config TOUCHSCREEN_HP600
tristate "HP Jornada 6xx touchscreen"
depends on SH_HP6XX && SH_ADC

View File

@@ -68,7 +68,6 @@ obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o
obj-$(CONFIG_TOUCHSCREEN_MSG2638) += msg2638.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS) += novatek-nvt-ts.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o

View File

@@ -376,17 +376,14 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
static void ad7877_timer(struct timer_list *t)
{
struct ad7877 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
guard(spinlock_irqsave)(&ts->lock);
ad7877_ts_event_release(ts);
spin_unlock_irqrestore(&ts->lock, flags);
}
static irqreturn_t ad7877_irq(int irq, void *handle)
{
struct ad7877 *ts = handle;
unsigned long flags;
int error;
error = spi_sync(ts->spi, &ts->msg);
@@ -395,11 +392,13 @@ static irqreturn_t ad7877_irq(int irq, void *handle)
goto out;
}
spin_lock_irqsave(&ts->lock, flags);
error = ad7877_process_data(ts);
if (!error)
scoped_guard(spinlock_irqsave, &ts->lock) {
error = ad7877_process_data(ts);
if (error)
goto out;
mod_timer(&ts->timer, jiffies + TS_PEN_UP_TIMEOUT);
spin_unlock_irqrestore(&ts->lock, flags);
}
out:
return IRQ_HANDLED;
@@ -409,7 +408,7 @@ static void ad7877_disable(void *data)
{
struct ad7877 *ts = data;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
if (!ts->disabled) {
ts->disabled = true;
@@ -423,20 +422,16 @@ static void ad7877_disable(void *data)
* We know the chip's in lowpower mode since we always
* leave it that way after every request
*/
mutex_unlock(&ts->mutex);
}
static void ad7877_enable(struct ad7877 *ts)
{
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
if (ts->disabled) {
ts->disabled = false;
enable_irq(ts->spi->irq);
}
mutex_unlock(&ts->mutex);
}
#define SHOW(name) static ssize_t \
@@ -509,10 +504,9 @@ static ssize_t ad7877_dac_store(struct device *dev,
if (error)
return error;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
ts->dac = val & 0xFF;
ad7877_write(ts->spi, AD7877_REG_DAC, (ts->dac << 4) | AD7877_DAC_CONF);
mutex_unlock(&ts->mutex);
return count;
}
@@ -539,11 +533,10 @@ static ssize_t ad7877_gpio3_store(struct device *dev,
if (error)
return error;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
ts->gpio3 = !!val;
ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA |
(ts->gpio4 << 4) | (ts->gpio3 << 5));
mutex_unlock(&ts->mutex);
return count;
}
@@ -570,11 +563,10 @@ static ssize_t ad7877_gpio4_store(struct device *dev,
if (error)
return error;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
ts->gpio4 = !!val;
ad7877_write(ts->spi, AD7877_REG_EXTWRITE, AD7877_EXTW_GPIO_DATA |
(ts->gpio4 << 4) | (ts->gpio3 << 5));
mutex_unlock(&ts->mutex);
return count;
}

View File

@@ -305,15 +305,13 @@ static int __maybe_unused ad7879_suspend(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (!ts->suspended && !ts->disabled && input_device_enabled(ts->input))
__ad7879_disable(ts);
ts->suspended = true;
mutex_unlock(&ts->input->mutex);
return 0;
}
@@ -321,15 +319,13 @@ static int __maybe_unused ad7879_resume(struct device *dev)
{
struct ad7879 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (ts->suspended && !ts->disabled && input_device_enabled(ts->input))
__ad7879_enable(ts);
ts->suspended = false;
mutex_unlock(&ts->input->mutex);
return 0;
}
@@ -338,7 +334,7 @@ EXPORT_SYMBOL(ad7879_pm_ops);
static void ad7879_toggle(struct ad7879 *ts, bool disable)
{
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (!ts->suspended && input_device_enabled(ts->input)) {
@@ -352,8 +348,6 @@ static void ad7879_toggle(struct ad7879 *ts, bool disable)
}
ts->disabled = disable;
mutex_unlock(&ts->input->mutex);
}
static ssize_t ad7879_disable_show(struct device *dev,
@@ -403,23 +397,20 @@ static int ad7879_gpio_direction_input(struct gpio_chip *chip,
unsigned gpio)
{
struct ad7879 *ts = gpiochip_get_data(chip);
int err;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIODIR | AD7879_GPIOPOL;
err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return err;
return ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
}
static int ad7879_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int level)
{
struct ad7879 *ts = gpiochip_get_data(chip);
int err;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
ts->cmd_crtl2 &= ~AD7879_GPIODIR;
ts->cmd_crtl2 |= AD7879_GPIO_EN | AD7879_GPIOPOL;
if (level)
@@ -427,21 +418,17 @@ static int ad7879_gpio_direction_output(struct gpio_chip *chip,
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
err = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return err;
return ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
}
static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned int gpio)
{
struct ad7879 *ts = gpiochip_get_data(chip);
u16 val;
mutex_lock(&ts->mutex);
val = ad7879_read(ts, AD7879_REG_CTRL2);
mutex_unlock(&ts->mutex);
guard(mutex)(&ts->mutex);
val = ad7879_read(ts, AD7879_REG_CTRL2);
return !!(val & AD7879_GPIO_DATA);
}
@@ -449,18 +436,15 @@ static int ad7879_gpio_set_value(struct gpio_chip *chip, unsigned int gpio,
int value)
{
struct ad7879 *ts = gpiochip_get_data(chip);
int ret;
mutex_lock(&ts->mutex);
guard(mutex)(&ts->mutex);
if (value)
ts->cmd_crtl2 |= AD7879_GPIO_DATA;
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
ret = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
return ret;
return ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
}
static int ad7879_gpio_add(struct ad7879 *ts)

View File

@@ -289,7 +289,7 @@ static void __ads7846_enable(struct ads7846 *ts)
static void ads7846_disable(struct ads7846 *ts)
{
mutex_lock(&ts->lock);
guard(mutex)(&ts->lock);
if (!ts->disabled) {
@@ -298,13 +298,11 @@ static void ads7846_disable(struct ads7846 *ts)
ts->disabled = true;
}
mutex_unlock(&ts->lock);
}
static void ads7846_enable(struct ads7846 *ts)
{
mutex_lock(&ts->lock);
guard(mutex)(&ts->lock);
if (ts->disabled) {
@@ -313,8 +311,6 @@ static void ads7846_enable(struct ads7846 *ts)
if (!ts->suspended)
__ads7846_enable(ts);
}
mutex_unlock(&ts->lock);
}
/*--------------------------------------------------------------------------*/
@@ -354,10 +350,9 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
{
struct spi_device *spi = to_spi_device(dev);
struct ads7846 *ts = dev_get_drvdata(dev);
struct ser_req *req;
int status;
req = kzalloc_obj(*req);
struct ser_req *req __free(kfree) = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -418,11 +413,11 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
CS_CHANGE(req->xfer[7]);
spi_message_add_tail(&req->xfer[7], &req->msg);
mutex_lock(&ts->lock);
ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
ads7846_restart(ts);
mutex_unlock(&ts->lock);
scoped_guard(mutex, &ts->lock) {
ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
ads7846_restart(ts);
}
if (status == 0) {
/* on-wire is a must-ignore bit, a BE12 value, then padding */
@@ -431,7 +426,6 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
status &= 0x0fff;
}
kfree(req);
return status;
}
@@ -439,10 +433,9 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
{
struct spi_device *spi = to_spi_device(dev);
struct ads7846 *ts = dev_get_drvdata(dev);
struct ads7845_ser_req *req;
int status;
req = kzalloc_obj(*req);
struct ads7845_ser_req *req __free(kfree) = kzalloc_obj(*req);
if (!req)
return -ENOMEM;
@@ -454,11 +447,11 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
req->xfer[0].len = 3;
spi_message_add_tail(&req->xfer[0], &req->msg);
mutex_lock(&ts->lock);
ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
ads7846_restart(ts);
mutex_unlock(&ts->lock);
scoped_guard(mutex, &ts->lock) {
ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
ads7846_restart(ts);
}
if (status == 0) {
/* BE12 value, then padding */
@@ -467,7 +460,6 @@ static int ads7845_read12_ser(struct device *dev, unsigned command)
status &= 0x0fff;
}
kfree(req);
return status;
}
@@ -966,7 +958,7 @@ static int ads7846_suspend(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->lock);
guard(mutex)(&ts->lock);
if (!ts->suspended) {
@@ -979,8 +971,6 @@ static int ads7846_suspend(struct device *dev)
ts->suspended = true;
}
mutex_unlock(&ts->lock);
return 0;
}
@@ -988,7 +978,7 @@ static int ads7846_resume(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
mutex_lock(&ts->lock);
guard(mutex)(&ts->lock);
if (ts->suspended) {
@@ -1001,8 +991,6 @@ static int ads7846_resume(struct device *dev)
__ads7846_enable(ts);
}
mutex_unlock(&ts->lock);
return 0;
}

View File

@@ -713,12 +713,11 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
const void *val)
{
bool retried = false;
u8 *buf;
size_t count;
size_t count = len + 2;
int error;
int ret;
count = len + 2;
buf = kmalloc(count, GFP_KERNEL);
u8 *buf __free(kfree) = kmalloc(count, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -728,20 +727,17 @@ static int __mxt_write_reg(struct i2c_client *client, u16 reg, u16 len,
retry:
ret = i2c_master_send(client, buf, count);
if (ret == count) {
ret = 0;
} else if (!retried && mxt_wakeup_toggle(client, true, true)) {
if (ret == count)
return 0;
if (!retried && mxt_wakeup_toggle(client, true, true)) {
retried = true;
goto retry;
} else {
if (ret >= 0)
ret = -EIO;
dev_err(&client->dev, "%s: i2c send failed (%d)\n",
__func__, ret);
}
kfree(buf);
return ret;
error = ret < 0 ? ret : -EIO;
dev_err(&client->dev, "%s: i2c send failed (%d)\n", __func__, error);
return error;
}
static int mxt_write_reg(struct i2c_client *client, u16 reg, u8 val)
@@ -1547,14 +1543,15 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
{
struct device *dev = &data->client->dev;
struct mxt_cfg cfg;
int ret;
int error;
int offset;
int i;
u32 info_crc, config_crc, calculated_crc;
u16 crc_start = 0;
/* Make zero terminated copy of the OBP_RAW file */
cfg.raw = kmemdup_nul(fw->data, fw->size, GFP_KERNEL);
u8 *raw_buf __free(kfree) = cfg.raw = kmemdup_nul(fw->data, fw->size,
GFP_KERNEL);
if (!cfg.raw)
return -ENOMEM;
@@ -1564,21 +1561,17 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
if (strncmp(cfg.raw, MXT_CFG_MAGIC, strlen(MXT_CFG_MAGIC))) {
dev_err(dev, "Unrecognised config file\n");
ret = -EINVAL;
goto release_raw;
return -EINVAL;
}
cfg.raw_pos = strlen(MXT_CFG_MAGIC);
/* Load information block and check */
for (i = 0; i < sizeof(struct mxt_info); i++) {
ret = sscanf(cfg.raw + cfg.raw_pos, "%hhx%n",
(unsigned char *)&cfg.info + i,
&offset);
if (ret != 1) {
if (sscanf(cfg.raw + cfg.raw_pos, "%hhx%n",
(unsigned char *)&cfg.info + i, &offset) != 1) {
dev_err(dev, "Bad format\n");
ret = -EINVAL;
goto release_raw;
return -EINVAL;
}
cfg.raw_pos += offset;
@@ -1586,30 +1579,24 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
if (cfg.info.family_id != data->info->family_id) {
dev_err(dev, "Family ID mismatch!\n");
ret = -EINVAL;
goto release_raw;
return -EINVAL;
}
if (cfg.info.variant_id != data->info->variant_id) {
dev_err(dev, "Variant ID mismatch!\n");
ret = -EINVAL;
goto release_raw;
return -EINVAL;
}
/* Read CRCs */
ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset);
if (ret != 1) {
if (sscanf(cfg.raw + cfg.raw_pos, "%x%n", &info_crc, &offset) != 1) {
dev_err(dev, "Bad format: failed to parse Info CRC\n");
ret = -EINVAL;
goto release_raw;
return -EINVAL;
}
cfg.raw_pos += offset;
ret = sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset);
if (ret != 1) {
if (sscanf(cfg.raw + cfg.raw_pos, "%x%n", &config_crc, &offset) != 1) {
dev_err(dev, "Bad format: failed to parse Config CRC\n");
ret = -EINVAL;
goto release_raw;
return -EINVAL;
}
cfg.raw_pos += offset;
@@ -1625,8 +1612,7 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
} else if (config_crc == data->config_crc) {
dev_dbg(dev, "Config CRC 0x%06X: OK\n",
data->config_crc);
ret = 0;
goto release_raw;
return 0;
} else {
dev_info(dev, "Config CRC 0x%06X: does not match file 0x%06X\n",
data->config_crc, config_crc);
@@ -1642,15 +1628,14 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
data->info->object_num * sizeof(struct mxt_object) +
MXT_INFO_CHECKSUM_SIZE;
cfg.mem_size = data->mem_size - cfg.start_ofs;
cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL);
if (!cfg.mem) {
ret = -ENOMEM;
goto release_raw;
}
ret = mxt_prepare_cfg_mem(data, &cfg);
if (ret)
goto release_mem;
u8 *mem_buf __free(kfree) = cfg.mem = kzalloc(cfg.mem_size, GFP_KERNEL);
if (!cfg.mem)
return -ENOMEM;
error = mxt_prepare_cfg_mem(data, &cfg);
if (error)
return error;
/* Calculate crc of the received configs (not the raw config file) */
if (data->T71_address)
@@ -1670,30 +1655,26 @@ static int mxt_update_cfg(struct mxt_data *data, const struct firmware *fw)
calculated_crc, config_crc);
}
ret = mxt_upload_cfg_mem(data, &cfg);
if (ret)
goto release_mem;
error = mxt_upload_cfg_mem(data, &cfg);
if (error)
return error;
mxt_update_crc(data, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE);
ret = mxt_check_retrigen(data);
if (ret)
goto release_mem;
error = mxt_check_retrigen(data);
if (error)
return error;
ret = mxt_soft_reset(data);
if (ret)
goto release_mem;
error = mxt_soft_reset(data);
if (error)
return error;
dev_info(dev, "Config successfully updated\n");
/* T7 config may have changed */
mxt_init_t7_power_cfg(data);
release_mem:
kfree(cfg.mem);
release_raw:
kfree(cfg.raw);
return ret;
return 0;
}
static void mxt_free_input_device(struct mxt_data *data)
@@ -1857,7 +1838,6 @@ static int mxt_read_info_block(struct mxt_data *data)
struct i2c_client *client = data->client;
int error;
size_t size;
void *id_buf, *buf;
uint8_t num_objects;
u32 calculated_crc;
u8 *crc_ptr;
@@ -1868,24 +1848,23 @@ static int mxt_read_info_block(struct mxt_data *data)
/* Read 7-byte ID information block starting at address 0 */
size = sizeof(struct mxt_info);
id_buf = kzalloc(size, GFP_KERNEL);
void *id_buf __free(kfree) = kzalloc(size, GFP_KERNEL);
if (!id_buf)
return -ENOMEM;
error = __mxt_read_reg(client, 0, size, id_buf);
if (error)
goto err_free_mem;
return error;
/* Resize buffer to give space for rest of info block */
num_objects = ((struct mxt_info *)id_buf)->object_num;
size += (num_objects * sizeof(struct mxt_object))
+ MXT_INFO_CHECKSUM_SIZE;
buf = krealloc(id_buf, size, GFP_KERNEL);
if (!buf) {
error = -ENOMEM;
goto err_free_mem;
}
void *buf = krealloc(id_buf, size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
id_buf = buf;
/* Read rest of info block */
@@ -1893,7 +1872,7 @@ static int mxt_read_info_block(struct mxt_data *data)
size - MXT_OBJECT_START,
id_buf + MXT_OBJECT_START);
if (error)
goto err_free_mem;
return error;
/* Extract & calculate checksum */
crc_ptr = id_buf + size - MXT_INFO_CHECKSUM_SIZE;
@@ -1910,12 +1889,11 @@ static int mxt_read_info_block(struct mxt_data *data)
dev_err(&client->dev,
"Info Block CRC error calculated=0x%06X read=0x%06X\n",
calculated_crc, data->info_crc);
error = -EIO;
goto err_free_mem;
return -EIO;
}
data->raw_info_block = id_buf;
data->info = (struct mxt_info *)id_buf;
data->raw_info_block = no_free_ptr(id_buf);
data->info = (struct mxt_info *)data->raw_info_block;
dev_info(&client->dev,
"Family: %u Variant: %u Firmware V%u.%u.%02X Objects: %u\n",
@@ -1924,20 +1902,18 @@ static int mxt_read_info_block(struct mxt_data *data)
data->info->build, data->info->object_num);
/* Parse object table information */
error = mxt_parse_object_table(data, id_buf + MXT_OBJECT_START);
error = mxt_parse_object_table(data,
data->raw_info_block + MXT_OBJECT_START);
if (error) {
dev_err(&client->dev, "Error %d parsing object table\n", error);
mxt_free_object_table(data);
return error;
}
data->object_table = (struct mxt_object *)(id_buf + MXT_OBJECT_START);
data->object_table =
(struct mxt_object *)(data->raw_info_block + MXT_OBJECT_START);
return 0;
err_free_mem:
kfree(id_buf);
return error;
}
static int mxt_read_t9_resolution(struct mxt_data *data)
@@ -2914,70 +2890,38 @@ static int mxt_check_firmware_format(struct device *dev,
return -EINVAL;
}
static int mxt_load_fw(struct device *dev, const char *fn)
static int mxt_flash_fw(struct mxt_data *data, const struct firmware *fw)
{
struct mxt_data *data = dev_get_drvdata(dev);
const struct firmware *fw = NULL;
struct device *dev = &data->client->dev;
unsigned int frame_size;
unsigned int pos = 0;
unsigned int retry = 0;
unsigned int frame = 0;
int ret;
ret = request_firmware(&fw, fn, dev);
if (ret) {
dev_err(dev, "Unable to open firmware %s\n", fn);
return ret;
}
/* Check for incorrect enc file */
ret = mxt_check_firmware_format(dev, fw);
if (ret)
goto release_firmware;
if (!data->in_bootloader) {
/* Change to the bootloader mode */
data->in_bootloader = true;
ret = mxt_t6_command(data, MXT_COMMAND_RESET,
MXT_BOOT_VALUE, false);
if (ret)
goto release_firmware;
msleep(MXT_RESET_TIME);
/* Do not need to scan since we know family ID */
ret = mxt_lookup_bootloader_address(data, 0);
if (ret)
goto release_firmware;
mxt_free_input_device(data);
mxt_free_object_table(data);
} else {
enable_irq(data->irq);
}
int error;
reinit_completion(&data->bl_completion);
ret = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
if (ret) {
error = mxt_check_bootloader(data, MXT_WAITING_BOOTLOAD_CMD, false);
if (error) {
/* Bootloader may still be unlocked from previous attempt */
ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, false);
if (ret)
goto disable_irq;
error = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA,
false);
if (error)
return error;
} else {
dev_info(dev, "Unlocking bootloader\n");
/* Unlock bootloader */
ret = mxt_send_bootloader_cmd(data, true);
if (ret)
goto disable_irq;
error = mxt_send_bootloader_cmd(data, true);
if (error)
return error;
}
while (pos < fw->size) {
ret = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA, true);
if (ret)
goto disable_irq;
error = mxt_check_bootloader(data, MXT_WAITING_FRAME_DATA,
true);
if (error)
return error;
frame_size = ((*(fw->data + pos) << 8) | *(fw->data + pos + 1));
@@ -2985,12 +2929,12 @@ static int mxt_load_fw(struct device *dev, const char *fn)
frame_size += 2;
/* Write one frame to device */
ret = mxt_bootloader_write(data, fw->data + pos, frame_size);
if (ret)
goto disable_irq;
error = mxt_bootloader_write(data, fw->data + pos, frame_size);
if (error)
return error;
ret = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
if (ret) {
error = mxt_check_bootloader(data, MXT_FRAME_CRC_PASS, true);
if (error) {
retry++;
/* Back off by 20ms per retry */
@@ -2998,7 +2942,7 @@ static int mxt_load_fw(struct device *dev, const char *fn)
if (retry > 20) {
dev_err(dev, "Retry count exceeded\n");
goto disable_irq;
return error;
}
} else {
retry = 0;
@@ -3012,10 +2956,10 @@ static int mxt_load_fw(struct device *dev, const char *fn)
}
/* Wait for flash. */
ret = mxt_wait_for_completion(data, &data->bl_completion,
MXT_FW_RESET_TIME);
if (ret)
goto disable_irq;
error = mxt_wait_for_completion(data, &data->bl_completion,
MXT_FW_RESET_TIME);
if (error)
return error;
dev_dbg(dev, "Sent %d frames, %d bytes\n", frame, pos);
@@ -3025,14 +2969,56 @@ static int mxt_load_fw(struct device *dev, const char *fn)
* errors.
*/
mxt_wait_for_completion(data, &data->bl_completion, MXT_FW_RESET_TIME);
data->in_bootloader = false;
disable_irq:
return 0;
}
static int mxt_load_fw(struct device *dev, const char *fn)
{
struct mxt_data *data = dev_get_drvdata(dev);
int retval;
int error;
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fn, dev);
if (error) {
dev_err(dev, "Unable to open firmware %s\n", fn);
return error;
}
/* Check for incorrect enc file */
error = mxt_check_firmware_format(dev, fw);
if (error)
return error;
if (!data->in_bootloader) {
/* Change to the bootloader mode */
data->in_bootloader = true;
error = mxt_t6_command(data, MXT_COMMAND_RESET,
MXT_BOOT_VALUE, false);
if (error)
return error;
msleep(MXT_RESET_TIME);
/* Do not need to scan since we know family ID */
error = mxt_lookup_bootloader_address(data, 0);
if (error)
return error;
mxt_free_input_device(data);
mxt_free_object_table(data);
} else {
enable_irq(data->irq);
}
retval = mxt_flash_fw(data, fw);
disable_irq(data->irq);
release_firmware:
release_firmware(fw);
return ret;
return retval;
}
static ssize_t mxt_update_fw_store(struct device *dev,
@@ -3375,12 +3361,10 @@ static int mxt_suspend(struct device *dev)
if (!input_dev)
return 0;
mutex_lock(&input_dev->mutex);
if (input_device_enabled(input_dev))
mxt_stop(data);
mutex_unlock(&input_dev->mutex);
scoped_guard(mutex, &input_dev->mutex) {
if (input_device_enabled(input_dev))
mxt_stop(data);
}
disable_irq(data->irq);
@@ -3398,12 +3382,10 @@ static int mxt_resume(struct device *dev)
enable_irq(data->irq);
mutex_lock(&input_dev->mutex);
if (input_device_enabled(input_dev))
mxt_start(data);
mutex_unlock(&input_dev->mutex);
scoped_guard(mutex, &input_dev->mutex) {
if (input_device_enabled(input_dev))
mxt_start(data);
}
return 0;
}

View File

@@ -415,9 +415,9 @@ static int auo_pixcir_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
int error;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
/* when configured as wakeup source, device should always wake system
* therefore start device if necessary
@@ -425,21 +425,23 @@ static int auo_pixcir_suspend(struct device *dev)
if (device_may_wakeup(&client->dev)) {
/* need to start device if not open, to be wakeup source */
if (!input_device_enabled(input)) {
ret = auo_pixcir_start(ts);
if (ret)
goto unlock;
error = auo_pixcir_start(ts);
if (error)
return error;
}
enable_irq_wake(client->irq);
ret = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
error = auo_pixcir_power_mode(ts, AUO_PIXCIR_POWER_SLEEP);
if (error)
return error;
} else if (input_device_enabled(input)) {
ret = auo_pixcir_stop(ts);
error = auo_pixcir_stop(ts);
if (error)
return error;
}
unlock:
mutex_unlock(&input->mutex);
return ret;
return 0;
}
static int auo_pixcir_resume(struct device *dev)
@@ -447,29 +449,28 @@ static int auo_pixcir_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct auo_pixcir_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
int error;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (device_may_wakeup(&client->dev)) {
disable_irq_wake(client->irq);
/* need to stop device if it was not open on suspend */
if (!input_device_enabled(input)) {
ret = auo_pixcir_stop(ts);
if (ret)
goto unlock;
error = auo_pixcir_stop(ts);
if (error)
return error;
}
/* device wakes automatically from SLEEP */
} else if (input_device_enabled(input)) {
ret = auo_pixcir_start(ts);
error = auo_pixcir_start(ts);
if (error)
return error;
}
unlock:
mutex_unlock(&input->mutex);
return ret;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(auo_pixcir_pm_ops,

View File

@@ -416,10 +416,10 @@ static int bu21029_suspend(struct device *dev)
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
if (!device_may_wakeup(dev)) {
mutex_lock(&bu21029->in_dev->mutex);
guard(mutex)(&bu21029->in_dev->mutex);
if (input_device_enabled(bu21029->in_dev))
bu21029_stop_chip(bu21029->in_dev);
mutex_unlock(&bu21029->in_dev->mutex);
}
return 0;
@@ -431,10 +431,10 @@ static int bu21029_resume(struct device *dev)
struct bu21029_ts_data *bu21029 = i2c_get_clientdata(i2c);
if (!device_may_wakeup(dev)) {
mutex_lock(&bu21029->in_dev->mutex);
guard(mutex)(&bu21029->in_dev->mutex);
if (input_device_enabled(bu21029->in_dev))
bu21029_start_chip(bu21029->in_dev);
mutex_unlock(&bu21029->in_dev->mutex);
}
return 0;

View File

@@ -152,10 +152,10 @@ static int icn8318_suspend(struct device *dev)
{
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
guard(mutex)(&data->input->mutex);
if (input_device_enabled(data->input))
icn8318_stop(data->input);
mutex_unlock(&data->input->mutex);
return 0;
}
@@ -164,10 +164,10 @@ static int icn8318_resume(struct device *dev)
{
struct icn8318_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
guard(mutex)(&data->input->mutex);
if (input_device_enabled(data->input))
icn8318_start(data->input);
mutex_unlock(&data->input->mutex);
return 0;
}

View File

@@ -494,34 +494,30 @@ static int cyttsp_disable(struct cyttsp *ts)
static int cyttsp_suspend(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
int retval = 0;
int error;
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (input_device_enabled(ts->input)) {
retval = cyttsp_disable(ts);
if (retval == 0)
ts->suspended = true;
error = cyttsp_disable(ts);
if (error)
return error;
}
mutex_unlock(&ts->input->mutex);
return retval;
ts->suspended = true;
return 0;
}
static int cyttsp_resume(struct device *dev)
{
struct cyttsp *ts = dev_get_drvdata(dev);
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (input_device_enabled(ts->input))
cyttsp_enable(ts);
ts->suspended = false;
mutex_unlock(&ts->input->mutex);
return 0;
}

View File

@@ -380,16 +380,13 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
container_of(dattr, struct edt_ft5x06_attribute, dattr);
u8 *field = (u8 *)tsdata + attr->field_offset;
unsigned int val;
size_t count = 0;
int error = 0;
int error;
u8 addr;
mutex_lock(&tsdata->mutex);
guard(mutex)(&tsdata->mutex);
if (tsdata->factory_mode) {
error = -EIO;
goto out;
}
if (tsdata->factory_mode)
return -EIO;
switch (tsdata->version) {
case EDT_M06:
@@ -407,8 +404,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
break;
default:
error = -ENODEV;
goto out;
return -ENODEV;
}
if (addr != NO_REGISTER) {
@@ -417,7 +413,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
dev_err(&tsdata->client->dev,
"Failed to fetch attribute %s, error %d\n",
dattr->attr.name, error);
goto out;
return error;
}
} else {
val = *field;
@@ -430,10 +426,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev,
*field = val;
}
count = sysfs_emit(buf, "%d\n", val);
out:
mutex_unlock(&tsdata->mutex);
return error ?: count;
return sysfs_emit(buf, "%d\n", val);
}
static ssize_t edt_ft5x06_setting_store(struct device *dev,
@@ -449,21 +442,17 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
int error;
u8 addr;
mutex_lock(&tsdata->mutex);
guard(mutex)(&tsdata->mutex);
if (tsdata->factory_mode) {
error = -EIO;
goto out;
}
if (tsdata->factory_mode)
return -EIO;
error = kstrtouint(buf, 0, &val);
if (error)
goto out;
return error;
if (val < attr->limit_low || val > attr->limit_high) {
error = -ERANGE;
goto out;
}
if (val < attr->limit_low || val > attr->limit_high)
return -ERANGE;
switch (tsdata->version) {
case EDT_M06:
@@ -481,8 +470,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
break;
default:
error = -ENODEV;
goto out;
return -ENODEV;
}
if (addr != NO_REGISTER) {
@@ -491,14 +479,12 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev,
dev_err(&tsdata->client->dev,
"Failed to update attribute %s, error: %d\n",
dattr->attr.name, error);
goto out;
return error;
}
}
*field = val;
out:
mutex_unlock(&tsdata->mutex);
return error ?: count;
return count;
}
/* m06, m09: range 0-31, m12: range 0-5 */
@@ -714,21 +700,17 @@ static int edt_ft5x06_debugfs_mode_get(void *data, u64 *mode)
static int edt_ft5x06_debugfs_mode_set(void *data, u64 mode)
{
struct edt_ft5x06_ts_data *tsdata = data;
int retval = 0;
if (mode > 1)
return -ERANGE;
mutex_lock(&tsdata->mutex);
guard(mutex)(&tsdata->mutex);
if (mode != tsdata->factory_mode) {
retval = mode ? edt_ft5x06_factory_mode(tsdata) :
edt_ft5x06_work_mode(tsdata);
}
if (mode == tsdata->factory_mode)
return 0;
mutex_unlock(&tsdata->mutex);
return retval;
return mode ? edt_ft5x06_factory_mode(tsdata) :
edt_ft5x06_work_mode(tsdata);
};
DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get,
@@ -750,18 +732,16 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
if (*off < 0 || *off >= tsdata->raw_bufsize)
return 0;
mutex_lock(&tsdata->mutex);
guard(mutex)(&tsdata->mutex);
if (!tsdata->factory_mode || !tsdata->raw_buffer) {
error = -EIO;
goto out;
}
if (!tsdata->factory_mode || !tsdata->raw_buffer)
return -EIO;
error = regmap_write(tsdata->regmap, 0x08, 0x01);
if (error) {
dev_err(&client->dev,
"failed to write 0x08 register, error %d\n", error);
goto out;
return error;
}
do {
@@ -771,7 +751,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
dev_err(&client->dev,
"failed to read 0x08 register, error %d\n",
error);
goto out;
return error;
}
if (val == 1)
@@ -781,8 +761,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
if (retries == 0) {
dev_err(&client->dev,
"timed out waiting for register to settle\n");
error = -ETIMEDOUT;
goto out;
return -ETIMEDOUT;
}
rdbuf = tsdata->raw_buffer;
@@ -792,21 +771,17 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file,
rdbuf[0] = i; /* column index */
error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes);
if (error)
goto out;
return error;
rdbuf += colbytes;
}
read = min_t(size_t, count, tsdata->raw_bufsize - *off);
if (copy_to_user(buf, tsdata->raw_buffer + *off, read)) {
error = -EFAULT;
goto out;
}
if (copy_to_user(buf, tsdata->raw_buffer + *off, read))
return -EFAULT;
*off += read;
out:
mutex_unlock(&tsdata->mutex);
return error ?: read;
return read;
};
static const struct file_operations debugfs_raw_data_fops = {
@@ -829,7 +804,10 @@ static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
guard(mutex)(&tsdata->mutex);
kfree(tsdata->raw_buffer);
tsdata->raw_buffer = NULL;
}
#else

View File

@@ -89,7 +89,7 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
struct eeti_ts *eeti = dev_id;
int error;
mutex_lock(&eeti->mutex);
guard(mutex)(&eeti->mutex);
do {
/*
@@ -109,13 +109,12 @@ static irqreturn_t eeti_ts_isr(int irq, void *dev_id)
} while (eeti->running && eeti->attn_gpio);
mutex_unlock(&eeti->mutex);
return IRQ_HANDLED;
}
static void eeti_ts_start(struct eeti_ts *eeti)
{
mutex_lock(&eeti->mutex);
guard(mutex)(&eeti->mutex);
eeti->running = true;
enable_irq(eeti->client->irq);
@@ -127,8 +126,6 @@ static void eeti_ts_start(struct eeti_ts *eeti)
*/
if (eeti->attn_gpio && gpiod_get_value_cansleep(eeti->attn_gpio))
eeti_ts_read(eeti);
mutex_unlock(&eeti->mutex);
}
static void eeti_ts_stop(struct eeti_ts *eeti)
@@ -238,12 +235,10 @@ static int eeti_ts_suspend(struct device *dev)
struct eeti_ts *eeti = i2c_get_clientdata(client);
struct input_dev *input_dev = eeti->input;
mutex_lock(&input_dev->mutex);
if (input_device_enabled(input_dev))
eeti_ts_stop(eeti);
mutex_unlock(&input_dev->mutex);
scoped_guard(mutex, &input_dev->mutex) {
if (input_device_enabled(input_dev))
eeti_ts_stop(eeti);
}
if (device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
@@ -260,12 +255,10 @@ static int eeti_ts_resume(struct device *dev)
if (device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
mutex_lock(&input_dev->mutex);
if (input_device_enabled(input_dev))
eeti_ts_start(eeti);
mutex_unlock(&input_dev->mutex);
scoped_guard(mutex, &input_dev->mutex) {
if (input_device_enabled(input_dev))
eeti_ts_start(eeti);
}
return 0;
}

View File

@@ -187,10 +187,10 @@ static int ektf2127_suspend(struct device *dev)
{
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (input_device_enabled(ts->input))
ektf2127_stop(ts->input);
mutex_unlock(&ts->input->mutex);
return 0;
}
@@ -199,10 +199,10 @@ static int ektf2127_resume(struct device *dev)
{
struct ektf2127_ts *ts = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
if (input_device_enabled(ts->input))
ektf2127_start(ts->input);
mutex_unlock(&ts->input->mutex);
return 0;
}

View File

@@ -303,15 +303,13 @@ static int elants_i2c_calibrate(struct elants_data *ts)
static const u8 rek[] = { CMD_HEADER_WRITE, 0x29, 0x00, 0x01 };
static const u8 rek_resp[] = { CMD_HEADER_REK, 0x66, 0x66, 0x66 };
disable_irq(client->irq);
scoped_guard(disable_irq, &client->irq) {
ts->state = ELAN_WAIT_RECALIBRATION;
reinit_completion(&ts->cmd_done);
ts->state = ELAN_WAIT_RECALIBRATION;
reinit_completion(&ts->cmd_done);
elants_i2c_send(client, w_flashkey, sizeof(w_flashkey));
elants_i2c_send(client, rek, sizeof(rek));
enable_irq(client->irq);
elants_i2c_send(client, w_flashkey, sizeof(w_flashkey));
elants_i2c_send(client, rek, sizeof(rek));
}
ret = wait_for_completion_interruptible_timeout(&ts->cmd_done,
msecs_to_jiffies(ELAN_CALI_TIMEOUT_MSEC));
@@ -906,17 +904,17 @@ static int elants_i2c_do_update_firmware(struct i2c_client *client,
static int elants_i2c_fw_update(struct elants_data *ts)
{
struct i2c_client *client = ts->client;
const struct firmware *fw;
char *fw_name;
int error;
fw_name = kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version);
const char *fw_name __free(kfree) =
kasprintf(GFP_KERNEL, "elants_i2c_%04x.bin", ts->hw_version);
if (!fw_name)
return -ENOMEM;
dev_info(&client->dev, "requesting fw name = %s\n", fw_name);
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fw_name, &client->dev);
kfree(fw_name);
if (error) {
dev_err(&client->dev, "failed to request firmware: %d\n",
error);
@@ -926,40 +924,32 @@ static int elants_i2c_fw_update(struct elants_data *ts)
if (fw->size % ELAN_FW_PAGESIZE) {
dev_err(&client->dev, "invalid firmware length: %zu\n",
fw->size);
error = -EINVAL;
goto out;
return -EINVAL;
}
disable_irq(client->irq);
scoped_guard(disable_irq, &client->irq) {
bool force_update = ts->iap_mode == ELAN_IAP_RECOVERY;
error = elants_i2c_do_update_firmware(client, fw,
ts->iap_mode == ELAN_IAP_RECOVERY);
if (error) {
dev_err(&client->dev, "firmware update failed: %d\n", error);
ts->iap_mode = ELAN_IAP_RECOVERY;
goto out_enable_irq;
error = elants_i2c_do_update_firmware(client, fw, force_update);
if (error) {
dev_err(&client->dev, "firmware update failed: %d\n",
error);
} else {
error = elants_i2c_initialize(ts);
if (error)
dev_err(&client->dev,
"failed to initialize device after firmware update: %d\n",
error);
}
ts->iap_mode = error ? ELAN_IAP_RECOVERY : ELAN_IAP_OPERATIONAL;
ts->state = ELAN_STATE_NORMAL;
}
error = elants_i2c_initialize(ts);
if (error) {
dev_err(&client->dev,
"failed to initialize device after firmware update: %d\n",
error);
ts->iap_mode = ELAN_IAP_RECOVERY;
goto out_enable_irq;
}
ts->iap_mode = ELAN_IAP_OPERATIONAL;
out_enable_irq:
ts->state = ELAN_STATE_NORMAL;
enable_irq(client->irq);
msleep(100);
if (!error)
elants_i2c_calibrate(ts);
out:
release_firmware(fw);
return error;
}
@@ -1186,14 +1176,13 @@ static ssize_t calibrate_store(struct device *dev,
struct elants_data *ts = i2c_get_clientdata(client);
int error;
error = mutex_lock_interruptible(&ts->sysfs_mutex);
if (error)
return error;
scoped_cond_guard(mutex_intr, return -EINTR, &ts->sysfs_mutex) {
error = elants_i2c_calibrate(ts);
if (error)
return error;
}
error = elants_i2c_calibrate(ts);
mutex_unlock(&ts->sysfs_mutex);
return error ?: count;
return count;
}
static ssize_t write_update_fw(struct device *dev,
@@ -1204,15 +1193,13 @@ static ssize_t write_update_fw(struct device *dev,
struct elants_data *ts = i2c_get_clientdata(client);
int error;
error = mutex_lock_interruptible(&ts->sysfs_mutex);
if (error)
return error;
scoped_cond_guard(mutex_intr, return -EINTR, &ts->sysfs_mutex) {
error = elants_i2c_fw_update(ts);
if (error)
return error;
}
error = elants_i2c_fw_update(ts);
dev_dbg(dev, "firmware update result: %d\n", error);
mutex_unlock(&ts->sysfs_mutex);
return error ?: count;
return count;
}
static ssize_t show_iap_mode(struct device *dev,

View File

@@ -219,40 +219,40 @@ static irqreturn_t elo_interrupt(struct serio *serio,
static int elo_command_10(struct elo *elo, unsigned char *packet)
{
int rc = -1;
int error;
int i;
unsigned char csum = 0xaa + ELO10_LEAD_BYTE;
mutex_lock(&elo->cmd_mutex);
guard(mutex)(&elo->cmd_mutex);
scoped_guard(serio_pause_rx, elo->serio) {
elo->expected_packet = toupper(packet[0]);
init_completion(&elo->cmd_done);
}
if (serio_write(elo->serio, ELO10_LEAD_BYTE))
goto out;
error = serio_write(elo->serio, ELO10_LEAD_BYTE);
if (error)
return error;
for (i = 0; i < ELO10_PACKET_LEN; i++) {
csum += packet[i];
if (serio_write(elo->serio, packet[i]))
goto out;
error = serio_write(elo->serio, packet[i]);
if (error)
return error;
}
if (serio_write(elo->serio, csum))
goto out;
error = serio_write(elo->serio, csum);
if (error)
return error;
wait_for_completion_timeout(&elo->cmd_done, HZ);
if (elo->expected_packet == ELO10_TOUCH_PACKET) {
/* We are back in reporting mode, the command was ACKed */
memcpy(packet, elo->response, ELO10_PACKET_LEN);
rc = 0;
}
if (elo->expected_packet != ELO10_TOUCH_PACKET)
return -EIO;
out:
mutex_unlock(&elo->cmd_mutex);
return rc;
/* We are back in reporting mode, the command was ACKed */
memcpy(packet, elo->response, ELO10_PACKET_LEN);
return 0;
}
static int elo_setup_10(struct elo *elo)

View File

@@ -234,7 +234,7 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request,
int ret;
unsigned long time_left;
mutex_lock(&data->query_lock);
guard(mutex)(&data->query_lock);
reinit_completion(&data->wait_event);
@@ -243,29 +243,18 @@ static int exc3000_vendor_data_request(struct exc3000_data *data, u8 *request,
ret = i2c_master_send(data->client, buf, EXC3000_LEN_VENDOR_REQUEST);
if (ret < 0)
goto out_unlock;
return ret;
if (response) {
time_left = wait_for_completion_timeout(&data->wait_event,
timeout * HZ);
if (time_left == 0) {
ret = -ETIMEDOUT;
goto out_unlock;
}
time_left = wait_for_completion_timeout(&data->wait_event,
timeout * HZ);
if (time_left == 0)
return -ETIMEDOUT;
if (data->buf[3] >= EXC3000_LEN_FRAME) {
ret = -ENOSPC;
goto out_unlock;
}
if (data->buf[3] >= EXC3000_LEN_FRAME)
return -ENOSPC;
memcpy(response, &data->buf[4], data->buf[3]);
ret = data->buf[3];
}
out_unlock:
mutex_unlock(&data->query_lock);
return ret;
memcpy(response, &data->buf[4], data->buf[3]);
return data->buf[3];
}
static ssize_t fw_version_show(struct device *dev,

View File

@@ -628,6 +628,14 @@ static int goodix_berlin_input_dev_config(struct goodix_berlin_core *cd,
touchscreen_parse_properties(cd->input_dev, true, &cd->props);
/*
* The resolution of these touchscreens is about 10 units/mm, the actual
* resolution does not matter much since we set INPUT_PROP_DIRECT.
* Set it to 10 to ensure userspace isn't off by an order of magnitude.
*/
input_abs_set_res(cd->input_dev, ABS_MT_POSITION_X, 10);
input_abs_set_res(cd->input_dev, ABS_MT_POSITION_Y, 10);
error = input_mt_init_slots(cd->input_dev, GOODIX_BERLIN_MAX_TOUCH,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error)

View File

@@ -188,13 +188,13 @@ static int goodix_start_firmware(struct i2c_client *client)
static int goodix_firmware_upload(struct goodix_ts_data *ts)
{
const struct firmware *fw;
char fw_name[64];
const u8 *data;
int error;
snprintf(fw_name, sizeof(fw_name), "goodix/%s", ts->firmware_name);
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fw_name, &ts->client->dev);
if (error) {
dev_err(&ts->client->dev, "Firmware request error %d\n", error);
@@ -203,60 +203,61 @@ static int goodix_firmware_upload(struct goodix_ts_data *ts)
error = goodix_firmware_verify(&ts->client->dev, fw);
if (error)
goto release;
return error;
error = goodix_reset_no_int_sync(ts);
if (error)
goto release;
return error;
error = goodix_enter_upload_mode(ts->client);
if (error)
goto release;
return error;
/* Select SRAM bank 0 and upload section 1 & 2 */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x00);
if (error)
goto release;
return error;
data = fw->data + GOODIX_FW_HEADER_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, 2 * GOODIX_FW_SECTION_LENGTH);
if (error)
goto release;
return error;
/* Select SRAM bank 1 and upload section 3 & 4 */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x01);
if (error)
goto release;
return error;
data += 2 * GOODIX_FW_SECTION_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, 2 * GOODIX_FW_SECTION_LENGTH);
if (error)
goto release;
return error;
/* Select SRAM bank 2 and upload the DSP firmware */
error = goodix_i2c_write_u8(ts->client,
GOODIX_REG_MISCTL_SRAM_BANK, 0x02);
if (error)
goto release;
return error;
data += 2 * GOODIX_FW_SECTION_LENGTH;
error = goodix_i2c_write(ts->client, GOODIX_FW_UPLOAD_ADDRESS,
data, GOODIX_FW_DSP_LENGTH);
if (error)
goto release;
return error;
error = goodix_start_firmware(ts->client);
if (error)
goto release;
return error;
error = goodix_int_sync(ts);
release:
release_firmware(fw);
return error;
if (error)
return error;
return 0;
}
static int goodix_prepare_bak_ref(struct goodix_ts_data *ts)

View File

@@ -869,8 +869,6 @@ static ssize_t hideep_update_fw(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
const struct firmware *fw_entry;
char *fw_name;
int mode;
int error;
@@ -878,46 +876,42 @@ static ssize_t hideep_update_fw(struct device *dev,
if (error)
return error;
fw_name = kasprintf(GFP_KERNEL, "hideep_ts_%04x.bin",
be16_to_cpu(ts->dwz_info.product_id));
const char *fw_name __free(kfree) =
kasprintf(GFP_KERNEL, "hideep_ts_%04x.bin",
be16_to_cpu(ts->dwz_info.product_id));
if (!fw_name)
return -ENOMEM;
const struct firmware *fw_entry __free(firmware) = NULL;
error = request_firmware(&fw_entry, fw_name, dev);
if (error) {
dev_err(dev, "failed to request firmware %s: %d",
fw_name, error);
goto out_free_fw_name;
return error;
}
if (fw_entry->size % sizeof(__be32)) {
dev_err(dev, "invalid firmware size %zu\n", fw_entry->size);
error = -EINVAL;
goto out_release_fw;
return -EINVAL;
}
if (fw_entry->size > ts->fw_size) {
dev_err(dev, "fw size (%zu) is too big (memory size %d)\n",
fw_entry->size, ts->fw_size);
error = -EFBIG;
goto out_release_fw;
return -EFBIG;
}
mutex_lock(&ts->dev_mutex);
disable_irq(client->irq);
scoped_guard(mutex, &ts->dev_mutex) {
guard(disable_irq)(&client->irq);
error = hideep_update_firmware(ts, (const __be32 *)fw_entry->data,
fw_entry->size);
error = hideep_update_firmware(ts,
(const __be32 *)fw_entry->data,
fw_entry->size);
if (error)
return error;
}
enable_irq(client->irq);
mutex_unlock(&ts->dev_mutex);
out_release_fw:
release_firmware(fw_entry);
out_free_fw_name:
kfree(fw_name);
return error ?: count;
return count;
}
static ssize_t hideep_fw_version_show(struct device *dev,
@@ -925,13 +919,9 @@ static ssize_t hideep_fw_version_show(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
ssize_t len;
mutex_lock(&ts->dev_mutex);
len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver));
mutex_unlock(&ts->dev_mutex);
return len;
guard(mutex)(&ts->dev_mutex);
return sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.release_ver));
}
static ssize_t hideep_product_id_show(struct device *dev,
@@ -939,13 +929,9 @@ static ssize_t hideep_product_id_show(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct hideep_ts *ts = i2c_get_clientdata(client);
ssize_t len;
mutex_lock(&ts->dev_mutex);
len = sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id));
mutex_unlock(&ts->dev_mutex);
return len;
guard(mutex)(&ts->dev_mutex);
return sysfs_emit(buf, "%04x\n", be16_to_cpu(ts->dwz_info.product_id));
}
static DEVICE_ATTR(version, 0664, hideep_fw_version_show, NULL);

View File

@@ -181,18 +181,17 @@ static ssize_t hycon_hy46xx_setting_show(struct device *dev,
struct hycon_hy46xx_attribute *attr =
container_of(dattr, struct hycon_hy46xx_attribute, dattr);
u8 *field = (u8 *)tsdata + attr->field_offset;
size_t count = 0;
int error = 0;
int val;
mutex_lock(&tsdata->mutex);
guard(mutex)(&tsdata->mutex);
error = regmap_read(tsdata->regmap, attr->address, &val);
if (error < 0) {
if (error) {
dev_err(&tsdata->client->dev,
"Failed to fetch attribute %s, error %d\n",
dattr->attr.name, error);
goto out;
return error;
}
if (val != *field) {
@@ -202,11 +201,7 @@ static ssize_t hycon_hy46xx_setting_show(struct device *dev,
*field = val;
}
count = sysfs_emit(buf, "%d\n", val);
out:
mutex_unlock(&tsdata->mutex);
return error ?: count;
return sysfs_emit(buf, "%d\n", val);
}
static ssize_t hycon_hy46xx_setting_store(struct device *dev,
@@ -221,29 +216,25 @@ static ssize_t hycon_hy46xx_setting_store(struct device *dev,
unsigned int val;
int error;
mutex_lock(&tsdata->mutex);
guard(mutex)(&tsdata->mutex);
error = kstrtouint(buf, 0, &val);
if (error)
goto out;
return error;
if (val < attr->limit_low || val > attr->limit_high) {
error = -ERANGE;
goto out;
}
if (val < attr->limit_low || val > attr->limit_high)
return -ERANGE;
error = regmap_write(tsdata->regmap, attr->address, val);
if (error < 0) {
if (error) {
dev_err(&tsdata->client->dev,
"Failed to update attribute %s, error: %d\n",
dattr->attr.name, error);
goto out;
return error;
}
*field = val;
out:
mutex_unlock(&tsdata->mutex);
return error ?: count;
return count;
}
static HYCON_ATTR_U8(threshold, 0644, HY46XX_THRESHOLD, 0, 255);

View File

@@ -366,32 +366,34 @@ static int imagis_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct imagis_ts *ts = i2c_get_clientdata(client);
int retval = 0;
int error;
mutex_lock(&ts->input_dev->mutex);
guard(mutex)(&ts->input_dev->mutex);
if (input_device_enabled(ts->input_dev))
retval = imagis_stop(ts);
if (input_device_enabled(ts->input_dev)) {
error = imagis_stop(ts);
if (error)
return error;
}
mutex_unlock(&ts->input_dev->mutex);
return retval;
return 0;
}
static int imagis_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct imagis_ts *ts = i2c_get_clientdata(client);
int retval = 0;
int error;
mutex_lock(&ts->input_dev->mutex);
guard(mutex)(&ts->input_dev->mutex);
if (input_device_enabled(ts->input_dev))
retval = imagis_start(ts);
if (input_device_enabled(ts->input_dev)) {
error = imagis_start(ts);
if (error)
return error;
}
mutex_unlock(&ts->input_dev->mutex);
return retval;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);

View File

@@ -551,13 +551,11 @@ static int imx6ul_tsc_suspend(struct device *dev)
struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
struct input_dev *input_dev = tsc->input;
mutex_lock(&input_dev->mutex);
guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
imx6ul_tsc_stop(tsc);
mutex_unlock(&input_dev->mutex);
return 0;
}
@@ -566,16 +564,17 @@ static int imx6ul_tsc_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct imx6ul_tsc *tsc = platform_get_drvdata(pdev);
struct input_dev *input_dev = tsc->input;
int retval = 0;
int error;
mutex_lock(&input_dev->mutex);
guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
retval = imx6ul_tsc_start(tsc);
if (input_device_enabled(input_dev)) {
error = imx6ul_tsc_start(tsc);
if (error)
return error;
}
mutex_unlock(&input_dev->mutex);
return retval;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops,

View File

@@ -47,7 +47,7 @@ static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable)
{
struct ipaq_micro *micro = ts->micro;
spin_lock_irq(&micro->lock);
guard(spinlock_irq)(&micro->lock);
if (enable) {
micro->ts = micro_ts_receive;
@@ -56,8 +56,6 @@ static void micro_ts_toggle_receive(struct touchscreen_data *ts, bool enable)
micro->ts = NULL;
micro->ts_data = NULL;
}
spin_unlock_irq(&ts->micro->lock);
}
static int micro_ts_open(struct input_dev *input)
@@ -133,13 +131,11 @@ static int micro_ts_resume(struct device *dev)
struct touchscreen_data *ts = dev_get_drvdata(dev);
struct input_dev *input = ts->input;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (input_device_enabled(input))
micro_ts_toggle_receive(ts, true);
mutex_unlock(&input->mutex);
return 0;
}

View File

@@ -73,8 +73,11 @@
#define IQS5XX_CSTM_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CSTM)
#define IQS5XX_PMAP_LEN (IQS5XX_PMAP_END + 1 - IQS5XX_CHKSM)
#define IQS5XX_REC_HDR_LEN 4
#define IQS5XX_REC_LEN_MAX 255
/* Length of firmware header in hexadecimal characters */
#define IQS5XX_REC_HDR_LEN_HEX (1 /* start */ + 2 /* size */ + \
4 /* addr */ + 2 /* type */)
#define IQS5XX_REC_HDR_SIZE 4 /* size + addr (2 bytes) + type, in bytes*/
#define IQS5XX_REC_DATA_SIZE 255 /* maximum size of the data portion */
#define IQS5XX_REC_TYPE_DATA 0x00
#define IQS5XX_REC_TYPE_EOF 0x01
@@ -98,14 +101,6 @@ struct iqs5xx_dev_id_info {
u8 bl_status;
} __packed;
struct iqs5xx_ihex_rec {
char start;
char len[2];
char addr[4];
char type[2];
char data[2];
} __packed;
struct iqs5xx_touch_data {
__be16 abs_x;
__be16 abs_y;
@@ -356,7 +351,7 @@ static int iqs5xx_bl_open(struct i2c_client *client)
}
static int iqs5xx_bl_write(struct i2c_client *client,
u16 bl_addr, u8 *pmap_data, u16 pmap_len)
u16 bl_addr, const u8 *pmap_data, u16 pmap_len)
{
struct i2c_msg msg;
int ret, i;
@@ -395,7 +390,7 @@ static int iqs5xx_bl_write(struct i2c_client *client,
}
static int iqs5xx_bl_verify(struct i2c_client *client,
u16 bl_addr, u8 *pmap_data, u16 pmap_len)
u16 bl_addr, const u8 *pmap_data, u16 pmap_len)
{
struct i2c_msg msg;
int ret, i;
@@ -446,27 +441,21 @@ static int iqs5xx_set_state(struct i2c_client *client, u8 state)
if (!iqs5xx->dev_id_info.bl_status)
return 0;
mutex_lock(&iqs5xx->lock);
guard(mutex)(&iqs5xx->lock);
/*
* Addressing the device outside of a communication window prompts it
* to assert the RDY output, so disable the interrupt line to prevent
* the handler from servicing a false interrupt.
*/
disable_irq(client->irq);
guard(disable_irq)(&client->irq);
error1 = iqs5xx_write_byte(client, IQS5XX_SYS_CTRL1, state);
error2 = iqs5xx_write_byte(client, IQS5XX_END_COMM, 0);
usleep_range(50, 100);
enable_irq(client->irq);
mutex_unlock(&iqs5xx->lock);
if (error1)
return error1;
return error2;
return error1 ?: error2;
}
static int iqs5xx_open(struct input_dev *input)
@@ -703,15 +692,13 @@ static irqreturn_t iqs5xx_irq(int irq, void *data)
static int iqs5xx_fw_file_parse(struct i2c_client *client,
const char *fw_file, u8 *pmap)
{
const struct firmware *fw;
struct iqs5xx_ihex_rec *rec;
size_t pos = 0;
int error, i;
u16 rec_num = 1;
u16 rec_addr;
u8 rec_len, rec_type, rec_chksm, chksm;
u8 rec_hdr[IQS5XX_REC_HDR_LEN];
u8 rec_data[IQS5XX_REC_LEN_MAX];
u8 rec_hdr[IQS5XX_REC_HDR_SIZE];
u8 rec_data[IQS5XX_REC_DATA_SIZE];
/*
* Firmware exported from the vendor's configuration tool deviates from
@@ -722,6 +709,7 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
* Because the ihex2fw tool tolerates neither (1) nor (2), the slightly
* nonstandard ihex firmware is parsed directly by the driver.
*/
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fw_file, &client->dev);
if (error) {
dev_err(&client->dev, "Failed to request firmware %s: %d\n",
@@ -730,53 +718,55 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
}
do {
if (pos + sizeof(*rec) > fw->size) {
if (pos + IQS5XX_REC_HDR_LEN_HEX > fw->size) {
dev_err(&client->dev, "Insufficient firmware size\n");
error = -EINVAL;
break;
return -EINVAL;
}
rec = (struct iqs5xx_ihex_rec *)(fw->data + pos);
pos += sizeof(*rec);
if (rec->start != ':') {
if (fw->data[pos] != ':') {
dev_err(&client->dev, "Invalid start at record %u\n",
rec_num);
error = -EINVAL;
break;
return -EINVAL;
}
error = hex2bin(rec_hdr, rec->len, sizeof(rec_hdr));
/* Convert all 3 fields (length, address, and type) in one go */
error = hex2bin(rec_hdr, &fw->data[pos + 1], sizeof(rec_hdr));
if (error) {
dev_err(&client->dev, "Invalid header at record %u\n",
rec_num);
break;
return error;
}
pos += IQS5XX_REC_HDR_LEN_HEX;
rec_len = *rec_hdr;
rec_addr = get_unaligned_be16(rec_hdr + sizeof(rec_len));
rec_type = *(rec_hdr + sizeof(rec_len) + sizeof(rec_addr));
if (pos + rec_len * 2 > fw->size) {
/*
* Check if we have enough data for the data portion of the
* record, as well as the checksum byte. Everything is doubled
* because data is in ASCII HEX and not binary format.
*/
if (pos + (rec_len + sizeof(rec_chksm)) * 2 > fw->size) {
dev_err(&client->dev, "Insufficient firmware size\n");
error = -EINVAL;
break;
return -EINVAL;
}
pos += (rec_len * 2);
error = hex2bin(rec_data, rec->data, rec_len);
error = hex2bin(rec_data, &fw->data[pos], rec_len);
if (error) {
dev_err(&client->dev, "Invalid data at record %u\n",
rec_num);
break;
return error;
}
pos += rec_len * 2;
error = hex2bin(&rec_chksm,
rec->data + rec_len * 2, sizeof(rec_chksm));
error = hex2bin(&rec_chksm, &fw->data[pos], sizeof(rec_chksm));
if (error) {
dev_err(&client->dev, "Invalid checksum at record %u\n",
rec_num);
break;
return error;
}
pos += 2;
chksm = 0;
for (i = 0; i < sizeof(rec_hdr); i++)
@@ -800,23 +790,22 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
dev_err(&client->dev,
"Invalid address at record %u\n",
rec_num);
error = -EINVAL;
} else {
memcpy(pmap + rec_addr - IQS5XX_CHKSM,
rec_data, rec_len);
return -EINVAL;
}
memcpy(pmap + rec_addr - IQS5XX_CHKSM,
rec_data, rec_len);
break;
case IQS5XX_REC_TYPE_EOF:
break;
default:
dev_err(&client->dev, "Invalid type at record %u\n",
rec_num);
error = -EINVAL;
return -EINVAL;
}
if (error)
break;
rec_num++;
while (pos < fw->size) {
if (*(fw->data + pos) == ':')
@@ -825,33 +814,13 @@ static int iqs5xx_fw_file_parse(struct i2c_client *client,
}
} while (rec_type != IQS5XX_REC_TYPE_EOF);
release_firmware(fw);
return error;
return 0;
}
static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
static int iqs5xx_update_firmware(struct iqs5xx_private *iqs5xx, const u8 *pmap)
{
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
int error, error_init = 0;
u8 *pmap;
pmap = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
if (!pmap)
return -ENOMEM;
error = iqs5xx_fw_file_parse(client, fw_file, pmap);
if (error)
goto err_kfree;
mutex_lock(&iqs5xx->lock);
/*
* Disable the interrupt line in case the first attempt(s) to enter the
* bootloader don't happen quickly enough, in which case the device may
* assert the RDY output until the next attempt.
*/
disable_irq(client->irq);
struct i2c_client *client = iqs5xx->client;
int error;
iqs5xx->dev_id_info.bl_status = 0;
@@ -859,22 +828,50 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
if (error) {
error = iqs5xx_bl_open(client);
if (error)
goto err_reset;
return error;
}
error = iqs5xx_bl_write(client, IQS5XX_CHKSM, pmap, IQS5XX_PMAP_LEN);
if (error)
goto err_reset;
return error;
error = iqs5xx_bl_cmd(client, IQS5XX_BL_CMD_CRC, 0);
if (error)
goto err_reset;
return error;
error = iqs5xx_bl_verify(client, IQS5XX_CSTM,
pmap + IQS5XX_CHKSM_LEN + IQS5XX_APP_LEN,
IQS5XX_CSTM_LEN);
if (error)
return error;
return 0;
}
static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
{
struct iqs5xx_private *iqs5xx = i2c_get_clientdata(client);
int error, error_init = 0;
u8 *pmap __free(kfree) = kzalloc(IQS5XX_PMAP_LEN, GFP_KERNEL);
if (!pmap)
return -ENOMEM;
error = iqs5xx_fw_file_parse(client, fw_file, pmap);
if (error)
return error;
guard(mutex)(&iqs5xx->lock);
/*
* Disable the interrupt line in case the first attempt(s) to enter the
* bootloader don't happen quickly enough, in which case the device may
* assert the RDY output until the next attempt.
*/
guard(disable_irq)(&client->irq);
error = iqs5xx_update_firmware(iqs5xx, pmap);
err_reset:
iqs5xx_reset(client);
usleep_range(15000, 15100);
@@ -882,14 +879,7 @@ static int iqs5xx_fw_file_write(struct i2c_client *client, const char *fw_file)
if (!iqs5xx->dev_id_info.bl_status)
error_init = error_init ? : -EINVAL;
enable_irq(client->irq);
mutex_unlock(&iqs5xx->lock);
err_kfree:
kfree(pmap);
return error ? : error_init;
return error ?: error_init;
}
static ssize_t fw_file_store(struct device *dev,
@@ -985,38 +975,30 @@ static int iqs5xx_suspend(struct device *dev)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct input_dev *input = iqs5xx->input;
int error = 0;
if (!input || device_may_wakeup(dev))
return error;
mutex_lock(&input->mutex);
return 0;
guard(mutex)(&input->mutex);
if (input_device_enabled(input))
error = iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
return iqs5xx_set_state(iqs5xx->client, IQS5XX_SUSPEND);
mutex_unlock(&input->mutex);
return error;
return 0;
}
static int iqs5xx_resume(struct device *dev)
{
struct iqs5xx_private *iqs5xx = dev_get_drvdata(dev);
struct input_dev *input = iqs5xx->input;
int error = 0;
if (!input || device_may_wakeup(dev))
return error;
mutex_lock(&input->mutex);
return 0;
guard(mutex)(&input->mutex);
if (input_device_enabled(input))
error = iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
return iqs5xx_set_state(iqs5xx->client, IQS5XX_RESUME);
mutex_unlock(&input->mutex);
return error;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(iqs5xx_pm, iqs5xx_suspend, iqs5xx_resume);

View File

@@ -2060,19 +2060,16 @@ static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211,
for (i = 0; i < dev_desc->num_kp_events; i++) {
const char *event_name = dev_desc->kp_events[i].name;
struct fwnode_handle *event_node;
if (dev_desc->kp_events[i].reg_grp != reg_grp)
continue;
reg_field.mask |= dev_desc->kp_events[i].enable;
if (event_name)
event_node = fwnode_get_named_child_node(reg_grp_node,
event_name);
else
event_node = fwnode_handle_get(reg_grp_node);
struct fwnode_handle *event_node __free(fwnode_handle) =
event_name ? fwnode_get_named_child_node(reg_grp_node,
event_name) :
fwnode_handle_get(reg_grp_node);
if (!event_node)
continue;
@@ -2080,7 +2077,6 @@ static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211,
dev_desc->kp_events[i].reg_grp,
dev_desc->kp_events[i].reg_key,
&iqs7211->kp_code[i]);
fwnode_handle_put(event_node);
if (error)
return error;
@@ -2496,19 +2492,15 @@ static int iqs7211_probe(struct i2c_client *client)
for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) {
const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp];
struct fwnode_handle *reg_grp_node;
if (reg_grp_name)
reg_grp_node = device_get_named_child_node(&client->dev,
reg_grp_name);
else
reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
struct fwnode_handle *reg_grp_node __free(fwnode_handle) =
reg_grp_name ? device_get_named_child_node(&client->dev,
reg_grp_name) :
fwnode_handle_get(dev_fwnode(&client->dev));
if (!reg_grp_node)
continue;
error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp);
fwnode_handle_put(reg_grp_node);
if (error)
return error;
}

View File

@@ -279,7 +279,7 @@ static int lpc32xx_ts_suspend(struct device *dev)
* avoid calling the TSC stop and start functions as the TSC
* isn't yet clocked.
*/
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (input_device_enabled(input)) {
if (device_may_wakeup(dev))
@@ -288,8 +288,6 @@ static int lpc32xx_ts_suspend(struct device *dev)
lpc32xx_stop_tsc(tsc);
}
mutex_unlock(&input->mutex);
return 0;
}
@@ -298,7 +296,7 @@ static int lpc32xx_ts_resume(struct device *dev)
struct lpc32xx_tsc *tsc = dev_get_drvdata(dev);
struct input_dev *input = tsc->dev;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (input_device_enabled(input)) {
if (device_may_wakeup(dev))
@@ -307,8 +305,6 @@ static int lpc32xx_ts_resume(struct device *dev)
lpc32xx_setup_tsc(tsc);
}
mutex_unlock(&input->mutex);
return 0;
}

View File

@@ -881,8 +881,6 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset,
const u8 *data, int length, u16 buf_addr)
{
u8 cmd[6];
u8 *data_buf;
u16 buf_offset;
int ret;
int error;
@@ -895,7 +893,8 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset,
return -EINVAL;
}
data_buf = kmalloc(2 + MIP4_BL_PACKET_SIZE, GFP_KERNEL);
u8 *data_buf __free(kfree) = kmalloc(2 + MIP4_BL_PACKET_SIZE,
GFP_KERNEL);
if (!data_buf)
return -ENOMEM;
@@ -908,7 +907,7 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset,
error = ret < 0 ? ret : -EIO;
dev_err(&ts->client->dev,
"Failed to send write page address: %d\n", error);
goto out;
return error;
}
/* Size */
@@ -920,11 +919,11 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset,
error = ret < 0 ? ret : -EIO;
dev_err(&ts->client->dev,
"Failed to send write page size: %d\n", error);
goto out;
return error;
}
/* Data */
for (buf_offset = 0;
for (int buf_offset = 0;
buf_offset < length;
buf_offset += MIP4_BL_PACKET_SIZE) {
dev_dbg(&ts->client->dev,
@@ -939,7 +938,7 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset,
dev_err(&ts->client->dev,
"Failed to read chunk at %#04x (size %d): %d\n",
buf_offset, MIP4_BL_PACKET_SIZE, error);
goto out;
return error;
}
}
@@ -952,35 +951,21 @@ static int mip4_bl_program_page(struct mip4_ts *ts, int offset,
error = ret < 0 ? ret : -EIO;
dev_err(&ts->client->dev,
"Failed to send 'write' command: %d\n", error);
goto out;
return error;
}
/* Status */
error = mip4_bl_read_status(ts);
if (error)
return error;
out:
kfree(data_buf);
return error ? error : 0;
return 0;
}
static int mip4_bl_verify_page(struct mip4_ts *ts, int offset,
const u8 *data, int length, int buf_addr)
{
u8 cmd[8];
u8 *read_buf;
int buf_offset;
struct i2c_msg msg[] = {
{
.addr = ts->client->addr,
.flags = 0,
.buf = cmd,
.len = 2,
}, {
.addr = ts->client->addr,
.flags = I2C_M_RD,
.len = MIP4_BL_PACKET_SIZE,
},
};
int ret;
int error;
@@ -1029,11 +1014,25 @@ static int mip4_bl_verify_page(struct mip4_ts *ts, int offset,
return error;
/* Read */
msg[1].buf = read_buf = kmalloc(MIP4_BL_PACKET_SIZE, GFP_KERNEL);
u8 *read_buf __free(kfree) = kmalloc(MIP4_BL_PACKET_SIZE, GFP_KERNEL);
if (!read_buf)
return -ENOMEM;
for (buf_offset = 0;
struct i2c_msg msg[] = {
{
.addr = ts->client->addr,
.flags = 0,
.buf = cmd,
.len = 2,
}, {
.addr = ts->client->addr,
.flags = I2C_M_RD,
.buf = read_buf,
.len = MIP4_BL_PACKET_SIZE,
},
};
for (int buf_offset = 0;
buf_offset < length;
buf_offset += MIP4_BL_PACKET_SIZE) {
dev_dbg(&ts->client->dev,
@@ -1046,7 +1045,7 @@ static int mip4_bl_verify_page(struct mip4_ts *ts, int offset,
dev_err(&ts->client->dev,
"Failed to read chunk at %#04x (size %d): %d\n",
buf_offset, MIP4_BL_PACKET_SIZE, error);
break;
return error;
}
if (memcmp(&data[buf_offset], read_buf, MIP4_BL_PACKET_SIZE)) {
@@ -1064,13 +1063,11 @@ static int mip4_bl_verify_page(struct mip4_ts *ts, int offset,
DUMP_PREFIX_OFFSET, 16, 1,
read_buf, MIP4_BL_PAGE_SIZE, false);
#endif
error = -EINVAL;
break;
return -EINVAL;
}
}
kfree(read_buf);
return error ? error : 0;
return 0;
}
/*
@@ -1290,9 +1287,9 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
const struct firmware *fw;
int error;
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, ts->fw_name, dev);
if (error) {
dev_err(&ts->client->dev,
@@ -1306,14 +1303,9 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev,
* userspace opening and closing the device and also suspend/resume
* transitions.
*/
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
error = mip4_execute_fw_update(ts, fw);
mutex_unlock(&ts->input->mutex);
release_firmware(fw);
if (error) {
dev_err(&ts->client->dev,
"Firmware update failed: %d\n", error);
@@ -1331,18 +1323,13 @@ static ssize_t mip4_sysfs_read_fw_version(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
size_t count;
/* Take lock to prevent racing with firmware update */
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
count = sysfs_emit(buf, "%04X %04X %04X %04X\n",
ts->fw_version.boot, ts->fw_version.core,
ts->fw_version.app, ts->fw_version.param);
mutex_unlock(&ts->input->mutex);
return count;
return sysfs_emit(buf, "%04X %04X %04X %04X\n",
ts->fw_version.boot, ts->fw_version.core,
ts->fw_version.app, ts->fw_version.param);
}
static DEVICE_ATTR(fw_version, S_IRUGO, mip4_sysfs_read_fw_version, NULL);
@@ -1353,21 +1340,16 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
size_t count;
/* Take lock to prevent racing with firmware update */
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
/*
* product_name shows the name or version of the hardware
* paired with current firmware in the chip.
*/
count = sysfs_emit(buf, "%.*s\n",
(int)sizeof(ts->product_name), ts->product_name);
mutex_unlock(&ts->input->mutex);
return count;
return sysfs_emit(buf, "%.*s\n",
(int)sizeof(ts->product_name), ts->product_name);
}
static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
@@ -1378,15 +1360,10 @@ static ssize_t mip4_sysfs_read_product_id(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
size_t count;
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
count = sysfs_emit(buf, "%04X\n", ts->product_id);
mutex_unlock(&ts->input->mutex);
return count;
return sysfs_emit(buf, "%04X\n", ts->product_id);
}
static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL);
@@ -1397,16 +1374,10 @@ static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct mip4_ts *ts = i2c_get_clientdata(client);
size_t count;
mutex_lock(&ts->input->mutex);
guard(mutex)(&ts->input->mutex);
count = sysfs_emit(buf, "%.*s\n",
(int)sizeof(ts->ic_name), ts->ic_name);
mutex_unlock(&ts->input->mutex);
return count;
return sysfs_emit(buf, "%.*s\n", (int)sizeof(ts->ic_name), ts->ic_name);
}
static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
@@ -1520,15 +1491,13 @@ static int mip4_suspend(struct device *dev)
struct mip4_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (device_may_wakeup(dev))
ts->wake_irq_enabled = enable_irq_wake(client->irq) == 0;
else if (input_device_enabled(input))
mip4_disable(ts);
mutex_unlock(&input->mutex);
return 0;
}
@@ -1538,15 +1507,13 @@ static int mip4_resume(struct device *dev)
struct mip4_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (ts->wake_irq_enabled)
disable_irq_wake(client->irq);
else if (input_device_enabled(input))
mip4_enable(ts);
mutex_unlock(&input->mutex);
return 0;
}

View File

@@ -1,215 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* ICS MK712 touchscreen controller driver
*
* Copyright (c) 1999-2002 Transmeta Corporation
* Copyright (c) 2005 Rick Koch <n1gp@hotmail.com>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
*/
/*
* This driver supports the ICS MicroClock MK712 TouchScreen controller,
* found in Gateway AOL Connected Touchpad computers.
*
* Documentation for ICS MK712 can be found at:
* https://www.idt.com/general-parts/mk712-touch-screen-controller
*/
/*
* 1999-12-18: original version, Daniel Quinlan
* 1999-12-19: added anti-jitter code, report pen-up events, fixed mk712_poll
* to use queue_empty, Nathan Laredo
* 1999-12-20: improved random point rejection, Nathan Laredo
* 2000-01-05: checked in new anti-jitter code, changed mouse protocol, fixed
* queue code, added module options, other fixes, Daniel Quinlan
* 2002-03-15: Clean up for kernel merge <alan@redhat.com>
* Fixed multi open race, fixed memory checks, fixed resource
* allocation, fixed close/powerdown bug, switched to new init
* 2005-01-18: Ported to 2.6 from 2.4.28, Rick Koch
* 2005-02-05: Rewritten for the input layer, Vojtech Pavlik
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <asm/io.h>
MODULE_AUTHOR("Daniel Quinlan <quinlan@pathname.com>, Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION("ICS MicroClock MK712 TouchScreen driver");
MODULE_LICENSE("GPL");
static unsigned int mk712_io = 0x260; /* Also 0x200, 0x208, 0x300 */
module_param_hw_named(io, mk712_io, uint, ioport, 0);
MODULE_PARM_DESC(io, "I/O base address of MK712 touchscreen controller");
static unsigned int mk712_irq = 10; /* Also 12, 14, 15 */
module_param_hw_named(irq, mk712_irq, uint, irq, 0);
MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
/* eight 8-bit registers */
#define MK712_STATUS 0
#define MK712_X 2
#define MK712_Y 4
#define MK712_CONTROL 6
#define MK712_RATE 7
/* status */
#define MK712_STATUS_TOUCH 0x10
#define MK712_CONVERSION_COMPLETE 0x80
/* control */
#define MK712_ENABLE_INT 0x01
#define MK712_INT_ON_CONVERSION_COMPLETE 0x02
#define MK712_INT_ON_CHANGE_IN_TOUCH_STATUS 0x04
#define MK712_ENABLE_PERIODIC_CONVERSIONS 0x10
#define MK712_READ_ONE_POINT 0x20
#define MK712_POWERUP 0x40
static struct input_dev *mk712_dev;
static DEFINE_SPINLOCK(mk712_lock);
static irqreturn_t mk712_interrupt(int irq, void *dev_id)
{
unsigned char status;
static int debounce = 1;
static unsigned short last_x;
static unsigned short last_y;
spin_lock(&mk712_lock);
status = inb(mk712_io + MK712_STATUS);
if (~status & MK712_CONVERSION_COMPLETE) {
debounce = 1;
goto end;
}
if (~status & MK712_STATUS_TOUCH) {
debounce = 1;
input_report_key(mk712_dev, BTN_TOUCH, 0);
goto end;
}
if (debounce) {
debounce = 0;
goto end;
}
input_report_key(mk712_dev, BTN_TOUCH, 1);
input_report_abs(mk712_dev, ABS_X, last_x);
input_report_abs(mk712_dev, ABS_Y, last_y);
end:
last_x = inw(mk712_io + MK712_X) & 0x0fff;
last_y = inw(mk712_io + MK712_Y) & 0x0fff;
input_sync(mk712_dev);
spin_unlock(&mk712_lock);
return IRQ_HANDLED;
}
static int mk712_open(struct input_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&mk712_lock, flags);
outb(0, mk712_io + MK712_CONTROL); /* Reset */
outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
MK712_ENABLE_PERIODIC_CONVERSIONS |
MK712_POWERUP, mk712_io + MK712_CONTROL);
outb(10, mk712_io + MK712_RATE); /* 187 points per second */
spin_unlock_irqrestore(&mk712_lock, flags);
return 0;
}
static void mk712_close(struct input_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&mk712_lock, flags);
outb(0, mk712_io + MK712_CONTROL);
spin_unlock_irqrestore(&mk712_lock, flags);
}
static int __init mk712_init(void)
{
int err;
if (!request_region(mk712_io, 8, "mk712")) {
printk(KERN_WARNING "mk712: unable to get IO region\n");
return -ENODEV;
}
outb(0, mk712_io + MK712_CONTROL);
if ((inw(mk712_io + MK712_X) & 0xf000) || /* Sanity check */
(inw(mk712_io + MK712_Y) & 0xf000) ||
(inw(mk712_io + MK712_STATUS) & 0xf333)) {
printk(KERN_WARNING "mk712: device not present\n");
err = -ENODEV;
goto fail1;
}
mk712_dev = input_allocate_device();
if (!mk712_dev) {
printk(KERN_ERR "mk712: not enough memory\n");
err = -ENOMEM;
goto fail1;
}
mk712_dev->name = "ICS MicroClock MK712 TouchScreen";
mk712_dev->phys = "isa0260/input0";
mk712_dev->id.bustype = BUS_ISA;
mk712_dev->id.vendor = 0x0005;
mk712_dev->id.product = 0x0001;
mk712_dev->id.version = 0x0100;
mk712_dev->open = mk712_open;
mk712_dev->close = mk712_close;
mk712_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
mk712_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(mk712_dev, ABS_X, 0, 0xfff, 88, 0);
input_set_abs_params(mk712_dev, ABS_Y, 0, 0xfff, 88, 0);
if (request_irq(mk712_irq, mk712_interrupt, 0, "mk712", mk712_dev)) {
printk(KERN_WARNING "mk712: unable to get IRQ\n");
err = -EBUSY;
goto fail1;
}
err = input_register_device(mk712_dev);
if (err)
goto fail2;
return 0;
fail2: free_irq(mk712_irq, mk712_dev);
fail1: input_free_device(mk712_dev);
release_region(mk712_io, 8);
return err;
}
static void __exit mk712_exit(void)
{
input_unregister_device(mk712_dev);
free_irq(mk712_irq, mk712_dev);
release_region(mk712_io, 8);
}
module_init(mk712_init);
module_exit(mk712_exit);

View File

@@ -216,20 +216,12 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
{
struct mms114_data *data = dev_id;
struct i2c_client *client = data->client;
struct input_dev *input_dev = data->input_dev;
struct mms114_touch touch[MMS114_MAX_TOUCH];
int packet_size;
int touch_size;
int index;
int error;
mutex_lock(&input_dev->mutex);
if (!input_device_enabled(input_dev)) {
mutex_unlock(&input_dev->mutex);
goto out;
}
mutex_unlock(&input_dev->mutex);
packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE);
if (packet_size <= 0)
goto out;
@@ -646,10 +638,10 @@ static int mms114_suspend(struct device *dev)
input_mt_report_pointer_emulation(input_dev, true);
input_sync(input_dev);
mutex_lock(&input_dev->mutex);
guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
mms114_stop(data);
mutex_unlock(&input_dev->mutex);
return 0;
}
@@ -661,15 +653,13 @@ static int mms114_resume(struct device *dev)
struct input_dev *input_dev = data->input_dev;
int error;
mutex_lock(&input_dev->mutex);
guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev)) {
error = mms114_start(data);
if (error < 0) {
mutex_unlock(&input_dev->mutex);
if (error)
return error;
}
}
mutex_unlock(&input_dev->mutex);
return 0;
}

View File

@@ -446,13 +446,11 @@ static int msg2638_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client);
mutex_lock(&msg2638->input_dev->mutex);
guard(mutex)(&msg2638->input_dev->mutex);
if (input_device_enabled(msg2638->input_dev))
msg2638_stop(msg2638);
mutex_unlock(&msg2638->input_dev->mutex);
return 0;
}
@@ -460,16 +458,17 @@ static int msg2638_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct msg2638_ts_data *msg2638 = i2c_get_clientdata(client);
int ret = 0;
int error;
mutex_lock(&msg2638->input_dev->mutex);
guard(mutex)(&msg2638->input_dev->mutex);
if (input_device_enabled(msg2638->input_dev))
ret = msg2638_start(msg2638);
if (input_device_enabled(msg2638->input_dev)) {
error = msg2638_start(msg2638);
if (error)
return error;
}
mutex_unlock(&msg2638->input_dev->mutex);
return ret;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(msg2638_pm_ops, msg2638_suspend, msg2638_resume);

View File

@@ -500,15 +500,14 @@ static irqreturn_t mxs_lradc_ts_handle_irq(int irq, void *data)
LRADC_CTRL1_TOUCH_DETECT_IRQ |
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2);
unsigned long flags;
if (!(reg & mxs_lradc_irq_mask(lradc)))
return IRQ_NONE;
if (reg & ts_irq_mask) {
spin_lock_irqsave(&ts->lock, flags);
mxs_lradc_handle_touch(ts);
spin_unlock_irqrestore(&ts->lock, flags);
scoped_guard(spinlock_irqsave, &ts->lock) {
mxs_lradc_handle_touch(ts);
}
/* Make sure we don't clear the next conversion's interrupt. */
clr_irq &= ~(LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL1) |
LRADC_CTRL1_LRADC_IRQ(TOUCHSCREEN_VCHANNEL2));

View File

@@ -170,10 +170,10 @@ static int nvt_ts_suspend(struct device *dev)
{
struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
guard(mutex)(&data->input->mutex);
if (input_device_enabled(data->input))
nvt_ts_stop(data->input);
mutex_unlock(&data->input->mutex);
return 0;
}
@@ -182,10 +182,10 @@ static int nvt_ts_resume(struct device *dev)
{
struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev));
mutex_lock(&data->input->mutex);
guard(mutex)(&data->input->mutex);
if (input_device_enabled(data->input))
nvt_ts_start(data->input);
mutex_unlock(&data->input->mutex);
return 0;
}

View File

@@ -410,26 +410,25 @@ static int pixcir_i2c_ts_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
int error;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (device_may_wakeup(&client->dev)) {
if (!input_device_enabled(input)) {
ret = pixcir_start(ts);
if (ret) {
error = pixcir_start(ts);
if (error) {
dev_err(dev, "Failed to start\n");
goto unlock;
return error;
}
}
} else if (input_device_enabled(input)) {
ret = pixcir_stop(ts);
error = pixcir_stop(ts);
if (error)
return error;
}
unlock:
mutex_unlock(&input->mutex);
return ret;
return 0;
}
static int pixcir_i2c_ts_resume(struct device *dev)
@@ -437,26 +436,25 @@ static int pixcir_i2c_ts_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
int ret = 0;
int error;
mutex_lock(&input->mutex);
guard(mutex)(&input->mutex);
if (device_may_wakeup(&client->dev)) {
if (!input_device_enabled(input)) {
ret = pixcir_stop(ts);
if (ret) {
error = pixcir_stop(ts);
if (error) {
dev_err(dev, "Failed to stop\n");
goto unlock;
return error;
}
}
} else if (input_device_enabled(input)) {
ret = pixcir_start(ts);
error = pixcir_start(ts);
if (error)
return error;
}
unlock:
mutex_unlock(&input->mutex);
return ret;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,

View File

@@ -169,10 +169,9 @@ static int raydium_i2c_send(struct i2c_client *client,
{
int tries = 0;
int error;
u8 *tx_buf;
u8 reg_addr = addr & 0xff;
tx_buf = kmalloc(len + 1, GFP_KERNEL);
u8 *tx_buf __free(kfree) = kmalloc(len + 1, GFP_KERNEL);
if (!tx_buf)
return -ENOMEM;
@@ -210,14 +209,12 @@ static int raydium_i2c_send(struct i2c_client *client,
error = raydium_i2c_xfer(client, addr, xfer, ARRAY_SIZE(xfer));
if (likely(!error))
goto out;
return 0;
msleep(RM_RETRY_DELAY_MS);
} while (++tries < RM_MAX_RETRIES);
dev_err(&client->dev, "%s failed: %d\n", __func__, error);
out:
kfree(tx_buf);
return error;
}
@@ -815,21 +812,21 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts,
static int raydium_i2c_fw_update(struct raydium_data *ts)
{
struct i2c_client *client = ts->client;
const struct firmware *fw = NULL;
char *fw_file;
int error;
fw_file = kasprintf(GFP_KERNEL, "raydium_%#04x.fw",
le32_to_cpu(ts->info.hw_ver));
const char *fw_file __free(kfree) =
kasprintf(GFP_KERNEL, "raydium_%#04x.fw",
le32_to_cpu(ts->info.hw_ver));
if (!fw_file)
return -ENOMEM;
dev_dbg(&client->dev, "firmware name: %s\n", fw_file);
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fw_file, &client->dev);
if (error) {
dev_err(&client->dev, "Unable to open firmware %s\n", fw_file);
goto out_free_fw_file;
return error;
}
disable_irq(client->irq);
@@ -856,11 +853,6 @@ static int raydium_i2c_fw_update(struct raydium_data *ts)
enable_irq(client->irq);
msleep(100);
release_firmware(fw);
out_free_fw_file:
kfree(fw_file);
return error;
}
@@ -965,15 +957,12 @@ static ssize_t raydium_i2c_update_fw_store(struct device *dev,
struct raydium_data *ts = i2c_get_clientdata(client);
int error;
error = mutex_lock_interruptible(&ts->sysfs_mutex);
if (error)
return error;
scoped_guard(mutex_intr, &ts->sysfs_mutex) {
error = raydium_i2c_fw_update(ts);
return error ?: count;
}
error = raydium_i2c_fw_update(ts);
mutex_unlock(&ts->sysfs_mutex);
return error ?: count;
return -EINTR;
}
static ssize_t raydium_i2c_calibrate_store(struct device *dev,
@@ -985,17 +974,20 @@ static ssize_t raydium_i2c_calibrate_store(struct device *dev,
static const u8 cal_cmd[] = { 0x00, 0x01, 0x9E };
int error;
error = mutex_lock_interruptible(&ts->sysfs_mutex);
if (error)
return error;
scoped_guard(mutex_intr, &ts->sysfs_mutex) {
error = raydium_i2c_write_object(client,
cal_cmd, sizeof(cal_cmd),
RAYDIUM_WAIT_READY);
if (error) {
dev_err(&client->dev,
"calibrate command failed: %d\n", error);
return error;
}
error = raydium_i2c_write_object(client, cal_cmd, sizeof(cal_cmd),
RAYDIUM_WAIT_READY);
if (error)
dev_err(&client->dev, "calibrate command failed: %d\n", error);
return count;
}
mutex_unlock(&ts->sysfs_mutex);
return error ?: count;
return -EINTR;
}
static DEVICE_ATTR(fw_version, S_IRUGO, raydium_i2c_fw_ver_show, NULL);

View File

@@ -15,6 +15,7 @@
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touch-overlay.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -22,11 +23,14 @@
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/input/touch-overlay.h>
#include <asm/byteorder.h>
#define ST1232_TS_NAME "st1232-ts"
#define ST1633_TS_NAME "st1633-ts"
#define REG_FIRMWARE_VERSION 0x00
#define REG_FIRMWARE_REVISION_3 0x0C
#define REG_STATUS 0x01 /* Device Status | Error Code */
#define STATUS_NORMAL 0x00
@@ -61,8 +65,38 @@ struct st1232_ts_data {
struct list_head touch_overlay_list;
int read_buf_len;
u8 *read_buf;
u8 fw_version;
u32 fw_revision;
};
static ssize_t fw_version_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct st1232_ts_data *st1232_ts = i2c_get_clientdata(client);
return sysfs_emit(buf, "%u\n", st1232_ts->fw_version);
}
static ssize_t fw_revision_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct st1232_ts_data *st1232_ts = i2c_get_clientdata(client);
return sysfs_emit(buf, "%08x\n", st1232_ts->fw_revision);
}
static DEVICE_ATTR_RO(fw_version);
static DEVICE_ATTR_RO(fw_revision);
static struct attribute *st1232_attrs[] = {
&dev_attr_fw_version.attr,
&dev_attr_fw_revision.attr,
NULL,
};
ATTRIBUTE_GROUPS(st1232);
static int st1232_ts_read_data(struct st1232_ts_data *ts, u8 reg,
unsigned int n)
{
@@ -110,6 +144,26 @@ static int st1232_ts_wait_ready(struct st1232_ts_data *ts)
return -ENXIO;
}
static int st1232_ts_read_fw_version(struct st1232_ts_data *ts,
u8 *fw_version, u32 *fw_revision)
{
int error;
/* select firmware version register */
error = st1232_ts_read_data(ts, REG_FIRMWARE_VERSION, 1);
if (error)
return error;
*fw_version = ts->read_buf[0];
/* select firmware revision register */
error = st1232_ts_read_data(ts, REG_FIRMWARE_REVISION_3, 4);
if (error)
return error;
*fw_revision = le32_to_cpup((__le32 *)ts->read_buf);
return 0;
}
static int st1232_ts_read_resolution(struct st1232_ts_data *ts, u16 *max_x,
u16 *max_y)
{
@@ -299,6 +353,16 @@ static int st1232_ts_probe(struct i2c_client *client)
if (error)
return error;
/* Read firmware version from the chip */
error = st1232_ts_read_fw_version(ts, &ts->fw_version, &ts->fw_revision);
if (error) {
dev_err(&client->dev,
"Failed to read firmware version: %d\n", error);
return error;
}
dev_dbg(&client->dev, "Detected firmware version %u, rev %08x\n",
ts->fw_version, ts->fw_revision);
if (ts->chip_info->have_z)
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ts->chip_info->max_area, 0, 0);
@@ -408,6 +472,7 @@ static struct i2c_driver st1232_ts_driver = {
.driver = {
.name = ST1232_TS_NAME,
.of_match_table = st1232_ts_dt_ids,
.dev_groups = st1232_groups,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.pm = pm_sleep_ptr(&st1232_ts_pm_ops),
},

View File

@@ -302,7 +302,7 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev)
struct stmfts_data *sdata = dev;
int err;
mutex_lock(&sdata->mutex);
guard(mutex)(&sdata->mutex);
err = stmfts_read_events(sdata);
if (unlikely(err))
@@ -311,7 +311,6 @@ static irqreturn_t stmfts_irq_handler(int irq, void *dev)
else
stmfts_parse_events(sdata);
mutex_unlock(&sdata->mutex);
return IRQ_HANDLED;
}
@@ -347,17 +346,17 @@ static int stmfts_input_open(struct input_dev *dev)
return err;
}
mutex_lock(&sdata->mutex);
sdata->running = true;
scoped_guard(mutex, &sdata->mutex) {
sdata->running = true;
if (sdata->hover_enabled) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_SS_HOVER_SENSE_ON);
if (err)
dev_warn(&sdata->client->dev,
"failed to enable hover\n");
if (sdata->hover_enabled) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_SS_HOVER_SENSE_ON);
if (err)
dev_warn(&sdata->client->dev,
"failed to enable hover\n");
}
}
mutex_unlock(&sdata->mutex);
if (sdata->use_key) {
err = i2c_smbus_write_byte(sdata->client,
@@ -381,18 +380,17 @@ static void stmfts_input_close(struct input_dev *dev)
dev_warn(&sdata->client->dev,
"failed to disable touchscreen: %d\n", err);
mutex_lock(&sdata->mutex);
scoped_guard(mutex, &sdata->mutex) {
sdata->running = false;
sdata->running = false;
if (sdata->hover_enabled) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_SS_HOVER_SENSE_OFF);
if (err)
dev_warn(&sdata->client->dev,
"failed to disable hover: %d\n", err);
if (sdata->hover_enabled) {
err = i2c_smbus_write_byte(sdata->client,
STMFTS_SS_HOVER_SENSE_OFF);
if (err)
dev_warn(&sdata->client->dev,
"failed to disable hover: %d\n", err);
}
}
mutex_unlock(&sdata->mutex);
if (sdata->use_key) {
err = i2c_smbus_write_byte(sdata->client,
@@ -474,26 +472,27 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
{
struct stmfts_data *sdata = dev_get_drvdata(dev);
unsigned long value;
int err = 0;
bool hover;
int err;
if (kstrtoul(buf, 0, &value))
return -EINVAL;
mutex_lock(&sdata->mutex);
hover = !!value;
if (value && sdata->hover_enabled)
goto out;
guard(mutex)(&sdata->mutex);
if (sdata->running)
err = i2c_smbus_write_byte(sdata->client,
if (hover != sdata->hover_enabled) {
if (sdata->running) {
err = i2c_smbus_write_byte(sdata->client,
value ? STMFTS_SS_HOVER_SENSE_ON :
STMFTS_SS_HOVER_SENSE_OFF);
if (err)
return err;
}
if (!err)
sdata->hover_enabled = !!value;
out:
mutex_unlock(&sdata->mutex);
sdata->hover_enabled = hover;
}
return len;
}

View File

@@ -538,15 +538,15 @@ static void sur40_process_video(struct sur40_state *sur40)
return;
/* get a new buffer from the list */
spin_lock(&sur40->qlock);
if (list_empty(&sur40->buf_list)) {
dev_dbg(sur40->dev, "buffer queue empty\n");
spin_unlock(&sur40->qlock);
return;
scoped_guard(spinlock, &sur40->qlock) {
if (list_empty(&sur40->buf_list)) {
dev_dbg(sur40->dev, "buffer queue empty\n");
return;
}
new_buf = list_first_entry(&sur40->buf_list,
struct sur40_buffer, list);
list_del(&new_buf->list);
}
new_buf = list_entry(sur40->buf_list.next, struct sur40_buffer, list);
list_del(&new_buf->list);
spin_unlock(&sur40->qlock);
dev_dbg(sur40->dev, "buffer acquired\n");
@@ -888,9 +888,8 @@ static void sur40_buffer_queue(struct vb2_buffer *vb)
struct sur40_state *sur40 = vb2_get_drv_priv(vb->vb2_queue);
struct sur40_buffer *buf = (struct sur40_buffer *)vb;
spin_lock(&sur40->qlock);
guard(spinlock)(&sur40->qlock);
list_add_tail(&buf->list, &sur40->buf_list);
spin_unlock(&sur40->qlock);
}
static void return_all_buffers(struct sur40_state *sur40,
@@ -898,12 +897,12 @@ static void return_all_buffers(struct sur40_state *sur40,
{
struct sur40_buffer *buf, *node;
spin_lock(&sur40->qlock);
guard(spinlock)(&sur40->qlock);
list_for_each_entry_safe(buf, node, &sur40->buf_list, list) {
vb2_buffer_done(&buf->vb.vb2_buf, state);
list_del(&buf->list);
}
spin_unlock(&sur40->qlock);
}
/*

View File

@@ -117,12 +117,11 @@ static inline void sx865x_penrelease(struct sx8654 *ts)
static void sx865x_penrelease_timer_handler(struct timer_list *t)
{
struct sx8654 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
sx865x_penrelease(ts);
spin_unlock_irqrestore(&ts->lock, flags);
dev_dbg(&ts->client->dev, "penrelease by timer\n");
guard(spinlock_irqsave)(&ts->lock);
sx865x_penrelease(ts);
}
static irqreturn_t sx8650_irq(int irq, void *handle)
@@ -130,7 +129,6 @@ static irqreturn_t sx8650_irq(int irq, void *handle)
struct sx8654 *ts = handle;
struct device *dev = &ts->client->dev;
int len, i;
unsigned long flags;
u8 stat;
u16 x, y;
u16 ch;
@@ -153,7 +151,7 @@ static irqreturn_t sx8650_irq(int irq, void *handle)
return IRQ_HANDLED;
}
spin_lock_irqsave(&ts->lock, flags);
guard(spinlock_irqsave)(&ts->lock);
x = 0;
y = 0;
@@ -184,7 +182,6 @@ static irqreturn_t sx8650_irq(int irq, void *handle)
dev_dbg(dev, "point(%4d,%4d)\n", x, y);
mod_timer(&ts->timer, jiffies + SX8650_PENIRQ_TIMEOUT);
spin_unlock_irqrestore(&ts->lock, flags);
return IRQ_HANDLED;
}
@@ -394,9 +391,13 @@ static int sx8654_probe(struct i2c_client *client)
return error;
}
/*
* Start with the interrupt disabled, it will be enabled in
* sx8654_open().
*/
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, sx8654->data->irqh,
IRQF_ONESHOT,
IRQF_ONESHOT | IRQF_NO_AUTOEN,
client->name, sx8654);
if (error) {
dev_err(&client->dev,
@@ -405,9 +406,6 @@ static int sx8654_probe(struct i2c_client *client)
return error;
}
/* Disable the IRQ, we'll enable it in sx8654_open() */
disable_irq(client->irq);
error = input_register_device(sx8654->input);
if (error)
return error;

View File

@@ -122,9 +122,10 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
/* pen is down, continue with the measurement */
mutex_lock(&ts->mlock);
tsc2007_read_values(ts, &tc);
mutex_unlock(&ts->mlock);
/* Serialize access between the ISR and IIO reads. */
scoped_guard(mutex, &ts->mlock) {
tsc2007_read_values(ts, &tc);
}
rt = tsc2007_calculate_resistance(ts, &tc);

View File

@@ -41,7 +41,6 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev,
struct tsc2007_iio *iio = iio_priv(indio_dev);
struct tsc2007 *tsc = iio->ts;
int adc_chan = chan->channel;
int ret = 0;
if (adc_chan >= ARRAY_SIZE(tsc2007_iio_channel))
return -EINVAL;
@@ -49,7 +48,7 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev,
if (mask != IIO_CHAN_INFO_RAW)
return -EINVAL;
mutex_lock(&tsc->mlock);
guard(mutex)(&tsc->mlock);
switch (chan->channel) {
case 0:
@@ -92,11 +91,7 @@ static int tsc2007_read_raw(struct iio_dev *indio_dev,
/* Prepare for next touch reading - power down ADC, enable PENIRQ */
tsc2007_xfer(tsc, PWRDOWN);
mutex_unlock(&tsc->mlock);
ret = IIO_VAL_INT;
return ret;
return IIO_VAL_INT;
}
static const struct iio_info tsc2007_iio_info = {

View File

@@ -969,24 +969,21 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
{
struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
struct usb_host_interface *interface = usbtouch->interface->cur_altsetting;
struct usb_endpoint_descriptor *ep_in, *ep_out;
struct nexio_priv *priv = usbtouch->priv;
int ret = -ENOMEM;
int actual_len, i;
char *firmware_ver = NULL, *device_name = NULL;
int input_ep = 0, output_ep = 0;
int input_ep, output_ep;
int ret;
/* find first input and output endpoint */
for (i = 0; i < interface->desc.bNumEndpoints; i++) {
if (!input_ep &&
usb_endpoint_dir_in(&interface->endpoint[i].desc))
input_ep = interface->endpoint[i].desc.bEndpointAddress;
if (!output_ep &&
usb_endpoint_dir_out(&interface->endpoint[i].desc))
output_ep = interface->endpoint[i].desc.bEndpointAddress;
}
if (!input_ep || !output_ep)
ret = usb_find_common_endpoints(interface, &ep_in, &ep_out, NULL, NULL);
if (ret)
return -ENXIO;
input_ep = usb_endpoint_num(ep_in);
output_ep = usb_endpoint_num(ep_out);
u8 *buf __free(kfree) = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
if (!buf)
return -ENOMEM;
@@ -1427,18 +1424,6 @@ static void usbtouch_free_buffers(struct usb_device *udev,
kfree(usbtouch->buffer);
}
static struct usb_endpoint_descriptor *
usbtouch_get_input_endpoint(struct usb_host_interface *interface)
{
int i;
for (i = 0; i < interface->desc.bNumEndpoints; i++)
if (usb_endpoint_dir_in(&interface->endpoint[i].desc))
return &interface->endpoint[i].desc;
return NULL;
}
static int usbtouch_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -1447,17 +1432,21 @@ static int usbtouch_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
const struct usbtouch_device_info *type;
int err = -ENOMEM;
int err;
/* some devices are ignored */
type = (const struct usbtouch_device_info *)id->driver_info;
if (!type)
return -ENODEV;
endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
if (!endpoint)
return -ENXIO;
err = usb_find_int_in_endpoint(intf->cur_altsetting, &endpoint);
if (err) {
err = usb_find_bulk_in_endpoint(intf->cur_altsetting, &endpoint);
if (err)
return -ENXIO;
}
err = -ENOMEM;
usbtouch = kzalloc_obj(*usbtouch);
input_dev = input_allocate_device();
if (!usbtouch || !input_dev)

View File

@@ -813,56 +813,46 @@ static int wdt87xx_load_chunk(struct i2c_client *client,
return 0;
}
static int wdt87xx_do_update_firmware(struct i2c_client *client,
static int wdt87xx_do_update_firmware(struct wdt87xx_data *wdt,
const struct firmware *fw,
unsigned int chunk_id)
{
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
struct i2c_client *client = wdt->client;
int error;
error = wdt87xx_validate_firmware(wdt, fw);
if (error)
return error;
error = mutex_lock_interruptible(&wdt->fw_mutex);
if (error)
return error;
disable_irq(client->irq);
error = wdt87xx_load_chunk(client, fw, chunk_id);
if (error) {
dev_err(&client->dev,
"firmware load failed (type: %d): %d\n",
chunk_id, error);
goto out;
return error;
}
error = wdt87xx_sw_reset(client);
if (error) {
dev_err(&client->dev, "soft reset failed: %d\n", error);
goto out;
return error;
}
/* Refresh the parameters */
error = wdt87xx_get_sysparam(client, &wdt->param);
if (error)
if (error) {
dev_err(&client->dev,
"failed to refresh system parameters: %d\n", error);
out:
enable_irq(client->irq);
mutex_unlock(&wdt->fw_mutex);
return error;
}
return error ? error : 0;
return 0;
}
static int wdt87xx_update_firmware(struct device *dev,
const char *fw_name, unsigned int chunk_id)
{
struct i2c_client *client = to_i2c_client(dev);
const struct firmware *fw;
struct wdt87xx_data *wdt = i2c_get_clientdata(client);
int error;
const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fw_name, dev);
if (error) {
dev_err(&client->dev, "unable to retrieve firmware %s: %d\n",
@@ -870,11 +860,19 @@ static int wdt87xx_update_firmware(struct device *dev,
return error;
}
error = wdt87xx_do_update_firmware(client, fw, chunk_id);
error = wdt87xx_validate_firmware(wdt, fw);
if (error)
return error;
release_firmware(fw);
scoped_cond_guard(mutex_intr, return -EINTR, &wdt->fw_mutex) {
guard(disable_irq)(&client->irq);
return error ? error : 0;
error = wdt87xx_do_update_firmware(wdt, fw, chunk_id);
if (error)
return error;
}
return 0;
}
static ssize_t config_csum_show(struct device *dev,

View File

@@ -126,7 +126,7 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
int timeout = 0;
/* get codec */
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
/* When the touchscreen is not in use, we may have to power up
* the AUX ADC before we can use sample the AUX inputs->
@@ -160,7 +160,6 @@ int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
wm->codec->dig_enable(wm, false);
}
mutex_unlock(&wm->codec_mutex);
return (rc == RC_VALID ? auxval & 0xfff : -EBUSY);
}
EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
@@ -176,18 +175,11 @@ EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio)
{
u16 status;
enum wm97xx_gpio_status ret;
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
if (status & gpio)
ret = WM97XX_GPIO_HIGH;
else
ret = WM97XX_GPIO_LOW;
mutex_unlock(&wm->codec_mutex);
return ret;
return (status & gpio) ? WM97XX_GPIO_HIGH : WM97XX_GPIO_LOW;
}
EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
@@ -205,7 +197,8 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
{
u16 reg;
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
if (status == WM97XX_GPIO_HIGH)
@@ -217,7 +210,6 @@ void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
else
wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
mutex_unlock(&wm->codec_mutex);
}
EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
@@ -231,7 +223,8 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
{
u16 reg;
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
if (pol == WM97XX_GPIO_POL_HIGH)
@@ -264,7 +257,6 @@ void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
reg &= ~gpio;
wm97xx_reg_write(wm, AC97_GPIO_CFG, reg);
mutex_unlock(&wm->codec_mutex);
}
EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
@@ -303,7 +295,9 @@ static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
wm->pen_is_down = 0;
} else {
u16 status, pol;
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
@@ -323,7 +317,6 @@ static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
else
wm97xx_reg_write(wm, AC97_GPIO_STATUS, status &
~WM97XX_GPIO_13);
mutex_unlock(&wm->codec_mutex);
}
/* If the system is not using continuous mode or it provides a
@@ -382,7 +375,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
struct wm97xx_data data;
int rc;
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
if (wm->mach_ops && wm->mach_ops->acc_enabled)
rc = wm->mach_ops->acc_pen_down(wm);
@@ -422,8 +415,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
abs_y[0] > (data.y & 0xfff) ||
abs_y[1] < (data.y & 0xfff)) {
dev_dbg(wm->dev, "Measurement out of range, dropping it\n");
rc = RC_AGAIN;
goto out;
return RC_AGAIN;
}
input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
@@ -439,8 +431,6 @@ static int wm97xx_read_samples(struct wm97xx *wm)
wm->ts_reader_interval = wm->ts_reader_min_interval;
}
out:
mutex_unlock(&wm->codec_mutex);
return rc;
}
@@ -773,7 +763,8 @@ static int wm97xx_suspend(struct device *dev)
else
suspend_mode = 0;
mutex_lock(&wm->input_dev->mutex);
guard(mutex)(&wm->input_dev->mutex);
if (input_device_enabled(wm->input_dev))
cancel_delayed_work_sync(&wm->ts_reader);
@@ -791,7 +782,6 @@ static int wm97xx_suspend(struct device *dev)
reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) | 0x8000;
wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
}
mutex_unlock(&wm->input_dev->mutex);
return 0;
}
@@ -800,7 +790,8 @@ static int wm97xx_resume(struct device *dev)
{
struct wm97xx *wm = dev_get_drvdata(dev);
mutex_lock(&wm->input_dev->mutex);
guard(mutex)(&wm->input_dev->mutex);
/* restore digitiser and gpios */
if (wm->id == WM9713_ID2) {
wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
@@ -827,7 +818,6 @@ static int wm97xx_resume(struct device *dev)
queue_delayed_work(wm->ts_workq, &wm->ts_reader,
wm->ts_reader_interval);
}
mutex_unlock(&wm->input_dev->mutex);
return 0;
}
@@ -840,13 +830,12 @@ static DEFINE_SIMPLE_DEV_PM_OPS(wm97xx_pm_ops, wm97xx_suspend, wm97xx_resume);
int wm97xx_register_mach_ops(struct wm97xx *wm,
struct wm97xx_mach_ops *mach_ops)
{
mutex_lock(&wm->codec_mutex);
if (wm->mach_ops) {
mutex_unlock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
if (wm->mach_ops)
return -EINVAL;
}
wm->mach_ops = mach_ops;
mutex_unlock(&wm->codec_mutex);
return 0;
}
@@ -854,9 +843,9 @@ EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops);
void wm97xx_unregister_mach_ops(struct wm97xx *wm)
{
mutex_lock(&wm->codec_mutex);
guard(mutex)(&wm->codec_mutex);
wm->mach_ops = NULL;
mutex_unlock(&wm->codec_mutex);
}
EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);

View File

@@ -703,13 +703,11 @@ static int zinitix_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
mutex_lock(&bt541->input_dev->mutex);
guard(mutex)(&bt541->input_dev->mutex);
if (input_device_enabled(bt541->input_dev))
zinitix_stop(bt541);
mutex_unlock(&bt541->input_dev->mutex);
return 0;
}
@@ -717,16 +715,17 @@ static int zinitix_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct bt541_ts_data *bt541 = i2c_get_clientdata(client);
int ret = 0;
int error;
mutex_lock(&bt541->input_dev->mutex);
guard(mutex)(&bt541->input_dev->mutex);
if (input_device_enabled(bt541->input_dev))
ret = zinitix_start(bt541);
if (input_device_enabled(bt541->input_dev)) {
error = zinitix_start(bt541);
if (error)
return error;
}
mutex_unlock(&bt541->input_dev->mutex);
return ret;
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);

View File

@@ -517,6 +517,10 @@ INPUT_GENERATE_ABS_ACCESSORS(res, resolution)
int input_scancode_to_scalar(const struct input_keymap_entry *ke,
unsigned int *scancode);
int input_default_setkeycode(struct input_dev *dev,
const struct input_keymap_entry *ke,
unsigned int *old_keycode);
int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke);
int input_set_keycode(struct input_dev *dev,
const struct input_keymap_entry *ke);