From d30cccfe22511c69326d6844a887521dbd18a342 Mon Sep 17 00:00:00 2001 From: Abinaya P Date: Fri, 19 Feb 2016 13:43:59 +0530 Subject: input: ft5x06: Add support for clocks for secure touch on 8937 QRD Because of a change in the underlying bus driver, the secure touch layer in the input drivers is now required to control directly the clocks which are needed during the touch sessions. The clocks which are associated with the underlying I2C bus are clk_gcc_blsp1_ahb_clk and clk_gcc_blsp1_qup3_i2c_apps_clk. These clocks are turned on/off when the secure touch session is started/ended. Change-Id: If5abca579e264cc7799310628c4e379ac4368e7e Signed-off-by: Abinaya P --- .../bindings/input/touchscreen/ft5x06-ts.txt | 7 +++ drivers/input/touchscreen/ft5x06_ts.c | 65 ++++++++++++++++++++-- 2 files changed, 68 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt index ec8b08ad60e4..f7494c4c6e2b 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt @@ -72,6 +72,9 @@ Optional properties: - focaltech,psensor-support : specify whether support the proximity sensor - focaltech,gesture-support : specify whether support gesture feature - focaltech,resume-in-workqueue : specifiy whether to defer the resume to workqueue + - clock-names: : Clock names used for secure touch. They are: "iface_clk", "core_clk" + - clocks : Defined if 'clock-names' DT property is defined. These clocks + are associated with the underlying I2C bus. Example: i2c@f9923000{ @@ -109,5 +112,9 @@ Example: focaltech,fw-auto-cal; focaltech,psensor-support; focaltech,gesture-support; + /* Underlying clocks used by secure touch */ + clock-names = "iface_clk", "core_clk"; + clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>, + <&clock_gcc clk_gcc_blsp1_qup3_i2c_apps_clk>; }; }; diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index 2db0256b22a7..3154df26fb22 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -50,7 +50,9 @@ #if defined(CONFIG_FT_SECURE_TOUCH) #include #include +#include #include +static irqreturn_t ft5x06_ts_interrupt(int irq, void *data); #endif #define FT_DRIVER_VERSION 0x02 @@ -276,6 +278,9 @@ struct ft5x06_ts_data { atomic_t st_pending_irqs; struct completion st_powerdown; struct completion st_irq_processed; + bool st_initialized; + struct clk *core_clk; + struct clk *iface_clk; #endif }; @@ -285,8 +290,26 @@ static int ft5x06_ts_stop(struct device *dev); #if defined(CONFIG_FT_SECURE_TOUCH) static void ft5x06_secure_touch_init(struct ft5x06_ts_data *data) { + data->st_initialized = 0; + init_completion(&data->st_powerdown); init_completion(&data->st_irq_processed); + + /* Get clocks */ + data->core_clk = devm_clk_get(&data->client->dev, "core_clk"); + if (IS_ERR(data->core_clk)) { + data->core_clk = NULL; + dev_warn(&data->client->dev, + "%s: core_clk is not defined\n", __func__); + } + + data->iface_clk = devm_clk_get(&data->client->dev, "iface_clk"); + if (IS_ERR(data->iface_clk)) { + data->iface_clk = NULL; + dev_warn(&data->client->dev, + "%s: iface_clk is not defined", __func__); + } + data->st_initialized = 1; } static void ft5x06_secure_touch_notify(struct ft5x06_ts_data *data) @@ -324,12 +347,43 @@ static void ft5x06_secure_touch_stop(struct ft5x06_ts_data *data, bool blocking) } } +static int ft5x06_clk_prepare_enable(struct ft5x06_ts_data *data) +{ + int ret; + + ret = clk_prepare_enable(data->iface_clk); + if (ret) { + dev_err(&data->client->dev, + "error on clk_prepare_enable(iface_clk):%d\n", ret); + return ret; + } + + ret = clk_prepare_enable(data->core_clk); + if (ret) { + clk_disable_unprepare(data->iface_clk); + dev_err(&data->client->dev, + "error clk_prepare_enable(core_clk):%d\n", ret); + } + return ret; +} + +static void ft5x06_clk_disable_unprepare(struct ft5x06_ts_data *data) +{ + clk_disable_unprepare(data->core_clk); + clk_disable_unprepare(data->iface_clk); +} + static int ft5x06_bus_get(struct ft5x06_ts_data *data) { int retval; mutex_lock(&data->ft_clk_io_ctrl_mutex); retval = pm_runtime_get_sync(data->client->adapter->dev.parent); + if (retval >= 0 && data->core_clk != NULL && data->iface_clk != NULL) { + retval = ft5x06_clk_prepare_enable(data); + if (retval) + pm_runtime_put_sync(data->client->adapter->dev.parent); + } mutex_unlock(&data->ft_clk_io_ctrl_mutex); return retval; } @@ -337,6 +391,8 @@ static int ft5x06_bus_get(struct ft5x06_ts_data *data) static void ft5x06_bus_put(struct ft5x06_ts_data *data) { mutex_lock(&data->ft_clk_io_ctrl_mutex); + if (data->core_clk != NULL && data->iface_clk != NULL) + ft5x06_clk_disable_unprepare(data); pm_runtime_put_sync(data->client->adapter->dev.parent); mutex_unlock(&data->ft_clk_io_ctrl_mutex); } @@ -374,6 +430,9 @@ static ssize_t ft5x06_secure_touch_enable_store(struct device *dev, if (err != 0) return err; + if (!data->st_initialized) + return -EIO; + err = count; switch (value) { case 0: @@ -394,8 +453,7 @@ static ssize_t ft5x06_secure_touch_enable_store(struct device *dev, } synchronize_irq(data->client->irq); if (ft5x06_bus_get(data) < 0) { - dev_err(data->client->dev.parent, - "focalTech_bus_get failed\n"); + dev_err(&data->client->dev, "ft5x06_bus_get failed\n"); err = -EIO; break; } @@ -406,8 +464,7 @@ static ssize_t ft5x06_secure_touch_enable_store(struct device *dev, break; default: - dev_err(data->client->dev.parent, - "unsupported value: %lu\n", value); + dev_err(&data->client->dev, "unsupported value: %lu\n", value); err = -EINVAL; break; } -- cgit v1.2.3 From 501c621ee3c6c3cf17eb11971ff32a7ffaaf67e6 Mon Sep 17 00:00:00 2001 From: Himanshu Aggarwal Date: Tue, 8 Mar 2016 14:46:51 +0530 Subject: input: ft5x06: check return value of kobject_create_and_add The Focaltech driver creates a sysfs under sys/kernel/ts_info to access touch panel details. However, the return value of the API is not checked properly. Check the return value of the API. Also avoid making a duplicate copy of the kobject and clean up the show routine. Change-Id: Ib36e9d7661ee3d2ce7b229d8692e6212e33cbf36 Signed-off-by: Himanshu Aggarwal --- drivers/input/touchscreen/ft5x06_ts.c | 66 +++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/drivers/input/touchscreen/ft5x06_ts.c b/drivers/input/touchscreen/ft5x06_ts.c index 3154df26fb22..499ba692d53c 100644 --- a/drivers/input/touchscreen/ft5x06_ts.c +++ b/drivers/input/touchscreen/ft5x06_ts.c @@ -156,9 +156,6 @@ static irqreturn_t ft5x06_ts_interrupt(int irq, void *data); #define FT_FW_FILE_MAJ_VER_FT6X36(x) ((x)->data[0x10a]) #define FT_FW_FILE_VENDOR_ID_FT6X36(x) ((x)->data[0x108]) -#define FT_SYSFS_TS_INFO "ts_info" - - /** * Application data verification will be run before upgrade flow. * Firmware image stores some flags with negative and positive value @@ -225,8 +222,17 @@ enum { FT_FT5336_FAMILY_ID_0x14 = 0x14, }; -#define FT_STORE_TS_INFO(buf, id, name, max_tch, group_id, fw_vkey_support, \ - fw_name, fw_maj, fw_min, fw_sub_min) \ +#define FT_STORE_TS_INFO(buf, id, fw_maj, fw_min, fw_sub_min) \ + snprintf(buf, FT_INFO_MAX_LEN, \ + "vendor name = Focaltech\n" \ + "model = 0x%x\n" \ + "fw_version = %d.%d.%d\n", \ + id, fw_maj, fw_min, fw_sub_min) +#define FT_TS_INFO_SYSFS_DIR_NAME "ts_info" +static char *ts_info_buff; + +#define FT_STORE_TS_DBG_INFO(buf, id, name, max_tch, group_id, \ + fw_vkey_support, fw_name, fw_maj, fw_min, fw_sub_min) \ snprintf(buf, FT_INFO_MAX_LEN, \ "controller\t= focaltech\n" \ "model\t\t= 0x%x\n" \ @@ -262,7 +268,7 @@ struct ft5x06_ts_data { u32 tch_data_len; u8 fw_ver[3]; u8 fw_vendor_id; - struct kobject ts_info_kobj; + struct kobject *ts_info_kobj; #if defined(CONFIG_FB) struct work_struct fb_notify_work; struct notifier_block fb_notif; @@ -1784,11 +1790,13 @@ static int ft5x06_fw_upgrade(struct device *dev, bool force) ft5x06_update_fw_ver(data); - FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name, + FT_STORE_TS_DBG_INFO(data->ts_info, data->family_id, data->pdata->name, data->pdata->num_max_touches, data->pdata->group_id, data->pdata->fw_vkey_support ? "yes" : "no", data->pdata->fw_name, data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]); + FT_STORE_TS_INFO(ts_info_buff, data->family_id, data->fw_ver[0], + data->fw_ver[1], data->fw_ver[2]); rel_fw: release_firmware(fw); return rc; @@ -1891,22 +1899,13 @@ static ssize_t ft5x06_fw_name_store(struct device *dev, static DEVICE_ATTR(fw_name, 0664, ft5x06_fw_name_show, ft5x06_fw_name_store); - -static ssize_t ft5x06_ts_info_show(struct kobject *kobj, +static ssize_t ts_info_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { - struct ft5x06_ts_data *data = container_of(kobj, - struct ft5x06_ts_data, ts_info_kobj); - return snprintf(buf, FT_INFO_MAX_LEN, - "vendor name = Focaltech\n" - "model = 0x%x\n" - "fw_verion = %d.%d.%d\n", - data->family_id, data->fw_ver[0], - data->fw_ver[1], data->fw_ver[2]); + strlcpy(buf, ts_info_buff, FT_INFO_MAX_LEN); + return strnlen(buf, FT_INFO_MAX_LEN); } - -static struct kobj_attribute ts_info_attribute = __ATTR(ts_info, - 0664, ft5x06_ts_info_show, NULL); +static struct kobj_attribute ts_info_attr = __ATTR_RO(ts_info); static bool ft5x06_debug_addr_is_valid(int addr) { @@ -2546,16 +2545,20 @@ static int ft5x06_ts_probe(struct i2c_client *client, dev_dbg(&client->dev, "touch threshold = %d\n", reg_value * 4); /*creation touch panel info kobj*/ - data->ts_info_kobj = *(kobject_create_and_add(FT_SYSFS_TS_INFO, - kernel_kobj)); - if (!&(data->ts_info_kobj)) { - dev_err(&client->dev, "kob creation failed .\n"); + data->ts_info_kobj = kobject_create_and_add(FT_TS_INFO_SYSFS_DIR_NAME, + kernel_kobj); + if (!data->ts_info_kobj) { + dev_err(&client->dev, "kobject creation failed.\n"); } else { - err = sysfs_create_file(&(data->ts_info_kobj), - &ts_info_attribute.attr); + err = sysfs_create_file(data->ts_info_kobj, &ts_info_attr.attr); if (err) { - kobject_put(&(data->ts_info_kobj)); - dev_err(&client->dev, "sysfs create fail .\n"); + kobject_put(data->ts_info_kobj); + dev_err(&client->dev, "sysfs creation failed.\n"); + } else { + ts_info_buff = devm_kzalloc(&client->dev, + FT_INFO_MAX_LEN, GFP_KERNEL); + if (!ts_info_buff) + goto free_debug_dir; } } @@ -2579,12 +2582,13 @@ static int ft5x06_ts_probe(struct i2c_client *client, ft5x06_update_fw_ver(data); ft5x06_update_fw_vendor_id(data); - FT_STORE_TS_INFO(data->ts_info, data->family_id, data->pdata->name, + FT_STORE_TS_DBG_INFO(data->ts_info, data->family_id, data->pdata->name, data->pdata->num_max_touches, data->pdata->group_id, data->pdata->fw_vkey_support ? "yes" : "no", data->pdata->fw_name, data->fw_ver[0], data->fw_ver[1], data->fw_ver[2]); - + FT_STORE_TS_INFO(ts_info_buff, data->family_id, data->fw_ver[0], + data->fw_ver[1], data->fw_ver[2]); #if defined(CONFIG_FB) INIT_WORK(&data->fb_notify_work, fb_notify_resume_work); data->fb_notif.notifier_call = fb_notifier_callback; @@ -2727,7 +2731,7 @@ static int ft5x06_ts_remove(struct i2c_client *client) ft5x06_power_init(data, false); input_unregister_device(data->input_dev); - kobject_put(&(data->ts_info_kobj)); + kobject_put(data->ts_info_kobj); return 0; } -- cgit v1.2.3