Commit bd7e8c99 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input updates from Dmitry Torokhov:

 - a new driver for ADC driven joysticks

 - a new Zintix touchscreen driver

 - enhancements to Intel SoC button array driver

 - support for F3A "function" in Synaptics RMI4 driver

 - assorted driver fixups

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (29 commits)
  Input: Add MAINTAINERS entry for SiS i2c touch input driver
  Input: evdev - per-client waitgroups
  Input: synaptics - enable InterTouch for ThinkPad T14 Gen 1
  Input: synaptics - enable InterTouch for ThinkPad P1/X1E gen 2
  Input: synaptics-rmi4 - support bootloader v8 in f34v7
  Input: synaptics-rmi4 - add support for F3A
  Input: synaptics-rmi4 - rename f30_data to gpio_data
  Input: add zinitix touchscreen driver
  dt-bindings: input/touchscreen: add bindings for zinitix
  Input: joystick - add ADC attached joystick driver.
  dt-bindings: input: Add docs for ADC driven joystick
  Input: sun4i-ps2 - fix handling of platform_get_irq() error
  Input: twl4030_keypad - fix handling of platform_get_irq() error
  Input: omap4-keypad - fix handling of platform_get_irq() error
  Input: ep93xx_keypad - fix handling of platform_get_irq() error
  Input: stmfts - fix a & vs && typo
  Input: imx6ul_tsc - unify open/close and PM paths
  Input: imx6ul_tsc - clean up some errors in imx6ul_tsc_resume()
  Input: elants_i2c - fix typo for an attribute to show calibration count
  Input: elants_i2c - report resolution of ABS_MT_TOUCH_MAJOR by FW information.
  ...
