From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
To: Mike Rapoport <mike@compulab.co.il>
Cc: Jean Delvare <khali@linux-fr.org>,
grinberg <grinberg@compulab.co.il>,
linux-input <linux-input@vger.kernel.org>
Subject: Re: [PATCH v2] input: add synaptics_i2c driver
Date: Thu, 11 Jun 2009 00:14:29 -0700 [thread overview]
Message-ID: <20090611071428.GC8035@dtor-d630.eng.vmware.com> (raw)
In-Reply-To: <4A262D5F.1070803@compulab.co.il>
Hi Mike,
On Wed, Jun 03, 2009 at 10:59:27AM +0300, Mike Rapoport wrote:
>
> This driver supports Synaptics I2C touchpad controller on eXeda
> mobile device.
>
>
Looks much better, one concern still though:
> +
> +/* Work Handler */
> +static void synaptics_i2c_work_handler(struct work_struct *work)
> +{
> + int data = 1;
> + struct synaptics_i2c *touch =
> + container_of(work, struct synaptics_i2c, dwork.work);
> + unsigned long delay;
> +
> + synaptics_i2c_check_params(touch);
> +
> + do {
> + data = synaptics_i2c_get_input(touch);
> + delay = synaptics_i2c_fix_delay(touch, data);
> + } while (data);
> +
This will spin in the work handler for the duration of the touch
hogging keventd on this CPU and delaying all other scheduled works. I
don't think we can do that.
Please try the patchg below and if it still works I will fold it all
together and queue for upstream. Thanks!
--
Dmitry
Input: synaptics_i2c fixups
From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
---
drivers/input/mouse/synaptics_i2c.c | 94 ++++++++++++++++++++---------------
1 files changed, 53 insertions(+), 41 deletions(-)
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 32a5d87..eac9fdd 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -241,10 +241,10 @@ static s32 synaptics_i2c_reg_get(struct i2c_client *client, u16 reg)
int ret;
ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
- if (ret)
- return ret;
+ if (ret == 0)
+ ret = i2c_smbus_read_byte_data(client, reg & 0xff);
- return i2c_smbus_read_byte_data(client, reg & 0xff);
+ return ret;
}
static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val)
@@ -252,10 +252,10 @@ static s32 synaptics_i2c_reg_set(struct i2c_client *client, u16 reg, u8 val)
int ret;
ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
- if (ret)
- return ret;
+ if (ret == 0)
+ ret = i2c_smbus_write_byte_data(client, reg & 0xff, val);
- return i2c_smbus_write_byte_data(client, reg & 0xff, val);
+ return ret;
}
static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg)
@@ -263,10 +263,10 @@ static s32 synaptics_i2c_word_get(struct i2c_client *client, u16 reg)
int ret;
ret = i2c_smbus_write_byte_data(client, PAGE_SEL_REG, reg >> 8);
- if (ret)
- return ret;
+ if (ret == 0)
+ ret = i2c_smbus_read_word_data(client, reg & 0xff);
- return i2c_smbus_read_word_data(client, reg & 0xff);
+ return ret;
}
static int synaptics_i2c_config(struct i2c_client *client)
@@ -287,11 +287,11 @@ static int synaptics_i2c_config(struct i2c_client *client)
control = synaptics_i2c_reg_get(client, GENERAL_2D_CONTROL_REG);
/* No Deceleration */
- control |= (no_decel) ? 1 << NO_DECELERATION : 0;
+ control |= no_decel ? 1 << NO_DECELERATION : 0;
/* Reduced Reporting */
- control |= (reduce_report) ? 1 << REDUCE_REPORTING : 0;
+ control |= reduce_report ? 1 << REDUCE_REPORTING : 0;
/* No Filter */
- control |= (no_filter) ? 1 << NO_FILTER : 0;
+ control |= no_filter ? 1 << NO_FILTER : 0;
ret = synaptics_i2c_reg_set(client, GENERAL_2D_CONTROL_REG, control);
if (ret)
return ret;
@@ -302,6 +302,7 @@ static int synaptics_i2c_config(struct i2c_client *client)
static int synaptics_i2c_reset_config(struct i2c_client *client)
{
int ret;
+
/* Reset the Touchpad */
ret = synaptics_i2c_reg_set(client, DEV_COMMAND_REG, RESET_COMMAND);
if (ret) {
@@ -329,10 +330,11 @@ static int synaptics_i2c_check_error(struct i2c_client *client)
return ret;
}
-static int synaptics_i2c_get_input(struct synaptics_i2c *touch)
+static bool synaptics_i2c_get_input(struct synaptics_i2c *touch)
{
struct input_dev *input = touch->input;
int xy_delta, gesture;
+ s32 data;
s8 x_delta, y_delta;
/* Deal with spontanious resets and errors */
@@ -340,8 +342,8 @@ static int synaptics_i2c_get_input(struct synaptics_i2c *touch)
return 0;
/* Get Gesture Bit */
- gesture = (synaptics_i2c_reg_get(touch->client, DATA_REG0)
- >> GESTURE) & 0x1;
+ data = synaptics_i2c_reg_get(touch->client, DATA_REG0);
+ gesture = (data >> GESTURE) & 0x1;
/*
* Get Relative axes. we have to get them in one shot,
@@ -361,7 +363,7 @@ static int synaptics_i2c_get_input(struct synaptics_i2c *touch)
input_report_rel(input, REL_Y, -y_delta);
input_sync(input);
- return (xy_delta || gesture) ? 1 : 0;
+ return xy_delta || gesture;
}
static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
@@ -369,8 +371,9 @@ static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
struct synaptics_i2c *touch = dev_id;
/*
- * This cancels the work scheduled in work handler.
- * See explanation on this in work handler func.
+ * We want to have the work run immediately but it might have
+ * already been scheduled with a delay, that's why we have to
+ * cancel it first.
*/
cancel_delayed_work(&touch->dwork);
schedule_delayed_work(&touch->dwork, 0);
@@ -380,34 +383,39 @@ static irqreturn_t synaptics_i2c_irq(int irq, void *dev_id)
static void synaptics_i2c_check_params(struct synaptics_i2c *touch)
{
- int reset = 0;
+ bool reset = false;
+
if (scan_rate != touch->scan_rate_param)
set_scan_rate(touch, scan_rate);
if (no_decel != touch->no_decel_param) {
touch->no_decel_param = no_decel;
- reset = 1;
+ reset = true;
}
+
if (no_filter != touch->no_filter_param) {
touch->no_filter_param = no_filter;
- reset = 1;
+ reset = true;
}
+
if (reduce_report != touch->reduce_report_param) {
touch->reduce_report_param = reduce_report;
- reset = 1;
+ reset = true;
}
+
if (reset)
synaptics_i2c_reset_config(touch->client);
}
/* Control the Device polling rate / Work Handler sleep time */
-unsigned long synaptics_i2c_fix_delay(struct synaptics_i2c *touch, int data)
+unsigned long synaptics_i2c_adjust_delay(struct synaptics_i2c *touch,
+ bool have_data)
{
- int delay, nodata_count_thres;
+ unsigned long delay, nodata_count_thres;
if (polling_req) {
delay = touch->scan_ms;
- if (data) {
+ if (have_data) {
touch->no_data_count = 0;
} else {
nodata_count_thres = NO_DATA_THRES / touch->scan_ms;
@@ -416,26 +424,25 @@ unsigned long synaptics_i2c_fix_delay(struct synaptics_i2c *touch, int data)
else
delay = NO_DATA_SLEEP_MSECS;
}
- } else
- delay = THREAD_IRQ_SLEEP_MSECS;
-
- return msecs_to_jiffies(delay);
+ return msecs_to_jiffies(delay);
+ } else {
+ delay = msecs_to_jiffies(THREAD_IRQ_SLEEP_MSECS);
+ return round_jiffies_relative(delay);
+ }
}
/* Work Handler */
static void synaptics_i2c_work_handler(struct work_struct *work)
{
- int data = 1;
+ bool have_data;
struct synaptics_i2c *touch =
container_of(work, struct synaptics_i2c, dwork.work);
unsigned long delay;
synaptics_i2c_check_params(touch);
- do {
- data = synaptics_i2c_get_input(touch);
- delay = synaptics_i2c_fix_delay(touch, data);
- } while (data);
+ have_data = synaptics_i2c_get_input(touch);
+ delay = synaptics_i2c_adjust_delay(touch, have_data);
/*
* While interrupt driven, there is no real need to poll the device.
@@ -450,8 +457,8 @@ static void synaptics_i2c_work_handler(struct work_struct *work)
static int synaptics_i2c_open(struct input_dev *input)
{
- int ret = 0;
struct synaptics_i2c *touch = input_get_drvdata(input);
+ int ret;
ret = synaptics_i2c_reset_config(touch->client);
if (ret)
@@ -461,7 +468,7 @@ static int synaptics_i2c_open(struct input_dev *input)
schedule_delayed_work(&touch->dwork,
msecs_to_jiffies(NO_DATA_SLEEP_MSECS));
- return ret;
+ return 0;
}
static void synaptics_i2c_close(struct input_dev *input)
@@ -492,13 +499,13 @@ static void synaptics_i2c_set_input_params(struct synaptics_i2c *touch)
input_set_drvdata(input, touch);
/* Register the device as mouse */
- set_bit(EV_REL, input->evbit);
- set_bit(REL_X, input->relbit);
- set_bit(REL_Y, input->relbit);
+ __set_bit(EV_REL, input->evbit);
+ __set_bit(REL_X, input->relbit);
+ __set_bit(REL_Y, input->relbit);
/* Register device's buttons and keys */
- set_bit(EV_KEY, input->evbit);
- set_bit(BTN_LEFT, input->keybit);
+ __set_bit(EV_KEY, input->evbit);
+ __set_bit(BTN_LEFT, input->keybit);
}
struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *client)
@@ -598,6 +605,7 @@ static int __devexit synaptics_i2c_remove(struct i2c_client *client)
return 0;
}
+#ifdef CONFIG_PM
static int synaptics_i2c_suspend(struct i2c_client *client, pm_message_t mesg)
{
struct synaptics_i2c *touch = i2c_get_clientdata(client);
@@ -624,6 +632,10 @@ static int synaptics_i2c_resume(struct i2c_client *client)
return 0;
}
+#else
+#define synaptics_i2c_suspend NULL
+#define synaptics_i2c_resume NULL
+#endif
static const struct i2c_device_id synaptics_i2c_id_table[] = {
{ "synaptics_i2c", 0 },
next prev parent reply other threads:[~2009-06-11 7:20 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-05-20 12:36 [PATCH v2] input: add synaptics_i2c driver Mike Rapoport
2009-05-20 12:49 ` Jean Delvare
2009-06-02 5:40 ` Mike Rapoport
2009-06-02 11:58 ` Dmitry Torokhov
2009-06-03 7:59 ` Mike Rapoport
2009-06-11 5:52 ` Mike Rapoport
2009-06-11 7:14 ` Dmitry Torokhov [this message]
2009-06-11 10:35 ` Mike Rapoport
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090611071428.GC8035@dtor-d630.eng.vmware.com \
--to=dmitry.torokhov@gmail.com \
--cc=grinberg@compulab.co.il \
--cc=khali@linux-fr.org \
--cc=linux-input@vger.kernel.org \
--cc=mike@compulab.co.il \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).