Merge branch 'synaptics-rmi4' into next

Bring in support for devices using Synaptics RMI4 protocol, including
RMI4 bus, 2D sensor and button handlers, and SPI and I2C interface
drivers.
This commit is contained in:
Dmitry Torokhov 2016-03-11 09:51:25 -08:00
commit 62d5bdf972
25 changed files with 6618 additions and 0 deletions

View File

@ -0,0 +1,56 @@
Synaptics RMI4 2D Sensor Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices which contain 2D sensors using Function 11 or
Function 12. Complete documentation for transports and other functions
can be found in:
Documentation/devicetree/bindings/input/rmi4.
RMI4 Function 11 and Function 12 are for 2D touch position sensing.
Additional documentation for F11 can be found at:
http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
Optional Touch Properties:
Description in Documentation/devicetree/bindings/input/touch
- touchscreen-inverted-x
- touchscreen-inverted-y
- touchscreen-swapped-x-y
- touchscreen-x-mm
- touchscreen-y-mm
Optional Properties:
- syna,clip-x-low: Sets a minimum value for X.
- syna,clip-y-low: Sets a minimum value for Y.
- syna,clip-x-high: Sets a maximum value for X.
- syna,clip-y-high: Sets a maximum value for Y.
- syna,offset-x: Add an offset to X.
- syna,offset-y: Add an offset to Y.
- syna,delta-x-threshold: Set the minimum distance on the X axis required
to generate an interrupt in reduced reporting
mode.
- syna,delta-y-threshold: Set the minimum distance on the Y axis required
to generate an interrupt in reduced reporting
mode.
- syna,sensor-type: Set the sensor type. 1 for touchscreen 2 for touchpad.
- syna,disable-report-mask: Mask for disabling posiiton reporting. Used to
disable reporing absolute position data.
- syna,rezero-wait-ms: Time in miliseconds to wait after issuing a rezero
command.
Example of a RMI4 I2C device with F11:
Example:
&i2c1 {
rmi4-i2c-dev@2c {
compatible = "syna,rmi4-i2c";
...
rmi4-f11@11 {
reg = <0x11>;
touchscreen-inverted-y;
syna,sensor-type = <2>;
};
};
};

View File

@ -0,0 +1,39 @@
Synaptics RMI4 F01 Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices which contain Function 1. Complete documentation
for transports and other functions can be found in:
Documentation/devicetree/bindings/input/rmi4.
Additional documentation for F01 can be found at:
http://www.synaptics.com/sites/default/files/511-000136-01-Rev-E-RMI4-Interfacing-Guide.pdf
Optional Properties:
- syna,nosleep-mode: If set the device will run at full power without sleeping.
nosleep has 3 modes, 0 will not change the default
setting, 1 will disable nosleep (allow sleeping),
and 2 will enable nosleep (disabling sleep).
- syna,wakeup-threshold: Defines the amplitude of the disturbance to the
background capacitance that will cause the
device to wake from dozing.
- syna,doze-holdoff-ms: The delay to wait after the last finger lift and the
first doze cycle.
- syna,doze-interval-ms: The time period that the device sleeps between finger
activity.
Example of a RMI4 I2C device with F01:
Example:
&i2c1 {
rmi4-i2c-dev@2c {
compatible = "syna,rmi4-i2c";
...
rmi4-f01@1 {
reg = <0x1>;
syna,nosleep-mode = <1>;
};
};
};

View File

@ -0,0 +1,53 @@
Synaptics RMI4 I2C Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices using the I2C transport driver. Complete documentation
for other transports and functions can be found in
Documentation/devicetree/bindings/input/rmi4.
Required Properties:
- compatible: syna,rmi4-i2c
- reg: I2C address
- #address-cells: Set to 1 to indicate that the function child nodes
consist of only on uint32 value.
- #size-cells: Set to 0 to indicate that the function child nodes do not
have a size property.
Optional Properties:
- interrupts: interrupt which the rmi device is connected to.
- interrupt-parent: The interrupt controller.
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- syna,reset-delay-ms: The number of milliseconds to wait after resetting the
device.
Function Parameters:
Parameters specific to RMI functions are contained in child nodes of the rmi device
node. Documentation for the parameters of each function can be found in:
Documentation/devicetree/bindings/input/rmi4/rmi_f*.txt.
Example:
&i2c1 {
rmi4-i2c-dev@2c {
compatible = "syna,rmi4-i2c";
reg = <0x2c>;
#address-cells = <1>;
#size-cells = <0>;
interrupt-parent = <&gpio>;
interrupts = <4 2>;
rmi4-f01@1 {
reg = <0x1>;
syna,nosleep-mode = <1>;
};
rmi4-f11@11 {
reg = <0x11>;
touchscreen-inverted-y;
syna,sensor-type = <2>;
};
};
};

View File

@ -0,0 +1,57 @@
Synaptics RMI4 SPI Device Binding
The Synaptics RMI4 core is able to support RMI4 devices using different
transports and different functions. This file describes the device tree
bindings for devices using the SPI transport driver. Complete documentation
for other transports and functions can be found in
Documentation/devicetree/bindings/input/rmi4.
Required Properties:
- compatible: syna,rmi4-spi
- reg: Chip select address for the device
- #address-cells: Set to 1 to indicate that the function child nodes
consist of only on uint32 value.
- #size-cells: Set to 0 to indicate that the function child nodes do not
have a size property.
Optional Properties:
- interrupts: interrupt which the rmi device is connected to.
- interrupt-parent: The interrupt controller.
See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
- spi-rx-delay-us: microsecond delay after a read transfer.
- spi-tx-delay-us: microsecond delay after a write transfer.
Function Parameters:
Parameters specific to RMI functions are contained in child nodes of the rmi device
node. Documentation for the parameters of each function can be found in:
Documentation/devicetree/bindings/input/rmi4/rmi_f*.txt.
Example:
spi@7000d800 {
rmi4-spi-dev@0 {
compatible = "syna,rmi4-spi";
reg = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
spi-max-frequency = <4000000>;
spi-cpha;
spi-cpol;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(K, 2) 0x2>;
spi-rx-delay-us = <30>;
rmi4-f01@1 {
reg = <0x1>;
syna,nosleep-mode = <1>;
};
rmi4-f11@11 {
reg = <0x11>;
touchscreen-inverted-y;
syna,sensor-type = <2>;
};
};
};

View File

@ -18,6 +18,8 @@ Optional properties for Touchscreens:
- touchscreen-inverted-y : Y axis is inverted (boolean) - touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean) - touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
Swapping is done after inverting the axis Swapping is done after inverting the axis
- touchscreen-x-mm : horizontal length in mm of the touchscreen
- touchscreen-y-mm : vertical length in mm of the touchscreen
Deprecated properties for Touchscreens: Deprecated properties for Touchscreens:
- x-size : deprecated name for touchscreen-size-x - x-size : deprecated name for touchscreen-size-x

View File

@ -61,6 +61,8 @@ contain the following properties.
used for MOSI. Defaults to 1 if not present. used for MOSI. Defaults to 1 if not present.
- spi-rx-bus-width - (optional) The bus width(number of data wires) that - spi-rx-bus-width - (optional) The bus width(number of data wires) that
used for MISO. Defaults to 1 if not present. used for MISO. Defaults to 1 if not present.
- spi-rx-delay-us - (optional) Microsecond delay after a read transfer.
- spi-tx-delay-us - (optional) Microsecond delay after a write transfer.
Some SPI controllers and devices support Dual and Quad SPI transfer mode. Some SPI controllers and devices support Dual and Quad SPI transfer mode.
It allows data in the SPI system to be transferred in 2 wires(DUAL) or 4 wires(QUAD). It allows data in the SPI system to be transferred in 2 wires(DUAL) or 4 wires(QUAD).

View File

@ -220,6 +220,7 @@ sprd Spreadtrum Communications Inc.
st STMicroelectronics st STMicroelectronics
ste ST-Ericsson ste ST-Ericsson
stericsson ST-Ericsson stericsson ST-Ericsson
syna Synaptics Inc.
synology Synology, Inc. synology Synology, Inc.
tbs TBS Technologies tbs TBS Technologies
tcl Toby Churchill Ltd. tcl Toby Churchill Ltd.

View File

@ -201,6 +201,8 @@ source "drivers/input/touchscreen/Kconfig"
source "drivers/input/misc/Kconfig" source "drivers/input/misc/Kconfig"
source "drivers/input/rmi4/Kconfig"
endif endif
menu "Hardware I/O ports" menu "Hardware I/O ports"

View File

@ -26,3 +26,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
obj-$(CONFIG_RMI4_CORE) += rmi4/

View File

@ -0,0 +1,63 @@
#
# RMI4 configuration
#
config RMI4_CORE
tristate "Synaptics RMI4 bus support"
help
Say Y here if you want to support the Synaptics RMI4 bus. This is
required for all RMI4 device support.
If unsure, say Y.
config RMI4_I2C
tristate "RMI4 I2C Support"
depends on RMI4_CORE && I2C
help
Say Y here if you want to support RMI4 devices connected to an I2C
bus.
If unsure, say Y.
config RMI4_SPI
tristate "RMI4 SPI Support"
depends on RMI4_CORE && SPI
help
Say Y here if you want to support RMI4 devices connected to a SPI
bus.
If unsure, say N.
config RMI4_2D_SENSOR
bool
depends on RMI4_CORE
config RMI4_F11
bool "RMI4 Function 11 (2D pointing)"
select RMI4_2D_SENSOR
depends on RMI4_CORE
help
Say Y here if you want to add support for RMI4 function 11.
Function 11 provides 2D multifinger pointing for touchscreens and
touchpads. For sensors that support relative pointing, F11 also
provides mouse input.
config RMI4_F12
bool "RMI4 Function 12 (2D pointing)"
select RMI4_2D_SENSOR
depends on RMI4_CORE
help
Say Y here if you want to add support for RMI4 function 12.
Function 12 provides 2D multifinger pointing for touchscreens and
touchpads. For sensors that support relative pointing, F12 also
provides mouse input.
config RMI4_F30
bool "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.

View File

@ -0,0 +1,13 @@
obj-$(CONFIG_RMI4_CORE) += rmi_core.o
rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o
rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
# Function drivers
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
# Transports
obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o
obj-$(CONFIG_RMI4_SPI) += rmi_spi.o

View File

@ -0,0 +1,329 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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/device.h>
#include <linux/of.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/rmi.h>
#include "rmi_driver.h"
#include "rmi_2d_sensor.h"
#define RMI_2D_REL_POS_MIN -128
#define RMI_2D_REL_POS_MAX 127
/* maximum ABS_MT_POSITION displacement (in mm) */
#define DMAX 10
void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot)
{
struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align;
/* we keep the previous values if the finger is released */
if (obj->type == RMI_2D_OBJECT_NONE)
return;
if (axis_align->swap_axes)
swap(obj->x, obj->y);
if (axis_align->flip_x)
obj->x = sensor->max_x - obj->x;
if (axis_align->flip_y)
obj->y = sensor->max_y - obj->y;
/*
* Here checking if X offset or y offset are specified is
* redundant. We just add the offsets or clip the values.
*
* Note: offsets need to be applied before clipping occurs,
* or we could get funny values that are outside of
* clipping boundaries.
*/
obj->x += axis_align->offset_x;
obj->y += axis_align->offset_y;
obj->x = max(axis_align->clip_x_low, obj->x);
obj->y = max(axis_align->clip_y_low, obj->y);
if (axis_align->clip_x_high)
obj->x = min(sensor->max_x, obj->x);
if (axis_align->clip_y_high)
obj->y = min(sensor->max_y, obj->y);
sensor->tracking_pos[slot].x = obj->x;
sensor->tracking_pos[slot].y = obj->y;
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_process);
void rmi_2d_sensor_abs_report(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot)
{
struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align;
struct input_dev *input = sensor->input;
int wide, major, minor;
if (sensor->kernel_tracking)
input_mt_slot(input, sensor->tracking_slots[slot]);
else
input_mt_slot(input, slot);
input_mt_report_slot_state(input, obj->mt_tool,
obj->type != RMI_2D_OBJECT_NONE);
if (obj->type != RMI_2D_OBJECT_NONE) {
obj->x = sensor->tracking_pos[slot].x;
obj->y = sensor->tracking_pos[slot].y;
if (axis_align->swap_axes)
swap(obj->wx, obj->wy);
wide = (obj->wx > obj->wy);
major = max(obj->wx, obj->wy);
minor = min(obj->wx, obj->wy);
if (obj->type == RMI_2D_OBJECT_STYLUS) {
major = max(1, major);
minor = max(1, minor);
}
input_event(sensor->input, EV_ABS, ABS_MT_POSITION_X, obj->x);
input_event(sensor->input, EV_ABS, ABS_MT_POSITION_Y, obj->y);
input_event(sensor->input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(sensor->input, EV_ABS, ABS_MT_PRESSURE, obj->z);
input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(sensor->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
rmi_dbg(RMI_DEBUG_2D_SENSOR, &sensor->input->dev,
"%s: obj[%d]: type: 0x%02x X: %d Y: %d Z: %d WX: %d WY: %d\n",
__func__, slot, obj->type, obj->x, obj->y, obj->z,
obj->wx, obj->wy);
}
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_abs_report);
void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y)
{
struct rmi_2d_axis_alignment *axis_align = &sensor->axis_align;
x = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)x));
y = min(RMI_2D_REL_POS_MAX, max(RMI_2D_REL_POS_MIN, (int)y));
if (axis_align->swap_axes)
swap(x, y);
if (axis_align->flip_x)
x = min(RMI_2D_REL_POS_MAX, -x);
if (axis_align->flip_y)
y = min(RMI_2D_REL_POS_MAX, -y);
if (x || y) {
input_report_rel(sensor->input, REL_X, x);
input_report_rel(sensor->input, REL_Y, y);
}
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_rel_report);
static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor)
{
struct input_dev *input = sensor->input;
int res_x;
int res_y;
int input_flags = 0;
if (sensor->report_abs) {
if (sensor->axis_align.swap_axes)
swap(sensor->max_x, sensor->max_y);
sensor->min_x = sensor->axis_align.clip_x_low;
if (sensor->axis_align.clip_x_high)
sensor->max_x = min(sensor->max_x,
sensor->axis_align.clip_x_high);
sensor->min_y = sensor->axis_align.clip_y_low;
if (sensor->axis_align.clip_y_high)
sensor->max_y = min(sensor->max_y,
sensor->axis_align.clip_y_high);
set_bit(EV_ABS, input->evbit);
input_set_abs_params(input, ABS_MT_POSITION_X, 0, sensor->max_x,
0, 0);
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, sensor->max_y,
0, 0);
if (sensor->x_mm && sensor->y_mm) {
res_x = (sensor->max_x - sensor->min_x) / sensor->x_mm;
res_y = (sensor->max_y - sensor->min_y) / sensor->y_mm;
input_abs_set_res(input, ABS_X, res_x);
input_abs_set_res(input, ABS_Y, res_y);
input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
if (!sensor->dmax)
sensor->dmax = DMAX * res_x;
}
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
if (sensor->sensor_type == rmi_sensor_touchpad)
input_flags = INPUT_MT_POINTER;
else
input_flags = INPUT_MT_DIRECT;
if (sensor->kernel_tracking)
input_flags |= INPUT_MT_TRACK;
input_mt_init_slots(input, sensor->nbr_fingers, input_flags);
}
if (sensor->report_rel) {
set_bit(EV_REL, input->evbit);
set_bit(REL_X, input->relbit);
set_bit(REL_Y, input->relbit);
}
if (sensor->topbuttonpad)
set_bit(INPUT_PROP_TOPBUTTONPAD, input->propbit);
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_set_input_params);
int rmi_2d_sensor_configure_input(struct rmi_function *fn,
struct rmi_2d_sensor *sensor)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
if (!drv_data->input)
return -ENODEV;
sensor->input = drv_data->input;
rmi_2d_sensor_set_input_params(sensor);
return 0;
}
EXPORT_SYMBOL_GPL(rmi_2d_sensor_configure_input);
#ifdef CONFIG_OF
int rmi_2d_sensor_of_probe(struct device *dev,
struct rmi_2d_sensor_platform_data *pdata)
{
int retval;
u32 val;
pdata->axis_align.swap_axes = of_property_read_bool(dev->of_node,
"touchscreen-swapped-x-y");
pdata->axis_align.flip_x = of_property_read_bool(dev->of_node,
"touchscreen-inverted-x");
pdata->axis_align.flip_y = of_property_read_bool(dev->of_node,
"touchscreen-inverted-y");
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-low", 1);
if (retval)
return retval;
pdata->axis_align.clip_x_low = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-low", 1);
if (retval)
return retval;
pdata->axis_align.clip_y_low = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-x-high", 1);
if (retval)
return retval;
pdata->axis_align.clip_x_high = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,clip-y-high", 1);
if (retval)
return retval;
pdata->axis_align.clip_y_high = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,offset-x", 1);
if (retval)
return retval;
pdata->axis_align.offset_x = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,offset-y", 1);
if (retval)
return retval;
pdata->axis_align.offset_y = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,delta-x-threshold",
1);
if (retval)
return retval;
pdata->axis_align.delta_x_threshold = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,delta-y-threshold",
1);
if (retval)
return retval;
pdata->axis_align.delta_y_threshold = val;
retval = rmi_of_property_read_u32(dev, (u32 *)&pdata->sensor_type,
"syna,sensor-type", 1);
if (retval)
return retval;
retval = rmi_of_property_read_u32(dev, &val, "touchscreen-x-mm", 1);
if (retval)
return retval;
pdata->x_mm = val;
retval = rmi_of_property_read_u32(dev, &val, "touchscreen-y-mm", 1);
if (retval)
return retval;
pdata->y_mm = val;
retval = rmi_of_property_read_u32(dev, &val,
"syna,disable-report-mask", 1);
if (retval)
return retval;
pdata->disable_report_mask = val;
retval = rmi_of_property_read_u32(dev, &val, "syna,rezero-wait-ms",
1);
if (retval)
return retval;
pdata->rezero_wait = val;
return 0;
}
#else
inline int rmi_2d_sensor_of_probe(struct device *dev,
struct rmi_2d_sensor_platform_data *pdata)
{
return -ENODEV;
}
#endif
EXPORT_SYMBOL_GPL(rmi_2d_sensor_of_probe);

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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.
*/
#ifndef _RMI_2D_SENSOR_H
#define _RMI_2D_SENSOR_H
enum rmi_2d_sensor_object_type {
RMI_2D_OBJECT_NONE,
RMI_2D_OBJECT_FINGER,
RMI_2D_OBJECT_STYLUS,
RMI_2D_OBJECT_PALM,
RMI_2D_OBJECT_UNCLASSIFIED,
};
struct rmi_2d_sensor_abs_object {
enum rmi_2d_sensor_object_type type;
int mt_tool;
u16 x;
u16 y;
u8 z;
u8 wx;
u8 wy;
};
/**
* @axis_align - controls parameters that are useful in system prototyping
* and bring up.
* @max_x - The maximum X coordinate that will be reported by this sensor.
* @max_y - The maximum Y coordinate that will be reported by this sensor.
* @nbr_fingers - How many fingers can this sensor report?
* @data_pkt - buffer for data reported by this sensor.
* @pkt_size - number of bytes in that buffer.
* @attn_size - Size of the HID attention report (only contains abs data).
* position when two fingers are on the device. When this is true, we
* assume we have one of those sensors and report events appropriately.
* @sensor_type - indicates whether we're touchscreen or touchpad.
* @input - input device for absolute pointing stream
* @input_phys - buffer for the absolute phys name for this sensor.
*/
struct rmi_2d_sensor {
struct rmi_2d_axis_alignment axis_align;
struct input_mt_pos *tracking_pos;
int *tracking_slots;
bool kernel_tracking;
struct rmi_2d_sensor_abs_object *objs;
int dmax;
u16 min_x;
u16 max_x;
u16 min_y;
u16 max_y;
u8 nbr_fingers;
u8 *data_pkt;
int pkt_size;
int attn_size;
bool topbuttonpad;
enum rmi_sensor_type sensor_type;
struct input_dev *input;
struct rmi_function *fn;
char input_phys[32];
u8 report_abs;
u8 report_rel;
u8 x_mm;
u8 y_mm;
};
int rmi_2d_sensor_of_probe(struct device *dev,
struct rmi_2d_sensor_platform_data *pdata);
void rmi_2d_sensor_abs_process(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot);
void rmi_2d_sensor_abs_report(struct rmi_2d_sensor *sensor,
struct rmi_2d_sensor_abs_object *obj,
int slot);
void rmi_2d_sensor_rel_report(struct rmi_2d_sensor *sensor, int x, int y);
int rmi_2d_sensor_configure_input(struct rmi_function *fn,
struct rmi_2d_sensor *sensor);
#endif /* _RMI_2D_SENSOR_H */

View File

@ -0,0 +1,419 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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/device.h>
#include <linux/kconfig.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/of.h>
#include "rmi_bus.h"
#include "rmi_driver.h"
static int debug_flags;
module_param(debug_flags, int, 0644);
MODULE_PARM_DESC(debug_flags, "control debugging information");
void rmi_dbg(int flags, struct device *dev, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
if (flags & debug_flags) {
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
dev_printk(KERN_DEBUG, dev, "%pV", &vaf);
va_end(args);
}
}
EXPORT_SYMBOL_GPL(rmi_dbg);
/*
* RMI Physical devices
*
* Physical RMI device consists of several functions serving particular
* purpose. For example F11 is a 2D touch sensor while F01 is a generic
* function present in every RMI device.
*/
static void rmi_release_device(struct device *dev)
{
struct rmi_device *rmi_dev = to_rmi_device(dev);
kfree(rmi_dev);
}
static struct device_type rmi_device_type = {
.name = "rmi4_sensor",
.release = rmi_release_device,
};
bool rmi_is_physical_device(struct device *dev)
{
return dev->type == &rmi_device_type;
}
/**
* rmi_register_transport_device - register a transport device connection
* on the RMI bus. Transport drivers provide communication from the devices
* on a bus (such as SPI, I2C, and so on) to the RMI4 sensor.
*
* @xport: the transport device to register
*/
int rmi_register_transport_device(struct rmi_transport_dev *xport)
{
static atomic_t transport_device_count = ATOMIC_INIT(0);
struct rmi_device *rmi_dev;
int error;
rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL);
if (!rmi_dev)
return -ENOMEM;
device_initialize(&rmi_dev->dev);
rmi_dev->xport = xport;
rmi_dev->number = atomic_inc_return(&transport_device_count) - 1;
dev_set_name(&rmi_dev->dev, "rmi4-%02d", rmi_dev->number);
rmi_dev->dev.bus = &rmi_bus_type;
rmi_dev->dev.type = &rmi_device_type;
xport->rmi_dev = rmi_dev;
error = device_add(&rmi_dev->dev);
if (error)
goto err_put_device;
rmi_dbg(RMI_DEBUG_CORE, xport->dev,
"%s: Registered %s as %s.\n", __func__,
dev_name(rmi_dev->xport->dev), dev_name(&rmi_dev->dev));
return 0;
err_put_device:
put_device(&rmi_dev->dev);
return error;
}
EXPORT_SYMBOL_GPL(rmi_register_transport_device);
/**
* rmi_unregister_transport_device - unregister a transport device connection
* @xport: the transport driver to unregister
*
*/
void rmi_unregister_transport_device(struct rmi_transport_dev *xport)
{
struct rmi_device *rmi_dev = xport->rmi_dev;
device_del(&rmi_dev->dev);
put_device(&rmi_dev->dev);
}
EXPORT_SYMBOL(rmi_unregister_transport_device);
/* Function specific stuff */
static void rmi_release_function(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
kfree(fn);
}
static struct device_type rmi_function_type = {
.name = "rmi4_function",
.release = rmi_release_function,
};
bool rmi_is_function_device(struct device *dev)
{
return dev->type == &rmi_function_type;
}
static int rmi_function_match(struct device *dev, struct device_driver *drv)
{
struct rmi_function_handler *handler = to_rmi_function_handler(drv);
struct rmi_function *fn = to_rmi_function(dev);
return fn->fd.function_number == handler->func;
}
#ifdef CONFIG_OF
static void rmi_function_of_probe(struct rmi_function *fn)
{
char of_name[9];
snprintf(of_name, sizeof(of_name), "rmi4-f%02x",
fn->fd.function_number);
fn->dev.of_node = of_find_node_by_name(
fn->rmi_dev->xport->dev->of_node, of_name);
}
#else
static inline void rmi_function_of_probe(struct rmi_function *fn)
{}
#endif
static int rmi_function_probe(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
struct rmi_function_handler *handler =
to_rmi_function_handler(dev->driver);
int error;
rmi_function_of_probe(fn);
if (handler->probe) {
error = handler->probe(fn);
return error;
}
return 0;
}
static int rmi_function_remove(struct device *dev)
{
struct rmi_function *fn = to_rmi_function(dev);
struct rmi_function_handler *handler =
to_rmi_function_handler(dev->driver);
if (handler->remove)
handler->remove(fn);
return 0;
}
int rmi_register_function(struct rmi_function *fn)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
int error;
device_initialize(&fn->dev);
dev_set_name(&fn->dev, "%s.fn%02x",
dev_name(&rmi_dev->dev), fn->fd.function_number);
fn->dev.parent = &rmi_dev->dev;
fn->dev.type = &rmi_function_type;
fn->dev.bus = &rmi_bus_type;
error = device_add(&fn->dev);
if (error) {
dev_err(&rmi_dev->dev,
"Failed device_register function device %s\n",
dev_name(&fn->dev));
goto err_put_device;
}
rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Registered F%02X.\n",
fn->fd.function_number);
return 0;
err_put_device:
put_device(&fn->dev);
return error;
}
void rmi_unregister_function(struct rmi_function *fn)
{
device_del(&fn->dev);
if (fn->dev.of_node)
of_node_put(fn->dev.of_node);
put_device(&fn->dev);
}
/**
* rmi_register_function_handler - register a handler for an RMI function
* @handler: RMI handler that should be registered.
* @module: pointer to module that implements the handler
* @mod_name: name of the module implementing the handler
*
* This function performs additional setup of RMI function handler and
* registers it with the RMI core so that it can be bound to
* RMI function devices.
*/
int __rmi_register_function_handler(struct rmi_function_handler *handler,
struct module *owner,
const char *mod_name)
{
struct device_driver *driver = &handler->driver;
int error;
driver->bus = &rmi_bus_type;
driver->owner = owner;
driver->mod_name = mod_name;
driver->probe = rmi_function_probe;
driver->remove = rmi_function_remove;
error = driver_register(&handler->driver);
if (error) {
pr_err("driver_register() failed for %s, error: %d\n",
handler->driver.name, error);
return error;
}
return 0;
}
EXPORT_SYMBOL_GPL(__rmi_register_function_handler);
/**
* rmi_unregister_function_handler - unregister given RMI function handler
* @handler: RMI handler that should be unregistered.
*
* This function unregisters given function handler from RMI core which
* causes it to be unbound from the function devices.
*/
void rmi_unregister_function_handler(struct rmi_function_handler *handler)
{
driver_unregister(&handler->driver);
}
EXPORT_SYMBOL_GPL(rmi_unregister_function_handler);
/* Bus specific stuff */
static int rmi_bus_match(struct device *dev, struct device_driver *drv)
{
bool physical = rmi_is_physical_device(dev);
/* First see if types are not compatible */
if (physical != rmi_is_physical_driver(drv))
return 0;
return physical || rmi_function_match(dev, drv);
}
struct bus_type rmi_bus_type = {
.match = rmi_bus_match,
.name = "rmi4",
};
static struct rmi_function_handler *fn_handlers[] = {
&rmi_f01_handler,
#ifdef CONFIG_RMI4_F11
&rmi_f11_handler,
#endif
#ifdef CONFIG_RMI4_F12
&rmi_f12_handler,
#endif
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif
};
static void __rmi_unregister_function_handlers(int start_idx)
{
int i;
for (i = start_idx; i >= 0; i--)
rmi_unregister_function_handler(fn_handlers[i]);
}
static void rmi_unregister_function_handlers(void)
{
__rmi_unregister_function_handlers(ARRAY_SIZE(fn_handlers) - 1);
}
static int rmi_register_function_handlers(void)
{
int ret;
int i;
for (i = 0; i < ARRAY_SIZE(fn_handlers); i++) {
ret = rmi_register_function_handler(fn_handlers[i]);
if (ret) {
pr_err("%s: error registering the RMI F%02x handler: %d\n",
__func__, fn_handlers[i]->func, ret);
goto err_unregister_function_handlers;
}
}
return 0;
err_unregister_function_handlers:
__rmi_unregister_function_handlers(i - 1);
return ret;
}
int rmi_of_property_read_u32(struct device *dev, u32 *result,
const char *prop, bool optional)
{
int retval;
u32 val = 0;
retval = of_property_read_u32(dev->of_node, prop, &val);
if (retval && (!optional && retval == -EINVAL)) {
dev_err(dev, "Failed to get %s value: %d\n",
prop, retval);
return retval;
}
*result = val;
return 0;
}
EXPORT_SYMBOL_GPL(rmi_of_property_read_u32);
static int __init rmi_bus_init(void)
{
int error;
error = bus_register(&rmi_bus_type);
if (error) {
pr_err("%s: error registering the RMI bus: %d\n",
__func__, error);
return error;
}
error = rmi_register_function_handlers();
if (error)
goto err_unregister_bus;
error = rmi_register_physical_driver();
if (error) {
pr_err("%s: error registering the RMI physical driver: %d\n",
__func__, error);
goto err_unregister_bus;
}
return 0;
err_unregister_bus:
bus_unregister(&rmi_bus_type);
return error;
}
module_init(rmi_bus_init);
static void __exit rmi_bus_exit(void)
{
/*
* We should only ever get here if all drivers are unloaded, so
* all we have to do at this point is unregister ourselves.
*/
rmi_unregister_physical_driver();
rmi_unregister_function_handlers();
bus_unregister(&rmi_bus_type);
}
module_exit(rmi_bus_exit);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com");
MODULE_DESCRIPTION("RMI bus");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

View File

@ -0,0 +1,182 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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.
*/
#ifndef _RMI_BUS_H
#define _RMI_BUS_H
#include <linux/rmi.h>
struct rmi_device;
/**
* struct rmi_function - represents the implementation of an RMI4
* function for a particular device (basically, a driver for that RMI4 function)
*
* @fd: The function descriptor of the RMI function
* @rmi_dev: Pointer to the RMI device associated with this function container
* @dev: The device associated with this particular function.
*
* @num_of_irqs: The number of irqs needed by this function
* @irq_pos: The position in the irq bitfield this function holds
* @irq_mask: For convenience, can be used to mask IRQ bits off during ATTN
* interrupt handling.
*
* @node: entry in device's list of functions
*/
struct rmi_function {
struct rmi_function_descriptor fd;
struct rmi_device *rmi_dev;
struct device dev;
struct list_head node;
unsigned int num_of_irqs;
unsigned int irq_pos;
unsigned long irq_mask[];
};
#define to_rmi_function(d) container_of(d, struct rmi_function, dev)
bool rmi_is_function_device(struct device *dev);
int __must_check rmi_register_function(struct rmi_function *);
void rmi_unregister_function(struct rmi_function *);
/**
* struct rmi_function_handler - driver routines for a particular RMI function.
*
* @func: The RMI function number
* @reset: Called when a reset of the touch sensor is detected. The routine
* should perform any out-of-the-ordinary reset handling that might be
* necessary. Restoring of touch sensor configuration registers should be
* handled in the config() callback, below.
* @config: Called when the function container is first initialized, and
* after a reset is detected. This routine should write any necessary
* configuration settings to the device.
* @attention: Called when the IRQ(s) for the function are set by the touch
* sensor.
* @suspend: Should perform any required operations to suspend the particular
* function.
* @resume: Should perform any required operations to resume the particular
* function.
*
* All callbacks are expected to return 0 on success, error code on failure.
*/
struct rmi_function_handler {
struct device_driver driver;
u8 func;
int (*probe)(struct rmi_function *fn);
void (*remove)(struct rmi_function *fn);
int (*config)(struct rmi_function *fn);
int (*reset)(struct rmi_function *fn);
int (*attention)(struct rmi_function *fn, unsigned long *irq_bits);
int (*suspend)(struct rmi_function *fn);
int (*resume)(struct rmi_function *fn);
};
#define to_rmi_function_handler(d) \
container_of(d, struct rmi_function_handler, driver)
int __must_check __rmi_register_function_handler(struct rmi_function_handler *,
struct module *, const char *);
#define rmi_register_function_handler(handler) \
__rmi_register_function_handler(handler, THIS_MODULE, KBUILD_MODNAME)
void rmi_unregister_function_handler(struct rmi_function_handler *);
#define to_rmi_driver(d) \
container_of(d, struct rmi_driver, driver)
#define to_rmi_device(d) container_of(d, struct rmi_device, dev)
static inline struct rmi_device_platform_data *
rmi_get_platform_data(struct rmi_device *d)
{
return &d->xport->pdata;
}
bool rmi_is_physical_device(struct device *dev);
/**
* rmi_read - read a single byte
* @d: Pointer to an RMI device
* @addr: The address to read from
* @buf: The read buffer
*
* Reads a single byte of data using the underlying transport protocol
* into memory pointed by @buf. It returns 0 on success or a negative
* error code.
*/
static inline int rmi_read(struct rmi_device *d, u16 addr, u8 *buf)
{
return d->xport->ops->read_block(d->xport, addr, buf, 1);
}
/**
* rmi_read_block - read a block of bytes
* @d: Pointer to an RMI device
* @addr: The start address to read from
* @buf: The read buffer
* @len: Length of the read buffer
*
* Reads a block of byte data using the underlying transport protocol
* into memory pointed by @buf. It returns 0 on success or a negative
* error code.
*/
static inline int rmi_read_block(struct rmi_device *d, u16 addr,
void *buf, size_t len)
{
return d->xport->ops->read_block(d->xport, addr, buf, len);
}
/**
* rmi_write - write a single byte
* @d: Pointer to an RMI device
* @addr: The address to write to
* @data: The data to write
*
* Writes a single byte using the underlying transport protocol. It
* returns zero on success or a negative error code.
*/
static inline int rmi_write(struct rmi_device *d, u16 addr, u8 data)
{
return d->xport->ops->write_block(d->xport, addr, &data, 1);
}
/**
* rmi_write_block - write a block of bytes
* @d: Pointer to an RMI device
* @addr: The start address to write to
* @buf: The write buffer
* @len: Length of the write buffer
*
* Writes a block of byte data from buf using the underlaying transport
* protocol. It returns the amount of bytes written or a negative error code.
*/
static inline int rmi_write_block(struct rmi_device *d, u16 addr,
const void *buf, size_t len)
{
return d->xport->ops->write_block(d->xport, addr, buf, len);
}
int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data));
extern struct bus_type rmi_bus_type;
int rmi_of_property_read_u32(struct device *dev, u32 *result,
const char *prop, bool optional);
#define RMI_DEBUG_CORE BIT(0)
#define RMI_DEBUG_XPORT BIT(1)
#define RMI_DEBUG_FN BIT(2)
#define RMI_DEBUG_2D_SENSOR BIT(3)
void rmi_dbg(int flags, struct device *dev, const char *fmt, ...);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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.
*/
#ifndef _RMI_DRIVER_H
#define _RMI_DRIVER_H
#include <linux/ctype.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>
#include <linux/input.h>
#include "rmi_bus.h"
#define RMI_DRIVER_VERSION "2.0"
#define SYNAPTICS_INPUT_DEVICE_NAME "Synaptics RMI4 Touch Sensor"
#define SYNAPTICS_VENDOR_ID 0x06cb
#define GROUP(_attrs) { \
.attrs = _attrs, \
}
#define PDT_PROPERTIES_LOCATION 0x00EF
#define BSR_LOCATION 0x00FE
#define RMI_PDT_PROPS_HAS_BSR 0x02
#define NAME_BUFFER_SIZE 256
#define RMI_PDT_ENTRY_SIZE 6
#define RMI_PDT_FUNCTION_VERSION_MASK 0x60
#define RMI_PDT_INT_SOURCE_COUNT_MASK 0x07
#define PDT_START_SCAN_LOCATION 0x00e9
#define PDT_END_SCAN_LOCATION 0x0005
#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
struct pdt_entry {
u16 page_start;
u8 query_base_addr;
u8 command_base_addr;
u8 control_base_addr;
u8 data_base_addr;
u8 interrupt_source_count;
u8 function_version;
u8 function_number;
};
int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry,
u16 pdt_address);
#define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE)
#define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE)
/* describes a single packet register */
struct rmi_register_desc_item {
u16 reg;
unsigned long reg_size;
u8 num_subpackets;
unsigned long subpacket_map[BITS_TO_LONGS(
RMI_REG_DESC_SUBPACKET_BITS)];
};
/*
* describes the packet registers for a particular type
* (ie query, control, data)
*/
struct rmi_register_descriptor {
unsigned long struct_size;
unsigned long presense_map[BITS_TO_LONGS(RMI_REG_DESC_PRESENSE_BITS)];
u8 num_registers;
struct rmi_register_desc_item *registers;
};
int rmi_read_register_desc(struct rmi_device *d, u16 addr,
struct rmi_register_descriptor *rdesc);
const struct rmi_register_desc_item *rmi_get_register_desc_item(
struct rmi_register_descriptor *rdesc, u16 reg);
/*
* Calculate the total size of all of the registers described in the
* descriptor.
*/
size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc);
int rmi_register_desc_calc_reg_offset(
struct rmi_register_descriptor *rdesc, u16 reg);
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
u8 subpacket);
bool rmi_is_physical_driver(struct device_driver *);
int rmi_register_physical_driver(void);
void rmi_unregister_physical_driver(void);
char *rmi_f01_get_product_ID(struct rmi_function *fn);
extern struct rmi_function_handler rmi_f01_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
extern struct rmi_function_handler rmi_f30_handler;
#endif

View File

@ -0,0 +1,624 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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/kconfig.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include "rmi_driver.h"
#define RMI_PRODUCT_ID_LENGTH 10
#define RMI_PRODUCT_INFO_LENGTH 2
#define RMI_DATE_CODE_LENGTH 3
#define PRODUCT_ID_OFFSET 0x10
#define PRODUCT_INFO_OFFSET 0x1E
/* Force a firmware reset of the sensor */
#define RMI_F01_CMD_DEVICE_RESET 1
/* Various F01_RMI_QueryX bits */
#define RMI_F01_QRY1_CUSTOM_MAP BIT(0)
#define RMI_F01_QRY1_NON_COMPLIANT BIT(1)
#define RMI_F01_QRY1_HAS_LTS BIT(2)
#define RMI_F01_QRY1_HAS_SENSOR_ID BIT(3)
#define RMI_F01_QRY1_HAS_CHARGER_INP BIT(4)
#define RMI_F01_QRY1_HAS_ADJ_DOZE BIT(5)
#define RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF BIT(6)
#define RMI_F01_QRY1_HAS_QUERY42 BIT(7)
#define RMI_F01_QRY5_YEAR_MASK 0x1f
#define RMI_F01_QRY6_MONTH_MASK 0x0f
#define RMI_F01_QRY7_DAY_MASK 0x1f
#define RMI_F01_QRY2_PRODINFO_MASK 0x7f
#define RMI_F01_BASIC_QUERY_LEN 21 /* From Query 00 through 20 */
struct f01_basic_properties {
u8 manufacturer_id;
bool has_lts;
bool has_adjustable_doze;
bool has_adjustable_doze_holdoff;
char dom[11]; /* YYYY/MM/DD + '\0' */
u8 product_id[RMI_PRODUCT_ID_LENGTH + 1];
u16 productinfo;
u32 firmware_id;
};
/* F01 device status bits */
/* Most recent device status event */
#define RMI_F01_STATUS_CODE(status) ((status) & 0x0f)
/* The device has lost its configuration for some reason. */
#define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80))
/* Control register bits */
/*
* Sleep mode controls power management on the device and affects all
* functions of the device.
*/
#define RMI_F01_CTRL0_SLEEP_MODE_MASK 0x03
#define RMI_SLEEP_MODE_NORMAL 0x00
#define RMI_SLEEP_MODE_SENSOR_SLEEP 0x01
#define RMI_SLEEP_MODE_RESERVED0 0x02
#define RMI_SLEEP_MODE_RESERVED1 0x03
/*
* This bit disables whatever sleep mode may be selected by the sleep_mode
* field and forces the device to run at full power without sleeping.
*/
#define RMI_F01_CRTL0_NOSLEEP_BIT BIT(2)
/*
* When this bit is set, the touch controller employs a noise-filtering
* algorithm designed for use with a connected battery charger.
*/
#define RMI_F01_CRTL0_CHARGER_BIT BIT(5)
/*
* Sets the report rate for the device. The effect of this setting is
* highly product dependent. Check the spec sheet for your particular
* touch sensor.
*/
#define RMI_F01_CRTL0_REPORTRATE_BIT BIT(6)
/*
* Written by the host as an indicator that the device has been
* successfully configured.
*/
#define RMI_F01_CRTL0_CONFIGURED_BIT BIT(7)
/**
* @ctrl0 - see the bit definitions above.
* @doze_interval - controls the interval between checks for finger presence
* when the touch sensor is in doze mode, in units of 10ms.
* @wakeup_threshold - controls the capacitance threshold at which the touch
* sensor will decide to wake up from that low power state.
* @doze_holdoff - controls how long the touch sensor waits after the last
* finger lifts before entering the doze state, in units of 100ms.
*/
struct f01_device_control {
u8 ctrl0;
u8 doze_interval;
u8 wakeup_threshold;
u8 doze_holdoff;
};
struct f01_data {
struct f01_basic_properties properties;
struct f01_device_control device_control;
u16 doze_interval_addr;
u16 wakeup_threshold_addr;
u16 doze_holdoff_addr;
bool suspended;
bool old_nosleep;
unsigned int num_of_irq_regs;
};
static int rmi_f01_read_properties(struct rmi_device *rmi_dev,
u16 query_base_addr,
struct f01_basic_properties *props)
{
u8 queries[RMI_F01_BASIC_QUERY_LEN];
int ret;
int query_offset = query_base_addr;
bool has_ds4_queries = false;
bool has_query42 = false;
bool has_sensor_id = false;
bool has_package_id_query = false;
bool has_build_id_query = false;
u16 prod_info_addr;
u8 ds4_query_len;
ret = rmi_read_block(rmi_dev, query_offset,
queries, RMI_F01_BASIC_QUERY_LEN);
if (ret) {
dev_err(&rmi_dev->dev,
"Failed to read device query registers: %d\n", ret);
return ret;
}
prod_info_addr = query_offset + 17;
query_offset += RMI_F01_BASIC_QUERY_LEN;
/* Now parse what we got */
props->manufacturer_id = queries[0];
props->has_lts = queries[1] & RMI_F01_QRY1_HAS_LTS;
props->has_adjustable_doze =
queries[1] & RMI_F01_QRY1_HAS_ADJ_DOZE;
props->has_adjustable_doze_holdoff =
queries[1] & RMI_F01_QRY1_HAS_ADJ_DOZE_HOFF;
has_query42 = queries[1] & RMI_F01_QRY1_HAS_QUERY42;
has_sensor_id = queries[1] & RMI_F01_QRY1_HAS_SENSOR_ID;
snprintf(props->dom, sizeof(props->dom), "20%02d/%02d/%02d",
queries[5] & RMI_F01_QRY5_YEAR_MASK,
queries[6] & RMI_F01_QRY6_MONTH_MASK,
queries[7] & RMI_F01_QRY7_DAY_MASK);
memcpy(props->product_id, &queries[11],
RMI_PRODUCT_ID_LENGTH);
props->product_id[RMI_PRODUCT_ID_LENGTH] = '\0';
props->productinfo =
((queries[2] & RMI_F01_QRY2_PRODINFO_MASK) << 7) |
(queries[3] & RMI_F01_QRY2_PRODINFO_MASK);
if (has_sensor_id)
query_offset++;
if (has_query42) {
ret = rmi_read(rmi_dev, query_offset, queries);
if (ret) {
dev_err(&rmi_dev->dev,
"Failed to read query 42 register: %d\n", ret);
return ret;
}
has_ds4_queries = !!(queries[0] & BIT(0));
query_offset++;
}
if (has_ds4_queries) {
ret = rmi_read(rmi_dev, query_offset, &ds4_query_len);
if (ret) {
dev_err(&rmi_dev->dev,
"Failed to read DS4 queries length: %d\n", ret);
return ret;
}
query_offset++;
if (ds4_query_len > 0) {
ret = rmi_read(rmi_dev, query_offset, queries);
if (ret) {
dev_err(&rmi_dev->dev,
"Failed to read DS4 queries: %d\n",
ret);
return ret;
}
has_package_id_query = !!(queries[0] & BIT(0));
has_build_id_query = !!(queries[0] & BIT(1));
}
if (has_package_id_query)
prod_info_addr++;
if (has_build_id_query) {
ret = rmi_read_block(rmi_dev, prod_info_addr, queries,
3);
if (ret) {
dev_err(&rmi_dev->dev,
"Failed to read product info: %d\n",
ret);
return ret;
}
props->firmware_id = queries[1] << 8 | queries[0];
props->firmware_id += queries[2] * 65536;
}
}
return 0;
}
char *rmi_f01_get_product_ID(struct rmi_function *fn)
{
struct f01_data *f01 = dev_get_drvdata(&fn->dev);
return f01->properties.product_id;
}
#ifdef CONFIG_OF
static int rmi_f01_of_probe(struct device *dev,
struct rmi_device_platform_data *pdata)
{
int retval;
u32 val;
retval = rmi_of_property_read_u32(dev,
(u32 *)&pdata->power_management.nosleep,
"syna,nosleep-mode", 1);
if (retval)
return retval;
retval = rmi_of_property_read_u32(dev, &val,
"syna,wakeup-threshold", 1);
if (retval)
return retval;
pdata->power_management.wakeup_threshold = val;
retval = rmi_of_property_read_u32(dev, &val,
"syna,doze-holdoff-ms", 1);
if (retval)
return retval;
pdata->power_management.doze_holdoff = val * 100;
retval = rmi_of_property_read_u32(dev, &val,
"syna,doze-interval-ms", 1);
if (retval)
return retval;
pdata->power_management.doze_interval = val / 10;
return 0;
}
#else
static inline int rmi_f01_of_probe(struct device *dev,
struct rmi_device_platform_data *pdata)
{
return -ENODEV;
}
#endif
static int rmi_f01_probe(struct rmi_function *fn)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *driver_data = dev_get_drvdata(&rmi_dev->dev);
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
struct f01_data *f01;
int error;
u16 ctrl_base_addr = fn->fd.control_base_addr;
u8 device_status;
u8 temp;
if (fn->dev.of_node) {
error = rmi_f01_of_probe(&fn->dev, pdata);
if (error)
return error;
}
f01 = devm_kzalloc(&fn->dev, sizeof(struct f01_data), GFP_KERNEL);
if (!f01)
return -ENOMEM;
f01->num_of_irq_regs = driver_data->num_of_irq_regs;
/*
* Set the configured bit and (optionally) other important stuff
* in the device control register.
*/
error = rmi_read(rmi_dev, fn->fd.control_base_addr,
&f01->device_control.ctrl0);
if (error) {
dev_err(&fn->dev, "Failed to read F01 control: %d\n", error);
return error;
}
switch (pdata->power_management.nosleep) {
case RMI_F01_NOSLEEP_DEFAULT:
break;
case RMI_F01_NOSLEEP_OFF:
f01->device_control.ctrl0 &= ~RMI_F01_CRTL0_NOSLEEP_BIT;
break;
case RMI_F01_NOSLEEP_ON:
f01->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
break;
}
/*
* Sleep mode might be set as a hangover from a system crash or
* reboot without power cycle. If so, clear it so the sensor
* is certain to function.
*/
if ((f01->device_control.ctrl0 & RMI_F01_CTRL0_SLEEP_MODE_MASK) !=
RMI_SLEEP_MODE_NORMAL) {
dev_warn(&fn->dev,
"WARNING: Non-zero sleep mode found. Clearing...\n");
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
}
f01->device_control.ctrl0 |= RMI_F01_CRTL0_CONFIGURED_BIT;
error = rmi_write(rmi_dev, fn->fd.control_base_addr,
f01->device_control.ctrl0);
if (error) {
dev_err(&fn->dev, "Failed to write F01 control: %d\n", error);
return error;
}
/* Dummy read in order to clear irqs */
error = rmi_read(rmi_dev, fn->fd.data_base_addr + 1, &temp);
if (error < 0) {
dev_err(&fn->dev, "Failed to read Interrupt Status.\n");
return error;
}
error = rmi_f01_read_properties(rmi_dev, fn->fd.query_base_addr,
&f01->properties);
if (error < 0) {
dev_err(&fn->dev, "Failed to read F01 properties.\n");
return error;
}
dev_info(&fn->dev, "found RMI device, manufacturer: %s, product: %s, fw id: %d\n",
f01->properties.manufacturer_id == 1 ? "Synaptics" : "unknown",
f01->properties.product_id, f01->properties.firmware_id);
/* Advance to interrupt control registers, then skip over them. */
ctrl_base_addr++;
ctrl_base_addr += f01->num_of_irq_regs;
/* read control register */
if (f01->properties.has_adjustable_doze) {
f01->doze_interval_addr = ctrl_base_addr;
ctrl_base_addr++;
if (pdata->power_management.doze_interval) {
f01->device_control.doze_interval =
pdata->power_management.doze_interval;
error = rmi_write(rmi_dev, f01->doze_interval_addr,
f01->device_control.doze_interval);
if (error) {
dev_err(&fn->dev,
"Failed to configure F01 doze interval register: %d\n",
error);
return error;
}
} else {
error = rmi_read(rmi_dev, f01->doze_interval_addr,
&f01->device_control.doze_interval);
if (error) {
dev_err(&fn->dev,
"Failed to read F01 doze interval register: %d\n",
error);
return error;
}
}
f01->wakeup_threshold_addr = ctrl_base_addr;
ctrl_base_addr++;
if (pdata->power_management.wakeup_threshold) {
f01->device_control.wakeup_threshold =
pdata->power_management.wakeup_threshold;
error = rmi_write(rmi_dev, f01->wakeup_threshold_addr,
f01->device_control.wakeup_threshold);
if (error) {
dev_err(&fn->dev,
"Failed to configure F01 wakeup threshold register: %d\n",
error);
return error;
}
} else {
error = rmi_read(rmi_dev, f01->wakeup_threshold_addr,
&f01->device_control.wakeup_threshold);
if (error < 0) {
dev_err(&fn->dev,
"Failed to read F01 wakeup threshold register: %d\n",
error);
return error;
}
}
}
if (f01->properties.has_lts)
ctrl_base_addr++;
if (f01->properties.has_adjustable_doze_holdoff) {
f01->doze_holdoff_addr = ctrl_base_addr;
ctrl_base_addr++;
if (pdata->power_management.doze_holdoff) {
f01->device_control.doze_holdoff =
pdata->power_management.doze_holdoff;
error = rmi_write(rmi_dev, f01->doze_holdoff_addr,
f01->device_control.doze_holdoff);
if (error) {
dev_err(&fn->dev,
"Failed to configure F01 doze holdoff register: %d\n",
error);
return error;
}
} else {
error = rmi_read(rmi_dev, f01->doze_holdoff_addr,
&f01->device_control.doze_holdoff);
if (error) {
dev_err(&fn->dev,
"Failed to read F01 doze holdoff register: %d\n",
error);
return error;
}
}
}
error = rmi_read(rmi_dev, fn->fd.data_base_addr, &device_status);
if (error < 0) {
dev_err(&fn->dev,
"Failed to read device status: %d\n", error);
return error;
}
if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
dev_err(&fn->dev,
"Device was reset during configuration process, status: %#02x!\n",
RMI_F01_STATUS_CODE(device_status));
return -EINVAL;
}
dev_set_drvdata(&fn->dev, f01);
return 0;
}
static int rmi_f01_config(struct rmi_function *fn)
{
struct f01_data *f01 = dev_get_drvdata(&fn->dev);
int error;
error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr,
f01->device_control.ctrl0);
if (error) {
dev_err(&fn->dev,
"Failed to write device_control register: %d\n", error);
return error;
}
if (f01->properties.has_adjustable_doze) {
error = rmi_write(fn->rmi_dev, f01->doze_interval_addr,
f01->device_control.doze_interval);
if (error) {
dev_err(&fn->dev,
"Failed to write doze interval: %d\n", error);
return error;
}
error = rmi_write_block(fn->rmi_dev,
f01->wakeup_threshold_addr,
&f01->device_control.wakeup_threshold,
sizeof(u8));
if (error) {
dev_err(&fn->dev,
"Failed to write wakeup threshold: %d\n",
error);
return error;
}
}
if (f01->properties.has_adjustable_doze_holdoff) {
error = rmi_write(fn->rmi_dev, f01->doze_holdoff_addr,
f01->device_control.doze_holdoff);
if (error) {
dev_err(&fn->dev,
"Failed to write doze holdoff: %d\n", error);
return error;
}
}
return 0;
}
static int rmi_f01_suspend(struct rmi_function *fn)
{
struct f01_data *f01 = dev_get_drvdata(&fn->dev);
int error;
f01->old_nosleep =
f01->device_control.ctrl0 & RMI_F01_CRTL0_NOSLEEP_BIT;
f01->device_control.ctrl0 &= ~RMI_F01_CRTL0_NOSLEEP_BIT;
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
if (device_may_wakeup(fn->rmi_dev->xport->dev))
f01->device_control.ctrl0 |= RMI_SLEEP_MODE_RESERVED1;
else
f01->device_control.ctrl0 |= RMI_SLEEP_MODE_SENSOR_SLEEP;
error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr,
f01->device_control.ctrl0);
if (error) {
dev_err(&fn->dev, "Failed to write sleep mode: %d.\n", error);
if (f01->old_nosleep)
f01->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL;
return error;
}
return 0;
}
static int rmi_f01_resume(struct rmi_function *fn)
{
struct f01_data *f01 = dev_get_drvdata(&fn->dev);
int error;
if (f01->old_nosleep)
f01->device_control.ctrl0 |= RMI_F01_CRTL0_NOSLEEP_BIT;
f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_SLEEP_MODE_MASK;
f01->device_control.ctrl0 |= RMI_SLEEP_MODE_NORMAL;
error = rmi_write(fn->rmi_dev, fn->fd.control_base_addr,
f01->device_control.ctrl0);
if (error) {
dev_err(&fn->dev,
"Failed to restore normal operation: %d.\n", error);
return error;
}
return 0;
}
static int rmi_f01_attention(struct rmi_function *fn,
unsigned long *irq_bits)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
int error;
u8 device_status;
error = rmi_read(rmi_dev, fn->fd.data_base_addr, &device_status);
if (error) {
dev_err(&fn->dev,
"Failed to read device status: %d.\n", error);
return error;
}
if (RMI_F01_STATUS_UNCONFIGURED(device_status)) {
dev_warn(&fn->dev, "Device reset detected.\n");
error = rmi_dev->driver->reset_handler(rmi_dev);
if (error) {
dev_err(&fn->dev, "Device reset failed: %d\n", error);
return error;
}
}
return 0;
}
struct rmi_function_handler rmi_f01_handler = {
.driver = {
.name = "rmi4_f01",
/*
* Do not allow user unbinding F01 as it is critical
* function.
*/
.suppress_bind_attrs = true,
},
.func = 0x01,
.probe = rmi_f01_probe,
.config = rmi_f01_config,
.attention = rmi_f01_attention,
.suspend = rmi_f01_suspend,
.resume = rmi_f01_resume,
};

1317
drivers/input/rmi4/rmi_f11.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,457 @@
/*
* 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/input.h>
#include <linux/input/mt.h>
#include <linux/rmi.h>
#include "rmi_driver.h"
#include "rmi_2d_sensor.h"
enum rmi_f12_object_type {
RMI_F12_OBJECT_NONE = 0x00,
RMI_F12_OBJECT_FINGER = 0x01,
RMI_F12_OBJECT_STYLUS = 0x02,
RMI_F12_OBJECT_PALM = 0x03,
RMI_F12_OBJECT_UNCLASSIFIED = 0x04,
RMI_F12_OBJECT_GLOVED_FINGER = 0x06,
RMI_F12_OBJECT_NARROW_OBJECT = 0x07,
RMI_F12_OBJECT_HAND_EDGE = 0x08,
RMI_F12_OBJECT_COVER = 0x0A,
RMI_F12_OBJECT_STYLUS_2 = 0x0B,
RMI_F12_OBJECT_ERASER = 0x0C,
RMI_F12_OBJECT_SMALL_OBJECT = 0x0D,
};
struct f12_data {
struct rmi_function *fn;
struct rmi_2d_sensor sensor;
struct rmi_2d_sensor_platform_data sensor_pdata;
u16 data_addr;
struct rmi_register_descriptor query_reg_desc;
struct rmi_register_descriptor control_reg_desc;
struct rmi_register_descriptor data_reg_desc;
/* F12 Data1 describes sensed objects */
const struct rmi_register_desc_item *data1;
u16 data1_offset;
/* F12 Data5 describes finger ACM */
const struct rmi_register_desc_item *data5;
u16 data5_offset;
/* F12 Data5 describes Pen */
const struct rmi_register_desc_item *data6;
u16 data6_offset;
/* F12 Data9 reports relative data */
const struct rmi_register_desc_item *data9;
u16 data9_offset;
const struct rmi_register_desc_item *data15;
u16 data15_offset;
};
static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
{
const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor = &f12->sensor;
struct rmi_function *fn = sensor->fn;
struct rmi_device *rmi_dev = fn->rmi_dev;
int ret;
int offset;
u8 buf[14];
int pitch_x = 0;
int pitch_y = 0;
int clip_x_low = 0;
int clip_x_high = 0;
int clip_y_low = 0;
int clip_y_high = 0;
int rx_receivers = 0;
int tx_receivers = 0;
int sensor_flags = 0;
item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
if (!item) {
dev_err(&fn->dev,
"F12 does not have the sensor tuning control register\n");
return -ENODEV;
}
offset = rmi_register_desc_calc_reg_offset(&f12->control_reg_desc, 8);
if (item->reg_size > 14) {
dev_err(&fn->dev, "F12 control8 should be 14 bytes, not: %ld\n",
item->reg_size);
return -ENODEV;
}
ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + offset, buf,
item->reg_size);
if (ret)
return ret;
offset = 0;
if (rmi_register_desc_has_subpacket(item, 0)) {
sensor->max_x = (buf[offset + 1] << 8) | buf[offset];
sensor->max_y = (buf[offset + 3] << 8) | buf[offset + 2];
offset += 4;
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: max_x: %d max_y: %d\n", __func__,
sensor->max_x, sensor->max_y);
if (rmi_register_desc_has_subpacket(item, 1)) {
pitch_x = (buf[offset + 1] << 8) | buf[offset];
pitch_y = (buf[offset + 3] << 8) | buf[offset + 2];
offset += 4;
}
if (rmi_register_desc_has_subpacket(item, 2)) {
sensor->axis_align.clip_x_low = buf[offset];
sensor->axis_align.clip_x_high = sensor->max_x
- buf[offset + 1];
sensor->axis_align.clip_y_low = buf[offset + 2];
sensor->axis_align.clip_y_high = sensor->max_y
- buf[offset + 3];
offset += 4;
}
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n",
__func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high);
if (rmi_register_desc_has_subpacket(item, 3)) {
rx_receivers = buf[offset];
tx_receivers = buf[offset + 1];
offset += 2;
}
if (rmi_register_desc_has_subpacket(item, 4)) {
sensor_flags = buf[offset];
offset += 1;
}
sensor->x_mm = (pitch_x * rx_receivers) >> 12;
sensor->y_mm = (pitch_y * tx_receivers) >> 12;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x_mm: %d y_mm: %d\n", __func__,
sensor->x_mm, sensor->y_mm);
return 0;
}
static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1)
{
int i;
struct rmi_2d_sensor *sensor = &f12->sensor;
for (i = 0; i < f12->data1->num_subpackets; i++) {
struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i];
obj->type = RMI_2D_OBJECT_NONE;
obj->mt_tool = MT_TOOL_FINGER;
switch (data1[0]) {
case RMI_F12_OBJECT_FINGER:
obj->type = RMI_2D_OBJECT_FINGER;
break;
case RMI_F12_OBJECT_STYLUS:
obj->type = RMI_2D_OBJECT_STYLUS;
obj->mt_tool = MT_TOOL_PEN;
break;
case RMI_F12_OBJECT_PALM:
obj->type = RMI_2D_OBJECT_PALM;
obj->mt_tool = MT_TOOL_PALM;
break;
case RMI_F12_OBJECT_UNCLASSIFIED:
obj->type = RMI_2D_OBJECT_UNCLASSIFIED;
break;
}
obj->x = (data1[2] << 8) | data1[1];
obj->y = (data1[4] << 8) | data1[3];
obj->z = data1[5];
obj->wx = data1[6];
obj->wy = data1[7];
rmi_2d_sensor_abs_process(sensor, obj, i);
data1 += 8;
}
if (sensor->kernel_tracking)
input_mt_assign_slots(sensor->input,
sensor->tracking_slots,
sensor->tracking_pos,
sensor->nbr_fingers,
sensor->dmax);
for (i = 0; i < sensor->nbr_fingers; i++)
rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i);
}
static int rmi_f12_attention(struct rmi_function *fn,
unsigned long *irq_nr_regs)
{
int retval;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct f12_data *f12 = dev_get_drvdata(&fn->dev);
struct rmi_2d_sensor *sensor = &f12->sensor;
if (rmi_dev->xport->attn_data) {
memcpy(sensor->data_pkt, rmi_dev->xport->attn_data,
sensor->attn_size);
rmi_dev->xport->attn_data += sensor->attn_size;
rmi_dev->xport->attn_size -= sensor->attn_size;
} else {
retval = rmi_read_block(rmi_dev, f12->data_addr,
sensor->data_pkt, sensor->pkt_size);
if (retval < 0) {
dev_err(&fn->dev, "Failed to read object data. Code: %d.\n",
retval);
return retval;
}
}
if (f12->data1)
rmi_f12_process_objects(f12,
&sensor->data_pkt[f12->data1_offset]);
input_mt_sync_frame(sensor->input);
return 0;
}
static int rmi_f12_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_f12_probe(struct rmi_function *fn)
{
struct f12_data *f12;
int ret;
struct rmi_device *rmi_dev = fn->rmi_dev;
char buf;
u16 query_addr = fn->fd.query_base_addr;
const struct rmi_register_desc_item *item;
struct rmi_2d_sensor *sensor;
struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev);
struct rmi_transport_dev *xport = rmi_dev->xport;
u16 data_offset = 0;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__);
ret = rmi_read(fn->rmi_dev, query_addr, &buf);
if (ret < 0) {
dev_err(&fn->dev, "Failed to read general info register: %d\n",
ret);
return -ENODEV;
}
++query_addr;
if (!(buf & 0x1)) {
dev_err(&fn->dev,
"Behavior of F12 without register descriptors is undefined.\n");
return -ENODEV;
}
f12 = devm_kzalloc(&fn->dev, sizeof(struct f12_data), GFP_KERNEL);
if (!f12)
return -ENOMEM;
if (fn->dev.of_node) {
ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata);
if (ret)
return ret;
} else if (pdata->sensor_pdata) {
f12->sensor_pdata = *pdata->sensor_pdata;
}
ret = rmi_read_register_desc(rmi_dev, query_addr,
&f12->query_reg_desc);
if (ret) {
dev_err(&fn->dev,
"Failed to read the Query Register Descriptor: %d\n",
ret);
return ret;
}
query_addr += 3;
ret = rmi_read_register_desc(rmi_dev, query_addr,
&f12->control_reg_desc);
if (ret) {
dev_err(&fn->dev,
"Failed to read the Control Register Descriptor: %d\n",
ret);
return ret;
}
query_addr += 3;
ret = rmi_read_register_desc(rmi_dev, query_addr,
&f12->data_reg_desc);
if (ret) {
dev_err(&fn->dev,
"Failed to read the Data Register Descriptor: %d\n",
ret);
return ret;
}
query_addr += 3;
sensor = &f12->sensor;
sensor->fn = fn;
f12->data_addr = fn->fd.data_base_addr;
sensor->pkt_size = rmi_register_desc_calc_size(&f12->data_reg_desc);
sensor->axis_align =
f12->sensor_pdata.axis_align;
sensor->x_mm = f12->sensor_pdata.x_mm;
sensor->y_mm = f12->sensor_pdata.y_mm;
if (sensor->sensor_type == rmi_sensor_default)
sensor->sensor_type =
f12->sensor_pdata.sensor_type;
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: data packet size: %d\n", __func__,
sensor->pkt_size);
sensor->data_pkt = devm_kzalloc(&fn->dev, sensor->pkt_size, GFP_KERNEL);
if (!sensor->data_pkt)
return -ENOMEM;
dev_set_drvdata(&fn->dev, f12);
ret = rmi_f12_read_sensor_tuning(f12);
if (ret)
return ret;
/*
* Figure out what data is contained in the data registers. HID devices
* may have registers defined, but their data is not reported in the
* HID attention report. Registers which are not reported in the HID
* attention report check to see if the device is receiving data from
* HID attention reports.
*/
item = rmi_get_register_desc_item(&f12->data_reg_desc, 0);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 1);
if (item) {
f12->data1 = item;
f12->data1_offset = data_offset;
data_offset += item->reg_size;
sensor->nbr_fingers = item->num_subpackets;
sensor->report_abs = 1;
sensor->attn_size += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 2);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 3);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 4);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 5);
if (item) {
f12->data5 = item;
f12->data5_offset = data_offset;
data_offset += item->reg_size;
sensor->attn_size += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 6);
if (item && !xport->attn_data) {
f12->data6 = item;
f12->data6_offset = data_offset;
data_offset += item->reg_size;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 7);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 8);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 9);
if (item && !xport->attn_data) {
f12->data9 = item;
f12->data9_offset = data_offset;
data_offset += item->reg_size;
if (!sensor->report_abs)
sensor->report_rel = 1;
}
item = rmi_get_register_desc_item(&f12->data_reg_desc, 10);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 11);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 12);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 13);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 14);
if (item && !xport->attn_data)
data_offset += item->reg_size;
item = rmi_get_register_desc_item(&f12->data_reg_desc, 15);
if (item && !xport->attn_data) {
f12->data15 = item;
f12->data15_offset = data_offset;
data_offset += item->reg_size;
}
/* allocate the in-kernel tracking buffers */
sensor->tracking_pos = devm_kzalloc(&fn->dev,
sizeof(struct input_mt_pos) * sensor->nbr_fingers,
GFP_KERNEL);
sensor->tracking_slots = devm_kzalloc(&fn->dev,
sizeof(int) * sensor->nbr_fingers, GFP_KERNEL);
sensor->objs = devm_kzalloc(&fn->dev,
sizeof(struct rmi_2d_sensor_abs_object)
* sensor->nbr_fingers, GFP_KERNEL);
if (!sensor->tracking_pos || !sensor->tracking_slots || !sensor->objs)
return -ENOMEM;
ret = rmi_2d_sensor_configure_input(fn, sensor);
if (ret)
return ret;
return 0;
}
struct rmi_function_handler rmi_f12_handler = {
.driver = {
.name = "rmi4_f12",
},
.func = 0x12,
.probe = rmi_f12_probe,
.config = rmi_f12_config,
.attention = rmi_f12_attention,
};

View File

@ -0,0 +1,407 @@
/*
* 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 (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
struct rmi_f30_ctrl_data {
int address;
int length;
u8 *regs;
};
#define RMI_F30_CTRL_MAX_REGS 32
#define RMI_F30_CTRL_MAX_BYTES ((RMI_F30_CTRL_MAX_REGS + 7) >> 3)
#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)
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;
};
static int rmi_f30_read_control_parameters(struct rmi_function *fn,
struct f30_data *f30)
{
struct rmi_device *rmi_dev = fn->rmi_dev;
int error = 0;
error = rmi_read_block(rmi_dev, fn->fd.control_base_addr,
f30->ctrl_regs, f30->ctrl_regs_size);
if (error) {
dev_err(&rmi_dev->dev, "%s : Could not read control registers at 0x%x error (%d)\n",
__func__, fn->fd.control_base_addr, error);
return error;
}
return 0;
}
static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits)
{
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct rmi_device *rmi_dev = fn->rmi_dev;
int retval;
int gpiled = 0;
int value = 0;
int i;
int reg_num;
if (!f30->input)
return 0;
/* Read the gpi led data. */
if (rmi_dev->xport->attn_data) {
memcpy(f30->data_regs, rmi_dev->xport->attn_data,
f30->register_count);
rmi_dev->xport->attn_data += f30->register_count;
rmi_dev->xport->attn_size -= f30->register_count;
} else {
retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr,
f30->data_regs, f30->register_count);
if (retval) {
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_key_map[gpiled] != 0) {
/* buttons have pull up resistors */
value = (((f30->data_regs[reg_num] >> i) & 0x01)
== 0);
rmi_dbg(RMI_DEBUG_FN, &fn->dev,
"%s: call input report key (0x%04x) value (0x%02x)",
__func__,
f30->gpioled_key_map[gpiled], value);
input_report_key(f30->input,
f30->gpioled_key_map[gpiled],
value);
}
}
}
return 0;
}
static int rmi_f30_register_device(struct rmi_function *fn)
{
int i;
struct rmi_device *rmi_dev = fn->rmi_dev;
struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
struct f30_data *f30 = dev_get_drvdata(&fn->dev);
struct input_dev *input_dev;
int button_count = 0;
input_dev = drv_data->input;
if (!input_dev) {
dev_info(&fn->dev, "F30: no input device found, ignoring.\n");
return -EINVAL;
}
f30->input = input_dev;
set_bit(EV_KEY, input_dev->evbit);
input_dev->keycode = f30->gpioled_key_map;
input_dev->keycodesize = sizeof(u16);
input_dev->keycodemax = f30->gpioled_count;
for (i = 0; i < f30->gpioled_count; i++) {
if (f30->gpioled_key_map[i] != 0) {
input_set_capability(input_dev, EV_KEY,
f30->gpioled_key_map[i]);
button_count++;
}
}
if (button_count == 1)
__set_bit(INPUT_PROP_BUTTONPAD, input_dev->propbit);
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 && 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->rmi_dev->dev,
"%s : Could not write control registers at 0x%x error (%d)\n",
__func__, fn->fd.control_base_addr, error);
return error;
}
drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
}
return 0;
}
static inline 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 inline 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 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;
int i;
int button;
u8 buf[RMI_F30_QUERY_SIZE];
u8 *ctrl_reg;
u8 *map_memory;
f30 = devm_kzalloc(&fn->dev, sizeof(struct f30_data),
GFP_KERNEL);
if (!f30)
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) {
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;
ctrl_reg = f30->ctrl_regs;
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) {
int ctrl5_len;
rmi_f30_set_ctrl_data(&f30->ctrl[4], &control_address,
f30->register_count, &ctrl_reg);
if (f30->has_extended_pattern)
ctrl5_len = 6;
else
ctrl5_len = 2;
rmi_f30_set_ctrl_data(&f30->ctrl[5], &control_address,
ctrl5_len, &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;
retval = rmi_f30_read_control_parameters(fn, f30);
if (retval < 0) {
dev_err(&fn->dev,
"Failed to initialize F19 control params.\n");
return retval;
}
map_memory = devm_kzalloc(&fn->dev,
(f30->gpioled_count * (sizeof(u16))),
GFP_KERNEL);
if (!map_memory) {
dev_err(&fn->dev, "Failed to allocate gpioled map memory.\n");
return -ENOMEM;
}
f30->gpioled_key_map = (u16 *)map_memory;
pdata = rmi_get_platform_data(rmi_dev);
if (pdata && f30->has_gpio) {
button = BTN_LEFT;
for (i = 0; i < f30->gpioled_count; i++) {
if (rmi_f30_is_valid_button(i, f30->ctrl)) {
f30->gpioled_key_map[i] = button++;
/*
* buttonpad might be given by
* f30->has_mech_mouse_btns, but I am
* not sure, so use only the pdata info
*/
if (pdata->f30_data &&
pdata->f30_data->buttonpad)
break;
}
}
}
return 0;
}
static int rmi_f30_probe(struct rmi_function *fn)
{
int rc;
const struct rmi_device_platform_data *pdata =
rmi_get_platform_data(fn->rmi_dev);
if (pdata->f30_data && pdata->f30_data->disable)
return 0;
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;
}
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,
};

View File

