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 <shjain@codeaurora.org>
This commit is contained in:
Shantanu Jain 2016-03-17 15:25:59 +05:30 committed by Abinaya P
parent e97b6a0e02
commit 930440dc31
3 changed files with 107 additions and 1 deletions

View file

@ -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

View file

@ -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);

View file

@ -48,6 +48,12 @@
#include <linux/earlysuspend.h>
#endif
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
#include <linux/completion.h>
#include <linux/atomic.h>
#include <linux/pm_runtime.h>
#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 {