Merge "input: synaptics_dsx_2.6: fix issues raised by static analyzer"
This commit is contained in:
commit
9a7c65cabe
6 changed files with 449 additions and 17 deletions
|
@ -25,6 +25,9 @@ Optional property:
|
|||
- synaptics,y-flip : modify orientation of the y axis.
|
||||
- synaptics,reset-delay-ms : reset delay for controller (ms), default 100.
|
||||
- synaptics,max-y-for-2d : maximal y value of the panel.
|
||||
- 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@78b7000 {
|
||||
|
@ -46,5 +49,9 @@ Example:
|
|||
synaptics,max-y-for-2d = <1919>; /* remove if no virtual buttons */
|
||||
synaptics,cap-button-codes = <139 172 158>;
|
||||
synaptics,vir-button-codes = <139 180 2000 320 160 172 540 2000 320 160 158 900 2000 320 160>;
|
||||
/* 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>;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -114,4 +114,14 @@ config TOUCHSCREEN_SYNAPTICS_DSX_VIDEO_v26
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called synaptics_dsx_video.
|
||||
|
||||
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
|
||||
|
|
|
@ -122,6 +122,7 @@ static int synaptics_rmi4_reset_device(struct synaptics_rmi4_data *rmi4_data,
|
|||
bool rebuild);
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work);
|
||||
static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
|
||||
unsigned long event, void *data);
|
||||
#endif
|
||||
|
@ -172,6 +173,19 @@ static ssize_t synaptics_rmi4_wake_gesture_store(struct device *dev,
|
|||
static ssize_t synaptics_rmi4_virtual_key_map_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr, char *buf);
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
|
||||
static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count);
|
||||
|
||||
static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf);
|
||||
#endif
|
||||
|
||||
static irqreturn_t synaptics_rmi4_irq(int irq, void *data);
|
||||
|
||||
struct synaptics_rmi4_f01_device_status {
|
||||
union {
|
||||
struct {
|
||||
|
@ -617,6 +631,14 @@ static struct device_attribute attrs[] = {
|
|||
__ATTR(wake_gesture, (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
synaptics_rmi4_wake_gesture_show,
|
||||
synaptics_rmi4_wake_gesture_store),
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
__ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP),
|
||||
synaptics_rmi4_secure_touch_enable_show,
|
||||
synaptics_rmi4_secure_touch_enable_store),
|
||||
__ATTR(secure_touch, S_IRUGO,
|
||||
synaptics_rmi4_secure_touch_show,
|
||||
NULL),
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct kobj_attribute virtual_key_map_attr = {
|
||||
|
@ -627,6 +649,210 @@ 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)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
data->st_initialized = 0;
|
||||
init_completion(&data->st_powerdown);
|
||||
init_completion(&data->st_irq_processed);
|
||||
|
||||
/* Get clocks */
|
||||
data->core_clk = devm_clk_get(data->pdev->dev.parent, "core_clk");
|
||||
if (IS_ERR(data->core_clk)) {
|
||||
ret = PTR_ERR(data->core_clk);
|
||||
data->core_clk = NULL;
|
||||
dev_warn(data->pdev->dev.parent,
|
||||
"%s: error on clk_get(core_clk): %d\n", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
data->iface_clk = devm_clk_get(data->pdev->dev.parent, "iface_clk");
|
||||
if (IS_ERR(data->iface_clk)) {
|
||||
ret = PTR_ERR(data->iface_clk);
|
||||
data->iface_clk = NULL;
|
||||
dev_warn(data->pdev->dev.parent,
|
||||
"%s: error on clk_get(iface_clk): %d\n", __func__, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
data->st_initialized = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
static ssize_t synaptics_rmi4_secure_touch_enable_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d",
|
||||
atomic_read(&rmi4_data->st_enabled));
|
||||
}
|
||||
/*
|
||||
* Accept only "0" and "1" valid values.
|
||||
* "0" will reset the st_enabled flag, then wake up the reading process and
|
||||
* the interrupt handler.
|
||||
* The bus driver is notified via pm_runtime that it is not required to stay
|
||||
* awake anymore.
|
||||
* It will also make sure the queue of events is emptied in the controller,
|
||||
* in case a touch happened in between the secure touch being disabled and
|
||||
* the local ISR being ungated.
|
||||
* "1" will set the st_enabled flag and clear the st_pending_irqs flag.
|
||||
* The bus driver is requested via pm_runtime to stay awake.
|
||||
*/
|
||||
static ssize_t synaptics_rmi4_secure_touch_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
|
||||
unsigned long value;
|
||||
int err = 0;
|
||||
|
||||
if (count > 2)
|
||||
return -EINVAL;
|
||||
|
||||
err = kstrtoul(buf, 10, &value);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
||||
if (!rmi4_data->st_initialized)
|
||||
return -EIO;
|
||||
|
||||
err = count;
|
||||
|
||||
switch (value) {
|
||||
case 0:
|
||||
if (atomic_read(&rmi4_data->st_enabled) == 0)
|
||||
break;
|
||||
|
||||
synaptics_rmi4_bus_put(rmi4_data);
|
||||
atomic_set(&rmi4_data->st_enabled, 0);
|
||||
synaptics_secure_touch_notify(rmi4_data);
|
||||
complete(&rmi4_data->st_irq_processed);
|
||||
synaptics_rmi4_irq(rmi4_data->irq, rmi4_data);
|
||||
complete(&rmi4_data->st_powerdown);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
if (atomic_read(&rmi4_data->st_enabled)) {
|
||||
err = -EBUSY;
|
||||
break;
|
||||
}
|
||||
|
||||
synchronize_irq(rmi4_data->irq);
|
||||
|
||||
if (synaptics_rmi4_bus_get(rmi4_data) < 0) {
|
||||
dev_err(
|
||||
rmi4_data->pdev->dev.parent,
|
||||
"synaptics_rmi4_bus_get failed\n");
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
reinit_completion(&rmi4_data->st_powerdown);
|
||||
reinit_completion(&rmi4_data->st_irq_processed);
|
||||
atomic_set(&rmi4_data->st_enabled, 1);
|
||||
atomic_set(&rmi4_data->st_pending_irqs, 0);
|
||||
break;
|
||||
default:
|
||||
dev_err(
|
||||
rmi4_data->pdev->dev.parent,
|
||||
"unsupported value: %lu\n", value);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns whether there are pending interrupts, or
|
||||
* other error conditions that need to be signaled to the userspace library,
|
||||
* according tot he following logic:
|
||||
* - st_enabled is 0 if secure touch is not enabled, returning -EBADF
|
||||
* - st_pending_irqs is -1 to signal that secure touch is in being stopped,
|
||||
* returning -EINVAL
|
||||
* - st_pending_irqs is 1 to signal that there is a pending irq, returning
|
||||
* the value "1" to the sysfs read operation
|
||||
* - st_pending_irqs is 0 (only remaining case left) if the pending interrupt
|
||||
* has been processed, so the interrupt handler can be allowed to continue.
|
||||
*/
|
||||
static ssize_t synaptics_rmi4_secure_touch_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct synaptics_rmi4_data *rmi4_data = dev_get_drvdata(dev);
|
||||
int val = 0;
|
||||
|
||||
if (atomic_read(&rmi4_data->st_enabled) == 0)
|
||||
return -EBADF;
|
||||
|
||||
if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, -1, 0) == -1)
|
||||
return -EINVAL;
|
||||
|
||||
if (atomic_cmpxchg(&rmi4_data->st_pending_irqs, 1, 0) == 1)
|
||||
val = 1;
|
||||
else
|
||||
complete(&rmi4_data->st_irq_processed);
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%u", val);
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static ssize_t synaptics_rmi4_f01_reset_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
|
@ -1173,7 +1399,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
|
|||
#ifndef TYPE_B_PROTOCOL
|
||||
input_mt_sync(rmi4_data->input_dev);
|
||||
#endif
|
||||
input_sync(rmi4_data->input_dev);
|
||||
|
||||
dev_dbg(rmi4_data->pdev->dev.parent,
|
||||
"%s: Finger %d: status = 0x%02x, x = %d, y = %d, wx = %d, wy = %d\n",
|
||||
|
@ -1245,7 +1470,6 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
|
|||
#ifndef TYPE_B_PROTOCOL
|
||||
input_mt_sync(rmi4_data->input_dev);
|
||||
#endif
|
||||
input_sync(rmi4_data->input_dev);
|
||||
|
||||
if (rmi4_data->stylus_enable) {
|
||||
stylus_presence = 0;
|
||||
|
@ -1261,6 +1485,8 @@ static int synaptics_rmi4_f12_abs_report(struct synaptics_rmi4_data *rmi4_data,
|
|||
}
|
||||
}
|
||||
|
||||
input_sync(rmi4_data->input_dev);
|
||||
|
||||
mutex_unlock(&(rmi4_data->rmi4_report_mutex));
|
||||
|
||||
return touch_count;
|
||||
|
@ -1512,6 +1738,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;
|
||||
|
||||
|
@ -2911,7 +3140,9 @@ static int synaptics_rmi4_gpio_setup(int gpio, bool config, int dir, int state)
|
|||
unsigned char buf[16];
|
||||
|
||||
if (config) {
|
||||
snprintf(buf, PAGE_SIZE, "dsx_gpio_%u\n", gpio);
|
||||
retval = snprintf(buf, ARRAY_SIZE(buf), "dsx_gpio_%u\n", gpio);
|
||||
if (retval >= 16)
|
||||
return -EINVAL;
|
||||
|
||||
retval = gpio_request(gpio, buf);
|
||||
if (retval) {
|
||||
|
@ -3784,6 +4015,8 @@ static int synaptics_rmi4_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
INIT_WORK(&rmi4_data->fb_notify_work,
|
||||
synaptics_rmi4_fb_notify_resume_work);
|
||||
rmi4_data->fb_notifier.notifier_call = synaptics_rmi4_fb_notifier_cb;
|
||||
retval = fb_register_client(&rmi4_data->fb_notifier);
|
||||
if (retval < 0) {
|
||||
|
@ -3849,25 +4082,52 @@ static int synaptics_rmi4_probe(struct platform_device *pdev)
|
|||
|
||||
rmi4_data->rb_workqueue =
|
||||
create_singlethread_workqueue("dsx_rebuild_workqueue");
|
||||
if (!rmi4_data->rb_workqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto err_rb_workqueue;
|
||||
}
|
||||
INIT_DELAYED_WORK(&rmi4_data->rb_work, synaptics_rmi4_rebuild_work);
|
||||
|
||||
exp_data.workqueue = create_singlethread_workqueue("dsx_exp_workqueue");
|
||||
if (!exp_data.workqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto err_exp_data_workqueue;
|
||||
}
|
||||
INIT_DELAYED_WORK(&exp_data.work, synaptics_rmi4_exp_fn_work);
|
||||
exp_data.rmi4_data = rmi4_data;
|
||||
exp_data.queue_work = true;
|
||||
queue_delayed_work(exp_data.workqueue,
|
||||
&exp_data.work,
|
||||
0);
|
||||
queue_delayed_work(exp_data.workqueue, &exp_data.work, 0);
|
||||
|
||||
#ifdef FB_READY_RESET
|
||||
rmi4_data->reset_workqueue =
|
||||
create_singlethread_workqueue("dsx_reset_workqueue");
|
||||
if (!rmi4_data->reset_workqueue) {
|
||||
retval = -ENOMEM;
|
||||
goto err_reset_workqueue;
|
||||
}
|
||||
INIT_WORK(&rmi4_data->reset_work, synaptics_rmi4_reset_work);
|
||||
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;
|
||||
|
||||
#ifdef FB_READY_RESET
|
||||
err_reset_workqueue:
|
||||
#endif
|
||||
cancel_delayed_work_sync(&exp_data.work);
|
||||
flush_workqueue(exp_data.workqueue);
|
||||
destroy_workqueue(exp_data.workqueue);
|
||||
|
||||
err_exp_data_workqueue:
|
||||
cancel_delayed_work_sync(&rmi4_data->rb_work);
|
||||
flush_workqueue(rmi4_data->rb_workqueue);
|
||||
destroy_workqueue(rmi4_data->rb_workqueue);
|
||||
|
||||
err_rb_workqueue:
|
||||
err_sysfs:
|
||||
for (attr_count--; attr_count >= 0; attr_count--) {
|
||||
sysfs_remove_file(&rmi4_data->input_dev->dev.kobj,
|
||||
|
@ -4096,6 +4356,14 @@ static void synaptics_rmi4_wakeup_gesture(struct synaptics_rmi4_data *rmi4_data,
|
|||
}
|
||||
|
||||
#ifdef CONFIG_FB
|
||||
static void synaptics_rmi4_fb_notify_resume_work(struct work_struct *work)
|
||||
{
|
||||
struct synaptics_rmi4_data *rmi4_data =
|
||||
container_of(work, struct synaptics_rmi4_data, fb_notify_work);
|
||||
synaptics_rmi4_resume(&(rmi4_data->input_dev->dev));
|
||||
rmi4_data->fb_ready = true;
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
|
||||
unsigned long event, void *data)
|
||||
{
|
||||
|
@ -4106,14 +4374,36 @@ static int synaptics_rmi4_fb_notifier_cb(struct notifier_block *self,
|
|||
fb_notifier);
|
||||
|
||||
if (evdata && evdata->data && rmi4_data) {
|
||||
if (event == FB_EVENT_BLANK) {
|
||||
transition = evdata->data;
|
||||
if (*transition == FB_BLANK_POWERDOWN) {
|
||||
synaptics_rmi4_suspend(&rmi4_data->pdev->dev);
|
||||
rmi4_data->fb_ready = false;
|
||||
} else if (*transition == FB_BLANK_UNBLANK) {
|
||||
synaptics_rmi4_resume(&rmi4_data->pdev->dev);
|
||||
rmi4_data->fb_ready = true;
|
||||
if (rmi4_data->hw_if->board_data->resume_in_workqueue) {
|
||||
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) {
|
||||
flush_work(
|
||||
&(rmi4_data->fb_notify_work));
|
||||
synaptics_rmi4_suspend(
|
||||
&rmi4_data->pdev->dev);
|
||||
rmi4_data->fb_ready = false;
|
||||
} else if (*transition == FB_BLANK_UNBLANK) {
|
||||
schedule_work(
|
||||
&(rmi4_data->fb_notify_work));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
rmi4_data->fb_ready = false;
|
||||
} else if (*transition == FB_BLANK_UNBLANK) {
|
||||
synaptics_rmi4_resume(
|
||||
&rmi4_data->pdev->dev);
|
||||
rmi4_data->fb_ready = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4133,6 +4423,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 +4468,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 +4516,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);
|
||||
|
@ -4237,6 +4539,10 @@ exit:
|
|||
}
|
||||
mutex_unlock(&exp_data.mutex);
|
||||
|
||||
if (!rmi4_data->suspend) {
|
||||
synaptics_rmi4_enable_reg(rmi4_data, false);
|
||||
synaptics_rmi4_get_reg(rmi4_data, false);
|
||||
}
|
||||
rmi4_data->suspend = true;
|
||||
|
||||
return 0;
|
||||
|
@ -4253,6 +4559,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);
|
||||
|
@ -4261,6 +4569,11 @@ static int synaptics_rmi4_resume(struct device *dev)
|
|||
|
||||
rmi4_data->current_page = MASK_8BIT;
|
||||
|
||||
if (rmi4_data->suspend) {
|
||||
synaptics_rmi4_get_reg(rmi4_data, true);
|
||||
synaptics_rmi4_enable_reg(rmi4_data, true);
|
||||
}
|
||||
|
||||
synaptics_rmi4_sleep_enable(rmi4_data, false);
|
||||
synaptics_rmi4_irq_enable(rmi4_data, true, false);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
*
|
||||
* Copyright (C) 2016 The Linux Foundation. All rights reserved.
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
|
@ -48,6 +48,13 @@
|
|||
#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>
|
||||
#include <linux/clk.h>
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 38))
|
||||
#define KERNEL_ABOVE_2_6_38
|
||||
#endif
|
||||
|
@ -324,6 +331,7 @@ struct synaptics_rmi4_data {
|
|||
struct delayed_work rb_work;
|
||||
struct workqueue_struct *rb_workqueue;
|
||||
#ifdef CONFIG_FB
|
||||
struct work_struct fb_notify_work;
|
||||
struct notifier_block fb_notifier;
|
||||
struct work_struct reset_work;
|
||||
struct workqueue_struct *reset_workqueue;
|
||||
|
@ -374,6 +382,15 @@ 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;
|
||||
bool st_initialized;
|
||||
struct clk *core_clk;
|
||||
struct clk *iface_clk;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct synaptics_dsx_bus_access {
|
||||
|
@ -382,6 +399,10 @@ struct synaptics_dsx_bus_access {
|
|||
unsigned char *data, unsigned short length);
|
||||
int (*write)(struct synaptics_rmi4_data *rmi4_data, unsigned short addr,
|
||||
unsigned char *data, unsigned short length);
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
int (*get)(struct synaptics_rmi4_data *rmi4_data);
|
||||
void (*put)(struct synaptics_rmi4_data *rmi4_data);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct synaptics_dsx_hw_interface {
|
||||
|
@ -432,6 +453,17 @@ static inline int synaptics_rmi4_reg_write(
|
|||
return rmi4_data->hw_if->bus_access->write(rmi4_data, addr, data, len);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
static inline int synaptics_rmi4_bus_get(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
return rmi4_data->hw_if->bus_access->get(rmi4_data);
|
||||
}
|
||||
static inline void synaptics_rmi4_bus_put(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
rmi4_data->hw_if->bus_access->put(rmi4_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline ssize_t synaptics_rmi4_show_error(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
*
|
||||
* Copyright (C) 2016, The Linux Foundation. All rights reserved.
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
|
@ -78,6 +78,9 @@ static int parse_dt(struct device *dev, struct synaptics_dsx_board_data *bdata)
|
|||
else
|
||||
bdata->irq_on_state = value;
|
||||
|
||||
bdata->resume_in_workqueue = of_property_read_bool(np,
|
||||
"synaptics,resume-in-workqueue");
|
||||
|
||||
retval = of_property_read_string(np, "synaptics,pwr-reg-name", &name);
|
||||
if (retval < 0)
|
||||
bdata->pwr_reg_name = NULL;
|
||||
|
@ -288,7 +291,7 @@ static void synaptics_rmi4_i2c_check_addr(struct synaptics_rmi4_data *rmi4_data,
|
|||
static int synaptics_rmi4_i2c_set_page(struct synaptics_rmi4_data *rmi4_data,
|
||||
unsigned short addr)
|
||||
{
|
||||
int retval;
|
||||
int retval = 0;
|
||||
unsigned char retry;
|
||||
unsigned char buf[PAGE_SELECT_LEN];
|
||||
unsigned char page;
|
||||
|
@ -497,10 +500,73 @@ exit:
|
|||
return retval;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
static int synaptics_rmi4_clk_prepare_enable(
|
||||
struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = clk_prepare_enable(rmi4_data->iface_clk);
|
||||
if (ret) {
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"error on clk_prepare_enable(iface_clk):%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(rmi4_data->core_clk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(rmi4_data->iface_clk);
|
||||
dev_err(rmi4_data->pdev->dev.parent,
|
||||
"error clk_prepare_enable(core_clk):%d\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_clk_disable_unprepare(
|
||||
struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
clk_disable_unprepare(rmi4_data->core_clk);
|
||||
clk_disable_unprepare(rmi4_data->iface_clk);
|
||||
}
|
||||
|
||||
static int synaptics_rmi4_i2c_get(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
int retval;
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
retval = pm_runtime_get_sync(i2c->adapter->dev.parent);
|
||||
if (retval >= 0 && rmi4_data->core_clk != NULL &&
|
||||
rmi4_data->iface_clk != NULL) {
|
||||
retval = synaptics_rmi4_clk_prepare_enable(rmi4_data);
|
||||
if (retval)
|
||||
pm_runtime_put_sync(i2c->adapter->dev.parent);
|
||||
}
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void synaptics_rmi4_i2c_put(struct synaptics_rmi4_data *rmi4_data)
|
||||
{
|
||||
struct i2c_client *i2c = to_i2c_client(rmi4_data->pdev->dev.parent);
|
||||
|
||||
mutex_lock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
if (rmi4_data->core_clk != NULL && rmi4_data->iface_clk != NULL)
|
||||
synaptics_rmi4_clk_disable_unprepare(rmi4_data);
|
||||
pm_runtime_put_sync(i2c->adapter->dev.parent);
|
||||
mutex_unlock(&rmi4_data->rmi4_io_ctrl_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct synaptics_dsx_bus_access bus_access = {
|
||||
.type = BUS_I2C,
|
||||
.read = synaptics_rmi4_i2c_read,
|
||||
.write = synaptics_rmi4_i2c_write,
|
||||
#if defined(CONFIG_SECURE_TOUCH_SYNAPTICS_DSX_V26)
|
||||
.get = synaptics_rmi4_i2c_get,
|
||||
.put = synaptics_rmi4_i2c_put,
|
||||
#endif
|
||||
};
|
||||
|
||||
static void synaptics_rmi4_i2c_dev_release(struct device *dev)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
* Copyright (C) 2012 Alexandra Chin <alexandra.chin@tw.synaptics.com>
|
||||
* Copyright (C) 2012 Scott Lin <scott.lin@tw.synaptics.com>
|
||||
* Copyright (C) 2016, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
@ -57,6 +58,7 @@ struct synaptics_dsx_button_map {
|
|||
* @x_flip: x flip flag
|
||||
* @y_flip: y flip flag
|
||||
* @swap_axes: swap axes flag
|
||||
* @resume_in_workqueue: defer resume function to workqueue
|
||||
* @irq_gpio: attention interrupt GPIO
|
||||
* @irq_on_state: attention interrupt active state
|
||||
* @power_gpio: power switch GPIO
|
||||
|
@ -79,11 +81,13 @@ struct synaptics_dsx_button_map {
|
|||
* @bus_reg_name: pointer to name of regulator for bus pullup control
|
||||
* @cap_button_map: pointer to 0D button map
|
||||
* @vir_button_map: pointer to virtual button map
|
||||
* @resume_in_workqueue: defer resume function to workqueue
|
||||
*/
|
||||
struct synaptics_dsx_board_data {
|
||||
bool x_flip;
|
||||
bool y_flip;
|
||||
bool swap_axes;
|
||||
bool resume_in_workqueue;
|
||||
int irq_gpio;
|
||||
int irq_on_state;
|
||||
int power_gpio;
|
||||
|
|
Loading…
Add table
Reference in a new issue