parents 40a03b75 bb0bc0cf
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
# Copyright 2019-2020 Artur Rojek
%YAML 1.2
---
$id: "http://devicetree.org/schemas/input/adc-joystick.yaml#"
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
title: ADC attached joystick
maintainers:
- Artur Rojek <contact@artur-rojek.eu>
description: >
Bindings for joystick devices connected to ADC controllers supporting
the Industrial I/O subsystem.
properties:
compatible:
const: adc-joystick
io-channels:
minItems: 1
maxItems: 1024
description: >
List of phandle and IIO specifier pairs.
Each pair defines one ADC channel to which a joystick axis is connected.
See Documentation/devicetree/bindings/iio/iio-bindings.txt for details.
'#address-cells':
const: 1
'#size-cells':
const: 0
required:
- compatible
- io-channels
- '#address-cells'
- '#size-cells'
additionalProperties: false
patternProperties:
"^axis@[0-9a-f]+$":
type: object
description: >
Represents a joystick axis bound to the given ADC channel.
For each entry in the io-channels list, one axis subnode with a matching
reg property must be specified.
properties:
reg:
minimum: 0
maximum: 1023
description: Index of an io-channels list entry bound to this axis.
linux,code:
$ref: /schemas/types.yaml#/definitions/uint32
description: EV_ABS specific event code generated by the axis.
abs-range:
allOf:
- $ref: /schemas/types.yaml#/definitions/uint32-array
- items:
- description: minimum value
- description: maximum value
description: >
Minimum and maximum values produced by the axis.
For an ABS_X axis this will be the left-most and right-most
inclination of the joystick. If min > max, it is left to userspace to
treat the axis as inverted.
This property is interpreted as two signed 32 bit values.
abs-fuzz:
$ref: /schemas/types.yaml#/definitions/uint32
description: >
Amount of noise in the input value.
Omitting this property indicates the axis is precise.
abs-flat:
$ref: /schemas/types.yaml#/definitions/uint32
description: >
Axial "deadzone", or area around the center position, where the axis
is considered to be at rest.
Omitting this property indicates the axis always returns to exactly
the center position.
required:
- reg
- linux,code
- abs-range
additionalProperties: false
examples:
- |
#include <dt-bindings/iio/adc/ingenic,adc.h>
#include <dt-bindings/input/input.h>
joystick: adc-joystick {
compatible = "adc-joystick";
io-channels = <&adc INGENIC_ADC_TOUCH_XP>,
<&adc INGENIC_ADC_TOUCH_YP>;
#address-cells = <1>;
#size-cells = <0>;
axis@0 {
reg = <0>;
linux,code = <ABS_X>;
abs-range = <3300 0>;
abs-fuzz = <4>;
abs-flat = <200>;
};
axis@1 {
reg = <1>;
linux,code = <ABS_Y>;
abs-range = <0 3300>;
abs-fuzz = <4>;
abs-flat = <200>;
};
};
Device tree bindings for Zinitx BT541 touchscreen controller
Required properties:
- compatible : Should be "zinitix,bt541"
- reg : I2C address of the chip. Should be 0x20
- interrupts : Interrupt to which the chip is connected
Optional properties:
- vdd-supply : Analog power supply regulator on VCCA pin
- vddo-supply : Digital power supply regulator on VDD pin
- zinitix,mode : Mode of reporting touch points. Some modes may not work
with a particular ts firmware for unknown reasons. Available
modes are 1 and 2. Mode 2 is the default and preferred.
The touchscreen-* properties are documented in touchscreen.txt in this
directory.
Example:
i2c@00000000 {
/* ... */
bt541@20 {
compatible = "zinitix,bt541";
reg = <0x20>;
interrupt-parent = <&msmgpio>;
interrupts = <13 IRQ_TYPE_EDGE_FALLING>;
pinctrl-names = "default";
pinctrl-0 = <&tsp_default>;
vdd-supply = <&reg_vdd_tsp>;
vddo-supply = <&pm8916_l6>;
touchscreen-size-x = <540>;
touchscreen-size-y = <960>;
zinitix,mode = <2>;
};
/* ... */
};
...@@ -1222,6 +1222,8 @@ patternProperties: ...@@ -1222,6 +1222,8 @@ patternProperties:
description: Shenzhen Zidoo Technology Co., Ltd. description: Shenzhen Zidoo Technology Co., Ltd.
"^zii,.*": "^zii,.*":
description: Zodiac Inflight Innovations description: Zodiac Inflight Innovations
"^zinitix,.*":
description: Zinitix Co., Ltd
"^zte,.*": "^zte,.*":
description: ZTE Corp. description: ZTE Corp.
"^zyxel,.*": "^zyxel,.*":
......
...@@ -16044,6 +16044,13 @@ F: Documentation/fb/sisfb.rst ...@@ -16044,6 +16044,13 @@ F: Documentation/fb/sisfb.rst
F: drivers/video/fbdev/sis/ F: drivers/video/fbdev/sis/
F: include/video/sisfb.h F: include/video/sisfb.h
SIS I2C TOUCHSCREEN DRIVER
M: Mika Penttilä <mika.penttila@nextfour.com>
L: linux-input@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/input/touchscreen/sis_i2c.txt
F: drivers/input/touchscreen/sis_i2c.c
SIS USB2VGA DRIVER SIS USB2VGA DRIVER
M: Thomas Winischhofer <thomas@winischhofer.net> M: Thomas Winischhofer <thomas@winischhofer.net>
S: Maintained S: Maintained
......
...@@ -720,7 +720,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -720,7 +720,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
} }
if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS)
rmi_hid_pdata.f30_data.disable = true; rmi_hid_pdata.gpio_data.disable = true;
data->xport.dev = hdev->dev.parent; data->xport.dev = hdev->dev.parent;
data->xport.pdata = rmi_hid_pdata; data->xport.pdata = rmi_hid_pdata;
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
struct evdev { struct evdev {
int open; int open;
struct input_handle handle; struct input_handle handle;
wait_queue_head_t wait;
struct evdev_client __rcu *grab; struct evdev_client __rcu *grab;
struct list_head client_list; struct list_head client_list;
spinlock_t client_lock; /* protects client_list */ spinlock_t client_lock; /* protects client_list */
...@@ -43,6 +42,7 @@ struct evdev_client { ...@@ -43,6 +42,7 @@ struct evdev_client {
unsigned int tail; unsigned int tail;
unsigned int packet_head; /* [future] position of the first element of next packet */ unsigned int packet_head; /* [future] position of the first element of next packet */
spinlock_t buffer_lock; /* protects access to buffer, head and tail */ spinlock_t buffer_lock; /* protects access to buffer, head and tail */
wait_queue_head_t wait;
struct fasync_struct *fasync; struct fasync_struct *fasync;
struct evdev *evdev; struct evdev *evdev;
struct list_head node; struct list_head node;
...@@ -245,7 +245,6 @@ static void evdev_pass_values(struct evdev_client *client, ...@@ -245,7 +245,6 @@ static void evdev_pass_values(struct evdev_client *client,
const struct input_value *vals, unsigned int count, const struct input_value *vals, unsigned int count,
ktime_t *ev_time) ktime_t *ev_time)
{ {
struct evdev *evdev = client->evdev;
const struct input_value *v; const struct input_value *v;
struct input_event event; struct input_event event;
struct timespec64 ts; struct timespec64 ts;
...@@ -282,7 +281,7 @@ static void evdev_pass_values(struct evdev_client *client, ...@@ -282,7 +281,7 @@ static void evdev_pass_values(struct evdev_client *client,
spin_unlock(&client->buffer_lock); spin_unlock(&client->buffer_lock);
if (wakeup) if (wakeup)
wake_up_interruptible_poll(&evdev->wait, wake_up_interruptible_poll(&client->wait,
EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM); EPOLLIN | EPOLLOUT | EPOLLRDNORM | EPOLLWRNORM);
} }
...@@ -426,11 +425,11 @@ static void evdev_hangup(struct evdev *evdev) ...@@ -426,11 +425,11 @@ static void evdev_hangup(struct evdev *evdev)
struct evdev_client *client; struct evdev_client *client;
spin_lock(&evdev->client_lock); spin_lock(&evdev->client_lock);
list_for_each_entry(client, &evdev->client_list, node) list_for_each_entry(client, &evdev->client_list, node) {
kill_fasync(&client->fasync, SIGIO, POLL_HUP); kill_fasync(&client->fasync, SIGIO, POLL_HUP);
wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
}
spin_unlock(&evdev->client_lock); spin_unlock(&evdev->client_lock);
wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR);
} }
static int evdev_release(struct inode *inode, struct file *file) static int evdev_release(struct inode *inode, struct file *file)
...@@ -479,6 +478,7 @@ static int evdev_open(struct inode *inode, struct file *file) ...@@ -479,6 +478,7 @@ static int evdev_open(struct inode *inode, struct file *file)
if (!client) if (!client)
return -ENOMEM; return -ENOMEM;
init_waitqueue_head(&client->wait);
client->bufsize = bufsize; client->bufsize = bufsize;
spin_lock_init(&client->buffer_lock); spin_lock_init(&client->buffer_lock);
client->evdev = evdev; client->evdev = evdev;
...@@ -595,7 +595,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer, ...@@ -595,7 +595,7 @@ static ssize_t evdev_read(struct file *file, char __user *buffer,
break; break;
if (!(file->f_flags & O_NONBLOCK)) { if (!(file->f_flags & O_NONBLOCK)) {
error = wait_event_interruptible(evdev->wait, error = wait_event_interruptible(client->wait,
client->packet_head != client->tail || client->packet_head != client->tail ||
!evdev->exist || client->revoked); !evdev->exist || client->revoked);
if (error) if (error)
...@@ -613,7 +613,7 @@ static __poll_t evdev_poll(struct file *file, poll_table *wait) ...@@ -613,7 +613,7 @@ static __poll_t evdev_poll(struct file *file, poll_table *wait)
struct evdev *evdev = client->evdev; struct evdev *evdev = client->evdev;
__poll_t mask; __poll_t mask;
poll_wait(file, &evdev->wait, wait); poll_wait(file, &client->wait, wait);
if (evdev->exist && !client->revoked) if (evdev->exist && !client->revoked)
mask = EPOLLOUT | EPOLLWRNORM; mask = EPOLLOUT | EPOLLWRNORM;
...@@ -946,7 +946,7 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client, ...@@ -946,7 +946,7 @@ static int evdev_revoke(struct evdev *evdev, struct evdev_client *client,
client->revoked = true; client->revoked = true;
evdev_ungrab(evdev, client); evdev_ungrab(evdev, client);
input_flush_device(&evdev->handle, file); input_flush_device(&evdev->handle, file);
wake_up_interruptible_poll(&evdev->wait, EPOLLHUP | EPOLLERR); wake_up_interruptible_poll(&client->wait, EPOLLHUP | EPOLLERR);
return 0; return 0;
} }
...@@ -1358,7 +1358,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev, ...@@ -1358,7 +1358,6 @@ static int evdev_connect(struct input_handler *handler, struct input_dev *dev,
INIT_LIST_HEAD(&evdev->client_list); INIT_LIST_HEAD(&evdev->client_list);
spin_lock_init(&evdev->client_lock); spin_lock_init(&evdev->client_lock);
mutex_init(&evdev->mutex); mutex_init(&evdev->mutex);
init_waitqueue_head(&evdev->wait);
evdev->exist = true; evdev->exist = true;
dev_no = minor; dev_no = minor;
......
...@@ -323,11 +323,14 @@ static int adjust_dual(int *begin, int step, int *end, int eq, int mu) ...@@ -323,11 +323,14 @@ static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
p = begin + step; p = begin + step;
s = p == end ? f + 1 : *p; s = p == end ? f + 1 : *p;
for (; p != end; p += step) for (; p != end; p += step) {
if (*p < f) if (*p < f) {
s = f, f = *p; s = f;
else if (*p < s) f = *p;
} else if (*p < s) {
s = *p; s = *p;
}
}
c = (f + s + 1) / 2; c = (f + s + 1) / 2;
if (c == 0 || (c > mu && (!eq || mu > 0))) if (c == 0 || (c > mu && (!eq || mu > 0)))
......
...@@ -42,6 +42,16 @@ config JOYSTICK_A3D ...@@ -42,6 +42,16 @@ config JOYSTICK_A3D
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called a3d. module will be called a3d.
config JOYSTICK_ADC
tristate "Simple joystick connected over ADC"
depends on IIO
select IIO_BUFFER_CB
help
Say Y here if you have a simple joystick connected over ADC.
To compile this driver as a module, choose M here: the
module will be called adc-joystick.
config JOYSTICK_ADI config JOYSTICK_ADI
tristate "Logitech ADI digital joysticks and gamepads" tristate "Logitech ADI digital joysticks and gamepads"
select GAMEPORT select GAMEPORT
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
# Each configuration option enables a list of files. # Each configuration option enables a list of files.
obj-$(CONFIG_JOYSTICK_A3D) += a3d.o obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
obj-$(CONFIG_JOYSTICK_ADC) += adc-joystick.o
obj-$(CONFIG_JOYSTICK_ADI) += adi.o obj-$(CONFIG_JOYSTICK_ADI) += adi.o
obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o
obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o obj-$(CONFIG_JOYSTICK_AS5011) += as5011.o
......
// SPDX-License-Identifier: GPL-2.0
/*
* Input driver for joysticks connected over ADC.
* Copyright (c) 2019-2020 Artur Rojek <contact@artur-rojek.eu>
*/
#include <linux/ctype.h>
#include <linux/input.h>
#include <linux/iio/iio.h>
#include <linux/iio/consumer.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <asm/unaligned.h>
struct adc_joystick_axis {
u32 code;
s32 range[2];
s32 fuzz;
s32 flat;
};
struct adc_joystick {
struct input_dev *input;
struct iio_cb_buffer *buffer;
struct adc_joystick_axis *axes;
struct iio_channel *chans;
int num_chans;
};
static int adc_joystick_handle(const void *data, void *private)
{
struct adc_joystick *joy = private;
enum iio_endian endianness;
int bytes, msb, val, idx, i;
const u16 *data_u16;
bool sign;
bytes = joy->chans[0].channel->scan_type.storagebits >> 3;
for (i = 0; i < joy->num_chans; ++i) {
idx = joy->chans[i].channel->scan_index;
endianness = joy->chans[i].channel->scan_type.endianness;
msb = joy->chans[i].channel->scan_type.realbits - 1;
sign = tolower(joy->chans[i].channel->scan_type.sign) == 's';
switch (bytes) {
case 1:
val = ((const u8 *)data)[idx];
break;
case 2:
data_u16 = (const u16 *)data + idx;
/*
* Data is aligned to the sample size by IIO core.
* Call `get_unaligned_xe16` to hide type casting.
*/
if (endianness == IIO_BE)
val = get_unaligned_be16(data_u16);
else if (endianness == IIO_LE)
val = get_unaligned_le16(data_u16);
else /* IIO_CPU */
val = *data_u16;
break;
default:
return -EINVAL;
}
val >>= joy->chans[i].channel->scan_type.shift;
if (sign)
val = sign_extend32(val, msb);
else
val &= GENMASK(msb, 0);
input_report_abs(joy->input, joy->axes[i].code, val);
}
input_sync(joy->input);
return 0;
}
static int adc_joystick_open(struct input_dev *dev)
{
struct adc_joystick *joy = input_get_drvdata(dev);
struct device *devp = &dev->dev;
int ret;
ret = iio_channel_start_all_cb(joy->buffer);
if (ret)
dev_err(devp, "Unable to start callback buffer: %d\n", ret);
return ret;
}
static void adc_joystick_close(struct input_dev *dev)
{
struct adc_joystick *joy = input_get_drvdata(dev);
iio_channel_stop_all_cb(joy->buffer);
}
static void adc_joystick_cleanup(void *data)
{
iio_channel_release_all_cb(data);
}
static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
{
struct adc_joystick_axis *axes;
struct fwnode_handle *child;
int num_axes, error, i;
num_axes = device_get_child_node_count(dev);
if (!num_axes) {
dev_err(dev, "Unable to find child nodes\n");
return -EINVAL;
}
if (num_axes != joy->num_chans) {
dev_err(dev, "Got %d child nodes for %d channels\n",
num_axes, joy->num_chans);
return -EINVAL;
}
axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
if (!axes)
return -ENOMEM;
device_for_each_child_node(dev, child) {
error = fwnode_property_read_u32(child, "reg", &i);
if (error) {
dev_err(dev, "reg invalid or missing\n");
goto err_fwnode_put;
}
if (i >= num_axes) {
error = -EINVAL;
dev_err(dev, "No matching axis for reg %d\n", i);
goto err_fwnode_put;
}
error = fwnode_property_read_u32(child, "linux,code",
&axes[i].code);
if (error) {
dev_err(dev, "linux,code invalid or missing\n");
goto err_fwnode_put;
}
error = fwnode_property_read_u32_array(child, "abs-range",
axes[i].range, 2);
if (error) {
dev_err(dev, "abs-range invalid or missing\n");
goto err_fwnode_put;
}
fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
input_set_abs_params(joy->input, axes[i].code,
axes[i].range[0], axes[i].range[1],
axes[i].fuzz, axes[i].flat);
input_set_capability(joy->input, EV_ABS, axes[i].code);
}
joy->axes = axes;
return 0;
err_fwnode_put:
fwnode_handle_put(child);
return error;
}
static int adc_joystick_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct adc_joystick *joy;
struct input_dev *input;
int error;
int bits;
int i;
joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
if (!joy)
return -ENOMEM;
joy->chans = devm_iio_channel_get_all(dev);
if (IS_ERR(joy->chans)) {
error = PTR_ERR(joy->chans);
if (error != -EPROBE_DEFER)
dev_err(dev, "Unable to get IIO channels");
return error;
}
/* Count how many channels we got. NULL terminated. */
for (i = 0; joy->chans[i].indio_dev; i++) {
bits = joy->chans[i].channel->scan_type.storagebits;
if (!bits || bits > 16) {
dev_err(dev, "Unsupported channel storage size\n");
return -EINVAL;
}
if (bits != joy->chans[0].channel->scan_type.storagebits) {
dev_err(dev, "Channels must have equal storage size\n");
return -EINVAL;
}
}
joy->num_chans = i;
input = devm_input_allocate_device(dev);
if (!input) {
dev_err(dev, "Unable to allocate input device\n");
return -ENOMEM;
}
joy->input = input;
input->name = pdev->name;
input->id.bustype = BUS_HOST;
input->open = adc_joystick_open;
input->close = adc_joystick_close;
error = adc_joystick_set_axes(dev, joy);
if (error)
return error;
input_set_drvdata(input, joy);
error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device\n");
return error;
}
joy->buffer = iio_channel_get_all_cb(dev, adc_joystick_handle, joy);
if (IS_ERR(joy->buffer)) {
dev_err(dev, "Unable to allocate callback buffer\n");
return PTR_ERR(joy->buffer);
}
error = devm_add_action_or_reset(dev, adc_joystick_cleanup, joy->buffer);
if (error) {
dev_err(dev, "Unable to add action\n");
return error;
}
return 0;
}
static const struct of_device_id adc_joystick_of_match[] = {
{ .compatible = "adc-joystick", },
{ }
};
MODULE_DEVICE_TABLE(of, adc_joystick_of_match);
static struct platform_driver adc_joystick_driver = {
.driver = {
.name = "adc-joystick",
.of_match_table = adc_joystick_of_match,
},
.probe = adc_joystick_probe,
};
module_platform_driver(adc_joystick_driver);
MODULE_DESCRIPTION("Input driver for joysticks connected over ADC");
MODULE_AUTHOR("Artur Rojek <contact@artur-rojek.eu>");
MODULE_LICENSE("GPL");
...@@ -250,8 +250,8 @@ static int ep93xx_keypad_probe(struct platform_device *pdev) ...@@ -250,8 +250,8 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
} }
keypad->irq = platform_get_irq(pdev, 0); keypad->irq = platform_get_irq(pdev, 0);
if (!keypad->irq) { if (keypad->irq < 0) {
err = -ENXIO; err = keypad->irq;
goto failed_free; goto failed_free;
} }
......
...@@ -240,10 +240,8 @@ static int omap4_keypad_probe(struct platform_device *pdev) ...@@ -240,10 +240,8 @@ static int omap4_keypad_probe(struct platform_device *pdev)
} }
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (!irq) { if (irq < 0)
dev_err(&pdev->dev, "no keyboard irq assigned\n"); return irq;
return -EINVAL;
}
keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL); keypad_data = kzalloc(sizeof(struct omap4_keypad), GFP_KERNEL);
if (!keypad_data) { if (!keypad_data) {
......
...@@ -50,7 +50,7 @@ struct twl4030_keypad { ...@@ -50,7 +50,7 @@ struct twl4030_keypad {
bool autorepeat; bool autorepeat;
unsigned int n_rows; unsigned int n_rows;
unsigned int n_cols; unsigned int n_cols;
unsigned int irq; int irq;
struct device *dbg_dev; struct device *dbg_dev;
struct input_dev *input; struct input_dev *input;
...@@ -376,10 +376,8 @@ static int twl4030_kp_probe(struct platform_device *pdev) ...@@ -376,10 +376,8 @@ static int twl4030_kp_probe(struct platform_device *pdev)
} }
kp->irq = platform_get_irq(pdev, 0); kp->irq = platform_get_irq(pdev, 0);
if (!kp->irq) { if (kp->irq < 0)
dev_err(&pdev->dev, "no keyboard irq assigned\n"); return kp->irq;
return -EINVAL;
}
error = matrix_keypad_build_keymap(keymap_data, NULL, error = matrix_keypad_build_keymap(keymap_data, NULL,
TWL4030_MAX_ROWS, TWL4030_MAX_ROWS,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/gpio.h> #include <linux/gpio.h>
...@@ -23,6 +24,7 @@ struct soc_button_info { ...@@ -23,6 +24,7 @@ struct soc_button_info {
unsigned int event_code; unsigned int event_code;
bool autorepeat; bool autorepeat;
bool wakeup; bool wakeup;
bool active_low;
}; };
struct soc_device_data { struct soc_device_data {
...@@ -41,23 +43,66 @@ struct soc_button_data { ...@@ -41,23 +43,66 @@ struct soc_button_data {
struct platform_device *children[BUTTON_TYPES]; struct platform_device *children[BUTTON_TYPES];
}; };
/*
* Some 2-in-1s which use the soc_button_array driver have this ugly issue in
* their DSDT where the _LID method modifies the irq-type settings of the GPIOs
* used for the power and home buttons. The intend of this AML code is to
* disable these buttons when the lid is closed.
* The AML does this by directly poking the GPIO controllers registers. This is
* problematic because when re-enabling the irq, which happens whenever _LID
* gets called with the lid open (e.g. on boot and on resume), it sets the
* irq-type to IRQ_TYPE_LEVEL_LOW. Where as the gpio-keys driver programs the
* type to, and expects it to be, IRQ_TYPE_EDGE_BOTH.
* To work around this we don't set gpio_keys_button.gpio on these 2-in-1s,
* instead we get the irq for the GPIO ourselves, configure it as
* IRQ_TYPE_LEVEL_LOW (to match how the _LID AML code configures it) and pass
* the irq in gpio_keys_button.irq. Below is a list of affected devices.
*/
static const struct dmi_system_id dmi_use_low_level_irq[] = {
{
/*
* Acer Switch 10 SW5-012. _LID method messes with home- and
* power-button GPIO IRQ settings. When (re-)enabling the irq
* it ors in its own flags without clearing the previous set
* ones, leading to an irq-type of IRQ_TYPE_LEVEL_LOW |
* IRQ_TYPE_LEVEL_HIGH causing a continuous interrupt storm.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire SW5-012"),
},
},
{
/*
* Acer One S1003. _LID method messes with power-button GPIO
* IRQ settings, leading to a non working power-button.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "One S1003"),
},
},
{} /* Terminating entry */
};
/* /*
* Get the Nth GPIO number from the ACPI object. * Get the Nth GPIO number from the ACPI object.
*/ */
static int soc_button_lookup_gpio(struct device *dev, int acpi_index) static int soc_button_lookup_gpio(struct device *dev, int acpi_index,
int *gpio_ret, int *irq_ret)
{ {
struct gpio_desc *desc; struct gpio_desc *desc;
int gpio;
desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS); desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS);
if (IS_ERR(desc)) if (IS_ERR(desc))
return PTR_ERR(desc); return PTR_ERR(desc);
gpio = desc_to_gpio(desc); *gpio_ret = desc_to_gpio(desc);
*irq_ret = gpiod_to_irq(desc);
gpiod_put(desc); gpiod_put(desc);
return gpio; return 0;
} }
static struct platform_device * static struct platform_device *
...@@ -69,9 +114,8 @@ soc_button_device_create(struct platform_device *pdev, ...@@ -69,9 +114,8 @@ soc_button_device_create(struct platform_device *pdev,
struct platform_device *pd; struct platform_device *pd;
struct gpio_keys_button *gpio_keys; struct gpio_keys_button *gpio_keys;
struct gpio_keys_platform_data *gpio_keys_pdata; struct gpio_keys_platform_data *gpio_keys_pdata;
int error, gpio, irq;
int n_buttons = 0; int n_buttons = 0;
int gpio;
int error;
for (info = button_info; info->name; info++) for (info = button_info; info->name; info++)
if (info->autorepeat == autorepeat) if (info->autorepeat == autorepeat)
...@@ -91,8 +135,8 @@ soc_button_device_create(struct platform_device *pdev, ...@@ -91,8 +135,8 @@ soc_button_device_create(struct platform_device *pdev,
if (info->autorepeat != autorepeat) if (info->autorepeat != autorepeat)
continue; continue;
gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
if (!gpio_is_valid(gpio)) { if (error || irq < 0) {
/* /*
* Skip GPIO if not present. Note we deliberately * Skip GPIO if not present. Note we deliberately
* ignore -EPROBE_DEFER errors here. On some devices * ignore -EPROBE_DEFER errors here. On some devices
...@@ -107,10 +151,18 @@ soc_button_device_create(struct platform_device *pdev, ...@@ -107,10 +151,18 @@ soc_button_device_create(struct platform_device *pdev,
continue; continue;
} }
/* See dmi_use_low_level_irq[] comment */
if (!autorepeat && dmi_check_system(dmi_use_low_level_irq)) {
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
gpio_keys[n_buttons].irq = irq;
gpio_keys[n_buttons].gpio = -ENOENT;
} else {
gpio_keys[n_buttons].gpio = gpio;
}
gpio_keys[n_buttons].type = info->event_type; gpio_keys[n_buttons].type = info->event_type;
gpio_keys[n_buttons].code = info->event_code; gpio_keys[n_buttons].code = info->event_code;
gpio_keys[n_buttons].gpio = gpio; gpio_keys[n_buttons].active_low = info->active_low;
gpio_keys[n_buttons].active_low = 1;
gpio_keys[n_buttons].desc = info->name; gpio_keys[n_buttons].desc = info->name;
gpio_keys[n_buttons].wakeup = info->wakeup; gpio_keys[n_buttons].wakeup = info->wakeup;
/* These devices often use cheap buttons, use 50 ms debounce */ /* These devices often use cheap buttons, use 50 ms debounce */
...@@ -173,6 +225,7 @@ static int soc_button_parse_btn_desc(struct device *dev, ...@@ -173,6 +225,7 @@ static int soc_button_parse_btn_desc(struct device *dev,
} }
info->event_type = EV_KEY; info->event_type = EV_KEY;
info->active_low = true;
info->acpi_index = info->acpi_index =
soc_button_get_acpi_object_int(&desc->package.elements[1]); soc_button_get_acpi_object_int(&desc->package.elements[1]);
upage = soc_button_get_acpi_object_int(&desc->package.elements[3]); upage = soc_button_get_acpi_object_int(&desc->package.elements[3]);
...@@ -383,11 +436,11 @@ static int soc_button_probe(struct platform_device *pdev) ...@@ -383,11 +436,11 @@ static int soc_button_probe(struct platform_device *pdev)
* Platforms" * Platforms"
*/ */
static const struct soc_button_info soc_button_PNP0C40[] = { static const struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true }, { "power", 0, EV_KEY, KEY_POWER, false, true, true },
{ "home", 1, EV_KEY, KEY_LEFTMETA, false, true }, { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false }, { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
{ "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false }, { "rotation_lock", 4, EV_KEY, KEY_ROTATE_LOCK_TOGGLE, false, false, true },
{ } { }
}; };
...@@ -395,6 +448,15 @@ static const struct soc_device_data soc_device_PNP0C40 = { ...@@ -395,6 +448,15 @@ static const struct soc_device_data soc_device_PNP0C40 = {
.button_info = soc_button_PNP0C40, .button_info = soc_button_PNP0C40,
}; };
static const struct soc_button_info soc_button_INT33D3[] = {
{ "tablet_mode", 0, EV_SW, SW_TABLET_MODE, false, false, false },
{ }
};
static const struct soc_device_data soc_device_INT33D3 = {
.button_info = soc_button_INT33D3,
};
/* /*
* Special device check for Surface Book 2 and Surface Pro (2017). * Special device check for Surface Book 2 and Surface Pro (2017).
* Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned * Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
...@@ -444,9 +506,9 @@ static int soc_device_check_MSHW0040(struct device *dev) ...@@ -444,9 +506,9 @@ static int soc_device_check_MSHW0040(struct device *dev)
* Obtained from DSDT/testing. * Obtained from DSDT/testing.
*/ */
static const struct soc_button_info soc_button_MSHW0040[] = { static const struct soc_button_info soc_button_MSHW0040[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true }, { "power", 0, EV_KEY, KEY_POWER, false, true, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false }, { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
{ "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false }, { "volume_down", 4, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
{ } { }
}; };
...@@ -457,6 +519,8 @@ static const struct soc_device_data soc_device_MSHW0040 = { ...@@ -457,6 +519,8 @@ static const struct soc_device_data soc_device_MSHW0040 = {
static const struct acpi_device_id soc_button_acpi_match[] = { static const struct acpi_device_id soc_button_acpi_match[] = {
{ "PNP0C40", (unsigned long)&soc_device_PNP0C40 }, { "PNP0C40", (unsigned long)&soc_device_PNP0C40 },
{ "INT33D3", (unsigned long)&soc_device_INT33D3 },
{ "ID9001", (unsigned long)&soc_device_INT33D3 },
{ "ACPI0011", 0 }, { "ACPI0011", 0 },
/* Microsoft Surface Devices (5th and 6th generation) */ /* Microsoft Surface Devices (5th and 6th generation) */
......
...@@ -179,12 +179,14 @@ static const char * const smbus_pnp_ids[] = { ...@@ -179,12 +179,14 @@ static const char * const smbus_pnp_ids[] = {
"LEN0093", /* T480 */ "LEN0093", /* T480 */
"LEN0096", /* X280 */ "LEN0096", /* X280 */
"LEN0097", /* X280 -> ALPS trackpoint */ "LEN0097", /* X280 -> ALPS trackpoint */
"LEN0099", /* X1 Extreme 1st */ "LEN0099", /* X1 Extreme Gen 1 / P1 Gen 1 */
"LEN009b", /* T580 */ "LEN009b", /* T580 */
"LEN0402", /* X1 Extreme Gen 2 / P1 Gen 2 */
"LEN200f", /* T450s */ "LEN200f", /* T450s */
"LEN2044", /* L470 */ "LEN2044", /* L470 */
"LEN2054", /* E480 */ "LEN2054", /* E480 */
"LEN2055", /* E580 */ "LEN2055", /* E580 */
"LEN2068", /* T14 Gen 1 */
"SYN3052", /* HP EliteBook 840 G4 */ "SYN3052", /* HP EliteBook 840 G4 */
"SYN3221", /* HP 15-ay000 */ "SYN3221", /* HP 15-ay000 */
"SYN323d", /* HP Spectre X360 13-w013dx */ "SYN323d", /* HP Spectre X360 13-w013dx */
...@@ -1752,7 +1754,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse, ...@@ -1752,7 +1754,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse,
.kernel_tracking = false, .kernel_tracking = false,
.topbuttonpad = topbuttonpad, .topbuttonpad = topbuttonpad,
}, },
.f30_data = { .gpio_data = {
.buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c), .buttonpad = SYN_CAP_CLICKPAD(info->ext_cap_0c),
.trackstick_buttons = .trackstick_buttons =
!!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10), !!SYN_CAP_EXT_BUTTONS_STICK(info->ext_cap_10),
......
...@@ -100,6 +100,14 @@ config RMI4_F34 ...@@ -100,6 +100,14 @@ config RMI4_F34
device via the firmware loader interface. This is triggered using a device via the firmware loader interface. This is triggered using a
sysfs attribute. sysfs attribute.
config RMI4_F3A
bool "RMI4 Function 3A (GPIO)"
help
Say Y here if you want to add support for RMI4 function 3A.
Function 3A provides GPIO support for RMI4 devices. This includes
support for buttons on TouchPads and ClickPads.
config RMI4_F54 config RMI4_F54
bool "RMI4 Function 54 (Analog diagnostics)" bool "RMI4 Function 54 (Analog diagnostics)"
depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m) depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m)
......
...@@ -10,6 +10,7 @@ rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o ...@@ -10,6 +10,7 @@ rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o
rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o
rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o
......
...@@ -365,6 +365,9 @@ static struct rmi_function_handler *fn_handlers[] = { ...@@ -365,6 +365,9 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F34 #ifdef CONFIG_RMI4_F34
&rmi_f34_handler, &rmi_f34_handler,
#endif #endif
#ifdef CONFIG_RMI4_F3A
&rmi_f3a_handler,
#endif
#ifdef CONFIG_RMI4_F54 #ifdef CONFIG_RMI4_F54
&rmi_f54_handler, &rmi_f54_handler,
#endif #endif
......
...@@ -135,6 +135,7 @@ extern struct rmi_function_handler rmi_f11_handler; ...@@ -135,6 +135,7 @@ extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler; extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_handler; extern struct rmi_function_handler rmi_f30_handler;
extern struct rmi_function_handler rmi_f34_handler; extern struct rmi_function_handler rmi_f34_handler;
extern struct rmi_function_handler rmi_f3a_handler;
extern struct rmi_function_handler rmi_f54_handler; extern struct rmi_function_handler rmi_f54_handler;
extern struct rmi_function_handler rmi_f55_handler; extern struct rmi_function_handler rmi_f55_handler;
#endif #endif
...@@ -168,17 +168,17 @@ static int rmi_f30_config(struct rmi_function *fn) ...@@ -168,17 +168,17 @@ static int rmi_f30_config(struct rmi_function *fn)
rmi_get_platform_data(fn->rmi_dev); rmi_get_platform_data(fn->rmi_dev);
int error; int error;
/* can happen if f30_data.disable is set */ /* can happen if gpio_data.disable is set */
if (!f30) if (!f30)
return 0; return 0;
if (pdata->f30_data.trackstick_buttons) { if (pdata->gpio_data.trackstick_buttons) {
/* Try [re-]establish link to F03. */ /* Try [re-]establish link to F03. */
f30->f03 = rmi_find_function(fn->rmi_dev, 0x03); f30->f03 = rmi_find_function(fn->rmi_dev, 0x03);
f30->trackstick_buttons = f30->f03 != NULL; f30->trackstick_buttons = f30->f03 != NULL;
} }
if (pdata->f30_data.disable) { if (pdata->gpio_data.disable) {
drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask); drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
} else { } else {
/* Write Control Register values back to device */ /* Write Control Register values back to device */
...@@ -245,10 +245,10 @@ static int rmi_f30_map_gpios(struct rmi_function *fn, ...@@ -245,10 +245,10 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
if (!rmi_f30_is_valid_button(i, f30->ctrl)) if (!rmi_f30_is_valid_button(i, f30->ctrl))
continue; continue;
if (pdata->f30_data.trackstick_buttons && if (pdata->gpio_data.trackstick_buttons &&
i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) { i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) {
f30->gpioled_key_map[i] = trackstick_button++; f30->gpioled_key_map[i] = trackstick_button++;
} else if (!pdata->f30_data.buttonpad || !button_mapped) { } else if (!pdata->gpio_data.buttonpad || !button_mapped) {
f30->gpioled_key_map[i] = button; f30->gpioled_key_map[i] = button;
input_set_capability(input, EV_KEY, button++); input_set_capability(input, EV_KEY, button++);
button_mapped = true; button_mapped = true;
...@@ -264,7 +264,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn, ...@@ -264,7 +264,7 @@ static int rmi_f30_map_gpios(struct rmi_function *fn,
* but I am not sure, so use only the pdata info and the number of * but I am not sure, so use only the pdata info and the number of
* mapped buttons. * mapped buttons.
*/ */
if (pdata->f30_data.buttonpad || (button - BTN_LEFT == 1)) if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1))
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit); __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
return 0; return 0;
...@@ -372,7 +372,7 @@ static int rmi_f30_probe(struct rmi_function *fn) ...@@ -372,7 +372,7 @@ static int rmi_f30_probe(struct rmi_function *fn)
struct f30_data *f30; struct f30_data *f30;
int error; int error;
if (pdata->f30_data.disable) if (pdata->gpio_data.disable)
return 0; return 0;
if (!drv_data->input) { if (!drv_data->input) {
......
...@@ -1364,9 +1364,14 @@ int rmi_f34v7_probe(struct f34_data *f34) ...@@ -1364,9 +1364,14 @@ int rmi_f34v7_probe(struct f34_data *f34)
f34->bl_version = 6; f34->bl_version = 6;
} else if (f34->bootloader_id[1] == 7) { } else if (f34->bootloader_id[1] == 7) {
f34->bl_version = 7; f34->bl_version = 7;
} else if (f34->bootloader_id[1] == 8) {
f34->bl_version = 8;
} else { } else {
dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n", dev_err(&f34->fn->dev,
__func__); "%s: Unrecognized bootloader version: %d (%c) %d (%c)\n",
__func__,
f34->bootloader_id[0], f34->bootloader_id[0],
f34->bootloader_id[1], f34->bootloader_id[1]);
return -EINVAL; return -EINVAL;
} }
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2012-2020 Synaptics Incorporated
*/
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/input.h>
#include <linux/slab.h>
#include "rmi_driver.h"
#define RMI_F3A_MAX_GPIO_COUNT 128
#define RMI_F3A_MAX_REG_SIZE DIV_ROUND_UP(RMI_F3A_MAX_GPIO_COUNT, 8)
/* Defs for Query 0 */
#define RMI_F3A_GPIO_COUNT 0x7F
#define RMI_F3A_DATA_REGS_MAX_SIZE RMI_F3A_MAX_REG_SIZE
#define TRACKSTICK_RANGE_START 3
#define TRACKSTICK_RANGE_END 6
struct f3a_data {
/* Query Data */
u8 gpio_count;
u8 register_count;
u8 data_regs[RMI_F3A_DATA_REGS_MAX_SIZE];
u16 *gpio_key_map;
struct input_dev *input;
struct rmi_function *f03;
bool trackstick_buttons;
};
static void rmi_f3a_report_button(struct rmi_function *fn,
struct f3a_data *f3a, unsigned int button)
{
u16 key_code = f3a->gpio_key_map[button];
bool key_down = !(f3a->data_regs[0] & BIT(button));
if (f3a->trackstick_buttons &&
button >= TRACKSTICK_RANGE_START &&
button <= TRACKSTICK_RANGE_END) {
rmi_f03_overwrite_button(f3a->f03, key_code, key_down);
} else {
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
"%s: call input report key (0x%04x) value (0x%02x)",
__func__, key_code, key_down);
input_report_key(f3a->input, key_code, key_down);
}
}
static irqreturn_t rmi_f3a_attention(int irq, void *ctx)
{
struct rmi_function *fn = ctx;
struct f3a_data *f3a = dev_get_drvdata(&fn->dev);
struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
int error;
int i;
if (drvdata->attn_data.data) {
if (drvdata->attn_data.size < f3a->register_count) {
dev_warn(&fn->dev,
"F3A interrupted, but data is missing\n");
return IRQ_HANDLED;
}
memcpy(f3a->data_regs, drvdata->attn_data.data,
f3a->register_count);
drvdata->attn_data.data += f3a->register_count;
drvdata->attn_data.size -= f3a->register_count;
} else {
error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
f3a->data_regs, f3a->register_count);
if (error) {
dev_err(&fn->dev,
"%s: Failed to read F3a data registers: %d\n",
__func__, error);
return IRQ_RETVAL(error);
}
}
for (i = 0; i < f3a->gpio_count; i++)
if (f3a->gpio_key_map[i] != KEY_RESERVED)
rmi_f3a_report_button(fn, f3a, i);
if (f3a->trackstick_buttons)
rmi_f03_commit_buttons(f3a->f03);
return IRQ_HANDLED;
}
static int rmi_f3a_config(struct rmi_function *fn)
{
struct f3a_data *f3a = dev_get_drvdata(&fn->dev);
struct rmi_driver *drv = fn->rmi_dev->driver;
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
if (!f3a)
return 0;
if (pdata->gpio_data.trackstick_buttons) {
/* Try [re-]establish link to F03. */
f3a->f03 = rmi_find_function(fn->rmi_dev, 0x03);
f3a->trackstick_buttons = f3a->f03 != NULL;
}
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
return 0;
}
static bool rmi_f3a_is_valid_button(int button, struct f3a_data *f3a,
u8 *query1_regs, u8 *ctrl1_regs)
{
/* gpio exist && direction input */
return (query1_regs[0] & BIT(button)) && !(ctrl1_regs[0] & BIT(button));
}
static int rmi_f3a_map_gpios(struct rmi_function *fn, struct f3a_data *f3a,
u8 *query1_regs, u8 *ctrl1_regs)
{
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
struct input_dev *input = f3a->input;
unsigned int button = BTN_LEFT;
unsigned int trackstick_button = BTN_LEFT;
bool button_mapped = false;
int i;
int button_count = min_t(u8, f3a->gpio_count, TRACKSTICK_RANGE_END);
f3a->gpio_key_map = devm_kcalloc(&fn->dev,
button_count,
sizeof(f3a->gpio_key_map[0]),
GFP_KERNEL);
if (!f3a->gpio_key_map) {
dev_err(&fn->dev, "Failed to allocate gpio map memory.\n");
return -ENOMEM;
}
for (i = 0; i < button_count; i++) {
if (!rmi_f3a_is_valid_button(i, f3a, query1_regs, ctrl1_regs))
continue;
if (pdata->gpio_data.trackstick_buttons &&
i >= TRACKSTICK_RANGE_START &&
i < TRACKSTICK_RANGE_END) {
f3a->gpio_key_map[i] = trackstick_button++;
} else if (!pdata->gpio_data.buttonpad || !button_mapped) {
f3a->gpio_key_map[i] = button;
input_set_capability(input, EV_KEY, button++);
button_mapped = true;
}
}
input->keycode = f3a->gpio_key_map;
input->keycodesize = sizeof(f3a->gpio_key_map[0]);
input->keycodemax = f3a->gpio_count;
if (pdata->gpio_data.buttonpad || (button - BTN_LEFT == 1))
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
return 0;
}
static int rmi_f3a_initialize(struct rmi_function *fn, struct f3a_data *f3a)
{
u8 query1[RMI_F3A_MAX_REG_SIZE];
u8 ctrl1[RMI_F3A_MAX_REG_SIZE];
u8 buf;
int error;
error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &buf);
if (error < 0) {
dev_err(&fn->dev, "Failed to read general info register: %d\n",
error);
return -ENODEV;
}
f3a->gpio_count = buf & RMI_F3A_GPIO_COUNT;
f3a->register_count = DIV_ROUND_UP(f3a->gpio_count, 8);
/* Query1 -> gpio exist */
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
query1, f3a->register_count);
if (error) {
dev_err(&fn->dev, "Failed to read query1 register\n");
return error;
}
/* Ctrl1 -> gpio direction */
error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr + 1,
ctrl1, f3a->register_count);
if (error) {
dev_err(&fn->dev, "Failed to read control1 register\n");
return error;
}
error = rmi_f3a_map_gpios(fn, f3a, query1, ctrl1);
if (error)
return error;
return 0;
}
static int rmi_f3a_probe(struct rmi_function *fn)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
struct f3a_data *f3a;
int error;
if (!drv_data->input) {
dev_info(&fn->dev, "F3A: no input device found, ignoring\n");
return -ENXIO;
}
f3a = devm_kzalloc(&fn->dev, sizeof(*f3a), GFP_KERNEL);
if (!f3a)
return -ENOMEM;
f3a->input = drv_data->input;
error = rmi_f3a_initialize(fn, f3a);
if (error)
return error;
dev_set_drvdata(&fn->dev, f3a);
return 0;
}
struct rmi_function_handler rmi_f3a_handler = {
.driver = {
.name = "rmi4_f3a",
},
.func = 0x3a,
.probe = rmi_f3a_probe,
.config = rmi_f3a_config,
.attention = rmi_f3a_attention,
};
...@@ -211,7 +211,6 @@ static int sun4i_ps2_probe(struct platform_device *pdev) ...@@ -211,7 +211,6 @@ static int sun4i_ps2_probe(struct platform_device *pdev)
struct sun4i_ps2data *drvdata; struct sun4i_ps2data *drvdata;
struct serio *serio; struct serio *serio;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
unsigned int irq;
int error; int error;
drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL); drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL);
...@@ -264,14 +263,12 @@ static int sun4i_ps2_probe(struct platform_device *pdev) ...@@ -264,14 +263,12 @@ static int sun4i_ps2_probe(struct platform_device *pdev)
writel(0, drvdata->reg_base + PS2_REG_GCTL); writel(0, drvdata->reg_base + PS2_REG_GCTL);
/* Get IRQ for the device */ /* Get IRQ for the device */
irq = platform_get_irq(pdev, 0); drvdata->irq = platform_get_irq(pdev, 0);
if (!irq) { if (drvdata->irq < 0) {
dev_err(dev, "no IRQ found\n"); error = drvdata->irq;
error = -ENXIO;
goto err_disable_clk; goto err_disable_clk;
} }
drvdata->irq = irq;
drvdata->serio = serio; drvdata->serio = serio;
drvdata->dev = dev; drvdata->dev = dev;
......
...@@ -1322,4 +1322,16 @@ config TOUCHSCREEN_IQS5XX ...@@ -1322,4 +1322,16 @@ config TOUCHSCREEN_IQS5XX
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called iqs5xx. module will be called iqs5xx.
config TOUCHSCREEN_ZINITIX
tristate "Zinitix touchscreen support"
depends on I2C
help
Say Y here if you have a touchscreen using Zinitix bt541,
or something similar enough.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called zinitix.
endif endif
...@@ -111,3 +111,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o ...@@ -111,3 +111,4 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o
obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o
obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o
obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o
obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o
...@@ -90,7 +90,7 @@ ...@@ -90,7 +90,7 @@
/* FW read command, 0x53 0x?? 0x0, 0x01 */ /* FW read command, 0x53 0x?? 0x0, 0x01 */
#define E_ELAN_INFO_FW_VER 0x00 #define E_ELAN_INFO_FW_VER 0x00
#define E_ELAN_INFO_BC_VER 0x10 #define E_ELAN_INFO_BC_VER 0x10
#define E_ELAN_INFO_REK 0xE0 #define E_ELAN_INFO_REK 0xD0
#define E_ELAN_INFO_TEST_VER 0xE0 #define E_ELAN_INFO_TEST_VER 0xE0
#define E_ELAN_INFO_FW_ID 0xF0 #define E_ELAN_INFO_FW_ID 0xF0
#define E_INFO_OSR 0xD6 #define E_INFO_OSR 0xD6
...@@ -134,6 +134,7 @@ struct elants_data { ...@@ -134,6 +134,7 @@ struct elants_data {
u8 bc_version; u8 bc_version;
u8 iap_version; u8 iap_version;
u16 hw_version; u16 hw_version;
u8 major_res;
unsigned int x_res; /* resolution in units/mm */ unsigned int x_res; /* resolution in units/mm */
unsigned int y_res; unsigned int y_res;
unsigned int x_max; unsigned int x_max;
...@@ -459,6 +460,9 @@ static int elants_i2c_query_ts_info(struct elants_data *ts) ...@@ -459,6 +460,9 @@ static int elants_i2c_query_ts_info(struct elants_data *ts)
rows = resp[2] + resp[6] + resp[10]; rows = resp[2] + resp[6] + resp[10];
cols = resp[3] + resp[7] + resp[11]; cols = resp[3] + resp[7] + resp[11];
/* Get report resolution value of ABS_MT_TOUCH_MAJOR */
ts->major_res = resp[16];
/* Process mm_to_pixel information */ /* Process mm_to_pixel information */
error = elants_i2c_execute_command(client, error = elants_i2c_execute_command(client,
get_osr_cmd, sizeof(get_osr_cmd), get_osr_cmd, sizeof(get_osr_cmd),
...@@ -1325,6 +1329,8 @@ static int elants_i2c_probe(struct i2c_client *client, ...@@ -1325,6 +1329,8 @@ static int elants_i2c_probe(struct i2c_client *client,
0, MT_TOOL_PALM, 0, 0); 0, MT_TOOL_PALM, 0, 0);
input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res); input_abs_set_res(ts->input, ABS_MT_POSITION_X, ts->x_res);
input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res); input_abs_set_res(ts->input, ABS_MT_POSITION_Y, ts->y_res);
if (ts->major_res > 0)
input_abs_set_res(ts->input, ABS_MT_TOUCH_MAJOR, ts->major_res);
touchscreen_parse_properties(ts->input, true, &ts->prop); touchscreen_parse_properties(ts->input, true, &ts->prop);
......
...@@ -315,9 +315,8 @@ static irqreturn_t adc_irq_fn(int irq, void *dev_id) ...@@ -315,9 +315,8 @@ static irqreturn_t adc_irq_fn(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static int imx6ul_tsc_open(struct input_dev *input_dev) static int imx6ul_tsc_start(struct imx6ul_tsc *tsc)
{ {
struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
int err; int err;
err = clk_prepare_enable(tsc->adc_clk); err = clk_prepare_enable(tsc->adc_clk);
...@@ -349,16 +348,29 @@ static int imx6ul_tsc_open(struct input_dev *input_dev) ...@@ -349,16 +348,29 @@ static int imx6ul_tsc_open(struct input_dev *input_dev)
return err; return err;
} }
static void imx6ul_tsc_close(struct input_dev *input_dev) static void imx6ul_tsc_stop(struct imx6ul_tsc *tsc)
{ {
struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
imx6ul_tsc_disable(tsc); imx6ul_tsc_disable(tsc);
clk_disable_unprepare(tsc->tsc_clk); clk_disable_unprepare(tsc->tsc_clk);
clk_disable_unprepare(tsc->adc_clk); clk_disable_unprepare(tsc->adc_clk);
} }
static int imx6ul_tsc_open(struct input_dev *input_dev)
{
struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
return imx6ul_tsc_start(tsc);
}
static void imx6ul_tsc_close(struct input_dev *input_dev)
{
struct imx6ul_tsc *tsc = input_get_drvdata(input_dev);
imx6ul_tsc_stop(tsc);
}
static int imx6ul_tsc_probe(struct platform_device *pdev) static int imx6ul_tsc_probe(struct platform_device *pdev)
{ {
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
...@@ -509,12 +521,8 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev) ...@@ -509,12 +521,8 @@ static int __maybe_unused imx6ul_tsc_suspend(struct device *dev)
mutex_lock(&input_dev->mutex); mutex_lock(&input_dev->mutex);
if (input_dev->users) { if (input_dev->users)
imx6ul_tsc_disable(tsc); imx6ul_tsc_stop(tsc);
clk_disable_unprepare(tsc->tsc_clk);
clk_disable_unprepare(tsc->adc_clk);
}
mutex_unlock(&input_dev->mutex); mutex_unlock(&input_dev->mutex);
...@@ -530,22 +538,11 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev) ...@@ -530,22 +538,11 @@ static int __maybe_unused imx6ul_tsc_resume(struct device *dev)
mutex_lock(&input_dev->mutex); mutex_lock(&input_dev->mutex);
if (input_dev->users) { if (input_dev->users)
retval = clk_prepare_enable(tsc->adc_clk); retval = imx6ul_tsc_start(tsc);
if (retval)
goto out;
retval = clk_prepare_enable(tsc->tsc_clk);
if (retval) {
clk_disable_unprepare(tsc->adc_clk);
goto out;
}
retval = imx6ul_tsc_init(tsc);
}
out:
mutex_unlock(&input_dev->mutex); mutex_unlock(&input_dev->mutex);
return retval; return retval;
} }
......
...@@ -51,6 +51,7 @@ ...@@ -51,6 +51,7 @@
/* Touch relative info */ /* Touch relative info */
#define RM_MAX_RETRIES 3 #define RM_MAX_RETRIES 3
#define RM_RETRY_DELAY_MS 20
#define RM_MAX_TOUCH_NUM 10 #define RM_MAX_TOUCH_NUM 10
#define RM_BOOT_DELAY_MS 100 #define RM_BOOT_DELAY_MS 100
...@@ -136,83 +137,82 @@ struct raydium_data { ...@@ -136,83 +137,82 @@ struct raydium_data {
bool wake_irq_enabled; bool wake_irq_enabled;
}; };
static int raydium_i2c_send(struct i2c_client *client, static int raydium_i2c_xfer(struct i2c_client *client,
u8 addr, const void *data, size_t len) u32 addr, void *data, size_t len, bool is_read)
{ {
u8 *buf; struct raydium_bank_switch_header {
int tries = 0; u8 cmd;
int ret; __be32 be_addr;
} __packed header = {
buf = kmalloc(len + 1, GFP_KERNEL); .cmd = RM_CMD_BANK_SWITCH,
if (!buf) .be_addr = cpu_to_be32(addr),
return -ENOMEM; };
buf[0] = addr;
memcpy(buf + 1, data, len);
do {
ret = i2c_master_send(client, buf, len + 1);
if (likely(ret == len + 1))
break;
msleep(20);
} while (++tries < RM_MAX_RETRIES);
kfree(buf);
if (unlikely(ret != len + 1)) {
if (ret >= 0)
ret = -EIO;
dev_err(&client->dev, "%s failed: %d\n", __func__, ret);
return ret;
}
return 0; u8 reg_addr = addr & 0xff;
}
static int raydium_i2c_read(struct i2c_client *client,
u8 addr, void *data, size_t len)
{
struct i2c_msg xfer[] = { struct i2c_msg xfer[] = {
{
.addr = client->addr,
.len = sizeof(header),
.buf = (u8 *)&header,
},
{ {
.addr = client->addr, .addr = client->addr,
.len = 1, .len = 1,
.buf = &addr, .buf = &reg_addr,
}, },
{ {
.addr = client->addr, .addr = client->addr,
.flags = I2C_M_RD,
.len = len, .len = len,
.buf = data, .buf = data,
.flags = is_read ? I2C_M_RD : 0,
} }
}; };
/*
* If address is greater than 255, then RM_CMD_BANK_SWITCH needs to be
* sent first. Else, skip the header i.e. xfer[0].
*/
int xfer_start_idx = (addr > 0xff) ? 0 : 1;
size_t xfer_count = ARRAY_SIZE(xfer) - xfer_start_idx;
int ret; int ret;
ret = i2c_transfer(client->adapter, xfer, ARRAY_SIZE(xfer)); ret = i2c_transfer(client->adapter, &xfer[xfer_start_idx], xfer_count);
if (unlikely(ret != ARRAY_SIZE(xfer))) if (likely(ret == xfer_count))
return 0;
return ret < 0 ? ret : -EIO; return ret < 0 ? ret : -EIO;
}
static int raydium_i2c_send(struct i2c_client *client,
u32 addr, const void *data, size_t len)
{
int tries = 0;
int error;
do {
error = raydium_i2c_xfer(client, addr, (void *)data, len,
false);
if (likely(!error))
return 0; return 0;
msleep(RM_RETRY_DELAY_MS);
} while (++tries < RM_MAX_RETRIES);
dev_err(&client->dev, "%s failed: %d\n", __func__, error);
return error;
} }
static int raydium_i2c_read_message(struct i2c_client *client, static int raydium_i2c_read(struct i2c_client *client,
u32 addr, void *data, size_t len) u32 addr, void *data, size_t len)
{ {
__be32 be_addr;
size_t xfer_len; size_t xfer_len;
int error; int error;
while (len) { while (len) {
xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE); xfer_len = min_t(size_t, len, RM_MAX_READ_SIZE);
error = raydium_i2c_xfer(client, addr, data, xfer_len, true);
be_addr = cpu_to_be32(addr); if (unlikely(error))
error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
&be_addr, sizeof(be_addr));
if (!error)
error = raydium_i2c_read(client, addr & 0xff,
data, xfer_len);
if (error)
return error; return error;
len -= xfer_len; len -= xfer_len;
...@@ -223,27 +223,13 @@ static int raydium_i2c_read_message(struct i2c_client *client, ...@@ -223,27 +223,13 @@ static int raydium_i2c_read_message(struct i2c_client *client,
return 0; return 0;
} }
static int raydium_i2c_send_message(struct i2c_client *client,
u32 addr, const void *data, size_t len)
{
__be32 be_addr = cpu_to_be32(addr);
int error;
error = raydium_i2c_send(client, RM_CMD_BANK_SWITCH,
&be_addr, sizeof(be_addr));
if (!error)
error = raydium_i2c_send(client, addr & 0xff, data, len);
return error;
}
static int raydium_i2c_sw_reset(struct i2c_client *client) static int raydium_i2c_sw_reset(struct i2c_client *client)
{ {
const u8 soft_rst_cmd = 0x01; const u8 soft_rst_cmd = 0x01;
int error; int error;
error = raydium_i2c_send_message(client, RM_RESET_MSG_ADDR, error = raydium_i2c_send(client, RM_RESET_MSG_ADDR, &soft_rst_cmd,
&soft_rst_cmd, sizeof(soft_rst_cmd)); sizeof(soft_rst_cmd));
if (error) { if (error) {
dev_err(&client->dev, "software reset failed: %d\n", error); dev_err(&client->dev, "software reset failed: %d\n", error);
return error; return error;
...@@ -295,8 +281,7 @@ static int raydium_i2c_query_ts_info(struct raydium_data *ts) ...@@ -295,8 +281,7 @@ static int raydium_i2c_query_ts_info(struct raydium_data *ts)
if (error) if (error)
continue; continue;
error = raydium_i2c_read_message(client, error = raydium_i2c_read(client, le32_to_cpu(query_bank_addr),
le32_to_cpu(query_bank_addr),
&ts->info, sizeof(ts->info)); &ts->info, sizeof(ts->info));
if (error) if (error)
continue; continue;
...@@ -834,7 +819,7 @@ static irqreturn_t raydium_i2c_irq(int irq, void *_dev) ...@@ -834,7 +819,7 @@ static irqreturn_t raydium_i2c_irq(int irq, void *_dev)
if (ts->boot_mode != RAYDIUM_TS_MAIN) if (ts->boot_mode != RAYDIUM_TS_MAIN)
goto out; goto out;
error = raydium_i2c_read_message(ts->client, ts->data_bank_addr, error = raydium_i2c_read(ts->client, ts->data_bank_addr,
ts->report_data, ts->pkg_size); ts->report_data, ts->pkg_size);
if (error) if (error)
goto out; goto out;
......
...@@ -479,7 +479,7 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev, ...@@ -479,7 +479,7 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
mutex_lock(&sdata->mutex); mutex_lock(&sdata->mutex);
if (value & sdata->hover_enabled) if (value && sdata->hover_enabled)
goto out; goto out;
if (sdata->running) if (sdata->running)
......
// SPDX-License-Identifier: GPL-2.0-only
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
/* Register Map */
#define BT541_SWRESET_CMD 0x0000
#define BT541_WAKEUP_CMD 0x0001
#define BT541_IDLE_CMD 0x0004
#define BT541_SLEEP_CMD 0x0005
#define BT541_CLEAR_INT_STATUS_CMD 0x0003
#define BT541_CALIBRATE_CMD 0x0006
#define BT541_SAVE_STATUS_CMD 0x0007
#define BT541_SAVE_CALIBRATION_CMD 0x0008
#define BT541_RECALL_FACTORY_CMD 0x000f
#define BT541_THRESHOLD 0x0020
#define BT541_LARGE_PALM_REJECT_AREA_TH 0x003F
#define BT541_DEBUG_REG 0x0115 /* 0~7 */
#define BT541_TOUCH_MODE 0x0010
#define BT541_CHIP_REVISION 0x0011
#define BT541_FIRMWARE_VERSION 0x0012
#define ZINITIX_USB_DETECT 0x116
#define BT541_MINOR_FW_VERSION 0x0121
#define BT541_VENDOR_ID 0x001C
#define BT541_HW_ID 0x0014
#define BT541_DATA_VERSION_REG 0x0013
#define BT541_SUPPORTED_FINGER_NUM 0x0015
#define BT541_EEPROM_INFO 0x0018
#define BT541_INITIAL_TOUCH_MODE 0x0019
#define BT541_TOTAL_NUMBER_OF_X 0x0060
#define BT541_TOTAL_NUMBER_OF_Y 0x0061
#define BT541_DELAY_RAW_FOR_HOST 0x007f
#define BT541_BUTTON_SUPPORTED_NUM 0x00B0
#define BT541_BUTTON_SENSITIVITY 0x00B2
#define BT541_DUMMY_BUTTON_SENSITIVITY 0X00C8
#define BT541_X_RESOLUTION 0x00C0
#define BT541_Y_RESOLUTION 0x00C1
#define BT541_POINT_STATUS_REG 0x0080
#define BT541_ICON_STATUS_REG 0x00AA
#define BT541_POINT_COORD_REG (BT541_POINT_STATUS_REG + 2)
#define BT541_AFE_FREQUENCY 0x0100
#define BT541_DND_N_COUNT 0x0122
#define BT541_DND_U_COUNT 0x0135
#define BT541_RAWDATA_REG 0x0200
#define BT541_EEPROM_INFO_REG 0x0018
#define BT541_INT_ENABLE_FLAG 0x00f0
#define BT541_PERIODICAL_INTERRUPT_INTERVAL 0x00f1
#define BT541_BTN_WIDTH 0x016d
#define BT541_CHECKSUM_RESULT 0x012c
#define BT541_INIT_FLASH 0x01d0
#define BT541_WRITE_FLASH 0x01d1
#define BT541_READ_FLASH 0x01d2
#define ZINITIX_INTERNAL_FLAG_02 0x011e
#define ZINITIX_INTERNAL_FLAG_03 0x011f
#define ZINITIX_I2C_CHECKSUM_WCNT 0x016a
#define ZINITIX_I2C_CHECKSUM_RESULT 0x016c
/* Interrupt & status register flags */
#define BIT_PT_CNT_CHANGE BIT(0)
#define BIT_DOWN BIT(1)
#define BIT_MOVE BIT(2)
#define BIT_UP BIT(3)
#define BIT_PALM BIT(4)
#define BIT_PALM_REJECT BIT(5)
#define BIT_RESERVED_0 BIT(6)
#define BIT_RESERVED_1 BIT(7)
#define BIT_WEIGHT_CHANGE BIT(8)
#define BIT_PT_NO_CHANGE BIT(9)
#define BIT_REJECT BIT(10)
#define BIT_PT_EXIST BIT(11)
#define BIT_RESERVED_2 BIT(12)
#define BIT_ERROR BIT(13)
#define BIT_DEBUG BIT(14)
#define BIT_ICON_EVENT BIT(15)
#define SUB_BIT_EXIST BIT(0)
#define SUB_BIT_DOWN BIT(1)
#define SUB_BIT_MOVE BIT(2)
#define SUB_BIT_UP BIT(3)
#define SUB_BIT_UPDATE BIT(4)
#define SUB_BIT_WAIT BIT(5)
#define DEFAULT_TOUCH_POINT_MODE 2
#define MAX_SUPPORTED_FINGER_NUM 5
#define CHIP_ON_DELAY 15 // ms
#define FIRMWARE_ON_DELAY 40 // ms
struct point_coord {
__le16 x;
__le16 y;
u8 width;
u8 sub_status;
// currently unused, but needed as padding:
u8 minor_width;
u8 angle;
};
struct touch_event {
__le16 status;
u8 finger_cnt;
u8 time_stamp;
struct point_coord point_coord[MAX_SUPPORTED_FINGER_NUM];
};
struct bt541_ts_data {
struct i2c_client *client;
struct input_dev *input_dev;
struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2];
u32 zinitix_mode;
};
static int zinitix_read_data(struct i2c_client *client,
u16 reg, void *values, size_t length)
{
__le16 reg_le = cpu_to_le16(reg);
int ret;
/* A single i2c_transfer() transaction does not work here. */
ret = i2c_master_send(client, (u8 *)&reg_le, sizeof(reg_le));
if (ret != sizeof(reg_le))
return ret < 0 ? ret : -EIO;
ret = i2c_master_recv(client, (u8 *)values, length);
if (ret != length)
return ret < 0 ? ret : -EIO; ;
return 0;
}
static int zinitix_write_u16(struct i2c_client *client, u16 reg, u16 value)
{
__le16 packet[2] = {cpu_to_le16(reg), cpu_to_le16(value)};
int ret;
ret = i2c_master_send(client, (u8 *)packet, sizeof(packet));
if (ret != sizeof(packet))
return ret < 0 ? ret : -EIO;
return 0;
}
static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
{
__le16 reg_le = cpu_to_le16(reg);
int ret;
ret = i2c_master_send(client, (u8 *)&reg_le, sizeof(reg_le));
if (ret != sizeof(reg_le))
return ret < 0 ? ret : -EIO;
return 0;
}
static bool zinitix_init_touch(struct bt541_ts_data *bt541)
{
struct i2c_client *client = bt541->client;
int i;
int error;
error = zinitix_write_cmd(client, BT541_SWRESET_CMD);
if (error) {
dev_err(&client->dev, "Failed to write reset command\n");
return error;
}
error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG, 0x0);
if (error) {
dev_err(&client->dev,
"Failed to reset interrupt enable flag\n");
return error;
}
/* initialize */
error = zinitix_write_u16(client, BT541_X_RESOLUTION,
bt541->prop.max_x);
if (error)
return error;
error = zinitix_write_u16(client, BT541_Y_RESOLUTION,
bt541->prop.max_y);
if (error)
return error;
error = zinitix_write_u16(client, BT541_SUPPORTED_FINGER_NUM,
MAX_SUPPORTED_FINGER_NUM);
if (error)
return error;
error = zinitix_write_u16(client, BT541_INITIAL_TOUCH_MODE,
bt541->zinitix_mode);
if (error)
return error;
error = zinitix_write_u16(client, BT541_TOUCH_MODE,
bt541->zinitix_mode);
if (error)
return error;
error = zinitix_write_u16(client, BT541_INT_ENABLE_FLAG,
BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE |
BIT_UP);
if (error)
return error;
/* clear queue */
for (i = 0; i < 10; i++) {
zinitix_write_cmd(client, BT541_CLEAR_INT_STATUS_CMD);
udelay(10);
}
return 0;
}
static int zinitix_init_regulators(struct bt541_ts_data *bt541)
{
struct i2c_client *client = bt541->client;
int error;
bt541->supplies[0].supply = "vdd";
bt541->supplies[1].supply = "vddo";
error = devm_regulator_bulk_get(&client->dev,
ARRAY_SIZE(bt541->supplies),
bt541->supplies);
if (error < 0) {
dev_err(&client->dev, "Failed to get regulators: %d\n", error);
return error;
}
return 0;
}
static int zinitix_send_power_on_sequence(struct bt541_ts_data *bt541)
{
int error;
struct i2c_client *client = bt541->client;
error = zinitix_write_u16(client, 0xc000, 0x0001);
if (error) {
dev_err(&client->dev,
"Failed to send power sequence(vendor cmd enable)\n");
return error;
}
udelay(10);
error = zinitix_write_cmd(client, 0xc004);
if (error) {
dev_err(&client->dev,
"Failed to send power sequence (intn clear)\n");
return error;
}
udelay(10);
error = zinitix_write_u16(client, 0xc002, 0x0001);
if (error) {
dev_err(&client->dev,
"Failed to send power sequence (nvm init)\n");
return error;
}
mdelay(2);
error = zinitix_write_u16(client, 0xc001, 0x0001);
if (error) {
dev_err(&client->dev,
"Failed to send power sequence (program start)\n");
return error;
}
msleep(FIRMWARE_ON_DELAY);
return 0;
}
static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
const struct point_coord *p)
{
input_mt_slot(bt541->input_dev, slot);
input_mt_report_slot_state(bt541->input_dev, MT_TOOL_FINGER, true);
touchscreen_report_pos(bt541->input_dev, &bt541->prop,
le16_to_cpu(p->x), le16_to_cpu(p->y), true);
input_report_abs(bt541->input_dev, ABS_MT_TOUCH_MAJOR, p->width);
}
static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
{
struct bt541_ts_data *bt541 = bt541_handler;
struct i2c_client *client = bt541->client;
struct touch_event touch_event;
int error;
int i;
memset(&touch_event, 0, sizeof(struct touch_event));
error = zinitix_read_data(bt541->client, BT541_POINT_STATUS_REG,
&touch_event, sizeof(struct touch_event));
if (error) {
dev_err(&client->dev, "Failed to read in touchpoint struct\n");
goto out;
}
for (i = 0; i < MAX_SUPPORTED_FINGER_NUM; i++)
if (touch_event.point_coord[i].sub_status & SUB_BIT_EXIST)
zinitix_report_finger(bt541, i,
&touch_event.point_coord[i]);
input_mt_sync_frame(bt541->input_dev);
input_sync(bt541->input_dev);
out:
zinitix_write_cmd(bt541->client, BT541_CLEAR_INT_STATUS_CMD);
return IRQ_HANDLED;
}
static int zinitix_start(struct bt541_ts_data *bt541)
{
int error;
error = regulator_bulk_enable(ARRAY_SIZE(bt541->supplies),
bt541->supplies);
if (error) {
dev_err(&bt541->client->dev,
"Failed to enable regulators: %d\n", error);
return error;
}
msleep(CHIP_ON_DELAY);
error = zinitix_send_power_on_sequence(bt541);
if (error) {
dev_err(&bt541->client->dev,
"Error while sending power-on sequence: %d\n", error);
return error;
}
error = zinitix_init_touch(bt541);
if (error) {
dev_err(&bt541->client->dev,
"Error while configuring touch IC\n");
return error;
}
enable_irq(bt541->client->irq);
return 0;
}
static int zinitix_stop(struct bt541_ts_data *bt541)
{
int error;
disable_irq(bt541->client->irq);
error = regulator_bulk_disable(ARRAY_SIZE(bt541->supplies),
bt541->supplies);
if (error) {
dev_err(&bt541->client->dev,
"Failed to disable regulators: %d\n", error);
return error;
}
return 0;
}
static int zinitix_input_open(struct input_dev *dev)
{
struct bt541_ts_data *bt541 = input_get_drvdata(dev);
return zinitix_start(bt541);
}
static void zinitix_input_close(struct input_dev *dev)
{
struct bt541_ts_data *bt541 = input_get_drvdata(dev);
zinitix_stop(bt541);
}
static int zinitix_init_input_dev(struct bt541_ts_data *bt541)
{
struct input_dev *input_dev;
int error;
input_dev = devm_input_allocate_device(&bt541->client->dev);
if (!input_dev) {
dev_err(&bt541->client->dev,
"Failed to allocate input device.");
return -ENOMEM;
}
input_set_drvdata(input_dev, bt541);
bt541->input_dev = input_dev;
input_dev->name = "Zinitix Capacitive TouchScreen";
input_dev->phys = "input/ts";
input_dev->id.bustype = BUS_I2C;
input_dev->open = zinitix_input_open;
input_dev->close = zinitix_input_close;
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
touchscreen_parse_properties(input_dev, true, &bt541->prop);
if (!bt541->prop.max_x || !bt541->prop.max_y) {
dev_err(&bt541->client->dev,
"Touchscreen-size-x and/or touchscreen-size-y not set in dts\n");
return -EINVAL;
}
error = input_mt_init_slots(input_dev, MAX_SUPPORTED_FINGER_NUM,
INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
if (error) {
dev_err(&bt541->client->dev,
"Failed to initialize MT slots: %d", error);
return error;
}
error = input_register_device(input_dev);
if (error) {
dev_err(&bt541->client->dev,
"Failed to register input device: %d", error);
return error;
}
return 0;
}
static int zinitix_ts_probe(struct i2c_client *client)
{
struct bt541_ts_data *bt541;
int error;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev,
"Failed to assert adapter's support for plain I2C.\n");
return -ENXIO;
}
bt541 = devm_kzalloc(&client->dev, sizeof(*bt541), GFP_KERNEL);
if (!bt541)
return -ENOMEM;
bt541->client = client;
i2c_set_clientdata(client, bt541);
error = zinitix_init_regulators(bt541);
if (error) {
dev_err(&client->dev,
"Failed to initialize regulators: %d\n", error);
return error;
}
error = zinitix_init_input_dev(bt541);
if (error) {
dev_err(&client->dev,
"Failed to initialize input device: %d\n", error);
return error;
}
error = device_property_read_u32(&client->dev, "zinitix,mode",
&bt541->zinitix_mode);
if (error < 0) {
/* fall back to mode 2 */
bt541->zinitix_mode = DEFAULT_TOUCH_POINT_MODE;
}
if (bt541->zinitix_mode != 2) {
/*
* If there are devices that don't support mode 2, support
* for other modes (0, 1) will be needed.
*/
dev_err(&client->dev,
"Malformed zinitix,mode property, must be 2 (supplied: %d)\n",
bt541->zinitix_mode);
return -EINVAL;
}
irq_set_status_flags(client->irq, IRQ_NOAUTOEN);
error = devm_request_threaded_irq(&client->dev, client->irq,
NULL, zinitix_ts_irq_handler,
IRQF_ONESHOT, client->name, bt541);
if (error) {
dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
return error;
}
return 0;
}
static int __maybe_unused 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);
if (bt541->input_dev->users)
zinitix_stop(bt541);
mutex_unlock(&bt541->input_dev->mutex);
return 0;
}
static int __maybe_unused 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;
mutex_lock(&bt541->input_dev->mutex);
if (bt541->input_dev->users)
ret = zinitix_start(bt541);
mutex_unlock(&bt541->input_dev->mutex);
return ret;
}
static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume);
#ifdef CONFIG_OF
static const struct of_device_id zinitix_of_match[] = {
{ .compatible = "zinitix,bt541" },
{ }
};
MODULE_DEVICE_TABLE(of, zinitix_of_match);
#endif
static struct i2c_driver zinitix_ts_driver = {
.probe_new = zinitix_ts_probe,
.driver = {
.name = "Zinitix-TS",
.pm = &zinitix_pm_ops,
.of_match_table = of_match_ptr(zinitix_of_match),
},
};
module_i2c_driver(zinitix_ts_driver);
MODULE_AUTHOR("Michael Srba <Michael.Srba@seznam.cz>");
MODULE_DESCRIPTION("Zinitix touchscreen driver");
MODULE_LICENSE("GPL v2");
...@@ -1913,6 +1913,10 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */ ...@@ -1913,6 +1913,10 @@ enum { /* hot key scan codes (derived from ACPI DSDT) */
TP_ACPI_HOTKEYSCAN_CALCULATOR, TP_ACPI_HOTKEYSCAN_CALCULATOR,
TP_ACPI_HOTKEYSCAN_BLUETOOTH, TP_ACPI_HOTKEYSCAN_BLUETOOTH,
TP_ACPI_HOTKEYSCAN_KEYBOARD, TP_ACPI_HOTKEYSCAN_KEYBOARD,
TP_ACPI_HOTKEYSCAN_FN_RIGHT_SHIFT, /* Used by "Lenovo Quick Clean" */
TP_ACPI_HOTKEYSCAN_NOTIFICATION_CENTER,
TP_ACPI_HOTKEYSCAN_PICKUP_PHONE,
TP_ACPI_HOTKEYSCAN_HANGUP_PHONE,
/* Hotkey keymap size */ /* Hotkey keymap size */
TPACPI_HOTKEY_MAP_LEN TPACPI_HOTKEY_MAP_LEN
...@@ -3430,10 +3434,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) ...@@ -3430,10 +3434,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
KEY_UNKNOWN, KEY_UNKNOWN,
KEY_BOOKMARKS, /* Favorite app, 0x311 */ KEY_BOOKMARKS, /* Favorite app, 0x311 */
KEY_RESERVED, /* Clipping tool */ KEY_SELECTIVE_SCREENSHOT, /* Clipping tool */
KEY_CALC, /* Calculator (above numpad, P52) */ KEY_CALC, /* Calculator (above numpad, P52) */
KEY_BLUETOOTH, /* Bluetooth */ KEY_BLUETOOTH, /* Bluetooth */
KEY_KEYBOARD /* Keyboard, 0x315 */ KEY_KEYBOARD, /* Keyboard, 0x315 */
KEY_FN_RIGHT_SHIFT, /* Fn + right Shift */
KEY_NOTIFICATION_CENTER, /* Notification Center */
KEY_PICKUP_PHONE, /* Answer incoming call */
KEY_HANGUP_PHONE, /* Decline incoming call */
}, },
}; };
......
...@@ -102,15 +102,16 @@ struct rmi_2d_sensor_platform_data { ...@@ -102,15 +102,16 @@ struct rmi_2d_sensor_platform_data {
}; };
/** /**
* struct rmi_f30_data - overrides defaults for a single F30 GPIOs/LED chip. * struct rmi_gpio_data - overrides defaults for a single F30/F3A GPIOs/LED
* chip.
* @buttonpad - the touchpad is a buttonpad, so enable only the first actual * @buttonpad - the touchpad is a buttonpad, so enable only the first actual
* button that is found. * button that is found.
* @trackstick_buttons - Set when the function 30 is handling the physical * @trackstick_buttons - Set when the function 30 or 3a is handling the physical
* buttons of the trackstick (as a PS/2 passthrough device). * buttons of the trackstick (as a PS/2 passthrough device).
* @disable - the touchpad incorrectly reports F30 and it should be ignored. * @disable - the touchpad incorrectly reports F30/F3A and it should be ignored.
* This is a special case which is due to misconfigured firmware. * This is a special case which is due to misconfigured firmware.
*/ */
struct rmi_f30_data { struct rmi_gpio_data {
bool buttonpad; bool buttonpad;
bool trackstick_buttons; bool trackstick_buttons;
bool disable; bool disable;
...@@ -218,7 +219,7 @@ struct rmi_device_platform_data { ...@@ -218,7 +219,7 @@ struct rmi_device_platform_data {
/* function handler pdata */ /* function handler pdata */
struct rmi_2d_sensor_platform_data sensor_pdata; struct rmi_2d_sensor_platform_data sensor_pdata;
struct rmi_f01_power_management power_management; struct rmi_f01_power_management power_management;
struct rmi_f30_data f30_data; struct rmi_gpio_data gpio_data;
}; };
/** /**
......
...@@ -515,6 +515,9 @@ ...@@ -515,6 +515,9 @@
#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ #define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */
#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ #define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */
#define KEY_IMAGES 0x1ba /* AL Image Browser */ #define KEY_IMAGES 0x1ba /* AL Image Browser */
#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */
#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */
#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */
#define KEY_DEL_EOL 0x1c0 #define KEY_DEL_EOL 0x1c0
#define KEY_DEL_EOS 0x1c1 #define KEY_DEL_EOS 0x1c1
...@@ -542,6 +545,7 @@ ...@@ -542,6 +545,7 @@
#define KEY_FN_F 0x1e2 #define KEY_FN_F 0x1e2
#define KEY_FN_S 0x1e3 #define KEY_FN_S 0x1e3
#define KEY_FN_B 0x1e4 #define KEY_FN_B 0x1e4
#define KEY_FN_RIGHT_SHIFT 0x1e5
#define KEY_BRL_DOT1 0x1f1 #define KEY_BRL_DOT1 0x1f1
#define KEY_BRL_DOT2 0x1f2 #define KEY_BRL_DOT2 0x1f2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment