input: touchscreen: remove synaptics v2.6 touch driver
Remove synaptics v2.6 touch driver from the kernel code as it has never been used in any of the recent platforms. Change-Id: Ibf14dec548a180e517d9b41098af642577c4328b Signed-off-by: Shantanu Jain <shjain@codeaurora.org>
This commit is contained in:
parent
92124c76a2
commit
27ff365a17
18 changed files with 0 additions and 21581 deletions
|
@ -1,57 +0,0 @@
|
|||
Synaptics DSXV26 touch controller
|
||||
|
||||
Please add this description here: The Synaptics Touch controller is connected to the
|
||||
host processor via I2C. The controller generates interrupts when the user touches
|
||||
the panel. The host controller is expected to read the touch coordinates over I2C and
|
||||
pass the coordinates to the rest of the system.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : should be "synaptics,dsx-i2c".
|
||||
- reg : i2c slave address of the device.
|
||||
- interrupt-parent : parent of interrupt.
|
||||
- synaptics,irq-gpio : irq gpio.
|
||||
- synaptics,irq-flags : irq flags.
|
||||
|
||||
Optional property:
|
||||
- vdd_ana-supply : digital voltage power supply needed to power device.
|
||||
- vcc_i2c-supply : analog voltage power supply needed to power device.
|
||||
- synaptics,pwr-reg-name : power reg name of digital voltage.
|
||||
- synaptics,bus-reg-name : bus reg name of analog voltage.
|
||||
- synaptics,irq-on-state : status of irq gpio.
|
||||
- synaptics,cap-button-codes : virtual key code mappings to be used.
|
||||
- synaptics,vir-button-codes : virtual key code and the response region on panel.
|
||||
- synaptics,x-flip : modify orientation of the x axis.
|
||||
- synaptics,y-flip : modify orientation of the y axis.
|
||||
- synaptics,reset-delay-ms : reset delay for controller (ms), default 100.
|
||||
- synaptics,max-y-for-2d : maximal y value of the panel.
|
||||
- clock-names : Clock names used for secure touch. They are: "iface_clk", "core_clk"
|
||||
- clocks : Defined if 'clock-names' DT property is defined. These clocks
|
||||
are associated with the underlying I2C bus.
|
||||
|
||||
Example:
|
||||
i2c@78b7000 {
|
||||
status = "ok";
|
||||
synaptics@4b {
|
||||
compatible = "synaptics,dsx-i2c";
|
||||
reg = <0x4b>;
|
||||
interrupt-parent = <&tlmm>;
|
||||
interrupts = <65 0x2008>;
|
||||
vdd_ana-supply = <&pmtitanium_l17>;
|
||||
vcc_i2c-supply = <&pmtitanium_l6>;
|
||||
synaptics,pwr-reg-name = "vdd_ana";
|
||||
synaptics,bus-reg-name = "vcc_i2c";
|
||||
synaptics,irq-gpio = <&tlmm 65 0x2008>;
|
||||
synaptics,irq-on-state = <0>;
|
||||
synaptics,irq-flags = <0x2008>; /* IRQF_ONESHOT | IRQF_TRIGGER_LOW */
|
||||
synaptics,power-delay-ms = <200>;
|
||||
synaptics,reset-delay-ms = <200>;
|
||||
synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */
|
||||
synaptics,cap-button-codes = <139 172 158>;
|
||||
synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>;
|
||||
/* Underlying clocks used by secure touch */
|
||||
clock-names = "iface_clk", "core_clk";
|
||||
clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
|
||||
<&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>;
|
||||
};
|
||||
};
|
|
@ -12,7 +12,6 @@ menuconfig INPUT_TOUCHSCREEN
|
|||
if INPUT_TOUCHSCREEN
|
||||
|
||||
source "drivers/input/touchscreen/synaptics_dsx/Kconfig"
|
||||
source "drivers/input/touchscreen/synaptics_dsx_2.6/Kconfig"
|
||||
|
||||
config OF_TOUCHSCREEN
|
||||
def_tristate INPUT
|
||||
|
|
|
@ -70,7 +70,6 @@ obj-$(CONFIG_TOUCHSCREEN_STMPE) += stmpe-ts.o
|
|||
obj-$(CONFIG_TOUCHSCREEN_SUN4I) += sun4i-ts.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SUR40) += sur40.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v21) += synaptics_dsx/
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_v26) += synaptics_dsx_2.6/
|
||||
obj-$(CONFIG_TOUCHSCREEN_TI_AM335X_TSC) += ti_am335x_tsc.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
|
||||
|
|
|
@ -1,127 +0,0 @@
|
|||
#
|
||||
# Synaptics DSX v2.6 touchscreen driver configuration
|
||||
#
|
||||
menuconfig TOUCHSCREEN_SYNAPTICS_DSX_v26
|
||||
bool "Synaptics DSX v2.6 touchscreen"
|
||||
default y
|
||||
help
|
||||
Say Y here if you have a Synaptics DSX touchscreen connected
|
||||
to your system.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
if TOUCHSCREEN_SYNAPTICS_DSX_v26
|
||||
|
||||
choice
|
||||
default TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
|
||||
prompt "Synaptics DSX v2.6 bus interface"
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
|
||||
bool "RMI over I2C"
|
||||
depends on I2C
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_SPI_v26
|
||||
bool "RMI over SPI"
|
||||
depends on SPI_MASTER
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_v26
|
||||
bool "HID over I2C"
|
||||
depends on I2C
|
||||
endchoice
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
tristate "Synaptics DSX v2.6 core driver module"
|
||||
depends on I2C || SPI_MASTER
|
||||
help
|
||||
Say Y here to enable basic touch reporting functionality.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_core.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26
|
||||
tristate "Synaptics DSX v2.6 RMI device module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for direct RMI register access.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_rmi_dev.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26
|
||||
tristate "Synaptics DSX v2.6 firmware update module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for doing firmware update.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_fw_update.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_v26
|
||||
tristate "Synaptics DSX v2.6 test reporting module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for retrieving production test reports.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_test_reporting.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v26
|
||||
tristate "Synaptics DSX v2.6 proximity module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for proximity functionality.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_proximity.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_v26
|
||||
tristate "Synaptics DSX v2.6 active pen module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for active pen functionality.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_active_pen.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_v26
|
||||
tristate "Synaptics DSX v2.6 user defined gesture module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for user defined gesture functionality.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_gesture.
|
||||
|
||||
config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26
|
||||
tristate "Synaptics DSX v2.6 video module"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26
|
||||
help
|
||||
Say Y here to enable support for video communication functionality.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_video.
|
||||
|
||||
config SECURE_TOUCH_SYNAPTICS_DSX_V26
|
||||
bool "Secure Touch support for Synaptics V2.6 Touchscreen"
|
||||
depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26
|
||||
help
|
||||
Say Y here
|
||||
-Synaptics DSX V2.6 touch driver is connected
|
||||
-To enable secure touch for Synaptics DSX V2.6 touch driver
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
endif
|
|
@ -1,17 +0,0 @@
|
|||
#
|
||||
# Makefile for the Synaptics DSX touchscreen driver.
|
||||
#
|
||||
|
||||
# Each configuration option enables a list of files.
|
||||
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26) += synaptics_dsx_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_SPI_v26) += synaptics_dsx_spi.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_HID_I2C_v26) += synaptics_dsx_rmi_hid_i2c.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CORE_v26) += synaptics_dsx_core.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_RMI_DEV_v26) += synaptics_dsx_rmi_dev.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_FW_UPDATE_v26) += synaptics_dsx_fw_update.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_TEST_REPORTING_v26) += synaptics_dsx_test_reporting.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_PROXIMITY_v26) += synaptics_dsx_proximity.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_ACTIVE_PEN_v26) += synaptics_dsx_active_pen.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_GESTURE_v26) += synaptics_dsx_gesture.o
|
||||
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26) += synaptics_dsx_video.o
|
|
@ -1,624 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input/synaptics_dsx_v2_6.h>
|
||||
#include "synaptics_dsx_core.h"
|
||||
|
||||
#define APEN_PHYS_NAME "synaptics_dsx/active_pen"
|
||||
|
||||
#define ACTIVE_PEN_MAX_PRESSURE_16BIT 65535
|
||||
#define ACTIVE_PEN_MAX_PRESSURE_8BIT 255
|
||||
|
||||
struct synaptics_rmi4_f12_query_8 {
|
||||
union {
|
||||
struct {
|
||||
unsigned char size_of_query9;
|
||||
struct {
|
||||
unsigned char data0_is_present:1;
|
||||
unsigned char data1_is_present:1;
|
||||
unsigned char data2_is_present:1;
|
||||
unsigned char data3_is_present:1;
|
||||
unsigned char data4_is_present:1;
|
||||
unsigned char data5_is_present:1;
|
||||
unsigned char data6_is_present:1;
|
||||
unsigned char data7_is_present:1;
|
||||
} __packed;
|
||||
};
|
||||
unsigned char data[2];
|
||||
};
|
||||
};
|
||||
|
||||
struct apen_data_8b_pressure {
|
||||
union {
|
||||
struct {
|
||||
unsigned char status_pen:1;
|
||||
unsigned char status_invert:1;
|
||||
unsigned char status_barrel:1;
|
||||
unsigned char status_reserved:5;
|
||||
unsigned char x_lsb;
|
||||
unsigned char x_msb;
|
||||
unsigned char y_lsb;
|
||||
unsigned char y_msb;
|
||||
unsigned char pressure_msb;
|
||||
unsigned char battery_state;
|
||||
unsigned char pen_id_0_7;
|
||||
unsigned char pen_id_8_15;
|
||||
unsigned char pen_id_16_23;
|
||||
unsigned char pen_id_24_31;
|
||||
} __packed;
|
||||
unsigned char data[11];
|
||||
};
|
||||
};
|
||||
|
||||
struct apen_data {
|
||||
union {
|
||||
struct {
|
||||
unsigned char status_pen:1;
|
||||
unsigned char status_invert:1;
|
||||
unsigned char status_barrel:1;
|
||||
unsigned char status_reserved:5;
|
||||
unsigned char x_lsb;
|
||||
unsigned char x_msb;
|
||||
unsigned char y_lsb;
|
||||
unsigned char y_msb;
|
||||
unsigned char pressure_lsb;
|
||||
unsigned char pressure_msb;
|
||||
unsigned char battery_state;
|
||||
unsigned char pen_id_0_7;
|
||||
unsigned char pen_id_8_15;
|
||||
unsigned char pen_id_16_23;
|
||||
unsigned char pen_id_24_31;
|
||||
} __packed;
|
||||
unsigned char data[12];
|
||||
};
|
||||
};
|
||||
|
||||
struct synaptics_rmi4_apen_handle {
|
||||
bool apen_present;
|
||||
unsigned char intr_mask;
|
||||
unsigned char battery_state;
|
||||
unsigned short query_base_addr;
|
||||
unsigned short control_base_addr;
|
||||
unsigned short data_base_addr;
|
||||
unsigned short command_base_addr;
|
||||
unsigned short apen_data_addr;
|
||||
unsigned short max_pressure;
|
||||
unsigned int pen_id;
|
||||
struct input_dev *apen_dev;
|
||||
struct apen_data *apen_data;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
};
|
||||
|
||||
static struct synaptics_rmi4_apen_handle *apen;
|
||||
|
||||
DECLARE_COMPLETION(apen_remove_complete);
|
||||
|
||||
static void apen_lift(void)
|
||||
{
|
||||
input_report_key(apen->apen_dev, BTN_TOUCH, 0);
|
||||
input_report_key(apen->apen_dev, BTN_TOOL_PEN, 0);
|
||||
input_report_key(apen->apen_dev, BTN_TOOL_RUBBER, 0);
|
||||
input_sync(apen->apen_dev);
|
||||
apen->apen_present = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void apen_report(void)
|
||||
{
|
||||
int retval;
|
||||
int x;
|
||||
int y;
|
||||
int pressure;
|
||||
static int invert = -1;
|
||||
struct apen_data_8b_pressure *apen_data_8b;
|
||||
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
apen->apen_data_addr,
|
||||
apen->apen_data->data,
|
||||
sizeof(apen->apen_data->data));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to read active pen data\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (apen->apen_data->status_pen == 0) {
|
||||
if (apen->apen_present)
|
||||
apen_lift();
|
||||
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: No active pen data\n",
|
||||
__func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
x = (apen->apen_data->x_msb << 8) | (apen->apen_data->x_lsb);
|
||||
y = (apen->apen_data->y_msb << 8) | (apen->apen_data->y_lsb);
|
||||
|
||||
if ((x == -1) && (y == -1)) {
|
||||
if (apen->apen_present)
|
||||
apen_lift();
|
||||
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Active pen in range but no valid x & y\n",
|
||||
__func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!apen->apen_present)
|
||||
invert = -1;
|
||||
|
||||
if (invert != -1 && invert != apen->apen_data->status_invert)
|
||||
apen_lift();
|
||||
|
||||
invert = apen->apen_data->status_invert;
|
||||
|
||||
if (apen->max_pressure == ACTIVE_PEN_MAX_PRESSURE_16BIT) {
|
||||
pressure = (apen->apen_data->pressure_msb << 8) |
|
||||
apen->apen_data->pressure_lsb;
|
||||
apen->battery_state = apen->apen_data->battery_state;
|
||||
apen->pen_id = (apen->apen_data->pen_id_24_31 << 24) |
|
||||
(apen->apen_data->pen_id_16_23 << 16) |
|
||||
(apen->apen_data->pen_id_8_15 << 8) |
|
||||
apen->apen_data->pen_id_0_7;
|
||||
} else {
|
||||
apen_data_8b = (struct apen_data_8b_pressure *)apen->apen_data;
|
||||
pressure = apen_data_8b->pressure_msb;
|
||||
apen->battery_state = apen_data_8b->battery_state;
|
||||
apen->pen_id = (apen_data_8b->pen_id_24_31 << 24) |
|
||||
(apen_data_8b->pen_id_16_23 << 16) |
|
||||
(apen_data_8b->pen_id_8_15 << 8) |
|
||||
apen_data_8b->pen_id_0_7;
|
||||
}
|
||||
|
||||
input_report_key(apen->apen_dev, BTN_TOUCH, pressure > 0 ? 1 : 0);
|
||||
input_report_key(apen->apen_dev,
|
||||
apen->apen_data->status_invert > 0 ?
|
||||
BTN_TOOL_RUBBER : BTN_TOOL_PEN, 1);
|
||||
input_report_key(apen->apen_dev,
|
||||
BTN_STYLUS, apen->apen_data->status_barrel > 0 ?
|
||||
1 : 0);
|
||||
input_report_abs(apen->apen_dev, ABS_X, x);
|
||||
input_report_abs(apen->apen_dev, ABS_Y, y);
|
||||
input_report_abs(apen->apen_dev, ABS_PRESSURE, pressure);
|
||||
|
||||
input_sync(apen->apen_dev);
|
||||
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Active pen: status = %d, invert = %d, barrel = %d, x = %d, y = %d, pressure = %d\n",
|
||||
__func__,
|
||||
apen->apen_data->status_pen,
|
||||
apen->apen_data->status_invert,
|
||||
apen->apen_data->status_barrel,
|
||||
x, y, pressure);
|
||||
|
||||
apen->apen_present = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void apen_set_params(void)
|
||||
{
|
||||
input_set_abs_params(apen->apen_dev, ABS_X, 0,
|
||||
apen->rmi4_data->sensor_max_x, 0, 0);
|
||||
input_set_abs_params(apen->apen_dev, ABS_Y, 0,
|
||||
apen->rmi4_data->sensor_max_y, 0, 0);
|
||||
input_set_abs_params(apen->apen_dev, ABS_PRESSURE, 0,
|
||||
apen->max_pressure, 0, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int apen_pressure(struct synaptics_rmi4_f12_query_8 *query_8)
|
||||
{
|
||||
int retval;
|
||||
unsigned char ii;
|
||||
unsigned char data_reg_presence;
|
||||
unsigned char size_of_query_9;
|
||||
unsigned char *query_9;
|
||||
unsigned char *data_desc;
|
||||
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
|
||||
|
||||
data_reg_presence = query_8->data[1];
|
||||
|
||||
size_of_query_9 = query_8->size_of_query9;
|
||||
query_9 = kmalloc(size_of_query_9, GFP_KERNEL);
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
apen->query_base_addr + 9,
|
||||
query_9,
|
||||
size_of_query_9);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
data_desc = query_9;
|
||||
|
||||
for (ii = 0; ii < 6; ii++) {
|
||||
if (!(data_reg_presence & (1 << ii)))
|
||||
continue; /* The data register is not present */
|
||||
data_desc++; /* Jump over the size entry */
|
||||
while (*data_desc & (1 << 7))
|
||||
data_desc++;
|
||||
data_desc++; /* Go to the next descriptor */
|
||||
}
|
||||
|
||||
data_desc++; /* Jump over the size entry */
|
||||
/* Check for the presence of subpackets 1 and 2 */
|
||||
if ((*data_desc & (3 << 1)) == (3 << 1))
|
||||
apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_16BIT;
|
||||
else
|
||||
apen->max_pressure = ACTIVE_PEN_MAX_PRESSURE_8BIT;
|
||||
|
||||
exit:
|
||||
kfree(query_9);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int apen_reg_init(void)
|
||||
{
|
||||
int retval;
|
||||
unsigned char data_offset;
|
||||
unsigned char size_of_query8;
|
||||
struct synaptics_rmi4_f12_query_8 query_8;
|
||||
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
apen->query_base_addr + 7,
|
||||
&size_of_query8,
|
||||
sizeof(size_of_query8));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
apen->query_base_addr + 8,
|
||||
query_8.data,
|
||||
sizeof(query_8.data));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
if ((size_of_query8 >= 2) && (query_8.data6_is_present)) {
|
||||
data_offset = query_8.data0_is_present +
|
||||
query_8.data1_is_present +
|
||||
query_8.data2_is_present +
|
||||
query_8.data3_is_present +
|
||||
query_8.data4_is_present +
|
||||
query_8.data5_is_present;
|
||||
apen->apen_data_addr = apen->data_base_addr + data_offset;
|
||||
retval = apen_pressure(&query_8);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
} else {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Active pen support unavailable\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int apen_scan_pdt(void)
|
||||
{
|
||||
int retval;
|
||||
unsigned char ii;
|
||||
unsigned char page;
|
||||
unsigned char intr_count = 0;
|
||||
unsigned char intr_off;
|
||||
unsigned char intr_src;
|
||||
unsigned short addr;
|
||||
struct synaptics_rmi4_fn_desc fd;
|
||||
struct synaptics_rmi4_data *rmi4_data = apen->rmi4_data;
|
||||
|
||||
for (page = 0; page < PAGES_TO_SERVICE; page++) {
|
||||
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
|
||||
addr |= (page << 8);
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
addr,
|
||||
(unsigned char *)&fd,
|
||||
sizeof(fd));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
addr &= ~(MASK_8BIT << 8);
|
||||
|
||||
if (fd.fn_number) {
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Found F%02x\n",
|
||||
__func__, fd.fn_number);
|
||||
switch (fd.fn_number) {
|
||||
case SYNAPTICS_RMI4_F12:
|
||||
goto f12_found;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
intr_count += fd.intr_src_count;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to find F12\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
|
||||
f12_found:
|
||||
apen->query_base_addr = fd.query_base_addr | (page << 8);
|
||||
apen->control_base_addr = fd.ctrl_base_addr | (page << 8);
|
||||
apen->data_base_addr = fd.data_base_addr | (page << 8);
|
||||
apen->command_base_addr = fd.cmd_base_addr | (page << 8);
|
||||
|
||||
retval = apen_reg_init();
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to initialize active pen registers\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
apen->intr_mask = 0;
|
||||
intr_src = fd.intr_src_count;
|
||||
intr_off = intr_count % 8;
|
||||
for (ii = intr_off;
|
||||
ii < (intr_src + intr_off);
|
||||
ii++) {
|
||||
apen->intr_mask |= 1 << ii;
|
||||
}
|
||||
|
||||
rmi4_data->intr_mask[0] |= apen->intr_mask;
|
||||
|
||||
addr = rmi4_data->f01_ctrl_base_addr + 1;
|
||||
|
||||
retval = synaptics_rmi4_reg_write(rmi4_data,
|
||||
addr,
|
||||
&(rmi4_data->intr_mask[0]),
|
||||
sizeof(rmi4_data->intr_mask[0]));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to set interrupt enable bit\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_apen_attn(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned char intr_mask)
|
||||
{
|
||||
if (!apen)
|
||||
return;
|
||||
|
||||
if (apen->intr_mask & intr_mask)
|
||||
apen_report();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_apen_init(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (apen) {
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Handle already exists\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
apen = kzalloc(sizeof(*apen), GFP_KERNEL);
|
||||
if (!apen) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to alloc mem for apen\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
apen->apen_data = kzalloc(sizeof(*(apen->apen_data)), GFP_KERNEL);
|
||||
if (!apen->apen_data) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to alloc mem for apen_data\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit_free_apen;
|
||||
}
|
||||
|
||||
apen->rmi4_data = rmi4_data;
|
||||
|
||||
retval = apen_scan_pdt();
|
||||
if (retval < 0)
|
||||
goto exit_free_apen_data;
|
||||
|
||||
apen->apen_dev = input_allocate_device();
|
||||
if (apen->apen_dev == NULL) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to allocate active pen device\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit_free_apen_data;
|
||||
}
|
||||
|
||||
apen->apen_dev->name = ACTIVE_PEN_DRIVER_NAME;
|
||||
apen->apen_dev->phys = APEN_PHYS_NAME;
|
||||
apen->apen_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
|
||||
apen->apen_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
|
||||
apen->apen_dev->dev.parent = rmi4_data->pdev->dev.parent;
|
||||
input_set_drvdata(apen->apen_dev, rmi4_data);
|
||||
|
||||
set_bit(EV_KEY, apen->apen_dev->evbit);
|
||||
set_bit(EV_ABS, apen->apen_dev->evbit);
|
||||
set_bit(BTN_TOUCH, apen->apen_dev->keybit);
|
||||
set_bit(BTN_TOOL_PEN, apen->apen_dev->keybit);
|
||||
set_bit(BTN_TOOL_RUBBER, apen->apen_dev->keybit);
|
||||
set_bit(BTN_STYLUS, apen->apen_dev->keybit);
|
||||
#ifdef INPUT_PROP_DIRECT
|
||||
set_bit(INPUT_PROP_DIRECT, apen->apen_dev->propbit);
|
||||
#endif
|
||||
|
||||
apen_set_params();
|
||||
|
||||
retval = input_register_device(apen->apen_dev);
|
||||
if (retval) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to register active pen device\n",
|
||||
__func__);
|
||||
goto exit_free_input_device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_input_device:
|
||||
input_free_device(apen->apen_dev);
|
||||
|
||||
exit_free_apen_data:
|
||||
kfree(apen->apen_data);
|
||||
|
||||
exit_free_apen:
|
||||
kfree(apen);
|
||||
apen = NULL;
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_apen_remove(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!apen)
|
||||
goto exit;
|
||||
|
||||
input_unregister_device(apen->apen_dev);
|
||||
kfree(apen->apen_data);
|
||||
kfree(apen);
|
||||
apen = NULL;
|
||||
|
||||
exit:
|
||||
complete(&apen_remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_apen_reset(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!apen) {
|
||||
synaptics_rmi4_apen_init(rmi4_data);
|
||||
return;
|
||||
}
|
||||
|
||||
apen_lift();
|
||||
|
||||
apen_scan_pdt();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_apen_reinit(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!apen)
|
||||
return;
|
||||
|
||||
apen_lift();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_apen_e_suspend(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!apen)
|
||||
return;
|
||||
|
||||
apen_lift();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_apen_suspend(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!apen)
|
||||
return;
|
||||
|
||||
apen_lift();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct synaptics_rmi4_exp_fn active_pen_module = {
|
||||
.fn_type = RMI_ACTIVE_PEN,
|
||||
.init = synaptics_rmi4_apen_init,
|
||||
.remove = synaptics_rmi4_apen_remove,
|
||||
.reset = synaptics_rmi4_apen_reset,
|
||||
.reinit = synaptics_rmi4_apen_reinit,
|
||||
.early_suspend = synaptics_rmi4_apen_e_suspend,
|
||||
.suspend = synaptics_rmi4_apen_suspend,
|
||||
.resume = NULL,
|
||||
.late_resume = NULL,
|
||||
.attn = synaptics_rmi4_apen_attn,
|
||||
};
|
||||
|
||||
static int __init rmi4_active_pen_module_init(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(&active_pen_module, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rmi4_active_pen_module_exit(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(&active_pen_module, false);
|
||||
|
||||
wait_for_completion(&apen_remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(rmi4_active_pen_module_init);
|
||||
module_exit(rmi4_active_pen_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Synaptics, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX Active Pen Module");
|
||||
MODULE_LICENSE("GPL v2");
|
File diff suppressed because it is too large
Load diff
|
@ -1,500 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
* Copyright (C) 2016 The Linux Foundation. All rights reserved.
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#ifndef _SYNAPTICS_DSX_RMI4_H_
|
||||
#define _SYNAPTICS_DSX_RMI4_H_
|
||||
|
||||
#define SYNAPTICS_DS4 (1 << 0)
|
||||
#define SYNAPTICS_DS5 (1 << 1)
|
||||
#define SYNAPTICS_DSX_DRIVER_PRODUCT (SYNAPTICS_DS4 | SYNAPTICS_DS5)
|
||||
#define SYNAPTICS_DSX_DRIVER_VERSION 0x2061
|
||||
|
||||
#include <linux/version.h>
|
||||
#ifdef CONFIG_FB
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/fb.h>
|
||||
#endif
|
||||
#ifdef CONFIG_HAS_EARLYSUSPEND
|
||||
#include <linux/earlysuspend.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
#include <linux/completion.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/clk.h>
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
|
||||
#define KERNEL_ABOVE_2_6_38
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0))
|
||||
#define KERNEL_ABOVE_3_6
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_ABOVE_2_6_38
|
||||
#define sstrtoul(...) kstrtoul(__VA_ARGS__)
|
||||
#else
|
||||
#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define PDT_PROPS (0X00EF)
|
||||
#define PDT_START (0x00E9)
|
||||
#define PDT_END (0x00D0)
|
||||
#define PDT_ENTRY_SIZE (0x0006)
|
||||
#define PAGES_TO_SERVICE (10)
|
||||
#define PAGE_SELECT_LEN (2)
|
||||
#define ADDRESS_WORD_LEN (2)
|
||||
|
||||
#define SYNAPTICS_RMI4_F01 (0x01)
|
||||
#define SYNAPTICS_RMI4_F11 (0x11)
|
||||
#define SYNAPTICS_RMI4_F12 (0x12)
|
||||
#define SYNAPTICS_RMI4_F1A (0x1A)
|
||||
#define SYNAPTICS_RMI4_F34 (0x34)
|
||||
#define SYNAPTICS_RMI4_F35 (0x35)
|
||||
#define SYNAPTICS_RMI4_F38 (0x38)
|
||||
#define SYNAPTICS_RMI4_F51 (0x51)
|
||||
#define SYNAPTICS_RMI4_F54 (0x54)
|
||||
#define SYNAPTICS_RMI4_F55 (0x55)
|
||||
#define SYNAPTICS_RMI4_FDB (0xDB)
|
||||
|
||||
#define PRODUCT_INFO_SIZE 2
|
||||
#define PRODUCT_ID_SIZE 10
|
||||
#define BUILD_ID_SIZE 3
|
||||
|
||||
#define F12_FINGERS_TO_SUPPORT 10
|
||||
#define F12_NO_OBJECT_STATUS 0x00
|
||||
#define F12_FINGER_STATUS 0x01
|
||||
#define F12_ACTIVE_STYLUS_STATUS 0x02
|
||||
#define F12_PALM_STATUS 0x03
|
||||
#define F12_HOVERING_FINGER_STATUS 0x05
|
||||
#define F12_GLOVED_FINGER_STATUS 0x06
|
||||
#define F12_NARROW_OBJECT_STATUS 0x07
|
||||
#define F12_HAND_EDGE_STATUS 0x08
|
||||
#define F12_COVER_STATUS 0x0A
|
||||
#define F12_STYLUS_STATUS 0x0B
|
||||
#define F12_ERASER_STATUS 0x0C
|
||||
#define F12_SMALL_OBJECT_STATUS 0x0D
|
||||
|
||||
#define F12_GESTURE_DETECTION_LEN 5
|
||||
|
||||
#define MAX_NUMBER_OF_BUTTONS 4
|
||||
#define MAX_INTR_REGISTERS 4
|
||||
|
||||
#define MASK_16BIT 0xFFFF
|
||||
#define MASK_8BIT 0xFF
|
||||
#define MASK_7BIT 0x7F
|
||||
#define MASK_6BIT 0x3F
|
||||
#define MASK_5BIT 0x1F
|
||||
#define MASK_4BIT 0x0F
|
||||
#define MASK_3BIT 0x07
|
||||
#define MASK_2BIT 0x03
|
||||
#define MASK_1BIT 0x01
|
||||
|
||||
#define PINCTRL_STATE_ACTIVE "pmx_ts_active"
|
||||
#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend"
|
||||
#define PINCTRL_STATE_RELEASE "pmx_ts_release"
|
||||
enum exp_fn {
|
||||
RMI_DEV = 0,
|
||||
RMI_FW_UPDATER,
|
||||
RMI_TEST_REPORTING,
|
||||
RMI_PROXIMITY,
|
||||
RMI_ACTIVE_PEN,
|
||||
RMI_GESTURE,
|
||||
RMI_VIDEO,
|
||||
RMI_DEBUG,
|
||||
RMI_LAST,
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_fn_desc - function descriptor fields in PDT entry
|
||||
* @query_base_addr: base address for query registers
|
||||
* @cmd_base_addr: base address for command registers
|
||||
* @ctrl_base_addr: base address for control registers
|
||||
* @data_base_addr: base address for data registers
|
||||
* @intr_src_count: number of interrupt sources
|
||||
* @fn_version: version of function
|
||||
* @fn_number: function number
|
||||
*/
|
||||
struct synaptics_rmi4_fn_desc {
|
||||
union {
|
||||
struct {
|
||||
unsigned char query_base_addr;
|
||||
unsigned char cmd_base_addr;
|
||||
unsigned char ctrl_base_addr;
|
||||
unsigned char data_base_addr;
|
||||
unsigned char intr_src_count:3;
|
||||
unsigned char reserved_1:2;
|
||||
unsigned char fn_version:2;
|
||||
unsigned char reserved_2:1;
|
||||
unsigned char fn_number;
|
||||
} __packed;
|
||||
unsigned char data[6];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* synaptics_rmi4_fn_full_addr - full 16-bit base addresses
|
||||
* @query_base: 16-bit base address for query registers
|
||||
* @cmd_base: 16-bit base address for command registers
|
||||
* @ctrl_base: 16-bit base address for control registers
|
||||
* @data_base: 16-bit base address for data registers
|
||||
*/
|
||||
struct synaptics_rmi4_fn_full_addr {
|
||||
unsigned short query_base;
|
||||
unsigned short cmd_base;
|
||||
unsigned short ctrl_base;
|
||||
unsigned short data_base;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_f11_extra_data - extra data of F$11
|
||||
* @data38_offset: offset to F11_2D_DATA38 register
|
||||
*/
|
||||
struct synaptics_rmi4_f11_extra_data {
|
||||
unsigned char data38_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_f12_extra_data - extra data of F$12
|
||||
* @data1_offset: offset to F12_2D_DATA01 register
|
||||
* @data4_offset: offset to F12_2D_DATA04 register
|
||||
* @data15_offset: offset to F12_2D_DATA15 register
|
||||
* @data15_size: size of F12_2D_DATA15 register
|
||||
* @data15_data: buffer for reading F12_2D_DATA15 register
|
||||
* @data23_offset: offset to F12_2D_DATA23 register
|
||||
* @data23_size: size of F12_2D_DATA23 register
|
||||
* @data23_data: buffer for reading F12_2D_DATA23 register
|
||||
* @ctrl20_offset: offset to F12_2D_CTRL20 register
|
||||
*/
|
||||
struct synaptics_rmi4_f12_extra_data {
|
||||
unsigned char data1_offset;
|
||||
unsigned char data4_offset;
|
||||
unsigned char data15_offset;
|
||||
unsigned char data15_size;
|
||||
unsigned char data15_data[(F12_FINGERS_TO_SUPPORT + 7) / 8];
|
||||
unsigned char data23_offset;
|
||||
unsigned char data23_size;
|
||||
unsigned char data23_data[F12_FINGERS_TO_SUPPORT];
|
||||
unsigned char ctrl20_offset;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_fn - RMI function handler
|
||||
* @fn_number: function number
|
||||
* @num_of_data_sources: number of data sources
|
||||
* @num_of_data_points: maximum number of fingers supported
|
||||
* @intr_reg_num: index to associated interrupt register
|
||||
* @intr_mask: interrupt mask
|
||||
* @full_addr: full 16-bit base addresses of function registers
|
||||
* @link: linked list for function handlers
|
||||
* @data_size: size of private data
|
||||
* @data: pointer to private data
|
||||
* @extra: pointer to extra data
|
||||
*/
|
||||
struct synaptics_rmi4_fn {
|
||||
unsigned char fn_number;
|
||||
unsigned char num_of_data_sources;
|
||||
unsigned char num_of_data_points;
|
||||
unsigned char intr_reg_num;
|
||||
unsigned char intr_mask;
|
||||
struct synaptics_rmi4_fn_full_addr full_addr;
|
||||
struct list_head link;
|
||||
int data_size;
|
||||
void *data;
|
||||
void *extra;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_device_info - device information
|
||||
* @version_major: RMI protocol major version number
|
||||
* @version_minor: RMI protocol minor version number
|
||||
* @manufacturer_id: manufacturer ID
|
||||
* @product_props: product properties
|
||||
* @product_info: product information
|
||||
* @product_id_string: product ID
|
||||
* @build_id: firmware build ID
|
||||
* @support_fn_list: linked list for function handlers
|
||||
*/
|
||||
struct synaptics_rmi4_device_info {
|
||||
unsigned int version_major;
|
||||
unsigned int version_minor;
|
||||
unsigned char manufacturer_id;
|
||||
unsigned char product_props;
|
||||
unsigned char product_info[PRODUCT_INFO_SIZE];
|
||||
unsigned char product_id_string[PRODUCT_ID_SIZE + 1];
|
||||
unsigned char build_id[BUILD_ID_SIZE];
|
||||
struct list_head support_fn_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_data - RMI4 device instance data
|
||||
* @pdev: pointer to platform device
|
||||
* @input_dev: pointer to associated input device
|
||||
* @stylus_dev: pointer to associated stylus device
|
||||
* @hw_if: pointer to hardware interface data
|
||||
* @rmi4_mod_info: device information
|
||||
* @board_prop_dir: /sys/board_properties directory for virtual key map file
|
||||
* @pwr_reg: pointer to regulator for power control
|
||||
* @bus_reg: pointer to regulator for bus pullup control
|
||||
* @rmi4_reset_mutex: mutex for software reset
|
||||
* @rmi4_report_mutex: mutex for input event reporting
|
||||
* @rmi4_io_ctrl_mutex: mutex for communication interface I/O
|
||||
* @rmi4_exp_init_mutex: mutex for expansion function module initialization
|
||||
* @rb_work: work for rebuilding input device
|
||||
* @rb_workqueue: workqueue for rebuilding input device
|
||||
* @fb_notifier: framebuffer notifier client
|
||||
* @reset_work: work for issuing reset after display framebuffer ready
|
||||
* @reset_workqueue: workqueue for issuing reset after display framebuffer ready
|
||||
* @early_suspend: early suspend power management
|
||||
* @current_page: current RMI page for register access
|
||||
* @button_0d_enabled: switch for enabling 0d button support
|
||||
* @num_of_tx: number of Tx channels for 2D touch
|
||||
* @num_of_rx: number of Rx channels for 2D touch
|
||||
* @num_of_fingers: maximum number of fingers for 2D touch
|
||||
* @max_touch_width: maximum touch width
|
||||
* @report_enable: input data to report for F$12
|
||||
* @no_sleep_setting: default setting of NoSleep in F01_RMI_CTRL00 register
|
||||
* @gesture_detection: detected gesture type and properties
|
||||
* @intr_mask: interrupt enable mask
|
||||
* @button_txrx_mapping: Tx Rx mapping of 0D buttons
|
||||
* @num_of_intr_regs: number of interrupt registers
|
||||
* @f01_query_base_addr: query base address for f$01
|
||||
* @f01_cmd_base_addr: command base address for f$01
|
||||
* @f01_ctrl_base_addr: control base address for f$01
|
||||
* @f01_data_base_addr: data base address for f$01
|
||||
* @firmware_id: firmware build ID
|
||||
* @irq: attention interrupt
|
||||
* @sensor_max_x: maximum x coordinate for 2D touch
|
||||
* @sensor_max_y: maximum y coordinate for 2D touch
|
||||
* @flash_prog_mode: flag to indicate flash programming mode status
|
||||
* @irq_enabled: flag to indicate attention interrupt enable status
|
||||
* @fingers_on_2d: flag to indicate presence of fingers in 2D area
|
||||
* @suspend: flag to indicate whether in suspend state
|
||||
* @sensor_sleep: flag to indicate sleep state of sensor
|
||||
* @stay_awake: flag to indicate whether to stay awake during suspend
|
||||
* @fb_ready: flag to indicate whether display framebuffer in ready state
|
||||
* @f11_wakeup_gesture: flag to indicate support for wakeup gestures in F$11
|
||||
* @f12_wakeup_gesture: flag to indicate support for wakeup gestures in F$12
|
||||
* @enable_wakeup_gesture: flag to indicate usage of wakeup gestures
|
||||
* @wedge_sensor: flag to indicate use of wedge sensor
|
||||
* @report_pressure: flag to indicate reporting of pressure data
|
||||
* @stylus_enable: flag to indicate reporting of stylus data
|
||||
* @eraser_enable: flag to indicate reporting of eraser data
|
||||
* @external_afe_buttons: flag to indicate presence of external AFE buttons
|
||||
* @reset_device: pointer to device reset function
|
||||
* @irq_enable: pointer to interrupt enable function
|
||||
* @sleep_enable: pointer to sleep enable function
|
||||
* @report_touch: pointer to touch reporting function
|
||||
*/
|
||||
struct synaptics_rmi4_data {
|
||||
struct platform_device *pdev;
|
||||
struct input_dev *input_dev;
|
||||
struct input_dev *stylus_dev;
|
||||
const struct synaptics_dsx_hw_interface *hw_if;
|
||||
struct synaptics_rmi4_device_info rmi4_mod_info;
|
||||
struct kobject *board_prop_dir;
|
||||
struct regulator *pwr_reg;
|
||||
struct regulator *bus_reg;
|
||||
struct mutex rmi4_reset_mutex;
|
||||
struct mutex rmi4_report_mutex;
|
||||
struct mutex rmi4_io_ctrl_mutex;
|
||||
struct mutex rmi4_exp_init_mutex;
|
||||
struct delayed_work rb_work;
|
||||
struct workqueue_struct *rb_workqueue;
|
||||
#ifdef CONFIG_FB
|
||||
struct work_struct fb_notify_work;
|
||||
struct notifier_block fb_notifier;
|
||||
struct work_struct reset_work;
|
||||
struct workqueue_struct *reset_workqueue;
|
||||
#endif
|
||||
#ifdef CONFIG_HAS_EARLYSUSPEND
|
||||
struct early_suspend early_suspend;
|
||||
#endif
|
||||
unsigned char current_page;
|
||||
unsigned char button_0d_enabled;
|
||||
unsigned char num_of_tx;
|
||||
unsigned char num_of_rx;
|
||||
unsigned char num_of_fingers;
|
||||
unsigned char max_touch_width;
|
||||
unsigned char report_enable;
|
||||
unsigned char no_sleep_setting;
|
||||
unsigned char gesture_detection[F12_GESTURE_DETECTION_LEN];
|
||||
unsigned char intr_mask[MAX_INTR_REGISTERS];
|
||||
unsigned char *button_txrx_mapping;
|
||||
unsigned short num_of_intr_regs;
|
||||
unsigned short f01_query_base_addr;
|
||||
unsigned short f01_cmd_base_addr;
|
||||
unsigned short f01_ctrl_base_addr;
|
||||
unsigned short f01_data_base_addr;
|
||||
unsigned int firmware_id;
|
||||
int irq;
|
||||
int sensor_max_x;
|
||||
int sensor_max_y;
|
||||
bool flash_prog_mode;
|
||||
bool irq_enabled;
|
||||
bool fingers_on_2d;
|
||||
bool suspend;
|
||||
bool sensor_sleep;
|
||||
bool stay_awake;
|
||||
bool fb_ready;
|
||||
bool f11_wakeup_gesture;
|
||||
bool f12_wakeup_gesture;
|
||||
bool enable_wakeup_gesture;
|
||||
bool wedge_sensor;
|
||||
bool report_pressure;
|
||||
bool stylus_enable;
|
||||
bool eraser_enable;
|
||||
bool external_afe_buttons;
|
||||
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data,
|
||||
bool rebuild);
|
||||
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable,
|
||||
bool attn_only);
|
||||
void (*sleep_enable)(struct synaptics_rmi4_data *rmi4_data,
|
||||
bool enable);
|
||||
void (*report_touch)(struct synaptics_rmi4_data *rmi4_data,
|
||||
struct synaptics_rmi4_fn *fhandler);
|
||||
struct pinctrl *ts_pinctrl;
|
||||
struct pinctrl_state *pinctrl_state_active;
|
||||
struct pinctrl_state *pinctrl_state_suspend;
|
||||
struct pinctrl_state *pinctrl_state_release;
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
atomic_t st_enabled;
|
||||
atomic_t st_pending_irqs;
|
||||
struct completion st_powerdown;
|
||||
struct completion st_irq_processed;
|
||||
bool st_initialized;
|
||||
struct clk *core_clk;
|
||||
struct clk *iface_clk;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct synaptics_dsx_bus_access {
|
||||
unsigned char type;
|
||||
int (*read)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
|
||||
unsigned char *data, unsigned short length);
|
||||
int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
|
||||
unsigned char *data, unsigned short length);
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
int (*get)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*put)(struct synaptics_rmi4_data *rmi4_data);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct synaptics_dsx_hw_interface {
|
||||
struct synaptics_dsx_board_data *board_data;
|
||||
const struct synaptics_dsx_bus_access *bus_access;
|
||||
int (*bl_hw_init)(struct synaptics_rmi4_data *rmi4_data);
|
||||
int (*ui_hw_init)(struct synaptics_rmi4_data *rmi4_data);
|
||||
};
|
||||
|
||||
struct synaptics_rmi4_exp_fn {
|
||||
enum exp_fn fn_type;
|
||||
int (*init)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*remove)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*reset)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*reinit)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*early_suspend)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*suspend)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*resume)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*late_resume)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*attn)(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned char intr_mask);
|
||||
};
|
||||
|
||||
int synaptics_rmi4_bus_init_v26(void);
|
||||
|
||||
void synaptics_rmi4_bus_exit_v26(void);
|
||||
|
||||
void synaptics_rmi4_new_function(struct synaptics_rmi4_exp_fn *exp_fn_module,
|
||||
bool insert);
|
||||
|
||||
int synaptics_fw_updater(const unsigned char *fw_data);
|
||||
|
||||
static inline int synaptics_rmi4_reg_read(
|
||||
struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr,
|
||||
unsigned char *data,
|
||||
unsigned short len)
|
||||
{
|
||||
return rmi4_data->hw_if->bus_access->read(rmi4_data, addr, data, len);
|
||||
}
|
||||
|
||||
static inline int synaptics_rmi4_reg_write(
|
||||
struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr,
|
||||
unsigned char *data,
|
||||
unsigned short len)
|
||||
{
|
||||
return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
return rmi4_data->hw_if->bus_access->get(rmi4_data);
|
||||
}
|
||||
static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
rmi4_data->hw_if->bus_access->put(rmi4_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int secure_memcpy(unsigned char *dest, unsigned int dest_size,
|
||||
const unsigned char *src, unsigned int src_size,
|
||||
unsigned int count)
|
||||
{
|
||||
if (dest == NULL || src == NULL)
|
||||
return -EINVAL;
|
||||
|
||||
if (count > dest_size || count > src_size)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy((void *)dest, (const void *)src, count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void batohs(unsigned short *dest, unsigned char *src)
|
||||
{
|
||||
*dest = src[1] * 0x100 + src[0];
|
||||
}
|
||||
|
||||
static inline void hstoba(unsigned char *dest, unsigned short src)
|
||||
{
|
||||
dest[0] = src % 0x100;
|
||||
dest[1] = src / 0x100;
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,712 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
* Copyright (C) 2016, The Linux Foundation. All rights reserved.
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input/synaptics_dsx_v2_6.h>
|
||||
#include "synaptics_dsx_core.h"
|
||||
|
||||
#define SYN_I2C_RETRY_TIMES 10
|
||||
|
||||
/*
|
||||
#define I2C_BURST_LIMIT 255
|
||||
*/
|
||||
/*
|
||||
#define XFER_MSGS_LIMIT 8
|
||||
*/
|
||||
|
||||
static unsigned char *wr_buf;
|
||||
|
||||
static struct synaptics_dsx_hw_interface hw_if;
|
||||
|
||||
static struct platform_device *synaptics_dsx_i2c_device;
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
|
||||
{
|
||||
int retval;
|
||||
u32 value;
|
||||
const char *name;
|
||||
struct property *prop;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
bdata->irq_gpio = of_get_named_gpio_flags(np,
|
||||
"synaptics,irq-gpio", 0,
|
||||
(enum of_gpio_flags *)&bdata->irq_flags);
|
||||
|
||||
retval = of_property_read_u32(np, "synaptics,irq-on-state",
|
||||
&value);
|
||||
if (retval < 0)
|
||||
bdata->irq_on_state = 0;
|
||||
else
|
||||
bdata->irq_on_state = value;
|
||||
|
||||
bdata->resume_in_workqueue = of_property_read_bool(np,
|
||||
"synaptics,resume-in-workqueue");
|
||||
|
||||
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
|
||||
if (retval < 0)
|
||||
bdata->pwr_reg_name = NULL;
|
||||
else
|
||||
bdata->pwr_reg_name = name;
|
||||
|
||||
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
|
||||
if (retval < 0)
|
||||
bdata->bus_reg_name = NULL;
|
||||
else
|
||||
bdata->bus_reg_name = name;
|
||||
|
||||
prop = of_find_property(np, "synaptics,power-gpio", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->power_gpio = of_get_named_gpio_flags(np,
|
||||
"synaptics,power-gpio", 0, NULL);
|
||||
retval = of_property_read_u32(np, "synaptics,power-on-state",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->power_on_state = value;
|
||||
}
|
||||
} else {
|
||||
bdata->power_gpio = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->power_delay_ms = value;
|
||||
}
|
||||
} else {
|
||||
bdata->power_delay_ms = 0;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->reset_gpio = of_get_named_gpio_flags(np,
|
||||
"synaptics,reset-gpio", 0, NULL);
|
||||
retval = of_property_read_u32(np, "synaptics,reset-on-state",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->reset_on_state = value;
|
||||
}
|
||||
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->reset_active_ms = value;
|
||||
}
|
||||
} else {
|
||||
bdata->reset_gpio = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->reset_delay_ms = value;
|
||||
}
|
||||
} else {
|
||||
bdata->reset_delay_ms = 0;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->max_y_for_2d = value;
|
||||
}
|
||||
} else {
|
||||
bdata->max_y_for_2d = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,swap-axes", NULL);
|
||||
bdata->swap_axes = prop > 0 ? true : false;
|
||||
|
||||
prop = of_find_property(np, "synaptics,x-flip", NULL);
|
||||
bdata->x_flip = prop > 0 ? true : false;
|
||||
|
||||
prop = of_find_property(np, "synaptics,y-flip", NULL);
|
||||
bdata->y_flip = prop > 0 ? true : false;
|
||||
|
||||
prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->ub_i2c_addr = (unsigned short)value;
|
||||
}
|
||||
} else {
|
||||
bdata->ub_i2c_addr = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->cap_button_map->map = devm_kzalloc(dev,
|
||||
prop->length,
|
||||
GFP_KERNEL);
|
||||
if (!bdata->cap_button_map->map)
|
||||
return -ENOMEM;
|
||||
bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
|
||||
retval = of_property_read_u32_array(np,
|
||||
"synaptics,cap-button-codes",
|
||||
bdata->cap_button_map->map,
|
||||
bdata->cap_button_map->nbuttons);
|
||||
if (retval < 0) {
|
||||
bdata->cap_button_map->nbuttons = 0;
|
||||
bdata->cap_button_map->map = NULL;
|
||||
}
|
||||
} else {
|
||||
bdata->cap_button_map->nbuttons = 0;
|
||||
bdata->cap_button_map->map = NULL;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->vir_button_map->map = devm_kzalloc(dev,
|
||||
prop->length,
|
||||
GFP_KERNEL);
|
||||
if (!bdata->vir_button_map->map)
|
||||
return -ENOMEM;
|
||||
bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
|
||||
bdata->vir_button_map->nbuttons /= 5;
|
||||
retval = of_property_read_u32_array(np,
|
||||
"synaptics,vir-button-codes",
|
||||
bdata->vir_button_map->map,
|
||||
bdata->vir_button_map->nbuttons * 5);
|
||||
if (retval < 0) {
|
||||
bdata->vir_button_map->nbuttons = 0;
|
||||
bdata->vir_button_map->map = NULL;
|
||||
}
|
||||
} else {
|
||||
bdata->vir_button_map->nbuttons = 0;
|
||||
bdata->vir_button_map->map = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int synaptics_rmi4_i2c_alloc_buf(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned int count)
|
||||
{
|
||||
static unsigned int buf_size;
|
||||
|
||||
if (count > buf_size) {
|
||||
if (buf_size)
|
||||
kfree(wr_buf);
|
||||
wr_buf = kzalloc(count, GFP_KERNEL);
|
||||
if (!wr_buf) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to alloc mem for buffer\n",
|
||||
__func__);
|
||||
buf_size = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
buf_size = count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_i2c_check_addr(struct synaptics_rmi4_data *rmi4_data,
|
||||
struct i2c_client *i2c)
|
||||
{
|
||||
if (hw_if.board_data->ub_i2c_addr == -1)
|
||||
return;
|
||||
|
||||
if (hw_if.board_data->i2c_addr == i2c->addr)
|
||||
hw_if.board_data->i2c_addr = hw_if.board_data->ub_i2c_addr;
|
||||
else
|
||||
hw_if.board_data->i2c_addr = i2c->addr;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_set_page(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr)
|
||||
{
|
||||
int retval = 0;
|
||||
unsigned char retry;
|
||||
unsigned char buf[PAGE_SELECT_LEN];
|
||||
unsigned char page;
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
struct i2c_msg msg[1];
|
||||
|
||||
msg[0].addr = hw_if.board_data->i2c_addr;
|
||||
msg[0].flags = 0;
|
||||
msg[0].len = PAGE_SELECT_LEN;
|
||||
msg[0].buf = buf;
|
||||
|
||||
page = ((addr >> 8) & MASK_8BIT);
|
||||
buf[0] = MASK_8BIT;
|
||||
buf[1] = page;
|
||||
|
||||
if (page != rmi4_data->current_page) {
|
||||
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
|
||||
if (i2c_transfer(i2c->adapter, msg, 1) == 1) {
|
||||
rmi4_data->current_page = page;
|
||||
retval = PAGE_SELECT_LEN;
|
||||
break;
|
||||
}
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: I2C retry %d\n",
|
||||
__func__, retry + 1);
|
||||
msleep(20);
|
||||
|
||||
if (retry == SYN_I2C_RETRY_TIMES / 2) {
|
||||
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
|
||||
msg[0].addr = hw_if.board_data->i2c_addr;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
retval = PAGE_SELECT_LEN;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_read(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr, unsigned char *data, unsigned short length)
|
||||
{
|
||||
int retval;
|
||||
unsigned char retry;
|
||||
unsigned char buf;
|
||||
#ifdef I2C_BURST_LIMIT
|
||||
unsigned char ii;
|
||||
unsigned char rd_msgs = ((length - 1) / I2C_BURST_LIMIT) + 1;
|
||||
#else
|
||||
unsigned char rd_msgs = 1;
|
||||
#endif
|
||||
unsigned char index = 0;
|
||||
unsigned char xfer_msgs;
|
||||
unsigned char remaining_msgs;
|
||||
unsigned short i2c_addr;
|
||||
unsigned short data_offset = 0;
|
||||
unsigned short remaining_length = length;
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
struct i2c_adapter *adap = i2c->adapter;
|
||||
struct i2c_msg msg[rd_msgs + 1];
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
|
||||
if (retval != PAGE_SELECT_LEN) {
|
||||
retval = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
msg[0].addr = hw_if.board_data->i2c_addr;
|
||||
msg[0].flags = 0;
|
||||
msg[0].len = 1;
|
||||
msg[0].buf = &buf;
|
||||
|
||||
#ifdef I2C_BURST_LIMIT
|
||||
for (ii = 0; ii < (rd_msgs - 1); ii++) {
|
||||
msg[ii + 1].addr = hw_if.board_data->i2c_addr;
|
||||
msg[ii + 1].flags = I2C_M_RD;
|
||||
msg[ii + 1].len = I2C_BURST_LIMIT;
|
||||
msg[ii + 1].buf = &data[data_offset];
|
||||
data_offset += I2C_BURST_LIMIT;
|
||||
remaining_length -= I2C_BURST_LIMIT;
|
||||
}
|
||||
#endif
|
||||
|
||||
msg[rd_msgs].addr = hw_if.board_data->i2c_addr;
|
||||
msg[rd_msgs].flags = I2C_M_RD;
|
||||
msg[rd_msgs].len = remaining_length;
|
||||
msg[rd_msgs].buf = &data[data_offset];
|
||||
|
||||
buf = addr & MASK_8BIT;
|
||||
|
||||
remaining_msgs = rd_msgs + 1;
|
||||
|
||||
while (remaining_msgs) {
|
||||
#ifdef XFER_MSGS_LIMIT
|
||||
if (remaining_msgs > XFER_MSGS_LIMIT)
|
||||
xfer_msgs = XFER_MSGS_LIMIT;
|
||||
else
|
||||
xfer_msgs = remaining_msgs;
|
||||
#else
|
||||
xfer_msgs = remaining_msgs;
|
||||
#endif
|
||||
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
|
||||
retval = i2c_transfer(adap, &msg[index], xfer_msgs);
|
||||
if (retval == xfer_msgs)
|
||||
break;
|
||||
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: I2C retry %d\n",
|
||||
__func__, retry + 1);
|
||||
msleep(20);
|
||||
|
||||
if (retry == SYN_I2C_RETRY_TIMES / 2) {
|
||||
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
|
||||
i2c_addr = hw_if.board_data->i2c_addr;
|
||||
msg[0].addr = i2c_addr;
|
||||
#ifdef I2C_BURST_LIMIT
|
||||
for (ii = 0; ii < (rd_msgs - 1); ii++)
|
||||
msg[ii + 1].addr = i2c_addr;
|
||||
#endif
|
||||
msg[rd_msgs].addr = i2c_addr;
|
||||
}
|
||||
}
|
||||
|
||||
if (retry == SYN_I2C_RETRY_TIMES) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: I2C read over retry limit\n",
|
||||
__func__);
|
||||
retval = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
remaining_msgs -= xfer_msgs;
|
||||
index += xfer_msgs;
|
||||
}
|
||||
|
||||
retval = length;
|
||||
|
||||
exit:
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_write(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr, unsigned char *data, unsigned short length)
|
||||
{
|
||||
int retval;
|
||||
unsigned char retry;
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
struct i2c_msg msg[1];
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
retval = synaptics_rmi4_i2c_alloc_buf(rmi4_data, length + 1);
|
||||
if (retval < 0)
|
||||
goto exit;
|
||||
|
||||
retval = synaptics_rmi4_i2c_set_page(rmi4_data, addr);
|
||||
if (retval != PAGE_SELECT_LEN) {
|
||||
retval = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
msg[0].addr = hw_if.board_data->i2c_addr;
|
||||
msg[0].flags = 0;
|
||||
msg[0].len = length + 1;
|
||||
msg[0].buf = wr_buf;
|
||||
|
||||
wr_buf[0] = addr & MASK_8BIT;
|
||||
retval = secure_memcpy(&wr_buf[1], length, &data[0], length, length);
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to copy data\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) {
|
||||
if (i2c_transfer(i2c->adapter, msg, 1) == 1) {
|
||||
retval = length;
|
||||
break;
|
||||
}
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: I2C retry %d\n",
|
||||
__func__, retry + 1);
|
||||
msleep(20);
|
||||
|
||||
if (retry == SYN_I2C_RETRY_TIMES / 2) {
|
||||
synaptics_rmi4_i2c_check_addr(rmi4_data, i2c);
|
||||
msg[0].addr = hw_if.board_data->i2c_addr;
|
||||
}
|
||||
}
|
||||
|
||||
if (retry == SYN_I2C_RETRY_TIMES) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: I2C write over retry limit\n",
|
||||
__func__);
|
||||
retval = -EIO;
|
||||
}
|
||||
|
||||
exit:
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
static int synaptics_rmi4_clk_prepare_enable(
|
||||
struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(rmi4_data->iface_clk);
|
||||
if (ret) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"error on clk_prepare_enable(iface_clk):%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rmi4_data->core_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(rmi4_data->iface_clk);
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"error clk_prepare_enable(core_clk):%d\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_clk_disable_unprepare(
|
||||
struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
clk_disable_unprepare(rmi4_data->core_clk);
|
||||
clk_disable_unprepare(rmi4_data->iface_clk);
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
retval = pm_runtime_get_sync(i2c->adapter->dev.parent);
|
||||
if (retval >= 0 && rmi4_data->core_clk != NULL &&
|
||||
rmi4_data->iface_clk != NULL) {
|
||||
retval = synaptics_rmi4_clk_prepare_enable(rmi4_data);
|
||||
if (retval)
|
||||
pm_runtime_put_sync(i2c->adapter->dev.parent);
|
||||
}
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
if (rmi4_data->core_clk != NULL && rmi4_data->iface_clk != NULL)
|
||||
synaptics_rmi4_clk_disable_unprepare(rmi4_data);
|
||||
pm_runtime_put_sync(i2c->adapter->dev.parent);
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct synaptics_dsx_bus_access bus_access = {
|
||||
.type = BUS_I2C,
|
||||
.read = synaptics_rmi4_i2c_read,
|
||||
.write = synaptics_rmi4_i2c_write,
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
.get = synaptics_rmi4_i2c_get,
|
||||
.put = synaptics_rmi4_i2c_put,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void synaptics_rmi4_i2c_dev_release(struct device *dev)
|
||||
{
|
||||
kfree(synaptics_dsx_i2c_device);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *dev_id)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter,
|
||||
I2C_FUNC_SMBUS_BYTE_DATA)) {
|
||||
dev_err(&client->dev,
|
||||
"%s: SMBus byte data commands not supported by host\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
synaptics_dsx_i2c_device = kzalloc(
|
||||
sizeof(struct platform_device),
|
||||
GFP_KERNEL);
|
||||
if (!synaptics_dsx_i2c_device) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to allocate memory for synaptics_dsx_i2c_device\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (client->dev.of_node) {
|
||||
hw_if.board_data = devm_kzalloc(&client->dev,
|
||||
sizeof(struct synaptics_dsx_board_data),
|
||||
GFP_KERNEL);
|
||||
if (!hw_if.board_data) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to allocate memory for board data\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
hw_if.board_data->cap_button_map = devm_kzalloc(&client->dev,
|
||||
sizeof(struct synaptics_dsx_button_map),
|
||||
GFP_KERNEL);
|
||||
if (!hw_if.board_data->cap_button_map) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to allocate memory for 0D button map\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
hw_if.board_data->vir_button_map = devm_kzalloc(&client->dev,
|
||||
sizeof(struct synaptics_dsx_button_map),
|
||||
GFP_KERNEL);
|
||||
if (!hw_if.board_data->vir_button_map) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to allocate memory for virtual button map\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
parse_dt(&client->dev, hw_if.board_data);
|
||||
}
|
||||
#else
|
||||
hw_if.board_data = client->dev.platform_data;
|
||||
#endif
|
||||
|
||||
hw_if.bus_access = &bus_access;
|
||||
hw_if.board_data->i2c_addr = client->addr;
|
||||
|
||||
synaptics_dsx_i2c_device->name = PLATFORM_DRIVER_NAME;
|
||||
synaptics_dsx_i2c_device->id = 0;
|
||||
synaptics_dsx_i2c_device->num_resources = 0;
|
||||
synaptics_dsx_i2c_device->dev.parent = &client->dev;
|
||||
synaptics_dsx_i2c_device->dev.platform_data = &hw_if;
|
||||
synaptics_dsx_i2c_device->dev.release = synaptics_rmi4_i2c_dev_release;
|
||||
|
||||
retval = platform_device_register(synaptics_dsx_i2c_device);
|
||||
if (retval) {
|
||||
dev_err(&client->dev,
|
||||
"%s: Failed to register platform device\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
platform_device_unregister(synaptics_dsx_i2c_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id synaptics_rmi4_id_table[] = {
|
||||
{I2C_DRIVER_NAME, 0},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, synaptics_rmi4_id_table);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id synaptics_rmi4_of_match_table[] = {
|
||||
{
|
||||
.compatible = "synaptics,dsx-i2c",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
|
||||
#else
|
||||
#define synaptics_rmi4_of_match_table NULL
|
||||
#endif
|
||||
|
||||
static struct i2c_driver synaptics_rmi4_i2c_driver = {
|
||||
.driver = {
|
||||
.name = I2C_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = synaptics_rmi4_of_match_table,
|
||||
},
|
||||
.probe = synaptics_rmi4_i2c_probe,
|
||||
.remove = synaptics_rmi4_i2c_remove,
|
||||
.id_table = synaptics_rmi4_id_table,
|
||||
};
|
||||
|
||||
int synaptics_rmi4_bus_init_v26(void)
|
||||
{
|
||||
return i2c_add_driver(&synaptics_rmi4_i2c_driver);
|
||||
}
|
||||
EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26);
|
||||
|
||||
void synaptics_rmi4_bus_exit_v26(void)
|
||||
{
|
||||
kfree(wr_buf);
|
||||
|
||||
i2c_del_driver(&synaptics_rmi4_i2c_driver);
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26);
|
||||
|
||||
MODULE_AUTHOR("Synaptics, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX I2C Bus Support Module");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,692 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input/synaptics_dsx_v2_6.h>
|
||||
#include "synaptics_dsx_core.h"
|
||||
|
||||
#define PROX_PHYS_NAME "synaptics_dsx/proximity"
|
||||
|
||||
#define HOVER_Z_MAX (255)
|
||||
|
||||
#define HOVERING_FINGER_EN (1 << 4)
|
||||
|
||||
static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
|
||||
static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static struct device_attribute attrs[] = {
|
||||
__ATTR(hover_finger_en, (S_IRUGO | S_IWUGO),
|
||||
synaptics_rmi4_hover_finger_en_show,
|
||||
synaptics_rmi4_hover_finger_en_store),
|
||||
};
|
||||
|
||||
struct synaptics_rmi4_f12_query_5 {
|
||||
union {
|
||||
struct {
|
||||
unsigned char size_of_query6;
|
||||
struct {
|
||||
unsigned char ctrl0_is_present:1;
|
||||
unsigned char ctrl1_is_present:1;
|
||||
unsigned char ctrl2_is_present:1;
|
||||
unsigned char ctrl3_is_present:1;
|
||||
unsigned char ctrl4_is_present:1;
|
||||
unsigned char ctrl5_is_present:1;
|
||||
unsigned char ctrl6_is_present:1;
|
||||
unsigned char ctrl7_is_present:1;
|
||||
} __packed;
|
||||
struct {
|
||||
unsigned char ctrl8_is_present:1;
|
||||
unsigned char ctrl9_is_present:1;
|
||||
unsigned char ctrl10_is_present:1;
|
||||
unsigned char ctrl11_is_present:1;
|
||||
unsigned char ctrl12_is_present:1;
|
||||
unsigned char ctrl13_is_present:1;
|
||||
unsigned char ctrl14_is_present:1;
|
||||
unsigned char ctrl15_is_present:1;
|
||||
} __packed;
|
||||
struct {
|
||||
unsigned char ctrl16_is_present:1;
|
||||
unsigned char ctrl17_is_present:1;
|
||||
unsigned char ctrl18_is_present:1;
|
||||
unsigned char ctrl19_is_present:1;
|
||||
unsigned char ctrl20_is_present:1;
|
||||
unsigned char ctrl21_is_present:1;
|
||||
unsigned char ctrl22_is_present:1;
|
||||
unsigned char ctrl23_is_present:1;
|
||||
} __packed;
|
||||
};
|
||||
unsigned char data[4];
|
||||
};
|
||||
};
|
||||
|
||||
struct synaptics_rmi4_f12_query_8 {
|
||||
union {
|
||||
struct {
|
||||
unsigned char size_of_query9;
|
||||
struct {
|
||||
unsigned char data0_is_present:1;
|
||||
unsigned char data1_is_present:1;
|
||||
unsigned char data2_is_present:1;
|
||||
unsigned char data3_is_present:1;
|
||||
unsigned char data4_is_present:1;
|
||||
unsigned char data5_is_present:1;
|
||||
unsigned char data6_is_present:1;
|
||||
unsigned char data7_is_present:1;
|
||||
} __packed;
|
||||
};
|
||||
unsigned char data[2];
|
||||
};
|
||||
};
|
||||
|
||||
struct prox_finger_data {
|
||||
union {
|
||||
struct {
|
||||
unsigned char object_type_and_status;
|
||||
unsigned char x_lsb;
|
||||
unsigned char x_msb;
|
||||
unsigned char y_lsb;
|
||||
unsigned char y_msb;
|
||||
unsigned char z;
|
||||
} __packed;
|
||||
unsigned char proximity_data[6];
|
||||
};
|
||||
};
|
||||
|
||||
struct synaptics_rmi4_prox_handle {
|
||||
bool hover_finger_present;
|
||||
bool hover_finger_en;
|
||||
unsigned char intr_mask;
|
||||
unsigned short query_base_addr;
|
||||
unsigned short control_base_addr;
|
||||
unsigned short data_base_addr;
|
||||
unsigned short command_base_addr;
|
||||
unsigned short hover_finger_en_addr;
|
||||
unsigned short hover_finger_data_addr;
|
||||
struct input_dev *prox_dev;
|
||||
struct prox_finger_data *finger_data;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
};
|
||||
|
||||
static struct synaptics_rmi4_prox_handle *prox;
|
||||
|
||||
DECLARE_COMPLETION(prox_remove_complete);
|
||||
|
||||
static void prox_hover_finger_lift(void)
|
||||
{
|
||||
input_report_key(prox->prox_dev, BTN_TOUCH, 0);
|
||||
input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 0);
|
||||
input_sync(prox->prox_dev);
|
||||
prox->hover_finger_present = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void prox_hover_finger_report(void)
|
||||
{
|
||||
int retval;
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
struct prox_finger_data *data;
|
||||
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
|
||||
|
||||
data = prox->finger_data;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
prox->hover_finger_data_addr,
|
||||
data->proximity_data,
|
||||
sizeof(data->proximity_data));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to read hovering finger data\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->object_type_and_status != F12_HOVERING_FINGER_STATUS) {
|
||||
if (prox->hover_finger_present)
|
||||
prox_hover_finger_lift();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
x = (data->x_msb << 8) | (data->x_lsb);
|
||||
y = (data->y_msb << 8) | (data->y_lsb);
|
||||
z = HOVER_Z_MAX - data->z;
|
||||
|
||||
input_report_key(prox->prox_dev, BTN_TOUCH, 0);
|
||||
input_report_key(prox->prox_dev, BTN_TOOL_FINGER, 1);
|
||||
input_report_abs(prox->prox_dev, ABS_X, x);
|
||||
input_report_abs(prox->prox_dev, ABS_Y, y);
|
||||
input_report_abs(prox->prox_dev, ABS_DISTANCE, z);
|
||||
|
||||
input_sync(prox->prox_dev);
|
||||
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: x = %d y = %d z = %d\n",
|
||||
__func__, x, y, z);
|
||||
|
||||
prox->hover_finger_present = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int prox_set_hover_finger_en(void)
|
||||
{
|
||||
int retval;
|
||||
unsigned char object_report_enable;
|
||||
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
prox->hover_finger_en_addr,
|
||||
&object_report_enable,
|
||||
sizeof(object_report_enable));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to read from object report enable register\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (prox->hover_finger_en)
|
||||
object_report_enable |= HOVERING_FINGER_EN;
|
||||
else
|
||||
object_report_enable &= ~HOVERING_FINGER_EN;
|
||||
|
||||
retval = synaptics_rmi4_reg_write(rmi4_data,
|
||||
prox->hover_finger_en_addr,
|
||||
&object_report_enable,
|
||||
sizeof(object_report_enable));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to write to object report enable register\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prox_set_params(void)
|
||||
{
|
||||
input_set_abs_params(prox->prox_dev, ABS_X, 0,
|
||||
prox->rmi4_data->sensor_max_x, 0, 0);
|
||||
input_set_abs_params(prox->prox_dev, ABS_Y, 0,
|
||||
prox->rmi4_data->sensor_max_y, 0, 0);
|
||||
input_set_abs_params(prox->prox_dev, ABS_DISTANCE, 0,
|
||||
HOVER_Z_MAX, 0, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int prox_reg_init(void)
|
||||
{
|
||||
int retval;
|
||||
unsigned char ctrl_23_offset;
|
||||
unsigned char data_1_offset;
|
||||
struct synaptics_rmi4_f12_query_5 query_5;
|
||||
struct synaptics_rmi4_f12_query_8 query_8;
|
||||
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
prox->query_base_addr + 5,
|
||||
query_5.data,
|
||||
sizeof(query_5.data));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
ctrl_23_offset = query_5.ctrl0_is_present +
|
||||
query_5.ctrl1_is_present +
|
||||
query_5.ctrl2_is_present +
|
||||
query_5.ctrl3_is_present +
|
||||
query_5.ctrl4_is_present +
|
||||
query_5.ctrl5_is_present +
|
||||
query_5.ctrl6_is_present +
|
||||
query_5.ctrl7_is_present +
|
||||
query_5.ctrl8_is_present +
|
||||
query_5.ctrl9_is_present +
|
||||
query_5.ctrl10_is_present +
|
||||
query_5.ctrl11_is_present +
|
||||
query_5.ctrl12_is_present +
|
||||
query_5.ctrl13_is_present +
|
||||
query_5.ctrl14_is_present +
|
||||
query_5.ctrl15_is_present +
|
||||
query_5.ctrl16_is_present +
|
||||
query_5.ctrl17_is_present +
|
||||
query_5.ctrl18_is_present +
|
||||
query_5.ctrl19_is_present +
|
||||
query_5.ctrl20_is_present +
|
||||
query_5.ctrl21_is_present +
|
||||
query_5.ctrl22_is_present;
|
||||
|
||||
prox->hover_finger_en_addr = prox->control_base_addr + ctrl_23_offset;
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
prox->query_base_addr + 8,
|
||||
query_8.data,
|
||||
sizeof(query_8.data));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
data_1_offset = query_8.data0_is_present;
|
||||
prox->hover_finger_data_addr = prox->data_base_addr + data_1_offset;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int prox_scan_pdt(void)
|
||||
{
|
||||
int retval;
|
||||
unsigned char ii;
|
||||
unsigned char page;
|
||||
unsigned char intr_count = 0;
|
||||
unsigned char intr_off;
|
||||
unsigned char intr_src;
|
||||
unsigned short addr;
|
||||
struct synaptics_rmi4_fn_desc fd;
|
||||
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
|
||||
|
||||
for (page = 0; page < PAGES_TO_SERVICE; page++) {
|
||||
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
|
||||
addr |= (page << 8);
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
addr,
|
||||
(unsigned char *)&fd,
|
||||
sizeof(fd));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
addr &= ~(MASK_8BIT << 8);
|
||||
|
||||
if (fd.fn_number) {
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Found F%02x\n",
|
||||
__func__, fd.fn_number);
|
||||
switch (fd.fn_number) {
|
||||
case SYNAPTICS_RMI4_F12:
|
||||
goto f12_found;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
intr_count += fd.intr_src_count;
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to find F12\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
|
||||
f12_found:
|
||||
prox->query_base_addr = fd.query_base_addr | (page << 8);
|
||||
prox->control_base_addr = fd.ctrl_base_addr | (page << 8);
|
||||
prox->data_base_addr = fd.data_base_addr | (page << 8);
|
||||
prox->command_base_addr = fd.cmd_base_addr | (page << 8);
|
||||
|
||||
retval = prox_reg_init();
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to initialize proximity registers\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
prox->intr_mask = 0;
|
||||
intr_src = fd.intr_src_count;
|
||||
intr_off = intr_count % 8;
|
||||
for (ii = intr_off;
|
||||
ii < (intr_src + intr_off);
|
||||
ii++) {
|
||||
prox->intr_mask |= 1 << ii;
|
||||
}
|
||||
|
||||
rmi4_data->intr_mask[0] |= prox->intr_mask;
|
||||
|
||||
addr = rmi4_data->f01_ctrl_base_addr + 1;
|
||||
|
||||
retval = synaptics_rmi4_reg_write(rmi4_data,
|
||||
addr,
|
||||
&(rmi4_data->intr_mask[0]),
|
||||
sizeof(rmi4_data->intr_mask[0]));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to set interrupt enable bit\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t synaptics_rmi4_hover_finger_en_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
if (!prox)
|
||||
return -ENODEV;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n",
|
||||
prox->hover_finger_en);
|
||||
}
|
||||
|
||||
static ssize_t synaptics_rmi4_hover_finger_en_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int retval;
|
||||
unsigned int input;
|
||||
struct synaptics_rmi4_data *rmi4_data = prox->rmi4_data;
|
||||
|
||||
if (!prox)
|
||||
return -ENODEV;
|
||||
|
||||
if (sscanf(buf, "%x", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input == 1)
|
||||
prox->hover_finger_en = true;
|
||||
else if (input == 0)
|
||||
prox->hover_finger_en = false;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
retval = prox_set_hover_finger_en();
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to change hovering finger enable setting\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int synaptics_rmi4_prox_hover_finger_en(bool enable)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (!prox)
|
||||
return -ENODEV;
|
||||
|
||||
prox->hover_finger_en = enable;
|
||||
|
||||
retval = prox_set_hover_finger_en();
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(synaptics_rmi4_prox_hover_finger_en);
|
||||
|
||||
static void synaptics_rmi4_prox_attn(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned char intr_mask)
|
||||
{
|
||||
if (!prox)
|
||||
return;
|
||||
|
||||
if (prox->intr_mask & intr_mask)
|
||||
prox_hover_finger_report();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_prox_init(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
unsigned char attr_count;
|
||||
|
||||
if (prox) {
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Handle already exists\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
prox = kzalloc(sizeof(*prox), GFP_KERNEL);
|
||||
if (!prox) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to alloc mem for prox\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
prox->finger_data = kzalloc(sizeof(*(prox->finger_data)), GFP_KERNEL);
|
||||
if (!prox->finger_data) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to alloc mem for finger_data\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit_free_prox;
|
||||
}
|
||||
|
||||
prox->rmi4_data = rmi4_data;
|
||||
|
||||
retval = prox_scan_pdt();
|
||||
if (retval < 0)
|
||||
goto exit_free_finger_data;
|
||||
|
||||
prox->hover_finger_en = true;
|
||||
|
||||
retval = prox_set_hover_finger_en();
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
prox->prox_dev = input_allocate_device();
|
||||
if (prox->prox_dev == NULL) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to allocate proximity device\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit_free_finger_data;
|
||||
}
|
||||
|
||||
prox->prox_dev->name = PROXIMITY_DRIVER_NAME;
|
||||
prox->prox_dev->phys = PROX_PHYS_NAME;
|
||||
prox->prox_dev->id.product = SYNAPTICS_DSX_DRIVER_PRODUCT;
|
||||
prox->prox_dev->id.version = SYNAPTICS_DSX_DRIVER_VERSION;
|
||||
prox->prox_dev->dev.parent = rmi4_data->pdev->dev.parent;
|
||||
input_set_drvdata(prox->prox_dev, rmi4_data);
|
||||
|
||||
set_bit(EV_KEY, prox->prox_dev->evbit);
|
||||
set_bit(EV_ABS, prox->prox_dev->evbit);
|
||||
set_bit(BTN_TOUCH, prox->prox_dev->keybit);
|
||||
set_bit(BTN_TOOL_FINGER, prox->prox_dev->keybit);
|
||||
#ifdef INPUT_PROP_DIRECT
|
||||
set_bit(INPUT_PROP_DIRECT, prox->prox_dev->propbit);
|
||||
#endif
|
||||
|
||||
prox_set_params();
|
||||
|
||||
retval = input_register_device(prox->prox_dev);
|
||||
if (retval) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to register proximity device\n",
|
||||
__func__);
|
||||
goto exit_free_input_device;
|
||||
}
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
retval = sysfs_create_file(&rmi4_data->input_dev->dev.kobj,
|
||||
&attrs[attr_count].attr);
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to create sysfs attributes\n",
|
||||
__func__);
|
||||
goto exit_free_sysfs;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_free_sysfs:
|
||||
for (attr_count--; attr_count >= 0; attr_count--) {
|
||||
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
|
||||
&attrs[attr_count].attr);
|
||||
}
|
||||
|
||||
input_unregister_device(prox->prox_dev);
|
||||
prox->prox_dev = NULL;
|
||||
|
||||
exit_free_input_device:
|
||||
if (prox->prox_dev)
|
||||
input_free_device(prox->prox_dev);
|
||||
|
||||
exit_free_finger_data:
|
||||
kfree(prox->finger_data);
|
||||
|
||||
exit_free_prox:
|
||||
kfree(prox);
|
||||
prox = NULL;
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_prox_remove(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
unsigned char attr_count;
|
||||
|
||||
if (!prox)
|
||||
goto exit;
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
|
||||
&attrs[attr_count].attr);
|
||||
}
|
||||
|
||||
input_unregister_device(prox->prox_dev);
|
||||
kfree(prox->finger_data);
|
||||
kfree(prox);
|
||||
prox = NULL;
|
||||
|
||||
exit:
|
||||
complete(&prox_remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_prox_reset(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!prox) {
|
||||
synaptics_rmi4_prox_init(rmi4_data);
|
||||
return;
|
||||
}
|
||||
|
||||
prox_hover_finger_lift();
|
||||
|
||||
prox_scan_pdt();
|
||||
|
||||
prox_set_hover_finger_en();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_prox_reinit(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!prox)
|
||||
return;
|
||||
|
||||
prox_hover_finger_lift();
|
||||
|
||||
prox_set_hover_finger_en();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_prox_e_suspend(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!prox)
|
||||
return;
|
||||
|
||||
prox_hover_finger_lift();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_prox_suspend(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!prox)
|
||||
return;
|
||||
|
||||
prox_hover_finger_lift();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static struct synaptics_rmi4_exp_fn proximity_module = {
|
||||
.fn_type = RMI_PROXIMITY,
|
||||
.init = synaptics_rmi4_prox_init,
|
||||
.remove = synaptics_rmi4_prox_remove,
|
||||
.reset = synaptics_rmi4_prox_reset,
|
||||
.reinit = synaptics_rmi4_prox_reinit,
|
||||
.early_suspend = synaptics_rmi4_prox_e_suspend,
|
||||
.suspend = synaptics_rmi4_prox_suspend,
|
||||
.resume = NULL,
|
||||
.late_resume = NULL,
|
||||
.attn = synaptics_rmi4_prox_attn,
|
||||
};
|
||||
|
||||
static int __init rmi4_proximity_module_init(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(&proximity_module, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rmi4_proximity_module_exit(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(&proximity_module, false);
|
||||
|
||||
wait_for_completion(&prox_remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(rmi4_proximity_module_init);
|
||||
module_exit(rmi4_proximity_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Synaptics, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX Proximity Module");
|
||||
MODULE_LICENSE("GPL v2");
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,634 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input/synaptics_dsx_v2_6.h>
|
||||
#include "synaptics_dsx_core.h"
|
||||
|
||||
#define SPI_READ 0x80
|
||||
#define SPI_WRITE 0x00
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
|
||||
{
|
||||
int retval;
|
||||
u32 value;
|
||||
const char *name;
|
||||
struct property *prop;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
||||
bdata->irq_gpio = of_get_named_gpio_flags(np,
|
||||
"synaptics,irq-gpio", 0,
|
||||
(enum of_gpio_flags *)&bdata->irq_flags);
|
||||
|
||||
retval = of_property_read_u32(np, "synaptics,irq-on-state",
|
||||
&value);
|
||||
if (retval < 0)
|
||||
bdata->irq_on_state = 0;
|
||||
else
|
||||
bdata->irq_on_state = value;
|
||||
|
||||
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
|
||||
if (retval < 0)
|
||||
bdata->pwr_reg_name = NULL;
|
||||
else
|
||||
bdata->pwr_reg_name = name;
|
||||
|
||||
retval = of_property_read_string(np, "synaptics,bus-reg-name", &name);
|
||||
if (retval < 0)
|
||||
bdata->bus_reg_name = NULL;
|
||||
else
|
||||
bdata->bus_reg_name = name;
|
||||
|
||||
prop = of_find_property(np, "synaptics,power-gpio", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->power_gpio = of_get_named_gpio_flags(np,
|
||||
"synaptics,power-gpio", 0, NULL);
|
||||
retval = of_property_read_u32(np, "synaptics,power-on-state",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,power-on-state property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->power_on_state = value;
|
||||
}
|
||||
} else {
|
||||
bdata->power_gpio = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,power-delay-ms", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,power-delay-ms",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,power-delay-ms property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->power_delay_ms = value;
|
||||
}
|
||||
} else {
|
||||
bdata->power_delay_ms = 0;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,reset-gpio", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->reset_gpio = of_get_named_gpio_flags(np,
|
||||
"synaptics,reset-gpio", 0, NULL);
|
||||
retval = of_property_read_u32(np, "synaptics,reset-on-state",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,reset-on-state property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->reset_on_state = value;
|
||||
}
|
||||
retval = of_property_read_u32(np, "synaptics,reset-active-ms",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,reset-active-ms property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->reset_active_ms = value;
|
||||
}
|
||||
} else {
|
||||
bdata->reset_gpio = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,reset-delay-ms", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,reset-delay-ms",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,reset-delay-ms property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->reset_delay_ms = value;
|
||||
}
|
||||
} else {
|
||||
bdata->reset_delay_ms = 0;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,byte-delay-us", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,byte-delay-us",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,byte-delay-us property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->byte_delay_us = value;
|
||||
}
|
||||
} else {
|
||||
bdata->byte_delay_us = 0;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,block-delay-us", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,block-delay-us",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,block-delay-us property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->block_delay_us = value;
|
||||
}
|
||||
} else {
|
||||
bdata->block_delay_us = 0;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,max-y-for-2d", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,max-y-for-2d",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,max-y-for-2d property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->max_y_for_2d = value;
|
||||
}
|
||||
} else {
|
||||
bdata->max_y_for_2d = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,swap-axes", NULL);
|
||||
bdata->swap_axes = prop > 0 ? true : false;
|
||||
|
||||
prop = of_find_property(np, "synaptics,x-flip", NULL);
|
||||
bdata->x_flip = prop > 0 ? true : false;
|
||||
|
||||
prop = of_find_property(np, "synaptics,y-flip", NULL);
|
||||
bdata->y_flip = prop > 0 ? true : false;
|
||||
|
||||
prop = of_find_property(np, "synaptics,ub-i2c-addr", NULL);
|
||||
if (prop && prop->length) {
|
||||
retval = of_property_read_u32(np, "synaptics,ub-i2c-addr",
|
||||
&value);
|
||||
if (retval < 0) {
|
||||
dev_err(dev, "%s: Unable to read synaptics,ub-i2c-addr property\n",
|
||||
__func__);
|
||||
return retval;
|
||||
} else {
|
||||
bdata->ub_i2c_addr = (unsigned short)value;
|
||||
}
|
||||
} else {
|
||||
bdata->ub_i2c_addr = -1;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,cap-button-codes", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->cap_button_map->map = devm_kzalloc(dev,
|
||||
prop->length,
|
||||
GFP_KERNEL);
|
||||
if (!bdata->cap_button_map->map)
|
||||
return -ENOMEM;
|
||||
bdata->cap_button_map->nbuttons = prop->length / sizeof(u32);
|
||||
retval = of_property_read_u32_array(np,
|
||||
"synaptics,cap-button-codes",
|
||||
bdata->cap_button_map->map,
|
||||
bdata->cap_button_map->nbuttons);
|
||||
if (retval < 0) {
|
||||
bdata->cap_button_map->nbuttons = 0;
|
||||
bdata->cap_button_map->map = NULL;
|
||||
}
|
||||
} else {
|
||||
bdata->cap_button_map->nbuttons = 0;
|
||||
bdata->cap_button_map->map = NULL;
|
||||
}
|
||||
|
||||
prop = of_find_property(np, "synaptics,vir-button-codes", NULL);
|
||||
if (prop && prop->length) {
|
||||
bdata->vir_button_map->map = devm_kzalloc(dev,
|
||||
prop->length,
|
||||
GFP_KERNEL);
|
||||
if (!bdata->vir_button_map->map)
|
||||
return -ENOMEM;
|
||||
bdata->vir_button_map->nbuttons = prop->length / sizeof(u32);
|
||||
bdata->vir_button_map->nbuttons /= 5;
|
||||
retval = of_property_read_u32_array(np,
|
||||
"synaptics,vir-button-codes",
|
||||
bdata->vir_button_map->map,
|
||||
bdata->vir_button_map->nbuttons * 5);
|
||||
if (retval < 0) {
|
||||
bdata->vir_button_map->nbuttons = 0;
|
||||
bdata->vir_button_map->map = NULL;
|
||||
}
|
||||
} else {
|
||||
bdata->vir_button_map->nbuttons = 0;
|
||||
bdata->vir_button_map->map = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int synaptics_rmi4_spi_set_page(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr)
|
||||
{
|
||||
int retval;
|
||||
unsigned int index;
|
||||
unsigned int xfer_count = PAGE_SELECT_LEN + 1;
|
||||
unsigned char txbuf[xfer_count];
|
||||
unsigned char page;
|
||||
struct spi_message msg;
|
||||
struct spi_transfer xfers[xfer_count];
|
||||
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
|
||||
const struct synaptics_dsx_board_data *bdata =
|
||||
rmi4_data->hw_if->board_data;
|
||||
|
||||
page = ((addr >> 8) & ~MASK_7BIT);
|
||||
if (page != rmi4_data->current_page) {
|
||||
spi_message_init(&msg);
|
||||
|
||||
txbuf[0] = SPI_WRITE;
|
||||
txbuf[1] = MASK_8BIT;
|
||||
txbuf[2] = page;
|
||||
|
||||
for (index = 0; index < xfer_count; index++) {
|
||||
memset(&xfers[index], 0, sizeof(struct spi_transfer));
|
||||
xfers[index].len = 1;
|
||||
xfers[index].delay_usecs = bdata->byte_delay_us;
|
||||
xfers[index].tx_buf = &txbuf[index];
|
||||
spi_message_add_tail(&xfers[index], &msg);
|
||||
}
|
||||
|
||||
if (bdata->block_delay_us)
|
||||
xfers[index - 1].delay_usecs = bdata->block_delay_us;
|
||||
|
||||
retval = spi_sync(spi, &msg);
|
||||
if (retval == 0) {
|
||||
rmi4_data->current_page = page;
|
||||
retval = PAGE_SELECT_LEN;
|
||||
} else {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to complete SPI transfer, error = %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
} else {
|
||||
retval = PAGE_SELECT_LEN;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_spi_read(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr, unsigned char *data, unsigned short length)
|
||||
{
|
||||
int retval;
|
||||
unsigned int index;
|
||||
unsigned int xfer_count = length + ADDRESS_WORD_LEN;
|
||||
unsigned char txbuf[ADDRESS_WORD_LEN];
|
||||
unsigned char *rxbuf = NULL;
|
||||
struct spi_message msg;
|
||||
struct spi_transfer *xfers = NULL;
|
||||
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
|
||||
const struct synaptics_dsx_board_data *bdata =
|
||||
rmi4_data->hw_if->board_data;
|
||||
|
||||
spi_message_init(&msg);
|
||||
|
||||
xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL);
|
||||
if (!xfers) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to allocate memory for xfers\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
txbuf[0] = (addr >> 8) | SPI_READ;
|
||||
txbuf[1] = addr & MASK_8BIT;
|
||||
|
||||
rxbuf = kmalloc(length, GFP_KERNEL);
|
||||
if (!rxbuf) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to allocate memory for rxbuf\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
retval = synaptics_rmi4_spi_set_page(rmi4_data, addr);
|
||||
if (retval != PAGE_SELECT_LEN) {
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
retval = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (index = 0; index < xfer_count; index++) {
|
||||
xfers[index].len = 1;
|
||||
xfers[index].delay_usecs = bdata->byte_delay_us;
|
||||
if (index < ADDRESS_WORD_LEN)
|
||||
xfers[index].tx_buf = &txbuf[index];
|
||||
else
|
||||
xfers[index].rx_buf = &rxbuf[index - ADDRESS_WORD_LEN];
|
||||
spi_message_add_tail(&xfers[index], &msg);
|
||||
}
|
||||
|
||||
if (bdata->block_delay_us)
|
||||
xfers[index - 1].delay_usecs = bdata->block_delay_us;
|
||||
|
||||
retval = spi_sync(spi, &msg);
|
||||
if (retval == 0) {
|
||||
retval = secure_memcpy(data, length, rxbuf, length, length);
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to copy data\n",
|
||||
__func__);
|
||||
} else {
|
||||
retval = length;
|
||||
}
|
||||
} else {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to complete SPI transfer, error = %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
exit:
|
||||
kfree(rxbuf);
|
||||
kfree(xfers);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_spi_write(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr, unsigned char *data, unsigned short length)
|
||||
{
|
||||
int retval;
|
||||
unsigned int index;
|
||||
unsigned int xfer_count = length + ADDRESS_WORD_LEN;
|
||||
unsigned char *txbuf = NULL;
|
||||
struct spi_message msg;
|
||||
struct spi_transfer *xfers = NULL;
|
||||
struct spi_device *spi = to_spi_device(rmi4_data->pdev->dev.parent);
|
||||
const struct synaptics_dsx_board_data *bdata =
|
||||
rmi4_data->hw_if->board_data;
|
||||
|
||||
spi_message_init(&msg);
|
||||
|
||||
xfers = kcalloc(xfer_count, sizeof(struct spi_transfer), GFP_KERNEL);
|
||||
if (!xfers) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to allocate memory for xfers\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
txbuf = kmalloc(xfer_count, GFP_KERNEL);
|
||||
if (!txbuf) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to allocate memory for txbuf\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
txbuf[0] = (addr >> 8) & ~SPI_READ;
|
||||
txbuf[1] = addr & MASK_8BIT;
|
||||
retval = secure_memcpy(&txbuf[ADDRESS_WORD_LEN],
|
||||
xfer_count - ADDRESS_WORD_LEN, data, length, length);
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to copy data\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
retval = synaptics_rmi4_spi_set_page(rmi4_data, addr);
|
||||
if (retval != PAGE_SELECT_LEN) {
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
retval = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
for (index = 0; index < xfer_count; index++) {
|
||||
xfers[index].len = 1;
|
||||
xfers[index].delay_usecs = bdata->byte_delay_us;
|
||||
xfers[index].tx_buf = &txbuf[index];
|
||||
spi_message_add_tail(&xfers[index], &msg);
|
||||
}
|
||||
|
||||
if (bdata->block_delay_us)
|
||||
xfers[index - 1].delay_usecs = bdata->block_delay_us;
|
||||
|
||||
retval = spi_sync(spi, &msg);
|
||||
if (retval == 0) {
|
||||
retval = length;
|
||||
} else {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to complete SPI transfer, error = %d\n",
|
||||
__func__, retval);
|
||||
}
|
||||
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
exit:
|
||||
kfree(txbuf);
|
||||
kfree(xfers);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct synaptics_dsx_bus_access bus_access = {
|
||||
.type = BUS_SPI,
|
||||
.read = synaptics_rmi4_spi_read,
|
||||
.write = synaptics_rmi4_spi_write,
|
||||
};
|
||||
|
||||
static struct synaptics_dsx_hw_interface hw_if;
|
||||
|
||||
static struct platform_device *synaptics_dsx_spi_device;
|
||||
|
||||
static void synaptics_rmi4_spi_dev_release(struct device *dev)
|
||||
{
|
||||
kfree(synaptics_dsx_spi_device);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
int retval;
|
||||
|
||||
if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Full duplex not supported by host\n",
|
||||
__func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
synaptics_dsx_spi_device = kzalloc(
|
||||
sizeof(struct platform_device),
|
||||
GFP_KERNEL);
|
||||
if (!synaptics_dsx_spi_device) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Failed to allocate memory for synaptics_dsx_spi_device\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
if (spi->dev.of_node) {
|
||||
hw_if.board_data = devm_kzalloc(&spi->dev,
|
||||
sizeof(struct synaptics_dsx_board_data),
|
||||
GFP_KERNEL);
|
||||
if (!hw_if.board_data) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Failed to allocate memory for board data\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
hw_if.board_data->cap_button_map = devm_kzalloc(&spi->dev,
|
||||
sizeof(struct synaptics_dsx_button_map),
|
||||
GFP_KERNEL);
|
||||
if (!hw_if.board_data->cap_button_map) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Failed to allocate memory for 0D button map\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
hw_if.board_data->vir_button_map = devm_kzalloc(&spi->dev,
|
||||
sizeof(struct synaptics_dsx_button_map),
|
||||
GFP_KERNEL);
|
||||
if (!hw_if.board_data->vir_button_map) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Failed to allocate memory for virtual button map\n",
|
||||
__func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
parse_dt(&spi->dev, hw_if.board_data);
|
||||
}
|
||||
#else
|
||||
hw_if.board_data = spi->dev.platform_data;
|
||||
#endif
|
||||
|
||||
hw_if.bus_access = &bus_access;
|
||||
|
||||
spi->bits_per_word = 8;
|
||||
spi->mode = SPI_MODE_3;
|
||||
|
||||
retval = spi_setup(spi);
|
||||
if (retval < 0) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Failed to perform SPI setup\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
synaptics_dsx_spi_device->name = PLATFORM_DRIVER_NAME;
|
||||
synaptics_dsx_spi_device->id = 0;
|
||||
synaptics_dsx_spi_device->num_resources = 0;
|
||||
synaptics_dsx_spi_device->dev.parent = &spi->dev;
|
||||
synaptics_dsx_spi_device->dev.platform_data = &hw_if;
|
||||
synaptics_dsx_spi_device->dev.release = synaptics_rmi4_spi_dev_release;
|
||||
|
||||
retval = platform_device_register(synaptics_dsx_spi_device);
|
||||
if (retval) {
|
||||
dev_err(&spi->dev,
|
||||
"%s: Failed to register platform device\n",
|
||||
__func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
platform_device_unregister(synaptics_dsx_spi_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static struct of_device_id synaptics_rmi4_of_match_table[] = {
|
||||
{
|
||||
.compatible = "synaptics,dsx-spi",
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, synaptics_rmi4_of_match_table);
|
||||
#else
|
||||
#define synaptics_rmi4_of_match_table NULL
|
||||
#endif
|
||||
|
||||
static struct spi_driver synaptics_rmi4_spi_driver = {
|
||||
.driver = {
|
||||
.name = SPI_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = synaptics_rmi4_of_match_table,
|
||||
},
|
||||
.probe = synaptics_rmi4_spi_probe,
|
||||
.remove = synaptics_rmi4_spi_remove,
|
||||
};
|
||||
|
||||
|
||||
int synaptics_rmi4_bus_init_v26(void)
|
||||
{
|
||||
return spi_register_driver(&synaptics_rmi4_spi_driver);
|
||||
}
|
||||
EXPORT_SYMBOL(synaptics_rmi4_bus_init_v26);
|
||||
|
||||
void synaptics_rmi4_bus_exit_v26(void)
|
||||
{
|
||||
spi_unregister_driver(&synaptics_rmi4_spi_driver);
|
||||
|
||||
return;
|
||||
}
|
||||
EXPORT_SYMBOL(synaptics_rmi4_bus_exit_v26);
|
||||
|
||||
MODULE_AUTHOR("Synaptics, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX SPI Bus Support Module");
|
||||
MODULE_LICENSE("GPL v2");
|
File diff suppressed because it is too large
Load diff
|
@ -1,416 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/input/synaptics_dsx_v2_6.h>
|
||||
#include "synaptics_dsx_core.h"
|
||||
|
||||
#define SYSFS_FOLDER_NAME "video"
|
||||
|
||||
/*
|
||||
#define RMI_DCS_SUSPEND_RESUME
|
||||
*/
|
||||
|
||||
static ssize_t video_sysfs_dcs_write_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static ssize_t video_sysfs_param_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static int video_send_dcs_command(unsigned char command_opcode);
|
||||
|
||||
struct f38_command {
|
||||
union {
|
||||
struct {
|
||||
unsigned char command_opcode;
|
||||
unsigned char register_access:1;
|
||||
unsigned char gamma_page:1;
|
||||
unsigned char f38_control1_b2__7:6;
|
||||
unsigned char parameter_field_1;
|
||||
unsigned char parameter_field_2;
|
||||
unsigned char parameter_field_3;
|
||||
unsigned char parameter_field_4;
|
||||
unsigned char send_to_dcs:1;
|
||||
unsigned char f38_command6_b1__7:7;
|
||||
} __packed;
|
||||
unsigned char data[7];
|
||||
};
|
||||
};
|
||||
|
||||
struct synaptics_rmi4_video_handle {
|
||||
unsigned char param;
|
||||
unsigned short query_base_addr;
|
||||
unsigned short control_base_addr;
|
||||
unsigned short data_base_addr;
|
||||
unsigned short command_base_addr;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
struct kobject *sysfs_dir;
|
||||
};
|
||||
|
||||
#ifdef RMI_DCS_SUSPEND_RESUME
|
||||
struct dcs_command {
|
||||
unsigned char command;
|
||||
unsigned int wait_time;
|
||||
};
|
||||
|
||||
static struct dcs_command suspend_sequence[] = {
|
||||
{
|
||||
.command = 0x28,
|
||||
.wait_time = 200,
|
||||
},
|
||||
{
|
||||
.command = 0x10,
|
||||
.wait_time = 200,
|
||||
},
|
||||
};
|
||||
|
||||
static struct dcs_command resume_sequence[] = {
|
||||
{
|
||||
.command = 0x11,
|
||||
.wait_time = 200,
|
||||
},
|
||||
{
|
||||
.command = 0x29,
|
||||
.wait_time = 200,
|
||||
},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct device_attribute attrs[] = {
|
||||
__ATTR(dcs_write, S_IWUGO,
|
||||
NULL,
|
||||
video_sysfs_dcs_write_store),
|
||||
__ATTR(param, S_IWUGO,
|
||||
NULL,
|
||||
video_sysfs_param_store),
|
||||
};
|
||||
|
||||
static struct synaptics_rmi4_video_handle *video;
|
||||
|
||||
DECLARE_COMPLETION(video_remove_complete);
|
||||
|
||||
static ssize_t video_sysfs_dcs_write_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
int retval;
|
||||
unsigned int input;
|
||||
|
||||
if (sscanf(buf, "%x", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
retval = video_send_dcs_command((unsigned char)input);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t video_sysfs_param_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
unsigned int input;
|
||||
|
||||
if (sscanf(buf, "%x", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
video->param = (unsigned char)input;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static int video_send_dcs_command(unsigned char command_opcode)
|
||||
{
|
||||
int retval;
|
||||
struct f38_command command;
|
||||
struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
|
||||
|
||||
memset(&command, 0x00, sizeof(command));
|
||||
|
||||
command.command_opcode = command_opcode;
|
||||
command.parameter_field_1 = video->param;
|
||||
command.send_to_dcs = 1;
|
||||
|
||||
video->param = 0;
|
||||
|
||||
retval = synaptics_rmi4_reg_write(rmi4_data,
|
||||
video->command_base_addr,
|
||||
command.data,
|
||||
sizeof(command.data));
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to send DCS command\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int video_scan_pdt(void)
|
||||
{
|
||||
int retval;
|
||||
unsigned char page;
|
||||
unsigned short addr;
|
||||
bool f38_found = false;
|
||||
struct synaptics_rmi4_fn_desc rmi_fd;
|
||||
struct synaptics_rmi4_data *rmi4_data = video->rmi4_data;
|
||||
|
||||
for (page = 0; page < PAGES_TO_SERVICE; page++) {
|
||||
for (addr = PDT_START; addr > PDT_END; addr -= PDT_ENTRY_SIZE) {
|
||||
addr |= (page << 8);
|
||||
|
||||
retval = synaptics_rmi4_reg_read(rmi4_data,
|
||||
addr,
|
||||
(unsigned char *)&rmi_fd,
|
||||
sizeof(rmi_fd));
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
addr &= ~(MASK_8BIT << 8);
|
||||
|
||||
if (!rmi_fd.fn_number)
|
||||
break;
|
||||
|
||||
if (rmi_fd.fn_number == SYNAPTICS_RMI4_F38) {
|
||||
f38_found = true;
|
||||
goto f38_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!f38_found) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to find F38\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
f38_found:
|
||||
video->query_base_addr = rmi_fd.query_base_addr | (page << 8);
|
||||
video->control_base_addr = rmi_fd.ctrl_base_addr | (page << 8);
|
||||
video->data_base_addr = rmi_fd.data_base_addr | (page << 8);
|
||||
video->command_base_addr = rmi_fd.cmd_base_addr | (page << 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_video_init(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
unsigned char attr_count;
|
||||
|
||||
if (video) {
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Handle already exists\n",
|
||||
__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
video = kzalloc(sizeof(*video), GFP_KERNEL);
|
||||
if (!video) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to alloc mem for video\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
video->rmi4_data = rmi4_data;
|
||||
|
||||
retval = video_scan_pdt();
|
||||
if (retval < 0) {
|
||||
retval = 0;
|
||||
goto exit_scan_pdt;
|
||||
}
|
||||
|
||||
video->sysfs_dir = kobject_create_and_add(SYSFS_FOLDER_NAME,
|
||||
&rmi4_data->input_dev->dev.kobj);
|
||||
if (!video->sysfs_dir) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to create sysfs directory\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
goto exit_sysfs_dir;
|
||||
}
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
retval = sysfs_create_file(video->sysfs_dir,
|
||||
&attrs[attr_count].attr);
|
||||
if (retval < 0) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"%s: Failed to create sysfs attributes\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
goto exit_sysfs_attrs;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_sysfs_attrs:
|
||||
for (attr_count--; attr_count >= 0; attr_count--)
|
||||
sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
|
||||
|
||||
kobject_put(video->sysfs_dir);
|
||||
|
||||
exit_sysfs_dir:
|
||||
exit_scan_pdt:
|
||||
kfree(video);
|
||||
video = NULL;
|
||||
|
||||
exit:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_video_remove(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
unsigned char attr_count;
|
||||
|
||||
if (!video)
|
||||
goto exit;
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
|
||||
sysfs_remove_file(video->sysfs_dir, &attrs[attr_count].attr);
|
||||
|
||||
kobject_put(video->sysfs_dir);
|
||||
|
||||
kfree(video);
|
||||
video = NULL;
|
||||
|
||||
exit:
|
||||
complete(&video_remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_video_reset(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
if (!video)
|
||||
synaptics_rmi4_video_init(rmi4_data);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef RMI_DCS_SUSPEND_RESUME
|
||||
static void synaptics_rmi4_video_suspend(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
unsigned char ii;
|
||||
unsigned char command;
|
||||
unsigned char num_of_cmds;
|
||||
|
||||
if (!video)
|
||||
return;
|
||||
|
||||
num_of_cmds = ARRAY_SIZE(suspend_sequence);
|
||||
|
||||
for (ii = 0; ii < num_of_cmds; ii++) {
|
||||
command = suspend_sequence[ii].command;
|
||||
retval = video_send_dcs_command(command);
|
||||
if (retval < 0)
|
||||
return;
|
||||
msleep(suspend_sequence[ii].wait_time);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_video_resume(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
unsigned char ii;
|
||||
unsigned char command;
|
||||
unsigned char num_of_cmds;
|
||||
|
||||
if (!video)
|
||||
return;
|
||||
|
||||
num_of_cmds = ARRAY_SIZE(resume_sequence);
|
||||
|
||||
for (ii = 0; ii < num_of_cmds; ii++) {
|
||||
command = resume_sequence[ii].command;
|
||||
retval = video_send_dcs_command(command);
|
||||
if (retval < 0)
|
||||
return;
|
||||
msleep(resume_sequence[ii].wait_time);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct synaptics_rmi4_exp_fn video_module = {
|
||||
.fn_type = RMI_VIDEO,
|
||||
.init = synaptics_rmi4_video_init,
|
||||
.remove = synaptics_rmi4_video_remove,
|
||||
.reset = synaptics_rmi4_video_reset,
|
||||
.reinit = NULL,
|
||||
.early_suspend = NULL,
|
||||
#ifdef RMI_DCS_SUSPEND_RESUME
|
||||
.suspend = synaptics_rmi4_video_suspend,
|
||||
.resume = synaptics_rmi4_video_resume,
|
||||
#else
|
||||
.suspend = NULL,
|
||||
.resume = NULL,
|
||||
#endif
|
||||
.late_resume = NULL,
|
||||
.attn = NULL,
|
||||
};
|
||||
|
||||
static int __init rmi4_video_module_init(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(&video_module, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rmi4_video_module_exit(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(&video_module, false);
|
||||
|
||||
wait_for_completion(&video_remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(rmi4_video_module_init);
|
||||
module_exit(rmi4_video_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Synaptics, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX Video Module");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012-2015 Synaptics Incorporated. All rights reserved.
|
||||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
* Copyright (C) 2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND SYNAPTICS
|
||||
* EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES, INCLUDING ANY
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE,
|
||||
* AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY INTELLECTUAL PROPERTY RIGHTS.
|
||||
* IN NO EVENT SHALL SYNAPTICS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, PUNITIVE, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION
|
||||
* WITH THE USE OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED
|
||||
* AND BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF COMPETENT JURISDICTION DOES
|
||||
* NOT PERMIT THE DISCLAIMER OF DIRECT DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS'
|
||||
* TOTAL CUMULATIVE LIABILITY TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S.
|
||||
* DOLLARS.
|
||||
*/
|
||||
|
||||
#ifndef _SYNAPTICS_DSX_H_
|
||||
#define _SYNAPTICS_DSX_H_
|
||||
|
||||
#define PLATFORM_DRIVER_NAME "synaptics_dsxv26"
|
||||
#define STYLUS_DRIVER_NAME "synaptics_dsxv26_stylus"
|
||||
#define ACTIVE_PEN_DRIVER_NAME "synaptics_dsxv26_active_pen"
|
||||
#define PROXIMITY_DRIVER_NAME "synaptics_dsxv26_proximity"
|
||||
#define GESTURE_DRIVER_NAME "synaptics_dsxv26_gesture"
|
||||
#define I2C_DRIVER_NAME "synaptics_dsxv26"
|
||||
#define SPI_DRIVER_NAME "synaptics_dsxv26"
|
||||
|
||||
/*
|
||||
* struct synaptics_dsx_button_map - button map
|
||||
* @nbuttons: number of buttons
|
||||
* @map: pointer to array of button codes
|
||||
*/
|
||||
struct synaptics_dsx_button_map {
|
||||
unsigned char nbuttons;
|
||||
unsigned int *map;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_dsx_board_data - DSX board data
|
||||
* @x_flip: x flip flag
|
||||
* @y_flip: y flip flag
|
||||
* @swap_axes: swap axes flag
|
||||
* @resume_in_workqueue: defer resume function to workqueue
|
||||
* @irq_gpio: attention interrupt GPIO
|
||||
* @irq_on_state: attention interrupt active state
|
||||
* @power_gpio: power switch GPIO
|
||||
* @power_on_state: power switch active state
|
||||
* @reset_gpio: reset GPIO
|
||||
* @reset_on_state: reset active state
|
||||
* @max_y_for_2d: maximum y value for 2D area when virtual buttons are present
|
||||
* @irq_flags: IRQ flags
|
||||
* @i2c_addr: I2C slave address
|
||||
* @ub_i2c_addr: microbootloader mode I2C slave address
|
||||
* @device_descriptor_addr: HID device descriptor address
|
||||
* @panel_x: x-axis resolution of display panel
|
||||
* @panel_y: y-axis resolution of display panel
|
||||
* @power_delay_ms: delay time to wait after powering up device
|
||||
* @reset_delay_ms: delay time to wait after resetting device
|
||||
* @reset_active_ms: reset active time
|
||||
* @byte_delay_us: delay time between two bytes of SPI data
|
||||
* @block_delay_us: delay time between two SPI transfers
|
||||
* @pwr_reg_name: pointer to name of regulator for power control
|
||||
* @bus_reg_name: pointer to name of regulator for bus pullup control
|
||||
* @cap_button_map: pointer to 0D button map
|
||||
* @vir_button_map: pointer to virtual button map
|
||||
* @resume_in_workqueue: defer resume function to workqueue
|
||||
*/
|
||||
struct synaptics_dsx_board_data {
|
||||
bool x_flip;
|
||||
bool y_flip;
|
||||
bool swap_axes;
|
||||
bool resume_in_workqueue;
|
||||
int irq_gpio;
|
||||
int irq_on_state;
|
||||
int power_gpio;
|
||||
int power_on_state;
|
||||
int reset_gpio;
|
||||
int reset_on_state;
|
||||
int max_y_for_2d;
|
||||
unsigned long irq_flags;
|
||||
unsigned short i2c_addr;
|
||||
unsigned short ub_i2c_addr;
|
||||
unsigned short device_descriptor_addr;
|
||||
unsigned int panel_x;
|
||||
unsigned int panel_y;
|
||||
unsigned int power_delay_ms;
|
||||
unsigned int reset_delay_ms;
|
||||
unsigned int reset_active_ms;
|
||||
unsigned int byte_delay_us;
|
||||
unsigned int block_delay_us;
|
||||
const char *pwr_reg_name;
|
||||
const char *bus_reg_name;
|
||||
struct synaptics_dsx_button_map *cap_button_map;
|
||||
struct synaptics_dsx_button_map *vir_button_map;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue