Ocean: DLKM: Bringup ili9881h touch driver

Bringup ili9881h touch driver for ocean

Change-Id: I4371a5db7ce5a95baeb67dc6f23346fbd05695cc
Signed-off-by: wengjun1 <wengjun1@motorola.com>
Reviewed-on: https://gerrit.mot.com/1213203
SME-Granted: SME Approvals Granted
SLTApproved: Slta Waiver
Tested-by: Jira Key
Reviewed-by: Huosheng Liao <liaohs@motorola.com>
Submit-Approved: Jira Key
This commit is contained in:
wengjun1 2018-07-20 14:35:21 +08:00 • committed by Jun Weng
commit b09895661b
29 changed files with 19619 additions and 0 deletions

View file

@ -0,0 +1,8 @@
DLKM_DIR := motorola/kernel/modules
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ilitek_mmi.ko
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
include $(DLKM_DIR)/AndroidKernelModule.mk

View file

@ -0,0 +1,20 @@
# 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/ilitek_mmi
ifeq ($(filter m y, $(CONFIG_TOUCHSCREEN_ILITEK_CHIPSET)),)
obj-m += ilitek_mmi.o
endif
ilitek_mmi-objs += platform.o userspace.o
ilitek_mmi-objs += core/config.o \
core/finger_report.o \
core/firmware.o \
core/flash.o \
core/i2c.o \
core/spi.o \
core/mp_test.o \
core/protocol.o \
core/parser.o \
core/gesture.o

View 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

View file

