diff options
author | Srikanth Shivanand <srikanth.shivanand@stericsson.com> | 2010-10-12 17:58:58 +0530 |
---|---|---|
committer | Sundar Iyer <sundar.iyer@stericsson.com> | 2010-11-10 17:30:26 +0530 |
commit | 85e0ffefaa39700fb1279b5b0ba7317f5376b019 (patch) | |
tree | 2f9430104f77c808d922e01bea01f4f41d826a1a /drivers/input | |
parent | 12df797506fc5e01668538dfcf57cbe7a36b5419 (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.c | 404 |
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; |