input synaptics-rmi4: Add F30 support
Subsystems (2)
PATCH v2 1/1 input synaptics-rmi4: Add F30 support
RMI4 Function 0x30 provides support for GPIOs, LEDs and mechanical buttons. In particular, the mechanical button support is used in an increasing number of touchpads.
Note - this is basically the same as last week's patch, just updated to work with the changes committed to synaptics-rmi4 branch over the weekend.
---
drivers/input/rmi4/Kconfig | 12 + drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_f30.c | 618 +++++++++++++++++++++++++++++++++++++++++++ include/linux/rmi.h | 7 +- 4 files changed, 637 insertions(+), 1 deletion(-)
drivers/input/rmi4/Kconfig +12 -0
@@ -63,3 +63,15 @@ config RMI4_F11_PEN If your system is not recognizing pen touches and you know your sensor supports pen input, you probably want to turn this feature off. + +config RMI4_F30 + tristate "RMI4 Function 30 (GPIO LED)" + depends on RMI4_CORE + help + Say Y here if you want to add support for RMI4 function 30. + + Function 30 provides GPIO and LED support for RMI4 devices. This + includes support for buttons on TouchPads and ClickPads. + + To compile this driver as a module, choose M here: the + module will be called rmi-f30.
drivers/input/rmi4/Makefile +1 -0
@@ -3,6 +3,7 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o # Function drivers obj-$(CONFIG_RMI4_F11) += rmi_f11.o +obj-$(CONFIG_RMI4_F30) += rmi_f30.o # Transports obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
drivers/input/rmi4/rmi_f30.c new file +618 -0
618 lines not on this page · raw message
include/linux/rmi.h +6 -1
@@ -139,9 +139,14 @@ struct rmi_button_map {u8 *map; }; +struct rmi_f30_button { +u16 button; +int sense; +}; +struct rmi_f30_gpioled_map {u8 ngpioleds; -u8 *map; +struct rmi_f30_button *map; };/**
Dmitry Torokhov
maintainerHi Chris,
Quoted 123 lines · Christopher Heiny
RMI4 Function
0x30provides support for GPIOs, LEDs and mechanical buttons. In particular, the mechanical button support is used in an increasing number of touchpads.Note - this is basically the same as last week's patch, just updated to work with the changes committed to synaptics-rmi4 branch over the weekend.
Signed-off-by Andrew Duggan <[email protected]>Signed-off-by Allie Xiong <[email protected]>Cc Dmitry Torokhov <[email protected]>Cc Benjamin Tissoires <[email protected]>Cc Linux Walleij <[email protected]>Cc David Herrmann <[email protected]>Cc Jiri Kosina <[email protected]>---
drivers/input/rmi4/Kconfig | 12 + drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_f30.c | 618 +++++++++++++++++++++++++++++++++++++++++++ include/linux/rmi.h | 7 +- 4 files changed, 637 insertions(+), 1 deletion(-)drivers/input/rmi4/Kconfig +12
-0@@ -63,3 +63,15 @@ config RMI4_F11_PEN If your system is not recognizing pen touches and you know your sensor supports pen input, you probably want to turn this feature off. + +config RMI4_F30 + tristate "RMI4 Function 30 (GPIO LED)" + depends on RMI4_CORE + help + Say Y here if you want to add support for RMI4 function 30. + + Function 30 provides GPIO and LED support for RMI4 devices. This + includes support for buttons on TouchPads and ClickPads. + + To compile this driver as a module, choose M here: the + module will be called rmi-f30.drivers/input/rmi4/Makefile +1
-0@@ -3,6 +3,7 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o # Function drivers obj-$(CONFIG_RMI4_F11) += rmi_f11.o +obj-$(CONFIG_RMI4_F30) += rmi_f30.o # Transports obj-$(CONFIG_RMI4_I2C) += rmi_i2c.odrivers/input/rmi4/rmi_f30.c new file +61
-0@@ -0,0 +1,618 @@ +/* +* Copyright (c) 2012 - 2014 Synaptics Incorporated +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2 as published by +* the Free Software Foundation. +*/ + +#include <linux/kernel.h> +#include <linux/rmi.h> +#include <linux/input.h> +#include <linux/slab.h> +#include <linux/gpio.h> +#include <linux/leds.h> +#include "rmi_driver.h" + +#define RMI_F30_QUERY_SIZE 2 + +/* Defs for Query 0 */ +#define RMI_F30_EXTENDED_PATTERNS 0x01 +#define RMI_F30_HAS_MAPPABLE_BUTTONS (1 << 1) +#define RMI_F30_HAS_LED (1 << 2) +#define RMI_F30_HAS_GPIO (1 << 3) +#define RMI_F30_HAS_HAPTIC (1 << 4) +#define RMI_F30_HAS_GPIO_DRV_CTL (1 << 5) +#define RMI_F30_HAS_MECH_MOUSE_BTNS (1 << 6) + +/* Defs for Query 1 */ +#define RMI_F30_GPIO_LED_COUNT 0x1F + +/* Defs for Control Registers */ +#define RMI_F30_CTRL_1_GPIO_DEBOUNCE 0x01 +#define RMI_F30_CTRL_1_HALT (1 << 4) +#define RMI_F30_CTRL_1_HALTED (1 << 5) +#define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS 0x03 + +#define RMI_F30_CTRL_DATA (ctrl_num, max_size) \ +struct rmi_f30_ctrl##ctrl_num##_data { \ + int address; \ + int length; \ + u8 regs[max_size]; \ +} + +#define RMI_F30_CTRL_MAX_REGS 32 +#define RMI_F30_CTRL_MAX_BYTES ((RMI_F30_CTRL_MAX_REGS + 7) >> 3) + +struct f30_data { +/* Query Data */ +bool has_extended_pattern; +bool has_mappable_buttons; +bool has_led; +bool has_gpio; +bool has_haptic; +bool has_gpio_driver_control; +bool has_mech_mouse_btns; +u8 gpioled_count; + +u8 register_count; + +/* Control Register Data */ + RMI_F30_CTRL_DATA(0, RMI_F30_CTRL_MAX_BYTES) ctrl_0;
drivers/input/rmi4/rmi_f30.c line 71
Quoted 10 lines
drivers/input/rmi4/rmi_f30.c new file +10
-0+ RMI_F30_CTRL_DATA(1, 1) ctrl_1; + RMI_F30_CTRL_DATA(2, RMI_F30_CTRL_MAX_BYTES) ctrl_2; + RMI_F30_CTRL_DATA(3, RMI_F30_CTRL_MAX_BYTES) ctrl_3; + RMI_F30_CTRL_DATA(4, RMI_F30_CTRL_MAX_BYTES) ctrl_4; + RMI_F30_CTRL_DATA(5, 6) ctrl_5; + RMI_F30_CTRL_DATA(6, RMI_F30_CTRL_MAX_REGS) ctrl_6; + RMI_F30_CTRL_DATA(7, RMI_F30_CTRL_MAX_REGS) ctrl_7; + RMI_F30_CTRL_DATA(8, RMI_F30_CTRL_MAX_BYTES) ctrl_8; + RMI_F30_CTRL_DATA(9, 1) ctrl_9; + RMI_F30_CTRL_DATA(10, 1) ctrl_10;
This should probably be an array so you could use loops to populate it.
Quoted 7 lines
drivers/input/rmi4/rmi_f30.c new file +7
-0+ +u8 data_regs[RMI_F30_CTRL_MAX_BYTES ]; +struct rmi_f30_button *gpioled_map; + +char input_phys[NAME_BUFFER_SIZE ]; +struct input_dev *input; +};
drivers/input/rmi4/rmi_f30.c line 88
Quoted 10 lines
drivers/input/rmi4/rmi_f30.c new file +10
-0+ +static int rmi_f30_read_control_parameters (struct rmi_device *rmi_dev, +struct f30_data *f30) +{ +int retval =0 ; + +if (f30->ctrl_0.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_0.address, + f30->ctrl_0.regs, f30->ctrl_0.length); +if (retval <0 ) {
rmi_read/write are no longer return partial writes so lets do:
error = rmi_XXX(); if (error) dev_err(...) return error;
Might also want to report error code in error messages.
Quoted 161 lines
drivers/input/rmi4/rmi_f30.c new file +161
-0+dev_err (&rmi_dev->dev, +"%s : Could not read control reg0 to 0x%x\n" , + __func__, f30->ctrl_0.address); +return retval; + } + } + +if (f30->ctrl_1.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_1.address, + f30->ctrl_1.regs, f30->ctrl_1.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg1 to 0x%x\n" , + __func__, f30->ctrl_1.address); +return retval; + } + } + +if (f30->ctrl_2.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_2.address, + f30->ctrl_2.regs, f30->ctrl_2.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg2 to 0x%x\n" , + __func__, f30->ctrl_2.address); +return retval; + } + } + +if (f30->ctrl_3.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_3.address, + f30->ctrl_3.regs, f30->ctrl_3.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg3 to 0x%x\n" , + __func__, f30->ctrl_3.address); +return retval; + } + } + +if (f30->ctrl_4.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_4.address, + f30->ctrl_4.regs, f30->ctrl_4.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg4 to 0x%x\n" , + __func__, f30->ctrl_4.address); +return retval; + } + } + +if (f30->ctrl_5.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_5.address, + f30->ctrl_5.regs, f30->ctrl_5.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg5 to 0x%x\n" , + __func__, f30->ctrl_5.address); +return retval; + } + } + +if (f30->ctrl_6.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_6.address, + f30->ctrl_6.regs, f30->ctrl_6.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg6 to 0x%x\n" , + __func__, f30->ctrl_6.address); +return retval; + } + } + +if (f30->ctrl_7.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_7.address, + f30->ctrl_1.regs, f30->ctrl_7.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg7 to 0x%x\n" , + __func__, f30->ctrl_7.address); +return retval; + } + } + +if (f30->ctrl_8.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_8.address, + f30->ctrl_8.regs, f30->ctrl_8.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg8 to 0x%x\n" , + __func__, f30->ctrl_8.address); +return retval; + } + } + +if (f30->ctrl_9.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_9.address, + f30->ctrl_9.regs, f30->ctrl_9.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg9 to 0x%x\n" , + __func__, f30->ctrl_9.address); +return retval; + } + } + +if (f30->ctrl_10.length) { + retval =rmi_read_block (rmi_dev, f30->ctrl_10.address, + f30->ctrl_10.regs, f30->ctrl_10.length); +if (retval <0 ) { +dev_err (&rmi_dev->dev, +"%s : Could not read control reg1 to 0x%x\n" , + __func__, f30->ctrl_10.address); +return retval; + } + } + +return 0 ; +} + +static int rmi_f30_attention (struct rmi_function *fn, +unsigned long *irq_bits) +{ +struct f30_data *f30 =dev_get_drvdata (&fn->dev); +int retval; +int gpiled =0 ; +int value =0 ; +int i; +int reg_num; + +/* Read the gpi led data. */ + retval =rmi_read_block (fn->rmi_dev, fn->fd.data_base_addr, + f30->data_regs, f30->register_count); + +if (retval <0 ) { +dev_err (&fn->dev,"%s: Failed to read F30 data registers.\n" , + __func__); +return retval; + } + +for (reg_num =0 ; reg_num < f30->register_count; ++reg_num) { +for (i =0 ; gpiled < f30->gpioled_count && i <8 ; ++i, + ++gpiled) { +if (f30->gpioled_map[gpiled].button !=0 ) { + value = (((f30->data_regs[reg_num] >> i) &0x01 ) + == f30->gpioled_map[gpiled].sense); + +dev_dbg (&fn->dev, +"%s: call input report key (0x%04x) value (0x%02x)" , + __func__, + f30->gpioled_map[gpiled].button, value); +input_report_key (f30->input, + f30->gpioled_map[gpiled].button, + value); + } + + } + } + +input_sync (f30->input);/* sync after groups of events */ +return 0 ;
drivers/input/rmi4/rmi_f30.c line 259
Quoted 10 lines
drivers/input/rmi4/rmi_f30.c new file +10
-0+} + +static int rmi_f30_register_device (struct rmi_function *fn) +{ +int i; +int rc; +struct rmi_device *rmi_dev = fn->rmi_dev; +struct f30_data *f30 =dev_get_drvdata (&fn->dev); +struct rmi_driver *driver = fn->rmi_dev->driver; +struct input_dev *input_dev =input_allocate_device ();
I would prefer you did not hide allocation in variable declarations. Also since the rest of resources in f30 implementation are devres managed you can use devm_input_allocate_device(). Otherwise you need to provide remove) methof for f30 which is currently is missing.
Quoted 16 lines
drivers/input/rmi4/rmi_f30.c new file +16
-0+ +if (!input_dev) { +dev_err (&fn->dev,"Failed to allocate input device.\n" ); +return -ENOMEM ; + } + + f30->input = input_dev; + +if (driver->set_input_params) { + rc = driver->set_input_params (rmi_dev, input_dev); +if (rc <0 ) { +dev_err (&fn->dev,"%s: Error in setting input device.\n" , + __func__); + goto error_free_device; + } + }
drivers/input/rmi4/rmi_f30.c line 285
Quoted 10 lines
drivers/input/rmi4/rmi_f30.c new file +10
-0+sprintf (f30->input_phys,"%s/input0" ,dev_name (&fn->dev)); + input_dev->phys = f30->input_phys; + input_dev->dev.parent = &rmi_dev->dev; +input_set_drvdata (input_dev, f30); + +/* Set up any input events. */ +set_bit (EV_SYN , input_dev->evbit); +set_bit (EV_KEY , input_dev->evbit); + input_dev->keycode = f30->gpioled_map; + input_dev->keycodesize =1 ;
This should be sizeof(unsigned short) - we have passed 255 limit on keycodes.
drivers/input/rmi4/rmi_f30.c line 286
Quoted 1 line
drivers/input/rmi4/rmi_f30.c new file +1
-0+ input_dev->keycodemax = f30->gpioled_count;
By doing the above 2 assigments you indicate to input core that it shoudl use default implementation of EVIOCGKEYCODE/EVIOCSKEYCODE, but what you supply in input_dev->keycode is not a flat keymap.
drivers/input/rmi4/rmi_f30.c line 292
Quoted 6 lines
drivers/input/rmi4/rmi_f30.c new file +6
-0+/* set bits for each qpio led pin... */ +for (i =0 ; i < f30->gpioled_count; i++) { +if (f30->gpioled_map[i].button !=0 ) { +set_bit (f30->gpioled_map[i].button, input_dev->keybit); +input_set_capability (input_dev,EV_KEY , + f30->gpioled_map[i].button);
input_set_capability() does the set_bit(keycode, input_dev->keybit) for you.
Quoted 255 lines
drivers/input/rmi4/rmi_f30.c new file +255
-0+ } + } + + rc =input_register_device (input_dev); +if (rc <0 ) { +dev_err (&fn->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_f30_config (struct rmi_function *fn) +{ +struct f30_data *f30 =dev_get_drvdata (&fn->dev); +int rc; + +/* Write Control Register values back to device */ +if (f30->ctrl_0.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_0.address, + f30->ctrl_0.regs, + f30->ctrl_0.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 0 to 0x%x\n" , + __func__, rc, f30->ctrl_0.address); +return rc; + } + } + +if (f30->ctrl_1.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_1.address, + f30->ctrl_1.regs, + f30->ctrl_1.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 1 to 0x%x\n" , + __func__, rc, f30->ctrl_1.address); +return rc; + } + } + +if (f30->ctrl_2.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_2.address, + f30->ctrl_2.regs, + f30->ctrl_2.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 2 to 0x%x\n" , + __func__, rc, f30->ctrl_2.address); +return rc; + } + } + +if (f30->ctrl_3.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_3.address, + f30->ctrl_3.regs, + f30->ctrl_3.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 3 to 0x%x\n" , + __func__, rc, f30->ctrl_3.address); +return rc; + } + } + +if (f30->ctrl_4.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_4.address, + f30->ctrl_4.regs, + f30->ctrl_4.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 4 to 0x%x\n" , + __func__, rc, f30->ctrl_4.address); +return rc; + } + } + +if (f30->ctrl_5.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_5.address, + f30->ctrl_5.regs, + f30->ctrl_5.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 5 to 0x%x\n" , + __func__, rc, f30->ctrl_5.address); +return rc; + } + } + +if (f30->ctrl_6.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_6.address, + f30->ctrl_6.regs, + f30->ctrl_6.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 6 to 0x%x\n" , + __func__, rc, f30->ctrl_6.address); +return rc; + } + } + +if (f30->ctrl_7.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_7.address, + f30->ctrl_7.regs, + f30->ctrl_7.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 7 to 0x%x\n" , + __func__, rc, f30->ctrl_7.address); +return rc; + } + } + +if (f30->ctrl_8.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_8.address, + f30->ctrl_8.regs, + f30->ctrl_8.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 8 to 0x%x\n" , + __func__, rc, f30->ctrl_8.address); +return rc; + } + } + +if (f30->ctrl_9.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_9.address, + f30->ctrl_9.regs, + f30->ctrl_9.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 9 to 0x%x\n" , + __func__, rc, f30->ctrl_9.address); +return rc; + } + } + +if (f30->ctrl_10.length) { + rc =rmi_write_block (fn->rmi_dev, f30->ctrl_10.address, + f30->ctrl_10.regs, + f30->ctrl_10.length); +if (rc <0 ) { +dev_err (&fn->dev,"%s error %d: Could not write control 10 to 0x%x\n" , + __func__, rc, f30->ctrl_10.address); +return rc; + } + } + +return 0 ; +} + +static inline int rmi_f30_initialize (struct rmi_function *fn) +{ +struct f30_data *f30; +struct rmi_device *rmi_dev = fn->rmi_dev; +const struct rmi_device_platform_data *pdata; +int retval =0 ; +int control_address; +u8 buf[RMI_F30_QUERY_SIZE ]; + + f30 =devm_kzalloc (&fn->dev,sizeof (struct f30_data ), +GFP_KERNEL ); +if (!f30) { +dev_err (&fn->dev,"Failed to allocate f30_data.\n" ); +return -ENOMEM ; + } +dev_set_drvdata (&fn->dev, f30); + + retval =rmi_read_block (fn->rmi_dev, fn->fd.query_base_addr, buf, +RMI_F30_QUERY_SIZE ); + +if (retval <0 ) { +dev_err (&fn->dev,"Failed to read query register.\n" ); +return retval; + } + + f30->has_extended_pattern = buf[0 ] &RMI_F30_EXTENDED_PATTERNS ; + f30->has_mappable_buttons = buf[0 ] &RMI_F30_HAS_MAPPABLE_BUTTONS ; + f30->has_led = buf[0 ] &RMI_F30_HAS_LED ; + f30->has_gpio = buf[0 ] &RMI_F30_HAS_GPIO ; + f30->has_haptic = buf[0 ] &RMI_F30_HAS_HAPTIC ; + f30->has_gpio_driver_control = buf[0 ] &RMI_F30_HAS_GPIO_DRV_CTL ; + f30->has_mech_mouse_btns = buf[0 ] &RMI_F30_HAS_MECH_MOUSE_BTNS ; + f30->gpioled_count = buf[1 ] &RMI_F30_GPIO_LED_COUNT ; + + f30->register_count = (f30->gpioled_count +7 ) >>3 ; + + control_address = fn->fd.control_base_addr; + +/* Allocate buffers for the control registers */ +if (f30->has_led && f30->has_led) { + f30->ctrl_0.address = control_address; + f30->ctrl_0.length = f30->register_count; + control_address += f30->ctrl_0.length; + } + + f30->ctrl_1.address = control_address; + f30->ctrl_1.length =sizeof (u8); + control_address += f30->ctrl_1.length; + +if (f30->has_gpio) { + f30->ctrl_2.address = control_address; + f30->ctrl_2.length = f30->register_count; + control_address += f30->ctrl_2.length; + + f30->ctrl_3.address = control_address; + f30->ctrl_3.length = f30->register_count; + control_address += f30->ctrl_3.length; + } + +if (f30->has_led) { + f30->ctrl_4.address = control_address; + f30->ctrl_4.length = f30->register_count; + control_address += f30->ctrl_4.length; + +if (f30->has_extended_pattern) + f30->ctrl_5.length =6 ; +else + f30->ctrl_5.length =2 ; + + f30->ctrl_5.address = control_address; + control_address += f30->ctrl_5.length; + } + +if (f30->has_led || f30->has_gpio_driver_control) { +/* control 6 uses a byte per gpio/led */ + f30->ctrl_6.address = control_address; + f30->ctrl_6.length = f30->gpioled_count; + control_address += f30->ctrl_6.length; + + } + +if (f30->has_mappable_buttons) { +/* control 7 uses a byte per gpio/led */ + f30->ctrl_7.address = control_address; + f30->ctrl_7.length = f30->gpioled_count; + control_address += f30->ctrl_7.length; + } + +if (f30->has_haptic) { + f30->ctrl_8.address = control_address; + f30->ctrl_8.length = f30->register_count; + control_address += f30->ctrl_8.length; + + f30->ctrl_9.address = control_address; + f30->ctrl_9.length =sizeof (u8); + control_address += f30->ctrl_9.length; + } + +if (f30->has_mech_mouse_btns) { + f30->ctrl_10.address = control_address; + f30->ctrl_10.length =sizeof (u8); + control_address += f30->ctrl_10.length; + } + + f30->gpioled_map =devm_kzalloc (&fn->dev, + f30->gpioled_count + *sizeof (struct rmi_f30_button ), +GFP_KERNEL ); +if (!f30->gpioled_map) {
drivers/input/rmi4/rmi_f30.c line 557
Quoted 10 lines
drivers/input/rmi4/rmi_f30.c new file +10
-0+dev_err (&fn->dev,"Failed to allocate button map.\n" ); +return -ENOMEM ; + } + + pdata =rmi_get_platform_data (rmi_dev); +if (pdata) { +if (!pdata->gpioled_map) { +dev_warn (&fn->dev, +"%s - gpioled_map is NULL" , __func__); + }else if (pdata->gpioled_map->ngpioleds < f30->gpioled_count) {
Should you only map the entries that have 'valid' bit and export the rest as generic gpio? And leds as leds?
Quoted 71 lines
drivers/input/rmi4/rmi_f30.c new file +61
-0+dev_warn (&fn->dev, +"Platform Data gpioled map size (%d) is less then the number of buttons on device (%d) - ignored\n" , + pdata->gpioled_map->ngpioleds, + f30->gpioled_count); + }else if (!pdata->gpioled_map->map) { +dev_warn (&fn->dev, +"Platform Data button map is missing!\n" ); + }else { +int i; +for (i =0 ; i < f30->gpioled_count; i++) +memcpy (&f30->gpioled_map[i], + &pdata->gpioled_map->map[i], +sizeof (struct rmi_f30_button )); + } + } + + retval =rmi_f30_read_control_parameters (rmi_dev, f30); +if (retval <0 ) { +dev_err (&fn->dev, +"Failed to initialize F19 control params.\n" ); +return retval; + } + +return 0 ; +} + +static int rmi_f30_probe (struct rmi_function *fn) +{ +int rc; + + rc =rmi_f30_initialize (fn); +if (rc <0 ) + goto error_exit; + + rc =rmi_f30_register_device (fn); +if (rc <0 ) + goto error_exit; + +return 0 ; + +error_exit: +return rc; + +} + +static struct rmi_function_handler rmi_f30_handler = { + .driver = { + .name ="rmi_f30" , + }, + .func =0x30 , + .probe = rmi_f30_probe, + .config = rmi_f30_config, + .attention = rmi_f30_attention, +}; + +module_rmi_driver (rmi_f30_handler); + +MODULE_AUTHOR ("Allie Xiong <[email protected]>" ); +MODULE_AUTHOR ("Andrew Duggan <[email protected]>" ); +MODULE_DESCRIPTION ("RMI F30 module" ); +MODULE_LICENSE ("GPL" );include/linux/rmi.h +2
-0@@ -139,9 +139,14 @@ struct rmi_button_map {u8 *map; }; +struct rmi_f30_button { +u16 button;
include/linux/rmi.h struct rmi_button_map { · line 152
Quoted 10 lines
include/linux/rmi.h +4
-1+int sense; +}; +struct rmi_f30_gpioled_map {u8 ngpioleds; -u8 *map; +struct rmi_f30_button *map; };/**
Thanks.
Signature · 1 line
Dmitry