@ -0,0 +1,259 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __COMMON_H
#define __COMMON_H
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/kobject.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/version.h>
#include <linux/regulator/consumer.h>
#include <linux/power_supply.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/netlink.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <net/sock.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/time.h>
#include <linux/namei.h>
#include <linux/vmalloc.h>
#include <linux/timer.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h>
#ifdef CONFIG_OF
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#endif
#ifdef CONFIG_FB
#include <linux/notifier.h>
#include <linux/fb.h>
#else
#include <linux/earlysuspend.h>
#endif
/*
* Relative Driver with Touch IC
*/
/* An Touch IC currently supported by driver */
#define CHIP_TYPE_ILI7807 0x7807
#define CHIP_TYPE_ILI9881 0x9881
#define CHIP_ID_ERR (-100)
/* A interface currently supported by driver */
#define I2C_INTERFACE 1
#define SPI_INTERFACE 2
#define INTERFACE I2C_INTERFACE
/* Driver version */
#define DRIVER_VERSION "1.0.3.5"
/* Driver core type */
#define CORE_TYPE_B 0x00
#define CORE_TYPE_E 0x03
/* Protocol version */
#define PROTOCOL_MAJOR 0x5
#define PROTOCOL_MID 0x4
#define PROTOCOL_MINOR 0x0
/* Debug messages */
#ifdef BIT
#undef BIT
#endif
#define BIT(x) (1 << (x))
enum {
DEBUG_NONE = 0,
DEBUG_IRQ = BIT(0),
DEBUG_FINGER_REPORT = BIT(1),
DEBUG_FIRMWARE = BIT(2),
DEBUG_CONFIG = BIT(3),
DEBUG_I2C = BIT(4),
DEBUG_BATTERY = BIT(5),
DEBUG_MP_TEST = BIT(6),
DEBUG_IOCTL = BIT(7),
DEBUG_NETLINK = BIT(8),
DEBUG_PARSER = BIT(9),
DEBUG_GESTURE = BIT(10),
DEBUG_ALL = ~0,
};
#define ipio_info(fmt, arg...) \
pr_info("ILITEK: (%s, %d): " fmt, __func__, __LINE__, ##arg)
#define ipio_err(fmt, arg...) \
pr_err("ILITEK: (%s, %d): " fmt, __func__, __LINE__, ##arg)
#define ipio_debug(level, fmt, arg...) \
do { \
if (level & ipio_debug_level) \
pr_info("ILITEK: (%s, %d): " fmt, __func__, \
__LINE__, ##arg); \
} while (0)
/* Distributed to all core functions */
extern uint32_t ipio_debug_level;
extern uint32_t ipio_chip_list[2];
/* Macros */
#define CHECK_EQUAL(X, Y) ((X == Y) ? 0 : -1)
#define ERR_ALLOC_MEM(X) ((IS_ERR(X) || X == NULL) ? 1 : 0)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define USEC 1
#define MSEC (USEC * 1000)
/* The size of firmware upgrade */
#define MAX_HEX_FILE_SIZE (160*1024)
#define MAX_FLASH_FIRMWARE_SIZE (256*1024)
#define MAX_IRAM_FIRMWARE_SIZE (60*1024)
#define ILI_FILE_HEADER 64
#define MAX_AP_FIRMWARE_SIZE (64*1024)
#define MAX_DLM_FIRMWARE_SIZE (8*1024)
#define MAX_MP_FIRMWARE_SIZE (64*1024)
#define MAX_GESTURE_FIRMWARE_SIZE (8*1024)
#define DLM_START_ADDRESS 0x20610
#define DLM_HEX_ADDRESS 0x10000
#define MP_HEX_ADDRESS 0x13000
#define SPI_UPGRADE_LEN 2048
#define UPDATE_RETRY_COUNT 3
/* ILI7807 Series */
enum ili7881_types {
ILI7807_TYPE_F_AA = 0x0000,
ILI7807_TYPE_F_AB = 0x0001,
ILI7807_TYPE_H = 0x1100
};
#define ILI7807_SLAVE_ADDR 0x41
#define ILI7807_ICE_MODE_ADDR 0x181062
#define ILI7807_PID_ADDR 0x4009C
#define ILI7808_WDT_ADDR 0x5100C
/* ILI9881 Series */
enum ili9881_types {
ILI9881_TYPE_F = 0x0F,
ILI9881_TYPE_H = 0x11
};
/*Error code*/
#define SUCCESS 0
#define ERROR (-1)
#define UPDATE_FAIL (-1)
#define CHECK_RECOVER -2
#define ILI9881_SLAVE_ADDR 0x41
#define ILI9881_ICE_MODE_ADDR 0x181062
#define ILI9881_PID_ADDR 0x4009C
#define ILI9881_WDT_ADDR 0x5100C
/*
* Other settings
*/
#define CSV_PATH "/sdcard"
#define INI_NAME_PATH "/sdcard/mp.ini"
#define UPDATE_FW_PATH "/mnt/sdcard/ILITEK_FW"
#define ILITEK_FW_FILENAME "ILITEK_FW.bin"
#define POWER_STATUS_PATH "/sys/class/power_supply/battery/status"
#define CHECK_BATTERY_TIME 2000
#define VDD_VOLTAGE 1800000
#define VDD_I2C_VOLTAGE 1800000
/* It's only for spi interface used to download data to iram */
#if (INTERFACE == SPI_INTERFACE)
#define HOST_DOWNLOAD
#endif
/* Linux multiple touch protocol, either B type or A type. */
//#define MT_B_TYPE
/* Enable the support of regulator power. */
/* #define REGULATOR_POWER_ON */
/* Either an interrupt event handled by kthread or work queue. */
#define USE_KTHREAD
/* Enable DMA with I2C. */
/* #define I2C_DMA */
/* Split the length written to or read from IC via I2C. */
/* #define I2C_SEGMENT */
/* Be able to upgrade fw at boot stage */
/* #define BOOT_FW_UPGRADE */
/* Check battery's status in order to avoid some effects from charge. */
/* #define BATTERY_CHECK */
/*suspend TP power off*/
#define SUSPEND_TP_POWER_OFF
static inline void ipio_kfree(void **mem)
{
if (*mem != NULL) {
kfree(*mem);
*mem = NULL;
}
}
extern int katoi(char *string);
extern int str2hex(char *str);
#endif /* __COMMON_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,134 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __CONFIG_H
#define __CONFIG_H
typedef struct {
int nId;
int nX;
int nY;
int nStatus;
int nFlag;
} VIRTUAL_KEYS;
typedef struct {
uint16_t nMaxX;
uint16_t nMaxY;
uint16_t nMinX;
uint16_t nMinY;
uint8_t nMaxTouchNum;
uint8_t nMaxKeyButtonNum;
uint8_t nXChannelNum;
uint8_t nYChannelNum;
uint8_t nHandleKeyFlag;
uint8_t nKeyCount;
uint16_t nKeyAreaXLength;
uint16_t nKeyAreaYLength;
VIRTUAL_KEYS virtual_key[10];
/* added for protocol v5 */
uint8_t self_tx_channel_num;
uint8_t self_rx_channel_num;
uint8_t side_touch_type;
} TP_INFO;
struct core_config_data {
uint32_t chip_id;
uint32_t chip_type;
uint32_t chip_pid;
uint8_t core_type;
uint32_t slave_i2c_addr;
uint32_t ice_mode_addr;
uint32_t pid_addr;
uint32_t wdt_addr;
uint32_t ic_reset_addr;
uint8_t protocol_ver[4];
uint8_t firmware_ver[9];
uint8_t core_ver[5];
bool do_ic_reset;
bool isEnableGesture;
bool icemodeenable;
bool spi_pro_9881h11;
TP_INFO *tp_info;
};
extern struct core_config_data *core_config;
extern int fw_cmd_len;
extern int protocol_cmd_len;
extern int tp_info_len;
extern int key_info_len;
extern int core_cmd_len;
/* R/W with Touch ICs */
extern uint32_t core_config_ice_mode_read(uint32_t addr);
extern int core_config_ice_mode_write(uint32_t addr, uint32_t data, uint32_t size);
extern uint32_t core_config_read_write_onebyte(uint32_t addr);
extern int core_config_ice_mode_disable(void);
extern int core_config_ice_mode_enable(void);
/* Touch IC status */
extern int core_config_set_watch_dog(bool enable);
extern int core_config_check_cdc_busy(int count, int delay);
extern int core_config_check_int_status(bool high);
extern void core_config_ic_suspend(void);
extern void core_config_ic_resume(void);
extern void core_config_ic_reset(void);
/* control features of Touch IC */
extern void core_config_sense_ctrl(bool start);
extern void core_config_sleep_ctrl(bool out);
extern void core_config_glove_ctrl(bool enable, bool seamless);
extern void core_config_stylus_ctrl(bool enable, bool seamless);
extern void core_config_tp_scan_mode(bool mode);
extern void core_config_lpwg_ctrl(bool enable);
extern void core_config_gesture_ctrl(uint8_t func);
extern void core_config_phone_cover_ctrl(bool enable);
extern void core_config_finger_sense_ctrl(bool enable);
extern void core_config_proximity_ctrl(bool enable);
extern void core_config_plug_ctrl(bool out);
extern void core_config_set_phone_cover(uint8_t *pattern);
/* Touch IC information */
extern int core_config_get_core_ver(void);
extern int core_config_get_key_info(void);
extern int core_config_get_tp_info(void);
extern int core_config_get_protocol_ver(void);
extern int core_config_get_fw_ver(void);
extern int core_config_get_chip_id(void);
extern int core_config_init(void);
extern void core_config_remove(void);
#endif /* __CONFIG_H */

View file

@ -0,0 +1,822 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/i2c.h>
#include <linux/list.h>
#include "../common.h"
#include "../platform.h"
#include "config.h"
#include "i2c.h"
#include "finger_report.h"
#include "gesture.h"
#include "mp_test.h"
#include "protocol.h"
/* An id with position in each fingers */
struct mutual_touch_point {
uint16_t id;
uint16_t x;
uint16_t y;
uint16_t pressure;
};
/* Keys and code with each fingers */
struct mutual_touch_info {
uint8_t touch_num;
uint8_t key_code;
struct mutual_touch_point mtp[10];
};
/* Store the packet of finger report */
struct fr_data_node {
uint8_t *data;
uint16_t len;
};
/* record the status of touch being pressed or released currently and previosuly */
uint8_t g_current_touch[10];
uint8_t g_previous_touch[10];
/* the total length of finger report packet */
uint16_t g_total_len;
struct mutual_touch_info g_mutual_data;
struct fr_data_node *g_fr_node = NULL, *g_fr_uart = NULL;
struct core_fr_data *core_fr;
/**
* Calculate the check sum of each packet reported by firmware
*
* @pMsg: packet come from firmware
* @nLength : the length of its packet
*/
uint8_t core_fr_calc_checksum(uint8_t *pMsg, uint32_t nLength)
{
int i;
int32_t nCheckSum = 0;
for (i = 0 ; i < nLength; i++) {
nCheckSum += pMsg[i];
}
return (uint8_t) ((-nCheckSum) & 0xFF);
}
EXPORT_SYMBOL(core_fr_calc_checksum);
/**
* Receive data when fw mode stays at i2cuart mode.
*
* the first is to receive N bytes depending on the mode that firmware stays
* before going in this function, and it would check with i2c buffer if it
* remains the rest of data.
*/
static void i2cuart_recv_packet(void)
{
int res = 0, need_read_len = 0, one_data_bytes = 0;
int type = g_fr_node->data[3] & 0x0F;
int actual_len = g_fr_node->len - 5;
ipio_debug(DEBUG_FINGER_REPORT, "pid = %x, data[3] = %x, type = %x, actual_len = %d\n",
g_fr_node->data[0], g_fr_node->data[3], type, actual_len);
need_read_len = g_fr_node->data[1] * g_fr_node->data[2];
if (type == 0 || type == 1 || type == 6) {
one_data_bytes = 1;
} else if (type == 2 || type == 3) {
one_data_bytes = 2;
} else if (type == 4 || type == 5) {
one_data_bytes = 4;
}
ipio_debug(DEBUG_FINGER_REPORT, "need_read_len = %d one_data_bytes = %d\n", need_read_len, one_data_bytes);
need_read_len = need_read_len * one_data_bytes + 1;
if (need_read_len > actual_len) {
g_fr_uart = kmalloc(sizeof(*g_fr_uart), GFP_ATOMIC);
if (ERR_ALLOC_MEM(g_fr_uart)) {
ipio_err("Failed to allocate g_fr_uart memory %ld\n", PTR_ERR(g_fr_uart));
return;
}
g_fr_uart->len = need_read_len - actual_len;
g_fr_uart->data = kzalloc(g_fr_uart->len, GFP_ATOMIC);
if (ERR_ALLOC_MEM(g_fr_uart->data)) {
ipio_err("Failed to allocate g_fr_uart memory %ld\n", PTR_ERR(g_fr_uart->data));
return;
}
g_total_len += g_fr_uart->len;
res = core_read(core_config->slave_i2c_addr, g_fr_uart->data, g_fr_uart->len);
if (res < 0)
ipio_err("Failed to read finger report packet\n");
}
}
/*
* It'd be called when a finger's touching down a screen. It'll notify the event
* to the uplayer from input device.
*
* @x: the axis of X
* @y: the axis of Y
* @pressure: the value of pressue on a screen
* @id: an id represents a finger pressing on a screen
*/
void core_fr_touch_press(int32_t x, int32_t y, uint32_t pressure, int32_t id)
{
ipio_debug(DEBUG_FINGER_REPORT, "DOWN: id = %d, x = %d, y = %d\n", id, x, y);
if (ipd->x_flip)
x = ipd->x_max - x;
if (ipd->y_flip)
y = ipd->y_max - y;
ipio_debug(DEBUG_FINGER_REPORT, "Flip:: DOWN: id = %d, x = %d, y = %d\n", id, x, y);
if (ipd->MT_B_TYPE) {
input_mt_slot(core_fr->input_device, id);
input_mt_report_slot_state(core_fr->input_device, MT_TOOL_FINGER, true);
input_report_abs(core_fr->input_device, ABS_MT_POSITION_X, x);
input_report_abs(core_fr->input_device, ABS_MT_POSITION_Y, y);
if (core_fr->isEnablePressure)
input_report_abs(core_fr->input_device, ABS_MT_PRESSURE, pressure);
} else{
input_report_key(core_fr->input_device, BTN_TOUCH, 1);
input_report_abs(core_fr->input_device, ABS_MT_TRACKING_ID, id);
input_report_abs(core_fr->input_device, ABS_MT_TOUCH_MAJOR, 1);
input_report_abs(core_fr->input_device, ABS_MT_WIDTH_MAJOR, 1);
input_report_abs(core_fr->input_device, ABS_MT_POSITION_X, x);
input_report_abs(core_fr->input_device, ABS_MT_POSITION_Y, y);
if (core_fr->isEnablePressure)
input_report_abs(core_fr->input_device, ABS_MT_PRESSURE, pressure);
input_mt_sync(core_fr->input_device);
}
}
EXPORT_SYMBOL(core_fr_touch_press);
/*
* It'd be called when a finger's touched up from a screen. It'll notify
* the event to the uplayer from input device.
*
* @x: the axis of X
* @y: the axis of Y
* @id: an id represents a finger leaving from a screen.
*/
void core_fr_touch_release(int32_t x, int32_t y, int32_t id)
{
ipio_debug(DEBUG_FINGER_REPORT, "UP: id = %d, x = %d, y = %d\n", id, x, y);
if (ipd->MT_B_TYPE) {
input_mt_slot(core_fr->input_device, id);
input_mt_report_slot_state(core_fr->input_device, MT_TOOL_FINGER, false);
} else{
input_report_key(core_fr->input_device, BTN_TOUCH, 0);
input_mt_sync(core_fr->input_device);
}
}
EXPORT_SYMBOL(core_fr_touch_release);
static int parse_touch_package_v3_2(void)
{
ipio_info("Not implemented yet\n");
return 0;
}
static int finger_report_ver_3_2(void)
{
ipio_info("Not implemented yet\n");
parse_touch_package_v3_2();
return 0;
}
/*
* It mainly parses the packet assembled by protocol v5.0
*/
static int parse_touch_package_v5_0(uint8_t pid)
{
int i, res = 0;
uint8_t check_sum = 0;
uint32_t nX = 0, nY = 0;
for (i = 0 ; i < 9; i++)
ipio_debug(DEBUG_FINGER_REPORT, "data[%d] = %x\n", i, g_fr_node->data[i]);
check_sum = core_fr_calc_checksum(&g_fr_node->data[0], (g_fr_node->len - 1));
ipio_debug(DEBUG_FINGER_REPORT, "data = %x ; check_sum : %x\n", g_fr_node->data[g_fr_node->len - 1], check_sum);
if (g_fr_node->data[g_fr_node->len - 1] != check_sum) {
ipio_err("Wrong checksum\n");
res = ERROR;
goto out;
}
/* start to parsing the packet of finger report */
if (pid == protocol->demo_pid) {
ipio_debug(DEBUG_FINGER_REPORT, " **** Parsing DEMO packets : 0x%x ****\n", pid);
for (i = 0 ; i < ipd->MAX_TOUCH_NUM; i++) {
if ((g_fr_node->data[(4 * i) + 1] == 0xFF) && (g_fr_node->data[(4 * i) + 2] && 0xFF)
&& (g_fr_node->data[(4 * i) + 3] == 0xFF)) {
if (ipd->MT_B_TYPE)
g_current_touch[i] = 0;
continue;
}
nX = (((g_fr_node->data[(4 * i) + 1] & 0xF0) << 4) | (g_fr_node->data[(4 * i) + 2]));
nY = (((g_fr_node->data[(4 * i) + 1] & 0x0F) << 8) | (g_fr_node->data[(4 * i) + 3]));
if (!core_fr->isSetResolution) {
g_mutual_data.mtp[g_mutual_data.touch_num].x = nX * (ipd->x_max) / (ipd->TPD_WIDTH);
g_mutual_data.mtp[g_mutual_data.touch_num].y = nY * (ipd->y_max) / (ipd->TPD_HEIGHT);
g_mutual_data.mtp[g_mutual_data.touch_num].id = i;
} else {
g_mutual_data.mtp[g_mutual_data.touch_num].x = nX;
g_mutual_data.mtp[g_mutual_data.touch_num].y = nY;
g_mutual_data.mtp[g_mutual_data.touch_num].id = i;
}
if (core_fr->isEnablePressure)
g_mutual_data.mtp[g_mutual_data.touch_num].pressure = g_fr_node->data[(4 * i) + 4];
else
g_mutual_data.mtp[g_mutual_data.touch_num].pressure = 1;
ipio_debug(DEBUG_FINGER_REPORT, "[x,y]=[%d,%d]\n", nX, nY);
ipio_debug(DEBUG_FINGER_REPORT, "point[%d] : (%d,%d) = %d\n",
g_mutual_data.mtp[g_mutual_data.touch_num].id,
g_mutual_data.mtp[g_mutual_data.touch_num].x,
g_mutual_data.mtp[g_mutual_data.touch_num].y, g_mutual_data.mtp[g_mutual_data.touch_num].pressure);
g_mutual_data.touch_num++;
if (ipd->MT_B_TYPE)
g_current_touch[i] = 1;
}
} else if (pid == protocol->debug_pid) {
ipio_debug(DEBUG_FINGER_REPORT, " **** Parsing DEBUG packets : 0x%x ****\n", pid);
ipio_debug(DEBUG_FINGER_REPORT, "Length = %d\n", (g_fr_node->data[1] << 8 | g_fr_node->data[2]));
for (i = 0 ; i < ipd->MAX_TOUCH_NUM; i++) {
if ((g_fr_node->data[(3 * i) + 5] == 0xFF) && (g_fr_node->data[(3 * i) + 6] && 0xFF)
&& (g_fr_node->data[(3 * i) + 7] == 0xFF)) {
if (ipd->MT_B_TYPE)
g_current_touch[i] = 0;
continue;
}
nX = (((g_fr_node->data[(3 * i) + 5] & 0xF0) << 4) | (g_fr_node->data[(3 * i) + 6]));
nY = (((g_fr_node->data[(3 * i) + 5] & 0x0F) << 8) | (g_fr_node->data[(3 * i) + 7]));
if (!core_fr->isSetResolution) {
g_mutual_data.mtp[g_mutual_data.touch_num].x = nX * (ipd->x_max) / (ipd->TPD_WIDTH);
g_mutual_data.mtp[g_mutual_data.touch_num].y = nY * (ipd->y_max) / (ipd->TPD_HEIGHT);
g_mutual_data.mtp[g_mutual_data.touch_num].id = i;
} else {
g_mutual_data.mtp[g_mutual_data.touch_num].x = nX;
g_mutual_data.mtp[g_mutual_data.touch_num].y = nY;
g_mutual_data.mtp[g_mutual_data.touch_num].id = i;
}
if (core_fr->isEnablePressure)
g_mutual_data.mtp[g_mutual_data.touch_num].pressure = g_fr_node->data[(4 * i) + 4];
else
g_mutual_data.mtp[g_mutual_data.touch_num].pressure = 1;
ipio_debug(DEBUG_FINGER_REPORT, "[x,y]=[%d,%d]\n", nX, nY);
ipio_debug(DEBUG_FINGER_REPORT, "point[%d] : (%d,%d) = %d\n",
g_mutual_data.mtp[g_mutual_data.touch_num].id,
g_mutual_data.mtp[g_mutual_data.touch_num].x,
g_mutual_data.mtp[g_mutual_data.touch_num].y, g_mutual_data.mtp[g_mutual_data.touch_num].pressure);
g_mutual_data.touch_num++;
if (ipd->MT_B_TYPE)
g_current_touch[i] = 1;
}
} else {
if (pid != 0) {
/* ignore the pid with 0x0 after enable irq at once */
ipio_err(" **** Unknown PID : 0x%x ****\n", pid);
res = ERROR;
}
}
out:
return res;
}
/*
* The function is called by an interrupt and used to handle packet of finger
* touch from firmware. A differnece in the process of the data is acorrding to the protocol
*/
static int finger_report_ver_5_0(void)
{
int i, gesture, res = 0;
static int last_touch;
uint8_t pid = 0x0;
memset(&g_mutual_data, 0x0, sizeof(struct mutual_touch_info));
#ifdef I2C_SEGMENT
res = core_i2c_segmental_read(core_config->slave_i2c_addr, g_fr_node->data, g_fr_node->len);
#else
res = core_read(core_config->slave_i2c_addr, g_fr_node->data, g_fr_node->len);
#endif
if (res < 0) {
ipio_err("Failed to read finger report packet\n");
if (res == CHECK_RECOVER) {
ipio_err("==================Recover=================\n");
/*ilitek_platform_tp_hw_reset(true);*/
/* Soft reset */
core_config_ice_mode_enable();
core_config_set_watch_dog(false);
mdelay(10);
core_config_ic_reset();
}
goto out;
}
pid = g_fr_node->data[0];
ipio_debug(DEBUG_FINGER_REPORT, "PID = 0x%x\n", pid);
if (pid == 0)
goto out;
if (pid == protocol->i2cuart_pid) {
ipio_debug(DEBUG_FINGER_REPORT, "I2CUART(0x%x): prepare to receive rest of data\n", pid);
i2cuart_recv_packet();
goto out;
}
if (pid == protocol->ges_pid && core_config->isEnableGesture) {
ipio_debug(DEBUG_FINGER_REPORT, "pid = 0x%x, code = %x\n", pid, g_fr_node->data[1]);
gesture = core_gesture_match_key(g_fr_node->data[1]);
if (gesture != -1) {
input_report_key(core_fr->input_device, gesture, 1);
input_sync(core_fr->input_device);
input_report_key(core_fr->input_device, gesture, 0);
input_sync(core_fr->input_device);
}
goto out;
}
res = parse_touch_package_v5_0(pid);
if (res < 0) {
ipio_err("Failed to parse packet of finger touch\n");
goto out;
}
ipio_debug(DEBUG_FINGER_REPORT, "Touch Num = %d, LastTouch = %d\n", g_mutual_data.touch_num, last_touch);
/* interpret parsed packat and send input events to system */
if (g_mutual_data.touch_num > 0) {
if (ipd->MT_B_TYPE) {
for (i = 0 ; i < g_mutual_data.touch_num; i++) {
input_report_key(core_fr->input_device, BTN_TOUCH, 1);
core_fr_touch_press(g_mutual_data.mtp[i].x, g_mutual_data.mtp[i].y, g_mutual_data.mtp[i].pressure, g_mutual_data.mtp[i].id);
input_report_key(core_fr->input_device, BTN_TOOL_FINGER, 1);
}
for (i = 0 ; i < ipd->MAX_TOUCH_NUM; i++) {
ipio_debug(DEBUG_FINGER_REPORT, "g_previous_touch[%d]=%d, g_current_touch[%d]=%d\n", i,
g_previous_touch[i], i, g_current_touch[i]);
if (g_current_touch[i] == 0 && g_previous_touch[i] == 1) {
core_fr_touch_release(0, 0, i);
}
g_previous_touch[i] = g_current_touch[i];
}
} else{
for (i = 0 ; i < g_mutual_data.touch_num; i++) {
core_fr_touch_press(g_mutual_data.mtp[i].x, g_mutual_data.mtp[i].y, g_mutual_data.mtp[i].pressure, g_mutual_data.mtp[i].id);
}
}
input_sync(core_fr->input_device);
last_touch = g_mutual_data.touch_num;
} else {
if (last_touch > 0) {
if (ipd->MT_B_TYPE) {
for (i = 0 ; i < ipd->MAX_TOUCH_NUM; i++) {
ipio_debug(DEBUG_FINGER_REPORT, "g_previous_touch[%d]=%d, g_current_touch[%d]=%d\n", i,
g_previous_touch[i], i, g_current_touch[i]);
if (g_current_touch[i] == 0 && g_previous_touch[i] == 1) {
core_fr_touch_release(0, 0, i);
}
g_previous_touch[i] = g_current_touch[i];
}
input_report_key(core_fr->input_device, BTN_TOUCH, 0);
input_report_key(core_fr->input_device, BTN_TOOL_FINGER, 0);
} else{
core_fr_touch_release(0, 0, 0);
}
input_sync(core_fr->input_device);
last_touch = 0;
}
}
out:
return res;
}
void core_fr_mode_control(uint8_t *from_user)
{
int i, mode;
int checksum = 0, codeLength = 8;
uint8_t mp_code[8] = { 0 };
uint8_t cmd[4] = { 0 };
ilitek_platform_disable_irq();
if (from_user == NULL) {
ipio_err("Arguments from user space are invaild\n");
goto out;
}
ipio_debug(DEBUG_FINGER_REPORT, "mode = %x, b1 = %x, b2 = %x, b3 = %x\n",
from_user[0], from_user[1], from_user[2], from_user[3]);
mode = from_user[0];
if (protocol->major == 0x5) {
if (mode == protocol->i2cuart_mode) {
cmd[0] = protocol->cmd_i2cuart;
cmd[1] = *(from_user + 1);
cmd[2] = *(from_user + 2);
ipio_info("Switch to I2CUART mode, cmd = %x, b1 = %x, b2 = %x\n", cmd[0], cmd[1], cmd[2]);
if ((core_write(core_config->slave_i2c_addr, cmd, 3)) < 0) {
ipio_err("Failed to switch I2CUART mode\n");
goto out;
}
} else if (mode == protocol->demo_mode || mode == protocol->debug_mode) {
cmd[0] = protocol->cmd_mode_ctrl;
cmd[1] = mode;
ipio_info("Switch to Demo/Debug mode, cmd = 0x%x, b1 = 0x%x\n", cmd[0], cmd[1]);
if ((core_write(core_config->slave_i2c_addr, cmd, 2)) < 0) {
ipio_err("Failed to switch Demo/Debug mode\n");
goto out;
}
core_fr->actual_fw_mode = mode;
} else if (mode == protocol->test_mode) {
cmd[0] = protocol->cmd_mode_ctrl;
cmd[1] = mode;
ipio_info("Switch to Test mode, cmd = 0x%x, b1 = 0x%x\n", cmd[0], cmd[1]);
if ((core_write(core_config->slave_i2c_addr, cmd, 2)) < 0) {
ipio_err("Failed to switch Test mode\n");
goto out;
}
cmd[0] = 0xFE;
/* Read MP Test information to ensure if fw supports test mode. */
core_write(core_config->slave_i2c_addr, cmd, 1);
mdelay(10);
core_read(core_config->slave_i2c_addr, mp_code, codeLength);
for (i = 0 ; i < codeLength - 1; i++)
checksum += mp_code[i];
if ((-checksum & 0xFF) != mp_code[codeLength - 1]) {
ipio_info("checksume error (0x%x), FW doesn't support test mode.\n",
(-checksum & 0XFF));
goto out;
}
/* FW enter to Test Mode */
#if (INTERFACE == SPI_INTERFACE)
core_fr->actual_fw_mode = mode;
#endif
if (core_mp_move_code() == 0)
core_fr->actual_fw_mode = mode;
} else {
ipio_err("Unknown firmware mode: %x\n", mode);
}
} else {
ipio_err("Wrong the major version of protocol, 0x%x\n", protocol->major);
}
out:
ilitek_platform_enable_irq();
}
EXPORT_SYMBOL(core_fr_mode_control);
/**
* Calculate the length with different modes according to the format of protocol 5.0
*
* We compute the length before receiving its packet. If the length is differnet between
* firmware and the number we calculated, in this case I just print an error to inform users
* and still send up to users.
*/
static uint16_t calc_packet_length(void)
{
uint16_t xch = 0, ych = 0, stx = 0, srx = 0;
/* FIXME: self_key not defined by firmware yet */
uint16_t self_key = 2;
uint16_t rlen = 0;
if (protocol->major == 0x5) {
if (!ERR_ALLOC_MEM(core_config->tp_info)) {
xch = core_config->tp_info->nXChannelNum;
ych = core_config->tp_info->nYChannelNum;
stx = core_config->tp_info->self_tx_channel_num;
srx = core_config->tp_info->self_rx_channel_num;
}
ipio_debug(DEBUG_FINGER_REPORT, "firmware mode : 0x%x\n", core_fr->actual_fw_mode);
if (protocol->demo_mode == core_fr->actual_fw_mode) {
rlen = protocol->demo_len;
} else if (protocol->test_mode == core_fr->actual_fw_mode) {
if (ERR_ALLOC_MEM(core_config->tp_info)) {
rlen = protocol->test_len;
} else {
rlen = (2 * xch * ych) + (stx * 2) + (srx * 2) + 2 * self_key + 1;
rlen += 1;
}
} else if (protocol->debug_mode == core_fr->actual_fw_mode) {
if (ERR_ALLOC_MEM(core_config->tp_info)) {
rlen = protocol->debug_len;
} else {
rlen = (2 * xch * ych) + (stx * 2) + (srx * 2) + 2 * self_key + (8 * 2) + 1;
rlen += 35;
}
} else if (protocol->gesture_mode == core_fr->actual_fw_mode) {
if (core_gesture->mode == GESTURE_NORMAL_MODE)
rlen = GESTURE_MORMAL_LENGTH;
else
rlen = GESTURE_INFO_LENGTH;
ipio_debug(DEBUG_FINGER_REPORT, "rlen = %d\n", rlen);
} else {
ipio_err("Unknown firmware mode : %d\n", core_fr->actual_fw_mode);
rlen = 0;
}
} else {
ipio_err("Wrong the major version of protocol, 0x%x\n", protocol->major);
return ERROR;
}
ipio_debug(DEBUG_FINGER_REPORT, "rlen = %d\n", rlen);
return rlen;
}
/**
* The table is used to handle calling functions that deal with packets of finger report.
* The callback function might be different of what a protocol is used on a chip.
*
* It's possible to have the different protocol according to customer's requirement on the same
* touch ic with customised firmware, so I don't have to identify which of the ic has been used; instead,
* the version of protocol should match its parsing pattern.
*/
typedef struct {
uint8_t protocol_marjor_ver;
uint8_t protocol_minor_ver;
int (*finger_report)(void);
} fr_hashtable;
fr_hashtable fr_t[] = {
{0x3, 0x2, finger_report_ver_3_2},
{0x5, 0x0, finger_report_ver_5_0},
{0x5, 0x1, finger_report_ver_5_0},
};
/**
* The function is an entry for the work queue registered by ISR activates.
*
* Here will allocate the size of packet depending on what the current protocol
* is used on its firmware.
*/
void core_fr_handler(void)
{
int i = 0;
uint8_t *tdata = NULL;
if (core_fr->isEnableFR) {
g_total_len = calc_packet_length();
if (g_total_len) {
g_fr_node = kmalloc(sizeof(*g_fr_node), GFP_ATOMIC);
if (ERR_ALLOC_MEM(g_fr_node)) {
ipio_err("Failed to allocate g_fr_node memory %ld\n", PTR_ERR(g_fr_node));
goto out;
}
g_fr_node->data = kcalloc(g_total_len, sizeof(uint8_t), GFP_ATOMIC);
if (ERR_ALLOC_MEM(g_fr_node->data)) {
ipio_err("Failed to allocate g_fr_node memory %ld\n", PTR_ERR(g_fr_node->data));
goto out;
}
g_fr_node->len = g_total_len;
memset(g_fr_node->data, 0xFF, (uint8_t) sizeof(uint8_t) * g_total_len);
while (i < ARRAY_SIZE(fr_t)) {
if (protocol->major == fr_t[i].protocol_marjor_ver) {
mutex_lock(&ipd->plat_mutex);
fr_t[i].finger_report();
mutex_unlock(&ipd->plat_mutex);
/* 2048 is referred to the defination by user */
if (g_total_len < 2048) {
tdata = kmalloc(g_total_len, GFP_ATOMIC);
if (ERR_ALLOC_MEM(tdata)) {
ipio_err("Failed to allocate g_fr_node memory %ld\n",
PTR_ERR(tdata));
goto out;
}
memcpy(tdata, g_fr_node->data, g_fr_node->len);
/* merge uart data if it's at i2cuart mode */
if (g_fr_uart != NULL)
memcpy(tdata + g_fr_node->len, g_fr_uart->data, g_fr_uart->len);
} else {
ipio_err("total length (%d) is too long than user can handle\n",
g_total_len);
goto out;
}
if (core_fr->isEnableNetlink)
netlink_reply_msg(tdata, g_total_len);
if (ipd->debug_node_open) {
mutex_lock(&ipd->ilitek_debug_mutex);
memset(ipd->debug_buf[ipd->debug_data_frame], 0x00,
(uint8_t) sizeof(uint8_t) * 2048);
memcpy(ipd->debug_buf[ipd->debug_data_frame], tdata, g_total_len);
ipd->debug_data_frame++;
if (ipd->debug_data_frame > 1) {
ipio_info("ipd->debug_data_frame = %d\n", ipd->debug_data_frame);
}
if (ipd->debug_data_frame > 1023) {
ipio_err("ipd->debug_data_frame = %d > 1024\n",
ipd->debug_data_frame);
ipd->debug_data_frame = 1023;
}
mutex_unlock(&ipd->ilitek_debug_mutex);
wake_up(&(ipd->inq));
}
break;
}
i++;
}
if (i >= ARRAY_SIZE(fr_t))
ipio_err("Can't find any callback functions to handle INT event\n");
} else {
ipio_err("Wrong the length of packet\n");
}
} else {
ipio_err("The figner report was disabled\n");
return;
}
ilitek_platform_enable_irq();
out:
ipio_kfree((void **)&tdata);
if (g_fr_node != NULL) {
ipio_kfree((void **)&g_fr_node->data);
ipio_kfree((void **)&g_fr_node);
}
if (g_fr_uart != NULL) {
ipio_kfree((void **)&g_fr_uart->data);
ipio_kfree((void **)&g_fr_uart);
}
g_total_len = 0;
ipio_debug(DEBUG_IRQ, "handle INT done\n\n");
}
EXPORT_SYMBOL(core_fr_handler);
void core_fr_input_set_param(struct input_dev *input_device)
{
int max_x = 0, max_y = 0, min_x = 0, min_y = 0;
int max_tp = 0;
core_fr->input_device = input_device;
/* set the supported event type for input device */
set_bit(EV_ABS, core_fr->input_device->evbit);
set_bit(EV_SYN, core_fr->input_device->evbit);
set_bit(EV_KEY, core_fr->input_device->evbit);
set_bit(BTN_TOUCH, core_fr->input_device->keybit);
set_bit(BTN_TOOL_FINGER, core_fr->input_device->keybit);
set_bit(INPUT_PROP_DIRECT, core_fr->input_device->propbit);
if (core_fr->isSetResolution) {
max_x = core_config->tp_info->nMaxX;
max_y = core_config->tp_info->nMaxY;
min_x = core_config->tp_info->nMinX;
min_y = core_config->tp_info->nMinY;
max_tp = core_config->tp_info->nMaxTouchNum;
} else {
max_x = ipd->x_max;
max_y = ipd->y_max;
min_x = ipd->x_min;
min_y = ipd->y_min;
max_tp = ipd->MAX_TOUCH_NUM;
}
ipio_info("input resolution : max_x = %d, max_y = %d, min_x = %d, min_y = %d\n", max_x, max_y, min_x, min_y);
ipio_info("input touch number: max_tp = %d\n", max_tp);
input_set_abs_params(core_fr->input_device, ABS_MT_POSITION_X, min_x, max_x - 1, 0, 0);
input_set_abs_params(core_fr->input_device, ABS_MT_POSITION_Y, min_y, max_y - 1, 0, 0);
input_set_abs_params(core_fr->input_device, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(core_fr->input_device, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
if (core_fr->isEnablePressure)
input_set_abs_params(core_fr->input_device, ABS_MT_PRESSURE, 0, 255, 0, 0);
if (ipd->MT_B_TYPE) {
#if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE
input_mt_init_slots(core_fr->input_device, max_tp, INPUT_MT_DIRECT);
#else
input_mt_init_slots(core_fr->input_device, max_tp);
#endif /* LINUX_VERSION_CODE */
} else{
input_set_abs_params(core_fr->input_device, ABS_MT_TRACKING_ID, 0, max_tp, 0, 0);
} /* MT_B_TYPE */
/* Set up virtual key with gesture code */
core_gesture_set_key(core_fr);
}
EXPORT_SYMBOL(core_fr_input_set_param);
int core_fr_init(void)
{
int i = 0;
core_fr = kzalloc(sizeof(*core_fr), GFP_KERNEL);
if (ERR_ALLOC_MEM(core_fr)) {
ipio_err("Failed to allocate core_fr mem, %ld\n", PTR_ERR(core_fr));
core_fr_remove();
return -ENOMEM;
}
for (i = 0 ; i < ARRAY_SIZE(ipio_chip_list); i++) {
if (ipio_chip_list[i] == ipd->chip_id) {
core_fr->isEnableFR = true;
core_fr->isEnableNetlink = false;
core_fr->isEnablePressure = false;
core_fr->isSetResolution = false;
core_fr->actual_fw_mode = protocol->demo_mode;
return 0;
}
}
ipio_err("Can't find this chip in support list\n");
return 0;
}
EXPORT_SYMBOL(core_fr_init);
void core_fr_remove(void)
{
ipio_info("Remove core-FingerReport members\n");
ipio_kfree((void **)&core_fr);
}
EXPORT_SYMBOL(core_fr_remove);

View file

@ -0,0 +1,67 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __FINGER_REPORT_H
#define __FINGER_REPORT_H
struct core_fr_data {
struct input_dev *input_device;
/* the default of finger report is enabled */
bool isEnableFR;
/* used to send finger report packet to user psace */
bool isEnableNetlink;
/* allow input dev to report the value of physical touch */
bool isEnablePressure;
/* get screen resloution from fw if it's true */
bool isSetResolution;
/* used to change I2C Uart Mode when fw mode is in this mode */
uint8_t i2cuart_mode;
/* current firmware mode in driver */
uint16_t actual_fw_mode;
/* mutual firmware info */
uint16_t log_packet_length;
uint8_t log_packet_header;
uint8_t type;
uint8_t Mx;
uint8_t My;
uint8_t Sd;
uint8_t Ss;
};
extern struct core_fr_data *core_fr;
extern uint8_t core_fr_calc_checksum(uint8_t *pMsg, uint32_t nLength);
extern void core_fr_touch_press(int32_t x, int32_t y, uint32_t pressure
, int32_t id);
extern void core_fr_touch_release(int32_t x, int32_t y, int32_t id);
extern void core_fr_mode_control(uint8_t *from_user);
extern void core_fr_handler(void);
extern void core_fr_input_set_param(struct input_dev *input_device);
extern int core_fr_init(void);
extern void core_fr_remove(void);
#endif /* __FINGER_REPORT_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __FIRMWARE_H
#define __FIRMWARE_H
struct core_firmware_data {
uint8_t new_fw_ver[4];
uint8_t old_fw_ver[4];
uint32_t start_addr;
uint32_t end_addr;
uint32_t checksum;
uint32_t crc32;
uint32_t update_status;
uint32_t max_count;
int delay_after_upgrade;
bool isUpgrading;
bool force_upgrad;
bool isCRC;
bool isboot;
bool hasBlockInfo;
int (*upgrade_func)(bool isIRAM);
};
extern struct core_firmware_data *core_firmware;
#ifdef HOST_DOWNLOAD
extern int core_firmware_boot_host_download(void);
extern int tddi_host_download(bool isIRAM);
#endif
#ifdef BOOT_FW_UPGRADE
extern int core_firmware_boot_upgrade(void);
#endif
/* extern int core_firmware_iram_upgrade(const char* fpath); */
extern int core_firmware_upgrade(const char *pFilePath, bool isIRAM);
extern int core_firmware_init(void);
extern void core_firmware_remove(void);
#endif /* __FIRMWARE_H */

View file

@ -0,0 +1,187 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common.h"
#include "config.h"
#include "flash.h"
#define K (1024)
#define M (K * K)
/*
* The table contains fundamental data used to program our flash, which
* would be different according to the vendors.
*/
struct flash_table ft[] = {
{0xEF, 0x6011, (128 * K), 256, (4 * K), (64 * K)}, /* W25Q10EW */
{0xEF, 0x6012, (256 * K), 256, (4 * K), (64 * K)}, /* W25Q20EW */
{0xC8, 0x6012, (256 * K), 256, (4 * K), (64 * K)}, /* GD25LQ20B */
{0xC8, 0x6013, (512 * K), 256, (4 * K), (64 * K)}, /* GD25LQ40 */
{0x85, 0x6013, (4 * M), 256, (4 * K), (64 * K)},
{0xC2, 0x2812, (256 * K), 256, (4 * K), (64 * K)},
{0x1C, 0x3812, (256 * K), 256, (4 * K), (64 * K)},
};
struct flash_table *flashtab;
int core_flash_poll_busy(void)
{
int timer = 500, res = 0;
core_config_ice_mode_write(0x041000, 0x0, 1); /* CS low */
core_config_ice_mode_write(0x041004, 0x66aa55, 3); /* Key */
core_config_ice_mode_write(0x041008, 0x5, 1);
while (timer > 0) {
core_config_ice_mode_write(0x041008, 0xFF, 1);
mdelay(1);
if ((core_config_read_write_onebyte(0x041010) & 0x03) == 0x00)
goto out;
timer--;
}
ipio_err("Polling busy Time out !\n");
res = ERROR;
out:
core_config_ice_mode_write(0x041000, 0x1, 1); /* CS high */
return res;
}
EXPORT_SYMBOL(core_flash_poll_busy);
int core_flash_write_enable(void)
{
if (core_config_ice_mode_write(0x041000, 0x0, 1) < 0)
goto out;
if (core_config_ice_mode_write(0x041004, 0x66aa55, 3) < 0)
goto out;
if (core_config_ice_mode_write(0x041008, 0x6, 1) < 0)
goto out;
if (core_config_ice_mode_write(0x041000, 0x1, 1) < 0)
goto out;
return 0;
out:
ipio_err("Write enable failed !\n");
return -EIO;
}
EXPORT_SYMBOL(core_flash_write_enable);
void core_flash_enable_protect(bool enable)
{
ipio_info("Set flash protect as (%d)\n", enable);
if (core_flash_write_enable() < 0) {
ipio_err("Failed to config flash's write enable\n");
return;
}
core_config_ice_mode_write(0x041000, 0x0, 1); /* CS low */
core_config_ice_mode_write(0x041004, 0x66aa55, 3); /* Key */
switch (flashtab->mid) {
case 0xEF:
if (flashtab->dev_id == 0x6012 || flashtab->dev_id == 0x6011) {
core_config_ice_mode_write(0x041008, 0x1, 1);
core_config_ice_mode_write(0x041008, 0x00, 1);
if (enable)
core_config_ice_mode_write(0x041008, 0x7E, 1);
else
core_config_ice_mode_write(0x041008, 0x00, 1);
}
break;
case 0xC8:
if (flashtab->dev_id == 0x6012 || flashtab->dev_id == 0x6013) {
core_config_ice_mode_write(0x041008, 0x1, 1);
core_config_ice_mode_write(0x041008, 0x00, 1);
if (enable)
core_config_ice_mode_write(0x041008, 0x7A, 1);
else
core_config_ice_mode_write(0x041008, 0x00, 1);
}
break;
default:
ipio_err("Can't find flash id, ignore protection\n");
break;
}
core_config_ice_mode_write(0x041000, 0x1, 1); /* CS high */
mdelay(5);
}
EXPORT_SYMBOL(core_flash_enable_protect);
void core_flash_init(uint16_t mid, uint16_t did)
{
int i = 0;
ipio_info("M_ID = %x, DEV_ID = %x", mid, did);
flashtab = kzalloc(sizeof(ft), GFP_KERNEL);
if (ERR_ALLOC_MEM(flashtab)) {
ipio_err("Failed to allocate flashtab memory, %ld\n", PTR_ERR(flashtab));
return;
}
for (; i < ARRAY_SIZE(ft); i++) {
if (mid == ft[i].mid && did == ft[i].dev_id) {
ipio_info("Find them in flash table\n");
flashtab->mid = mid;
flashtab->dev_id = did;
flashtab->mem_size = ft[i].mem_size;
flashtab->program_page = ft[i].program_page;
flashtab->sector = ft[i].sector;
flashtab->block = ft[i].block;
break;
}
}
if (i >= ARRAY_SIZE(ft)) {
ipio_err("Can't find them in flash table, apply default flash config\n");
flashtab->mid = mid;
flashtab->dev_id = did;
flashtab->mem_size = (256 * K);
flashtab->program_page = 256;
flashtab->sector = (4 * K);
flashtab->block = (64 * K);
}
ipio_info("Max Memory size = %d\n", flashtab->mem_size);
ipio_info("Per program page = %d\n", flashtab->program_page);
ipio_info("Sector size = %d\n", flashtab->sector);
ipio_info("Block size = %d\n", flashtab->block);
}
EXPORT_SYMBOL(core_flash_init);
void core_flash_remove(void)
{
ipio_info("Remove core-flash memebers\n");
ipio_kfree((void **)&flashtab);
}
EXPORT_SYMBOL(core_flash_remove);

View file

@ -0,0 +1,45 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __FLASH_H
#define __FLASH_H
struct flash_table {
uint16_t mid;
uint16_t dev_id;
int mem_size;
int program_page;
int sector;
int block;
};
extern struct flash_table *flashtab;
extern int core_flash_poll_busy(void);
extern int core_flash_write_enable(void);
extern void core_flash_enable_protect(bool status);
extern void core_flash_init(uint16_t mid, uint16_t did);
extern void core_flash_remove(void);
#endif /* __FLASH_H */

View file

@ -0,0 +1,289 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common.h"
#include "finger_report.h"
#include "firmware.h"
#include "gesture.h"
#include "protocol.h"
#include "config.h"
struct core_gesture_data *core_gesture;
#ifdef HOST_DOWNLOAD
int core_gesture_load_code(void)
{
int i = 0, ret = 0;
uint8_t temp[64] = {0};
core_gesture->entry = true;
/* Already read during parsing hex file */
ipio_info("gesture_start_addr = 0x%x, length = 0x%x\n",
core_gesture->start_addr, core_gesture->length);
ipio_info("area = %d, ap_start_addr = 0x%x, ap_length = 0x%x\n",
core_gesture->area_section, core_gesture->ap_start_addr,
core_gesture->ap_length);
/* write load gesture flag */
ipio_info("write load gesture flag\n");
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = 0x03;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write gesture flag error\n");
ipio_info("enter gesture cmd lpwg start\n");
/* enter gesture cmd lpwg start */
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = core_gesture->mode + 1;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write lpwg start error\n");
for (i = 0 ; i < 20 ; i++) {
temp[0] = 0xF6;
temp[1] = 0x0A;
temp[2] = 0x05;
if ((core_write(core_config->slave_i2c_addr, temp, 2)) < 0)
ipio_err("write 0xF6,0xA,0x05 command error\n");
mdelay(i * 50);
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = 0x05;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write command error\n");
if ((core_read(core_config->slave_i2c_addr, temp, 1)) < 0)
ipio_err("Read command error\n");
if (temp[0] == 0x91) {
ipio_info("check fw ready\n");
break;
}
}
if (temp[0] != 0x91)
ipio_err("FW is busy, error\n");
ipio_info("load gesture code\n");
/* load gesture code */
if (core_config_ice_mode_enable() < 0)
ipio_err("Failed to enter ICE mode\n");
tddi_host_download(true);
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = 0x06;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write command error\n");
core_gesture->entry = false;
return ret;
}
EXPORT_SYMBOL(core_gesture_load_code);
int core_gesture_load_ap_code(void)
{
int i = 0, ret = 0;
uint8_t temp[64] = {0};
core_gesture->entry = true;
/* Write Load AP Flag */
temp[0] = 0x01;
temp[1] = 0x01;
temp[2] = 0x00;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write command AP Flag error\n");
if ((core_read(core_config->slave_i2c_addr, temp, 20)) < 0)
ipio_err("Read AP Flag error\n");
/* Leave Gesture Cmd LPWG Stop */
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = 0x00;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write command LPWG Stop error\n");
for (i = 0 ; i < 20 ; i++) {
mdelay(i * 100 + 100);
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = 0x05;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write command error\n");
if ((core_read(core_config->slave_i2c_addr, temp, 1)) < 0)
ipio_err("Read command error\n");
if (temp[0] == 0x91) {
ipio_info("check fw ready\n");
break;
}
}
if (i == 3 && temp[0] != 0x01)
ipio_err("FW is busy, error\n");
/* load AP code */
if (core_config_ice_mode_enable() < 0)
ipio_err("Failed to enter ICE mode\n");
tddi_host_download(false);
temp[0] = 0x01;
temp[1] = 0x0A;
temp[2] = 0x06;
if ((core_write(core_config->slave_i2c_addr, temp, 3)) < 0)
ipio_err("write command error\n");
core_gesture->entry = false;
return ret;
}
EXPORT_SYMBOL(core_gesture_load_ap_code);
#endif
int core_gesture_match_key(uint8_t gdata)
{
int gcode;
switch (gdata) {
case GESTURE_LEFT:
gcode = KEY_GESTURE_LEFT;
break;
case GESTURE_RIGHT:
gcode = KEY_GESTURE_RIGHT;
break;
case GESTURE_UP:
gcode = KEY_GESTURE_UP;
break;
case GESTURE_DOWN:
gcode = KEY_GESTURE_DOWN;
break;
case GESTURE_DOUBLECLICK:
gcode = KEY_GESTURE_D;
break;
case GESTURE_O:
gcode = KEY_GESTURE_O;
break;
case GESTURE_W:
gcode = KEY_GESTURE_W;
break;
case GESTURE_M:
gcode = KEY_GESTURE_M;
break;
case GESTURE_E:
gcode = KEY_GESTURE_E;
break;
case GESTURE_S:
gcode = KEY_GESTURE_S;
break;
case GESTURE_V:
gcode = KEY_GESTURE_V;
break;
case GESTURE_Z:
gcode = KEY_GESTURE_Z;
break;
case GESTURE_C:
gcode = KEY_GESTURE_C;
break;
default:
gcode = ERROR;
break;
}
ipio_debug(DEBUG_GESTURE, "gcode = %d\n", gcode);
return gcode;
}
EXPORT_SYMBOL(core_gesture_match_key);
void core_gesture_set_key(struct core_fr_data *fr_data)
{
struct input_dev *input_dev = fr_data->input_device;
if (input_dev != NULL) {
input_set_capability(input_dev, EV_KEY, KEY_POWER);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_UP);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_DOWN);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_LEFT);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_RIGHT);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_O);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_E);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_M);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_W);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_S);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_V);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_Z);
input_set_capability(input_dev, EV_KEY, KEY_GESTURE_C);
__set_bit(KEY_POWER, input_dev->keybit);
__set_bit(KEY_GESTURE_UP, input_dev->keybit);
__set_bit(KEY_GESTURE_DOWN, input_dev->keybit);
__set_bit(KEY_GESTURE_LEFT, input_dev->keybit);
__set_bit(KEY_GESTURE_RIGHT, input_dev->keybit);
__set_bit(KEY_GESTURE_O, input_dev->keybit);
__set_bit(KEY_GESTURE_E, input_dev->keybit);
__set_bit(KEY_GESTURE_M, input_dev->keybit);
__set_bit(KEY_GESTURE_W, input_dev->keybit);
__set_bit(KEY_GESTURE_S, input_dev->keybit);
__set_bit(KEY_GESTURE_V, input_dev->keybit);
__set_bit(KEY_GESTURE_Z, input_dev->keybit);
__set_bit(KEY_GESTURE_C, input_dev->keybit);
return;
}
ipio_err("GESTURE: input dev is NULL\n");
}
EXPORT_SYMBOL(core_gesture_set_key);
int core_gesture_init(void)
{
if (core_gesture == NULL) {
core_gesture = kzalloc(sizeof(*core_gesture), GFP_KERNEL);
if (ERR_ALLOC_MEM(core_gesture)) {
ipio_err("Failed to allocate core_gesture mem, %ld\n",
PTR_ERR(core_gesture));
core_gesture_remove();
return -ENOMEM;
}
core_gesture->entry = false;
}
return 0;
}
EXPORT_SYMBOL(core_gesture_init);
void core_gesture_remove(void)
{
ipio_info("Remove core-gesture members\n");
ipio_kfree((void **)&core_gesture);
}
EXPORT_SYMBOL(core_gesture_remove);

View file

@ -0,0 +1,88 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __GESTURE_H
#define __GESTURE_H
#define GESTURE_NORMAL_MODE 0
#define GESTURE_INFO_MPDE 1
#define GESTURE_INFO_LENGTH 170
#define GESTURE_MORMAL_LENGTH 8
/* The example for the gesture virtual keys */
#define GESTURE_DOUBLECLICK 0x58
#define GESTURE_UP 0x60
#define GESTURE_DOWN 0x61
#define GESTURE_LEFT 0x62
#define GESTURE_RIGHT 0x63
#define GESTURE_M 0x64
#define GESTURE_W 0x65
#define GESTURE_C 0x66
#define GESTURE_E 0x67
#define GESTURE_V 0x68
#define GESTURE_O 0x69
#define GESTURE_S 0x6A
#define GESTURE_Z 0x6B
/* oppo gesture define */
#define GESTURE_CODE_V_DOWN 0x6C
#define GESTURE_CODE_V_LEFT 0x6D
#define GESTURE_CODE_V_RIGHT 0x6E
#define GESTURE_CODE_TWO_LINE_2_BOTTOM 0x6F
#define KEY_GESTURE_D KEY_D
#define KEY_GESTURE_UP KEY_UP
#define KEY_GESTURE_DOWN KEY_DOWN
#define KEY_GESTURE_LEFT KEY_LEFT
#define KEY_GESTURE_RIGHT KEY_RIGHT
#define KEY_GESTURE_O KEY_O
#define KEY_GESTURE_E KEY_E
#define KEY_GESTURE_M KEY_M
#define KEY_GESTURE_W KEY_W
#define KEY_GESTURE_S KEY_S
#define KEY_GESTURE_V KEY_V
#define KEY_GESTURE_C KEY_C
#define KEY_GESTURE_Z KEY_Z
struct core_gesture_data {
uint32_t start_addr;
uint32_t length;
bool entry;
uint8_t mode; /* normal:0 info:1 */
uint32_t ap_start_addr;
uint32_t ap_length;
uint32_t area_section;
bool suspend;
};
extern struct core_gesture_data *core_gesture;
extern uint8_t ap_fw[MAX_AP_FIRMWARE_SIZE];
#ifdef HOST_DOWNLOAD
extern int core_gesture_load_code(void);
extern int core_gesture_load_ap_code(void);
#endif
extern int core_gesture_match_key(uint8_t gid);
extern void core_gesture_set_key(struct core_fr_data *fr_data);
extern int core_gesture_init(void);
extern void core_gesture_remove(void);
#endif

View file

@ -0,0 +1,278 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common.h"
#include "config.h"
#include "i2c.h"
#include "mp_test.h"
#include "finger_report.h"
#include "protocol.h"
#include "../platform.h"
struct core_i2c_data *core_i2c;
#ifdef I2C_DMA
static unsigned char *ilitek_dma_va;
static dma_addr_t ilitek_dma_pa;
#define DMA_VA_BUFFER 4096
static int dma_alloc(struct core_i2c_data *i2c)
{
if (i2c->client != NULL) {
i2c->client->dev.coherent_dma_mask = DMA_BIT_MASK(32);
ilitek_dma_va = (u8 *) dma_alloc_coherent(&i2c->client->dev
, DMA_VA_BUFFER, &ilitek_dma_pa, GFP_KERNEL);
if (ERR_ALLOC_MEM(ilitek_dma_va)) {
ipio_err("Allocate DMA I2C Buffer failed\n");
return -ENOMEM;
}
memset(ilitek_dma_va, 0, DMA_VA_BUFFER);
i2c->client->ext_flag |= I2C_DMA_FLAG;
return 0;
}
ipio_err("i2c->client is NULL, return fail\n");
return -ENODEV;
}
static void dma_free(void)
{
if (ilitek_dma_va != NULL) {
dma_free_coherent(&core_i2c->client->dev, DMA_VA_BUFFER
, ilitek_dma_va, ilitek_dma_pa);
ilitek_dma_va = NULL;
ilitek_dma_pa = 0;
ipio_info("Succeed to free DMA buffer\n");
}
}
#endif /* I2C_DMA */
int core_i2c_write(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize)
{
int res = 0;
uint8_t check_sum = 0;
uint8_t *txbuf = NULL;
struct i2c_msg msgs[] = {
{
.addr = nSlaveId,
.flags = 0, /* write flag. */
.len = nSize,
.buf = pBuf,
},
};
#ifdef I2C_DMA
ipio_debug(DEBUG_I2C, "DMA: size = %d\n", nSize);
if (nSize > 8) {
msgs[0].addr = (core_i2c->client->addr & I2C_MASK_FLAG);
msgs[0].ext_flag =
(core_i2c->client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
memcpy(ilitek_dma_va, pBuf, nSize);
msgs[0].buf = (uint8_t *) ilitek_dma_pa;
}
#endif /* I2C_DMA */
/*
* NOTE: If TP driver is doing MP test and commanding 0xF1 to FW,
* we add a checksum to the last index and plus 1 with size.
*/
if (protocol->major >= 5 && protocol->mid >= 4) {
if (!core_config->icemodeenable && pBuf[0] == 0xF1 &&
core_mp->run) {
check_sum = core_fr_calc_checksum(pBuf, nSize);
txbuf =
kcalloc(nSize + 1, sizeof(uint8_t), GFP_KERNEL);
if (ERR_ALLOC_MEM(txbuf)) {
ipio_err("Failed to allocate txbuf mem\n");
res = -ENOMEM;
goto out;
}
memcpy(txbuf, pBuf, nSize);
txbuf[nSize] = check_sum;
msgs[0].buf = txbuf;
msgs[0].len = nSize + 1;
dump_data(txbuf, 8, nSize + 1, nSize + 1, "summer_i2c_dump");
}
}
if (i2c_transfer(core_i2c->client->adapter, msgs, 1) < 0) {
if (core_config->do_ic_reset) {
/* ignore i2c error if doing ic reset */
res = 0;
} else {
res = -EIO;
ipio_err("I2C Write Error, res = %d\n", res);
goto out;
}
}
out:
ipio_kfree((void **)&txbuf);
return res;
}
EXPORT_SYMBOL(core_i2c_write);
int core_i2c_read(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize)
{
int res = 0;
struct i2c_msg msgs[] = {
{
.addr = nSlaveId,
.flags = I2C_M_RD, /* read flag */
.len = nSize,
.buf = pBuf,
},
};
#ifdef I2C_DMA
ipio_debug(DEBUG_I2C, "DMA: size = %d\n", nSize);
if (nSize > 8) {
msgs[0].addr = (core_i2c->client->addr & I2C_MASK_FLAG);
msgs[0].ext_flag =
(core_i2c->client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
msgs[0].buf = (uint8_t *) ilitek_dma_pa;
} else {
msgs[0].buf = pBuf;
}
#endif /* I2C_DMA */
if (i2c_transfer(core_i2c->client->adapter, msgs, 1) < 0) {
res = -EIO;
ipio_err("I2C Read Error, res = %d\n", res);
goto out;
}
#ifdef I2C_DMA
if (nSize > 8)
memcpy(pBuf, ilitek_dma_va, nSize);
#endif /* I2C_DMA */
out:
return res;
}
EXPORT_SYMBOL(core_i2c_read);
int core_i2c_segmental_read(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize)
{
int res = 0;
int offset = 0;
struct i2c_msg msgs[] = {
{
.addr = nSlaveId,
.flags = I2C_M_RD,
.len = nSize,
/* .buf = pBuf, */
},
};
while (nSize > 0) {
msgs[0].buf = &pBuf[offset];
if (nSize > core_i2c->seg_len) {
msgs[0].len = core_i2c->seg_len;
nSize -= core_i2c->seg_len;
offset += msgs[0].len;
} else {
msgs[0].len = nSize;
nSize = 0;
}
ipio_debug(DEBUG_I2C, "Length = %d\n", msgs[0].len);
if (i2c_transfer(core_i2c->client->adapter, msgs, 1) < 0) {
res = -EIO;
ipio_err("I2C Read Error, res = %d\n", res);
goto out;
}
}
out:
return res;
}
EXPORT_SYMBOL(core_i2c_segmental_read);
int core_i2c_init(struct i2c_client *client)
{
int i;
core_i2c = kmalloc(sizeof(*core_i2c), GFP_KERNEL);
if (ERR_ALLOC_MEM(core_i2c)) {
ipio_err("Failed to alllocate core_i2c mem %ld\n",
PTR_ERR(core_i2c));
core_i2c_remove();
return -ENOMEM;
}
core_i2c->client = client;
core_i2c->seg_len = 256; /* length of segment */
#ifdef I2C_DMA
if (dma_alloc(core_i2c->client) < 0) {
ipio_err("Failed to alllocate DMA mem %ld\n",
PTR_ERR(core_i2c));
return -ENOMEM;
}
#endif /* I2C_DMA */
for (i = 0 ; i < ARRAY_SIZE(ipio_chip_list); i++) {
if (ipio_chip_list[i] == ipd->chip_id) {
if (ipio_chip_list[i] == CHIP_TYPE_ILI7807) {
if (core_config->chip_type == ILI7807_TYPE_F_AA
&& core_config->chip_type == ILI7807_TYPE_F_AB)
core_i2c->clk = 100000;
else
core_i2c->clk = 400000;
} else if (ipio_chip_list[i] == CHIP_TYPE_ILI9881) {
core_i2c->clk = 400000;
}
return 0;
}
}
ipio_err("Can't find this chip in support list\n");
return 0;
}
EXPORT_SYMBOL(core_i2c_init);
void core_i2c_remove(void)
{
ipio_info("Remove core-i2c members\n");
#ifdef I2C_DMA
dma_free();
#endif /* I2C_DMA */
ipio_kfree((void **)&core_i2c);
}
EXPORT_SYMBOL(core_i2c_remove);

View file

@ -0,0 +1,45 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __I2C_H
#define __I2C_H
struct core_i2c_data {
struct i2c_client *client;
int clk;
int seg_len;
};
extern struct core_i2c_data *core_i2c;
extern int core_i2c_write(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize);
extern int core_i2c_read(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize);
extern int core_i2c_segmental_read(uint8_t nSlaveId, uint8_t *pBuf
, uint16_t nSize);
extern int core_i2c_init(struct i2c_client *client);
extern void core_i2c_remove(void);
#endif

View file

@ -0,0 +1,3 @@
static unsigned char CTPM_FW[] = {
#include "FW_TDDI_9881H.ili"
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,172 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __MP_TEST_H
#define __MP_TEST_H
#define MP_PASS 1
#define MP_FAIL -1
#define BENCHMARK 1
#define NODETYPE 1
#define RAWDATA_NO_BK_DATA_SHIFT_9881H 8192
#define RAWDATA_NO_BK_DATA_SHIFT_9881F 4096
#define TYPE_BENCHMARK 0
#define TYPE_NO_JUGE 1
#define TYPE_JUGE 2
struct mp_test_P540_open {
int32_t *cbk_700;
int32_t *cbk_250;
int32_t *cbk_200;
int32_t *charg_rate;
int32_t *full_Open;
int32_t *dac;
int32_t *cdc;
};
struct mp_test_items {
char *name;
/* The description must be the same as ini's section name */
char *desp;
char *result;
int catalog;
uint8_t cmd;
uint8_t spec_option;
uint8_t type_option;
bool run;
int max;
int max_res;
int item_result;
int test_count;
int min;
int min_res;
int frame_count;
int trimmed_mean;
int lowest_percentage;
int highest_percentage;
int32_t *result_buf;
int32_t *buf;
int32_t *max_buf;
int32_t *min_buf;
int32_t *bench_mark_max;
int32_t *bench_mark_min;
int32_t *node_type;
int (*do_test)(int index);
};
struct mp_nodp_calc {
bool is60HZ;
bool isLongV;
/* Input */
uint16_t tshd;
uint8_t multi_term_num_120;
uint8_t multi_term_num_60;
uint16_t tsvd_to_tshd;
uint16_t qsh_tdf;
/* Settings */
uint8_t auto_trim;
uint16_t tp_tshd_wait_120;
uint16_t ddi_width_120;
uint16_t tp_tshd_wait_60;
uint16_t ddi_width_60;
uint16_t dp_to_tp;
uint16_t tx_wait_const;
uint16_t tx_wait_const_multi;
uint16_t tp_to_dp;
uint8_t phase_adc;
uint8_t r2d_pw;
uint8_t rst_pw;
uint8_t rst_pw_back;
uint8_t dac_td;
uint8_t qsh_pw;
uint8_t qsh_td;
uint8_t drop_nodp;
/* Output */
uint32_t first_tp_width;
uint32_t tp_width;
uint32_t txpw;
uint32_t long_tsdh_wait;
uint32_t nodp;
};
struct core_mp_test_data {
struct mp_nodp_calc nodp;
/* A flag shows a test run in particular */
bool run;
bool oppo_run;
bool oppo_lcm;
bool m_signal;
bool m_dac;
bool s_signal;
bool s_dac;
bool key_dac;
bool st_dac;
bool p_no_bk;
bool p_has_bk;
bool open_integ;
bool open_cap;
int xch_len;
int ych_len;
int stx_len;
int srx_len;
int key_len;
int st_len;
int frame_len;
int mp_items;
int final_result;
/* Tx/Rx threshold & buffer */
int TxDeltaMax;
int TxDeltaMin;
int RxDeltaMax;
int RxDeltaMin;
int32_t *tx_delta_buf;
int32_t *rx_delta_buf;
int32_t *tx_max_buf;
int32_t *tx_min_buf;
int32_t *rx_max_buf;
int32_t *rx_min_buf;
int tdf;
bool retry;
bool busy_cdc;
bool ctrl_lcm;
};
extern struct core_mp_test_data *core_mp;
extern struct mp_test_items tItems[];
extern void dump_data(void *data, int type, int len, int row_len, const char *name);
extern int core_mp_calc_timing_nodp(void);
extern int core_mp_ctrl_lcm_status(bool on);
extern void core_mp_test_free(void);
extern void core_mp_show_result(void);
extern void core_mp_run_test(char *item, bool ini);
extern int core_mp_move_code(void);
extern int core_mp_init(void);
#endif

View file

@ -0,0 +1,500 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common.h"
#include "parser.h"
#include "config.h"
#define PARSER_MAX_CFG_BUF (512 * 3)
#define PARSER_MAX_KEY_NUM (600 * 3)
#define PARSER_MAX_KEY_NAME_LEN 100
#define PARSER_MAX_KEY_VALUE_LEN 2000
#define INI_ERR_OUT_OF_LINE -1
struct ini_file_data {
char pSectionName[PARSER_MAX_KEY_NAME_LEN];
char pKeyName[PARSER_MAX_KEY_NAME_LEN];
char pKeyValue[PARSER_MAX_KEY_VALUE_LEN];
int iSectionNameLen;
int iKeyNameLen;
int iKeyValueLen;
} ilitek_ini_file_data[PARSER_MAX_KEY_NUM];
int g_ini_items;
static int isspace_t(int x)
{
if (x == ' ' || x == '\t' || x == '\n' || x == '\f' || x == '\b' || x == '\r')
return ERROR;
else
return SUCCESS;
}
static char *ini_str_trim_r(char *buf)
{
int len, i;
char tmp[512] = { 0 };
len = strlen(buf)+1;
for (i = 0 ; i < len ; i++) {
if (buf[i] != ' ')
break;
}
if (i < len)
strlcpy(tmp, (buf + i), (len - i));
strlcpy(buf, tmp, len);
return buf;
}
/* Count the number of each line and assign the content to tmp buffer */
static int get_ini_phy_line(char *data, char *buffer, int maxlen)
{
int i = 0;
int j = 0;
int iRetNum = -1;
char ch1 = '\0';
for (i = 0, j = 0 ; i < maxlen ; j++) {
ch1 = data[j];
iRetNum = j + 1;
if (ch1 == '\n' || ch1 == '\r') { /* line end */
ch1 = data[j + 1];
if (ch1 == '\n' || ch1 == '\r') {
iRetNum++;
}
break;
} else if (ch1 == 0x00) {
//iRetNum = -1;
break; /* file end */
}
buffer[i++] = ch1;
}
buffer[i] = '\0';
return iRetNum;
}
static int get_ini_phy_data(char *data, int fsize)
{
int i, n = 0, res = 0, banchmark_flag = 0, empty_section, nodetype_flag = 0;
int offset = 0, isEqualSign = 0;
char *ini_buf = NULL, *tmpSectionName = NULL, *temp;
char M_CFG_SSL = '[';
char M_CFG_SSR = ']';
/* char M_CFG_NIS = ':'; */
char M_CFG_NTS = '#';
char M_CFG_EQS = '=';
if (data == NULL) {
ipio_err("INI data is NULL\n");
res = -EINVAL;
goto out;
}
ini_buf = kzalloc((PARSER_MAX_CFG_BUF + 1) * sizeof(char), GFP_KERNEL);
if (ERR_ALLOC_MEM(ini_buf)) {
ipio_err("Failed to allocate ini_buf memory, %ld\n", PTR_ERR(ini_buf));
res = -ENOMEM;
goto out;
}
tmpSectionName = kzalloc((PARSER_MAX_CFG_BUF + 1) * sizeof(char), GFP_KERNEL);
if (ERR_ALLOC_MEM(tmpSectionName)) {
ipio_err("Failed to allocate tmpSectionName memory, %ld\n", PTR_ERR(tmpSectionName));
res = -ENOMEM;
goto out;
}
temp = strnstr(data, TYPE_MARK, fsize);
if (temp != NULL) {
ipio_debug(DEBUG_PARSER, "Find Type mark, locat = %ld", temp-data);
if (core_config->core_type == CORE_TYPE_B)
offset = temp-data;
else
fsize = temp-data;
}
while (true) {
banchmark_flag = 0;
empty_section = 0;
nodetype_flag = 0;
if (g_ini_items > PARSER_MAX_KEY_NUM) {
ipio_err("MAX_KEY_NUM: Out of length\n");
goto out;
}
if (offset >= fsize)
goto out;/*over size*/
n = get_ini_phy_line(data + offset, ini_buf, PARSER_MAX_CFG_BUF);
if (n < 0) {
ipio_err("End of Line\n");
goto out;
}
offset += n;
n = strlen(ini_str_trim_r(ini_buf));
if (n == 0 || ini_buf[0] == M_CFG_NTS)
continue;
/* Get section names */
if (n > 2 && ((ini_buf[0] == M_CFG_SSL && ini_buf[n - 1] != M_CFG_SSR))) {
ipio_err("Bad Section: %s\n", ini_buf);
res = -EINVAL;
goto out;
} else {
if (ini_buf[0] == M_CFG_SSL) {
ilitek_ini_file_data[g_ini_items].iSectionNameLen = n - 2;
if (ilitek_ini_file_data[g_ini_items].iSectionNameLen > PARSER_MAX_KEY_NAME_LEN) {
ipio_err("MAX_KEY_NAME_LEN: Out Of Length\n");
res = INI_ERR_OUT_OF_LINE;
goto out;
}
ini_buf[n - 1] = 0x00;
strlcpy((char *)tmpSectionName, ini_buf + 1, ((PARSER_MAX_CFG_BUF + 1) * sizeof(char)));
banchmark_flag = 0;
nodetype_flag = 0;
ipio_debug(DEBUG_PARSER, "Section Name: %s, Len: %d, offset = %d\n", tmpSectionName, n - 2, offset);
continue;
}
}
/* copy section's name without square brackets to its real buffer */
strlcpy(ilitek_ini_file_data[g_ini_items].pSectionName, tmpSectionName, strlen(tmpSectionName)+1);
ilitek_ini_file_data[g_ini_items].iSectionNameLen = strlen(tmpSectionName);
isEqualSign = 0;
for (i = 0 ; i < n ; i++) {
if (ini_buf[i] == M_CFG_EQS) {
isEqualSign = i;
break;
}
if (ini_buf[i] == M_CFG_SSL || ini_buf[i] == M_CFG_SSR) {
empty_section = 1;
break;
}
}
if (isEqualSign == 0) {
if (empty_section)
continue;
if (strnstr(ilitek_ini_file_data[g_ini_items].pSectionName, "Benchmark_Data", strlen(ilitek_ini_file_data[g_ini_items].pSectionName)) > 0) {
banchmark_flag = 1;
isEqualSign = -1;
} else if (strnstr(ilitek_ini_file_data[g_ini_items].pSectionName, "Node Type", strlen(ilitek_ini_file_data[g_ini_items].pSectionName)) > 0) {
nodetype_flag = 1;
isEqualSign = -1;
} else {
continue;
}
}
if (banchmark_flag) {
/* Get Key names */
ilitek_ini_file_data[g_ini_items].iKeyNameLen = strlen(BENCHMARK_KEY_NAME);
strlcpy(ilitek_ini_file_data[g_ini_items].pKeyName, BENCHMARK_KEY_NAME, strlen(BENCHMARK_KEY_NAME)+1);
ilitek_ini_file_data[g_ini_items].iKeyValueLen = n;
} else if (nodetype_flag) {
/* Get Key names */
ilitek_ini_file_data[g_ini_items].iKeyNameLen = strlen(NODE_TYPE_KEY_NAME);
strlcpy(ilitek_ini_file_data[g_ini_items].pKeyName, NODE_TYPE_KEY_NAME, strlen(NODE_TYPE_KEY_NAME)+1);
ilitek_ini_file_data[g_ini_items].iKeyValueLen = n;
} else {
/* Get Key names */
ilitek_ini_file_data[g_ini_items].iKeyNameLen = isEqualSign;
if (ilitek_ini_file_data[g_ini_items].iKeyNameLen > PARSER_MAX_KEY_NAME_LEN) {
/* ret = CFG_ERR_OUT_OF_LEN; */
ipio_err("MAX_KEY_NAME_LEN: Out Of Length\n");
res = INI_ERR_OUT_OF_LINE;
goto out;
}
memcpy(ilitek_ini_file_data[g_ini_items].pKeyName,
ini_buf, ilitek_ini_file_data[g_ini_items].iKeyNameLen);
ilitek_ini_file_data[g_ini_items].iKeyValueLen = n - isEqualSign - 1;
}
/* Get a value assigned to a key */
if (ilitek_ini_file_data[g_ini_items].iKeyValueLen > PARSER_MAX_KEY_VALUE_LEN) {
ipio_err("MAX_KEY_VALUE_LEN: Out Of Length\n");
res = INI_ERR_OUT_OF_LINE;
goto out;
}
memcpy(ilitek_ini_file_data[g_ini_items].pKeyValue,
ini_buf + isEqualSign + 1, ilitek_ini_file_data[g_ini_items].iKeyValueLen);
ipio_debug(DEBUG_PARSER, "%s = %s\n", ilitek_ini_file_data[g_ini_items].pKeyName,
ilitek_ini_file_data[g_ini_items].pKeyValue);
g_ini_items++;
}
out:
ipio_kfree((void **)&ini_buf);
ipio_kfree((void **)&tmpSectionName);
return res;
}
static void init_ilitek_ini_data(void)
{
int i;
g_ini_items = 0;
/* Initialise ini strcture */
for (i = 0 ; i < PARSER_MAX_KEY_NUM; i++) {
memset(ilitek_ini_file_data[i].pSectionName, 0, PARSER_MAX_KEY_NAME_LEN);
memset(ilitek_ini_file_data[i].pKeyName, 0, PARSER_MAX_KEY_NAME_LEN);
memset(ilitek_ini_file_data[i].pKeyValue, 0, PARSER_MAX_KEY_VALUE_LEN);
ilitek_ini_file_data[i].iSectionNameLen = 0;
ilitek_ini_file_data[i].iKeyNameLen = 0;
ilitek_ini_file_data[i].iKeyValueLen = 0;
}
}
/* get_ini_key_value - get ini's key and value based on its section from its array
*
* A function is digging into the key and value by its section from the ini array.
* The comparsion is not only a string's name, but its length.
*/
static int get_ini_key_value(char *section, char *key, char *value)
{
int i = 0;
int ret = ERROR;
int len = 0;
len = strlen(key);
for (i = 0 ; i < g_ini_items; i++) {
if (strcmp(section, ilitek_ini_file_data[i].pSectionName) != 0)
continue;
if (strcmp(key, ilitek_ini_file_data[i].pKeyName) == 0) {
memcpy(value, ilitek_ini_file_data[i].pKeyValue, ilitek_ini_file_data[i].iKeyValueLen);
ret = 0;
break;
}
}
return ret;
}
void core_parser_nodetype(int32_t *type_ptr, char *desp)
{
int i = 0, j = 0, index1 = 0, temp, count = 0;
char str[512] = { 0 }, record = ',';
for (i = 0 ; i < g_ini_items; i++) {
if ((strnstr(ilitek_ini_file_data[i].pSectionName, desp, strlen(ilitek_ini_file_data[i].pSectionName)) <= 0) ||
strcmp(ilitek_ini_file_data[i].pKeyName, NODE_TYPE_KEY_NAME) != 0) {
continue;
}
record = ',';
for (j = 0, index1 = 0 ; j <= ilitek_ini_file_data[i].iKeyValueLen ; j++) {
if (ilitek_ini_file_data[i].pKeyValue[j] == ';' || j == ilitek_ini_file_data[i].iKeyValueLen) {
if (record != '.') {
memset(str, 0, sizeof(str));
memcpy(str, &ilitek_ini_file_data[i].pKeyValue[index1], (j - index1));
temp = katoi(str);
type_ptr[count] = temp;
printk("%04d, ", temp);
count++;
}
record = ilitek_ini_file_data[i].pKeyValue[j];
index1 = j+1;
}
}
printk("\n");
}
}
void core_parser_benchmark(int32_t *max_ptr, int32_t *min_ptr, int8_t type, char *desp)
{
int i = 0, j = 0, index1 = 0, temp, count = 0;
char str[512] = { 0 }, record = ',';
int32_t data[4];
for (i = 0 ; i < g_ini_items; i++) {
if ((strnstr(ilitek_ini_file_data[i].pSectionName, desp, strlen(ilitek_ini_file_data[i].pSectionName)) <= 0) ||
strcmp(ilitek_ini_file_data[i].pKeyName, BENCHMARK_KEY_NAME) != 0) {
continue;
}
record = ',';
for (j = 0, index1 = 0 ; j <= ilitek_ini_file_data[i].iKeyValueLen ; j++) {
if (ilitek_ini_file_data[i].pKeyValue[j] == ',' || ilitek_ini_file_data[i].pKeyValue[j] == ';' ||
ilitek_ini_file_data[i].pKeyValue[j] == '.' || j == ilitek_ini_file_data[i].iKeyValueLen) {
if (record != '.') {
memset(str, 0, sizeof(str));
memcpy(str, &ilitek_ini_file_data[i].pKeyValue[index1], (j - index1));
temp = katoi(str);
data[(count % 4)] = temp;
if ((count % 4) == 3) {
if (data[0] == 1) {
if (type == VALUE) {
max_ptr[count/4] = data[1] + data[2];
min_ptr[count/4] = data[1] + data[3];
} else {
max_ptr[count/4] = data[1] + (data[1] * data[2]) / 100;
min_ptr[count/4] = data[1] - (data[1] * data[3]) / 100;
}
} else {
max_ptr[count/4] = INT_MAX;
min_ptr[count/4] = INT_MIN;
}
}
count++;
}
record = ilitek_ini_file_data[i].pKeyValue[j];
index1 = j + 1;
}
}
}
}
EXPORT_SYMBOL(core_parser_benchmark);
int core_parser_get_u8_array(char *key, uint8_t *buf)
{
char *s = key;
char *pToken;
int res, conut = 0;
long s_to_long = 0;
if (isspace_t((int)(unsigned char)*s) == SUCCESS) {
while ((pToken = strsep(&s, ",")) != NULL) {
res = kstrtol(pToken, 0, &s_to_long);
if (res == 0)
buf[conut] = s_to_long;
else
ipio_info("convert string too long, res = %d\n", res);
conut++;
}
}
return conut;
}
EXPORT_SYMBOL(core_parser_get_u8_array);
int core_parser_get_int_data(char *section, char *keyname, char *rv)
{
int len = 0;
char value[512] = { 0 };
if (rv == NULL || section == NULL || keyname == NULL) {
ipio_err("Parameters are invalid\n");
return -EINVAL;
}
/* return a white-space string if get nothing */
if (get_ini_key_value(section, keyname, value) < 0) {
snprintf(rv, sizeof(value), "%s", value);
return 0;
}
len = snprintf(rv, sizeof(value), "%s", value);
printk("section =%s,keyname =%s,value = %s,rv =%s\n", section, keyname, value, rv);//summer
return len;
}
EXPORT_SYMBOL(core_parser_get_int_data);
int core_parser_path(char *path)
{
int res = 0, fsize = 0;
char *tmp = NULL;
struct file *f = NULL;
struct inode *inode;
mm_segment_t old_fs;
loff_t pos = 0;
ipio_info("path = %s\n", path);
f = filp_open(path, O_RDONLY, 0);
if (ERR_ALLOC_MEM(f)) {
ipio_err("Failed to open the file at %ld.\n", PTR_ERR(f));
res = -ENOENT;
return res;
}
#if KERNEL_VERSION(3, 18, 0) >= LINUX_VERSION_CODE
inode = f->f_dentry->d_inode;
#else
inode = f->f_path.dentry->d_inode;
#endif
fsize = inode->i_size;
ipio_info("fsize = %d\n", fsize);
if (fsize <= 0) {
ipio_err("The size of file is invaild\n");
res = -EINVAL;
goto out;
}
tmp = kmalloc(fsize+1, GFP_KERNEL);
if (ERR_ALLOC_MEM(tmp)) {
ipio_err("Failed to allocate tmp memory, %ld\n", PTR_ERR(tmp));
res = -ENOMEM;
goto out;
}
/* ready to map user's memory to obtain data by reading files */
old_fs = get_fs();
set_fs(get_ds());
vfs_read(f, tmp, fsize, &pos);
set_fs(old_fs);
tmp[fsize] = 0x00;
init_ilitek_ini_data();
res = get_ini_phy_data(tmp, fsize);
if (res < 0) {
ipio_err("Failed to get physical ini data, res = %d\n", res);
goto out;
}
ipio_info("Parsing INI file doen\n");
out:
ipio_kfree((void **)&tmp);
filp_close(f, NULL);
return res;
}
EXPORT_SYMBOL(core_parser_path);

View file

@ -0,0 +1,40 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __PARSER_H
#define __PARSER_H
#include "config.h"
#define BENCHMARK_KEY_NAME "Benchmark_Data"
#define NODE_TYPE_KEY_NAME "node_type_Data"
#define TYPE_MARK "[Driver Type Mark]"
#define VALUE 0
extern void core_parser_nodetype(int32_t *type_ptr, char *desp);
extern void core_parser_benchmark(int32_t *max_ptr, int32_t *min_ptr, int8_t type, char *desp);
extern int core_parser_get_u8_array(char *key, uint8_t *buf);
extern int core_parser_get_int_data(char *section, char *keyname, char *rv);
extern int core_parser_path(char *path);
#endif

View file

@ -0,0 +1,414 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common.h"
#include "config.h"
#include "i2c.h"
#include "spi.h"
#include "protocol.h"
#define FUNC_NUM 20
struct protocol_sup_list {
uint8_t major;
uint8_t mid;
uint8_t minor;
};
struct DataItem {
int key;
char *name;
int len;
uint8_t *cmd;
};
struct DataItem *hashArray[FUNC_NUM];
struct protocol_cmd_list *protocol;
int core_write(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize)
{
#if (INTERFACE == I2C_INTERFACE)
return core_i2c_write(nSlaveId, pBuf, nSize);
#else
return core_spi_write(pBuf, nSize);
#endif
}
EXPORT_SYMBOL(core_write);
int core_read(uint8_t nSlaveId, uint8_t *pBuf, uint16_t nSize)
{
#if (INTERFACE == I2C_INTERFACE)
return core_i2c_read(nSlaveId, pBuf, nSize);
#else
return core_spi_read(pBuf, nSize);
#endif
}
EXPORT_SYMBOL(core_read);
static int hashCode(int key)
{
return key % FUNC_NUM;
}
static struct DataItem *search_func(int key)
{
int hashIndex = hashCode(key);
while (hashArray[hashIndex] != NULL) {
if (hashArray[hashIndex]->key == key)
return hashArray[hashIndex];
hashIndex++;
hashIndex %= FUNC_NUM;
}
return NULL;
}
static void insert_func(int key, int len, uint8_t *cmd, char *name)
{
int i, hashIndex;
struct DataItem *tmp = NULL;
tmp = kmalloc(sizeof(struct DataItem), GFP_KERNEL);
if (ERR_ALLOC_MEM(tmp)) {
ipio_err("Failed to allocate memory\n");
return;
}
tmp->key = key;
tmp->name = name;
tmp->len = len;
tmp->cmd = kcalloc(len, sizeof(uint8_t), GFP_KERNEL);
for (i = 0 ; i < len ; i++)
tmp->cmd[i] = cmd[i];
hashIndex = hashCode(key);
while (hashArray[hashIndex] != NULL) {
hashIndex++;
hashIndex %= FUNC_NUM;
}
hashArray[hashIndex] = tmp;
}
static void free_func_hash(void)
{
int i;
for (i = 0 ; i < FUNC_NUM; i++)
ipio_kfree((void **)&hashArray[i]);
}
static void create_func_hash(void)
{
/* if protocol is updated, we free its allocated mem at all before create new ones. */
free_func_hash();
insert_func(0, protocol->func_ctrl_len, protocol->sense_ctrl, "sense_ctrl");
insert_func(1, protocol->func_ctrl_len, protocol->sleep_ctrl, "sleep_ctrl");
insert_func(2, protocol->func_ctrl_len, protocol->glove_ctrl, "glove_ctrl");
insert_func(3, protocol->func_ctrl_len, protocol->stylus_ctrl, "stylus_ctrl");
insert_func(4, protocol->func_ctrl_len, protocol->tp_scan_mode, "tp_scan_mode");
insert_func(5, protocol->func_ctrl_len, protocol->lpwg_ctrl, "lpwg_ctrl");
insert_func(6, protocol->func_ctrl_len, protocol->gesture_ctrl, "gesture_ctrl");
insert_func(7, protocol->func_ctrl_len, protocol->phone_cover_ctrl, "phone_cover_ctrl");
insert_func(8, protocol->func_ctrl_len, protocol->finger_sense_ctrl, "finger_sense_ctrl");
insert_func(9, protocol->window_len, protocol->phone_cover_window, "phone_cover_window");
insert_func(10, protocol->func_ctrl_len, protocol->finger_sense_ctrl, "finger_sense_ctrl");
insert_func(11, protocol->func_ctrl_len, protocol->proximity_ctrl, "proximity_ctrl");
insert_func(12, protocol->func_ctrl_len, protocol->plug_ctrl, "plug_ctrl");
}
static void config_protocol_v5_cmd(void)
{
if (protocol->mid == 0x0) {
protocol->func_ctrl_len = 2;
protocol->sense_ctrl[0] = 0x1;
protocol->sense_ctrl[1] = 0x0;
protocol->sleep_ctrl[0] = 0x2;
protocol->sleep_ctrl[1] = 0x0;
protocol->glove_ctrl[0] = 0x6;
protocol->glove_ctrl[1] = 0x0;
protocol->stylus_ctrl[0] = 0x7;
protocol->stylus_ctrl[1] = 0x0;
protocol->tp_scan_mode[0] = 0x8;
protocol->tp_scan_mode[1] = 0x0;
protocol->lpwg_ctrl[0] = 0xA;
protocol->lpwg_ctrl[1] = 0x0;
protocol->gesture_ctrl[0] = 0xB;
protocol->gesture_ctrl[1] = 0x3F;
protocol->phone_cover_ctrl[0] = 0xC;
protocol->phone_cover_ctrl[1] = 0x0;
protocol->finger_sense_ctrl[0] = 0xF;
protocol->finger_sense_ctrl[1] = 0x0;
protocol->phone_cover_window[0] = 0xD;
/* Non support on v5.0 */
/* protocol->proximity_ctrl[0] = 0x10; */
/* protocol->proximity_ctrl[1] = 0x0; */
/* protocol->plug_ctrl[0] = 0x11; */
/* protocol->plug_ctrl[1] = 0x0; */
} else {
protocol->func_ctrl_len = 3;
protocol->sense_ctrl[0] = 0x1;
protocol->sense_ctrl[1] = 0x1;
protocol->sense_ctrl[2] = 0x0;
protocol->sleep_ctrl[0] = 0x1;
protocol->sleep_ctrl[1] = 0x2;
protocol->sleep_ctrl[2] = 0x0;
protocol->glove_ctrl[0] = 0x1;
protocol->glove_ctrl[1] = 0x6;
protocol->glove_ctrl[2] = 0x0;
protocol->stylus_ctrl[0] = 0x1;
protocol->stylus_ctrl[1] = 0x7;
protocol->stylus_ctrl[2] = 0x0;
protocol->tp_scan_mode[0] = 0x1;
protocol->tp_scan_mode[1] = 0x8;
protocol->tp_scan_mode[2] = 0x0;
protocol->lpwg_ctrl[0] = 0x1;
protocol->lpwg_ctrl[1] = 0xA;
protocol->lpwg_ctrl[2] = 0x0;
protocol->gesture_ctrl[0] = 0x1;
protocol->gesture_ctrl[1] = 0xB;
protocol->gesture_ctrl[2] = 0x3F;
protocol->phone_cover_ctrl[0] = 0x1;
protocol->phone_cover_ctrl[1] = 0xC;
protocol->phone_cover_ctrl[2] = 0x0;
protocol->finger_sense_ctrl[0] = 0x1;
protocol->finger_sense_ctrl[1] = 0xF;
protocol->finger_sense_ctrl[2] = 0x0;
protocol->proximity_ctrl[0] = 0x1;
protocol->proximity_ctrl[1] = 0x10;
protocol->proximity_ctrl[2] = 0x0;
protocol->plug_ctrl[0] = 0x1;
protocol->plug_ctrl[1] = 0x11;
protocol->plug_ctrl[2] = 0x0;
protocol->phone_cover_window[0] = 0xE;
}
if (protocol->mid >= 0x3)
protocol->fw_ver_len = 9;
else
protocol->fw_ver_len = 4;
if (protocol->mid == 0x1) {
protocol->pro_ver_len = 3;
} else {
protocol->pro_ver_len = 4;
}
protocol->tp_info_len = 14;
protocol->key_info_len = 30;
protocol->core_ver_len = 5;
protocol->window_len = 8;
/* The commadns about panel information */
protocol->cmd_read_ctrl = P5_0_READ_DATA_CTRL;
protocol->cmd_get_tp_info = P5_0_GET_TP_INFORMATION;
protocol->cmd_get_key_info = P5_0_GET_KEY_INFORMATION;
protocol->cmd_get_fw_ver = P5_0_GET_FIRMWARE_VERSION;
protocol->cmd_get_pro_ver = P5_0_GET_PROTOCOL_VERSION;
protocol->cmd_get_core_ver = P5_0_GET_CORE_VERSION;
protocol->cmd_mode_ctrl = P5_0_MODE_CONTROL;
protocol->cmd_cdc_busy = P5_0_CDC_BUSY_STATE;
protocol->cmd_i2cuart = P5_0_I2C_UART;
/* The commands about the packets of finger report from FW */
protocol->unknown_mode = P5_0_FIRMWARE_UNKNOWN_MODE;
protocol->demo_mode = P5_0_FIRMWARE_DEMO_MODE;
protocol->debug_mode = P5_0_FIRMWARE_DEBUG_MODE;
protocol->test_mode = P5_0_FIRMWARE_TEST_MODE;
protocol->i2cuart_mode = P5_0_FIRMWARE_I2CUART_MODE;
protocol->gesture_mode = P5_0_FIRMWARE_GESTURE_MODE;
protocol->demo_pid = P5_0_DEMO_PACKET_ID;
protocol->debug_pid = P5_0_DEBUG_PACKET_ID;
protocol->test_pid = P5_0_TEST_PACKET_ID;
protocol->i2cuart_pid = P5_0_I2CUART_PACKET_ID;
protocol->ges_pid = P5_0_GESTURE_PACKET_ID;
protocol->demo_len = P5_0_DEMO_MODE_PACKET_LENGTH;
protocol->debug_len = P5_0_DEBUG_MODE_PACKET_LENGTH;
protocol->test_len = P5_0_TEST_MODE_PACKET_LENGTH;
/* The commands about MP test */
protocol->cmd_cdc = P5_0_SET_CDC_INIT;
protocol->cmd_get_cdc = P5_0_GET_CDC_DATA;
if (protocol->mid < 4) {
protocol->cdc_len = 3;
} else {
protocol->cdc_len = 15;
}
protocol->mutual_dac = 0x1;
protocol->mutual_bg = 0x2;
protocol->mutual_signal = 0x3;
protocol->mutual_no_bk = 0x5;
protocol->mutual_has_bk = 0x8;
protocol->mutual_bk_dac = 0x10;
protocol->self_dac = 0xC;
protocol->self_bg = 0xF;
protocol->self_signal = 0xD;
protocol->self_no_bk = 0xE;
protocol->self_has_bk = 0xB;
protocol->self_bk_dac = 0x11;
protocol->key_dac = 0x14;
protocol->key_bg = 0x16;
protocol->key_no_bk = 0x7;
protocol->key_has_bk = 0x15;
protocol->key_open = 0x12;
protocol->key_short = 0x13;
protocol->st_dac = 0x1A;
protocol->st_bg = 0x1C;
protocol->st_no_bk = 0x17;
protocol->st_has_bk = 0x1B;
protocol->st_open = 0x18;
protocol->tx_short = 0x19;
protocol->rx_short = 0x4;
protocol->rx_open = 0x6;
protocol->tx_rx_delta = 0x1E;
protocol->cm_data = 0x9;
protocol->cs_data = 0xA;
protocol->trcrq_pin = 0x20;
protocol->resx2_pin = 0x21;
protocol->mutual_integra_time = 0x22;
protocol->self_integra_time = 0x23;
protocol->key_integra_time = 0x24;
protocol->st_integra_time = 0x25;
protocol->peak_to_peak = 0x1D;
protocol->get_timing = 0x30;
protocol->doze_p2p = 0x32;
protocol->doze_raw = 0x33;
}
void core_protocol_func_control(int key, int ctrl)
{
struct DataItem *tmp = search_func(key);
if (tmp != NULL) {
ipio_info("Found func's name: %s, key = %d\n", tmp->name, key);
/* last element is used to control this func */
if (tmp->key != 9)
tmp->cmd[tmp->len - 1] = ctrl;
core_write(core_config->slave_i2c_addr, tmp->cmd, tmp->len);
return;
}
ipio_info("Can't find any main functions\n");
}
EXPORT_SYMBOL(core_protocol_func_control);
int core_protocol_update_ver(uint8_t major, uint8_t mid, uint8_t minor)
{
int i = 0;
struct protocol_sup_list pver[] = {
{0x5, 0x0, 0x0},
{0x5, 0x1, 0x0},
{0x5, 0x2, 0x0},
{0x5, 0x3, 0x0},
{0x5, 0x4, 0x0},
};
for (i = 0 ; i < ARRAY_SIZE(pver); i++) {
if (pver[i].major == major && pver[i].mid == mid && pver[i].minor == minor) {
protocol->major = major;
protocol->mid = mid;
protocol->minor = minor;
ipio_info("protocol: major = %d, mid = %d, minor = %d\n",
protocol->major, protocol->mid, protocol->minor);
if (protocol->major == 0x5)
config_protocol_v5_cmd();
/* We need to recreate function controls because of the commands updated. */
create_func_hash();
return 0;
}
}
ipio_err("Doesn't support this version of protocol\n");
return ERROR;
}
EXPORT_SYMBOL(core_protocol_update_ver);
int core_protocol_init(void)
{
if (protocol == NULL) {
protocol = kzalloc(sizeof(*protocol), GFP_KERNEL);
if (ERR_ALLOC_MEM(protocol)) {
ipio_err("Failed to allocate protocol mem, %ld\n", PTR_ERR(protocol));
core_protocol_remove();
return -ENOMEM;
}
}
/* The default version must only once be set up at this initial time. */
core_protocol_update_ver(PROTOCOL_MAJOR, PROTOCOL_MID, PROTOCOL_MINOR);
return 0;
}
EXPORT_SYMBOL(core_protocol_init);
void core_protocol_remove(void)
{
ipio_info("Remove core-protocol memebers\n");
ipio_kfree((void **)&protocol);
free_func_hash();
}
EXPORT_SYMBOL(core_protocol_remove);

View file

@ -0,0 +1,189 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __PROTOCOL_H
#define __PROTOCOL_H
/* V3.2 */
#define P3_2_GET_TP_INFORMATION 0x20
#define P3_2_GET_KEY_INFORMATION 0x22
#define P3_2_GET_FIRMWARE_VERSION 0x40
#define P3_2_GET_PROTOCOL_VERSION 0x42
/* V5.X */
#define P5_0_READ_DATA_CTRL 0xF6
#define P5_0_GET_TP_INFORMATION 0x20
#define P5_0_GET_KEY_INFORMATION 0x27
#define P5_0_GET_FIRMWARE_VERSION 0x21
#define P5_0_GET_PROTOCOL_VERSION 0x22
#define P5_0_GET_CORE_VERSION 0x23
#define P5_0_MODE_CONTROL 0xF0
#define P5_0_SET_CDC_INIT 0xF1
#define P5_0_GET_CDC_DATA 0xF2
#define P5_0_CDC_BUSY_STATE 0xF3
#define P5_0_I2C_UART 0x40
#define P5_0_FIRMWARE_UNKNOWN_MODE 0xFF
#define P5_0_FIRMWARE_DEMO_MODE 0x00
#define P5_0_FIRMWARE_TEST_MODE 0x01
#define P5_0_FIRMWARE_DEBUG_MODE 0x02
#define P5_0_FIRMWARE_I2CUART_MODE 0x03
#define P5_0_FIRMWARE_GESTURE_MODE 0x04
#define P5_0_DEMO_PACKET_ID 0x5A
#define P5_0_DEBUG_PACKET_ID 0xA7
#define P5_0_TEST_PACKET_ID 0xF2
#define P5_0_GESTURE_PACKET_ID 0xAA
#define P5_0_I2CUART_PACKET_ID 0x7A
#define P5_0_DEMO_MODE_PACKET_LENGTH 43
#define P5_0_DEBUG_MODE_PACKET_LENGTH 1280
#define P5_0_TEST_MODE_PACKET_LENGTH 1180
struct protocol_cmd_list {
/* version of protocol */
uint8_t major;
uint8_t mid;
uint8_t minor;
/* Length of command */
int fw_ver_len;
int pro_ver_len;
int tp_info_len;
int key_info_len;
int core_ver_len;
int func_ctrl_len;
int window_len;
int cdc_len;
int cdc_raw_len;
/* TP information */
uint8_t cmd_read_ctrl;
uint8_t cmd_get_tp_info;
uint8_t cmd_get_key_info;
uint8_t cmd_get_fw_ver;
uint8_t cmd_get_pro_ver;
uint8_t cmd_get_core_ver;
uint8_t cmd_mode_ctrl;
uint8_t cmd_i2cuart;
uint8_t cmd_cdc_busy;
/* Function control */
uint8_t sense_ctrl[3];
uint8_t sleep_ctrl[3];
uint8_t glove_ctrl[3];
uint8_t stylus_ctrl[3];
uint8_t tp_scan_mode[3];
uint8_t lpwg_ctrl[3];
uint8_t gesture_ctrl[3];
uint8_t phone_cover_ctrl[3];
uint8_t finger_sense_ctrl[3];
uint8_t proximity_ctrl[3];
uint8_t plug_ctrl[3];
uint8_t phone_cover_window[9];
/* firmware mode */
uint8_t unknown_mode;
uint8_t demo_mode;
uint8_t debug_mode;
uint8_t test_mode;
uint8_t i2cuart_mode;
uint8_t gesture_mode;
/* Pakcet ID reported by FW */
uint8_t demo_pid;
uint8_t debug_pid;
uint8_t i2cuart_pid;
uint8_t test_pid;
uint8_t ges_pid;
/* Length of finger report */
int demo_len;
int debug_len;
int test_len;
int gesture_len;
/* MP Test with cdc commands */
uint8_t cmd_cdc;
uint8_t cmd_get_cdc;
uint8_t cm_data;
uint8_t cs_data;
uint8_t rx_short;
uint8_t rx_open;
uint8_t tx_short;
uint8_t mutual_dac;
uint8_t mutual_bg;
uint8_t mutual_signal;
uint8_t mutual_no_bk;
uint8_t mutual_bk_dac;
uint8_t mutual_has_bk;
uint16_t mutual_has_bk_16;
uint8_t self_dac;
uint8_t self_bk_dac;
uint8_t self_has_bk;
uint8_t self_no_bk;
uint8_t self_signal;
uint8_t self_bg;
uint8_t key_dac;
uint8_t key_has_bk;
uint8_t key_bg;
uint8_t key_no_bk;
uint8_t key_open;
uint8_t key_short;
uint8_t st_no_bk;
uint8_t st_open;
uint8_t st_dac;
uint8_t st_has_bk;
uint8_t st_bg;
uint8_t tx_rx_delta;
uint8_t trcrq_pin;
uint8_t resx2_pin;
uint8_t mutual_integra_time;
uint8_t self_integra_time;
uint8_t key_integra_time;
uint8_t st_integra_time;
uint8_t peak_to_peak;
uint8_t get_timing;
uint8_t doze_p2p;
uint8_t doze_raw;
};
extern struct protocol_cmd_list *protocol;
extern void core_protocol_func_control(int key, int ctrl);
extern int core_protocol_update_ver(uint8_t major, uint8_t mid, uint8_t minor);
extern int core_protocol_init(void);
extern void core_protocol_remove(void);
extern int core_write(uint8_t, uint8_t *, uint16_t);
extern int core_read(uint8_t, uint8_t *, uint16_t);
#endif

View file

@ -0,0 +1,412 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "../common.h"
#include "config.h"
#include "spi.h"
#include "finger_report.h"
struct core_spi_data *core_spi;
int core_Rx_check(uint16_t check)
{
int size = 0, i, count = 100;
uint8_t txbuf[5] = { 0 }, rxbuf[4] = {0};
uint16_t status = 0;
txbuf[0] = SPI_WRITE;
txbuf[1] = 0x25;
txbuf[2] = 0x94;
txbuf[3] = 0x0;
txbuf[4] = 0x2;
for (i = 0 ; i < count; i++) {
txbuf[0] = SPI_WRITE;
if (spi_write_then_read(core_spi->spi, txbuf, 5, txbuf, 0) < 0) {
size = -EIO;
ipio_err("spi Write Error, res = %d\n", size);
}
txbuf[0] = SPI_READ;
if (spi_write_then_read(core_spi->spi, txbuf, 1, rxbuf, 4) < 0) {
size = -EIO;
ipio_err("spi Read Error, res = %d\n", size);
}
status = (rxbuf[2] << 8) + rxbuf[3];
size = (rxbuf[0] << 8) + rxbuf[1];
if (status == check)
return size;
mdelay(1);
}
size = -EIO;
ipio_err("Check lock error\n");
return size;
}
int core_Tx_unlock_check(void)
{
int res = 0, i, count = 100;
uint8_t txbuf[5] = { 0 }, rxbuf[4] = {0};
uint16_t unlock = 0;
txbuf[0] = SPI_WRITE;
txbuf[1] = 0x25;
txbuf[2] = 0x0;
txbuf[3] = 0x0;
txbuf[4] = 0x2;
for (i = 0; i < count; i++) {
txbuf[0] = SPI_WRITE;
if (spi_write_then_read(core_spi->spi, txbuf, 5, txbuf, 0) < 0) {
res = -EIO;
ipio_err("spi Write Error, res = %d\n", res);
}
txbuf[0] = SPI_READ;
if (spi_write_then_read(core_spi->spi, txbuf, 1, rxbuf, 4) < 0) {
res = -EIO;
ipio_err("spi Read Error, res = %d\n", res);
}
unlock = (rxbuf[2] << 8) + rxbuf[3];
if (unlock == 0x9881)
return res;
mdelay(1);
}
ipio_err("Check unlock error\n");
return res;
}
int core_ice_mode_read_9881H11(uint8_t *data, uint32_t size)
{
int res = 0;
uint8_t txbuf[64] = { 0 };
/* set read address */
txbuf[0] = SPI_WRITE;
txbuf[1] = 0x25;
txbuf[2] = 0x98;
txbuf[3] = 0x0;
txbuf[4] = 0x2;
if (spi_write_then_read(core_spi->spi, txbuf, 5, txbuf, 0) < 0) {
res = -EIO;
return res;
}
/* read data */
txbuf[0] = SPI_READ;
if (spi_write_then_read(core_spi->spi, txbuf, 1, data, size) < 0) {
res = -EIO;
return res;
}
/* write data unlock */
txbuf[0] = SPI_WRITE;
txbuf[1] = 0x25;
txbuf[2] = 0x94;
txbuf[3] = 0x0;
txbuf[4] = 0x2;
txbuf[5] = (size & 0xFF00) >> 8;
txbuf[6] = size & 0xFF;
txbuf[7] = (char)0x98;
txbuf[8] = (char)0x81;
if (spi_write_then_read(core_spi->spi, txbuf, 9, txbuf, 0) < 0) {
res = -EIO;
ipio_err("spi Write data unlock error, res = %d\n", res);
}
return res;
}
int core_ice_mode_write_9881H11(uint8_t *data, uint32_t size)
{
int res = 0;
uint8_t check_sum = 0, wsize = 0;
uint8_t *txbuf = NULL;
txbuf = kcalloc(size + 9, sizeof(uint8_t), GFP_KERNEL);
if (ERR_ALLOC_MEM(txbuf)) {
ipio_err("Failed to allocate txbuf\n");
res = -ENOMEM;
goto out;
}
/* Write data */
txbuf[0] = SPI_WRITE;
txbuf[1] = 0x25;
txbuf[2] = 0x4;
txbuf[3] = 0x0;
txbuf[4] = 0x2;
/* Calcuate checsum and fill it in the last byte */
check_sum = core_fr_calc_checksum(data, size);
memcpy(txbuf + 5, data, size);
txbuf[5 + size] = check_sum;
size++;
wsize = size;
if (wsize % 4 != 0)
wsize += 4 - (wsize % 4);
if (spi_write_then_read(core_spi->spi, txbuf, wsize + 5, txbuf, 0) < 0) {
res = -EIO;
ipio_err("spi Write Error, res = %d\n", res);
goto out;
}
/* write data lock */
txbuf[0] = SPI_WRITE;
txbuf[1] = 0x25;
txbuf[2] = 0x0;
txbuf[3] = 0x0;
txbuf[4] = 0x2;
txbuf[5] = (size & 0xFF00) >> 8;
txbuf[6] = size & 0xFF;
txbuf[7] = (char)0x5A;
txbuf[8] = (char)0xA5;
if (spi_write_then_read(core_spi->spi, txbuf, 9, txbuf, 0) < 0) {
res = -EIO;
ipio_err("spi Write data lock Error, res = %d\n", res);
}
out:
ipio_kfree((void **)&txbuf);
return res;
}
int core_ice_mode_disable_9881H11(void)
{
int res = 0;
uint8_t txbuf[5] = {0};
txbuf[0] = 0x82;
txbuf[1] = 0x1B;
txbuf[2] = 0x62;
txbuf[3] = 0x10;
txbuf[4] = 0x18;
if (spi_write_then_read(core_spi->spi, txbuf, 5, txbuf, 0) < 0) {
res = -EIO;
ipio_err("spi_write_then_read Error, res = %d\n", res);
}
return res;
}
int core_ice_mode_enable_9881H11(void)
{
int res = 0;
uint8_t txbuf[5] = {0}, rxbuf[2] = {0};
txbuf[0] = 0x82;
txbuf[1] = 0x1F;
txbuf[2] = 0x62;
txbuf[3] = 0x10;
txbuf[4] = 0x18;
if (spi_write_then_read(core_spi->spi, txbuf, 1, rxbuf, 1) < 0) {
res = -EIO;
ipio_err("spi Write Error, res = %d\n", res);
return res;
}
/* check recover data */
if (rxbuf[0] == 0x82) {
ipio_info("rxbuf:0x%x\n", rxbuf[0]);
return CHECK_RECOVER;
}
if (spi_write_then_read(core_spi->spi, txbuf, 5, rxbuf, 0) < 0) {
res = -EIO;
ipio_err("spi Write Error, res = %d\n", res);
}
return res;
}
int core_spi_read_9881H11(uint8_t *pBuf, uint16_t nSize)
{
int res = 0, size = 0;
res = core_ice_mode_enable_9881H11();
if (res < 0) {
goto out;
}
size = core_Rx_check(0x5AA5);
if (size < 0) {
res = -EIO;
goto out;
}
if (core_ice_mode_read_9881H11(pBuf, size) < 0) {
res = -EIO;
goto out;
}
if (core_ice_mode_disable_9881H11() < 0) {
res = -EIO;
goto out;
}
out:
return res;
}
int core_spi_write_9881H11(uint8_t *pBuf, uint16_t nSize)
{
int res = 0;
uint8_t *txbuf = NULL;
txbuf = kcalloc(nSize + 5, sizeof(uint8_t), GFP_KERNEL);
if (ERR_ALLOC_MEM(txbuf)) {
ipio_err("Failed to allocate txbuf\n");
return -ENOMEM;
goto out;
}
res = core_ice_mode_enable_9881H11();
if (res < 0)
return res;
if (core_ice_mode_write_9881H11(pBuf, nSize) < 0) {
res = -EIO;
goto out;
}
if (core_Tx_unlock_check() < 0) {
res = -ETXTBSY;
}
out:
ipio_kfree((void **)&txbuf);
return res;
}
int core_spi_write(uint8_t *pBuf, uint16_t nSize)
{
int res = 0;
uint8_t *txbuf = NULL;
txbuf = kcalloc(nSize + 1, sizeof(uint8_t), GFP_KERNEL);
if (ERR_ALLOC_MEM(txbuf)) {
ipio_err("Failed to allocate txbuf\n");
return -ENOMEM;
goto out;
}
if (core_config->icemodeenable == false) {
res = core_spi_write_9881H11(pBuf, nSize);
core_ice_mode_disable_9881H11();
ipio_kfree((void **)&txbuf);
return res;
}
txbuf[0] = SPI_WRITE;
memcpy(txbuf+1, pBuf, nSize);
if (spi_write_then_read(core_spi->spi, txbuf, nSize+1, txbuf, 0) < 0) {
if (core_config->do_ic_reset) {
/* ignore spi error if doing ic reset */
res = 0;
} else {
res = -EIO;
ipio_err("spi Write Error, res = %d\n", res);
goto out;
}
}
out:
ipio_kfree((void **)&txbuf);
return res;
}
EXPORT_SYMBOL(core_spi_write);
int core_spi_read(uint8_t *pBuf, uint16_t nSize)
{
int res = 0;
uint8_t txbuf[1] = {0};
txbuf[0] = SPI_READ;
if (core_config->icemodeenable == false)
return core_spi_read_9881H11(pBuf, nSize);
if (spi_write_then_read(core_spi->spi, txbuf, 1, pBuf, nSize) < 0) {
if (core_config->do_ic_reset) {
/* ignore spi error if doing ic reset */
res = 0;
} else {
res = -EIO;
ipio_err("spi Read Error, res = %d\n", res);
goto out;
}
}
out:
return res;
}
EXPORT_SYMBOL(core_spi_read);
int core_spi_init(struct spi_device *spi)
{
int ret;
core_spi = kmalloc(sizeof(*core_spi), GFP_KERNEL);
if (ERR_ALLOC_MEM(core_spi)) {
ipio_err("Failed to alllocate core_i2c mem %ld\n", PTR_ERR(core_spi));
core_spi_remove();
return -ENOMEM;
}
core_spi->spi = spi;
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0) {
ipio_err("ERR: fail to setup spi\n");
return -ENODEV;
}
ipio_info("name = %s, bus_num = %d,cs = %d, mode = %d, speed = %d\n", spi->modalias,
spi->master->bus_num, spi->chip_select, spi->mode, spi->max_speed_hz);
return 0;
}
EXPORT_SYMBOL(core_spi_init);
void core_spi_remove(void)
{
ipio_info("Remove core-spi members\n");
ipio_kfree((void **)&core_spi);
}
EXPORT_SYMBOL(core_spi_remove);

View file

@ -0,0 +1,42 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __SPI_H
#define __SPI_H
#define SPI_WRITE 0X82
#define SPI_READ 0X83
struct core_spi_data {
struct spi_device *spi;
};
extern struct core_spi_data *core_spi;
extern int core_spi_write(uint8_t *pBuf, uint16_t nSize);
extern int core_spi_read(uint8_t *pBuf, uint16_t nSize);
extern int core_spi_init(struct spi_device *spi);
extern void core_spi_remove(void);
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,128 @@
/*
* ILITEK Touch IC driver
*
* Copyright (C) 2011 ILI Technology Corporation.
*
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
* Based on TDD v7.0 implemented by Mstar & ILITEK
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __PLATFORM_H
#define __PLATFORM_H
struct ilitek_platform_data {
struct i2c_client *client;
struct input_dev *input_device;
const struct i2c_device_id *i2c_id;
struct regulator *vdd;
struct regulator *vdd_i2c;
struct mutex plat_mutex;
spinlock_t plat_spinlock;
uint32_t chip_id;
int int_gpio;
int reset_gpio;
int isr_gpio;
int delay_time_high;
int delay_time_low;
int edge_delay;
bool isEnableIRQ;
bool isEnablePollCheckPower;
#ifdef USE_KTHREAD
struct task_struct *irq_thread;
bool irq_trigger;
bool free_irq_thread;
#else
struct work_struct report_work_queue;
#endif
#ifdef CONFIG_FB
struct notifier_block notifier_fb;
#else
struct early_suspend early_suspend;
#endif
#ifdef BOOT_FW_UPGRADE
struct task_struct *update_thread;
#endif
/* obtain msg when battery status has changed */
struct delayed_work check_power_status_work;
struct workqueue_struct *check_power_status_queue;
unsigned long work_delay;
bool vpower_reg_nb;
/* Sending report data to users for the debug */
bool debug_node_open;
int debug_data_frame;
wait_queue_head_t inq;
unsigned char debug_buf[1024][2048];
struct mutex ilitek_debug_mutex;
struct mutex ilitek_debug_read_mutex;
struct spi_device *spi;
bool suspended;
const char *TP_IC_TYPE;
bool MT_B_TYPE;
bool REGULATOR_POWER_ON;
bool BATTERY_CHECK;
bool ENABLE_BATTERY_CHECK;
u32 x_max;
u32 y_max;
u32 x_min;
u32 y_min;
bool x_flip;
bool y_flip;
int TPD_WIDTH;
int TPD_HEIGHT;
int MAX_TOUCH_NUM;
};
extern struct ilitek_platform_data *ipd;
extern struct tpd_device *tpd;
/* exported from platform.c */
extern void ilitek_platform_disable_irq(void);
extern void ilitek_platform_enable_irq(void);
extern int ilitek_platform_read_tp_info(void);
extern void ilitek_platform_tp_hw_reset(bool isEnable);
#ifdef ENABLE_REGULATOR_POWER_ON
extern void ilitek_regulator_power_on(bool status);
#endif
/* exported from userspsace.c */
extern void netlink_reply_msg(void *raw, int size);
extern int ilitek_proc_init(void);
extern void ilitek_proc_remove(void);
extern int ilitek_sys_init(void);
extern void ilitek_sys_remove(void);
#endif /* __PLATFORM_H */

File diff suppressed because it is too large Load diff