diff options
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/ft5x06-ts.txt | 7 | ||||
-rw-r--r-- | 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 <linux/completion.h> #include <linux/atomic.h> +#include <linux/clk.h> #include <linux/pm_runtime.h> +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; } |