@ -0,0 +1,397 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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/i2c.h>
#include <linux/rmi.h>
#include <linux/irq.h>
#include <linux/of.h>
#include "rmi_driver.h"
#define BUFFER_SIZE_INCREMENT 32
/**
* struct rmi_i2c_xport - stores information for i2c communication
*
* @xport: The transport interface structure
*
* @page_mutex: Locks current page to avoid changing pages in unexpected ways.
* @page: Keeps track of the current virtual page
*
* @tx_buf: Buffer used for transmitting data to the sensor over i2c.
* @tx_buf_size: Size of the buffer
*/
struct rmi_i2c_xport {
struct rmi_transport_dev xport;
struct i2c_client *client;
struct mutex page_mutex;
int page;
int irq;
u8 *tx_buf;
size_t tx_buf_size;
};
#define RMI_PAGE_SELECT_REGISTER 0xff
#define RMI_I2C_PAGE(addr) (((addr) >> 8) & 0xff)
/*
* rmi_set_page - Set RMI page
* @xport: The pointer to the rmi_transport_dev struct
* @page: The new page address.
*
* RMI devices have 16-bit addressing, but some of the transport
* implementations (like SMBus) only have 8-bit addressing. So RMI implements
* a page address at 0xff of every page so we can reliable page addresses
* every 256 registers.
*
* The page_mutex lock must be held when this function is entered.
*
* Returns zero on success, non-zero on failure.
*/
static int rmi_set_page(struct rmi_i2c_xport *rmi_i2c, u8 page)
{
struct i2c_client *client = rmi_i2c->client;
u8 txbuf[2] = {RMI_PAGE_SELECT_REGISTER, page};
int retval;
retval = i2c_master_send(client, txbuf, sizeof(txbuf));
if (retval != sizeof(txbuf)) {
dev_err(&client->dev,
"%s: set page failed: %d.", __func__, retval);
return (retval < 0) ? retval : -EIO;
}
rmi_i2c->page = page;
return 0;
}
static int rmi_i2c_write_block(struct rmi_transport_dev *xport, u16 addr,
const void *buf, size_t len)
{
struct rmi_i2c_xport *rmi_i2c =
container_of(xport, struct rmi_i2c_xport, xport);
struct i2c_client *client = rmi_i2c->client;
size_t tx_size = len + 1;
int retval;
mutex_lock(&rmi_i2c->page_mutex);
if (!rmi_i2c->tx_buf || rmi_i2c->tx_buf_size < tx_size) {
if (rmi_i2c->tx_buf)
devm_kfree(&client->dev, rmi_i2c->tx_buf);
rmi_i2c->tx_buf_size = tx_size + BUFFER_SIZE_INCREMENT;
rmi_i2c->tx_buf = devm_kzalloc(&client->dev,
rmi_i2c->tx_buf_size,
GFP_KERNEL);
if (!rmi_i2c->tx_buf) {
rmi_i2c->tx_buf_size = 0;
retval = -ENOMEM;
goto exit;
}
}
rmi_i2c->tx_buf[0] = addr & 0xff;
memcpy(rmi_i2c->tx_buf + 1, buf, len);
if (RMI_I2C_PAGE(addr) != rmi_i2c->page) {
retval = rmi_set_page(rmi_i2c, RMI_I2C_PAGE(addr));
if (retval)
goto exit;
}
retval = i2c_master_send(client, rmi_i2c->tx_buf, tx_size);
if (retval == tx_size)
retval = 0;
else if (retval >= 0)
retval = -EIO;
exit:
rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
"write %zd bytes at %#06x: %d (%*ph)\n",
len, addr, retval, (int)len, buf);
mutex_unlock(&rmi_i2c->page_mutex);
return retval;
}
static int rmi_i2c_read_block(struct rmi_transport_dev *xport, u16 addr,
void *buf, size_t len)
{
struct rmi_i2c_xport *rmi_i2c =
container_of(xport, struct rmi_i2c_xport, xport);
struct i2c_client *client = rmi_i2c->client;
u8 addr_offset = addr & 0xff;
int retval;
struct i2c_msg msgs[] = {
{
.addr = client->addr,
.len = sizeof(addr_offset),
.buf = &addr_offset,
},
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = len,
.buf = buf,
},
};
mutex_lock(&rmi_i2c->page_mutex);
if (RMI_I2C_PAGE(addr) != rmi_i2c->page) {
retval = rmi_set_page(rmi_i2c, RMI_I2C_PAGE(addr));
if (retval)
goto exit;
}
retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (retval == ARRAY_SIZE(msgs))
retval = 0; /* success */
else if (retval >= 0)
retval = -EIO;
exit:
rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
"read %zd bytes at %#06x: %d (%*ph)\n",
len, addr, retval, (int)len, buf);
mutex_unlock(&rmi_i2c->page_mutex);
return retval;
}
static const struct rmi_transport_ops rmi_i2c_ops = {
.write_block = rmi_i2c_write_block,
.read_block = rmi_i2c_read_block,
};
static irqreturn_t rmi_i2c_irq(int irq, void *dev_id)
{
struct rmi_i2c_xport *rmi_i2c = dev_id;
struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev;
int ret;
ret = rmi_process_interrupt_requests(rmi_dev);
if (ret)
rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
"Failed to process interrupt request: %d\n", ret);
return IRQ_HANDLED;
}
static int rmi_i2c_init_irq(struct i2c_client *client)
{
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq));
int ret;
if (!irq_flags)
irq_flags = IRQF_TRIGGER_LOW;
ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL,
rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name,
rmi_i2c);
if (ret < 0) {
dev_warn(&client->dev, "Failed to register interrupt %d\n",
rmi_i2c->irq);
return ret;
}
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id rmi_i2c_of_match[] = {
{ .compatible = "syna,rmi4-i2c" },
{},
};
MODULE_DEVICE_TABLE(of, rmi_i2c_of_match);
#endif
static int rmi_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct rmi_device_platform_data *pdata;
struct rmi_device_platform_data *client_pdata =
dev_get_platdata(&client->dev);
struct rmi_i2c_xport *rmi_i2c;
int retval;
rmi_i2c = devm_kzalloc(&client->dev, sizeof(struct rmi_i2c_xport),
GFP_KERNEL);
if (!rmi_i2c)
return -ENOMEM;
pdata = &rmi_i2c->xport.pdata;
if (!client->dev.of_node && client_pdata)
*pdata = *client_pdata;
if (client->irq > 0)
rmi_i2c->irq = client->irq;
rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
dev_name(&client->dev));
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev,
"adapter does not support required functionality.\n");
return -ENODEV;
}
rmi_i2c->client = client;
mutex_init(&rmi_i2c->page_mutex);
rmi_i2c->xport.dev = &client->dev;
rmi_i2c->xport.proto_name = "i2c";
rmi_i2c->xport.ops = &rmi_i2c_ops;
i2c_set_clientdata(client, rmi_i2c);
/*
* Setting the page to zero will (a) make sure the PSR is in a
* known state, and (b) make sure we can talk to the device.
*/
retval = rmi_set_page(rmi_i2c, 0);
if (retval) {
dev_err(&client->dev, "Failed to set page select to 0.\n");
return retval;
}
retval = rmi_register_transport_device(&rmi_i2c->xport);
if (retval) {
dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
client->addr);
return retval;
}
retval = rmi_i2c_init_irq(client);
if (retval < 0)
return retval;
dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n",
client->addr);
return 0;
}
static int rmi_i2c_remove(struct i2c_client *client)
{
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
rmi_unregister_transport_device(&rmi_i2c->xport);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rmi_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
disable_irq(rmi_i2c->irq);
if (device_may_wakeup(&client->dev)) {
ret = enable_irq_wake(rmi_i2c->irq);
if (!ret)
dev_warn(dev, "Failed to enable irq for wake: %d\n",
ret);
}
return ret;
}
static int rmi_i2c_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
enable_irq(rmi_i2c->irq);
if (device_may_wakeup(&client->dev)) {
ret = disable_irq_wake(rmi_i2c->irq);
if (!ret)
dev_warn(dev, "Failed to disable irq for wake: %d\n",
ret);
}
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
return ret;
}
#endif
#ifdef CONFIG_PM
static int rmi_i2c_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
disable_irq(rmi_i2c->irq);
return 0;
}
static int rmi_i2c_runtime_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
int ret;
enable_irq(rmi_i2c->irq);
ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
return 0;
}
#endif
static const struct dev_pm_ops rmi_i2c_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rmi_i2c_suspend, rmi_i2c_resume)
SET_RUNTIME_PM_OPS(rmi_i2c_runtime_suspend, rmi_i2c_runtime_resume,
NULL)
};
static const struct i2c_device_id rmi_id[] = {
{ "rmi4_i2c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rmi_id);
static struct i2c_driver rmi_i2c_driver = {
.driver = {
.name = "rmi4_i2c",
.pm = &rmi_i2c_pm,
.of_match_table = of_match_ptr(rmi_i2c_of_match),
},
.id_table = rmi_id,
.probe = rmi_i2c_probe,
.remove = rmi_i2c_remove,
};
module_i2c_driver(rmi_i2c_driver);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
MODULE_DESCRIPTION("RMI I2C driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

View File

@ -0,0 +1,589 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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/module.h>
#include <linux/rmi.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/irq.h>
#include <linux/of.h>
#include "rmi_driver.h"
#define RMI_SPI_DEFAULT_XFER_BUF_SIZE 64
#define RMI_PAGE_SELECT_REGISTER 0x00FF
#define RMI_SPI_PAGE(addr) (((addr) >> 8) & 0x80)
#define RMI_SPI_XFER_SIZE_LIMIT 255
#define BUFFER_SIZE_INCREMENT 32
enum rmi_spi_op {
RMI_SPI_WRITE = 0,
RMI_SPI_READ,
RMI_SPI_V2_READ_UNIFIED,
RMI_SPI_V2_READ_SPLIT,
RMI_SPI_V2_WRITE,
};
struct rmi_spi_cmd {
enum rmi_spi_op op;
u16 addr;
};
struct rmi_spi_xport {
struct rmi_transport_dev xport;
struct spi_device *spi;
struct mutex page_mutex;
int page;
int irq;
u8 *rx_buf;
u8 *tx_buf;
int xfer_buf_size;
struct spi_transfer *rx_xfers;
struct spi_transfer *tx_xfers;
int rx_xfer_count;
int tx_xfer_count;
};
static int rmi_spi_manage_pools(struct rmi_spi_xport *rmi_spi, int len)
{
struct spi_device *spi = rmi_spi->spi;
int buf_size = rmi_spi->xfer_buf_size
? rmi_spi->xfer_buf_size : RMI_SPI_DEFAULT_XFER_BUF_SIZE;
struct spi_transfer *xfer_buf;
void *buf;
void *tmp;
while (buf_size < len)
buf_size *= 2;
if (buf_size > RMI_SPI_XFER_SIZE_LIMIT)
buf_size = RMI_SPI_XFER_SIZE_LIMIT;
tmp = rmi_spi->rx_buf;
buf = devm_kzalloc(&spi->dev, buf_size * 2,
GFP_KERNEL | GFP_DMA);
if (!buf)
return -ENOMEM;
rmi_spi->rx_buf = buf;
rmi_spi->tx_buf = &rmi_spi->rx_buf[buf_size];
rmi_spi->xfer_buf_size = buf_size;
if (tmp)
devm_kfree(&spi->dev, tmp);
if (rmi_spi->xport.pdata.spi_data.read_delay_us)
rmi_spi->rx_xfer_count = buf_size;
else
rmi_spi->rx_xfer_count = 1;
if (rmi_spi->xport.pdata.spi_data.write_delay_us)
rmi_spi->tx_xfer_count = buf_size;
else
rmi_spi->tx_xfer_count = 1;
/*
* Allocate a pool of spi_transfer buffers for devices which need
* per byte delays.
*/
tmp = rmi_spi->rx_xfers;
xfer_buf = devm_kzalloc(&spi->dev,
(rmi_spi->rx_xfer_count + rmi_spi->tx_xfer_count)
* sizeof(struct spi_transfer), GFP_KERNEL);
if (!xfer_buf)
return -ENOMEM;
rmi_spi->rx_xfers = xfer_buf;
rmi_spi->tx_xfers = &xfer_buf[rmi_spi->rx_xfer_count];
if (tmp)
devm_kfree(&spi->dev, tmp);
return 0;
}
static int rmi_spi_xfer(struct rmi_spi_xport *rmi_spi,
const struct rmi_spi_cmd *cmd, const u8 *tx_buf,
int tx_len, u8 *rx_buf, int rx_len)
{
struct spi_device *spi = rmi_spi->spi;
struct rmi_device_platform_data_spi *spi_data =
&rmi_spi->xport.pdata.spi_data;
struct spi_message msg;
struct spi_transfer *xfer;
int ret = 0;
int len;
int cmd_len = 0;
int total_tx_len;
int i;
u16 addr = cmd->addr;
spi_message_init(&msg);
switch (cmd->op) {
case RMI_SPI_WRITE:
case RMI_SPI_READ:
cmd_len += 2;
break;
case RMI_SPI_V2_READ_UNIFIED:
case RMI_SPI_V2_READ_SPLIT:
case RMI_SPI_V2_WRITE:
cmd_len += 4;
break;
}
total_tx_len = cmd_len + tx_len;
len = max(total_tx_len, rx_len);
if (len > RMI_SPI_XFER_SIZE_LIMIT)
return -EINVAL;
if (rmi_spi->xfer_buf_size < len)
rmi_spi_manage_pools(rmi_spi, len);
if (addr == 0)
/*
* SPI needs an address. Use 0x7FF if we want to keep
* reading from the last position of the register pointer.
*/
addr = 0x7FF;
switch (cmd->op) {
case RMI_SPI_WRITE:
rmi_spi->tx_buf[0] = (addr >> 8);
rmi_spi->tx_buf[1] = addr & 0xFF;
break;
case RMI_SPI_READ:
rmi_spi->tx_buf[0] = (addr >> 8) | 0x80;
rmi_spi->tx_buf[1] = addr & 0xFF;
break;
case RMI_SPI_V2_READ_UNIFIED:
break;
case RMI_SPI_V2_READ_SPLIT:
break;
case RMI_SPI_V2_WRITE:
rmi_spi->tx_buf[0] = 0x40;
rmi_spi->tx_buf[1] = (addr >> 8) & 0xFF;
rmi_spi->tx_buf[2] = addr & 0xFF;
rmi_spi->tx_buf[3] = tx_len;
break;
}
if (tx_buf)
memcpy(&rmi_spi->tx_buf[cmd_len], tx_buf, tx_len);
if (rmi_spi->tx_xfer_count > 1) {
for (i = 0; i < total_tx_len; i++) {
xfer = &rmi_spi->tx_xfers[i];
memset(xfer, 0, sizeof(struct spi_transfer));
xfer->tx_buf = &rmi_spi->tx_buf[i];
xfer->len = 1;
xfer->delay_usecs = spi_data->write_delay_us;
spi_message_add_tail(xfer, &msg);
}
} else {
xfer = rmi_spi->tx_xfers;
memset(xfer, 0, sizeof(struct spi_transfer));
xfer->tx_buf = rmi_spi->tx_buf;
xfer->len = total_tx_len;
spi_message_add_tail(xfer, &msg);
}
rmi_dbg(RMI_DEBUG_XPORT, &spi->dev, "%s: cmd: %s tx_buf len: %d tx_buf: %*ph\n",
__func__, cmd->op == RMI_SPI_WRITE ? "WRITE" : "READ",
total_tx_len, total_tx_len, rmi_spi->tx_buf);
if (rx_buf) {
if (rmi_spi->rx_xfer_count > 1) {
for (i = 0; i < rx_len; i++) {
xfer = &rmi_spi->rx_xfers[i];
memset(xfer, 0, sizeof(struct spi_transfer));
xfer->rx_buf = &rmi_spi->rx_buf[i];
xfer->len = 1;
xfer->delay_usecs = spi_data->read_delay_us;
spi_message_add_tail(xfer, &msg);
}
} else {
xfer = rmi_spi->rx_xfers;
memset(xfer, 0, sizeof(struct spi_transfer));
xfer->rx_buf = rmi_spi->rx_buf;
xfer->len = rx_len;
spi_message_add_tail(xfer, &msg);
}
}
ret = spi_sync(spi, &msg);
if (ret < 0) {
dev_err(&spi->dev, "spi xfer failed: %d\n", ret);
return ret;
}
if (rx_buf) {
memcpy(rx_buf, rmi_spi->rx_buf, rx_len);
rmi_dbg(RMI_DEBUG_XPORT, &spi->dev, "%s: (%d) %*ph\n",
__func__, rx_len, rx_len, rx_buf);
}
return 0;
}
/*
* rmi_set_page - Set RMI page
* @xport: The pointer to the rmi_transport_dev struct
* @page: The new page address.
*
* RMI devices have 16-bit addressing, but some of the transport
* implementations (like SMBus) only have 8-bit addressing. So RMI implements
* a page address at 0xff of every page so we can reliable page addresses
* every 256 registers.
*
* The page_mutex lock must be held when this function is entered.
*
* Returns zero on success, non-zero on failure.
*/
static int rmi_set_page(struct rmi_spi_xport *rmi_spi, u8 page)
{
struct rmi_spi_cmd cmd;
int ret;
cmd.op = RMI_SPI_WRITE;
cmd.addr = RMI_PAGE_SELECT_REGISTER;
ret = rmi_spi_xfer(rmi_spi, &cmd, &page, 1, NULL, 0);
if (ret)
rmi_spi->page = page;
return ret;
}
static int rmi_spi_write_block(struct rmi_transport_dev *xport, u16 addr,
const void *buf, size_t len)
{
struct rmi_spi_xport *rmi_spi =
container_of(xport, struct rmi_spi_xport, xport);
struct rmi_spi_cmd cmd;
int ret;
mutex_lock(&rmi_spi->page_mutex);
if (RMI_SPI_PAGE(addr) != rmi_spi->page) {
ret = rmi_set_page(rmi_spi, RMI_SPI_PAGE(addr));
if (ret)
goto exit;
}
cmd.op = RMI_SPI_WRITE;
cmd.addr = addr;
ret = rmi_spi_xfer(rmi_spi, &cmd, buf, len, NULL, 0);
exit:
mutex_unlock(&rmi_spi->page_mutex);
return ret;
}
static int rmi_spi_read_block(struct rmi_transport_dev *xport, u16 addr,
void *buf, size_t len)
{
struct rmi_spi_xport *rmi_spi =
container_of(xport, struct rmi_spi_xport, xport);
struct rmi_spi_cmd cmd;
int ret;
mutex_lock(&rmi_spi->page_mutex);
if (RMI_SPI_PAGE(addr) != rmi_spi->page) {
ret = rmi_set_page(rmi_spi, RMI_SPI_PAGE(addr));
if (ret)
goto exit;
}
cmd.op = RMI_SPI_READ;
cmd.addr = addr;
ret = rmi_spi_xfer(rmi_spi, &cmd, NULL, 0, buf, len);
exit:
mutex_unlock(&rmi_spi->page_mutex);
return ret;
}
static const struct rmi_transport_ops rmi_spi_ops = {
.write_block = rmi_spi_write_block,
.read_block = rmi_spi_read_block,
};
static irqreturn_t rmi_spi_irq(int irq, void *dev_id)
{
struct rmi_spi_xport *rmi_spi = dev_id;
struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev;
int ret;
ret = rmi_process_interrupt_requests(rmi_dev);
if (ret)
rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev,
"Failed to process interrupt request: %d\n", ret);
return IRQ_HANDLED;
}
static int rmi_spi_init_irq(struct spi_device *spi)
{
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq));
int ret;
if (!irq_flags)
irq_flags = IRQF_TRIGGER_LOW;
ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL,
rmi_spi_irq, irq_flags | IRQF_ONESHOT,
dev_name(&spi->dev), rmi_spi);
if (ret < 0) {
dev_warn(&spi->dev, "Failed to register interrupt %d\n",
rmi_spi->irq);
return ret;
}
return 0;
}
#ifdef CONFIG_OF
static int rmi_spi_of_probe(struct spi_device *spi,
struct rmi_device_platform_data *pdata)
{
struct device *dev = &spi->dev;
int retval;
retval = rmi_of_property_read_u32(dev,
&pdata->spi_data.read_delay_us,
"spi-rx-delay-us", 1);
if (retval)
return retval;
retval = rmi_of_property_read_u32(dev,
&pdata->spi_data.write_delay_us,
"spi-tx-delay-us", 1);
if (retval)
return retval;
return 0;
}
static const struct of_device_id rmi_spi_of_match[] = {
{ .compatible = "syna,rmi4-spi" },
{},
};
MODULE_DEVICE_TABLE(of, rmi_spi_of_match);
#else
static inline int rmi_spi_of_probe(struct spi_device *spi,
struct rmi_device_platform_data *pdata)
{
return -ENODEV;
}
#endif
static int rmi_spi_probe(struct spi_device *spi)
{
struct rmi_spi_xport *rmi_spi;
struct rmi_device_platform_data *pdata;
struct rmi_device_platform_data *spi_pdata = spi->dev.platform_data;
int retval;
if (spi->master->flags & SPI_MASTER_HALF_DUPLEX)
return -EINVAL;
rmi_spi = devm_kzalloc(&spi->dev, sizeof(struct rmi_spi_xport),
GFP_KERNEL);
if (!rmi_spi)
return -ENOMEM;
pdata = &rmi_spi->xport.pdata;
if (spi->dev.of_node) {
retval = rmi_spi_of_probe(spi, pdata);
if (retval)
return retval;
} else if (spi_pdata) {
*pdata = *spi_pdata;
}
if (pdata->spi_data.bits_per_word)
spi->bits_per_word = pdata->spi_data.bits_per_word;
if (pdata->spi_data.mode)
spi->mode = pdata->spi_data.mode;
retval = spi_setup(spi);
if (retval < 0) {
dev_err(&spi->dev, "spi_setup failed!\n");
return retval;
}
if (spi->irq > 0)
rmi_spi->irq = spi->irq;
rmi_spi->spi = spi;
mutex_init(&rmi_spi->page_mutex);
rmi_spi->xport.dev = &spi->dev;
rmi_spi->xport.proto_name = "spi";
rmi_spi->xport.ops = &rmi_spi_ops;
spi_set_drvdata(spi, rmi_spi);
retval = rmi_spi_manage_pools(rmi_spi, RMI_SPI_DEFAULT_XFER_BUF_SIZE);
if (retval)
return retval;
/*
* Setting the page to zero will (a) make sure the PSR is in a
* known state, and (b) make sure we can talk to the device.
*/
retval = rmi_set_page(rmi_spi, 0);
if (retval) {
dev_err(&spi->dev, "Failed to set page select to 0.\n");
return retval;
}
retval = rmi_register_transport_device(&rmi_spi->xport);
if (retval) {
dev_err(&spi->dev, "failed to register transport.\n");
return retval;
}
retval = rmi_spi_init_irq(spi);
if (retval < 0)
return retval;
dev_info(&spi->dev, "registered RMI SPI driver\n");
return 0;
}
static int rmi_spi_remove(struct spi_device *spi)
{
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
rmi_unregister_transport_device(&rmi_spi->xport);
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int rmi_spi_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
disable_irq(rmi_spi->irq);
if (device_may_wakeup(&spi->dev)) {
ret = enable_irq_wake(rmi_spi->irq);
if (!ret)
dev_warn(dev, "Failed to enable irq for wake: %d\n",
ret);
}
return ret;
}
static int rmi_spi_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
enable_irq(rmi_spi->irq);
if (device_may_wakeup(&spi->dev)) {
ret = disable_irq_wake(rmi_spi->irq);
if (!ret)
dev_warn(dev, "Failed to disable irq for wake: %d\n",
ret);
}
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
return ret;
}
#endif
#ifdef CONFIG_PM
static int rmi_spi_runtime_suspend(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
disable_irq(rmi_spi->irq);
return 0;
}
static int rmi_spi_runtime_resume(struct device *dev)
{
struct spi_device *spi = to_spi_device(dev);
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
int ret;
enable_irq(rmi_spi->irq);
ret = rmi_driver_resume(rmi_spi->xport.rmi_dev);
if (ret)
dev_warn(dev, "Failed to resume device: %d\n", ret);
return 0;
}
#endif
static const struct dev_pm_ops rmi_spi_pm = {
SET_SYSTEM_SLEEP_PM_OPS(rmi_spi_suspend, rmi_spi_resume)
SET_RUNTIME_PM_OPS(rmi_spi_runtime_suspend, rmi_spi_runtime_resume,
NULL)
};
static const struct spi_device_id rmi_id[] = {
{ "rmi4_spi", 0 },
{ }
};
MODULE_DEVICE_TABLE(spi, rmi_id);
static struct spi_driver rmi_spi_driver = {
.driver = {
.name = "rmi4_spi",
.pm = &rmi_spi_pm,
.of_match_table = of_match_ptr(rmi_spi_of_match),
},
.id_table = rmi_id,
.probe = rmi_spi_probe,
.remove = rmi_spi_remove,
};
module_spi_driver(rmi_spi_driver);
MODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com>");
MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
MODULE_DESCRIPTION("RMI SPI driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(RMI_DRIVER_VERSION);

359
include/linux/rmi.h Normal file
View File

@ -0,0 +1,359 @@
/*
* Copyright (c) 2011-2016 Synaptics Incorporated
* Copyright (c) 2011 Unixphere
*
* 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.
*/
#ifndef _RMI_H
#define _RMI_H
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/types.h>
#define NAME_BUFFER_SIZE 256
/**
* struct rmi_2d_axis_alignment - target axis alignment
* @swap_axes: set to TRUE if desired to swap x- and y-axis
* @flip_x: set to TRUE if desired to flip direction on x-axis
* @flip_y: set to TRUE if desired to flip direction on y-axis
* @clip_x_low - reported X coordinates below this setting will be clipped to
* the specified value
* @clip_x_high - reported X coordinates above this setting will be clipped to
* the specified value
* @clip_y_low - reported Y coordinates below this setting will be clipped to
* the specified value
* @clip_y_high - reported Y coordinates above this setting will be clipped to
* the specified value
* @offset_x - this value will be added to all reported X coordinates
* @offset_y - this value will be added to all reported Y coordinates
* @rel_report_enabled - if set to true, the relative reporting will be
* automatically enabled for this sensor.
*/
struct rmi_2d_axis_alignment {
bool swap_axes;
bool flip_x;
bool flip_y;
u16 clip_x_low;
u16 clip_y_low;
u16 clip_x_high;
u16 clip_y_high;
u16 offset_x;
u16 offset_y;
u8 delta_x_threshold;
u8 delta_y_threshold;
};
/** This is used to override any hints an F11 2D sensor might have provided
* as to what type of sensor it is.
*
* @rmi_f11_sensor_default - do not override, determine from F11_2D_QUERY14 if
* available.
* @rmi_f11_sensor_touchscreen - treat the sensor as a touchscreen (direct
* pointing).
* @rmi_f11_sensor_touchpad - thread the sensor as a touchpad (indirect
* pointing).
*/
enum rmi_sensor_type {
rmi_sensor_default = 0,
rmi_sensor_touchscreen,
rmi_sensor_touchpad
};
#define RMI_F11_DISABLE_ABS_REPORT BIT(0)
/**
* struct rmi_2d_sensor_data - overrides defaults for a 2D sensor.
* @axis_align - provides axis alignment overrides (see above).
* @sensor_type - Forces the driver to treat the sensor as an indirect
* pointing device (touchpad) rather than a direct pointing device
* (touchscreen). This is useful when F11_2D_QUERY14 register is not
* available.
* @disable_report_mask - Force data to not be reported even if it is supported
* by the firware.
* @topbuttonpad - Used with the "5 buttons touchpads" found on the Lenovo 40
* series
* @kernel_tracking - most moderns RMI f11 firmwares implement Multifinger
* Type B protocol. However, there are some corner cases where the user
* triggers some jumps by tapping with two fingers on the touchpad.
* Use this setting and dmax to filter out these jumps.
* Also, when using an old sensor using MF Type A behavior, set to true to
* report an actual MT protocol B.
* @dmax - the maximum distance (in sensor units) the kernel tracking allows two
* distincts fingers to be considered the same.
*/
struct rmi_2d_sensor_platform_data {
struct rmi_2d_axis_alignment axis_align;
enum rmi_sensor_type sensor_type;
int x_mm;
int y_mm;
int disable_report_mask;
u16 rezero_wait;
bool topbuttonpad;
bool kernel_tracking;
int dmax;
};
/**
* struct rmi_f30_data - overrides defaults for a single F30 GPIOs/LED chip.
* @buttonpad - the touchpad is a buttonpad, so enable only the first actual
* button that is found.
* @trackstick_buttons - Set when the function 30 is handling the physical
* buttons of the trackstick (as a PD/2 passthrough device.
* @disable - the touchpad incorrectly reports F30 and it should be ignored.
* This is a special case which is due to misconfigured firmware.
*/
struct rmi_f30_data {
bool buttonpad;
bool trackstick_buttons;
bool disable;
};
/**
* struct rmi_f01_power - override default power management settings.
*
*/
enum rmi_f01_nosleep {
RMI_F01_NOSLEEP_DEFAULT = 0,
RMI_F01_NOSLEEP_OFF = 1,
RMI_F01_NOSLEEP_ON = 2
};
/**
* struct rmi_f01_power_management -When non-zero, these values will be written
* to the touch sensor to override the default firmware settigns. For a
* detailed explanation of what each field does, see the corresponding
* documention in the RMI4 specification.
*
* @nosleep - specifies whether the device is permitted to sleep or doze (that
* is, enter a temporary low power state) when no fingers are touching the
* sensor.
* @wakeup_threshold - controls the capacitance threshold at which the touch
* sensor will decide to wake up from that low power state.
* @doze_holdoff - controls how long the touch sensor waits after the last
* finger lifts before entering the doze state, in units of 100ms.
* @doze_interval - controls the interval between checks for finger presence
* when the touch sensor is in doze mode, in units of 10ms.
*/
struct rmi_f01_power_management {
enum rmi_f01_nosleep nosleep;
u8 wakeup_threshold;
u8 doze_holdoff;
u8 doze_interval;
};
/**
* struct rmi_device_platform_data_spi - provides parameters used in SPI
* communications. All Synaptics SPI products support a standard SPI
* interface; some also support what is called SPI V2 mode, depending on
* firmware and/or ASIC limitations. In V2 mode, the touch sensor can
* support shorter delays during certain operations, and these are specified
* separately from the standard mode delays.
*
* @block_delay - for standard SPI transactions consisting of both a read and
* write operation, the delay (in microseconds) between the read and write
* operations.
* @split_read_block_delay_us - for V2 SPI transactions consisting of both a
* read and write operation, the delay (in microseconds) between the read and
* write operations.
* @read_delay_us - the delay between each byte of a read operation in normal
* SPI mode.
* @write_delay_us - the delay between each byte of a write operation in normal
* SPI mode.
* @split_read_byte_delay_us - the delay between each byte of a read operation
* in V2 mode.
* @pre_delay_us - the delay before the start of a SPI transaction. This is
* typically useful in conjunction with custom chip select assertions (see
* below).
* @post_delay_us - the delay after the completion of an SPI transaction. This
* is typically useful in conjunction with custom chip select assertions (see
* below).
* @cs_assert - For systems where the SPI subsystem does not control the CS/SSB
* line, or where such control is broken, you can provide a custom routine to
* handle a GPIO as CS/SSB. This routine will be called at the beginning and
* end of each SPI transaction. The RMI SPI implementation will wait
* pre_delay_us after this routine returns before starting the SPI transfer;
* and post_delay_us after completion of the SPI transfer(s) before calling it
* with assert==FALSE.
*/
struct rmi_device_platform_data_spi {
u32 block_delay_us;
u32 split_read_block_delay_us;
u32 read_delay_us;
u32 write_delay_us;
u32 split_read_byte_delay_us;
u32 pre_delay_us;
u32 post_delay_us;
u8 bits_per_word;
u16 mode;
void *cs_assert_data;
int (*cs_assert)(const void *cs_assert_data, const bool assert);
};
/**
* struct rmi_device_platform_data - system specific configuration info.
*
* @reset_delay_ms - after issuing a reset command to the touch sensor, the
* driver waits a few milliseconds to give the firmware a chance to
* to re-initialize. You can override the default wait period here.
*/
struct rmi_device_platform_data {
int reset_delay_ms;
struct rmi_device_platform_data_spi spi_data;
/* function handler pdata */
struct rmi_2d_sensor_platform_data *sensor_pdata;
struct rmi_f01_power_management power_management;
struct rmi_f30_data *f30_data;
};
/**
* struct rmi_function_descriptor - RMI function base addresses
*
* @query_base_addr: The RMI Query base address
* @command_base_addr: The RMI Command base address
* @control_base_addr: The RMI Control base address
* @data_base_addr: The RMI Data base address
* @interrupt_source_count: The number of irqs this RMI function needs
* @function_number: The RMI function number
*
* This struct is used when iterating the Page Description Table. The addresses
* are 16-bit values to include the current page address.
*
*/
struct rmi_function_descriptor {
u16 query_base_addr;
u16 command_base_addr;
u16 control_base_addr;
u16 data_base_addr;
u8 interrupt_source_count;
u8 function_number;
u8 function_version;
};
struct rmi_device;
/**
* struct rmi_transport_dev - represent an RMI transport device
*
* @dev: Pointer to the communication device, e.g. i2c or spi
* @rmi_dev: Pointer to the RMI device
* @proto_name: name of the transport protocol (SPI, i2c, etc)
* @ops: pointer to transport operations implementation
*
* The RMI transport device implements the glue between different communication
* buses such as I2C and SPI.
*
*/
struct rmi_transport_dev {
struct device *dev;
struct rmi_device *rmi_dev;
const char *proto_name;
const struct rmi_transport_ops *ops;
struct rmi_device_platform_data pdata;
struct input_dev *input;
void *attn_data;
int attn_size;
};
/**
* struct rmi_transport_ops - defines transport protocol operations.
*
* @write_block: Writing a block of data to the specified address
* @read_block: Read a block of data from the specified address.
*/
struct rmi_transport_ops {
int (*write_block)(struct rmi_transport_dev *xport, u16 addr,
const void *buf, size_t len);
int (*read_block)(struct rmi_transport_dev *xport, u16 addr,
void *buf, size_t len);
int (*reset)(struct rmi_transport_dev *xport, u16 reset_addr);
};
/**
* struct rmi_driver - driver for an RMI4 sensor on the RMI bus.
*
* @driver: Device driver model driver
* @reset_handler: Called when a reset is detected.
* @clear_irq_bits: Clear the specified bits in the current interrupt mask.
* @set_irq_bist: Set the specified bits in the current interrupt mask.
* @store_productid: Callback for cache product id from function 01
* @data: Private data pointer
*
*/
struct rmi_driver {
struct device_driver driver;
int (*reset_handler)(struct rmi_device *rmi_dev);
int (*clear_irq_bits)(struct rmi_device *rmi_dev, unsigned long *mask);
int (*set_irq_bits)(struct rmi_device *rmi_dev, unsigned long *mask);
int (*store_productid)(struct rmi_device *rmi_dev);
int (*set_input_params)(struct rmi_device *rmi_dev,
struct input_dev *input);
void *data;
};
/**
* struct rmi_device - represents an RMI4 sensor device on the RMI bus.
*
* @dev: The device created for the RMI bus
* @number: Unique number for the device on the bus.
* @driver: Pointer to associated driver
* @xport: Pointer to the transport interface
*
*/
struct rmi_device {
struct device dev;
int number;
struct rmi_driver *driver;
struct rmi_transport_dev *xport;
};
struct rmi_driver_data {
struct list_head function_list;
struct rmi_device *rmi_dev;
struct rmi_function *f01_container;
bool f01_bootloader_mode;
u32 attn_count;
int num_of_irq_regs;
int irq_count;
unsigned long *irq_status;
unsigned long *fn_irq_bits;
unsigned long *current_irq_mask;
unsigned long *new_irq_mask;
struct mutex irq_mutex;
struct input_dev *input;
u8 pdt_props;
u8 bsr;
bool enabled;
void *data;
};
int rmi_register_transport_device(struct rmi_transport_dev *xport);
void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
int rmi_process_interrupt_requests(struct rmi_device *rmi_dev);
int rmi_driver_suspend(struct rmi_device *rmi_dev);
int rmi_driver_resume(struct rmi_device *rmi_dev);
#endif

View File

@ -246,6 +246,7 @@ struct input_mask {
#define BUS_GSC 0x1A #define BUS_GSC 0x1A
#define BUS_ATARI 0x1B #define BUS_ATARI 0x1B
#define BUS_SPI 0x1C #define BUS_SPI 0x1C
#define BUS_RMI 0x1D
/* /*
* MT_TOOL types * MT_TOOL types