// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2012 Synaptics Incorporated. */ #include #include #include #include /*#include */ #include #include #include #include #include "tpd.h" #include "include/synaptics_dsx_rmi4_i2c.h" #include "SynaImage.h" #include /*#include */ /* #include */ #ifdef CONFIG_MTK_BOOT #include "mtk_boot_common.h" #endif #include #include #include #include #include /* #define HAVE_TOUCH_KEY */ #define CONFIG_ID 0x30303033 /* DTS2012031404176 linghai 20120314 end */ /* add by huxin */ #ifdef HAVE_TOUCH_KEY const u16 touch_key_array[] = { KEY_MENU, KEY_HOMEPAGE, KEY_BACK }; #define MAX_KEY_NUM (ARRAY_SIZE(touch_key_array)/sizeof(touch_key_array[0])) #endif #if (defined(TPD_WARP_START) && defined(TPD_WARP_END)) static int tpd_wb_start_local[TPD_WARP_CNT] = TPD_WARP_START; static int tpd_wb_end_local[TPD_WARP_CNT] = TPD_WARP_END; #endif #if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION)) static int tpd_calmat_local[8] = TPD_CALIBRATION_MATRIX; static int tpd_def_calmat_local[8] = TPD_CALIBRATION_MATRIX; #endif unsigned int touch_irq; struct point { int x; int raw_x; int y; int raw_y; int z; int status; }; struct function_descriptor { u16 query_base; u16 cmd_base; u16 ctrl_base; u16 data_base; u8 intSrc; #define FUNCTION_VERSION(x) ((x >> 5) & 3) #define INTERRUPT_SOURCE_COUNT(x) (x & 7) u8 functionNumber; }; struct tpd_data { struct i2c_client *client; struct function_descriptor f01; struct function_descriptor f11; struct function_descriptor f1a; u8 fn11_mask; u8 fn1a_mask; struct point *cur_points; struct point *pre_points; struct mutex io_ctrl_mutex; struct work_struct work; int f11_max_x, f11_max_y; u8 points_supported; u8 data_length; u8 current_page; }; struct tpd_debug { u8 button_0d_enabled; }; static DECLARE_WAIT_QUEUE_HEAD(waiter); static struct tpd_data *ts; static struct tpd_debug *td; #ifdef CONFIG_MTK_BOOT static u8 boot_mode; #endif static int tpd_flag; static int tpd_halt; static DEFINE_MUTEX(i2c_access); /* Function extern */ static int tpd_probe(struct i2c_client *client, const struct i2c_device_id *id); static int tpd_detect(struct i2c_client *client, struct i2c_board_info *info); static int tpd_remove(struct i2c_client *client); /* static void tpd_work_func(struct work_struct *work); */ static void tpd_down(int x, int y, int p, int id); static void tpd_up(int x, int y); /* static int tpd_sw_power(struct i2c_client *client, int on); */ static int tpd_clear_interrupt(struct i2c_client *client); /* static u8 get_config_version(void); */ static const struct i2c_device_id tpd_id[] = { {TPD_DEVICE, 0}, {} }; /* DTS2012040603460 gkf61766 20120406 begin */ static unsigned short force[] = { 0, 0x40, I2C_CLIENT_END, I2C_CLIENT_END }; /* DTS2012040603460 gkf61766 20120406 end */ static const unsigned short *const forces[] = { force, NULL }; /* static struct i2c_client_address_data addr_data = { .forces = forces, }; */ static const struct of_device_id synaptics_dt_match[] = { {.compatible = "mediatek,cap_touch"}, {}, }; MODULE_DEVICE_TABLE(of, synaptics_dt_match); static struct i2c_driver tpd_i2c_driver = { .driver = { .name = TPD_DEVICE, .owner = THIS_MODULE, .of_match_table = of_match_ptr(synaptics_dt_match), }, .probe = tpd_probe, .remove = tpd_remove, .id_table = tpd_id, .detect = tpd_detect, .address_list = (const unsigned short *)forces, /* .address_data = &addr_data, */ }; unsigned int tpd_rst_gpio_number; unsigned int tpd_int_gpio_number; #ifdef CONFIG_OF static int of_get_synaptic_platform_data(struct device *dev) { /*int ret, num;*/ if (dev->of_node) { const struct of_device_id *match; match = of_match_device(of_match_ptr(synaptics_dt_match), dev); if (!match) { TPD_DEBUG("Error: No device match found\n"); return -ENODEV; } } tpd_rst_gpio_number = of_get_named_gpio(dev->of_node, "rst-gpio", 0); tpd_int_gpio_number = of_get_named_gpio(dev->of_node, "int-gpio", 0); TPD_DEBUG("g_vproc_en_gpio_number %d\n", tpd_rst_gpio_number); TPD_DEBUG("g_vproc_vsel_gpio_number %d\n", tpd_int_gpio_number); return 0; } #else static int of_get_synaptic_platform_data(struct device *dev) { return 0; } #endif #if PROXIMITY static ssize_t synaptics_rmi4_f51_enables_show(struct device *dev, struct device_attribute *attr, char *buf); static ssize_t synaptics_rmi4_f51_enables_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); #endif static irqreturn_t tpd_eint_handler(int irq, void *dev_id); struct kobject *properties_kobj_synap; struct kobject *properties_kobj_driver; static struct device_attribute attrs[] = { #if PROXIMITY __ATTR(proximity_enables, (0666), synaptics_rmi4_f51_enables_show, synaptics_rmi4_f51_enables_store), #endif }; static int tpd_irq_registration(void) { struct device_node *node = NULL; int ret = 0; TPD_DEBUG("Device Tree Tpd_irq_registration!"); node = of_find_compatible_node(NULL, NULL, "mediatek,cap_touch"); if (node) { /*touch_irq = gpio_to_irq(tpd_int_gpio_number);*/ touch_irq = irq_of_parse_and_map(node, 0); TPD_DEBUG("touch_irq number %d\n", touch_irq); ret = request_irq(touch_irq, tpd_eint_handler, IRQF_TRIGGER_FALLING, TPD_DEVICE, NULL); if (ret > 0) TPD_DMESG("tpd IRQ LINE NOT AVAILABLE!."); } else { TPD_DMESG("tpd can not find touch eint device node!."); } return ret; } static bool exp_fn_inited; static struct mutex exp_fn_list_mutex; static struct list_head exp_fn_list; #if PROXIMITY static struct synaptics_rmi4_f51_handle *f51; #endif #if PROXIMITY static ssize_t synaptics_rmi4_f51_enables_show(struct device *dev, struct device_attribute *attr, char *buf) { int retval; unsigned char proximity_enables; if (!f51) return -ENODEV; retval = synaptics_rmi4_i2c_read(f51->rmi4_data, f51->proximity_enables_addr, &proximity_enables, sizeof(proximity_enables)); if (retval < 0) { dev_info(dev, "%s: Failed to read proximity enables, error = %d\n", __func__, retval); return retval; } return snprintf(buf, PAGE_SIZE, "0x%02x\n", proximity_enables); } static ssize_t synaptics_rmi4_f51_enables_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int retval; unsigned int input; unsigned char proximity_enables; if (!f51) return -ENODEV; if (kstrtoint(buf, 10, &input)) return -EINVAL; proximity_enables = input; retval = synaptics_rmi4_i2c_write(f51->rmi4_data, f51->proximity_enables_addr, &proximity_enables, sizeof(proximity_enables)); if (retval < 0) { dev_info(dev, "%s: Failed to write proximity enables, error = %d\n", __func__, retval); return retval; } return count; } #endif static int tpd_set_page(struct i2c_client *client, unsigned int address) { int retval = 0; unsigned char retry; unsigned char buf[PAGE_SELECT_LEN]; unsigned char page; page = ((address >> 8) & MASK_8BIT); if (page != ts->current_page) { buf[0] = MASK_8BIT; buf[1] = page; for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { retval = i2c_master_send(client, buf, PAGE_SELECT_LEN); if (retval != PAGE_SELECT_LEN) { dev_info(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1); msleep(20); } else { ts->current_page = page; break; } } } else { retval = PAGE_SELECT_LEN; } return retval; } int tpd_i2c_read_data(struct i2c_client *client, unsigned short addr, unsigned char *data, unsigned short length) { u8 retval = 0; u8 retry = 0; u8 *pData = data; int tmp_addr = addr; int left_len = length; /* u16 old_flag; */ mutex_lock(&(ts->io_ctrl_mutex)); retval = tpd_set_page(client, addr); if (retval != PAGE_SELECT_LEN) goto exit; /* old_flag = client->ext_flag; */ /* client->addr = client->addr & I2C_MASK_FLAG ; */ while (left_len > 0) { pData[0] = tmp_addr; for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { retval = i2c_master_send(client, pData, 1); if (retval <= 0) { dev_info(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1); msleep(20); continue; } if (left_len > 8) retval = i2c_master_recv(client, pData, 8); else retval = i2c_master_recv(client, pData, left_len); if (retval <= 0) { dev_info(&client->dev, "%s: I2C retry %d\n", __func__, retry + 1); msleep(20); continue; } else break; } left_len -= 8; pData += 8; tmp_addr += 8; } /* client->ext_flag = old_flag; */ exit: mutex_unlock(&(ts->io_ctrl_mutex)); return retval; } EXPORT_SYMBOL(tpd_i2c_read_data); int tpd_i2c_write_data(struct i2c_client *client, unsigned short addr, unsigned char *data, unsigned short length) { u8 retval = 0; u8 retry = 0; u8 *pData = data; u8 buf[5] = { 0 }; int tmp_addr = addr; int left_len = length; mutex_lock(&(ts->io_ctrl_mutex)); retval = tpd_set_page(client, addr); if (retval != PAGE_SELECT_LEN) { TPD_DMESG("tpd_set_page fail, retval = %d\n", retval); retval = -EIO; goto exit; } while (left_len > 0) { buf[0] = tmp_addr; for (retry = 0; retry < SYN_I2C_RETRY_TIMES; retry++) { if (left_len > 4) { memcpy(buf + 1, pData, 4); retval = i2c_master_send(client, buf, 5); } else { memcpy(buf + 1, pData, left_len); retval = i2c_master_send(client, buf, left_len + 1); } if (retval > 0) break; TPD_DMESG("%s: I2C retry %d\n", __func__, retry + 1); msleep(20); } left_len -= 4; pData += 4; tmp_addr += 4; } exit: mutex_unlock(&(ts->io_ctrl_mutex)); return retval; } EXPORT_SYMBOL(tpd_i2c_write_data); #if PROXIMITY static int synaptics_rmi4_f51_report( struct synaptics_rmi4_data *rmi4_data, struct synaptics_rmi4_fn *fhandler) { int retval; unsigned char touch_count = 0; /* number of touch points */ unsigned short data_base_addr; int x; int y; int z; struct synaptics_rmi4_f51_data *data_reg; data_base_addr = fhandler->full_addr.data_base; data_reg = (struct synaptics_rmi4_f51_data *)fhandler->data; retval = tpd_i2c_read(rmi4_data, data_base_addr, data_reg->data, sizeof(data_reg->data)); if (retval < 0) return 0; if (data_reg->data[0] == 0x00) return 0; #if sdfsdfadf if (data_reg->finger_hover_det) { if (data_reg->hover_finger_z > 0) { x = (data_reg->hover_finger_x_4__11 << 4) | (data_reg->hover_finger_xy_0__3 & 0x0f); y = (data_reg->hover_finger_y_4__11 << 4) | (data_reg->hover_finger_xy_0__3 >> 4); z = HOVER_Z_MAX - data_reg->hover_finger_z; dev_dbg(&rmi4_data->i2c_client->dev, "%s: Hover finger: x = %d, y = %d, z = %d\n", __func__, x, y, z); input_report_abs(tpd->dev, ABS_MT_POSITION_X, x); input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y); #ifdef INPUT_MULTITOUCH input_report_abs(tpd->dev, ABS_MT_DISTANCE, z); #endif input_mt_sync(tpd->dev); touch_count++; } } if (data_reg->air_swipe_det) { dev_dbg(&rmi4_data->i2c_client->dev, "%s: Swipe direction 0 = %d\n", __func__, data_reg->air_swipe_dir_0); dev_dbg(&rmi4_data->i2c_client->dev, "%s: Swipe direction 1 = %d\n", __func__, data_reg->air_swipe_dir_1); } if (data_reg->large_obj_det) { dev_dbg(&rmi4_data->i2c_client->dev, "%s: Large object activity = %d\n", __func__, data_reg->large_obj_act); } if (data_reg->hover_pinch_det) { dev_dbg(&rmi4_data->i2c_client->dev, "%s: Hover pinch direction = %d\n", __func__, data_reg->hover_pinch_dir); } #endif if (!touch_count) input_mt_sync(tpd->dev); input_sync(tpd->dev); return touch_count; } #endif #if PROXIMITY static int synaptics_rmi4_f51_init( struct synaptics_rmi4_data *rmi4_data, struct synaptics_rmi4_fn *fhandler, struct synaptics_rmi4_fn_desc *fd, unsigned int intr_count) { int retval; unsigned char ii; unsigned short intr_offset; unsigned char proximity_enable_mask = PROXIMITY_ENABLE; struct synaptics_rmi4_f51_query query_register; struct synaptics_rmi4_f51_data *data_register; fhandler->fn_number = fd->fn_number; fhandler->num_of_data_sources = fd->intr_src_count; fhandler->intr_reg_num = (intr_count + 7) / 8; if (fhandler->intr_reg_num != 0) fhandler->intr_reg_num -= 1; /* Set an enable bit for each data source */ intr_offset = intr_count % 8; fhandler->intr_mask = 0; for (ii = intr_offset; ii < ((fd->intr_src_count & MASK_3BIT) + intr_offset); ii++) fhandler->intr_mask |= 1 << ii; retval = synaptics_rmi4_i2c_read(rmi4_data, fhandler->full_addr.query_base, query_register.data, sizeof(query_register.data)); if (retval < 0) return retval; fhandler->data_size = sizeof(data_register->data); data_register = kmalloc(fhandler->data_size, GFP_KERNEL); fhandler->data = (void *)data_register; retval = synaptics_rmi4_i2c_write(rmi4_data, fhandler->full_addr.ctrl_base + query_register.control_register_count - 1, &proximity_enable_mask, sizeof(proximity_enable_mask)); if (retval < 0) return retval; f51 = kmalloc(sizeof(*f51), GFP_KERNEL); f51->rmi4_data = rmi4_data; f51->proximity_enables_addr = fhandler->full_addr.ctrl_base + query_register.control_register_count - 1; return 0; } int synaptics_rmi4_proximity_enables(unsigned char enables) { int retval; unsigned char proximity_enables = enables; if (!f51) return -ENODEV; retval = synaptics_rmi4_i2c_write(f51->rmi4_data, f51->proximity_enables_addr, &proximity_enables, sizeof(proximity_enables)); if (retval < 0) return retval; return 0; } EXPORT_SYMBOL(synaptics_rmi4_proximity_enables); #endif static int tpd_rmi4_read_pdt(struct tpd_data *ts) { int retval; unsigned char ii; unsigned char offset = 0; unsigned char page_number; unsigned char intr_count = 0; /* unsigned char data_sources = 0; */ /* unsigned char f01_query[F01_STD_QUERY_LEN]; */ unsigned char f11_query[F11_STD_QUERY_LEN]; unsigned int f11_max_xy; /* u8 point_length; */ unsigned short pdt_entry_addr; /* unsigned short intr_addr; */ static unsigned char intsrc = 1; /* struct synaptics_rmi4_f01_device_status status; */ struct synaptics_rmi4_fn_desc rmi_fd; /* Scan the page description tables of the pages to service */ for (page_number = 0; page_number < PAGES_TO_SERVICE; page_number++) { for (pdt_entry_addr = PDT_START; pdt_entry_addr > PDT_END; pdt_entry_addr -= PDT_ENTRY_SIZE) { pdt_entry_addr |= (page_number << 8); retval = tpd_i2c_read_data(ts->client, pdt_entry_addr, (unsigned char *)&rmi_fd, sizeof(rmi_fd)); if (retval < 0) return retval; if (rmi_fd.fn_number == 0) { dev_dbg(&ts->client->dev, "%s: Reached end of PDT\n", __func__); break; } dev_dbg(&ts->client->dev, "%s: F%02x found (page %d)\n", __func__, rmi_fd.fn_number, page_number); switch (rmi_fd.fn_number) { case SYNAPTICS_RMI4_F01: ts->f01.query_base = rmi_fd.query_base_addr; ts->f01.ctrl_base = rmi_fd.ctrl_base_addr; ts->f01.cmd_base = rmi_fd.cmd_base_addr; ts->f01.data_base = rmi_fd.data_base_addr; ts->f01.intSrc = intsrc++; ts->f01.functionNumber = rmi_fd.fn_number; break; case SYNAPTICS_RMI4_F11: if (rmi_fd.intr_src_count == 0) break; ts->f11.query_base = rmi_fd.query_base_addr; ts->f11.ctrl_base = rmi_fd.ctrl_base_addr; ts->f11.cmd_base = rmi_fd.cmd_base_addr; ts->f11.data_base = rmi_fd.data_base_addr; ts->f11.intSrc = intsrc++; ts->f11.functionNumber = rmi_fd.fn_number; ts->fn11_mask = 0; offset = intr_count % 8; for (ii = offset; ii < (rmi_fd.intr_src_count + offset); ii++) ts->fn11_mask |= 1 << ii; retval = tpd_i2c_read_data(ts->client, ts->f11.query_base, f11_query, sizeof(f11_query)); if (retval < 0) return retval; TPD_DEBUG("f11 query base=%d\n", ts->f11.query_base); /* Maximum number of fingers supported */ if ((f11_query[1] & MASK_3BIT) <= 4) { ts->points_supported = (f11_query[1] & MASK_3BIT) + 1; TPD_DEBUG("points_supported=%d\n", ts->points_supported); } else if ((f11_query[1] & MASK_3BIT) == 5) { ts->points_supported = 10; TPD_DEBUG("points_supported=%d\n", ts->points_supported); } retval = tpd_i2c_read_data(ts->client, ts->f11.ctrl_base + 6, (char *)(&f11_max_xy), sizeof(f11_max_xy)); if (retval < 0) return retval; /* Maximum x and y */ ts->f11_max_x = f11_max_xy & 0xFFF; ts->f11_max_y = (f11_max_xy >> 16) & 0xFFF; ts->pre_points = kzalloc(ts->points_supported * sizeof(struct point), GFP_KERNEL); if (ts->pre_points == NULL) { TPD_DMESG("Error zalloc failed!\n"); retval = -ENOMEM; return retval; } ts->cur_points = kzalloc(ts->points_supported * sizeof(struct point), GFP_KERNEL); if (ts->cur_points == NULL) { TPD_DMESG("Error zalloc failed!\n"); retval = -ENOMEM; return retval; } ts->data_length = 3 + (2 * ((f11_query[5] & MASK_2BIT) == 0 ? 1 : 0)); break; case SYNAPTICS_RMI4_F12: break; case SYNAPTICS_RMI4_F1A: if (rmi_fd.intr_src_count == 0) break; ts->f1a.query_base = rmi_fd.query_base_addr; ts->f1a.ctrl_base = rmi_fd.ctrl_base_addr; ts->f1a.cmd_base = rmi_fd.cmd_base_addr; ts->f1a.data_base = rmi_fd.data_base_addr; ts->f01.intSrc = intsrc++; ts->f01.functionNumber = rmi_fd.fn_number; td->button_0d_enabled = 1; ts->fn1a_mask = 0; offset = intr_count % 8; for (ii = offset; ii < (rmi_fd.intr_src_count + offset); ii++) ts->fn1a_mask |= 1 << ii; break; #if PROXIMITY case SYNAPTICS_RMI4_F51: if (rmi_fd.intr_src_count == 0) break; break; #endif } if (rmi_fd.intr_src_count & 0x03) intr_count += rmi_fd.intr_src_count & 0x03; } } return 0; } #ifdef TPD_UPDATE_FIRMWARE static void synaptics_rmi4_detection_work(struct work_struct *work) { struct synaptics_rmi4_exp_fn *exp_fhandler, *next_list_entry; mutex_lock(&exp_fn_list_mutex); if (!list_empty(&exp_fn_list)) { list_for_each_entry_safe(exp_fhandler, next_list_entry, &exp_fn_list, link) { if ((exp_fhandler->func_init != NULL) && (exp_fhandler->inserted == false)) { exp_fhandler->func_init(ts->client); exp_fhandler->inserted = true; } else if ((exp_fhandler->func_init == NULL) && (exp_fhandler->inserted == true)) { exp_fhandler->func_remove(ts->client); list_del(&exp_fhandler->link); kfree(exp_fhandler); } } } mutex_unlock(&exp_fn_list_mutex); } static int touch_update_handler(void *unused) { int retval = 0; msleep(10000); TPD_DEBUG("start to touch update_handler\n"); mutex_lock(&i2c_access); if (tpd_halt) { mutex_unlock(&i2c_access); TPD_DMESG("the touch has been suspend\n"); return 0; } disable_irq(touch_irq); synaptics_rmi4_detection_work(NULL); /* synaptics_fw_updater(synaImage); */ synaptics_fw_updater(NULL); /* auto detect by sensor id */ retval = tpd_rmi4_read_pdt(ts); if (retval < 0) TPD_DMESG("Failed to query device\n"); tpd_clear_interrupt(ts->client); enable_irq(touch_irq); mutex_unlock(&i2c_access); return 0; } #endif void synaptics_rmi4_new_function(enum exp_fn fn_type, bool insert, int (*func_init)(struct i2c_client *client), void (*func_remove)(struct i2c_client *client), void (*func_attn)(struct i2c_client *client, unsigned char intr_mask)) { struct synaptics_rmi4_exp_fn *exp_fhandler; if (!exp_fn_inited) { mutex_init(&exp_fn_list_mutex); INIT_LIST_HEAD(&exp_fn_list); exp_fn_inited = 1; } mutex_lock(&exp_fn_list_mutex); if (insert) { exp_fhandler = kzalloc(sizeof(*exp_fhandler), GFP_KERNEL); exp_fhandler->fn_type = fn_type; exp_fhandler->func_init = func_init; exp_fhandler->func_attn = func_attn; exp_fhandler->func_remove = func_remove; exp_fhandler->inserted = false; list_add_tail(&exp_fhandler->link, &exp_fn_list); } else { list_for_each_entry(exp_fhandler, &exp_fn_list, link) { if (exp_fhandler->func_init == func_init) { exp_fhandler->inserted = false; exp_fhandler->func_init = NULL; exp_fhandler->func_attn = NULL; goto exit; } } } exit: mutex_unlock(&exp_fn_list_mutex); } EXPORT_SYMBOL(synaptics_rmi4_new_function); static void tpd_down(int x, int y, int p, int id) { input_report_key(tpd->dev, BTN_TOUCH, 1); input_report_abs(tpd->dev, ABS_MT_TRACKING_ID, id); /* input_report_abs(tpd->dev, ABS_PRESSURE, p); */ input_report_abs(tpd->dev, ABS_MT_TOUCH_MAJOR, p); input_report_abs(tpd->dev, ABS_MT_POSITION_X, x); input_report_abs(tpd->dev, ABS_MT_POSITION_Y, y); input_mt_sync(tpd->dev); TPD_DEBUG_SET_TIME; TPD_EM_PRINT(x, y, x, y, 0, 1); #ifdef CONFIG_MTK_BOOT if (tpd_dts_data.use_tpd_button) { if (boot_mode == FACTORY_BOOT || boot_mode == RECOVERY_BOOT) tpd_button(x, y, 1); } #endif } static void tpd_up(int x, int y) { input_report_key(tpd->dev, BTN_TOUCH, 0); TPD_DEBUG_SET_TIME; TPD_EM_PRINT(x, y, x, y, 0, 0); #ifdef CONFIG_MTK_BOOT if (tpd_dts_data.use_tpd_button) { if (boot_mode == FACTORY_BOOT || boot_mode == RECOVERY_BOOT) tpd_button(x, y, 0); } #endif } static int touch_event_handler(void *unused) { struct sched_param param = {.sched_priority = 4 }; u16 temp = 0; u8 i = 0; u8 status = 0; u8 retval = 0; u8 finger_num = 0; u8 finger_status = 0; u8 finger_status_reg[3]; u8 data[F11_STD_DATA_LEN]; u8 num_of_finger_status_regs = 0; u8 button = 0; struct point *ppt = NULL; #ifdef HAVE_TOUCH_KEY struct point ppt_v = { 0 }; #endif sched_setscheduler(current, SCHED_RR, ¶m); do { set_current_state(TASK_INTERRUPTIBLE); wait_event_interruptible(waiter, tpd_flag != 0); tpd_flag = 0; set_current_state(TASK_RUNNING); mutex_lock(&i2c_access); if (tpd_halt) { mutex_unlock(&i2c_access); TPD_DEBUG("return for interrupt after suspend..."); continue; } /* clear interrupt bit */ retval = tpd_i2c_read_data(ts->client, ts->f01.data_base + 1, &status, 1); if (retval < 0) { /* disable_irq_nosync(touch_irq);*/ mutex_unlock(&i2c_access); /* enable_irq(touch_irq);*/ continue; } if (status & ts->fn11_mask) { tpd_i2c_read_data(ts->client, ts->f11.data_base, finger_status_reg, (ts->points_supported + 3) / 4); num_of_finger_status_regs = (ts->points_supported + 3) / 4; finger_num = ts->points_supported; for (i = 0; i < ts->points_supported; i++) { finger_status = finger_status_reg[i / 4]; finger_status = (finger_status >> ((i % 4) * 2)) & 3; ppt = &ts->cur_points[i]; ppt->status = finger_status; if (finger_status == 0x01 || finger_status == 0x02) { temp = ts->f11.data_base + num_of_finger_status_regs + i * ts->data_length; tpd_i2c_read_data(ts->client, ts->f11.data_base + num_of_finger_status_regs + i * ts->data_length, data, ts->data_length); ppt->raw_x = ppt->x = (((u16) (data[0]) << 4) | (data[2] & 0x0F)); ppt->raw_y = ppt->y = (((u16) (data[1]) << 4) | ((data[2] >> 4) & 0x0F)); ppt->z = data[4]; pr_debug("[TPD]point %d: [X:%04d, Y:%04d]", i, ppt->x, ppt->y); tpd_down(ppt->x, ppt->y, ppt->z, i); } else { finger_num--; } } } #ifdef HAVE_TOUCH_KEY if (status & ts->fn1a_mask) retval = tpd_i2c_read_data(ts->client, 0x200, &button, 1); if (button) { for (i = 0; i < MAX_KEY_NUM; i++) { if (button & (0x01 << i)) { ppt_v.x = tpd_keys_dim_local_wvga[i][0]; ppt_v.y = tpd_keys_dim_local_wvga[i][1]; tpd_down(ppt_v.x, ppt_v.y, 20, 10 + i); } } } #endif mutex_unlock(&i2c_access); if (!finger_num && !button) tpd_up(0, 0); input_sync(tpd->dev); /* ts->pre_points = ts->cur_points; */ /* disable_irq_nosync(touch_irq);*/ /* enable_irq(touch_irq);*/ } while (!kthread_should_stop()); return 0; } static irqreturn_t tpd_eint_handler(int irq, void *dev_id) { TPD_DEBUG_PRINT_INT; tpd_flag = 1; wake_up_interruptible(&waiter); return IRQ_HANDLED; } static int tpd_detect(struct i2c_client *client, struct i2c_board_info *info) { strcpy(info->type, TPD_DEVICE); return 0; } static int tpd_remove(struct i2c_client *client) { TPD_DEBUG("TPD removed\n"); return 0; } static int tpd_clear_interrupt(struct i2c_client *client) { int retval = 0; u8 status = 0; retval = tpd_i2c_read_data(client, ts->f01.data_base + 1, &status, 1); if (retval < 0) dev_info(&client->dev, "%s: Failed to enable attention interrupt\n", __func__); return retval; } static int tpd_probe(struct i2c_client *client, const struct i2c_device_id *id) { /* u8 ii; */ u8 attr_count; /* u8 status = 0; */ int retval; /* int i; */ u8 data; int reset_count = 3; /* unsigned char config_id[4]; */ /* unsigned char tp_id[8]; */ /* unsigned int config_id_no = 0; */ /* u16 tp_x_for_lcd=0; */ /* u16 tp_y_for_lcd=0; */ /* struct synaptics_rmi4_fn *fhandler; */ /* struct synaptics_rmi4_data *rmi4_data; */ /* struct synaptics_rmi4_device_info *rmi; */ struct task_struct *thread = NULL; TPD_DMESG("%s:enter\n", __func__); TPD_RESET_PROBE: ts = kzalloc(sizeof(struct tpd_data), GFP_KERNEL); if (!ts) { TPD_DMESG("Failed to alloc mem for tpd_data\n"); return -ENOMEM; } td = kzalloc(sizeof(struct tpd_debug), GFP_KERNEL); if (!td) TPD_DMESG("Failed to alloc mem for tpd_debug\n"); ts->client = client; mutex_init(&(ts->io_ctrl_mutex)); of_get_synaptic_platform_data(&client->dev); /* configure the gpio pins */ retval = gpio_request_one(tpd_rst_gpio_number, GPIOF_OUT_INIT_LOW, "touchp_reset"); if (retval < 0) { TPD_DMESG("Unable to request gpio reset_pin\n"); return -1; } retval = gpio_request_one(tpd_int_gpio_number, GPIOF_IN, "tpd_int"); if (retval < 0) { TPD_DMESG("Unable to request gpio int_pin\n"); gpio_free(tpd_rst_gpio_number); return -1; } retval = regulator_enable(tpd->reg); if (retval != 0) { dev_info(&client->dev, "Failed to enable reg-vgp6: %d\n", retval); goto err_query_device; } retval = regulator_enable(tpd->io_reg); if (retval != 0) { dev_info(&client->dev, "Failed to enable reg-vgp4: %d\n", retval); goto err_query_device; } msleep(20); /*tpd_gpio_output(GTP_RST_PORT, 0);*/ gpio_direction_output(tpd_rst_gpio_number, 0); msleep(50); /*tpd_gpio_output(GTP_RST_PORT, 1);*/ gpio_direction_output(tpd_rst_gpio_number, 1); msleep(50); if ((tpd_i2c_read_data(ts->client, 0xEE, &data, 1)) < 0) { if (reset_count-- > 0) goto TPD_RESET_PROBE; dev_info(&client->dev, "Can't connect touch panel.\n"); return -1; } retval = tpd_rmi4_read_pdt(ts); if (retval < 0) { dev_info(&client->dev, "Failed to query device\n"); goto err_query_device; } if (!exp_fn_inited) { mutex_init(&exp_fn_list_mutex); INIT_LIST_HEAD(&exp_fn_list); exp_fn_inited = 1; } tpd_clear_interrupt(client); properties_kobj_synap = kobject_create_and_add("synapics", NULL); #ifdef HAVE_TOUCH_KEY set_bit(EV_KEY, tpd->dev->evbit); for (i = 0; i < MAX_KEY_NUM; i++) __set_bit(touch_key_array[i], tpd->dev->keybit); #endif #ifdef VELOCITY_CUSTOM tpd_v_magnify_x = TPD_VELOCITY_CUSTOM_X; tpd_v_magnify_y = TPD_VELOCITY_CUSTOM_Y; #endif #ifdef TPD_UPDATE_FIRMWARE thread = kthread_run(touch_update_handler, 0, TPD_DEVICE); if (IS_ERR(thread)) { retval = PTR_ERR(thread); TPD_DMESG("failed to create kernel thread: %d\n", retval); goto error_kthread_creat_failed; } #endif properties_kobj_driver = kobject_create_and_add("driver", properties_kobj_synap); for (attr_count = 0; attr_count < ARRAY_SIZE(attrs); attr_count++) { retval = sysfs_create_file(properties_kobj_driver, &attrs[attr_count].attr); if (retval < 0) { dev_info(&client->dev, "%s: Failed to create sysfs attributes\n", __func__); goto err_sysfs; } } thread = kthread_run(touch_event_handler, 0, TPD_DEVICE); if (IS_ERR(thread)) { retval = PTR_ERR(thread); TPD_DMESG("failed to create kernel thread: %d\n", retval); goto error_kthread_creat_failed; } tpd_irq_registration(); /* disable_irq_nosync(touch_irq);*/ /* enable_irq(touch_irq);*/ tpd_load_status = 1; TPD_DMESG("%s: TouchPanel Device Probe %s\n", __func__, (retval < 0) ? "FAIL" : "PASS"); return 0; err_sysfs: for (attr_count--; attr_count >= 0; attr_count--) sysfs_remove_file(properties_kobj_driver, &attrs[attr_count].attr); error_kthread_creat_failed: err_query_device: kfree(td); kfree(ts); /* hwPowerDown(MT65XX_POWER_LDO_VGP2, "TP"); */ return retval; } static int tpd_local_init(void) { int retval; TPD_DEBUG("Synaptics I2C Touchscreen Driver load\n"); tpd->reg = regulator_get(tpd->tpd_dev, "vtouch"); tpd->io_reg = regulator_get(tpd->tpd_dev, "vtouchio"); retval = regulator_set_voltage(tpd->reg, 3300000, 3300000); if (retval != 0) { TPD_DMESG("Failed to set reg-vgp6 voltage: %d\n", retval); return -1; } retval = regulator_set_voltage(tpd->io_reg, 1800000, 1800000); if (retval != 0) { TPD_DMESG("Failed to set reg-vgp4 voltage: %d\n", retval); return -1; } if (i2c_add_driver(&tpd_i2c_driver) != 0) { TPD_DMESG("Error unable to add i2c driver.\n"); return -1; } if (tpd_load_status == 0) { TPD_DMESG("Synaptics add error touch panel driver.\n"); i2c_del_driver(&tpd_i2c_driver); return -1; } if (tpd_dts_data.use_tpd_button) { /*initialize tpd button data*/ tpd_button_setting(tpd_dts_data.tpd_key_num, tpd_dts_data.tpd_key_local, tpd_dts_data.tpd_key_dim_local); } #if (defined(TPD_WARP_START) && defined(TPD_WARP_END)) TPD_DO_WARP = 1; memcpy(tpd_wb_start, tpd_wb_start_local, TPD_WARP_CNT * 4); memcpy(tpd_wb_end, tpd_wb_start_local, TPD_WARP_CNT * 4); #endif #if (defined(TPD_HAVE_CALIBRATION) && !defined(TPD_CUSTOM_CALIBRATION)) memcpy(tpd_calmat, tpd_def_calmat_local, 8 * 4); memcpy(tpd_def_calmat, tpd_def_calmat_local, 8 * 4); #endif #ifdef CONFIG_MTK_BOOT boot_mode = get_boot_mode(); /* if (boot_mode == 3) boot_mode = NORMAL_BOOT; */ #endif input_set_abs_params(tpd->dev, ABS_MT_TRACKING_ID, 0, (10 - 1), 0, 0); TPD_DEBUG("end %s, %d\n", __func__, __LINE__); tpd_type_cap = 1; return 0; } static void tpd_resume(struct device *h) { /* u16 tp_x_for_lcd=0; */ /* u16 tp_y_for_lcd=0; */ u8 data; int reset_count = 5; int retval; TPD_RESET_RESUME: retval = regulator_enable(tpd->reg); if (retval != 0) TPD_DMESG("Failed to enable reg-vgp6: %d\n", retval); retval = regulator_enable(tpd->io_reg); if (retval != 0) TPD_DMESG("Failed to enable reg-vgp4: %d\n", retval); /* hwPowerOn(MT6323_POWER_LDO_VGP2, VOL_1800, "TP"); */ msleep(20); /*tpd_gpio_output(GTP_RST_PORT, 0);*/ gpio_direction_output(tpd_rst_gpio_number, 0); msleep(50); /*tpd_gpio_output(GTP_RST_PORT, 1);*/ gpio_direction_output(tpd_rst_gpio_number, 1); msleep(50); /* Recovery EINT Mode */ /*tpd_gpio_as_int(GTP_INT_PORT);*/ gpio_direction_input(tpd_int_gpio_number); if ((tpd_i2c_read_data(ts->client, 0xEE, &data, 1)) < 0) { if (reset_count-- > 0) goto TPD_RESET_RESUME; TPD_DMESG("Can't connect touch panel.\n"); } tpd_clear_interrupt(ts->client); mutex_lock(&i2c_access); tpd_halt = 0; enable_irq(touch_irq); mutex_unlock(&i2c_access); } static void tpd_suspend(struct device *h) { int retval; mutex_lock(&i2c_access); disable_irq(touch_irq); tpd_halt = 1; mutex_unlock(&i2c_access); /* Set EINT PIN to low */ /*tpd_gpio_output(GTP_INT_PORT, 0);*/ gpio_direction_output(tpd_int_gpio_number, 0); /* Set RST PIN to low */ /*tpd_gpio_output(GTP_RST_PORT, 0);*/ gpio_direction_output(tpd_rst_gpio_number, 0); retval = regulator_disable(tpd->io_reg); if (retval != 0) TPD_DMESG("Failed to disable reg-vgp4: %d\n", retval); retval = regulator_disable(tpd->reg); if (retval != 0) TPD_DMESG("Failed to disable reg-vgp6: %d\n", retval); TPD_DEBUG("TPD enter sleep\n"); } static struct tpd_driver_t tpd_device_driver = { .tpd_device_name = "synaptics", .tpd_local_init = tpd_local_init, .suspend = tpd_suspend, .resume = tpd_resume, }; static int __init tpd_driver_init(void) { TPD_DEBUG("Synaptics touch panel driver init\n"); tpd_get_dts_info(); if (tpd_driver_add(&tpd_device_driver) < 0) TPD_DMESG("Error Add Synaptics driver failed\n"); return 0; } static void __exit tpd_driver_exit(void) { TPD_DEBUG("Synaptics touch panel driver exit\n"); tpd_driver_remove(&tpd_device_driver); } module_init(tpd_driver_init); module_exit(tpd_driver_exit); MODULE_DESCRIPTION("Mediatek Synaptics Driver");