mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
Merge tag 'input-for-v7.2-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull input updates from Dmitry Torokhov: - A new driver for Wacom W9000-series penabled touchscreens - Updates to STM FTS driver adding support for reset line and preparing the driver for STMFTS5 support - Updates to RMI4 and IMS PCU drivers hardening the code - Support for half-duplex mode restored in ADS7846 driver - Updates to driver's device_id tables to use named initializers - Removal of no longer used PCAP keys and touchscreen drivers (support for the ezx series of phones was removed in 2022) - Removal of xilinx_ps2 driver which is no longer used either - Updates to userio to allow setting up additional serio port characteristics (such as id, extra and proto) - Assorted hardening and cleanup fixes for other drivers * tag 'input-for-v7.2-rc0' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (72 commits) Input: mms114 - fix touch indexing for MMS134S and MMS136 Input: elan_i2c - prevent division by zero and arithmetic underflow Input: stop force-feedback timer when unregistering input devices Input: iforce - bound the device-reported force-feedback effect index Input: goodix - clamp the device-reported contact count Input: mms114 - reject an oversized device packet size Input: touchwin - reset the packet index on every complete packet Input: rmi4 - update formatting in F12 Input: rmi4 - propagate proper error code in F12 sensor tuning Input: rmi4 - simplify size calculations in F12 Input: rmi4 - use sizeof(*ptr) and idiomatic checks in f12 allocators Input: rmi4 - use devm_kmalloc for F12 data packet buffer Input: rmi4 - use flexible array member for IRQ masks in F12 Input: rmi4 - use unaligned access helpers in F12 Input: rmi4 - change reg_size type to u32 Input: rmi4 - refactor F12 probe function Input: rmi4 - use kzalloc_flex() for struct rmi_function Input: rmi4 - refactor function allocation and registration Input: rmi4 - use local presence map in rmi_read_register_desc() Input: rmi4 - fix limit in rmi_register_desc_has_subpacket() ...
This commit is contained in:
@@ -40,6 +40,10 @@ properties:
|
||||
vdd-supply:
|
||||
description: Power supply
|
||||
|
||||
reset-gpios:
|
||||
description: Reset GPIO (active-low)
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/input/touchscreen/wacom,w9007a-lt03.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Wacom W9000-series penabled I2C touchscreen
|
||||
|
||||
maintainers:
|
||||
- Hendrik Noack <hendrik-noack@gmx.de>
|
||||
|
||||
description: |
|
||||
The W9000-series are penabled touchscreen controllers by Wacom.
|
||||
|
||||
The firmware of controllers in different devices may differ. This can also
|
||||
affect the controller's behavior.
|
||||
|
||||
allOf:
|
||||
- $ref: touchscreen.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- wacom,w9002
|
||||
- wacom,w9007a-lt03
|
||||
- wacom,w9007a-v1
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
vdd-supply: true
|
||||
|
||||
flash-mode-gpios:
|
||||
maxItems: 1
|
||||
|
||||
reset-gpios:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
i2c {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
digitizer@56 {
|
||||
compatible = "wacom,w9007a-lt03";
|
||||
reg = <0x56>;
|
||||
interrupt-parent = <&gpd1>;
|
||||
interrupts = <1 IRQ_TYPE_EDGE_RISING>;
|
||||
|
||||
vdd-supply = <&stylus_reg>;
|
||||
|
||||
flash-mode-gpios = <&gpd1 3 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpx0 1 GPIO_ACTIVE_LOW>;
|
||||
|
||||
touchscreen-x-mm = <216>;
|
||||
touchscreen-y-mm = <135>;
|
||||
touchscreen-inverted-x;
|
||||
};
|
||||
};
|
||||
@@ -5,7 +5,7 @@ The userio Protocol
|
||||
===================
|
||||
|
||||
|
||||
:Copyright: |copy| 2015 Stephen Chandler Paul <thatslyude@gmail.com>
|
||||
:Copyright: |copy| 2015 Lyude Paul <thatslyude@gmail.com>
|
||||
|
||||
Sponsored by Red Hat
|
||||
|
||||
@@ -66,8 +66,27 @@ USERIO_CMD_SET_PORT_TYPE
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the type of port we're emulating, where ``data`` is the port type being
|
||||
set. Can be any of the macros from <linux/serio.h>. For example: SERIO_8042
|
||||
would set the port type to be a normal PS/2 port.
|
||||
set. Can be any of the serio type macros from <linux/serio.h>. For example:
|
||||
SERIO_8042 would set the port type to be a normal PS/2 port.
|
||||
|
||||
USERIO_CMD_SET_PORT_PROTO
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the protocol of port we're emulating, where ``data`` is the protocol being
|
||||
set. Can be any of the serio proto macros from <linux/serio.h>. For example:
|
||||
SERIO_IFORCE would set the port type to be an I-Force serial joystick.
|
||||
|
||||
USERIO_CMD_SET_PORT_ID
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the ``id`` value on the identification of port we're emulating, where
|
||||
``data`` is the value being set.
|
||||
|
||||
USERIO_CMD_SET_PORT_EXTRA
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sets the ``extra`` value on the identification of port we're emulating, where
|
||||
``data`` is the value being set.
|
||||
|
||||
USERIO_CMD_SEND_INTERRUPT
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -28731,7 +28731,7 @@ F: sound/drivers/pcmtest.c
|
||||
F: tools/testing/selftests/alsa/test-pcmtest-driver.c
|
||||
|
||||
VIRTUAL SERIO DEVICE DRIVER
|
||||
M: Stephen Chandler Paul <thatslyude@gmail.com>
|
||||
M: Lyude Paul <thatslyude@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/input/serio/userio.c
|
||||
F: include/uapi/linux/userio.h
|
||||
|
||||
@@ -484,17 +484,31 @@ static void ml_ff_destroy(struct ff_device *ff)
|
||||
struct ml_device *ml = ff->private;
|
||||
|
||||
/*
|
||||
* Even though we stop all playing effects when tearing down
|
||||
* an input device (via input_device_flush() that calls into
|
||||
* input_ff_flush() that stops and erases all effects), we
|
||||
* do not actually stop the timer, and therefore we should
|
||||
* do it here.
|
||||
* The timer is normally shut down in ml_ff_stop() when the device
|
||||
* is unregistered. However, we still shut it down here as a safety
|
||||
* net and for cases where the device was never registered (e.g.
|
||||
* error paths during probe).
|
||||
*/
|
||||
timer_delete_sync(&ml->timer);
|
||||
timer_shutdown_sync(&ml->timer);
|
||||
|
||||
kfree(ml->private);
|
||||
}
|
||||
|
||||
static void ml_ff_stop(struct ff_device *ff)
|
||||
{
|
||||
struct ml_device *ml = ff->private;
|
||||
|
||||
/*
|
||||
* Even though we stop all playing effects when tearing down an
|
||||
* input device (by the way of evdev calling input_flush_device()
|
||||
* that calls into input_ff_flush() that stops and erases all
|
||||
* effects), we do not actually shutdown the timer, and therefore
|
||||
* we should do it here to prevent it firing after the input
|
||||
* device is unregistered and its associated resources are freed.
|
||||
*/
|
||||
timer_shutdown_sync(&ml->timer);
|
||||
}
|
||||
|
||||
/**
|
||||
* input_ff_create_memless() - create memoryless force-feedback device
|
||||
* @dev: input device supporting force-feedback
|
||||
@@ -529,6 +543,7 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
|
||||
ff->playback = ml_ff_playback;
|
||||
ff->set_gain = ml_ff_set_gain;
|
||||
ff->destroy = ml_ff_destroy;
|
||||
ff->stop = ml_ff_stop;
|
||||
|
||||
/* we can emulate periodic effects with RUMBLE */
|
||||
if (test_bit(FF_RUMBLE, ff->ffbit)) {
|
||||
|
||||
@@ -148,29 +148,29 @@ static int ns558_isa_probe(int io)
|
||||
#ifdef CONFIG_PNP
|
||||
|
||||
static const struct pnp_device_id pnp_devids[] = {
|
||||
{ .id = "@P@0001", .driver_data = 0 }, /* ALS 100 */
|
||||
{ .id = "@P@0020", .driver_data = 0 }, /* ALS 200 */
|
||||
{ .id = "@P@1001", .driver_data = 0 }, /* ALS 100+ */
|
||||
{ .id = "@P@2001", .driver_data = 0 }, /* ALS 120 */
|
||||
{ .id = "ASB16fd", .driver_data = 0 }, /* AdLib NSC16 */
|
||||
{ .id = "AZT3001", .driver_data = 0 }, /* AZT1008 */
|
||||
{ .id = "CDC0001", .driver_data = 0 }, /* Opl3-SAx */
|
||||
{ .id = "CSC0001", .driver_data = 0 }, /* CS4232 */
|
||||
{ .id = "CSC000f", .driver_data = 0 }, /* CS4236 */
|
||||
{ .id = "CSC0101", .driver_data = 0 }, /* CS4327 */
|
||||
{ .id = "CTL7001", .driver_data = 0 }, /* SB16 */
|
||||
{ .id = "CTL7002", .driver_data = 0 }, /* AWE64 */
|
||||
{ .id = "CTL7005", .driver_data = 0 }, /* Vibra16 */
|
||||
{ .id = "ENS2020", .driver_data = 0 }, /* SoundscapeVIVO */
|
||||
{ .id = "ESS0001", .driver_data = 0 }, /* ES1869 */
|
||||
{ .id = "ESS0005", .driver_data = 0 }, /* ES1878 */
|
||||
{ .id = "ESS6880", .driver_data = 0 }, /* ES688 */
|
||||
{ .id = "IBM0012", .driver_data = 0 }, /* CS4232 */
|
||||
{ .id = "OPT0001", .driver_data = 0 }, /* OPTi Audio16 */
|
||||
{ .id = "YMH0006", .driver_data = 0 }, /* Opl3-SA */
|
||||
{ .id = "YMH0022", .driver_data = 0 }, /* Opl3-SAx */
|
||||
{ .id = "PNPb02f", .driver_data = 0 }, /* Generic */
|
||||
{ .id = "", },
|
||||
{ .id = "@P@0001" }, /* ALS 100 */
|
||||
{ .id = "@P@0020" }, /* ALS 200 */
|
||||
{ .id = "@P@1001" }, /* ALS 100+ */
|
||||
{ .id = "@P@2001" }, /* ALS 120 */
|
||||
{ .id = "ASB16fd" }, /* AdLib NSC16 */
|
||||
{ .id = "AZT3001" }, /* AZT1008 */
|
||||
{ .id = "CDC0001" }, /* Opl3-SAx */
|
||||
{ .id = "CSC0001" }, /* CS4232 */
|
||||
{ .id = "CSC000f" }, /* CS4236 */
|
||||
{ .id = "CSC0101" }, /* CS4327 */
|
||||
{ .id = "CTL7001" }, /* SB16 */
|
||||
{ .id = "CTL7002" }, /* AWE64 */
|
||||
{ .id = "CTL7005" }, /* Vibra16 */
|
||||
{ .id = "ENS2020" }, /* SoundscapeVIVO */
|
||||
{ .id = "ESS0001" }, /* ES1869 */
|
||||
{ .id = "ESS0005" }, /* ES1878 */
|
||||
{ .id = "ESS6880" }, /* ES688 */
|
||||
{ .id = "IBM0012" }, /* CS4232 */
|
||||
{ .id = "OPT0001" }, /* OPTi Audio16 */
|
||||
{ .id = "YMH0006" }, /* Opl3-SA */
|
||||
{ .id = "YMH0022" }, /* Opl3-SAx */
|
||||
{ .id = "PNPb02f" }, /* Generic */
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pnp, pnp_devids);
|
||||
|
||||
@@ -2212,6 +2212,9 @@ static void __input_unregister_device(struct input_dev *dev)
|
||||
input_wakeup_procfs_readers();
|
||||
}
|
||||
|
||||
if (dev->ff && dev->ff->stop)
|
||||
dev->ff->stop(dev->ff);
|
||||
|
||||
device_del(&dev->dev);
|
||||
}
|
||||
|
||||
|
||||
@@ -304,7 +304,7 @@ static int seesaw_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id seesaw_id_table[] = {
|
||||
{ SEESAW_DEVICE_NAME },
|
||||
{ .name = SEESAW_DEVICE_NAME },
|
||||
{ /* Sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, seesaw_id_table);
|
||||
|
||||
@@ -337,7 +337,7 @@ static void as5011_remove(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id as5011_id[] = {
|
||||
{ MODULE_DEVICE_ALIAS },
|
||||
{ .name = MODULE_DEVICE_ALIAS },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, as5011_id);
|
||||
|
||||
@@ -186,14 +186,18 @@ void iforce_process_packet(struct iforce *iforce,
|
||||
|
||||
/* Check if an effect was just started or stopped */
|
||||
i = data[1] & 0x7f;
|
||||
if (data[1] & 0x80) {
|
||||
if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
|
||||
/* Report play event */
|
||||
input_report_ff_status(dev, i, FF_STATUS_PLAYING);
|
||||
if (i < IFORCE_EFFECTS_MAX) {
|
||||
if (data[1] & 0x80) {
|
||||
if (!test_and_set_bit(FF_CORE_IS_PLAYED,
|
||||
iforce->core_effects[i].flags)) {
|
||||
/* Report play event */
|
||||
input_report_ff_status(dev, i, FF_STATUS_PLAYING);
|
||||
}
|
||||
} else if (test_and_clear_bit(FF_CORE_IS_PLAYED,
|
||||
iforce->core_effects[i].flags)) {
|
||||
/* Report stop event */
|
||||
input_report_ff_status(dev, i, FF_STATUS_STOPPED);
|
||||
}
|
||||
} else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
|
||||
/* Report stop event */
|
||||
input_report_ff_status(dev, i, FF_STATUS_STOPPED);
|
||||
}
|
||||
|
||||
for (j = 3; j < len; j += 2)
|
||||
|
||||
@@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, of_qwiic_match);
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static const struct i2c_device_id qwiic_id_table[] = {
|
||||
{ KBUILD_MODNAME },
|
||||
{ .name = KBUILD_MODNAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, qwiic_id_table);
|
||||
|
||||
@@ -842,8 +842,8 @@ static int adp5588_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(adp5588_dev_pm_ops, adp5588_suspend, adp5588_resume);
|
||||
|
||||
static const struct i2c_device_id adp5588_id[] = {
|
||||
{ "adp5588-keys" },
|
||||
{ "adp5587-keys" },
|
||||
{ .name = "adp5588-keys" },
|
||||
{ .name = "adp5587-keys" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, adp5588_id);
|
||||
|
||||
@@ -651,13 +651,13 @@ static const struct of_device_id cap11xx_dt_ids[] = {
|
||||
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
|
||||
|
||||
static const struct i2c_device_id cap11xx_i2c_ids[] = {
|
||||
{ "cap1106", (kernel_ulong_t)&cap1106_model },
|
||||
{ "cap1126", (kernel_ulong_t)&cap1126_model },
|
||||
{ "cap1188", (kernel_ulong_t)&cap1188_model },
|
||||
{ "cap1203", (kernel_ulong_t)&cap1203_model },
|
||||
{ "cap1206", (kernel_ulong_t)&cap1206_model },
|
||||
{ "cap1293", (kernel_ulong_t)&cap1293_model },
|
||||
{ "cap1298", (kernel_ulong_t)&cap1298_model },
|
||||
{ .name = "cap1106", .driver_data = (kernel_ulong_t)&cap1106_model },
|
||||
{ .name = "cap1126", .driver_data = (kernel_ulong_t)&cap1126_model },
|
||||
{ .name = "cap1188", .driver_data = (kernel_ulong_t)&cap1188_model },
|
||||
{ .name = "cap1203", .driver_data = (kernel_ulong_t)&cap1203_model },
|
||||
{ .name = "cap1206", .driver_data = (kernel_ulong_t)&cap1206_model },
|
||||
{ .name = "cap1293", .driver_data = (kernel_ulong_t)&cap1293_model },
|
||||
{ .name = "cap1298", .driver_data = (kernel_ulong_t)&cap1298_model },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
|
||||
|
||||
@@ -209,7 +209,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
|
||||
cypress_sf_suspend, cypress_sf_resume);
|
||||
|
||||
static const struct i2c_device_id cypress_sf_id_table[] = {
|
||||
{ CYPRESS_SF_DEV_NAME },
|
||||
{ .name = CYPRESS_SF_DEV_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cypress_sf_id_table);
|
||||
|
||||
@@ -128,7 +128,7 @@ static int dir685_tk_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id dir685_tk_id[] = {
|
||||
{ "dir685tk" },
|
||||
{ .name = "dir685tk" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, dir685_tk_id);
|
||||
|
||||
@@ -20,12 +20,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mfd/ipaq-micro.h>
|
||||
|
||||
struct ipaq_micro_keys {
|
||||
struct ipaq_micro *micro;
|
||||
struct input_dev *input;
|
||||
u16 *codes;
|
||||
};
|
||||
|
||||
static const u16 micro_keycodes[] = {
|
||||
KEY_RECORD, /* 1: Record button */
|
||||
KEY_CALENDAR, /* 2: Calendar */
|
||||
@@ -38,11 +32,20 @@ static const u16 micro_keycodes[] = {
|
||||
KEY_DOWN, /* 9: Down */
|
||||
};
|
||||
|
||||
struct ipaq_micro_keys {
|
||||
struct ipaq_micro *micro;
|
||||
struct input_dev *input;
|
||||
u16 codes[ARRAY_SIZE(micro_keycodes)];
|
||||
};
|
||||
|
||||
static void micro_key_receive(void *data, int len, unsigned char *msg)
|
||||
{
|
||||
struct ipaq_micro_keys *keys = data;
|
||||
int key, down;
|
||||
|
||||
if (len < 1)
|
||||
return;
|
||||
|
||||
down = 0x80 & msg[0];
|
||||
key = 0x7f & msg[0];
|
||||
|
||||
@@ -54,7 +57,7 @@ static void micro_key_receive(void *data, int len, unsigned char *msg)
|
||||
|
||||
static void micro_key_start(struct ipaq_micro_keys *keys)
|
||||
{
|
||||
guard(spinlock)(&keys->micro->lock);
|
||||
guard(spinlock_irq)(&keys->micro->lock);
|
||||
|
||||
keys->micro->key = micro_key_receive;
|
||||
keys->micro->key_data = keys;
|
||||
@@ -62,7 +65,7 @@ static void micro_key_start(struct ipaq_micro_keys *keys)
|
||||
|
||||
static void micro_key_stop(struct ipaq_micro_keys *keys)
|
||||
{
|
||||
guard(spinlock)(&keys->micro->lock);
|
||||
guard(spinlock_irq)(&keys->micro->lock);
|
||||
|
||||
keys->micro->key = NULL;
|
||||
keys->micro->key_data = NULL;
|
||||
@@ -102,10 +105,7 @@ static int micro_key_probe(struct platform_device *pdev)
|
||||
|
||||
keys->input->keycodesize = sizeof(micro_keycodes[0]);
|
||||
keys->input->keycodemax = ARRAY_SIZE(micro_keycodes);
|
||||
keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax,
|
||||
keys->input->keycodesize, GFP_KERNEL);
|
||||
if (!keys->codes)
|
||||
return -ENOMEM;
|
||||
memcpy(keys->codes, micro_keycodes, sizeof(keys->codes));
|
||||
|
||||
keys->input->keycode = keys->codes;
|
||||
|
||||
|
||||
@@ -259,7 +259,7 @@ static void process_keys(struct lm8323_chip *lm)
|
||||
ret = lm8323_read(lm, LM8323_CMD_READ_FIFO, key_fifo, LM8323_FIFO_LEN);
|
||||
|
||||
if (ret < 0) {
|
||||
dev_err(&lm->client->dev, "Failed reading fifo \n");
|
||||
dev_err(&lm->client->dev, "Failed reading fifo\n");
|
||||
return;
|
||||
}
|
||||
key_fifo[ret] = 0;
|
||||
@@ -788,7 +788,7 @@ static int lm8323_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(lm8323_pm_ops, lm8323_suspend, lm8323_resume);
|
||||
|
||||
static const struct i2c_device_id lm8323_id[] = {
|
||||
{ "lm8323" },
|
||||
{ .name = "lm8323" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -194,7 +194,7 @@ static int lm8333_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id lm8333_id[] = {
|
||||
{ "lm8333" },
|
||||
{ .name = "lm8333" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, lm8333_id);
|
||||
|
||||
@@ -270,7 +270,7 @@ static int max7359_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(max7359_pm, max7359_suspend, max7359_resume);
|
||||
|
||||
static const struct i2c_device_id max7359_ids[] = {
|
||||
{ "max7359" },
|
||||
{ .name = "max7359" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max7359_ids);
|
||||
|
||||
@@ -322,7 +322,7 @@ static int mpr_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(mpr121_touchkey_pm_ops, mpr_suspend, mpr_resume);
|
||||
|
||||
static const struct i2c_device_id mpr121_id[] = {
|
||||
{ "mpr121_touchkey" },
|
||||
{ .name = "mpr121_touchkey" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mpr121_id);
|
||||
|
||||
@@ -233,7 +233,7 @@ static int qt1070_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(qt1070_pm_ops, qt1070_suspend, qt1070_resume);
|
||||
|
||||
static const struct i2c_device_id qt1070_id[] = {
|
||||
{ "qt1070" },
|
||||
{ .name = "qt1070" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, qt1070_id);
|
||||
|
||||
@@ -393,7 +393,7 @@ static int qt2160_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id qt2160_idtable[] = {
|
||||
{ "qt2160" },
|
||||
{ .name = "qt2160" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -354,7 +354,7 @@ static int tca8418_keypad_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tca8418_id[] = {
|
||||
{ "tca8418", 8418, },
|
||||
{ .name = "tca8418", .driver_data = 8418 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tca8418_id);
|
||||
|
||||
@@ -326,7 +326,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(tm2_touchkey_pm_ops,
|
||||
tm2_touchkey_suspend, tm2_touchkey_resume);
|
||||
|
||||
static const struct i2c_device_id tm2_touchkey_id_table[] = {
|
||||
{ TM2_TOUCHKEY_DEV_NAME },
|
||||
{ .name = TM2_TOUCHKEY_DEV_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, tm2_touchkey_id_table);
|
||||
|
||||
@@ -745,16 +745,6 @@ config INPUT_WM831X_ON
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called wm831x_on.
|
||||
|
||||
config INPUT_PCAP
|
||||
tristate "Motorola EZX PCAP misc input events"
|
||||
depends on EZX_PCAP
|
||||
help
|
||||
Say Y here if you want to use Power key and Headphone button
|
||||
on Motorola EZX phones.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pcap_keys.
|
||||
|
||||
config INPUT_ADXL34X
|
||||
tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer"
|
||||
default n
|
||||
|
||||
@@ -60,7 +60,6 @@ obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
|
||||
obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
|
||||
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
|
||||
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
|
||||
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
|
||||
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
|
||||
obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o
|
||||
|
||||
@@ -72,11 +72,11 @@ static int ad714x_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ad714x_id[] = {
|
||||
{ "ad7142_captouch" },
|
||||
{ "ad7143_captouch" },
|
||||
{ "ad7147_captouch" },
|
||||
{ "ad7147a_captouch" },
|
||||
{ "ad7148_captouch" },
|
||||
{ .name = "ad7142_captouch" },
|
||||
{ .name = "ad7143_captouch" },
|
||||
{ .name = "ad7147_captouch" },
|
||||
{ .name = "ad7147a_captouch" },
|
||||
{ .name = "ad7148_captouch" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad714x_id);
|
||||
|
||||
@@ -96,7 +96,7 @@ static int adxl34x_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id adxl34x_id[] = {
|
||||
{ "adxl34x" },
|
||||
{ .name = "adxl34x" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -192,7 +192,7 @@ static void apanel_shutdown(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id apanel_id[] = {
|
||||
{ "fujitsu_apanel" },
|
||||
{ .name = "fujitsu_apanel" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, apanel_id);
|
||||
|
||||
@@ -15,17 +15,18 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define ACPI_ATLAS_NAME "Atlas ACPI"
|
||||
#define ACPI_ATLAS_CLASS "Atlas"
|
||||
|
||||
static unsigned short atlas_keymap[16];
|
||||
static struct input_dev *input_dev;
|
||||
struct atlas_btns {
|
||||
struct input_dev *input_dev;
|
||||
unsigned short keymap[16];
|
||||
};
|
||||
|
||||
/* button handling code */
|
||||
static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
|
||||
u32 function, void *handler_context, void **return_context)
|
||||
u32 function, void *handler_context,
|
||||
void **return_context)
|
||||
{
|
||||
*return_context =
|
||||
(function != ACPI_REGION_DEACTIVATE) ? handler_context : NULL;
|
||||
@@ -34,33 +35,37 @@ static acpi_status acpi_atlas_button_setup(acpi_handle region_handle,
|
||||
}
|
||||
|
||||
static acpi_status acpi_atlas_button_handler(u32 function,
|
||||
acpi_physical_address address,
|
||||
u32 bit_width, u64 *value,
|
||||
void *handler_context, void *region_context)
|
||||
acpi_physical_address address,
|
||||
u32 bit_width, u64 *value,
|
||||
void *handler_context,
|
||||
void *region_context)
|
||||
{
|
||||
acpi_status status;
|
||||
struct atlas_btns *atlas = region_context;
|
||||
|
||||
if (function == ACPI_WRITE) {
|
||||
int code = address & 0x0f;
|
||||
int key_down = !(address & 0x10);
|
||||
|
||||
input_event(input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(input_dev, atlas_keymap[code], key_down);
|
||||
input_sync(input_dev);
|
||||
input_event(atlas->input_dev, EV_MSC, MSC_SCAN, code);
|
||||
input_report_key(atlas->input_dev, atlas->keymap[code],
|
||||
key_down);
|
||||
input_sync(atlas->input_dev);
|
||||
|
||||
status = AE_OK;
|
||||
} else {
|
||||
pr_warn("shrugged on unexpected function: function=%x,address=%lx,value=%x\n",
|
||||
function, (unsigned long)address, (u32)*value);
|
||||
status = AE_BAD_PARAMETER;
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
return status;
|
||||
dev_warn(atlas->input_dev->dev.parent,
|
||||
"unexpected function: function=%x,address=%lx,value=%x\n",
|
||||
function, (unsigned long)address, (u32)*value);
|
||||
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
|
||||
static int atlas_acpi_button_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct acpi_device *device;
|
||||
struct atlas_btns *atlas;
|
||||
struct input_dev *input_dev;
|
||||
acpi_status status;
|
||||
int i;
|
||||
int err;
|
||||
@@ -69,65 +74,62 @@ static int atlas_acpi_button_probe(struct platform_device *pdev)
|
||||
if (!device)
|
||||
return -ENODEV;
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev) {
|
||||
pr_err("unable to allocate input device\n");
|
||||
atlas = devm_kzalloc(&pdev->dev, sizeof(*atlas), GFP_KERNEL);
|
||||
if (!atlas)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
input_dev = devm_input_allocate_device(&pdev->dev);
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
atlas->input_dev = input_dev;
|
||||
|
||||
input_dev->name = "Atlas ACPI button driver";
|
||||
input_dev->phys = "ASIM0000/atlas/input0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->keycode = atlas_keymap;
|
||||
input_dev->keycodesize = sizeof(unsigned short);
|
||||
input_dev->keycodemax = ARRAY_SIZE(atlas_keymap);
|
||||
input_dev->keycode = atlas->keymap;
|
||||
input_dev->keycodesize = sizeof(atlas->keymap[0]);
|
||||
input_dev->keycodemax = ARRAY_SIZE(atlas->keymap);
|
||||
|
||||
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(atlas->keymap); i++) {
|
||||
if (i < 9) {
|
||||
atlas_keymap[i] = KEY_F1 + i;
|
||||
__set_bit(KEY_F1 + i, input_dev->keybit);
|
||||
} else
|
||||
atlas_keymap[i] = KEY_RESERVED;
|
||||
atlas->keymap[i] = KEY_F1 + i;
|
||||
input_set_capability(input_dev, EV_KEY, KEY_F1 + i);
|
||||
} else {
|
||||
atlas->keymap[i] = KEY_RESERVED;
|
||||
}
|
||||
}
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
pr_err("couldn't register input device\n");
|
||||
input_free_device(input_dev);
|
||||
return err;
|
||||
}
|
||||
if (err)
|
||||
return dev_err_probe(&pdev->dev, err,
|
||||
"couldn't register input device\n");
|
||||
|
||||
/* hookup button handler */
|
||||
status = acpi_install_address_space_handler(device->handle,
|
||||
0x81, &acpi_atlas_button_handler,
|
||||
&acpi_atlas_button_setup, device);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("error installing addr spc handler\n");
|
||||
input_unregister_device(input_dev);
|
||||
err = -EINVAL;
|
||||
}
|
||||
0x81,
|
||||
&acpi_atlas_button_handler,
|
||||
&acpi_atlas_button_setup,
|
||||
atlas);
|
||||
if (ACPI_FAILURE(status))
|
||||
return dev_err_probe(&pdev->dev, -EINVAL,
|
||||
"error installing addr spc handler\n");
|
||||
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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,
|
||||
0x81, &acpi_atlas_button_handler);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("error removing addr spc handler\n");
|
||||
|
||||
input_unregister_device(input_dev);
|
||||
acpi_remove_address_space_handler(device->handle, 0x81,
|
||||
&acpi_atlas_button_handler);
|
||||
}
|
||||
|
||||
static const struct acpi_device_id atlas_device_ids[] = {
|
||||
{"ASIM0000", 0},
|
||||
{"", 0},
|
||||
{ "ASIM0000" },
|
||||
{ "" }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
|
||||
|
||||
@@ -144,4 +146,3 @@ module_platform_driver(atlas_acpi_driver);
|
||||
MODULE_AUTHOR("Jaya Kumar");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Atlas button driver");
|
||||
|
||||
|
||||
@@ -257,7 +257,7 @@ static const struct of_device_id atmel_captouch_of_id[] = {
|
||||
MODULE_DEVICE_TABLE(of, atmel_captouch_of_id);
|
||||
|
||||
static const struct i2c_device_id atmel_captouch_id[] = {
|
||||
{ "atmel_captouch" },
|
||||
{ .name = "atmel_captouch" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, atmel_captouch_id);
|
||||
|
||||
@@ -536,9 +536,9 @@ static int __maybe_unused bma150_resume(struct device *dev)
|
||||
static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
|
||||
|
||||
static const struct i2c_device_id bma150_id[] = {
|
||||
{ "bma150" },
|
||||
{ "smb380" },
|
||||
{ "bma023" },
|
||||
{ .name = "bma150" },
|
||||
{ .name = "smb380" },
|
||||
{ .name = "bma023" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ static const struct dev_pm_ops cma3000_i2c_pm_ops = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id cma3000_i2c_id[] = {
|
||||
{ "cma3000_d01" },
|
||||
{ .name = "cma3000_d01" },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -1305,7 +1305,7 @@ MODULE_DEVICE_TABLE(of, da7280_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id da7280_i2c_id[] = {
|
||||
{ "da7280", },
|
||||
{ .name = "da7280" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
|
||||
|
||||
@@ -630,10 +630,10 @@ 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" },
|
||||
{ .name = "drv2604" },
|
||||
{ .name = "drv2604l" },
|
||||
{ .name = "drv2605" },
|
||||
{ .name = "drv2605l" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, drv260x_id);
|
||||
|
||||
@@ -281,7 +281,7 @@ static int drv2665_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
|
||||
|
||||
static const struct i2c_device_id drv2665_id[] = {
|
||||
{ "drv2665" },
|
||||
{ .name = "drv2665" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, drv2665_id);
|
||||
|
||||
@@ -458,7 +458,7 @@ static int drv2667_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
|
||||
|
||||
static const struct i2c_device_id drv2667_id[] = {
|
||||
{ "drv2667" },
|
||||
{ .name = "drv2667" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, drv2667_id);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/leds.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/usb/input.h>
|
||||
#include <linux/usb/cdc.h>
|
||||
@@ -406,7 +407,16 @@ static void ims_pcu_destroy_gamepad(struct ims_pcu *pcu)
|
||||
|
||||
static void ims_pcu_report_events(struct ims_pcu *pcu)
|
||||
{
|
||||
u32 data = get_unaligned_be32(&pcu->read_buf[3]);
|
||||
u32 data;
|
||||
|
||||
/* 6-axis setting (1 byte) + button data + checksum */
|
||||
if (pcu->read_pos < IMS_PCU_DATA_OFFSET + 1 + sizeof(data) + 1) {
|
||||
dev_warn(pcu->dev, "Short buttons report: %d bytes\n",
|
||||
pcu->read_pos);
|
||||
return;
|
||||
}
|
||||
|
||||
data = get_unaligned_be32(&pcu->read_buf[IMS_PCU_DATA_OFFSET + 1]);
|
||||
|
||||
ims_pcu_buttons_report(pcu, data & ~IMS_PCU_GAMEPAD_MASK);
|
||||
if (pcu->gamepad)
|
||||
@@ -440,7 +450,7 @@ 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_stx = false;
|
||||
pcu->have_dle = false;
|
||||
pcu->read_pos = 0;
|
||||
pcu->check_sum = 0;
|
||||
@@ -686,11 +696,19 @@ static int __ims_pcu_execute_bl_command(struct ims_pcu *pcu,
|
||||
return error;
|
||||
}
|
||||
|
||||
if (expected_response && pcu->cmd_buf[2] != expected_response) {
|
||||
dev_err(pcu->dev,
|
||||
"Unexpected response from bootloader: 0x%02x, wanted 0x%02x\n",
|
||||
pcu->cmd_buf[2], expected_response);
|
||||
return -EINVAL;
|
||||
if (expected_response) {
|
||||
if (pcu->cmd_buf_len < 3) {
|
||||
dev_err(pcu->dev, "Short response from bootloader: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf[2] != expected_response) {
|
||||
dev_err(pcu->dev,
|
||||
"Unexpected response from bootloader: 0x%02x, wanted 0x%02x\n",
|
||||
pcu->cmd_buf[2], expected_response);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -718,6 +736,12 @@ static int ims_pcu_get_info(struct ims_pcu *pcu)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + IMS_PCU_SET_INFO_SIZE + 1) {
|
||||
dev_err(pcu->dev, "Short GET_INFO response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(pcu->part_number,
|
||||
&pcu->cmd_buf[IMS_PCU_INFO_PART_OFFSET],
|
||||
sizeof(pcu->part_number));
|
||||
@@ -815,6 +839,12 @@ static int ims_pcu_verify_block(struct ims_pcu *pcu,
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_BL_DATA_OFFSET + sizeof(*fragment) + len + 1) {
|
||||
dev_err(pcu->dev, "Short READ_APP response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fragment = (void *)&pcu->cmd_buf[IMS_PCU_BL_DATA_OFFSET];
|
||||
if (get_unaligned_le32(&fragment->addr) != addr ||
|
||||
fragment->len != len) {
|
||||
@@ -934,9 +964,10 @@ static int ims_pcu_handle_firmware_update(struct ims_pcu *pcu,
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void ims_pcu_process_async_firmware(const struct firmware *fw,
|
||||
static void ims_pcu_process_async_firmware(const struct firmware *_fw,
|
||||
void *context)
|
||||
{
|
||||
const struct firmware *fw __free(firmware) = _fw;
|
||||
struct ims_pcu *pcu = context;
|
||||
int error;
|
||||
|
||||
@@ -956,8 +987,6 @@ static void ims_pcu_process_async_firmware(const struct firmware *fw,
|
||||
scoped_guard(mutex, &pcu->cmd_mutex)
|
||||
ims_pcu_handle_firmware_update(pcu, fw);
|
||||
|
||||
release_firmware(fw);
|
||||
|
||||
out:
|
||||
complete(&pcu->async_firmware_done);
|
||||
}
|
||||
@@ -1009,6 +1038,10 @@ ims_pcu_backlight_get_brightness(struct led_classdev *cdev)
|
||||
error);
|
||||
/* Assume the LED is OFF */
|
||||
brightness = LED_OFF;
|
||||
} else if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 2 + 1) {
|
||||
dev_err(pcu->dev, "Short GET_BRIGHTNESS response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
brightness = LED_OFF;
|
||||
} else {
|
||||
brightness =
|
||||
get_unaligned_le16(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
|
||||
@@ -1153,6 +1186,8 @@ static ssize_t ims_pcu_reset_device(struct device *dev,
|
||||
|
||||
dev_info(pcu->dev, "Attempting to reset device\n");
|
||||
|
||||
guard(mutex)(&pcu->cmd_mutex);
|
||||
|
||||
error = ims_pcu_execute_command(pcu, PCU_RESET, &reset_byte, 1);
|
||||
if (error) {
|
||||
dev_info(pcu->dev,
|
||||
@@ -1249,6 +1284,9 @@ static umode_t ims_pcu_is_attr_visible(struct kobject *kobj,
|
||||
struct ims_pcu *pcu = usb_get_intfdata(intf);
|
||||
umode_t mode = attr->mode;
|
||||
|
||||
if (intf != pcu->ctrl_intf)
|
||||
return 0;
|
||||
|
||||
if (pcu->bootloader_mode) {
|
||||
if (attr != &dev_attr_update_firmware_status.attr &&
|
||||
attr != &dev_attr_update_firmware.attr &&
|
||||
@@ -1282,6 +1320,12 @@ static int ims_pcu_read_ofn_config(struct ims_pcu *pcu, u8 addr, u8 *data)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (pcu->cmd_buf_len < OFN_REG_RESULT_OFFSET + 2 + 1) {
|
||||
dev_err(pcu->dev, "Short OFN_GET_CONFIG response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
|
||||
if (result < 0)
|
||||
return -EIO;
|
||||
@@ -1302,6 +1346,12 @@ static int ims_pcu_write_ofn_config(struct ims_pcu *pcu, u8 addr, u8 data)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (pcu->cmd_buf_len < OFN_REG_RESULT_OFFSET + 2 + 1) {
|
||||
dev_err(pcu->dev, "Short OFN_SET_CONFIG response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
result = (s16)get_unaligned_le16(pcu->cmd_buf + OFN_REG_RESULT_OFFSET);
|
||||
if (result < 0)
|
||||
return -EIO;
|
||||
@@ -1488,6 +1538,9 @@ static umode_t ims_pcu_ofn_is_attr_visible(struct kobject *kobj,
|
||||
struct ims_pcu *pcu = usb_get_intfdata(intf);
|
||||
umode_t mode = attr->mode;
|
||||
|
||||
if (intf != pcu->ctrl_intf)
|
||||
return SYSFS_GROUP_INVISIBLE;
|
||||
|
||||
/*
|
||||
* PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor.
|
||||
*/
|
||||
@@ -1528,7 +1581,7 @@ static void ims_pcu_irq(struct urb *urb)
|
||||
}
|
||||
|
||||
dev_dbg(pcu->dev, "%s: received %d: %*ph\n", __func__,
|
||||
urb->actual_length, urb->actual_length, pcu->urb_in_buf);
|
||||
urb->actual_length, urb->actual_length, urb->transfer_buffer);
|
||||
|
||||
if (urb == pcu->urb_in)
|
||||
ims_pcu_process_data(pcu, urb);
|
||||
@@ -1656,8 +1709,9 @@ ims_pcu_get_cdc_union_desc(struct usb_interface *intf)
|
||||
while (buflen >= sizeof(*union_desc)) {
|
||||
union_desc = (struct usb_cdc_union_desc *)buf;
|
||||
|
||||
if (union_desc->bLength > buflen) {
|
||||
dev_err(&intf->dev, "Too large descriptor\n");
|
||||
if (union_desc->bLength < 2 || union_desc->bLength > buflen) {
|
||||
dev_err(&intf->dev, "Invalid descriptor length: %d\n",
|
||||
union_desc->bLength);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -1693,7 +1747,7 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
|
||||
|
||||
pcu->ctrl_intf = usb_ifnum_to_if(pcu->udev,
|
||||
union_desc->bMasterInterface0);
|
||||
if (!pcu->ctrl_intf)
|
||||
if (pcu->ctrl_intf != intf)
|
||||
return -EINVAL;
|
||||
|
||||
alt = pcu->ctrl_intf->cur_altsetting;
|
||||
@@ -1702,6 +1756,12 @@ static int ims_pcu_parse_cdc_data(struct usb_interface *intf, struct ims_pcu *pc
|
||||
return -ENODEV;
|
||||
|
||||
pcu->ep_ctrl = &alt->endpoint[0].desc;
|
||||
if (!usb_endpoint_is_int_in(pcu->ep_ctrl)) {
|
||||
dev_err(pcu->dev,
|
||||
"Control endpoint is not INTERRUPT IN\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pcu->max_ctrl_size = usb_endpoint_maxp(pcu->ep_ctrl);
|
||||
|
||||
pcu->data_intf = usb_ifnum_to_if(pcu->udev,
|
||||
@@ -1783,11 +1843,16 @@ static void ims_pcu_stop_io(struct ims_pcu *pcu)
|
||||
static int ims_pcu_line_setup(struct ims_pcu *pcu)
|
||||
{
|
||||
struct usb_host_interface *interface = pcu->ctrl_intf->cur_altsetting;
|
||||
struct usb_cdc_line_coding *line = (void *)pcu->cmd_buf;
|
||||
struct usb_cdc_line_coding *line __free(kfree) =
|
||||
kmalloc(sizeof(*line), GFP_KERNEL);
|
||||
int error;
|
||||
|
||||
memset(line, 0, sizeof(*line));
|
||||
if (!line)
|
||||
return -ENOMEM;
|
||||
|
||||
line->dwDTERate = cpu_to_le32(57600);
|
||||
line->bCharFormat = USB_CDC_1_STOP_BITS;
|
||||
line->bParityType = USB_CDC_NO_PARITY;
|
||||
line->bDataBits = 8;
|
||||
|
||||
error = usb_control_msg(pcu->udev, usb_sndctrlpipe(pcu->udev, 0),
|
||||
@@ -1831,6 +1896,12 @@ static int ims_pcu_get_device_info(struct ims_pcu *pcu)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 6 + 1) {
|
||||
dev_err(pcu->dev, "Short GET_FW_VERSION response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
snprintf(pcu->fw_version, sizeof(pcu->fw_version),
|
||||
"%02d%02d%02d%02d.%c%c",
|
||||
pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5],
|
||||
@@ -1843,6 +1914,12 @@ static int ims_pcu_get_device_info(struct ims_pcu *pcu)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 6 + 1) {
|
||||
dev_err(pcu->dev, "Short GET_BL_VERSION response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
snprintf(pcu->bl_version, sizeof(pcu->bl_version),
|
||||
"%02d%02d%02d%02d.%c%c",
|
||||
pcu->cmd_buf[2], pcu->cmd_buf[3], pcu->cmd_buf[4], pcu->cmd_buf[5],
|
||||
@@ -1855,6 +1932,12 @@ static int ims_pcu_get_device_info(struct ims_pcu *pcu)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 1 + 1) {
|
||||
dev_err(pcu->dev, "Short RESET_REASON response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
snprintf(pcu->reset_reason, sizeof(pcu->reset_reason),
|
||||
"%02x", pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
|
||||
|
||||
@@ -1881,6 +1964,12 @@ static int ims_pcu_identify_type(struct ims_pcu *pcu, u8 *device_id)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 1 + 1) {
|
||||
dev_err(pcu->dev, "Short GET_DEVICE_ID response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*device_id = pcu->cmd_buf[IMS_PCU_DATA_OFFSET];
|
||||
dev_dbg(pcu->dev, "Detected device ID: %d\n", *device_id);
|
||||
|
||||
@@ -1972,6 +2061,12 @@ static int ims_pcu_init_bootloader_mode(struct ims_pcu *pcu)
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pcu->cmd_buf_len < IMS_PCU_DATA_OFFSET + 15 + 4 + 1) {
|
||||
dev_err(pcu->dev, "Short QUERY_DEVICE response: %d bytes\n",
|
||||
pcu->cmd_buf_len);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
pcu->fw_start_addr =
|
||||
get_unaligned_le32(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET + 11]);
|
||||
pcu->fw_end_addr =
|
||||
@@ -2071,7 +2166,6 @@ static int ims_pcu_probe(struct usb_interface *intf,
|
||||
static void ims_pcu_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct ims_pcu *pcu = usb_get_intfdata(intf);
|
||||
struct usb_host_interface *alt = intf->cur_altsetting;
|
||||
|
||||
usb_set_intfdata(intf, NULL);
|
||||
|
||||
@@ -2079,7 +2173,7 @@ static void ims_pcu_disconnect(struct usb_interface *intf)
|
||||
* See if we are dealing with control or data interface. The cleanup
|
||||
* happens when we unbind primary (control) interface.
|
||||
*/
|
||||
if (alt->desc.bInterfaceClass != USB_CLASS_COMM)
|
||||
if (intf != pcu->ctrl_intf)
|
||||
return;
|
||||
|
||||
ims_pcu_stop_io(pcu);
|
||||
@@ -2090,6 +2184,7 @@ static void ims_pcu_disconnect(struct usb_interface *intf)
|
||||
ims_pcu_destroy_application_mode(pcu);
|
||||
|
||||
ims_pcu_buffers_free(pcu);
|
||||
usb_driver_release_interface(&ims_pcu_driver, pcu->data_intf);
|
||||
kfree(pcu);
|
||||
}
|
||||
|
||||
|
||||
@@ -525,7 +525,7 @@ static int kxtj9_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
|
||||
|
||||
static const struct i2c_device_id kxtj9_id[] = {
|
||||
{ NAME },
|
||||
{ .name = NAME },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -200,7 +200,7 @@ static int mma8450_probe(struct i2c_client *c)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id mma8450_id[] = {
|
||||
{ MMA8450_DRV_NAME },
|
||||
{ .name = MMA8450_DRV_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mma8450_id);
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Input driver for PCAP events:
|
||||
* * Power key
|
||||
* * Headphone button
|
||||
*
|
||||
* Copyright (c) 2008,2009 Ilya Petrov <ilya.muromec@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/ezx-pcap.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
struct pcap_keys {
|
||||
struct pcap_chip *pcap;
|
||||
struct input_dev *input;
|
||||
};
|
||||
|
||||
/* PCAP2 interrupts us on keypress */
|
||||
static irqreturn_t pcap_keys_handler(int irq, void *_pcap_keys)
|
||||
{
|
||||
struct pcap_keys *pcap_keys = _pcap_keys;
|
||||
int pirq = irq_to_pcap(pcap_keys->pcap, irq);
|
||||
u32 pstat;
|
||||
|
||||
ezx_pcap_read(pcap_keys->pcap, PCAP_REG_PSTAT, &pstat);
|
||||
pstat &= 1 << pirq;
|
||||
|
||||
switch (pirq) {
|
||||
case PCAP_IRQ_ONOFF:
|
||||
input_report_key(pcap_keys->input, KEY_POWER, !pstat);
|
||||
break;
|
||||
case PCAP_IRQ_MIC:
|
||||
input_report_key(pcap_keys->input, KEY_HP, !pstat);
|
||||
break;
|
||||
}
|
||||
|
||||
input_sync(pcap_keys->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pcap_keys_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err = -ENOMEM;
|
||||
struct pcap_keys *pcap_keys;
|
||||
struct input_dev *input_dev;
|
||||
|
||||
pcap_keys = kmalloc_obj(*pcap_keys);
|
||||
if (!pcap_keys)
|
||||
return err;
|
||||
|
||||
pcap_keys->pcap = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
goto fail;
|
||||
|
||||
pcap_keys->input = input_dev;
|
||||
|
||||
platform_set_drvdata(pdev, pcap_keys);
|
||||
input_dev->name = pdev->name;
|
||||
input_dev->phys = "pcap-keys/input0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
|
||||
__set_bit(EV_KEY, input_dev->evbit);
|
||||
__set_bit(KEY_POWER, input_dev->keybit);
|
||||
__set_bit(KEY_HP, input_dev->keybit);
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err)
|
||||
goto fail_allocate;
|
||||
|
||||
err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF),
|
||||
pcap_keys_handler, 0, "Power key", pcap_keys);
|
||||
if (err)
|
||||
goto fail_register;
|
||||
|
||||
err = request_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC),
|
||||
pcap_keys_handler, 0, "Headphone button", pcap_keys);
|
||||
if (err)
|
||||
goto fail_pwrkey;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_pwrkey:
|
||||
free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys);
|
||||
fail_register:
|
||||
input_unregister_device(input_dev);
|
||||
goto fail;
|
||||
fail_allocate:
|
||||
input_free_device(input_dev);
|
||||
fail:
|
||||
kfree(pcap_keys);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pcap_keys_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pcap_keys *pcap_keys = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_ONOFF), pcap_keys);
|
||||
free_irq(pcap_to_irq(pcap_keys->pcap, PCAP_IRQ_MIC), pcap_keys);
|
||||
|
||||
input_unregister_device(pcap_keys->input);
|
||||
kfree(pcap_keys);
|
||||
}
|
||||
|
||||
static struct platform_driver pcap_keys_device_driver = {
|
||||
.probe = pcap_keys_probe,
|
||||
.remove = pcap_keys_remove,
|
||||
.driver = {
|
||||
.name = "pcap-keys",
|
||||
}
|
||||
};
|
||||
module_platform_driver(pcap_keys_device_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Motorola PCAP2 input events driver");
|
||||
MODULE_AUTHOR("Ilya Petrov <ilya.muromec@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pcap_keys");
|
||||
@@ -189,7 +189,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pcf8574_kp_pm_ops,
|
||||
pcf8574_kp_suspend, pcf8574_kp_resume);
|
||||
|
||||
static const struct i2c_device_id pcf8574_kp_id[] = {
|
||||
{ DRV_NAME },
|
||||
{ .name = DRV_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
|
||||
|
||||
@@ -22,15 +22,6 @@
|
||||
* - Olivier Vandorpe, for providing the usbb2k-api.
|
||||
* - Martin Diehl, for spotting my memory allocation bug.
|
||||
*
|
||||
* History:
|
||||
* 20050527 henk First version, functional keyboard. Keyboard events
|
||||
* will pop-up on the ../input/eventX bus.
|
||||
* 20050531 henk Added led, LCD, dialtone and sysfs interface.
|
||||
* 20050610 henk Cleanups, make it ready for public consumption.
|
||||
* 20050630 henk Cleanups, fixes in response to comments.
|
||||
* 20050701 henk sysfs write serialisation, fix potential unload races
|
||||
* 20050801 henk Added ringtone, restructure USB
|
||||
* 20050816 henk Merge 2.6.13-rc6
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -1456,7 +1456,7 @@ static const struct dev_pm_ops cyapa_pm_ops = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id cyapa_id_table[] = {
|
||||
{ "cyapa" },
|
||||
{ .name = "cyapa" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
|
||||
|
||||
@@ -428,8 +428,17 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
data->width_x = data->max_x / x_traces;
|
||||
data->width_y = data->max_y / y_traces;
|
||||
|
||||
if (!x_traces || !y_traces) {
|
||||
dev_warn(&client->dev,
|
||||
"invalid trace numbers: x=%u, y=%u\n",
|
||||
x_traces, y_traces);
|
||||
data->width_x = 1;
|
||||
data->width_y = 1;
|
||||
} else {
|
||||
data->width_x = data->max_x / x_traces;
|
||||
data->width_y = data->max_y / y_traces;
|
||||
}
|
||||
|
||||
if (device_property_read_u32(&client->dev,
|
||||
"touchscreen-x-mm", &x_mm) ||
|
||||
@@ -443,8 +452,16 @@ static int elan_query_device_parameters(struct elan_tp_data *data)
|
||||
data->x_res = elan_convert_resolution(hw_x_res, data->pattern);
|
||||
data->y_res = elan_convert_resolution(hw_y_res, data->pattern);
|
||||
} else {
|
||||
data->x_res = (data->max_x + 1) / x_mm;
|
||||
data->y_res = (data->max_y + 1) / y_mm;
|
||||
if (unlikely(x_mm == 0 || y_mm == 0)) {
|
||||
dev_warn(&client->dev,
|
||||
"invalid physical dimensions: x_mm=%u, y_mm=%u\n",
|
||||
x_mm, y_mm);
|
||||
data->x_res = 1;
|
||||
data->y_res = 1;
|
||||
} else {
|
||||
data->x_res = (data->max_x + 1) / x_mm;
|
||||
data->y_res = (data->max_y + 1) / y_mm;
|
||||
}
|
||||
}
|
||||
|
||||
if (device_property_read_bool(&client->dev, "elan,clickpad"))
|
||||
@@ -956,6 +973,7 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num,
|
||||
|
||||
if (data->report_features & ETP_FEATURE_REPORT_MK) {
|
||||
unsigned int mk_x, mk_y, area_x, area_y;
|
||||
int adj_width_x, adj_width_y;
|
||||
u8 mk_data = high_precision ?
|
||||
packet[ETP_MK_DATA_OFFSET + contact_num] :
|
||||
finger_data[3];
|
||||
@@ -967,8 +985,14 @@ static void elan_report_contact(struct elan_tp_data *data, int contact_num,
|
||||
* To avoid treating large finger as palm, let's reduce
|
||||
* the width x and y per trace.
|
||||
*/
|
||||
area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
|
||||
area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
|
||||
|
||||
adj_width_x = data->width_x > ETP_FWIDTH_REDUCE ?
|
||||
data->width_x - ETP_FWIDTH_REDUCE : 0;
|
||||
adj_width_y = data->width_y > ETP_FWIDTH_REDUCE ?
|
||||
data->width_y - ETP_FWIDTH_REDUCE : 0;
|
||||
|
||||
area_x = mk_x * adj_width_x;
|
||||
area_y = mk_y * adj_width_y;
|
||||
|
||||
input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
|
||||
input_report_abs(input, ABS_MT_TOUCH_MAJOR,
|
||||
@@ -1407,7 +1431,7 @@ static int elan_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
|
||||
|
||||
static const struct i2c_device_id elan_id[] = {
|
||||
{ DRIVER_NAME },
|
||||
{ .name = DRIVER_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, elan_id);
|
||||
|
||||
@@ -607,7 +607,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(synaptics_i2c_pm, synaptics_i2c_suspend,
|
||||
synaptics_i2c_resume);
|
||||
|
||||
static const struct i2c_device_id synaptics_i2c_id_table[] = {
|
||||
{ "synaptics_i2c" },
|
||||
{ .name = "synaptics_i2c" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table);
|
||||
|
||||
@@ -56,8 +56,8 @@ struct rmi_2d_sensor {
|
||||
u16 max_y;
|
||||
u8 nbr_fingers;
|
||||
u8 *data_pkt;
|
||||
int pkt_size;
|
||||
int attn_size;
|
||||
u32 pkt_size;
|
||||
u32 attn_size;
|
||||
bool topbuttonpad;
|
||||
enum rmi_sensor_type sensor_type;
|
||||
struct input_dev *input;
|
||||
|
||||
@@ -237,36 +237,44 @@ static int rmi_function_remove(struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rmi_function *rmi_alloc_function(struct rmi_device *rmi_dev, u8 id)
|
||||
{
|
||||
struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct rmi_function *fn;
|
||||
|
||||
fn = kzalloc_flex(*fn, irq_mask, BITS_TO_LONGS(data->irq_count));
|
||||
if (!fn)
|
||||
return NULL;
|
||||
|
||||
device_initialize(&fn->dev);
|
||||
|
||||
dev_set_name(&fn->dev, "%s.fn%02x", dev_name(&rmi_dev->dev), id);
|
||||
|
||||
fn->dev.parent = &rmi_dev->dev;
|
||||
fn->dev.type = &rmi_function_type;
|
||||
fn->dev.bus = &rmi_bus_type;
|
||||
fn->rmi_dev = rmi_dev;
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
int rmi_register_function(struct rmi_function *fn)
|
||||
{
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
int error;
|
||||
|
||||
device_initialize(&fn->dev);
|
||||
|
||||
dev_set_name(&fn->dev, "%s.fn%02x",
|
||||
dev_name(&rmi_dev->dev), fn->fd.function_number);
|
||||
|
||||
fn->dev.parent = &rmi_dev->dev;
|
||||
fn->dev.type = &rmi_function_type;
|
||||
fn->dev.bus = &rmi_bus_type;
|
||||
|
||||
error = device_add(&fn->dev);
|
||||
if (error) {
|
||||
dev_err(&rmi_dev->dev,
|
||||
"Failed device_register function device %s\n",
|
||||
"Failed to register function device %s\n",
|
||||
dev_name(&fn->dev));
|
||||
goto err_put_device;
|
||||
return error;
|
||||
}
|
||||
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Registered F%02X.\n",
|
||||
fn->fd.function_number);
|
||||
|
||||
return 0;
|
||||
|
||||
err_put_device:
|
||||
put_device(&fn->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
void rmi_unregister_function(struct rmi_function *fn)
|
||||
@@ -455,11 +463,13 @@ static int __init rmi_bus_init(void)
|
||||
if (error) {
|
||||
pr_err("%s: error registering the RMI physical driver: %d\n",
|
||||
__func__, error);
|
||||
goto err_unregister_bus;
|
||||
goto err_unregister_function_handlers;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_unregister_function_handlers:
|
||||
rmi_unregister_function_handlers();
|
||||
err_unregister_bus:
|
||||
bus_unregister(&rmi_bus_type);
|
||||
return error;
|
||||
|
||||
@@ -49,6 +49,7 @@ struct rmi_function {
|
||||
|
||||
bool rmi_is_function_device(struct device *dev);
|
||||
|
||||
struct rmi_function *rmi_alloc_function(struct rmi_device *rmi_dev, u8 id);
|
||||
int __must_check rmi_register_function(struct rmi_function *);
|
||||
void rmi_unregister_function(struct rmi_function *);
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <uapi/linux/input.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include "rmi_bus.h"
|
||||
#include "rmi_driver.h"
|
||||
|
||||
@@ -182,7 +183,11 @@ void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status,
|
||||
attn_data.size = size;
|
||||
attn_data.data = fifo_data;
|
||||
|
||||
kfifo_put(&drvdata->attn_fifo, attn_data);
|
||||
if (!kfifo_put(&drvdata->attn_fifo, attn_data)) {
|
||||
dev_warn_ratelimited(&rmi_dev->dev,
|
||||
"Failed to enqueue attention data, FIFO full\n");
|
||||
kfree(fifo_data);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rmi_set_attn_data);
|
||||
|
||||
@@ -193,24 +198,24 @@ static irqreturn_t rmi_irq_fn(int irq, void *dev_id)
|
||||
struct rmi4_attn_data attn_data = {0};
|
||||
int ret, count;
|
||||
|
||||
count = kfifo_get(&drvdata->attn_fifo, &attn_data);
|
||||
if (count) {
|
||||
*(drvdata->irq_status) = attn_data.irq_status;
|
||||
drvdata->attn_data = attn_data;
|
||||
}
|
||||
do {
|
||||
count = kfifo_get(&drvdata->attn_fifo, &attn_data);
|
||||
if (count) {
|
||||
*drvdata->irq_status = attn_data.irq_status;
|
||||
drvdata->attn_data = attn_data;
|
||||
}
|
||||
|
||||
ret = rmi_process_interrupt_requests(rmi_dev);
|
||||
if (ret)
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
|
||||
"Failed to process interrupt request: %d\n", ret);
|
||||
ret = rmi_process_interrupt_requests(rmi_dev);
|
||||
if (ret)
|
||||
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev,
|
||||
"Failed to process interrupt request: %d\n",
|
||||
ret);
|
||||
|
||||
if (count) {
|
||||
kfree(attn_data.data);
|
||||
drvdata->attn_data.data = NULL;
|
||||
}
|
||||
|
||||
if (!kfifo_is_empty(&drvdata->attn_fifo))
|
||||
return rmi_irq_fn(irq, dev_id);
|
||||
if (count) {
|
||||
kfree(attn_data.data);
|
||||
drvdata->attn_data.data = NULL;
|
||||
}
|
||||
} while (!kfifo_is_empty(&drvdata->attn_fifo));
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -383,9 +388,8 @@ static int rmi_driver_set_irq_bits(struct rmi_device *rmi_dev,
|
||||
__func__);
|
||||
goto error_unlock;
|
||||
}
|
||||
bitmap_copy(data->current_irq_mask, data->new_irq_mask,
|
||||
data->num_of_irq_regs);
|
||||
|
||||
bitmap_copy(data->current_irq_mask, data->new_irq_mask, data->irq_count);
|
||||
bitmap_or(data->fn_irq_bits, data->fn_irq_bits, mask, data->irq_count);
|
||||
|
||||
error_unlock:
|
||||
@@ -414,8 +418,8 @@ static int rmi_driver_clear_irq_bits(struct rmi_device *rmi_dev,
|
||||
__func__);
|
||||
goto error_unlock;
|
||||
}
|
||||
bitmap_copy(data->current_irq_mask, data->new_irq_mask,
|
||||
data->num_of_irq_regs);
|
||||
|
||||
bitmap_copy(data->current_irq_mask, data->new_irq_mask, data->irq_count);
|
||||
|
||||
error_unlock:
|
||||
mutex_unlock(&data->irq_mutex);
|
||||
@@ -558,30 +562,75 @@ int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx,
|
||||
return retval < 0 ? retval : 0;
|
||||
}
|
||||
|
||||
int rmi_read_register_desc(struct rmi_device *d, u16 addr,
|
||||
struct rmi_register_descriptor *rdesc)
|
||||
static int rmi_parse_register_desc_item(struct rmi_register_desc_item *item,
|
||||
const u8 *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
unsigned int offset = 0;
|
||||
unsigned int map_offset = 0;
|
||||
int b;
|
||||
|
||||
if (offset >= size)
|
||||
return -EIO;
|
||||
|
||||
item->reg_size = buf[offset++];
|
||||
if (item->reg_size == 0) {
|
||||
if (size - offset < 2)
|
||||
return -EIO;
|
||||
item->reg_size = get_unaligned_le16(&buf[offset]);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
if (item->reg_size == 0) {
|
||||
if (size - offset < 4)
|
||||
return -EIO;
|
||||
item->reg_size = get_unaligned_le32(&buf[offset]);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
do {
|
||||
if (offset >= size)
|
||||
return -EIO;
|
||||
|
||||
for (b = 0; b < 7; b++) {
|
||||
if (buf[offset] & BIT(b)) {
|
||||
if (map_offset >= RMI_REG_DESC_SUBPACKET_BITS)
|
||||
return -EIO;
|
||||
__set_bit(map_offset, item->subpacket_map);
|
||||
}
|
||||
++map_offset;
|
||||
}
|
||||
} while (buf[offset++] & BIT(7));
|
||||
|
||||
item->num_subpackets = bitmap_weight(item->subpacket_map,
|
||||
RMI_REG_DESC_SUBPACKET_BITS);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
int rmi_read_register_desc(struct rmi_device *d, u16 addr,
|
||||
struct rmi_register_descriptor *rdesc)
|
||||
{
|
||||
DECLARE_BITMAP(presence_map, RMI_REG_DESC_PRESENCE_BITS);
|
||||
u8 buf[RMI_REG_DESC_PRESENCE_REGS_MAX];
|
||||
u8 size_presence_reg;
|
||||
u8 buf[35];
|
||||
int presense_offset = 1;
|
||||
u8 *struct_buf;
|
||||
int reg;
|
||||
int offset = 0;
|
||||
int map_offset = 0;
|
||||
unsigned int presence_offset;
|
||||
unsigned int map_offset;
|
||||
unsigned int offset;
|
||||
unsigned int reg;
|
||||
int i;
|
||||
int b;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The first register of the register descriptor is the size of
|
||||
* the register descriptor's presense register.
|
||||
* the register descriptor's presence register.
|
||||
*/
|
||||
ret = rmi_read(d, addr, &size_presence_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
++addr;
|
||||
|
||||
if (size_presence_reg < 0 || size_presence_reg > 35)
|
||||
if (size_presence_reg < 1 || size_presence_reg > RMI_REG_DESC_PRESENCE_REGS_MAX)
|
||||
return -EIO;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
@@ -594,25 +643,33 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
|
||||
ret = rmi_read_block(d, addr, buf, size_presence_reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
++addr;
|
||||
addr += size_presence_reg;
|
||||
|
||||
if (buf[0] == 0) {
|
||||
presense_offset = 3;
|
||||
rdesc->struct_size = buf[1] | (buf[2] << 8);
|
||||
if (size_presence_reg < 3)
|
||||
return -EIO;
|
||||
presence_offset = 3;
|
||||
rdesc->struct_size = get_unaligned_le16(&buf[1]);
|
||||
} else {
|
||||
presence_offset = 1;
|
||||
rdesc->struct_size = buf[0];
|
||||
}
|
||||
|
||||
for (i = presense_offset; i < size_presence_reg; i++) {
|
||||
memset(presence_map, 0, sizeof(presence_map));
|
||||
map_offset = 0;
|
||||
for (i = presence_offset; i < size_presence_reg; i++) {
|
||||
for (b = 0; b < 8; b++) {
|
||||
if (buf[i] & (0x1 << b))
|
||||
bitmap_set(rdesc->presense_map, map_offset, 1);
|
||||
if (buf[i] & BIT(b)) {
|
||||
if (map_offset >= RMI_REG_DESC_PRESENCE_BITS)
|
||||
return -EIO;
|
||||
bitmap_set(presence_map, map_offset, 1);
|
||||
}
|
||||
++map_offset;
|
||||
}
|
||||
}
|
||||
|
||||
rdesc->num_registers = bitmap_weight(rdesc->presense_map,
|
||||
RMI_REG_DESC_PRESENSE_BITS);
|
||||
rdesc->num_registers = bitmap_weight(presence_map,
|
||||
RMI_REG_DESC_PRESENCE_BITS);
|
||||
|
||||
rdesc->registers = devm_kcalloc(&d->dev,
|
||||
rdesc->num_registers,
|
||||
@@ -626,7 +683,7 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
|
||||
* I'm not using devm_kzalloc here since it will not be retained
|
||||
* after exiting this function
|
||||
*/
|
||||
struct_buf = kzalloc(rdesc->struct_size, GFP_KERNEL);
|
||||
u8 *struct_buf __free(kfree) = kzalloc(rdesc->struct_size, GFP_KERNEL);
|
||||
if (!struct_buf)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -638,56 +695,32 @@ int rmi_read_register_desc(struct rmi_device *d, u16 addr,
|
||||
*/
|
||||
ret = rmi_read_block(d, addr, struct_buf, rdesc->struct_size);
|
||||
if (ret)
|
||||
goto free_struct_buff;
|
||||
return ret;
|
||||
|
||||
reg = find_first_bit(rdesc->presense_map, RMI_REG_DESC_PRESENSE_BITS);
|
||||
reg = find_first_bit(presence_map, RMI_REG_DESC_PRESENCE_BITS);
|
||||
offset = 0;
|
||||
for (i = 0; i < rdesc->num_registers; i++) {
|
||||
struct rmi_register_desc_item *item = &rdesc->registers[i];
|
||||
int reg_size = struct_buf[offset];
|
||||
int item_size;
|
||||
|
||||
++offset;
|
||||
if (reg_size == 0) {
|
||||
reg_size = struct_buf[offset] |
|
||||
(struct_buf[offset + 1] << 8);
|
||||
offset += 2;
|
||||
}
|
||||
|
||||
if (reg_size == 0) {
|
||||
reg_size = struct_buf[offset] |
|
||||
(struct_buf[offset + 1] << 8) |
|
||||
(struct_buf[offset + 2] << 16) |
|
||||
(struct_buf[offset + 3] << 24);
|
||||
offset += 4;
|
||||
}
|
||||
item_size = rmi_parse_register_desc_item(item,
|
||||
&struct_buf[offset],
|
||||
rdesc->struct_size - offset);
|
||||
if (item_size < 0)
|
||||
return item_size;
|
||||
|
||||
item->reg = reg;
|
||||
item->reg_size = reg_size;
|
||||
|
||||
map_offset = 0;
|
||||
|
||||
do {
|
||||
for (b = 0; b < 7; b++) {
|
||||
if (struct_buf[offset] & (0x1 << b))
|
||||
bitmap_set(item->subpacket_map,
|
||||
map_offset, 1);
|
||||
++map_offset;
|
||||
}
|
||||
} while (struct_buf[offset++] & 0x80);
|
||||
|
||||
item->num_subpackets = bitmap_weight(item->subpacket_map,
|
||||
RMI_REG_DESC_SUBPACKET_BITS);
|
||||
offset += item_size;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_CORE, &d->dev,
|
||||
"%s: reg: %d reg size: %ld subpackets: %d\n", __func__,
|
||||
"%s: reg: %d reg size: %u subpackets: %d\n", __func__,
|
||||
item->reg, item->reg_size, item->num_subpackets);
|
||||
|
||||
reg = find_next_bit(rdesc->presense_map,
|
||||
RMI_REG_DESC_PRESENSE_BITS, reg + 1);
|
||||
reg = find_next_bit(presence_map,
|
||||
RMI_REG_DESC_PRESENCE_BITS, reg + 1);
|
||||
}
|
||||
|
||||
free_struct_buff:
|
||||
kfree(struct_buf);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct rmi_register_desc_item *rmi_get_register_desc_item(
|
||||
@@ -713,7 +746,7 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc)
|
||||
|
||||
for (i = 0; i < rdesc->num_registers; i++) {
|
||||
item = &rdesc->registers[i];
|
||||
size += item->reg_size;
|
||||
size = size_add(size, item->reg_size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
@@ -738,7 +771,7 @@ int rmi_register_desc_calc_reg_offset(
|
||||
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
|
||||
u8 subpacket)
|
||||
{
|
||||
return find_next_bit(item->subpacket_map, RMI_REG_DESC_PRESENSE_BITS,
|
||||
return find_next_bit(item->subpacket_map, RMI_REG_DESC_SUBPACKET_BITS,
|
||||
subpacket) == subpacket;
|
||||
}
|
||||
|
||||
@@ -839,9 +872,7 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
|
||||
rmi_dbg(RMI_DEBUG_CORE, dev, "Initializing F%02X.\n",
|
||||
pdt->function_number);
|
||||
|
||||
fn = kzalloc(sizeof(struct rmi_function) +
|
||||
BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long),
|
||||
GFP_KERNEL);
|
||||
fn = rmi_alloc_function(rmi_dev, pdt->function_number);
|
||||
if (!fn) {
|
||||
dev_err(dev, "Failed to allocate memory for F%02X\n",
|
||||
pdt->function_number);
|
||||
@@ -851,8 +882,6 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
|
||||
INIT_LIST_HEAD(&fn->node);
|
||||
rmi_driver_copy_pdt_to_fd(pdt, &fn->fd);
|
||||
|
||||
fn->rmi_dev = rmi_dev;
|
||||
|
||||
fn->num_of_irqs = pdt->interrupt_source_count;
|
||||
fn->irq_pos = *current_irq_count;
|
||||
*current_irq_count += fn->num_of_irqs;
|
||||
@@ -861,8 +890,10 @@ static int rmi_create_function(struct rmi_device *rmi_dev,
|
||||
set_bit(fn->irq_pos + i, fn->irq_mask);
|
||||
|
||||
error = rmi_register_function(fn);
|
||||
if (error)
|
||||
if (error) {
|
||||
put_device(&fn->dev);
|
||||
return error;
|
||||
}
|
||||
|
||||
if (pdt->function_number == 0x01)
|
||||
data->f01_container = fn;
|
||||
@@ -1133,6 +1164,7 @@ static int rmi_driver_probe(struct device *dev)
|
||||
return -ENOMEM;
|
||||
|
||||
INIT_LIST_HEAD(&data->function_list);
|
||||
INIT_KFIFO(data->attn_fifo);
|
||||
data->rmi_dev = rmi_dev;
|
||||
dev_set_drvdata(&rmi_dev->dev, data);
|
||||
|
||||
|
||||
@@ -46,16 +46,16 @@ struct pdt_entry {
|
||||
u8 function_number;
|
||||
};
|
||||
|
||||
#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE)
|
||||
#define RMI_REG_DESC_PRESENCE_BITS (32 * BITS_PER_BYTE)
|
||||
#define RMI_REG_DESC_PRESENCE_REGS_MAX (3 + RMI_REG_DESC_PRESENCE_BITS / 8)
|
||||
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
|
||||
|
||||
/* describes a single packet register */
|
||||
struct rmi_register_desc_item {
|
||||
u32 reg_size;
|
||||
u16 reg;
|
||||
unsigned long reg_size;
|
||||
u8 num_subpackets;
|
||||
unsigned long subpacket_map[BITS_TO_LONGS(
|
||||
RMI_REG_DESC_SUBPACKET_BITS)];
|
||||
u16 num_subpackets;
|
||||
DECLARE_BITMAP(subpacket_map, RMI_REG_DESC_SUBPACKET_BITS);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -64,8 +64,7 @@ struct rmi_register_desc_item {
|
||||
*/
|
||||
struct rmi_register_descriptor {
|
||||
unsigned long struct_size;
|
||||
unsigned long presense_map[BITS_TO_LONGS(RMI_REG_DESC_PRESENSE_BITS)];
|
||||
u8 num_registers;
|
||||
u16 num_registers;
|
||||
struct rmi_register_desc_item *registers;
|
||||
};
|
||||
|
||||
|
||||
@@ -1304,7 +1304,7 @@ static irqreturn_t rmi_f11_attention(int irq, void *ctx)
|
||||
struct f11_data *f11 = dev_get_drvdata(&fn->dev);
|
||||
u16 data_base_addr = fn->fd.data_base_addr;
|
||||
int error;
|
||||
int valid_bytes = f11->sensor.pkt_size;
|
||||
u32 valid_bytes = f11->sensor.pkt_size;
|
||||
|
||||
if (drvdata->attn_data.data) {
|
||||
/*
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/rmi.h>
|
||||
#include <linux/sizes.h>
|
||||
#include <linux/unaligned.h>
|
||||
#include "rmi_driver.h"
|
||||
#include "rmi_2d_sensor.h"
|
||||
|
||||
@@ -49,7 +51,6 @@ struct f12_data {
|
||||
const struct rmi_register_desc_item *data6;
|
||||
u16 data6_offset;
|
||||
|
||||
|
||||
/* F12 Data9 reports relative data */
|
||||
const struct rmi_register_desc_item *data9;
|
||||
u16 data9_offset;
|
||||
@@ -57,10 +58,39 @@ struct f12_data {
|
||||
const struct rmi_register_desc_item *data15;
|
||||
u16 data15_offset;
|
||||
|
||||
unsigned long *abs_mask;
|
||||
unsigned long *rel_mask;
|
||||
unsigned long irq_mask[];
|
||||
};
|
||||
|
||||
static int rmi_f12_read_register_descs(struct rmi_function *fn,
|
||||
struct f12_data *f12, u16 query_addr)
|
||||
{
|
||||
struct {
|
||||
struct rmi_register_descriptor *desc;
|
||||
const char *name;
|
||||
} descriptors[] = {
|
||||
{ &f12->query_reg_desc, "Query" },
|
||||
{ &f12->control_reg_desc, "Control" },
|
||||
{ &f12->data_reg_desc, "Data" },
|
||||
};
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
int error;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(descriptors); i++) {
|
||||
error = rmi_read_register_desc(rmi_dev, query_addr,
|
||||
descriptors[i].desc);
|
||||
if (error) {
|
||||
dev_err(&fn->dev,
|
||||
"Failed to read the %s Register Descriptor: %d\n",
|
||||
descriptors[i].name, error);
|
||||
return error;
|
||||
}
|
||||
query_addr += 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
{
|
||||
const struct rmi_register_desc_item *item;
|
||||
@@ -88,20 +118,20 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
|
||||
if (item->reg_size > sizeof(buf)) {
|
||||
dev_err(&fn->dev,
|
||||
"F12 control8 should be no bigger than %zd bytes, not: %ld\n",
|
||||
"F12 control8 should be no bigger than %zd bytes, not: %u\n",
|
||||
sizeof(buf), item->reg_size);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + offset, buf,
|
||||
item->reg_size);
|
||||
ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + offset,
|
||||
buf, item->reg_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
offset = 0;
|
||||
if (rmi_register_desc_has_subpacket(item, 0)) {
|
||||
sensor->max_x = (buf[offset + 1] << 8) | buf[offset];
|
||||
sensor->max_y = (buf[offset + 3] << 8) | buf[offset + 2];
|
||||
sensor->max_x = get_unaligned_le16(&buf[offset]);
|
||||
sensor->max_y = get_unaligned_le16(&buf[offset + 2]);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
@@ -109,8 +139,8 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
sensor->max_x, sensor->max_y);
|
||||
|
||||
if (rmi_register_desc_has_subpacket(item, 1)) {
|
||||
pitch_x = (buf[offset + 1] << 8) | buf[offset];
|
||||
pitch_y = (buf[offset + 3] << 8) | buf[offset + 2];
|
||||
pitch_x = get_unaligned_le16(&buf[offset]);
|
||||
pitch_y = get_unaligned_le16(&buf[offset + 2]);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
@@ -132,12 +162,12 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
if (rmi_get_register_desc_item(&f12->query_reg_desc,
|
||||
RMI_F12_QUERY_RESOLUTION)) {
|
||||
offset = rmi_register_desc_calc_reg_offset(&f12->query_reg_desc,
|
||||
RMI_F12_QUERY_RESOLUTION);
|
||||
RMI_F12_QUERY_RESOLUTION);
|
||||
query_dpm_addr = fn->fd.query_base_addr + offset;
|
||||
ret = rmi_read(fn->rmi_dev, query_dpm_addr, buf);
|
||||
if (ret < 0) {
|
||||
if (ret) {
|
||||
dev_err(&fn->dev, "Failed to read DPM value: %d\n", ret);
|
||||
return -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
dpm_resolution = buf[0];
|
||||
|
||||
@@ -164,14 +194,11 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
|
||||
static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, u32 size)
|
||||
{
|
||||
int i;
|
||||
struct rmi_2d_sensor *sensor = &f12->sensor;
|
||||
int objects = f12->data1->num_subpackets;
|
||||
|
||||
if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size)
|
||||
objects = size / F12_DATA1_BYTES_PER_OBJ;
|
||||
u32 objects = min(f12->data1->num_subpackets, size / F12_DATA1_BYTES_PER_OBJ);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < objects; i++) {
|
||||
struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
|
||||
@@ -196,8 +223,8 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
|
||||
break;
|
||||
}
|
||||
|
||||
obj->x = (data1[2] << 8) | data1[1];
|
||||
obj->y = (data1[4] << 8) | data1[3];
|
||||
obj->x = get_unaligned_le16(&data1[1]);
|
||||
obj->y = get_unaligned_le16(&data1[3]);
|
||||
obj->z = data1[5];
|
||||
obj->wx = data1[6];
|
||||
obj->wy = data1[7];
|
||||
@@ -220,21 +247,17 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size)
|
||||
|
||||
static irqreturn_t rmi_f12_attention(int irq, void *ctx)
|
||||
{
|
||||
int retval;
|
||||
struct rmi_function *fn = ctx;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
|
||||
struct rmi_2d_sensor *sensor = &f12->sensor;
|
||||
int valid_bytes = sensor->pkt_size;
|
||||
u32 valid_bytes = sensor->pkt_size;
|
||||
int retval;
|
||||
|
||||
if (drvdata->attn_data.data) {
|
||||
if (sensor->attn_size > drvdata->attn_data.size)
|
||||
valid_bytes = drvdata->attn_data.size;
|
||||
else
|
||||
valid_bytes = sensor->attn_size;
|
||||
memcpy(sensor->data_pkt, drvdata->attn_data.data,
|
||||
valid_bytes);
|
||||
valid_bytes = min_t(u32, sensor->attn_size, drvdata->attn_data.size);
|
||||
memcpy(sensor->data_pkt, drvdata->attn_data.data, valid_bytes);
|
||||
drvdata->attn_data.data += valid_bytes;
|
||||
drvdata->attn_data.size -= valid_bytes;
|
||||
} else {
|
||||
@@ -248,92 +271,100 @@ static irqreturn_t rmi_f12_attention(int irq, void *ctx)
|
||||
}
|
||||
|
||||
if (f12->data1)
|
||||
rmi_f12_process_objects(f12,
|
||||
&sensor->data_pkt[f12->data1_offset], valid_bytes);
|
||||
rmi_f12_process_objects(f12, &sensor->data_pkt[f12->data1_offset],
|
||||
valid_bytes);
|
||||
|
||||
input_mt_sync_frame(sensor->input);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int rmi_f12_write_control_regs(struct rmi_function *fn)
|
||||
static int rmi_f12_update_dribble(struct rmi_function *fn, struct f12_data *f12)
|
||||
{
|
||||
int ret;
|
||||
const struct rmi_register_desc_item *item;
|
||||
struct rmi_device *rmi_dev = fn->rmi_dev;
|
||||
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
|
||||
int control_size;
|
||||
char buf[3];
|
||||
u16 control_offset = 0;
|
||||
u8 subpacket_offset = 0;
|
||||
u16 control_offset;
|
||||
u32 control_size;
|
||||
int error;
|
||||
u8 buf[3];
|
||||
|
||||
if (f12->has_dribble
|
||||
&& (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) {
|
||||
item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
|
||||
if (item) {
|
||||
control_offset = rmi_register_desc_calc_reg_offset(
|
||||
&f12->control_reg_desc, 20);
|
||||
item = rmi_get_register_desc_item(&f12->control_reg_desc, 20);
|
||||
if (!item)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The byte containing the EnableDribble bit will be
|
||||
* in either byte 0 or byte 2 of control 20. Depending
|
||||
* on the existence of subpacket 0. If control 20 is
|
||||
* larger then 3 bytes, just read the first 3.
|
||||
*/
|
||||
control_size = min(item->reg_size, 3UL);
|
||||
control_offset = rmi_register_desc_calc_reg_offset(&f12->control_reg_desc, 20);
|
||||
|
||||
ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr
|
||||
+ control_offset, buf, control_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
/*
|
||||
* The byte containing the EnableDribble bit will be
|
||||
* in either byte 0 or byte 2 of control 20. Depending
|
||||
* on the existence of subpacket 0. If control 20 is
|
||||
* larger then 3 bytes, just read the first 3.
|
||||
*/
|
||||
control_size = min(item->reg_size, 3U);
|
||||
|
||||
if (rmi_register_desc_has_subpacket(item, 0))
|
||||
subpacket_offset += 1;
|
||||
error = rmi_read_block(rmi_dev, fn->fd.control_base_addr + control_offset,
|
||||
buf, control_size);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
switch (f12->sensor.dribble) {
|
||||
case RMI_REG_STATE_OFF:
|
||||
buf[subpacket_offset] &= ~BIT(2);
|
||||
break;
|
||||
case RMI_REG_STATE_ON:
|
||||
buf[subpacket_offset] |= BIT(2);
|
||||
break;
|
||||
case RMI_REG_STATE_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (rmi_register_desc_has_subpacket(item, 0))
|
||||
subpacket_offset += 1;
|
||||
|
||||
ret = rmi_write_block(rmi_dev,
|
||||
fn->fd.control_base_addr + control_offset,
|
||||
buf, control_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
switch (f12->sensor.dribble) {
|
||||
case RMI_REG_STATE_OFF:
|
||||
buf[subpacket_offset] &= ~BIT(2);
|
||||
break;
|
||||
case RMI_REG_STATE_ON:
|
||||
buf[subpacket_offset] |= BIT(2);
|
||||
break;
|
||||
case RMI_REG_STATE_DEFAULT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
error = rmi_write_block(rmi_dev, fn->fd.control_base_addr + control_offset,
|
||||
buf, control_size);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f12_write_control_regs(struct rmi_function *fn)
|
||||
{
|
||||
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
|
||||
|
||||
if (f12->has_dribble && f12->sensor.dribble != RMI_REG_STATE_DEFAULT)
|
||||
return rmi_f12_update_dribble(fn, f12);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_f12_config(struct rmi_function *fn)
|
||||
{
|
||||
struct rmi_driver *drv = fn->rmi_dev->driver;
|
||||
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
|
||||
int irq_mask_size = BITS_TO_LONGS(drvdata->irq_count);
|
||||
unsigned long *abs_mask = f12->irq_mask;
|
||||
unsigned long *rel_mask = f12->irq_mask + irq_mask_size;
|
||||
struct rmi_2d_sensor *sensor;
|
||||
int ret;
|
||||
|
||||
sensor = &f12->sensor;
|
||||
|
||||
if (!sensor->report_abs)
|
||||
drv->clear_irq_bits(fn->rmi_dev, f12->abs_mask);
|
||||
drv->clear_irq_bits(fn->rmi_dev, abs_mask);
|
||||
else
|
||||
drv->set_irq_bits(fn->rmi_dev, f12->abs_mask);
|
||||
drv->set_irq_bits(fn->rmi_dev, abs_mask);
|
||||
|
||||
drv->clear_irq_bits(fn->rmi_dev, f12->rel_mask);
|
||||
drv->clear_irq_bits(fn->rmi_dev, rel_mask);
|
||||
|
||||
ret = rmi_f12_write_control_regs(fn);
|
||||
if (ret)
|
||||
dev_warn(&fn->dev,
|
||||
"Failed to write F12 control registers: %d\n", ret);
|
||||
"Failed to write F12 control registers: %d\n", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -349,12 +380,14 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
struct rmi_2d_sensor *sensor;
|
||||
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
|
||||
struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
|
||||
u16 data_offset = 0;
|
||||
int mask_size;
|
||||
size_t data_offset = 0;
|
||||
size_t pkt_size;
|
||||
int irq_mask_size;
|
||||
int i;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
|
||||
|
||||
mask_size = BITS_TO_LONGS(drvdata->irq_count) * sizeof(unsigned long);
|
||||
irq_mask_size = BITS_TO_LONGS(drvdata->irq_count);
|
||||
|
||||
ret = rmi_read(fn->rmi_dev, query_addr, &buf);
|
||||
if (ret < 0) {
|
||||
@@ -370,18 +403,13 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
f12 = devm_kzalloc(&fn->dev, sizeof(struct f12_data) + mask_size * 2,
|
||||
GFP_KERNEL);
|
||||
f12 = devm_kzalloc(&fn->dev, struct_size(f12, irq_mask, irq_mask_size * 2),
|
||||
GFP_KERNEL);
|
||||
if (!f12)
|
||||
return -ENOMEM;
|
||||
|
||||
f12->abs_mask = (unsigned long *)((char *)f12
|
||||
+ sizeof(struct f12_data));
|
||||
f12->rel_mask = (unsigned long *)((char *)f12
|
||||
+ sizeof(struct f12_data) + mask_size);
|
||||
|
||||
set_bit(fn->irq_pos, f12->abs_mask);
|
||||
set_bit(fn->irq_pos + 1, f12->rel_mask);
|
||||
set_bit(fn->irq_pos, f12->irq_mask);
|
||||
set_bit(fn->irq_pos + 1, f12->irq_mask + irq_mask_size);
|
||||
|
||||
f12->has_dribble = !!(buf & BIT(3));
|
||||
|
||||
@@ -393,55 +421,32 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
f12->sensor_pdata = pdata->sensor_pdata;
|
||||
}
|
||||
|
||||
ret = rmi_read_register_desc(rmi_dev, query_addr,
|
||||
&f12->query_reg_desc);
|
||||
if (ret) {
|
||||
dev_err(&fn->dev,
|
||||
"Failed to read the Query Register Descriptor: %d\n",
|
||||
ret);
|
||||
ret = rmi_f12_read_register_descs(fn, f12, query_addr);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
query_addr += 3;
|
||||
|
||||
ret = rmi_read_register_desc(rmi_dev, query_addr,
|
||||
&f12->control_reg_desc);
|
||||
if (ret) {
|
||||
dev_err(&fn->dev,
|
||||
"Failed to read the Control Register Descriptor: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
query_addr += 3;
|
||||
|
||||
ret = rmi_read_register_desc(rmi_dev, query_addr,
|
||||
&f12->data_reg_desc);
|
||||
if (ret) {
|
||||
dev_err(&fn->dev,
|
||||
"Failed to read the Data Register Descriptor: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
query_addr += 3;
|
||||
|
||||
sensor = &f12->sensor;
|
||||
sensor->fn = fn;
|
||||
f12->data_addr = fn->fd.data_base_addr;
|
||||
sensor->pkt_size = rmi_register_desc_calc_size(&f12->data_reg_desc);
|
||||
pkt_size = rmi_register_desc_calc_size(&f12->data_reg_desc);
|
||||
if (pkt_size > SZ_1M) {
|
||||
dev_err(&fn->dev, "Invalid data packet size: %zu\n", pkt_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
sensor->pkt_size = pkt_size;
|
||||
|
||||
sensor->axis_align =
|
||||
f12->sensor_pdata.axis_align;
|
||||
sensor->axis_align = f12->sensor_pdata.axis_align;
|
||||
|
||||
sensor->x_mm = f12->sensor_pdata.x_mm;
|
||||
sensor->y_mm = f12->sensor_pdata.y_mm;
|
||||
sensor->dribble = f12->sensor_pdata.dribble;
|
||||
|
||||
if (sensor->sensor_type == rmi_sensor_default)
|
||||
sensor->sensor_type =
|
||||
f12->sensor_pdata.sensor_type;
|
||||
sensor->sensor_type = f12->sensor_pdata.sensor_type;
|
||||
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: data packet size: %d\n", __func__,
|
||||
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: data packet size: %u\n", __func__,
|
||||
sensor->pkt_size);
|
||||
sensor->data_pkt = devm_kzalloc(&fn->dev, sensor->pkt_size, GFP_KERNEL);
|
||||
sensor->data_pkt = devm_kmalloc(&fn->dev, sensor->pkt_size, GFP_KERNEL);
|
||||
if (!sensor->data_pkt)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -452,108 +457,86 @@ static int rmi_f12_probe(struct rmi_function *fn)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Figure out what data is contained in the data registers. HID devices
|
||||
* may have registers defined, but their data is not reported in the
|
||||
* HID attention report. Registers which are not reported in the HID
|
||||
* attention report check to see if the device is receiving data from
|
||||
* HID attention reports.
|
||||
* Identify available data registers and calculate their offsets within
|
||||
* the attention report. For HID devices, only Data1 and Data5 are
|
||||
* included in the report; other registers may be described but are
|
||||
* not transmitted in the attention packet and thus skipped here.
|
||||
*/
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
for (i = 0; i < 16; i++) {
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, i);
|
||||
if (!item)
|
||||
continue;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
|
||||
if (item) {
|
||||
f12->data1 = item;
|
||||
f12->data1_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
sensor->nbr_fingers = item->num_subpackets;
|
||||
sensor->report_abs = 1;
|
||||
sensor->attn_size += item->reg_size;
|
||||
}
|
||||
/* HID attention reports only contain Data1 and Data5 */
|
||||
if (drvdata->attn_data.data && i != 1 && i != 5)
|
||||
continue;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
if (data_offset > U16_MAX) {
|
||||
dev_err(&fn->dev, "Invalid offset for data%d: %zu\n",
|
||||
i, data_offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
switch (i) {
|
||||
case 1:
|
||||
f12->data1 = item;
|
||||
f12->data1_offset = data_offset;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
if (item->num_subpackets > 255) {
|
||||
dev_err(&fn->dev,
|
||||
"Too many fingers declared: %d\n",
|
||||
item->num_subpackets);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
|
||||
if (item) {
|
||||
f12->data5 = item;
|
||||
f12->data5_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
sensor->attn_size += item->reg_size;
|
||||
}
|
||||
sensor->nbr_fingers = item->num_subpackets;
|
||||
sensor->report_abs = 1;
|
||||
sensor->attn_size += item->reg_size;
|
||||
break;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
|
||||
if (item && !drvdata->attn_data.data) {
|
||||
f12->data6 = item;
|
||||
f12->data6_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
}
|
||||
case 5:
|
||||
f12->data5 = item;
|
||||
f12->data5_offset = data_offset;
|
||||
sensor->attn_size += item->reg_size;
|
||||
break;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
case 6:
|
||||
f12->data6 = item;
|
||||
f12->data6_offset = data_offset;
|
||||
break;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
case 9:
|
||||
f12->data9 = item;
|
||||
f12->data9_offset = data_offset;
|
||||
if (!sensor->report_abs)
|
||||
sensor->report_rel = 1;
|
||||
break;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
|
||||
if (item && !drvdata->attn_data.data) {
|
||||
f12->data9 = item;
|
||||
f12->data9_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
if (!sensor->report_abs)
|
||||
sensor->report_rel = 1;
|
||||
}
|
||||
case 15:
|
||||
f12->data15 = item;
|
||||
f12->data15_offset = data_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
|
||||
if (item && !drvdata->attn_data.data)
|
||||
data_offset += item->reg_size;
|
||||
|
||||
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
|
||||
if (item && !drvdata->attn_data.data) {
|
||||
f12->data15 = item;
|
||||
f12->data15_offset = data_offset;
|
||||
data_offset += item->reg_size;
|
||||
}
|
||||
|
||||
/* allocate the in-kernel tracking buffers */
|
||||
sensor->tracking_pos = devm_kcalloc(&fn->dev,
|
||||
sensor->nbr_fingers, sizeof(struct input_mt_pos),
|
||||
GFP_KERNEL);
|
||||
sensor->tracking_slots = devm_kcalloc(&fn->dev,
|
||||
sensor->nbr_fingers, sizeof(int), GFP_KERNEL);
|
||||
sensor->objs = devm_kcalloc(&fn->dev,
|
||||
sensor->nbr_fingers,
|
||||
sizeof(struct rmi_2d_sensor_abs_object),
|
||||
GFP_KERNEL);
|
||||
if (!sensor->tracking_pos || !sensor->tracking_slots || !sensor->objs)
|
||||
sensor->tracking_pos = devm_kcalloc(&fn->dev, sensor->nbr_fingers,
|
||||
sizeof(*sensor->tracking_pos),
|
||||
GFP_KERNEL);
|
||||
if (!sensor->tracking_pos)
|
||||
return -ENOMEM;
|
||||
|
||||
sensor->tracking_slots = devm_kcalloc(&fn->dev, sensor->nbr_fingers,
|
||||
sizeof(*sensor->tracking_slots),
|
||||
GFP_KERNEL);
|
||||
if (!sensor->tracking_slots)
|
||||
return -ENOMEM;
|
||||
|
||||
sensor->objs = devm_kcalloc(&fn->dev, sensor->nbr_fingers,
|
||||
sizeof(*sensor->objs), GFP_KERNEL);
|
||||
if (!sensor->objs)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = rmi_2d_sensor_configure_input(fn, sensor);
|
||||
|
||||
@@ -365,7 +365,7 @@ static const struct dev_pm_ops rmi_i2c_pm = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id rmi_id[] = {
|
||||
{ "rmi4_i2c" },
|
||||
{ .name = "rmi4_i2c" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rmi_id);
|
||||
|
||||
@@ -413,7 +413,7 @@ static const struct dev_pm_ops rmi_smb_pm = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id rmi_id[] = {
|
||||
{ "rmi4_smbus" },
|
||||
{ .name = "rmi4_smbus" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rmi_id);
|
||||
|
||||
@@ -188,16 +188,6 @@ config SERIO_RAW
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called serio_raw.
|
||||
|
||||
config SERIO_XILINX_XPS_PS2
|
||||
tristate "Xilinx XPS PS/2 Controller Support"
|
||||
depends on PPC || MICROBLAZE
|
||||
help
|
||||
This driver supports XPS PS/2 IP from the Xilinx EDK on
|
||||
PowerPC platform.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called xilinx_ps2.
|
||||
|
||||
config SERIO_ALTERA_PS2
|
||||
tristate "Altera UP PS/2 controller"
|
||||
depends on HAS_IOMEM
|
||||
|
||||
@@ -23,7 +23,6 @@ obj-$(CONFIG_SERIO_SGI_IOC3) += ioc3kbd.o
|
||||
obj-$(CONFIG_SERIO_LIBPS2) += libps2.o
|
||||
obj-$(CONFIG_SERIO_RAW) += serio_raw.o
|
||||
obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o
|
||||
obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o
|
||||
obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o
|
||||
obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
|
||||
obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
|
||||
|
||||
@@ -140,7 +140,7 @@ static int apbps2_of_probe(struct platform_device *ofdev)
|
||||
}
|
||||
|
||||
/* Find device address */
|
||||
priv->regs = devm_platform_get_and_ioremap_resource(ofdev, 0, NULL);
|
||||
priv->regs = devm_platform_ioremap_resource(ofdev, 0);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
@@ -148,7 +148,10 @@ static int apbps2_of_probe(struct platform_device *ofdev)
|
||||
iowrite32be(0, &priv->regs->ctrl);
|
||||
|
||||
/* IRQ */
|
||||
irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
|
||||
irq = platform_get_irq(ofdev, 0);
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
err = devm_request_irq(&ofdev->dev, irq, apbps2_isr,
|
||||
IRQF_SHARED, "apbps2", priv);
|
||||
if (err) {
|
||||
|
||||
@@ -1539,22 +1539,22 @@ static int i8042_pnp_aux_probe(struct pnp_dev *dev, const struct pnp_device_id *
|
||||
}
|
||||
|
||||
static const struct pnp_device_id pnp_kbd_devids[] = {
|
||||
{ .id = "PNP0300", .driver_data = 0 },
|
||||
{ .id = "PNP0301", .driver_data = 0 },
|
||||
{ .id = "PNP0302", .driver_data = 0 },
|
||||
{ .id = "PNP0303", .driver_data = 0 },
|
||||
{ .id = "PNP0304", .driver_data = 0 },
|
||||
{ .id = "PNP0305", .driver_data = 0 },
|
||||
{ .id = "PNP0306", .driver_data = 0 },
|
||||
{ .id = "PNP0309", .driver_data = 0 },
|
||||
{ .id = "PNP030a", .driver_data = 0 },
|
||||
{ .id = "PNP030b", .driver_data = 0 },
|
||||
{ .id = "PNP0320", .driver_data = 0 },
|
||||
{ .id = "PNP0343", .driver_data = 0 },
|
||||
{ .id = "PNP0344", .driver_data = 0 },
|
||||
{ .id = "PNP0345", .driver_data = 0 },
|
||||
{ .id = "CPQA0D7", .driver_data = 0 },
|
||||
{ .id = "", },
|
||||
{ .id = "PNP0300" },
|
||||
{ .id = "PNP0301" },
|
||||
{ .id = "PNP0302" },
|
||||
{ .id = "PNP0303" },
|
||||
{ .id = "PNP0304" },
|
||||
{ .id = "PNP0305" },
|
||||
{ .id = "PNP0306" },
|
||||
{ .id = "PNP0309" },
|
||||
{ .id = "PNP030a" },
|
||||
{ .id = "PNP030b" },
|
||||
{ .id = "PNP0320" },
|
||||
{ .id = "PNP0343" },
|
||||
{ .id = "PNP0344" },
|
||||
{ .id = "PNP0345" },
|
||||
{ .id = "CPQA0D7" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pnp, pnp_kbd_devids);
|
||||
|
||||
@@ -1569,18 +1569,18 @@ static struct pnp_driver i8042_pnp_kbd_driver = {
|
||||
};
|
||||
|
||||
static const struct pnp_device_id pnp_aux_devids[] = {
|
||||
{ .id = "AUI0200", .driver_data = 0 },
|
||||
{ .id = "FJC6000", .driver_data = 0 },
|
||||
{ .id = "FJC6001", .driver_data = 0 },
|
||||
{ .id = "PNP0f03", .driver_data = 0 },
|
||||
{ .id = "PNP0f0b", .driver_data = 0 },
|
||||
{ .id = "PNP0f0e", .driver_data = 0 },
|
||||
{ .id = "PNP0f12", .driver_data = 0 },
|
||||
{ .id = "PNP0f13", .driver_data = 0 },
|
||||
{ .id = "PNP0f19", .driver_data = 0 },
|
||||
{ .id = "PNP0f1c", .driver_data = 0 },
|
||||
{ .id = "SYN0801", .driver_data = 0 },
|
||||
{ .id = "", },
|
||||
{ .id = "AUI0200" },
|
||||
{ .id = "FJC6000" },
|
||||
{ .id = "FJC6001" },
|
||||
{ .id = "PNP0f03" },
|
||||
{ .id = "PNP0f0b" },
|
||||
{ .id = "PNP0f0e" },
|
||||
{ .id = "PNP0f12" },
|
||||
{ .id = "PNP0f13" },
|
||||
{ .id = "PNP0f19" },
|
||||
{ .id = "PNP0f1c" },
|
||||
{ .id = "SYN0801" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pnp, pnp_aux_devids);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* userio kernel serio device emulation module
|
||||
* Copyright (C) 2015 Red Hat
|
||||
* Copyright (C) 2015 Stephen Chandler Paul <thatslyude@gmail.com>
|
||||
* Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as published by
|
||||
@@ -206,6 +206,36 @@ static int userio_execute_cmd(struct userio_device *userio,
|
||||
userio->serio->id.type = cmd->data;
|
||||
break;
|
||||
|
||||
case USERIO_CMD_SET_PORT_EXTRA:
|
||||
if (userio->running) {
|
||||
dev_warn(userio_misc.this_device,
|
||||
"Can't change port extra on an already running userio instance\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
userio->serio->id.extra = cmd->data;
|
||||
break;
|
||||
|
||||
case USERIO_CMD_SET_PORT_ID:
|
||||
if (userio->running) {
|
||||
dev_warn(userio_misc.this_device,
|
||||
"Can't change port id on an already running userio instance\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
userio->serio->id.id = cmd->data;
|
||||
break;
|
||||
|
||||
case USERIO_CMD_SET_PORT_PROTO:
|
||||
if (userio->running) {
|
||||
dev_warn(userio_misc.this_device,
|
||||
"Can't change port proto on an already running userio instance\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
userio->serio->id.proto = cmd->data;
|
||||
break;
|
||||
|
||||
case USERIO_CMD_SEND_INTERRUPT:
|
||||
if (!userio->running) {
|
||||
dev_warn(userio_misc.this_device,
|
||||
@@ -278,6 +308,6 @@ module_driver(userio_misc, misc_register, misc_deregister);
|
||||
MODULE_ALIAS_MISCDEV(USERIO_MINOR);
|
||||
MODULE_ALIAS("devname:" USERIO_NAME);
|
||||
|
||||
MODULE_AUTHOR("Stephen Chandler Paul <thatslyude@gmail.com>");
|
||||
MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
|
||||
MODULE_DESCRIPTION("Virtual Serio Device Support");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -1,363 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Xilinx XPS PS/2 device driver
|
||||
*
|
||||
* (c) 2005 MontaVista Software, Inc.
|
||||
* (c) 2008 Xilinx, Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/serio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRIVER_NAME "xilinx_ps2"
|
||||
|
||||
/* Register offsets for the xps2 device */
|
||||
#define XPS2_SRST_OFFSET 0x00000000 /* Software Reset register */
|
||||
#define XPS2_STATUS_OFFSET 0x00000004 /* Status register */
|
||||
#define XPS2_RX_DATA_OFFSET 0x00000008 /* Receive Data register */
|
||||
#define XPS2_TX_DATA_OFFSET 0x0000000C /* Transmit Data register */
|
||||
#define XPS2_GIER_OFFSET 0x0000002C /* Global Interrupt Enable reg */
|
||||
#define XPS2_IPISR_OFFSET 0x00000030 /* Interrupt Status register */
|
||||
#define XPS2_IPIER_OFFSET 0x00000038 /* Interrupt Enable register */
|
||||
|
||||
/* Reset Register Bit Definitions */
|
||||
#define XPS2_SRST_RESET 0x0000000A /* Software Reset */
|
||||
|
||||
/* Status Register Bit Positions */
|
||||
#define XPS2_STATUS_RX_FULL 0x00000001 /* Receive Full */
|
||||
#define XPS2_STATUS_TX_FULL 0x00000002 /* Transmit Full */
|
||||
|
||||
/*
|
||||
* Bit definitions for ISR/IER registers. Both the registers have the same bit
|
||||
* definitions and are only defined once.
|
||||
*/
|
||||
#define XPS2_IPIXR_WDT_TOUT 0x00000001 /* Watchdog Timeout Interrupt */
|
||||
#define XPS2_IPIXR_TX_NOACK 0x00000002 /* Transmit No ACK Interrupt */
|
||||
#define XPS2_IPIXR_TX_ACK 0x00000004 /* Transmit ACK (Data) Interrupt */
|
||||
#define XPS2_IPIXR_RX_OVF 0x00000008 /* Receive Overflow Interrupt */
|
||||
#define XPS2_IPIXR_RX_ERR 0x00000010 /* Receive Error Interrupt */
|
||||
#define XPS2_IPIXR_RX_FULL 0x00000020 /* Receive Data Interrupt */
|
||||
|
||||
/* Mask for all the Transmit Interrupts */
|
||||
#define XPS2_IPIXR_TX_ALL (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_TX_ACK)
|
||||
|
||||
/* Mask for all the Receive Interrupts */
|
||||
#define XPS2_IPIXR_RX_ALL (XPS2_IPIXR_RX_OVF | XPS2_IPIXR_RX_ERR | \
|
||||
XPS2_IPIXR_RX_FULL)
|
||||
|
||||
/* Mask for all the Interrupts */
|
||||
#define XPS2_IPIXR_ALL (XPS2_IPIXR_TX_ALL | XPS2_IPIXR_RX_ALL | \
|
||||
XPS2_IPIXR_WDT_TOUT)
|
||||
|
||||
/* Global Interrupt Enable mask */
|
||||
#define XPS2_GIER_GIE_MASK 0x80000000
|
||||
|
||||
struct xps2data {
|
||||
int irq;
|
||||
spinlock_t lock;
|
||||
void __iomem *base_address; /* virt. address of control registers */
|
||||
unsigned int flags;
|
||||
struct serio *serio; /* serio */
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
/************************************/
|
||||
/* XPS PS/2 data transmission calls */
|
||||
/************************************/
|
||||
|
||||
/**
|
||||
* xps2_recv() - attempts to receive a byte from the PS/2 port.
|
||||
* @drvdata: pointer to ps2 device private data structure
|
||||
* @byte: address where the read data will be copied
|
||||
*
|
||||
* If there is any data available in the PS/2 receiver, this functions reads
|
||||
* the data, otherwise it returns error.
|
||||
*/
|
||||
static int xps2_recv(struct xps2data *drvdata, u8 *byte)
|
||||
{
|
||||
u32 sr;
|
||||
int status = -1;
|
||||
|
||||
/* If there is data available in the PS/2 receiver, read it */
|
||||
sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
|
||||
if (sr & XPS2_STATUS_RX_FULL) {
|
||||
*byte = in_be32(drvdata->base_address + XPS2_RX_DATA_OFFSET);
|
||||
status = 0;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*********************/
|
||||
/* Interrupt handler */
|
||||
/*********************/
|
||||
static irqreturn_t xps2_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct xps2data *drvdata = dev_id;
|
||||
u32 intr_sr;
|
||||
u8 c;
|
||||
int status;
|
||||
|
||||
/* Get the PS/2 interrupts and clear them */
|
||||
intr_sr = in_be32(drvdata->base_address + XPS2_IPISR_OFFSET);
|
||||
out_be32(drvdata->base_address + XPS2_IPISR_OFFSET, intr_sr);
|
||||
|
||||
/* Check which interrupt is active */
|
||||
if (intr_sr & XPS2_IPIXR_RX_OVF)
|
||||
dev_warn(drvdata->dev, "receive overrun error\n");
|
||||
|
||||
if (intr_sr & XPS2_IPIXR_RX_ERR)
|
||||
drvdata->flags |= SERIO_PARITY;
|
||||
|
||||
if (intr_sr & (XPS2_IPIXR_TX_NOACK | XPS2_IPIXR_WDT_TOUT))
|
||||
drvdata->flags |= SERIO_TIMEOUT;
|
||||
|
||||
if (intr_sr & XPS2_IPIXR_RX_FULL) {
|
||||
status = xps2_recv(drvdata, &c);
|
||||
|
||||
/* Error, if a byte is not received */
|
||||
if (status) {
|
||||
dev_err(drvdata->dev,
|
||||
"wrong rcvd byte count (%d)\n", status);
|
||||
} else {
|
||||
serio_interrupt(drvdata->serio, c, drvdata->flags);
|
||||
drvdata->flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/*******************/
|
||||
/* serio callbacks */
|
||||
/*******************/
|
||||
|
||||
/**
|
||||
* sxps2_write() - sends a byte out through the PS/2 port.
|
||||
* @pserio: pointer to the serio structure of the PS/2 port
|
||||
* @c: data that needs to be written to the PS/2 port
|
||||
*
|
||||
* This function checks if the PS/2 transmitter is empty and sends a byte.
|
||||
* Otherwise it returns error. Transmission fails only when nothing is connected
|
||||
* to the PS/2 port. Thats why, we do not try to resend the data in case of a
|
||||
* failure.
|
||||
*/
|
||||
static int sxps2_write(struct serio *pserio, unsigned char c)
|
||||
{
|
||||
struct xps2data *drvdata = pserio->port_data;
|
||||
u32 sr;
|
||||
|
||||
guard(spinlock_irqsave)(&drvdata->lock);
|
||||
|
||||
/* If the PS/2 transmitter is empty send a byte of data */
|
||||
sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
|
||||
if (sr & XPS2_STATUS_TX_FULL)
|
||||
return -EAGAIN;
|
||||
|
||||
out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* sxps2_open() - called when a port is opened by the higher layer.
|
||||
* @pserio: pointer to the serio structure of the PS/2 device
|
||||
*
|
||||
* This function requests irq and enables interrupts for the PS/2 device.
|
||||
*/
|
||||
static int sxps2_open(struct serio *pserio)
|
||||
{
|
||||
struct xps2data *drvdata = pserio->port_data;
|
||||
int error;
|
||||
u8 c;
|
||||
|
||||
error = request_irq(drvdata->irq, &xps2_interrupt, 0,
|
||||
DRIVER_NAME, drvdata);
|
||||
if (error) {
|
||||
dev_err(drvdata->dev,
|
||||
"Couldn't allocate interrupt %d\n", drvdata->irq);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* start reception by enabling the interrupts */
|
||||
out_be32(drvdata->base_address + XPS2_GIER_OFFSET, XPS2_GIER_GIE_MASK);
|
||||
out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, XPS2_IPIXR_RX_ALL);
|
||||
(void)xps2_recv(drvdata, &c);
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
/**
|
||||
* sxps2_close() - frees the interrupt.
|
||||
* @pserio: pointer to the serio structure of the PS/2 device
|
||||
*
|
||||
* This function frees the irq and disables interrupts for the PS/2 device.
|
||||
*/
|
||||
static void sxps2_close(struct serio *pserio)
|
||||
{
|
||||
struct xps2data *drvdata = pserio->port_data;
|
||||
|
||||
/* Disable the PS2 interrupts */
|
||||
out_be32(drvdata->base_address + XPS2_GIER_OFFSET, 0x00);
|
||||
out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0x00);
|
||||
free_irq(drvdata->irq, drvdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* xps2_of_probe - probe method for the PS/2 device.
|
||||
* @ofdev: pointer to OF device structure
|
||||
*
|
||||
* This function probes the PS/2 device in the device tree.
|
||||
* It initializes the driver data structure and the hardware.
|
||||
* It returns 0, if the driver is bound to the PS/2 device, or a negative
|
||||
* value if there is an error.
|
||||
*/
|
||||
static int xps2_of_probe(struct platform_device *ofdev)
|
||||
{
|
||||
struct resource r_mem; /* IO mem resources */
|
||||
struct xps2data *drvdata;
|
||||
struct serio *serio;
|
||||
struct device *dev = &ofdev->dev;
|
||||
resource_size_t remap_size, phys_addr;
|
||||
unsigned int irq;
|
||||
int error;
|
||||
|
||||
dev_info(dev, "Device Tree Probing \'%pOFn\'\n", dev->of_node);
|
||||
|
||||
/* Get iospace for the device */
|
||||
error = of_address_to_resource(dev->of_node, 0, &r_mem);
|
||||
if (error) {
|
||||
dev_err(dev, "invalid address\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* Get IRQ for the device */
|
||||
irq = irq_of_parse_and_map(dev->of_node, 0);
|
||||
if (!irq) {
|
||||
dev_err(dev, "no IRQ found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
drvdata = kzalloc_obj(*drvdata);
|
||||
serio = kzalloc_obj(*serio);
|
||||
if (!drvdata || !serio) {
|
||||
error = -ENOMEM;
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
spin_lock_init(&drvdata->lock);
|
||||
drvdata->irq = irq;
|
||||
drvdata->serio = serio;
|
||||
drvdata->dev = dev;
|
||||
|
||||
phys_addr = r_mem.start;
|
||||
remap_size = resource_size(&r_mem);
|
||||
if (!request_mem_region(phys_addr, remap_size, DRIVER_NAME)) {
|
||||
dev_err(dev, "Couldn't lock memory region at 0x%08llX\n",
|
||||
(unsigned long long)phys_addr);
|
||||
error = -EBUSY;
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
/* Fill in configuration data and add them to the list */
|
||||
drvdata->base_address = ioremap(phys_addr, remap_size);
|
||||
if (drvdata->base_address == NULL) {
|
||||
dev_err(dev, "Couldn't ioremap memory at 0x%08llX\n",
|
||||
(unsigned long long)phys_addr);
|
||||
error = -EFAULT;
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
/* Disable all the interrupts, just in case */
|
||||
out_be32(drvdata->base_address + XPS2_IPIER_OFFSET, 0);
|
||||
|
||||
/*
|
||||
* Reset the PS2 device and abort any current transaction,
|
||||
* to make sure we have the PS2 in a good state.
|
||||
*/
|
||||
out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
|
||||
|
||||
dev_info(dev, "Xilinx PS2 at 0x%08llX mapped to 0x%p, irq=%d\n",
|
||||
(unsigned long long)phys_addr, drvdata->base_address,
|
||||
drvdata->irq);
|
||||
|
||||
serio->id.type = SERIO_8042;
|
||||
serio->write = sxps2_write;
|
||||
serio->open = sxps2_open;
|
||||
serio->close = sxps2_close;
|
||||
serio->port_data = drvdata;
|
||||
serio->dev.parent = dev;
|
||||
snprintf(serio->name, sizeof(serio->name),
|
||||
"Xilinx XPS PS/2 at %08llX", (unsigned long long)phys_addr);
|
||||
snprintf(serio->phys, sizeof(serio->phys),
|
||||
"xilinxps2/serio at %08llX", (unsigned long long)phys_addr);
|
||||
|
||||
serio_register_port(serio);
|
||||
|
||||
platform_set_drvdata(ofdev, drvdata);
|
||||
return 0; /* success */
|
||||
|
||||
failed2:
|
||||
release_mem_region(phys_addr, remap_size);
|
||||
failed1:
|
||||
kfree(serio);
|
||||
kfree(drvdata);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* xps2_of_remove - unbinds the driver from the PS/2 device.
|
||||
* @of_dev: pointer to OF device structure
|
||||
*
|
||||
* This function is called if a device is physically removed from the system or
|
||||
* if the driver module is being unloaded. It frees any resources allocated to
|
||||
* the device.
|
||||
*/
|
||||
static void xps2_of_remove(struct platform_device *of_dev)
|
||||
{
|
||||
struct xps2data *drvdata = platform_get_drvdata(of_dev);
|
||||
struct resource r_mem; /* IO mem resources */
|
||||
|
||||
serio_unregister_port(drvdata->serio);
|
||||
iounmap(drvdata->base_address);
|
||||
|
||||
/* Get iospace of the device */
|
||||
if (of_address_to_resource(of_dev->dev.of_node, 0, &r_mem))
|
||||
dev_err(drvdata->dev, "invalid address\n");
|
||||
else
|
||||
release_mem_region(r_mem.start, resource_size(&r_mem));
|
||||
|
||||
kfree(drvdata);
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id xps2_of_match[] = {
|
||||
{ .compatible = "xlnx,xps-ps2-1.00.a", },
|
||||
{ /* end of list */ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xps2_of_match);
|
||||
|
||||
static struct platform_driver xps2_of_driver = {
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.of_match_table = xps2_of_match,
|
||||
},
|
||||
.probe = xps2_of_probe,
|
||||
.remove = xps2_of_remove,
|
||||
};
|
||||
module_platform_driver(xps2_of_driver);
|
||||
|
||||
MODULE_AUTHOR("Xilinx, Inc.");
|
||||
MODULE_DESCRIPTION("Xilinx XPS PS/2 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
@@ -16,37 +16,6 @@
|
||||
*
|
||||
* Many thanks to Oliver Kuechemann for his support.
|
||||
*
|
||||
* ChangeLog:
|
||||
* v0.1 - Initial release
|
||||
* v0.2 - Hack to get around fake event 28's. (Bryan W. Headley)
|
||||
* v0.3 - Make URB dynamic (Bryan W. Headley, Jun-8-2002)
|
||||
* Released to Linux 2.4.19 and 2.5.x
|
||||
* v0.4 - Rewrote substantial portions of the code to deal with
|
||||
* corrected control sequences, timing, dynamic configuration,
|
||||
* support of 6000U - 12000U, procfs, and macro key support
|
||||
* (Jan-1-2003 - Feb-5-2003, Bryan W. Headley)
|
||||
* v1.0 - Added support for diagnostic messages, count of messages
|
||||
* received from URB - Mar-8-2003, Bryan W. Headley
|
||||
* v1.1 - added support for tablet resolution, changed DV and proximity
|
||||
* some corrections - Jun-22-2003, martin schneebacher
|
||||
* - Added support for the sysfs interface, deprecating the
|
||||
* procfs interface for 2.5.x kernel. Also added support for
|
||||
* Wheel command. Bryan W. Headley July-15-2003.
|
||||
* v1.2 - Reworked jitter timer as a kernel thread.
|
||||
* Bryan W. Headley November-28-2003/Jan-10-2004.
|
||||
* v1.3 - Repaired issue of kernel thread going nuts on single-processor
|
||||
* machines, introduced programmableDelay as a command line
|
||||
* parameter. Feb 7 2004, Bryan W. Headley.
|
||||
* v1.4 - Re-wire jitter so it does not require a thread. Courtesy of
|
||||
* Rene van Paassen. Added reporting of physical pointer device
|
||||
* (e.g., stylus, mouse in reports 2, 3, 4, 5. We don't know
|
||||
* for reports 1, 6.)
|
||||
* what physical device reports for reports 1, 6.) Also enabled
|
||||
* MOUSE and LENS tool button modes. Renamed "rubber" to "eraser".
|
||||
* Feb 20, 2004, Bryan W. Headley.
|
||||
* v1.5 - Added previousJitterable, so we don't do jitter delay when the
|
||||
* user is holding a button down for periods of time.
|
||||
*
|
||||
* NOTE:
|
||||
* This kernel driver is augmented by the "Aiptek" XFree86 input
|
||||
* driver for your X server, as well as the Gaiptek GUI Front-end
|
||||
|
||||
@@ -610,6 +610,18 @@ config TOUCHSCREEN_WACOM_I2C
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called wacom_i2c.
|
||||
|
||||
config TOUCHSCREEN_WACOM_W9000
|
||||
tristate "Wacom W9000-series penabled touchscreen (I2C)"
|
||||
depends on I2C
|
||||
help
|
||||
Say Y here if you have a Wacom W9000-series penabled I2C touchscreen.
|
||||
This driver supports models W9002 and W9007A.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called wacom_w9000.
|
||||
|
||||
config TOUCHSCREEN_LPC32XX
|
||||
tristate "LPC32XX touchscreen controller"
|
||||
depends on ARCH_LPC32XX
|
||||
@@ -1178,16 +1190,6 @@ config TOUCHSCREEN_TSC2007_IIO
|
||||
or ambient light monitoring), temperature and raw input
|
||||
values.
|
||||
|
||||
config TOUCHSCREEN_PCAP
|
||||
tristate "Motorola PCAP touchscreen"
|
||||
depends on EZX_PCAP
|
||||
help
|
||||
Say Y here if you have a Motorola EZX telephone and
|
||||
want to enable support for the built-in touchscreen.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called pcap_ts.
|
||||
|
||||
config TOUCHSCREEN_RM_TS
|
||||
tristate "Raydium I2C Touchscreen"
|
||||
depends on I2C
|
||||
|
||||
@@ -74,7 +74,6 @@ obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_HTCPEN) += htcpen.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_USB_COMPOSITE) += usbtouchscreen.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_PCAP) += pcap_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_PIXCIR) += pixcir_i2c_ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_RM_TS) += raydium_i2c_ts.o
|
||||
@@ -101,6 +100,7 @@ tsc2007-$(CONFIG_TOUCHSCREEN_TSC2007_IIO) += tsc2007_iio.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TSC2007) += tsc2007.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_WACOM_I2C) += wacom_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_WACOM_W9000) += wacom_w9000.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_WDT87XX_I2C) += wdt87xx_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_WM831X) += wm831x-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o
|
||||
|
||||
@@ -42,8 +42,8 @@ static int ad7879_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ad7879_id[] = {
|
||||
{ "ad7879" },
|
||||
{ "ad7889" },
|
||||
{ .name = "ad7879" },
|
||||
{ .name = "ad7889" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad7879_id);
|
||||
|
||||
@@ -134,6 +134,9 @@ struct ads7846 {
|
||||
bool disabled; /* P: lock */
|
||||
bool suspended; /* P: lock */
|
||||
|
||||
int (*setup_spi_msg)(struct ads7846 *ts,
|
||||
const struct ads7846_platform_data *pdata);
|
||||
void (*read_state)(struct ads7846 *ts);
|
||||
int (*filter)(void *data, int data_idx, int *val);
|
||||
void *filter_data;
|
||||
int (*get_pendown_state)(void);
|
||||
@@ -325,7 +328,6 @@ struct ser_req {
|
||||
u8 ref_on;
|
||||
u8 command;
|
||||
u8 ref_off;
|
||||
u16 scratch;
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfer[8];
|
||||
/*
|
||||
@@ -333,6 +335,7 @@ struct ser_req {
|
||||
* transfer buffers to live in their own cache lines.
|
||||
*/
|
||||
__be16 sample ____cacheline_aligned;
|
||||
u16 scratch;
|
||||
};
|
||||
|
||||
struct ads7845_ser_req {
|
||||
@@ -403,8 +406,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
|
||||
spi_message_add_tail(&req->xfer[5], &req->msg);
|
||||
|
||||
/* clear the command register */
|
||||
req->scratch = 0;
|
||||
req->xfer[6].tx_buf = &req->scratch;
|
||||
req->xfer[6].rx_buf = &req->scratch;
|
||||
req->xfer[6].len = 1;
|
||||
spi_message_add_tail(&req->xfer[6], &req->msg);
|
||||
|
||||
@@ -789,6 +791,22 @@ static int ads7846_filter(struct ads7846 *ts)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ads7846_filter_one(struct ads7846 *ts, unsigned int cmd_idx)
|
||||
{
|
||||
struct ads7846_packet *packet = ts->packet;
|
||||
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
|
||||
int action, val;
|
||||
|
||||
val = ads7846_get_value(&packet->rx[l->offset + l->count - 1]);
|
||||
action = ts->filter(ts->filter_data, cmd_idx, &val);
|
||||
if (action == ADS7846_FILTER_REPEAT)
|
||||
return -EAGAIN;
|
||||
else if (action != ADS7846_FILTER_OK)
|
||||
return -EIO;
|
||||
ads7846_set_cmd_val(ts, cmd_idx, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ads7846_wait_for_hsync(struct ads7846 *ts)
|
||||
{
|
||||
if (ts->wait_for_sync) {
|
||||
@@ -811,6 +829,45 @@ static void ads7846_wait_for_hsync(struct ads7846 *ts)
|
||||
cpu_relax();
|
||||
}
|
||||
|
||||
static void ads7846_halfd_read_state(struct ads7846 *ts)
|
||||
{
|
||||
struct ads7846_packet *packet = ts->packet;
|
||||
int msg_idx = 0;
|
||||
|
||||
packet->ignore = false;
|
||||
|
||||
while (msg_idx < ts->msg_count) {
|
||||
int error;
|
||||
|
||||
ads7846_wait_for_hsync(ts);
|
||||
|
||||
error = spi_sync(ts->spi, &ts->msg[msg_idx]);
|
||||
if (error) {
|
||||
dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n",
|
||||
error);
|
||||
packet->ignore = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Last message is power down request, no need to convert
|
||||
* or filter the value.
|
||||
*/
|
||||
if (msg_idx == ts->msg_count - 1)
|
||||
break;
|
||||
|
||||
error = ads7846_filter_one(ts, msg_idx);
|
||||
if (error == -EAGAIN) {
|
||||
continue;
|
||||
} else if (error) {
|
||||
packet->ignore = true;
|
||||
msg_idx = ts->msg_count - 1;
|
||||
} else {
|
||||
msg_idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ads7846_read_state(struct ads7846 *ts)
|
||||
{
|
||||
struct ads7846_packet *packet = ts->packet;
|
||||
@@ -939,7 +996,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
|
||||
while (!ts->stopped && get_pendown_state(ts)) {
|
||||
|
||||
/* pen is down, continue with the measurement */
|
||||
ads7846_read_state(ts);
|
||||
ts->read_state(ts);
|
||||
|
||||
if (!ts->stopped)
|
||||
ads7846_report_state(ts);
|
||||
@@ -1022,6 +1079,102 @@ static int ads7846_setup_pendown(struct spi_device *spi,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the transfers to read touchscreen state; this assumes we
|
||||
* use formula #2 for pressure, not #3.
|
||||
*/
|
||||
static int ads7846_halfd_spi_msg(struct ads7846 *ts,
|
||||
const struct ads7846_platform_data *pdata)
|
||||
{
|
||||
struct spi_message *m = ts->msg;
|
||||
struct spi_transfer *x = ts->xfer;
|
||||
struct ads7846_packet *packet = ts->packet;
|
||||
int vref = pdata->keep_vref_on;
|
||||
unsigned int offset = 0;
|
||||
unsigned int cmd_idx, b;
|
||||
size_t size = 0;
|
||||
|
||||
if (pdata->settle_delay_usecs)
|
||||
packet->count = 2;
|
||||
else
|
||||
packet->count = 1;
|
||||
|
||||
if (ts->model == 7846)
|
||||
packet->cmds = 5; /* x, y, z1, z2, pwdown */
|
||||
else
|
||||
packet->cmds = 3; /* x, y, pwdown */
|
||||
|
||||
for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
|
||||
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
|
||||
unsigned int max_count;
|
||||
|
||||
if (cmd_idx == packet->cmds - 1) {
|
||||
cmd_idx = ADS7846_PWDOWN;
|
||||
max_count = 1;
|
||||
} else {
|
||||
max_count = packet->count;
|
||||
}
|
||||
|
||||
l->offset = offset;
|
||||
offset += max_count;
|
||||
l->count = max_count;
|
||||
l->skip = 0;
|
||||
size += sizeof(*packet->rx) * max_count;
|
||||
}
|
||||
|
||||
/* We use two transfers per command. */
|
||||
if (ARRAY_SIZE(ts->xfer) < offset * 2)
|
||||
return -ENOMEM;
|
||||
|
||||
packet->rx = devm_kzalloc(&ts->spi->dev, size, GFP_KERNEL);
|
||||
if (!packet->rx)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ts->model == 7873) {
|
||||
/*
|
||||
* The AD7873 is almost identical to the ADS7846
|
||||
* keep VREF off during differential/ratiometric
|
||||
* conversion modes.
|
||||
*/
|
||||
ts->model = 7846;
|
||||
vref = 0;
|
||||
}
|
||||
|
||||
ts->msg_count = 0;
|
||||
|
||||
for (cmd_idx = 0; cmd_idx < packet->cmds; cmd_idx++) {
|
||||
struct ads7846_buf_layout *l = &packet->l[cmd_idx];
|
||||
u8 cmd;
|
||||
|
||||
ts->msg_count++;
|
||||
spi_message_init(m);
|
||||
m->context = ts;
|
||||
|
||||
if (cmd_idx == packet->cmds - 1)
|
||||
cmd_idx = ADS7846_PWDOWN;
|
||||
|
||||
cmd = ads7846_get_cmd(cmd_idx, vref);
|
||||
|
||||
for (b = 0; b < l->count; b++) {
|
||||
packet->rx[l->offset + b].cmd = cmd;
|
||||
x->tx_buf = &packet->rx[l->offset + b].cmd;
|
||||
x->len = 1;
|
||||
spi_message_add_tail(x, m);
|
||||
x++;
|
||||
x->rx_buf = &packet->rx[l->offset + b].data;
|
||||
x->len = 2;
|
||||
if (b < l->count - 1 && l->count > 1) {
|
||||
x->delay.value = pdata->settle_delay_usecs;
|
||||
x->delay.unit = SPI_DELAY_UNIT_USECS;
|
||||
}
|
||||
spi_message_add_tail(x, m);
|
||||
x++;
|
||||
}
|
||||
m++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the transfers to read touchscreen state; this assumes we
|
||||
* use formula #2 for pressure, not #3.
|
||||
@@ -1236,6 +1389,14 @@ static int ads7846_probe(struct spi_device *spi)
|
||||
if (!ts)
|
||||
return -ENOMEM;
|
||||
|
||||
if (spi->controller->flags & SPI_CONTROLLER_HALF_DUPLEX) {
|
||||
ts->setup_spi_msg = ads7846_halfd_spi_msg;
|
||||
ts->read_state = ads7846_halfd_read_state;
|
||||
} else {
|
||||
ts->setup_spi_msg = ads7846_setup_spi_msg;
|
||||
ts->read_state = ads7846_read_state;
|
||||
}
|
||||
|
||||
packet = devm_kzalloc(dev, sizeof(struct ads7846_packet), GFP_KERNEL);
|
||||
if (!packet)
|
||||
return -ENOMEM;
|
||||
@@ -1330,7 +1491,9 @@ static int ads7846_probe(struct spi_device *spi)
|
||||
ts->core_prop.swap_x_y = true;
|
||||
}
|
||||
|
||||
ads7846_setup_spi_msg(ts, pdata);
|
||||
err = ts->setup_spi_msg(ts, pdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
ts->reg = devm_regulator_get(dev, "vcc");
|
||||
if (IS_ERR(ts->reg)) {
|
||||
|
||||
@@ -164,7 +164,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(ar1021_i2c_pm,
|
||||
ar1021_i2c_suspend, ar1021_i2c_resume);
|
||||
|
||||
static const struct i2c_device_id ar1021_i2c_id[] = {
|
||||
{ "ar1021" },
|
||||
{ .name = "ar1021" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ar1021_i2c_id);
|
||||
|
||||
@@ -1397,7 +1397,8 @@ static int mxt_prepare_cfg_mem(struct mxt_data *data, struct mxt_cfg *cfg)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
struct mxt_object *object;
|
||||
unsigned int type, instance, size, byte_offset;
|
||||
unsigned int type, instance, size;
|
||||
int byte_offset;
|
||||
int offset;
|
||||
int ret;
|
||||
int i;
|
||||
@@ -2840,14 +2841,12 @@ static ssize_t mxt_object_show(struct device *dev,
|
||||
int count = 0;
|
||||
int i, j;
|
||||
int error;
|
||||
u8 *obuf;
|
||||
|
||||
/* Pre-allocate buffer large enough to hold max sized object. */
|
||||
obuf = kmalloc(256, GFP_KERNEL);
|
||||
u8 *obuf __free(kfree) = kmalloc(256, GFP_KERNEL);
|
||||
if (!obuf)
|
||||
return -ENOMEM;
|
||||
|
||||
error = 0;
|
||||
for (i = 0; i < data->info->object_num; i++) {
|
||||
object = data->object_table + i;
|
||||
|
||||
@@ -2862,15 +2861,13 @@ static ssize_t mxt_object_show(struct device *dev,
|
||||
|
||||
error = __mxt_read_reg(data->client, addr, size, obuf);
|
||||
if (error)
|
||||
goto done;
|
||||
return error;
|
||||
|
||||
count = mxt_show_instance(buf, count, object, j, obuf);
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
kfree(obuf);
|
||||
return error ?: count;
|
||||
return count;
|
||||
}
|
||||
|
||||
static int mxt_check_firmware_format(struct device *dev,
|
||||
@@ -3420,11 +3417,11 @@ MODULE_DEVICE_TABLE(acpi, mxt_acpi_id);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id mxt_id[] = {
|
||||
{ "qt602240_ts" },
|
||||
{ "atmel_mxt_ts" },
|
||||
{ "atmel_mxt_tp" },
|
||||
{ "maxtouch" },
|
||||
{ "mXT224" },
|
||||
{ .name = "qt602240_ts" },
|
||||
{ .name = "atmel_mxt_ts" },
|
||||
{ .name = "atmel_mxt_tp" },
|
||||
{ .name = "maxtouch" },
|
||||
{ .name = "mXT224" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mxt_id);
|
||||
|
||||
@@ -618,7 +618,7 @@ static int auo_pixcir_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id auo_pixcir_idtable[] = {
|
||||
{ "auo_pixcir_ts" },
|
||||
{ .name = "auo_pixcir_ts" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, auo_pixcir_idtable);
|
||||
|
||||
@@ -597,7 +597,7 @@ static int bu21013_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(bu21013_dev_pm_ops, bu21013_suspend, bu21013_resume);
|
||||
|
||||
static const struct i2c_device_id bu21013_id[] = {
|
||||
{ DRIVER_TP },
|
||||
{ .name = DRIVER_TP },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bu21013_id);
|
||||
|
||||
@@ -442,7 +442,7 @@ static int bu21029_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(bu21029_pm_ops, bu21029_suspend, bu21029_resume);
|
||||
|
||||
static const struct i2c_device_id bu21029_ids[] = {
|
||||
{ DRIVER_NAME },
|
||||
{ .name = DRIVER_NAME },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bu21029_ids);
|
||||
|
||||
@@ -322,7 +322,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctma140_pm,
|
||||
cy8ctma140_suspend, cy8ctma140_resume);
|
||||
|
||||
static const struct i2c_device_id cy8ctma140_idtable[] = {
|
||||
{ CY8CTMA140_NAME },
|
||||
{ .name = CY8CTMA140_NAME },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cy8ctma140_idtable);
|
||||
|
||||
@@ -267,7 +267,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cy8ctmg110_pm,
|
||||
cy8ctmg110_suspend, cy8ctmg110_resume);
|
||||
|
||||
static const struct i2c_device_id cy8ctmg110_idtable[] = {
|
||||
{ CY8CTMG110_DRIVER_NAME, 1 },
|
||||
{ .name = CY8CTMG110_DRIVER_NAME, .driver_data = 1 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
@@ -938,7 +938,7 @@ static const struct of_device_id cyttsp5_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, cyttsp5_of_match);
|
||||
|
||||
static const struct i2c_device_id cyttsp5_i2c_id[] = {
|
||||
{ CYTTSP5_NAME },
|
||||
{ .name = CYTTSP5_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id);
|
||||
|
||||
@@ -103,7 +103,7 @@ static int cyttsp_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cyttsp_i2c_id[] = {
|
||||
{ CY_I2C_NAME },
|
||||
{ .name = CY_I2C_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id);
|
||||
|
||||
@@ -266,7 +266,7 @@ static int eeti_ts_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(eeti_ts_pm, eeti_ts_suspend, eeti_ts_resume);
|
||||
|
||||
static const struct i2c_device_id eeti_ts_id[] = {
|
||||
{ "eeti_ts" },
|
||||
{ .name = "eeti_ts" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, eeti_ts_id);
|
||||
|
||||
@@ -219,7 +219,7 @@ static int egalax_ts_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id egalax_ts_id[] = {
|
||||
{ "egalax_ts" },
|
||||
{ .name = "egalax_ts" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, egalax_ts_id);
|
||||
|
||||
@@ -1615,9 +1615,9 @@ static DEFINE_SIMPLE_DEV_PM_OPS(elants_i2c_pm_ops,
|
||||
elants_i2c_suspend, elants_i2c_resume);
|
||||
|
||||
static const struct i2c_device_id elants_i2c_id[] = {
|
||||
{ DEVICE_NAME, EKTH3500 },
|
||||
{ "ekth3500", EKTH3500 },
|
||||
{ "ektf3624", EKTF3624 },
|
||||
{ .name = DEVICE_NAME, .driver_data = EKTH3500 },
|
||||
{ .name = "ekth3500", .driver_data = EKTH3500 },
|
||||
{ .name = "ektf3624", .driver_data = EKTF3624 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, elants_i2c_id);
|
||||
|
||||
@@ -432,10 +432,10 @@ static int exc3000_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id exc3000_id[] = {
|
||||
{ "exc3000", EETI_EXC3000 },
|
||||
{ "exc80h60", EETI_EXC80H60 },
|
||||
{ "exc80h84", EETI_EXC80H84 },
|
||||
{ "exc81w32", EETI_EXC81W32 },
|
||||
{ .name = "exc3000", .driver_data = EETI_EXC3000 },
|
||||
{ .name = "exc80h60", .driver_data = EETI_EXC80H60 },
|
||||
{ .name = "exc80h84", .driver_data = EETI_EXC80H84 },
|
||||
{ .name = "exc81w32", .driver_data = EETI_EXC81W32 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, exc3000_id);
|
||||
|
||||
@@ -1057,7 +1057,8 @@ static void goodix_read_config(struct goodix_ts_data *ts)
|
||||
}
|
||||
|
||||
ts->int_trigger_type = ts->config[TRIGGER_LOC] & 0x03;
|
||||
ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f;
|
||||
ts->max_touch_num = min(ts->config[MAX_CONTACTS_LOC] & 0x0f,
|
||||
GOODIX_MAX_CONTACTS);
|
||||
|
||||
x_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC]);
|
||||
y_max = get_unaligned_le16(&ts->config[RESOLUTION_LOC + 2]);
|
||||
@@ -1523,7 +1524,7 @@ static int goodix_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(goodix_pm_ops, goodix_suspend, goodix_resume);
|
||||
|
||||
static const struct i2c_device_id goodix_ts_id[] = {
|
||||
{ "GDIX1001:00" },
|
||||
{ .name = "GDIX1001:00" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
|
||||
|
||||
@@ -1081,7 +1081,7 @@ static int hideep_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id hideep_i2c_id[] = {
|
||||
{ HIDEEP_I2C_NAME },
|
||||
{ .name = HIDEEP_I2C_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, hideep_i2c_id);
|
||||
|
||||
@@ -406,8 +406,8 @@ static const struct himax_chip hx83112b_chip = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id himax_ts_id[] = {
|
||||
{ "hx83100a", (kernel_ulong_t)&hx83100a_chip },
|
||||
{ "hx83112b", (kernel_ulong_t)&hx83112b_chip },
|
||||
{ .name = "hx83100a", .driver_data = (kernel_ulong_t)&hx83100a_chip },
|
||||
{ .name = "hx83112b", .driver_data = (kernel_ulong_t)&hx83112b_chip },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, himax_ts_id);
|
||||
|
||||
@@ -226,7 +226,7 @@ static int cst816x_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id cst816x_id[] = {
|
||||
{ .name = "cst816s", 0 },
|
||||
{ .name = "cst816s" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, cst816x_id);
|
||||
|
||||
@@ -1049,10 +1049,10 @@ static int ili210x_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ili210x_i2c_id[] = {
|
||||
{ "ili210x", (long)&ili210x_chip },
|
||||
{ "ili2117", (long)&ili211x_chip },
|
||||
{ "ili2120", (long)&ili212x_chip },
|
||||
{ "ili251x", (long)&ili251x_chip },
|
||||
{ .name = "ili210x", .driver_data = (long)&ili210x_chip },
|
||||
{ .name = "ili2117", .driver_data = (long)&ili211x_chip },
|
||||
{ .name = "ili2120", .driver_data = (long)&ili212x_chip },
|
||||
{ .name = "ili251x", .driver_data = (long)&ili251x_chip },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id);
|
||||
|
||||
@@ -639,7 +639,7 @@ static int ilitek_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(ilitek_pm_ops, ilitek_suspend, ilitek_resume);
|
||||
|
||||
static const struct i2c_device_id ilitek_ts_i2c_id[] = {
|
||||
{ ILITEK_TS_NAME },
|
||||
{ .name = ILITEK_TS_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ilitek_ts_i2c_id);
|
||||
|
||||
@@ -1049,9 +1049,9 @@ static int iqs5xx_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id iqs5xx_id[] = {
|
||||
{ "iqs550", 0 },
|
||||
{ "iqs572", 1 },
|
||||
{ "iqs525", 2 },
|
||||
{ .name = "iqs550" },
|
||||
{ .name = "iqs572" },
|
||||
{ .name = "iqs525" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, iqs5xx_id);
|
||||
|
||||
@@ -213,7 +213,7 @@ static int max11801_ts_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id max11801_ts_id[] = {
|
||||
{ "max11801" },
|
||||
{ .name = "max11801" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, max11801_ts_id);
|
||||
|
||||
@@ -1536,7 +1536,7 @@ MODULE_DEVICE_TABLE(acpi, mip4_acpi_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id mip4_i2c_ids[] = {
|
||||
{ MIP4_DEVICE_NAME },
|
||||
{ .name = MIP4_DEVICE_NAME },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids);
|
||||
|
||||
@@ -211,7 +211,7 @@ static int migor_ts_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(migor_ts_pm, migor_ts_suspend, migor_ts_resume);
|
||||
|
||||
static const struct i2c_device_id migor_ts_id[] = {
|
||||
{ "migor_ts" },
|
||||
{ .name = "migor_ts" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, migor_ts_id);
|
||||
|
||||
@@ -217,7 +217,9 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
|
||||
struct mms114_data *data = dev_id;
|
||||
struct i2c_client *client = data->client;
|
||||
struct mms114_touch touch[MMS114_MAX_TOUCH];
|
||||
struct mms114_touch *t;
|
||||
int packet_size;
|
||||
int event_size;
|
||||
int touch_size;
|
||||
int index;
|
||||
int error;
|
||||
@@ -226,11 +228,19 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
|
||||
if (packet_size <= 0)
|
||||
goto out;
|
||||
|
||||
if (packet_size > sizeof(touch)) {
|
||||
dev_err(&client->dev, "Invalid packet size %d (max %zu)\n",
|
||||
packet_size, sizeof(touch));
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* MMS136 has slightly different event size */
|
||||
if (data->type == TYPE_MMS134S || data->type == TYPE_MMS136)
|
||||
touch_size = packet_size / MMS136_EVENT_SIZE;
|
||||
event_size = MMS136_EVENT_SIZE;
|
||||
else
|
||||
touch_size = packet_size / MMS114_EVENT_SIZE;
|
||||
event_size = MMS114_EVENT_SIZE;
|
||||
|
||||
touch_size = packet_size / event_size;
|
||||
|
||||
error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size,
|
||||
(u8 *)touch);
|
||||
@@ -238,18 +248,20 @@ static irqreturn_t mms114_interrupt(int irq, void *dev_id)
|
||||
goto out;
|
||||
|
||||
for (index = 0; index < touch_size; index++) {
|
||||
switch (touch[index].type) {
|
||||
t = (struct mms114_touch *)((u8 *)touch + index * event_size);
|
||||
|
||||
switch (t->type) {
|
||||
case MMS114_TYPE_TOUCHSCREEN:
|
||||
mms114_process_mt(data, touch + index);
|
||||
mms114_process_mt(data, t);
|
||||
break;
|
||||
|
||||
case MMS114_TYPE_TOUCHKEY:
|
||||
mms114_process_touchkey(data, touch + index);
|
||||
mms114_process_touchkey(data, t);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(&client->dev, "Wrong touch type (%d)\n",
|
||||
touch[index].type);
|
||||
t->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -667,7 +679,7 @@ static int mms114_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(mms114_pm_ops, mms114_suspend, mms114_resume);
|
||||
|
||||
static const struct i2c_device_id mms114_id[] = {
|
||||
{ "mms114" },
|
||||
{ .name = "mms114" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, mms114_id);
|
||||
|
||||
@@ -326,8 +326,8 @@ static const struct of_device_id nvt_ts_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, nvt_ts_of_match);
|
||||
|
||||
static const struct i2c_device_id nvt_ts_i2c_id[] = {
|
||||
{ "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data },
|
||||
{ "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data },
|
||||
{ .name = "nt11205-ts", .driver_data = (unsigned long)&nvt_nt11205_ts_data },
|
||||
{ .name = "nt36672a-ts", .driver_data = (unsigned long)&nvt_nt36672a_ts_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id);
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Driver for Motorola PCAP2 touchscreen as found in the EZX phone platform.
|
||||
*
|
||||
* Copyright (C) 2006 Harald Welte <laforge@openezx.org>
|
||||
* Copyright (C) 2009 Daniel Ribeiro <drwyrm@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/mfd/ezx-pcap.h>
|
||||
|
||||
struct pcap_ts {
|
||||
struct pcap_chip *pcap;
|
||||
struct input_dev *input;
|
||||
struct delayed_work work;
|
||||
u16 x, y;
|
||||
u16 pressure;
|
||||
u8 read_state;
|
||||
};
|
||||
|
||||
#define SAMPLE_DELAY 20 /* msecs */
|
||||
|
||||
#define X_AXIS_MIN 0
|
||||
#define X_AXIS_MAX 1023
|
||||
#define Y_AXIS_MAX X_AXIS_MAX
|
||||
#define Y_AXIS_MIN X_AXIS_MIN
|
||||
#define PRESSURE_MAX X_AXIS_MAX
|
||||
#define PRESSURE_MIN X_AXIS_MIN
|
||||
|
||||
static void pcap_ts_read_xy(void *data, u16 res[2])
|
||||
{
|
||||
struct pcap_ts *pcap_ts = data;
|
||||
|
||||
switch (pcap_ts->read_state) {
|
||||
case PCAP_ADC_TS_M_PRESSURE:
|
||||
/* pressure reading is unreliable */
|
||||
if (res[0] > PRESSURE_MIN && res[0] < PRESSURE_MAX)
|
||||
pcap_ts->pressure = res[0];
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_XY;
|
||||
schedule_delayed_work(&pcap_ts->work, 0);
|
||||
break;
|
||||
case PCAP_ADC_TS_M_XY:
|
||||
pcap_ts->y = res[0];
|
||||
pcap_ts->x = res[1];
|
||||
if (pcap_ts->x <= X_AXIS_MIN || pcap_ts->x >= X_AXIS_MAX ||
|
||||
pcap_ts->y <= Y_AXIS_MIN || pcap_ts->y >= Y_AXIS_MAX) {
|
||||
/* pen has been released */
|
||||
input_report_abs(pcap_ts->input, ABS_PRESSURE, 0);
|
||||
input_report_key(pcap_ts->input, BTN_TOUCH, 0);
|
||||
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
|
||||
schedule_delayed_work(&pcap_ts->work, 0);
|
||||
} else {
|
||||
/* pen is touching the screen */
|
||||
input_report_abs(pcap_ts->input, ABS_X, pcap_ts->x);
|
||||
input_report_abs(pcap_ts->input, ABS_Y, pcap_ts->y);
|
||||
input_report_key(pcap_ts->input, BTN_TOUCH, 1);
|
||||
input_report_abs(pcap_ts->input, ABS_PRESSURE,
|
||||
pcap_ts->pressure);
|
||||
|
||||
/* switch back to pressure read mode */
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
|
||||
schedule_delayed_work(&pcap_ts->work,
|
||||
msecs_to_jiffies(SAMPLE_DELAY));
|
||||
}
|
||||
input_sync(pcap_ts->input);
|
||||
break;
|
||||
default:
|
||||
dev_warn(&pcap_ts->input->dev,
|
||||
"pcap_ts: Warning, unhandled read_state %d\n",
|
||||
pcap_ts->read_state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void pcap_ts_work(struct work_struct *work)
|
||||
{
|
||||
struct delayed_work *dw = to_delayed_work(work);
|
||||
struct pcap_ts *pcap_ts = container_of(dw, struct pcap_ts, work);
|
||||
u8 ch[2];
|
||||
|
||||
pcap_set_ts_bits(pcap_ts->pcap,
|
||||
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
|
||||
|
||||
if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY)
|
||||
return;
|
||||
|
||||
/* start adc conversion */
|
||||
ch[0] = PCAP_ADC_CH_TS_X1;
|
||||
ch[1] = PCAP_ADC_CH_TS_Y1;
|
||||
pcap_adc_async(pcap_ts->pcap, PCAP_ADC_BANK_1, 0, ch,
|
||||
pcap_ts_read_xy, pcap_ts);
|
||||
}
|
||||
|
||||
static irqreturn_t pcap_ts_event_touch(int pirq, void *data)
|
||||
{
|
||||
struct pcap_ts *pcap_ts = data;
|
||||
|
||||
if (pcap_ts->read_state == PCAP_ADC_TS_M_STANDBY) {
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_PRESSURE;
|
||||
schedule_delayed_work(&pcap_ts->work, 0);
|
||||
}
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int pcap_ts_open(struct input_dev *dev)
|
||||
{
|
||||
struct pcap_ts *pcap_ts = input_get_drvdata(dev);
|
||||
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_STANDBY;
|
||||
schedule_delayed_work(&pcap_ts->work, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pcap_ts_close(struct input_dev *dev)
|
||||
{
|
||||
struct pcap_ts *pcap_ts = input_get_drvdata(dev);
|
||||
|
||||
cancel_delayed_work_sync(&pcap_ts->work);
|
||||
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
|
||||
pcap_set_ts_bits(pcap_ts->pcap,
|
||||
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
|
||||
}
|
||||
|
||||
static int pcap_ts_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct input_dev *input_dev;
|
||||
struct pcap_ts *pcap_ts;
|
||||
int err = -ENOMEM;
|
||||
|
||||
pcap_ts = kzalloc_obj(*pcap_ts);
|
||||
if (!pcap_ts)
|
||||
return err;
|
||||
|
||||
pcap_ts->pcap = dev_get_drvdata(pdev->dev.parent);
|
||||
platform_set_drvdata(pdev, pcap_ts);
|
||||
|
||||
input_dev = input_allocate_device();
|
||||
if (!input_dev)
|
||||
goto fail;
|
||||
|
||||
INIT_DELAYED_WORK(&pcap_ts->work, pcap_ts_work);
|
||||
|
||||
pcap_ts->read_state = PCAP_ADC_TS_M_NONTS;
|
||||
pcap_set_ts_bits(pcap_ts->pcap,
|
||||
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
|
||||
|
||||
pcap_ts->input = input_dev;
|
||||
input_set_drvdata(input_dev, pcap_ts);
|
||||
|
||||
input_dev->name = "pcap-touchscreen";
|
||||
input_dev->phys = "pcap_ts/input0";
|
||||
input_dev->id.bustype = BUS_HOST;
|
||||
input_dev->id.vendor = 0x0001;
|
||||
input_dev->id.product = 0x0002;
|
||||
input_dev->id.version = 0x0100;
|
||||
input_dev->dev.parent = &pdev->dev;
|
||||
input_dev->open = pcap_ts_open;
|
||||
input_dev->close = pcap_ts_close;
|
||||
|
||||
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
|
||||
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
|
||||
input_set_abs_params(input_dev, ABS_X, X_AXIS_MIN, X_AXIS_MAX, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_Y, Y_AXIS_MIN, Y_AXIS_MAX, 0, 0);
|
||||
input_set_abs_params(input_dev, ABS_PRESSURE, PRESSURE_MIN,
|
||||
PRESSURE_MAX, 0, 0);
|
||||
|
||||
err = input_register_device(pcap_ts->input);
|
||||
if (err)
|
||||
goto fail_allocate;
|
||||
|
||||
err = request_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS),
|
||||
pcap_ts_event_touch, 0, "Touch Screen", pcap_ts);
|
||||
if (err)
|
||||
goto fail_register;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_register:
|
||||
input_unregister_device(input_dev);
|
||||
goto fail;
|
||||
fail_allocate:
|
||||
input_free_device(input_dev);
|
||||
fail:
|
||||
kfree(pcap_ts);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void pcap_ts_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct pcap_ts *pcap_ts = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(pcap_to_irq(pcap_ts->pcap, PCAP_IRQ_TS), pcap_ts);
|
||||
cancel_delayed_work_sync(&pcap_ts->work);
|
||||
|
||||
input_unregister_device(pcap_ts->input);
|
||||
|
||||
kfree(pcap_ts);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int pcap_ts_suspend(struct device *dev)
|
||||
{
|
||||
struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
|
||||
|
||||
pcap_set_ts_bits(pcap_ts->pcap, PCAP_ADC_TS_REF_LOWPWR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcap_ts_resume(struct device *dev)
|
||||
{
|
||||
struct pcap_ts *pcap_ts = dev_get_drvdata(dev);
|
||||
|
||||
pcap_set_ts_bits(pcap_ts->pcap,
|
||||
pcap_ts->read_state << PCAP_ADC_TS_M_SHIFT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops pcap_ts_pm_ops = {
|
||||
.suspend = pcap_ts_suspend,
|
||||
.resume = pcap_ts_resume,
|
||||
};
|
||||
#define PCAP_TS_PM_OPS (&pcap_ts_pm_ops)
|
||||
#else
|
||||
#define PCAP_TS_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static struct platform_driver pcap_ts_driver = {
|
||||
.probe = pcap_ts_probe,
|
||||
.remove = pcap_ts_remove,
|
||||
.driver = {
|
||||
.name = "pcap-ts",
|
||||
.pm = PCAP_TS_PM_OPS,
|
||||
},
|
||||
};
|
||||
module_platform_driver(pcap_ts_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Motorola PCAP2 touchscreen driver");
|
||||
MODULE_AUTHOR("Daniel Ribeiro / Harald Welte");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:pcap_ts");
|
||||
@@ -580,8 +580,8 @@ static const struct pixcir_i2c_chip_data pixcir_tangoc_data = {
|
||||
};
|
||||
|
||||
static const struct i2c_device_id pixcir_i2c_ts_id[] = {
|
||||
{ "pixcir_ts", (unsigned long) &pixcir_ts_data },
|
||||
{ "pixcir_tangoc", (unsigned long) &pixcir_tangoc_data },
|
||||
{ .name = "pixcir_ts", .driver_data = (unsigned long)&pixcir_ts_data },
|
||||
{ .name = "pixcir_tangoc", .driver_data = (unsigned long)&pixcir_tangoc_data },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
|
||||
|
||||
@@ -1219,8 +1219,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(raydium_i2c_pm_ops,
|
||||
raydium_i2c_suspend, raydium_i2c_resume);
|
||||
|
||||
static const struct i2c_device_id raydium_i2c_id[] = {
|
||||
{ "raydium_i2c" },
|
||||
{ "rm32380" },
|
||||
{ .name = "raydium_i2c" },
|
||||
{ .name = "rm32380" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, raydium_i2c_id);
|
||||
|
||||
@@ -1144,7 +1144,7 @@ static int rohm_bu21023_i2c_probe(struct i2c_client *client)
|
||||
}
|
||||
|
||||
static const struct i2c_device_id rohm_bu21023_i2c_id[] = {
|
||||
{ BU21023_NAME },
|
||||
{ .name = BU21023_NAME },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, rohm_bu21023_i2c_id);
|
||||
|
||||
@@ -520,7 +520,7 @@ MODULE_DEVICE_TABLE(of, s6sy761_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id s6sy761_id[] = {
|
||||
{ "s6sy761" },
|
||||
{ .name = "s6sy761" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, s6sy761_id);
|
||||
|
||||
@@ -776,12 +776,12 @@ static int silead_ts_resume(struct device *dev)
|
||||
static DEFINE_SIMPLE_DEV_PM_OPS(silead_ts_pm, silead_ts_suspend, silead_ts_resume);
|
||||
|
||||
static const struct i2c_device_id silead_ts_id[] = {
|
||||
{ "gsl1680" },
|
||||
{ "gsl1688" },
|
||||
{ "gsl3670" },
|
||||
{ "gsl3675" },
|
||||
{ "gsl3692" },
|
||||
{ "mssl1680" },
|
||||
{ .name = "gsl1680" },
|
||||
{ .name = "gsl1688" },
|
||||
{ .name = "gsl3670" },
|
||||
{ .name = "gsl3675" },
|
||||
{ .name = "gsl3692" },
|
||||
{ .name = "mssl1680" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, silead_ts_id);
|
||||
|
||||
@@ -374,8 +374,8 @@ MODULE_DEVICE_TABLE(of, sis_ts_dt_ids);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id sis_ts_id[] = {
|
||||
{ SIS_I2C_NAME },
|
||||
{ "9200-ts" },
|
||||
{ .name = SIS_I2C_NAME },
|
||||
{ .name = "9200-ts" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, sis_ts_id);
|
||||
|
||||
@@ -453,8 +453,8 @@ static DEFINE_SIMPLE_DEV_PM_OPS(st1232_ts_pm_ops,
|
||||
st1232_ts_suspend, st1232_ts_resume);
|
||||
|
||||
static const struct i2c_device_id st1232_ts_id[] = {
|
||||
{ ST1232_TS_NAME, (unsigned long)&st1232_chip_info },
|
||||
{ ST1633_TS_NAME, (unsigned long)&st1633_chip_info },
|
||||
{ .name = ST1232_TS_NAME, .driver_data = (unsigned long)&st1232_chip_info },
|
||||
{ .name = ST1633_TS_NAME, .driver_data = (unsigned long)&st1633_chip_info },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, st1232_ts_id);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input/mt.h>
|
||||
#include <linux/input/touchscreen.h>
|
||||
@@ -69,20 +70,21 @@
|
||||
#define STMFTS_MAX_FINGERS 10
|
||||
#define STMFTS_DEV_NAME "stmfts"
|
||||
|
||||
enum stmfts_regulators {
|
||||
STMFTS_REGULATOR_VDD,
|
||||
STMFTS_REGULATOR_AVDD,
|
||||
static const struct regulator_bulk_data stmfts_supplies[] = {
|
||||
{ .supply = "vdd" },
|
||||
{ .supply = "avdd" },
|
||||
};
|
||||
|
||||
struct stmfts_data {
|
||||
struct i2c_client *client;
|
||||
struct input_dev *input;
|
||||
struct gpio_desc *reset_gpio;
|
||||
struct led_classdev led_cdev;
|
||||
struct mutex mutex;
|
||||
|
||||
struct touchscreen_properties prop;
|
||||
|
||||
struct regulator_bulk_data regulators[2];
|
||||
struct regulator_bulk_data *supplies;
|
||||
|
||||
/*
|
||||
* Presence of ledvdd will be used also to check
|
||||
@@ -107,7 +109,7 @@ struct stmfts_data {
|
||||
};
|
||||
|
||||
static int stmfts_brightness_set(struct led_classdev *led_cdev,
|
||||
enum led_brightness value)
|
||||
enum led_brightness value)
|
||||
{
|
||||
struct stmfts_data *sdata = container_of(led_cdev,
|
||||
struct stmfts_data, led_cdev);
|
||||
@@ -250,7 +252,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
|
||||
u8 *event = &sdata->data[i * STMFTS_EVENT_SIZE];
|
||||
|
||||
switch (event[0]) {
|
||||
|
||||
case STMFTS_EV_CONTROLLER_READY:
|
||||
case STMFTS_EV_SLEEP_OUT_CONTROLLER_READY:
|
||||
case STMFTS_EV_STATUS:
|
||||
@@ -263,7 +264,6 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
|
||||
}
|
||||
|
||||
switch (event[0] & STMFTS_MASK_EVENT_ID) {
|
||||
|
||||
case STMFTS_EV_MULTI_TOUCH_ENTER:
|
||||
case STMFTS_EV_MULTI_TOUCH_MOTION:
|
||||
stmfts_report_contact_event(sdata, event);
|
||||
@@ -285,9 +285,9 @@ static void stmfts_parse_events(struct stmfts_data *sdata)
|
||||
|
||||
case STMFTS_EV_ERROR:
|
||||
dev_warn(&sdata->client->dev,
|
||||
"error code: 0x%x%x%x%x%x%x",
|
||||
event[6], event[5], event[4],
|
||||
event[3], event[2], event[1]);
|
||||
"error code: 0x%x%x%x%x%x%x",
|
||||
event[6], event[5], event[4],
|
||||
event[3], event[2], event[1]);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -404,7 +404,7 @@ static void stmfts_input_close(struct input_dev *dev)
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_chip_id(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
@@ -412,7 +412,8 @@ static ssize_t stmfts_sysfs_chip_id(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_chip_version(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
@@ -420,7 +421,7 @@ static ssize_t stmfts_sysfs_chip_version(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
@@ -428,7 +429,7 @@ static ssize_t stmfts_sysfs_fw_ver(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_config_id(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
@@ -436,7 +437,8 @@ static ssize_t stmfts_sysfs_config_id(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_config_version(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
@@ -444,7 +446,8 @@ static ssize_t stmfts_sysfs_config_version(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_read_status(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
u8 status[4];
|
||||
@@ -459,7 +462,8 @@ static ssize_t stmfts_sysfs_read_status(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
|
||||
@@ -467,8 +471,8 @@ static ssize_t stmfts_sysfs_hover_enable_read(struct device *dev,
|
||||
}
|
||||
|
||||
static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
unsigned long value;
|
||||
@@ -485,8 +489,8 @@ static ssize_t stmfts_sysfs_hover_enable_write(struct device *dev,
|
||||
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);
|
||||
value ? STMFTS_SS_HOVER_SENSE_ON :
|
||||
STMFTS_SS_HOVER_SENSE_OFF);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -518,22 +522,11 @@ static struct attribute *stmfts_sysfs_attrs[] = {
|
||||
};
|
||||
ATTRIBUTE_GROUPS(stmfts_sysfs);
|
||||
|
||||
static int stmfts_power_on(struct stmfts_data *sdata)
|
||||
static int stmfts_read_system_info(struct stmfts_data *sdata)
|
||||
{
|
||||
int err;
|
||||
u8 reg[8];
|
||||
|
||||
err = regulator_bulk_enable(ARRAY_SIZE(sdata->regulators),
|
||||
sdata->regulators);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* The datasheet does not specify the power on time, but considering
|
||||
* that the reset time is < 10ms, I sleep 20ms to be sure
|
||||
*/
|
||||
msleep(20);
|
||||
|
||||
err = i2c_smbus_read_i2c_block_data(sdata->client, STMFTS_READ_INFO,
|
||||
sizeof(reg), reg);
|
||||
if (err < 0)
|
||||
@@ -547,9 +540,21 @@ static int stmfts_power_on(struct stmfts_data *sdata)
|
||||
sdata->config_id = reg[4];
|
||||
sdata->config_ver = reg[5];
|
||||
|
||||
enable_irq(sdata->client->irq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void stmfts_reset(struct stmfts_data *sdata)
|
||||
{
|
||||
gpiod_set_value_cansleep(sdata->reset_gpio, 1);
|
||||
msleep(20);
|
||||
|
||||
gpiod_set_value_cansleep(sdata->reset_gpio, 0);
|
||||
msleep(50);
|
||||
}
|
||||
|
||||
static int stmfts_configure(struct stmfts_data *sdata)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = stmfts_command(sdata, STMFTS_SYSTEM_RESET);
|
||||
if (err)
|
||||
@@ -575,13 +580,52 @@ static int stmfts_power_on(struct stmfts_data *sdata)
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stmfts_power_on(struct stmfts_data *sdata)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = regulator_bulk_enable(ARRAY_SIZE(stmfts_supplies),
|
||||
sdata->supplies);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* The datasheet does not specify the power on time, but considering
|
||||
* that the reset time is < 10ms, I sleep 20ms to be sure
|
||||
*/
|
||||
msleep(20);
|
||||
|
||||
if (sdata->reset_gpio)
|
||||
stmfts_reset(sdata);
|
||||
|
||||
err = stmfts_read_system_info(sdata);
|
||||
if (err)
|
||||
goto err_disable_regulators;
|
||||
|
||||
enable_irq(sdata->client->irq);
|
||||
|
||||
msleep(50);
|
||||
|
||||
err = stmfts_configure(sdata);
|
||||
if (err)
|
||||
goto err_disable_irq;
|
||||
|
||||
/*
|
||||
* At this point no one is using the touchscreen
|
||||
* and I don't really care about the return value
|
||||
*/
|
||||
(void) i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
|
||||
(void)i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_IN);
|
||||
|
||||
return 0;
|
||||
|
||||
err_disable_irq:
|
||||
disable_irq(sdata->client->irq);
|
||||
err_disable_regulators:
|
||||
regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies), sdata->supplies);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void stmfts_power_off(void *data)
|
||||
@@ -589,8 +633,11 @@ static void stmfts_power_off(void *data)
|
||||
struct stmfts_data *sdata = data;
|
||||
|
||||
disable_irq(sdata->client->irq);
|
||||
regulator_bulk_disable(ARRAY_SIZE(sdata->regulators),
|
||||
sdata->regulators);
|
||||
|
||||
if (sdata->reset_gpio)
|
||||
gpiod_set_value_cansleep(sdata->reset_gpio, 1);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(stmfts_supplies), sdata->supplies);
|
||||
}
|
||||
|
||||
static int stmfts_enable_led(struct stmfts_data *sdata)
|
||||
@@ -619,6 +666,7 @@ static int stmfts_enable_led(struct stmfts_data *sdata)
|
||||
|
||||
static int stmfts_probe(struct i2c_client *client)
|
||||
{
|
||||
struct device *dev = &client->dev;
|
||||
int err;
|
||||
struct stmfts_data *sdata;
|
||||
|
||||
@@ -627,7 +675,7 @@ static int stmfts_probe(struct i2c_client *client)
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
|
||||
sdata = devm_kzalloc(&client->dev, sizeof(*sdata), GFP_KERNEL);
|
||||
sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL);
|
||||
if (!sdata)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -637,15 +685,19 @@ static int stmfts_probe(struct i2c_client *client)
|
||||
mutex_init(&sdata->mutex);
|
||||
init_completion(&sdata->cmd_done);
|
||||
|
||||
sdata->regulators[STMFTS_REGULATOR_VDD].supply = "vdd";
|
||||
sdata->regulators[STMFTS_REGULATOR_AVDD].supply = "avdd";
|
||||
err = devm_regulator_bulk_get(&client->dev,
|
||||
ARRAY_SIZE(sdata->regulators),
|
||||
sdata->regulators);
|
||||
err = devm_regulator_bulk_get_const(dev,
|
||||
ARRAY_SIZE(stmfts_supplies),
|
||||
stmfts_supplies,
|
||||
&sdata->supplies);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
sdata->input = devm_input_allocate_device(&client->dev);
|
||||
sdata->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(sdata->reset_gpio))
|
||||
return dev_err_probe(dev, PTR_ERR(sdata->reset_gpio),
|
||||
"Failed to get GPIO 'reset'\n");
|
||||
|
||||
sdata->input = devm_input_allocate_device(dev);
|
||||
if (!sdata->input)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -664,8 +716,7 @@ static int stmfts_probe(struct i2c_client *client)
|
||||
input_set_abs_params(sdata->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
|
||||
input_set_abs_params(sdata->input, ABS_DISTANCE, 0, 255, 0, 0);
|
||||
|
||||
sdata->use_key = device_property_read_bool(&client->dev,
|
||||
"touch-key-connected");
|
||||
sdata->use_key = device_property_read_bool(dev, "touch-key-connected");
|
||||
if (sdata->use_key) {
|
||||
input_set_capability(sdata->input, EV_KEY, KEY_MENU);
|
||||
input_set_capability(sdata->input, EV_KEY, KEY_BACK);
|
||||
@@ -685,20 +736,20 @@ static int stmfts_probe(struct i2c_client *client)
|
||||
* interrupts. To be on the safe side it's better to not enable
|
||||
* the interrupts during their request.
|
||||
*/
|
||||
err = devm_request_threaded_irq(&client->dev, client->irq,
|
||||
err = devm_request_threaded_irq(dev, client->irq,
|
||||
NULL, stmfts_irq_handler,
|
||||
IRQF_ONESHOT | IRQF_NO_AUTOEN,
|
||||
"stmfts_irq", sdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dev_dbg(&client->dev, "initializing ST-Microelectronics FTS...\n");
|
||||
dev_dbg(dev, "initializing ST-Microelectronics FTS...\n");
|
||||
|
||||
err = stmfts_power_on(sdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_add_action_or_reset(&client->dev, stmfts_power_off, sdata);
|
||||
err = devm_add_action_or_reset(dev, stmfts_power_off, sdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -715,13 +766,13 @@ static int stmfts_probe(struct i2c_client *client)
|
||||
* without LEDs. The ledvdd regulator pointer will be
|
||||
* used as a flag.
|
||||
*/
|
||||
dev_warn(&client->dev, "unable to use touchkey leds\n");
|
||||
dev_warn(dev, "unable to use touchkey leds\n");
|
||||
sdata->ledvdd = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
pm_runtime_enable(&client->dev);
|
||||
device_enable_async_suspend(&client->dev);
|
||||
pm_runtime_enable(dev);
|
||||
device_enable_async_suspend(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -746,9 +797,10 @@ static int stmfts_runtime_suspend(struct device *dev)
|
||||
static int stmfts_runtime_resume(struct device *dev)
|
||||
{
|
||||
struct stmfts_data *sdata = dev_get_drvdata(dev);
|
||||
struct i2c_client *client = sdata->client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte(sdata->client, STMFTS_SLEEP_OUT);
|
||||
ret = i2c_smbus_write_byte(client, STMFTS_SLEEP_OUT);
|
||||
if (ret)
|
||||
dev_err(dev, "failed to resume device: %d\n", ret);
|
||||
|
||||
@@ -785,7 +837,7 @@ MODULE_DEVICE_TABLE(of, stmfts_of_match);
|
||||
#endif
|
||||
|
||||
static const struct i2c_device_id stmfts_id[] = {
|
||||
{ "stmfts" },
|
||||
{ .name = "stmfts" },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, stmfts_id);
|
||||
@@ -807,4 +859,4 @@ module_i2c_driver(stmfts_driver);
|
||||
|
||||
MODULE_AUTHOR("Andi Shyti <andi.shyti@samsung.com>");
|
||||
MODULE_DESCRIPTION("STMicroelectronics FTS Touch Screen");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user