Merge "input: synaptics_dsx_2.6: fix issues raised by static analyzer"

This commit is contained in:
Linux Build Service Account 2016-08-26 22:22:51 -07:00 committed by Gerrit - the friendly Code Review server
commit 9a7c65cabe
6 changed files with 449 additions and 17 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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