linux-stable/drivers/input/rmi4/rmi_f30.c
Benjamin Tissoires 522214d9be Input: rmi4 - f30: detect INPUT_PROP_BUTTONPAD from the button count
INPUT_PROP_BUTTONPAD is currently only set through the platform data.
The RMI4 header doc says that this property is there to force the
buttonpad property, so we also need to detect it by looking at
the exported buttons count.

Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Reported-and-tested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2017-03-01 10:01:56 -08:00

402 lines
10 KiB
C

/*
* Copyright (c) 2012-2016 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 "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 BIT(1)
#define RMI_F30_HAS_LED BIT(2)
#define RMI_F30_HAS_GPIO BIT(3)
#define RMI_F30_HAS_HAPTIC BIT(4)
#define RMI_F30_HAS_GPIO_DRV_CTL BIT(5)
#define RMI_F30_HAS_MECH_MOUSE_BTNS BIT(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 BIT(4)
#define RMI_F30_CTRL_1_HALTED BIT(5)
#define RMI_F30_CTRL_10_NUM_MECH_MOUSE_BTNS 0x03
#define RMI_F30_CTRL_MAX_REGS 32
#define RMI_F30_CTRL_MAX_BYTES DIV_ROUND_UP(RMI_F30_CTRL_MAX_REGS, 8)
#define RMI_F30_CTRL_MAX_REG_BLOCKS 11
#define RMI_F30_CTRL_REGS_MAX_SIZE (RMI_F30_CTRL_MAX_BYTES \
+ 1 \
+ RMI_F30_CTRL_MAX_BYTES \
+ RMI_F30_CTRL_MAX_BYTES \
+ RMI_F30_CTRL_MAX_BYTES \
+ 6 \
+ RMI_F30_CTRL_MAX_REGS \
+ RMI_F30_CTRL_MAX_REGS \
+ RMI_F30_CTRL_MAX_BYTES \
+ 1 \
+ 1)
#define TRACKSTICK_RANGE_START 3
#define TRACKSTICK_RANGE_END 6
struct rmi_f30_ctrl_data {
int address;
int length;
u8 *regs;
};
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 */
struct rmi_f30_ctrl_data ctrl[RMI_F30_CTRL_MAX_REG_BLOCKS];
u8 ctrl_regs[RMI_F30_CTRL_REGS_MAX_SIZE];
u32 ctrl_regs_size;
u8 data_regs[RMI_F30_CTRL_MAX_BYTES];
u16 *gpioled_key_map;
struct input_dev *input;
struct rmi_function *f03;
bool trackstick_buttons;
};
static int rmi_f30_read_control_parameters(struct rmi_function *fn,
struct f30_data *f30)
{
int error;
error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
f30->ctrl_regs, f30->ctrl_regs_size);
if (error) {
dev_err(&fn->dev,
"%s: Could not read control registers at 0x%x: %d\n",
__func__, fn->fd.control_base_addr, error);
return error;
}
return 0;
}
static void rmi_f30_report_button(struct rmi_function *fn,
struct f30_data *f30, unsigned int button)
{
unsigned int reg_num = button >> 3;
unsigned int bit_num = button & 0x07;
u16 key_code = f30->gpioled_key_map[button];
bool key_down = !(f30->data_regs[reg_num] & BIT(bit_num));
if (f30->trackstick_buttons &&
button >= TRACKSTICK_RANGE_START &&
button <= TRACKSTICK_RANGE_END) {
rmi_f03_overwrite_button(f30->f03, key_code, key_down);
} else {
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
"%s: call input report key (0x%04x) value (0x%02x)",
__func__, key_code, key_down);
input_report_key(f30->input, key_code, key_down);
}
}
static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
{
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
int error;
int i;
/* Read the gpi led data. */
if (drvdata->attn_data.data) {
if (drvdata->attn_data.size < f30->register_count) {
dev_warn(&fn->dev,
"F30 interrupted, but data is missing\n");
return 0;
}
memcpy(f30->data_regs, drvdata->attn_data.data,
f30->register_count);
drvdata->attn_data.data += f30->register_count;
drvdata->attn_data.size -= f30->register_count;
} else {
error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
f30->data_regs, f30->register_count);
if (error) {
dev_err(&fn->dev,
"%s: Failed to read F30 data registers: %d\n",
__func__, error);
return error;
}
}
if (f30->has_gpio) {
for (i = 0; i < f30->gpioled_count; i++)
if (f30->gpioled_key_map[i] != KEY_RESERVED)
rmi_f30_report_button(fn, f30, i);
if (f30->trackstick_buttons)
rmi_f03_commit_buttons(f30->f03);
}
return 0;
}
static int rmi_f30_config(struct rmi_function *fn)
{
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_driver *drv = fn->rmi_dev->driver;
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
int error;
if (pdata->f30_data.trackstick_buttons) {
/* Try [re-]establish link to F03. */
f30->f03 = rmi_find_function(fn->rmi_dev, 0x03);
f30->trackstick_buttons = f30->f03 != NULL;
}
if (pdata->f30_data.disable) {
drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask);
} else {
/* Write Control Register values back to device */
error = rmi_write_block(fn->rmi_dev, fn->fd.control_base_addr,
f30->ctrl_regs, f30->ctrl_regs_size);
if (error) {
dev_err(&fn->dev,
"%s: Could not write control registers at 0x%x: %d\n",
__func__, fn->fd.control_base_addr, error);
return error;
}
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
}
return 0;
}
static void rmi_f30_set_ctrl_data(struct rmi_f30_ctrl_data *ctrl,
int *ctrl_addr, int len, u8 **reg)
{
ctrl->address = *ctrl_addr;
ctrl->length = len;
ctrl->regs = *reg;
*ctrl_addr += len;
*reg += len;
}
static bool rmi_f30_is_valid_button(int button, struct rmi_f30_ctrl_data *ctrl)
{
int byte_position = button >> 3;
int bit_position = button & 0x07;
/*
* ctrl2 -> dir == 0 -> input mode
* ctrl3 -> data == 1 -> actual button
*/
return !(ctrl[2].regs[byte_position] & BIT(bit_position)) &&
(ctrl[3].regs[byte_position] & BIT(bit_position));
}
static int rmi_f30_map_gpios(struct rmi_function *fn,
struct f30_data *f30)
{
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
struct input_dev *input = f30->input;
unsigned int button = BTN_LEFT;
unsigned int trackstick_button = BTN_LEFT;
bool button_mapped = false;
int i;
f30->gpioled_key_map = devm_kcalloc(&fn->dev,
f30->gpioled_count,
sizeof(f30->gpioled_key_map[0]),
GFP_KERNEL);
if (!f30->gpioled_key_map) {
dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
return -ENOMEM;
}
for (i = 0; i < f30->gpioled_count; i++) {
if (!rmi_f30_is_valid_button(i, f30->ctrl))
continue;
if (pdata->f30_data.trackstick_buttons &&
i >= TRACKSTICK_RANGE_START && i < TRACKSTICK_RANGE_END) {
f30->gpioled_key_map[i] = trackstick_button++;
} else if (!pdata->f30_data.buttonpad || !button_mapped) {
f30->gpioled_key_map[i] = button;
input_set_capability(input, EV_KEY, button++);
button_mapped = true;
}
}
input->keycode = f30->gpioled_key_map;
input->keycodesize = sizeof(f30->gpioled_key_map[0]);
input->keycodemax = f30->gpioled_count;
/*
* Buttonpad could be also inferred from f30->has_mech_mouse_btns,
* but I am not sure, so use only the pdata info and the number of
* mapped buttons.
*/
if (pdata->f30_data.buttonpad || (button - BTN_LEFT == 1))
__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
return 0;
}
static int rmi_f30_initialize(struct rmi_function *fn, struct f30_data *f30)
{
u8 *ctrl_reg = f30->ctrl_regs;
int control_address = fn->fd.control_base_addr;
u8 buf[RMI_F30_QUERY_SIZE];
int error;
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
buf, RMI_F30_QUERY_SIZE);
if (error) {
dev_err(&fn->dev, "Failed to read query register\n");
return error;
}
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 = DIV_ROUND_UP(f30->gpioled_count, 8);
if (f30->has_gpio && f30->has_led)
rmi_f30_set_ctrl_data(&f30->ctrl[0], &control_address,
f30->register_count, &ctrl_reg);
rmi_f30_set_ctrl_data(&f30->ctrl[1], &control_address,
sizeof(u8), &ctrl_reg);
if (f30->has_gpio) {
rmi_f30_set_ctrl_data(&f30->ctrl[2], &control_address,
f30->register_count, &ctrl_reg);
rmi_f30_set_ctrl_data(&f30->ctrl[3], &control_address,
f30->register_count, &ctrl_reg);
}
if (f30->has_led) {
rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address,
f30->register_count, &ctrl_reg);
rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address,
f30->has_extended_pattern ? 6 : 2,
&ctrl_reg);
}
if (f30->has_led || f30->has_gpio_driver_control) {
/* control 6 uses a byte per gpio/led */
rmi_f30_set_ctrl_data(&f30->ctrl[6], &control_address,
f30->gpioled_count, &ctrl_reg);
}
if (f30->has_mappable_buttons) {
/* control 7 uses a byte per gpio/led */
rmi_f30_set_ctrl_data(&f30->ctrl[7], &control_address,
f30->gpioled_count, &ctrl_reg);
}
if (f30->has_haptic) {
rmi_f30_set_ctrl_data(&f30->ctrl[8], &control_address,
f30->register_count, &ctrl_reg);
rmi_f30_set_ctrl_data(&f30->ctrl[9], &control_address,
sizeof(u8), &ctrl_reg);
}
if (f30->has_mech_mouse_btns)
rmi_f30_set_ctrl_data(&f30->ctrl[10], &control_address,
sizeof(u8), &ctrl_reg);
f30->ctrl_regs_size = ctrl_reg -
f30->ctrl_regs ?: RMI_F30_CTRL_REGS_MAX_SIZE;
error = rmi_f30_read_control_parameters(fn, f30);
if (error) {
dev_err(&fn->dev,
"Failed to initialize F30 control params: %d\n",
error);
return error;
}
if (f30->has_gpio) {
error = rmi_f30_map_gpios(fn, f30);
if (error)
return error;
}
return 0;
}
static int rmi_f30_probe(struct rmi_function *fn)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(rmi_dev);
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
struct f30_data *f30;
int error;
if (pdata->f30_data.disable)
return 0;
if (!drv_data->input) {
dev_info(&fn->dev, "F30: no input device found, ignoring\n");
return -ENXIO;
}
f30 = devm_kzalloc(&fn->dev, sizeof(*f30), GFP_KERNEL);
if (!f30)
return -ENOMEM;
f30->input = drv_data->input;
error = rmi_f30_initialize(fn, f30);
if (error)
return error;
dev_set_drvdata(&fn->dev, f30);
return 0;
}
struct rmi_function_handler rmi_f30_handler = {
.driver = {
.name = "rmi4_f30",
},
.func = 0x30,
.probe = rmi_f30_probe,
.config = rmi_f30_config,
.attention = rmi_f30_attention,
};