From 930440dc319d1e37c2ab7e76c5880b0d9f1b3c61 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Thu, 17 Mar 2016 15:25:59 +0530 Subject: input: synaptics_dsx_2.6: add secure touch support for Synaptics V2.6 8953 QRD supports Synaptics touch controller. For synaptics_dsx_2.6 driver to work with the TrustZone secure touch, all the touch interrupts must be forwarded between the Linux Kernel and the TrustZone input driver. Add APIs and configuration to support this. Change-Id: I47520f9ba91b7645dff2c11b4c58a0b7aeed2765 Signed-off-by: Shantanu Jain --- drivers/input/touchscreen/Kconfig | 10 +++ .../synaptics_dsx_2.6/synaptics_dsx_core.c | 86 +++++++++++++++++++++- .../synaptics_dsx_2.6/synaptics_dsx_core.h | 12 +++ 3 files changed, 107 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 69028bd45fdd..61a13ddabc5e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1177,4 +1177,14 @@ config TOUCHSCREEN_FT5X06 To compile this driver as a module, choose M here: the module will be called ft5x06_ts. +config SECURE_TOUCH_SYNAPTICS_DSX_V26 + bool "Secure Touch support for Synaptics V2.6 Touchscreen" + depends on TOUCHSCREEN_SYNAPTICS_DSX_I2C_v26 + help + Say Y here + -Synaptics DSX V2.6 touch driver is connected + -To enable secure touch for Synaptics DSX V2.6 touch driver + + If unsure, say N. + endif diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c index 07d2c479aa39..4b15935b2d4c 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.c @@ -627,6 +627,67 @@ static struct kobj_attribute virtual_key_map_attr = { .show = synaptics_rmi4_virtual_key_map_show, }; +#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) +static void synaptics_secure_touch_init(struct synaptics_rmi4_data *data) +{ + init_completion(&data->st_powerdown); + init_completion(&data->st_irq_processed); +} + +static void synaptics_secure_touch_notify(struct synaptics_rmi4_data *rmi4_data) +{ + sysfs_notify(&rmi4_data->input_dev->dev.kobj, NULL, "secure_touch"); +} + +static irqreturn_t synaptics_filter_interrupt( + struct synaptics_rmi4_data *rmi4_data) +{ + if (atomic_read(&rmi4_data->st_enabled)) { + if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 0, 1) == 0) { + reinit_completion(&rmi4_data->st_irq_processed); + synaptics_secure_touch_notify(rmi4_data); + wait_for_completion_interruptible( + &rmi4_data->st_irq_processed); + } + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +/* + * 'blocking' variable will have value 'true' when we want to prevent the driver + * from accessing the xPU/SMMU protected HW resources while the session is + * active. + */ +static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, + bool blocking) +{ + if (atomic_read(&rmi4_data->st_enabled)) { + atomic_set(&rmi4_data->st_pending_irqs, -1); + synaptics_secure_touch_notify(rmi4_data); + if (blocking) + wait_for_completion_interruptible( + &rmi4_data->st_powerdown); + } +} + +#else +static void synaptics_secure_touch_init(struct synaptics_rmi4_data *rmi4_data) +{ +} + +static irqreturn_t synaptics_filter_interrupt( + struct synaptics_rmi4_data *rmi4_data) +{ + return IRQ_NONE; +} + +static void synaptics_secure_touch_stop(struct synaptics_rmi4_data *rmi4_data, + bool blocking) +{ +} +#endif + static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -1512,6 +1573,9 @@ static irqreturn_t synaptics_rmi4_irq(int irq, void *data) const struct synaptics_dsx_board_data *bdata = rmi4_data->hw_if->board_data; + if (synaptics_filter_interrupt(data) == IRQ_HANDLED) + return IRQ_HANDLED; + if (gpio_get_value(bdata->irq_gpio) != bdata->irq_on_state) goto exit; @@ -3866,6 +3930,10 @@ static int synaptics_rmi4_probe(struct platform_device *pdev) queue_work(rmi4_data->reset_workqueue, &rmi4_data->reset_work); #endif + /* Initialize secure touch */ + synaptics_secure_touch_init(rmi4_data); + synaptics_secure_touch_stop(rmi4_data, true); + return retval; err_sysfs: @@ -4106,7 +4174,9 @@ static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self, fb_notifier); if (evdata && evdata->data && rmi4_data) { - if (event == FB_EVENT_BLANK) { + if (event == FB_EARLY_EVENT_BLANK) { + synaptics_secure_touch_stop(rmi4_data, false); + } else if (event == FB_EVENT_BLANK) { transition = evdata->data; if (*transition == FB_BLANK_POWERDOWN) { synaptics_rmi4_suspend(&rmi4_data->pdev->dev); @@ -4133,6 +4203,14 @@ static void synaptics_rmi4_early_suspend(struct early_suspend *h) if (rmi4_data->stay_awake) return; + /* + * During early suspend/late resume, the driver doesn't access xPU/SMMU + * protected HW resources. So, there is no compelling need to block, + * but notifying the userspace that a power event has occurred is + * enough. Hence 'blocking' variable can be set to false. + */ + synaptics_secure_touch_stop(rmi4_data, false); + if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); @@ -4170,6 +4248,8 @@ static void synaptics_rmi4_late_resume(struct early_suspend *h) if (rmi4_data->stay_awake) return; + synaptics_secure_touch_stop(rmi4_data, false); + if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); @@ -4216,6 +4296,8 @@ static int synaptics_rmi4_suspend(struct device *dev) if (rmi4_data->stay_awake) return 0; + synaptics_secure_touch_stop(rmi4_data, true); + if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, true); enable_irq_wake(rmi4_data->irq); @@ -4253,6 +4335,8 @@ static int synaptics_rmi4_resume(struct device *dev) if (rmi4_data->stay_awake) return 0; + synaptics_secure_touch_stop(rmi4_data, true); + if (rmi4_data->enable_wakeup_gesture) { synaptics_rmi4_wakeup_gesture(rmi4_data, false); disable_irq_wake(rmi4_data->irq); diff --git a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h index 0de0e9905cb4..0bab0c233a12 100644 --- a/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h +++ b/drivers/input/touchscreen/synaptics_dsx_2.6/synaptics_dsx_core.h @@ -48,6 +48,12 @@ #include #endif +#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) +#include +#include +#include +#endif + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38)) #define KERNEL_ABOVE_2_6_38 #endif @@ -374,6 +380,12 @@ struct synaptics_rmi4_data { bool enable); void (*report_touch)(struct synaptics_rmi4_data *rmi4_data, struct synaptics_rmi4_fn *fhandler); +#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26) + atomic_t st_enabled; + atomic_t st_pending_irqs; + struct completion st_powerdown; + struct completion st_irq_processed; +#endif }; struct synaptics_dsx_bus_access { -- cgit v1.2.3