mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-07 20:33:58 -04:00
guam: input add touch ilitek support
input add touch ilitek support NO_PROP_NEEDED:only for guam/guamp/guamna Change-Id: I7cd9be63ad90f6c67d8df810799308b5a9fa7b26 Signed-off-by: dengwei1 <dengwei1@motorola.com> Reviewed-on: https://gerrit.mot.com/1702165 SME-Granted: SME Approvals Granted SLTApproved: Slta Waiver Tested-by: Jira Key Reviewed-by: Xiangpo Zhao <zhaoxp3@motorola.com> Submit-Approved: Jira Key
This commit is contained in:
parent
f0353502be
commit
69aa47a468
16 changed files with 15825 additions and 0 deletions
20
drivers/input/touchscreen/ili9882_mmi/Android.mk
Normal file
20
drivers/input/touchscreen/ili9882_mmi/Android.mk
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
DLKM_DIR := motorola/kernel/modules
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
ifneq ($(BOARD_USES_DOUBLE_TAP),)
|
||||
KERNEL_CFLAGS += CONFIG_INPUT_ILI_0FLASH_MMI_ENABLE_DOUBLE_TAP=y
|
||||
endif
|
||||
|
||||
ifneq ($(BOARD_USES_PANEL_NOTIFICATIONS),)
|
||||
KERNEL_CFLAGS += CONFIG_INPUT_ILI_PANEL_NOTIFICATIONS=y
|
||||
endif
|
||||
|
||||
ifneq ($(DL_FW_BY_DISPLAY),)
|
||||
KERNEL_CFLAGS += CONFIG_ILITEK_RESUME_BY_DDI=y
|
||||
endif
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := ili9882_mmi.ko
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT)
|
||||
include $(DLKM_DIR)/AndroidKernelModule.mk
|
||||
28
drivers/input/touchscreen/ili9882_mmi/Kbuild
Normal file
28
drivers/input/touchscreen/ili9882_mmi/Kbuild
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
# 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/ili9882_mmi \
|
||||
-I$(TOP)/motorola/kernel/modules/drivers/input/touchscreen/ili9882_mmi/firmware
|
||||
|
||||
ifeq ($(filter m y, $(CONFIG_TOUCHSCREEN_ILITEK_CHIPSET)),)
|
||||
obj-m += ili9882_mmi.o
|
||||
endif
|
||||
|
||||
ifneq ($(filter m y,$(CONFIG_INPUT_ILI_0FLASH_MMI_ENABLE_DOUBLE_TAP)),)
|
||||
EXTRA_CFLAGS += -DILI_SENSOR_EN
|
||||
endif
|
||||
ifneq ($(filter m y,$(CONFIG_INPUT_ILI_PANEL_NOTIFICATIONS)),)
|
||||
EXTRA_CFLAGS += -DILI_CONFIG_PANEL_NOTIFICATIONS
|
||||
endif
|
||||
ifneq ($(filter m y,$(CONFIG_ILITEK_RESUME_BY_DDI)),)
|
||||
EXTRA_CFLAGS += -DILI_CONFIG_RESUME_BY_DDI
|
||||
endif
|
||||
|
||||
ili9882_mmi-objs += ili9882.o
|
||||
ili9882_mmi-objs += ili9882_spi.o
|
||||
ili9882_mmi-objs += ili9882_qcom.o
|
||||
ili9882_mmi-objs += ili9882_ic.o
|
||||
ili9882_mmi-objs += ili9882_touch.o
|
||||
ili9882_mmi-objs += ili9882_mp.o
|
||||
ili9882_mmi-objs += ili9882_hostdl.o
|
||||
ili9882_mmi-objs += ili9882_node.o
|
||||
10
drivers/input/touchscreen/ili9882_mmi/Makefile
Normal file
10
drivers/input/touchscreen/ili9882_mmi/Makefile
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
KERNEL_SRC ?= /lib/modules/$(shell uname -r)/build
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(shell pwd) modules $(KBUILD_OPTIONS)
|
||||
|
||||
modules_install:
|
||||
$(MAKE) INSTALL_MOD_STRIP=1 -C $(KERNEL_SRC) M=$(shell pwd) modules_install
|
||||
|
||||
clean:
|
||||
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) clean
|
||||
97
drivers/input/touchscreen/ili9882_mmi/firmware/ili9882_fw.h
Executable file
97
drivers/input/touchscreen/ili9882_mmi/firmware/ili9882_fw.h
Executable file
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* ILITEK Touch IC driver
|
||||
*
|
||||
* Copyright (C) 2011 ILI Technology Corporation.
|
||||
*
|
||||
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 __ILI9881X_FW_H
|
||||
#define __ILI9881X_FW_H
|
||||
|
||||
/* define names and paths for the variety of tp modules */
|
||||
#define DEF_INI_NAME_PATH "/sdcard/mp.ini"
|
||||
#define DEF_FW_FILP_PATH "/sdcard/ILITEK_FW"
|
||||
#define DEF_INI_REQUEST_PATH "mp.ini"
|
||||
#define DEF_FW_REQUEST_PATH "ilitek_fw.bin"
|
||||
static unsigned char CTPM_FW_DEF[] = {
|
||||
};
|
||||
|
||||
#define CSOT_INI_NAME_PATH "/sdcard/mp_csot.ini"
|
||||
#define CSOT_FW_FILP_PATH "/sdcard/ILITEK_FW_CSOT"
|
||||
#define CSOT_INI_REQUEST_PATH "mp_csot.ini"
|
||||
#define CSOT_FW_REQUEST_PATH "ILITEK_FW_CSOT"
|
||||
static unsigned char CTPM_FW_CSOT[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define AUO_INI_NAME_PATH "/sdcard/mp_auo.ini"
|
||||
#define AUO_FW_FILP_PATH "/sdcard/ILITEK_FW_AUO"
|
||||
#define AUO_INI_REQUEST_PATH "mp_auo.ini"
|
||||
#define AUO_FW_REQUEST_PATH "ILITEK_FW_AUO"
|
||||
static unsigned char CTPM_FW_AUO[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define BOE_INI_NAME_PATH "/sdcard/mp_boe.ini"
|
||||
#define BOE_FW_FILP_PATH "/sdcard/ILITEK_FW_BOE"
|
||||
#define BOE_INI_REQUEST_PATH "mp_boe.ini"
|
||||
#define BOE_FW_REQUEST_PATH "ILITEK_FW_BOE"
|
||||
static unsigned char CTPM_FW_BOE[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define INX_INI_NAME_PATH "/sdcard/mp_inx.ini"
|
||||
#define INX_FW_FILP_PATH "/sdcard/ILITEK_FW_INX"
|
||||
#define INX_INI_REQUEST_PATH "mp_inx.ini"
|
||||
#define INX_FW_REQUEST_PATH "ILITEK_FW_INX"
|
||||
static unsigned char CTPM_FW_INX[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define DJ_INI_NAME_PATH "/sdcard/mp_dj.ini"
|
||||
#define DJ_FW_FILP_PATH "/sdcard/ILITEK_FW_DJ"
|
||||
#define DJ_INI_REQUEST_PATH "mp_dj.ini"
|
||||
#define DJ_FW_REQUEST_PATH "ILITEK_FW_DJ"
|
||||
static unsigned char CTPM_FW_DJ[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define TXD_INI_NAME_PATH "/sdcard/mp_txd.ini"
|
||||
#define TXD_FW_FILP_PATH "/sdcard/ILITEK_FW_TXD"
|
||||
#define TXD_INI_REQUEST_PATH "mp_txd.ini"
|
||||
#define TXD_FW_REQUEST_PATH "ILITEK_FW_TXD"
|
||||
static unsigned char CTPM_FW_TXD[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define TM_INI_NAME_PATH "/sdcard/mp_tm.ini"
|
||||
#define TM_FW_FILP_PATH "/sdcard/ILITEK_FW_TM"
|
||||
#define TM_INI_REQUEST_PATH "mp_tm.ini"
|
||||
#define TM_FW_REQUEST_PATH "ILITEK_FW_TM"
|
||||
static unsigned char CTPM_FW_TM[] = {
|
||||
0xFF,
|
||||
};
|
||||
|
||||
#define HLT_INI_NAME_PATH "/sdcard/mp_hlt.ini"
|
||||
#define HLT_FW_FILP_PATH "/sdcard/ILITEK_FW_HLT.hex"
|
||||
#define HLT_INI_REQUEST_PATH "mp_hlt.ini"
|
||||
#define HLT_FW_REQUEST_PATH "ILITEK_FW_HLT.hex"
|
||||
static unsigned char CTPM_FW_HLT[] = {
|
||||
};
|
||||
|
||||
#endif
|
||||
1056
drivers/input/touchscreen/ili9882_mmi/ili9882.c
Executable file
1056
drivers/input/touchscreen/ili9882_mmi/ili9882.c
Executable file
File diff suppressed because it is too large
Load diff
1151
drivers/input/touchscreen/ili9882_mmi/ili9882.h
Executable file
1151
drivers/input/touchscreen/ili9882_mmi/ili9882.h
Executable file
File diff suppressed because it is too large
Load diff
1477
drivers/input/touchscreen/ili9882_mmi/ili9882_flash.c
Executable file
1477
drivers/input/touchscreen/ili9882_mmi/ili9882_flash.c
Executable file
File diff suppressed because it is too large
Load diff
917
drivers/input/touchscreen/ili9882_mmi/ili9882_hostdl.c
Executable file
917
drivers/input/touchscreen/ili9882_mmi/ili9882_hostdl.c
Executable file
|
|
@ -0,0 +1,917 @@
|
|||
/*
|
||||
* ILITEK Touch IC driver
|
||||
*
|
||||
* Copyright (C) 2011 ILI Technology Corporation.
|
||||
*
|
||||
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 "ili9882.h"
|
||||
|
||||
#define UPDATE_PASS 0
|
||||
#define UPDATE_FAIL -1
|
||||
#define TIMEOUT_SECTOR 500
|
||||
#define TIMEOUT_PAGE 3500
|
||||
#define TIMEOUT_PROGRAM 10
|
||||
|
||||
static struct touch_fw_data {
|
||||
u8 block_number;
|
||||
u32 start_addr;
|
||||
u32 end_addr;
|
||||
u32 new_fw_cb;
|
||||
int delay_after_upgrade;
|
||||
bool isCRC;
|
||||
bool isboot;
|
||||
bool is80k;
|
||||
int hex_tag;
|
||||
} tfd;
|
||||
|
||||
static struct flash_block_info {
|
||||
char *name;
|
||||
u32 start;
|
||||
u32 end;
|
||||
u32 len;
|
||||
u32 mem_start;
|
||||
u32 fix_mem_start;
|
||||
u8 mode;
|
||||
} fbi[FW_BLOCK_INFO_NUM];
|
||||
|
||||
static u8 *pfw;
|
||||
static u8 *CTPM_FW;
|
||||
|
||||
static u32 HexToDec(char *phex, s32 len)
|
||||
{
|
||||
u32 ret = 0, temp = 0, i;
|
||||
s32 shift = (len - 1) * 4;
|
||||
|
||||
for (i = 0; i < len; shift -= 4, i++) {
|
||||
if ((phex[i] >= '0') && (phex[i] <= '9'))
|
||||
temp = phex[i] - '0';
|
||||
else if ((phex[i] >= 'a') && (phex[i] <= 'f'))
|
||||
temp = (phex[i] - 'a') + 10;
|
||||
else if ((phex[i] >= 'A') && (phex[i] <= 'F'))
|
||||
temp = (phex[i] - 'A') + 10;
|
||||
|
||||
ret |= (temp << shift);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int CalculateCRC32(u32 start_addr, u32 len, u8 *pfw)
|
||||
{
|
||||
int i = 0, j = 0;
|
||||
int crc_poly = 0x04C11DB7;
|
||||
int tmp_crc = 0xFFFFFFFF;
|
||||
|
||||
for (i = start_addr; i < start_addr + len; i++) {
|
||||
tmp_crc ^= (pfw[i] << 24);
|
||||
|
||||
for (j = 0; j < 8; j++) {
|
||||
if ((tmp_crc & 0x80000000) != 0)
|
||||
tmp_crc = tmp_crc << 1 ^ crc_poly;
|
||||
else
|
||||
tmp_crc = tmp_crc << 1;
|
||||
}
|
||||
}
|
||||
return tmp_crc;
|
||||
}
|
||||
|
||||
static int calc_hw_dma_crc(u32 start_addr, u32 block_size)
|
||||
{
|
||||
int count = 50;
|
||||
u32 busy = 0;
|
||||
|
||||
/* dma1 src1 address */
|
||||
if (ili_ice_mode_write(0x072104, start_addr, 4) < 0)
|
||||
ILI_ERR("Write dma1 src1 address failed\n");
|
||||
/* dma1 src1 format */
|
||||
if (ili_ice_mode_write(0x072108, 0x80000001, 4) < 0)
|
||||
ILI_ERR("Write dma1 src1 format failed\n");
|
||||
/* dma1 dest address */
|
||||
if (ili_ice_mode_write(0x072114, 0x0002725C, 4) < 0)
|
||||
ILI_ERR("Write dma1 src1 format failed\n");
|
||||
/* dma1 dest format */
|
||||
if (ili_ice_mode_write(0x072118, 0x80000000, 4) < 0)
|
||||
ILI_ERR("Write dma1 dest format failed\n");
|
||||
/* Block size*/
|
||||
if (ili_ice_mode_write(0x07211C, block_size, 4) < 0)
|
||||
ILI_ERR("Write block size (%d) failed\n", block_size);
|
||||
/* crc off */
|
||||
if (ili_ice_mode_write(0x041016, 0x00, 1) < 0)
|
||||
ILI_INFO("Write crc of failed\n");
|
||||
/* dma crc */
|
||||
if (ili_ice_mode_write(0x041017, 0x03, 1) < 0)
|
||||
ILI_ERR("Write dma 1 crc failed\n");
|
||||
/* Dma1 stop */
|
||||
if (ili_ice_mode_write(0x072100, 0x02000000, 4) < 0)
|
||||
ILI_ERR("Write dma1 stop failed\n");
|
||||
/* crc on */
|
||||
if (ili_ice_mode_write(0x041016, 0x01, 1) < 0)
|
||||
ILI_ERR("Write crc on failed\n");
|
||||
/* clr int */
|
||||
if (ili_ice_mode_write(0x048006, 0x2, 1) < 0)
|
||||
ILI_ERR("Write clr int failed\n");
|
||||
/* Dma1 start */
|
||||
if (ili_ice_mode_write(0x072100, 0x01000000, 4) < 0)
|
||||
ILI_ERR("Write dma1 start failed\n");
|
||||
|
||||
/* Polling BIT0 */
|
||||
while (count > 0) {
|
||||
mdelay(1);
|
||||
if (ili_ice_mode_read(0x048006, &busy, sizeof(u8)) < 0)
|
||||
ILI_ERR("Read busy error\n");
|
||||
ILI_DBG("busy = %x\n", busy);
|
||||
if ((busy & 0x02) == 2)
|
||||
break;
|
||||
count--;
|
||||
}
|
||||
|
||||
if (count <= 0) {
|
||||
ILI_ERR("BIT0 is busy\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ili_ice_mode_read(0x04101C, &busy, sizeof(u32)) < 0) {
|
||||
ILI_ERR("Read dma crc error\n");
|
||||
return -1;
|
||||
}
|
||||
return busy;
|
||||
}
|
||||
|
||||
static int ilitek_tddi_fw_iram_read(u8 *buf, u32 start, int len)
|
||||
{
|
||||
int limit = SPI_RX_BUF_SIZE;
|
||||
int addr = 0, loop = 0, tmp_len = len, cnt = 0;
|
||||
u8 cmd[4] = {0};
|
||||
|
||||
if (!buf) {
|
||||
ILI_ERR("buf is null\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (len % limit)
|
||||
loop = (len / limit) + 1;
|
||||
else
|
||||
loop = len / limit;
|
||||
|
||||
for (cnt = 0, addr = start; cnt < loop; cnt++, addr += limit) {
|
||||
if (tmp_len > limit)
|
||||
tmp_len = limit;
|
||||
|
||||
cmd[0] = 0x25;
|
||||
cmd[3] = (char)((addr & 0x00FF0000) >> 16);
|
||||
cmd[2] = (char)((addr & 0x0000FF00) >> 8);
|
||||
cmd[1] = (char)((addr & 0x000000FF));
|
||||
|
||||
if (ilits->wrapper(cmd, 4, NULL, 0, OFF, OFF) < 0) {
|
||||
ILI_ERR("Failed to write iram data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (ilits->wrapper(NULL, 0, buf + cnt * limit, tmp_len, OFF, OFF) < 0) {
|
||||
ILI_ERR("Failed to Read iram data\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tmp_len = len - cnt * limit;
|
||||
ilits->fw_update_stat = ((len - tmp_len) * 100) / len;
|
||||
ILI_INFO("Reading iram data .... %d%c", ilits->fw_update_stat, '%');
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ili_fw_dump_iram_data(u32 start, u32 end, bool save)
|
||||
{
|
||||
struct file *f = NULL;
|
||||
mm_segment_t old_fs;
|
||||
loff_t pos = 0;
|
||||
int i, ret = 0;
|
||||
int len, tmp = debug_en;
|
||||
bool ice = atomic_read(&ilits->ice_stat);
|
||||
|
||||
if (!ice) {
|
||||
ret = ili_ice_mode_ctrl(ENABLE, OFF);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Enable ice mode failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
len = end - start + 1;
|
||||
|
||||
if (len > MAX_HEX_FILE_SIZE) {
|
||||
ILI_ERR("len is larger than buffer, abort\n");
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_HEX_FILE_SIZE; i++)
|
||||
ilits->update_buf[i] = 0xFF;
|
||||
|
||||
ret = ilitek_tddi_fw_iram_read(ilits->update_buf, start, len);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Read IRAM data failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (save) {
|
||||
f = filp_open(DUMP_IRAM_PATH, O_WRONLY | O_CREAT | O_TRUNC, 644);
|
||||
if (ERR_ALLOC_MEM(f)) {
|
||||
ILI_ERR("Failed to open the file at %ld.\n", PTR_ERR(f));
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
set_fs(KERNEL_DS);
|
||||
pos = 0;
|
||||
vfs_write(f, ilits->update_buf, len, &pos);
|
||||
set_fs(old_fs);
|
||||
filp_close(f, NULL);
|
||||
ILI_INFO("Save iram data to %s\n", DUMP_IRAM_PATH);
|
||||
} else {
|
||||
debug_en = DEBUG_ALL;
|
||||
ili_dump_data(ilits->update_buf, 8, len, 0, "IRAM");
|
||||
debug_en = tmp;
|
||||
}
|
||||
|
||||
out:
|
||||
if (!ice) {
|
||||
if (ili_ice_mode_ctrl(DISABLE, OFF) < 0)
|
||||
ILI_ERR("Enable ice mode failed after code reset\n");
|
||||
}
|
||||
|
||||
ILI_INFO("Dump IRAM %s\n", (ret < 0) ? "FAIL" : "SUCCESS");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ilitek_tddi_fw_iram_program(u32 start, u8 *w_buf, u32 w_len, u32 split_len)
|
||||
{
|
||||
int i = 0, j = 0, addr = 0;
|
||||
u32 end = start + w_len;
|
||||
bool fix_4_alignment = false;
|
||||
|
||||
if (split_len % 4 > 0)
|
||||
ILI_ERR("Since split_len must be four-aligned, it must be a multiple of four");
|
||||
|
||||
if (split_len != 0) {
|
||||
for (addr = start, i = 0; addr < end; addr += split_len, i += split_len) {
|
||||
if ((addr + split_len) > end) {
|
||||
split_len = end - addr;
|
||||
if (split_len % 4 != 0)
|
||||
fix_4_alignment = true;
|
||||
}
|
||||
|
||||
ilits->update_buf[0] = SPI_WRITE;
|
||||
ilits->update_buf[1] = 0x25;
|
||||
ilits->update_buf[2] = (char)((addr & 0x000000FF));
|
||||
ilits->update_buf[3] = (char)((addr & 0x0000FF00) >> 8);
|
||||
ilits->update_buf[4] = (char)((addr & 0x00FF0000) >> 16);
|
||||
|
||||
for (j = 0; j < split_len; j++)
|
||||
ilits->update_buf[5 + j] = w_buf[i + j];
|
||||
|
||||
if (fix_4_alignment) {
|
||||
ILI_INFO("org split_len = 0x%X\n", split_len);
|
||||
ILI_INFO("idev->update_buf[5 + 0x%X] = 0x%X\n", split_len - 4, ilits->update_buf[5 + split_len - 4]);
|
||||
ILI_INFO("idev->update_buf[5 + 0x%X] = 0x%X\n", split_len - 3, ilits->update_buf[5 + split_len - 3]);
|
||||
ILI_INFO("idev->update_buf[5 + 0x%X] = 0x%X\n", split_len - 2, ilits->update_buf[5 + split_len - 2]);
|
||||
ILI_INFO("idev->update_buf[5 + 0x%X] = 0x%X\n", split_len - 1, ilits->update_buf[5 + split_len - 1]);
|
||||
for (j = 0; j < (4 - (split_len % 4)); j++) {
|
||||
ilits->update_buf[5 + j + split_len] = 0xFF;
|
||||
ILI_INFO("idev->update_buf[5 + 0x%X] = 0x%X\n",j + split_len, ilits->update_buf[5 + j + split_len]);
|
||||
}
|
||||
|
||||
ILI_INFO("split_len %% 4 = %d\n", split_len % 4);
|
||||
split_len = split_len + (4 - (split_len % 4));
|
||||
ILI_INFO("fix split_len = 0x%X\n", split_len);
|
||||
}
|
||||
if (ilits->spi_write_then_read(ilits->spi, ilits->update_buf, split_len + 5, NULL, 0)) {
|
||||
ILI_ERR("Failed to write data via SPI in host download (%x)\n", split_len + 5);
|
||||
return -EIO;
|
||||
}
|
||||
ilits->fw_update_stat = (i * 100) / w_len;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < MAX_HEX_FILE_SIZE; i++)
|
||||
ilits->update_buf[i] = 0xFF;
|
||||
|
||||
ilits->update_buf[0] = SPI_WRITE;
|
||||
ilits->update_buf[1] = 0x25;
|
||||
ilits->update_buf[2] = (char)((start & 0x000000FF));
|
||||
ilits->update_buf[3] = (char)((start & 0x0000FF00) >> 8);
|
||||
ilits->update_buf[4] = (char)((start & 0x00FF0000) >> 16);
|
||||
|
||||
memcpy(&ilits->update_buf[5], w_buf, w_len);
|
||||
if (w_len % 4 != 0) {
|
||||
ILI_INFO("org w_len = %d\n", w_len);
|
||||
w_len = w_len + (4 - (w_len % 4));
|
||||
ILI_INFO("w_len = %d w_len %% 4 = %d\n", w_len, w_len % 4);
|
||||
}
|
||||
/* It must be supported by platforms that have the ability to transfer all data at once. */
|
||||
if (ilits->spi_write_then_read(ilits->spi, ilits->update_buf, w_len + 5, NULL, 0) < 0) {
|
||||
ILI_ERR("Failed to write data via SPI in host download (%x)\n", w_len + 5);
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tddi_fw_iram_upgrade(u8 *pfw)
|
||||
{
|
||||
int i, ret = UPDATE_PASS;
|
||||
u32 mode, crc, dma, iram_crc = 0;
|
||||
u8 *fw_ptr = NULL, crc_temp[4], crc_len = 4;
|
||||
bool iram_crc_err = false;
|
||||
|
||||
if (!ilits->ddi_rest_done) {
|
||||
if (ilits->actual_tp_mode != P5_X_FW_GESTURE_MODE)
|
||||
ili_reset_ctrl(ilits->reset);
|
||||
|
||||
ret = ili_ice_mode_ctrl(ENABLE, OFF);
|
||||
if (ret < 0)
|
||||
return -EFW_ICE_MODE;
|
||||
} else {
|
||||
/* Restore it if the wq of load_fw_ddi has been called. */
|
||||
ilits->ddi_rest_done = false;
|
||||
}
|
||||
|
||||
if (ilits->chip->dma_reset) {
|
||||
ILI_INFO("operate dma reset in reg after tp reset\n");
|
||||
if (ili_ice_mode_write(0x40040, 0x00800000, 4) < 0)
|
||||
ILI_INFO("Failed to open DMA reset\n");
|
||||
if (ili_ice_mode_write(0x40040, 0x00000000, 4) < 0)
|
||||
ILI_INFO("Failed to close DMA reset\n");
|
||||
}
|
||||
|
||||
/* Point to pfw with different addresses for getting its block data. */
|
||||
fw_ptr = pfw;
|
||||
if (ilits->actual_tp_mode == P5_X_FW_TEST_MODE) {
|
||||
|
||||
mode = MP;
|
||||
} else if (ilits->actual_tp_mode == P5_X_FW_GESTURE_MODE) {
|
||||
mode = GESTURE;
|
||||
crc_len = 0;
|
||||
} else {
|
||||
mode = AP;
|
||||
}
|
||||
|
||||
/* Program data to iram acorrding to each block */
|
||||
for (i = 0; i < FW_BLOCK_INFO_NUM; i++) {
|
||||
if (fbi[i].mode == mode && fbi[i].len != 0) {
|
||||
ILI_DBG("Download %s code from hex 0x%x to IRAM 0x%x, len = 0x%x\n",
|
||||
fbi[i].name, fbi[i].start, fbi[i].mem_start, fbi[i].len);
|
||||
|
||||
#if SPI_DMA_TRANSFER_SPLIT
|
||||
if (ilitek_tddi_fw_iram_program(fbi[i].mem_start, (fw_ptr + fbi[i].start), fbi[i].len, SPI_UPGRADE_LEN) < 0)
|
||||
ILI_ERR("IRAM program failed\n");
|
||||
#else
|
||||
if (ilitek_tddi_fw_iram_program(fbi[i].mem_start, (fw_ptr + fbi[i].start), fbi[i].len, 0) < 0)
|
||||
ILI_ERR("IRAM program failed\n");
|
||||
#endif
|
||||
crc = CalculateCRC32(fbi[i].start, fbi[i].len - crc_len, fw_ptr);
|
||||
dma = calc_hw_dma_crc(fbi[i].mem_start, fbi[i].len - crc_len);
|
||||
|
||||
if (mode != GESTURE) {
|
||||
ilitek_tddi_fw_iram_read(crc_temp, (fbi[i].mem_start + fbi[i].len - crc_len), sizeof(crc_temp));
|
||||
iram_crc = crc_temp[0] << 24 | crc_temp[1] << 16 |crc_temp[2] << 8 | crc_temp[3];
|
||||
if (iram_crc != dma)
|
||||
iram_crc_err = true;
|
||||
}
|
||||
|
||||
ILI_INFO("%s CRC is %s hex(%x) : dma(%x) : iram(%x), calculation len is 0x%x\n",
|
||||
fbi[i].name,((crc != dma)||(iram_crc_err)) ? "Invalid !" : "Correct !", crc, dma, iram_crc, fbi[i].len - crc_len);
|
||||
|
||||
if ((crc != dma)|| iram_crc_err) {
|
||||
ILI_ERR("CRC Error! print iram data with first 16 bytes\n");
|
||||
ili_fw_dump_iram_data(0x0, 0xF, false);
|
||||
return -EFW_CRC;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ilits->actual_tp_mode != P5_X_FW_GESTURE_MODE) {
|
||||
if (ili_reset_ctrl(TP_IC_CODE_RST) < 0) {
|
||||
ILI_ERR("TP Code reset failed during iram programming\n");
|
||||
ret = -EFW_REST;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (ili_ice_mode_ctrl(DISABLE, OFF) < 0) {
|
||||
ILI_ERR("Disable ice mode failed after code reset\n");
|
||||
ret = -EFW_ICE_MODE;
|
||||
}
|
||||
|
||||
/* Waiting for fw ready sending first cmd */
|
||||
if (!ilits->info_from_hex || (ilits->chip->core_ver < CORE_VER_1410))
|
||||
mdelay(100);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ilitek_fw_calc_file_crc(u8 *pfw)
|
||||
{
|
||||
int i;
|
||||
u32 ex_addr, data_crc, file_crc;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fbi); i++) {
|
||||
if (fbi[i].end == 0)
|
||||
continue;
|
||||
ex_addr = fbi[i].end;
|
||||
data_crc = CalculateCRC32(fbi[i].start, fbi[i].len - 4, pfw);
|
||||
file_crc = pfw[ex_addr - 3] << 24 | pfw[ex_addr - 2] << 16 | pfw[ex_addr - 1] << 8 | pfw[ex_addr];
|
||||
ILI_DBG("data crc = %x, file crc = %x\n", data_crc, file_crc);
|
||||
if (data_crc != file_crc) {
|
||||
ILI_ERR("Content of fw file is broken. (%d, %x, %x)\n",
|
||||
i, data_crc, file_crc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ILI_INFO("Content of fw file is correct\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tddi_fw_update_block_info(u8 *pfw)
|
||||
{
|
||||
u32 ges_area_section = 0, ges_info_addr = 0, ges_fw_start = 0, ges_fw_end = 0;
|
||||
u32 ap_end = 0, ap_len = 0;
|
||||
u32 fw_info_addr = 0, fw_mp_ver_addr = 0;
|
||||
|
||||
if (tfd.hex_tag != BLOCK_TAG_AF) {
|
||||
ILI_ERR("HEX TAG is invalid (0x%X)\n", tfd.hex_tag);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fbi[AP].mem_start = (fbi[AP].fix_mem_start != INT_MAX) ? fbi[AP].fix_mem_start : 0;
|
||||
fbi[DATA].mem_start = (fbi[DATA].fix_mem_start != INT_MAX) ? fbi[DATA].fix_mem_start : DLM_START_ADDRESS;
|
||||
fbi[TUNING].mem_start = (fbi[TUNING].fix_mem_start != INT_MAX) ? fbi[TUNING].fix_mem_start : fbi[DATA].mem_start + fbi[DATA].len;
|
||||
fbi[MP].mem_start = (fbi[MP].fix_mem_start != INT_MAX) ? fbi[MP].fix_mem_start : 0;
|
||||
fbi[GESTURE].mem_start = (fbi[GESTURE].fix_mem_start != INT_MAX) ? fbi[GESTURE].fix_mem_start : 0;
|
||||
fbi[TAG].mem_start = (fbi[TAG].fix_mem_start != INT_MAX) ? fbi[TAG].fix_mem_start : 0;
|
||||
fbi[PARA_BACKUP].mem_start = (fbi[PARA_BACKUP].fix_mem_start != INT_MAX) ? fbi[PARA_BACKUP].fix_mem_start : 0;
|
||||
fbi[DDI].mem_start = (fbi[DDI].fix_mem_start != INT_MAX) ? fbi[DDI].fix_mem_start : 0;
|
||||
|
||||
/* Parsing gesture info form AP code */
|
||||
ges_info_addr = (fbi[AP].end + 1 - 60);
|
||||
ges_area_section = (pfw[ges_info_addr + 3] << 24) + (pfw[ges_info_addr + 2] << 16) + (pfw[ges_info_addr + 1] << 8) + pfw[ges_info_addr];
|
||||
fbi[GESTURE].mem_start = (pfw[ges_info_addr + 7] << 24) + (pfw[ges_info_addr + 6] << 16) + (pfw[ges_info_addr + 5] << 8) + pfw[ges_info_addr + 4];
|
||||
ap_end = (pfw[ges_info_addr + 11] << 24) + (pfw[ges_info_addr + 10] << 16) + (pfw[ges_info_addr + 9] << 8) + pfw[ges_info_addr + 8];
|
||||
|
||||
if (ap_end != fbi[GESTURE].mem_start)
|
||||
ap_len = ap_end - fbi[GESTURE].mem_start + 1;
|
||||
|
||||
ges_fw_start = (pfw[ges_info_addr + 15] << 24) + (pfw[ges_info_addr + 14] << 16) + (pfw[ges_info_addr + 13] << 8) + pfw[ges_info_addr + 12];
|
||||
ges_fw_end = (pfw[ges_info_addr + 19] << 24) + (pfw[ges_info_addr + 18] << 16) + (pfw[ges_info_addr + 17] << 8) + pfw[ges_info_addr + 16];
|
||||
|
||||
if (ges_fw_end != ges_fw_start)
|
||||
fbi[GESTURE].len = ges_fw_end - ges_fw_start;
|
||||
|
||||
/* update gesture address */
|
||||
fbi[GESTURE].start = ges_fw_start;
|
||||
|
||||
ILI_INFO("==== Gesture loader info ====\n");
|
||||
ILI_INFO("gesture move to ap addr => start = 0x%x, ap_end = 0x%x, ap_len = 0x%x\n", fbi[GESTURE].mem_start, ap_end, ap_len);
|
||||
ILI_INFO("gesture hex addr => start = 0x%x, gesture_end = 0x%x, gesture_len = 0x%x\n", ges_fw_start, ges_fw_end, fbi[GESTURE].len);
|
||||
ILI_INFO("=============================\n");
|
||||
|
||||
fbi[AP].name = "AP";
|
||||
fbi[DATA].name = "DATA";
|
||||
fbi[TUNING].name = "TUNING";
|
||||
fbi[MP].name = "MP";
|
||||
fbi[GESTURE].name = "GESTURE";
|
||||
fbi[TAG].name = "TAG";
|
||||
fbi[PARA_BACKUP].name = "PARA_BACKUP";
|
||||
fbi[DDI].name = "DDI";
|
||||
|
||||
/* upgrade mode define */
|
||||
fbi[DATA].mode = fbi[AP].mode = fbi[TUNING].mode = AP;
|
||||
fbi[MP].mode = MP;
|
||||
fbi[GESTURE].mode = GESTURE;
|
||||
|
||||
if (fbi[AP].end > (64*K))
|
||||
tfd.is80k = true;
|
||||
|
||||
/* Copy fw info */
|
||||
fw_info_addr = fbi[AP].end - INFO_HEX_ST_ADDR;
|
||||
ILI_INFO("Parsing hex info start addr = 0x%x\n", fw_info_addr);
|
||||
ipio_memcpy(ilits->fw_info, (pfw + fw_info_addr), sizeof(ilits->fw_info), sizeof(ilits->fw_info));
|
||||
|
||||
/* copy fw mp ver */
|
||||
fw_mp_ver_addr = fbi[MP].end - INFO_MP_HEX_ADDR;
|
||||
ILI_INFO("Parsing hex mp ver addr = 0x%x\n", fw_mp_ver_addr);
|
||||
ipio_memcpy(ilits->fw_mp_ver, pfw + fw_mp_ver_addr, sizeof(ilits->fw_mp_ver), sizeof(ilits->fw_mp_ver));
|
||||
|
||||
/* copy fw core ver */
|
||||
ilits->chip->core_ver = (ilits->fw_info[68] << 24) | (ilits->fw_info[69] << 16) |
|
||||
(ilits->fw_info[70] << 8) | ilits->fw_info[71];
|
||||
ILI_INFO("New FW Core version = %x\n", ilits->chip->core_ver);
|
||||
|
||||
/* Get hex fw vers */
|
||||
tfd.new_fw_cb = (ilits->fw_info[48] << 24) | (ilits->fw_info[49] << 16) |
|
||||
(ilits->fw_info[50] << 8) | ilits->fw_info[51];
|
||||
|
||||
/* Get hex report info block*/
|
||||
ipio_memcpy(&ilits->rib, ilits->fw_info, sizeof(ilits->rib), sizeof(ilits->rib));
|
||||
ILI_INFO("report_info_block : nReportByPixel = %d, nIsHostDownload = %d, nIsSPIICE = %d, nIsSPISLAVE = %d\n",
|
||||
ilits->rib.nReportByPixel, ilits->rib.nIsHostDownload, ilits->rib.nIsSPIICE, ilits->rib.nIsSPISLAVE);
|
||||
ILI_INFO("report_info_block : nIsI2C = %d, nReserved00 = %d, nReserved01 = %x, nReserved02 = %x, nReserved03 = %x\n",
|
||||
ilits->rib.nIsI2C, ilits->rib.nReserved00, ilits->rib.nReserved01, ilits->rib.nReserved02, ilits->rib.nReserved03);
|
||||
|
||||
/* Calculate update address */
|
||||
ILI_INFO("New FW ver = 0x%x\n", tfd.new_fw_cb);
|
||||
ILI_INFO("star_addr = 0x%06X, end_addr = 0x%06X, Block Num = %d\n", tfd.start_addr, tfd.end_addr, tfd.block_number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tddi_fw_ili_convert(u8 *pfw)
|
||||
{
|
||||
int i, size, blk_num = 0, blk_map = 0, num;
|
||||
int b0_addr = 0, b0_num = 0;
|
||||
|
||||
if (ERR_ALLOC_MEM(ilits->md_fw_ili))
|
||||
return -ENOMEM;
|
||||
|
||||
CTPM_FW = ilits->md_fw_ili;
|
||||
size = ilits->md_fw_ili_size;
|
||||
|
||||
if (size < ILI_FILE_HEADER || size > MAX_HEX_FILE_SIZE) {
|
||||
ILI_ERR("size of ILI file is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Check if it's old version of ILI format. */
|
||||
if (CTPM_FW[22] == 0xFF && CTPM_FW[23] == 0xFF &&
|
||||
CTPM_FW[24] == 0xFF && CTPM_FW[25] == 0xFF) {
|
||||
ILI_ERR("Invaild ILI format, abort!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
blk_num = CTPM_FW[131];
|
||||
blk_map = (CTPM_FW[129] << 8) | CTPM_FW[130];
|
||||
ILI_INFO("Parsing ILI file, block num = %d, block mapping = %x\n", blk_num, blk_map);
|
||||
|
||||
if (blk_num > (FW_BLOCK_INFO_NUM - 1) || !blk_num || !blk_map) {
|
||||
ILI_ERR("Number of block or block mapping is invalid, abort!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(fbi, 0x0, sizeof(fbi));
|
||||
|
||||
tfd.start_addr = 0;
|
||||
tfd.end_addr = 0;
|
||||
tfd.hex_tag = BLOCK_TAG_AF;
|
||||
|
||||
/* Parsing block info */
|
||||
for (i = 0; i < FW_BLOCK_INFO_NUM; i++) {
|
||||
/* B0 tag */
|
||||
b0_addr = (CTPM_FW[4 + i * 4] << 16) | (CTPM_FW[5 + i * 4] << 8) | (CTPM_FW[6 + i * 4]);
|
||||
b0_num = CTPM_FW[7 + i * 4];
|
||||
if ((b0_num != 0) && (b0_addr != 0x000000))
|
||||
fbi[b0_num].fix_mem_start = b0_addr;
|
||||
|
||||
/* AF tag */
|
||||
num = i + 1;
|
||||
if (((blk_map >> i) & 0x01) == 0x01) {
|
||||
fbi[num].start = (CTPM_FW[132 + i * 6] << 16) | (CTPM_FW[133 + i * 6] << 8) | CTPM_FW[134 + i * 6];
|
||||
fbi[num].end = (CTPM_FW[135 + i * 6] << 16) | (CTPM_FW[136 + i * 6] << 8) | CTPM_FW[137 + i * 6];
|
||||
|
||||
if (fbi[num].fix_mem_start == 0)
|
||||
fbi[num].fix_mem_start = INT_MAX;
|
||||
|
||||
fbi[num].len = fbi[num].end - fbi[num].start + 1;
|
||||
ILI_DBG("Block[%d]: start_addr = %x, end = %x, fix_mem_start = 0x%x\n", num, fbi[num].start,
|
||||
fbi[num].end, fbi[num].fix_mem_start);
|
||||
if (num == GESTURE)
|
||||
ilits->gesture_load_code = true;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(pfw, CTPM_FW + ILI_FILE_HEADER, size - ILI_FILE_HEADER);
|
||||
|
||||
if (ilitek_fw_calc_file_crc(pfw) < 0)
|
||||
return -1;
|
||||
|
||||
tfd.block_number = blk_num;
|
||||
tfd.end_addr = size - ILI_FILE_HEADER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tddi_fw_hex_convert(u8 *phex, int size, u8 *pfw)
|
||||
{
|
||||
int block = 0;
|
||||
u32 i = 0, j = 0, k = 0, num = 0;
|
||||
u32 len = 0, addr = 0, type = 0;
|
||||
u32 start_addr = 0x0, end_addr = 0x0, ex_addr = 0;
|
||||
u32 offset;
|
||||
|
||||
memset(fbi, 0x0, sizeof(fbi));
|
||||
|
||||
/* Parsing HEX file */
|
||||
for (; i < size;) {
|
||||
len = HexToDec(&phex[i + 1], 2);
|
||||
addr = HexToDec(&phex[i + 3], 4);
|
||||
type = HexToDec(&phex[i + 7], 2);
|
||||
|
||||
if (type == 0x04) {
|
||||
ex_addr = HexToDec(&phex[i + 9], 4);
|
||||
} else if (type == 0x02) {
|
||||
ex_addr = HexToDec(&phex[i + 9], 4);
|
||||
ex_addr = ex_addr >> 12;
|
||||
} else if (type == BLOCK_TAG_AF) {
|
||||
/* insert block info extracted from hex */
|
||||
tfd.hex_tag = type;
|
||||
if (tfd.hex_tag == BLOCK_TAG_AF)
|
||||
num = HexToDec(&phex[i + 9 + 6 + 6], 2);
|
||||
else
|
||||
num = 0xFF;
|
||||
|
||||
if (num > (FW_BLOCK_INFO_NUM - 1)) {
|
||||
ILI_ERR("ERROR! block num is larger than its define (%d, %d)\n",
|
||||
num, FW_BLOCK_INFO_NUM - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fbi[num].start = HexToDec(&phex[i + 9], 6);
|
||||
fbi[num].end = HexToDec(&phex[i + 9 + 6], 6);
|
||||
fbi[num].fix_mem_start = INT_MAX;
|
||||
fbi[num].len = fbi[num].end - fbi[num].start + 1;
|
||||
ILI_DBG("Block[%d]: start_addr = %x, end = %x", num, fbi[num].start, fbi[num].end);
|
||||
|
||||
if (num == GESTURE)
|
||||
ilits->gesture_load_code = true;
|
||||
|
||||
block++;
|
||||
} else if (type == BLOCK_TAG_B0 && tfd.hex_tag == BLOCK_TAG_AF) {
|
||||
num = HexToDec(&phex[i + 9 + 6], 2);
|
||||
|
||||
if (num > (FW_BLOCK_INFO_NUM - 1)) {
|
||||
ILI_ERR("ERROR! block num is larger than its define (%d, %d)\n",
|
||||
num, FW_BLOCK_INFO_NUM - 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fbi[num].fix_mem_start = HexToDec(&phex[i + 9], 6);
|
||||
ILI_DBG("Tag 0xB0: change Block[%d] to addr = 0x%x\n", num, fbi[num].fix_mem_start);
|
||||
}
|
||||
|
||||
addr = addr + (ex_addr << 16);
|
||||
|
||||
if (phex[i + 1 + 2 + 4 + 2 + (len * 2) + 2] == 0x0D)
|
||||
offset = 2;
|
||||
else
|
||||
offset = 1;
|
||||
|
||||
if (addr > MAX_HEX_FILE_SIZE) {
|
||||
ILI_ERR("Invalid hex format %d\n", addr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (type == 0x00) {
|
||||
end_addr = addr + len;
|
||||
if (addr < start_addr)
|
||||
start_addr = addr;
|
||||
/* fill data */
|
||||
for (j = 0, k = 0; j < (len * 2); j += 2, k++)
|
||||
pfw[addr + k] = HexToDec(&phex[i + 9 + j], 2);
|
||||
}
|
||||
i += 1 + 2 + 4 + 2 + (len * 2) + 2 + offset;
|
||||
}
|
||||
|
||||
if (ilitek_fw_calc_file_crc(pfw) < 0)
|
||||
return -1;
|
||||
|
||||
tfd.start_addr = start_addr;
|
||||
tfd.end_addr = end_addr;
|
||||
tfd.block_number = block;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tdd_fw_hex_open(u8 op, u8 *pfw)
|
||||
{
|
||||
int ret =0, fsize = 0;
|
||||
const struct firmware *fw = NULL;
|
||||
struct file *f = NULL;
|
||||
mm_segment_t old_fs;
|
||||
loff_t pos = 0;
|
||||
|
||||
ILI_INFO("Open file method = %s, path = %s\n",
|
||||
op ? "FILP_OPEN" : "REQUEST_FIRMWARE",
|
||||
op ? ilits->md_fw_filp_path : ilits->md_fw_rq_path);
|
||||
|
||||
switch (op) {
|
||||
case REQUEST_FIRMWARE:
|
||||
if (request_firmware(&fw, ilits->md_fw_rq_path, ilits->dev) < 0) {
|
||||
ILI_ERR("Request firmware failed, try again\n");
|
||||
if (request_firmware(&fw, ilits->md_fw_rq_path, ilits->dev) < 0) {
|
||||
ILI_ERR("Request firmware failed after retry\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
fsize = fw->size;
|
||||
ILI_INFO("fsize = %d\n", fsize);
|
||||
if (fsize <= 0) {
|
||||
ILI_ERR("The size of file is invaild\n");
|
||||
release_firmware(fw);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ilits->tp_fw.size = 0;
|
||||
ilits->tp_fw.data = vmalloc(fsize);
|
||||
if (ERR_ALLOC_MEM(ilits->tp_fw.data)) {
|
||||
ILI_ERR("Failed to allocate tp_fw by vmalloc, try again\n");
|
||||
ilits->tp_fw.data = vmalloc(fsize);
|
||||
if (ERR_ALLOC_MEM(ilits->tp_fw.data)) {
|
||||
ILI_ERR("Failed to allocate tp_fw after retry\n");
|
||||
release_firmware(fw);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy fw data got from request_firmware to global */
|
||||
ipio_memcpy((u8 *)ilits->tp_fw.data, fw->data, fsize * sizeof(*fw->data), fsize);
|
||||
ilits->tp_fw.size = fsize;
|
||||
release_firmware(fw);
|
||||
break;
|
||||
case FILP_OPEN:
|
||||
f = filp_open(ilits->md_fw_filp_path, O_RDONLY, 0644);
|
||||
if (ERR_ALLOC_MEM(f)) {
|
||||
ILI_ERR("Failed to open the file, %ld\n", PTR_ERR(f));
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fsize = f->f_inode->i_size;
|
||||
ILI_INFO("fsize = %d\n", fsize);
|
||||
if (fsize <= 0) {
|
||||
ILI_ERR("The size of file is invaild\n");
|
||||
filp_close(f, NULL);
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ilits->tp_fw.size = 0;
|
||||
ilits->tp_fw.data = vmalloc(fsize);
|
||||
if (ERR_ALLOC_MEM(ilits->tp_fw.data)) {
|
||||
ILI_ERR("Failed to allocate tp_fw by vmalloc, try again\n");
|
||||
ilits->tp_fw.data = vmalloc(fsize);
|
||||
if (ERR_ALLOC_MEM(ilits->tp_fw.data)) {
|
||||
ILI_ERR("Failed to allocate tp_fw after retry\n");
|
||||
filp_close(f, NULL);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* ready to map user's memory to obtain data by reading files */
|
||||
old_fs = get_fs();
|
||||
set_fs(get_ds());
|
||||
set_fs(KERNEL_DS);
|
||||
pos = 0;
|
||||
vfs_read(f, (u8 *)ilits->tp_fw.data, fsize, &pos);
|
||||
set_fs(old_fs);
|
||||
filp_close(f, NULL);
|
||||
ilits->tp_fw.size = fsize;
|
||||
break;
|
||||
default:
|
||||
ILI_ERR("Unknown open file method, %d\n", op);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ERR_ALLOC_MEM(ilits->tp_fw.data) || ilits->tp_fw.size <= 0) {
|
||||
ILI_ERR("fw data/size is invaild\n");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Convert hex and copy data from tp_fw.data to pfw */
|
||||
if (ilitek_tddi_fw_hex_convert((u8 *)ilits->tp_fw.data, ilits->tp_fw.size, pfw) < 0) {
|
||||
ILI_ERR("Convert hex file failed\n");
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
out:
|
||||
ipio_vfree((void **)&(ilits->tp_fw.data));
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ili_fw_upgrade(int op)
|
||||
{
|
||||
int i, ret = 0, retry = 3;
|
||||
|
||||
if (!ilits->boot || ilits->force_fw_update || ERR_ALLOC_MEM(pfw)) {
|
||||
ilits->gesture_load_code = false;
|
||||
|
||||
if (ERR_ALLOC_MEM(pfw)) {
|
||||
ipio_vfree((void **)&pfw);
|
||||
pfw = vmalloc(MAX_HEX_FILE_SIZE * sizeof(u8));
|
||||
if (ERR_ALLOC_MEM(pfw)) {
|
||||
ILI_ERR("Failed to allocate pfw memory, %ld\n", PTR_ERR(pfw));
|
||||
ipio_vfree((void **)&pfw);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_HEX_FILE_SIZE; i++)
|
||||
pfw[i] = 0xFF;
|
||||
|
||||
if (ilitek_tdd_fw_hex_open(op, pfw) < 0) {
|
||||
ILI_ERR("Open hex file fail, try upgrade from ILI file\n");
|
||||
|
||||
/*
|
||||
* Users might not be aware of a broken hex file when recovering
|
||||
* fw from ILI file. We should force them to check
|
||||
* hex files if they attempt to update via device node.
|
||||
*/
|
||||
if (ilits->node_update) {
|
||||
ILI_ERR("Ignore update from ILI file\n");
|
||||
ipio_vfree((void **)&pfw);
|
||||
return -EFW_CONVERT_FILE;
|
||||
}
|
||||
|
||||
if (ilitek_tddi_fw_ili_convert(pfw) < 0) {
|
||||
ILI_ERR("Convert ILI file error\n");
|
||||
ret = -EFW_CONVERT_FILE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (ilitek_tddi_fw_update_block_info(pfw) < 0) {
|
||||
ret = -EFW_CONVERT_FILE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ilits->chip->core_ver >= CORE_VER_1470 && ilits->rib.nIsHostDownload == 0) {
|
||||
ILI_ERR("hex file interface no match error\n");
|
||||
return -EFW_INTERFACE;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
ret = ilitek_tddi_fw_iram_upgrade(pfw);
|
||||
if (ret == UPDATE_PASS)
|
||||
break;
|
||||
|
||||
ILI_ERR("Upgrade failed, do retry!\n");
|
||||
} while (--retry > 0);
|
||||
|
||||
if (ret != UPDATE_PASS) {
|
||||
ILI_ERR("Failed to upgrade fw %d times, erasing iram\n", retry);
|
||||
if (ili_reset_ctrl(ilits->reset) < 0)
|
||||
ILI_ERR("TP reset failed while erasing data\n");
|
||||
ilits->xch_num = 0;
|
||||
ilits->ych_num = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
out:
|
||||
ili_ic_get_core_ver();
|
||||
ili_ic_get_protocl_ver();
|
||||
ili_ic_get_fw_ver();
|
||||
ili_ic_get_tp_info();
|
||||
ili_ic_get_panel_info();
|
||||
ili_ic_func_ctrl_reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ili_fw_read_flash_info(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void ili_flash_clear_dma(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void ili_flash_dma_write(u32 start, u32 end, u32 len)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int ili_fw_dump_flash_data(u32 start, u32 end, bool user)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
470
drivers/input/touchscreen/ili9882_mmi/ili9882_i2c.c
Executable file
470
drivers/input/touchscreen/ili9882_mmi/ili9882_i2c.c
Executable file
|
|
@ -0,0 +1,470 @@
|
|||
/*
|
||||
* ILITEK Touch IC driver
|
||||
*
|
||||
* Copyright (C) 2011 ILI Technology Corporation.
|
||||
*
|
||||
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 "ili9882.h"
|
||||
|
||||
struct touch_bus_info {
|
||||
struct i2c_driver bus_driver;
|
||||
struct ilitek_hwif_info *hwif;
|
||||
};
|
||||
|
||||
struct ilitek_ts_data *ilits;
|
||||
|
||||
#define RW_SYNC 0
|
||||
#define R_ONLY 1
|
||||
#define W_ONLY 2
|
||||
|
||||
#if I2C_DMA_TRANSFER
|
||||
static unsigned char *ilitek_dma_va;
|
||||
static dma_addr_t ilitek_dma_pa;
|
||||
|
||||
#define DMA_VA_BUFFER 4096
|
||||
|
||||
static int dma_i2c_alloc(struct i2c_client *client)
|
||||
{
|
||||
if (client != NULL) {
|
||||
client->dev.coherent_dma_mask = DMA_BIT_MASK(32);
|
||||
ilitek_dma_va = (u8 *)dmam_alloc_coherent(client->dev, DMA_VA_BUFFER, &ilitek_dma_pa, GFP_KERNEL);
|
||||
if (ERR_ALLOC_MEM(ilitek_dma_va)) {
|
||||
ILI_ERR("Allocate DMA I2C Buffer failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(ilitek_dma_va, 0, DMA_VA_BUFFER);
|
||||
client->ext_flag |= I2C_DMA_FLAG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ILI_ERR("client is NULL, allocated dma i2c failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int core_i2c_write(void *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 *txbuf = (u8 *)buf;
|
||||
u8 check_sum = 0;
|
||||
u8 *mpbuf = NULL;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = ilits->i2c->addr,
|
||||
.flags = 0, /* write flag. */
|
||||
.len = len,
|
||||
.buf = txbuf,
|
||||
},
|
||||
};
|
||||
|
||||
#if I2C_DMA_TRANSFER
|
||||
if (len > 8) {
|
||||
msgs[0].addr = (ilits->client->addr & I2C_MASK_FLAG);
|
||||
msgs[0].ext_flag = (ilits->client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
|
||||
memcpy(ilitek_dma_va, txbuf, len);
|
||||
msgs[0].buf = (u8 *)ilitek_dma_pa;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* 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 (atomic_read(&ilits->mp_stat) && txbuf[0] == P5_X_SET_CDC_INIT) {
|
||||
check_sum = ili_calc_packet_checksum(txbuf, len);
|
||||
mpbuf = kcalloc(len + 1, sizeof(u8), GFP_KERNEL);
|
||||
if (ERR_ALLOC_MEM(mpbuf)) {
|
||||
ILI_ERR("Failed to allocate mpbuf mem\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ipio_memcpy(mpbuf, txbuf, len, msgs[0].len);
|
||||
mpbuf[len] = check_sum;
|
||||
msgs[0].buf = mpbuf;
|
||||
ili_dump_data(mpbuf, 8, len+1, 0, "mp cdc cmd");
|
||||
msgs[0].len = len + 1;
|
||||
}
|
||||
|
||||
if (i2c_transfer(ilits->i2c->adapter, msgs, 1) != 1)
|
||||
ret = -1;
|
||||
|
||||
ipio_kfree((void **)&mpbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int core_i2c_read(void *buf, int len)
|
||||
{
|
||||
int ret;
|
||||
u8 *rxbuf = (u8 *)buf;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{
|
||||
.addr = ilits->i2c->addr,
|
||||
.flags = I2C_M_RD, /* read flag. */
|
||||
.len = len,
|
||||
.buf = rxbuf,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
#if I2C_DMA_TRANSFER
|
||||
if (len > 8) {
|
||||
msgs[0].addr = (ilits->client->addr & I2C_MASK_FLAG);
|
||||
msgs[0].ext_flag = (ilits->client->ext_flag | I2C_ENEXT_FLAG | I2C_DMA_FLAG);
|
||||
msgs[0].buf = (u8 *)ilitek_dma_pa;
|
||||
} else {
|
||||
msgs[0].buf = rxbuf;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
ret = i2c_transfer(ilits->i2c->adapter, msgs, 1);
|
||||
|
||||
#if I2C_DMA_TRANSFER
|
||||
if (len > 8)
|
||||
memcpy(rxbuf, ilitek_dma_va, len);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If i2c_transfer is ok (must return 1 because only sends one msg),
|
||||
* return #bytes transferred, else error code.
|
||||
*/
|
||||
return (ret == 1) ? len : ret;
|
||||
}
|
||||
|
||||
static int ilitek_i2c_write(void *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (len == 0) {
|
||||
ILI_ERR("i2c write len is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = core_i2c_write(buf, len);
|
||||
if (ret < 0) {
|
||||
if (atomic_read(&ilits->tp_reset) == START) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
ILI_ERR("i2c write error, ret = %d\n", ret);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ilitek_i2c_read(void *buf, int len)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (len == 0) {
|
||||
ILI_ERR("i2c read len is invalid\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = core_i2c_read(buf, len);
|
||||
if (ret < 0) {
|
||||
if (atomic_read(&ilits->tp_reset) == START) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
ILI_ERR("i2c read error, ret = %d\n", ret);
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ili_i2c_pll_clk_wakeup(void)
|
||||
{
|
||||
int ret = 0;
|
||||
u8 wakeup = 0xA3;
|
||||
#if (PLL_CLK_WAKEUP_TP_RESUME == ENABLE)
|
||||
if (ilits->pll_clk_wakeup == true) {
|
||||
#else
|
||||
if ((ilits->pll_clk_wakeup == true) && (ilits->tp_suspend == true)) {
|
||||
#endif
|
||||
ret = ilitek_i2c_write(&wakeup, sizeof(wakeup));
|
||||
if (ret < 0)
|
||||
ILI_ERR("i2c write dummy cmd error\n");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ili_i2c_wrapper(u8 *txbuf, u32 wlen, u8 *rxbuf, u32 rlen, bool spi_irq, bool i2c_irq)
|
||||
{
|
||||
int ret = 0, operate = -1;
|
||||
|
||||
if (wlen > 0) {
|
||||
if (ERR_ALLOC_MEM(txbuf)) {
|
||||
ILI_ERR("txbuf is null\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (rlen > 0) {
|
||||
if (ERR_ALLOC_MEM(rxbuf)) {
|
||||
ILI_ERR("rxbuf is null\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (wlen > 0 && rlen > 0)
|
||||
operate = RW_SYNC;
|
||||
else if (wlen > 0 && !rlen)
|
||||
operate = W_ONLY;
|
||||
else
|
||||
operate = R_ONLY;
|
||||
|
||||
if (ilits->int_pulse)
|
||||
ilits->detect_int_stat = ili_ic_check_int_pulse;
|
||||
else
|
||||
ilits->detect_int_stat = ili_ic_check_int_level;
|
||||
|
||||
if (i2c_irq)
|
||||
atomic_set(&ilits->cmd_int_check, ENABLE);
|
||||
|
||||
switch (operate) {
|
||||
case RW_SYNC:
|
||||
ret = ilitek_i2c_write(txbuf, wlen);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("i2c-wrapper write error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (i2c_irq) {
|
||||
if (ilits->detect_int_stat(false) < 0) {
|
||||
ILI_ERR("ERROR! Check INT timeout\n");
|
||||
ret = -ETIME;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
ret = ilitek_i2c_read(rxbuf, rlen);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("i2c-wrapper read error\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case W_ONLY:
|
||||
ret = ili_i2c_pll_clk_wakeup();
|
||||
if (ret < 0) {
|
||||
ILI_ERR("i2c-wrapper dummy cmd write error\n");
|
||||
}
|
||||
ret = ilitek_i2c_write(txbuf, wlen);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("i2c-wrapper write error\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case R_ONLY:
|
||||
if (i2c_irq) {
|
||||
if (ilits->detect_int_stat(false) < 0) {
|
||||
ILI_ERR("ERROR! Check INT timeout\n");
|
||||
ret = -ETIME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ilitek_i2c_read(rxbuf, rlen);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("i2c-wrapper read error\n");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ILI_ERR("Unknown ts-i2c operation\n");
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (i2c_irq)
|
||||
atomic_set(&ilits->cmd_int_check, DISABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ili_core_spi_setup(int num)
|
||||
{
|
||||
ILI_ERR("Not support this interface\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
|
||||
{
|
||||
struct touch_bus_info *info =
|
||||
container_of(to_i2c_driver(i2c->dev.driver),
|
||||
struct touch_bus_info, bus_driver);
|
||||
|
||||
ILI_INFO("ilitek i2c probe\n");
|
||||
|
||||
if (!i2c) {
|
||||
ILI_ERR("i2c client is NULL\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (i2c->addr != TDDI_I2C_ADDR) {
|
||||
i2c->addr = TDDI_I2C_ADDR;
|
||||
ILI_INFO("i2c addr doesn't be set up, use default : 0x%x\n", i2c->addr);
|
||||
}
|
||||
|
||||
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) {
|
||||
ILI_ERR("i2c functions are not supported!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ilits = devm_kzalloc(&i2c->dev, sizeof(struct ilitek_ts_data), GFP_KERNEL);
|
||||
if (ERR_ALLOC_MEM(ilits)) {
|
||||
ILI_ERR("Failed to allocate ts memory, %ld\n", PTR_ERR(ilits));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Used for receiving touch data only, do not mix up with others. */
|
||||
ilits->tr_buf = kzalloc(TR_BUF_SIZE, GFP_ATOMIC);
|
||||
if (ERR_ALLOC_MEM(ilits->tr_buf)) {
|
||||
ILI_ERR("failed to allocate touch report buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ilits->gcoord = kzalloc(sizeof(struct gesture_coordinate), GFP_KERNEL);
|
||||
if (ERR_ALLOC_MEM(ilits->gcoord)) {
|
||||
ILI_ERR("Failed to allocate gresture coordinate buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ilits->i2c = i2c;
|
||||
ilits->spi = NULL;
|
||||
ilits->dev = &i2c->dev;
|
||||
ilits->hwif = info->hwif;
|
||||
ilits->phys = "I2C";
|
||||
ilits->wrapper = ili_i2c_wrapper;
|
||||
ilits->detect_int_stat = ili_ic_check_int_pulse;
|
||||
ilits->int_pulse = true;
|
||||
ilits->mp_retry = false;
|
||||
|
||||
#if I2C_DMA_TRANSFER
|
||||
if (dma_i2c_alloc(ilits->i2c) < 0)
|
||||
ILI_ERR("Failed to alllocate DMA mem %ld\n", PTR_ERR(ilits->i2c));
|
||||
#endif
|
||||
|
||||
ilits->actual_tp_mode = P5_X_FW_AP_MODE;
|
||||
|
||||
if (TDDI_RST_BIND)
|
||||
ilits->reset = TP_IC_WHOLE_RST;
|
||||
else
|
||||
ilits->reset = TP_HW_RST_ONLY;
|
||||
|
||||
ilits->rst_edge_delay = 100;
|
||||
ilits->fw_open = FILP_OPEN;
|
||||
ilits->fw_upgrade_mode = UPGRADE_FLASH;
|
||||
ilits->mp_move_code = ili_move_mp_code_flash;
|
||||
ilits->gesture_move_code = ili_move_gesture_code_flash;
|
||||
ilits->esd_recover = ili_wq_esd_i2c_check;
|
||||
ilits->ges_recover = ili_touch_esd_gesture_flash;
|
||||
ilits->gesture_mode = DATA_FORMAT_GESTURE_INFO;
|
||||
ilits->gesture_demo_ctrl = DISABLE;
|
||||
ilits->wtd_ctrl = OFF;
|
||||
ilits->report = ENABLE;
|
||||
ilits->netlink = DISABLE;
|
||||
ilits->dnp = DISABLE;
|
||||
ilits->irq_tirgger_type = IRQF_TRIGGER_FALLING;
|
||||
ilits->info_from_hex = DISABLE;
|
||||
ilits->wait_int_timeout = AP_INT_TIMEOUT;
|
||||
|
||||
#if ENABLE_GESTURE
|
||||
ilits->gesture = DISABLE;
|
||||
ilits->ges_sym.double_tap = DOUBLE_TAP;
|
||||
ilits->ges_sym.alphabet_line_2_top = ALPHABET_LINE_2_TOP;
|
||||
ilits->ges_sym.alphabet_line_2_bottom = ALPHABET_LINE_2_BOTTOM;
|
||||
ilits->ges_sym.alphabet_line_2_left = ALPHABET_LINE_2_LEFT;
|
||||
ilits->ges_sym.alphabet_line_2_right = ALPHABET_LINE_2_RIGHT;
|
||||
ilits->ges_sym.alphabet_m = ALPHABET_M;
|
||||
ilits->ges_sym.alphabet_w = ALPHABET_W;
|
||||
ilits->ges_sym.alphabet_c = ALPHABET_C;
|
||||
ilits->ges_sym.alphabet_E = ALPHABET_E;
|
||||
ilits->ges_sym.alphabet_V = ALPHABET_V;
|
||||
ilits->ges_sym.alphabet_O = ALPHABET_O;
|
||||
ilits->ges_sym.alphabet_S = ALPHABET_S;
|
||||
ilits->ges_sym.alphabet_Z = ALPHABET_Z;
|
||||
ilits->ges_sym.alphabet_V_down = ALPHABET_V_DOWN;
|
||||
ilits->ges_sym.alphabet_V_left = ALPHABET_V_LEFT;
|
||||
ilits->ges_sym.alphabet_V_right = ALPHABET_V_RIGHT;
|
||||
ilits->ges_sym.alphabet_two_line_2_bottom = ALPHABET_TWO_LINE_2_BOTTOM;
|
||||
ilits->ges_sym.alphabet_F = ALPHABET_F;
|
||||
ilits->ges_sym.alphabet_AT = ALPHABET_AT;
|
||||
#endif
|
||||
|
||||
return info->hwif->plat_probe();
|
||||
}
|
||||
|
||||
static int ilitek_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
ILI_INFO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id tp_i2c_id[] = {
|
||||
{TDDI_DEV_ID, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
int ili_interface_dev_init(struct ilitek_hwif_info *hwif)
|
||||
{
|
||||
struct touch_bus_info *info;
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
ILI_ERR("faied to allocate i2c_driver\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (hwif->bus_type != BUS_I2C) {
|
||||
ILI_ERR("Not I2C dev\n");
|
||||
ipio_kfree((void **)&info);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hwif->info = info;
|
||||
|
||||
info->bus_driver.driver.name = hwif->name;
|
||||
info->bus_driver.driver.owner = hwif->owner;
|
||||
info->bus_driver.driver.of_match_table = hwif->of_match_table;
|
||||
info->bus_driver.driver.pm = hwif->pm;
|
||||
|
||||
info->bus_driver.probe = ilitek_i2c_probe;
|
||||
info->bus_driver.remove = ilitek_i2c_remove;
|
||||
info->bus_driver.id_table = tp_i2c_id;
|
||||
|
||||
info->hwif = hwif;
|
||||
return i2c_add_driver(&info->bus_driver);
|
||||
}
|
||||
|
||||
void ili_interface_dev_exit(struct ilitek_ts_data *ts)
|
||||
{
|
||||
struct touch_bus_info *info = (struct touch_bus_info *)ilits->hwif->info;
|
||||
|
||||
ILI_INFO("remove i2c dev\n");
|
||||
i2c_del_driver(&info->bus_driver);
|
||||
ipio_kfree((void **)&info);
|
||||
}
|
||||
1017
drivers/input/touchscreen/ili9882_mmi/ili9882_ic.c
Executable file
1017
drivers/input/touchscreen/ili9882_mmi/ili9882_ic.c
Executable file
File diff suppressed because it is too large
Load diff
3822
drivers/input/touchscreen/ili9882_mmi/ili9882_mp.c
Executable file
3822
drivers/input/touchscreen/ili9882_mmi/ili9882_mp.c
Executable file
File diff suppressed because it is too large
Load diff
459
drivers/input/touchscreen/ili9882_mmi/ili9882_mtk.c
Executable file
459
drivers/input/touchscreen/ili9882_mmi/ili9882_mtk.c
Executable file
|
|
@ -0,0 +1,459 @@
|
|||
/*
|
||||
* ILITEK Touch IC driver
|
||||
*
|
||||
* Copyright (C) 2011 ILI Technology Corporation.
|
||||
*
|
||||
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 "ili9882.h"
|
||||
#include "tpd.h"
|
||||
|
||||
#define DTS_INT_GPIO "touch,irq-gpio"
|
||||
#define DTS_RESET_GPIO "touch,reset-gpio"
|
||||
#define DTS_OF_NAME "mediatek,cap_touch"
|
||||
#define MTK_RST_GPIO GTP_RST_PORT
|
||||
#define MTK_INT_GPIO GTP_INT_PORT
|
||||
|
||||
extern struct tpd_device *tpd;
|
||||
|
||||
void ili_tp_reset(void)
|
||||
{
|
||||
ILI_INFO("edge delay = %d\n", ilits->rst_edge_delay);
|
||||
|
||||
/* Need accurate power sequence, do not change it to msleep */
|
||||
tpd_gpio_output(ilits->tp_rst, 1);
|
||||
mdelay(1);
|
||||
tpd_gpio_output(ilits->tp_rst, 0);
|
||||
mdelay(5);
|
||||
tpd_gpio_output(ilits->tp_rst, 1);
|
||||
mdelay(ilits->rst_edge_delay);
|
||||
}
|
||||
|
||||
void ili_input_register(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
ilits->input = tpd->dev;
|
||||
|
||||
if (tpd_dts_data.use_tpd_button) {
|
||||
for (i = 0; i < tpd_dts_data.tpd_key_num; i++)
|
||||
input_set_capability(ilits->input, EV_KEY, tpd_dts_data.tpd_key_local[i]);
|
||||
}
|
||||
|
||||
/* set the supported event type for input device */
|
||||
set_bit(EV_ABS, ilits->input->evbit);
|
||||
set_bit(EV_SYN, ilits->input->evbit);
|
||||
set_bit(EV_KEY, ilits->input->evbit);
|
||||
set_bit(BTN_TOUCH, ilits->input->keybit);
|
||||
set_bit(BTN_TOOL_FINGER, ilits->input->keybit);
|
||||
set_bit(INPUT_PROP_DIRECT, ilits->input->propbit);
|
||||
|
||||
if (MT_PRESSURE)
|
||||
input_set_abs_params(ilits->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
|
||||
|
||||
if (MT_B_TYPE) {
|
||||
#if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE
|
||||
input_mt_init_slots(ilits->input, MAX_TOUCH_NUM, INPUT_MT_DIRECT);
|
||||
#else
|
||||
input_mt_init_slots(ilits->input, MAX_TOUCH_NUM);
|
||||
#endif /* LINUX_VERSION_CODE */
|
||||
} else {
|
||||
input_set_abs_params(ilits->input, ABS_MT_TRACKING_ID, 0, MAX_TOUCH_NUM, 0, 0);
|
||||
}
|
||||
|
||||
/* Gesture keys register */
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_POWER);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_UP);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_DOWN);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_LEFT);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_RIGHT);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_O);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_E);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_M);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_W);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_S);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_V);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_Z);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_C);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_F);
|
||||
|
||||
__set_bit(KEY_GESTURE_POWER, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_UP, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_DOWN, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_LEFT, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_RIGHT, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_O, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_E, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_M, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_W, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_S, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_V, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_Z, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_C, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_F, ilits->input->keybit);
|
||||
}
|
||||
|
||||
#if REGULATOR_POWER
|
||||
void ili_plat_regulator_power_on(bool status)
|
||||
{
|
||||
ILI_INFO("%s\n", status ? "POWER ON" : "POWER OFF");
|
||||
|
||||
if (status) {
|
||||
if (ilits->vdd) {
|
||||
if (regulator_enable(ilits->vdd) < 0)
|
||||
ILI_ERR("regulator_enable VDD fail\n");
|
||||
}
|
||||
if (ilits->vcc) {
|
||||
if (regulator_enable(ilits->vcc) < 0)
|
||||
ILI_ERR("regulator_enable VCC fail\n");
|
||||
}
|
||||
} else {
|
||||
if (ilits->vdd) {
|
||||
if (regulator_disable(ilits->vdd) < 0)
|
||||
ILI_ERR("regulator_enable VDD fail\n");
|
||||
}
|
||||
if (ilits->vcc) {
|
||||
if (regulator_disable(ilits->vcc) < 0)
|
||||
ILI_ERR("regulator_enable VCC fail\n");
|
||||
}
|
||||
}
|
||||
atomic_set(&ilits->ice_stat, DISABLE);
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
static void ilitek_plat_regulator_power_init(void)
|
||||
{
|
||||
const char *vdd_name = "vdd";
|
||||
const char *vcc_name = "vcc";
|
||||
|
||||
ilits->vdd = regulator_get(tpd->tpd_dev, vdd_name);
|
||||
if (ERR_ALLOC_MEM(ilits->vdd)) {
|
||||
ILI_ERR("regulator_get VDD fail\n");
|
||||
ilits->vdd = NULL;
|
||||
}
|
||||
|
||||
tpd->reg = ilits->vdd;
|
||||
|
||||
if (regulator_set_voltage(ilits->vdd, VDD_VOLTAGE, VDD_VOLTAGE) < 0)
|
||||
ILI_ERR("Failed to set VDD %d\n", VDD_VOLTAGE);
|
||||
|
||||
ilits->vcc = regulator_get(ilits->dev, vcc_name);
|
||||
if (ERR_ALLOC_MEM(ilits->vcc)) {
|
||||
ILI_ERR("regulator_get VCC fail.\n");
|
||||
ilits->vcc = NULL;
|
||||
}
|
||||
if (regulator_set_voltage(ilits->vcc, VCC_VOLTAGE, VCC_VOLTAGE) < 0)
|
||||
ILI_ERR("Failed to set VCC %d\n", VCC_VOLTAGE);
|
||||
|
||||
ili_plat_regulator_power_on(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ilitek_plat_gpio_register(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ilits->tp_int = MTK_INT_GPIO;
|
||||
ilits->tp_rst = MTK_RST_GPIO;
|
||||
|
||||
ILI_INFO("TP INT: %d\n", ilits->tp_int);
|
||||
ILI_INFO("TP RESET: %d\n", ilits->tp_rst);
|
||||
|
||||
if (!gpio_is_valid(ilits->tp_int)) {
|
||||
ILI_ERR("Invalid INT gpio: %d\n", ilits->tp_int);
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
if (!gpio_is_valid(ilits->tp_rst)) {
|
||||
ILI_ERR("Invalid RESET gpio: %d\n", ilits->tp_rst);
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
gpio_direction_input(ilits->tp_int);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ili_irq_disable(void)
|
||||
{
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ilits->irq_spin, flag);
|
||||
|
||||
if (atomic_read(&ilits->irq_stat) == DISABLE)
|
||||
goto out;
|
||||
|
||||
if (!ilits->irq_num) {
|
||||
ILI_ERR("gpio_to_irq (%d) is incorrect\n", ilits->irq_num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
disable_irq_nosync(ilits->irq_num);
|
||||
atomic_set(&ilits->irq_stat, DISABLE);
|
||||
ILI_DBG("Disable irq success\n");
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&ilits->irq_spin, flag);
|
||||
}
|
||||
|
||||
void ili_irq_enable(void)
|
||||
{
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ilits->irq_spin, flag);
|
||||
|
||||
if (atomic_read(&ilits->irq_stat) == ENABLE)
|
||||
goto out;
|
||||
|
||||
if (!ilits->irq_num) {
|
||||
ILI_ERR("gpio_to_irq (%d) is incorrect\n", ilits->irq_num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
enable_irq(ilits->irq_num);
|
||||
atomic_set(&ilits->irq_stat, ENABLE);
|
||||
ILI_DBG("Enable irq success\n");
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&ilits->irq_spin, flag);
|
||||
}
|
||||
|
||||
static irqreturn_t ilitek_plat_isr_top_half(int irq, void *dev_id)
|
||||
{
|
||||
if (irq != ilits->irq_num) {
|
||||
ILI_ERR("Incorrect irq number (%d)\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (atomic_read(&ilits->cmd_int_check) == ENABLE) {
|
||||
atomic_set(&ilits->cmd_int_check, DISABLE);
|
||||
ILI_DBG("CMD INT detected, ignore\n");
|
||||
wake_up(&(ilits->inq));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (ilits->prox_near) {
|
||||
ILI_INFO("Proximity event, ignore interrupt!\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
ILI_DBG("report: %d, rst: %d, fw: %d, switch: %d, mp: %d, sleep: %d, esd: %d\n",
|
||||
ilits->report,
|
||||
atomic_read(&ilits->tp_reset),
|
||||
atomic_read(&ilits->fw_stat),
|
||||
atomic_read(&ilits->tp_sw_mode),
|
||||
atomic_read(&ilits->mp_stat),
|
||||
atomic_read(&ilits->tp_sleep),
|
||||
atomic_read(&ilits->esd_stat));
|
||||
|
||||
if (!ilits->report || atomic_read(&ilits->tp_reset) ||
|
||||
atomic_read(&ilits->fw_stat) || atomic_read(&ilits->tp_sw_mode) ||
|
||||
atomic_read(&ilits->mp_stat) || atomic_read(&ilits->tp_sleep) ||
|
||||
atomic_read(&ilits->esd_stat)) {
|
||||
ILI_DBG("ignore interrupt !\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t ilitek_plat_isr_bottom_half(int irq, void *dev_id)
|
||||
{
|
||||
if (mutex_is_locked(&ilits->touch_mutex)) {
|
||||
ILI_DBG("touch is locked, ignore\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
mutex_lock(&ilits->touch_mutex);
|
||||
ili_report_handler();
|
||||
mutex_unlock(&ilits->touch_mutex);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void ili_irq_unregister(void)
|
||||
{
|
||||
devm_free_irq(ilits->dev, ilits->irq_num, NULL);
|
||||
}
|
||||
|
||||
int ili_irq_register(int type)
|
||||
{
|
||||
int ret = 0;
|
||||
static bool get_irq_pin;
|
||||
struct device_node *node;
|
||||
|
||||
atomic_set(&ilits->irq_stat, DISABLE);
|
||||
|
||||
if (get_irq_pin == false) {
|
||||
node = of_find_matching_node(NULL, touch_of_match);
|
||||
if (node)
|
||||
ilits->irq_num = irq_of_parse_and_map(node, 0);
|
||||
|
||||
ILI_INFO("ilits->irq_num = %d\n", ilits->irq_num);
|
||||
get_irq_pin = true;
|
||||
}
|
||||
|
||||
ret = devm_request_threaded_irq(ilits->dev, ilits->irq_num,
|
||||
ilitek_plat_isr_top_half,
|
||||
ilitek_plat_isr_bottom_half,
|
||||
type | IRQF_ONESHOT, "ilitek", NULL);
|
||||
|
||||
if (type == IRQF_TRIGGER_FALLING)
|
||||
ILI_INFO("IRQ TYPE = IRQF_TRIGGER_FALLING\n");
|
||||
if (type == IRQF_TRIGGER_RISING)
|
||||
ILI_INFO("IRQ TYPE = IRQF_TRIGGER_RISING\n");
|
||||
|
||||
if (ret != 0)
|
||||
ILI_ERR("Failed to register irq handler, irq = %d, ret = %d\n", ilits->irq_num, ret);
|
||||
|
||||
atomic_set(&ilits->irq_stat, ENABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void tpd_resume(struct device *h)
|
||||
{
|
||||
if (ili_sleep_handler(TP_RESUME) < 0)
|
||||
ILI_ERR("TP resume failed\n");
|
||||
}
|
||||
|
||||
static void tpd_suspend(struct device *h)
|
||||
{
|
||||
if (ili_sleep_handler(TP_SUSPEND) < 0)
|
||||
ILI_ERR("TP suspend failed\n");
|
||||
}
|
||||
|
||||
static int ilitek_tp_pm_suspend(struct device *dev)
|
||||
{
|
||||
ILI_INFO("CALL BACK TP PM SUSPEND");
|
||||
ilits->pm_suspend = true;
|
||||
reinit_completion(&ilits->pm_completion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tp_pm_resume(struct device *dev)
|
||||
{
|
||||
ILI_INFO("CALL BACK TP PM RESUME");
|
||||
ilits->pm_suspend = false;
|
||||
complete(&ilits->pm_completion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_plat_probe(void)
|
||||
{
|
||||
ILI_INFO("platform probe\n");
|
||||
|
||||
#if REGULATOR_POWER
|
||||
ilitek_plat_regulator_power_init();
|
||||
#endif
|
||||
|
||||
if (ilitek_plat_gpio_register() < 0)
|
||||
ILI_ERR("Register gpio failed\n");
|
||||
|
||||
ili_irq_register(ilits->irq_tirgger_type);
|
||||
|
||||
if (ili_tddi_init() < 0) {
|
||||
ILI_ERR("ILITEK Driver probe failed\n");
|
||||
ili_irq_unregister();
|
||||
return -ENODEV;
|
||||
}
|
||||
tpd_load_status = 1;
|
||||
ilits->pm_suspend = false;
|
||||
init_completion(&ilits->pm_completion);
|
||||
|
||||
ILI_INFO("ILITEK Driver loaded successfully!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_plat_remove(void)
|
||||
{
|
||||
ILI_INFO("remove plat dev\n");
|
||||
ili_dev_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tp_pm_ops = {
|
||||
.suspend = ilitek_tp_pm_suspend,
|
||||
.resume = ilitek_tp_pm_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id tp_match_table[] = {
|
||||
{.compatible = DTS_OF_NAME},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct ilitek_hwif_info hwif = {
|
||||
.bus_type = TDDI_INTERFACE,
|
||||
.plat_type = TP_PLAT_MTK,
|
||||
.owner = THIS_MODULE,
|
||||
.name = TDDI_DEV_ID,
|
||||
.of_match_table = of_match_ptr(tp_match_table),
|
||||
.plat_probe = ilitek_plat_probe,
|
||||
.plat_remove = ilitek_plat_remove,
|
||||
.pm = &tp_pm_ops,
|
||||
};
|
||||
|
||||
static int tpd_local_init(void)
|
||||
{
|
||||
ILI_INFO("TPD init device driver\n");
|
||||
|
||||
if (ili_dev_init(&hwif) < 0) {
|
||||
ILI_ERR("Failed to register i2c/spi bus driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (tpd_load_status == 0) {
|
||||
ILI_ERR("Add error touch panel driver\n");
|
||||
return -1;
|
||||
}
|
||||
if (tpd_dts_data.use_tpd_button) {
|
||||
tpd_button_setting(tpd_dts_data.tpd_key_num, tpd_dts_data.tpd_key_local,
|
||||
tpd_dts_data.tpd_key_dim_local);
|
||||
}
|
||||
tpd_type_cap = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct tpd_driver_t tpd_device_driver = {
|
||||
.tpd_device_name = TDDI_DEV_ID,
|
||||
.tpd_local_init = tpd_local_init,
|
||||
.suspend = tpd_suspend,
|
||||
.resume = tpd_resume,
|
||||
};
|
||||
|
||||
static int __init ilitek_plat_dev_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ILI_INFO("ILITEK TP driver init for MTK\n");
|
||||
tpd_get_dts_info();
|
||||
ret = tpd_driver_add(&tpd_device_driver);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("ILITEK add TP driver failed\n");
|
||||
tpd_driver_remove(&tpd_device_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ilitek_plat_dev_exit(void)
|
||||
{
|
||||
ILI_INFO("ilitek driver has been removed\n");
|
||||
tpd_driver_remove(&tpd_device_driver);
|
||||
}
|
||||
|
||||
module_init(ilitek_plat_dev_init);
|
||||
module_exit(ilitek_plat_dev_exit);
|
||||
MODULE_AUTHOR("ILITEK");
|
||||
MODULE_LICENSE("GPL");
|
||||
2587
drivers/input/touchscreen/ili9882_mmi/ili9882_node.c
Executable file
2587
drivers/input/touchscreen/ili9882_mmi/ili9882_node.c
Executable file
File diff suppressed because it is too large
Load diff
758
drivers/input/touchscreen/ili9882_mmi/ili9882_qcom.c
Executable file
758
drivers/input/touchscreen/ili9882_mmi/ili9882_qcom.c
Executable file
|
|
@ -0,0 +1,758 @@
|
|||
/*
|
||||
* ILITEK Touch IC driver
|
||||
*
|
||||
* Copyright (C) 2011 ILI Technology Corporation.
|
||||
*
|
||||
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 "ili9882.h"
|
||||
|
||||
#define DTS_INT_GPIO "touch,irq-gpio"
|
||||
#define DTS_RESET_GPIO "touch,reset-gpio"
|
||||
#define DTS_OF_NAME "tchip,ilitek"
|
||||
|
||||
void ili_tp_reset(void)
|
||||
{
|
||||
ILI_INFO("edge delay = %d\n", ilits->rst_edge_delay);
|
||||
|
||||
/* Need accurate power sequence, do not change it to msleep */
|
||||
gpio_direction_output(ilits->tp_rst, 1);
|
||||
mdelay(1);
|
||||
gpio_set_value(ilits->tp_rst, 0);
|
||||
mdelay(5);
|
||||
gpio_set_value(ilits->tp_rst, 1);
|
||||
mdelay(ilits->rst_edge_delay);
|
||||
}
|
||||
|
||||
void ili_input_register(void)
|
||||
{
|
||||
ILI_INFO();
|
||||
|
||||
ilits->input = input_allocate_device();
|
||||
if (ERR_ALLOC_MEM(ilits->input)) {
|
||||
ILI_ERR("Failed to allocate touch input device\n");
|
||||
input_free_device(ilits->input);
|
||||
return;
|
||||
}
|
||||
|
||||
ilits->input->name = ilits->hwif->name;
|
||||
ilits->input->phys = ilits->phys;
|
||||
ilits->input->dev.parent = ilits->dev;
|
||||
ilits->input->id.bustype = ilits->hwif->bus_type;
|
||||
|
||||
/* set the supported event type for input device */
|
||||
set_bit(EV_ABS, ilits->input->evbit);
|
||||
set_bit(EV_SYN, ilits->input->evbit);
|
||||
set_bit(EV_KEY, ilits->input->evbit);
|
||||
set_bit(BTN_TOUCH, ilits->input->keybit);
|
||||
set_bit(BTN_TOOL_FINGER, ilits->input->keybit);
|
||||
set_bit(INPUT_PROP_DIRECT, ilits->input->propbit);
|
||||
|
||||
input_set_abs_params(ilits->input, ABS_MT_POSITION_X, TOUCH_SCREEN_X_MIN, ilits->panel_wid - 1, 0, 0);
|
||||
input_set_abs_params(ilits->input, ABS_MT_POSITION_Y, TOUCH_SCREEN_Y_MIN, ilits->panel_hei - 1, 0, 0);
|
||||
input_set_abs_params(ilits->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
|
||||
input_set_abs_params(ilits->input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
|
||||
|
||||
if (MT_PRESSURE)
|
||||
input_set_abs_params(ilits->input, ABS_MT_PRESSURE, 0, 255, 0, 0);
|
||||
|
||||
if (MT_B_TYPE) {
|
||||
#if KERNEL_VERSION(3, 7, 0) <= LINUX_VERSION_CODE
|
||||
input_mt_init_slots(ilits->input, MAX_TOUCH_NUM, INPUT_MT_DIRECT);
|
||||
#else
|
||||
input_mt_init_slots(ilits->input, MAX_TOUCH_NUM);
|
||||
#endif /* LINUX_VERSION_CODE */
|
||||
} else {
|
||||
input_set_abs_params(ilits->input, ABS_MT_TRACKING_ID, 0, MAX_TOUCH_NUM, 0, 0);
|
||||
}
|
||||
|
||||
/* Gesture keys register */
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_POWER);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_UP);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_DOWN);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_LEFT);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_RIGHT);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_O);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_E);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_M);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_W);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_S);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_V);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_Z);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_C);
|
||||
input_set_capability(ilits->input, EV_KEY, KEY_GESTURE_F);
|
||||
|
||||
__set_bit(KEY_GESTURE_POWER, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_UP, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_DOWN, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_LEFT, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_RIGHT, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_O, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_E, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_M, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_W, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_S, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_V, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_Z, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_C, ilits->input->keybit);
|
||||
__set_bit(KEY_GESTURE_F, ilits->input->keybit);
|
||||
|
||||
/* register the input device to input sub-system */
|
||||
if (input_register_device(ilits->input) < 0) {
|
||||
ILI_ERR("Failed to register touch input device\n");
|
||||
input_unregister_device(ilits->input);
|
||||
input_free_device(ilits->input);
|
||||
}
|
||||
}
|
||||
|
||||
#if REGULATOR_POWER
|
||||
void ili_plat_regulator_power_on(bool status)
|
||||
{
|
||||
ILI_INFO("%s\n", status ? "POWER ON" : "POWER OFF");
|
||||
|
||||
if (status) {
|
||||
if (ilits->vdd) {
|
||||
if (regulator_enable(ilits->vdd) < 0)
|
||||
ILI_ERR("regulator_enable VDD fail\n");
|
||||
}
|
||||
if (ilits->vcc) {
|
||||
if (regulator_enable(ilits->vcc) < 0)
|
||||
ILI_ERR("regulator_enable VCC fail\n");
|
||||
}
|
||||
} else {
|
||||
if (ilits->vdd) {
|
||||
if (regulator_disable(ilits->vdd) < 0)
|
||||
ILI_ERR("regulator_enable VDD fail\n");
|
||||
}
|
||||
if (ilits->vcc) {
|
||||
if (regulator_disable(ilits->vcc) < 0)
|
||||
ILI_ERR("regulator_enable VCC fail\n");
|
||||
}
|
||||
}
|
||||
atomic_set(&ilits->ice_stat, DISABLE);
|
||||
mdelay(5);
|
||||
}
|
||||
|
||||
static void ilitek_plat_regulator_power_init(void)
|
||||
{
|
||||
const char *vdd_name = "vdd";
|
||||
const char *vcc_name = "vcc";
|
||||
|
||||
ilits->vdd = regulator_get(ilits->dev, vdd_name);
|
||||
if (ERR_ALLOC_MEM(ilits->vdd)) {
|
||||
ILI_ERR("regulator_get VDD fail\n");
|
||||
ilits->vdd = NULL;
|
||||
}
|
||||
if (regulator_set_voltage(ilits->vdd, VDD_VOLTAGE, VDD_VOLTAGE) < 0)
|
||||
ILI_ERR("Failed to set VDD %d\n", VDD_VOLTAGE);
|
||||
|
||||
ilits->vcc = regulator_get(ilits->dev, vcc_name);
|
||||
if (ERR_ALLOC_MEM(ilits->vcc)) {
|
||||
ILI_ERR("regulator_get VCC fail.\n");
|
||||
ilits->vcc = NULL;
|
||||
}
|
||||
if (regulator_set_voltage(ilits->vcc, VCC_VOLTAGE, VCC_VOLTAGE) < 0)
|
||||
ILI_ERR("Failed to set VCC %d\n", VCC_VOLTAGE);
|
||||
|
||||
ili_plat_regulator_power_on(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ilitek_plat_gpio_register(void)
|
||||
{
|
||||
int ret = 0;
|
||||
u32 flag;
|
||||
struct device_node *dev_node = ilits->dev->of_node;
|
||||
|
||||
ilits->tp_int = of_get_named_gpio_flags(dev_node, DTS_INT_GPIO, 0, &flag);
|
||||
ilits->tp_rst = of_get_named_gpio_flags(dev_node, DTS_RESET_GPIO, 0, &flag);
|
||||
|
||||
ILI_INFO("TP INT: %d\n", ilits->tp_int);
|
||||
ILI_INFO("TP RESET: %d\n", ilits->tp_rst);
|
||||
|
||||
if (!gpio_is_valid(ilits->tp_int)) {
|
||||
ILI_ERR("Invalid INT gpio: %d\n", ilits->tp_int);
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
if (!gpio_is_valid(ilits->tp_rst)) {
|
||||
ILI_ERR("Invalid RESET gpio: %d\n", ilits->tp_rst);
|
||||
return -EBADR;
|
||||
}
|
||||
|
||||
ret = gpio_request(ilits->tp_int, "TP_INT");
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Request IRQ GPIO failed, ret = %d\n", ret);
|
||||
gpio_free(ilits->tp_int);
|
||||
ret = gpio_request(ilits->tp_int, "TP_INT");
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Retrying request INT GPIO still failed , ret = %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
ret = gpio_request(ilits->tp_rst, "TP_RESET");
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Request RESET GPIO failed, ret = %d\n", ret);
|
||||
gpio_free(ilits->tp_rst);
|
||||
ret = gpio_request(ilits->tp_rst, "TP_RESET");
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Retrying request RESET GPIO still failed , ret = %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
gpio_direction_input(ilits->tp_int);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ili_irq_disable(void)
|
||||
{
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ilits->irq_spin, flag);
|
||||
|
||||
if (atomic_read(&ilits->irq_stat) == DISABLE)
|
||||
goto out;
|
||||
|
||||
if (!ilits->irq_num) {
|
||||
ILI_ERR("gpio_to_irq (%d) is incorrect\n", ilits->irq_num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
disable_irq_nosync(ilits->irq_num);
|
||||
atomic_set(&ilits->irq_stat, DISABLE);
|
||||
ILI_DBG("Disable irq success\n");
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&ilits->irq_spin, flag);
|
||||
}
|
||||
|
||||
void ili_irq_enable(void)
|
||||
{
|
||||
unsigned long flag;
|
||||
|
||||
spin_lock_irqsave(&ilits->irq_spin, flag);
|
||||
|
||||
if (atomic_read(&ilits->irq_stat) == ENABLE)
|
||||
goto out;
|
||||
|
||||
if (!ilits->irq_num) {
|
||||
ILI_ERR("gpio_to_irq (%d) is incorrect\n", ilits->irq_num);
|
||||
goto out;
|
||||
}
|
||||
|
||||
enable_irq(ilits->irq_num);
|
||||
atomic_set(&ilits->irq_stat, ENABLE);
|
||||
ILI_DBG("Enable irq success\n");
|
||||
|
||||
out:
|
||||
spin_unlock_irqrestore(&ilits->irq_spin, flag);
|
||||
}
|
||||
|
||||
static irqreturn_t ilitek_plat_isr_top_half(int irq, void *dev_id)
|
||||
{
|
||||
if (irq != ilits->irq_num) {
|
||||
ILI_ERR("Incorrect irq number (%d)\n", irq);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
if (atomic_read(&ilits->cmd_int_check) == ENABLE) {
|
||||
atomic_set(&ilits->cmd_int_check, DISABLE);
|
||||
ILI_DBG("CMD INT detected, ignore\n");
|
||||
wake_up(&(ilits->inq));
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (ilits->prox_near) {
|
||||
ILI_INFO("Proximity event, ignore interrupt!\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
ILI_DBG("report: %d, rst: %d, fw: %d, switch: %d, mp: %d, sleep: %d, esd: %d\n",
|
||||
ilits->report,
|
||||
atomic_read(&ilits->tp_reset),
|
||||
atomic_read(&ilits->fw_stat),
|
||||
atomic_read(&ilits->tp_sw_mode),
|
||||
atomic_read(&ilits->mp_stat),
|
||||
atomic_read(&ilits->tp_sleep),
|
||||
atomic_read(&ilits->esd_stat));
|
||||
|
||||
if (!ilits->report || atomic_read(&ilits->tp_reset) ||
|
||||
atomic_read(&ilits->fw_stat) || atomic_read(&ilits->tp_sw_mode) ||
|
||||
atomic_read(&ilits->mp_stat) || atomic_read(&ilits->tp_sleep) ||
|
||||
atomic_read(&ilits->esd_stat)) {
|
||||
ILI_DBG("ignore interrupt !\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
return IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
static irqreturn_t ilitek_plat_isr_bottom_half(int irq, void *dev_id)
|
||||
{
|
||||
if (mutex_is_locked(&ilits->touch_mutex)) {
|
||||
ILI_DBG("touch is locked, ignore\n");
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
mutex_lock(&ilits->touch_mutex);
|
||||
ili_report_handler();
|
||||
mutex_unlock(&ilits->touch_mutex);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
void ili_irq_unregister(void)
|
||||
{
|
||||
devm_free_irq(ilits->dev, ilits->irq_num, NULL);
|
||||
}
|
||||
|
||||
int ili_irq_register(int type)
|
||||
{
|
||||
int ret = 0;
|
||||
static bool get_irq_pin;
|
||||
|
||||
atomic_set(&ilits->irq_stat, DISABLE);
|
||||
|
||||
if (get_irq_pin == false) {
|
||||
ilits->irq_num = gpio_to_irq(ilits->tp_int);
|
||||
get_irq_pin = true;
|
||||
}
|
||||
|
||||
ILI_INFO("ilits->irq_num = %d\n", ilits->irq_num);
|
||||
|
||||
ret = devm_request_threaded_irq(ilits->dev, ilits->irq_num,
|
||||
ilitek_plat_isr_top_half,
|
||||
ilitek_plat_isr_bottom_half,
|
||||
type | IRQF_ONESHOT, "ilitek", NULL);
|
||||
|
||||
if (type == IRQF_TRIGGER_FALLING)
|
||||
ILI_INFO("IRQ TYPE = IRQF_TRIGGER_FALLING\n");
|
||||
if (type == IRQF_TRIGGER_RISING)
|
||||
ILI_INFO("IRQ TYPE = IRQF_TRIGGER_RISING\n");
|
||||
|
||||
if (ret != 0)
|
||||
ILI_ERR("Failed to register irq handler, irq = %d, ret = %d\n", ilits->irq_num, ret);
|
||||
|
||||
atomic_set(&ilits->irq_stat, ENABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if SPRD_SYSFS_SUSPEND_RESUME
|
||||
static ssize_t ts_suspend_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%s\n", ilits->tp_suspend ? "true" : "false");
|
||||
}
|
||||
|
||||
static ssize_t ts_suspend_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
if ((buf[0] == '1') && !ilits->tp_suspend)
|
||||
ili_sleep_handler(TP_DEEP_SLEEP);
|
||||
else if ((buf[0] == '0') && ilits->tp_suspend)
|
||||
ili_sleep_handler(TP_RESUME);
|
||||
|
||||
return count;
|
||||
}
|
||||
static DEVICE_ATTR_RW(ts_suspend);
|
||||
|
||||
static struct attribute *ilitek_dev_suspend_atts[] = {
|
||||
&dev_attr_ts_suspend.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group ilitek_dev_suspend_atts_group = {
|
||||
.attrs = ilitek_dev_suspend_atts,
|
||||
};
|
||||
|
||||
static const struct attribute_group *ilitek_dev_attr_groups[] = {
|
||||
&ilitek_dev_suspend_atts_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
int ili_sysfs_add_device(struct device *dev) {
|
||||
int ret = 0, i;
|
||||
|
||||
for (i = 0; ilitek_dev_attr_groups[i]; i++) {
|
||||
ret = sysfs_create_group(&dev->kobj, ilitek_dev_attr_groups[i]);
|
||||
if (ret) {
|
||||
while (--i >= 0) {
|
||||
sysfs_remove_group(&dev->kobj, ilitek_dev_attr_groups[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ili_sysfs_remove_device(struct device *dev) {
|
||||
int i;
|
||||
|
||||
sysfs_remove_link(NULL, "touchscreen");
|
||||
for (i = 0; ilitek_dev_attr_groups[i]; i++) {
|
||||
sysfs_remove_group(&dev->kobj, ilitek_dev_attr_groups[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_DRM
|
||||
static int ilitek_plat_notifier_fb(struct notifier_block *self, unsigned long event, void *data)
|
||||
{
|
||||
int *blank;
|
||||
struct drm_panel_notifier *evdata = data;
|
||||
|
||||
ILI_INFO("Notifier's event = %ld\n", event);
|
||||
|
||||
if (!(evdata && evdata->data))
|
||||
return 0;
|
||||
|
||||
blank = evdata->data;
|
||||
|
||||
switch (*blank) {
|
||||
case DRM_PANEL_BLANK_POWERDOWN:
|
||||
/*
|
||||
if (TP_SUSPEND_PRIO) {
|
||||
if (event != MSM_DRM_EARLY_EVENT_BLANK)
|
||||
return NOTIFY_DONE;
|
||||
} else {
|
||||
if (event != MSM_DRM_EVENT_BLANK)
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
*/
|
||||
if (event == DRM_PANEL_EARLY_EVENT_BLANK)
|
||||
if (ili_sleep_handler(TP_SUSPEND) < 0)
|
||||
ILI_ERR("TP suspend failed\n");
|
||||
break;
|
||||
|
||||
case DRM_PANEL_BLANK_UNBLANK:
|
||||
if (event == DRM_PANEL_EVENT_BLANK)
|
||||
{
|
||||
if (ili_sleep_handler(TP_RESUME) < 0)
|
||||
ILI_ERR("TP resume failed\n");
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ILI_ERR("Unknown event, blank = %d\n", *blank);
|
||||
break;
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#else
|
||||
|
||||
#if defined(CONFIG_FB) || defined(CONFIG_DRM_MSM)
|
||||
static int ilitek_plat_notifier_fb(struct notifier_block *self, unsigned long event, void *data)
|
||||
{
|
||||
int *blank;
|
||||
struct fb_event *evdata = data;
|
||||
|
||||
ILI_INFO("Notifier's event = %ld\n", event);
|
||||
|
||||
/*
|
||||
* FB_EVENT_BLANK(0x09): A hardware display blank change occurred.
|
||||
* FB_EARLY_EVENT_BLANK(0x10): A hardware display blank early change occurred.
|
||||
*/
|
||||
if (evdata && evdata->data) {
|
||||
blank = evdata->data;
|
||||
switch (*blank) {
|
||||
#ifdef CONFIG_DRM_MSM
|
||||
case MSM_DRM_BLANK_POWERDOWN:
|
||||
#else
|
||||
case FB_BLANK_POWERDOWN:
|
||||
#endif
|
||||
#if CONFIG_PLAT_SPRD
|
||||
case DRM_MODE_DPMS_OFF:
|
||||
#endif /* CONFIG_PLAT_SPRD */
|
||||
if (TP_SUSPEND_PRIO) {
|
||||
#ifdef CONFIG_DRM_MSM
|
||||
if (event != MSM_DRM_EARLY_EVENT_BLANK)
|
||||
#else
|
||||
if (event != FB_EARLY_EVENT_BLANK)
|
||||
#endif
|
||||
return NOTIFY_DONE;
|
||||
} else {
|
||||
#ifdef CONFIG_DRM_MSM
|
||||
if (event != MSM_DRM_EVENT_BLANK)
|
||||
#else
|
||||
if (event != FB_EVENT_BLANK)
|
||||
#endif
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
if (ili_sleep_handler(TP_SUSPEND) < 0)
|
||||
ILI_ERR("TP suspend failed\n");
|
||||
break;
|
||||
#ifdef CONFIG_DRM_MSM
|
||||
case MSM_DRM_BLANK_UNBLANK:
|
||||
case MSM_DRM_BLANK_NORMAL:
|
||||
#else
|
||||
case FB_BLANK_UNBLANK:
|
||||
case FB_BLANK_NORMAL:
|
||||
#endif
|
||||
|
||||
#if CONFIG_PLAT_SPRD
|
||||
case DRM_MODE_DPMS_ON:
|
||||
#endif /* CONFIG_PLAT_SPRD */
|
||||
|
||||
#ifdef CONFIG_DRM_MSM
|
||||
if (event == MSM_DRM_EVENT_BLANK)
|
||||
#else
|
||||
if (event == FB_EVENT_BLANK)
|
||||
#endif
|
||||
{
|
||||
if (ili_sleep_handler(TP_RESUME) < 0)
|
||||
ILI_ERR("TP resume failed\n");
|
||||
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ILI_ERR("Unknown event, blank = %d\n", *blank);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
#else
|
||||
static void ilitek_plat_early_suspend(struct early_suspend *h)
|
||||
{
|
||||
if (ili_sleep_handler(TP_SUSPEND) < 0)
|
||||
ILI_ERR("TP suspend failed\n");
|
||||
}
|
||||
|
||||
static void ilitek_plat_late_resume(struct early_suspend *h)
|
||||
{
|
||||
if (ili_sleep_handler(TP_RESUME) < 0)
|
||||
ILI_ERR("TP resume failed\n");
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static void ilitek_plat_sleep_init(void)
|
||||
{
|
||||
ILI_INFO("Init notifier_fb struct\n");
|
||||
ilits->notifier_fb.notifier_call = ilitek_plat_notifier_fb;
|
||||
#if defined(CONFIG_DRM)
|
||||
{
|
||||
int ret = 0;
|
||||
extern struct drm_panel *ili_active_panel;
|
||||
if (ili_active_panel) {
|
||||
ret = drm_panel_notifier_register(ili_active_panel, &ilits->notifier_fb);
|
||||
if(ret) {
|
||||
ILI_ERR("register drm_notifier failed. ret=%d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#if defined(CONFIG_FB) || defined(CONFIG_DRM_MSM)
|
||||
#if defined(CONFIG_DRM_MSM)
|
||||
if (msm_drm_register_client(&ilits->notifier_fb)) {
|
||||
ILI_ERR("msm_drm_register_client Unable to register fb_notifier\n");
|
||||
}
|
||||
#else
|
||||
#if CONFIG_PLAT_SPRD
|
||||
if (adf_register_client(&ilits->notifier_fb))
|
||||
ILI_ERR("Unable to register notifier_fb\n");
|
||||
#else
|
||||
if (fb_register_client(&ilits->notifier_fb))
|
||||
ILI_ERR("Unable to register notifier_fb\n");
|
||||
#endif /* CONFIG_PLAT_SPRD */
|
||||
#endif /* CONFIG_DRM_MSM */
|
||||
#else
|
||||
ILI_INFO("Init eqarly_suspend struct\n");
|
||||
ilits->early_suspend.suspend = ilitek_plat_early_suspend;
|
||||
ilits->early_suspend.resume = ilitek_plat_late_resume;
|
||||
ilits->early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN + 1;
|
||||
register_early_suspend(&ilits->early_suspend);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#if CHARGER_NOTIFIER_CALLBACK
|
||||
#if KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE
|
||||
/* add_for_charger_start */
|
||||
static int ilitek_charger_notifier_callback(struct notifier_block *nb,
|
||||
unsigned long val, void *v) {
|
||||
int ret = 0;
|
||||
struct power_supply *psy = NULL;
|
||||
union power_supply_propval prop;
|
||||
|
||||
|
||||
if(ilits->fw_update_stat != 100)
|
||||
return 0;
|
||||
|
||||
psy= power_supply_get_by_name("usb");
|
||||
if (!psy) {
|
||||
ILI_ERR("Couldn't get usbpsy\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!strcmp(psy->desc->name, "usb")) {
|
||||
if (psy && val == POWER_SUPPLY_PROP_STATUS) {
|
||||
ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_PRESENT,&prop);
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Couldn't get POWER_SUPPLY_PROP_ONLINE rc=%d\n", ret);
|
||||
return ret;
|
||||
} else {
|
||||
if(ilits->usb_plug_status == 2)
|
||||
ilits->usb_plug_status = prop.intval;
|
||||
if(ilits->usb_plug_status != prop.intval) {
|
||||
ILI_INFO("usb prop.intval =%d\n", prop.intval);
|
||||
ilits->usb_plug_status = prop.intval;
|
||||
if(!ilits->tp_suspend && (ilits->charger_notify_wq != NULL))
|
||||
queue_work(ilits->charger_notify_wq,&ilits->update_charger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static void ilitek_update_charger(struct work_struct *work)
|
||||
{
|
||||
int ret = 0;
|
||||
mutex_lock(&ilits->touch_mutex);
|
||||
ret = ili_ic_func_ctrl("plug", !ilits->usb_plug_status);// plug in
|
||||
if(ret<0) {
|
||||
ILI_ERR("Write plug in failed\n");
|
||||
}
|
||||
mutex_unlock(&ilits->touch_mutex);
|
||||
}
|
||||
void ilitek_plat_charger_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
ilits->usb_plug_status = 2;
|
||||
ilits->charger_notify_wq = create_singlethread_workqueue("ili_charger_wq");
|
||||
if (!ilits->charger_notify_wq) {
|
||||
ILI_ERR("allocate ili_charger_notify_wq failed\n");
|
||||
return;
|
||||
}
|
||||
INIT_WORK(&ilits->update_charger, ilitek_update_charger);
|
||||
ilits->notifier_charger.notifier_call = ilitek_charger_notifier_callback;
|
||||
ret = power_supply_reg_notifier(&ilits->notifier_charger);
|
||||
if (ret < 0)
|
||||
ILI_ERR("power_supply_reg_notifier failed\n");
|
||||
}
|
||||
/* add_for_charger_end */
|
||||
#endif
|
||||
#endif
|
||||
static int ilitek_plat_probe(void)
|
||||
{
|
||||
ILI_INFO("platform probe\n");
|
||||
|
||||
#if REGULATOR_POWER
|
||||
ilitek_plat_regulator_power_init();
|
||||
#endif
|
||||
|
||||
if (ilitek_plat_gpio_register() < 0)
|
||||
ILI_ERR("Register gpio failed\n");
|
||||
|
||||
ili_irq_register(ilits->irq_tirgger_type);
|
||||
|
||||
if (ili_tddi_init() < 0) {
|
||||
ILI_ERR("ILITEK Driver probe failed\n");
|
||||
ili_irq_unregister();
|
||||
return -ENODEV;
|
||||
}
|
||||
#if SPRD_SYSFS_SUSPEND_RESUME
|
||||
ili_sysfs_add_device(ilits->dev);
|
||||
if (sysfs_create_link(NULL, &ilits->dev->kobj, "touchscreen") < 0)
|
||||
ILI_INFO("Failed to create link!\n");
|
||||
#else
|
||||
ilitek_plat_sleep_init();
|
||||
#endif
|
||||
ilits->pm_suspend = false;
|
||||
init_completion(&ilits->pm_completion);
|
||||
#if CHARGER_NOTIFIER_CALLBACK
|
||||
#if KERNEL_VERSION(4, 1, 0) <= LINUX_VERSION_CODE
|
||||
/* add_for_charger_start */
|
||||
ilitek_plat_charger_init();
|
||||
/* add_for_charger_end */
|
||||
#endif
|
||||
#endif
|
||||
ILI_INFO("ILITEK Driver loaded successfully!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tp_pm_suspend(struct device *dev)
|
||||
{
|
||||
ILI_INFO("CALL BACK TP PM SUSPEND");
|
||||
ilits->pm_suspend = true;
|
||||
reinit_completion(&ilits->pm_completion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_tp_pm_resume(struct device *dev)
|
||||
{
|
||||
ILI_INFO("CALL BACK TP PM RESUME");
|
||||
ilits->pm_suspend = false;
|
||||
complete(&ilits->pm_completion);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ilitek_plat_remove(void)
|
||||
{
|
||||
ILI_INFO("remove plat dev\n");
|
||||
#if SPRD_SYSFS_SUSPEND_RESUME
|
||||
ili_sysfs_remove_device(ilits->dev);
|
||||
#endif
|
||||
ili_dev_remove();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops tp_pm_ops = {
|
||||
.suspend = ilitek_tp_pm_suspend,
|
||||
.resume = ilitek_tp_pm_resume,
|
||||
};
|
||||
|
||||
static const struct of_device_id tp_match_table[] = {
|
||||
{.compatible = DTS_OF_NAME},
|
||||
{},
|
||||
};
|
||||
|
||||
static struct ilitek_hwif_info hwif = {
|
||||
.bus_type = TDDI_INTERFACE,
|
||||
.plat_type = TP_PLAT_QCOM,
|
||||
.owner = THIS_MODULE,
|
||||
.name = TDDI_DEV_ID,
|
||||
.of_match_table = of_match_ptr(tp_match_table),
|
||||
.plat_probe = ilitek_plat_probe,
|
||||
.plat_remove = ilitek_plat_remove,
|
||||
.pm = &tp_pm_ops,
|
||||
};
|
||||
|
||||
static int __init ilitek_plat_dev_init(void)
|
||||
{
|
||||
ILI_INFO("ILITEK TP driver init for QCOM\n");
|
||||
if (ili_dev_init(&hwif) < 0) {
|
||||
ILI_ERR("Failed to register i2c/spi bus driver\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ilitek_plat_dev_exit(void)
|
||||
{
|
||||
ILI_INFO("remove plat dev\n");
|
||||
ili_dev_remove();
|
||||
}
|
||||
|
||||
//module_init(ilitek_plat_dev_init);
|
||||
late_initcall(ilitek_plat_dev_init);
|
||||
module_exit(ilitek_plat_dev_exit);
|
||||
MODULE_AUTHOR("ILITEK");
|
||||
MODULE_LICENSE("GPL");
|
||||
655
drivers/input/touchscreen/ili9882_mmi/ili9882_spi.c
Executable file
655
drivers/input/touchscreen/ili9882_mmi/ili9882_spi.c
Executable file
|
|
@ -0,0 +1,655 @@
|
|||
/*
|
||||
* ILITEK Touch IC driver
|
||||
*
|
||||
* Copyright (C) 2011 ILI Technology Corporation.
|
||||
*
|
||||
* Author: Dicky Chiang <dicky_chiang@ilitek.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 "ili9882.h"
|
||||
#ifdef CONFIG_DRM
|
||||
struct drm_panel *ili_active_panel;
|
||||
static int check_dt(struct device_node *np);
|
||||
#endif
|
||||
|
||||
struct touch_bus_info {
|
||||
struct spi_driver bus_driver;
|
||||
struct ilitek_hwif_info *hwif;
|
||||
};
|
||||
|
||||
struct ilitek_ts_data *ilits;
|
||||
|
||||
#if SPI_DMA_TRANSFER_SPLIT
|
||||
#define DMA_TRANSFER_MAX_CHUNK 64 // number of chunks to be transferred.
|
||||
#define DMA_TRANSFER_MAX_LEN 4096 // length of a chunk.
|
||||
|
||||
int ili_spi_write_then_read_split(struct spi_device *spi,
|
||||
const void *txbuf, unsigned n_tx,
|
||||
void *rxbuf, unsigned n_rx)
|
||||
{
|
||||
int status = -1, duplex_len = 0;
|
||||
int xfercnt = 0, xferlen = 0, xferloop = 0;
|
||||
int offset = 0;
|
||||
u8 cmd = 0;
|
||||
struct spi_message message;
|
||||
struct spi_transfer *xfer;
|
||||
|
||||
xfer = kzalloc(DMA_TRANSFER_MAX_CHUNK * sizeof(struct spi_transfer), GFP_KERNEL);
|
||||
|
||||
if (n_rx > SPI_RX_BUF_SIZE) {
|
||||
ILI_ERR("Rx length is greater than spi local buf, abort\n");
|
||||
status = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spi_message_init(&message);
|
||||
memset(ilits->spi_tx, 0x0, SPI_TX_BUF_SIZE);
|
||||
memset(ilits->spi_rx, 0x0, SPI_RX_BUF_SIZE);
|
||||
|
||||
if ((n_tx > 0) && (n_rx > 0))
|
||||
cmd = SPI_READ;
|
||||
else
|
||||
cmd = SPI_WRITE;
|
||||
|
||||
switch (cmd) {
|
||||
case SPI_WRITE:
|
||||
if (n_tx % DMA_TRANSFER_MAX_LEN)
|
||||
xferloop = (n_tx / DMA_TRANSFER_MAX_LEN) + 1;
|
||||
else
|
||||
xferloop = n_tx / DMA_TRANSFER_MAX_LEN;
|
||||
|
||||
xferlen = n_tx;
|
||||
memcpy(ilits->spi_tx, (u8 *)txbuf, xferlen);
|
||||
|
||||
for (xfercnt = 0; xfercnt < xferloop; xfercnt++) {
|
||||
if (xferlen > DMA_TRANSFER_MAX_LEN)
|
||||
xferlen = DMA_TRANSFER_MAX_LEN;
|
||||
|
||||
xfer[xfercnt].len = xferlen;
|
||||
xfer[xfercnt].tx_buf = ilits->spi_tx + xfercnt * DMA_TRANSFER_MAX_LEN;
|
||||
spi_message_add_tail(&xfer[xfercnt], &message);
|
||||
xferlen = n_tx - (xfercnt+1) * DMA_TRANSFER_MAX_LEN;
|
||||
}
|
||||
status = spi_sync(spi, &message);
|
||||
break;
|
||||
case SPI_READ:
|
||||
if (n_tx > DMA_TRANSFER_MAX_LEN) {
|
||||
ILI_ERR("Tx length must be lower than dma length (%d).\n", DMA_TRANSFER_MAX_LEN);
|
||||
status = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!atomic_read(&ilits->ice_stat))
|
||||
offset = 2;
|
||||
|
||||
memcpy(ilits->spi_tx, txbuf, n_tx);
|
||||
duplex_len = n_tx + n_rx + offset;
|
||||
|
||||
if (duplex_len % DMA_TRANSFER_MAX_LEN)
|
||||
xferloop = (duplex_len / DMA_TRANSFER_MAX_LEN) + 1;
|
||||
else
|
||||
xferloop = duplex_len / DMA_TRANSFER_MAX_LEN;
|
||||
|
||||
xferlen = duplex_len;
|
||||
for (xfercnt = 0; xfercnt < xferloop; xfercnt++) {
|
||||
if (xferlen > DMA_TRANSFER_MAX_LEN)
|
||||
xferlen = DMA_TRANSFER_MAX_LEN;
|
||||
|
||||
xfer[xfercnt].len = xferlen;
|
||||
xfer[xfercnt].tx_buf = ilits->spi_tx;
|
||||
xfer[xfercnt].rx_buf = ilits->spi_rx + xfercnt * DMA_TRANSFER_MAX_LEN;
|
||||
spi_message_add_tail(&xfer[xfercnt], &message);
|
||||
xferlen = duplex_len - (xfercnt + 1) * DMA_TRANSFER_MAX_LEN;
|
||||
}
|
||||
|
||||
status = spi_sync(spi, &message);
|
||||
if (status == 0) {
|
||||
if (ilits->spi_rx[1] != SPI_ACK && !atomic_read(&ilits->ice_stat)) {
|
||||
status = DO_SPI_RECOVER;
|
||||
ILI_ERR("Do spi recovery: rxbuf[1] = 0x%x, ice = %d\n", ilits->spi_rx[1], atomic_read(&ilits->ice_stat));
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy((u8 *)rxbuf, ilits->spi_rx + offset + 1, n_rx);
|
||||
} else {
|
||||
ILI_ERR("spi read fail, status = %d\n", status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ILI_INFO("Unknown command 0x%x\n", cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
ipio_kfree((void **)&xfer);
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
int ili_spi_write_then_read_direct(struct spi_device *spi,
|
||||
const void *txbuf, unsigned n_tx,
|
||||
void *rxbuf, unsigned n_rx)
|
||||
{
|
||||
int status = -1, duplex_len = 0;
|
||||
int offset = 0;
|
||||
u8 cmd;
|
||||
struct spi_message message;
|
||||
struct spi_transfer xfer;
|
||||
|
||||
if (n_rx > SPI_RX_BUF_SIZE) {
|
||||
ILI_ERR("Rx length is greater than spi local buf, abort\n");
|
||||
status = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spi_message_init(&message);
|
||||
memset(&xfer, 0, sizeof(xfer));
|
||||
|
||||
if ((n_tx > 0) && (n_rx > 0))
|
||||
cmd = SPI_READ;
|
||||
else
|
||||
cmd = SPI_WRITE;
|
||||
|
||||
switch (cmd) {
|
||||
case SPI_WRITE:
|
||||
xfer.len = n_tx;
|
||||
xfer.tx_buf = txbuf;
|
||||
spi_message_add_tail(&xfer, &message);
|
||||
status = spi_sync(spi, &message);
|
||||
break;
|
||||
case SPI_READ:
|
||||
if (!atomic_read(&ilits->ice_stat))
|
||||
offset = 2;
|
||||
|
||||
duplex_len = n_tx + n_rx + offset;
|
||||
if ((duplex_len > SPI_TX_BUF_SIZE) ||
|
||||
(duplex_len > SPI_RX_BUF_SIZE)) {
|
||||
ILI_ERR("duplex_len is over than dma buf, abort\n");
|
||||
status = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(ilits->spi_tx, 0x0, SPI_TX_BUF_SIZE);
|
||||
memset(ilits->spi_rx, 0x0, SPI_RX_BUF_SIZE);
|
||||
|
||||
xfer.len = duplex_len;
|
||||
memcpy(ilits->spi_tx, txbuf, n_tx);
|
||||
xfer.tx_buf = ilits->spi_tx;
|
||||
xfer.rx_buf = ilits->spi_rx;
|
||||
|
||||
spi_message_add_tail(&xfer, &message);
|
||||
status = spi_sync(spi, &message);
|
||||
if (status == 0) {
|
||||
if (ilits->spi_rx[1] != SPI_ACK && !atomic_read(&ilits->ice_stat)) {
|
||||
status = DO_SPI_RECOVER;
|
||||
ILI_ERR("Do spi recovery: rxbuf[1] = 0x%x, ice = %d\n", ilits->spi_rx[1], atomic_read(&ilits->ice_stat));
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy((u8 *)rxbuf, ilits->spi_rx + offset + 1, n_rx);
|
||||
} else {
|
||||
ILI_ERR("spi read fail, status = %d\n", status);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ILI_INFO("Unknown command 0x%x\n", cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ili_spi_mp_pre_cmd(u8 cdc)
|
||||
{
|
||||
u8 pre[5] = {0};
|
||||
|
||||
if (!atomic_read(&ilits->mp_stat) || cdc != P5_X_SET_CDC_INIT ||
|
||||
ilits->chip->core_ver >= CORE_VER_1430)
|
||||
return 0;
|
||||
|
||||
ILI_DBG("mp test with pre commands\n");
|
||||
|
||||
pre[0] = SPI_WRITE;
|
||||
pre[1] = 0x0;// dummy byte
|
||||
pre[2] = 0x2;// Write len byte
|
||||
pre[3] = P5_X_READ_DATA_CTRL;
|
||||
pre[4] = P5_X_GET_CDC_DATA;
|
||||
if (ilits->spi_write_then_read(ilits->spi, pre, 5, NULL, 0) < 0) {
|
||||
ILI_ERR("Failed to write pre commands\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pre[0] = SPI_WRITE;
|
||||
pre[1] = 0x0;// dummy byte
|
||||
pre[2] = 0x1;// Write len byte
|
||||
pre[3] = P5_X_GET_CDC_DATA;
|
||||
if (ilits->spi_write_then_read(ilits->spi, pre, 4, NULL, 0) < 0) {
|
||||
ILI_ERR("Failed to write pre commands\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili_spi_pll_clk_wakeup(void)
|
||||
{
|
||||
int index = 0;
|
||||
u8 wdata[32] = {0};
|
||||
u8 wakeup[9] = {0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3, 0xA3};
|
||||
u32 wlen = sizeof(wakeup);
|
||||
|
||||
wdata[0] = SPI_WRITE;
|
||||
wdata[1] = wlen >> 8;
|
||||
wdata[2] = wlen & 0xff;
|
||||
index = 3;
|
||||
wlen += index;
|
||||
|
||||
ipio_memcpy(&wdata[index], wakeup, wlen, wlen);
|
||||
|
||||
ILI_INFO("Write dummy to wake up spi pll clk\n");
|
||||
if (ilits->spi_write_then_read(ilits->spi, wdata, wlen, NULL, 0) < 0) {
|
||||
ILI_INFO("spi slave write error\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ili_spi_wrapper(u8 *txbuf, u32 wlen, u8 *rxbuf, u32 rlen, bool spi_irq, bool i2c_irq)
|
||||
{
|
||||
int ret = 0;
|
||||
int mode = 0, index = 0;
|
||||
u8 wdata[32] = {0};
|
||||
u8 checksum = 0;
|
||||
bool ice = atomic_read(&ilits->ice_stat);
|
||||
|
||||
if (wlen > 0) {
|
||||
if (!txbuf) {
|
||||
ILI_ERR("txbuf is null\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* 3 bytes data consist of length and header */
|
||||
if ((wlen + 3) > sizeof(wdata)) {
|
||||
ILI_ERR("WARNING! wlen(%d) > wdata(%d), using wdata length to transfer\n", wlen, (int)sizeof(wdata));
|
||||
wlen = sizeof(wdata);
|
||||
}
|
||||
}
|
||||
|
||||
if (rlen > 0) {
|
||||
if (!rxbuf) {
|
||||
ILI_ERR("rxbuf is null\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (rlen > 0 && !wlen)
|
||||
mode = SPI_READ;
|
||||
else
|
||||
mode = SPI_WRITE;
|
||||
|
||||
if (ilits->int_pulse)
|
||||
ilits->detect_int_stat = ili_ic_check_int_pulse;
|
||||
else
|
||||
ilits->detect_int_stat = ili_ic_check_int_level;
|
||||
|
||||
if (spi_irq)
|
||||
atomic_set(&ilits->cmd_int_check, ENABLE);
|
||||
|
||||
switch (mode) {
|
||||
case SPI_WRITE:
|
||||
#if ( PLL_CLK_WAKEUP_TP_RESUME == ENABLE )
|
||||
if (ilits->pll_clk_wakeup == true) {
|
||||
#else
|
||||
if ((ilits->pll_clk_wakeup == true) && (ilits->tp_suspend == true)) {
|
||||
#endif
|
||||
ret = ili_spi_pll_clk_wakeup();
|
||||
if (ret < 0) {
|
||||
ILI_ERR("Wakeup pll clk error\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ice) {
|
||||
wdata[0] = SPI_WRITE;
|
||||
index = 1;
|
||||
} else {
|
||||
wdata[0] = SPI_WRITE;
|
||||
wdata[1] = wlen >> 8;
|
||||
wdata[2] = wlen & 0xff;
|
||||
index = 3;
|
||||
}
|
||||
|
||||
wlen += index;
|
||||
|
||||
ipio_memcpy(&wdata[index], txbuf, wlen, wlen);
|
||||
|
||||
/*
|
||||
* 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 (atomic_read(&ilits->mp_stat) && wdata[index] == P5_X_SET_CDC_INIT) {
|
||||
checksum = ili_calc_packet_checksum(&wdata[index], wlen - index);
|
||||
wdata[wlen] = checksum;
|
||||
wlen++;
|
||||
wdata[1] = (wlen - index) >> 8;
|
||||
wdata[2] = (wlen - index) & 0xff;
|
||||
ili_dump_data(wdata, 8, wlen, 0, "mp cdc cmd with checksum");
|
||||
}
|
||||
|
||||
ret = ilits->spi_write_then_read(ilits->spi, wdata, wlen, txbuf, 0);
|
||||
if (ret < 0) {
|
||||
ILI_INFO("spi-wrapper write error\n");
|
||||
break;
|
||||
}
|
||||
|
||||
/* Won't break if it needs to read data following with writing. */
|
||||
if (!rlen)
|
||||
break;
|
||||
case SPI_READ:
|
||||
if (!ice && spi_irq) {
|
||||
/* Check INT triggered by FW when sending cmds. */
|
||||
if (ilits->detect_int_stat(false) < 0) {
|
||||
ILI_ERR("ERROR! Check INT timeout\n");
|
||||
ret = -ETIME;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = ili_spi_mp_pre_cmd(wdata[3]);
|
||||
if (ret < 0)
|
||||
ILI_ERR("spi-wrapper mp pre cmd error\n");
|
||||
|
||||
wdata[0] = SPI_READ;
|
||||
|
||||
ret = ilits->spi_write_then_read(ilits->spi, wdata, 1, rxbuf, rlen);
|
||||
if (ret < 0)
|
||||
ILI_ERR("spi-wrapper read error\n");
|
||||
|
||||
break;
|
||||
default:
|
||||
ILI_ERR("Unknown spi mode (%d)\n", mode);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (spi_irq)
|
||||
atomic_set(&ilits->cmd_int_check, DISABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ili_core_spi_setup(int num)
|
||||
{
|
||||
u32 freq[] = {
|
||||
TP_SPI_CLK_1M,
|
||||
TP_SPI_CLK_2M,
|
||||
TP_SPI_CLK_3M,
|
||||
TP_SPI_CLK_4M,
|
||||
TP_SPI_CLK_5M,
|
||||
TP_SPI_CLK_6M,
|
||||
TP_SPI_CLK_7M,
|
||||
TP_SPI_CLK_8M,
|
||||
TP_SPI_CLK_9M,
|
||||
TP_SPI_CLK_10M,
|
||||
TP_SPI_CLK_11M,
|
||||
TP_SPI_CLK_12M,
|
||||
TP_SPI_CLK_13M,
|
||||
TP_SPI_CLK_14M,
|
||||
TP_SPI_CLK_15M
|
||||
};
|
||||
|
||||
if (num > sizeof(freq)) {
|
||||
ILI_ERR("Invaild clk freq, set default clk freq\n");
|
||||
num = 7;
|
||||
}
|
||||
|
||||
ILI_INFO("spi clock = %d\n", freq[num]);
|
||||
|
||||
ilits->spi->mode = SPI_MODE_0;
|
||||
ilits->spi->bits_per_word = 8;
|
||||
ilits->spi->max_speed_hz = freq[num];
|
||||
ilits->spi->chip_select = 0;
|
||||
|
||||
if (spi_setup(ilits->spi) < 0) {
|
||||
ILI_ERR("Failed to setup spi device\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ILI_INFO("name = %s, bus_num = %d,cs = %d, mode = %d, speed = %d\n",
|
||||
ilits->spi->modalias,
|
||||
ilits->spi->master->bus_num,
|
||||
ilits->spi->chip_select,
|
||||
ilits->spi->mode,
|
||||
ilits->spi->max_speed_hz);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM
|
||||
static int check_dt(struct device_node *np)
|
||||
{
|
||||
int i;
|
||||
int count;
|
||||
struct device_node *node;
|
||||
struct drm_panel *panel;
|
||||
|
||||
count = of_count_phandle_with_args(np, "panel", NULL);
|
||||
if (count <= 0)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
node = of_parse_phandle(np, "panel", i);
|
||||
panel = of_drm_find_panel(node);
|
||||
of_node_put(node);
|
||||
if (!IS_ERR(panel)) {
|
||||
ili_active_panel = panel;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (node)
|
||||
pr_err("%s: %s not actived\n", __func__, node->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ilitek_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct touch_bus_info *info =
|
||||
container_of(to_spi_driver(spi->dev.driver),
|
||||
struct touch_bus_info, bus_driver);
|
||||
|
||||
ILI_INFO("ilitek spi probe\n");
|
||||
|
||||
if (!spi) {
|
||||
ILI_ERR("spi device is NULL\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DRM
|
||||
{
|
||||
struct device_node *dp = spi->dev.of_node;
|
||||
if (check_dt(dp)) {
|
||||
ILI_ERR("%s: %s not actived\n", __func__, dp->name);
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ilits = devm_kzalloc(&spi->dev, sizeof(struct ilitek_ts_data), GFP_KERNEL);
|
||||
if (ERR_ALLOC_MEM(ilits)) {
|
||||
ILI_ERR("Failed to allocate ts memory, %ld\n", PTR_ERR(ilits));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {
|
||||
ILI_ERR("Full duplex not supported by master\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
ilits->update_buf = kzalloc(MAX_HEX_FILE_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
if (ERR_ALLOC_MEM(ilits->update_buf)) {
|
||||
ILI_ERR("fw kzalloc error\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Used for receiving touch data only, do not mix up with others. */
|
||||
ilits->tr_buf = kzalloc(TR_BUF_SIZE, GFP_ATOMIC);
|
||||
if (ERR_ALLOC_MEM(ilits->tr_buf)) {
|
||||
ILI_ERR("failed to allocate touch report buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ilits->spi_tx = kzalloc(SPI_TX_BUF_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
if (ERR_ALLOC_MEM(ilits->spi_tx)) {
|
||||
ILI_ERR("Failed to allocate spi tx buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ilits->spi_rx = kzalloc(SPI_RX_BUF_SIZE, GFP_KERNEL | GFP_DMA);
|
||||
if (ERR_ALLOC_MEM(ilits->spi_rx)) {
|
||||
ILI_ERR("Failed to allocate spi rx buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ilits->gcoord = kzalloc(sizeof(struct gesture_coordinate), GFP_KERNEL);
|
||||
if (ERR_ALLOC_MEM(ilits->gcoord)) {
|
||||
ILI_ERR("Failed to allocate gresture coordinate buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ilits->i2c = NULL;
|
||||
ilits->spi = spi;
|
||||
ilits->dev = &spi->dev;
|
||||
ilits->hwif = info->hwif;
|
||||
ilits->phys = "SPI";
|
||||
ilits->wrapper = ili_spi_wrapper;
|
||||
ilits->detect_int_stat = ili_ic_check_int_pulse;
|
||||
ilits->int_pulse = true;
|
||||
ilits->mp_retry = false;
|
||||
|
||||
#if SPI_DMA_TRANSFER_SPLIT
|
||||
ilits->spi_write_then_read = ili_spi_write_then_read_split;
|
||||
#else
|
||||
ilits->spi_write_then_read = ili_spi_write_then_read_direct;
|
||||
#endif
|
||||
|
||||
ilits->actual_tp_mode = P5_X_FW_AP_MODE;
|
||||
ilits->tp_data_format = DATA_FORMAT_DEMO;
|
||||
ilits->tp_data_len = P5_X_DEMO_MODE_PACKET_LEN;
|
||||
|
||||
if (TDDI_RST_BIND)
|
||||
ilits->reset = TP_IC_WHOLE_RST;
|
||||
else
|
||||
ilits->reset = TP_HW_RST_ONLY;
|
||||
|
||||
ilits->rst_edge_delay = 10;
|
||||
ilits->fw_open = REQUEST_FIRMWARE;
|
||||
ilits->fw_upgrade_mode = UPGRADE_IRAM;
|
||||
ilits->mp_move_code = ili_move_mp_code_iram;
|
||||
ilits->gesture_move_code = ili_move_gesture_code_iram;
|
||||
ilits->esd_recover = ili_wq_esd_spi_check;
|
||||
ilits->ges_recover = ili_touch_esd_gesture_iram;
|
||||
ilits->gesture_mode = DATA_FORMAT_GESTURE_INFO;
|
||||
ilits->gesture_demo_ctrl = DISABLE;
|
||||
ilits->wtd_ctrl = OFF;
|
||||
ilits->report = ENABLE;
|
||||
ilits->netlink = DISABLE;
|
||||
ilits->dnp = DISABLE;
|
||||
ilits->irq_tirgger_type = IRQF_TRIGGER_FALLING;
|
||||
ilits->info_from_hex = ENABLE;
|
||||
ilits->wait_int_timeout = AP_INT_TIMEOUT;
|
||||
|
||||
#if ENABLE_GESTURE
|
||||
ilits->gesture = DISABLE;
|
||||
ilits->ges_sym.double_tap = DOUBLE_TAP;
|
||||
ilits->ges_sym.alphabet_line_2_top = ALPHABET_LINE_2_TOP;
|
||||
ilits->ges_sym.alphabet_line_2_bottom = ALPHABET_LINE_2_BOTTOM;
|
||||
ilits->ges_sym.alphabet_line_2_left = ALPHABET_LINE_2_LEFT;
|
||||
ilits->ges_sym.alphabet_line_2_right = ALPHABET_LINE_2_RIGHT;
|
||||
ilits->ges_sym.alphabet_m = ALPHABET_M;
|
||||
ilits->ges_sym.alphabet_w = ALPHABET_W;
|
||||
ilits->ges_sym.alphabet_c = ALPHABET_C;
|
||||
ilits->ges_sym.alphabet_E = ALPHABET_E;
|
||||
ilits->ges_sym.alphabet_V = ALPHABET_V;
|
||||
ilits->ges_sym.alphabet_O = ALPHABET_O;
|
||||
ilits->ges_sym.alphabet_S = ALPHABET_S;
|
||||
ilits->ges_sym.alphabet_Z = ALPHABET_Z;
|
||||
ilits->ges_sym.alphabet_V_down = ALPHABET_V_DOWN;
|
||||
ilits->ges_sym.alphabet_V_left = ALPHABET_V_LEFT;
|
||||
ilits->ges_sym.alphabet_V_right = ALPHABET_V_RIGHT;
|
||||
ilits->ges_sym.alphabet_two_line_2_bottom = ALPHABET_TWO_LINE_2_BOTTOM;
|
||||
ilits->ges_sym.alphabet_F = ALPHABET_F;
|
||||
ilits->ges_sym.alphabet_AT = ALPHABET_AT;
|
||||
#endif
|
||||
|
||||
if (ili_core_spi_setup(SPI_CLK) < 0)
|
||||
return -EINVAL;
|
||||
|
||||
return info->hwif->plat_probe();
|
||||
}
|
||||
|
||||
static int ilitek_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
ILI_INFO();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_device_id tp_spi_id[] = {
|
||||
{TDDI_DEV_ID, 0},
|
||||
{},
|
||||
};
|
||||
|
||||
int ili_interface_dev_init(struct ilitek_hwif_info *hwif)
|
||||
{
|
||||
struct touch_bus_info *info;
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
ILI_ERR("faied to allocate spi_driver\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (hwif->bus_type != BUS_SPI) {
|
||||
ILI_ERR("Not SPI dev\n");
|
||||
ipio_kfree((void **)&info);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hwif->info = info;
|
||||
|
||||
info->bus_driver.driver.name = hwif->name;
|
||||
info->bus_driver.driver.owner = hwif->owner;
|
||||
info->bus_driver.driver.of_match_table = hwif->of_match_table;
|
||||
info->bus_driver.driver.pm = hwif->pm;
|
||||
|
||||
info->bus_driver.probe = ilitek_spi_probe;
|
||||
info->bus_driver.remove = ilitek_spi_remove;
|
||||
info->bus_driver.id_table = tp_spi_id;
|
||||
|
||||
info->hwif = hwif;
|
||||
return spi_register_driver(&info->bus_driver);
|
||||
}
|
||||
|
||||
void ili_interface_dev_exit(struct ilitek_ts_data *ts)
|
||||
{
|
||||
struct touch_bus_info *info = (struct touch_bus_info *)ilits->hwif->info;
|
||||
|
||||
ILI_INFO("remove spi dev\n");
|
||||
kfree(ilits->update_buf);
|
||||
kfree(ilits->spi_tx);
|
||||
kfree(ilits->spi_rx);
|
||||
spi_unregister_driver(&info->bus_driver);
|
||||
ipio_kfree((void **)&info);
|
||||
}
|
||||
1301
drivers/input/touchscreen/ili9882_mmi/ili9882_touch.c
Executable file
1301
drivers/input/touchscreen/ili9882_mmi/ili9882_touch.c
Executable file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue