Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH 3/9] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode
From: Dmitry Torokhov @ 2013-12-18 14:14 UTC (permalink / raw)
  To: Roger Quadros
  Cc: rydberg-Hk7bIW8heu4wFerOooGFRg, jcbian-mY6CKx1T+M6Pt1CcHtbs0g,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1387358480-8313-4-git-send-email-rogerq-l0cyMroinI0@public.gmane.org>

On Wed, Dec 18, 2013 at 02:51:14PM +0530, Roger Quadros wrote:
> +
> +static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
> +{
> +	struct device *dev = &ts->client->dev;
> +	int ret;
> +
> +	/* disable interrupt generation */
> +	ret = pixcir_int_enable(ts, 0);
> +	if (ret) {
> +		dev_err(dev, "Failed to disable interrupt generation\n");
> +		return ret;
> +	}
> +
> +	disable_irq(ts->client->irq);

Why do you need to disable IRQ? If you disable interrupt generation in
the chip I think you only need to call synchronize_irq() to make sure
it's completed if it happens to be running. Also you need to move the
code:

	tsdata->exiting = true;
	mb();

here from pixcir_i2c_ts_remove() to make sure handler exits promptly.

You will also need to reset tsdata->exiting in your start method.

Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 2/9] Input: pixcir_i2c_ts: Add register definitions
From: Dmitry Torokhov @ 2013-12-18 14:09 UTC (permalink / raw)
  To: Roger Quadros; +Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree
In-Reply-To: <1387358480-8313-3-git-send-email-rogerq@ti.com>

On Wed, Dec 18, 2013 at 02:51:13PM +0530, Roger Quadros wrote:
> Add power and interrupt register definitions.
> 

Please fold into the next patch that uses these definitions.

> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
> ---
>  include/linux/input/pixcir_ts.h | 42 +++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 42 insertions(+)
> 
> diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
> index b34ff7e..f17c192 100644
> --- a/include/linux/input/pixcir_ts.h
> +++ b/include/linux/input/pixcir_ts.h
> @@ -1,6 +1,48 @@
>  #ifndef	_PIXCIR_I2C_TS_H
>  #define	_PIXCIR_I2C_TS_H
>  
> +/*
> + * Register map
> + */
> +#define PIXCIR_REG_POWER_MODE	51
> +#define PIXCIR_REG_INT_MODE	52
> +
> +/*
> + * Power modes:
> + * active: max scan speed
> + * idle: lower scan speed with automatic transition to active on touch
> + * halt: datasheet says sleep but this is more like halt as the chip
> + *       clocks are cut and it can only be brought out of this mode
> + *	 using the RESET pin.
> + */
> +enum pixcir_power_mode {
> +	PIXCIR_POWER_ACTIVE,
> +	PIXCIR_POWER_IDLE,
> +	PIXCIR_POWER_HALT,
> +};
> +
> +#define PIXCIR_POWER_MODE_MASK	0x03
> +#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
> +
> +/*
> + * Interrupt modes:
> + * periodical: interrupt is asserted periodicaly
> + * diff coordinates: interrupt is asserted when coordinates change
> + * level on touch: interrupt level asserted during touch
> + * pulse on touch: interrupt pulse asserted druing touch
> + *
> + */
> +enum pixcir_int_mode {
> +	PIXCIR_INT_PERIODICAL,
> +	PIXCIR_INT_DIFF_COORD,
> +	PIXCIR_INT_LEVEL_TOUCH,
> +	PIXCIR_INT_PULSE_TOUCH,
> +};
> +
> +#define PIXCIR_INT_MODE_MASK	0x03
> +#define PIXCIR_INT_ENABLE	(1UL << 3)
> +#define PIXCIR_INT_POL_HIGH	(1UL << 2)
> +
>  struct pixcir_ts_platform_data {
>  	int (*attb_read_val)(void);
>  	unsigned int x_size;	/* X axis resolution */
> -- 
> 1.8.3.2
> 

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 1/9] Input: pixcir_i2c_ts: Add device tree support
From: Dmitry Torokhov @ 2013-12-18 14:09 UTC (permalink / raw)
  To: Roger Quadros; +Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree
In-Reply-To: <1387358480-8313-2-git-send-email-rogerq@ti.com>

Hi Roger,

On Wed, Dec 18, 2013 at 02:51:12PM +0530, Roger Quadros wrote:
> Provide device tree support and binding information.
> Change platform data parameters from x/y_max to x/y_size..

I'd rather keep them as they were.

> 
> Signed-off-by: Roger Quadros <rogerq@ti.com>
> Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
> ---
>  .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
>  drivers/input/touchscreen/pixcir_i2c_ts.c          | 77 ++++++++++++++++++++--
>  include/linux/input/pixcir_ts.h                    |  5 +-
>  3 files changed, 101 insertions(+), 7 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
> 
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
> new file mode 100644
> index 0000000..c0b0b270
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
> @@ -0,0 +1,26 @@
> +* Pixcir I2C touchscreen controllers
> +
> +Required properties:
> +- compatible: must be "pixcir,pixcir_ts"
> +- reg: I2C address of the chip
> +- interrupts: interrupt to which the chip is connected
> +- attb-gpio: GPIO connected to the ATTB line of the chip
> +- x-size: horizontal resolution of touchscreen
> +- y-size: vertical resolution of touchscreen
> +
> +Example:
> +
> +	i2c@00000000 {
> +		/* ... */
> +
> +		pixcir_ts@5c {
> +			compatible = "pixcir,pixcir_ts";
> +			reg = <0x5c>;
> +			interrupts = <2 0>;
> +			attb-gpio = <&gpf 2 0 2>;
> +			x-size = <800>;
> +			y-size = <600>;
> +		};
> +
> +		/* ... */
> +	};
> diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
> index 6cc6b36..3a447c9 100644
> --- a/drivers/input/touchscreen/pixcir_i2c_ts.c
> +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
> @@ -24,6 +24,10 @@
>  #include <linux/i2c.h>
>  #include <linux/input.h>
>  #include <linux/input/pixcir_ts.h>
> +#include <linux/gpio.h>
> +#include <linux/of.h>
> +#include <linux/of_gpio.h>
> +#include <linux/of_device.h>
>  
>  struct pixcir_i2c_ts_data {
>  	struct i2c_client *client;
> @@ -125,15 +129,65 @@ static int pixcir_i2c_ts_resume(struct device *dev)
>  static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
>  			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
>  
> +#if defined(CONFIG_OF)

#ifdef is preferred for simple conditions.

> +static const struct of_device_id pixcir_of_match[];
> +
> +static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
> +{
> +	struct pixcir_ts_platform_data *pdata;
> +	struct device_node *np = dev->of_node;
> +	const struct of_device_id *match;
> +
> +	match = of_match_device(of_match_ptr(pixcir_of_match), dev);
> +	if (!match)
> +		return ERR_PTR(-EINVAL);

Why do you need an explicit match here?

> +
> +	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
> +	if (!pdata)
> +		return ERR_PTR(-ENOMEM);
> +
> +	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
> +	if (!gpio_is_valid(pdata->gpio_attb))
> +		dev_err(dev, "Failed to get ATTB GPIO\n");
> +
> +	if (of_property_read_u32(np, "x-size", &pdata->x_size)) {
> +		dev_err(dev, "Failed to get x-size property\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	if (of_property_read_u32(np, "y-size", &pdata->y_size)) {
> +		dev_err(dev, "Failed to get y-size property\n");
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
> +				pdata->x_size, pdata->y_size, pdata->gpio_attb);
> +
> +	return pdata;
> +}
> +#else
> +static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
> +{
> +	return NULL;

This should be

	return ERR_PTR(-EINVAL);

since you test it with IS_ERR() later.

> +}
> +#endif
> +
>  static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  					 const struct i2c_device_id *id)
>  {
>  	const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
> +	struct device *dev = &client->dev;
> +	struct device_node *np = dev->of_node;
>  	struct pixcir_i2c_ts_data *tsdata;
>  	struct input_dev *input;
>  	int error;
>  
> -	if (!pdata) {
> +	if (np) {
> +		pdata = pixcir_parse_dt(dev);
> +		if (IS_ERR(pdata))
> +			return PTR_ERR(pdata);

We should be favoring kernel-provided platform data if it is pesent even
if there is dt-data available. This way user can override firmware,m if
needed.

> +
> +	} else if (!pdata) {
>  		dev_err(&client->dev, "platform data not defined\n");
>  		return -EINVAL;
>  	}
> @@ -157,10 +211,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
>  	__set_bit(EV_KEY, input->evbit);
>  	__set_bit(EV_ABS, input->evbit);
>  	__set_bit(BTN_TOUCH, input->keybit);
> -	input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
> -	input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
> -	input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
> -	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
> +	input_set_abs_params(input, ABS_X,
> +					0, pdata->x_size - 1, 0, 0);
> +	input_set_abs_params(input, ABS_Y,
> +					0, pdata->y_size - 1, 0, 0);
> +	input_set_abs_params(input, ABS_MT_POSITION_X,
> +					0, pdata->x_size - 1, 0, 0);
> +	input_set_abs_params(input, ABS_MT_POSITION_Y,
> +					0, pdata->y_size - 1, 0, 0);
>  
>  	input_set_drvdata(input, tsdata);
>  
> @@ -211,11 +269,20 @@ static const struct i2c_device_id pixcir_i2c_ts_id[] = {
>  };
>  MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
>  
> +#if defined(CONFIG_OF)
> +static const struct of_device_id pixcir_of_match[] = {
> +	{ .compatible = "pixcir,pixcir_ts", },
> +	{ }
> +};
> +MODULE_DEVICE_TABLE(of, pixcir_of_match);
> +#endif

#ifdef is preferred for simple conditions.

> +
>  static struct i2c_driver pixcir_i2c_ts_driver = {
>  	.driver = {
>  		.owner	= THIS_MODULE,
>  		.name	= "pixcir_ts",
>  		.pm	= &pixcir_dev_pm_ops,
> +		.of_match_table = of_match_ptr(pixcir_of_match),
>  	},
>  	.probe		= pixcir_i2c_ts_probe,
>  	.remove		= pixcir_i2c_ts_remove,
> diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
> index 7163d91..b34ff7e 100644
> --- a/include/linux/input/pixcir_ts.h
> +++ b/include/linux/input/pixcir_ts.h
> @@ -3,8 +3,9 @@
>  
>  struct pixcir_ts_platform_data {
>  	int (*attb_read_val)(void);
> -	int x_max;
> -	int y_max;
> +	unsigned int x_size;	/* X axis resolution */
> +	unsigned int y_size;	/* Y axis resolution */
> +	int gpio_attb;		/* GPIO connected to ATTB line */
>  };

OK, it looks like the series were split awkwardly: you are defining data
that is used by follow-up patches and its purpose is unclear when
reviewing patch-by-patch. I'd recommend rearranging so that DT support
patch is the very last in the series.

>  
>  #endif
> -- 
> 1.8.3.2
> 

Thanks.

-- 
Dmitry

^ permalink raw reply

* [PATCH 1/9] Input: pixcir_i2c_ts: Add device tree support
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Provide device tree support and binding information.
Change platform data parameters from x/y_max to x/y_size..

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   | 26 ++++++++
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 77 ++++++++++++++++++++--
 include/linux/input/pixcir_ts.h                    |  5 +-
 3 files changed, 101 insertions(+), 7 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
new file mode 100644
index 0000000..c0b0b270
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -0,0 +1,26 @@
+* Pixcir I2C touchscreen controllers
+
+Required properties:
+- compatible: must be "pixcir,pixcir_ts"
+- reg: I2C address of the chip
+- interrupts: interrupt to which the chip is connected
+- attb-gpio: GPIO connected to the ATTB line of the chip
+- x-size: horizontal resolution of touchscreen
+- y-size: vertical resolution of touchscreen
+
+Example:
+
+	i2c@00000000 {
+		/* ... */
+
+		pixcir_ts@5c {
+			compatible = "pixcir,pixcir_ts";
+			reg = <0x5c>;
+			interrupts = <2 0>;
+			attb-gpio = <&gpf 2 0 2>;
+			x-size = <800>;
+			y-size = <600>;
+		};
+
+		/* ... */
+	};
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 6cc6b36..3a447c9 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -24,6 +24,10 @@
 #include <linux/i2c.h>
 #include <linux/input.h>
 #include <linux/input/pixcir_ts.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
 
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
@@ -125,15 +129,65 @@ static int pixcir_i2c_ts_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
 			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
 
+#if defined(CONFIG_OF)
+static const struct of_device_id pixcir_of_match[];
+
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	struct pixcir_ts_platform_data *pdata;
+	struct device_node *np = dev->of_node;
+	const struct of_device_id *match;
+
+	match = of_match_device(of_match_ptr(pixcir_of_match), dev);
+	if (!match)
+		return ERR_PTR(-EINVAL);
+
+	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+	if (!pdata)
+		return ERR_PTR(-ENOMEM);
+
+	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
+	if (!gpio_is_valid(pdata->gpio_attb))
+		dev_err(dev, "Failed to get ATTB GPIO\n");
+
+	if (of_property_read_u32(np, "x-size", &pdata->x_size)) {
+		dev_err(dev, "Failed to get x-size property\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (of_property_read_u32(np, "y-size", &pdata->y_size)) {
+		dev_err(dev, "Failed to get y-size property\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__,
+				pdata->x_size, pdata->y_size, pdata->gpio_attb);
+
+	return pdata;
+}
+#else
+static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
+{
+	return NULL;
+}
+#endif
+
 static int pixcir_i2c_ts_probe(struct i2c_client *client,
 					 const struct i2c_device_id *id)
 {
 	const struct pixcir_ts_platform_data *pdata = client->dev.platform_data;
+	struct device *dev = &client->dev;
+	struct device_node *np = dev->of_node;
 	struct pixcir_i2c_ts_data *tsdata;
 	struct input_dev *input;
 	int error;
 
-	if (!pdata) {
+	if (np) {
+		pdata = pixcir_parse_dt(dev);
+		if (IS_ERR(pdata))
+			return PTR_ERR(pdata);
+
+	} else if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
 	}
@@ -157,10 +211,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	__set_bit(EV_KEY, input->evbit);
 	__set_bit(EV_ABS, input->evbit);
 	__set_bit(BTN_TOUCH, input->keybit);
-	input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0);
-	input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0);
-	input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0);
-	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0);
+	input_set_abs_params(input, ABS_X,
+					0, pdata->x_size - 1, 0, 0);
+	input_set_abs_params(input, ABS_Y,
+					0, pdata->y_size - 1, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_X,
+					0, pdata->x_size - 1, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y,
+					0, pdata->y_size - 1, 0, 0);
 
 	input_set_drvdata(input, tsdata);
 
@@ -211,11 +269,20 @@ static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 
+#if defined(CONFIG_OF)
+static const struct of_device_id pixcir_of_match[] = {
+	{ .compatible = "pixcir,pixcir_ts", },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, pixcir_of_match);
+#endif
+
 static struct i2c_driver pixcir_i2c_ts_driver = {
 	.driver = {
 		.owner	= THIS_MODULE,
 		.name	= "pixcir_ts",
 		.pm	= &pixcir_dev_pm_ops,
+		.of_match_table = of_match_ptr(pixcir_of_match),
 	},
 	.probe		= pixcir_i2c_ts_probe,
 	.remove		= pixcir_i2c_ts_remove,
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 7163d91..b34ff7e 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -3,8 +3,9 @@
 
 struct pixcir_ts_platform_data {
 	int (*attb_read_val)(void);
-	int x_max;
-	int y_max;
+	unsigned int x_size;	/* X axis resolution */
+	unsigned int y_size;	/* Y axis resolution */
+	int gpio_attb;		/* GPIO connected to ATTB line */
 };
 
 #endif
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 0/9] Input: pixcir_i2c_ts: Add Type-B Multitouch support
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros

Hi,

Some variants of the Pixcir I2C touch controller are more suitable for
Type-B multi-touch reporting (e.g. Tango C). This series enhances the driver
to support Type-B multi-touch reports. It also adds device tree support
and power management.

cheers,
-roger

Roger Quadros (9):
  Input: pixcir_i2c_ts: Add device tree support
  Input: pixcir_i2c_ts: Add register definitions
  Input: pixcir_i2c_ts: Initialize interrupt mode and power mode
  Input: pixcir_i2c_ts: Use devres managed resource allocations
  Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
  Input: pixcir_i2c_ts: Add chip specific data structure
  Input: pixcir_i2c_ts: Implement Type B Multi Touch reporting
  Input: pixcir_i2c_ts: Add support for TangoC family
  Input: pixcir_i2c_ts: Implement wakeup from suspend

 .../bindings/input/touchscreen/pixcir_i2c_ts.txt   |  26 +
 drivers/input/touchscreen/pixcir_i2c_ts.c          | 570 +++++++++++++++++----
 include/linux/input/pixcir_ts.h                    |  59 ++-
 3 files changed, 564 insertions(+), 91 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt

-- 
1.8.3.2


^ permalink raw reply

* [PATCH 9/9] Input: pixcir_i2c_ts: Implement wakeup from suspend
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Improve the suspend and resume handlers to allow the device
to wakeup the system from suspend.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 89 ++++++++++++++++++++++---------
 1 file changed, 63 insertions(+), 26 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 3575eab..a7725b9 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -347,32 +347,6 @@ static void pixcir_input_close(struct input_dev *dev)
 	return;
 }
 
-
-#ifdef CONFIG_PM_SLEEP
-static int pixcir_i2c_ts_suspend(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-
-	if (device_may_wakeup(&client->dev))
-		enable_irq_wake(client->irq);
-
-	return 0;
-}
-
-static int pixcir_i2c_ts_resume(struct device *dev)
-{
-	struct i2c_client *client = to_i2c_client(dev);
-
-	if (device_may_wakeup(&client->dev))
-		disable_irq_wake(client->irq);
-
-	return 0;
-}
-#endif
-
-static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
-			 pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
-
 #if defined(CONFIG_OF)
 static const struct of_device_id pixcir_of_match[];
 
@@ -547,6 +521,69 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 	return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int pixcir_i2c_ts_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	if (device_may_wakeup(&client->dev)) {
+		/* need to start device if not open, to be wakeup source */
+		if (!input->users) {
+			ret = pixcir_start(ts);
+			if (ret)
+				goto unlock;
+		}
+
+		enable_irq_wake(client->irq);
+
+	} else if (input->users) {
+		ret = pixcir_stop(ts);
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
+}
+
+static int pixcir_i2c_ts_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pixcir_i2c_ts_data *ts = i2c_get_clientdata(client);
+	struct input_dev *input = ts->input;
+	int ret = 0;
+
+	mutex_lock(&input->mutex);
+
+	if (device_may_wakeup(&client->dev)) {
+		disable_irq_wake(client->irq);
+
+		/* need to stop device if it was not open on suspend */
+		if (!input->users) {
+			ret = pixcir_stop(ts);
+			if (ret)
+				goto unlock;
+		}
+
+	} else if (input->users) {
+		ret = pixcir_start(ts);
+	}
+
+unlock:
+	mutex_unlock(&input->mutex);
+
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops,
+				pixcir_i2c_ts_suspend, pixcir_i2c_ts_resume);
+
 static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 	{ "pixcir_ts", 0 },
 	{ "pixcir_tangoc", 0},
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 8/9] Input: pixcir_i2c_ts: Add support for TangoC family
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Add support for Pixcir TangoC controller.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 .../devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt         | 2 +-
 drivers/input/touchscreen/pixcir_i2c_ts.c                           | 6 ++++++
 2 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
