mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-15 22:31:47 -04:00
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:
@@ -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
|
||||
|
||||
|
||||
@@ -11,7 +11,12 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: awinic,aw86927
|
||||
oneOf:
|
||||
- const: awinic,aw86927
|
||||
- items:
|
||||
- enum:
|
||||
- awinic,aw86938
|
||||
- const: awinic,aw86927
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
>;
|
||||
};
|
||||
@@ -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:
|
||||
|
||||
@@ -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" ]
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ maintainers:
|
||||
- Mattijs Korpershoek <mkorpershoek@kernel.org>
|
||||
|
||||
allOf:
|
||||
- $ref: input.yaml#
|
||||
- $ref: /schemas/input/matrix-keymap.yaml#
|
||||
|
||||
description: |
|
||||
|
||||
68
Documentation/devicetree/bindings/input/parade,tc3408.yaml
Normal file
68
Documentation/devicetree/bindings/input/parade,tc3408.yaml
Normal 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>;
|
||||
};
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -53,14 +53,14 @@ properties:
|
||||
|
||||
wakeup-source: true
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = ¶de_tc3408_chip_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 */
|
||||
{ }
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
232
drivers/input/keyboard/charlieplex_keypad.c
Normal file
232
drivers/input/keyboard/charlieplex_keypad.c
Normal 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");
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(µ->lock);
|
||||
guard(spinlock_irq)(µ->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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user