summaryrefslogtreecommitdiff
path: root/drivers/input/rmi4
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/rmi4')
-rw-r--r--drivers/input/rmi4/Kconfig15
-rw-r--r--drivers/input/rmi4/Makefile2
-rw-r--r--drivers/input/rmi4/rmi_bus.c6
-rw-r--r--drivers/input/rmi4/rmi_driver.h2
-rw-r--r--drivers/input/rmi4/rmi_f1a.c143
-rw-r--r--drivers/input/rmi4/rmi_f21.c179
-rw-r--r--drivers/input/rmi4/rmi_f34.c135
7 files changed, 423 insertions, 59 deletions
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index c0163b983ce6..5db58fc9e11b 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -82,6 +82,21 @@ config RMI4_F12
touchpads. For sensors that support relative pointing, F12 also
provides mouse input.
+config RMI4_F1A
+ bool "RMI4 Function 1A (0D pointing)"
+ help
+ Say Y here if you want to add support for RMI4 function 1A.
+
+ Function 1A provides capacitive keys support for RMI4 devices.
+
+config RMI4_F21
+ bool "RMI4 Function 21 (PRESSURE)"
+ help
+ Say Y here if you want to add support for RMI4 function 21.
+
+ Function 21 provides buttons/pressure handling for RMI4 devices.
+ This includes support for buttons/pressure on PressurePad.
+
config RMI4_F30
bool "RMI4 Function 30 (GPIO LED)"
help
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index 02f14c846861..35ae29f72497 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -8,6 +8,8 @@ rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
+rmi_core-$(CONFIG_RMI4_F1A) += rmi_f1a.o
+rmi_core-$(CONFIG_RMI4_F21) += rmi_f21.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 3aee04837205..5f98c3bcfd46 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -360,6 +360,12 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F12
&rmi_f12_handler,
#endif
+#ifdef CONFIG_RMI4_F1A
+ &rmi_f1a_handler,
+#endif
+#ifdef CONFIG_RMI4_F21
+ &rmi_f21_handler,
+#endif
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 3bfe9013043e..e84495caab15 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -133,6 +133,8 @@ extern struct rmi_function_handler rmi_f01_handler;
extern struct rmi_function_handler rmi_f03_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
+extern struct rmi_function_handler rmi_f1a_handler;
+extern struct rmi_function_handler rmi_f21_handler;
extern struct rmi_function_handler rmi_f30_handler;
extern struct rmi_function_handler rmi_f34_handler;
extern struct rmi_function_handler rmi_f3a_handler;
diff --git a/drivers/input/rmi4/rmi_f1a.c b/drivers/input/rmi4/rmi_f1a.c
new file mode 100644
index 000000000000..765e9eae4cdc
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f1a.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 André Apitzsch <git@apitzsch.eu>
+ */
+
+#include <linux/input.h>
+#include <linux/property.h>
+#include "rmi_driver.h"
+
+struct f1a_data {
+ struct input_dev *input;
+
+ u32 *keymap;
+ unsigned int num_keys;
+};
+
+static int rmi_f1a_parse_device_properties(struct rmi_function *fn, struct f1a_data *f1a)
+{
+ static const char buttons_property[] = "linux,keycodes";
+ struct device *dev = &fn->dev;
+ u32 *buttonmap;
+ int n_keys;
+ int error;
+
+ if (!device_property_present(dev, buttons_property))
+ return 0;
+
+ n_keys = device_property_count_u32(dev, buttons_property);
+ if (n_keys <= 0) {
+ error = n_keys < 0 ? n_keys : -EINVAL;
+ dev_err(dev, "Invalid/malformed '%s' property: %d\n",
+ buttons_property, error);
+ return error;
+ }
+
+ buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap),
+ GFP_KERNEL);
+ if (!buttonmap)
+ return -ENOMEM;
+
+ error = device_property_read_u32_array(dev, buttons_property,
+ buttonmap, n_keys);
+ if (error) {
+ dev_err(dev, "Failed to parse '%s' property: %d\n",
+ buttons_property, error);
+ return error;
+ }
+
+ f1a->keymap = buttonmap;
+ f1a->num_keys = n_keys;
+
+ return 0;
+}
+
+static irqreturn_t rmi_f1a_attention(int irq, void *ctx)
+{
+ struct rmi_function *fn = ctx;
+ struct f1a_data *f1a = dev_get_drvdata(&fn->dev);
+ char button_bitmask;
+ int key;
+ int error;
+
+ error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
+ &button_bitmask, sizeof(button_bitmask));
+ if (error) {
+ dev_err(&fn->dev, "Failed to read object data. Code: %d.\n",
+ error);
+ return IRQ_RETVAL(error);
+ }
+
+ for (key = 0; key < f1a->num_keys; key++)
+ input_report_key(f1a->input, f1a->keymap[key],
+ button_bitmask & BIT(key));
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_f1a_config(struct rmi_function *fn)
+{
+ struct f1a_data *f1a = dev_get_drvdata(&fn->dev);
+ struct rmi_driver *drv = fn->rmi_dev->driver;
+
+ if (f1a->num_keys)
+ drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f1a_initialize(struct rmi_function *fn, struct f1a_data *f1a)
+{
+ int error;
+ int i;
+
+ error = rmi_f1a_parse_device_properties(fn, f1a);
+ if (error)
+ return error;
+
+ for (i = 0; i < f1a->num_keys; i++)
+ input_set_capability(f1a->input, EV_KEY, f1a->keymap[i]);
+
+ f1a->input->keycode = f1a->keymap;
+ f1a->input->keycodemax = f1a->num_keys;
+ f1a->input->keycodesize = sizeof(f1a->keymap[0]);
+
+ return 0;
+}
+
+static int rmi_f1a_probe(struct rmi_function *fn)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ struct f1a_data *f1a;
+ int error;
+
+ if (!drv_data->input) {
+ dev_info(&fn->dev, "F1A: no input device found, ignoring\n");
+ return -ENXIO;
+ }
+
+ f1a = devm_kzalloc(&fn->dev, sizeof(*f1a), GFP_KERNEL);
+ if (!f1a)
+ return -ENOMEM;
+
+ f1a->input = drv_data->input;
+
+ error = rmi_f1a_initialize(fn, f1a);
+ if (error)
+ return error;
+
+ dev_set_drvdata(&fn->dev, f1a);
+
+ return 0;
+}
+
+struct rmi_function_handler rmi_f1a_handler = {
+ .driver = {
+ .name = "rmi4_f1a",
+ },
+ .func = 0x1a,
+ .probe = rmi_f1a_probe,
+ .config = rmi_f1a_config,
+ .attention = rmi_f1a_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f21.c b/drivers/input/rmi4/rmi_f21.c
new file mode 100644
index 000000000000..e3a9dfc3f0ec
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f21.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2025 Synaptics Incorporated
+ */
+
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define RMI_F21_SENSOR_COUNT_MASK GENMASK(3, 0)
+#define RMI_F21_FINGER_COUNT_PRESENT BIT(5)
+#define RMI_F21_NEW_REPORT_FORMAT BIT(6)
+
+#define RMI_F21_FINGER_COUNT_MASK GENMASK(3, 0)
+
+#define RMI_F21_MAX_SENSORS 16
+#define RMI_F21_MAX_FINGERS 16
+#define RMI_F21_DATA_REGS_MAX_SIZE (RMI_F21_MAX_SENSORS * 2 + \
+ RMI_F21_MAX_FINGERS * 2 + 1)
+
+#define RMI_F21_FORCE_CLICK_BIT BIT(0)
+
+#define RMI_F21_FORCEPAD_BUTTON_COUNT 1
+
+struct f21_data {
+ struct input_dev *input;
+ u16 key_code;
+
+ unsigned int attn_data_size;
+ unsigned int attn_data_button_offset;
+
+ unsigned int data_reg_size;
+ unsigned int data_reg_button_offset;
+ u8 data_regs[RMI_F21_DATA_REGS_MAX_SIZE];
+};
+
+static irqreturn_t rmi_f21_attention(int irq, void *ctx)
+{
+ struct rmi_function *fn = ctx;
+ struct f21_data *f21 = dev_get_drvdata(&fn->dev);
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
+ u8 *pdata;
+ int error;
+ bool pressed;
+
+ if (drvdata->attn_data.data) {
+ if (drvdata->attn_data.size < f21->attn_data_size) {
+ dev_warn(&fn->dev, "f21 interrupt, but data is missing\n");
+ return IRQ_HANDLED;
+ }
+
+ pdata = drvdata->attn_data.data + f21->attn_data_button_offset;
+
+ drvdata->attn_data.data += f21->attn_data_size;
+ drvdata->attn_data.size -= f21->attn_data_size;
+ } else {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
+ f21->data_regs, f21->data_reg_size);
+ if (error) {
+ dev_err(&fn->dev, "failed to read f21 data registers: %d\n",
+ error);
+ return IRQ_RETVAL(error);
+ }
+
+ pdata = f21->data_regs + f21->data_reg_button_offset;
+ }
+
+ pressed = *pdata & RMI_F21_FORCE_CLICK_BIT;
+ input_report_key(f21->input, f21->key_code, pressed);
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_f21_config(struct rmi_function *fn)
+{
+ struct rmi_driver *drv = fn->rmi_dev->driver;
+
+ drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f21_initialize(struct rmi_function *fn, struct f21_data *f21)
+{
+ struct input_dev *input = f21->input;
+
+ f21->key_code = BTN_LEFT;
+
+ input->keycode = &f21->key_code;
+ input->keycodesize = sizeof(f21->key_code);
+ input->keycodemax = RMI_F21_FORCEPAD_BUTTON_COUNT;
+
+ input_set_capability(input, EV_KEY, f21->key_code);
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+ return 0;
+}
+
+static int rmi_f21_probe(struct rmi_function *fn)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ struct f21_data *f21;
+ unsigned int sensor_count;
+ unsigned int max_fingers;
+ unsigned int query15_offset;
+ u8 query15_data;
+ int error;
+
+ if (!drv_data->input) {
+ dev_info(&fn->dev, "f21: no input device found, ignoring\n");
+ return -ENXIO;
+ }
+
+ f21 = devm_kzalloc(&fn->dev, sizeof(*f21), GFP_KERNEL);
+ if (!f21)
+ return -ENOMEM;
+
+ f21->input = drv_data->input;
+
+ error = rmi_f21_initialize(fn, f21);
+ if (error)
+ return error;
+
+ dev_set_drvdata(&fn->dev, f21);
+
+ sensor_count = fn->fd.query_base_addr & RMI_F21_SENSOR_COUNT_MASK;
+ if (fn->fd.query_base_addr & RMI_F21_FINGER_COUNT_PRESENT) {
+ query15_offset = fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT ? 2 : 1;
+ error = rmi_read_block(fn->rmi_dev,
+ fn->fd.query_base_addr + query15_offset,
+ &query15_data, sizeof(query15_data));
+ if (error)
+ return dev_err_probe(&fn->dev, error,
+ "failed to read 'query15' data");
+
+ max_fingers = query15_data & RMI_F21_FINGER_COUNT_MASK;
+ } else {
+ max_fingers = 5;
+ }
+
+ if (fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT) {
+ /* Each finger uses one byte, and the button state uses one byte.*/
+ f21->attn_data_size = max_fingers + 1;
+ f21->attn_data_button_offset = f21->attn_data_size - 1;
+ /*
+ * Each sensor uses two bytes, the button state uses one byte,
+ * and each finger uses two bytes.
+ */
+ f21->data_reg_size = sensor_count * 2 + 1 + max_fingers * 2;
+ f21->data_reg_button_offset = sensor_count * 2;
+ } else {
+ /*
+ * Regardless of the transport each finger uses two bytes,
+ * and the button state uses one byte.
+ */
+ f21->attn_data_size = sensor_count * 2 + 1;
+ f21->attn_data_button_offset = sensor_count * 2;
+
+ f21->data_reg_size = f21->attn_data_size;
+ f21->data_reg_button_offset = f21->attn_data_button_offset;
+ }
+
+ return 0;
+}
+
+struct rmi_function_handler rmi_f21_handler = {
+ .driver = {
+ .name = "rmi4_f21",
+ },
+ .func = 0x21,
+ .probe = rmi_f21_probe,
+ .config = rmi_f21_config,
+ .attention = rmi_f21_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
index d760af4cc12e..f1947f03b06a 100644
--- a/drivers/input/rmi4/rmi_f34.c
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -4,6 +4,7 @@
* Copyright (C) 2016 Zodiac Inflight Innovations
*/
+#include "linux/device.h"
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/firmware.h>
@@ -289,39 +290,30 @@ static int rmi_f34_update_firmware(struct f34_data *f34,
return rmi_f34_flash_firmware(f34, syn_fw);
}
-static int rmi_f34_status(struct rmi_function *fn)
-{
- struct f34_data *f34 = dev_get_drvdata(&fn->dev);
-
- /*
- * The status is the percentage complete, or once complete,
- * zero for success or a negative return code.
- */
- return f34->update_status;
-}
-
static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
struct device_attribute *dattr,
char *buf)
{
struct rmi_driver_data *data = dev_get_drvdata(dev);
- struct rmi_function *fn = data->f34_container;
+ struct rmi_function *fn;
struct f34_data *f34;
- if (fn) {
- f34 = dev_get_drvdata(&fn->dev);
-
- if (f34->bl_version == 5)
- return sysfs_emit(buf, "%c%c\n",
- f34->bootloader_id[0],
- f34->bootloader_id[1]);
- else
- return sysfs_emit(buf, "V%d.%d\n",
- f34->bootloader_id[1],
- f34->bootloader_id[0]);
- }
+ fn = data->f34_container;
+ if (!fn)
+ return -ENODEV;
- return 0;
+ f34 = dev_get_drvdata(&fn->dev);
+ if (!f34)
+ return -ENODEV;
+
+ if (f34->bl_version == 5)
+ return sysfs_emit(buf, "%c%c\n",
+ f34->bootloader_id[0],
+ f34->bootloader_id[1]);
+ else
+ return sysfs_emit(buf, "V%d.%d\n",
+ f34->bootloader_id[1],
+ f34->bootloader_id[0]);
}
static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL);
@@ -334,13 +326,16 @@ static ssize_t rmi_driver_configuration_id_show(struct device *dev,
struct rmi_function *fn = data->f34_container;
struct f34_data *f34;
- if (fn) {
- f34 = dev_get_drvdata(&fn->dev);
+ fn = data->f34_container;
+ if (!fn)
+ return -ENODEV;
+
+ f34 = dev_get_drvdata(&fn->dev);
+ if (!f34)
+ return -ENODEV;
- return sysfs_emit(buf, "%s\n", f34->configuration_id);
- }
- return 0;
+ return sysfs_emit(buf, "%s\n", f34->configuration_id);
}
static DEVICE_ATTR(configuration_id, 0444,
@@ -356,10 +351,14 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
if (!data->f34_container) {
dev_warn(dev, "%s: No F34 present!\n", __func__);
- return -EINVAL;
+ return -ENODEV;
}
f34 = dev_get_drvdata(&data->f34_container->dev);
+ if (!f34) {
+ dev_warn(dev, "%s: No valid F34 present!\n", __func__);
+ return -ENODEV;
+ }
if (f34->bl_version >= 7) {
if (data->pdt_props & HAS_BSR) {
@@ -485,10 +484,18 @@ static ssize_t rmi_driver_update_fw_status_show(struct device *dev,
char *buf)
{
struct rmi_driver_data *data = dev_get_drvdata(dev);
- int update_status = 0;
+ struct f34_data *f34;
+ int update_status = -ENODEV;
- if (data->f34_container)
- update_status = rmi_f34_status(data->f34_container);
+ /*
+ * The status is the percentage complete, or once complete,
+ * zero for success or a negative return code.
+ */
+ if (data->f34_container) {
+ f34 = dev_get_drvdata(&data->f34_container->dev);
+ if (f34)
+ update_status = f34->update_status;
+ }
return sysfs_emit(buf, "%d\n", update_status);
}
@@ -508,33 +515,21 @@ static const struct attribute_group rmi_firmware_attr_group = {
.attrs = rmi_firmware_attrs,
};
-static int rmi_f34_probe(struct rmi_function *fn)
+static int rmi_f34v5_probe(struct f34_data *f34)
{
- struct f34_data *f34;
- unsigned char f34_queries[9];
+ struct rmi_function *fn = f34->fn;
+ u8 f34_queries[9];
bool has_config_id;
- u8 version = fn->fd.function_version;
- int ret;
-
- f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
- if (!f34)
- return -ENOMEM;
-
- f34->fn = fn;
- dev_set_drvdata(&fn->dev, f34);
-
- /* v5 code only supported version 0, try V7 probe */
- if (version > 0)
- return rmi_f34v7_probe(f34);
+ int error;
f34->bl_version = 5;
- ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
- f34_queries, sizeof(f34_queries));
- if (ret) {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (error) {
dev_err(&fn->dev, "%s: Failed to query properties\n",
__func__);
- return ret;
+ return error;
}
snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
@@ -560,11 +555,11 @@ static int rmi_f34_probe(struct rmi_function *fn)
f34->v5.config_blocks);
if (has_config_id) {
- ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
- f34_queries, sizeof(f34_queries));
- if (ret) {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (error) {
dev_err(&fn->dev, "Failed to read F34 config ID\n");
- return ret;
+ return error;
}
snprintf(f34->configuration_id, sizeof(f34->configuration_id),
@@ -573,12 +568,34 @@ static int rmi_f34_probe(struct rmi_function *fn)
f34_queries[2], f34_queries[3]);
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
- f34->configuration_id);
+ f34->configuration_id);
}
return 0;
}
+static int rmi_f34_probe(struct rmi_function *fn)
+{
+ struct f34_data *f34;
+ u8 version = fn->fd.function_version;
+ int error;
+
+ f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
+ if (!f34)
+ return -ENOMEM;
+
+ f34->fn = fn;
+
+ /* v5 code only supported version 0 */
+ error = version == 0 ? rmi_f34v5_probe(f34) : rmi_f34v7_probe(f34);
+ if (error)
+ return error;
+
+ dev_set_drvdata(&fn->dev, f34);
+
+ return 0;
+}
+
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
{
return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);