Re: [PATCH v2] input: add synaptics_i2c driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

Signed-off-by: Dmitry Torokhov <dtor@xxxxxxx>
---

 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 },
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux