mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-13 08:07:32 -04:00
motorola: dlkm: synaptics touch driver
Moving Synaptics touchscreen driver from kernel to DLKM Change-Id: Ia72f58cd400fb2c51b6170a8e0b43ceb16c72c94 Signed-off-by: Konstantin Makariev <kmakariev@motorola.com> Reviewed-on: https://gerrit.mot.com/1102121 SLTApproved: Slta Waiver SME-Granted: SME Approvals Granted Tested-by: Jira Key Submit-Approved: Jira Key
This commit is contained in:
parent
5b026089e1
commit
bd24670ac0
13 changed files with 19910 additions and 0 deletions
27
drivers/input/touchscreen/synaptics_mmi/Android.mk
Normal file
27
drivers/input/touchscreen/synaptics_mmi/Android.mk
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := synaptics_mmi.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := synaptics_dsx_fw_update.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := synaptics_dsx_rmi_dev.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
|
||||
#This requires F54 support, thus disable it for now
|
||||
#include $(CLEAR_VARS)
|
||||
#LOCAL_MODULE := synaptics_dsx_test_reporting.ko
|
||||
#LOCAL_MODULE_TAGS := optional
|
||||
#LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
#include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
15
drivers/input/touchscreen/synaptics_mmi/Kbuild
Normal file
15
drivers/input/touchscreen/synaptics_mmi/Kbuild
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# add -Wall to try to catch everything we can.
|
||||
EXTRA_CFLAGS += -Wall
|
||||
EXTRA_CFLAGS += -I$(TOP)/motorola/kernel/modules/include \
|
||||
-I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/synaptics_mmi
|
||||
|
||||
synaptics_mmi-objs = synaptics_dsx_i2c.o
|
||||
|
||||
ifneq ($(filter m y,$(CONFIG_DROPBOX)),)
|
||||
synaptics_mmi-objs += synaptics_dsx_dropbox.o
|
||||
endif
|
||||
|
||||
obj-m += synaptics_mmi.o
|
||||
obj-m += synaptics_dsx_fw_update.o
|
||||
obj-m += synaptics_dsx_rmi_dev.o
|
||||
#obj-m += synaptics_dsx_test_reporting.o
|
||||
10
drivers/input/touchscreen/synaptics_mmi/Makefile
Normal file
10
drivers/input/touchscreen/synaptics_mmi/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
|
|
@ -0,0 +1,443 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver extension
|
||||
*
|
||||
* Copyright (C) 2015 Motorola Mobility, Inc.
|
||||
*
|
||||
* Copyright (C) 2015 Konstantin Makariev <kmakariev@motorola.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.
|
||||
*/
|
||||
#define pr_fmt(fmt) "synaptics-CAB: %s: " fmt, __func__
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include "synaptics_dsx_i2c.h"
|
||||
#include "synaptics_dsx_control_access_block.h"
|
||||
|
||||
#define cab_debug pr_debug
|
||||
|
||||
static struct touch_control_access_block *control_access_block;
|
||||
|
||||
struct touch_control_access_block *control_access_block_get(void) {
|
||||
return control_access_block;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(control_access_block_get);
|
||||
|
||||
#define GROUP_NAME(grp) (grp == SYN_DSX_STATUS ? "STATUS" : \
|
||||
(grp == SYN_DSX_DATA ? "DATA" : \
|
||||
(grp == SYN_DSX_MODE ? "MODE" : \
|
||||
(grp == SYN_DSX_WAKE ? "WAKE" : \
|
||||
(grp == SYN_DSX_SLEEP ? "SLEEP" : \
|
||||
(grp == SYN_DSX_RESET ? "RESET" : "CONFIG"))))))
|
||||
|
||||
#define DIR_NAME(grp) (grp & MODE_WO ? "WO" : "RO")
|
||||
|
||||
#define SPRINTF_PAGE(fmt, args...) {\
|
||||
blen += scnprintf(buf + blen, PAGE_SIZE - blen, fmt, ##args);\
|
||||
}
|
||||
|
||||
static ssize_t control_access_block_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int i, j, k, m;
|
||||
ssize_t blen = 0;
|
||||
struct touch_control_access_block *cab = control_access_block_get();
|
||||
|
||||
if (cab->do_sync)
|
||||
SPRINTF_PAGE("has been changed, ");
|
||||
SPRINTF_PAGE("has %d groups\n", cab->grp_num);
|
||||
|
||||
for (i = 0; i < cab->grp_num; i++) {
|
||||
struct grp_info *ginfo = cab->grp_ptr[i];
|
||||
/* skip empty slots */
|
||||
if (!ginfo)
|
||||
continue;
|
||||
SPRINTF_PAGE("group [%s] access %s has %d data blocks\n",
|
||||
GROUP_NAME(ginfo->group),
|
||||
DIR_NAME(ginfo->group),
|
||||
ginfo->data_blk_cnt);
|
||||
for (m = 0; m < ginfo->data_blk_cnt; m++) {
|
||||
SPRINTF_PAGE("\tdata block %d:\n", m);
|
||||
if (ginfo->group & MODE_WO) {
|
||||
struct op_write *wo = ginfo->wo_data[m];
|
||||
SPRINTF_PAGE("\t\tpage:%d, addr:0x%X, blk_sz:%d, blk_cnt:%d, mask:0x%x\n",
|
||||
wo->paddr >> 8, wo->paddr & 0xff,
|
||||
wo->blk_sz, wo->blk_cnt, wo->mask);
|
||||
SPRINTF_PAGE("\t\tdata: ");
|
||||
for (j = 0; j < wo->blk_cnt; j++) {
|
||||
unsigned char *data = &wo->data[j];
|
||||
SPRINTF_PAGE("[%d] ", j);
|
||||
for (k = 0; k < wo->blk_sz; k++)
|
||||
SPRINTF_PAGE("0x%X ", *(data + k));
|
||||
SPRINTF_PAGE("\n");
|
||||
}
|
||||
} else {
|
||||
struct op_read *ro = ginfo->ro_data[m];
|
||||
SPRINTF_PAGE("\t\tpage:%d, addr:0x%X, blk_sz:%d, blk_cnt:%d\n",
|
||||
ro->paddr >> 8, ro->paddr & 0xff,
|
||||
ro->blk_sz, ro->blk_cnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cab->do_sync = false;
|
||||
cab_debug("clear do_sync flag\n");
|
||||
|
||||
return blen;
|
||||
}
|
||||
|
||||
static struct op_write *alloc_op_write(unsigned short paddr,
|
||||
unsigned char blk_sz, unsigned char blk_cnt,
|
||||
unsigned char mask, unsigned char *data)
|
||||
{
|
||||
int i;
|
||||
struct op_write *wo;
|
||||
wo = kzalloc(sizeof(struct op_write) + blk_sz, GFP_KERNEL);
|
||||
if (!wo)
|
||||
return NULL;
|
||||
wo->paddr = paddr;
|
||||
wo->blk_sz = blk_sz;
|
||||
wo->blk_cnt = blk_cnt;
|
||||
wo->mask = mask;
|
||||
for (i = 0; i < blk_sz; i++)
|
||||
wo->data[i] = *data++;
|
||||
cab_debug("added WO block: addr={%X}, sz=%u, cnt=%u\n", paddr, blk_sz, blk_cnt);
|
||||
return wo;
|
||||
}
|
||||
|
||||
static struct op_read *alloc_op_read(unsigned short paddr,
|
||||
unsigned char blk_sz, unsigned char blk_cnt)
|
||||
{
|
||||
struct op_read *ro;
|
||||
ro = kzalloc(sizeof(struct op_read), GFP_KERNEL);
|
||||
if (!ro)
|
||||
return NULL;
|
||||
ro->paddr = paddr;
|
||||
ro->blk_sz = blk_sz;
|
||||
ro->blk_cnt = blk_cnt;
|
||||
cab_debug("added RO block: addr={%X}, sz=%u, cnt=%u\n", paddr, blk_sz, blk_cnt);
|
||||
return ro;
|
||||
}
|
||||
|
||||
/* create a new group and add one or more entities */
|
||||
static struct grp_info *alloc_grp_info(unsigned char group,
|
||||
unsigned char data_blk_cnt, ...)
|
||||
{
|
||||
int i;
|
||||
va_list ap;
|
||||
struct grp_info *gi;
|
||||
gi = kzalloc(sizeof(struct grp_info), GFP_KERNEL);
|
||||
if (!gi)
|
||||
return NULL;
|
||||
gi->group = group;
|
||||
gi->data_blk_cnt = data_blk_cnt;
|
||||
va_start(ap, data_blk_cnt);
|
||||
if (group & MODE_WO) {
|
||||
struct op_write *data;
|
||||
gi->wo_data = (struct op_write **)kzalloc(
|
||||
sizeof(struct op_write *)*data_blk_cnt,
|
||||
GFP_KERNEL);
|
||||
if (!gi->wo_data)
|
||||
goto alloc_failure;
|
||||
for (i = 0; i < data_blk_cnt; i++) {
|
||||
data = va_arg(ap, struct op_write *);
|
||||
gi->wo_data[i] = data;
|
||||
}
|
||||
} else {
|
||||
struct op_read *data;
|
||||
gi->ro_data = (struct op_read **)kzalloc(
|
||||
sizeof(struct op_read *)*data_blk_cnt,
|
||||
GFP_KERNEL);
|
||||
if (!gi->ro_data)
|
||||
goto alloc_failure;
|
||||
for (i = 0; i < data_blk_cnt; i++) {
|
||||
data = va_arg(ap, struct op_read *);
|
||||
gi->ro_data[i] = data;
|
||||
}
|
||||
}
|
||||
goto success;
|
||||
alloc_failure:
|
||||
gi->data_blk_cnt = 0;
|
||||
success:
|
||||
cab_debug("created group [%s] access %s has %d data block(s)\n",
|
||||
GROUP_NAME(gi->group), DIR_NAME(gi->group), gi->data_blk_cnt);
|
||||
va_end(ap);
|
||||
return gi;
|
||||
}
|
||||
|
||||
/* add one or more entities to existing group */
|
||||
static int modify_grp_info(struct grp_info *gi,
|
||||
unsigned char data_blk_cnt, ...)
|
||||
{
|
||||
int i, retval = 0;
|
||||
int new_max = gi->data_blk_cnt + data_blk_cnt;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, data_blk_cnt);
|
||||
if (gi->group & MODE_WO) {
|
||||
struct op_write **realloc, *append;
|
||||
realloc = (struct op_write **)kzalloc(sizeof(struct op_write *)*
|
||||
(gi->data_blk_cnt + data_blk_cnt),
|
||||
GFP_KERNEL);
|
||||
if (!realloc) {
|
||||
retval = -ENOMEM;
|
||||
goto alloc_failure;
|
||||
}
|
||||
for (i = 0; i < new_max; i++) {
|
||||
if (i < gi->data_blk_cnt) {
|
||||
realloc[i] = gi->wo_data[i];
|
||||
}else {
|
||||
append = va_arg(ap, struct op_write *);
|
||||
realloc[i] = append;
|
||||
}
|
||||
}
|
||||
kfree(gi->wo_data);
|
||||
gi->wo_data = realloc;
|
||||
} else {
|
||||
struct op_read **realloc, *append;
|
||||
realloc = (struct op_read **)kzalloc(sizeof(struct op_read *)*
|
||||
(gi->data_blk_cnt + data_blk_cnt),
|
||||
GFP_KERNEL);
|
||||
if (!realloc) {
|
||||
retval = -ENOMEM;
|
||||
goto alloc_failure;
|
||||
}
|
||||
for (i = 0; i < new_max; i++) {
|
||||
if (i < gi->data_blk_cnt) {
|
||||
realloc[i] = gi->ro_data[i];
|
||||
}else {
|
||||
append = va_arg(ap, struct op_read *);
|
||||
realloc[i] = append;
|
||||
}
|
||||
}
|
||||
kfree(gi->ro_data);
|
||||
gi->ro_data = realloc;
|
||||
}
|
||||
gi->data_blk_cnt += data_blk_cnt;
|
||||
cab_debug("modified group:[%s] access:%s has %d data blocks\n",
|
||||
GROUP_NAME(gi->group), DIR_NAME(gi->group), gi->data_blk_cnt);
|
||||
alloc_failure:
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void control_access_block_zap(unsigned char gid)
|
||||
{
|
||||
struct touch_control_access_block *cab = control_access_block_get();
|
||||
struct grp_info **grp_ptr = NULL;
|
||||
int i, idx = 0;
|
||||
|
||||
for (i = 0; i < cab->grp_num; i++) {
|
||||
if (cab->grp_ptr[i] && cab->grp_ptr[i]->group == gid) {
|
||||
idx = i;
|
||||
grp_ptr = &cab->grp_ptr[idx];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!grp_ptr)
|
||||
return;
|
||||
|
||||
/* clean up data and make slot available */
|
||||
if ((*grp_ptr)->group & MODE_WO) {
|
||||
struct op_write *data;
|
||||
for (i = 0; i < (*grp_ptr)->data_blk_cnt; i++) {
|
||||
data = (*grp_ptr)->wo_data[i];
|
||||
kfree(data);
|
||||
}
|
||||
kfree((*grp_ptr)->wo_data);
|
||||
} else {
|
||||
struct op_read *data;
|
||||
for (i = 0; i < (*grp_ptr)->data_blk_cnt; i++) {
|
||||
data = (*grp_ptr)->ro_data[i];
|
||||
kfree(data);
|
||||
}
|
||||
kfree((*grp_ptr)->ro_data);
|
||||
}
|
||||
|
||||
kfree(*grp_ptr);
|
||||
*grp_ptr = NULL;
|
||||
|
||||
cab_debug("group [%s] idx %d removed %d record(s)\n", GROUP_NAME(gid), idx, i);
|
||||
}
|
||||
|
||||
static struct grp_info **find_group(unsigned char gid)
|
||||
{
|
||||
struct touch_control_access_block *cab = control_access_block_get();
|
||||
struct grp_info **grp_ptr = NULL;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < cab->grp_num; i++) {
|
||||
if (cab->grp_ptr[i] && cab->grp_ptr[i]->group &&
|
||||
cab->grp_ptr[i]->group != gid)
|
||||
continue;
|
||||
/* match or empty slot */
|
||||
grp_ptr = &cab->grp_ptr[i];
|
||||
break;
|
||||
}
|
||||
cab_debug("idx %d %s\n", i, *grp_ptr ? "existing" : "new");
|
||||
return grp_ptr;
|
||||
}
|
||||
|
||||
static int add_tail(struct grp_info **grp, unsigned char gid, void *io_data)
|
||||
{
|
||||
int retval = 0;
|
||||
|
||||
if (!*grp) {
|
||||
struct grp_info *new;
|
||||
|
||||
new = alloc_grp_info(gid, 1, (void *)io_data);
|
||||
if (!new) {
|
||||
retval = -ENOMEM;
|
||||
goto alloc_failure;
|
||||
}
|
||||
*grp = new;
|
||||
cab_debug("created new %s group\n", DIR_NAME((*grp)->group));
|
||||
} else {
|
||||
modify_grp_info(*grp, 1, (void *)io_data);
|
||||
cab_debug("added %s block\n", DIR_NAME((*grp)->group));
|
||||
}
|
||||
alloc_failure:
|
||||
return retval;
|
||||
}
|
||||
|
||||
int control_access_block_update_ro(
|
||||
unsigned char gid,
|
||||
unsigned short paddr,
|
||||
unsigned char sz,
|
||||
unsigned char cnt)
|
||||
{
|
||||
struct op_read *ro = alloc_op_read(paddr, sz, cnt);
|
||||
struct grp_info **grp = find_group(gid);
|
||||
return !ro ? -1 : add_tail(grp, gid, (void *)ro);
|
||||
}
|
||||
|
||||
int control_access_block_update_wo(
|
||||
unsigned char gid,
|
||||
unsigned short paddr,
|
||||
unsigned char sz,
|
||||
unsigned char mask,
|
||||
unsigned char *data)
|
||||
{
|
||||
struct op_write *wo = alloc_op_write(paddr, sz, 1, mask, data);
|
||||
struct grp_info **grp = find_group(gid);
|
||||
return !wo ? -1 : add_tail(grp, gid, (void *)wo);
|
||||
}
|
||||
|
||||
static struct device_attribute attrs[] = {
|
||||
__ATTR(control_access_block, S_IRUSR | S_IRGRP,
|
||||
control_access_block_show, NULL),
|
||||
};
|
||||
|
||||
static int synaptics_control_access_block_init(
|
||||
struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval, attr_count;
|
||||
|
||||
control_access_block = kzalloc(sizeof(*control_access_block), GFP_KERNEL);
|
||||
if (!control_access_block) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to alloc controll access block\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
control_access_block->grp_num = GROUP_MAX;
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
retval = sysfs_create_file(&rmi4_data->i2c_client->dev.kobj,
|
||||
&attrs[attr_count].attr);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs attributes\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
goto exit_remove_attrs;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_attrs:
|
||||
for (attr_count--; attr_count >= 0; attr_count--) {
|
||||
sysfs_remove_file(&rmi4_data->i2c_client->dev.kobj,
|
||||
&attrs[attr_count].attr);
|
||||
}
|
||||
exit:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct completion remove_complete;
|
||||
|
||||
static void synaptics_control_access_block_remove(
|
||||
struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int i, m, attr_count;
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
sysfs_remove_file(&rmi4_data->i2c_client->dev.kobj,
|
||||
&attrs[attr_count].attr);
|
||||
}
|
||||
|
||||
for (i = 0; i < control_access_block->grp_num; i++) {
|
||||
struct grp_info *ginfo = control_access_block->grp_ptr[i];
|
||||
void **ptr_to_free;
|
||||
|
||||
if (ginfo->group & MODE_WO)
|
||||
ptr_to_free = (void **)ginfo->wo_data;
|
||||
else
|
||||
ptr_to_free = (void **)ginfo->ro_data;
|
||||
|
||||
for (m = 0; m < ginfo->data_blk_cnt; m++) {
|
||||
if (ginfo->group & MODE_WO)
|
||||
kfree(ginfo->wo_data[m]);
|
||||
else
|
||||
kfree(ginfo->ro_data[m]);
|
||||
}
|
||||
kfree(ptr_to_free);
|
||||
kfree(ginfo);
|
||||
}
|
||||
|
||||
kfree(control_access_block->grp_ptr);
|
||||
kfree(control_access_block);
|
||||
control_access_block = NULL;
|
||||
|
||||
complete(&remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int __init synaptics_control_access_block_module_init(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(RMI_CTRL_ACCESS_BLK, true,
|
||||
synaptics_control_access_block_init,
|
||||
synaptics_control_access_block_remove,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit synaptics_control_access_block_module_exit(void)
|
||||
{
|
||||
init_completion(&remove_complete);
|
||||
synaptics_rmi4_new_function(RMI_CTRL_ACCESS_BLK, false,
|
||||
synaptics_control_access_block_init,
|
||||
synaptics_control_access_block_remove,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
wait_for_completion(&remove_complete);
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(synaptics_control_access_block_module_init);
|
||||
module_exit(synaptics_control_access_block_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Motorola Mobility, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX Touch Access Block Module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(SYNAPTICS_DSX_DRIVER_VERSION);
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver extension
|
||||
*
|
||||
* Copyright (C) 2015 Motorola Mobility, Inc.
|
||||
*
|
||||
* Copyright (C) 2015 Konstantin Makariev <kmakariev@motorola.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.
|
||||
*/
|
||||
#ifndef _SYNAPTICS_DSX_CONTROL_ACCESS_BLOCK_H_
|
||||
#define _SYNAPTICS_DSX_CONTROL_ACCESS_BLOCK_H_
|
||||
|
||||
#define MODE_WO (1 << 7)
|
||||
#define GROUP_MAX 7
|
||||
|
||||
enum access_groups {
|
||||
SYN_DSX_STATUS = 1, /* RO:mandatory, read status to clear IRQ */
|
||||
SYN_DSX_MODE, /* RO:mandatory, read touch IC mode */
|
||||
SYN_DSX_DATA, /* RO:mandatory, read touch data */
|
||||
SYN_DSX_WAKE = SYN_DSX_DATA + 1 + MODE_WO,
|
||||
/* WO:mandatory, command(s) to wake up touch IC */
|
||||
SYN_DSX_SLEEP, /* WO:mandatory, command(s) to put touch IC to sleep */
|
||||
SYN_DSX_RESET, /* WO:optional, command to reset touch IC */
|
||||
SYN_DSX_CONFIG, /* WO:optional, command(s) to apply custom config */
|
||||
SYN_DSX_VAL_MAX = 0xff
|
||||
};
|
||||
|
||||
struct op_read {
|
||||
struct {
|
||||
unsigned short paddr; /* (page << 8) + address */
|
||||
unsigned char blk_sz; /* read block size */
|
||||
unsigned char blk_cnt; /* read block count */
|
||||
};
|
||||
};
|
||||
|
||||
struct op_write {
|
||||
struct {
|
||||
unsigned short paddr; /* (page << 8) + address */
|
||||
unsigned char blk_sz; /* write block size */
|
||||
unsigned char blk_cnt; /* write block count */
|
||||
};
|
||||
unsigned char mask; /* mask to clear bit(s) before apply data */
|
||||
/* only effective when blk_cnt and blk_sz */
|
||||
/* both are 1s, otherwise mask is ignored */
|
||||
unsigned char data[0]; /* blk_cnt of data chunks of blk_sz each */
|
||||
};
|
||||
|
||||
struct grp_info {
|
||||
unsigned char group; /* access group; defines type of data */
|
||||
unsigned char data_blk_cnt; /* number of data blocks in the group */
|
||||
union {
|
||||
struct op_read **ro_data;
|
||||
struct op_write **wo_data;
|
||||
};
|
||||
};
|
||||
|
||||
struct touch_control_access_block {
|
||||
unsigned char do_sync; /* flag to indicate data block was updated */
|
||||
unsigned char grp_num; /* number of groups in data block */
|
||||
struct grp_info *grp_ptr[GROUP_MAX];
|
||||
};
|
||||
|
||||
#if defined(CONFIG_TOUCHSCREEN_SYNAPTICS_DSX_CTRL_ACCESS_BLK)
|
||||
struct touch_control_access_block *control_access_block_get(void);
|
||||
int control_access_block_update_ro(unsigned char gid, unsigned short paddr,
|
||||
unsigned char sz, unsigned char cnt);
|
||||
int control_access_block_update_wo(unsigned char gid, unsigned short paddr,
|
||||
unsigned char sz, unsigned char mask, unsigned char *data);
|
||||
void control_access_block_zap(unsigned char gid);
|
||||
#else
|
||||
static inline struct touch_control_access_block *control_access_block_get(void) {
|
||||
return NULL;
|
||||
}
|
||||
static int inline control_access_block_update_ro(
|
||||
unsigned char gid, unsigned short paddr,
|
||||
unsigned char sz, unsigned char cnt) {
|
||||
return -1;
|
||||
}
|
||||
static int inline control_access_block_update_wo(
|
||||
unsigned char gid, unsigned short paddr,
|
||||
unsigned char sz, unsigned char mask, unsigned char *data) {
|
||||
return -1;
|
||||
}
|
||||
static void inline control_access_block_zap(unsigned char gid) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#define control_access_block_update_status(paddr, size) \
|
||||
control_access_block_update_ro(SYN_DSX_STATUS, paddr, size, 1)
|
||||
#define control_access_block_update_mode(paddr, size) \
|
||||
control_access_block_update_ro(SYN_DSX_MODE, paddr, size, 1)
|
||||
#define control_access_block_update_data(paddr, size) \
|
||||
control_access_block_update_ro(SYN_DSX_DATA, paddr, size, 1)
|
||||
#define control_access_block_update_data_mt(paddr, size, mt) \
|
||||
control_access_block_update_ro(SYN_DSX_DATA, paddr, size, mt)
|
||||
#define control_access_block_update_reset(paddr, size, data) \
|
||||
control_access_block_update_wo(SYN_DSX_RESET, paddr, size, 0, data)
|
||||
#define control_access_block_update_wake(paddr, size, data) \
|
||||
control_access_block_update_wo(SYN_DSX_WAKE, paddr, size, 0x7, data)
|
||||
#define control_access_block_update_sleep(paddr, size, data) \
|
||||
control_access_block_update_wo(SYN_DSX_SLEEP, paddr, size, 0x7, data)
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/* Copyright (c) 2014 - 2015, Motorola Mobility LLC. 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 version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/dropbox.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "synaptics_dsx_dropbox.h"
|
||||
|
||||
#define DROPBOX_TOUCH_ISSUE "touch_issue"
|
||||
|
||||
static DEFINE_RATELIMIT_STATE(synaptics_dropbox_global_rl, 3600 * HZ, 1);
|
||||
|
||||
void synaptics_dropbox_report_event(char *msg, int count)
|
||||
{
|
||||
char dropbox_entry[256];
|
||||
|
||||
snprintf(dropbox_entry, sizeof(dropbox_entry), "%s\ncount: %d",
|
||||
msg, count);
|
||||
pr_err("%s: touch issue detected[count: %d][%s], reporting dropbox\n",
|
||||
__func__, count, msg);
|
||||
dropbox_queue_event_text(DROPBOX_TOUCH_ISSUE,
|
||||
dropbox_entry, strlen(dropbox_entry));
|
||||
}
|
||||
|
||||
void synaptics_dropbox_report_event_ratelimit(char *msg, int count)
|
||||
{
|
||||
struct ratelimit_state *rs = &synaptics_dropbox_global_rl;
|
||||
|
||||
if (!__ratelimit(rs))
|
||||
return;
|
||||
synaptics_dropbox_report_event(msg, count);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/* Copyright (c) 2014 - 2015, Motorola Mobility LLC. 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 version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef SYNAPTICS_DROPBOX_H
|
||||
#define SYNAPTICS_DROPBOX_H
|
||||
|
||||
#include <linux/ratelimit.h>
|
||||
|
||||
#define SYNAPTICS_DROPBOX_MSG_I2C "Touch I2C communication error detected"
|
||||
#define SYNAPTICS_DROPBOX_MSG_RESET_TIMEOUT "Touch reset time out detected"
|
||||
|
||||
#if defined(CONFIG_DROPBOX)
|
||||
void synaptics_dropbox_report_event(char *msg, int count);
|
||||
void synaptics_dropbox_report_event_ratelimit(char *msg, int count);
|
||||
#else
|
||||
static inline void synaptics_dropbox_report_event(char *msg, int count) {}
|
||||
static inline void synaptics_dropbox_report_event_ratelimit(char *msg, int count) {}
|
||||
#endif
|
||||
#endif /* SYNAPTICS_DROPBOX_H */
|
||||
4522
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_fw_update.c
Normal file
4522
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_fw_update.c
Normal file
File diff suppressed because it is too large
Load diff
7876
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.c
Normal file
7876
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.c
Normal file
File diff suppressed because it is too large
Load diff
692
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.h
Normal file
692
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_i2c.h
Normal file
|
|
@ -0,0 +1,692 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012 Synaptics Incorporated
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYNAPTICS_DSX_RMI4_H_
|
||||
#define _SYNAPTICS_DSX_RMI4_H_
|
||||
|
||||
#define SYNAPTICS_DSX_DRIVER_VERSION "DSX 1.1"
|
||||
|
||||
/* define to enable USB charger detection */
|
||||
#undef USB_CHARGER_DETECTION
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#if defined(USB_CHARGER_DETECTION)
|
||||
#include <linux/usb.h>
|
||||
#include <linux/power_supply.h>
|
||||
#endif
|
||||
#if defined(CONFIG_MMI_PANEL_NOTIFICATIONS)
|
||||
#include <linux/mmi_panel_notifier.h>
|
||||
#elif defined(CONFIG_FB)
|
||||
#include <linux/notifier.h>
|
||||
#include <linux/fb.h>
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
|
||||
#define KERNEL_ABOVE_2_6_38
|
||||
#endif
|
||||
|
||||
#ifdef KERNEL_ABOVE_2_6_38
|
||||
#define sstrtoul(...) kstrtoul(__VA_ARGS__)
|
||||
#else
|
||||
#define sstrtoul(...) strict_strtoul(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(3, 7, 0))
|
||||
#define KERNEL_ABOVE_3_7
|
||||
#endif
|
||||
|
||||
#define PDT_PROPS (0x00EF)
|
||||
#define PDT_START (0x00E9)
|
||||
#define PDT_END (0x000A)
|
||||
#define PDT_ENTRY_SIZE (0x0006)
|
||||
#define PAGES_TO_SERVICE (10)
|
||||
#define PAGE_SELECT_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 SYNAPTICS_RMI4_PRODUCT_INFO_SIZE 2
|
||||
#define SYNAPTICS_RMI4_PRODUCT_ID_SIZE 10
|
||||
#define SYNAPTICS_RMI4_BUILD_ID_SIZE 3
|
||||
#define SYNAPTICS_RMI4_SERIAL_SIZE 7
|
||||
#define SYNAPTICS_RMI4_CONFIG_ID_SIZE 4
|
||||
#define SYNAPTICS_RMI4_PACKAGE_ID_SIZE 4
|
||||
#define SYNAPTICS_RMI4_FILENAME_SIZE 80
|
||||
|
||||
#define PACKAGE_ID_OFFSET 17
|
||||
#define FW_VERSION_OFFSET 18
|
||||
#define F34_PROPERTIES_OFFSET 1
|
||||
#define F34_PROPERTIES_OFFSET_V2 0
|
||||
|
||||
#define MAX_NUMBER_OF_FINGERS 10
|
||||
#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 PRODUCT_INFO_SIZE 2
|
||||
#define PRODUCT_ID_SIZE 10
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
|
||||
* @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_number: function number
|
||||
*/
|
||||
struct synaptics_rmi4_fn_desc {
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 data registers
|
||||
* @ctrl_base: 16-bit base address for command registers
|
||||
* @data_base: 16-bit base address for control 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_fn - function handler data structure
|
||||
* @fn_number: function number
|
||||
* @num_of_data_sources: number of data sources
|
||||
* @num_of_data_points: maximum number of fingers supported
|
||||
* @size_of_data_register_block: data register block size
|
||||
* @data1_offset: offset to data1 register from data base address
|
||||
* @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
|
||||
*/
|
||||
struct synaptics_rmi4_fn {
|
||||
unsigned char fn_number;
|
||||
unsigned char num_of_data_sources;
|
||||
unsigned char num_of_data_points;
|
||||
unsigned char size_of_data_register_block;
|
||||
unsigned char data1_offset;
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
* 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 information
|
||||
* @product_info: product info array
|
||||
* @date_code: device manufacture date
|
||||
* @tester_id: tester id array
|
||||
* @serial_number: device serial number
|
||||
* @product_id_string: device product 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[SYNAPTICS_RMI4_PRODUCT_INFO_SIZE];
|
||||
unsigned char serial[SYNAPTICS_RMI4_SERIAL_SIZE];
|
||||
unsigned char package_id[SYNAPTICS_RMI4_PACKAGE_ID_SIZE];
|
||||
unsigned char product_id_string[SYNAPTICS_RMI4_PRODUCT_ID_SIZE + 1];
|
||||
unsigned char build_id[SYNAPTICS_RMI4_BUILD_ID_SIZE];
|
||||
unsigned char config_id[SYNAPTICS_RMI4_CONFIG_ID_SIZE];
|
||||
struct list_head support_fn_list;
|
||||
};
|
||||
|
||||
struct touch_up_down {
|
||||
int mismatch;
|
||||
unsigned char up_down;
|
||||
unsigned int counter;
|
||||
};
|
||||
|
||||
struct touch_area_stats {
|
||||
struct touch_up_down *ud;
|
||||
ssize_t ud_len;
|
||||
ssize_t ud_id;
|
||||
ssize_t unknown_counter;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
struct synaptics_dsx_func_patch {
|
||||
unsigned short func;
|
||||
unsigned char regstr;
|
||||
unsigned char subpkt;
|
||||
unsigned char size;
|
||||
unsigned char bitmask;
|
||||
unsigned char *data;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
struct synaptics_clip_area {
|
||||
unsigned xul_clip, yul_clip, xbr_clip, ybr_clip;
|
||||
unsigned inversion; /* clip inside (when 1) or ouside otherwise */
|
||||
};
|
||||
|
||||
enum {
|
||||
SYNA_MOD_AOD,
|
||||
SYNA_MOD_STATS,
|
||||
SYNA_MOD_FOLIO,
|
||||
SYNA_MOD_CHARGER,
|
||||
SYNA_MOD_WAKEUP,
|
||||
SYNA_MOD_FPS,
|
||||
SYNA_MOD_QUERY, /* run time query; active only */
|
||||
SYNA_MOD_RT, /* run time patch; active only; always effective */
|
||||
SYNA_MOD_MAX
|
||||
};
|
||||
|
||||
#define FLAG_FORCE_UPDATE 1
|
||||
#define FLAG_WAKEABLE 2
|
||||
#define FLAG_POWER_SLEEP 4
|
||||
|
||||
struct synaptics_dsx_patch {
|
||||
const char *name;
|
||||
int cfg_num;
|
||||
unsigned int flags;
|
||||
struct semaphore list_sema;
|
||||
struct list_head cfg_head;
|
||||
};
|
||||
|
||||
struct config_modifier {
|
||||
const char *name;
|
||||
int id;
|
||||
bool effective;
|
||||
struct synaptics_dsx_patch *active;
|
||||
struct synaptics_dsx_patch *suspended;
|
||||
struct synaptics_clip_area *clipa;
|
||||
struct list_head link;
|
||||
};
|
||||
|
||||
struct synaptics_dsx_modifiers {
|
||||
int mods_num;
|
||||
struct semaphore list_sema;
|
||||
struct list_head mod_head;
|
||||
|
||||
};
|
||||
|
||||
struct f34_properties {
|
||||
union {
|
||||
struct {
|
||||
unsigned char regmap:1;
|
||||
unsigned char unlocked:1;
|
||||
unsigned char has_config_id:1;
|
||||
unsigned char has_perm_config:1;
|
||||
unsigned char has_bl_config:1;
|
||||
unsigned char has_display_config:1;
|
||||
unsigned char has_blob_config:1;
|
||||
unsigned char reserved:1;
|
||||
} __packed;
|
||||
unsigned char data[1];
|
||||
};
|
||||
};
|
||||
|
||||
struct f34_properties_v2 {
|
||||
union {
|
||||
struct {
|
||||
unsigned char query0_subpkt1_size:3;
|
||||
unsigned char has_config_id:1;
|
||||
unsigned char reserved:1;
|
||||
unsigned char has_thqa:1;
|
||||
unsigned char reserved2:2;
|
||||
} __packed;
|
||||
unsigned char data[1];
|
||||
};
|
||||
};
|
||||
|
||||
struct f54_control_95n {
|
||||
union {
|
||||
struct {
|
||||
/* byte 0 - flags*/
|
||||
unsigned char c95_filter_bw:3;
|
||||
unsigned char c95_byte0_b3_b6:4;
|
||||
unsigned char c95_disable:1;
|
||||
|
||||
/* bytes 1 - 10 */
|
||||
unsigned char c95_first_burst_length_lsb;
|
||||
unsigned char c95_first_burst_length_msb;
|
||||
unsigned char c95_addl_burst_length_lsb;
|
||||
unsigned char c95_addl_burst_length_msb;
|
||||
unsigned char c95_i_stretch;
|
||||
unsigned char c95_r_stretch;
|
||||
unsigned char c95_noise_control1;
|
||||
unsigned char c95_noise_control2;
|
||||
unsigned char c95_noise_control3;
|
||||
unsigned char c95_noise_control4;
|
||||
} __packed;
|
||||
struct {
|
||||
unsigned char data[11];
|
||||
} __packed;
|
||||
};
|
||||
};
|
||||
|
||||
enum {
|
||||
STATE_UNKNOWN,
|
||||
STATE_ACTIVE,
|
||||
STATE_SUSPEND,
|
||||
STATE_STANDBY = 4,
|
||||
STATE_BL,
|
||||
STATE_INIT,
|
||||
STATE_FLASH,
|
||||
STATE_QUERY,
|
||||
STATE_INVALID
|
||||
};
|
||||
|
||||
#define STATE_UI (STATE_ACTIVE | STATE_SUSPEND)
|
||||
|
||||
enum ic_modes {
|
||||
IC_MODE_ANY = 0,
|
||||
IC_MODE_BL,
|
||||
IC_MODE_UI
|
||||
};
|
||||
|
||||
enum exp_fn {
|
||||
RMI_DEV = 0,
|
||||
RMI_F34,
|
||||
RMI_F54,
|
||||
RMI_FW_UPDATER,
|
||||
RMI_CTRL_ACCESS_BLK,
|
||||
RMI_LAST,
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static inline void batohui(unsigned int *dest, unsigned char *src, size_t size)
|
||||
{
|
||||
int si = size;
|
||||
*dest = 0;
|
||||
for (; --si >= 0;)
|
||||
*dest += src[si] << (si << 3);
|
||||
}
|
||||
|
||||
struct synaptics_rmi4_subpkt {
|
||||
bool present;
|
||||
bool expected;
|
||||
short offset;
|
||||
unsigned int size;
|
||||
void *data;
|
||||
};
|
||||
|
||||
#define RMI4_SUBPKT(a)\
|
||||
{.present = 0, .expected = 1, .size = sizeof(a), .data = &a}
|
||||
#define RMI4_SUBPKT_STATIC(o, a)\
|
||||
{.present = 1, .expected = 1,\
|
||||
.offset = o, .size = sizeof(a), .data = &a}
|
||||
|
||||
struct synaptics_rmi4_packet_reg {
|
||||
unsigned short r_number;
|
||||
bool updated; /* indicate that value in *data has been updated */
|
||||
bool modified; /* indicate that value in *data has been modified */
|
||||
bool expected;
|
||||
short offset;
|
||||
unsigned int size;
|
||||
unsigned char *data;
|
||||
unsigned char nr_subpkts;
|
||||
struct synaptics_rmi4_subpkt *subpkt;
|
||||
};
|
||||
|
||||
#define RMI4_NO_REG(r) {\
|
||||
.r_number = r, .offset = -1, .updated = 0, .modified = 0,\
|
||||
.expected = 0, .size = 0, .data = NULL,\
|
||||
.nr_subpkts = 0, .subpkt = NULL}
|
||||
#define RMI4_REG(r, s) {\
|
||||
.r_number = r, .offset = -1, .updated = 0, .modified = 0,\
|
||||
.expected = 1, .size = 0, .data = NULL,\
|
||||
.nr_subpkts = ARRAY_SIZE(s), .subpkt = s}
|
||||
#define RMI4_REG_STATIC(r, s, sz) {\
|
||||
.r_number = r, .offset = r, .updated = 0, .modified = 0,\
|
||||
.expected = 1, .size = sz, .data = NULL,\
|
||||
.nr_subpkts = ARRAY_SIZE(s), .subpkt = s}
|
||||
|
||||
struct synaptics_rmi4_func_packet_regs {
|
||||
unsigned short f_number;
|
||||
unsigned short base_addr;
|
||||
unsigned short query_offset;
|
||||
int nr_regs;
|
||||
struct synaptics_rmi4_packet_reg *regs;
|
||||
};
|
||||
|
||||
struct reporting_ctrl {
|
||||
bool reporting_stopped;
|
||||
unsigned int events_cnt;
|
||||
int expected, max_seen;
|
||||
struct semaphore ctrl_sema;
|
||||
};
|
||||
|
||||
#define MAX_READ_WRITE_SIZE 8096
|
||||
#define MIN_READ_WRITE_BUF_SIZE 256
|
||||
|
||||
struct temp_buffer {
|
||||
unsigned char *buf;
|
||||
unsigned short buf_size;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_rmi4_data - rmi4 device instance data
|
||||
* @i2c_client: pointer to associated i2c client
|
||||
* @input_dev: pointer to associated input device
|
||||
* @board: constant pointer to platform data
|
||||
* @rmi4_mod_info: device information
|
||||
* @regulator: pointer to associated regulator
|
||||
* @vdd_quirk: pointer to associated regulator for 'quirk' config
|
||||
* @rmi4_io_ctrl_mutex: mutex for i2c i/o control
|
||||
* @det_work: work thread instance for expansion function detection
|
||||
* @det_workqueue: pointer to work queue for work thread instance
|
||||
* @early_suspend: instance to support early suspend power management
|
||||
* @current_page: current page in sensor to acess
|
||||
* @button_0d_enabled: flag for 0d button support
|
||||
* @full_pm_cycle: flag for full power management cycle in early suspend stage
|
||||
* @num_of_intr_regs: number of interrupt registers
|
||||
* @f01_query_base_addr: query base address for f01
|
||||
* @f01_cmd_base_addr: command base address for f01
|
||||
* @f01_ctrl_base_addr: control base address for f01
|
||||
* @f01_data_base_addr: data base address for f01
|
||||
* @irq: attention interrupt
|
||||
* @sensor_max_x: sensor maximum x value
|
||||
* @sensor_max_y: sensor maximum y value
|
||||
* @irq_enabled: flag for indicating interrupt enable status
|
||||
* @touch_stopped: touch is in suspend state
|
||||
* @flash_enabled: allow flashing once transition to active state is complete
|
||||
* @ic_on: touch ic power state
|
||||
* @fingers_on_2d: flag to indicate presence of fingers in 2d area
|
||||
* @wait: wait queue for touch data polling in interrupt thread
|
||||
* @number_irq: total number of remembered interrupt times
|
||||
* @last_irq: last interrup time's number (index of the location of interrupt)
|
||||
* @irq_info: information about last few interrupt times
|
||||
* @i2c_read: pointer to i2c read function
|
||||
* @i2c_write: pointer to i2c write function
|
||||
* @irq_enable: pointer to irq enable function
|
||||
*/
|
||||
struct synaptics_rmi4_data {
|
||||
struct i2c_client *i2c_client;
|
||||
struct input_dev *input_dev;
|
||||
const struct synaptics_dsx_platform_data *board;
|
||||
struct synaptics_rmi4_device_info rmi4_mod_info;
|
||||
struct regulator *regulator;
|
||||
struct regulator *vdd_quirk;
|
||||
struct mutex rmi4_io_ctrl_mutex;
|
||||
struct mutex state_mutex;
|
||||
#if defined(CONFIG_MMI_PANEL_NOTIFICATIONS)
|
||||
struct mmi_notifier panel_nb;
|
||||
#elif defined(CONFIG_FB)
|
||||
struct notifier_block panel_nb;
|
||||
#endif
|
||||
atomic_t panel_off_flag;
|
||||
unsigned char current_page;
|
||||
unsigned char button_0d_enabled;
|
||||
unsigned char num_of_rx;
|
||||
unsigned char num_of_tx;
|
||||
unsigned char num_of_fingers;
|
||||
unsigned char aod_mt;
|
||||
unsigned char f01_ctrl_register_0;
|
||||
unsigned char intr_mask[MAX_INTR_REGISTERS];
|
||||
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 active_fn_intr_mask;
|
||||
int state;
|
||||
int irq;
|
||||
int sensor_max_x;
|
||||
int sensor_max_y;
|
||||
bool irq_enabled;
|
||||
atomic_t touch_stopped;
|
||||
bool flash_enabled;
|
||||
bool ic_on;
|
||||
bool fingers_on_2d;
|
||||
bool input_registered;
|
||||
bool in_bootloader;
|
||||
wait_queue_head_t wait;
|
||||
int (*i2c_read)(struct synaptics_rmi4_data *pdata, unsigned short addr,
|
||||
unsigned char *data, unsigned short length);
|
||||
int (*i2c_write)(struct synaptics_rmi4_data *pdata, unsigned short addr,
|
||||
unsigned char *data, unsigned short length);
|
||||
void (*set_state)(struct synaptics_rmi4_data *rmi4_data, int state);
|
||||
int (*ready_state)(struct synaptics_rmi4_data *rmi4_data, bool standby);
|
||||
int (*irq_enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
|
||||
int (*reset_device)(struct synaptics_rmi4_data *rmi4_data);
|
||||
int (*get_status)(struct synaptics_rmi4_data *rmi4_data);
|
||||
int number_irq;
|
||||
int last_irq;
|
||||
struct synaptics_rmi4_irq_info *irq_info;
|
||||
|
||||
/* features enablers */
|
||||
bool charger_detection_enabled;
|
||||
bool folio_detection_enabled;
|
||||
bool fps_detection_enabled;
|
||||
bool wakeup_detection_enabled;
|
||||
bool patching_enabled;
|
||||
bool purge_enabled;
|
||||
|
||||
bool suspend_is_wakeable;
|
||||
bool clipping_on;
|
||||
struct synaptics_clip_area *clipa;
|
||||
struct synaptics_dsx_modifiers modifiers;
|
||||
|
||||
struct work_struct resume_work;
|
||||
struct synaptics_rmi4_func_packet_regs *f12_data_registers_ptr;
|
||||
struct notifier_block rmi_reboot;
|
||||
#if defined(USB_CHARGER_DETECTION)
|
||||
struct power_supply psy;
|
||||
#endif
|
||||
#ifdef CONFIG_MMI_HALL_NOTIFICATIONS
|
||||
struct notifier_block folio_notif;
|
||||
#endif
|
||||
bool is_fps_registered; /* FPS notif registration might be delayed */
|
||||
struct notifier_block fps_notif;
|
||||
|
||||
struct mutex rmi4_exp_init_mutex;
|
||||
uint32_t pm_qos_latency;
|
||||
struct pm_qos_request pm_qos_irq;
|
||||
|
||||
struct reporting_ctrl rctrl;
|
||||
unsigned char tsb_buff_clean_flag;
|
||||
|
||||
bool touch_data_contiguous;
|
||||
uint8_t *touch_data;
|
||||
uint16_t touch_data_size;
|
||||
|
||||
struct temp_buffer write_buf;
|
||||
|
||||
#if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
|
||||
/* TEST OPTIONS */
|
||||
int test_irq_delay_ms;
|
||||
int test_irq_data_contig;
|
||||
#endif
|
||||
};
|
||||
|
||||
static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
|
||||
|
||||
dev_warn(&rmi4_data->i2c_client->dev,
|
||||
"%s Attempted to read from write-only attribute %s\n",
|
||||
__func__, attr->attr.name);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
static inline ssize_t synaptics_rmi4_store_error(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
|
||||
|
||||
dev_warn(&rmi4_data->i2c_client->dev,
|
||||
"%s Attempted to write to read-only attribute %s\n",
|
||||
__func__, attr->attr.name);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
struct time_keeping {
|
||||
int id;
|
||||
unsigned long long duration;
|
||||
} __packed;
|
||||
|
||||
struct statistics {
|
||||
int active; /* current index within keeper array */
|
||||
int max; /* keeper array dimension */
|
||||
bool clk_run;/* flag to indicate whether clock is ticking */
|
||||
unsigned int flags; /* time keeping flags */
|
||||
unsigned char abbr; /* abbreviation letter */
|
||||
ktime_t start; /* time notch */
|
||||
struct time_keeping keeper[0];
|
||||
} __packed;
|
||||
|
||||
enum {
|
||||
FREQ_DURATION, /* scanning frequencies duration */
|
||||
FREQ_HOPPING, /* scanning frequencies hopping */
|
||||
MODE_NMS, /* noise mitigation mode */
|
||||
MODE_METAL_PLATE, /* metal plate detection */
|
||||
STATISTICS_MAX
|
||||
};
|
||||
|
||||
struct synaptics_dsx_stats {
|
||||
bool enabled;
|
||||
ktime_t uptime;
|
||||
bool uptime_run;
|
||||
unsigned long long uptime_dur;
|
||||
struct statistics *stats[STATISTICS_MAX];
|
||||
#define dur stats[FREQ_DURATION]
|
||||
#define hop stats[FREQ_HOPPING]
|
||||
#define nms stats[MODE_NMS]
|
||||
#define mpd stats[MODE_METAL_PLATE]
|
||||
} __packed;
|
||||
|
||||
struct synaptics_rmi4_exp_fn_ptr {
|
||||
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);
|
||||
int (*enable)(struct synaptics_rmi4_data *rmi4_data, bool enable);
|
||||
};
|
||||
|
||||
void synaptics_rmi4_new_function(enum exp_fn fn_type, bool insert,
|
||||
int (*func_init)(struct synaptics_rmi4_data *rmi4_data),
|
||||
void (*func_remove)(struct synaptics_rmi4_data *rmi4_data),
|
||||
void (*func_attn)(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned char intr_mask),
|
||||
int (*func_status)(struct synaptics_rmi4_data *rmi4_data),
|
||||
enum ic_modes mode);
|
||||
|
||||
int synaptics_rmi4_scan_packet_reg_info(
|
||||
struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short query_addr,
|
||||
unsigned short regs_base_addr,
|
||||
struct synaptics_rmi4_func_packet_regs *regs);
|
||||
|
||||
int synaptics_rmi4_read_packet_reg(
|
||||
struct synaptics_rmi4_data *rmi4_data,
|
||||
struct synaptics_rmi4_func_packet_regs *regs, int idx);
|
||||
|
||||
int synaptics_rmi4_read_packet_regs(
|
||||
struct synaptics_rmi4_data *rmi4_data,
|
||||
struct synaptics_rmi4_func_packet_regs *regs);
|
||||
|
||||
int alloc_buffer(struct temp_buffer *tb, size_t count);
|
||||
|
||||
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 int synaptics_rmi4_reg_read(
|
||||
struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr,
|
||||
unsigned char *data,
|
||||
unsigned short len)
|
||||
{
|
||||
return rmi4_data->i2c_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->i2c_write(rmi4_data, addr, data, len);
|
||||
}
|
||||
|
||||
extern int FPS_register_notifier(struct notifier_block *nb,
|
||||
unsigned long stype, bool report);
|
||||
extern int FPS_unregister_notifier(struct notifier_block *nb,
|
||||
unsigned long stype);
|
||||
#endif
|
||||
791
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_rmi_dev.c
Normal file
791
drivers/input/touchscreen/synaptics_mmi/synaptics_dsx_rmi_dev.c
Normal file
|
|
@ -0,0 +1,791 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012 Synaptics Incorporated
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/input/synaptics_dsx_mmi.h>
|
||||
|
||||
#include "synaptics_dsx_i2c.h"
|
||||
|
||||
#define CHAR_DEVICE_NAME "rmi"
|
||||
#define DEVICE_CLASS_NAME "rmidev"
|
||||
#define DEV_NUMBER 1
|
||||
#define REG_ADDR_LIMIT 0xFFFF
|
||||
|
||||
static ssize_t rmidev_sysfs_data_show(struct file *data_file,
|
||||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count);
|
||||
|
||||
static ssize_t rmidev_sysfs_data_store(struct file *data_file,
|
||||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count);
|
||||
|
||||
static ssize_t rmidev_sysfs_open_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static ssize_t rmidev_sysfs_release_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static ssize_t rmidev_sysfs_address_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static ssize_t rmidev_sysfs_length_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
|
||||
struct rmidev_handle {
|
||||
dev_t dev_no;
|
||||
unsigned short address;
|
||||
unsigned int length;
|
||||
struct device dev;
|
||||
struct synaptics_rmi4_data *rmi4_data;
|
||||
struct synaptics_rmi4_exp_fn_ptr *fn_ptr;
|
||||
struct kobject *sysfs_dir;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct rmidev_data {
|
||||
int ref_count;
|
||||
struct cdev main_dev;
|
||||
struct class *device_class;
|
||||
struct mutex file_mutex;
|
||||
struct rmidev_handle *rmi_dev;
|
||||
struct temp_buffer data_buf;
|
||||
};
|
||||
|
||||
static struct bin_attribute attr_data = {
|
||||
.attr = {
|
||||
.name = "data",
|
||||
.mode = (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
},
|
||||
.size = 0,
|
||||
.read = rmidev_sysfs_data_show,
|
||||
.write = rmidev_sysfs_data_store,
|
||||
};
|
||||
|
||||
static struct device_attribute attrs[] = {
|
||||
__ATTR(open, S_IWUSR | S_IWGRP,
|
||||
NULL,
|
||||
rmidev_sysfs_open_store),
|
||||
__ATTR(release, S_IWUSR | S_IWGRP,
|
||||
NULL,
|
||||
rmidev_sysfs_release_store),
|
||||
__ATTR(address, S_IWUSR | S_IWGRP,
|
||||
NULL,
|
||||
rmidev_sysfs_address_store),
|
||||
__ATTR(length, S_IWUSR | S_IWGRP,
|
||||
NULL,
|
||||
rmidev_sysfs_length_store),
|
||||
__ATTR(attn_state, S_IRUSR | S_IRGRP,
|
||||
rmidev_sysfs_attn_state_show,
|
||||
NULL),
|
||||
};
|
||||
|
||||
static int rmidev_major_num;
|
||||
|
||||
static struct class *rmidev_device_class;
|
||||
|
||||
static struct rmidev_handle *rmidev;
|
||||
|
||||
static struct completion remove_complete;
|
||||
|
||||
static ssize_t rmidev_sysfs_data_show(struct file *data_file,
|
||||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
int retval;
|
||||
unsigned int data_length = rmidev->length;
|
||||
|
||||
if (data_length > (REG_ADDR_LIMIT - rmidev->address))
|
||||
data_length = REG_ADDR_LIMIT - rmidev->address;
|
||||
|
||||
if (count < data_length) {
|
||||
dev_err(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Not enough space (%zu bytes) in buffer\n",
|
||||
__func__, count);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data_length) {
|
||||
retval = rmidev->fn_ptr->read(rmidev->rmi4_data,
|
||||
rmidev->address,
|
||||
(unsigned char *)buf,
|
||||
data_length);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to read data\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return data_length;
|
||||
}
|
||||
|
||||
static ssize_t rmidev_sysfs_data_store(struct file *data_file,
|
||||
struct kobject *kobj, struct bin_attribute *attributes,
|
||||
char *buf, loff_t pos, size_t count)
|
||||
{
|
||||
int retval;
|
||||
unsigned int data_length = rmidev->length;
|
||||
|
||||
if (data_length > (REG_ADDR_LIMIT - rmidev->address))
|
||||
data_length = REG_ADDR_LIMIT - rmidev->address;
|
||||
|
||||
if (data_length) {
|
||||
retval = rmidev->fn_ptr->write(rmidev->rmi4_data,
|
||||
rmidev->address,
|
||||
(unsigned char *)buf,
|
||||
data_length);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to write data\n",
|
||||
__func__);
|
||||
return retval;
|
||||
}
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rmidev_sysfs_open_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
unsigned int input;
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input != 1)
|
||||
return -EINVAL;
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, false);
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Attention interrupt disabled\n",
|
||||
__func__);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rmidev_sysfs_release_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
unsigned int input;
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input != 1)
|
||||
return -EINVAL;
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, true);
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Attention interrupt enabled\n",
|
||||
__func__);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rmidev_sysfs_address_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
unsigned int input;
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input > REG_ADDR_LIMIT)
|
||||
return -EINVAL;
|
||||
|
||||
rmidev->address = (unsigned short)input;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rmidev_sysfs_length_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
unsigned int input;
|
||||
|
||||
if (sscanf(buf, "%u", &input) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (input > REG_ADDR_LIMIT)
|
||||
return -EINVAL;
|
||||
|
||||
rmidev->length = input;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t rmidev_sysfs_attn_state_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int attn_state;
|
||||
const struct synaptics_dsx_platform_data *platform_data =
|
||||
rmidev->rmi4_data->board;
|
||||
|
||||
attn_state = gpio_get_value(platform_data->irq_gpio);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", attn_state);
|
||||
}
|
||||
|
||||
/*
|
||||
* rmidev_llseek - used to set up register address
|
||||
*
|
||||
* @filp: file structure for seek
|
||||
* @off: offset
|
||||
* if whence == SEEK_SET,
|
||||
* high 16 bits: page address
|
||||
* low 16 bits: register address
|
||||
* if whence == SEEK_CUR,
|
||||
* offset from current position
|
||||
* if whence == SEEK_END,
|
||||
* offset from end position (0xFFFF)
|
||||
* @whence: SEEK_SET, SEEK_CUR, or SEEK_END
|
||||
*/
|
||||
static loff_t rmidev_llseek(struct file *filp, loff_t off, int whence)
|
||||
{
|
||||
loff_t newpos;
|
||||
struct rmidev_data *dev_data = filp->private_data;
|
||||
|
||||
if (IS_ERR(dev_data)) {
|
||||
pr_err("%s: Pointer of char device data is invalid", __func__);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
newpos = off;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
newpos = filp->f_pos + off;
|
||||
break;
|
||||
case SEEK_END:
|
||||
newpos = REG_ADDR_LIMIT + off;
|
||||
break;
|
||||
default:
|
||||
newpos = -EINVAL;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if (newpos < 0 || newpos > REG_ADDR_LIMIT) {
|
||||
dev_err(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: New position 0x%04x is invalid\n",
|
||||
__func__, (unsigned int)newpos);
|
||||
newpos = -EINVAL;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
filp->f_pos = newpos;
|
||||
|
||||
clean_up:
|
||||
mutex_unlock(&(dev_data->file_mutex));
|
||||
|
||||
return newpos;
|
||||
}
|
||||
|
||||
/*
|
||||
* rmidev_read: - use to read data from rmi device
|
||||
*
|
||||
* @filp: file structure for read
|
||||
* @buf: user space buffer pointer
|
||||
* @count: number of bytes to read
|
||||
* @f_pos: offset (starting register address)
|
||||
*/
|
||||
static ssize_t rmidev_read(struct file *filp, char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
ssize_t retval;
|
||||
struct rmidev_data *dev_data = filp->private_data;
|
||||
struct temp_buffer *tb;
|
||||
|
||||
if (IS_ERR(dev_data)) {
|
||||
pr_err("%s: Pointer of char device data is invalid", __func__);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
|
||||
if (count > (REG_ADDR_LIMIT - *f_pos))
|
||||
count = REG_ADDR_LIMIT - *f_pos;
|
||||
|
||||
if (count == 0) {
|
||||
retval = 0;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if (*f_pos > REG_ADDR_LIMIT) {
|
||||
retval = -EFAULT;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
tb = &dev_data->data_buf;
|
||||
|
||||
if (tb->buf_size < count && alloc_buffer(tb, count) != 0) {
|
||||
retval = -ENOMEM;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
retval = rmidev->fn_ptr->read(rmidev->rmi4_data,
|
||||
*f_pos,
|
||||
tb->buf,
|
||||
count);
|
||||
if (retval < 0)
|
||||
goto clean_up;
|
||||
|
||||
if (copy_to_user(buf, tb->buf, count))
|
||||
retval = -EFAULT;
|
||||
else
|
||||
*f_pos += retval;
|
||||
|
||||
clean_up:
|
||||
mutex_unlock(&(dev_data->file_mutex));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* rmidev_write: - used to write data to rmi device
|
||||
*
|
||||
* @filep: file structure for write
|
||||
* @buf: user space buffer pointer
|
||||
* @count: number of bytes to write
|
||||
* @f_pos: offset (starting register address)
|
||||
*/
|
||||
static ssize_t rmidev_write(struct file *filp, const char __user *buf,
|
||||
size_t count, loff_t *f_pos)
|
||||
{
|
||||
ssize_t retval;
|
||||
struct rmidev_data *dev_data = filp->private_data;
|
||||
struct temp_buffer *tb;
|
||||
|
||||
if (IS_ERR(dev_data)) {
|
||||
pr_err("%s: Pointer of char device data is invalid", __func__);
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
if (*f_pos > REG_ADDR_LIMIT) {
|
||||
retval = -EFAULT;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if (count > (REG_ADDR_LIMIT - *f_pos))
|
||||
count = REG_ADDR_LIMIT - *f_pos;
|
||||
|
||||
if (count == 0) {
|
||||
retval = 0;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
tb = &dev_data->data_buf;
|
||||
|
||||
if (tb->buf_size < count && alloc_buffer(tb, count) != 0) {
|
||||
retval = -ENOMEM;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
if (copy_from_user(tb->buf, buf, count)) {
|
||||
retval = -EFAULT;
|
||||
goto clean_up;
|
||||
}
|
||||
|
||||
retval = rmidev->fn_ptr->write(rmidev->rmi4_data,
|
||||
*f_pos,
|
||||
tb->buf,
|
||||
count);
|
||||
if (retval >= 0)
|
||||
*f_pos += retval;
|
||||
|
||||
clean_up:
|
||||
mutex_unlock(&(dev_data->file_mutex));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* rmidev_open: enable access to rmi device
|
||||
* @inp: inode struture
|
||||
* @filp: file structure
|
||||
*/
|
||||
static int rmidev_open(struct inode *inp, struct file *filp)
|
||||
{
|
||||
int retval = 0;
|
||||
struct rmidev_data *dev_data =
|
||||
container_of(inp->i_cdev, struct rmidev_data, main_dev);
|
||||
|
||||
if (!dev_data)
|
||||
return -EACCES;
|
||||
|
||||
filp->private_data = dev_data;
|
||||
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, false);
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Attention interrupt disabled\n",
|
||||
__func__);
|
||||
|
||||
if (dev_data->ref_count < 1)
|
||||
dev_data->ref_count++;
|
||||
else
|
||||
retval = -EACCES;
|
||||
|
||||
mutex_unlock(&(dev_data->file_mutex));
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* rmidev_release: - release access to rmi device
|
||||
* @inp: inode structure
|
||||
* @filp: file structure
|
||||
*/
|
||||
static int rmidev_release(struct inode *inp, struct file *filp)
|
||||
{
|
||||
struct rmidev_data *dev_data =
|
||||
container_of(inp->i_cdev, struct rmidev_data, main_dev);
|
||||
|
||||
if (!dev_data)
|
||||
return -EACCES;
|
||||
|
||||
mutex_lock(&(dev_data->file_mutex));
|
||||
|
||||
dev_data->ref_count--;
|
||||
if (dev_data->ref_count < 0)
|
||||
dev_data->ref_count = 0;
|
||||
|
||||
rmidev->fn_ptr->enable(rmidev->rmi4_data, true);
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: Attention interrupt enabled\n",
|
||||
__func__);
|
||||
|
||||
mutex_unlock(&(dev_data->file_mutex));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations rmidev_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = rmidev_llseek,
|
||||
.read = rmidev_read,
|
||||
.write = rmidev_write,
|
||||
.open = rmidev_open,
|
||||
.release = rmidev_release,
|
||||
};
|
||||
|
||||
static void rmidev_device_cleanup(struct rmidev_data *dev_data)
|
||||
{
|
||||
dev_t devno;
|
||||
|
||||
if (dev_data) {
|
||||
devno = dev_data->main_dev.dev;
|
||||
|
||||
if (dev_data->device_class)
|
||||
device_destroy(dev_data->device_class, devno);
|
||||
|
||||
cdev_del(&dev_data->main_dev);
|
||||
|
||||
unregister_chrdev_region(devno, 1);
|
||||
|
||||
dev_dbg(&rmidev->rmi4_data->i2c_client->dev,
|
||||
"%s: rmidev device removed\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static char *rmi_char_devnode(struct device *dev, umode_t *mode)
|
||||
{
|
||||
if (!mode)
|
||||
return NULL;
|
||||
|
||||
*mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
|
||||
|
||||
return kasprintf(GFP_KERNEL, "rmi/%s", dev_name(dev));
|
||||
}
|
||||
|
||||
static int rmidev_create_device_class(void)
|
||||
{
|
||||
rmidev_device_class = class_create(THIS_MODULE, DEVICE_CLASS_NAME);
|
||||
|
||||
if (IS_ERR(rmidev_device_class)) {
|
||||
pr_err("%s: Failed to create /dev/%s\n",
|
||||
__func__, CHAR_DEVICE_NAME);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rmidev_device_class->devnode = rmi_char_devnode;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmidev_init_device(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
dev_t dev_no;
|
||||
unsigned char attr_count;
|
||||
struct rmidev_data *dev_data;
|
||||
struct device *device_ptr;
|
||||
|
||||
rmidev = kzalloc(sizeof(*rmidev), GFP_KERNEL);
|
||||
if (!rmidev) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to alloc mem for rmidev\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_rmidev;
|
||||
}
|
||||
|
||||
rmidev->fn_ptr = kzalloc(sizeof(*(rmidev->fn_ptr)), GFP_KERNEL);
|
||||
if (!rmidev) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to alloc mem for fn_ptr\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_fn_ptr;
|
||||
}
|
||||
|
||||
rmidev->fn_ptr->read = rmi4_data->i2c_read;
|
||||
rmidev->fn_ptr->write = rmi4_data->i2c_write;
|
||||
rmidev->fn_ptr->enable = rmi4_data->irq_enable;
|
||||
rmidev->rmi4_data = rmi4_data;
|
||||
|
||||
retval = rmidev_create_device_class();
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create device class\n",
|
||||
__func__);
|
||||
goto err_device_class;
|
||||
}
|
||||
|
||||
if (rmidev_major_num) {
|
||||
dev_no = MKDEV(rmidev_major_num, DEV_NUMBER);
|
||||
retval = register_chrdev_region(dev_no, 1, CHAR_DEVICE_NAME);
|
||||
} else {
|
||||
retval = alloc_chrdev_region(&dev_no, 0, 1, CHAR_DEVICE_NAME);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to allocate char device region\n",
|
||||
__func__);
|
||||
goto err_device_region;
|
||||
}
|
||||
|
||||
rmidev_major_num = MAJOR(dev_no);
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Major number of rmidev = %d\n",
|
||||
__func__, rmidev_major_num);
|
||||
}
|
||||
|
||||
dev_data = kzalloc(sizeof(*dev_data), GFP_KERNEL);
|
||||
if (!dev_data) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to alloc mem for dev_data\n",
|
||||
__func__);
|
||||
retval = -ENOMEM;
|
||||
goto err_dev_data;
|
||||
}
|
||||
|
||||
mutex_init(&dev_data->file_mutex);
|
||||
dev_data->rmi_dev = rmidev;
|
||||
rmidev->data = dev_data;
|
||||
|
||||
cdev_init(&dev_data->main_dev, &rmidev_fops);
|
||||
|
||||
retval = cdev_add(&dev_data->main_dev, dev_no, 1);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to add rmi char device\n",
|
||||
__func__);
|
||||
goto err_char_device;
|
||||
}
|
||||
|
||||
dev_set_name(&rmidev->dev, "rmidev%d", MINOR(dev_no));
|
||||
dev_data->device_class = rmidev_device_class;
|
||||
|
||||
device_ptr = device_create(dev_data->device_class, NULL, dev_no,
|
||||
NULL, CHAR_DEVICE_NAME"%d", MINOR(dev_no));
|
||||
if (IS_ERR(device_ptr)) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create rmi char device\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
goto err_char_device;
|
||||
}
|
||||
|
||||
retval = gpio_export(rmi4_data->board->irq_gpio, false);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to export attention gpio\n",
|
||||
__func__);
|
||||
} else {
|
||||
retval = gpio_export_link(&(rmi4_data->i2c_client->dev),
|
||||
"attn", rmi4_data->board->irq_gpio);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s Failed to create gpio symlink\n",
|
||||
__func__);
|
||||
} else {
|
||||
dev_dbg(&rmi4_data->i2c_client->dev,
|
||||
"%s: Exported attention gpio %d\n",
|
||||
__func__, rmi4_data->board->irq_gpio);
|
||||
}
|
||||
}
|
||||
|
||||
rmidev->sysfs_dir = kobject_create_and_add("rmidev",
|
||||
&rmi4_data->i2c_client->dev.kobj);
|
||||
if (!rmidev->sysfs_dir) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs directory\n",
|
||||
__func__);
|
||||
goto err_sysfs_dir;
|
||||
}
|
||||
|
||||
retval = sysfs_create_bin_file(rmidev->sysfs_dir,
|
||||
&attr_data);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs bin file\n",
|
||||
__func__);
|
||||
goto err_sysfs_bin;
|
||||
}
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) {
|
||||
retval = sysfs_create_file(rmidev->sysfs_dir,
|
||||
&attrs[attr_count].attr);
|
||||
if (retval < 0) {
|
||||
dev_err(&rmi4_data->i2c_client->dev,
|
||||
"%s: Failed to create sysfs attributes\n",
|
||||
__func__);
|
||||
retval = -ENODEV;
|
||||
goto err_sysfs_attrs;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_sysfs_attrs:
|
||||
for (attr_count--; attr_count >= 0; attr_count--)
|
||||
sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
|
||||
|
||||
sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
|
||||
|
||||
err_sysfs_bin:
|
||||
kobject_put(rmidev->sysfs_dir);
|
||||
|
||||
err_sysfs_dir:
|
||||
err_char_device:
|
||||
rmidev_device_cleanup(dev_data);
|
||||
kfree(dev_data);
|
||||
|
||||
err_dev_data:
|
||||
unregister_chrdev_region(dev_no, 1);
|
||||
|
||||
err_device_region:
|
||||
class_destroy(rmidev_device_class);
|
||||
|
||||
err_device_class:
|
||||
kfree(rmidev->fn_ptr);
|
||||
|
||||
err_fn_ptr:
|
||||
kfree(rmidev);
|
||||
|
||||
err_rmidev:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rmidev_remove_device(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
unsigned char attr_count;
|
||||
struct rmidev_data *dev_data;
|
||||
|
||||
if (!rmidev)
|
||||
return;
|
||||
|
||||
for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++)
|
||||
sysfs_remove_file(rmidev->sysfs_dir, &attrs[attr_count].attr);
|
||||
|
||||
sysfs_remove_bin_file(rmidev->sysfs_dir, &attr_data);
|
||||
|
||||
kobject_put(rmidev->sysfs_dir);
|
||||
|
||||
dev_data = rmidev->data;
|
||||
if (dev_data) {
|
||||
rmidev_device_cleanup(dev_data);
|
||||
kfree(dev_data);
|
||||
}
|
||||
|
||||
unregister_chrdev_region(rmidev->dev_no, 1);
|
||||
|
||||
class_destroy(rmidev_device_class);
|
||||
|
||||
kfree(rmidev->fn_ptr);
|
||||
kfree(rmidev);
|
||||
|
||||
complete(&remove_complete);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int __init rmidev_module_init(void)
|
||||
{
|
||||
synaptics_rmi4_new_function(RMI_DEV, true,
|
||||
rmidev_init_device,
|
||||
rmidev_remove_device,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rmidev_module_exit(void)
|
||||
{
|
||||
init_completion(&remove_complete);
|
||||
synaptics_rmi4_new_function(RMI_DEV, false,
|
||||
rmidev_init_device,
|
||||
rmidev_remove_device,
|
||||
NULL, NULL, IC_MODE_ANY);
|
||||
wait_for_completion(&remove_complete);
|
||||
return;
|
||||
}
|
||||
|
||||
module_init(rmidev_module_init);
|
||||
module_exit(rmidev_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Synaptics, Inc.");
|
||||
MODULE_DESCRIPTION("Synaptics DSX RMI Dev Module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_VERSION(SYNAPTICS_DSX_DRIVER_VERSION);
|
||||
File diff suppressed because it is too large
Load diff
78
include/linux/input/synaptics_dsx_mmi.h
Normal file
78
include/linux/input/synaptics_dsx_mmi.h
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Synaptics DSX touchscreen driver
|
||||
*
|
||||
* Copyright (C) 2012 Synaptics Incorporated
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SYNAPTICS_DSX_H_
|
||||
#define _SYNAPTICS_DSX_H_
|
||||
|
||||
/*
|
||||
* struct synaptics_dsx_cap_button_map - 0d button map
|
||||
* @nbuttons: number of 0d buttons
|
||||
* @map: pointer to array of button types
|
||||
*/
|
||||
struct synaptics_dsx_cap_button_map {
|
||||
unsigned char nbuttons;
|
||||
unsigned char *map;
|
||||
};
|
||||
|
||||
/*
|
||||
* struct synaptics_dsx_platform_data - dsx platform data
|
||||
* @x_flip: x flip flag
|
||||
* @y_flip: y flip flag
|
||||
* @i2c_pull_up: pull up i2c bus with regulator
|
||||
* @power_down_enable: enable complete regulator shutdown in suspend
|
||||
* @irq_gpio: attention interrupt gpio
|
||||
* @irq_flags: flags used by the irq
|
||||
* @reset_flags: flags used by reset line
|
||||
* @reset_gpio: reset gpio
|
||||
* @disp_maxx: display panel maximum values on the x
|
||||
* @disp_maxy: display panel maximum values on the y
|
||||
* @disp_minx: display panel minimum values on the x
|
||||
* @disp_miny: display panel minimum values on the y
|
||||
* @panel_maxx: touch panel maximum values on the x
|
||||
* @panel_maxy: touch panel maximum values on the y
|
||||
* @panel_minx: touch panel minimum values on the x
|
||||
* @panel_miny: touch panel minimum values on the y
|
||||
* @reset_delay: reset delay
|
||||
* @gpio_config: pointer to gpio configuration function
|
||||
* @cap_button_map: pointer to 0d button map
|
||||
*/
|
||||
struct synaptics_dsx_platform_data {
|
||||
bool x_flip;
|
||||
bool y_flip;
|
||||
bool i2c_pull_up;
|
||||
bool power_down_enable;
|
||||
bool disable_gpios;
|
||||
bool do_lockdown;
|
||||
bool regulator_en;
|
||||
unsigned irq_gpio;
|
||||
unsigned long irq_flags;
|
||||
unsigned reset_gpio;
|
||||
unsigned panel_minx;
|
||||
unsigned panel_miny;
|
||||
unsigned panel_maxx;
|
||||
unsigned panel_maxy;
|
||||
unsigned disp_minx;
|
||||
unsigned disp_miny;
|
||||
unsigned reset_delay;
|
||||
int (*gpio_config)(struct synaptics_dsx_platform_data *pdata,
|
||||
bool configure);
|
||||
struct synaptics_dsx_cap_button_map *cap_button_map;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in a new issue