diff --git a/drivers/input/touchscreen/ili9882_mmi/Android.mk b/drivers/input/touchscreen/ili9882_mmi/Android.mk index 9cba9af6ade4..4b0116551a03 100644 --- a/drivers/input/touchscreen/ili9882_mmi/Android.mk +++ b/drivers/input/touchscreen/ili9882_mmi/Android.mk @@ -63,6 +63,10 @@ ifeq ($(TOUCHSCREEN_LAST_TIME),true) KBUILD_OPTIONS += CONFIG_ILI_TOUCH_LAST_TIME=y endif +ifeq ($(GTP_ENABLE_DDA_STYLUS),true) + KBUILD_OPTIONS += CONFIG_GTP_DDA_STYLUS=y +endif + include $(CLEAR_VARS) ifneq ($(BOARD_USES_DOUBLE_TAP),) LOCAL_ADDITIONAL_DEPENDENCIES += $(KERNEL_MODULES_OUT)/sensors_class.ko diff --git a/drivers/input/touchscreen/ili9882_mmi/Kbuild b/drivers/input/touchscreen/ili9882_mmi/Kbuild index d1f79a883c4c..62b3e7b9b34e 100644 --- a/drivers/input/touchscreen/ili9882_mmi/Kbuild +++ b/drivers/input/touchscreen/ili9882_mmi/Kbuild @@ -74,3 +74,8 @@ ifneq ($(filter m y,$(CONFIG_INPUT_TOUCHSCREEN_MMI)),) ili9882_mmi-objs += ili_mmi_class.o endif KBUILD_EXTRA_SYMBOLS += $(CURDIR)/../../kernel/msm-$(MODULE_KERNEL_VERSION)/Module.symvers + +ifneq ($(filter m y,$(CONFIG_GTP_DDA_STYLUS)),) + EXTRA_CFLAGS += -DCONFIG_MOTO_DDA_PASSIVESTYLUS + ili9882_mmi-objs += moto_ts_dda.o +endif diff --git a/drivers/input/touchscreen/ili9882_mmi/ili9882.c b/drivers/input/touchscreen/ili9882_mmi/ili9882.c index badd7b4d5ab7..9900cbb55707 100644 --- a/drivers/input/touchscreen/ili9882_mmi/ili9882.c +++ b/drivers/input/touchscreen/ili9882_mmi/ili9882.c @@ -21,6 +21,10 @@ */ #include "firmware/ili9882_fw.h" #include "ili9882.h" +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS +#include "moto_ts_dda.h" +#endif + /* Debug level */ bool debug_en = DEBUG_OUTPUT; @@ -1260,6 +1264,15 @@ int ili_tddi_init(void) ili_wq_ctrl(WQ_BAT, ENABLE); ilits->boot = true; #endif +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS + { + int err; + moto_dda_init("ilitek-ts for Geneva5G"); + err = moto_dda_register_cdevice(); + if (err) + ILI_ERR("Failed register stylus dda device, %d", err); + } +#endif PM_WAKEUP_REGISTER(NULL, ilits->ws, "ili_wakelock"); if (!ilits->ws) { @@ -1297,6 +1310,11 @@ void ili_dev_remove(void) kfree(ilits->tr_buf); kfree(ilits->gcoord); ili_interface_dev_exit(ilits); + +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS + moto_dda_exit(); +#endif + } int ili_dev_init(struct ilitek_hwif_info *hwif) diff --git a/drivers/input/touchscreen/ili9882_mmi/ili9882_touch.c b/drivers/input/touchscreen/ili9882_mmi/ili9882_touch.c index 0690f3b76e19..afd36429def1 100755 --- a/drivers/input/touchscreen/ili9882_mmi/ili9882_touch.c +++ b/drivers/input/touchscreen/ili9882_mmi/ili9882_touch.c @@ -22,6 +22,11 @@ #include "ili9882.h" +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS +#include "moto_ts_dda.h" +#endif + + /*gesture info mode*/ struct ili_demo_debug_info_id0 { u32 id : 8; @@ -889,6 +894,17 @@ void ili_touch_press_width(u16 x, u16 y, u16 pressure, u16 id, u16 width_major, input_mt_sync(ilits->input); } +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS + { + struct dda_finger_coords finger_data; + finger_data.x = x; + finger_data.y = y; + finger_data.p = pressure; + finger_data.minor = width_minor; + finger_data.major = width_major; + moto_dda_process_finger_press(id, &finger_data); + } +#endif } void ili_touch_press(u16 x, u16 y, u16 pressure, u16 id) @@ -914,6 +930,17 @@ void ili_touch_press(u16 x, u16 y, u16 pressure, u16 id) input_mt_sync(ilits->input); } +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS + { + struct dda_finger_coords finger_data; + finger_data.x = x; + finger_data.y = y; + finger_data.p = pressure; + finger_data.minor = 1; + finger_data.major = 1; + moto_dda_process_finger_press(id, &finger_data); + } +#endif } void ili_touch_release(u16 x, u16 y, u16 id) @@ -927,6 +954,9 @@ void ili_touch_release(u16 x, u16 y, u16 id) input_report_key(ilits->input, BTN_TOUCH, 0); input_mt_sync(ilits->input); } +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS + moto_dda_process_finger_release(id); +#endif } void ili_touch_release_all_point(void) @@ -943,6 +973,11 @@ void ili_touch_release_all_point(void) ili_touch_release(0, 0, 0); } input_sync(ilits->input); +#ifdef CONFIG_MOTO_DDA_PASSIVESTYLUS + for (i = 0 ; i < MAX_TOUCH_NUM; i++){ + moto_dda_process_finger_release(i); + } +#endif } static struct ilitek_touch_info touch_info[MAX_TOUCH_NUM]; diff --git a/drivers/input/touchscreen/ili9882_mmi/moto_ts_dda.c b/drivers/input/touchscreen/ili9882_mmi/moto_ts_dda.c new file mode 100644 index 000000000000..e11a44bf3eb2 --- /dev/null +++ b/drivers/input/touchscreen/ili9882_mmi/moto_ts_dda.c @@ -0,0 +1,582 @@ +#include +#include +#include +#include +#include +#include "moto_ts_dda.h" + +//cdev registration +#define DRIVER_NAME "moto_dda_penraw_driver" +#define DEVICE_NAME "moto_penraw" +#define MINOR_NUMBER_START ((const unsigned int)0) /* the minor number starts at */ +#define NUMBER_MINOR_NUMBER ((const unsigned int)1) /* the number of minor numbers */ +#define DDA_MAX_BUFFER 32 +#define MAX_IO_CONTROL_REPORT 16 +#define DDA_TOUCH_ID_MAX 10 +#define DDA_DEVICE_NAME_MAXLEN 32 + +static bool debug_log_flag = false; +#define DDA_INFO(fmt, args...) pr_info("[MOTO_DDA_INFO] %s %d: " fmt, __func__, __LINE__, ##args) +#define DDA_ERR(fmt, args...) pr_err("[MOTO_DDA_ERR] %s %d: " fmt, __func__, __LINE__, ##args) +#define DDA_DBG(fmt, args...) {if(debug_log_flag)pr_debug("[MOTO_DDA_DBG] %s %d: " fmt, __func__, __LINE__, ##args);} + + +struct dda_io_device_name { + char device_name[DDA_DEVICE_NAME_MAXLEN]; +}; + +#ifdef MOTO_DDA_PASSIVE_STYLUS +enum { + DDA_FINGER_RELEASE = 0, + DDA_FINGER_ENTER = 1, + DDA_FINGER_MOVE = 2 +}; + +struct dda_finger_info { + unsigned char frame_no; + unsigned char reserve[3]; + struct dda_finger_coords coords; +}; + +struct dda_io_finger_reports { + unsigned char report_num; + unsigned char reserve[3]; + struct dda_finger_info finger_info[MAX_IO_CONTROL_REPORT]; +}; + +struct dda_finger_report_buffer{ + unsigned char finger_report_num; + unsigned char frame_no; + unsigned char buffer_wp; + unsigned char reserve[1]; + unsigned char last_status; + struct dda_finger_info finger_report_buffer[DDA_MAX_BUFFER]; +}; +#endif //MOTO_DDA_PASSIVE_STYLUS + + +#ifdef MOTO_DDA_ACTIVE_STYLUS +/* for DDA goodix_penraw */ +enum{ + DATA_TYPE_RAW = 0 +}; + +struct dda_pen_info { + unsigned char frame_no; + unsigned char data_type; + unsigned char reserve[2]; + struct dda_pen_coords coords; +}; + +struct dda_io_pen_reports { + unsigned char report_num; + unsigned char reserve[3]; + struct dda_pen_info pen_info[MAX_IO_CONTROL_REPORT]; +}; + +struct dda_pen_report_buffer{ + unsigned char pen_report_num; + unsigned char frame_no; + unsigned char buffer_wp; + unsigned char reserve[1]; + struct dda_pen_info pen_report_buffer[DDA_MAX_BUFFER]; +}; +#endif //MOTO_DDA_ACTIVE_STYLUS + +struct dda_cdev_control{ + unsigned int major_number; /* the major number of the device */ + struct cdev penraw_char_dev; /* character device */ + struct class* penraw_char_dev_class; /* class object */ +}; + + +//DDA cdev +static struct dda_cdev_control dda_cdev_ctrl; + +#ifdef MOTO_DDA_PASSIVE_STYLUS +//DDA raw finger report buffer +static struct dda_finger_report_buffer dda_finger_report_buf[DDA_TOUCH_ID_MAX]; +static int dda_finger_id_assign_table[DDA_TOUCH_ID_MAX]; +static int dda_finger_id_last_assign_table[DDA_TOUCH_ID_MAX]; +#endif //MOTO_DDA_PASSIVE_STYLUS + +#ifdef MOTO_DDA_ACTIVE_STYLUS +//DDA raw pen report buffer +static struct dda_pen_report_buffer dda_pen_report_buf; +#endif //MOTO_DDA_ACTIVE_STYLUS + +static spinlock_t lock; +static int open_count = 0; + +static char dda_device_name[DDA_DEVICE_NAME_MAXLEN]; + + +//prototype of private functions +#ifdef MOTO_DDA_PASSIVE_STYLUS +static int get_finger_report(int id, unsigned long arg); +#endif //MOTO_DDA_PASSIVE_STYLUS +#ifdef MOTO_DDA_ACTIVE_STYLUS +static int get_pen_report(unsigned long arg); +#endif //MOTO_DDA_ACTIVE_STYLUS + +static int get_device_name(unsigned long arg); + +// Linux 2.0/2.2 +static int penraw_open(struct inode * inode, struct file * file) +{ + spin_lock(&lock); + if (open_count) { + spin_unlock(&lock); + return -EBUSY; + } + open_count++; + spin_unlock(&lock); + + return 0; +} + +// Linux 2.1: int type +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) +static int penraw_close(struct inode * inode, struct file * file) +{ + spin_lock(&lock); + open_count--; + spin_unlock(&lock); + + return 0; +} +#else +static void penraw_close(struct inode * inode, struct file * file) +{ + spinlock(&lock); + open_count--; + spin_unlock(&lock); +} +#endif + +#define PENRAW_IOC_TYPE 'P' +#ifdef MOTO_DDA_ACTIVE_STYLUS +#define PENRAW_GET_VALUES _IOR(PENRAW_IOC_TYPE, 0, struct dda_io_pen_reports) + +static struct dda_io_pen_reports pen_reports; // return report +#endif //MOTO_DDA_ACTIVE_STYLUS + +#ifdef MOTO_DDA_PASSIVE_STYLUS +#define PENRAW_GET_VALUES_ID0 _IOR(PENRAW_IOC_TYPE, 1, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID1 _IOR(PENRAW_IOC_TYPE, 2, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID2 _IOR(PENRAW_IOC_TYPE, 3, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID3 _IOR(PENRAW_IOC_TYPE, 4, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID4 _IOR(PENRAW_IOC_TYPE, 5, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID5 _IOR(PENRAW_IOC_TYPE, 6, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID6 _IOR(PENRAW_IOC_TYPE, 7, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID7 _IOR(PENRAW_IOC_TYPE, 8, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID8 _IOR(PENRAW_IOC_TYPE, 9, struct dda_io_finger_reports) +#define PENRAW_GET_VALUES_ID9 _IOR(PENRAW_IOC_TYPE, 10, struct dda_io_finger_reports) + +static struct dda_io_finger_reports finger_reports; // return report +#endif //MOTO_DDA_PASSIVE_STYLUS + +#define PENRAW_GET_DEVICE_NAME _IOR(PENRAW_IOC_TYPE, 11, struct dda_io_device_name) + +static long penraw_ioctl(struct file *file, + unsigned int cmd, unsigned long arg) +{ + int ret; + + switch (cmd) { +#ifdef MOTO_DDA_ACTIVE_STYLUS + case PENRAW_GET_VALUES: + ret = get_pen_report(arg); + break; +#endif +#ifdef MOTO_DDA_PASSIVE_STYLUS + case PENRAW_GET_VALUES_ID0: + ret = get_finger_report(0,arg); + break; + case PENRAW_GET_VALUES_ID1: + ret = get_finger_report(1,arg); + break; + case PENRAW_GET_VALUES_ID2: + ret = get_finger_report(2,arg); + break; + case PENRAW_GET_VALUES_ID3: + ret = get_finger_report(3,arg); + break; + case PENRAW_GET_VALUES_ID4: + ret = get_finger_report(4,arg); + break; + case PENRAW_GET_VALUES_ID5: + ret = get_finger_report(5,arg); + break; + case PENRAW_GET_VALUES_ID6: + ret = get_finger_report(6,arg); + break; + case PENRAW_GET_VALUES_ID7: + ret = get_finger_report(7,arg); + break; + case PENRAW_GET_VALUES_ID8: + ret = get_finger_report(8,arg); + break; + case PENRAW_GET_VALUES_ID9: + ret = get_finger_report(9,arg); + break; +#endif //MOTO_DDA_PASSIVE_STYLUS + case PENRAW_GET_DEVICE_NAME: + ret = get_device_name(arg); + break; + default: + DDA_ERR("unsupported command %d", cmd); + return -EFAULT; + } + return ret; +} + +#ifdef MOTO_DDA_PASSIVE_STYLUS +static int get_finger_report(int id, unsigned long arg){ + unsigned long flags; + struct dda_finger_info *pfinger_info; + unsigned char cnt; + unsigned char finger_buffer_rp; + unsigned char wp; + unsigned char num; + int touch_id; + //enter to critical session + local_irq_save(flags); + touch_id = dda_finger_id_assign_table[id]; + if(-1 == touch_id){ + touch_id = dda_finger_id_last_assign_table[id]; + if(-1 == touch_id){ + DDA_ERR("PassiveStylusDDA touch_id is not assignd for %d",id); + touch_id = id; + } + } + + wp = dda_finger_report_buf[touch_id].buffer_wp; + num = dda_finger_report_buf[touch_id].finger_report_num; + if(MAX_IO_CONTROL_REPORT <= num) { + finger_buffer_rp = (unsigned char)((wp + (DDA_MAX_BUFFER - + MAX_IO_CONTROL_REPORT)) % DDA_MAX_BUFFER); + } else { + num = MAX_IO_CONTROL_REPORT; //for safety implementation + finger_buffer_rp = 0; + } + memset(&finger_reports, 0, sizeof(finger_reports)); + finger_reports.report_num = num; + pfinger_info = (struct dda_finger_info *)&finger_reports.finger_info[0]; + for(cnt = 0; cnt < num; cnt++) { + memcpy(pfinger_info, &dda_finger_report_buf[touch_id].finger_report_buffer[finger_buffer_rp], + sizeof(struct dda_finger_info)); + pfinger_info++; + finger_buffer_rp++; + if(DDA_MAX_BUFFER == finger_buffer_rp) { + finger_buffer_rp = 0; + } + } + //leave from critical session + local_irq_restore(flags); + + + if (copy_to_user((void __user *)arg, &finger_reports, sizeof(finger_reports))) { + return -EFAULT; + } + return 0; +} +#endif //MOTO_DDA_PASSIVE_STYLUS + +#ifdef MOTO_DDA_ACTIVE_STYLUS +static int get_pen_report(unsigned long arg){ + unsigned long flags; + struct dda_pen_info *ppen_info; + unsigned char cnt; + unsigned char pen_buffer_rp; + unsigned char wp; + unsigned char num; + + local_irq_save(flags); + wp = dda_pen_report_buf.buffer_wp; + num = dda_pen_report_buf.pen_report_num; + local_irq_restore(flags); + if(MAX_IO_CONTROL_REPORT <= num) { + pen_buffer_rp = (unsigned char)((wp + (DDA_MAX_BUFFER - + MAX_IO_CONTROL_REPORT)) % DDA_MAX_BUFFER); + } else { + pen_buffer_rp = 0; + } + memset(&pen_reports, 0, sizeof(pen_reports)); + pen_reports.report_num = num; + ppen_info = (struct dda_pen_info *)&pen_reports.pen_info[0]; + for(cnt = 0; cnt < num; cnt++) { + memcpy(ppen_info, &dda_pen_report_buf.pen_report_buffer[pen_buffer_rp], + sizeof(struct dda_pen_info)); + ppen_info++; + pen_buffer_rp++; + if(DDA_MAX_BUFFER == pen_buffer_rp) { + pen_buffer_rp = 0; + } + } + if (copy_to_user((void __user *)arg, &pen_reports, sizeof(pen_reports))) { + return -EFAULT; + } + return 0; +} +#endif //MOTO_DDA_ACTIVE_STYLUS + +static int get_device_name(unsigned long arg){ + if (copy_to_user((void __user *)arg, &dda_device_name, sizeof(dda_device_name))) { + return -EFAULT; + } + return 0; +} + +static struct file_operations penraw_fops = { + .owner = THIS_MODULE, + .open = penraw_open, + .release = penraw_close, + .unlocked_ioctl = penraw_ioctl, +}; + +/* functions for DDA Features */ +#ifdef MOTO_DDA_PASSIVE_STYLUS +void moto_dda_process_finger_press(uint8_t touch_id, struct dda_finger_coords *finger_data) { + struct dda_finger_info *pfinger_info; + int i; + unsigned char id_is_found; + + if(touch_id >= DDA_TOUCH_ID_MAX){ + return; + } + + // ioctl-DAA Buffering finger raw data + pfinger_info = &dda_finger_report_buf[touch_id].finger_report_buffer[0]; + pfinger_info += dda_finger_report_buf[touch_id].buffer_wp; + memset(pfinger_info, 0, sizeof(struct dda_finger_info)); + pfinger_info->coords.x = finger_data->x; + pfinger_info->coords.y = finger_data->y; + pfinger_info->coords.p = finger_data->p; + pfinger_info->coords.minor = finger_data->minor; + pfinger_info->coords.major = finger_data->major; + pfinger_info->frame_no = dda_finger_report_buf[touch_id].frame_no; + DDA_DBG("P:[%d] %d %d %d (%d)\n",touch_id, finger_data->x, finger_data->y, finger_data->p, dda_finger_report_buf[touch_id].frame_no); + dda_finger_report_buf[touch_id].frame_no++; + if(DDA_FINGER_RELEASE == dda_finger_report_buf[touch_id].last_status){ + pfinger_info->coords.status = DDA_FINGER_ENTER; + //check registerd iDs to avoid duplicated registration. + id_is_found = 0; + for(i=0;icoords.status = DDA_FINGER_MOVE; + } + dda_finger_report_buf[touch_id].last_status = pfinger_info->coords.status; + if(MAX_IO_CONTROL_REPORT > dda_finger_report_buf[touch_id].finger_report_num) { + // Max count: MAX_IO_CONTROL_REPORT + dda_finger_report_buf[touch_id].finger_report_num++; + } + dda_finger_report_buf[touch_id].buffer_wp++; + if(DDA_MAX_BUFFER == dda_finger_report_buf[touch_id].buffer_wp) { + dda_finger_report_buf[touch_id].buffer_wp = 0; + } +} + +void moto_dda_process_finger_release(uint8_t touch_id) { + struct dda_finger_info *pfinger_info; + int i; + + if(touch_id >= DDA_TOUCH_ID_MAX){ + return; + } + + // ioctl-DAA Buffering finger raw data + pfinger_info = &dda_finger_report_buf[touch_id].finger_report_buffer[0]; + pfinger_info += dda_finger_report_buf[touch_id].buffer_wp; + memset(pfinger_info, 0, sizeof(struct dda_finger_info)); + pfinger_info->coords.x = 0xFFFFFFFF; + pfinger_info->coords.y = 0xFFFFFFFF; + pfinger_info->coords.p = 0; + pfinger_info->coords.minor = 0; + pfinger_info->coords.major = 0; + pfinger_info->frame_no = dda_finger_report_buf[touch_id].frame_no; + DDA_DBG("R:[%d] (%d)\n",touch_id, dda_finger_report_buf[touch_id].frame_no); + dda_finger_report_buf[touch_id].frame_no++; + pfinger_info->coords.status = DDA_FINGER_RELEASE; + dda_finger_report_buf[touch_id].last_status = pfinger_info->coords.status; + for(i=0;i dda_finger_report_buf[touch_id].finger_report_num) { + // Max count: MAX_IO_CONTROL_REPORT + dda_finger_report_buf[touch_id].finger_report_num++; + } + dda_finger_report_buf[touch_id].buffer_wp++; + if(DDA_MAX_BUFFER == dda_finger_report_buf[touch_id].buffer_wp) { + dda_finger_report_buf[touch_id].buffer_wp = 0; + } + +} +#endif //MOTO_DDA_PASSIVE_STYLUS + +#ifdef MOTO_DDA_ACTIVE_STYLUS +void moto_dda_process_pen_report(struct dda_pen_coords *pen_data) { + struct dda_pen_info *ppen_info; + + if (pen_data->status) { + // ioctl-DAA Buffering pen raw data + ppen_info = &dda_pen_report_buf.pen_report_buffer[0]; + ppen_info += dda_pen_report_buf.buffer_wp; + memset(ppen_info, 0, sizeof(struct dda_pen_info)); + ppen_info->coords.status = (signed char)pen_data->status; + ppen_info->coords.tool_type = (signed char)pen_data->tool_type; + ppen_info->coords.tilt_x = pen_data->tilt_x; + ppen_info->coords.tilt_y = pen_data->tilt_y; + ppen_info->coords.x = pen_data->x; + ppen_info->coords.y = pen_data->y; + ppen_info->coords.p = pen_data->p; + ppen_info->frame_no = dda_pen_report_buf.frame_no; + ppen_info->data_type = DATA_TYPE_RAW; + DDA_DBG("S:[%d] %d %d %d (%d)\n", pen_data->status, (int)pen_data->x, (int)pen_data->y, (int)pen_data->p, dda_pen_report_buf.frame_no); + dda_pen_report_buf.frame_no++; + if(MAX_IO_CONTROL_REPORT > dda_pen_report_buf.pen_report_num) { + // Max count: MAX_IO_CONTROL_REPORT + dda_pen_report_buf.pen_report_num++; + } + dda_pen_report_buf.buffer_wp++; + if(DDA_MAX_BUFFER == dda_pen_report_buf.buffer_wp) { + dda_pen_report_buf.buffer_wp = 0; + } + } +} +#endif //MOTO_DDA_ACTIVE_STYLUS + + +void moto_dda_init(char *device_name) { +#ifdef MOTO_DDA_PASSIVE_STYLUS + int cnt; +#endif //MOTO_DDA_PASSIVE_STYLUS + + memset(dda_device_name,0x00,sizeof(dda_device_name)); + strncpy(dda_device_name,device_name,sizeof(dda_device_name)-1); + +#ifdef MOTO_DDA_PASSIVE_STYLUS + for(cnt =0;cnt