index c0b0b270..0ab9505 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt
@@ -1,7 +1,7 @@
 * Pixcir I2C touchscreen controllers
 
 Required properties:
-- compatible: must be "pixcir,pixcir_ts"
+- compatible: must be "pixcir,pixcir_ts" or "pixcir,pixcir_tangoc"
 - reg: I2C address of the chip
 - interrupts: interrupt to which the chip is connected
 - attb-gpio: GPIO connected to the ATTB line of the chip
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 9e14415..3575eab 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -549,13 +549,19 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 static const struct i2c_device_id pixcir_i2c_ts_id[] = {
 	{ "pixcir_ts", 0 },
+	{ "pixcir_tangoc", 0},
 	{ }
 };
 MODULE_DEVICE_TABLE(i2c, pixcir_i2c_ts_id);
 
 #if defined(CONFIG_OF)
+static const struct pixcir_i2c_chip_data tangoc_data = {
+	.num_report_ids = 5,
+};
+
 static const struct of_device_id pixcir_of_match[] = {
 	{ .compatible = "pixcir,pixcir_ts", },
+	{ .compatible = "pixcir,pixcir_tangoc", .data = &tangoc_data, },
 	{ }
 };
 MODULE_DEVICE_TABLE(of, pixcir_of_match);
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 7/9] Input: pixcir_i2c_ts: Implement Type B Multi Touch reporting
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Some pixcir controllers e.g. tangoC family report finger IDs with
the co-ordinates and are more suitable for Type-B MT protocol.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 202 +++++++++++++++++++++++-------
 1 file changed, 155 insertions(+), 47 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index ff68246..9e14415 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -23,84 +23,173 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/input.h>
+#include <linux/input/mt.h>
 #include <linux/input/pixcir_ts.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
 #include <linux/of_device.h>
 
+#define MAX_FINGERS	5	/* Maximum supported by the driver */
+
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
 	const struct pixcir_ts_platform_data *pdata;
 	bool exiting;
+	u8 max_fingers;		/* Maximum supported by the chip */
 };
 
-static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
+static void pixcir_ts_typea_report(struct pixcir_i2c_ts_data *tsdata)
 {
-	struct pixcir_i2c_ts_data *tsdata = data;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 	u8 rdbuf[10], wrbuf[1] = { 0 };
 	u8 touch;
 	int ret;
 
-	ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
-	if (ret != sizeof(wrbuf)) {
-		dev_err(&tsdata->client->dev,
-			"%s: i2c_master_send failed(), ret=%d\n",
-			__func__, ret);
-		return;
-	}
+	while (!tsdata->exiting) {
 
-	ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
-	if (ret != sizeof(rdbuf)) {
-		dev_err(&tsdata->client->dev,
-			"%s: i2c_master_recv failed(), ret=%d\n",
-			__func__, ret);
-		return;
-	}
+		ret = i2c_master_send(tsdata->client, wrbuf, sizeof(wrbuf));
+		if (ret != sizeof(wrbuf)) {
+			dev_err(&tsdata->client->dev,
+				 "%s: i2c_master_send failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
+
+		ret = i2c_master_recv(tsdata->client, rdbuf, sizeof(rdbuf));
+		if (ret != sizeof(rdbuf)) {
+			dev_err(&tsdata->client->dev,
+				 "%s: i2c_master_recv failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
 
-	touch = rdbuf[0];
-	if (touch) {
-		u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
-		u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
-		u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
-		u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
-
-		input_report_key(tsdata->input, BTN_TOUCH, 1);
-		input_report_abs(tsdata->input, ABS_X, posx1);
-		input_report_abs(tsdata->input, ABS_Y, posy1);
-
-		input_report_abs(tsdata->input, ABS_MT_POSITION_X, posx1);
-		input_report_abs(tsdata->input, ABS_MT_POSITION_Y, posy1);
-		input_mt_sync(tsdata->input);
-
-		if (touch == 2) {
-			input_report_abs(tsdata->input,
-					 ABS_MT_POSITION_X, posx2);
-			input_report_abs(tsdata->input,
-					 ABS_MT_POSITION_Y, posy2);
+		touch = rdbuf[0];
+		if (touch) {
+			u16 posx1 = (rdbuf[3] << 8) | rdbuf[2];
+			u16 posy1 = (rdbuf[5] << 8) | rdbuf[4];
+			u16 posx2 = (rdbuf[7] << 8) | rdbuf[6];
+			u16 posy2 = (rdbuf[9] << 8) | rdbuf[8];
+
+			input_report_key(tsdata->input, BTN_TOUCH, 1);
+			input_report_abs(tsdata->input, ABS_X, posx1);
+			input_report_abs(tsdata->input, ABS_Y, posy1);
+
+			input_report_abs(tsdata->input, ABS_MT_POSITION_X,
+									posx1);
+			input_report_abs(tsdata->input, ABS_MT_POSITION_Y,
+									posy1);
 			input_mt_sync(tsdata->input);
+
+			if (touch == 2) {
+				input_report_abs(tsdata->input,
+						ABS_MT_POSITION_X, posx2);
+				input_report_abs(tsdata->input,
+						ABS_MT_POSITION_Y, posy2);
+				input_mt_sync(tsdata->input);
+			}
+		} else {
+			input_report_key(tsdata->input, BTN_TOUCH, 0);
 		}
-	} else {
-		input_report_key(tsdata->input, BTN_TOUCH, 0);
-	}
 
-	input_sync(tsdata->input);
+		input_sync(tsdata->input);
+
+		if (gpio_get_value(pdata->gpio_attb))
+			break;
+
+		msleep(20);
+	}
 }
 
-static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+static void pixcir_ts_typeb_report(struct pixcir_i2c_ts_data *ts)
 {
-	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
+	const struct pixcir_ts_platform_data *pdata = ts->pdata;
+	struct device *dev = &ts->client->dev;
+	u8 rdbuf[32], wrbuf[1] = { 0 };
+	u8 *bufptr;
+	u8 num_fingers;
+	u8 unreliable;
+	int ret, i;
+
+	while (!ts->exiting) {
+
+		ret = i2c_master_send(ts->client, wrbuf, sizeof(wrbuf));
+		if (ret != sizeof(wrbuf)) {
+			dev_err(dev, "%s: i2c_master_send failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
 
-	while (!tsdata->exiting) {
-		pixcir_ts_poscheck(tsdata);
+		ret = i2c_master_recv(ts->client, rdbuf, sizeof(rdbuf));
+		if (ret != sizeof(rdbuf)) {
+			dev_err(dev, "%s: i2c_master_recv failed(), ret=%d\n",
+				 __func__, ret);
+			return;
+		}
+
+		unreliable = rdbuf[0] & 0xe0;
+
+		if (unreliable)
+			goto next;	/* ignore unreliable data */
+
+		num_fingers = rdbuf[0] & 0x7;
+		bufptr = &rdbuf[2];
 
+		if (num_fingers > ts->max_fingers) {
+			num_fingers = ts->max_fingers;
+			dev_dbg(dev, "limiting num_fingers to %d\n",
+								num_fingers);
+		}
+
+		for (i = 0; i < num_fingers; i++) {
+			u8 id;
+			unsigned int x, y;
+			int slot;
+
+			id = bufptr[4];
+			slot = input_mt_get_slot_by_key(ts->input, id);
+			if (slot < 0) {
+				dev_dbg(dev, "no free slot for id 0x%x\n", id);
+				continue;
+			}
+
+
+			x = bufptr[1] << 8 | bufptr[0];
+			y = bufptr[3] << 8 | bufptr[2];
+
+			input_mt_slot(ts->input, slot);
+			input_mt_report_slot_state(ts->input,
+							MT_TOOL_FINGER, true);
+
+			input_event(ts->input, EV_ABS, ABS_MT_POSITION_X, x);
+			input_event(ts->input, EV_ABS, ABS_MT_POSITION_Y, y);
+
+			bufptr = &bufptr[5];
+			dev_dbg(dev, "%d: id 0x%x slot %d, x %d, y %d\n",
+							i, id, slot, x, y);
+		}
+
+		/* One frame is complete so sync it */
+		input_mt_sync_frame(ts->input);
+		input_sync(ts->input);
+
+next:
 		if (gpio_get_value(pdata->gpio_attb))
 			break;
 
-		msleep(20);
+		usleep_range(2000, 5000);
 	}
+}
+
+static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
+{
+	struct pixcir_i2c_ts_data *tsdata = dev_id;
+
+	if (tsdata->input->mt)
+		pixcir_ts_typeb_report(tsdata);
+	else
+		pixcir_ts_typea_report(tsdata);
 
 	return IRQ_HANDLED;
 }
@@ -376,9 +465,9 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	input->open = pixcir_input_open;
 	input->close = pixcir_input_close;
 
-	__set_bit(EV_KEY, input->evbit);
 	__set_bit(EV_ABS, input->evbit);
 	__set_bit(BTN_TOUCH, input->keybit);
+
 	input_set_abs_params(input, ABS_X,
 					0, pdata->x_size - 1, 0, 0);
 	input_set_abs_params(input, ABS_Y,
@@ -388,6 +477,25 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	input_set_abs_params(input, ABS_MT_POSITION_Y,
 					0, pdata->y_size - 1, 0, 0);
 
+	/* Type-B Multi-Touch support */
+	if (pdata->chip.num_report_ids) {
+		const struct pixcir_i2c_chip_data *chip = &pdata->chip;
+
+		tsdata->max_fingers = chip->num_report_ids;
+		if (tsdata->max_fingers > MAX_FINGERS) {
+			dev_info(dev, "Limiting maximum fingers to %d\n",
+								MAX_FINGERS);
+			tsdata->max_fingers = MAX_FINGERS;
+		}
+
+		error = input_mt_init_slots(input, tsdata->max_fingers,
+					INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+		if (error) {
+			dev_err(dev, "Error initializing Multi-Touch slots\n");
+			return error;
+		}
+	}
+
 	input_set_drvdata(input, tsdata);
 
 	error = devm_gpio_request_one(dev, pdata->gpio_attb,
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 6/9] Input: pixcir_i2c_ts: Add chip specific data structure
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

This is the data that differentiates different pixcir
chips.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c |  8 +++++---
 include/linux/input/pixcir_ts.h           | 11 +++++++++++
 2 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index a783d94..ff68246 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -32,7 +32,7 @@
 struct pixcir_i2c_ts_data {
 	struct i2c_client *client;
 	struct input_dev *input;
-	const struct pixcir_ts_platform_data *chip;
+	const struct pixcir_ts_platform_data *pdata;
 	bool exiting;
 };
 
@@ -91,7 +91,7 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
-	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
+	const struct pixcir_ts_platform_data *pdata = tsdata->pdata;
 
 	while (!tsdata->exiting) {
 		pixcir_ts_poscheck(tsdata);
@@ -301,6 +301,8 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
 	if (!pdata)
 		return ERR_PTR(-ENOMEM);
 
+	pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data;
+
 	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
 	if (!gpio_is_valid(pdata->gpio_attb)) {
 		dev_err(dev, "Failed to get ATTB GPIO\n");
@@ -366,7 +368,7 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	tsdata->client = client;
 	tsdata->input = input;
-	tsdata->chip = pdata;
+	tsdata->pdata = pdata;
 
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index 88ffdb50..b9a2f6f 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -43,10 +43,21 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_ENABLE	(1UL << 3)
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
+/**
+ * struct pixcir_irc_chip_data - chip related data
+ * @num_report_ids:     Max number of finger ids reported simultaneously.
+ *                      if 0 it means chip doesn't support finger id reporting
+ *                      and driver will resort to Type A Multi-Touch reporting.
+ */
+struct pixcir_i2c_chip_data {
+	u8 num_report_ids;
+};
+
 struct pixcir_ts_platform_data {
 	unsigned int x_size;	/* X axis resolution */
 	unsigned int y_size;	/* Y axis resolution */
 	int gpio_attb;		/* GPIO connected to ATTB line */
+	struct pixcir_i2c_chip_data chip;
 };
 
 #endif
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 5/9] Input: pixcir_i2c_ts: Get rid of pdata->attb_read_val()
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Get rid of the attb_read_val() platform hook. Instead,
read the ATTB gpio directly from the driver.

Fail if valid ATTB gpio is not provided by patform data.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 19 +++++++++++++++++--
 include/linux/input/pixcir_ts.h           |  1 -
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 3370fd9..a783d94 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -91,11 +91,12 @@ static void pixcir_ts_poscheck(struct pixcir_i2c_ts_data *data)
 static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 {
 	struct pixcir_i2c_ts_data *tsdata = dev_id;
+	const struct pixcir_ts_platform_data *pdata = tsdata->chip;
 
 	while (!tsdata->exiting) {
 		pixcir_ts_poscheck(tsdata);
 
-		if (tsdata->chip->attb_read_val())
+		if (gpio_get_value(pdata->gpio_attb))
 			break;
 
 		msleep(20);
@@ -301,8 +302,10 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev)
 		return ERR_PTR(-ENOMEM);
 
 	pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0);
-	if (!gpio_is_valid(pdata->gpio_attb))
+	if (!gpio_is_valid(pdata->gpio_attb)) {
 		dev_err(dev, "Failed to get ATTB GPIO\n");
+		return ERR_PTR(-EINVAL);
+	}
 
 	if (of_property_read_u32(np, "x-size", &pdata->x_size)) {
 		dev_err(dev, "Failed to get x-size property\n");
@@ -344,6 +347,11 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	} else if (!pdata) {
 		dev_err(&client->dev, "platform data not defined\n");
 		return -EINVAL;
+	} else {
+		if (!gpio_is_valid(pdata->gpio_attb)) {
+			dev_err(dev, "Invalid gpio_attb in pdata\n");
+			return -EINVAL;
+		}
 	}
 
 	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
@@ -380,6 +388,13 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input_set_drvdata(input, tsdata);
 
+	error = devm_gpio_request_one(dev, pdata->gpio_attb,
+			GPIOF_DIR_IN, "pixcir_i2c_attb");
+	if (error) {
+		dev_err(dev, "Failed to request ATTB gpio\n");
+		return error;
+	}
+
 	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
 				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 				     client->name, tsdata);
diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index f17c192..88ffdb50 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -44,7 +44,6 @@ enum pixcir_int_mode {
 #define PIXCIR_INT_POL_HIGH	(1UL << 2)
 
 struct pixcir_ts_platform_data {
-	int (*attb_read_val)(void);
 	unsigned int x_size;	/* X axis resolution */
 	unsigned int y_size;	/* Y axis resolution */
 	int gpio_attb;		/* GPIO connected to ATTB line */
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 4/9] Input: pixcir_i2c_ts: Use devres managed resource allocations
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Use devm_() and friends for allocating memory, input device
and IRQ.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 35 ++++++++++++-------------------
 1 file changed, 13 insertions(+), 22 deletions(-)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index ce8abcd..3370fd9 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -346,12 +346,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 		return -EINVAL;
 	}
 
-	tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
-	input = input_allocate_device();
-	if (!tsdata || !input) {
-		dev_err(&client->dev, "Failed to allocate driver data!\n");
-		error = -ENOMEM;
-		goto err_free_mem;
+	tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL);
+	if (!tsdata)
+		return -ENOMEM;
+
+	input = devm_input_allocate_device(dev);
+	if (!input) {
+		dev_err(&client->dev, "Failed to allocate input device\n");
+		return -ENOMEM;
 	}
 
 	tsdata->client = client;
@@ -378,12 +380,12 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 
 	input_set_drvdata(input, tsdata);
 
-	error = request_threaded_irq(client->irq, NULL, pixcir_ts_isr,
+	error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr,
 				     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
 				     client->name, tsdata);
 	if (error) {
-		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-		goto err_free_mem;
+		dev_err(dev, "failed to request irq %d\n", client->irq);
+		return error;
 	}
 
 	/* Always be in IDLE mode to save power, device supports auto wake */
@@ -396,23 +398,16 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	/* Stop device till opened */
 	error = pixcir_stop(tsdata);
 	if (error)
-		goto err_free_irq;
+		return error;
 
 	error = input_register_device(input);
 	if (error)
-		goto err_free_irq;
+		return error;
 
 	i2c_set_clientdata(client, tsdata);
 	device_init_wakeup(&client->dev, 1);
 
 	return 0;
-
-err_free_irq:
-	free_irq(client->irq, tsdata);
-err_free_mem:
-	input_free_device(input);
-	kfree(tsdata);
-	return error;
 }
 
 static int pixcir_i2c_ts_remove(struct i2c_client *client)
@@ -423,10 +418,6 @@ static int pixcir_i2c_ts_remove(struct i2c_client *client)
 
 	tsdata->exiting = true;
 	mb();
-	free_irq(client->irq, tsdata);
-
-	input_unregister_device(tsdata->input);
-	kfree(tsdata);
 
 	return 0;
 }
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 3/9] Input: pixcir_i2c_ts: Initialize interrupt mode and power mode
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Introduce helper functions to configure power and interrupt
registers. Default to IDLE mode on probe as device supports
auto wakeup to ACVIE mode on detecting finger touch.

Configure interrupt mode and polarity on start up.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 drivers/input/touchscreen/pixcir_i2c_ts.c | 168 ++++++++++++++++++++++++++++++
 1 file changed, 168 insertions(+)

diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 3a447c9..ce8abcd 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -104,6 +104,160 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts,
+						enum pixcir_power_mode mode)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_POWER_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+					__func__, PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~PIXCIR_POWER_MODE_MASK;
+	ret |= mode;
+
+	/* Always AUTO_IDLE */
+	ret |= PIXCIR_POWER_ALLOW_IDLE;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_POWER_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+					__func__, PIXCIR_REG_POWER_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Set the interrupt mode for the device i.e. ATTB line behaviour
+ *
+ * @polarity : 1 for active high, 0 for active low.
+ */
+static int pixcir_set_int_mode(struct pixcir_i2c_ts_data *ts,
+						enum pixcir_int_mode mode,
+					bool polarity)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+					__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	ret &= ~PIXCIR_INT_MODE_MASK;
+	ret |= mode;
+
+	if (polarity)
+		ret |= PIXCIR_INT_POL_HIGH;
+	else
+		ret &= ~PIXCIR_INT_POL_HIGH;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+					__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+/*
+ * Enable/disable interrupt generation
+ */
+static int pixcir_int_enable(struct pixcir_i2c_ts_data *ts, bool enable)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(ts->client, PIXCIR_REG_INT_MODE);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't read reg 0x%x : %d\n",
+					__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	if (enable)
+		ret |= PIXCIR_INT_ENABLE;
+	else
+		ret &= ~PIXCIR_INT_ENABLE;
+
+	ret = i2c_smbus_write_byte_data(ts->client, PIXCIR_REG_INT_MODE, ret);
+	if (ret < 0) {
+		dev_err(dev, "%s: can't write reg 0x%x : %d\n",
+					__func__, PIXCIR_REG_INT_MODE, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pixcir_start(struct pixcir_i2c_ts_data *ts)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	/* LEVEL_TOUCH interrupt with active low polarity */
+	ret = pixcir_set_int_mode(ts, PIXCIR_INT_LEVEL_TOUCH, 0);
+	if (ret) {
+		dev_err(dev, "Failed to set interrupt mode\n");
+		return ret;
+	}
+
+	enable_irq(ts->client->irq);
+
+	/* enable interrupt generation */
+	ret = pixcir_int_enable(ts, 1);
+	if (ret) {
+		dev_err(dev, "Failed to enable interrupt generation\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pixcir_stop(struct pixcir_i2c_ts_data *ts)
+{
+	struct device *dev = &ts->client->dev;
+	int ret;
+
+	/* disable interrupt generation */
+	ret = pixcir_int_enable(ts, 0);
+	if (ret) {
+		dev_err(dev, "Failed to disable interrupt generation\n");
+		return ret;
+	}
+
+	disable_irq(ts->client->irq);
+
+	return 0;
+}
+
+static int pixcir_input_open(struct input_dev *dev)
+{
+	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
+
+	return pixcir_start(ts);
+}
+
+static void pixcir_input_close(struct input_dev *dev)
+{
+	struct pixcir_i2c_ts_data *ts = input_get_drvdata(dev);
+
+	pixcir_stop(ts);
+
+	return;
+}
+
+
 #ifdef CONFIG_PM_SLEEP
 static int pixcir_i2c_ts_suspend(struct device *dev)
 {
@@ -207,6 +361,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 	input->name = client->name;
 	input->id.bustype = BUS_I2C;
 	input->dev.parent = &client->dev;
+	input->open = pixcir_input_open;
+	input->close = pixcir_input_close;
 
 	__set_bit(EV_KEY, input->evbit);
 	__set_bit(EV_ABS, input->evbit);
@@ -230,6 +386,18 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client,
 		goto err_free_mem;
 	}
 
+	/* Always be in IDLE mode to save power, device supports auto wake */
+	error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE);
+	if (error) {
+		dev_err(dev, "Failed to set IDLE mode\n");
+		return error;
+	}
+
+	/* Stop device till opened */
+	error = pixcir_stop(tsdata);
+	if (error)
+		goto err_free_irq;
+
 	error = input_register_device(input);
 	if (error)
 		goto err_free_irq;
-- 
1.8.3.2

^ permalink raw reply related

* [PATCH 2/9] Input: pixcir_i2c_ts: Add register definitions
From: Roger Quadros @ 2013-12-18  9:21 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: rydberg, jcbian, linux-input, linux-kernel, devicetree,
	Roger Quadros
In-Reply-To: <1387358480-8313-1-git-send-email-rogerq@ti.com>

Add power and interrupt register definitions.

Signed-off-by: Roger Quadros <rogerq@ti.com>
Acked-by: Mugunthan V N <mugunthanvnm@ti.com>
---
 include/linux/input/pixcir_ts.h | 42 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/include/linux/input/pixcir_ts.h b/include/linux/input/pixcir_ts.h
index b34ff7e..f17c192 100644
--- a/include/linux/input/pixcir_ts.h
+++ b/include/linux/input/pixcir_ts.h
@@ -1,6 +1,48 @@
 #ifndef	_PIXCIR_I2C_TS_H
 #define	_PIXCIR_I2C_TS_H
 
+/*
+ * Register map
+ */
+#define PIXCIR_REG_POWER_MODE	51
+#define PIXCIR_REG_INT_MODE	52
+
+/*
+ * Power modes:
+ * active: max scan speed
+ * idle: lower scan speed with automatic transition to active on touch
+ * halt: datasheet says sleep but this is more like halt as the chip
+ *       clocks are cut and it can only be brought out of this mode
+ *	 using the RESET pin.
+ */
+enum pixcir_power_mode {
+	PIXCIR_POWER_ACTIVE,
+	PIXCIR_POWER_IDLE,
+	PIXCIR_POWER_HALT,
+};
+
+#define PIXCIR_POWER_MODE_MASK	0x03
+#define PIXCIR_POWER_ALLOW_IDLE (1UL << 2)
+
+/*
+ * Interrupt modes:
+ * periodical: interrupt is asserted periodicaly
+ * diff coordinates: interrupt is asserted when coordinates change
+ * level on touch: interrupt level asserted during touch
+ * pulse on touch: interrupt pulse asserted druing touch
+ *
+ */
+enum pixcir_int_mode {
+	PIXCIR_INT_PERIODICAL,
+	PIXCIR_INT_DIFF_COORD,
+	PIXCIR_INT_LEVEL_TOUCH,
+	PIXCIR_INT_PULSE_TOUCH,
+};
+
+#define PIXCIR_INT_MODE_MASK	0x03
+#define PIXCIR_INT_ENABLE	(1UL << 3)
+#define PIXCIR_INT_POL_HIGH	(1UL << 2)
+
 struct pixcir_ts_platform_data {
 	int (*attb_read_val)(void);
 	unsigned int x_size;	/* X axis resolution */
-- 
1.8.3.2

^ permalink raw reply related

* Re: [PATCH 0/4] Input: ABS2 and friends
From: David Herrmann @ 2013-12-18  8:12 UTC (permalink / raw)
  To: Simon Wood
  Cc: open list:HID CORE LAYER, Dmitry Torokhov, Jiri Kosina,
	Benjamin Tissoires, Peter Hutterer, Antonio Ospite, linux-kernel,
	Input Tools
In-Reply-To: <190d226e64e177a3cb631b8fc6f4787c.squirrel@mungewell.org>

Hi

On Tue, Dec 17, 2013 at 10:28 PM,  <simon@mungewell.org> wrote:
>> Hi
>>
>> This implements the recently discussed ABS2 API. It's working fine on my
>> machine with libevdev. Comments welcome!
>
> Just looking at the documentation file, I have a couple of suggestions.
>
> 1). Make a note on the direction of gravity wrt the example image. Ie what
> which axis/value will be positive with the device laid flat/stationary on
> a desk. Might just prevent some confusion later.

Yepp, can add that to the Accelerometer section.

> 2). Calibration, Accels and Gyros are noisy in different ways. Gyros tend
> to be wrong in the long term, giving some consistant bias which should be
> calibrated out. Accels are noisy in the short term, but generally right
> over a long period.

I'm not entirely sure where to put calibration/normalization. Letting
user-space deal with that should simplify things a lot. We could even
add it to libevdev. Comments welcome..

> Am I correct that the event framework will provide time-stamping of data,
> thus making computation of relative movements possible.

Yes, part of the evdev API.

Thanks
David

^ permalink raw reply

* [RFC Patch v1 10/13] ACPI, i2c-hid: replace open-coded _DSM specific code with helper functions
From: Jiang Liu @ 2013-12-18  6:58 UTC (permalink / raw)
  To: Rafael J . Wysocki, Bjorn Helgaas, Lv Zheng, Len Brown,
	Leonidas Da Silva Barbosa, Ashley Lai, Peter Huewe, Rajiv Andrade,
	Marcel Selhorst, Sirrix AG, Daniel Vetter, David Airlie,
	Jiri Kosina, Benjamin Tissoires, Mika Westerberg,
	Greg Kroah-Hartman, linux-input, linux-kernel
  Cc: Jiang Liu, Tony Luck
In-Reply-To: <1387349901-3391-1-git-send-email-jiang.liu@linux.intel.com>

Use helper functions to simplify _DSM related code in i2c-hid driver.

Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
 drivers/hid/i2c-hid/i2c-hid.c |   26 ++++++--------------------
 1 file changed, 6 insertions(+), 20 deletions(-)

diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 5f7e55f..d22668f 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -850,37 +850,23 @@ static int i2c_hid_acpi_pdata(struct i2c_client *client,
 		0xF7, 0xF6, 0xDF, 0x3C, 0x67, 0x42, 0x55, 0x45,
 		0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE,
 	};
-	union acpi_object params[4];
-	struct acpi_object_list input;
+	union acpi_object *obj;
 	struct acpi_device *adev;
-	unsigned long long value;
 	acpi_handle handle;
 
 	handle = ACPI_HANDLE(&client->dev);
 	if (!handle || acpi_bus_get_device(handle, &adev))
 		return -ENODEV;
 
-	input.count = ARRAY_SIZE(params);
-	input.pointer = params;
-
-	params[0].type = ACPI_TYPE_BUFFER;
-	params[0].buffer.length = sizeof(i2c_hid_guid);
-	params[0].buffer.pointer = i2c_hid_guid;
-	params[1].type = ACPI_TYPE_INTEGER;
-	params[1].integer.value = 1;
-	params[2].type = ACPI_TYPE_INTEGER;
-	params[2].integer.value = 1; /* HID function */
-	params[3].type = ACPI_TYPE_PACKAGE;
-	params[3].package.count = 0;
-	params[3].package.elements = NULL;
-
-	if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_DSM", &input,
-								&value))) {
+	obj = acpi_evaluate_dsm_typed(handle, i2c_hid_guid, 1, 1, NULL,
+				      ACPI_TYPE_INTEGER);
+	if (!obj) {
 		dev_err(&client->dev, "device _DSM execution failed\n");
 		return -ENODEV;
 	}
 
-	pdata->hid_descriptor_address = value;
+	pdata->hid_descriptor_address = obj->integer.value;
+	ACPI_FREE(obj);
 
 	return 0;
 }
-- 
1.7.10.4


^ permalink raw reply related

* [PATCH v2] Input: add i2c/smbus driver for elan touchpad
From: Duson Lin @ 2013-12-18  3:46 UTC (permalink / raw)
  To: linux-kernel, linux-input, dmitry.torokhov
  Cc: bleung, agnescheng, phoenix, Duson Lin

This driver adds support for elan i2c/smbus touchpad found on some laptops PC

Signed-off-by: Duson Lin <dusonlin@emc.com.tw>
---
 drivers/input/mouse/Kconfig    |   10 +
 drivers/input/mouse/Makefile   |    1 +
 drivers/input/mouse/elan_i2c.c |  890 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 901 insertions(+)
 create mode 100644 drivers/input/mouse/elan_i2c.c

diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index effa9c5..095eccc 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -215,6 +215,16 @@ config MOUSE_CYAPA
 	  To compile this driver as a module, choose M here: the module will be
 	  called cyapa.
 
+config MOUSE_ELAN_I2C
+	tristate "ELAN I2C Touchpad support"
+	depends on I2C
+	help
+	  This driver adds support for Elan I2C Trackpads.
+	  Say Y here if you have a ELAN I2C Touchpad.
+
+	  To compile this driver as a module, choose M here: the module will be
+	  called elan_i2c.
+
 config MOUSE_INPORT
 	tristate "InPort/MS/ATIXL busmouse"
 	depends on ISA
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index c25efdb..24a12a6 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_MOUSE_APPLETOUCH)		+= appletouch.o
 obj-$(CONFIG_MOUSE_ATARI)		+= atarimouse.o
 obj-$(CONFIG_MOUSE_BCM5974)		+= bcm5974.o
 obj-$(CONFIG_MOUSE_CYAPA)		+= cyapa.o
+obj-$(CONFIG_MOUSE_ELAN_I2C)		+= elan_i2c.o
 obj-$(CONFIG_MOUSE_GPIO)		+= gpio_mouse.o
 obj-$(CONFIG_MOUSE_INPORT)		+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)		+= logibm.o
diff --git a/drivers/input/mouse/elan_i2c.c b/drivers/input/mouse/elan_i2c.c
new file mode 100644
index 0000000..f7bfa22
--- /dev/null
+++ b/drivers/input/mouse/elan_i2c.c
@@ -0,0 +1,890 @@
+/*
+ * Elan I2C/SMBus Touchpad driver
+ *
+ * Copyright (c) 2013 ELAN Microelectronics Corp.
+ *
+ * Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
+ * Version: 1.4.6
+ *
+ * Based on cyapa driver:
+ * copyright (c) 2011-2012 Cypress Semiconductor, Inc.
+ * copyright (c) 2011-2012 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ * Trademarks are the property of their respective owners.
+ */
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input/mt.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/cdev.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/sched.h>
+#include <linux/input.h>
+#include <linux/uaccess.h>
+#include <linux/jiffies.h>
+
+#define DRIVER_NAME		"elan_i2c"
+#define ELAN_DRIVER_VERSION	"1.4.6"
+#define ETP_PRESSURE_OFFSET	25
+#define ETP_MAX_PRESSURE	255
+#define ETP_FWIDTH_REDUCE	90
+#define ETP_FINGER_WIDTH	15
+
+#define ELAN_ADAPTER_FUNC_NONE   0
+#define ELAN_ADAPTER_FUNC_I2C    1
+#define ELAN_ADAPTER_FUNC_SMBUS  2
+#define ELAN_ADAPTER_FUNC_BOTH   3
+
+/* Length of Elan touchpad information */
+#define ETP_INF_LENGTH		2
+#define ETP_MAX_FINGERS		5
+#define ETP_FINGER_DATA_LEN	5
+#define ETP_REPORT_ID		0x5D
+#define ETP_MAX_REPORT_LEN	34
+#define ETP_ENABLE_ABS		0x0001
+#define ETP_ENABLE_CALIBRATE	0x0002
+#define ETP_DISABLE_CALIBRATE	0x0000
+
+/* Elan smbus command */
+#define ETP_SMBUS_IAP_CMD		0x00
+#define ETP_SMBUS_ENABLE_TP		0x20
+#define ETP_SMBUS_SLEEP_CMD		0x21
+#define ETP_SMBUS_IAP_PASSWORD_WRITE	0x29
+#define ETP_SMBUS_IAP_PASSWORD_READ	0x80
+#define ETP_SMBUS_WRITE_FW_BLOCK	0x2A
+#define ETP_SMBUS_IAP_RESET_CMD		0x2B
+#define ETP_SMBUS_RANGE_CMD		0xA0
+#define ETP_SMBUS_FW_VERSION_CMD	0xA1
+#define ETP_SMBUS_XY_TRACENUM_CMD	0xA2
+#define ETP_SMBUS_SM_VERSION_CMD	0xA3
+#define ETP_SMBUS_UNIQUEID_CMD		0xA3
+#define ETP_SMBUS_RESOLUTION_CMD	0xA4
+#define ETP_SMBUS_HELLOPACKET_CMD	0xA7
+#define ETP_SMBUS_PACKET_QUERY		0xA8
+#define ETP_SMBUS_IAP_VERSION_CMD	0xAC
+#define ETP_SMBUS_IAP_CTRL_CMD		0xAD
+#define ETP_SMBUS_IAP_CHECKSUM_CMD	0xAE
+#define ETP_SMBUS_FW_CHECKSUM_CMD	0xAF
+#define ETP_SMBUS_MAX_BASELINE_CMD	0xC3
+#define ETP_SMBUS_MIN_BASELINE_CMD	0xC4
+#define ETP_SMBUS_CALIBRATE_QUERY	0xC5
+#define ETP_SMBUS_REPORT_LEN		32
+#define ETP_SMBUS_FINGER_DATA_OFFSET	2
+#define ETP_SMBUS_HELLOPACKET_LEN	5
+#define ETP_SMBUS_IAP_PASSWORD		0x1234
+#define ETP_SMBUS_IAP_MODE_ON		(1<<6)
+
+/* Elan i2c command */
+#define ETP_I2C_RESET			0x0100
+#define ETP_I2C_WAKE_UP			0x0800
+#define ETP_I2C_SLEEP			0x0801
+#define ETP_I2C_DESC_CMD		0x0001
+#define ETP_I2C_REPORT_DESC_CMD		0x0002
+#define ETP_I2C_STAND_CMD		0x0005
+#define ETP_I2C_UNIQUEID_CMD		0x0101
+#define ETP_I2C_FW_VERSION_CMD		0x0102
+#define ETP_I2C_SM_VERSION_CMD		0x0103
+#define ETP_I2C_XY_TRACENUM_CMD		0x0105
+#define ETP_I2C_MAX_X_AXIS_CMD		0x0106
+#define ETP_I2C_MAX_Y_AXIS_CMD		0x0107
+#define ETP_I2C_RESOLUTION_CMD		0x0108
+#define ETP_I2C_IAP_VERSION_CMD		0x0110
+#define ETP_I2C_SET_CMD			0x0300
+#define ETP_I2C_MAX_BASELINE_CMD	0x0306
+#define ETP_I2C_MIN_BASELINE_CMD	0x0307
+#define ETP_I2C_FW_CHECKSUM_CMD		0x030F
+#define ETP_I2C_IAP_CTRL_CMD		0x0310
+#define ETP_I2C_IAP_CMD			0x0311
+#define ETP_I2C_IAP_RESET_CMD		0x0314
+#define ETP_I2C_IAP_CHECKSUM_CMD	0x0315
+#define ETP_I2C_CALIBRATE_CMD		0x0316
+#define ETP_I2C_REPORT_LEN		34
+#define ETP_I2C_FINGER_DATA_OFFSET	4
+#define ETP_I2C_REPORT_ID_OFFSET	2
+#define ETP_I2C_DESC_LENGTH		30
+#define ETP_I2C_REPORT_DESC_LENGTH	158
+#define ETP_I2C_IAP_PASSWORD		0x1EA5
+#define ETP_I2C_IAP_RESET		0xF0F0
+#define ETP_I2C_MAIN_MODE_ON		(1<<9)
+#define ETP_I2C_IAP_REG_L		0x01
+#define ETP_I2C_IAP_REG_H		0x06
+
+/* The main device structure */
+struct elan_tp_data {
+	struct i2c_client	*client;
+	struct input_dev	*input;
+	unsigned int		max_x;
+	unsigned int		max_y;
+	unsigned int		width_x;
+	unsigned int		width_y;
+	unsigned int		irq;
+	u16			unique_id;
+	u16			fw_version;
+	u16			sm_version;
+	u16			iap_version;
+	bool			smbus;
+};
+
+/*
+ *******************************************************************
+ * Elan smbus interface
+ *******************************************************************
+ */
+static int elan_smbus_initialize(struct i2c_client *client)
+{
+	u8 check[ETP_SMBUS_HELLOPACKET_LEN] = {0x55, 0x55, 0x55, 0x55, 0x55};
+	u8 values[ETP_SMBUS_HELLOPACKET_LEN] = {0, 0, 0, 0, 0};
+	int ret;
+
+	/* Get hello packet */
+	ret = i2c_smbus_read_block_data(client,
+					ETP_SMBUS_HELLOPACKET_CMD, values);
+	if (ret != ETP_SMBUS_HELLOPACKET_LEN) {
+		dev_err(&client->dev, "hello packet length fail\n");
+		return -1;
+	}
+
+	/* compare hello packet */
+	if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) {
+		dev_err(&client->dev, "hello packet fail [%x %x %x %x %x]\n",
+			values[0], values[1], values[2], values[3], values[4]);
+		return -1;
+	}
+
+	/* enable tp */
+	ret = i2c_smbus_write_byte(client, ETP_SMBUS_ENABLE_TP);
+	return ret;
+}
+
+static int elan_smbus_enable_absolute_mode(struct i2c_client *client)
+{
+	u8 cmd[4] = {0x00, 0x07, 0x00, ETP_ENABLE_ABS};
+
+	return i2c_smbus_write_block_data(client, ETP_SMBUS_IAP_CMD, 4, cmd);
+}
+
+/*
+ ******************************************************************
+ * Elan i2c interface
+ ******************************************************************
+ */
+static int elan_i2c_read_block(struct i2c_client *client,
+			       u16 reg, u8 *val, u16 len)
+{
+	struct i2c_msg msgs[2];
+	u8 buf[2];
+	int ret;
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+
+	msgs[0].addr = client->addr;
+	msgs[0].flags = client->flags & I2C_M_TEN;
+	msgs[0].len = 2;
+	msgs[0].buf = buf;
+
+	msgs[1].addr = client->addr;
+	msgs[1].flags = client->flags & I2C_M_TEN;
+	msgs[1].flags |= I2C_M_RD;
+	msgs[1].len = len;
+	msgs[1].buf = val;
+
+	ret = i2c_transfer(client->adapter, msgs, 2);
+	return ret != 2 ? -EIO : 0;
+}
+
+static int elan_i2c_read_cmd(struct i2c_client *client, u16 reg, u8 *val)
+{
+	int retval;
+
+	retval = elan_i2c_read_block(client, reg, val, ETP_INF_LENGTH);
+	if (retval < 0) {
+		dev_err(&client->dev, "reading cmd (0x%04x) fail.\n", reg);
+		return retval;
+	}
+	return 0;
+}
+
+static int elan_i2c_write_cmd(struct i2c_client *client, u16 reg, u16 cmd)
+{
+	struct i2c_msg msg;
+	u8 buf[4];
+	int ret;
+
+	buf[0] = reg & 0xff;
+	buf[1] = (reg >> 8) & 0xff;
+	buf[2] = cmd & 0xff;
+	buf[3] = (cmd >> 8) & 0xff;
+
+	msg.addr = client->addr;
+	msg.flags = client->flags & I2C_M_TEN;
+	msg.len = 4;
+	msg.buf = buf;
+
+	ret = i2c_transfer(client->adapter, &msg, 1);
+	return ret != 1 ? -EIO : 0;
+}
+
+static int elan_i2c_reset(struct i2c_client *client)
+{
+	return elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD,
+				  ETP_I2C_RESET);
+}
+
+static int elan_i2c_wake_up(struct i2c_client *client)
+{
+	return elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD,
+				  ETP_I2C_WAKE_UP);
+}
+
+static int elan_i2c_sleep(struct i2c_client *client)
+{
+	return elan_i2c_write_cmd(client, ETP_I2C_STAND_CMD,
+				  ETP_I2C_SLEEP);
+}
+
+static int elan_i2c_enable_absolute_mode(struct i2c_client *client)
+{
+	return elan_i2c_write_cmd(client, ETP_I2C_SET_CMD,
+				  ETP_ENABLE_ABS);
+}
+
+static int elan_i2c_get_desc(struct i2c_client *client, u8 *val)
+{
+	return elan_i2c_read_block(client, ETP_I2C_DESC_CMD, val,
+				   ETP_I2C_DESC_LENGTH);
+}
+
+static int elan_i2c_get_report_desc(struct i2c_client *client, u8 *val)
+{
+	return elan_i2c_read_block(client, ETP_I2C_REPORT_DESC_CMD,
+				   val, ETP_I2C_REPORT_DESC_LENGTH);
+}
+
+static int elan_i2c_initialize(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	int rc;
+	u8 val[256];
+
+	rc = elan_i2c_reset(client);
+	if (rc < 0) {
+		dev_err(dev, "device reset failed.\n");
+		return -1;
+	}
+
+	/* wait for get reset return flag */
+	msleep(100);
+	/* get reset return flag 0000 */
+	rc = i2c_master_recv(client, val, ETP_INF_LENGTH);
+	if (rc < 0) {
+		dev_err(dev, "get device reset return value failed.\n");
+		return -1;
+	}
+
+	rc = elan_i2c_get_desc(client, val);
+	if (rc < 0) {
+		dev_err(dev, "cannot get device descriptor.\n");
+		return -1;
+	}
+
+	rc = elan_i2c_get_report_desc(client, val);
+	if (rc < 0) {
+		dev_err(dev, "fetching report descriptor failed.\n");
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ ******************************************************************
+ * General functions
+ ******************************************************************
+ */
+/*
+ * (value from firmware) * 10 + 790 = dpi
+ * we also have to convert dpi to dots/mm (*10/254 to avoid floating point)
+ */
+static unsigned int elan_convert_res(char val)
+{
+	int res;
+	if (val & 0x80) {
+		val = ~val + 1;
+		res = (790 - val * 10) * 10 / 254;
+	} else
+		res = (val * 10 + 790) * 10 / 254;
+	return res;
+}
+
+static int elan_get_iap_version(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_IAP_VERSION_CMD, val);
+		ret = val[2];
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_IAP_VERSION_CMD, val);
+		ret = val[0];
+	}
+	return ret;
+}
+
+static int elan_get_x_max(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_RANGE_CMD, val);
+		ret = (0x0f & val[0]) << 8 | val[1];
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_MAX_X_AXIS_CMD, val);
+		ret = (0x0f & val[1]) << 8 | val[0];
+	}
+	return ret;
+}
+
+static int elan_get_y_max(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_RANGE_CMD, val);
+		ret = (0xf0 & val[0]) << 4 | val[2];
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_MAX_Y_AXIS_CMD, val);
+		ret = (0x0f & val[1]) << 8 | val[0];
+	}
+	return ret;
+}
+
+static int elan_get_x_tracenum(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_XY_TRACENUM_CMD, val);
+		ret = (val[1] - 1);
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_XY_TRACENUM_CMD, val);
+		ret = (val[0] - 1);
+	}
+	return ret;
+}
+
+static int elan_get_y_tracenum(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_XY_TRACENUM_CMD, val);
+		ret = (val[2] - 1);
+	} else {
+		ret = elan_i2c_read_cmd(data->client,
+					ETP_I2C_XY_TRACENUM_CMD, val);
+		ret = (val[1] - 1);
+	}
+	return ret;
+}
+
+static int elan_get_fw_version(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_FW_VERSION_CMD, val);
+		ret = val[2];
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_FW_VERSION_CMD, val);
+		ret = val[0];
+	}
+	return ret;
+}
+
+static int elan_get_sm_version(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus)
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_SM_VERSION_CMD, val);
+	else
+		elan_i2c_read_block(data->client,
+				    ETP_I2C_SM_VERSION_CMD, val, 1);
+	ret = val[0];
+	return ret;
+}
+
+static int elan_get_unique_id(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_UNIQUEID_CMD, val);
+		ret = val[1];
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_UNIQUEID_CMD, val);
+		ret = val[0];
+	}
+	return ret;
+}
+
+static int elan_get_x_resolution(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_RESOLUTION_CMD, val);
+		ret = elan_convert_res(val[1] & 0x0F);
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_RESOLUTION_CMD, val);
+		ret = elan_convert_res(val[0]);
+	}
+	return ret;
+}
+
+static int elan_get_y_resolution(struct elan_tp_data *data)
+{
+	int ret;
+	u8 val[3];
+	if (data->smbus) {
+		i2c_smbus_read_block_data(data->client,
+					  ETP_SMBUS_RESOLUTION_CMD, val);
+		ret = elan_convert_res((val[1] & 0xF0) >> 4);
+	} else {
+		elan_i2c_read_cmd(data->client,
+				  ETP_I2C_RESOLUTION_CMD, val);
+		ret = elan_convert_res(val[1]);
+	}
+	return ret;
+}
+
+static int elan_initialize(struct elan_tp_data *data)
+{
+	int ret;
+	if (data->smbus) {
+		ret = elan_smbus_initialize(data->client);
+		if (ret < 0) {
+			dev_err(&data->client->dev,
+				"device initialize failed.\n");
+			goto err_initialize;
+		}
+
+		ret = elan_smbus_enable_absolute_mode(data->client);
+		if (ret < 0)
+			dev_err(&data->client->dev,
+				"cannot switch to absolute mode.\n");
+	} else {
+		ret = elan_i2c_initialize(data->client);
+		if (ret < 0) {
+			dev_err(&data->client->dev,
+				"device initialize failed.\n");
+			goto err_initialize;
+		}
+
+		ret = elan_i2c_enable_absolute_mode(data->client);
+		if (ret < 0) {
+			dev_err(&data->client->dev,
+				"cannot switch to absolute mode.\n");
+			goto err_initialize;
+		}
+
+		ret = elan_i2c_wake_up(data->client);
+		if (ret < 0)
+			dev_err(&data->client->dev,
+				"device wake up failed.\n");
+	}
+err_initialize:
+	return ret;
+}
+
+
+/*
+ ******************************************************************
+ * Elan isr functions
+ ******************************************************************
+ */
+static int elan_check_packet(struct elan_tp_data *data, u8 *packet)
+{
+	u8 rid;
+
+	if (data->smbus)
+		rid = packet[0];
+	else
+		rid = packet[ETP_I2C_REPORT_ID_OFFSET];
+
+	/* check report id */
+	if (rid != ETP_REPORT_ID) {
+		dev_err(&data->client->dev, "report id [%x] fail.\n", rid);
+		return -1;
+	}
+	return 0;
+}
+
+static void elan_report_absolute(struct elan_tp_data *data, u8 *packet)
+{
+	struct input_dev *input = data->input;
+	u8 *finger_data;
+	bool finger_on;
+	int pos_x, pos_y;
+	int pressure, mk_x, mk_y;
+	int i, area_x, area_y, major, minor, new_pressure;
+	int finger_count = 0;
+	int btn_click;
+	u8  tp_info;
+
+	if (data->smbus) {
+		finger_data = &packet[ETP_SMBUS_FINGER_DATA_OFFSET];
+		tp_info = packet[1];
+	} else {
+		finger_data = &packet[ETP_I2C_FINGER_DATA_OFFSET];
+		tp_info = packet[3];
+	}
+
+	btn_click = (tp_info & 0x01);
+	for (i = 0; i < ETP_MAX_FINGERS; i++) {
+		finger_on = (tp_info >> (3 + i)) & 0x01;
+
+		/* analyze touched finger raw data*/
+		if (finger_on) {
+			pos_x = ((finger_data[0] & 0xf0) << 4) |
+							finger_data[1];
+			pos_y = ((finger_data[0] & 0x0f) << 8) |
+							finger_data[2];
+			pos_y =  data->max_y - pos_y;
+			mk_x = (finger_data[3] & 0x0f);
+			mk_y = (finger_data[3] >> 4);
+			pressure = finger_data[4];
+
+			/*
+			 * to avoid fat finger be as palm, so reduce the
+			 * width x and y per trace
+			 */
+			area_x = mk_x * (data->width_x - ETP_FWIDTH_REDUCE);
+			area_y = mk_y * (data->width_y - ETP_FWIDTH_REDUCE);
+
+			major = max(area_x, area_y);
+			minor = min(area_x, area_y);
+
+			new_pressure = pressure + ETP_PRESSURE_OFFSET;
+			if (new_pressure > ETP_MAX_PRESSURE)
+				new_pressure = ETP_MAX_PRESSURE;
+
+			input_mt_slot(input, i);
+			input_mt_report_slot_state(input, MT_TOOL_FINGER,
+						   true);
+			input_report_abs(input, ABS_MT_POSITION_X, pos_x);
+			input_report_abs(input, ABS_MT_POSITION_Y, pos_y);
+			input_report_abs(input, ABS_MT_PRESSURE, new_pressure);
+			input_report_abs(input, ABS_TOOL_WIDTH, mk_x);
+			input_report_abs(input, ABS_MT_TOUCH_MAJOR, major);
+			input_report_abs(input, ABS_MT_TOUCH_MINOR, minor);
+			finger_data += ETP_FINGER_DATA_LEN;
+			finger_count++;
+		} else {
+			input_mt_slot(input, i);
+			input_mt_report_slot_state(input,
+						   MT_TOOL_FINGER, false);
+		}
+	}
+
+	input_report_key(input, BTN_LEFT, (btn_click == 1));
+	input_mt_report_pointer_emulation(input, true);
+	input_sync(input);
+}
+
+static irqreturn_t elan_isr(int irq, void *dev_id)
+{
+	struct elan_tp_data *data = dev_id;
+	u8 raw[ETP_MAX_REPORT_LEN];
+	int retval;
+	int report_len;
+
+	if (data->smbus) {
+		report_len = ETP_SMBUS_REPORT_LEN;
+		retval = i2c_smbus_read_block_data(data->client,
+						   ETP_SMBUS_PACKET_QUERY,
+						   raw);
+	} else {
+		report_len = ETP_I2C_REPORT_LEN;
+		retval = i2c_master_recv(data->client, raw, report_len);
+	}
+
+	if (retval != report_len) {
+		dev_err(&data->client->dev, "wrong packet len(%d)", retval);
+		goto elan_isr_end;
+	}
+
+	if (elan_check_packet(data, raw) < 0) {
+		dev_err(&data->client->dev, "wrong packet format.");
+		goto elan_isr_end;
+	}
+	elan_report_absolute(data, raw);
+
+elan_isr_end:
+	return IRQ_HANDLED;
+}
+
+/*
+ ******************************************************************
+ * Elan initial functions
+ ******************************************************************
+ */
+static int elan_input_dev_create(struct elan_tp_data *data)
+{
+	struct i2c_client *client = data->client;
+	struct input_dev *input;
+	unsigned int x_res, y_res;
+	int ret, max_width, min_width;
+
+	data->input = input = input_allocate_device();
+	if (!input)
+		return -ENOMEM;
+	input->name = "Elan Touchpad";
+	input->id.bustype = BUS_I2C;
+	input->dev.parent = &data->client->dev;
+
+	__set_bit(EV_ABS, input->evbit);
+	__set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+	__set_bit(BTN_LEFT, input->keybit);
+
+	data->unique_id = elan_get_unique_id(data);
+	data->fw_version = elan_get_fw_version(data);
+	data->sm_version = elan_get_sm_version(data);
+	data->iap_version = elan_get_iap_version(data);
+	data->max_x = elan_get_x_max(data);
+	data->max_y = elan_get_y_max(data);
+	data->width_x = data->max_x / elan_get_x_tracenum(data);
+	data->width_y = data->max_y / elan_get_y_tracenum(data);
+	x_res = elan_get_x_resolution(data);
+	y_res = elan_get_y_resolution(data);
+	max_width = max(data->width_x, data->width_y);
+	min_width = min(data->width_x, data->width_y);
+
+	dev_dbg(&client->dev,
+		"Elan Touchpad Information:\n"
+		"    Module unique ID:  0x%04x\n"
+		"    Firmware Version:  0x%04x\n"
+		"    Sample Version:  0x%04x\n"
+		"    IAP Version:  0x%04x\n"
+		"    Max ABS X,Y:   %d,%d\n"
+		"    Width X,Y:   %d,%d\n"
+		"    Resolution X,Y:   %d,%d (dots/mm)\n",
+		data->unique_id,
+		data->fw_version,
+		data->sm_version,
+		data->iap_version,
+		data->max_x, data->max_y,
+		data->width_x, data->width_y,
+		x_res, y_res);
+
+	input_set_abs_params(input, ABS_X, 0, data->max_x, 0, 0);
+	input_set_abs_params(input, ABS_Y, 0, data->max_y, 0, 0);
+	input_abs_set_res(input, ABS_X, x_res);
+	input_abs_set_res(input, ABS_Y, y_res);
+	input_set_abs_params(input, ABS_PRESSURE, 0, ETP_MAX_PRESSURE, 0, 0);
+	input_set_abs_params(input, ABS_TOOL_WIDTH, 0, ETP_FINGER_WIDTH, 0, 0);
+
+	/* handle pointer emulation and unused slots in core */
+	ret = input_mt_init_slots(input, ETP_MAX_FINGERS,
+				  INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
+	if (ret) {
+		dev_err(&client->dev, "allocate MT slots failed, %d\n", ret);
+		goto err_free_device;
+	}
+	input_set_abs_params(input, ABS_MT_POSITION_X, 0, data->max_x, 0, 0);
+	input_set_abs_params(input, ABS_MT_POSITION_Y, 0, data->max_y, 0, 0);
+	input_abs_set_res(input, ABS_MT_POSITION_X, x_res);
+	input_abs_set_res(input, ABS_MT_POSITION_Y, y_res);
+	input_set_abs_params(input, ABS_MT_PRESSURE, 0,
+			     ETP_MAX_PRESSURE, 0, 0);
+	input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
+			     ETP_FINGER_WIDTH * max_width, 0, 0);
+	input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0,
+			     ETP_FINGER_WIDTH * min_width, 0, 0);
+
+	/* Register the device in input subsystem */
+	ret = input_register_device(input);
+	if (ret) {
+		dev_err(&client->dev, "input_dev register failed, %d\n", ret);
+		goto err_free_device;
+	}
+
+	return 0;
+
+err_free_device:
+	input_free_device(input);
+	return ret;
+}
+
+static u8 elan_check_adapter_functionality(struct i2c_client *client)
+{
+	u8 ret = ELAN_ADAPTER_FUNC_NONE;
+
+	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+		ret |= ELAN_ADAPTER_FUNC_I2C;
+	if (i2c_check_functionality(client->adapter,
+				    I2C_FUNC_SMBUS_BYTE_DATA |
+				    I2C_FUNC_SMBUS_BLOCK_DATA |
+				    I2C_FUNC_SMBUS_I2C_BLOCK))
+		ret |= ELAN_ADAPTER_FUNC_SMBUS;
+	return ret;
+}
+
+static int elan_probe(struct i2c_client *client,
+		      const struct i2c_device_id *dev_id)
+{
+	struct elan_tp_data *data;
+	int ret;
+	u8 adapter_func;
+	union i2c_smbus_data dummy;
+	struct device *dev = &client->dev;
+
+	adapter_func = elan_check_adapter_functionality(client);
+	if (adapter_func == ELAN_ADAPTER_FUNC_NONE) {
+		dev_err(dev, "not a supported I2C/SMBus adapter\n");
+		return -EIO;
+	}
+
+	/* Make sure there is something at this address */
+	if (i2c_smbus_xfer(client->adapter, client->addr, 0,
+			   I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
+		return -ENODEV;
+
+	data = kzalloc(sizeof(struct elan_tp_data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* check protocol type */
+	if (adapter_func == ELAN_ADAPTER_FUNC_SMBUS)
+		data->smbus = true;
+	else
+		data->smbus = false;
+	data->client = client;
+	data->irq = client->irq;
+
+	ret = request_threaded_irq(client->irq, NULL, elan_isr,
+				   IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+				   client->name, data);
+	if (ret < 0) {
+		dev_err(&client->dev, "cannot register irq=%d\n",
+				client->irq);
+		goto err_irq;
+	}
+
+	/* initial elan touch pad */
+	ret = elan_initialize(data);
+	if (ret < 0)
+		goto err_init;
+
+	/* create input device */
+	ret = elan_input_dev_create(data);
+	if (ret < 0)
+		goto err_input_dev;
+
+	device_init_wakeup(&client->dev, 1);
+	i2c_set_clientdata(client, data);
+	return 0;
+
+err_input_dev:
+err_init:
+	free_irq(data->irq, data);
+err_irq:
+	kfree(data);
+	dev_err(&client->dev, "Elan Trackpad probe fail!\n");
+	return ret;
+}
+
+static int elan_remove(struct i2c_client *client)
+{
+	struct elan_tp_data *data = i2c_get_clientdata(client);
+	free_irq(data->irq, data);
+	input_unregister_device(data->input);
+	kfree(data);
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int elan_suspend(struct device *dev)
+{
+	int ret = 0;
+	struct elan_tp_data *data = dev_get_drvdata(dev);
+
+	disable_irq(data->irq);
+	if (data->smbus)
+		ret = i2c_smbus_write_byte(data->client,
+					   ETP_SMBUS_SLEEP_CMD);
+	else
+		ret = elan_i2c_sleep(data->client);
+
+	if (ret < 0)
+		dev_err(dev, "suspend mode failed, %d\n", ret);
+
+	return ret;
+}
+
+static int elan_resume(struct device *dev)
+{
+	int ret = 0;
+	struct elan_tp_data *data = dev_get_drvdata(dev);
+
+	ret = elan_initialize(data);
+	if (ret < 0)
+		dev_err(dev, "resume active power failed, %d\n", ret);
+
+	enable_irq(data->irq);
+	return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(elan_pm_ops, elan_suspend, elan_resume);
+
+static const struct i2c_device_id elan_id[] = {
+	{ DRIVER_NAME, 0 },
+	{ },
+};
+MODULE_DEVICE_TABLE(i2c, elan_id);
+
+static struct i2c_driver elan_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.pm	= &elan_pm_ops,
+	},
+	.probe		= elan_probe,
+	.remove		= elan_remove,
+	.id_table	= elan_id,
+};
+
+module_i2c_driver(elan_driver);
+
+MODULE_AUTHOR("Duson Lin <dusonlin@emc.com.tw>");
+MODULE_DESCRIPTION("Elan I2C/SMBus Touchpad driver");
+MODULE_LICENSE("GPL");
-- 
1.7.10.4

^ permalink raw reply related

* [PATCH] input synaptics-rmi4: Transport layer renaming.
From: Christopher Heiny @ 2013-12-17 21:31 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
	Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
	Linus Walleij, Benjamin Tissoires

The current RMI4 driver uses the term "physical" for two different logical
entities: the communications transport layer (I2C, SPI, and so on), and the
actual RMI4 device that is being communicated with.  Such usage makes the
code harder to understand due to confusion as to just which elements are
being referred to.

This patch renames the transport layer elements in order to eliminate this
confusion.  Much of the renaming was accomplished by the following Bash script

  #!/bin/bash
  #
  # Update RMI4 driver transport layer naming.
  #

  files="rmi_bus.c rmi_bus.h rmi_driver.c rmi_driver.h rmi_f01.c rmi_i2c.c"
  cd drivers/input/rmi4

  for f in $files ; do
    echo $f
    sed -i.bak s/rmi_phys_device/rmi_transport_dev/g $f
    sed -i.bak s/rmi_phys_info/rmi_transport_info/g $f
    sed -i.bak "s/rmi_transport_dev \*phys/rmi_transport_dev \*xport/g" $f
    sed -i.bak "s/rmi_transport_dev \*rmi_phys/rmi_transport_dev \*xport/g" $f
    sed -i.bak "s/phys\([^i]\)/xport\1/g" $f
    sed -i.bak "s/->phys/->xport/g" $f
    sed -i.bak "s/register_physical_device/register_transport_device/g" $f
    sed -i.bak "s/physical_device_count/transport_device_count/g" $f
  done

although some changes proved easier to simply do by hand, particularly in the
comments.  Changes are confined strictly to the renaming, to keep the patch
relatively simple.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

 drivers/input/rmi4/rmi_bus.c    | 38 ++++++++---------
 drivers/input/rmi4/rmi_bus.h    | 54 ++++++++++++-------------
 drivers/input/rmi4/rmi_driver.c | 32 +++++++--------
 drivers/input/rmi4/rmi_driver.h |  2 +-
 drivers/input/rmi4/rmi_i2c.c    | 90 ++++++++++++++++++++---------------------
 5 files changed, 108 insertions(+), 108 deletions(-)

diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 173f6be..96a76e7 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -76,38 +76,38 @@ static void rmi_physical_teardown_debugfs(struct rmi_device *rmi_dev)
 #endif
 
 /**
- * rmi_register_physical_device - register a physical device connection on the RMI
- * bus.  Physical drivers provide communication from the devices on the bus to
- * the RMI4 sensor on a bus such as SPI, I2C, and so on.
+ * rmi_register_transport_device - register a transport device connection
+ * on the RMI bus.  Transport drivers provide communication from the devices
+ * on a bus (such as SPI, I2C, and so on) to the RMI4 sensor.
  *
- * @phys: the physical device to register
+ * @xport: the transport device to register
  */
-int rmi_register_physical_device(struct rmi_phys_device *phys)
+int rmi_register_transport_device(struct rmi_transport_dev *xport)
 {
-	static atomic_t physical_device_count = ATOMIC_INIT(0);
-	struct rmi_device_platform_data *pdata = phys->dev->platform_data;
+	static atomic_t transport_device_count = ATOMIC_INIT(0);
+	struct rmi_device_platform_data *pdata = xport->dev->platform_data;
 	struct rmi_device *rmi_dev;
 	int error;
 
 	if (!pdata) {
-		dev_err(phys->dev, "no platform data!\n");
+		dev_err(xport->dev, "no platform data!\n");
 		return -EINVAL;
 	}
 
-	rmi_dev = devm_kzalloc(phys->dev,
+	rmi_dev = devm_kzalloc(xport->dev,
 				sizeof(struct rmi_device), GFP_KERNEL);
 	if (!rmi_dev)
 		return -ENOMEM;
 
-	rmi_dev->phys = phys;
-	rmi_dev->number = atomic_inc_return(&physical_device_count) - 1;
+	rmi_dev->xport = xport;
+	rmi_dev->number = atomic_inc_return(&transport_device_count) - 1;
 
 	dev_set_name(&rmi_dev->dev, "sensor%02d", rmi_dev->number);
 
 	rmi_dev->dev.bus = &rmi_bus_type;
 	rmi_dev->dev.type = &rmi_device_type;
 
-	phys->rmi_dev = rmi_dev;
+	xport->rmi_dev = rmi_dev;
 
 	rmi_physical_setup_debugfs(rmi_dev);
 
@@ -115,26 +115,26 @@ int rmi_register_physical_device(struct rmi_phys_device *phys)
 	if (error)
 		return error;
 
-	dev_dbg(phys->dev, "%s: Registered %s as %s.\n", __func__,
+	dev_dbg(xport->dev, "%s: Registered %s as %s.\n", __func__,
 		pdata->sensor_name, dev_name(&rmi_dev->dev));
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(rmi_register_physical_device);
+EXPORT_SYMBOL_GPL(rmi_register_transport_device);
 
 /**
- * rmi_unregister_physical_device - unregister a physical device connection
- * @phys: the physical driver to unregister
+ * rmi_unregister_transport_device - unregister a transport device connection
+ * @xport: the transport driver to unregister
  *
  */
-void rmi_unregister_physical_device(struct rmi_phys_device *phys)
+void rmi_unregister_transport_device(struct rmi_transport_dev *xport)
 {
-	struct rmi_device *rmi_dev = phys->rmi_dev;
+	struct rmi_device *rmi_dev = xport->rmi_dev;
 
 	rmi_physical_teardown_debugfs(rmi_dev);
 	device_unregister(&rmi_dev->dev);
 }
-EXPORT_SYMBOL(rmi_unregister_physical_device);
+EXPORT_SYMBOL(rmi_unregister_transport_device);
 
 
 /* Function specific stuff */
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index e2a3dc6..65dd934 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -38,7 +38,7 @@ struct rmi_device;
  * interrupt handling.
  * @data: Private data pointer
  *
- * @node: entry in physical device list of functions
+ * @node: entry in device's list of functions
  * @debugfs_root: used during debugging
  */
 struct rmi_function {
@@ -135,8 +135,8 @@ struct rmi_driver {
 #define to_rmi_driver(d) \
 	container_of(d, struct rmi_driver, driver);
 
-/** struct rmi_phys_info - diagnostic information about the RMI physical
- * device, used in the phys debugfs file.
+/** struct rmi_transport_info - diagnostic information about the RMI transport
+ * device, used in the xport_info debugfs file.
  *
  * @proto String indicating the protocol being used.
  * @tx_count Number of transmit operations.
@@ -147,7 +147,7 @@ struct rmi_driver {
  * @rx_errs  Number of errors encountered during receive operations.
  * @att_count Number of times ATTN assertions have been handled.
  */
-struct rmi_phys_info {
+struct rmi_transport_info {
 	char *proto;
 	long tx_count;
 	long tx_bytes;
@@ -158,7 +158,7 @@ struct rmi_phys_info {
 };
 
 /**
- * struct rmi_phys_device - represent an RMI physical device
+ * struct rmi_transport_dev - represent an RMI transport device
  *
  * @dev: Pointer to the communication device, e.g. i2c or spi
  * @rmi_dev: Pointer to the RMI device
@@ -170,28 +170,28 @@ struct rmi_phys_info {
  * handling
  * @data: Private data pointer
  *
- * The RMI physical device implements the glue between different communication
+ * The RMI transport device implements the glue between different communication
  * buses such as I2C and SPI.
  *
  */
-struct rmi_phys_device {
+struct rmi_transport_dev {
 	struct device *dev;
 	struct rmi_device *rmi_dev;
 
-	int (*write_block)(struct rmi_phys_device *phys, u16 addr,
+	int (*write_block)(struct rmi_transport_dev *xport, u16 addr,
 			   const void *buf, const int len);
-	int (*read_block)(struct rmi_phys_device *phys, u16 addr,
+	int (*read_block)(struct rmi_transport_dev *xport, u16 addr,
 			  void *buf, const int len);
 
-	int (*enable_device) (struct rmi_phys_device *phys);
-	void (*disable_device) (struct rmi_phys_device *phys);
+	int (*enable_device) (struct rmi_transport_dev *xport);
+	void (*disable_device) (struct rmi_transport_dev *xport);
 
 	irqreturn_t (*irq_thread)(int irq, void *p);
 	irqreturn_t (*hard_irq)(int irq, void *p);
 
 	void *data;
 
-	struct rmi_phys_info info;
+	struct rmi_transport_info info;
 };
 
 /**
@@ -200,7 +200,7 @@ struct rmi_phys_device {
  * @dev: The device created for the RMI bus
  * @number: Unique number for the device on the bus.
  * @driver: Pointer to associated driver
- * @phys: Pointer to the physical interface
+ * @xport: Pointer to the transport interface
  * @debugfs_root: base for this particular sensor device.
  *
  */
@@ -209,7 +209,7 @@ struct rmi_device {
 	int number;
 
 	struct rmi_driver *driver;
-	struct rmi_phys_device *phys;
+	struct rmi_transport_dev *xport;
 
 #ifdef CONFIG_RMI4_DEBUG
 	struct dentry *debugfs_root;
@@ -217,7 +217,7 @@ struct rmi_device {
 };
 
 #define to_rmi_device(d) container_of(d, struct rmi_device, dev)
-#define to_rmi_platform_data(d) ((d)->phys->dev->platform_data)
+#define to_rmi_platform_data(d) ((d)->xport->dev->platform_data)
 
 bool rmi_is_physical_device(struct device *dev);
 
@@ -227,12 +227,12 @@ bool rmi_is_physical_device(struct device *dev);
  * @addr: The address to read from
  * @buf: The read buffer
  *
- * Reads a byte of data using the underlaying physical protocol in to buf. It
+ * Reads a byte of data using the underlaying transport protocol in to buf. It
  * returns zero or a negative error code.
  */
 static inline int rmi_read(struct rmi_device *d, u16 addr, void *buf)
 {
-	return d->phys->read_block(d->phys, addr, buf, 1);
+	return d->xport->read_block(d->xport, addr, buf, 1);
 }
 
 /**
@@ -242,13 +242,13 @@ static inline int rmi_read(struct rmi_device *d, u16 addr, void *buf)
  * @buf: The read buffer
  * @len: Length of the read buffer
  *
- * Reads a block of byte data using the underlaying physical protocol in to buf.
- * It returns the amount of bytes read or a negative error code.
+ * Reads a block of byte data using the underlaying transport protocol in
+ * to buf.  It returns the amount of bytes read or a negative error code.
  */
 static inline int rmi_read_block(struct rmi_device *d, u16 addr, void *buf,
 				 const int len)
 {
-	return d->phys->read_block(d->phys, addr, buf, len);
+	return d->xport->read_block(d->xport, addr, buf, len);
 }
 
 /**
@@ -257,12 +257,12 @@ static inline int rmi_read_block(struct rmi_device *d, u16 addr, void *buf,
  * @addr: The address to write to
  * @data: The data to write
  *
- * Writes a byte from buf using the underlaying physical protocol. It
+ * Writes a byte from buf using the underlaying transport protocol. It
  * returns zero or a negative error code.
  */
 static inline int rmi_write(struct rmi_device *d, u16 addr, const u8 data)
 {
-	return d->phys->write_block(d->phys, addr, &data, 1);
+	return d->xport->write_block(d->xport, addr, &data, 1);
 }
 
 /**
@@ -272,17 +272,17 @@ static inline int rmi_write(struct rmi_device *d, u16 addr, const u8 data)
  * @buf: The write buffer
  * @len: Length of the write buffer
  *
- * Writes a block of byte data from buf using the underlaying physical protocol.
- * It returns the amount of bytes written or a negative error code.
+ * Writes a block of byte data from buf using the underlaying transport
+ * protocol.  It returns the amount of bytes written or a negative error code.
  */
 static inline int rmi_write_block(struct rmi_device *d, u16 addr,
 				  const void *buf, const int len)
 {
-	return d->phys->write_block(d->phys, addr, buf, len);
+	return d->xport->write_block(d->xport, addr, buf, len);
 }
 
-int rmi_register_physical_device(struct rmi_phys_device *phys);
-void rmi_unregister_physical_device(struct rmi_phys_device *phys);
+int rmi_register_transport_device(struct rmi_transport_dev *xport);
+void rmi_unregister_transport_device(struct rmi_transport_dev *xport);
 int rmi_for_each_dev(void *data, int (*func)(struct device *dev, void *data));
 
 /**
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index a30c7d3..2ae9af9 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -45,16 +45,16 @@
 
 static irqreturn_t rmi_irq_thread(int irq, void *p)
 {
-	struct rmi_phys_device *phys = p;
-	struct rmi_device *rmi_dev = phys->rmi_dev;
+	struct rmi_transport_dev *xport = p;
+	struct rmi_device *rmi_dev = xport->rmi_dev;
 	struct rmi_driver *driver = rmi_dev->driver;
-	struct rmi_device_platform_data *pdata = phys->dev->platform_data;
+	struct rmi_device_platform_data *pdata = xport->dev->platform_data;
 	struct rmi_driver_data *data;
 
 	data = dev_get_drvdata(&rmi_dev->dev);
 
 	if (IRQ_DEBUG(data))
-		dev_dbg(phys->dev, "ATTN gpio, value: %d.\n",
+		dev_dbg(xport->dev, "ATTN gpio, value: %d.\n",
 				gpio_get_value(pdata->attn_gpio));
 
 	if (gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity) {
@@ -124,12 +124,12 @@ static void disable_sensor(struct rmi_device *rmi_dev)
 	if (!data->irq)
 		disable_polling(rmi_dev);
 
-	if (rmi_dev->phys->disable_device)
-		rmi_dev->phys->disable_device(rmi_dev->phys);
+	if (rmi_dev->xport->disable_device)
+		rmi_dev->xport->disable_device(rmi_dev->xport);
 
 	if (data->irq) {
 		disable_irq(data->irq);
-		free_irq(data->irq, rmi_dev->phys);
+		free_irq(data->irq, rmi_dev->xport);
 	}
 
 	data->enabled = false;
@@ -138,27 +138,27 @@ static void disable_sensor(struct rmi_device *rmi_dev)
 static int enable_sensor(struct rmi_device *rmi_dev)
 {
 	struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev);
-	struct rmi_phys_device *rmi_phys;
+	struct rmi_transport_dev *xport;
 	int retval = 0;
 	struct rmi_device_platform_data *pdata = to_rmi_platform_data(rmi_dev);
 
 	if (data->enabled)
 		return 0;
 
-	if (rmi_dev->phys->enable_device) {
-		retval = rmi_dev->phys->enable_device(rmi_dev->phys);
+	if (rmi_dev->xport->enable_device) {
+		retval = rmi_dev->xport->enable_device(rmi_dev->xport);
 		if (retval)
 			return retval;
 	}
 
-	rmi_phys = rmi_dev->phys;
+	xport = rmi_dev->xport;
 	if (data->irq) {
 		retval = request_threaded_irq(data->irq,
-				rmi_phys->hard_irq ? rmi_phys->hard_irq : NULL,
-				rmi_phys->irq_thread ?
-					rmi_phys->irq_thread : rmi_irq_thread,
+				xport->hard_irq ? xport->hard_irq : NULL,
+				xport->irq_thread ?
+					xport->irq_thread : rmi_irq_thread,
 				data->irq_flags,
-				dev_name(&rmi_dev->dev), rmi_phys);
+				dev_name(&rmi_dev->dev), xport);
 		if (retval)
 			return retval;
 	} else {
@@ -819,7 +819,7 @@ static int rmi_driver_probe(struct device *dev)
 	dev_dbg(dev, "%s: Starting probe.\n", __func__);
 
 	if (!rmi_is_physical_device(dev)) {
-		dev_dbg(dev, "Not a sensor device.\n");
+		dev_dbg(dev, "Not a physical device.\n");
 		return -ENODEV;
 	}
 
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 5e3c4d4..0d57700 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -74,7 +74,7 @@ struct rmi_driver_data {
 
 #ifdef CONFIG_RMI4_DEBUG
 	struct dentry *debugfs_delay;
-	struct dentry *debugfs_phys;
+	struct dentry *debugfs_xport;
 	struct dentry *debugfs_reg_ctl;
 	struct dentry *debugfs_reg;
 	struct dentry *debugfs_irq;
diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
index 62351c4..b33074c 100644
--- a/drivers/input/rmi4/rmi_i2c.c
+++ b/drivers/input/rmi4/rmi_i2c.c
@@ -27,7 +27,7 @@
  *
  * @page_mutex: Locks current page to avoid changing pages in unexpected ways.
  * @page: Keeps track of the current virtual page
- * @phys: Pointer to the physical interface
+ * @xport: Pointer to the transport interface
  *
  * @tx_buf: Buffer used for transmitting data to the sensor over i2c.
  * @tx_buf_size: Size of the buffer
@@ -40,7 +40,7 @@
 struct rmi_i2c_data {
 	struct mutex page_mutex;
 	int page;
-	struct rmi_phys_device *phys;
+	struct rmi_transport_dev *xport;
 
 	u8 *tx_buf;
 	int tx_buf_size;
@@ -97,14 +97,14 @@ static inline void teardown_debugfs(struct rmi_i2c_data *data)
 #define RMI_PAGE_SELECT_REGISTER 0xff
 #define RMI_I2C_PAGE(addr) (((addr) >> 8) & 0xff)
 
-static char *phys_proto_name = "i2c";
+static char *xport_proto_name = "i2c";
 
 /*
  * rmi_set_page - Set RMI page
- * @phys: The pointer to the rmi_phys_device struct
+ * @xport: The pointer to the rmi_transport_dev struct
  * @page: The new page address.
  *
- * RMI devices have 16-bit addressing, but some of the physical
+ * RMI devices have 16-bit addressing, but some of the transport
  * implementations (like SMBus) only have 8-bit addressing. So RMI implements
  * a page address at 0xff of every page so we can reliable page addresses
  * every 256 registers.
@@ -113,21 +113,21 @@ static char *phys_proto_name = "i2c";
  *
  * Returns zero on success, non-zero on failure.
  */
-static int rmi_set_page(struct rmi_phys_device *phys, u8 page)
+static int rmi_set_page(struct rmi_transport_dev *xport, u8 page)
 {
-	struct i2c_client *client = to_i2c_client(phys->dev);
-	struct rmi_i2c_data *data = phys->data;
+	struct i2c_client *client = to_i2c_client(xport->dev);
+	struct rmi_i2c_data *data = xport->data;
 	u8 txbuf[2] = {RMI_PAGE_SELECT_REGISTER, page};
 	int retval;
 
 	if (COMMS_DEBUG(data))
 		dev_dbg(&client->dev, "writes 3 bytes: %02x %02x\n",
 			txbuf[0], txbuf[1]);
-	phys->info.tx_count++;
-	phys->info.tx_bytes += sizeof(txbuf);
+	xport->info.tx_count++;
+	xport->info.tx_bytes += sizeof(txbuf);
 	retval = i2c_master_send(client, txbuf, sizeof(txbuf));
 	if (retval != sizeof(txbuf)) {
-		phys->info.tx_errs++;
+		xport->info.tx_errs++;
 		dev_err(&client->dev,
 			"%s: set page failed: %d.", __func__, retval);
 		return (retval < 0) ? retval : -EIO;
@@ -164,11 +164,11 @@ static int copy_to_debug_buf(struct device *dev, struct rmi_i2c_data *data,
 	return 0;
 }
 
-static int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr,
+static int rmi_i2c_write_block(struct rmi_transport_dev *xport, u16 addr,
 			       const void *buf, const int len)
 {
-	struct i2c_client *client = to_i2c_client(phys->dev);
-	struct rmi_i2c_data *data = phys->data;
+	struct i2c_client *client = to_i2c_client(xport->dev);
+	struct rmi_i2c_data *data = xport->data;
 	int retval;
 	int tx_size = len + 1;
 
@@ -190,7 +190,7 @@ static int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr,
 	memcpy(data->tx_buf + 1, buf, len);
 
 	if (RMI_I2C_PAGE(addr) != data->page) {
-		retval = rmi_set_page(phys, RMI_I2C_PAGE(addr));
+		retval = rmi_set_page(xport, RMI_I2C_PAGE(addr));
 		if (retval < 0)
 			goto exit;
 	}
@@ -202,11 +202,11 @@ static int rmi_i2c_write_block(struct rmi_phys_device *phys, u16 addr,
 				len, addr, data->debug_buf);
 	}
 
-	phys->info.tx_count++;
-	phys->info.tx_bytes += tx_size;
+	xport->info.tx_count++;
+	xport->info.tx_bytes += tx_size;
 	retval = i2c_master_send(client, data->tx_buf, tx_size);
 	if (retval < 0)
-		phys->info.tx_errs++;
+		xport->info.tx_errs++;
 	else
 		retval--; /* don't count the address byte */
 
@@ -216,18 +216,18 @@ exit:
 }
 
 
-static int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr,
+static int rmi_i2c_read_block(struct rmi_transport_dev *xport, u16 addr,
 			      void *buf, const int len)
 {
-	struct i2c_client *client = to_i2c_client(phys->dev);
-	struct rmi_i2c_data *data = phys->data;
+	struct i2c_client *client = to_i2c_client(xport->dev);
+	struct rmi_i2c_data *data = xport->data;
 	u8 txbuf[1] = {addr & 0xff};
 	int retval;
 
 	mutex_lock(&data->page_mutex);
 
 	if (RMI_I2C_PAGE(addr) != data->page) {
-		retval = rmi_set_page(phys, RMI_I2C_PAGE(addr));
+		retval = rmi_set_page(xport, RMI_I2C_PAGE(addr));
 		if (retval < 0)
 			goto exit;
 	}
@@ -235,21 +235,21 @@ static int rmi_i2c_read_block(struct rmi_phys_device *phys, u16 addr,
 	if (COMMS_DEBUG(data))
 		dev_dbg(&client->dev, "writes 1 bytes: %02x\n", txbuf[0]);
 
-	phys->info.tx_count++;
-	phys->info.tx_bytes += sizeof(txbuf);
+	xport->info.tx_count++;
+	xport->info.tx_bytes += sizeof(txbuf);
 	retval = i2c_master_send(client, txbuf, sizeof(txbuf));
 	if (retval != sizeof(txbuf)) {
-		phys->info.tx_errs++;
+		xport->info.tx_errs++;
 		retval = (retval < 0) ? retval : -EIO;
 		goto exit;
 	}
 
 	retval = i2c_master_recv(client, (u8 *) buf, len);
 
-	phys->info.rx_count++;
-	phys->info.rx_bytes += len;
+	xport->info.rx_count++;
+	xport->info.rx_bytes += len;
 	if (retval < 0)
-		phys->info.rx_errs++;
+		xport->info.rx_errs++;
 	else if (COMMS_DEBUG(data)) {
 		int rc = copy_to_debug_buf(&client->dev, data, (u8 *) buf, len);
 		if (!rc)
@@ -265,7 +265,7 @@ exit:
 static int rmi_i2c_probe(struct i2c_client *client,
 			 const struct i2c_device_id *id)
 {
-	struct rmi_phys_device *rmi_phys;
+	struct rmi_transport_dev *xport;
 	struct rmi_i2c_data *data;
 	struct rmi_device_platform_data *pdata = client->dev.platform_data;
 	int retval;
@@ -296,10 +296,10 @@ static int rmi_i2c_probe(struct i2c_client *client,
 		return retval;
 	}
 
-	rmi_phys = devm_kzalloc(&client->dev, sizeof(struct rmi_phys_device),
+	xport = devm_kzalloc(&client->dev, sizeof(struct rmi_transport_dev),
 				GFP_KERNEL);
 
-	if (!rmi_phys)
+	if (!xport)
 		return -ENOMEM;
 
 	data = devm_kzalloc(&client->dev, sizeof(struct rmi_i2c_data),
@@ -307,35 +307,35 @@ static int rmi_i2c_probe(struct i2c_client *client,
 	if (!data)
 		return -ENOMEM;
 
-	data->phys = rmi_phys;
+	data->xport = xport;
 
-	rmi_phys->data = data;
-	rmi_phys->dev = &client->dev;
+	xport->data = data;
+	xport->dev = &client->dev;
 
-	rmi_phys->write_block = rmi_i2c_write_block;
-	rmi_phys->read_block = rmi_i2c_read_block;
-	rmi_phys->info.proto = phys_proto_name;
+	xport->write_block = rmi_i2c_write_block;
+	xport->read_block = rmi_i2c_read_block;
+	xport->info.proto = xport_proto_name;
 
 	mutex_init(&data->page_mutex);
 
 	/* Setting the page to zero will (a) make sure the PSR is in a
 	 * known state, and (b) make sure we can talk to the device.
 	 */
-	retval = rmi_set_page(rmi_phys, 0);
+	retval = rmi_set_page(xport, 0);
 	if (retval) {
 		dev_err(&client->dev, "Failed to set page select to 0.\n");
 		return retval;
 	}
 
-	retval = rmi_register_physical_device(rmi_phys);
+	retval = rmi_register_transport_device(xport);
 	if (retval) {
-		dev_err(&client->dev, "Failed to register physical driver at 0x%.2X.\n",
+		dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
 			client->addr);
 		goto err_gpio;
 	}
-	i2c_set_clientdata(client, rmi_phys);
+	i2c_set_clientdata(client, xport);
 
-	retval = setup_debugfs(rmi_phys->rmi_dev, data);
+	retval = setup_debugfs(xport->rmi_dev, data);
 	if (retval < 0)
 		dev_warn(&client->dev, "Failed to setup debugfs. Code: %d.\n",
 			 retval);
@@ -352,12 +352,12 @@ err_gpio:
 
 static int rmi_i2c_remove(struct i2c_client *client)
 {
-	struct rmi_phys_device *phys = i2c_get_clientdata(client);
+	struct rmi_transport_dev *xport = i2c_get_clientdata(client);
 	struct rmi_device_platform_data *pd = client->dev.platform_data;
 
-	teardown_debugfs(phys->data);
+	teardown_debugfs(xport->data);
 
-	rmi_unregister_physical_device(phys);
+	rmi_unregister_transport_device(xport);
 
 	if (pd->gpio_config)
 		pd->gpio_config(&pd->gpio_data, false);

^ permalink raw reply related

* Re: [PATCH 0/4] Input: ABS2 and friends
From: simon @ 2013-12-17 21:28 UTC (permalink / raw)
  Cc: linux-input, Dmitry Torokhov, Jiri Kosina, Benjamin Tissoires,
	Peter Hutterer, Antonio Ospite, linux-kernel, input-tools,
	David Herrmann
In-Reply-To: <1387295334-1744-1-git-send-email-dh.herrmann@gmail.com>

> Hi
>
> This implements the recently discussed ABS2 API. It's working fine on my
> machine with libevdev. Comments welcome!

Just looking at the documentation file, I have a couple of suggestions.

1). Make a note on the direction of gravity wrt the example image. Ie what
which axis/value will be positive with the device laid flat/stationary on
a desk. Might just prevent some confusion later.

2). Calibration, Accels and Gyros are noisy in different ways. Gyros tend
to be wrong in the long term, giving some consistant bias which should be
calibrated out. Accels are noisy in the short term, but generally right
over a long period.

Am I correct that the event framework will provide time-stamping of data,
thus making computation of relative movements possible.

Simon



^ permalink raw reply

* Re: [Xen-devel] [PATCH v3 1/2] xen/pvhvm: If xen_platform_pci=0 is set don't blow up (v3).
From: Konrad Rzeszutek Wilk @ 2013-12-17 21:23 UTC (permalink / raw)
  To: Fabio Fantoni
  Cc: axboe, stefano.stabellini, ian.campbell, xen-devel, linux-kernel,
	boris.ostrovsky, david.vrabel, leosilva, ashley, peterhuewe, mail,
	tpmdd, dmitry.torokhov, bhelgaas, plagnioj, tomi.valkeinen,
	tpmdd-devel, linux-input, netdev, linux-pci, linux-fbdev
In-Reply-To: <20131217145150.GC4683@phenom.dumpdata.com>

On Tue, Dec 17, 2013 at 09:51:50AM -0500, Konrad Rzeszutek Wilk wrote:
> On Tue, Dec 17, 2013 at 10:54:47AM +0100, Fabio Fantoni wrote:
> > Il 16/12/2013 16:04, Konrad Rzeszutek Wilk ha scritto:
> > >The user has the option of disabling the platform driver:
> > >00:02.0 Unassigned class [ff80]: XenSource, Inc. Xen Platform Device (rev 01)
> > >
> > >which is used to unplug the emulated drivers (IDE, Realtek 8169, etc)
> > >and allow the PV drivers to take over. If the user wishes
> > >to disable that they can set:
> > >
> > >   xen_platform_pci=0
> > >   (in the guest config file)
> > >
> > >or
> > >   xen_emul_unplug=never
> > >   (on the Linux command line)
> > >
> > >except it does not work properly. The PV drivers still try to
> > >load and since the Xen platform driver is not run - and it
> > >has not initialized the grant tables, most of the PV drivers
> > >stumble upon:
> > >
> > >input: Xen Virtual Keyboard as /devices/virtual/input/input5
> > >input: Xen Virtual Pointer as /devices/virtual/input/input6M
> > >------------[ cut here ]------------
> > >kernel BUG at /home/konrad/ssd/konrad/linux/drivers/xen/grant-table.c:1206!
> > >invalid opcode: 0000 [#1] SMP
> > >Modules linked in: xen_kbdfront(+) xenfs xen_privcmd
> > >CPU: 6 PID: 1389 Comm: modprobe Not tainted 3.13.0-rc1upstream-00021-ga6c892b-dirty #1
> > >Hardware name: Xen HVM domU, BIOS 4.4-unstable 11/26/2013
> > >RIP: 0010:[<ffffffff813ddc40>]  [<ffffffff813ddc40>] get_free_entries+0x2e0/0x300
> > >Call Trace:
> > >  [<ffffffff8150d9a3>] ? evdev_connect+0x1e3/0x240
> > >  [<ffffffff813ddd0e>] gnttab_grant_foreign_access+0x2e/0x70
> > >  [<ffffffffa0010081>] xenkbd_connect_backend+0x41/0x290 [xen_kbdfront]
> > >  [<ffffffffa0010a12>] xenkbd_probe+0x2f2/0x324 [xen_kbdfront]
> > >  [<ffffffff813e5757>] xenbus_dev_probe+0x77/0x130
> > >  [<ffffffff813e7217>] xenbus_frontend_dev_probe+0x47/0x50
> > >  [<ffffffff8145e9a9>] driver_probe_device+0x89/0x230
> > >  [<ffffffff8145ebeb>] __driver_attach+0x9b/0xa0
> > >  [<ffffffff8145eb50>] ? driver_probe_device+0x230/0x230
> > >  [<ffffffff8145eb50>] ? driver_probe_device+0x230/0x230
> > >  [<ffffffff8145cf1c>] bus_for_each_dev+0x8c/0xb0
> > >  [<ffffffff8145e7d9>] driver_attach+0x19/0x20
> > >  [<ffffffff8145e260>] bus_add_driver+0x1a0/0x220
> > >  [<ffffffff8145f1ff>] driver_register+0x5f/0xf0
> > >  [<ffffffff813e55c5>] xenbus_register_driver_common+0x15/0x20
> > >  [<ffffffff813e76b3>] xenbus_register_frontend+0x23/0x40
> > >  [<ffffffffa0015000>] ? 0xffffffffa0014fff
> > >  [<ffffffffa001502b>] xenkbd_init+0x2b/0x1000 [xen_kbdfront]
> > >  [<ffffffff81002049>] do_one_initcall+0x49/0x170
> > >
> > >.. snip..
> > >
> > >which is hardly nice. This patch fixes this by having each
> > >PV driver check for:
> > >  - if running in PV, then it is fine to execute (as that is their
> > >    native environment).
> > >  - if running in HVM, check if user wanted 'xen_emul_unplug=never',
> > >    in which case bail out and don't load any PV drivers.
> > >  - if running in HVM, and if PCI device 5853:0001 (xen_platform_pci)
> > >    does not exist, then bail out and not load PV drivers.
> > >  - (v2) if running in HVM, and if the user wanted 'xen_emul_unplug=disks',
> > >    then bail out for all PV devices _except_ the block one.
> > >    Ditto for the network one ('nics').
> > >  - (v2) if running in HVM, and if the user wanted 'xen_emul_unplug=unnecessary'
> > >    then load block PV driver, and also setup the legacy IDE paths.
> > >    In (v3) make it actually load PV drivers.
> > >
> > >Reported-by: Sander Eikelenboom <linux@eikelenboom.it
> > >Reported-by: Anthony PERARD <anthony.perard@citrix.com>
> > >Reported-by: Fabio Fantoni <fabio.fantoni@m2r.biz>
> > >Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> > >[v2: Add extra logic to handle the myrid ways 'xen_emul_unplug'
> > >can be used per Ian and Stefano suggestion]
> > >[v3: Make the unnecessary case work properly]
> > >Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> > 
> > I tested this patch with all possible cases that I know, no crash or
> > calltrace found.
> > 
> > I don't understand the utility of 'xen_emul_unplug=unnecessary' but
> > probably it is working correctly, it shows both pv and not pv for
> > blocks and nics.
> 
> Great!
> > 
> > About 'xen_emul_unplug=disks' and 'xen_emul_unplug=nics' probably
> > there is something wrong.
> > With 'xen_emul_unplug=nics' it shows pv nic (this should be correct)
> > and about disks it shows the same disk twice, as pv and not pv (xvda
> > and sda) with different device number.
> 
> Good.
> > With 'xen_emul_unplug=disks' it shows pv block (this should be
> > correct) and it seems to show the pv nic too (this should be wrong).
> 
> Correct. You should see only the PV disk and all other PV devices
> should not function. Let me dig in this and see whether there is
> another bug. Thank you!

That is because 'disks' is incorrect. It should have been 'ide-disks'

[    0.000000] unrecognised option 'disks' in parameter 'xen_emul_unplug'

With the 'ide-disks' it should work. I will update the description to
mention 'ide-disks' instead of 'disks'. Thank you for finding this!

^ permalink raw reply

* [PATCH V2] input synaptics-rmi4: Bug fixes to ATTN GPIO handling.
From: Christopher Heiny @ 2013-12-17 20:16 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Linux Input, Christopher Heiny, Andrew Duggan, Vincent Huang,
	Vivian Ly, Daniel Rosenberg, Jean Delvare, Joerie de Gram,
	Linus Walleij, Benjamin Tissoires

This patch fixes two bugs in handling of the RMI4 attention line GPIO.

1) in enable_sensor(), make sure the attn_gpio is defined before attempting to
get its value.

2) in rmi_driver_probe(), declare the name of the attn_gpio, then
request the attn_gpio before attempting to export it.

Also introduces a GPIO_LABEL constant for identifying the attention GPIO.

Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>

---

 drivers/input/rmi4/rmi_driver.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index a30c7d3..33fb8f8 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -169,7 +169,7 @@ static int enable_sensor(struct rmi_device *rmi_dev)
 
 	data->enabled = true;
 
-	if (!pdata->level_triggered &&
+	if (pdata->attn_gpio && !pdata->level_triggered &&
 		    gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity)
 		retval = process_interrupt_requests(rmi_dev);
 
@@ -807,6 +807,8 @@ static int rmi_driver_remove(struct device *dev)
 	return 0;
 }
 
+static const char GPIO_LABEL[] = "attn";
+
 static int rmi_driver_probe(struct device *dev)
 {
 	struct rmi_driver *rmi_driver;
@@ -959,20 +961,24 @@ static int rmi_driver_probe(struct device *dev)
 	}
 
 	if (IS_ENABLED(CONFIG_RMI4_DEV) && pdata->attn_gpio) {
-		retval = gpio_export(pdata->attn_gpio, false);
+		retval = gpio_request(pdata->attn_gpio, GPIO_LABEL);
 		if (retval) {
-			dev_warn(dev, "WARNING: Failed to export ATTN gpio!\n");
-			retval = 0;
+			dev_warn(dev, "WARNING: Failed to request ATTN gpio %d, code: %d.\n",
+				pdata->attn_gpio, retval);
 		} else {
-			retval = gpio_export_link(dev,
-						  "attn", pdata->attn_gpio);
+			retval = gpio_export(pdata->attn_gpio, false);
 			if (retval) {
-				dev_warn(dev,
-					"WARNING: Failed to symlink ATTN gpio!\n");
-				retval = 0;
+				dev_warn(dev, "WARNING: Failed to export ATTN gpio %d, code: %d.\n",
+					pdata->attn_gpio, retval);
 			} else {
-				dev_info(dev, "Exported ATTN GPIO %d.",
-					pdata->attn_gpio);
+				retval = gpio_export_link(dev, GPIO_LABEL,
+							  pdata->attn_gpio);
+				if (retval)
+					dev_warn(dev,
+						"WARNING: Failed to symlink ATTN gpio!\n");
+				else
+					dev_info(dev, "Exported ATTN GPIO %d.",
+						pdata->attn_gpio);
 			}
 		}
 	}

^ permalink raw reply related

* Re: [PATCH] input synaptics-rmi4: Bug fixes to ATTN GPIO handling.
From: Christopher Heiny @ 2013-12-17 19:44 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
	Daniel Rosenberg, Jean Delvare, Joerie de Gram, Linus Walleij,
	Benjamin Tissoires
In-Reply-To: <20131217165752.GB17790@core.coreip.homeip.net>

On 12/17/2013 08:57 AM, Dmitry Torokhov wrote:
> Hi Chris,
>
> On Mon, Dec 16, 2013 at 07:45:06PM -0800, Christopher Heiny wrote:
>> This patch fixes two bugs in handling of the RMI4 attention line GPIO.
>>
>> 1) in enable_sensor(), make sure the attn_gpio is defined before attempting to
>> get its value.
>>
>> 2) in rmi_driver_probe(), declare the name of the attn_gpio, then
>> request the attn_gpio before attempting to export it. As an added bonus,
>> the code relating to the export is tidied up.
>>
>> Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
>> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>> Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>>
>> ---
>>
>> This patch implements changes to the synaptics-rmi4 branch of
>> Dmitry's input tree.  The base for the patch is commit
>> e0c5aec5e6144ae8391d164e2dc659f8ef2b2ba7.
>
> You do not have to mention base commit (and update it all the time),
> that's way too  much work. If you are the one posting patches I should
> be able to figure out how to apply them.
>
>>
>>   drivers/input/rmi4/rmi_driver.c | 37 ++++++++++++++++++++++---------------
>>   1 file changed, 22 insertions(+), 15 deletions(-)
>>
>> diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
>> index a30c7d3..030e8d5 100644
>> --- a/drivers/input/rmi4/rmi_driver.c
>> +++ b/drivers/input/rmi4/rmi_driver.c
>> @@ -169,7 +169,7 @@ static int enable_sensor(struct rmi_device *rmi_dev)
>>
>>   	data->enabled = true;
>>
>> -	if (!pdata->level_triggered &&
>> +	if (pdata->attn_gpio && !pdata->level_triggered &&
>>   		    gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity)
>>   		retval = process_interrupt_requests(rmi_dev);
>>
>> @@ -807,6 +807,9 @@ static int rmi_driver_remove(struct device *dev)
>>   	return 0;
>>   }
>>
>> +
>> +static const char *GPIO_LABEL = "attn";
>> +
>
> This wastes 4 or 8 bytes I believe. If you want to do that then you
> should say:
>
> static const char GPIO_LABEL[] = "attn";

Hmmm.  Learned something new today!

>
>
>>   static int rmi_driver_probe(struct device *dev)
>>   {
>>   	struct rmi_driver *rmi_driver;
>> @@ -959,20 +962,24 @@ static int rmi_driver_probe(struct device *dev)
>>   	}
>>
>>   	if (IS_ENABLED(CONFIG_RMI4_DEV) && pdata->attn_gpio) {
>> -		retval = gpio_export(pdata->attn_gpio, false);
>> -		if (retval) {
>> -			dev_warn(dev, "WARNING: Failed to export ATTN gpio!\n");
>> -			retval = 0;
>> -		} else {
>> -			retval = gpio_export_link(dev,
>> -						  "attn", pdata->attn_gpio);
>> -			if (retval) {
>> -				dev_warn(dev,
>> -					"WARNING: Failed to symlink ATTN gpio!\n");
>> -				retval = 0;
>> -			} else {
>> -				dev_info(dev, "Exported ATTN GPIO %d.",
>> -					pdata->attn_gpio);
>> +		retval = gpio_request(pdata->attn_gpio, GPIO_LABEL);
>> +		if (retval)
>> +			dev_warn(dev, "WARNING: Failed to request ATTN gpio %d, code: %d.\n",
>> +				pdata->attn_gpio, retval);
>> +		else {
>
> The rule is: if one branch needs {} then they both should use them:
>
> 	if (condition) {
> 		statement;
> 	} else {
> 		statement;
> 		...
> 		statement;
> 	}

OK.

>
>> +			retval = gpio_export(pdata->attn_gpio, false);
>> +			if (retval)
>> +				dev_warn(dev, "WARNING: Failed to export ATTN  %d, code: %d.\n",
>> +					pdata->attn_gpio, retval);
>> +			else {
>> +				retval = gpio_export_link(dev, "attn",
>
> Why are we using constant when we request gpio but not here?

It's a leftover that wasn't caught.  We'll use the constant.

>
>> +							  pdata->attn_gpio);
>> +				if (retval)
>> +					dev_warn(dev,
>> +						"WARNING: Failed to symlink ATTN gpio!\n");
>> +				else
>> +					dev_info(dev, "Exported ATTN GPIO %d.",
>> +						pdata->attn_gpio);
>>   			}
>>   		}
>>   	}
>
> Thanks.
>


^ permalink raw reply

* Re: [PATCH] input synaptics-rmi4: Bug fixes to ATTN GPIO handling.
From: Dmitry Torokhov @ 2013-12-17 16:57 UTC (permalink / raw)
  To: Christopher Heiny
  Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
	Daniel Rosenberg, Jean Delvare, Joerie de Gram, Linus Walleij,
	Benjamin Tissoires
In-Reply-To: <1387251906-23530-1-git-send-email-cheiny@synaptics.com>

Hi Chris,

On Mon, Dec 16, 2013 at 07:45:06PM -0800, Christopher Heiny wrote:
> This patch fixes two bugs in handling of the RMI4 attention line GPIO.
> 
> 1) in enable_sensor(), make sure the attn_gpio is defined before attempting to
> get its value.
> 
> 2) in rmi_driver_probe(), declare the name of the attn_gpio, then
> request the attn_gpio before attempting to export it. As an added bonus,
> the code relating to the export is tidied up.
> 
> Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> 
> ---
> 
> This patch implements changes to the synaptics-rmi4 branch of
> Dmitry's input tree.  The base for the patch is commit
> e0c5aec5e6144ae8391d164e2dc659f8ef2b2ba7.

You do not have to mention base commit (and update it all the time),
that's way too  much work. If you are the one posting patches I should
be able to figure out how to apply them.

> 
>  drivers/input/rmi4/rmi_driver.c | 37 ++++++++++++++++++++++---------------
>  1 file changed, 22 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
> index a30c7d3..030e8d5 100644
> --- a/drivers/input/rmi4/rmi_driver.c
> +++ b/drivers/input/rmi4/rmi_driver.c
> @@ -169,7 +169,7 @@ static int enable_sensor(struct rmi_device *rmi_dev)
>  
>  	data->enabled = true;
>  
> -	if (!pdata->level_triggered &&
> +	if (pdata->attn_gpio && !pdata->level_triggered &&
>  		    gpio_get_value(pdata->attn_gpio) == pdata->attn_polarity)
>  		retval = process_interrupt_requests(rmi_dev);
>  
> @@ -807,6 +807,9 @@ static int rmi_driver_remove(struct device *dev)
>  	return 0;
>  }
>  
> +
> +static const char *GPIO_LABEL = "attn";
> +

This wastes 4 or 8 bytes I believe. If you want to do that then you
should say:

static const char GPIO_LABEL[] = "attn";


>  static int rmi_driver_probe(struct device *dev)
>  {
>  	struct rmi_driver *rmi_driver;
> @@ -959,20 +962,24 @@ static int rmi_driver_probe(struct device *dev)
>  	}
>  
>  	if (IS_ENABLED(CONFIG_RMI4_DEV) && pdata->attn_gpio) {
> -		retval = gpio_export(pdata->attn_gpio, false);
> -		if (retval) {
> -			dev_warn(dev, "WARNING: Failed to export ATTN gpio!\n");
> -			retval = 0;
> -		} else {
> -			retval = gpio_export_link(dev,
> -						  "attn", pdata->attn_gpio);
> -			if (retval) {
> -				dev_warn(dev,
> -					"WARNING: Failed to symlink ATTN gpio!\n");
> -				retval = 0;
> -			} else {
> -				dev_info(dev, "Exported ATTN GPIO %d.",
> -					pdata->attn_gpio);
> +		retval = gpio_request(pdata->attn_gpio, GPIO_LABEL);
> +		if (retval)
> +			dev_warn(dev, "WARNING: Failed to request ATTN gpio %d, code: %d.\n",
> +				pdata->attn_gpio, retval);
> +		else {

The rule is: if one branch needs {} then they both should use them:

	if (condition) {
		statement;
	} else {
		statement;
		...
		statement;
	}

> +			retval = gpio_export(pdata->attn_gpio, false);
> +			if (retval)
> +				dev_warn(dev, "WARNING: Failed to export ATTN  %d, code: %d.\n",
> +					pdata->attn_gpio, retval);
> +			else {
> +				retval = gpio_export_link(dev, "attn",

Why are we using constant when we request gpio but not here?

> +							  pdata->attn_gpio);
> +				if (retval)
> +					dev_warn(dev,
> +						"WARNING: Failed to symlink ATTN gpio!\n");
> +				else
> +					dev_info(dev, "Exported ATTN GPIO %d.",
> +						pdata->attn_gpio);
>  			}
>  		}
>  	}

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH -next] Input: pmic8xxx-pwrkey - fix to pass correct device identity to free_irq()
From: Dmitry Torokhov @ 2013-12-17 16:48 UTC (permalink / raw)
  To: Stephen Boyd; +Cc: Wei Yongjun, lars, sachin.kamat, yongjun_wei, linux-input
In-Reply-To: <20131217012358.GA31766@codeaurora.org>

On Mon, Dec 16, 2013 at 05:23:58PM -0800, Stephen Boyd wrote:
> On 12/17, Wei Yongjun wrote:
> > From: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> > 
> > free_irq() in the error handling case is missing when change
> > pass input device directly to interrupt.
> > 
> > Fixes: b27f8fee4965('Input: pmic8xxx-pwrkey - pass input device directly to interrupt')
> > Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn>
> 
> This driver was supposed to be converted to devm before
> that patch. I forgot to send it and then Dmitry seems to have
> fixed up the patch to make it apply. We should just use the devm
> conversion patch to avoid needing to apply this one.

I am still going to apply it, but if you could take a look at my devm
conversion patch for the driver that would be great.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: Disable i8042 check on Apple machines
From: Dmitry Torokhov @ 2013-12-17 16:35 UTC (permalink / raw)
  To: Josh Boyer; +Cc: Bastien Nocera, linux-input
In-Reply-To: <CA+5PVA565FmR+f5eOZDSUv_pb-pbgExg5L6zHXf9aJyNUoRVdg@mail.gmail.com>

On Tue, Dec 17, 2013 at 10:25:36AM -0500, Josh Boyer wrote:
> Hi Bastien and Dmitry,
> 
> I was going through some of the patches we're carrying in Fedora and
> came across this one that Bastien submitted a long time ago:
> 
> http://lkml.indiana.edu/hypermail/linux/kernel/1005.0/00938.html
> 
> It works and we're still carrying it, but Dmitry said it needed to be
> done differently in i8042-x86ia64io.h.  Would that just mean adding a
> DMI for Apple machines to the i8042_dmi_nopnp_table struct?  Or
> exactly what should be done here?

That is one possible option that I had in mind originally. Another would
be to modify arch/x86/kernel/x86_init.c::default_x86_detect() and add
the check there.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH 0/4] Input: ABS2 and friends
From: David Herrmann @ 2013-12-17 16:34 UTC (permalink / raw)
  To: open list:HID CORE LAYER
  Cc: Dmitry Torokhov, Jiri Kosina, Benjamin Tissoires, Peter Hutterer,
	Antonio Ospite, linux-kernel, Input Tools, David Herrmann
In-Reply-To: <1387295334-1744-1-git-send-email-dh.herrmann@gmail.com>

Hi

On Tue, Dec 17, 2013 at 4:48 PM, David Herrmann <dh.herrmann@gmail.com> wrote:
> Hi
>
> This implements the recently discussed ABS2 API. It's working fine on my machine
> with libevdev. Comments welcome!
>
> * Patch #1 fixes some uinput shortcomings and prepares uinput for ABS2
> * Patch #2 adds ABS2
> * Patch #3 is just a small comment-fix for #4
> * Patch #4 adds some new example ABS values in the new range
>
> Note that I have patches pending which make use of the new ABS values, but I'd
> like to get this reduced series in first.

If someone is interested in the libevdev patches, see here:
  http://cgit.freedesktop.org/~dvdhrm/libevdev/log/?h=abs2

I tested the libevdev test-suite in all combinations linux+libevdev,
linux-abs2 + libevdev, linux + libevdev-abs2, linux-abs2 +
libevdev-abs2 and all worked fine.

Thanks
David

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox