aboutsummaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorSrikanth Shivanand <srikanth.shivanand@stericsson.com>2010-10-12 17:58:58 +0530
committerSundar Iyer <sundar.iyer@stericsson.com>2010-11-10 17:30:26 +0530
commit85e0ffefaa39700fb1279b5b0ba7317f5376b019 (patch)
tree2f9430104f77c808d922e01bea01f4f41d826a1a /drivers/input
parent12df797506fc5e01668538dfcf57cbe7a36b5419 (diff)
GENERIC:input: Dynamic enable or disable for the bu21013 touch screen
Added support for dynamic enable or disable for the bu21013 controller events and external clock using sysfs. enable command: echo 1 > /sys/devices/platform/nmk-i2c.3/i2c-3/3-005c/enable disable command: echo 0 > /sys/devices/platform/nmk-i2c.3/i2c-3/3-005c/enable enable external clock: echo 1 > /sys/devices/platform/nmk-i2c.3/i2c-3/3-005c/ext_clk disable external clock: echo 0 > /sys/devices/platform/nmk-i2c.3/i2c-3/3-005c/ext_clk ST-Ericsson Id: WP 273488 Change-Id: I89329cdebe9784ff3d32119ebe0976a56ca0e4d0 Signed-off-by: Srikanth Shivanand <srikanth.shivanand@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/7225 Tested-by: Naveen Kumar GADDIPATI <naveen.gaddipati@stericsson.com> Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/touchscreen/bu21013_ts.c404
1 files changed, 240 insertions, 164 deletions
diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c
index da9cd0ad15f..efe1b01679f 100644
--- a/drivers/input/touchscreen/bu21013_ts.c
+++ b/drivers/input/touchscreen/bu21013_ts.c
@@ -15,6 +15,8 @@
#include <linux/timer.h>
#include <linux/input/bu21013.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
#define PEN_DOWN_INTR 0
#define PEN_UP_INTR 1
@@ -24,7 +26,7 @@
#define MAX_TOUCH_MAJOR 255
#define MAX_TOUCH_MINOR 15
#define MAX_PRESSURE 1
-#define PENUP_TIMEOUT (2)
+#define PENUP_TIMEOUT (2)/* 2msecs */
#define SCALE_FACTOR 1000
#define DELTA_MIN 16
#define MASK_BITS 0x03
@@ -49,8 +51,10 @@
* @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
+ * @regulator: pointer to the Regulator used for touch screen controller
+ * @tpclk: pointer to clock structure
+ * @enable: variable to indicate the enable/disable of touch screen
*
* Touch panel data structure
*/
@@ -67,126 +71,221 @@ struct bu21013_ts_data {
int factor_x;
int factor_y;
bool previous_press_reported;
- struct kobject *touchp_kobj;
int penup_timer;
+ struct regulator *regulator;
+ struct clk *tpclk;
+ bool enable;
};
-/* 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
+/**
+ * bu21013_extclk_en() - enable the external clock
+ * @pdata:touch screen data
+ *
+ * This function used to enable the external clock for driver
+ * and returns integer
*/
-static ssize_t touchp1_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+static int bu21013_extclk_en(struct bu21013_ts_data *pdata)
{
- u8 timeout;
- u8 sys_ext_clock;
+ int retval;
+
+ if (pdata->tpclk && pdata->chip->ext_clk) {
+ retval = clk_enable(pdata->tpclk);
+ if (retval < 0)
+ return retval;
+ }
- 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);
+ retval = bu21013_init_chip(pdata);
+ if (retval < 0) {
+ dev_err(&pdata->client->dev, "chip config failed\n");
+ return retval;
}
- return strlen(buf);
+
+ return 0;
}
-static ssize_t touchp1_attr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t len)
+
+/**
+ * bu21013_extclk_dis() - disable the external clock
+ * @pdata:touch screen data
+ *
+ * This function used to disable the external clock for driver
+ * and returns none
+ */
+static void bu21013_extclk_dis(struct bu21013_ts_data *pdata)
{
- 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);
- }
+ int retval;
+
+ clk_disable(pdata->tpclk);
+ pdata->chip->ext_clk = false;
+ retval = bu21013_init_chip(pdata);
+ if (retval < 0)
+ dev_err(&pdata->client->dev, "chip config failed\n");
+}
+/**
+ * bu21013_enable() - enable the touch driver event
+ * @pdata:touch screen data
+ *
+ * This function used to enable the driver and returns integer
+ */
+static int bu21013_enable(struct bu21013_ts_data *pdata)
+{
+ int retval;
+
+ if (pdata->regulator)
+ regulator_enable(pdata->regulator);
+
+ retval = bu21013_extclk_en(pdata);
+ if (retval < 0) {
+ dev_err(&pdata->client->dev, "enable clock failed\n");
+ return retval;
}
- return ret == 1 ? len : -EINVAL;
+
+ enable_irq(pdata->chip->irq);
+
+ return 0;
}
-/*
- * sysfs is used to change the touchpanel2 parameters
- * and also enable the external clock dynamically
+/**
+ * bu21013_enable() - disable the touch driver event
+ * @pdata:touch screen data
+ *
+ * This function used to disable the driver and returns integer
*/
-static ssize_t touchp2_attr_show(struct kobject *kobj,
- struct attribute *attr, char *buf)
+static void bu21013_disable(struct bu21013_ts_data *pdata)
{
- u8 timeout;
- u8 sys_ext_clock;
+ if (pdata->tpclk && pdata->chip->ext_clk)
+ bu21013_extclk_dis(pdata);
+ disable_irq(pdata->chip->irq);
+ if (pdata->regulator)
+ regulator_disable(pdata->regulator);
+}
- 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);
+/**
+ * bu21013_show_attr_enable() - show the touch screen controller status
+ * @dev: pointer to device structure
+ * @attr: pointer to device attribute
+ * @buf: parameter buffer
+ *
+ * This funtion is used to show whether the touch screen is enabled or
+ * disabled
+ */
+static ssize_t bu21013_show_attr_enable(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bu21013_ts_data *pdata = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", pdata->enable);
}
-static ssize_t touchp2_attr_store(struct kobject *kobj,
- struct attribute *attr, const char *buf, size_t len)
+
+/**
+ * bu21013_show_attr_enable() - Enable/Disable the touchscreen.
+ * @dev: pointer to device structure
+ * @attr: pointer to device attribute
+ * @buf: parameter buffer
+ * @count: number of parameters
+ *
+ * This funtion is used to enable or disable the touch screen controller.
+ */
+static ssize_t bu21013_store_attr_enable(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
{
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);
+ unsigned long val;
+
+ struct bu21013_ts_data *pdata = dev_get_drvdata(dev);
+
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ if (pdata->enable != val) {
+ pdata->enable = val ? true : false;
+ if (pdata->enable) {
+ ret = bu21013_enable(pdata);
+ if (ret < 0)
+ return ret;
+ } else
+ bu21013_disable(pdata);
+ }
+ return count;
+}
+
+/**
+ * bu21013_show_attr_enable() - shows the external clock status
+ * @dev: pointer to device structure
+ * @attr: pointer to device attribute
+ * @buf: parameter buffer
+ *
+ * This funtion is used to show whether the external clock for the touch
+ * screen is enabled or disabled disabled.
+ */
+static ssize_t bu21013_show_attr_extclk(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct bu21013_ts_data *pdata = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", pdata->chip->ext_clk);
+}
+
+/**
+ * bu21013_show_attr_enable() - Enable/Disable the external clock
+ * for the tocuh screen controller.
+ * @dev: pointer to device structure
+ * @attr: pointer to device attribute
+ * @buf: parameter buffer
+ * @count: number of parameters
+ *
+ * This funtion is used enabled or disable the external clock for the touch
+ * screen controller.
+ */
+static ssize_t bu21013_store_attr_extclk(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ int retval = 0;
+ struct bu21013_ts_data *pdata = dev_get_drvdata(dev);
+ unsigned long val;
+
+ if (strict_strtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if ((val != 0) && (val != 1))
+ return -EINVAL;
+
+ if (val != pdata->chip->ext_clk) {
+ pdata->chip->ext_clk = val ? true : false;
+ if (pdata->chip->ext_clk) {
+ retval = bu21013_extclk_en(pdata);
+ if (retval < 0) {
+ dev_err(&pdata->client->dev,
+ "enable clock failed\n");
+ return retval;
+ }
+ } else {
+ if (pdata->tpclk)
+ bu21013_extclk_dis(pdata);
}
}
- return ret == 1 ? len : -EINVAL;
+ return count;
}
+static DEVICE_ATTR(enable, S_IWUSR | S_IRUGO,
+ bu21013_show_attr_enable, bu21013_store_attr_enable);
-static struct attribute touchp_timeout = {.name = "timeout_value",
- .mode = 0666};
-static struct attribute touchp_ext_clk = {.name = "ext_clk", .mode = 0666};
+static DEVICE_ATTR(ext_clk, S_IWUSR | S_IRUGO,
+ bu21013_show_attr_extclk, bu21013_store_attr_extclk);
-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 struct attribute *bu21013_attribute[] = {
+ &dev_attr_enable.attr,
+ &dev_attr_ext_clk.attr,
+ NULL,
};
-static const struct sysfs_ops touchp2_sysfs_ops = {
- .show = touchp2_attr_show,
- .store = touchp2_attr_store,
+static struct attribute_group bu21013_attr_group = {
+ .attrs = bu21013_attribute,
};
-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
@@ -675,10 +774,7 @@ 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);
+ bu21013_disable(bu21013_data);
return 0;
}
@@ -692,69 +788,13 @@ static int bu21013_suspend(struct i2c_client *client, pm_message_t mesg)
*/
static int bu21013_resume(struct i2c_client *client)
{
- 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;
+ return bu21013_enable(bu21013_data);
}
#endif
/**
- * 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
@@ -770,6 +810,7 @@ static int bu21013_probe(struct i2c_client *i2c,
struct input_dev *in_dev;
short x_max;
short y_max;
+
struct bu21013_platform_device *pdata = i2c->dev.platform_data;
if (!pdata) {
@@ -820,6 +861,15 @@ static int bu21013_probe(struct i2c_client *i2c,
bu21013_data->penirq_timer.function = bu21013_timer_callback;
i2c_set_clientdata(i2c, bu21013_data);
+ dev_set_name(&i2c->dev, pdata->name);
+ bu21013_data->regulator = regulator_get(&i2c->dev, "v-touch");
+ if (IS_ERR(bu21013_data->regulator)) {
+ dev_warn(&i2c->dev, "regulator_get failed\n");
+ bu21013_data->regulator = NULL;
+ }
+ if (bu21013_data->regulator)
+ regulator_enable(bu21013_data->regulator);
+
/* configure the gpio pins */
if (pdata->cs_en) {
retval = pdata->cs_en(pdata->cs_pin);
@@ -829,6 +879,18 @@ static int bu21013_probe(struct i2c_client *i2c,
}
}
+ bu21013_data->tpclk = clk_get(&i2c->dev, NULL);
+ if (IS_ERR(bu21013_data->tpclk)) {
+ dev_warn(&i2c->dev, "get extern clock failed\n");
+ bu21013_data->tpclk = NULL;
+ } else if (pdata->ext_clk) {
+ retval = clk_enable(bu21013_data->tpclk);
+ if (retval < 0) {
+ dev_err(&i2c->dev, "clock enable failed\n");
+ goto err_ext_clk;
+ }
+ }
+
/* configure the touch panel controller */
retval = bu21013_init_chip(bu21013_data);
if (retval < 0) {
@@ -871,29 +933,31 @@ static int bu21013_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "request irq %d failed\n", pdata->irq);
goto err_init_irq;
}
+ bu21013_data->enable = true;
- 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;
+ /* sysfs implementation for dynamic enable/disable the input event */
+ retval = sysfs_create_group(&i2c->dev.kobj, &bu21013_attr_group);
+ if (retval) {
+ dev_err(&i2c->dev, "failed to create sysfs entries\n");
+ goto err_sysfs;
+ }
dev_dbg(&i2c->dev, "init done");
return retval;
-err_init_sys:
+
+err_sysfs:
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:
+ if (bu21013_data->tpclk && pdata->ext_clk) {
+ clk_disable(bu21013_data->tpclk);
+ clk_put(bu21013_data->tpclk);
+ }
+err_ext_clk:
pdata->cs_dis(pdata->cs_pin);
err_init_cs:
del_timer_sync(&bu21013_data->penirq_timer);
@@ -904,6 +968,7 @@ err_alloc:
kfree(bu21013_data);
return retval;
}
+
/**
* bu21013_remove() - removes the i2c-client touchscreen driver
* @client: i2c client structure pointer
@@ -915,6 +980,8 @@ static int __devexit bu21013_remove(struct i2c_client *client)
{
struct bu21013_ts_data *data = i2c_get_clientdata(client);
+ sysfs_remove_group(&client->dev.kobj, &bu21013_attr_group);
+
del_timer_sync(&data->penirq_timer);
cancel_work_sync(&data->timer_wq_handler);
cancel_work_sync(&data->gpio_wq_handler);
@@ -924,6 +991,15 @@ static int __devexit bu21013_remove(struct i2c_client *client)
data->chip->cs_dis(data->chip->cs_pin);
}
input_unregister_device(data->in_dev);
+
+ if (data->tpclk && data->chip->ext_clk) {
+ clk_disable(data->tpclk);
+ clk_put(data->tpclk);
+ }
+ if (data->regulator) {
+ regulator_disable(data->regulator);
+ regulator_put(data->regulator);
+ }
kfree(data);
return 0;