|
@@ -0,0 +1,279 @@
|
|
|
+diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
|
|
|
+index c2aaa20..5977dda 100644
|
|
|
+--- a/drivers/input/touchscreen/edt-ft5x06.c
|
|
|
++++ b/drivers/input/touchscreen/edt-ft5x06.c
|
|
|
+@@ -24,7 +24,13 @@
|
|
|
+ * Development of this driver has been sponsored by Glyn:
|
|
|
+ * http://www.glyn.com/Products/Displays
|
|
|
+ */
|
|
|
++#define ISR_STAT 10 /*activate ISR Statistics*/
|
|
|
+
|
|
|
++#ifdef ISR_STAT
|
|
|
++#include <linux/kernel.h>
|
|
|
++#include <linux/timer.h>
|
|
|
++#include <linux/sched.h>
|
|
|
++#endif
|
|
|
+ #include <linux/module.h>
|
|
|
+ #include <linux/ratelimit.h>
|
|
|
+ #include <linux/interrupt.h>
|
|
|
+@@ -92,6 +98,20 @@ enum edt_ver {
|
|
|
+ MG1,
|
|
|
+ };
|
|
|
+
|
|
|
++
|
|
|
++#ifdef ISR_STAT
|
|
|
++#define STAT_HYST 2
|
|
|
++static int verbose = 0;
|
|
|
++static struct isr_statistics {
|
|
|
++ int index;
|
|
|
++ int reset_on_next_isr; /*reset TC Controller on next irq*/
|
|
|
++ int calls_count; /* actual isr calls*/
|
|
|
++ int calls_mean; /* menval calls_count last ISR_CALLSTAT_ANZ*/
|
|
|
++ int calls_stat_count[ISR_STAT];
|
|
|
++}isr_stat;
|
|
|
++static struct timer_list isr_timer;
|
|
|
++#endif
|
|
|
++
|
|
|
+ struct edt_reg_addr {
|
|
|
+ int reg_threshold;
|
|
|
+ int reg_report_rate;
|
|
|
+@@ -137,6 +157,57 @@ struct edt_ft5x06_ts_data {
|
|
|
+ enum edt_ver version;
|
|
|
+ };
|
|
|
+
|
|
|
++#ifdef ISR_STAT
|
|
|
++static void isr_timer_callback(unsigned long data) {
|
|
|
++ int i, val = 0;
|
|
|
++ int do_print = 0;
|
|
|
++ int val_in_range = 0;
|
|
|
++ char Buf[ISR_STAT * 5];
|
|
|
++
|
|
|
++ memset(Buf, ' ', sizeof(Buf));
|
|
|
++ Buf[ISR_STAT * 5 - 1] = 0;
|
|
|
++
|
|
|
++ isr_stat.calls_stat_count[isr_stat.index] = isr_stat.calls_count;
|
|
|
++
|
|
|
++ for (i = 0; i < ISR_STAT; i++) {
|
|
|
++ val += (isr_stat.calls_stat_count[i] * 10);
|
|
|
++ snprintf(Buf + i * 5, 5, "%d", isr_stat.calls_stat_count[i]);
|
|
|
++ }
|
|
|
++
|
|
|
++ for(i = 0; i < (ISR_STAT * 5 - 1); i++) if (!Buf[i]) Buf[i] = ' ';
|
|
|
++
|
|
|
++
|
|
|
++ if(val > 0)
|
|
|
++ isr_stat.calls_mean = (val + ISR_STAT/2) / (ISR_STAT * 10); /*round to next higher value*/
|
|
|
++ else
|
|
|
++ isr_stat.calls_mean = 0;
|
|
|
++
|
|
|
++ if(isr_stat.calls_mean > 0) { /*only when meanvalue availabel*/
|
|
|
++ for (i = 0; i < ISR_STAT; i++) {
|
|
|
++ if((isr_stat.calls_stat_count[i] >= isr_stat.calls_mean - STAT_HYST) &&
|
|
|
++ (isr_stat.calls_stat_count[i] <= isr_stat.calls_mean + STAT_HYST)) {
|
|
|
++ ++val_in_range;
|
|
|
++ }
|
|
|
++ }
|
|
|
++ if(val_in_range == ISR_STAT) {
|
|
|
++ printk(KERN_ALERT "ISR_STAT RESET Request\n");
|
|
|
++ do_print = 1;
|
|
|
++ isr_stat.reset_on_next_isr = 1;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++ if(verbose || do_print) {
|
|
|
++ printk(KERN_ALERT "ISR_STAT #_range: %d mean: %.4d calls: %.4d idx: %d [%s]\n",
|
|
|
++ val_in_range, isr_stat.calls_mean, isr_stat.calls_count, isr_stat.index, Buf);
|
|
|
++ }
|
|
|
++
|
|
|
++ isr_stat.calls_count = 0;
|
|
|
++ if ((++isr_stat.index) >= ISR_STAT) isr_stat.index = 0;
|
|
|
++
|
|
|
++ mod_timer(&isr_timer, jiffies + msecs_to_jiffies(1000));
|
|
|
++}
|
|
|
++#endif
|
|
|
++
|
|
|
+ static int edt_ft5x06_ts_readwrite(struct i2c_client *client,
|
|
|
+ u16 wr_len, u8 *wr_buf,
|
|
|
+ u16 rd_len, u8 *rd_buf)
|
|
|
+@@ -188,6 +259,45 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata,
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
++static int edt_ft5x06_ts_reset(struct i2c_client *client,
|
|
|
++ struct edt_ft5x06_ts_data *tsdata)
|
|
|
++{
|
|
|
++ int error;
|
|
|
++
|
|
|
++ if (gpio_is_valid(tsdata->wake_pin)) {
|
|
|
++ error = devm_gpio_request_one(&client->dev,
|
|
|
++ tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
|
|
|
++ "edt-ft5x06 wake");
|
|
|
++ if (error) {
|
|
|
++ dev_err(&client->dev,
|
|
|
++ "Failed to request GPIO %d as wake pin, error %d\n",
|
|
|
++ tsdata->wake_pin, error);
|
|
|
++ return error;
|
|
|
++ }
|
|
|
++
|
|
|
++ msleep(5);
|
|
|
++ gpio_set_value(tsdata->wake_pin, 1);
|
|
|
++ }
|
|
|
++ if (gpio_is_valid(tsdata->reset_pin)) {
|
|
|
++ /* this pulls reset down, enabling the low active reset */
|
|
|
++ error = devm_gpio_request_one(&client->dev,
|
|
|
++ tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
|
|
|
++ "edt-ft5x06 reset");
|
|
|
++ if (error) {
|
|
|
++ dev_err(&client->dev,
|
|
|
++ "Failed to request GPIO %d as reset pin, error %d\n",
|
|
|
++ tsdata->reset_pin, error);
|
|
|
++ return error;
|
|
|
++ }
|
|
|
++
|
|
|
++ msleep(5);
|
|
|
++ gpio_set_value(tsdata->reset_pin, 1);
|
|
|
++ msleep(300);
|
|
|
++ }
|
|
|
++
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
+ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
|
|
+ {
|
|
|
+ struct edt_ft5x06_ts_data *tsdata = dev_id;
|
|
|
+@@ -198,6 +308,10 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
|
|
+ int offset, tplen, datalen;
|
|
|
+ int error;
|
|
|
+
|
|
|
++#ifdef ISR_STAT
|
|
|
++ ++isr_stat.calls_count;
|
|
|
++#endif
|
|
|
++
|
|
|
+ switch (tsdata->version) {
|
|
|
+ case M06:
|
|
|
+ cmd = 0xf9; /* tell the controller to send touch data */
|
|
|
+@@ -295,6 +409,15 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id)
|
|
|
+ input_sync(tsdata->input);
|
|
|
+
|
|
|
+ out:
|
|
|
++
|
|
|
++#ifdef ISR_STAT
|
|
|
++ if(isr_stat.reset_on_next_isr) {
|
|
|
++ gpio_set_value(tsdata->reset_pin, 0);
|
|
|
++ msleep(5);
|
|
|
++ gpio_set_value(tsdata->reset_pin, 1);
|
|
|
++ memset(&isr_stat, 0, sizeof(isr_stat));
|
|
|
++ }
|
|
|
++#endif
|
|
|
+ return IRQ_HANDLED;
|
|
|
+ }
|
|
|
+
|
|
|
+@@ -667,6 +790,23 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
++#ifdef ISR_STAT
|
|
|
++static int edt_ft5x06_debugfs_verbose_get(void *data, u64 *verbose_print)
|
|
|
++{
|
|
|
++ *verbose_print = (u64)(verbose);
|
|
|
++ return 0;
|
|
|
++};
|
|
|
++
|
|
|
++static int edt_ft5x06_debugfs_verbose_set(void *data, u64 verbose_print)
|
|
|
++{
|
|
|
++ verbose = (u32)(verbose_print);
|
|
|
++ return 0;
|
|
|
++};
|
|
|
++
|
|
|
++DEFINE_SIMPLE_ATTRIBUTE(debugfs_verbose_fops, edt_ft5x06_debugfs_verbose_get,
|
|
|
++ edt_ft5x06_debugfs_verbose_set, "%llu\n");
|
|
|
++
|
|
|
++#endif
|
|
|
+
|
|
|
+ static int edt_ft5x06_debugfs_threshold_get(void *data, u64 *threshold)
|
|
|
+ {
|
|
|
+@@ -900,11 +1040,10 @@ edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
|
|
|
+ debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
|
|
|
+ debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
|
|
|
+
|
|
|
+-/*
|
|
|
+- debugfs_create_u32("threshold", S_IRUSR, tsdata->debug_dir, &tsdata->threshold);
|
|
|
+- debugfs_create_u32("gain", S_IRUSR, tsdata->debug_dir, &tsdata->gain);
|
|
|
+- debugfs_create_u32("offset", S_IRUSR, tsdata->debug_dir, &tsdata->offset);
|
|
|
+-*/
|
|
|
++#ifdef ISR_STAT
|
|
|
++ debugfs_create_file("verbose", S_IRUSR | S_IWUSR,
|
|
|
++ tsdata->debug_dir, tsdata, &debugfs_verbose_fops);
|
|
|
++#endif
|
|
|
+
|
|
|
+ debugfs_create_file("threshold", S_IRUSR | S_IWUSR,
|
|
|
+ tsdata->debug_dir, tsdata, &debugfs_threshold_fops);
|
|
|
+@@ -959,45 +1098,6 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
|
|
|
+
|
|
|
+ #endif /* CONFIG_DEBUGFS */
|
|
|
+
|
|
|
+-static int edt_ft5x06_ts_reset(struct i2c_client *client,
|
|
|
+- struct edt_ft5x06_ts_data *tsdata)
|
|
|
+-{
|
|
|
+- int error;
|
|
|
+-
|
|
|
+- if (gpio_is_valid(tsdata->wake_pin)) {
|
|
|
+- error = devm_gpio_request_one(&client->dev,
|
|
|
+- tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
|
|
|
+- "edt-ft5x06 wake");
|
|
|
+- if (error) {
|
|
|
+- dev_err(&client->dev,
|
|
|
+- "Failed to request GPIO %d as wake pin, error %d\n",
|
|
|
+- tsdata->wake_pin, error);
|
|
|
+- return error;
|
|
|
+- }
|
|
|
+-
|
|
|
+- msleep(5);
|
|
|
+- gpio_set_value(tsdata->wake_pin, 1);
|
|
|
+- }
|
|
|
+- if (gpio_is_valid(tsdata->reset_pin)) {
|
|
|
+- /* this pulls reset down, enabling the low active reset */
|
|
|
+- error = devm_gpio_request_one(&client->dev,
|
|
|
+- tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
|
|
|
+- "edt-ft5x06 reset");
|
|
|
+- if (error) {
|
|
|
+- dev_err(&client->dev,
|
|
|
+- "Failed to request GPIO %d as reset pin, error %d\n",
|
|
|
+- tsdata->reset_pin, error);
|
|
|
+- return error;
|
|
|
+- }
|
|
|
+-
|
|
|
+- msleep(5);
|
|
|
+- gpio_set_value(tsdata->reset_pin, 1);
|
|
|
+- msleep(300);
|
|
|
+- }
|
|
|
+-
|
|
|
+- return 0;
|
|
|
+-}
|
|
|
+-
|
|
|
+ static int edt_ft5x06_ts_identify(struct i2c_client *client,
|
|
|
+ struct edt_ft5x06_ts_data *tsdata,
|
|
|
+ char *fw_version)
|
|
|
+@@ -1268,6 +1368,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
|
|
|
+ int error;
|
|
|
+ char fw_version[EDT_NAME_LEN];
|
|
|
+
|
|
|
++#ifdef ISR_STAT
|
|
|
++ memset(&isr_stat, 0, sizeof(isr_stat));
|
|
|
++ setup_timer(&isr_timer, isr_timer_callback, 0);
|
|
|
++ mod_timer(&isr_timer, jiffies + msecs_to_jiffies(1000));
|
|
|
++#endif
|
|
|
++
|
|
|
+ dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
|
|
|
+
|
|
|
+ tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
|
|
|
+@@ -1396,6 +1502,9 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
|
|
|
+ edt_ft5x06_ts_teardown_debugfs(tsdata);
|
|
|
+ sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
|
|
|
+
|
|
|
++#ifdef ISR_STAT
|
|
|
++ del_timer(&isr_timer);
|
|
|
++#endif
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|