From b7e8630c76f8f64225066d93e8db41158fc92f16 Mon Sep 17 00:00:00 2001 From: Jami Kettunen Date: Fri, 21 May 2021 04:31:36 +0300 Subject: [PATCH] Input: synaptics-rmi4 - add support for F1A RMI4 F1A supports the simple capacitive buttons function, it's used for example on embedded devices such as smartphones for capacitive Android back and recents buttons. --- drivers/input/rmi4/Kconfig | 8 ++ drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_bus.c | 3 + drivers/input/rmi4/rmi_driver.h | 1 + drivers/input/rmi4/rmi_f1a.c | 190 ++++++++++++++++++++++++++++++++ 5 files changed, 203 insertions(+) create mode 100644 drivers/input/rmi4/rmi_f1a.c diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index c0163b983ce6..fbd3ace41373 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -82,6 +82,14 @@ config RMI4_F12 touchpads. For sensors that support relative pointing, F12 also provides mouse input. +config RMI4_F1A + bool "RMI4 Function 1A (Simple capacitive buttons)" + depends on OF + help + Say Y here if you want to add support for RMI4 function 1A. + + Function 1A provides GPIO capacitive button support for RMI4 devices. + config RMI4_F30 bool "RMI4 Function 30 (GPIO LED)" help diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index 02f14c846861..70f942196aa2 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -8,6 +8,7 @@ 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_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 50a0134b6901..fc39ba462ab0 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -360,6 +360,9 @@ 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_F30 &rmi_f30_handler, #endif diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index 1c6c6086c0e5..a05b8f9d7a46 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -133,6 +133,7 @@ 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_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..d4d47e59fa0d --- /dev/null +++ b/drivers/input/rmi4/rmi_f1a.c @@ -0,0 +1,190 @@ +// FIXME: Too much stuff is hardcoded in currently! +#include +#include +#include +#include "rmi_driver.h" + +/* Query 1 */ +//#define F1A_BUTTONS_COUNT 0b00011111 /* BIT(1) */ + +#define MAX_NAME_LEN 256 +#define F1A_MAX_BUTTONS 8 + +struct f1a_data { + struct rmi_function *fn; + + unsigned char button_count; + u32 button_map[F1A_MAX_BUTTONS]; + struct input_dev *input; + char input_name[MAX_NAME_LEN]; + char input_phys[MAX_NAME_LEN]; + u8 button_data_buffer; +}; + +static int rmi_f1a_initialize(struct f1a_data *f1a) +{ + struct rmi_function *fn = f1a->fn; + struct device *dev = &fn->dev; + //u8 query[2]; + int error; + + /*error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, query, 2); + if (error) { + dev_err(dev, "Failed to read query register (%d).\n", error); + return error; + } + printk("%s: query0: 0x%x, query1: 0x%x\n", __func__, query[0], query[1]);*/ + + error = of_property_read_variable_u32_array(dev_of_node(dev), + "syna,codes", f1a->button_map, 1, F1A_MAX_BUTTONS); + if (error < 0) { + dev_err(dev, "Failed to parse syna,codes from OF device tree (%d).\n", error); + return error; + } + // FIXME: button_count = query[1] & F1A_BUTTONS_COUNT; + f1a->button_count = 0; + for (f1a->button_count = 0; f1a->button_count < F1A_MAX_BUTTONS; f1a->button_count++) + if (f1a->button_map[f1a->button_count] == 0) + break; + rmi_dbg(RMI_DEBUG_FN, dev, "%s: %d button codes defined\n", __func__, f1a->button_count); + + return 0; +} + +static int rmi_f1a_register_device(struct f1a_data *f1a) +{ + struct rmi_function *fn = f1a->fn; + struct device *dev = &fn->dev; + struct rmi_device *rmi_dev = fn->rmi_dev; + struct input_dev *input_dev; + int i, rc; + + input_dev = input_allocate_device(); + if (!input_dev) { + dev_err(dev, "Failed to allocate input device.\n"); + return -ENOMEM; + } + + f1a->input = input_dev; + snprintf(f1a->input_name, MAX_NAME_LEN, "%s.fn%02x", + dev_name(&rmi_dev->dev), fn->fd.function_number); + input_dev->name = f1a->input_name; + snprintf(f1a->input_phys, MAX_NAME_LEN, "%s/input0", input_dev->name); + input_dev->phys = f1a->input_phys; + input_dev->dev.parent = &rmi_dev->dev; + input_set_drvdata(input_dev, f1a); + + /* set up any input events */ + set_bit(EV_SYN, input_dev->evbit); + set_bit(EV_KEY, input_dev->evbit); + + /* manage button map using input subsystem */ + input_dev->keycode = f1a->button_map; + input_dev->keycodesize = sizeof(f1a->button_map); /* f1a->button_count */ + input_dev->keycodemax = f1a->button_count; + + /* set bits for each button */ + for (i = 0; i < f1a->button_count; i++) { + set_bit(f1a->button_map[i], input_dev->keybit); + input_set_capability(input_dev, EV_KEY, f1a->button_map[i]); + } + + rc = input_register_device(input_dev); + if (rc < 0) { + dev_err(dev, "Failed to register input device.\n"); + goto error_free_device; + } + + return 0; + +error_free_device: + input_free_device(input_dev); + return rc; +} + +static int rmi_f1a_probe(struct rmi_function *fn) +{ + struct device *dev = &fn->dev; + struct f1a_data *f1a; + int error; + + rmi_dbg(RMI_DEBUG_FN, dev, "%s\n", __func__); + + if (!fn->dev.of_node) { + /* + * Some quirky devices (e.g. OnePlus 5T) report supporting F1A + * (Simple capacitive buttons) despite not having the hardware, + * so in case there isn't an associated device-tree node present + * just pretend we probed successfully. + */ + return 0; + } + + f1a = devm_kzalloc(dev, sizeof(struct f1a_data), GFP_KERNEL); + if (!f1a) + return -ENOMEM; + + f1a->fn = fn; + + error = rmi_f1a_initialize(f1a); + if (error < 0) + return error; + + error = rmi_f1a_register_device(f1a); + if (error < 0) + return error; + + dev_set_drvdata(dev, f1a); + return 0; +} + +static int rmi_f1a_config(struct rmi_function *fn) +{ + fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask); + return 0; +} + +static irqreturn_t rmi_f1a_attention(int irq, void *ctx) +{ + struct rmi_function *fn = ctx; + struct device *dev = &fn->dev; + struct rmi_device *rmi_dev = fn->rmi_dev; + struct f1a_data *f1a = dev_get_drvdata(dev); + int error, button; + + // TODO: use rmi_read_block() to accomodate up to 8 buttons? + error = rmi_read(rmi_dev, fn->fd.data_base_addr, &(f1a->button_data_buffer)); + if (error < 0) { + dev_err(dev, "Failed to read button data registers (%d).\n", error); + return error; + } + /*rmi_dbg(RMI_DEBUG_FN, dev, "%s: button_data=0x%x\n", __func__, f1a->button_data_buffer);*/ + + /* generate events for buttons that change state */ + // TODO: Implement button_data_buffer as array + button_reg = button / 8 + for (button = 0; button < f1a->button_count; button++) { + int button_shift; + bool button_status; + /* bit shift to get button's status */ + button_shift = button % 8; + button_status = ((f1a->button_data_buffer >> button_shift) & 0x01) != 0; + + rmi_dbg(RMI_DEBUG_FN, dev, "button %d (code %d) -> %d\n", + button, f1a->button_map[button], button_status); + /* generate an event here */ + input_report_key(f1a->input, f1a->button_map[button], button_status); + } + input_sync(f1a->input); /* sync after groups of events */ + + return IRQ_HANDLED; +} + +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, +};