diff options
author | Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> | 2010-06-01 18:03:51 +0530 |
---|---|---|
committer | John Rigby <john.rigby@linaro.org> | 2010-09-02 22:45:32 -0600 |
commit | ce731e3682788935e9d9b9889f9a15b4ea7d1785 (patch) | |
tree | a0c03319b2ec90e77fa5b66beeefd96f6d6eaf69 | |
parent | f344d5b7119e8729bcab6f7aed8541276f82759e (diff) | |
download | linux-2.6.34-ux500-ce731e3682788935e9d9b9889f9a15b4ea7d1785.tar.gz |
bu21013: Driver for new dual touch controllers support
Adding bu21013 dual touch controllers driver and
support for it in mach-ux500.
ST-Ericsson ID: WP 257134
Signed-off-by: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com>
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/413
Reviewed-by: Jonas ABERG <jonas.aberg@stericsson.com>
Tested-by: Jonas ABERG <jonas.aberg@stericsson.com>
Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Change-Id: If084c45539cd18982ddf210cf2b80be2e8da4dd3
Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/2390
-rwxr-xr-x[-rw-r--r--] | arch/arm/configs/mop500_USB_HOST_defconfig | 3 | ||||
-rwxr-xr-x | arch/arm/configs/mop500_defconfig | 9 | ||||
-rwxr-xr-x | arch/arm/configs/mop500_ed_defconfig | 9 | ||||
-rwxr-xr-x | arch/arm/configs/mop500_power_defconfig | 9 | ||||
-rwxr-xr-x | arch/arm/mach-ux500/board-mop500.c | 234 | ||||
-rwxr-xr-x | arch/arm/mach-ux500/include/mach/devices.h | 15 | ||||
-rwxr-xr-x | arch/arm/mach-ux500/include/mach/u8500_tsc.h | 286 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 51 | ||||
-rw-r--r-- | drivers/input/touchscreen/Makefile | 2 | ||||
-rwxr-xr-x | drivers/input/touchscreen/bu21013_ts.c | 1357 | ||||
-rw-r--r-- | drivers/input/touchscreen/u8500_tsc.c | 1474 | ||||
-rwxr-xr-x | include/linux/bu21013.h | 284 |
12 files changed, 1801 insertions, 1932 deletions
diff --git a/arch/arm/configs/mop500_USB_HOST_defconfig b/arch/arm/configs/mop500_USB_HOST_defconfig index 7a672a088b4..4d5baad47af 100644..100755 --- a/arch/arm/configs/mop500_USB_HOST_defconfig +++ b/arch/arm/configs/mop500_USB_HOST_defconfig @@ -784,6 +784,9 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_TOUCHSCREEN_W90X900 is not set +CONFIG_TOUCHSCREEN_BU21013=y +CONFIG_BU21013_TSC_CNTL1=y +# CONFIG_BU21013_TSC_CNTL2 is not set # CONFIG_INPUT_MISC is not set # diff --git a/arch/arm/configs/mop500_defconfig b/arch/arm/configs/mop500_defconfig index 8a20009329b..d5a6b934a81 100755 --- a/arch/arm/configs/mop500_defconfig +++ b/arch/arm/configs/mop500_defconfig @@ -903,13 +903,10 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_TOUCHSCREEN_W90X900 is not set -CONFIG_U8500_TSC=y -# CONFIG_U8500_TSC_SINGLETOUCH is not set -CONFIG_U8500_TSC_MULTITOUCH=y -# CONFIG_U8500_TSC_X_FLIP is not set -CONFIG_U8500_TSC_Y_FLIP=y -# CONFIG_U8500_TSC_EXT_CLK_9_6 is not set CONFIG_TOUCHP_TUNING=y +CONFIG_TOUCHSCREEN_BU21013=y +CONFIG_BU21013_TSC_CNTL1=y +# CONFIG_BU21013_TSC_CNTL2 is not set CONFIG_INPUT_MISC=y # CONFIG_INPUT_ATI_REMOTE is not set # CONFIG_INPUT_ATI_REMOTE2 is not set diff --git a/arch/arm/configs/mop500_ed_defconfig b/arch/arm/configs/mop500_ed_defconfig index 23ec4889f89..f54d89a9d47 100755 --- a/arch/arm/configs/mop500_ed_defconfig +++ b/arch/arm/configs/mop500_ed_defconfig @@ -881,13 +881,10 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_TOUCHSCREEN_W90X900 is not set -CONFIG_U8500_TSC=y -# CONFIG_U8500_TSC_SINGLETOUCH is not set -CONFIG_U8500_TSC_MULTITOUCH=y -# CONFIG_U8500_TSC_X_FLIP is not set -CONFIG_U8500_TSC_Y_FLIP=y -# CONFIG_U8500_TSC_EXT_CLK_9_6 is not set CONFIG_TOUCHP_TUNING=y +CONFIG_TOUCHSCREEN_BU21013=y +#CONFIG_BU21013_TSC_CNTL1=y +# CONFIG_BU21013_TSC_CNTL2 is not set # CONFIG_INPUT_MISC is not set # diff --git a/arch/arm/configs/mop500_power_defconfig b/arch/arm/configs/mop500_power_defconfig index 3d0ec148809..42664d52ef7 100755 --- a/arch/arm/configs/mop500_power_defconfig +++ b/arch/arm/configs/mop500_power_defconfig @@ -903,13 +903,10 @@ CONFIG_INPUT_TOUCHSCREEN=y # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set # CONFIG_TOUCHSCREEN_TSC2007 is not set # CONFIG_TOUCHSCREEN_W90X900 is not set -CONFIG_U8500_TSC=y -# CONFIG_U8500_TSC_SINGLETOUCH is not set -CONFIG_U8500_TSC_MULTITOUCH=y -# CONFIG_U8500_TSC_X_FLIP is not set -CONFIG_U8500_TSC_Y_FLIP=y -# CONFIG_U8500_TSC_EXT_CLK_9_6 is not set CONFIG_TOUCHP_TUNING=y +CONFIG_TOUCHSCREEN_BU21013=y +#CONFIG_BU21013_TSC_CNTL1=y +# CONFIG_BU21013_TSC_CNTL2 is not set CONFIG_INPUT_MISC=y # CONFIG_INPUT_ATI_REMOTE is not set # CONFIG_INPUT_ATI_REMOTE2 is not set diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index 4fd04c72af1..c72b3699c9c 100755 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c @@ -18,6 +18,7 @@ #include <linux/i2c/lp5521.h> #include <linux/power_supply.h> #include <linux/lsm303dlh.h> +#include <linux/bu21013.h> #include <asm/mach/arch.h> #include <asm/mach/irq.h> @@ -37,7 +38,6 @@ #include <mach/mmc.h> #include <mach/setup.h> #include <mach/i2c.h> -#include <mach/u8500_tsc.h> #include <video/mcde_display.h> #include <video/mcde_display-generic_dsi.h> @@ -179,243 +179,250 @@ static struct i2c_board_info __initdata nmdk_i2c0_egpio1_devices[] = { /** * Touch panel related platform specific initialization */ -#if defined(CONFIG_U8500_TSC) /** - * tp_gpio_board_init : configures the touch panel. + * bu21013_gpio_board_init : configures the touch panel. + * @ext_clk_en: external clcok enable + * @reset_pin: reset pin number * This function can be used to configures * the voltage and reset the touch panel controller. */ -int tp_gpio_board_init(void) +static int bu21013_gpio_board_init(int reset_pin) { #ifndef CONFIG_REGULATOR int val; #endif int retval = 0; -#if (defined CONFIG_U8500_TSC_EXT_CLK_9_6 && !defined CONFIG_U8500_TSC_EXT_CLK_SHARE) void __iomem *clk_base; unsigned int clk_value; -#endif + + static bool config_set; #ifndef CONFIG_REGULATOR - /** Set the voltage for Bu21013 controller */ + /* Set the voltage for Bu21013 controller */ val = ab8500_read(AB8500_REGU_CTRL2, AB8500_REGU_VAUX12_REGU_REG); retval = ab8500_write(AB8500_REGU_CTRL2, AB8500_REGU_VAUX12_REGU_REG, - (val | 0x1)); + (val | TSC_AVDD_AUX1_REGULATOR)); if (retval < 0) - return -1; + return retval; val = ab8500_read(AB8500_REGU_CTRL2, AB8500_REGU_VAUX1_SEL_REG); retval = ab8500_write(AB8500_REGU_CTRL2, AB8500_REGU_VAUX1_SEL_REG, - 0x0C); + TSC_AVDD_VOLTAGE_2_5); if (retval < 0) - return -1; -#endif -#ifdef CONFIG_U8500_TSC_EXT_CLK_9_6 -#ifndef CONFIG_U8500_TSC_EXT_CLK_SHARE - retval = stm_gpio_altfuncenable(GPIO_ALT_TP_SET_EXT_CLK); - if (retval < 0) { - printk(KERN_ERR " ext clock stm_gpio_altfuncenable failed \n"); - return -1; - } - clk_base = (void __iomem *)IO_ADDRESS(U8500_PRCMU_BASE + 0x1CC); - clk_value = readl(clk_base); - writel(0x840000, clk_base); -#endif + return retval; #endif - if (platform_id == MOP500_PLATFORM_ID) { - retval = gpio_request(TOUCHP_CS0, "touchp_cs0"); - if (retval) { - printk(KERN_ERR "Unable to request gpio TOUCHP_CS0"); + if (!config_set) { + retval = stm_gpio_altfuncenable(GPIO_ALT_TP_SET_EXT_CLK); + if (retval < 0) { + printk(KERN_ERR "%s: gpio alternate failed\n", __func__); return retval; } - /** why set directtion is not working ~ FIXME */ - /* gpio_direction_output(270,1); */ - gpio_set_value(TOUCHP_CS0, 1); + clk_base = (void __iomem *)IO_ADDRESS(U8500_PRCMU_BASE + PRCMU_CLOCK_OCR); + clk_value = readl(clk_base); + writel(TSC_EXT_CLOCK_9_6MHZ, clk_base); + } + if (platform_id == MOP500_PLATFORM_ID) { + gpio_set_value(EGPIO_PIN_2, 1); } else if (platform_id == HREF_PLATFORM_ID) { - retval = gpio_request(EGPIO_PIN_13, "touchp_cs0"); - if (retval) { - printk(KERN_ERR "Unable to request gpio TOUCHP_CS0"); - return retval; - } - - retval = gpio_direction_output(EGPIO_PIN_13, 1); - if (retval < 0) { - printk(KERN_ERR " reset gpio_direction_output init failed \n"); - return -1; + if (!config_set) { + retval = gpio_direction_output(reset_pin, 1); + if (retval < 0) { + printk(KERN_ERR "%s: gpio direction failed\n", __func__); + return retval; + } + gpio_set_value(reset_pin, 1); + config_set = true; } - gpio_set_value(EGPIO_PIN_13, 1); } return retval; } /** - * tp_gpio_board_exit : deconfigures the touch panel controller + * bu21013_gpio_board_exit : deconfigures the touch panel controller + * @reset_pin: reset pin number * This function can be used to deconfigures the chip selection * for touch panel controller. */ -int tp_gpio_board_exit(void) +static int bu21013_gpio_board_exit(int reset_pin) { int retval = 0; + static bool config_disable_set; if (platform_id == MOP500_PLATFORM_ID) { - /** why set directtion is not working ~ FIXME */ - /* gpio_direction_output(270,1); */ - gpio_set_value(TOUCHP_CS0, 0); + gpio_set_value(EGPIO_PIN_2, 0); } else if (platform_id == HREF_PLATFORM_ID) { - retval = gpio_direction_output(EGPIO_PIN_13, 0); - if (retval < 0) { - printk(KERN_ERR " reset gpio_direction_output exit failed \n"); - return -1; + if (!config_disable_set) { + retval = gpio_direction_output(reset_pin, 0); + if (retval < 0) { + printk(KERN_ERR "%s: gpio direction failed\n", __func__); + return retval; + } + gpio_set_value(reset_pin, 0); + config_disable_set = true; } - gpio_set_value(EGPIO_PIN_13, 0); } return retval; } /** - * tp_init_irq : sets the callback for touch panel controller + * bu21013_init_irq : sets the callback for touch panel controller * @parameter: function pointer for touch screen callback handler. * @data: data to be passed for touch panel callback handler. * This function can be used to set the callback handler for * touch panel controller. */ -int tp_init_irq(void (*callback)(void *parameter), void *data) +static int bu21013_init_irq(void (*callback)(void *parameter), void *data) { int retval = 0; - if (platform_id == MOP500_PLATFORM_ID) { - retval = stmpe2401_set_callback(TOUCHP_IRQ, callback, + retval = stmpe2401_set_callback(EGPIO_PIN_3, callback, (void *)data); if (retval < 0) - printk(KERN_ERR " stmpe2401_set_callback failed \n"); + printk(KERN_ERR "%s: set callback failed\n", __func__); } else if (platform_id == HREF_PLATFORM_ID) { - if (href_v1_board == 0) { + if (!href_v1_board) { retval = tc35892_set_callback(EGPIO_PIN_12, callback, (void *)data); if (retval < 0) - printk(KERN_ERR " tc35892_set_callback failed \n"); + printk(KERN_ERR "%s: set callback failed\n", __func__); + retval = tc35892_set_gpio_intr_conf(EGPIO_PIN_12, + EDGE_SENSITIVE, TC35892_FALLING_EDGE_OR_LOWLEVEL); + if (retval < 0) + printk(KERN_ERR "%s: config failed\n", __func__); } } return retval; } /** - * tp_exit_irq : removes the callback for touch panel controller + * bu21013_exit_irq : removes the callback for touch panel controller * This function can be used to removes the callback handler for * touch panel controller. */ -int tp_exit_irq(void) +static int bu21013_exit_irq(void) { int retval = 0; if (platform_id == MOP500_PLATFORM_ID) { - retval = stmpe2401_remove_callback(TOUCHP_IRQ); + retval = stmpe2401_remove_callback(EGPIO_PIN_3); if (retval < 0) - printk(KERN_ERR " stmpe2401_remove_callback failed \n"); + printk(KERN_ERR "%s: remove callback failed\n", __func__); } else if (platform_id == HREF_PLATFORM_ID) { - if (href_v1_board == 0) { + if (!href_v1_board) { retval = tc35892_remove_callback(EGPIO_PIN_12); if (retval < 0) - printk(KERN_ERR " tc35892_remove_callback failed \n"); + printk(KERN_ERR "%s: remove calllback failed\n", __func__); } } return retval; } /** - * tp_pen_down_irq_enable : enable the interrupt for touch panel controller + * bu21013_pen_down_irq_enable : enable the interrupt for touch panel controller * This function can be used to enable the interrupt for touch panel controller. */ -int tp_pen_down_irq_enable(void) +static int bu21013_pen_down_irq_enable(void) { int retval = 0; - if (platform_id == MOP500_PLATFORM_ID) { - /* do nothing */ - } else if (platform_id == HREF_PLATFORM_ID) { - if (href_v1_board == 0) { - retval = tc35892_set_gpio_intr_conf(EGPIO_PIN_12, - EDGE_SENSITIVE, TC35892_FALLING_EDGE_OR_LOWLEVEL); - if (retval < 0) - printk(KERN_ERR " tc35892_set_gpio_intr_conf failed\n"); + if (platform_id == HREF_PLATFORM_ID) { + if (!href_v1_board) { retval = tc35892_set_intr_enable(EGPIO_PIN_12, ENABLE_INTERRUPT); if (retval < 0) - printk(KERN_ERR " tc35892_set_intr_enable failed \n"); + printk(KERN_ERR "%s: failed\n", __func__); } } return retval; } /** - * tp_pen_down_irq_disable : disable the interrupt + * bu21013_pen_down_irq_disable : disable the interrupt * This function can be used to disable the interrupt for * touch panel controller. */ -int tp_pen_down_irq_disable(void) +static int bu21013_pen_down_irq_disable(void) { int retval = 0; - if (platform_id == MOP500_PLATFORM_ID) { - /* do nothing */ - } else if (platform_id == HREF_PLATFORM_ID) { - if (href_v1_board == 0) { + if (platform_id == HREF_PLATFORM_ID) { + if (!href_v1_board) { retval = tc35892_set_intr_enable(EGPIO_PIN_12, DISABLE_INTERRUPT); if (retval < 0) - printk(KERN_ERR " tc35892_set_intr_enable failed \n"); + printk(KERN_ERR "%s: failed\n", __func__); } } return retval; } /** - * tp_read_pin_val : get the interrupt pin value + * bu21013_read_pin_val : get the interrupt pin value * This function can be used to get the interrupt pin value for touch panel * controller. */ -int tp_read_pin_val(void) +static int bu21013_read_pin_val(void) { int data = 0; - unsigned int touch_gpio_pin = 84; if (platform_id == MOP500_PLATFORM_ID) - data = gpio_get_value(TOUCHP_IRQ); + data = gpio_get_value(EGPIO_PIN_3); else if (platform_id == HREF_PLATFORM_ID) { - if (href_v1_board == 0) + if (!href_v1_board) data = gpio_get_value(EGPIO_PIN_12); else - data = gpio_get_value(touch_gpio_pin); + data = gpio_get_value(TOUCH_GPIO_PIN); } return data; } /** - * tp_board_href_v1 : update the href v1 flag + * bu21013_board_href_v1 : update the href v1 flag * This function can be used to update the board. */ -int tp_board_href_v1(void) +static bool bu21013_board_check(void) { - unsigned int touch_gpio_pin = 84; + href_v1_board = false; if (platform_id == HREF_PLATFORM_ID) { - if (u8500_is_earlydrop()) - href_v1_board = 0; - else - href_v1_board = gpio_get_value(touch_gpio_pin); - } else - href_v1_board = 0; + if (!u8500_is_earlydrop()) { + if (gpio_get_value(TOUCH_GPIO_PIN) == 1) + href_v1_board = true; + } + } return href_v1_board; } -static struct tp_device tsc_plat_device = { - .cs_en = tp_gpio_board_init, - .cs_dis = tp_gpio_board_exit, - .irq_init = tp_init_irq, - .irq_exit = tp_exit_irq, - .pirq_en = tp_pen_down_irq_enable, - .pirq_dis = tp_pen_down_irq_disable, - .pirq_read_val = tp_read_pin_val, - .board_href_v1 = tp_board_href_v1, - .irq = GPIO_TO_IRQ(84), -}; +static struct bu21013_platform_device tsc_plat_device = { + .cs_en = bu21013_gpio_board_init, + .cs_dis = bu21013_gpio_board_exit, + .irq_init = bu21013_init_irq, + .irq_exit = bu21013_exit_irq, + .pirq_en = bu21013_pen_down_irq_enable, + .pirq_dis = bu21013_pen_down_irq_disable, + .pirq_read_val = bu21013_read_pin_val, + .board_check = bu21013_board_check, + .irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .cs_pin = EGPIO_PIN_13, + .x_max_res = 480, + .y_max_res = 864, + .touch_x_max = TOUCH_XMAX, + .touch_y_max = TOUCH_YMAX, +#ifdef CONFIG_BU21013_TSC_CNTL1 + .tp_cntl = 1, #endif +}; +static struct bu21013_platform_device tsc_cntl2_plat_device = { + .cs_en = bu21013_gpio_board_init, + .cs_dis = bu21013_gpio_board_exit, + .board_check = bu21013_board_check, + .pirq_read_val = bu21013_read_pin_val, + .irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN), + .cs_pin = EGPIO_PIN_13, + .x_max_res = 480, + .y_max_res = 864, + .touch_x_max = TOUCH_XMAX, + .touch_y_max = TOUCH_YMAX, +#ifdef CONFIG_BU21013_TSC_CNTL2 + .tp_cntl = 2, +#endif +}; /* Portrait */ #ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY /* Rotation always on */ @@ -510,13 +517,16 @@ static struct i2c_board_info __initdata u8500_i2c3_devices[] = { /* NFC - Address TBD, FIXME */ I2C_BOARD_INFO("nfc", 0x68), }, -#if defined(CONFIG_U8500_TSC) { /* Touschscreen */ - I2C_BOARD_INFO(DRIVER_TP, I2C3_TOUCHP_ADDRESS), + I2C_BOARD_INFO("bu21013_tp", 0x5C), .platform_data = &tsc_plat_device, }, -#endif + { + /* Touschscreen */ + I2C_BOARD_INFO("bu21013_tp", 0x5D), + .platform_data = &tsc_cntl2_plat_device, + }, }; @@ -1467,8 +1477,8 @@ static struct platform_device *platform_board_devs[] __initdata = { &ab8500_gpadc_device, &ab8500_bm_device, &ux500_musb_device, - &ux500_b2r2_device, &ux500_mcde_device, + &ux500_b2r2_device, #ifdef CONFIG_ANDROID_PMEM &u8500_pmem_device, &u8500_pmem_mio_device, diff --git a/arch/arm/mach-ux500/include/mach/devices.h b/arch/arm/mach-ux500/include/mach/devices.h index c00a36cffed..73ddb146626 100755 --- a/arch/arm/mach-ux500/include/mach/devices.h +++ b/arch/arm/mach-ux500/include/mach/devices.h @@ -63,4 +63,19 @@ extern int platform_id; #define MOP500_PLATFORM_ID 0 #define HREF_PLATFORM_ID 1 +#define MOP500_PLATFORM_ID 0 +#define HREF_PLATFORM_ID 1 + +/** + * Touchpanel related macros declaration + */ +#define TOUCH_GPIO_PIN 84 + +#define TOUCH_XMAX 384 +#define TOUCH_YMAX 704 + +#define PRCMU_CLOCK_OCR 0x1CC +#define TSC_EXT_CLOCK_9_6MHZ 0x840000 +#define TSC_AVDD_VOLTAGE_2_5 0x08 +#define TSC_AVDD_AUX1_REGULATOR 0x01 #endif diff --git a/arch/arm/mach-ux500/include/mach/u8500_tsc.h b/arch/arm/mach-ux500/include/mach/u8500_tsc.h deleted file mode 100755 index c51ca4cc207..00000000000 --- a/arch/arm/mach-ux500/include/mach/u8500_tsc.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * Overview: - * Touch panel register definitions - * - * Copyright (C) 2009 ST-Ericsson SA - * - * 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. - */ - - - -#ifndef _TOUCHP_NOMADIK_H -#define _TOUCHP_NOMADIK_H - -#include <mach/hardware.h> - -/** - * Touchpanel related macros declaration - */ -#define I2C3_TOUCHP_ADDRESS 0x5C/* I2C slave address */ -#define TOUCHP_IRQ EGPIO_PIN_3 /* PENIRQNO egpio3 */ -#define TOUCHP_CS0 EGPIO_PIN_2 /* Chip select egpio2 */ - -#define DRIVER_TP "u8500_tp" -/* - *TOUCH SCREEN DRIVER MACROS used for Power on Sequence - */ -#define TSC_INT_CLR 0xE8 -#define TSC_INT_MODE 0xE9 -#define TSC_GAIN 0xEA -#define TSC_OFFSET_MODE 0xEB -#define TSC_XY_EDGE 0xEC -#define TSC_RESET 0xED -#define TSC_CALIB 0xEE -#define TSC_DONE 0xEF -#define TSC_SENSOR_0_7 0xF0 -#define TSC_SENSOR_8_15 0xF1 -#define TSC_SENSOR_16_23 0xF2 -#define TSC_POS_MODE1 0xF3 -#define TSC_POS_MODE2 0xF4 -#define TSC_CLK_MODE 0xF5 -#define TSC_IDLE 0xFA -#define TSC_FILTER 0xFB -#define TSC_TH_ON 0xFC -#define TSC_TH_OFF 0xFD -#define TSC_INTR_STATUS 0x7B -#define TSC_POS_X1 0x73 -#define TSC_POS_Y1 0x75 -#define TSC_POS_X2 0x77 -#define TSC_POS_Y2 0x79 - -#define MAX_10BIT ((1<<10)-1) - - -#define TSC_CLK_MODE_VAL1 0x82 -#define TSC_CLK_MODE_VAL2 0x81 -#define TSC_IDLE_VAL 0x11 -#define TSC_INT_MODE_VAL 0x00 -#define TSC_FILTER_VAL 0xFF -#define TSC_TH_ON_VAL 0x20 -#define TSC_TH_OFF_VAL 0x18 -#define TSC_GAIN_VAL 0x03 -#define TSC_OFFSET_MODE_VAL 0x00 -#define TSC_XY_EDGE_VAL 0xA5 -#define TSC_DONE_VAL 0x01 - - -/* - * Resolutions - */ -/*Panel Resolution, Target size. (864*480)*/ -#define X_MAX (480) -#define Y_MAX (864) - -/*Touchpanel Resolution */ -#define TOUCH_XMAX 384 -#define TOUCH_YMAX 704 - -#define TRUE (1) -#define FALSE (0) - -#define SET (1) -#define CLR (0) - -#define START (0) -#define STOP (-1) - -/*Direction Indicator */ -#define DIR_INVALID (0) -#define DIR_LEFT (1) -#define DIR_RIGHT (2) -#define DIR_UP (3) -#define DIR_DOWN (4) - -/* Pinch */ -#define PINCH_KEEP (0) -#define PINCH_IN (1) -#define PINCH_OUT (2) - -/* Rotate */ -#define ROTATE_INVALID (0) -#define ROTATE_R_UR (1) -#define ROTATE_R_RD (2) -#define ROTATE_R_DL (3) -#define ROTATE_R_LU (4) -#define ROTATE_L_LD (5) -#define ROTATE_L_DR (6) -#define ROTATE_L_RU (7) -#define ROTATE_L_UL (8) - -/* Gesture Information */ -#define GES_FLICK 0x01 -#define GES_TAP 0x02 -#define GES_PINCH 0x03 -#define GES_DRAGDROP 0x04 -#define GES_TOUCHSTART 0x05 -#define GES_TOUCHEND 0x06 -#define GES_MOVE 0x07 -#define GES_ROTATE 0x08 -#define GES_UNKNOWN 0xff - -/* Tap times */ -#define TAP_SINGLE 0x01 -#define TAP_DOUBLE 0x02 -#define TAP_TRIPLE 0x03 - -/* Speed */ -#define LOWSPEED 1 -#define HIGHSPEED 2 -#define THRESHOLD_TAPLIMIT 60 -#define THRESHOLD_FLICK 60 -#define THRESHOLD_FLICK_SPEED 300 -#define THRESHOLD_PINCH_SPEED 3000 -#define THRESHOLD_DRAGDROP 100 -#define THRESHOLD_ROTATE 3 -#define THRESHOLD_ROTATE_HIST 8 -#define THRESHOLD_PINCH 500 -#define DIRHEADER 6 -#define DIRTRACEN 32 -#define SMA_N 80 -#define SMA_ARRAY 81 -#define THRESHOLD_SMA_N SMA_N -#define MULTITOUCH_SIN_N 6 -#define PENUP_TIMEOUT (10) /* msec */ - -/** - * Error handling messages - **/ -typedef enum { - TSC_OK = 0, - TSC_BAD_PARAMETER = -2, - TSC_FEAT_NOT_SUPPORTED = -3, - TSC_INTERNAL_ERROR = -4, - TSC_TIMEOUT_ERROR = -5, - TSC_INITIALIZATION_ERROR = -6, - TSC_I2C_ERROR = -7, - TSC_ERROR = -8 -} tsc_error; - -/** - * struct tp_device - Handle the platform data - * @cs_en: pointer to the cs enable function - * @cs_dis: pointer to the cs disable function - * @irq_init: pointer to the irq init function - * @irq_exit: pointer to the irq exit function - * @pirq_en: pointer to the pen irq en function - * @pirq_dis: pointer to the pen irq disable function - * @pirq_read_val: pointer to read the pen irq value function - * @board_href_v1: pointer to the get the board version - * @irq: irq variable - * This is used to handle the platform data - **/ -struct tp_device { - int (*cs_en)(void); - int (*cs_dis)(void); - int (*irq_init)(void (*callback)(void *parameter), void *p); - int (*irq_exit)(void); - int (*pirq_en) (void); - int (*pirq_dis)(void); - int (*pirq_read_val)(void); - int (*board_href_v1)(void); - unsigned int irq; -}; - -/** - * struct touch_point - x and y co-ordinates of touch panel - * @x: x co-ordinate - * @y: y co-ordinate - * This is used to hold the x and y co-ordinates of touch panel - **/ -struct touch_point { - signed short x; - signed short y; -}; - -/** - * struct gesture_info - hold the gesture of the touch - * @gesture_kind: gesture kind variable - * @pt: arry to touch_point structure - * @dir: direction variable - * @times: touch times - * @speed: speed of the touch - * This is used to hold the gesture of the touch. - **/ -struct gesture_info { - signed short gesture_kind; - struct touch_point pt[2]; - signed short dir; - signed short times; - signed short speed; -}; - -/** - * struct u8500_tsc_data - touch panel data structure - * @client: pointer to the i2c client - * @chip: pointer to the touch panel controller - * @pin_dev: pointer to the input device structure - * @penirq_timer: variable to the timer list structure - * @touchp_event: variable to the wait_queue_head_t structure - * @touch_en: variable for reporting the co-ordinates to input device. - * @finger1_pressed: variable to indicate the first co-ordinates. - * @finger2_pressed: variable to indicate the first co-ordinates. - * @m_tp_timer_int_wq: variable to work structure for timer - * @m_tp_timer_gpio_wq: variable to work structure for interrupt - * @gesture_info: variable to gesture_info structure - * @touch_count: variable to maintain sensors input count - * @touchflag: variable to indicate the touch - * @pre_tap_flag: flag to indicate the pre tap - * @flick_flag: flickering flag - * @touch_continue: to continue the touch flag - * @pre_tap_flag_level: pre tap level flag - * @x1: x1 co-ordinate - * @y1: y1 co-ordinate - * @x2: x2 co-ordinate - * @y2: y2 co-ordinate - * @pinch_start: pinch start - * @tap_start_point: variable to touch_point structure - * @dir_trace: array for data trace - * @dir_idx: id for direction - * @rotate_data: array to maintain the rotate data - * @href_v1_flag: variable to indicate the href v1 board - * @finger2_count: count for finger2 touches - * - * Tocuh panel data structure - */ -struct u8500_tsc_data { - struct i2c_client *client; - struct tp_device *chip; - struct input_dev *pin_dev; - struct task_struct *touchp_tsk; - struct timer_list penirq_timer; - wait_queue_head_t touchp_event; - unsigned short touch_en; - unsigned short finger1_pressed; - unsigned short finger2_pressed; - struct work_struct m_tp_timer_int_wq; - struct work_struct m_tp_gpio_int_wq; - struct gesture_info gesture_info; - signed long touch_count; - unsigned short touchflag; - unsigned char pre_tap_flag; - unsigned char flick_flag; - unsigned char touch_continue; - unsigned char pre_tap_flag_level; - signed short x1, y1; - signed short x2, y2; - unsigned char pinch_start; - struct touch_point tap_start_point; - unsigned char dir_trace[DIRHEADER+DIRTRACEN]; - unsigned char dir_idx; - unsigned char rotate_data[5][5]; - bool href_v1_flag; - u8 finger2_count; -}; - -int doCalibrate(struct i2c_client *i2c); -int getCalibStatus(struct i2c_client *i2c); -void init_config(struct u8500_tsc_data *data); -void get_touch(struct u8500_tsc_data *data); -void touch_calculation(struct gesture_info *p_gesture_info); -int get_touch_message(struct u8500_tsc_data *data); -void check_board(struct u8500_tsc_data *data); -#endif diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index b0866806767..1899e800bb8 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -595,49 +595,18 @@ config TOUCHSCREEN_PCAP To compile this driver as a module, choose M here: the module will be called pcap_ts. -config U8500_TSC - tristate "BU21013 based capcitive based sensors for U8500 platform" - depends on ARCH_U8500 && I2C_NOMADIK - default m - help - Say Y here if you have a touchscreen interface using the - BU21013 controller for U8500 platform. - - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: - choice - prompt "TOUCH MODE" - depends on U8500_TSC - default U8500_TSC_SINGLETOUCH - - config U8500_TSC_SINGLETOUCH - depends on U8500_TSC - bool "Single Touch Mode" - - config U8500_TSC_MULTITOUCH - depends on U8500_TSC - bool "Multi Touch Mode" - endchoice - -config U8500_TSC_X_FLIP - bool "Enable x flip for U8500 touch panel in portrait mode" - depends on U8500_TSC && FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - -config U8500_TSC_Y_FLIP - bool "Enable y flip for U8500 touch panel in portrait mode" - depends on U8500_TSC && FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT +config TOUCHSCREEN_BU21013 + tristate "BU21013 based touch panel controllers" + depends on I2C_NOMADIK && FB_MCDE default y -config U8500_TSC_EXT_CLK_9_6 - bool "Enable external clock for U8500 touch panel tuning" - depends on U8500_TSC +config BU21013_TSC_CNTL1 + bool "Touch panel1 with BU21013 controller" + depends on TOUCHSCREEN_BU21013 + default y -config U8500_TSC_EXT_CLK_SHARE - bool "Clock shared between Camera and touch panel" - depends on U8500_TSC_EXT_CLK_9_6 +config BU21013_TSC_CNTL2 + bool "Touch panel2 with BU21013 controller2" + depends on TOUCHSCREEN_BU21013 -config TOUCHP_TUNING - bool "Enable sysfs for U8500 touch panel tuning" - depends on U8500_TSC endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 7ff5b85e858..7ad9a8405d2 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -46,4 +46,4 @@ obj-$(CONFIG_TOUCHSCREEN_WM97XX_ATMEL) += atmel-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE) += mainstone-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_WM97XX_ZYLONITE) += zylonite-wm97xx.o obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o -obj-$(CONFIG_U8500_TSC) += u8500_tsc.o +obj-$(CONFIG_TOUCHSCREEN_BU21013) += bu21013_ts.o diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c new file mode 100755 index 00000000000..1b7f8c165df --- /dev/null +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -0,0 +1,1357 @@ +/* + * Copyright (C) ST-Ericsson SA 2009 + * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson + * License terms:GNU General Public License (GPL) version 2 + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/i2c.h> +#include <linux/workqueue.h> +#include <linux/input.h> +#include <linux/types.h> +#include <linux/timer.h> +#include <linux/bu21013.h> + +/** + * Touchpanel related macros declaration + */ +#define PEN_DOWN_INTR 0 +#define PEN_UP_INTR 1 +#define RESET_DELAY 30 +#define POLLING_DELAY 100 +#define MAX_TOOL_WIDTH 15 +#define MAX_TOUCH_MAJOR 255 +#define MAX_PRESSURE 1 +#define PENUP_TIMEOUT (20)/* msec */ +#define SCALE_FACTOR 1000 +#define I2C_ADDR_TP2 0x5D + +#define START (0) +#define STOP (-1) + +/*Direction Indicator */ +#define DIR_INVALID (0) +#define DIR_LEFT (1) +#define DIR_RIGHT (2) +#define DIR_UP (3) +#define DIR_DOWN (4) + +/* Pinch */ +#define PINCH_KEEP (0) +#define PINCH_IN (1) +#define PINCH_OUT (2) + +/* Rotate */ +#define ROTATE_INVALID (0) +#define ROTATE_R_UR (1) +#define ROTATE_R_RD (2) +#define ROTATE_R_DL (3) +#define ROTATE_R_LU (4) +#define ROTATE_L_LD (5) +#define ROTATE_L_DR (6) +#define ROTATE_L_RU (7) +#define ROTATE_L_UL (8) + +/* Gesture Information */ +#define GES_FLICK 0x01 +#define GES_TAP 0x02 +#define GES_PINCH 0x03 +#define GES_DRAGDROP 0x04 +#define GES_TOUCHSTART 0x05 +#define GES_TOUCHEND 0x06 +#define GES_MOVE 0x07 +#define GES_ROTATE 0x08 +#define GES_UNKNOWN 0xff + +/* Speed */ +#define LOWSPEED 1 +#define HIGHSPEED 2 +#define THRESHOLD_TAPLIMIT 60 +#define THRESHOLD_FLICK 60 +#define THRESHOLD_FLICK_SPEED 300 +#define THRESHOLD_PINCH_SPEED 3000 +#define THRESHOLD_DRAGDROP 100 +#define THRESHOLD_ROTATE 3 +#define THRESHOLD_ROTATE_HIST 8 +#define THRESHOLD_PINCH 500 +#define DIRHEADER 6 +#define DIRTRACEN 32 +#define DIR_TRACE_VALUE 0x05 +#define DRIVER_TP "bu21013_tp" + +static struct i2c_driver bu21013_tp_driver; +struct bu21013_ts_data *tp_sys_data; + +static int bu21013_init_chip(struct bu21013_ts_data *data); + +static ssize_t touchp_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + u8 timeout; + u8 sys_th_on; + u8 sys_th_off; + u8 sys_gain; + u8 sys_ext_clock; + u8 sys_edge_mode; + + if (strcmp(attr->name, "timeout_value") == 0) { + timeout = tp_sys_data->penup_timer; + sprintf(buf, "%d\n", timeout); + } else if (strcmp(attr->name, "th_on") == 0) { + sys_th_on = tp_sys_data->th_on; + sprintf(buf, "%d\n", sys_th_on); + } else if (strcmp(attr->name, "th_off") == 0) { + sys_th_off = tp_sys_data->th_off; + sprintf(buf, "%d\n", sys_th_off); + } else if (strcmp(attr->name, "gain") == 0) { + sys_gain = tp_sys_data->gain; + sprintf(buf, "%d\n", sys_gain); + } else if (strcmp(attr->name, "ext_clk") == 0) { + sys_ext_clock = tp_sys_data->chip->ext_clk; + sprintf(buf, "%d\n", sys_ext_clock); + } else if (strcmp(attr->name, "edge_mode") == 0) { + sys_edge_mode = tp_sys_data->chip->edge_mode; + sprintf(buf, "%d\n", sys_edge_mode); + } + return strlen(buf); +} +static ssize_t touchp_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + int ret = 0; + int timeout; + int sys_th_on; + int sys_th_off; + int sys_gain; + int sys_ext_clock; + int sys_edge_mode; + + if (strcmp(attr->name, "timeout_value") == 0) { + ret = sscanf(buf, "%d", &timeout); + if (ret == 1) + tp_sys_data->penup_timer = timeout; + } else if (strcmp(attr->name, "th_on") == 0) { + ret = sscanf(buf, "%d", &sys_th_on); + if ((ret == 1) && (tp_sys_data->th_on != sys_th_on)) { + tp_sys_data->th_on = sys_th_on; + if (tp_sys_data->th_on < BU21013_TH_ON_MAX) + bu21013_init_chip(tp_sys_data); + } + } else if (strcmp(attr->name, "th_off") == 0) { + ret = sscanf(buf, "%d", &sys_th_off); + if ((ret == 1) && (tp_sys_data->th_off != sys_th_off)) { + tp_sys_data->th_off = sys_th_off; + if (tp_sys_data->th_off < BU21013_TH_OFF_MAX) + bu21013_init_chip(tp_sys_data); + } + } else if (strcmp(attr->name, "gain") == 0) { + ret = sscanf(buf, "%d", &sys_gain); + if ((ret == 1) && (tp_sys_data->gain != sys_gain)) { + tp_sys_data->gain = sys_gain; + bu21013_init_chip(tp_sys_data); + } + } else if (strcmp(attr->name, "ext_clk") == 0) { + ret = sscanf(buf, "%d", &sys_ext_clock); + if ((ret == 1) && (tp_sys_data->chip->ext_clk != sys_ext_clock)) { + tp_sys_data->chip->ext_clk = sys_ext_clock; + bu21013_init_chip(tp_sys_data); + } + } else if (strcmp(attr->name, "edge_mode") == 0) { + ret = sscanf(buf, "%d", &sys_edge_mode); + if ((ret == 1) && (tp_sys_data->chip->edge_mode != sys_edge_mode)) { + tp_sys_data->chip->edge_mode = sys_edge_mode; + bu21013_init_chip(tp_sys_data); + } + } + return ret == 1 ? len : -EINVAL; +} + +static struct attribute touchp_timeout = {.name = "timeout_value", + .mode = 0666}; +static struct attribute touchp_th_on = {.name = "th_on", .mode = 0666}; +static struct attribute touchp_th_off = {.name = "th_off", .mode = 0666}; +static struct attribute touchp_gain = {.name = "gain", .mode = 0666}; +static struct attribute touchp_ext_clk = {.name = "ext_clk", .mode = 0666}; +static struct attribute touchp_edge_mode = {.name = "edge_mode", .mode = 0666}; + +static struct attribute *touchp_attribute[] = { + &touchp_timeout, + &touchp_th_on, + &touchp_th_off, + &touchp_gain, + &touchp_ext_clk, + &touchp_edge_mode, + NULL +}; + +static struct sysfs_ops touchp_sysfs_ops = { + .show = touchp_attr_show, + .store = touchp_attr_store, +}; + +static struct kobj_type ktype_touchp = { + .sysfs_ops = &touchp_sysfs_ops, + .default_attrs = touchp_attribute, +}; + +/* + * bu21013_do_calibrate() - Do the software Calibration + * @i2c: i2c_client structure pointer + * Do the soft calibration on the touch screen + * and returns integer + */ +int bu21013_do_calibrate(struct i2c_client *i2c) +{ + int retval; + retval = i2c_smbus_write_byte_data(i2c, BU21013_CALIB, + BU21013_CALIB_ENABLE); + if (retval < 0) + dev_err(&i2c->dev, "reset failed retval=0x%x \n", retval); + return retval; +} +/** + * bu21013_touch_calc(): Get the exact co-ordinates of the touch interrupt + * @data:bu21013_ts_data structure pointer + * Transfer the position information from touch sensor + * coordinate to display coordinate and returns none. + */ +void bu21013_touch_calc(struct bu21013_ts_data *data) +{ + signed short x1, y1; + struct bu21013_gesture_info *p_gesture_info = &data->gesture_info; + int tmpx, tmpy; + signed short x2, y2; + + tmpx = (data->chip->x_max_res * SCALE_FACTOR / data->chip->touch_x_max); + tmpy = (data->chip->y_max_res * SCALE_FACTOR / data->chip->touch_y_max); + x1 = p_gesture_info->pt[0].x; + y1 = p_gesture_info->pt[0].y; + x1 = x1 * tmpx / SCALE_FACTOR; + y1 = y1 * tmpy / SCALE_FACTOR; + if ((data->chip->portrait) && (y1 != 0)) + y1 = data->chip->y_max_res - y1; + p_gesture_info->pt[0].x = x1; + p_gesture_info->pt[0].y = y1; + x2 = p_gesture_info->pt[1].x; + y2 = p_gesture_info->pt[1].y; + x2 = x2 * tmpx / SCALE_FACTOR; + y2 = y2 * tmpy / SCALE_FACTOR; + if ((data->chip->portrait) && (y2 != 0)) + y2 = data->chip->y_max_res - y2; + p_gesture_info->pt[1].x = x2; + p_gesture_info->pt[1].y = y2; + +} + +/** + * bu21013_get_touch(): Get the co-ordinates of the touch interrupt + * @data:bu21013_ts_data structure pointer + * Get touched point position + * from touch sensor registers and write to global variables. + */ +void bu21013_get_touch(struct bu21013_ts_data *data) +{ + struct i2c_client *i2c = data->client; + int retval; + u8 sensors_buf[3]; + u8 finger1_buf[4]; + int count; + signed short tmp1x = 0; + signed short tmp1y = 0; + u8 finger2_buf[4]; + signed short tmp2x = 0; + signed short tmp2y = 0; + short touch_x_max = data->chip->touch_x_max; + short touch_y_max = data->chip->touch_y_max; + + for (count = 0; count < 2; count++) { + if (!data->chip->edge_mode) { + retval = i2c_smbus_read_i2c_block_data(i2c, BU21013_SENSORS_BTN_0_7, 3, sensors_buf); + if (retval < 0) + goto end; + data->last_press = sensors_buf[0] | sensors_buf[1] | sensors_buf[2]; + } + retval = i2c_smbus_read_i2c_block_data(i2c, BU21013_X1_POS_MSB, 4, finger1_buf); + if (retval < 0) + goto end; + tmp1x = (finger1_buf[0] << 2) | finger1_buf[1]; + tmp1y = (finger1_buf[2] << 2) | finger1_buf[3]; + if ((tmp1x != 0) && (tmp1y != 0)) + break; + } + data->finger1_pressed = false; + if ((data->chip->edge_mode || data->last_press) & + (tmp1x != 0 && tmp1y != 0) && + (tmp1x < touch_x_max && tmp1y < touch_y_max)) + data->finger1_pressed = true; + + if (data->finger1_pressed) { + data->x1 = tmp1x; + data->y1 = tmp1y; + } else { + data->x1 = 0; + data->y1 = 0; + } + for (count = 0; count < 2; count++) { + retval = i2c_smbus_read_i2c_block_data(i2c, BU21013_X2_POS_MSB, 4, finger2_buf); + if (retval < 0) + goto end; + tmp2x = (finger2_buf[0] << 2) | finger2_buf[1]; + tmp2y = (finger2_buf[2] << 2) | finger2_buf[3]; + if ((tmp2x != 0) && (tmp2y != 0)) + break; + } + data->finger2_pressed = false; + if ((data->chip->edge_mode || data->last_press) && + (tmp2x != 0 && tmp2y != 0) && + (tmp2x < touch_x_max && tmp2y < touch_y_max)) + data->finger2_pressed = true; + data->finger2_count = 1; +end: + if (data->finger2_pressed) { + data->x2 = tmp2x; + data->y2 = tmp2y; + } else { + data->x2 = 0; + data->y2 = 0; + } + if (data->finger1_pressed || data->finger2_pressed) { + data->touch_en = true; + data->touchflag = true; + } else { + data->touch_en = false; + data->touchflag = false; + } + if ((!data->finger1_pressed) && (data->finger2_pressed)) { + data->x1 = tmp2x; + data->y1 = tmp2y; + data->x2 = 0; + data->y2 = 0; + data->finger2_pressed = false; + } +} +/** + * bu21013_update_ges_no_touch(): Generate the gesture message for single touch + * @data: a pointer to the device structure + * Generate the gesture message for single touch. + */ +void bu21013_update_ges_st_touch(struct bu21013_ts_data *data) +{ + struct bu21013_gesture_info *p_gesture_info = &data->gesture_info; + signed short x_delta, y_delta; + unsigned char dir_left_right, dir_up_down; + unsigned char tmp; + unsigned char dir1, dir2; + static struct bu21013_touch_point pre_gesture_point; + x_delta = p_gesture_info->pt[0].x - pre_gesture_point.x; + y_delta = p_gesture_info->pt[0].y - pre_gesture_point.y; + if ((x_delta < THRESHOLD_ROTATE) || + (-x_delta < THRESHOLD_ROTATE)) + x_delta = 0; + + if ((y_delta < THRESHOLD_ROTATE) || + (-y_delta < THRESHOLD_ROTATE)) + y_delta = 0; + + p_gesture_info->dir = DIR_INVALID; + if (x_delta != y_delta) { + dir_left_right = DIR_RIGHT; + if (x_delta < 0) { + dir_left_right = DIR_LEFT; + x_delta = -x_delta; + } + dir_up_down = DIR_DOWN; + if (y_delta < 0) { + y_delta = -y_delta; + dir_up_down = DIR_UP; + } + p_gesture_info->dir = dir_up_down; + if (x_delta > y_delta) + p_gesture_info->dir = dir_left_right; + tmp = p_gesture_info->dir; + data->dir_trace[tmp]++; + data->dir_trace[data->dir_idx] = tmp; + if (data->dir_idx < (THRESHOLD_ROTATE_HIST + DIRHEADER)) + data->dir_idx++; + else + data->dir_idx = DIRHEADER; + data->dir_trace[data->dir_trace[data->dir_idx]]--; + dir1 = data->dir_trace[0]; + for (dir2 = 1; dir2 < 5; dir2++) { + if (data->dir_trace[data->dir_trace[0]] + < data->dir_trace[dir2]) { + data->dir_trace[0] = dir2; + p_gesture_info->dir + = data->rotate_data[dir1][dir2]; + if (p_gesture_info->dir) + p_gesture_info->gesture_kind + = GES_ROTATE; + break; + } + } + } + if (p_gesture_info->dir == ROTATE_INVALID) { + p_gesture_info->gesture_kind = GES_MOVE; + p_gesture_info->speed = data->touch_count; + } +} +/** + * bu21013_update_ges_no_touch(): Generate the gesture message for multi touch + * @data: a pointer to the device structure + * Generate the gesture message for multi touch. + */ +void bu21013_update_ges_mt_touch(struct bu21013_ts_data *data) +{ + struct bu21013_gesture_info *p_gesture_info = &data->gesture_info; + signed short x_delta, y_delta; + signed short area_diff; + unsigned long area; + static unsigned long pre_area; + + x_delta = p_gesture_info->pt[0].x - p_gesture_info->pt[1].x; + y_delta = p_gesture_info->pt[0].y - p_gesture_info->pt[1].y; + if (x_delta < 0) + x_delta = -x_delta; + if (y_delta < 0) + y_delta = -y_delta; + x_delta++; + y_delta++; + area = x_delta * y_delta; + p_gesture_info->dir = PINCH_KEEP; + area_diff = area - pre_area; + if (area_diff > 0) { + if (area_diff > THRESHOLD_PINCH) { + p_gesture_info->dir = PINCH_OUT; + if (area_diff < THRESHOLD_PINCH_SPEED) + p_gesture_info->speed = LOWSPEED; + else + p_gesture_info->speed = HIGHSPEED; + } + } else if (area_diff < 0) { + if ((pre_area - area) > THRESHOLD_PINCH) { + p_gesture_info->dir = PINCH_IN; + if ((pre_area - area) < THRESHOLD_PINCH_SPEED) + p_gesture_info->speed = LOWSPEED; + else + p_gesture_info->speed = HIGHSPEED; + } + } + if (data->pinch_start == false) { + p_gesture_info->dir = PINCH_KEEP; + pre_area = 0; + data->pinch_start = true; + } + p_gesture_info->gesture_kind = GES_PINCH; + pre_area = area; +} +/** + * bu21013_update_ges_no_touch(): Generate the gesture message for no touch + * @data: a pointer to the device structure + * Generate the gesture message for no touch. + */ +void bu21013_update_ges_no_touch(struct bu21013_ts_data *data) +{ + struct bu21013_gesture_info *p_gesture_info = &data->gesture_info; + signed short x_delta, y_delta; + bool flick_series_flag; + signed short i; + unsigned char dir_left_right, dir_up_down; + static struct bu21013_touch_point pre_gesture_point; + + flick_series_flag = false; + if (data->flick_flag) { + x_delta = p_gesture_info->pt[0].x - data->tap_start_point.x; + y_delta = p_gesture_info->pt[0].y - data->tap_start_point.y; + dir_left_right = DIR_RIGHT; + dir_up_down = DIR_DOWN; + if (x_delta < 0) { + dir_left_right = DIR_LEFT; + x_delta = -x_delta; + } + if (y_delta < 0) { + y_delta = -y_delta; + dir_up_down = DIR_UP; + } + if ((THRESHOLD_FLICK <= x_delta) || (THRESHOLD_FLICK <= y_delta)) { + if (THRESHOLD_DRAGDROP <= data->touch_count) { + p_gesture_info->gesture_kind = GES_DRAGDROP; + p_gesture_info->speed = data->touch_count; + p_gesture_info->pt[0].x = data->tap_start_point.x; + p_gesture_info->pt[0].y = data->tap_start_point.y; + p_gesture_info->pt[1].x = pre_gesture_point.x; + p_gesture_info->pt[1].y = pre_gesture_point.y; + } else { + p_gesture_info->speed = LOWSPEED; + p_gesture_info->gesture_kind = GES_FLICK; + p_gesture_info->dir = dir_up_down; + if ((THRESHOLD_FLICK_SPEED < x_delta) || + (THRESHOLD_FLICK_SPEED < y_delta)) + p_gesture_info->speed = HIGHSPEED; + if (x_delta > y_delta) + p_gesture_info->dir = dir_left_right; + } + data->pre_tap_flag_level = 0; + data->flick_flag = false; + data->touch_count = STOP; + flick_series_flag = true; + } + } + if (flick_series_flag == false) { + if (THRESHOLD_TAPLIMIT <= data->touch_count) { + p_gesture_info->gesture_kind = GES_TAP; + p_gesture_info->times = data->pre_tap_flag_level; + p_gesture_info->speed = data->touch_count; + data->pre_tap_flag_level = 0; + data->flick_flag = false; + data->touch_count = STOP; + data->dir_idx = DIRHEADER; + for (i = 0; i < DIRHEADER; i++) + data->dir_trace[i] = 0x0; + for (i = DIRHEADER; i < DIRTRACEN; i++) + data->dir_trace[i] = DIR_TRACE_VALUE; + } + } +} +/** + * bu21013_get_touch_mesg(): Generate the gesture message + * @data: a pointer to the device structure + * Generate the gesture message according to the + * information collected and returns integer. + */ +int bu21013_get_touch_mesg(struct bu21013_ts_data *data) +{ + struct bu21013_gesture_info *p_gesture_info = &data->gesture_info; + static struct bu21013_touch_point pre_gesture_point; + p_gesture_info->gesture_kind = GES_UNKNOWN; + + bu21013_get_touch(data); + if (!data->touchflag) { + if (data->touch_continue) { + data->touch_continue = false; + p_gesture_info->gesture_kind = GES_TOUCHEND; + if (data->pre_tap_flag_level <= 2) + data->pre_tap_flag_level++; + data->pre_tap_flag = false; + } else { + if (!data->pinch_start) { + bu21013_update_ges_no_touch(data); + } else { + data->pinch_start = false; + data->pre_tap_flag_level = 0; + data->flick_flag = false; + data->touch_count = STOP; + } + } + } else { + p_gesture_info->pt[0].x = data->x1; + p_gesture_info->pt[0].y = data->y1; + p_gesture_info->pt[1].x = data->x2; + p_gesture_info->pt[1].y = data->y2; + bu21013_touch_calc(data); + + if (data->touch_continue) { + if ((data->x2 != 0) && (data->y2 != 0)) + bu21013_update_ges_mt_touch(data); + else + bu21013_update_ges_st_touch(data); + data->flick_flag = true; + } else { + p_gesture_info->gesture_kind = GES_TOUCHSTART; + data->tap_start_point.x = p_gesture_info->pt[0].x; + data->tap_start_point.y = p_gesture_info->pt[0].y; + data->touch_count = START; + } + data->touch_continue = true; + pre_gesture_point.x = p_gesture_info->pt[0].x; + pre_gesture_point.y = p_gesture_info->pt[0].y; + } + return 0; +} + +/** + * bu21013_timer_start() - restart the timer + * @data:bu21013_ts_data structure pointer + * + * This funtion used to run the timer and returns none. + */ +static inline void bu21013_timer_start(struct bu21013_ts_data *data) +{ + mod_timer(&data->penirq_timer, jiffies + msecs_to_jiffies(data->penup_timer)); +} + +/** + * tsc_clear_irq() - clear the tsc interrupt + * @i2c:i2c_client structure pointer + * + * This funtion used to clear the + * bu21013 controller interrupt for next Pen interrupts and returns none. + */ +static void tsc_clear_irq(struct i2c_client *i2c) +{ + int retval; + retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_CLR, + BU21013_INTR_CLEAR); + if (retval < 0) + dev_err(&i2c->dev, "int cleared failed \n"); +} + +/** + * tsc_en_irq() - Reactivate the tsc interrupt + * @i2c:i2c_client structure pointer + * + * This funtion used to activate the bu21013 controller + * interrupt for next Pen interrupts. + */ +static void tsc_en_irq(struct i2c_client *i2c) +{ + int retval; + retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_CLR, + BU21013_INTR_ENABLE); + if (retval < 0) + dev_err(&i2c->dev, "interrupt enable failed\n"); +} +/** + * tsc_input_report_pen_down() - report the touch point + * @data:bu21013_ts_data structure pointer + * This funtion calls, when we need to report the Pen down interrupt + */ +static void tsc_input_report_pen_down(struct bu21013_ts_data *data) +{ + short pt0x; + short pt0y; + short pt1x; + short pt1y; + if (data->chip->portrait) { + pt0x = data->gesture_info.pt[0].x; + pt0y = data->gesture_info.pt[0].y; + pt1x = data->gesture_info.pt[1].x; + pt1y = data->gesture_info.pt[1].y; + } else { + pt0x = data->gesture_info.pt[0].y; + pt0y = data->gesture_info.pt[0].x; + pt1x = data->gesture_info.pt[1].y; + pt1y = data->gesture_info.pt[1].x; + } + + input_report_abs(data->pin_dev, ABS_X, pt0x); + input_report_abs(data->pin_dev, ABS_Y, pt0y); + + input_report_abs(data->pin_dev, ABS_PRESSURE, 1); + input_report_abs(data->pin_dev, ABS_TOOL_WIDTH, 1); + input_report_key(data->pin_dev, BTN_TOUCH, 1); + + if (data->finger2_pressed) { + input_report_key(data->pin_dev, BTN_2, 1); + input_report_abs(data->pin_dev, ABS_HAT0X, pt1x); + input_report_abs(data->pin_dev, ABS_HAT0Y, pt1y); + } + input_report_abs(data->pin_dev, ABS_MT_TOUCH_MAJOR, 1); + input_report_key(data->pin_dev, ABS_MT_WIDTH_MAJOR, 1); + input_report_abs(data->pin_dev, ABS_MT_POSITION_X, pt0x); + input_report_abs(data->pin_dev, ABS_MT_POSITION_Y, pt0y); + input_mt_sync(data->pin_dev); + if (data->finger2_pressed) { + input_report_abs(data->pin_dev, ABS_MT_TOUCH_MAJOR, 1); + input_report_key(data->pin_dev, ABS_MT_WIDTH_MAJOR, 1); + input_report_abs(data->pin_dev, ABS_MT_POSITION_X, pt1x); + input_report_abs(data->pin_dev, ABS_MT_POSITION_Y, pt1y); + input_mt_sync(data->pin_dev); + } + input_sync(data->pin_dev); +} +/** + * tsc_input_report_pen_up() - report the touch point + * @data:bu21013_ts_data structure pointer + * This funtion calls, when we need to report the Pen up interrupt + */ +static void tsc_input_report_pen_up(struct bu21013_ts_data *data) +{ + input_report_abs(data->pin_dev, ABS_PRESSURE, 0); + input_report_abs(data->pin_dev, ABS_TOOL_WIDTH, 0); + input_report_key(data->pin_dev, BTN_TOUCH, 0); + if (data->finger2_count) { + input_report_key(data->pin_dev, BTN_2, 0); + input_report_abs(data->pin_dev, ABS_MT_TOUCH_MAJOR, 0); + input_report_key(data->pin_dev, ABS_MT_WIDTH_MAJOR, 0); + input_mt_sync(data->pin_dev); + data->finger2_count = 0; + } + input_sync(data->pin_dev); +} +/** + * tsc_input_report() - report the touch point + * @data:bu21013_ts_data structure pointer + * @value:value to be passed for en down or pen up + * This funtion calls, when we need to report the Pen down/up interrupt + */ +static void tsc_input_report(struct bu21013_ts_data *data, bool value) +{ + if (value) + tsc_input_report_pen_down(data); + else + tsc_input_report_pen_up(data); +} + +/** + * tsc_callback() - callback handler for Pen down + * @device_data:void pointer + * + * This funtion calls, when we get the Pen down interrupt from Egpio Pin + * and assigns the task and returns none. + */ + +static void tsc_callback(void *device_data) +{ + struct bu21013_ts_data *data = (struct bu21013_ts_data *)device_data; + schedule_work(&data->tp_gpio_handler); +} + +/** + * tsc_gpio_callback() - callback handler for Pen down + * @device_data:void pointer + * @irq: irq value + * + * This funtion calls for HREF v1, when we get the Pen down interrupt from GPIO Pin + * and assigns the task and returns irqreturn_t. + */ + +static irqreturn_t tsc_gpio_callback(int irq, void *device_data) +{ + struct bu21013_ts_data *data = (struct bu21013_ts_data *)device_data; + schedule_work(&data->tp_gpio_handler); + return IRQ_HANDLED; +} + +/** + * tsc_timer_callback() - callback handler for Timer + * @dev_data:touch screen data + * + * This callback handler used to schedule the work for Pen up + * and Pen down interrupts and returns none + */ +static void tsc_timer_callback(unsigned long dev_data) +{ + struct bu21013_ts_data *data = (struct bu21013_ts_data *)dev_data; + schedule_work(&data->tp_timer_handler); +} +/** + * tsc_level_mode_report() - report the touch point in level mode + * @data:bu21013_ts_data structure pointer + * This funtion used to report the Pen down/up interrupt for level mode. + */ +static void tsc_level_mode_report(struct bu21013_ts_data *data) +{ + if (data->touch_en) { + data->prev_press_report = true; + tsc_input_report(data, true); + } else { + if (data->prev_press_report) { + data->prev_press_report = false; + tsc_input_report(data, false); + } + } +} +/** + * tp_timer_wq() - Work Queue for timer handler + * @work:work_struct structure pointer + * + * This work queue used to get the co-ordinates + * of the Pen up and Pen down interrupts and returns none + */ +static void tp_timer_wq(struct work_struct *work) +{ + struct bu21013_ts_data *data = container_of(work, struct bu21013_ts_data, tp_timer_handler); + struct task_struct *tsk = current; + + set_task_state(tsk, TASK_INTERRUPTIBLE); + data->intr_pin = data->chip->pirq_read_val(); + bu21013_get_touch_mesg(data); + + if (data->chip->edge_mode) + tsc_input_report(data, data->touch_en); + else + tsc_level_mode_report(data); + + if (data->intr_pin == PEN_DOWN_INTR) { + bu21013_timer_start(data); + } else { + if (!data->chip->edge_mode) { + tsc_clear_irq(data->client); + tsc_en_irq(data->client); + } + enable_irq(data->chip->irq); + } +} + +/** + * tp_gpio_int_wq() - Work Queue for GPIO_INT handler + * @work:work_struct structure pointer + * + * This work queue used to get the co-ordinates + * of the Pen up and Pen down interrupts and returns none + */ +static void tp_gpio_int_wq(struct work_struct *work) +{ + struct bu21013_ts_data *tp_data = container_of(work, struct bu21013_ts_data, tp_gpio_handler); + struct task_struct *tsk = current; + + set_task_state(tsk, TASK_INTERRUPTIBLE); + tp_data->intr_pin = tp_data->chip->pirq_read_val(); + if (tp_data->intr_pin == PEN_DOWN_INTR) { + disable_irq(tp_data->chip->irq); + bu21013_get_touch_mesg(tp_data); + if (tp_data->chip->edge_mode) + tsc_input_report(tp_data, tp_data->touch_en); + else + tsc_level_mode_report(tp_data); + if (!tp_data->chip->edge_mode) { + tsc_clear_irq(tp_data->client); + tsc_en_irq(tp_data->client); + } + bu21013_timer_start(tp_data); + } else { + if (tp_data->chip->edge_mode) { + tsc_input_report(tp_data, false); + } else if (tp_data->prev_press_report) { + tp_data->prev_press_report = false; + tsc_input_report(tp_data, false); + } + } +} + +/* + * bu21013_init_config(): Initialize the Global variables + * @data: device structure pointer + * This function used to initialize the device variables and returns none + */ +void bu21013_init_config(struct bu21013_ts_data *data) +{ + signed int i; + + data->touch_count = STOP; + /* turning right */ + data->rotate_data[DIR_UP][DIR_RIGHT] = ROTATE_R_UR; + data->rotate_data[DIR_RIGHT][DIR_DOWN] = ROTATE_R_RD; + data->rotate_data[DIR_DOWN][DIR_LEFT] = ROTATE_R_DL; + data->rotate_data[DIR_LEFT][DIR_UP] = ROTATE_R_LU; + + /* turning left */ + data->rotate_data[DIR_LEFT][DIR_DOWN] = ROTATE_L_LD; + data->rotate_data[DIR_RIGHT][DIR_UP] = ROTATE_L_DR; + data->rotate_data[DIR_DOWN][DIR_RIGHT] = ROTATE_L_RU; + data->rotate_data[DIR_UP][DIR_LEFT] = ROTATE_L_UL; + + data->dir_idx = DIRHEADER; + + for (i = DIRHEADER; i < DIRTRACEN; i++) + data->dir_trace[i] = DIR_TRACE_VALUE; + + return; +} +/** + * bu21013_init_chip() - Power on sequence for the bu21013 controller + * @data: device structure pointer + * + * This funtion is used to power on + * the bu21013 controller and returns integer. + **/ +static int bu21013_init_chip(struct bu21013_ts_data *data) +{ + int retval; + struct i2c_client *i2c = data->client; + + dev_dbg(&i2c->dev, "bu21013_init_chip start\n"); + + retval = i2c_smbus_write_byte_data(i2c, BU21013_RESET, + BU21013_RESET_ENABLE); + if (retval < 0) { + dev_err(&i2c->dev, "ED reg write failed\n"); + goto err; + } + mdelay(RESET_DELAY); + + retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7, + BU21013_SENSORS_EN_0_7); + if (retval < 0) { + dev_err(&i2c->dev, "F0 reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15, + BU21013_SENSORS_EN_8_15); + if (retval < 0) { + dev_err(&i2c->dev, "F1 reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23, + BU21013_SENSORS_EN_16_23); + if (retval < 0) { + dev_err(&i2c->dev, "F2 reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1, + (BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1)); + if (retval < 0) { + dev_err(&i2c->dev, "F3 reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2, + (BU21013_POS_MODE2_ZERO | BU21013_POS_MODE2_AVG1 | BU21013_POS_MODE2_AVG2 | + BU21013_POS_MODE2_EN_RAW | BU21013_POS_MODE2_MULTI)); + if (retval < 0) { + dev_err(&i2c->dev, "F4 reg write failed\n"); + goto err; + } + if (data->chip->ext_clk) { + retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE, + (BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB)); + if (retval < 0) { + dev_err(&i2c->dev, "F5 reg write failed\n"); + goto err; + } + } else { + retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE, + (BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB)); + if (retval < 0) { + dev_err(&i2c->dev, "F5 reg write failed\n"); + goto err; + } + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE, + (BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN)); + if (retval < 0) { + dev_err(&i2c->dev, "FA reg write failed\n"); + goto err; + } + if (data->chip->edge_mode) { + retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE, + BU21013_INT_MODE_EDGE); + if (retval < 0) { + dev_err(&i2c->dev, "E9 reg write failed\n"); + goto err; + } + } else { + retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE, + BU21013_INT_MODE_LEVEL); + if (retval < 0) { + dev_err(&i2c->dev, "E9 reg write failed\n"); + goto err; + } + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER, + (BU21013_DELTA_0_6 | BU21013_FILTER_EN)); + if (retval < 0) { + dev_err(&i2c->dev, "FB reg write failed\n"); + goto err; + } + + retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON, data->th_on); + if (retval < 0) { + dev_err(&i2c->dev, "FC reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF, data->th_off); + if (retval < 0) { + dev_err(&i2c->dev, "FD reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN, data->gain); + if (retval < 0) { + dev_err(&i2c->dev, "EA reg write failed\n"); + goto err; + } + + retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE, + BU21013_OFFSET_MODE_DEFAULT); + if (retval < 0) { + dev_err(&i2c->dev, "EB reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE, + (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 | + BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3)); + if (retval < 0) { + dev_err(&i2c->dev, "EC reg write failed\n"); + goto err; + } + retval = i2c_smbus_write_byte_data(i2c, BU21013_REG_DONE, BU21013_DONE); + if (retval < 0) { + dev_err(&i2c->dev, "EF reg write failed\n"); + goto err; + } +err: + return retval; +} +/* + * tsc_driver_register() - Used for input driver registeration + * @pdata: pointer to bu21013_tsc_data structure + * This function used to register the + * touch screen as input device and returns integer + */ +static int tsc_driver_register(struct bu21013_ts_data *pdata) +{ + int ret; + short x_max; + short y_max; + + struct input_dev *in_dev; + struct i2c_client *i2c = pdata->client; + dev_dbg(&i2c->dev, "input register start\n"); + + /* register the touch screen driver to input device */ + if (pdata->chip->portrait) { + x_max = pdata->chip->x_max_res; + y_max = pdata->chip->y_max_res; + } else { + x_max = pdata->chip->y_max_res; + y_max = pdata->chip->x_max_res; + } + in_dev = input_allocate_device(); + pdata->pin_dev = in_dev; + if (!in_dev) { + ret = -ENOMEM; + goto err; + } + + in_dev->name = DRIVER_TP; + set_bit(EV_SYN, in_dev->evbit); + set_bit(EV_KEY, in_dev->evbit); + set_bit(EV_ABS, in_dev->evbit); + set_bit(BTN_TOUCH, in_dev->keybit); + input_set_abs_params(in_dev, ABS_X, 0, x_max, 0, 0); + input_set_abs_params(in_dev, ABS_Y, 0, y_max, 0, 0); + input_set_abs_params(in_dev, ABS_PRESSURE, 0, MAX_PRESSURE, 0, 0); + input_set_abs_params(in_dev, ABS_TOOL_WIDTH, 0, MAX_TOOL_WIDTH, 0, 0); + set_bit(BTN_2, in_dev->keybit); + input_set_abs_params(in_dev, ABS_HAT0X, 0, x_max, 0, 0); + input_set_abs_params(in_dev, ABS_HAT0Y, 0, y_max, 0, 0); + input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, x_max, 0, 0); + input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, y_max, 0, 0); + input_set_abs_params(in_dev, ABS_MT_TOUCH_MAJOR, 0, MAX_TOUCH_MAJOR, 0, 0); + input_set_abs_params(in_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_TOOL_WIDTH, 0, 0); + ret = input_register_device(in_dev); + if (ret) { + dev_err(&i2c->dev, " input register error \n"); + goto err; + } + dev_dbg(&i2c->dev, "input register done \n"); +err: + return ret; +} +/** + * tsc_config() - configure the touch screen controller + * @pdev_data: pointer to bu21013_ts_data structure + * + * This funtion is used to configure + * the bu21013 controller and returns tsc error. + **/ +static int tsc_config(struct bu21013_ts_data *pdev_data) +{ + int retval; + + retval = bu21013_init_chip(pdev_data); + if (retval < 0) + goto err; + + bu21013_init_config(pdev_data); + if ((!pdev_data->board_flag) && + ((pdev_data->chip->pirq_en) && (pdev_data->chip->pirq_dis) && + (pdev_data->chip->irq_init))) { + retval = pdev_data->chip->pirq_dis(); + if (retval < 0) { + dev_err(&pdev_data->client->dev, "irq dis failed \n"); + goto err; + } + retval = pdev_data->chip->pirq_en(); + if (retval < 0) { + dev_err(&pdev_data->client->dev, "irq en failed \n"); + goto err_init_irq; + } + if (pdev_data->chip->irq_init(tsc_callback, pdev_data)) { + dev_err(&pdev_data->client->dev, "irq init failed \n"); + goto err_init_irq; + } + } + retval = bu21013_do_calibrate(pdev_data->client); + if (retval < 0) { + dev_err(&pdev_data->client->dev, "calibration not done \n"); + goto err_init_irq; + } + return retval; +err_init_irq: + pdev_data->chip->pirq_dis(); + pdev_data->chip->irq_exit(); +err: + pdev_data->chip->cs_dis(pdev_data->chip->cs_pin); + return retval; +} +#ifdef CONFIG_PM +/** + * bu21013_tp_suspend() - suspend the touch screen controller + * @client: pointer to i2c client structure + * @mesg: message from power manager + * + * This funtion is used to suspend the + * touch panel controller and returns integer + **/ +static int bu21013_tp_suspend(struct i2c_client *client, pm_message_t mesg) +{ + int retval; + struct bu21013_ts_data *tsc_data = i2c_get_clientdata(client); + + if (!tsc_data->board_flag) { + retval = tsc_data->chip->pirq_dis(); + if (retval < 0) { + dev_err(&client->dev, "irq disable failed \n"); + goto err; + } + retval = tsc_data->chip->irq_exit(); + if (retval < 0) { + dev_err(&client->dev, "irq exit failed \n"); + goto err; + } + } else + disable_irq(tsc_data->chip->irq); + return 0; +err: + kfree(tsc_data); + return retval; +} + +/** + * bu21013_tp_resume() - resume the touch screen controller + * @client: pointer to i2c client structure + * + * This funtion is used to resume the touch panel + * controller and returns integer. + **/ +static int bu21013_tp_resume(struct i2c_client *client) +{ + int retval; + struct bu21013_ts_data *tsc_data = i2c_get_clientdata(client); + + retval = tsc_config(tsc_data); + if (retval < 0) { + dev_err(&client->dev, "tsc config failed \n"); + goto err; + } + if (tsc_data->board_flag) + enable_irq(tsc_data->chip->irq); + return 0; +err: + kfree(tsc_data); + return retval; +} +#endif +/** + * bu21013_tp_sysfs() - sys fs parameters + * @tp_kobj: kernel object structure pointer + * + * This funtion uses to initialize the sysfs for touch panel + **/ +int bu21013_tp_sysfs(struct kobject *tp_kobj) +{ + int retval; + tp_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); + if (tp_kobj == NULL) { + retval = -ENOMEM; + goto err; + } + tp_kobj->ktype = &ktype_touchp; + kobject_init(tp_kobj, tp_kobj->ktype); + retval = kobject_set_name(tp_kobj, "touchp1"); + if (retval) { + kfree(tp_kobj); + goto err; + } + retval = kobject_add(tp_kobj, NULL, "touchp1"); + if (retval) { + kfree(tp_kobj); + goto err; + } + return 0; +err: + return retval; +} +/** + * bu21013_tp_probe() - Initialze the i2c-client touchscreen driver + * @i2c: i2c client structure pointer + * @id:i2c device id pointer + * + * This funtion uses to Initializes the i2c-client touchscreen + * driver and returns integer. + **/ +static int bu21013_tp_probe(struct i2c_client *i2c, const struct i2c_device_id *id) +{ + int retval; + struct bu21013_ts_data *tsc_data; + struct bu21013_platform_device *pdata = i2c->dev.platform_data; + dev_dbg(&i2c->dev, "u8500_tsc_probe:: start\n"); + + tsc_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL); + if (!tsc_data) { + dev_err(&i2c->dev, "tp memory alloc failed \n"); + retval = -ENOMEM; + return retval; + } + if (!pdata) { + dev_err(&i2c->dev, "tp platform data not defined \n"); + retval = -EINVAL; + goto err_alloc; + } + tsc_data->chip = pdata; + tsc_data->client = i2c; + /* + * Hack for dynamic detection of HREF v1 board + */ + tsc_data->board_flag = tsc_data->chip->board_check(); + /* + * Hack for not supporting touch panel controller2 + * for the ED and MOP500 v1 boards, due to no support + * of shared irq callback registeration in tc35892 + * and stmpe2401 driver. + */ + if ((!tsc_data->chip->tp_cntl) || + ((tsc_data->chip->tp_cntl == 2) && + (!tsc_data->board_flag))) { + dev_err(&i2c->dev, "tp is not supported \n"); + retval = -EINVAL; + goto err_alloc; + } + /* + * Hardcoded for portrait mode + */ + tsc_data->chip->portrait = true; + INIT_WORK(&tsc_data->tp_timer_handler, tp_timer_wq); + INIT_WORK(&tsc_data->tp_gpio_handler, tp_gpio_int_wq); + + init_timer(&tsc_data->penirq_timer); + tsc_data->penirq_timer.data = (unsigned long)tsc_data; + tsc_data->penirq_timer.function = tsc_timer_callback; + i2c_set_clientdata(i2c, tsc_data); + /* configure the gpio pins */ + if (tsc_data->chip->cs_en) { + retval = tsc_data->chip->cs_en(tsc_data->chip->cs_pin); + if (retval != 0) { + dev_err(&i2c->dev, "error in chip initialization\n"); + goto err; + } + } + /* sys_fs value configuration */ + tsc_data->th_on = BU21013_TH_ON_5; + tsc_data->th_off = (BU21013_TH_OFF_3 | BU21013_TH_OFF_4); + tsc_data->gain = (BU21013_GAIN_0 | BU21013_GAIN_1); + tsc_data->penup_timer = PENUP_TIMEOUT; + + /* configure the touch panel controller */ + retval = tsc_config(tsc_data); + if (retval < 0) { + dev_err(&i2c->dev, "error in tp config\n"); + goto err; + } + if (tsc_data->board_flag) { + retval = request_irq(tsc_data->chip->irq, tsc_gpio_callback, + (IRQF_TRIGGER_FALLING | IRQF_SHARED), DRIVER_TP, tsc_data); + if (retval) { + dev_err(&i2c->dev, "request irq %d failed\n", tsc_data->chip->irq); + free_irq(tsc_data->chip->irq, tsc_data); + goto err; + } + } + retval = tsc_driver_register(tsc_data); + if (retval) + goto err_init; + if (tsc_data->chip->tp_cntl != 2) { + retval = bu21013_tp_sysfs(&tsc_data->touchp_kobj); + if (retval) + goto err_init; + else + tp_sys_data = tsc_data; + } + dev_dbg(&i2c->dev, "u8500_tsc_probe : done \n"); + return retval; +err_init: + input_free_device(tsc_data->pin_dev); +err: + del_timer_sync(&tsc_data->penirq_timer); +err_alloc: + kfree(tsc_data); + return retval; +} +/** + * bu21013_tp_remove() - Removes the i2c-client touchscreen driver + * @client: i2c client structure pointer + * + * This funtion uses to remove the i2c-client + * touchscreen driver and returns integer. + **/ +static int __exit bu21013_tp_remove(struct i2c_client *client) +{ + struct bu21013_ts_data *data = i2c_get_clientdata(client); + del_timer_sync(&data->penirq_timer); + + if (data->chip != NULL) { + if (!data->board_flag) { + data->chip->irq_exit(); + data->chip->pirq_dis(); + } else + free_irq(data->chip->irq, data); + data->chip->cs_dis(data->chip->cs_pin); + } + kfree(&data->touchp_kobj); + input_unregister_device(data->pin_dev); + input_free_device(data->pin_dev); + kfree(data); + i2c_set_clientdata(client, NULL); + return 0; +} + +static const struct i2c_device_id bu21013_tp_id[] = { + { DRIVER_TP, 0 }, + { DRIVER_TP, 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, bu21013_tp_id); + +static struct i2c_driver bu21013_tp_driver = { + .driver = { + .name = DRIVER_TP, + .owner = THIS_MODULE, + }, + .probe = bu21013_tp_probe, +#ifdef CONFIG_PM + .suspend = bu21013_tp_suspend, + .resume = bu21013_tp_resume, +#endif + .remove = __exit_p(bu21013_tp_remove), + .id_table = bu21013_tp_id, +}; + +/** + * bu21013_tp_init() - Initialize the paltform touchscreen driver + * + * This funtion uses to initialize the platform + * touchscreen driver and returns integer. + **/ +static int __init bu21013_tp_init(void){ + return i2c_add_driver(&bu21013_tp_driver); +} + +/** + * bu21013_tp_exit() - De-initialize the paltform touchscreen driver + * + * This funtion uses to de-initialize the platform + * touchscreen driver and returns none. + **/ +static void __exit bu21013_tp_exit(void){ + i2c_del_driver(&bu21013_tp_driver); +} + +module_init(bu21013_tp_init); +module_exit(bu21013_tp_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("NAVEEN KUMAR G"); +MODULE_DESCRIPTION("Touch Screen driver for Bu21013 controller"); diff --git a/drivers/input/touchscreen/u8500_tsc.c b/drivers/input/touchscreen/u8500_tsc.c deleted file mode 100644 index 3aef1ea873b..00000000000 --- a/drivers/input/touchscreen/u8500_tsc.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* - * Overview: - * Touch panel driver for u8500 platform - * - * Copyright (C) 2009 ST-Ericsson SA - * - * 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. - */ - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/proc_fs.h> -#include <linux/platform_device.h> -#include <linux/poll.h> -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/i2c.h> -#include <linux/workqueue.h> -#include <linux/input.h> -#include <linux/kthread.h> -#include <linux/freezer.h> -#include <linux/gpio.h> -#include <linux/io.h> -#include <linux/types.h> -#include <mach/debug.h> -#include <mach/u8500_tsc.h> -#include <linux/timer.h> - -static void tsc_timer_wq(struct work_struct *_chip); -static void tp_gpio_int_wq(struct work_struct *_chip); - -static struct i2c_driver tp_driver; -static tsc_error tsc_write_byte(struct i2c_client *i2c, u8 reg, - unsigned char data); -static tsc_error bu21013_tsc_init(struct i2c_client *i2c); -static tsc_error tsc_config(struct u8500_tsc_data *pdev_data); -static void tsc_clear_irq(struct i2c_client *i2c); -static void tsc_en_irq(struct i2c_client *i2c); -static void tsc_callback(void *tsc); -static irqreturn_t tsc_gpio_callback(int irq, void *device_data); -static int tsc_driver_register(struct u8500_tsc_data *pdata); -static void tsc_timer_callback(unsigned long data); -#ifdef CONFIG_U8500_TSC_EXT_CLK_9_6 -static tsc_error tsc_read_byte(struct i2c_client *i2c, u8 reg, unsigned char *val); -#endif - -#if (defined CONFIG_CPU_IDLE || defined CONFIG_TOUCHP_TUNING) -static u8 th_on = TSC_TH_ON_VAL; /* 0x20; */ -static u8 th_off = TSC_TH_OFF_VAL; /* 0x18; */ -#endif -#ifdef CONFIG_TOUCHP_TUNING -unsigned long penup_timer = PENUP_TIMEOUT; -unsigned long g_tool_width = 1; -static struct kobject *touchp_kobj; -struct u8500_tsc_data *pdev_data; -static ssize_t touchp_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - u8 timeout = 0; - u8 sys_th_on = 0; - u8 sys_th_off = 0; - - if (strcmp(attr->name, "timeout_value") == 0) { - timeout = penup_timer; - sprintf(buf, "%d\n", timeout); - } else if (strcmp(attr->name, "th_on") == 0) { - sys_th_on = th_on; - sprintf(buf, "%d\n", sys_th_on); - } else if (strcmp(attr->name, "th_off") == 0) { - sys_th_off = th_off; - sprintf(buf, "%d\n", sys_th_off); - } - return strlen(buf); -} -static ssize_t touchp_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t len) -{ - int ret = 0; - int timeout = 0; - int sys_th_on = 0; - int sys_th_off = 0; - - if (strcmp(attr->name, "timeout_value") == 0) { - ret = sscanf(buf, "%d", &timeout); - if (ret == 1) - penup_timer = timeout; - } else if (strcmp(attr->name, "th_on") == 0) { - ret = sscanf(buf, "%d", &sys_th_on); - if ((ret == 1) && (th_on != sys_th_on)) { - th_on = sys_th_on; - if (th_on < 0xFF) - bu21013_tsc_init(pdev_data->client); - } - } else if (strcmp(attr->name, "th_off") == 0) { - ret = sscanf(buf, "%d", &sys_th_off); - if ((ret == 1) && (th_off != sys_th_off)) { - th_off = sys_th_off; - if (th_off < 0xFF) - bu21013_tsc_init(pdev_data->client); - } - } - return ret == 1 ? len : -EINVAL; -} - -static struct attribute touchp_timeout = {.name = "timeout_value", - .mode = 0666}; -static struct attribute touchp_th_on = {.name = "th_on", .mode = 0666}; -static struct attribute touchp_th_off = {.name = "th_off", .mode = 0666}; - -static struct attribute *touchp_attribute[] = { - &touchp_timeout, - &touchp_th_on, - &touchp_th_off, - NULL -}; - -static struct sysfs_ops touchp_sysfs_ops = { - .show = touchp_attr_show, - .store = touchp_attr_store, -}; - -static struct kobj_type ktype_touchp = { - .sysfs_ops = &touchp_sysfs_ops, - .default_attrs = touchp_attribute, -}; -#endif -/** - * tsc_write_byte() - Write a single byte to touch screen. - * @i2c:i2c client structure - * @reg:register offset - * @value:data byte to be written - * - * This funtion uses smbus byte write API - * to write a single byte to touch screen and returns tsc error. - */ -static tsc_error tsc_write_byte(struct i2c_client *i2c, u8 reg, - unsigned char value) -{ - int retval = TSC_OK; - retval = i2c_smbus_write_byte_data(i2c, reg, value); - if (retval < 0) - dev_err(&i2c->dev, - "tsc_write_byte:: i2c smbus write byte failed\n"); - return retval; -} -#ifdef CONFIG_U8500_TSC_EXT_CLK_9_6 -/** - * tsc_read_byte() - read single byte from touch screen - * @i2c:i2c client structure - * @reg:register offset - * @val:value to get from i2c register - * - * This funtion uses smbus read block API - * to read single byte from the reg offset and returns tsc error. - */ -static tsc_error tsc_read_byte(struct i2c_client *i2c, u8 reg, - unsigned char *val) -{ - int retval = 0; - retval = i2c_smbus_read_byte_data(i2c, reg); - if (retval < 0) - return retval; - *val = (unsigned char)retval; - return TSC_OK; -} -#endif -/** - * tsc_read()-read data from touch panel - * @i2c:i2c client structure pointer - * @reg:register offset - * @buf:read the data in this buffer - * @nbytes:number of bytes to read - * - * This funtion uses smbus read block API - * to read multiple bytes from the reg offset. - **/ -static int tsc_read_block(struct i2c_client *i2c, u8 reg, u8 *buf, u8 nbytes) -{ - int ret; - - ret = i2c_smbus_read_i2c_block_data(i2c, reg, nbytes, buf); - if (ret < nbytes) - return ret; - return TSC_OK; -} -/** - * tsc_read_10bit() - read 10 bit data from touch screen - * @i2c:i2c client structure - * @reg:register offset - * @val:value to get from i2c register - * - * This funtion uses smbus read block API - * to read 10-bit from the reg offset and returns tsc error. - */ -static tsc_error tsc_read_10bit(struct i2c_client *i2c, - u8 reg, unsigned int *val) -{ - u16 data = 0; - int retval = 0; - u8 buf[2]; - retval = tsc_read_block(i2c, reg, buf, 2); - if (retval < 0) - return retval; - data = buf[0]; - data = (data << 2) | buf[1]; - *val = data; - return TSC_OK; -} - -/** - * touch_calculation(): Get the exact co-ordinates of the touch interrupt - * @p_gesture_info: gesture_info structure pointer - * Transfer the position information from touch sensor - * coordinate to display coordinate and returns none. - */ -void touch_calculation(struct gesture_info *p_gesture_info) -{ - signed short x1, y1; - int tmpx, tmpy; -#ifdef CONFIG_U8500_TSC_MULTITOUCH - signed short x2, y2; -#endif - - tmpx = (X_MAX * 1000 / TOUCH_XMAX); - tmpy = (Y_MAX * 1000 / TOUCH_YMAX); - - x1 = p_gesture_info->pt[0].x; - y1 = p_gesture_info->pt[0].y; - - x1 = x1 * tmpx / 1000; -#if (defined CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT && defined CONFIG_U8500_TSC_X_FLIP) - x1 = X_MAX - x1; -#endif - p_gesture_info->pt[0].x = x1; - - y1 = y1 * tmpy / 1000; -#if (defined CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT && defined CONFIG_U8500_TSC_Y_FLIP) - y1 = Y_MAX - y1; -#endif - p_gesture_info->pt[0].y = y1; -#ifdef CONFIG_U8500_TSC_MULTITOUCH - x2 = p_gesture_info->pt[1].x; - x2 = x2 * tmpx / 1000; -#if (defined CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT && defined CONFIG_U8500_TSC_X_FLIP) - x2 = X_MAX - x2; -#endif - p_gesture_info->pt[1].x = x2; - - y2 = p_gesture_info->pt[1].y; - y2 = y2 * tmpy / 1000; -#if (defined CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT && defined CONFIG_U8500_TSC_Y_FLIP) - y2 = Y_MAX - y2; -#endif - p_gesture_info->pt[1].y = y2; -#endif -} - -/** - * get_touch(): Get the co-ordinates of the touch interrupt - * @data:u8500_tsc_data structure pointer - * Get touched point position - * from touch sensor registers and write to global variables. - */ -void get_touch(struct u8500_tsc_data *data) -{ - struct i2c_client *i2c = data->client; - tsc_error retval = TSC_OK; - u8 finger1_buf[4]; - int count; - signed short tmp1x, tmp1y; - u8 j, i; -#ifdef CONFIG_U8500_TSC_MULTITOUCH - u8 finger2_buf[4]; - signed short tmp2x, tmp2y; -#endif - if (i2c != NULL) { - for (count = 0; count < 2; count++) { - #ifdef CONFIG_U8500_TSC_EXT_CLK_9_6 - i = TSC_POS_X1; - for (j = 0; j < 2; j++) { - retval = tsc_read_byte(i2c, i, &finger1_buf[j]); - if (retval < 0) - return; - i++; - } - tmp1x = finger1_buf[0]; - tmp1x = (tmp1x << 2) | finger1_buf[1]; - if (tmp1x != 0) { - i = TSC_POS_Y1; - for (j = 2; j < 4; j++) { - retval = tsc_read_byte(i2c, i, &finger1_buf[j]); - if (retval < 0) - return; - i++; - } - tmp1y = finger1_buf[2]; - tmp1y = (tmp1y << 2) | finger1_buf[3]; - } else - tmp1y = 0; - #else - retval = tsc_read_block(i2c, TSC_POS_X1, finger1_buf, 4); - if (retval != 0) - return; - tmp1x = finger1_buf[0]; - tmp1x = (tmp1x << 2) | finger1_buf[1]; - tmp1y = finger1_buf[2]; - tmp1y = (tmp1y << 2) | finger1_buf[3]; - #endif - if (tmp1x != 0 && tmp1y != 0) - break; - } - if (tmp1x != 0 && tmp1y != 0) - data->finger1_pressed = TRUE; - else - data->finger1_pressed = FALSE; - - if (tmp1x > TOUCH_XMAX || tmp1y > TOUCH_YMAX) - data->finger1_pressed = FALSE; - - if (data->finger1_pressed) { - data->x1 = tmp1x; - data->y1 = tmp1y; - } else { - data->x1 = 0; - data->y1 = 0; - data->x2 = 0; - data->y2 = 0; - } - - #ifndef CONFIG_U8500_TSC_MULTITOUCH - if (data->finger1_pressed == TRUE) { - data->touch_en = TRUE; - data->touchflag = TRUE; - } else { - data->touch_en = FALSE; - data->touchflag = FALSE; - } - #else - for (count = 0; count < 2; count++) { - #ifdef CONFIG_U8500_TSC_EXT_CLK_9_6 - i = TSC_POS_X2; - for (j = 0; j < 2; j++) { - retval = tsc_read_byte(i2c, i, &finger2_buf[j]); - if (retval < 0) - return; - i++; - } - tmp2x = finger2_buf[0]; - tmp2x = (tmp2x << 2) | finger2_buf[1]; - if (tmp2x != 0) { - i = TSC_POS_Y2; - for (j = 2; j < 4; j++) { - retval = tsc_read_byte(i2c, i, &finger2_buf[j]); - if (retval < 0) - return; - i++; - } - tmp2y = finger2_buf[2]; - tmp2y = (tmp2y << 2) | finger2_buf[3]; - } else - tmp2y = 0; - #else - retval = tsc_read_block(i2c, TSC_POS_X2, finger2_buf, 4); - if (retval != 0) - return; - tmp2x = finger2_buf[0]; - tmp2x = (tmp2x << 2) | finger2_buf[1]; - tmp2y = finger2_buf[2]; - tmp2y = (tmp2y << 2) | finger2_buf[3]; - #endif - if (tmp2x != 0 && tmp2y != 0) - break; - } - if (tmp2x != 0 && tmp2y != 0) - data->finger2_pressed = TRUE; - else - data->finger2_pressed = FALSE; - - if (tmp2x > TOUCH_XMAX || tmp2y > TOUCH_YMAX) - data->finger2_pressed = FALSE; - data->finger2_count = 1; - if (data->finger2_pressed) { - data->x2 = tmp2x; - data->y2 = tmp2y; - } else { - data->x2 = 0; - data->y2 = 0; - } - if ((data->finger1_pressed == TRUE) - || (data->finger2_pressed == TRUE)) { - data->touch_en = TRUE; - data->touchflag = TRUE; - } else { - data->touch_en = FALSE; - data->touchflag = FALSE; - } - - if ((data->finger1_pressed == FALSE) - && (data->finger2_pressed == TRUE)) { - data->x1 = tmp2x; - data->y1 = tmp2y; - data->x2 = 0; - data->y2 = 0; - data->finger2_pressed = FALSE; - } - #endif - } -} - -/** - * get_touch_message(): Generate the gesture message - * @data: a pointer to the device structure - * Generate the gesture message according to the - * information collected and returns integer. - */ - -int get_touch_message(struct u8500_tsc_data *data) -{ - struct gesture_info *p_gesture_info = &data->gesture_info; - struct i2c_client *i2c = data->client; - unsigned int ret = TRUE; - - unsigned char flick_series_flag = TRUE; - signed short x_delta, y_delta; - unsigned char dir_left_right, dir_up_down; - unsigned char tmp; - signed short i; - unsigned char dir1, dir2; - - static struct touch_point pre_gesture_point; - - unsigned long area; - static unsigned long pre_area; - - p_gesture_info->gesture_kind = GES_UNKNOWN; - - if (i2c == NULL) - return -1; - - get_touch(data); - - if (data->touchflag == FALSE) { - if (data->touch_continue) { - data->touch_continue = FALSE; - - /* touch end message */ - p_gesture_info->gesture_kind = GES_TOUCHEND; - - /* tap flag less than 2 */ - if (data->pre_tap_flag_level <= 2) - data->pre_tap_flag_level++; - - data->pre_tap_flag = CLR; - } else { - if (!data->pinch_start) { - if (data->flick_flag) { - x_delta = p_gesture_info->pt[0].x - data->tap_start_point.x; - y_delta = p_gesture_info->pt[0].y - data->tap_start_point.y; - - if (x_delta < 0) { - dir_left_right = DIR_LEFT; - x_delta = -x_delta; - } else - dir_left_right = DIR_RIGHT; - - if (y_delta < 0) { - y_delta = -y_delta; - dir_up_down = DIR_UP; - } else - dir_up_down = DIR_DOWN; - - if ((THRESHOLD_FLICK <= x_delta) || (THRESHOLD_FLICK <= y_delta)) { - if (THRESHOLD_DRAGDROP <= data->touch_count) { - p_gesture_info->gesture_kind = GES_DRAGDROP; - p_gesture_info->speed = data->touch_count; - p_gesture_info->pt[0].x = data->tap_start_point.x; - p_gesture_info->pt[0].y = data->tap_start_point.y; - p_gesture_info->pt[1].x = pre_gesture_point.x; - p_gesture_info->pt[1].y = pre_gesture_point.y; - } else { - if ((THRESHOLD_FLICK_SPEED < x_delta) || (THRESHOLD_FLICK_SPEED < y_delta)) - p_gesture_info->speed = HIGHSPEED; - else - p_gesture_info->speed = LOWSPEED; - p_gesture_info->gesture_kind = GES_FLICK; - if (x_delta > y_delta) - p_gesture_info->dir = dir_left_right; - else - p_gesture_info->dir = dir_up_down; - } - data->pre_tap_flag_level = 0; - data->flick_flag = CLR; - data->touch_count = STOP; - } else { - flick_series_flag = FALSE; - } - } else { - flick_series_flag = FALSE; - } - if (flick_series_flag == FALSE) { - if (THRESHOLD_TAPLIMIT <= data->touch_count) { - p_gesture_info->gesture_kind = GES_TAP; - p_gesture_info->times = data->pre_tap_flag_level; - p_gesture_info->speed = data->touch_count; - data->pre_tap_flag_level = 0; - data->flick_flag = CLR; - data->touch_count = STOP; - data->dir_idx = DIRHEADER; - - for (i = 0; i < DIRHEADER; i++) - data->dir_trace[i] = 0x0; - for (i = DIRHEADER; i < DIRTRACEN; i++) - data->dir_trace[i] = 0x05; - } else { - ret = FALSE; - } - } - } else { - data->pinch_start = FALSE; - data->pre_tap_flag_level = 0; - data->flick_flag = CLR; - data->touch_count = STOP; - } - } - } else { - p_gesture_info->pt[0].x = data->x1; - p_gesture_info->pt[0].y = data->y1; - p_gesture_info->pt[1].x = data->x2; - p_gesture_info->pt[1].y = data->y2; - touch_calculation(p_gesture_info); - - if (data->touch_continue) { - if ((data->x2 != 0) && (data->y2 != 0)) { - x_delta = p_gesture_info->pt[0].x - p_gesture_info->pt[1].x; - y_delta = p_gesture_info->pt[0].y - p_gesture_info->pt[1].y; - if (x_delta < 0) - x_delta = -x_delta; - if (y_delta < 0) - y_delta = -y_delta; - x_delta++; - y_delta++; - area = x_delta * y_delta; - p_gesture_info->dir = PINCH_KEEP; - if (area != pre_area) { - if (area > pre_area) { - if ((area - pre_area) > THRESHOLD_PINCH) { - p_gesture_info->dir = PINCH_OUT; - if ((area - pre_area) < THRESHOLD_PINCH_SPEED) - p_gesture_info->speed = LOWSPEED; - else - p_gesture_info->speed = HIGHSPEED; - } - } else { - if ((pre_area - area) > THRESHOLD_PINCH) { - p_gesture_info->dir = PINCH_IN; - - if ((pre_area - area) < THRESHOLD_PINCH_SPEED) - p_gesture_info->speed = LOWSPEED; - else - p_gesture_info->speed = HIGHSPEED; - } - } - } - if (data->pinch_start == FALSE) { - p_gesture_info->dir = PINCH_KEEP; - pre_area = 0; - data->pinch_start = TRUE; - } - p_gesture_info->gesture_kind = GES_PINCH; - pre_area = area; - } else { - x_delta = p_gesture_info->pt[0].x - pre_gesture_point.x; - y_delta = p_gesture_info->pt[0].y - pre_gesture_point.y; - if (x_delta > 0) { - if (x_delta < THRESHOLD_ROTATE) - x_delta = 0; - } else { - if (-x_delta < THRESHOLD_ROTATE) - x_delta = 0; - } - if (y_delta > 0) { - if (y_delta < THRESHOLD_ROTATE) - y_delta = 0; - } else { - if (-y_delta < THRESHOLD_ROTATE) - y_delta = 0; - } - if (x_delta == y_delta) - p_gesture_info->dir = DIR_INVALID; - else { - if (x_delta < 0) { - dir_left_right = DIR_LEFT; - x_delta = -x_delta; - } else - dir_left_right = DIR_RIGHT; - if (y_delta < 0) { - y_delta = -y_delta; - dir_up_down = DIR_UP; - } else - dir_up_down = DIR_DOWN; - if (x_delta > y_delta) - p_gesture_info->dir = dir_left_right; - else - p_gesture_info->dir = dir_up_down; - tmp = p_gesture_info->dir; - data->dir_trace[tmp]++; - data->dir_trace[data->dir_idx] = tmp; - if (data->dir_idx < (THRESHOLD_ROTATE_HIST + DIRHEADER)) - data->dir_idx++; - else - data->dir_idx = DIRHEADER; - data->dir_trace[data->dir_trace[data->dir_idx]]--; - dir1 = data->dir_trace[0]; - for (dir2 = 1; dir2 < 5; dir2++) { - if (data->dir_trace[data->dir_trace[0]] - < data->dir_trace[dir2]) { - data->dir_trace[0] = dir2; - p_gesture_info->dir - = data->rotate_data[dir1][dir2]; - if (p_gesture_info->dir) - p_gesture_info->gesture_kind - = GES_ROTATE; - break; - } - } - } - if (p_gesture_info->dir == ROTATE_INVALID) { - p_gesture_info->gesture_kind - = GES_MOVE; - p_gesture_info->speed - = data->touch_count; - } - } - data->flick_flag = SET; - } else { - p_gesture_info->gesture_kind = GES_TOUCHSTART; - data->tap_start_point.x = p_gesture_info->pt[0].x; - data->tap_start_point.y = p_gesture_info->pt[0].y; - data->touch_count = START; - } - data->touch_continue = SET; - pre_gesture_point.x = p_gesture_info->pt[0].x; - pre_gesture_point.y = p_gesture_info->pt[0].y; - } - return ret; -} - -/** - * tsc_restart_pen_up_timer() - restart the timer - * @data:u8500_tsc_data structure pointer - * - * This funtion used to run the timer and returns none. - */ -static inline void tsc_restart_pen_up_timer(struct u8500_tsc_data *data) -{ -#ifdef CONFIG_TOUCHP_TUNING - mod_timer(&data->penirq_timer, jiffies + msecs_to_jiffies(penup_timer)); -#else - mod_timer(&data->penirq_timer, jiffies + msecs_to_jiffies(PENUP_TIMEOUT)); -#endif -} - -/** - * tsc_clear_irq() - clear the tsc interrupt - * @i2c:i2c_client structure pointer - * - * This funtion used to clear the - * bu21013 controller interrupt for next Pen interrupts and returns none. - */ -static void tsc_clear_irq(struct i2c_client *i2c) -{ - int retval; - retval = tsc_write_byte(i2c, TSC_INT_CLR, 0X01); - if (retval < 0) - dev_err(&i2c->dev, \ - "TSC_INT_CLR failed retval=0x%x \n", retval); -} - -/** - * tsc_en_irq() - Reactivate the tsc interrupt - * @i2c:i2c_client structure pointer - * - * This funtion used to activate the bu21013 controller - * interrupt for next Pen interrupts. - */ -static void tsc_en_irq(struct i2c_client *i2c) -{ - int retval; - retval = tsc_write_byte(i2c, TSC_INT_CLR, 0X00); - if (retval < 0) - dev_err(&i2c->dev, \ - "TSC_INT_CLR failed retval=0x%x \n", retval); -} -/** - * tsc_input_report() - report the touch point - * @data:u8500_tsc_data structure pointer - * @value:value to be passed for en down or pen up - * This funtion calls, when we need to report the Pen down/up interrupt - */ -static void tsc_input_report(struct u8500_tsc_data *data, unsigned int value) -{ - if (value) { - #ifdef CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - input_report_abs(data->pin_dev, ABS_X, - data->gesture_info.pt[0].x); - input_report_abs(data->pin_dev, ABS_Y, - data->gesture_info.pt[0].y); - #else - input_report_abs(data->pin_dev, ABS_X, - data->gesture_info.pt[0].y); - input_report_abs(data->pin_dev, ABS_Y, - data->gesture_info.pt[0].x); - #endif - input_report_abs(data->pin_dev, ABS_PRESSURE, 1); - input_report_abs(data->pin_dev, ABS_TOOL_WIDTH, 1); - input_report_key(data->pin_dev, BTN_TOUCH, 1); -#ifdef CONFIG_U8500_TSC_MULTITOUCH - if (data->finger2_pressed) { - input_report_key(data->pin_dev, BTN_2, 1); - #ifdef CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - input_report_abs(data->pin_dev, ABS_HAT0X, - data->gesture_info.pt[1].x); - input_report_abs(data->pin_dev, ABS_HAT0Y, - data->gesture_info.pt[1].y); - #else - input_report_abs(data->pin_dev, ABS_HAT0X, - data->gesture_info.pt[1].y); - input_report_abs(data->pin_dev, ABS_HAT0Y, - data->gesture_info.pt[1].x); - #endif - } - input_report_abs(data->pin_dev, ABS_MT_TOUCH_MAJOR, 1); - input_report_key(data->pin_dev, ABS_MT_WIDTH_MAJOR, 1); - #ifdef CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - input_report_abs(data->pin_dev, ABS_MT_POSITION_X, - data->gesture_info.pt[0].x); - input_report_abs(data->pin_dev, ABS_MT_POSITION_Y, - data->gesture_info.pt[0].y); - #else - input_report_abs(data->pin_dev, ABS_MT_POSITION_X, - data->gesture_info.pt[0].y); - input_report_abs(data->pin_dev, ABS_MT_POSITION_Y, - data->gesture_info.pt[0].x); - #endif - input_mt_sync(data->pin_dev); - if (data->finger2_pressed) { - input_report_abs(data->pin_dev, ABS_MT_TOUCH_MAJOR, 1); - input_report_key(data->pin_dev, ABS_MT_WIDTH_MAJOR, 1); - #ifdef CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - input_report_abs(data->pin_dev, ABS_MT_POSITION_X, - data->gesture_info.pt[1].x); - input_report_abs(data->pin_dev, ABS_MT_POSITION_Y, - data->gesture_info.pt[1].y); - #else - input_report_abs(data->pin_dev, ABS_MT_POSITION_X, - data->gesture_info.pt[1].y); - input_report_abs(data->pin_dev, ABS_MT_POSITION_Y, - data->gesture_info.pt[1].x); - #endif - input_mt_sync(data->pin_dev); - } -#endif - } else { - input_report_abs(data->pin_dev, ABS_PRESSURE, 0); - input_report_abs(data->pin_dev, ABS_TOOL_WIDTH, 0); - input_report_key(data->pin_dev, BTN_TOUCH, 0); - #ifdef CONFIG_U8500_TSC_MULTITOUCH - if (data->finger2_count > 0) { - input_report_key(data->pin_dev, BTN_2, 0); - input_report_abs(data->pin_dev, ABS_MT_TOUCH_MAJOR, 0); - input_report_key(data->pin_dev, ABS_MT_WIDTH_MAJOR, 0); - input_mt_sync(data->pin_dev); - data->finger2_count = 0; - } - #endif - } - input_sync(data->pin_dev); -} - -/** - * tsc_callback() - callback handler for Pen down - * @device_data:void pointer - * - * This funtion calls, when we get the Pen down interrupt from Egpio Pin - * and assigns the task and returns none. - */ - -static void tsc_callback(void *device_data) -{ - struct u8500_tsc_data *data = (struct u8500_tsc_data *)device_data; - schedule_work(&data->m_tp_gpio_int_wq); -} -/** - * tsc_gpio_callback() - callback handler for Pen down - * @device_data:void pointer - * @irq: irq value - * - * This funtion calls for HREF v1, when we get the Pen down interrupt from GPIO Pin - * and assigns the task and returns irqreturn_t. - */ - -static irqreturn_t tsc_gpio_callback(int irq, void *device_data) -{ - struct u8500_tsc_data *data = (struct u8500_tsc_data *)device_data; - schedule_work(&data->m_tp_gpio_int_wq); - return IRQ_HANDLED; -} - - - -/** - * tsc_timer_callback() - callback handler for Timer - * @dev_data:touch screen data - * - * This callback handler used to schedule the work for Pen up - * and Pen down interrupts and returns none - */ -static void tsc_timer_callback(unsigned long dev_data) -{ - struct u8500_tsc_data *data = (struct u8500_tsc_data *)dev_data; - schedule_work(&data->m_tp_timer_int_wq); -} - -/** - * tsc_timer_wq() - Work Queue for timer handler - * @work:work_struct structure pointer - * - * This work queue used to get the co-ordinates - * of the Pen up and Pen down interrupts and returns none - */ -static void tsc_timer_wq(struct work_struct *work) -{ - unsigned char pin_value; - struct u8500_tsc_data *data = container_of(work, struct u8500_tsc_data, m_tp_timer_int_wq); - struct task_struct *tsk = current; - - set_task_state(tsk, TASK_INTERRUPTIBLE); - pin_value = data->chip->pirq_read_val(); - - get_touch_message(data); - if (data->touch_en) - tsc_input_report(data, 1); - else - tsc_input_report(data, 0); - - if (pin_value == 0) { - tsc_restart_pen_up_timer(data); - } else { - enable_irq(data->chip->irq); - tsc_clear_irq(data->client); - tsc_en_irq(data->client); - } -} - -/** - * tp_gpio_int_wq() - Work Queue for GPIO_INT handler - * @work:work_struct structure pointer - * - * This work queue used to get the co-ordinates - * of the Pen up and Pen down interrupts and returns none - */ -static void tp_gpio_int_wq(struct work_struct *work) -{ - unsigned char pin_value; - struct u8500_tsc_data *tp_data = container_of(work, struct u8500_tsc_data, m_tp_gpio_int_wq); - struct task_struct *tsk = current; - set_task_state(tsk, TASK_INTERRUPTIBLE); - pin_value = tp_data->chip->pirq_read_val(); - if (pin_value == 0) { - disable_irq(tp_data->chip->irq); - get_touch_message(tp_data); - - if (tp_data->touch_en) - tsc_input_report(tp_data, 1); - else - tsc_input_report(tp_data, 0); - - tsc_clear_irq(tp_data->client); - tsc_en_irq(tp_data->client); - tsc_restart_pen_up_timer(tp_data); - } else { - tsc_input_report(tp_data, 0); - } -} -/* - * GetCaliStatus() - Get the Calibration status - * @i2c: i2c client structure pointer - * Get the calibration status of the touch sensor - * and returns integer - */ -int get_calib_status(struct i2c_client *i2c) -{ - tsc_error retval = TSC_OK; - unsigned int value; - u8 i; - - for (i = 0x40; i <= 0x4B; i += 2) { - retval = tsc_read_10bit(i2c, i, &value); - if (retval < 0) - dev_err(&i2c->dev, - "get_calib_status:failed retval=0x%x \n", retval); - } - for (i = 0x54; i <= 0x69; i += 2) { - retval = tsc_read_10bit(i2c, i, &value); - if (retval < 0) - dev_err(&i2c->dev, - "get_calib_status:failed retval=0x%x \n", retval); - } - return retval; -} -/* - * doCalibrate() - Do the software Calibration - * @i2c: i2c_client structure pointer - * Do the soft calibration on the touch screen - * and returns integer - */ -int doCalibrate(struct i2c_client *i2c) -{ - tsc_error retval = TSC_OK; - retval = tsc_write_byte(i2c, TSC_CALIB, 0X1); - if (retval < 0) - dev_err(&i2c->dev, "reset failed retval=0x%x \n", retval); - return retval; -} -/* - * check_board(): check for href v1 board - * @data: device structure pointer - * This function used to check_board - */ -void check_board(struct u8500_tsc_data *data) -{ - if (data->chip->board_href_v1) - data->href_v1_flag = data->chip->board_href_v1(); -} -/* - * init_config(): Initialize the Global variables - * @data: device structure pointer - * This function used to initialize the device variables and returns none - */ -void init_config(struct u8500_tsc_data *data) -{ - signed int i; - - data->touch_count = STOP; - data->touchflag = FALSE; - data->touch_continue = CLR; - - data->pre_tap_flag_level = 0; - data->pre_tap_flag = 0; - data->flick_flag = 0; - data->finger1_pressed = 0; - -#ifdef CONFIG_U8500_TSC_MULTITOUCH - data->finger2_pressed = 0; - data->finger2_count = 0; -#endif - data->x1 = 0; - data->y1 = 0; - data->x2 = 0; - data->y2 = 0; - - data->pinch_start = FALSE; - - /* turning right */ - data->rotate_data[DIR_UP][DIR_RIGHT] = ROTATE_R_UR; - data->rotate_data[DIR_RIGHT][DIR_DOWN] = ROTATE_R_RD; - data->rotate_data[DIR_DOWN][DIR_LEFT] = ROTATE_R_DL; - data->rotate_data[DIR_LEFT][DIR_UP] = ROTATE_R_LU; - - /* turning left */ - data->rotate_data[DIR_LEFT][DIR_DOWN] = ROTATE_L_LD; - data->rotate_data[DIR_RIGHT][DIR_UP] = ROTATE_L_DR; - data->rotate_data[DIR_DOWN][DIR_RIGHT] = ROTATE_L_RU; - data->rotate_data[DIR_UP][DIR_LEFT] = ROTATE_L_UL; - - /* invalid turning */ - data->rotate_data[DIR_UP][DIR_DOWN] = DIR_INVALID; - data->rotate_data[DIR_DOWN][DIR_UP] = DIR_INVALID; - data->rotate_data[DIR_LEFT][DIR_RIGHT] = DIR_INVALID; - data->rotate_data[DIR_RIGHT][DIR_LEFT] = DIR_INVALID; - data->rotate_data[DIR_UP][DIR_UP] = DIR_INVALID; - data->rotate_data[DIR_DOWN][DIR_DOWN] = DIR_INVALID; - data->rotate_data[DIR_LEFT][DIR_LEFT] = DIR_INVALID; - data->rotate_data[DIR_RIGHT][DIR_RIGHT] = DIR_INVALID; - - data->dir_idx = DIRHEADER; - - for (i = 0; i < DIRHEADER; i++) - data->dir_trace[i] = 0x0; - - for (i = DIRHEADER; i < DIRTRACEN; i++) - data->dir_trace[i] = 0x05; - - data->tap_start_point.x = 0x0; - data->tap_start_point.y = 0x0; - data->href_v1_flag = FALSE; - return; -} -/** - * bu21013_tsc_init() - Power on sequence for the bu21013 controller - * @i2c:pointer to i2c client structure - * - * This funtion is used to power on - * the bu21013 controller and returns tsc error. - **/ -static tsc_error bu21013_tsc_init(struct i2c_client *i2c) -{ - tsc_error retval = TSC_OK; - - dev_dbg(&i2c->dev, "bu21013_tsc_init start\n"); - - retval = i2c_smbus_write_byte_data(i2c, TSC_RESET, 0x01); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "ED reg i2c smbus write byte failed\n"); - goto err; - } - mdelay(30); - - retval = i2c_smbus_write_byte_data(i2c, TSC_SENSOR_0_7, 0x3F); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F0 reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_SENSOR_8_15, 0xFC); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F1 reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_SENSOR_16_23, 0x1F); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F2 reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_POS_MODE1, 0x06); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F3 reg i2c smbus write byte failed\n"); - goto err; - } -#ifdef CONFIG_U8500_TSC_MULTITOUCH - retval = i2c_smbus_write_byte_data(i2c, TSC_POS_MODE2, 0x97); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F4 reg i2c smbus write byte failed\n"); - goto err; - } -#else - retval = i2c_smbus_write_byte_data(i2c, TSC_POS_MODE2, 0x17); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F4 reg i2c smbus write byte failed\n"); - goto err; - } -#endif -#ifdef CONFIG_U8500_TSC_EXT_CLK_9_6 - retval = i2c_smbus_write_byte_data(i2c, TSC_CLK_MODE, TSC_CLK_MODE_VAL1); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F5 reg i2c smbus write byte failed\n"); - goto err; - } -#else - retval = i2c_smbus_write_byte_data(i2c, TSC_CLK_MODE, TSC_CLK_MODE_VAL2); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "F5 reg i2c smbus write byte failed\n"); - goto err; - } -#endif - retval = i2c_smbus_write_byte_data(i2c, TSC_IDLE, TSC_IDLE_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "FA reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_INT_MODE, TSC_INT_MODE_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "E9 reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_FILTER, TSC_FILTER_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "FB reg i2c smbus write byte failed\n"); - goto err; - } -#if (defined CONFIG_CPU_IDLE || defined CONFIG_TOUCHP_TUNING) - retval = i2c_smbus_write_byte_data(i2c, TSC_TH_ON, th_on); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "FC reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_TH_OFF, th_off); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "FD reg i2c smbus write byte failed\n"); - goto err; - } -#else - retval = i2c_smbus_write_byte_data(i2c, TSC_TH_ON, TSC_TH_ON_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "FC i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_TH_OFF, TSC_TH_OFF_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "FD i2c smbus write byte failed\n"); - goto err; - } -#endif - retval = i2c_smbus_write_byte_data(i2c, TSC_GAIN, TSC_GAIN_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "EA reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_OFFSET_MODE, TSC_OFFSET_MODE_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "EB reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_XY_EDGE, TSC_XY_EDGE_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "EC reg i2c smbus write byte failed\n"); - goto err; - } - retval = i2c_smbus_write_byte_data(i2c, TSC_DONE, TSC_DONE_VAL); - if (retval < TSC_OK) { - dev_err(&i2c->dev, "EF reg i2c smbus write byte failed\n"); - goto err; - } -err: - return retval; -} - -/* - * tsc_driver_register() - Used for input driver registeration - * @pdata: pointer to u8500_tsc_data structure - * This function used to register the - * touch screen as input device and returns integer - */ -static int tsc_driver_register(struct u8500_tsc_data *pdata) -{ - int ret = TSC_OK; - - struct input_dev *in_dev; - struct i2c_client *i2c = pdata->client; - dev_dbg(&i2c->dev, "tsc_driver_register start\n"); - - /* register the touch screen driver to input device */ - in_dev = input_allocate_device(); - pdata->pin_dev = in_dev; - if (!in_dev) { - ret = -ENOMEM; - goto err; - } - - in_dev->name = DRIVER_TP; - set_bit(EV_SYN, in_dev->evbit); - set_bit(EV_KEY, in_dev->evbit); - set_bit(EV_ABS, in_dev->evbit); - set_bit(BTN_TOUCH, in_dev->keybit); -#ifdef CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - input_set_abs_params(in_dev, ABS_X, 0, X_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_Y, 0, Y_MAX, 0, 0); -#else - input_set_abs_params(in_dev, ABS_X, 0, Y_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_Y, 0, X_MAX, 0, 0); -#endif - input_set_abs_params(in_dev, ABS_PRESSURE, 0, 1, 0, 0); - input_set_abs_params(in_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); -#ifdef CONFIG_U8500_TSC_MULTITOUCH - set_bit(BTN_2, in_dev->keybit); -#ifdef CONFIG_FB_U8500_MCDE_CHANNELC0_DISPLAY_WVGA_PORTRAIT - input_set_abs_params(in_dev, ABS_HAT0X, 0, X_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_HAT0Y, 0, Y_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, X_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, Y_MAX, 0, 0); -#else - input_set_abs_params(in_dev, ABS_HAT0X, 0, Y_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_HAT0Y, 0, X_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, Y_MAX, 0, 0); - input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, X_MAX, 0, 0); -#endif - input_set_abs_params(in_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0); - input_set_abs_params(in_dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0); -#endif - ret = input_register_device(in_dev); - if (ret) { - dev_err(&i2c->dev, " could not register error \n"); - goto err; - } - dev_dbg(&i2c->dev, "tsc_driver_register done \n"); -err: - return ret; -} -/** - * tsc_config() - configure the touch screen controller - * @pdev_data: pointer to u8500_tsc_data structure - * - * This funtion is used to configure - * the bu21013 controller and returns tsc error. - **/ -static tsc_error tsc_config(struct u8500_tsc_data *pdev_data) -{ - int retval; - - retval = bu21013_tsc_init(pdev_data->client); - if (retval == TSC_OK) { - init_config(pdev_data); - check_board(pdev_data); - if (pdev_data->href_v1_flag == FALSE) { - if ((pdev_data->chip->pirq_en) && (pdev_data->chip->pirq_dis) - && (pdev_data->chip->irq_init)) { - retval = pdev_data->chip->pirq_dis(); - if (retval < 0) { - dev_err(&pdev_data->client->dev, - " irq disable failed \n"); - goto err; - } - retval = pdev_data->chip->pirq_en(); - if (retval < 0) { - dev_err(&pdev_data->client->dev, - " irq en failed \n"); - goto err_init_irq; - } - if \ - (pdev_data->chip->irq_init \ - (tsc_callback, (void *)pdev_data)) { - dev_err(&pdev_data->client->dev, \ - " initiate the callback handler failed \n"); - goto err_init_irq; - } - } - } - retval = get_calib_status(pdev_data->client); - if (retval < 0) { - dev_err(&pdev_data->client->dev, - "u8500_tsc_probe::calibration not done \n"); - goto err_init_irq; - } - return retval; - } -err_init_irq: - pdev_data->chip->pirq_dis(); - pdev_data->chip->irq_exit(); -err: - pdev_data->chip->cs_dis(); - return retval; -} -#ifdef CONFIG_PM -/** - * tsc_suspend() - suspend the touch screen controller - * @client: pointer to i2c client structure - * @mesg: message from power manager - * - * This funtion is used to suspend the - * touch panel controller and returns integer - **/ -static int tsc_suspend(struct i2c_client *client, pm_message_t mesg) -{ - int retval; - struct u8500_tsc_data *tsc_data = i2c_get_clientdata(client); - retval = tsc_data->chip->pirq_dis(); - if (retval < 0) { - dev_err(&client->dev, "tsc_suspend:: irq disable failed \n"); - goto err; - } - retval = tsc_data->chip->irq_exit(); - if (retval < 0) { - dev_err(&client->dev, "tsc_suspend:: remove \ - the callback handler failed \n"); - goto err; - } - return TSC_OK; -err: - kfree(tsc_data); - return retval; -} - -/** - * tsc_resume() - resume the touch screen controller - * @client: pointer to i2c client structure - * - * This funtion is used to resume the touch panel - * controller and returns integer. - **/ -static int tsc_resume(struct i2c_client *client) -{ - int retval; - struct u8500_tsc_data *tsc_data = i2c_get_clientdata(client); - - retval = tsc_config(tsc_data); - if (retval < 0) { - dev_err(&client->dev, "tsc_resume:: error in \ - touch panel configuration\n"); - goto err; - } - return TSC_OK; -err: - kfree(tsc_data); - return retval; -} -#endif -/** - * tp_probe() - Initialze the i2c-client touchscreen driver - * @i2c: i2c client structure pointer - * @id:i2c device id pointer - * - * This funtion uses to Initializes the i2c-client touchscreen - * driver and returns integer. - **/ -static int tp_probe(struct i2c_client *i2c, const struct i2c_device_id *id) -{ - int retval = 0; - struct u8500_tsc_data *tsc_data; - struct tp_device *pdata = i2c->dev.platform_data; - dev_dbg(&i2c->dev, "u8500_tsc_probe:: start\n"); - - tsc_data = kzalloc(sizeof(struct u8500_tsc_data), GFP_KERNEL); - if (!tsc_data) { - dev_err(&i2c->dev, "tp memory allocation failed \n"); - retval = -ENOMEM; - return retval; - } - - if (!pdata) { - dev_err(&i2c->dev, "tp platform data not defined \n"); - retval = -EINVAL; - goto err_alloc; - } - tsc_data->chip = pdata; - tsc_data->client = i2c; - - init_timer(&tsc_data->penirq_timer); - tsc_data->penirq_timer.data = (unsigned long)tsc_data; - tsc_data->penirq_timer.function = tsc_timer_callback; - - INIT_WORK(&tsc_data->m_tp_timer_int_wq, tsc_timer_wq); - INIT_WORK(&tsc_data->m_tp_gpio_int_wq, tp_gpio_int_wq); - i2c_set_clientdata(i2c, tsc_data); - init_waitqueue_head(&tsc_data->touchp_event); - - /* configure the gpio pins */ - if (tsc_data->chip->cs_en) { - retval = tsc_data->chip->cs_en(); - if (retval != TSC_OK) { - dev_err(&tsc_data->client->dev, - "error in tp chip initialization\n"); - goto err; - } - } - - /** configure the touch panel controller */ - retval = tsc_config(tsc_data); - if (retval < 0) { - dev_err(&i2c->dev, "error in tp configuration\n"); - goto err; - } else { - if (tsc_data->href_v1_flag) { - retval = request_irq(tsc_data->chip->irq, tsc_gpio_callback, - IRQF_TRIGGER_FALLING, DRIVER_TP, tsc_data); - if (retval) { - dev_err(&tsc_data->client->dev, - "unable to request for the irq %d\n", tsc_data->chip->irq); - gpio_free(tsc_data->chip->irq); - goto err; - } - } - retval = tsc_driver_register(tsc_data); - if (retval) - goto err_init; - } -#ifdef CONFIG_TOUCHP_TUNING - /* Registering touchp device for sysfs */ - pdev_data = tsc_data; - touchp_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); - if (touchp_kobj == NULL) { - retval = -ENOMEM; - goto err_init; - } - touchp_kobj->ktype = &ktype_touchp; - kobject_init(touchp_kobj, touchp_kobj->ktype); - retval = kobject_set_name(touchp_kobj, "touchp_attribute"); - if (retval) { - kfree(touchp_kobj); - goto err_init; - } - retval = kobject_add(touchp_kobj, NULL, "touchp_attribute"); - if (retval) { - kfree(touchp_kobj); - goto err_init; - } -#endif - dev_dbg(&i2c->dev, "u8500_tsc_probe : done \n"); - return retval; -err_init: - input_free_device(tsc_data->pin_dev); -err: - del_timer_sync(&tsc_data->penirq_timer); -err_alloc: - kfree(tsc_data); - return retval; -} -/** - * tp_remove() - Removes the i2c-client touchscreen driver - * @client: i2c client structure pointer - * - * This funtion uses to remove the i2c-client - * touchscreen driver and returns integer. - **/ -static int __exit tp_remove(struct i2c_client *client) -{ - struct u8500_tsc_data *data = i2c_get_clientdata(client); - del_timer_sync(&data->penirq_timer); - if (data->chip != NULL) { - data->chip->irq_exit(); - data->chip->pirq_dis(); - data->chip->cs_dis(); - } - if (data->href_v1_flag != 0) { - if (data->chip != NULL) - gpio_free(data->chip->irq); - } - input_unregister_device(data->pin_dev); - input_free_device(data->pin_dev); - kfree(data); - i2c_set_clientdata(client, NULL); - return TSC_OK; -} - -static const struct i2c_device_id tp_id[] = { - { DRIVER_TP, 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, tp_id); - -static struct i2c_driver tp_driver = { - .driver = { - .name = DRIVER_TP, - .owner = THIS_MODULE, - }, - .probe = tp_probe, -#ifdef CONFIG_PM - .suspend = tsc_suspend, - .resume = tsc_resume, -#endif - .remove = __exit_p(tp_remove), - .id_table = tp_id, -}; - -/** - * tp_init() - Initialize the paltform touchscreen driver - * - * This funtion uses to initialize the platform - * touchscreen driver and returns integer. - **/ -static int __init tp_init(void){ - return i2c_add_driver(&tp_driver); -} - -/** - * tp_exit() - De-initialize the paltform touchscreen driver - * - * This funtion uses to de-initialize the platform - * touchscreen driver and returns none. - **/ -static void __exit tp_exit(void){ - i2c_del_driver(&tp_driver); -} - -module_init(tp_init); -module_exit(tp_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("NAVEEN KUMAR G"); -MODULE_DESCRIPTION("Touch Screen driver for U8500"); diff --git a/include/linux/bu21013.h b/include/linux/bu21013.h new file mode 100755 index 00000000000..1dcc841ff3f --- /dev/null +++ b/include/linux/bu21013.h @@ -0,0 +1,284 @@ +/* + * Copyright (C) ST-Ericsson SA 2009 + * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson + * License terms:GNU General Public License (GPL) version 2 + */ + +#ifndef _BU21013_H +#define _BU21013_H + +/* + * Touch screen register offsets + */ +#define BU21013_SENSORS_BTN_0_7 0x70 +#define BU21013_SENSORS_BTN_8_15 0x71 +#define BU21013_SENSORS_BTN_16_23 0x72 +#define BU21013_X1_POS_MSB 0x73 +#define BU21013_X1_POS_LSB 0x74 +#define BU21013_Y1_POS_MSB 0x75 +#define BU21013_Y1_POS_LSB 0x76 +#define BU21013_X2_POS_MSB 0x77 +#define BU21013_X2_POS_LSB 0x78 +#define BU21013_Y2_POS_MSB 0x79 +#define BU21013_Y2_POS_LSB 0x7A +#define BU21013_INT_CLR 0xE8 +#define BU21013_INT_MODE 0xE9 +#define BU21013_GAIN 0xEA +#define BU21013_OFFSET_MODE 0xEB +#define BU21013_XY_EDGE 0xEC +#define BU21013_RESET 0xED +#define BU21013_CALIB 0xEE +#define BU21013_REG_DONE 0xEF +#define BU21013_SENSOR_0_7 0xF0 +#define BU21013_SENSOR_8_15 0xF1 +#define BU21013_SENSOR_16_23 0xF2 +#define BU21013_POS_MODE1 0xF3 +#define BU21013_POS_MODE2 0xF4 +#define BU21013_CLK_MODE 0xF5 +#define BU21013_IDLE 0xFA +#define BU21013_FILTER 0xFB +#define BU21013_TH_ON 0xFC +#define BU21013_TH_OFF 0xFD + +/* + * Touch screen register offset values + */ +#define BU21013_INTR_CLEAR 0x01 +#define BU21013_INTR_ENABLE 0x00 +#define BU21013_CALIB_ENABLE 0x01 + +#define BU21013_RESET_ENABLE 0x01 + +/* Sensors Configuration */ +#define BU21013_SENSORS_EN_0_7 0x3F +#define BU21013_SENSORS_EN_8_15 0xFC +#define BU21013_SENSORS_EN_16_23 0x1F + +/* Position mode1 */ +#define BU21013_POS_MODE1_0 0x02 +#define BU21013_POS_MODE1_1 0x04 +#define BU21013_POS_MODE1_2 0x08 + +/* Position mode2 */ +#define BU21013_POS_MODE2_ZERO 0x01 +#define BU21013_POS_MODE2_AVG1 0x02 +#define BU21013_POS_MODE2_AVG2 0x04 +#define BU21013_POS_MODE2_EN_XY 0x08 +#define BU21013_POS_MODE2_EN_RAW 0x10 +#define BU21013_POS_MODE2_MULTI 0x80 + +/* Clock mode */ +#define BU21013_CLK_MODE_DIV 0x01 +#define BU21013_CLK_MODE_EXT 0x02 +#define BU21013_CLK_MODE_CALIB 0x80 + +/* IDLE time */ +#define BU21013_IDLET_0 0x01 +#define BU21013_IDLET_1 0x02 +#define BU21013_IDLET_2 0x04 +#define BU21013_IDLET_3 0x08 +#define BU21013_IDLE_INTERMIT_EN 0x10 + +/* FILTER reg values */ +#define BU21013_DELTA_0_6 0x7F +#define BU21013_FILTER_EN 0x80 + +/* interrupt mode */ +#define BU21013_INT_MODE_LEVEL 0x00 +#define BU21013_INT_MODE_EDGE 0x01 + +/* Gain reg values */ +#define BU21013_GAIN_0 0x01 +#define BU21013_GAIN_1 0x02 +#define BU21013_GAIN_2 0x04 + +/* OFFSET mode */ +#define BU21013_OFFSET_MODE_DEFAULT 0x00 +#define BU21013_OFFSET_MODE_MOVE 0x01 +#define BU21013_OFFSET_MODE_DISABLE 0x02 + +/* Threshold ON values */ +#define BU21013_TH_ON_0 0x01 +#define BU21013_TH_ON_1 0x02 +#define BU21013_TH_ON_2 0x04 +#define BU21013_TH_ON_3 0x08 +#define BU21013_TH_ON_4 0x10 +#define BU21013_TH_ON_5 0x20 +#define BU21013_TH_ON_6 0x40 +#define BU21013_TH_ON_7 0x80 + +#define BU21013_TH_ON_MAX 0xFF + +/* Threshold OFF values */ +#define BU21013_TH_OFF_0 0x01 +#define BU21013_TH_OFF_1 0x02 +#define BU21013_TH_OFF_2 0x04 +#define BU21013_TH_OFF_3 0x08 +#define BU21013_TH_OFF_4 0x10 +#define BU21013_TH_OFF_5 0x20 +#define BU21013_TH_OFF_6 0x40 +#define BU21013_TH_OFF_7 0x80 + +#define BU21013_TH_OFF_MAX 0xFF + +/* FILTER reg values */ +#define BU21013_X_EDGE_0 0x01 +#define BU21013_X_EDGE_1 0x02 +#define BU21013_X_EDGE_2 0x04 +#define BU21013_X_EDGE_3 0x08 +#define BU21013_Y_EDGE_0 0x10 +#define BU21013_Y_EDGE_1 0x20 +#define BU21013_Y_EDGE_2 0x40 +#define BU21013_Y_EDGE_3 0x80 + +#define BU21013_DONE 0x01 + +/** + * struct bu21013_platform_device - Handle the platform data + * @cs_en: pointer to the cs enable function + * @cs_dis: pointer to the cs disable function + * @irq_init: pointer to the irq init function + * @irq_exit: pointer to the irq exit function + * @pirq_en: pointer to the pen irq en function + * @pirq_dis: pointer to the pen irq disable function + * @pirq_read_val: pointer to read the pen irq value function + * @board_check: pointer to the get the board version + * @x_max_res: xmax resolution + * @y_max_res: ymax resolution + * @touch_x_max: touch x max + * @touch_y_max: touch y max + * @tp_cntl: controller id + * @cs_pin: chip select pin + * @irq: irq pin + * @ext_clk_en: external clock flag + * @portrait: portrait mode flag + * @edge_mode: edge mode flag + * This is used to handle the platform data + **/ +struct bu21013_platform_device { + int (*cs_en)(int reset_pin); + int (*cs_dis)(int reset_pin); + int (*irq_init)(void (*callback)(void *parameter), void *p); + int (*irq_exit)(void); + int (*pirq_en) (void); + int (*pirq_dis)(void); + int (*pirq_read_val)(void); + bool (*board_check)(void); + int x_max_res; + int y_max_res; + int touch_x_max; + int touch_y_max; + int tp_cntl; + unsigned int cs_pin; + unsigned int irq; + bool portrait; + bool ext_clk; + bool edge_mode; +}; + +/** + * struct bu21013_touch_point - x and y co-ordinates of touch panel + * @x: x co-ordinate + * @y: y co-ordinate + * This is used to hold the x and y co-ordinates of touch panel + **/ +struct bu21013_touch_point { + signed short x; + signed short y; +}; + +/** + * struct bu21013_gesture_info - hold the gesture of the touch + * @gesture_kind: gesture kind variable + * @pt: arry to touch_point structure + * @dir: direction variable + * @times: touch times + * @speed: speed of the touch + * This is used to hold the gesture of the touch. + **/ +struct bu21013_gesture_info { + signed short gesture_kind; + struct bu21013_touch_point pt[2]; + signed short dir; + signed short times; + signed short speed; +}; + +/** + * struct bu21013_ts_data - touch panel data structure + * @client: pointer to the i2c client + * @chip: pointer to the touch panel controller + * @pin_dev: pointer to the input device structure + * @penirq_timer: variable to the timer list structure + * @touch_en: variable for reporting the co-ordinates to input device. + * @finger1_pressed: variable to indicate the first co-ordinates. + * @finger2_pressed: variable to indicate the first co-ordinates. + * @tp_timer_handler: variable to work structure for timer + * @tp_gpio_handler: variable to work structure for gpio interrupt + * @gesture_info: variable to bu21013_gesture_info structure + * @touch_count: variable to maintain sensors input count + * @touchflag: variable to indicate the touch + * @pre_tap_flag: flag to indicate the pre tap + * @flick_flag: flickering flag + * @touch_continue: to continue the touch flag + * @pre_tap_flag_level: pre tap level flag + * @x1: x1 value + * @y1: y1 vlaue + * @x2: x2 value + * @y2: y2 value + * @pinch_start: pinch start + * @tap_start_point: variable to bu21013_touch_point structure + * @dir_trace: array for data trace + * @dir_idx: id for direction + * @rotate_data: array to maintain the rotate data + * @board_flag: variable to indicate the href v1 board + * @finger2_count: count for finger2 touches + * @intr_pin: interrupt pin value + * @last_press: sensor button pressed + * @prev_press_report: last reported flag + * @touchp_kobj: variable to kernel object for touch panel + * @gain: gain value + * @th_on: threshold on value + * @th_off: threshold off value + * @penup_timer: timeout value + * + * Tocuh panel data structure + */ +struct bu21013_ts_data { + struct i2c_client *client; + struct bu21013_platform_device *chip; + struct input_dev *pin_dev; + struct timer_list penirq_timer; + bool touch_en; + bool finger1_pressed; + bool finger2_pressed; + struct work_struct tp_timer_handler; + struct work_struct tp_gpio_handler; + struct bu21013_gesture_info gesture_info; + signed long touch_count; + bool touchflag; + bool pre_tap_flag; + bool flick_flag; + bool touch_continue; + unsigned char pre_tap_flag_level; + unsigned char pinch_start; + struct bu21013_touch_point tap_start_point; + unsigned char dir_trace[38]; + unsigned char dir_idx; + unsigned char rotate_data[5][5]; + bool board_flag; + u8 finger2_count; + unsigned int intr_pin; + signed short x1; + signed short y1; + signed short x2; + signed short y2; + int last_press; + bool prev_press_report; + struct kobject touchp_kobj; + int gain; + int th_on; + int th_off; + int penup_timer; +}; +#endif |