linux/drivers/input/rmi4/rmi_f55.c
Guenter Roeck c762cc68b6 Input: synaptics-rmi4 - propagate correct number of rx and tx electrodes to F54
F54 diagnostics report functions provide data based on the number of
enabled rx and tx electrodes, which is not identical to the number of
electrodes reported with F54:Query0 and F54:Query1. Those values report
the number of supported electrodes, not the number of enabled electrodes.
The number of enabled electrodes can be determined by analyzing F55:Ctrl1
(sensor receiver assignment) and F55:Ctrl2 (sensor transmitter assignment).

Propagate the number of enabled electrodes from F55 to F54 to avoid
corrupted output if not all electrodes are enabled.

Fixes: 3a762dbd53 ("[media] Input: synaptics-rmi4 - add support for F54 ...")
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Tested-by: Nick Dyer <nick@shmanahar.org>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
2016-11-22 17:59:25 -08:00

132 lines
3.3 KiB
C

/*
* Copyright (c) 2012-2015 Synaptics Incorporated
* Copyright (C) 2016 Zodiac Inflight Innovations
*
* 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/bitops.h>
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include "rmi_driver.h"
#define F55_NAME "rmi4_f55"
/* F55 data offsets */
#define F55_NUM_RX_OFFSET 0
#define F55_NUM_TX_OFFSET 1
#define F55_PHYS_CHAR_OFFSET 2
/* Only read required query registers */
#define F55_QUERY_LEN 3
/* F55 capabilities */
#define F55_CAP_SENSOR_ASSIGN BIT(0)
struct f55_data {
struct rmi_function *fn;
u8 qry[F55_QUERY_LEN];
u8 num_rx_electrodes;
u8 cfg_num_rx_electrodes;
u8 num_tx_electrodes;
u8 cfg_num_tx_electrodes;
};
static int rmi_f55_detect(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 f55_data *f55;
int error;
f55 = dev_get_drvdata(&fn->dev);
error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
&f55->qry, sizeof(f55->qry));
if (error) {
dev_err(&fn->dev, "%s: Failed to query F55 properties\n",
__func__);
return error;
}
f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET];
f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET];
f55->cfg_num_rx_electrodes = f55->num_rx_electrodes;
f55->cfg_num_tx_electrodes = f55->num_rx_electrodes;
drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes;
drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes;
if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) {
int i, total;
u8 buf[256];
/*
* Calculate the number of enabled receive and transmit
* electrodes by reading F55:Ctrl1 (sensor receiver assignment)
* and F55:Ctrl2 (sensor transmitter assignment). The number of
* enabled electrodes is the sum of all field entries with a
* value other than 0xff.
*/
error = rmi_read_block(fn->rmi_dev,
fn->fd.control_base_addr + 1,
buf, f55->num_rx_electrodes);
if (!error) {
total = 0;
for (i = 0; i < f55->num_rx_electrodes; i++) {
if (buf[i] != 0xff)
total++;
}
f55->cfg_num_rx_electrodes = total;
drv_data->num_rx_electrodes = total;
}
error = rmi_read_block(fn->rmi_dev,
fn->fd.control_base_addr + 2,
buf, f55->num_tx_electrodes);
if (!error) {
total = 0;
for (i = 0; i < f55->num_tx_electrodes; i++) {
if (buf[i] != 0xff)
total++;
}
f55->cfg_num_tx_electrodes = total;
drv_data->num_tx_electrodes = total;
}
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n",
f55->cfg_num_rx_electrodes, f55->num_rx_electrodes);
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n",
f55->cfg_num_tx_electrodes, f55->num_tx_electrodes);
return 0;
}
static int rmi_f55_probe(struct rmi_function *fn)
{
struct f55_data *f55;
f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL);
if (!f55)
return -ENOMEM;
f55->fn = fn;
dev_set_drvdata(&fn->dev, f55);
return rmi_f55_detect(fn);
}
struct rmi_function_handler rmi_f55_handler = {
.driver = {
.name = F55_NAME,
},
.func = 0x55,
.probe = rmi_f55_probe,
};