From 0b373509e05cf2f15df0319f239a1b653bf2a264 Mon Sep 17 00:00:00 2001 From: jli127 Date: Tue, 24 Apr 2012 13:24:09 +0800 Subject: [PATCH] driver/max11871: add sysfs debug interface BZ: 32663 This patch add sysfs debug interface to max11871 touchscreen driver. The interfaces added includes command, fw_ver, hreset, sreset, irq_count and panel_params. Signed-off-by: jli127 Change-Id: Ieabad396f23b2ee5868478c9f6f9b40360d4b9e0 Reviewed-on: http://android.intel.com:8080/45344 Reviewed-by: Koskinen, Ilkka Reviewed-by: Du, Alek Tested-by: Wang, Zhifeng Reviewed-by: buildbot Tested-by: buildbot --- .../intel-mid/device_libs/platform_max11871.c | 37 +++- drivers/input/touchscreen/max11871.c | 208 ++++++++++++++++++++- 2 files changed, 240 insertions(+), 5 deletions(-) diff --git a/arch/x86/platform/intel-mid/device_libs/platform_max11871.c b/arch/x86/platform/intel-mid/device_libs/platform_max11871.c index ef06d2b..0392096 100644 --- a/arch/x86/platform/intel-mid/device_libs/platform_max11871.c +++ b/arch/x86/platform/intel-mid/device_libs/platform_max11871.c @@ -51,14 +51,43 @@ static int max11871_power(int on) static int max11871_board_init(void) { int ret = 0; - int gpio = max11871_pdata.gpio_irq; - ret = gpio_request(gpio, "max11871_irq"); + ret = gpio_request(max11871_pdata.gpio_irq, "max11871_irq"); if (ret < 0) { - pr_err("%s: failed to request GPIO %d\n", __func__, gpio); + pr_err("%s: failed to request GPIO %d\n", + __func__, max11871_pdata.gpio_irq); return ret; } - return gpio_direction_input(gpio); + + ret = gpio_direction_input(max11871_pdata.gpio_irq); + if (ret < 0) { + pr_err("%s: failed to set GPIO direction %d\n", + __func__, max11871_pdata.gpio_irq); + goto out_free_irq; + } + + ret = gpio_request(max11871_pdata.gpio_rst, "max11871_rst"); + if (ret < 0) { + pr_err("%s: failed to request GPIO %d\n", + __func__, max11871_pdata.gpio_rst); + goto out_free_irq; + } + + ret = gpio_direction_output(max11871_pdata.gpio_rst, 0); + if (ret < 0) { + pr_err("%s: failed to set GPIO direction %d\n", + __func__, max11871_pdata.gpio_rst); + goto out_free_rst; + } + + return ret; + +out_free_rst: + gpio_free(max11871_pdata.gpio_rst); +out_free_irq: + gpio_free(max11871_pdata.gpio_irq); + + return ret; } static ssize_t max11871_virtual_keys_show(struct kobject *obj, diff --git a/drivers/input/touchscreen/max11871.c b/drivers/input/touchscreen/max11871.c index 56fa54d..c718706 100644 --- a/drivers/input/touchscreen/max11871.c +++ b/drivers/input/touchscreen/max11871.c @@ -31,6 +31,8 @@ #include #define NWORDS(a) (sizeof(a) / sizeof(u16)) +#define BYTEH(a) ((a) >> 8) +#define BYTEL(a) ((a) & 0xFF) #define MAX11871_CMD_ADDR 0x0000 #define MAX11871_ONE_CMD_LEN 9 @@ -155,6 +157,9 @@ struct max11871_data { u16 touch_config[MAX11871_MAX_CMD_LEN]; char phys[32]; char key_phys[32]; + + /* Debug values */ + u32 irq_counter; }; /* packet size in words including the header */ @@ -426,6 +431,7 @@ static irqreturn_t max11871_irq_handler(int irq, void *dev_id) max11871_process_report(ts, ts->report); out: + ts->irq_counter++; mutex_unlock(&ts->dev_mutex); return IRQ_HANDLED; } @@ -1031,6 +1037,193 @@ static void max11871_late_resume(struct early_suspend *h) } #endif +/* Debug sysfs support */ +static ssize_t irq_count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + int ret; + + mutex_lock(&ts->dev_mutex); + ret = snprintf(buf, PAGE_SIZE, "%u\n", ts->irq_counter); + mutex_unlock(&ts->dev_mutex); + return ret; +} + +static ssize_t irq_count_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + + mutex_lock(&ts->dev_mutex); + ts->irq_counter = 0; + mutex_unlock(&ts->dev_mutex); + return count; +} + +static ssize_t panel_params_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret; + struct max11871_platform_data *pdata = dev->platform_data; + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + + mutex_lock(&ts->dev_mutex); + ret = snprintf(buf, PAGE_SIZE, "%u %u %u %u %u %u %u %u %u %u %u %u " + "%u %u %u %u %u %u %u %u\n", pdata->abs_x_min, + pdata->abs_x_max, pdata->abs_y_min, pdata->abs_y_max, + pdata->abs_z_min, pdata->abs_z_max, + pdata->abs_button_area_x_max, pdata->abs_button_area_x_min, + pdata->abs_button_area_y_max, pdata->abs_button_area_y_min, + pdata->abs_back_button_x, pdata->abs_back_button_y, + pdata->abs_home_button_x, pdata->abs_home_button_y, + pdata->abs_menu_button_x, pdata->abs_menu_button_y, + pdata->abs_search_button_x, pdata->abs_search_button_y, + pdata->abs_button_fuzz_x, pdata->abs_button_fuzz_y); + mutex_unlock(&ts->dev_mutex); + + return ret; +} + +static ssize_t panel_params_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + int ret; + struct max11871_platform_data *pdata = dev->platform_data; + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + + mutex_lock(&ts->dev_mutex); + ret = sscanf(buf, "%hu %hu %hu %hu %hu %hu %hu %hu %hu %hu %hu %hu " + "%hu %hu %hu %hu %hu %hu %hu %hu", &pdata->abs_x_min, + &pdata->abs_x_max, &pdata->abs_y_min, &pdata->abs_y_max, + &pdata->abs_z_min, &pdata->abs_z_max, + &pdata->abs_button_area_x_max, &pdata->abs_button_area_x_min, + &pdata->abs_button_area_y_max, &pdata->abs_button_area_y_min, + &pdata->abs_back_button_x, &pdata->abs_back_button_y, + &pdata->abs_home_button_x, &pdata->abs_home_button_y, + &pdata->abs_menu_button_x, &pdata->abs_menu_button_y, + &pdata->abs_search_button_x, &pdata->abs_search_button_y, + &pdata->abs_button_fuzz_x, &pdata->abs_button_fuzz_y); + + mutex_unlock(&ts->dev_mutex); + if (ret != 20) { + dev_err(&client->dev, "not all values were entered"); + return -EINVAL; + } + return count; +} + +static ssize_t fw_ver_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + int ret; + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + + mutex_lock(&ts->dev_mutex); + ret = snprintf(buf, PAGE_SIZE, "%u.%u 0x%04X\n", BYTEH(ts->fw_version), + BYTEL(ts->fw_version), ts->fw_crc16); + mutex_unlock(&ts->dev_mutex); + + return ret; +} + +static ssize_t sreset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + + mutex_lock(&ts->dev_mutex); + ret = max11871_sw_reset(ts); + mutex_unlock(&ts->dev_mutex); + if (ret < 0) + dev_err(&client->dev, "Failed to do soft reset."); + + return count; +} + +static ssize_t command_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + u16 buffer[MAX11871_MAX_CMD_LEN]; + char scan_buf[5]; + int i; + + count--; /* ignore carriage return */ + if ((count % 4) != 0) { + dev_err(&client->dev, "words not properly defined"); + return -EINVAL; + } + if ((count / 4) > MAX11871_MAX_CMD_LEN) { + dev_err(&client->dev, "command too long"); + return -EINVAL; + } + scan_buf[4] = '\0'; + for (i = 0; i < count; i += 4) { + memcpy(scan_buf, &buf[i], 4); + ret = sscanf(scan_buf, "%hx", &buffer[i / 4]); + if (ret != 1) { + dev_err(&client->dev, "bad word %s", scan_buf); + return -EINVAL; + } + } + + mutex_lock(&ts->dev_mutex); + ret = max11871_send_cmd(ts, buffer, count / 4); + mutex_unlock(&ts->dev_mutex); + if (ret < 0) + dev_err(&client->dev, "MTP command failed"); + + return ++count; +} + +static ssize_t hreset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + struct max11871_data *ts = i2c_get_clientdata(client); + struct max11871_platform_data *pdata = client->dev.platform_data; + + mutex_lock(&ts->dev_mutex); + + ts->addr_pointer = 0; + pdata->power(0); + pdata->power(1); + + max11871_wait_sys_status(ts); + mutex_unlock(&ts->dev_mutex); + + return count; +} + +static DEVICE_ATTR(irq_count, S_IRUGO|S_IWUSR, irq_count_show, + irq_count_store); +static DEVICE_ATTR(panel_params, S_IRUGO|S_IWUSR, panel_params_show, + panel_params_store); +static DEVICE_ATTR(fw_ver, S_IRUGO, fw_ver_show, NULL); +static DEVICE_ATTR(sreset, S_IWUSR, NULL, sreset_store); +static DEVICE_ATTR(command, S_IWUSR, NULL, command_store); +static DEVICE_ATTR(hreset, S_IWUSR, NULL, hreset_store); + +static struct attribute *max11871_attributes[] = { + &dev_attr_irq_count.attr, + &dev_attr_panel_params.attr, + &dev_attr_fw_ver.attr, + &dev_attr_sreset.attr, + &dev_attr_command.attr, + &dev_attr_hreset.attr, + NULL +}; + static int __devinit max11871_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1062,7 +1255,8 @@ static int __devinit max11871_probe(struct i2c_client *client, ts = kzalloc(sizeof(*ts), GFP_KERNEL); if (!ts) { dev_err(dev, "fail to kzalloc max11871_data!\n"); - return -ENOMEM; + ret = -ENOMEM; + goto out_free_gpio; } ts->client = client; i2c_set_clientdata(client, ts); @@ -1132,6 +1326,11 @@ static int __devinit max11871_probe(struct i2c_client *client, #endif register_early_suspend(&ts->early_suspend); + /* create debug sysfs files */ + ret = sysfs_create_files(&client->dev.kobj, max11871_attributes); + if (ret) + dev_warn(&client->dev, "sysfs can not create files %d\n", ret); + ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG, "max11871.bin", dev, GFP_KERNEL, ts, max11871_update_fw); @@ -1146,18 +1345,25 @@ out_unresigter_input: input_unregister_device(ts->input_dev); out_free_ts: kfree(ts); +out_free_gpio: + gpio_free(pdata->gpio_irq); + gpio_free(pdata->gpio_rst); return ret; } static int max11871_remove(struct i2c_client *client) { struct max11871_data *ts = i2c_get_clientdata(client); + struct max11871_platform_data *pdata = client->dev.platform_data; free_irq(client->irq, ts); unregister_early_suspend(&ts->early_suspend); input_unregister_device(ts->input_dev); + sysfs_remove_files(&client->dev.kobj, max11871_attributes); kfree(ts); + gpio_free(pdata->gpio_irq); + gpio_free(pdata->gpio_rst); return 0; } -- 2.7.4