aboutsummaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorMian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>2010-10-18 17:33:52 +0200
committerMian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>2010-10-23 13:29:34 +0200
commitb96cb51296043b2411036d807090bdefbcdcc4f5 (patch)
tree798c2cc57ebf6ee965080601e573ae34983cc86e /drivers/input
parent1c9a174eaee3c120cc4d9fb205ae7f22c731f5da (diff)
input: update bu21013 touchscreen controller
This patch is based on the following work: input: bu21013 touch screen hangs with Gallery application using BT ST-Ericsson Id: ER 272266 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> input: bu21013: various clean-ups. ST-Ericsson Id: AP 267341 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> bu21013:Improve the touchscreen performance ST-Ericsson Id: ER 266784 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> bu21013: fix to increase the touch screen performance ST-Ericsson Id: ER 264213 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> bu21013:Fix for html docs in dual touch controllers support ST-Ericsson ID: WP 257134 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> bu21013:Coverity fix for Dual touch controllers support ST-Ericsson ID: WP 257134 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> bu21013: Driver for new dual touch controllers support ST-Ericsson ID: WP 257134 Author: Naveen Kumar Gaddipati <naveen.gaddipati@stericsson.com> Moreover, documentation is added to DocBook Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/Kconfig10
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c1070
2 files changed, 711 insertions, 369 deletions
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index 4b1c7f939a9..6c0b8dabc68 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -102,6 +102,7 @@ config TOUCHSCREEN_BITSY
config TOUCHSCREEN_BU21013
tristate "BU21013 based touch panel controllers"
depends on I2C
+ default y
help
Say Y here if you have a bu21013 touchscreen connected to
your system.
@@ -111,6 +112,15 @@ config TOUCHSCREEN_BU21013
To compile this driver as a module, choose M here: the
module will be called bu21013_ts.
+config BU21013_TSC_CNTL1
+ bool "Touch panel1 with BU21013 controller"
+ depends on TOUCHSCREEN_BU21013
+ default y
+
+config BU21013_TSC_CNTL2
+ bool "Touch panel2 with BU21013 controller2"
+ depends on TOUCHSCREEN_BU21013
+
config TOUCHSCREEN_DA9034
tristate "Touchscreen support for Dialog Semiconductor DA9034"
depends on PMIC_DA903X
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index ccde5860256..da9cd0ad15f 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -1,181 +1,338 @@
/*
- * Copyright (C) ST-Ericsson SA 2010
+ * 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/input/bu21013.h>
#include <linux/slab.h>
#define PEN_DOWN_INTR 0
-#define MAX_FINGERS 2
+#define PEN_UP_INTR 1
#define RESET_DELAY 30
-#define PENUP_TIMEOUT (10)
+#define POLLING_DELAY 100
+#define MAX_TOOL_WIDTH 15
+#define MAX_TOUCH_MAJOR 255
+#define MAX_TOUCH_MINOR 15
+#define MAX_PRESSURE 1
+#define PENUP_TIMEOUT (2)
+#define SCALE_FACTOR 1000
#define DELTA_MIN 16
#define MASK_BITS 0x03
#define SHIFT_8 8
#define SHIFT_2 2
#define LENGTH_OF_BUFFER 11
-#define I2C_RETRY_COUNT 5
-
-#define BU21013_SENSORS_BTN_0_7_REG 0x70
-#define BU21013_SENSORS_BTN_8_15_REG 0x71
-#define BU21013_SENSORS_BTN_16_23_REG 0x72
-#define BU21013_X1_POS_MSB_REG 0x73
-#define BU21013_X1_POS_LSB_REG 0x74
-#define BU21013_Y1_POS_MSB_REG 0x75
-#define BU21013_Y1_POS_LSB_REG 0x76
-#define BU21013_X2_POS_MSB_REG 0x77
-#define BU21013_X2_POS_LSB_REG 0x78
-#define BU21013_Y2_POS_MSB_REG 0x79
-#define BU21013_Y2_POS_LSB_REG 0x7A
-#define BU21013_INT_CLR_REG 0xE8
-#define BU21013_INT_MODE_REG 0xE9
-#define BU21013_GAIN_REG 0xEA
-#define BU21013_OFFSET_MODE_REG 0xEB
-#define BU21013_XY_EDGE_REG 0xEC
-#define BU21013_RESET_REG 0xED
-#define BU21013_CALIB_REG 0xEE
-#define BU21013_DONE_REG 0xEF
-#define BU21013_SENSOR_0_7_REG 0xF0
-#define BU21013_SENSOR_8_15_REG 0xF1
-#define BU21013_SENSOR_16_23_REG 0xF2
-#define BU21013_POS_MODE1_REG 0xF3
-#define BU21013_POS_MODE2_REG 0xF4
-#define BU21013_CLK_MODE_REG 0xF5
-#define BU21013_IDLE_REG 0xFA
-#define BU21013_FILTER_REG 0xFB
-#define BU21013_TH_ON_REG 0xFC
-#define BU21013_TH_OFF_REG 0xFD
-
-
-#define BU21013_RESET_ENABLE 0x01
-
-#define BU21013_SENSORS_EN_0_7 0x3F
-#define BU21013_SENSORS_EN_8_15 0xFC
-#define BU21013_SENSORS_EN_16_23 0x1F
-
-#define BU21013_POS_MODE1_0 0x02
-#define BU21013_POS_MODE1_1 0x04
-#define BU21013_POS_MODE1_2 0x08
-
-#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
-
-#define BU21013_CLK_MODE_DIV 0x01
-#define BU21013_CLK_MODE_EXT 0x02
-#define BU21013_CLK_MODE_CALIB 0x80
-
-#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
-
-#define BU21013_DELTA_0_6 0x7F
-#define BU21013_FILTER_EN 0x80
-
-#define BU21013_INT_MODE_LEVEL 0x00
-#define BU21013_INT_MODE_EDGE 0x01
-
-#define BU21013_GAIN_0 0x01
-#define BU21013_GAIN_1 0x02
-#define BU21013_GAIN_2 0x04
-
-#define BU21013_OFFSET_MODE_DEFAULT 0x00
-#define BU21013_OFFSET_MODE_MOVE 0x01
-#define BU21013_OFFSET_MODE_DISABLE 0x02
-
-#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
-
-#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
-
-#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
-#define BU21013_NUMBER_OF_X_SENSORS (6)
-#define BU21013_NUMBER_OF_Y_SENSORS (11)
#define DRIVER_TP "bu21013_tp"
/**
* struct bu21013_ts_data - touch panel data structure
- * @client: pointer to the i2c client
- * @wait: variable to wait_queue_head_t structure
- * @touch_stopped: touch stop flag
- * @chip: pointer to the touch panel controller
- * @in_dev: pointer to the input device structure
+ * @client: pointer to the i2c client
+ * @chip: pointer to the touch panel controller
+ * @in_dev: pointer to the input device structure
+ * @penirq_timer: variable to the timer list structure
+ * @timer_handler: variable to work structure for timer
+ * @gpio_handler: variable to work structure for gpio interrupt
+ * @board_flag: variable to indicate the href v1 board
* @intr_pin: interrupt pin value
+ * @x_pos: x position for two co-ordinates
+ * @y_pos: y position for two co-ordinates
+ * @factor_x: x scale factor
+ * @factor_y: y scale factor
+ * @previous_press_reported: last reported flag
+ * @touchp_kobj: pointer to kernel object for touch panel
+ * @penup_timer: timeout value
*
- * Touch panel device data structure
+ * Touch panel data structure
*/
struct bu21013_ts_data {
struct i2c_client *client;
- wait_queue_head_t wait;
- bool touch_stopped;
- const struct bu21013_platform_device *chip;
+ struct bu21013_platform_device *chip;
struct input_dev *in_dev;
+ struct timer_list penirq_timer;
+ struct work_struct timer_wq_handler;
+ struct work_struct gpio_wq_handler;
unsigned int intr_pin;
+ signed short x_pos[2];
+ signed short y_pos[2];
+ int factor_x;
+ int factor_y;
+ bool previous_press_reported;
+ struct kobject *touchp_kobj;
+ int penup_timer;
};
+/* Global variable to maintain the sys data for two controllers */
+struct bu21013_ts_data *tp1_sys_data, *tp2_sys_data;
+
+static int bu21013_init_chip(struct bu21013_ts_data *data);
+
+/*
+ * sysfs is used to change the touchpanel1 parameters
+ * and also enable the external clock dynamically
+ */
+static ssize_t touchp1_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ u8 timeout;
+ u8 sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ timeout = tp1_sys_data->penup_timer;
+ sprintf(buf, "%d\n", timeout);
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ sys_ext_clock = tp1_sys_data->chip->ext_clk;
+ sprintf(buf, "%d\n", sys_ext_clock);
+ }
+ return strlen(buf);
+}
+static ssize_t touchp1_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ int ret = 0;
+ int timeout;
+ int sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ ret = sscanf(buf, "%d", &timeout);
+ if (ret == 1)
+ tp1_sys_data->penup_timer = timeout;
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ ret = sscanf(buf, "%d", &sys_ext_clock);
+ if ((ret == 1) &&
+ (tp1_sys_data->chip->ext_clk != sys_ext_clock)) {
+ tp1_sys_data->chip->ext_clk = sys_ext_clock;
+ bu21013_init_chip(tp1_sys_data);
+ }
+ }
+ return ret == 1 ? len : -EINVAL;
+}
+
+/*
+ * sysfs is used to change the touchpanel2 parameters
+ * and also enable the external clock dynamically
+ */
+static ssize_t touchp2_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ u8 timeout;
+ u8 sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ timeout = tp2_sys_data->penup_timer;
+ sprintf(buf, "%d\n", timeout);
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ sys_ext_clock = tp2_sys_data->chip->ext_clk;
+ sprintf(buf, "%d\n", sys_ext_clock);
+ }
+ return strlen(buf);
+}
+static ssize_t touchp2_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ int ret = 0;
+ int timeout;
+ int sys_ext_clock;
+
+ if (strcmp(attr->name, "timeout_value") == 0) {
+ ret = sscanf(buf, "%d", &timeout);
+ if (ret == 1)
+ tp2_sys_data->penup_timer = timeout;
+ } else if (strcmp(attr->name, "ext_clk") == 0) {
+ ret = sscanf(buf, "%d", &sys_ext_clock);
+ if ((ret == 1) &&
+ (tp2_sys_data->chip->ext_clk != sys_ext_clock)) {
+ tp2_sys_data->chip->ext_clk = sys_ext_clock;
+ bu21013_init_chip(tp2_sys_data);
+ }
+ }
+ return ret == 1 ? len : -EINVAL;
+}
+
+
+static struct attribute touchp_timeout = {.name = "timeout_value",
+ .mode = 0666};
+static struct attribute touchp_ext_clk = {.name = "ext_clk", .mode = 0666};
+
+static struct attribute *touchp_attribute[] = {
+ &touchp_timeout,
+ &touchp_ext_clk,
+ NULL
+};
+
+static const struct sysfs_ops touchp1_sysfs_ops = {
+ .show = touchp1_attr_show,
+ .store = touchp1_attr_store,
+};
+
+static const struct sysfs_ops touchp2_sysfs_ops = {
+ .show = touchp2_attr_show,
+ .store = touchp2_attr_store,
+};
+
+static struct kobj_type ktype_touchp1 = {
+ .sysfs_ops = &touchp1_sysfs_ops,
+ .default_attrs = touchp_attribute,
+};
+static struct kobj_type ktype_touchp2 = {
+ .sysfs_ops = &touchp2_sysfs_ops,
+ .default_attrs = touchp_attribute,
+};
+
+/*
+ * bu21013_get_number_of_bits() - count the bits in given value
+ * @val: read bits from this value
+ * @range: maximum number of bits
+ *
+ * Read the number of bits from the given value
+ * and returns integer
+ */
+static inline int bu21013_get_number_of_bits(unsigned int val, int range)
+{
+ int i;
+ int num = 0;
+ unsigned int mask = 1;
+
+ for (i = 0; i < range; i++) {
+ if (val & mask)
+ num++;
+ mask = mask << 1;
+ }
+ return num;
+}
/**
- * bu21013_read_block_data(): read the touch co-ordinates
- * @data: bu21013_ts_data structure pointer
- * @buf: byte pointer
+ * bu21013_report_pen_down() - reports the pen down event
+ * @data:bu21013_ts_data structure pointer
+ * @count:touch count
*
- * Read the touch co-ordinates using i2c read block into buffer
- * and returns integer.
+ * This function used to report the pen down interrupt to
+ * input subsystem and returns none
*/
-static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
+static void bu21013_report_pen_down(struct bu21013_ts_data *data, int count)
{
- int ret, i;
+ short pt0x;
+ short pt0y;
+ short pt1x;
+ short pt1y;
+ if (data->chip->portrait) {
+ pt0x = data->x_pos[0];
+ pt0y = data->y_pos[0];
+ pt1x = data->x_pos[1];
+ pt1y = data->y_pos[1];
+ } else {
+ pt0x = data->y_pos[0];
+ pt0y = data->x_pos[0];
+ pt1x = data->y_pos[1];
+ pt1y = data->x_pos[1];
+ }
- for (i = 0; i < I2C_RETRY_COUNT; i++) {
- ret = i2c_smbus_read_i2c_block_data
- (data->client, BU21013_SENSORS_BTN_0_7_REG,
- LENGTH_OF_BUFFER, buf);
- if (ret == LENGTH_OF_BUFFER)
- return 0;
+ input_report_abs(data->in_dev, ABS_X, pt0x);
+ input_report_abs(data->in_dev, ABS_Y, pt0y);
+ input_report_abs(data->in_dev, ABS_PRESSURE, 1);
+ input_report_abs(data->in_dev, ABS_TOOL_WIDTH, 1);
+ input_report_key(data->in_dev, BTN_TOUCH, 1);
+
+ if (count > 1) {
+ input_report_key(data->in_dev, BTN_2, 1);
+ input_report_abs(data->in_dev, ABS_HAT0X, pt1x);
+ input_report_abs(data->in_dev, ABS_HAT0Y, pt1y);
+ }
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MINOR, 1);
+ input_report_key(data->in_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_X, pt0x);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_Y, pt0y);
+ input_mt_sync(data->in_dev);
+
+ if (count > 1) {
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MAJOR, 1);
+ input_report_key(data->in_dev, ABS_MT_WIDTH_MAJOR, 1);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_X, pt1x);
+ input_report_abs(data->in_dev, ABS_MT_POSITION_Y, pt1y);
+ input_mt_sync(data->in_dev);
+ }
+ input_sync(data->in_dev);
+ data->previous_press_reported = count;
+}
+/**
+ * bu21013_report_pen_up() - reports the pen up event
+ * @data:bu21013_ts_data structure pointer
+ *
+ * This function used to report the pen up interrupt
+ * to input subsystem and returns none
+ */
+static void bu21013_report_pen_up(struct bu21013_ts_data *data)
+{
+ input_report_abs(data->in_dev, ABS_PRESSURE, 0);
+ input_report_abs(data->in_dev, ABS_TOOL_WIDTH, 0);
+ input_report_key(data->in_dev, BTN_TOUCH, 0);
+ input_report_key(data->in_dev, BTN_2, 0);
+ input_report_abs(data->in_dev, ABS_MT_TOUCH_MAJOR, 0);
+ input_report_key(data->in_dev, ABS_MT_WIDTH_MAJOR, 0);
+ input_mt_sync(data->in_dev);
+ input_sync(data->in_dev);
+ data->previous_press_reported = 0;
+}
+/**
+ * bu21013_touch_calc() - calculates the co-ordinates delta
+ * @data: bu21013_ts_data structure pointer
+ * @x: x position
+ * @y: y position
+ * @count: touch count
+ *
+ * This function calculates the exact co-ordinates with respect to
+ * display resolution and returns none
+ */
+static void bu21013_touch_calc
+ (struct bu21013_ts_data *data, int x, int y, int count)
+{
+ data->x_pos[count] = x * data->factor_x / SCALE_FACTOR;
+ data->y_pos[count] = y * data->factor_y / SCALE_FACTOR;
+ if ((data->chip->portrait) && (data->chip->x_flip))
+ data->x_pos[count] =
+ data->chip->x_max_res - data->x_pos[count];
+ if ((data->chip->portrait) && (data->chip->y_flip))
+ data->y_pos[count] =
+ data->chip->y_max_res - data->y_pos[count];
+}
+/**
+ * bu21013_verify_delta() - verify the co-ordinates delta
+ * @x1: x1 position
+ * @y1: y1 position
+ * @x2: x2 position
+ * @y2: y2 position
+ *
+ * This function verifies the delta of the
+ * co-ordinates and returns boolean.
+ */
+static bool bu21013_verify_delta(int x1, int y1, int x2, int y2)
+{
+ int delta_x, delta_y;
+ if ((x1 != 0) && (y1 != 0)) {
+ delta_x = x2 - x1;
+ if (x1 > x2)
+ delta_x = x1 - x2;
+ delta_y = y2 - y1;
+ if (y1 > y2)
+ delta_y = y1 - y2;
+ if ((delta_x < DELTA_MIN) || (delta_y < DELTA_MIN))
+ return false;
}
- return -EINVAL;
+ return true;
}
/**
* bu21013_do_touch_report(): Get the touch co-ordinates
- * @data: bu21013_ts_data structure pointer
+ * @data:bu21013_ts_data structure pointer
*
* Get the touch co-ordinates from touch sensor registers and writes
* into device structure and returns integer.
@@ -183,91 +340,194 @@ static int bu21013_read_block_data(struct bu21013_ts_data *data, u8 *buf)
static int bu21013_do_touch_report(struct bu21013_ts_data *data)
{
u8 buf[LENGTH_OF_BUFFER];
- unsigned int pos_x[2], pos_y[2];
- bool has_x_sensors, has_y_sensors;
+ int finger1_valid = 0;
+ int finger2_valid = 0;
+ unsigned int finger1_pos_x;
+ unsigned int finger1_pos_y;
+ unsigned int finger2_pos_x;
+ unsigned int finger2_pos_y;
+ int number_of_active_x_sensors;
+ int number_of_active_y_sensors;
+ int total_number_of_active_sensors;
int finger_down_count = 0;
- int i;
-
- if (data == NULL)
- return -EINVAL;
+ int ret = 0;
+ int retry_count = 5;
- if (bu21013_read_block_data(data, buf) < 0)
+ if (data->client == NULL)
return -EINVAL;
- has_x_sensors = hweight32(buf[0] & BU21013_SENSORS_EN_0_7);
- has_y_sensors = hweight32(((buf[1] & BU21013_SENSORS_EN_8_15) |
- ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2);
- if (!has_x_sensors || !has_y_sensors)
+ do {
+ ret = i2c_smbus_read_i2c_block_data
+ (data->client, BU21013_SENSORS_BTN_0_7_REG,
+ LENGTH_OF_BUFFER, buf);
+ retry_count--;
+ if ((ret < LENGTH_OF_BUFFER) && (!retry_count))
+ return -EINVAL;
+ } while (ret < LENGTH_OF_BUFFER);
+
+ number_of_active_x_sensors =
+ bu21013_get_number_of_bits((buf[0] & BU21013_SENSORS_EN_0_7),
+ BU21013_NUMBER_OF_X_SENSORS);
+
+ number_of_active_y_sensors = bu21013_get_number_of_bits
+ ((((buf[1] & BU21013_SENSORS_EN_8_15) |
+ ((buf[2] & BU21013_SENSORS_EN_16_23) << SHIFT_8)) >> SHIFT_2),
+ BU21013_NUMBER_OF_Y_SENSORS);
+
+ if (((number_of_active_x_sensors != 0) &&
+ (number_of_active_y_sensors == 0)) ||
+ ((number_of_active_x_sensors == 0) &&
+ (number_of_active_y_sensors != 0)))
return 0;
- for (i = 0; i < MAX_FINGERS; i++) {
- const u8 *p = &buf[4 * i + 3];
- unsigned int x = p[0] << SHIFT_2 | (p[1] & MASK_BITS);
- unsigned int y = p[2] << SHIFT_2 | (p[3] & MASK_BITS);
- if (x == 0 || y == 0)
- continue;
- pos_x[finger_down_count] = x;
- pos_y[finger_down_count] = y;
- finger_down_count++;
- }
-
- if (finger_down_count) {
- if (finger_down_count == 2 &&
- (abs(pos_x[0] - pos_x[1]) < DELTA_MIN ||
- abs(pos_y[0] - pos_y[1]) < DELTA_MIN)) {
- return 0;
+ total_number_of_active_sensors =
+ number_of_active_x_sensors + number_of_active_y_sensors;
+
+ finger1_pos_x = buf[3] << SHIFT_2 | (buf[4] & MASK_BITS);
+ finger1_pos_y = buf[5] << SHIFT_2 | (buf[6] & MASK_BITS);
+ finger2_pos_x = buf[7] << SHIFT_2 | (buf[8] & MASK_BITS);
+ finger2_pos_y = buf[9] << SHIFT_2 | (buf[10] & MASK_BITS);
+
+ if (total_number_of_active_sensors) {
+ if ((finger2_pos_x != 0) && (finger2_pos_y != 0)) {
+ if ((finger1_pos_x == 0) || (finger1_pos_y == 0))
+ return 0;
+ ret = bu21013_verify_delta(finger1_pos_x,
+ finger1_pos_y, finger2_pos_x, finger2_pos_y);
+ if (!ret)
+ total_number_of_active_sensors = 0;
}
+ }
- for (i = 0; i < finger_down_count; i++) {
- if (data->chip->x_flip)
- pos_x[i] = data->chip->touch_x_max - pos_x[i];
- if (data->chip->y_flip)
- pos_y[i] = data->chip->touch_y_max - pos_y[i];
-
- input_report_abs(data->in_dev,
- ABS_MT_POSITION_X, pos_x[i]);
- input_report_abs(data->in_dev,
- ABS_MT_POSITION_Y, pos_y[i]);
- input_mt_sync(data->in_dev);
+ if (total_number_of_active_sensors) {
+ finger1_valid = 1;
+ if ((finger1_pos_x == 0) || (finger1_pos_y == 0) ||
+ (finger1_pos_x >= data->chip->touch_x_max) ||
+ (finger1_pos_y >= data->chip->touch_y_max))
+ finger1_valid = 0;
+ finger2_valid = 1;
+ if ((finger2_pos_x == 0) || (finger2_pos_y == 0) ||
+ (finger2_pos_x >= data->chip->touch_x_max) ||
+ (finger2_pos_y >= data->chip->touch_y_max))
+ finger2_valid = 0;
+ if ((finger1_valid == 0) && (finger2_valid == 0))
+ return 0;
+ if (finger1_valid) {
+ bu21013_touch_calc(data, finger1_pos_x,
+ finger1_pos_y, finger_down_count);
+ finger_down_count++;
}
- } else
- input_mt_sync(data->in_dev);
+ if (finger2_valid) {
+ bu21013_touch_calc(data, finger2_pos_x,
+ finger2_pos_y, finger_down_count);
+ finger_down_count++;
+ }
+ }
- input_sync(data->in_dev);
+ if (finger_down_count > 0)
+ bu21013_report_pen_down(data, finger_down_count);
+ else {
+ if (data->previous_press_reported)
+ bu21013_report_pen_up(data);
+ }
- return 0;
+ return ret;
+}
+
+/**
+ * bu21013_timer_start() - start 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));
}
+
/**
- * bu21013_gpio_irq() - gpio thread function for touch interrupt
- * @irq: irq value
- * @device_data: void pointer
+ * bu21013_timer_wq() - work queue for timer handler
+ * @work:work_struct structure pointer
*
- * This gpio thread function for touch interrupt
- * and returns irqreturn_t.
+ * This timer work queue used during polling of the co-ordinates
+ * for every timeout period and returns none
*/
-static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+static void bu21013_timer_wq(struct work_struct *work)
{
- struct bu21013_ts_data *data = device_data;
+ struct bu21013_ts_data *data =
+ container_of(work, struct bu21013_ts_data, timer_wq_handler);
+ struct task_struct *tsk = current;
struct i2c_client *i2c = data->client;
int retval;
- do {
- retval = bu21013_do_touch_report(data);
- if (retval < 0) {
- dev_err(&i2c->dev, "bu21013_do_touch_report failed\n");
- return IRQ_NONE;
- }
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+ retval = bu21013_do_touch_report(data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "get co-ordinates failed\n");
+ return;
+ }
+ data->intr_pin = data->chip->irq_read_val();
+ if (data->intr_pin == PEN_DOWN_INTR)
+ bu21013_timer_start(data);
+ else
+ enable_irq(data->chip->irq);
+}
- data->intr_pin = data->chip->irq_read_val();
- if (data->intr_pin == PEN_DOWN_INTR)
- wait_event_timeout(data->wait, data->touch_stopped,
- msecs_to_jiffies(2));
- } while (!data->intr_pin && !data->touch_stopped);
+/**
+ * bu21013_gpio_int_wq() - work queue for gpio interrupt handler
+ * @work:work_struct structure pointer
+ *
+ * This gpio work queue used to get the co-ordinates
+ * of the pen down interrupt and returns none
+ */
+static void bu21013_gpio_int_wq(struct work_struct *work)
+{
+ struct bu21013_ts_data *data =
+ container_of(work, struct bu21013_ts_data, gpio_wq_handler);
+ struct i2c_client *i2c = data->client;
+ struct task_struct *tsk = current;
+ int retval;
+ set_task_state(tsk, TASK_INTERRUPTIBLE);
+ disable_irq(data->chip->irq);
+ retval = bu21013_do_touch_report(data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "get co-ordinates failed\n");
+ return;
+ }
+ bu21013_timer_start(data);
+}
+
+/**
+ * bu21013_gpio_irq() - gpio callback handler for touch interrupt
+ * @irq: irq value
+ * @device_data:void pointer
+ *
+ * This gpio callback handler for gpio interrupt
+ * and assigns the task and returns irqreturn_t.
+ */
+static irqreturn_t bu21013_gpio_irq(int irq, void *device_data)
+{
+ struct bu21013_ts_data *data = (struct bu21013_ts_data *)device_data;
+ schedule_work(&data->gpio_wq_handler);
return IRQ_HANDLED;
}
/**
+ * bu21013_timer_callback() - callback handler for timer
+ * @dev_data:touch screen data
+ *
+ * This timer callback handler used to schedule the work during
+ * polling of pen down interrupts and returns none
+ */
+static void bu21013_timer_callback(unsigned long dev_data)
+{
+ struct bu21013_ts_data *data = (struct bu21013_ts_data *)dev_data;
+ schedule_work(&data->timer_wq_handler);
+}
+
+/**
* bu21013_init_chip() - power on sequence for the bu21013 controller
* @data: device structure pointer
*
@@ -283,47 +543,42 @@ static int bu21013_init_chip(struct bu21013_ts_data *data)
BU21013_RESET_ENABLE);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_RESET reg write failed\n");
- return retval;
+ goto err;
}
- msleep(RESET_DELAY);
+ mdelay(RESET_DELAY);
retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_0_7_REG,
BU21013_SENSORS_EN_0_7);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_SENSOR_0_7 reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_8_15_REG,
- BU21013_SENSORS_EN_8_15);
+ BU21013_SENSORS_EN_8_15);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_SENSOR_8_15 reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_SENSOR_16_23_REG,
- BU21013_SENSORS_EN_16_23);
+ BU21013_SENSORS_EN_16_23);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_SENSOR_16_23 reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE1_REG,
(BU21013_POS_MODE1_0 | BU21013_POS_MODE1_1));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_POS_MODE1 reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_POS_MODE2_REG,
(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, "BU21013_POS_MODE2 reg write failed\n");
- return retval;
+ goto err;
}
-
if (data->chip->ext_clk)
retval = i2c_smbus_write_byte_data(i2c, BU21013_CLK_MODE_REG,
(BU21013_CLK_MODE_EXT | BU21013_CLK_MODE_CALIB));
@@ -332,192 +587,322 @@ static int bu21013_init_chip(struct bu21013_ts_data *data)
(BU21013_CLK_MODE_DIV | BU21013_CLK_MODE_CALIB));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_CLK_MODE reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_IDLE_REG,
(BU21013_IDLET_0 | BU21013_IDLE_INTERMIT_EN));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_IDLE reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_INT_MODE_REG,
BU21013_INT_MODE_LEVEL);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_INT_MODE reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_FILTER_REG,
(BU21013_DELTA_0_6 |
BU21013_FILTER_EN));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_FILTER reg write failed\n");
- return retval;
+ goto err;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_ON_REG,
- BU21013_TH_ON_5);
+ (BU21013_TH_ON_3 | BU21013_TH_ON_4));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_TH_ON reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_TH_OFF_REG,
- BU21013_TH_OFF_4 || BU21013_TH_OFF_3);
+ BU21013_TH_OFF_4);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_TH_OFF reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_GAIN_REG,
(BU21013_GAIN_0 | BU21013_GAIN_1));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_GAIN reg write failed\n");
- return retval;
+ goto err;
}
retval = i2c_smbus_write_byte_data(i2c, BU21013_OFFSET_MODE_REG,
BU21013_OFFSET_MODE_DEFAULT);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_OFFSET_MODE reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_XY_EDGE_REG,
- (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
+ (BU21013_X_EDGE_0 | BU21013_X_EDGE_2 |
BU21013_Y_EDGE_1 | BU21013_Y_EDGE_3));
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_XY_EDGE reg write failed\n");
- return retval;
+ goto err;
}
-
retval = i2c_smbus_write_byte_data(i2c, BU21013_DONE_REG,
BU21013_DONE);
if (retval < 0) {
dev_err(&i2c->dev, "BU21013_REG_DONE reg write failed\n");
- return retval;
+ goto err;
}
+ data->x_pos[0] = 0;
+ data->x_pos[1] = 0;
+ data->y_pos[0] = 0;
+ data->y_pos[1] = 0;
+ data->previous_press_reported = 0;
+
+ data->factor_x = (data->chip->x_max_res * SCALE_FACTOR /
+ data->chip->touch_x_max);
+ data->factor_y = (data->chip->y_max_res * SCALE_FACTOR /
+ data->chip->touch_y_max);
+err:
+ return retval;
+}
+
+#ifdef CONFIG_PM
+/**
+ * bu21013_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_suspend(struct i2c_client *client, pm_message_t mesg)
+{
+ struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+ if (device_may_wakeup(&client->dev))
+ enable_irq(bu21013_data->chip->irq);
+ else
+ disable_irq(bu21013_data->chip->irq);
+
return 0;
}
/**
- * bu21013_free_irq() - frees IRQ registered for touchscreen
- * @bu21013_data: device structure pointer
+ * bu21013_resume() - resume the touch screen controller
+ * @client: pointer to i2c client structure
*
- * This function signals interrupt thread to stop processing and
- * frees interrupt.
+ * This funtion is used to resume the touch panel
+ * controller and returns integer.
*/
-static void bu21013_free_irq(struct bu21013_ts_data *bu21013_data)
+static int bu21013_resume(struct i2c_client *client)
{
- bu21013_data->touch_stopped = true;
- wake_up(&bu21013_data->wait);
- free_irq(bu21013_data->chip->irq, bu21013_data);
+ int retval;
+ struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+
+ retval = bu21013_init_chip(bu21013_data);
+ if (retval < 0) {
+ dev_err(&client->dev, "tsc config failed\n");
+ goto err;
+ }
+
+ if (device_may_wakeup(&client->dev))
+ disable_irq(bu21013_data->chip->irq);
+ else
+ enable_irq(bu21013_data->chip->irq);
+
+ return 0;
+err:
+ kfree(bu21013_data);
+ return retval;
}
+#endif
/**
- * bu21013_probe() - initializes the i2c-client touchscreen driver
- * @client: i2c client structure pointer
- * @id: i2c device id pointer
+ * bu21013_sysfs() - sys fs parameters
+ * @tp_kobj: kernel object structure pointer
+ *
+ * This function uses to initialize the sysfs for touch panel
+ * based on the controller number
+ */
+int bu21013_sysfs(struct kobject *tp_kobj , int ctrl)
+{
+ int retval = 0;
+
+ tp_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+ if (tp_kobj == NULL) {
+ retval = -ENOMEM;
+ goto err;
+ }
+ if (ctrl == 1)
+ tp_kobj->ktype = &ktype_touchp1;
+ else if (ctrl == 2)
+ tp_kobj->ktype = &ktype_touchp2;
+ kobject_init(tp_kobj, tp_kobj->ktype);
+ if (ctrl == 1)
+ retval = kobject_set_name(tp_kobj, "touchp1");
+ else if (ctrl == 2)
+ retval = kobject_set_name(tp_kobj, "touchp2");
+ if (retval) {
+ kfree(tp_kobj);
+ goto err;
+ }
+ if (ctrl == 1)
+ retval = kobject_add(tp_kobj, NULL, "touchp1");
+ else if (ctrl == 2)
+ retval = kobject_add(tp_kobj, NULL, "touchp2");
+ if (retval) {
+ kfree(tp_kobj);
+ goto err;
+ }
+ return 0;
+err:
+ return retval;
+}
+/**
+ * bu21013_probe() - initialzes the i2c-client touchscreen driver
+ * @i2c: i2c client structure pointer
+ * @id:i2c device id pointer
*
* This function used to initializes the i2c-client touchscreen
* driver and returns integer.
*/
-static int __devinit bu21013_probe(struct i2c_client *client,
+static int bu21013_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
+ int retval;
struct bu21013_ts_data *bu21013_data;
struct input_dev *in_dev;
- const struct bu21013_platform_device *pdata =
- client->dev.platform_data;
- int error;
+ short x_max;
+ short y_max;
+ struct bu21013_platform_device *pdata = i2c->dev.platform_data;
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev, "i2c smbus byte data not supported\n");
- return -EIO;
+ if (!pdata) {
+ dev_err(&i2c->dev, "platform data not defined\n");
+ retval = -EINVAL;
+ return retval;
}
- if (!pdata) {
- dev_err(&client->dev, "platform data not defined\n");
- return -EINVAL;
+ if (!pdata->tp_cntl) {
+ dev_err(&i2c->dev, "controller is not enabled\n");
+ retval = -EINVAL;
+ return retval;
}
bu21013_data = kzalloc(sizeof(struct bu21013_ts_data), GFP_KERNEL);
- in_dev = input_allocate_device();
- if (!bu21013_data || !in_dev) {
- dev_err(&client->dev, "device memory alloc failed\n");
- error = -ENOMEM;
- goto err_free_mem;
+ if (!bu21013_data) {
+ dev_err(&i2c->dev, "device memory alloc failed\n");
+ retval = -ENOMEM;
+ return retval;
}
+ /* allocate input device */
+ in_dev = input_allocate_device();
+ if (!in_dev) {
+ dev_err(&i2c->dev, "input device memory alloc failed\n");
+ retval = -ENOMEM;
+ goto err_alloc;
+ }
bu21013_data->in_dev = in_dev;
+
bu21013_data->chip = pdata;
- bu21013_data->client = client;
- bu21013_data->touch_stopped = false;
- init_waitqueue_head(&bu21013_data->wait);
+ bu21013_data->client = i2c;
+ bu21013_data->penup_timer = PENUP_TIMEOUT;
+
+ if (bu21013_data->chip->portrait) {
+ x_max = pdata->x_max_res;
+ y_max = pdata->y_max_res;
+ } else {
+ x_max = pdata->y_max_res;
+ y_max = pdata->x_max_res;
+ }
+
+ INIT_WORK(&bu21013_data->timer_wq_handler, bu21013_timer_wq);
+ INIT_WORK(&bu21013_data->gpio_wq_handler, bu21013_gpio_int_wq);
+
+ init_timer(&bu21013_data->penirq_timer);
+ bu21013_data->penirq_timer.data = (unsigned long)bu21013_data;
+ bu21013_data->penirq_timer.function = bu21013_timer_callback;
+ i2c_set_clientdata(i2c, bu21013_data);
/* configure the gpio pins */
if (pdata->cs_en) {
- error = pdata->cs_en(pdata->cs_pin);
- if (error < 0) {
- dev_err(&client->dev, "chip init failed\n");
- goto err_free_mem;
+ retval = pdata->cs_en(pdata->cs_pin);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "chip init failed\n");
+ goto err_init_cs;
}
}
/* configure the touch panel controller */
- error = bu21013_init_chip(bu21013_data);
- if (error) {
- dev_err(&client->dev, "error in bu21013 config\n");
- goto err_cs_disable;
+ retval = bu21013_init_chip(bu21013_data);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "error in bu21013 config\n");
+ goto err_init_config;
}
/* register the device to input subsystem */
in_dev->name = DRIVER_TP;
- in_dev->id.bustype = BUS_I2C;
- in_dev->dev.parent = &client->dev;
-
- __set_bit(EV_SYN, in_dev->evbit);
- __set_bit(EV_KEY, in_dev->evbit);
- __set_bit(EV_ABS, in_dev->evbit);
-
- input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0,
- pdata->x_max_res, 0, 0);
- input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0,
- pdata->y_max_res, 0, 0);
- input_set_drvdata(in_dev, bu21013_data);
-
- error = request_threaded_irq(pdata->irq, NULL, bu21013_gpio_irq,
- IRQF_TRIGGER_FALLING | IRQF_SHARED,
- DRIVER_TP, bu21013_data);
- if (error) {
- dev_err(&client->dev, "request irq %d failed\n", pdata->irq);
- goto err_cs_disable;
- }
-
- error = input_register_device(in_dev);
- if (error) {
- dev_err(&client->dev, "failed to register input device\n");
- goto err_free_irq;
+ 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_TOUCH_MINOR, 0, MAX_TOUCH_MINOR, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(in_dev, ABS_MT_WIDTH_MAJOR, 0, MAX_TOOL_WIDTH,
+ 0, 0);
+ retval = input_register_device(in_dev);
+ if (retval)
+ goto err_input_register;
+
+ retval = request_irq(pdata->irq, bu21013_gpio_irq,
+ (IRQF_TRIGGER_FALLING | IRQF_SHARED),
+ DRIVER_TP, bu21013_data);
+ if (retval) {
+ dev_err(&i2c->dev, "request irq %d failed\n", pdata->irq);
+ goto err_init_irq;
}
- device_init_wakeup(&client->dev, pdata->wakeup);
- i2c_set_clientdata(client, bu21013_data);
-
- return 0;
-
-err_free_irq:
- bu21013_free_irq(bu21013_data);
-err_cs_disable:
+ retval = bu21013_sysfs(bu21013_data->touchp_kobj, pdata->tp_cntl);
+ if (retval)
+ goto err_init_sys;
+ /*
+ * to maintain the each device data, we are storing
+ * in global varaiables for tuning the touch screen
+ */
+ if (pdata->tp_cntl == 1)
+ tp1_sys_data = bu21013_data;
+ else if (pdata->tp_cntl == 2)
+ tp2_sys_data = bu21013_data;
+
+ dev_dbg(&i2c->dev, "init done");
+
+ return retval;
+err_init_sys:
+ free_irq(pdata->irq, bu21013_data);
+err_init_irq:
+ input_unregister_device(bu21013_data->in_dev);
+ bu21013_data->in_dev = NULL;
+err_input_register:
+err_init_config:
pdata->cs_dis(pdata->cs_pin);
-err_free_mem:
+err_init_cs:
+ del_timer_sync(&bu21013_data->penirq_timer);
+ cancel_work_sync(&bu21013_data->timer_wq_handler);
+ cancel_work_sync(&bu21013_data->gpio_wq_handler);
input_free_device(bu21013_data->in_dev);
+err_alloc:
kfree(bu21013_data);
-
- return error;
+ return retval;
}
/**
* bu21013_remove() - removes the i2c-client touchscreen driver
@@ -528,79 +913,25 @@ err_free_mem:
*/
static int __devexit bu21013_remove(struct i2c_client *client)
{
- struct bu21013_ts_data *bu21013_data = i2c_get_clientdata(client);
+ struct bu21013_ts_data *data = i2c_get_clientdata(client);
- bu21013_free_irq(bu21013_data);
+ del_timer_sync(&data->penirq_timer);
+ cancel_work_sync(&data->timer_wq_handler);
+ cancel_work_sync(&data->gpio_wq_handler);
- bu21013_data->chip->cs_dis(bu21013_data->chip->cs_pin);
-
- input_unregister_device(bu21013_data->in_dev);
- kfree(bu21013_data);
-
- device_init_wakeup(&client->dev, false);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-/**
- * bu21013_suspend() - suspend the touch screen controller
- * @dev: pointer to device structure
- *
- * This function is used to suspend the
- * touch panel controller and returns integer
- */
-static int bu21013_suspend(struct device *dev)
-{
- struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
- struct i2c_client *client = bu21013_data->client;
-
- bu21013_data->touch_stopped = true;
- if (device_may_wakeup(&client->dev))
- enable_irq_wake(bu21013_data->chip->irq);
- else
- disable_irq(bu21013_data->chip->irq);
-
- return 0;
-}
-
-/**
- * bu21013_resume() - resume the touch screen controller
- * @dev: pointer to device structure
- *
- * This function is used to resume the touch panel
- * controller and returns integer.
- */
-static int bu21013_resume(struct device *dev)
-{
- struct bu21013_ts_data *bu21013_data = dev_get_drvdata(dev);
- struct i2c_client *client = bu21013_data->client;
- int retval;
-
- retval = bu21013_init_chip(bu21013_data);
- if (retval < 0) {
- dev_err(&client->dev, "bu21013 controller config failed\n");
- return retval;
+ if (data->chip != NULL) {
+ free_irq(data->chip->irq, data);
+ data->chip->cs_dis(data->chip->cs_pin);
}
-
- bu21013_data->touch_stopped = false;
-
- if (device_may_wakeup(&client->dev))
- disable_irq_wake(bu21013_data->chip->irq);
- else
- enable_irq(bu21013_data->chip->irq);
+ input_unregister_device(data->in_dev);
+ kfree(data);
return 0;
}
-static const struct dev_pm_ops bu21013_dev_pm_ops = {
- .suspend = bu21013_suspend,
- .resume = bu21013_resume,
-};
-#endif
-
static const struct i2c_device_id bu21013_id[] = {
{ DRIVER_TP, 0 },
+ { DRIVER_TP, 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, bu21013_id);
@@ -609,11 +940,12 @@ static struct i2c_driver bu21013_driver = {
.driver = {
.name = DRIVER_TP,
.owner = THIS_MODULE,
-#ifdef CONFIG_PM
- .pm = &bu21013_dev_pm_ops,
-#endif
},
.probe = bu21013_probe,
+#ifdef CONFIG_PM
+ .suspend = bu21013_suspend,
+ .resume = bu21013_resume,
+#endif
.remove = __devexit_p(bu21013_remove),
.id_table = bu21013_id,
};
@@ -644,5 +976,5 @@ module_init(bu21013_init);
module_exit(bu21013_exit);
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Naveen Kumar G <naveen.gaddipati@stericsson.com>");
+MODULE_AUTHOR("NAVEEN KUMAR G");
MODULE_DESCRIPTION("bu21013 touch screen controller driver");