Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH v2 2/3] Input: omap-keypad: Convert to threaded IRQ
From: Felipe Balbi @ 2013-07-23 17:32 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: Illia Smyrnov, Dmitry Torokhov, linux-input, linux-kernel,
	linux-omap
In-Reply-To: <20130723172501.GC9166@radagast>

[-- Attachment #1: Type: text/plain, Size: 1923 bytes --]

Hi,

On Tue, Jul 23, 2013 at 08:25:01PM +0300, Felipe Balbi wrote:
> > Convert to use threaded IRQ.
> > 
> > Cc: Felipe Balbi <balbi@ti.com>
> > Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>
> > ---
> >  drivers/input/keyboard/omap4-keypad.c |   29 ++++++++++++++++++++---------
> >  1 files changed, 20 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
> > index c727548..b876a0d 100644
> > --- a/drivers/input/keyboard/omap4-keypad.c
> > +++ b/drivers/input/keyboard/omap4-keypad.c
> > @@ -112,8 +112,22 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
> >  }
> >  
> >  
> > -/* Interrupt handler */
> > -static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
> > +/* Interrupt handlers */
> > +static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
> > +{
> > +	struct omap4_keypad *keypad_data = dev_id;
> > +
> > +	if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
> > +		/* Disable interrupts */
> > +		kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
> > +				 OMAP4_VAL_IRQDISABLE);
> > +		return IRQ_WAKE_THREAD;
> > +	}
> > +
> > +	return IRQ_NONE;
> > +}
> > +
> > +static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
> >  {
> >  	struct omap4_keypad *keypad_data = dev_id;
> >  	struct input_dev *input_dev = keypad_data->input;
> > @@ -121,10 +135,6 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
> >  	unsigned int col, row, code, changed;
> >  	u32 *new_state = (u32 *) key_state;
> >  
> > -	/* Disable interrupts */
> > -	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
> > -			 OMAP4_VAL_IRQDISABLE);
> 
> looking a lot better, but I wonder if you should add a mutex to this
> threaded handler, but I guess there's no way this will never race since

s/never/ever

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 2/3] Input: omap-keypad: Convert to threaded IRQ
From: Felipe Balbi @ 2013-07-23 17:25 UTC (permalink / raw)
  To: Illia Smyrnov
  Cc: Dmitry Torokhov, balbi, linux-input, linux-kernel, linux-omap
In-Reply-To: <1374595798-15492-3-git-send-email-illia.smyrnov@ti.com>

[-- Attachment #1: Type: text/plain, Size: 1941 bytes --]

Hi,

On Tue, Jul 23, 2013 at 07:09:57PM +0300, Illia Smyrnov wrote:
> Convert to use threaded IRQ.
> 
> Cc: Felipe Balbi <balbi@ti.com>
> Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>
> ---
>  drivers/input/keyboard/omap4-keypad.c |   29 ++++++++++++++++++++---------
>  1 files changed, 20 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
> index c727548..b876a0d 100644
> --- a/drivers/input/keyboard/omap4-keypad.c
> +++ b/drivers/input/keyboard/omap4-keypad.c
> @@ -112,8 +112,22 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
>  }
>  
>  
> -/* Interrupt handler */
> -static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
> +/* Interrupt handlers */
> +static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
> +{
> +	struct omap4_keypad *keypad_data = dev_id;
> +
> +	if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
> +		/* Disable interrupts */
> +		kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
> +				 OMAP4_VAL_IRQDISABLE);
> +		return IRQ_WAKE_THREAD;
> +	}
> +
> +	return IRQ_NONE;
> +}
> +
> +static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
>  {
>  	struct omap4_keypad *keypad_data = dev_id;
>  	struct input_dev *input_dev = keypad_data->input;
> @@ -121,10 +135,6 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
>  	unsigned int col, row, code, changed;
>  	u32 *new_state = (u32 *) key_state;
>  
> -	/* Disable interrupts */
> -	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
> -			 OMAP4_VAL_IRQDISABLE);

looking a lot better, but I wonder if you should add a mutex to this
threaded handler, but I guess there's no way this will never race since
IRQs are masked anyway and registers are only accessed from within IRQ
handlers.

Reviewed-by: Felipe Balbi <balbi@ti.com>

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 1/3] Input: omap-keypad: Cleanup - use bitfiled instead of hardcoded values
From: Felipe Balbi @ 2013-07-23 17:20 UTC (permalink / raw)
  To: Illia Smyrnov
  Cc: Dmitry Torokhov, balbi, linux-input, linux-kernel, linux-omap
In-Reply-To: <1374595798-15492-2-git-send-email-illia.smyrnov@ti.com>

[-- Attachment #1: Type: text/plain, Size: 290 bytes --]

Hi,

On Tue, Jul 23, 2013 at 07:09:56PM +0300, Illia Smyrnov wrote:
> Use bitfiled instead of hardcoded values to set KBD_CTRL, use BIT macro,
> remove unused defines.
> 
> Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>

Reviewed-by: Felipe Balbi <balbi@ti.com>

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: [PATCH v2 3/3] Input: omap-keypad: Clear pending interrupts on open
From: Felipe Balbi @ 2013-07-23 17:18 UTC (permalink / raw)
  To: Illia Smyrnov
  Cc: Dmitry Torokhov, balbi, linux-input, linux-kernel, linux-omap
In-Reply-To: <1374595798-15492-4-git-send-email-illia.smyrnov@ti.com>

[-- Attachment #1: Type: text/plain, Size: 1347 bytes --]

Hi,

On Tue, Jul 23, 2013 at 07:09:58PM +0300, Illia Smyrnov wrote:
> Clear pending interrupts when open keypad.

where are these interrupts coming from ?

> Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>
> ---
>  drivers/input/keyboard/omap4-keypad.c |    5 +++--
>  1 files changed, 3 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
> index b876a0d..62abc3e 100644
> --- a/drivers/input/keyboard/omap4-keypad.c
> +++ b/drivers/input/keyboard/omap4-keypad.c
> @@ -185,13 +185,14 @@ static int omap4_keypad_open(struct input_dev *input)
>  			(OMAP4_VAL_PVT << OMAP4_DEF_CTRL_PTV_SHIFT));
>  	kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
>  			OMAP4_VAL_DEBOUNCINGTIME);
> -	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
> -			OMAP4_VAL_IRQDISABLE);
>  	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
>  			OMAP4_DEF_IRQENABLE_EVENTEN |
>  				OMAP4_DEF_IRQENABLE_LONGKEY);
>  	kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
>  			OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
> +	/* clear pending interrupts */
> +	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
> +			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));

you might want to clear these interrupts before unmasking them :-)

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH v2 3/3] Input: omap-keypad: Clear pending interrupts on open
From: Illia Smyrnov @ 2013-07-23 16:09 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: balbi, linux-input, linux-kernel, linux-omap
In-Reply-To: <1374595798-15492-1-git-send-email-illia.smyrnov@ti.com>

Clear pending interrupts when open keypad.

Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>
---
 drivers/input/keyboard/omap4-keypad.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index b876a0d..62abc3e 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -185,13 +185,14 @@ static int omap4_keypad_open(struct input_dev *input)
 			(OMAP4_VAL_PVT << OMAP4_DEF_CTRL_PTV_SHIFT));
 	kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
 			OMAP4_VAL_DEBOUNCINGTIME);
-	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
-			OMAP4_VAL_IRQDISABLE);
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
 			OMAP4_DEF_IRQENABLE_EVENTEN |
 				OMAP4_DEF_IRQENABLE_LONGKEY);
 	kbd_writel(keypad_data, OMAP4_KBD_WAKEUPENABLE,
 			OMAP4_DEF_WUP_EVENT_ENA | OMAP4_DEF_WUP_LONG_KEY_ENA);
+	/* clear pending interrupts */
+	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
+			 kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS));
 
 	enable_irq(keypad_data->irq);
 
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v2 2/3] Input: omap-keypad: Convert to threaded IRQ
From: Illia Smyrnov @ 2013-07-23 16:09 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: balbi, linux-input, linux-kernel, linux-omap
In-Reply-To: <1374595798-15492-1-git-send-email-illia.smyrnov@ti.com>

Convert to use threaded IRQ.

Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>
---
 drivers/input/keyboard/omap4-keypad.c |   29 ++++++++++++++++++++---------
 1 files changed, 20 insertions(+), 9 deletions(-)

diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index c727548..b876a0d 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -112,8 +112,22 @@ static void kbd_write_irqreg(struct omap4_keypad *keypad_data,
 }
 
 
-/* Interrupt handler */
-static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
+/* Interrupt handlers */
+static irqreturn_t omap4_keypad_irq_handler(int irq, void *dev_id)
+{
+	struct omap4_keypad *keypad_data = dev_id;
+
+	if (kbd_read_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS)) {
+		/* Disable interrupts */
+		kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
+				 OMAP4_VAL_IRQDISABLE);
+		return IRQ_WAKE_THREAD;
+	}
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t omap4_keypad_irq_thread_fn(int irq, void *dev_id)
 {
 	struct omap4_keypad *keypad_data = dev_id;
 	struct input_dev *input_dev = keypad_data->input;
@@ -121,10 +135,6 @@ static irqreturn_t omap4_keypad_interrupt(int irq, void *dev_id)
 	unsigned int col, row, code, changed;
 	u32 *new_state = (u32 *) key_state;
 
-	/* Disable interrupts */
-	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQENABLE,
-			 OMAP4_VAL_IRQDISABLE);
-
 	*new_state = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE31_0);
 	*(new_state + 1) = kbd_readl(keypad_data, OMAP4_KBD_FULLCODE63_32);
 
@@ -360,9 +370,10 @@ static int omap4_keypad_probe(struct platform_device *pdev)
 		goto err_free_keymap;
 	}
 
-	error = request_irq(keypad_data->irq, omap4_keypad_interrupt,
-			     IRQF_TRIGGER_RISING,
-			     "omap4-keypad", keypad_data);
+	error = request_threaded_irq(keypad_data->irq, omap4_keypad_irq_handler,
+				     omap4_keypad_irq_thread_fn,
+				     IRQF_TRIGGER_RISING,
+				     "omap4-keypad", keypad_data);
 	if (error) {
 		dev_err(&pdev->dev, "failed to register interrupt\n");
 		goto err_free_input;
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v2 1/3] Input: omap-keypad: Cleanup - use bitfiled instead of hardcoded values
From: Illia Smyrnov @ 2013-07-23 16:09 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: balbi, linux-input, linux-kernel, linux-omap
In-Reply-To: <1374595798-15492-1-git-send-email-illia.smyrnov@ti.com>

Use bitfiled instead of hardcoded values to set KBD_CTRL, use BIT macro,
remove unused defines.

Signed-off-by: Illia Smyrnov <illia.smyrnov@ti.com>
---
 drivers/input/keyboard/omap4-keypad.c |   25 +++++++++++--------------
 1 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index f4aa53a..c727548 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -53,21 +53,17 @@
 #define OMAP4_KBD_FULLCODE63_32		0x48
 
 /* OMAP4 bit definitions */
-#define OMAP4_DEF_IRQENABLE_EVENTEN	(1 << 0)
-#define OMAP4_DEF_IRQENABLE_LONGKEY	(1 << 1)
-#define OMAP4_DEF_IRQENABLE_TIMEOUTEN	(1 << 2)
-#define OMAP4_DEF_WUP_EVENT_ENA		(1 << 0)
-#define OMAP4_DEF_WUP_LONG_KEY_ENA	(1 << 1)
-#define OMAP4_DEF_CTRL_NOSOFTMODE	(1 << 1)
-#define OMAP4_DEF_CTRLPTVVALUE		(1 << 2)
-#define OMAP4_DEF_CTRLPTV		(1 << 1)
+#define OMAP4_DEF_IRQENABLE_EVENTEN	BIT(0)
+#define OMAP4_DEF_IRQENABLE_LONGKEY	BIT(1)
+#define OMAP4_DEF_WUP_EVENT_ENA		BIT(0)
+#define OMAP4_DEF_WUP_LONG_KEY_ENA	BIT(1)
+#define OMAP4_DEF_CTRL_NOSOFTMODE	BIT(1)
+#define OMAP4_DEF_CTRL_PTV_SHIFT	2
 
 /* OMAP4 values */
-#define OMAP4_VAL_IRQDISABLE		0x00
-#define OMAP4_VAL_DEBOUNCINGTIME	0x07
-#define OMAP4_VAL_FUNCTIONALCFG		0x1E
-
-#define OMAP4_MASK_IRQSTATUSDISABLE	0xFFFF
+#define OMAP4_VAL_IRQDISABLE		0x0
+#define OMAP4_VAL_DEBOUNCINGTIME	0x7
+#define OMAP4_VAL_PVT			0x7
 
 enum {
 	KBD_REVISION_OMAP4 = 0,
@@ -175,7 +171,8 @@ static int omap4_keypad_open(struct input_dev *input)
 	disable_irq(keypad_data->irq);
 
 	kbd_writel(keypad_data, OMAP4_KBD_CTRL,
-			OMAP4_VAL_FUNCTIONALCFG);
+			OMAP4_DEF_CTRL_NOSOFTMODE |
+			(OMAP4_VAL_PVT << OMAP4_DEF_CTRL_PTV_SHIFT));
 	kbd_writel(keypad_data, OMAP4_KBD_DEBOUNCINGTIME,
 			OMAP4_VAL_DEBOUNCINGTIME);
 	kbd_write_irqreg(keypad_data, OMAP4_KBD_IRQSTATUS,
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v2 0/3] Input: omap-keypad: Convert to threaded IRQ and cleanup
From: Illia Smyrnov @ 2013-07-23 16:09 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: balbi, linux-input, linux-kernel, linux-omap

Replace unclear hardcoded values with bit field, convert to threaded IRQ and
clear pending interrupts when open the keypad.

Based on top of v3.11-rc2.

Tested on OMAP4 SDP.

Illia Smyrnov (3):
  Input: omap-keypad: Cleanup - use bitfiled instead of hardcoded
    values
  Input: omap-keypad: Convert to threaded IRQ
  Input: omap-keypad: Clear pending interrupts on open

 drivers/input/keyboard/omap4-keypad.c |   59 +++++++++++++++++++--------------
 1 files changed, 34 insertions(+), 25 deletions(-)


^ permalink raw reply

* Re: [PATCH] hid: replace strict_strtoul() with kstrtoul()
From: Jiri Kosina @ 2013-07-23 14:06 UTC (permalink / raw)
  To: Jingoo Han; +Cc: linux-input
In-Reply-To: <000601ce844c$a5059330$ef10b990$@samsung.com>

On Fri, 19 Jul 2013, Jingoo Han wrote:

> The usage of strict_strtoul() is not preferred, because
> strict_strtoul() is obsolete. Thus, kstrtoul() should be
> used.
> 
> Signed-off-by: Jingoo Han <jg1.han@samsung.com>

Applied, thanks.

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH v2 2/2] input/uinput: add UI_GET_SYSPATH ioctl to retrieve the sysfs path
From: Peter Hutterer @ 2013-07-23  1:15 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Dmitry Torokhov, Benjamin Tissoires, linux-input, linux-kernel
In-Reply-To: <1373895429-8846-2-git-send-email-benjamin.tissoires@redhat.com>

On Mon, Jul 15, 2013 at 03:37:09PM +0200, Benjamin Tissoires wrote:
> Evemu [1] uses uinput to replay devices traces it has recorded. However,
> the way evemu uses uinput is slightly different from how uinput is
> supposed to be used.
> Evemu creates the device node through uinput, bu inject events through
> the input device node directly (and skipping the uinput node).
> 
> Currently, evemu relies on an heuristic to guess which input node was
> created. The problem is that is heuristic is subjected to races between
> different uinput devices or even with physical devices. Having a way
> to retrieve the sysfs path allows us to find the event node without
> having to rely on this heuristic.
> 
> [1] http://www.freedesktop.org/wiki/Evemu/
> 
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>

Tested-by: Peter Hutterer <peter.hutterer@who-t.net>

I'd really appreciate a comment above the ioctl define stating what the
ioctl actually returns. only comment regarding the code:

> +static int uinput_str_to_user(const char *str, unsigned int maxlen,
> +			      void __user *p)

I'd do this with a signature of the type (dest, src, len).

Cheers,
   Peter

> ---
>  drivers/input/misc/uinput.c | 37 ++++++++++++++++++++++++++++++++++++-
>  include/linux/uinput.h      |  1 +
>  include/uapi/linux/uinput.h |  3 +++
>  3 files changed, 40 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
> index 7d518b4..49a9f7d 100644
> --- a/drivers/input/misc/uinput.c
> +++ b/drivers/input/misc/uinput.c
> @@ -22,6 +22,7 @@
>   * Changes/Revisions:
>   *	0.4	12/07/2013 (Peter Hutterer <peter.hutterer@redhat.com>)
>   *		- update uinput_user_dev struct to allow abs resolution
> + *		- add UI_GET_SYSPATH ioctl
>   *	0.3	09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
>   *		- updated ff support for the changes in kernel interface
>   *		- added MODULE_VERSION
> @@ -667,6 +668,21 @@ static int uinput_ff_upload_from_user(const char __user *buffer,
>  	__ret;						\
>  })
>  
> +static int uinput_str_to_user(const char *str, unsigned int maxlen,
> +			      void __user *p)
> +{
> +	int len;
> +
> +	if (!str)
> +		return -ENOENT;
> +
> +	len = strlen(str) + 1;
> +	if (len > maxlen)
> +		len = maxlen;
> +
> +	return copy_to_user(p, str, len) ? -EFAULT : len;
> +}
> +
>  static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>  				 unsigned long arg, void __user *p)
>  {
> @@ -676,6 +692,8 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>  	struct uinput_ff_erase  ff_erase;
>  	struct uinput_request   *req;
>  	char			*phys;
> +	const char		*path;
> +	unsigned int		size;
>  
>  	retval = mutex_lock_interruptible(&udev->mutex);
>  	if (retval)
> @@ -828,7 +846,24 @@ static long uinput_ioctl_handler(struct file *file, unsigned int cmd,
>  			break;
>  
>  		default:
> -			retval = -EINVAL;
> +			retval = -EAGAIN;
> +	}
> +
> +	if (retval == -EAGAIN) {
> +		size = _IOC_SIZE(cmd);
> +
> +		/* Now check variable-length commands */
> +		switch (cmd & ~IOCSIZE_MASK) {
> +			case UI_GET_SYSPATH(0):
> +				path = kobject_get_path(&udev->dev->dev.kobj,
> +							GFP_KERNEL);
> +				retval = uinput_str_to_user(path, size, p);
> +				kfree(path);
> +				break;
> +
> +			default:
> +				retval = -EINVAL;
> +		}
>  	}
>  
>   out:
> diff --git a/include/linux/uinput.h b/include/linux/uinput.h
> index 6291a22..64fab81 100644
> --- a/include/linux/uinput.h
> +++ b/include/linux/uinput.h
> @@ -22,6 +22,7 @@
>   * Changes/Revisions:
>   *	0.4	12/07/2013 (Peter Hutterer <peter.hutterer@redhat.com>)
>   *		- update uinput_user_dev struct to allow abs resolution
> + *		- add UI_GET_SYSPATH ioctl
>   *	0.3	24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
>   *		- update ff support for the changes in kernel interface
>   *		- add UINPUT_VERSION
> diff --git a/include/uapi/linux/uinput.h b/include/uapi/linux/uinput.h
> index f6a393b..d826409 100644
> --- a/include/uapi/linux/uinput.h
> +++ b/include/uapi/linux/uinput.h
> @@ -22,6 +22,7 @@
>   * Changes/Revisions:
>   *	0.4	12/07/2013 (Peter Hutterer <peter.hutterer@redhat.com>)
>   *		- update uinput_user_dev struct to allow abs resolution
> + *		- add UI_GET_SYSPATH ioctl
>   *	0.3	24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
>   *		- update ff support for the changes in kernel interface
>   *		- add UINPUT_VERSION
> @@ -75,6 +76,8 @@ struct uinput_ff_erase {
>  #define UI_BEGIN_FF_ERASE	_IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
>  #define UI_END_FF_ERASE		_IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
>  
> +#define UI_GET_SYSPATH(len)	_IOC(_IOC_READ, UINPUT_IOCTL_BASE, 300, len)
> +
>  /*
>   * To write a force-feedback-capable driver, the upload_effect
>   * and erase_effect callbacks in input_dev must be implemented.
> -- 
> 1.8.3.1
> 

^ permalink raw reply

* [ANNOUNCE] libevdev 0.2
From: Peter Hutterer @ 2013-07-22 23:09 UTC (permalink / raw)
  To: input-tools

[Note: bcc'd linux-input, wayland-devel and xorg-devel since those are the
expected interested parties. Apologies if you get this email multiple times,
I won't do this in the future. Future announcements will only go to
input-tools@lists.freedesktop.org]

This is the first release for libevdev, a C library that wraps the
kernel evdev interface. The benefits are
* type-safe interface for checking bits on a device
* various abstractions for ioctls that aren't quite as straightforward (e.g.
  EV_REP handling)
* simple abstraction for handling SYN_DROPPED events

This library is now hosted on freedesktop.org:
http://www.freedesktop.org/wiki/Software/libevdev/
API documentation: http://www.freedesktop.org/software/libevdev/doc/latest/
Bugzilla component: https://bugs.freedesktop.org/enter_bug.cgi?product=libevdev
cgit: http://cgit.freedesktop.org/libevdev/

libevdev provides API calls for the various bits, so a simple process can
work this way:

  struct libevdev *dev;

  fd = open("/dev/input/event0", O_RDONLY);
  rc = libevdev_new_from_fd(fd, &dev);

  if (libevdev_has_event_code(dev, EV_REL, REL_X))
        /* do something */

For event handling, libevdev provides one call that returns the next event
in the queue:

  rc = libevdev_next_event(dev, flags, &ev);

which does what you expect and returns 0 on success or -EAGAIN if there are
no events waiting. If a SYN_DROPPED is the next event in the queue, libevdev
syncs the device state and returns 1. The process can then handle the delta
by simply parsing events until the device is fully synced again:

  while ((rc = libevdev_next_event(dev, LIBEVEV_READ_SYNC, &ev)) == 1)
     /* this is a synced event */

  if (rc == -EAGAIN)
     /* we are now fully synced */
  else
     /* error */

To check out an example of how libevdev looks like, have a look at how
evtest would look like with libevdev.
http://cgit.freedesktop.org/libevdev/tree/tools/libevdev-events.c

The goal is that future and current processes that deal with evdev events
will switch to libevdev. An example of changes needed for the X.org
synaptics driver is here:
http://cgit.freedesktop.org/~whot/xf86-input-synaptics/commit/?h=libevdev

Suggestions, comments, etc. are all welcome. Please note that the library is
still in an early stage and may change in the future.

Cheers,
   Peter

git tag: libevdev-0.2

http://www.freedesktop.org/software/libevdev/libevdev-0.2.tar.xz
MD5:  bce22c2ae9c87b9a7b5c8d055f771084  libevdev-0.2.tar.xz
SHA1: 8efec1ff4f8b45929c3acc2b7e4f9fd37c9f8d37  libevdev-0.2.tar.xz
SHA256: da25b6efba09d7e357e50a31e599d98b97f116eb0f32086335640a06e13e37a6  libevdev-0.2.tar.xz


^ permalink raw reply

* Re: [PATCH 2/2] Input: omap-keypad: Cleanup - remove unnecessary IRQ enabling/disabling
From: Felipe Balbi @ 2013-07-22 21:04 UTC (permalink / raw)
  To: Illia Smyrnov
  Cc: balbi, Illia Smyrnov, Dmitry Torokhov, linux-input, linux-kernel,
	linux-omap
In-Reply-To: <51ED6AF1.9070605@ti.com>

[-- Attachment #1: Type: text/plain, Size: 2321 bytes --]

Hi,

On Mon, Jul 22, 2013 at 08:25:05PM +0300, Illia Smyrnov wrote:
> >please don't remove this code. It'll be good to have this around when we
> >move the driver to threaded IRQs without IRQF_ONESHOT. In fact, it would
> >be very simple to implement such a change, wanna take it up ?
> >
> >It should be doable in few patches:
> >
> >1) switch over to request_threaded_irq()
> >
> >	just blind move to a thread, without hardirq handler, so
> >	IRQF_ONESHOT is mandatory.
> >
> >2) add hardirq handler
> >
> >	read IRQSTATUS to check if our device has generated IRQs
> >	returning IRQ_WAKE_THREAD if true
> >
> >3) move 'IRQ masking logic' to hardirq handler, before returning
> >IRQ_WAKE_THREAD
> >
> >	this will let you remove IRQF_ONESHOT
> >
> >4) finally remove IRQF_ONESHOT
> >
> >	this makes sure that IRQs aren't kept disabled until we have
> >	time to iterate over the entire keypad matrix. Only the keypad
> >	IRQ will be masked.
> >
> 
> Ok, but why we need to remove IRQF_ONESHOT flag for omap keypad driver?

well, we might want to use this HW with the RT patchset. In that case,
we want to run with IRQs disabled for as short time as possible.

> The keypad IRQ isn't shared IRQ and in our case hardirq handler will
> always return IRQ_WAKE_THREAD like default

not entirely true, you still want to check if *this* HW generated to
interrupt in case you get spurious IRQs and whatnot.

> irq_default_primary_handler do. With IRQF_ONESHOT flag IRQ line will
> be masked until the threaded
> handler finished, but there is only keypad on this line.
> 
> I tested two versions:
> the first one - just threaded IRQs with IRQF_ONESHOT and without
> specific hardirq handler.
> the second version - threaded IRQs without IRQF_ONESHOT as you described.
> Both versions was successfully tested on Blaze's keypad.

you can't simply remove IRQF_ONESHOT, you need to mask this interrupt at
the keypad level, basically you clear IRQ_ENABLE_SET (or write to
IRQ_CLEAR or whatever it's called).

Remember that the hardirq handler runs with IRQs disabled and what you
need to guarantee is that once you go over your hardirq, you mask
keypad's IRQs only.

Currently, the RT patchset forces all IRQs to run as threads, but that's
less than optimal.

-- 
balbi

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Is it possible to debounce button events?
From: Adam Nielsen @ 2013-07-22 19:38 UTC (permalink / raw)
  To: linux-input

Hi all,

In every mouse I have ever owned, as it ages the buttons become less
and less reliable.  Usually this means it starts to send multiple
button press events each time the button is clicked.  The Logitech
mouse I am currently using is now producing double-clicks about 10% of
the time when I only press the left button once.

Rather than replace an otherwise perfectly working device, or
disassemble and clean the switches (again), I am wondering whether
there is any sort of debounce option in the input subsystem.

I am looking for some setting where I can tell the input subsystem to
ignore button-press/release events if they occur within a configurable
amount of time after the initial event, e.g. 10 milliseconds.

This would be quick enough that it would not interfere with intentional
double-clicks, but unintentional double-clicks would be eliminated.

It looks like a few input drivers internally implement debouncing, so
I'm wondering whether there is a generic mechanism that can be used for
any button on any input device?

Many thanks,
Adam.



^ permalink raw reply

* Re: [PATCH 1/2] Revert "Revert "HID: Fix logitech-dj: missing Unifying device issue""
From: Linus Torvalds @ 2013-07-22 19:21 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Nestor Lopez Casado, benjamin.tissoires, Andrew de los Reyes,
	joseph.salisbury, linux-input@vger.kernel.org,
	Linux Kernel Mailing List, Peter Hurley
In-Reply-To: <alpine.LNX.2.00.1307221633010.23128@pobox.suse.cz>

On Mon, Jul 22, 2013 at 7:35 AM, Jiri Kosina <jkosina@suse.cz> wrote:
>
> Linus -- could you please by any chance test whether the two patches in
> that branch make the problem you are observing any better? (and no, this
> is not a pull request yet).
>
> It's still not clear whether we are chasing two different issues here, or
> not.

I think it's two different issues. It sounds like the USB3 one is
fairly repeatable?

Mine is quite rare. I think it's so far happened just once during the
the 3.11 merge window+, and that's despite me rebooting usually a few
times a day (less now that things are calming down).

On Mon, Jul 22, 2013 at 8:27 AM, Jiri Kosina <jkosina@suse.cz> wrote:
>
> It might help to get a usbmon trace and dmesg log from Linus, if he
> still has this problem.

So see above. I've sent the dmesg - not that it's useful, since it
just lacks the lines showing the actual wireless device after plugging
it in (but the receiver is recognized). No error messages, just not
any working keyboard.

And it's not common. I think it has happened a handful of times over
the last four months or so.

                  Linus

^ permalink raw reply

* Re: [PATCH 2/2] Input: omap-keypad: Cleanup - remove unnecessary IRQ enabling/disabling
From: Illia Smyrnov @ 2013-07-22 17:25 UTC (permalink / raw)
  To: balbi; +Cc: Illia Smyrnov, Dmitry Torokhov, linux-input, linux-kernel,
	linux-omap
In-Reply-To: <20130719132648.GB17188@arwen.pp.htv.fi>

Hi,

On 07/19/2013 04:26 PM, Felipe Balbi wrote:
> Hi,
>
> [...]
> please don't remove this code. It'll be good to have this around when we
> move the driver to threaded IRQs without IRQF_ONESHOT. In fact, it would
> be very simple to implement such a change, wanna take it up ?
>
> It should be doable in few patches:
>
> 1) switch over to request_threaded_irq()
>
> 	just blind move to a thread, without hardirq handler, so
> 	IRQF_ONESHOT is mandatory.
>
> 2) add hardirq handler
>
> 	read IRQSTATUS to check if our device has generated IRQs
> 	returning IRQ_WAKE_THREAD if true
>
> 3) move 'IRQ masking logic' to hardirq handler, before returning
> IRQ_WAKE_THREAD
>
> 	this will let you remove IRQF_ONESHOT
>
> 4) finally remove IRQF_ONESHOT
>
> 	this makes sure that IRQs aren't kept disabled until we have
> 	time to iterate over the entire keypad matrix. Only the keypad
> 	IRQ will be masked.
>

Ok, but why we need to remove IRQF_ONESHOT flag for omap keypad driver?

The keypad IRQ isn't shared IRQ and in our case hardirq handler will 
always return IRQ_WAKE_THREAD like default irq_default_primary_handler 
do. With IRQF_ONESHOT flag IRQ line will be masked until the threaded
handler finished, but there is only keypad on this line.

I tested two versions:
the first one - just threaded IRQs with IRQF_ONESHOT and without 
specific hardirq handler.
the second version - threaded IRQs without IRQF_ONESHOT as you described.
Both versions was successfully tested on Blaze's keypad.

^ permalink raw reply

* Re: [PATCH 1/2] Revert "Revert "HID: Fix logitech-dj: missing Unifying device issue""
From: Alan Stern @ 2013-07-22 15:27 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Jiri Kosina, Sarah Sharp, Joseph Salisbury, Nestor Lopez Casado,
	benjamin.tissoires, adlr, linux-input, linux-kernel, linux-usb
In-Reply-To: <51ED3BC3.40300@hurleysoftware.com>

On Mon, 22 Jul 2013, Peter Hurley wrote:

> On 07/22/2013 07:44 AM, Jiri Kosina wrote:
...
> > Seems like this might be a part of the picture, but not a complete one.
> > Linus claims to have similar problem, but his receiver is not connected
> > through xHCI (I got this as an off-list report, so can't really provide a
> > pointer to ML archives).
> 
> Ah, ok. I wasn't aware of that. I'll assume then that the necessary
> people have the complete picture.

It might help to get a usbmon trace and dmesg log from Linus, if he
still has this problem.

Alan Stern

^ permalink raw reply

* Re: [PATCH 1/2] Revert "Revert "HID: Fix logitech-dj: missing Unifying device issue""
From: Jiri Kosina @ 2013-07-22 14:35 UTC (permalink / raw)
  To: Nestor Lopez Casado
  Cc: benjamin.tissoires, adlr, joseph.salisbury, linux-input,
	linux-kernel, Linus Torvalds, Peter Hurley
In-Reply-To: <1374153691-25100-1-git-send-email-nlopezcasad@logitech.com>

On Thu, 18 Jul 2013, Nestor Lopez Casado wrote:

> This reverts commit 8af6c08830b1ae114d1a8b548b1f8b056e068887.
> 
> This patch re-adds the workaround introduced by 596264082f10dd4
> which was reverted by 8af6c08830b1ae114.
> 
> The original patch 596264 was needed to overcome a situation where
> the hid-core would drop incoming reports while probe() was being
> executed.
> 
> This issue was solved by c849a6143bec520af which added
> hid_device_io_start() and hid_device_io_stop() that enable a specific
> hid driver to opt-in for input reports while its probe() is being
> executed.
> 
> Commit a9dd22b730857347 modified hid-logitech-dj so as to use the
> functionality added to hid-core. Having done that, workaround 596264
> was no longer necessary and was reverted by 8af6c08.
> 
> We now encounter a different problem that ends up 'again' thwarting
> the Unifying receiver enumeration. The problem is time and usb controller
> dependent. Ocasionally the reports sent to the usb receiver to start
> the paired devices enumeration fail with -EPIPE and the receiver never
> gets to enumerate the paired devices.
[ ... snip ... ]

Ok, this is now in

	git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git for-3.11/logitech-enumeration-fix

Linus added to CC.

Linus -- could you please by any chance test whether the two patches in 
that branch make the problem you are observing any better? (and no, this 
is not a pull request yet).

It's still not clear whether we are chasing two different issues here, or 
not.

Thanks,

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH 1/2] Revert "Revert "HID: Fix logitech-dj: missing Unifying device issue""
From: Peter Hurley @ 2013-07-22 14:03 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Sarah Sharp, Joseph Salisbury, Nestor Lopez Casado,
	benjamin.tissoires, adlr, linux-input, linux-kernel, linux-usb
In-Reply-To: <alpine.LNX.2.00.1307221342410.23128@pobox.suse.cz>

On 07/22/2013 07:44 AM, Jiri Kosina wrote:
> On Fri, 19 Jul 2013, Peter Hurley wrote:
>
>>>> As far as getting printk output from a custom kernel, I think that may
>>>> be beyond the reporter's capability. Perhaps one of the Ubuntu devs
>>>> triaging this bug could provide a test kernel for the OP with those
>>>> options on.
>>>>
>>>> Joseph, would you be willing to do that?
>>>
>>> Sure thing.  I'll build a kernel and request that the bug reporter
>>> collect usbmon data.
>>
>> Thanks Joseph for building the test kernel and getting it to the reporter!
>>
>> Sarah,
>>
>> I've attached the dmesg capture supplied by the original reporter on
>> a 3.10 custom kernel w/ the kbuild options you requested.
>>
>> It seems as if your initial suspicion is correct:
>>
>> [   46.785490] xhci_hcd 0000:00:14.0: Endpoint 0x81 not halted, refusing to
>> reset.
>> [   46.785493] xhci_hcd 0000:00:14.0: Endpoint 0x82 not halted, refusing to
>> reset.
>> [   46.785496] xhci_hcd 0000:00:14.0: Endpoint 0x83 not halted, refusing to
>> reset.
>> [   46.785952] xhci_hcd 0000:00:14.0: Waiting for status stage event
>>
>> At this point, would you recommend proceeding with the workaround or
>> waiting for an xHCI bug fix?
>
> Thanks for your efforts.
>
> Seems like this might be a part of the picture, but not a complete one.
> Linus claims to have similar problem, but his receiver is not connected
> through xHCI (I got this as an off-list report, so can't really provide a
> pointer to ML archives).

Ah, ok. I wasn't aware of that. I'll assume then that the necessary
people have the complete picture.

Regards,
Peter Hurley



^ permalink raw reply

* Re: [PATCH 1/2] Revert "Revert "HID: Fix logitech-dj: missing Unifying device issue""
From: Jiri Kosina @ 2013-07-22 11:44 UTC (permalink / raw)
  To: Peter Hurley
  Cc: Sarah Sharp, Joseph Salisbury, Nestor Lopez Casado,
	benjamin.tissoires, adlr, linux-input, linux-kernel, linux-usb
In-Reply-To: <51E9B025.8010803@hurleysoftware.com>

On Fri, 19 Jul 2013, Peter Hurley wrote:

> > > As far as getting printk output from a custom kernel, I think that may
> > > be beyond the reporter's capability. Perhaps one of the Ubuntu devs
> > > triaging this bug could provide a test kernel for the OP with those
> > > options on.
> > > 
> > > Joseph, would you be willing to do that?
> > 
> > Sure thing.  I'll build a kernel and request that the bug reporter
> > collect usbmon data.
> 
> Thanks Joseph for building the test kernel and getting it to the reporter!
> 
> Sarah,
> 
> I've attached the dmesg capture supplied by the original reporter on
> a 3.10 custom kernel w/ the kbuild options you requested.
> 
> It seems as if your initial suspicion is correct:
> 
> [   46.785490] xhci_hcd 0000:00:14.0: Endpoint 0x81 not halted, refusing to
> reset.
> [   46.785493] xhci_hcd 0000:00:14.0: Endpoint 0x82 not halted, refusing to
> reset.
> [   46.785496] xhci_hcd 0000:00:14.0: Endpoint 0x83 not halted, refusing to
> reset.
> [   46.785952] xhci_hcd 0000:00:14.0: Waiting for status stage event
> 
> At this point, would you recommend proceeding with the workaround or
> waiting for an xHCI bug fix?

Thanks for your efforts.

Seems like this might be a part of the picture, but not a complete one. 
Linus claims to have similar problem, but his receiver is not connected 
through xHCI (I got this as an off-list report, so can't really provide a 
pointer to ML archives).

Thanks,

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH 03/15] input: ti_tsc: Enable shared IRQ for TSC
From: Jonathan Cameron @ 2013-07-20 10:58 UTC (permalink / raw)
  To: Zubair Lutfullah
  Cc: jic23, gregkh, linux-input@vger.kernel.org, linux-kernel, koen,
	Torokhov
In-Reply-To: <51EA6D19.7040401@kernel.org>

On 07/20/2013 11:57 AM, Jonathan Cameron wrote:
> On 07/18/2013 11:21 PM, Zubair Lutfullah wrote:
>> From: "Patil, Rachna" <rachna@ti.com>
>>
>> Touchscreen and ADC share the same IRQ line from parent MFD core.
>> Previously only Touchscreen was interrupt based.
>> With continuous mode support added in ADC driver, driver requires
>> interrupt to process the ADC samples, so enable shared IRQ flag bit for
>> touchscreen.
>>
>> Signed-off-by: Patil, Rachna <rachna@ti.com>
>> Acked-by: Vaibhav Hiremath <hvaibhav@ti.com>
>> Signed-off-by: Zubair Lutfullah <zubair.lutfullah@gmail.com>
> cc'd Dmitry and Linux-input.
> 
> If this goes through IIO as it is required for the rest of the series to
> work then I will need an Ack from Dmitry.
Sorry, finger memory meant I cc'd linux-iio again, instead of linux-input.

> 
>> ---
>>  drivers/input/touchscreen/ti_am335x_tsc.c |   14 +++++++++++---
>>  1 file changed, 11 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
>> index 0e9f02a..edc3d03 100644
>> --- a/drivers/input/touchscreen/ti_am335x_tsc.c
>> +++ b/drivers/input/touchscreen/ti_am335x_tsc.c
>> @@ -260,8 +260,16 @@ static irqreturn_t titsc_irq(int irq, void *dev)
>>  	unsigned int fsm;
>>  
>>  	status = titsc_readl(ts_dev, REG_IRQSTATUS);
>> -	if (status & IRQENB_FIFO0THRES) {
>>  
>> +	/*
>> +	* ADC and touchscreen share the IRQ line.
>> +	* FIFO1 threshold interrupt is used by ADC,
>> +	* hence return from touchscreen IRQ handler if FIFO1
>> +	* threshold interrupt occurred.
>> +	*/
>> +	if (status & IRQENB_FIFO1THRES)
>> +		return IRQ_NONE;
>> +	else if (status & IRQENB_FIFO0THRES) {
>>  		titsc_read_coordinates(ts_dev, &x, &y, &z1, &z2);
>>  
>>  		if (ts_dev->pen_down && z1 != 0 && z2 != 0) {
>> @@ -315,7 +323,7 @@ static irqreturn_t titsc_irq(int irq, void *dev)
>>  	}
>>  
>>  	if (irqclr) {
>> -		titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
>> +		titsc_writel(ts_dev, REG_IRQSTATUS, (status | irqclr));
>>  		am335x_tsc_se_update(ts_dev->mfd_tscadc);
>>  		return IRQ_HANDLED;
>>  	}
>> @@ -389,7 +397,7 @@ static int titsc_probe(struct platform_device *pdev)
>>  	}
>>  
>>  	err = request_irq(ts_dev->irq, titsc_irq,
>> -			  0, pdev->dev.driver->name, ts_dev);
>> +			  IRQF_SHARED, pdev->dev.driver->name, ts_dev);
>>  	if (err) {
>>  		dev_err(&pdev->dev, "failed to allocate irq.\n");
>>  		goto err_free_mem;
>>

^ permalink raw reply

* Re: [PATCH 5/5] iio: at91: introduce touch screen support in iio adc driver
From: Jonathan Cameron @ 2013-07-20  9:57 UTC (permalink / raw)
  To: Josh Wu
  Cc: jic23-KWPb1pKIrIJaa/9Udqfwiw,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-iio-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	plagnioj-sclMFOaUSTBWk0Htik3J/w,
	nicolas.ferre-AIFe0yeh4nAAvxtiuMwx3w, Dmitry Torokhov,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1373789069-11604-6-git-send-email-josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>

On 07/14/2013 09:04 AM, Josh Wu wrote:
> AT91 ADC hardware integrate touch screen support. So this patch add touch
> screen support for at91 adc iio driver.
> To enable touch screen support in adc, you need to add the dt parameters:
>   which type of touch are used? (4 or 5 wires), sample period time,
>   pen detect debounce time, average samples and pen detect resistor.
>
> In the meantime, since touch screen will use a interal period trigger of adc,
> so it is conflict to other hardware triggers. Driver will disable the hardware
> trigger support if touch screen is enabled.
>
> This driver has been tested in AT91SAM9X5-EK and SAMA5D3x-EK.

Firstly, this is adding input subsystem stuff inside an iio driver.  Generally we
are very anti this sort of combination, but I agree that right now the support for
doing it any other way is not really present.

The next bit of text is actually largely irrelevant here as I actually read the driver after
I wrote it and discovered the hardware handles all the nastiness of touch screen processing here.
I'll leave it here for reference of anyone working on parts where it is relevant ;)

     When I had more time to work on IIO I was working on an iio to input
     bridge driver (similar to iio-hwmon, but using the buffered interface hooks instead).
     It was fundamentally working, but I never quite got around to cleaning it up for submission.
     I'd appreciate any comments on what is missing or does not work for this case.

     http://marc.info/?l=linux-iio&m=135167944813803&w=2

     Ulitimately what I would love to see is a generic touch screen consumer driver for IIO
     adc's but appreciate that is a big and complex job given all the different varieties of
     touch screen and trying to abstract the control of the various channels.

So back to this part.  My immediate thought is that this really ought to have an mfd
underneath separate IIO and input drivers.

Dmitry, what do you think?

>
> Signed-off-by: Josh Wu <josh.wu-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
> Cc: Dmitry Torokhov <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
>  .../devicetree/bindings/arm/atmel-adc.txt          |   13 +
>  arch/arm/mach-at91/include/mach/at91_adc.h         |   34 ++
>  drivers/iio/adc/at91_adc.c                         |  389 ++++++++++++++++++--
>  3 files changed, 412 insertions(+), 24 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/arm/atmel-adc.txt b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> index 0db2945..925d656 100644
> --- a/Documentation/devicetree/bindings/arm/atmel-adc.txt
> +++ b/Documentation/devicetree/bindings/arm/atmel-adc.txt
> @@ -29,6 +29,19 @@ Optional properties:
>    - atmel,adc-sample-hold-time: Sample and Hold Time in microseconds
>    - atmel,adc-clock-rate: ADC clock rate. If not specified, use the default
>  			  adc_op_clk.
> +  - atmel,adc-touchscreen-wires: Number of touch screen wires. Only support
> +				 4 and 5 wires touch screen.
> +    NOTE: when adc touch screen enabled, the adc hardware trigger will be
> +          disabled. Since touch screen will occupied the trigger register.
> +  - atmel,adc-ts-pendet-debounce: Debounce time in microsecond for touch pen
> +				  detect.
> +  - atmel,adc-ts-sample-period-time: Sample Period Time in microsecond for
> +				     touch screen
> +  - atmel,adc-ts-filter-average: Numbers of sampling data will be averaged.
> +    0 means no average. 1 means average two samples. 2 means average four
> +    samples. 3 means average eight samples.
> +  - atmel,adc-ts-pendet-sensitivity: Pen Detection input pull-up resistor.
> +    It can be 0, 1, 2, 3.
>
>  Optional trigger Nodes:
>    - Required properties:
> diff --git a/arch/arm/mach-at91/include/mach/at91_adc.h b/arch/arm/mach-at91/include/mach/at91_adc.h
> index ab273ee..6d6cc14 100644
> --- a/arch/arm/mach-at91/include/mach/at91_adc.h
> +++ b/arch/arm/mach-at91/include/mach/at91_adc.h
> @@ -57,10 +57,44 @@
>  #define AT91_ADC_IER		0x24		/* Interrupt Enable Register */
>  #define AT91_ADC_IDR		0x28		/* Interrupt Disable Register */
>  #define AT91_ADC_IMR		0x2C		/* Interrupt Mask Register */
> +#define		AT91_ADC_IER_PEN	(1 << 29)
> +#define		AT91_ADC_IER_NOPEN	(1 << 30)
> +#define		AT91_ADC_IER_XRDY	(1 << 20)
> +#define		AT91_ADC_IER_YRDY	(1 << 21)
> +#define		AT91_ADC_IER_PRDY	(1 << 22)
> +#define		AT91_ADC_ISR_PENS	(1 << 31)
>
>  #define AT91_ADC_CHR(n)		(0x30 + ((n) * 4))	/* Channel Data Register N */
>  #define		AT91_ADC_DATA		(0x3ff)
>
> +#define AT91_ADC_ACR		0x94	/* Analog Control Register */
> +#define		AT91_ADC_ACR_PENDETSENS	(0x3 << 0)	/* pull-up resistor */
> +
> +#define AT91_ADC_TSMR		0xB0
> +#define		AT91_ADC_TSMR_TSMODE	(3 << 0)	/* Touch Screen Mode */
> +#define			AT91_ADC_TSMR_TSMODE_NONE		(0 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_NO_PRESS	(1 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_4WIRE_PRESS	(2 << 0)
> +#define			AT91_ADC_TSMR_TSMODE_5WIRE		(3 << 0)
> +#define		AT91_ADC_TSMR_TSAV	(3 << 4)	/* Averages samples */
> +#define			AT91_ADC_TSMR_TSAV_(x)		((x) << 4)
> +#define		AT91_ADC_TSMR_SCTIM	(0x0f << 16)	/* Switch closure time */
> +#define		AT91_ADC_TSMR_PENDBC	(0x0f << 28)	/* Pen Debounce time */
> +#define			AT91_ADC_TSMR_PENDBC_(x)	((x) << 28)
> +#define		AT91_ADC_TSMR_NOTSDMA	(1 << 22)	/* No Touchscreen DMA */
> +#define		AT91_ADC_TSMR_PENDET_DIS	(0 << 24)	/* Pen contact detection disable */
> +#define		AT91_ADC_TSMR_PENDET_ENA	(1 << 24)	/* Pen contact detection enable */
> +
> +#define AT91_ADC_TSXPOSR	0xB4
> +#define AT91_ADC_TSYPOSR	0xB8
> +#define AT91_ADC_TSPRESSR	0xBC
> +
>  #define AT91_ADC_VERSION	0xFC
>
> +/* Trigger Register bit field */
> +#define		AT91_ADC_TRGR_TRGPER	(0xffff << 16)
> +#define			AT91_ADC_TRGR_TRGPER_(x)	((x) << 16)
> +#define		AT91_ADC_TRGR_TRGMOD	(0x7 << 0)
> +#define			AT91_ADC_TRGR_MOD_PERIOD_TRIG	(5 << 0)
> +
>  #endif
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 8f1386f..ffc0e42 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -11,6 +11,7 @@
>  #include <linux/clk.h>
>  #include <linux/err.h>
>  #include <linux/io.h>
> +#include <linux/input.h>
>  #include <linux/interrupt.h>
>  #include <linux/jiffies.h>
>  #include <linux/kernel.h>
> @@ -39,12 +40,24 @@
>  #define at91_adc_writel(st, reg, val) \
>  	(writel_relaxed(val, st->reg_base + reg))
>
> +#define DRIVER_NAME		"at91_adc"
> +#define MAX_POS_BITS		12
> +
> +#define ZTHRESHOLD		9000
> +
>  struct at91_adc_caps {
> +	bool	has_12bits_xy;	/* true means use 12 bits. Otherwise 10 bits */
>  	bool	has_tsmr;	/* only at91sam9x5, sama5d3 have TSMR reg */
>  	u32	mr_prescal_mask;
>  	u32	mr_startup_mask;
>  };
>
> +enum atmel_adc_ts_type {
> +	ATMEL_ADC_TOUCHSCREEN_NONE = 0,
> +	ATMEL_ADC_TOUCHSCREEN_4WIRE,
> +	ATMEL_ADC_TOUCHSCREEN_5WIRE,
> +};
> +
>  struct at91_adc_state {
>  	struct clk		*adc_clk;
>  	u32			adc_clk_rate;
> @@ -70,6 +83,29 @@ struct at91_adc_state {
>  	bool			low_res;	/* the resolution corresponds to the lowest one */
>  	wait_queue_head_t	wq_data_avail;
>  	struct at91_adc_caps	caps;
> +
> +	/*
> +	 * Following ADC channels are shared by touchscreen:
> +	 *
> +	 * CH0 -- Touch screen XP/UL
> +	 * CH1 -- Touch screen XM/UR
> +	 * CH2 -- Touch screen YP/LL
> +	 * CH3 -- Touch screen YM/Sense
> +	 * CH4 -- Touch screen LR(5-wire only)
> +	 *
> +	 * The bitfields below represents the reserved channel in the
> +	 * touchscreen mode.
> +	 */
> +#define CHAN_MASK_TOUCHSCREEN_4WIRE	(0xf << 0)
> +#define CHAN_MASK_TOUCHSCREEN_5WIRE	(0x1f << 0)
> +	enum atmel_adc_ts_type	touchscreen_type;
> +	struct input_dev		*ts_input;
> +
> +	u8			ts_filter_average;
> +	u16			ts_pen_detect_debounce;
> +	u8			ts_pen_detect_sensitivity;
> +	u16			ts_sample_period_time;
> +	u16			ts_sample_period_val;
>  };
>
>  static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
> @@ -104,14 +140,10 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
>  	return IRQ_HANDLED;
>  }
>
> -static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
> +/* Handler for classic adc channel eoc trigger */
> +void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
>  {
> -	struct iio_dev *idev = private;
>  	struct at91_adc_state *st = iio_priv(idev);
> -	u32 status = at91_adc_readl(st, st->registers->status_register);
> -
> -	if (!(status & st->registers->drdy_mask))
> -		return IRQ_HANDLED;
>
>  	if (iio_buffer_enabled(idev)) {
>  		disable_irq_nosync(irq);
> @@ -121,6 +153,115 @@ static irqreturn_t at91_adc_eoc_trigger(int irq, void *private)
>  		st->done = true;
>  		wake_up_interruptible(&st->wq_data_avail);
>  	}
> +}
> +
> +static int at91_ts_sample(struct at91_adc_state *st)
> +{
> +	unsigned int xscale, yscale, reg, z1, z2;
> +	unsigned int x, y, pres, xpos, ypos;
> +	unsigned int rxp = 1;
> +	unsigned int factor = 1000;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +
> +	unsigned int xyz_mask_bits = st->caps.has_12bits_xy ? 12 : 10;
> +	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
> +
> +	/* calculate position */
> +	/* x position = (x / xscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +	xpos = reg & xyz_mask;
> +	x = (xpos << MAX_POS_BITS) - xpos;
> +	xscale = (reg >> 16) & xyz_mask;
> +	if (xscale != 0)
> +		x /= xscale;
> +	else
> +		dev_err(&idev->dev, "xscale == 0!!!\n");
> +
> +	/* y position = (y / yscale) * max, max = 2^MAX_POS_BITS - 1 */
> +	reg = at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +	ypos = reg & xyz_mask;
> +	y = (ypos << MAX_POS_BITS) - ypos;
> +	yscale = (reg >> 16) & xyz_mask;
> +	if (yscale != 0)
> +		y /= yscale;
> +	else
> +		dev_err(&idev->dev, "yscale == 0!!!\n");
> +
> +	/* calculate the pressure */
> +	reg = at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +	z1 = reg & xyz_mask;
> +	z2 = (reg >> 16) & xyz_mask;
> +
> +	if (z1 != 0)
> +		pres = rxp * (x * factor / 1024) * (z2 * factor / z1 - factor)
> +			/ factor;
> +	else
> +		pres = ZTHRESHOLD;	/* no pen contacted */
> +
> +	dev_dbg(&idev->dev, "xpos = %d, xscale = %d, ypos = %d, yscale = %d, z1 = %d, z2 = %d, press = %d\n",
> +				xpos, xscale, ypos, yscale, z1, z2, pres);
> +
> +	if (pres < ZTHRESHOLD) {
> +		dev_dbg(&idev->dev, "x = %d, y = %d, pressure = %d\n",
> +					x, y, pres / factor);
> +		input_report_abs(st->ts_input, ABS_X, x);
> +		input_report_abs(st->ts_input, ABS_Y, y);
> +		input_report_abs(st->ts_input, ABS_PRESSURE, pres);
> +		input_report_key(st->ts_input, BTN_TOUCH, 1);
> +		input_sync(st->ts_input);
> +	} else {
> +		dev_dbg(&idev->dev,
> +				"pressure too low: not reporting\n");
> +	}
> +
> +	return 0;
> +}
> +
> +
> +static irqreturn_t at91_adc_interrupt(int irq, void *private)
> +{
> +	struct iio_dev *idev = private;
> +	struct at91_adc_state *st = iio_priv(idev);
> +	u32 status = at91_adc_readl(st, st->registers->status_register);
> +	const uint32_t ts_data_irq_mask =
> +		AT91_ADC_IER_XRDY |
> +		AT91_ADC_IER_YRDY |
> +		AT91_ADC_IER_PRDY;
> +
> +	if (status & st->registers->drdy_mask)
> +		handle_adc_eoc_trigger(irq, idev);
> +
> +	if (status & AT91_ADC_IER_PEN) {
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		/* Set up period trigger for sampling */
> +		at91_adc_writel(st, st->registers->trigger_register,
> +			AT91_ADC_TRGR_MOD_PERIOD_TRIG |
> +			AT91_ADC_TRGR_TRGPER_(st->ts_sample_period_val));
> +	} else if (status & AT91_ADC_IER_NOPEN) {
> +		at91_adc_writel(st, st->registers->trigger_register, 0);
> +		at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_NOPEN |
> +			ts_data_irq_mask);
> +		at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +
> +		input_report_key(st->ts_input, BTN_TOUCH, 0);
> +		input_sync(st->ts_input);
> +	} else if ((status & ts_data_irq_mask) == ts_data_irq_mask) {
> +		/* Now all touchscreen data is ready */
> +
> +		if (status & AT91_ADC_ISR_PENS) {
> +			/* validate data by pen contact */
> +			at91_ts_sample(st);
> +		} else {
> +			/* triggered by event that is no pen contact, just read
> +			 * them to clean the interrupt and discard all.
> +			 */
> +			at91_adc_readl(st, AT91_ADC_TSXPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSYPOSR);
> +			at91_adc_readl(st, AT91_ADC_TSPRESSR);
> +		}
> +	}
>
>  	return IRQ_HANDLED;
>  }
> @@ -130,6 +271,16 @@ static int at91_adc_channel_init(struct iio_dev *idev)
>  	struct at91_adc_state *st = iio_priv(idev);
>  	struct iio_chan_spec *chan_array, *timestamp;
>  	int bit, idx = 0;
> +	unsigned long rsvd_mask = 0;
> +
> +	/* If touchscreen is enable, then reserve the adc channels */
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_4WIRE;
> +	else if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_5WIRE)
> +		rsvd_mask = CHAN_MASK_TOUCHSCREEN_5WIRE;
> +
> +	/* set up the channel mask to reserve touchscreen channels */
> +	st->channels_mask &= ~rsvd_mask;
>
>  	idev->num_channels = bitmap_weight(&st->channels_mask,
>  					   st->num_channels) + 1;
> @@ -561,6 +712,57 @@ static int at91_adc_probe_dt(struct at91_adc_state *st,
>  		i++;
>  	}
>
> +	/* Check if touchscreen is enabled in DT. */
> +	ret = of_property_read_u32(node, "atmel,adc-touchscreen-wires", &prop);
> +	if (ret)
> +		dev_info(&idev->dev, "Touchscreen not enabled.\n");
> +	else if (prop == 4)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE;
> +	else if (prop == 5)
> +		st->touchscreen_type = ATMEL_ADC_TOUCHSCREEN_5WIRE;
> +	else
> +		dev_warn(&idev->dev, "Unsupported number of touchscreen wires (%d)\n",
> +				prop);
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_NONE)
> +		return 0;
> +
> +	/* Touch screen is enabled, so check touch screen dt parameters */
> +	if (of_property_read_u32(node, "atmel,adc-ts-filter-average", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_filter_average = prop;
> +	if (st->ts_filter_average > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-filtering-average property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
> +	prop = 0;
> +	of_property_read_u32(node, "atmel,adc-ts-pendet-debounce", &prop);
> +	st->ts_pen_detect_debounce = prop;
> +
> +	/* default sample period is 2ms. The real touch sample period should be
> +	 * this period * TSFREQ.
> +	 */
> +	prop = 2000;
> +	of_property_read_u32(node, "atmel,adc-ts-sample-period-time", &prop);
> +	st->ts_sample_period_time = prop;
> +
> +	if (of_property_read_u32(node, "atmel,adc-ts-pendet-sensitivity", &prop)) {
> +		dev_err(&idev->dev, "Missing atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +	st->ts_pen_detect_sensitivity = prop;
> +	if (st->ts_pen_detect_sensitivity > 3) {
> +		dev_err(&idev->dev, "Invalid atmel,adc-ts-pendet-sensitivity property in the DT.\n");
> +		ret = -EINVAL;
> +		goto error_ret;
> +	}
> +
>  	return 0;
>
>  error_ret:
> @@ -592,6 +794,114 @@ static const struct iio_info at91_adc_info = {
>  	.read_raw = &at91_adc_read_raw,
>  };
>
> +/* Touchscreen related functions */
> +static int atmel_ts_open(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IER, AT91_ADC_IER_PEN);
> +	return 0;
> +}
> +
> +static void atmel_ts_close(struct input_dev *dev)
> +{
> +	struct at91_adc_state *st = input_get_drvdata(dev);
> +
> +	at91_adc_writel(st, AT91_ADC_IDR, AT91_ADC_IER_PEN);
> +}
> +
> +static int at91_ts_hw_init(struct at91_adc_state *st, u32 adc_clk_khz)
> +{
> +	u32 reg = 0, pendbc;
> +	int i = 0;
> +
> +	if (st->touchscreen_type == ATMEL_ADC_TOUCHSCREEN_4WIRE)
> +		reg = AT91_ADC_TSMR_TSMODE_4WIRE_PRESS;
> +	else
> +		reg = AT91_ADC_TSMR_TSMODE_5WIRE;
> +
> +	/* a Pen Detect Debounce Time is necessary for the ADC Touch to avoid
> +	 * pen detect noise.
> +	 * The formula is : Pen Detect Debounce Time = (2 ^ pendbc) / ADCClock
> +	 */
> +	pendbc = round_up(st->ts_pen_detect_debounce * adc_clk_khz / 1000, 1);
> +
> +	while (pendbc >> ++i)
> +		;	/* Empty! Find the shift offset */
> +	if (abs(pendbc - (1 << i)) < abs(pendbc - (1 << (i - 1))))
> +		pendbc = i;
> +	else
> +		pendbc = i - 1;
> +
> +	if (st->caps.has_tsmr) {
> +		reg |= AT91_ADC_TSMR_TSAV_(st->ts_filter_average)
> +				& AT91_ADC_TSMR_TSAV;
> +		reg |= AT91_ADC_TSMR_PENDBC_(pendbc) & AT91_ADC_TSMR_PENDBC;
> +		reg |= AT91_ADC_TSMR_NOTSDMA;
> +		reg |= AT91_ADC_TSMR_PENDET_ENA;
> +		reg |= 0x03 << 8;	/* TSFREQ, need bigger than TSAV */
> +
> +		at91_adc_writel(st, AT91_ADC_TSMR, reg);
> +	} else {
> +		/* TODO: for 9g45 which has no TSMR */
> +	}
> +
> +	/* Change adc internal resistor value for better pen detection,
> +	 * default value is 100 kOhm.
> +	 * 0 = 200 kOhm, 1 = 150 kOhm, 2 = 100 kOhm, 3 = 50 kOhm
> +	 * option only available on ES2 and higher
> +	 */
> +	at91_adc_writel(st, AT91_ADC_ACR, st->ts_pen_detect_sensitivity
> +			& AT91_ADC_ACR_PENDETSENS);
> +
> +	/* Sample Peroid Time = (TRGPER + 1) / ADCClock */
> +	st->ts_sample_period_val = round_up((st->ts_sample_period_time *
> +			adc_clk_khz / 1000) - 1, 1);
> +
> +	return 0;
> +}
> +
> +static int at91_ts_register(struct at91_adc_state *st)
> +{
> +	struct input_dev *input;
> +	struct iio_dev *idev = iio_priv_to_dev(st);
> +	int ret;
> +
> +	input = input_allocate_device();
> +	if (!input) {
> +		dev_err(&idev->dev, "Failed to allocate TS device!\n");
> +		return -ENOMEM;
> +	}
> +
> +	input->name = DRIVER_NAME;
> +	input->id.bustype = BUS_HOST;
> +	input->dev.parent = idev->dev.parent;
> +	input->open = atmel_ts_open;
> +	input->close = atmel_ts_close;
> +
> +	__set_bit(EV_ABS, input->evbit);
> +	__set_bit(EV_KEY, input->evbit);
> +	__set_bit(BTN_TOUCH, input->keybit);
> +	input_set_abs_params(input, ABS_X, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_Y, 0, (1 << MAX_POS_BITS) - 1, 0, 0);
> +	input_set_abs_params(input, ABS_PRESSURE, 0, 0xffffff, 0, 0);
> +
> +	st->ts_input = input;
> +	input_set_drvdata(input, st);
> +
> +	ret = input_register_device(input);
> +	if (ret)
> +		input_free_device(st->ts_input);
> +
> +	return ret;
> +}
> +
> +static void at91_ts_unregister(struct at91_adc_state *st)
> +{
> +	input_unregister_device(st->ts_input);
> +	input_free_device(st->ts_input);
> +}
> +
>  /*
>   * Since atmel adc support different ip for touchscreen mode. Through the
>   * IP check, we will know the touchscreen capbilities.
> @@ -610,6 +920,7 @@ static void atmel_adc_get_cap(struct at91_adc_state *st)
>  	/* keep only major version number */
>  	switch (version & 0xf00) {
>  	case 0x500:	/* SAMA5D3 */
> +		st->caps.has_12bits_xy = 1;
>  	case 0x400:	/* AT91SAM9X5/9N12 */
>  		st->caps.has_tsmr = 1;
>  		st->caps.mr_startup_mask = AT91_ADC_STARTUP;
> @@ -683,7 +994,7 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	at91_adc_writel(st, AT91_ADC_CR, AT91_ADC_SWRST);
>  	at91_adc_writel(st, AT91_ADC_IDR, 0xFFFFFFFF);
>  	ret = request_irq(st->irq,
> -			  at91_adc_eoc_trigger,
> +			  at91_adc_interrupt,
>  			  0,
>  			  pdev->dev.driver->name,
>  			  idev);
> @@ -731,6 +1042,10 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	adc_clk = st->adc_clk_rate ?
>  		st->adc_clk_rate : clk_get_rate(st->adc_clk);
>  	adc_clk_khz = adc_clk / 1000;
> +
> +	dev_dbg(&pdev->dev, "Master clock is set as: %d Hz, adc_clk should set as: %d Hz\n",
> +		mstrclk, adc_clk);
> +
>  	prsc = (mstrclk / (2 * adc_clk)) - 1;
>
>  	if (!st->startup_time) {
> @@ -799,30 +1114,52 @@ static int at91_adc_probe(struct platform_device *pdev)
>  	init_waitqueue_head(&st->wq_data_avail);
>  	mutex_init(&st->lock);
>
> -	ret = at91_adc_buffer_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> -		goto error_disable_adc_clk;
> -	}
> +	/*
> +	 * Since touch screen will set trigger register as period trigger. So
> +	 * when touch screen is enabled, then we have to disable hardware
> +	 * trigger for classic adc.
> +	 */
> +	if (!st->touchscreen_type) {
> +		ret = at91_adc_buffer_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't initialize the buffer.\n");
> +			goto error_disable_adc_clk;
> +		}
>
> -	ret = at91_adc_trigger_init(idev);
> -	if (ret < 0) {
> -		dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> -		goto error_unregister_buffer;
> +		ret = at91_adc_trigger_init(idev);
> +		if (ret < 0) {
> +			dev_err(&pdev->dev, "Couldn't setup the triggers.\n");
> +			at91_adc_buffer_remove(idev);
> +			goto error_disable_adc_clk;
> +		}
> +	} else {
> +		if (!st->caps.has_tsmr) {
> +			dev_err(&pdev->dev, "We don't support non-TSMR adc\n");
> +			goto error_disable_adc_clk;
> +		}
> +
> +		ret = at91_ts_register(st);
> +		if (ret)
> +			goto error_disable_adc_clk;
> +
> +		at91_ts_hw_init(st, adc_clk_khz);
>  	}
>
>  	ret = iio_device_register(idev);
>  	if (ret < 0) {
>  		dev_err(&pdev->dev, "Couldn't register the device.\n");
> -		goto error_remove_triggers;
> +		goto error_iio_device_register;
>  	}
>
>  	return 0;
>
> -error_remove_triggers:
> -	at91_adc_trigger_remove(idev);
> -error_unregister_buffer:
> -	at91_adc_buffer_remove(idev);
> +error_iio_device_register:
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>  error_disable_adc_clk:
>  	clk_disable_unprepare(st->adc_clk);
>  error_disable_clk:
> @@ -841,8 +1178,12 @@ static int at91_adc_remove(struct platform_device *pdev)
>  	struct at91_adc_state *st = iio_priv(idev);
>
>  	iio_device_unregister(idev);
> -	at91_adc_trigger_remove(idev);
> -	at91_adc_buffer_remove(idev);
> +	if (!st->touchscreen_type) {
> +		at91_adc_trigger_remove(idev);
> +		at91_adc_buffer_remove(idev);
> +	} else {
> +		at91_ts_unregister(st);
> +	}
>  	clk_disable_unprepare(st->adc_clk);
>  	clk_disable_unprepare(st->clk);
>  	free_irq(st->irq, idev);
> @@ -861,7 +1202,7 @@ static struct platform_driver at91_adc_driver = {
>  	.probe = at91_adc_probe,
>  	.remove = at91_adc_remove,
>  	.driver = {
> -		   .name = "at91_adc",
> +		   .name = DRIVER_NAME,
>  		   .of_match_table = of_match_ptr(at91_adc_dt_ids),
>  	},
>  };
>

^ permalink raw reply

* [PATCH v3 3/3] input: mc13783: Add DT probe support
From: Alexander Shiyan @ 2013-07-20  5:41 UTC (permalink / raw)
  To: linux-input
  Cc: Grant Likely, Rob Herring, Sascha Hauer, Dmitry Torokhov,
	Alexander Shiyan
In-Reply-To: <1374298897-788-1-git-send-email-shc_work@mail.ru>

Patch adds DT support for MC13783/MC13892 PMICs.

Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
 Documentation/devicetree/bindings/mfd/mc13xxx.txt | 13 +++++
 drivers/input/misc/mc13783-pwrbutton.c            | 61 +++++++++++++++++------
 2 files changed, 60 insertions(+), 14 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/mc13xxx.txt b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
index abd9e3c..cf8b61c 100644
--- a/Documentation/devicetree/bindings/mfd/mc13xxx.txt
+++ b/Documentation/devicetree/bindings/mfd/mc13xxx.txt
@@ -10,6 +10,12 @@ Optional properties:
 - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
 
 Sub-nodes:
+- buttons : Contain power button nodes. Each button should be declared as
+  "button@<num>" and contain code in "linux,code" property.
+  Optional properties:
+    active-high : Change active button level from 0 to 1.
+    enable-reset: Performs hadware reset through PMIC.
+    debounce    : Debounce value which will be taken from PMIC datasheet.
 - regulators : Contain the regulator nodes. The regulators are bound using
   their names as listed below with their registers and bits for enabling.
 
@@ -89,6 +95,13 @@ ecspi@70010000 { /* ECSPI1 */
 		interrupt-parent = <&gpio0>;
 		interrupts = <8>;
 
+		buttons {
+			button@1 {
+				linux,code = <0x1f>;
+				debounce = <1>;
+			};
+		};
+
 		regulators {
 			sw1_reg: mc13892__sw1 {
 				regulator-min-microvolt = <600000>;
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index 2e21f19..3f9cfd1 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -24,6 +24,7 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/input.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mc13783.h>
 #include <linux/mfd/mc13892.h>
@@ -77,21 +78,28 @@ static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
 	struct mc13xxx *mc13xxx = dev_get_drvdata(pdev->dev.parent);
 	struct mc13xxx_pwrb_devtype *devtype =
 		(struct mc13xxx_pwrb_devtype *)pdev->id_entry->driver_data;
+	struct device_node *parent, *child;
 	struct mc13xxx_pwrb *priv;
 	int i, reg = 0, ret = -EINVAL;
 
-	if (!pdata) {
+	of_node_get(pdev->dev.parent->of_node);
+	parent = of_find_node_by_name(pdev->dev.parent->of_node, "buttons");
+	if (!pdata && !parent) {
 		dev_err(&pdev->dev, "Missing platform data\n");
 		return -ENODEV;
 	}
 
 	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
-	if (!priv)
-		return -ENOMEM;
+	if (!priv) {
+		ret = -ENOMEM;
+		goto out_node_put;
+	}
 
 	priv->input = devm_input_allocate_device(&pdev->dev);
-	if (!priv->input)
-		return -ENOMEM;
+	if (!priv->input) {
+		ret = -ENOMEM;
+		goto out_node_put;
+	}
 
 	priv->mc13xxx = mc13xxx;
 	priv->devtype = devtype;
@@ -99,15 +107,36 @@ static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
 
 	for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
 		u16 code, invert, reset, debounce;
-
-		if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
-			continue;
-		code = pdata->buttons[i].keycode;
-		invert = !!(pdata->buttons[i].flags &
-			    MC13XXX_BUTTON_POL_INVERT);
-		reset = !!(pdata->buttons[i].flags &
-			   MC13XXX_BUTTON_RESET_EN);
-		debounce = pdata->buttons[i].flags;
+		const __be32 *prop;
+		char childname[5];
+
+		if (parent) {
+			sprintf(childname, "button@%i", i + 1);
+			child = of_get_child_by_name(parent, childname);
+			if (!child)
+				continue;
+			prop = of_get_property(child, "linux,code", NULL);
+			if (prop)
+				code = be32_to_cpu(*prop) & 0xffff;
+			else {
+				dev_err(&pdev->dev,
+					"Button %i: Missing key code\n", i + 1);
+				continue;
+			}
+			invert = of_property_read_bool(child, "active-high");
+			reset = of_property_read_bool(child, "enable-reset");
+			prop = of_get_property(child, "debounce", NULL);
+			debounce = prop ? be32_to_cpu(*prop) : 0;
+		} else {
+			if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
+				continue;
+			code = pdata->buttons[i].keycode;
+			invert = !!(pdata->buttons[i].flags &
+				    MC13XXX_BUTTON_POL_INVERT);
+			reset = !!(pdata->buttons[i].flags &
+				   MC13XXX_BUTTON_RESET_EN);
+			debounce = pdata->buttons[i].flags;
+		}
 
 		priv->btn_code[i] = code;
 		if (code != KEY_RESERVED)
@@ -155,6 +184,10 @@ static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
 	if (ret)
 		dev_err(&pdev->dev, "Can't register input device: %i\n", ret);
 
+out_node_put:
+	if (parent)
+		of_node_put(parent);
+
 	return ret;
 }
 
-- 
1.8.1.5


^ permalink raw reply related

* [PATCH v3 2/3] input: mc13783: Add MC13892 support
From: Alexander Shiyan @ 2013-07-20  5:41 UTC (permalink / raw)
  To: linux-input
  Cc: Grant Likely, Rob Herring, Sascha Hauer, Dmitry Torokhov,
	Alexander Shiyan
In-Reply-To: <1374298897-788-1-git-send-email-shc_work@mail.ru>

This patch adds support for MC13892 PMIC in mc13783-pwrbutton driver.

Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
 drivers/input/misc/Kconfig             |  6 +++---
 drivers/input/misc/mc13783-pwrbutton.c | 10 +++++++++-
 include/linux/mfd/mc13892.h            |  4 ++++
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 0b541cd..0d83653 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -167,10 +167,10 @@ config INPUT_MAX8997_HAPTIC
 	  module will be called max8997-haptic.
 
 config INPUT_MC13783_PWRBUTTON
-	tristate "MC13783 ON buttons"
-	depends on MFD_MC13783
+	tristate "MC13783/MC13892 ON buttons"
+	depends on MFD_MC13XXX
 	help
-	  Support the ON buttons of MC13783 PMIC as an input device
+	  Support the ON buttons of MC13783/MC13892 PMIC as an input device
 	  reporting power button status.
 
 	  To compile this driver as a module, choose M here: the module
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index aaaacef..2e21f19 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -26,6 +26,7 @@
 #include <linux/input.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mc13783.h>
+#include <linux/mfd/mc13892.h>
 
 struct mc13xxx_button_def {
 	unsigned int	irq;
@@ -178,8 +179,15 @@ static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
 	.btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5) }
 };
 
+static const struct mc13xxx_pwrb_devtype mc13892_pwrb_devtype = {
+	.btn_def[0] = { MC13892_IRQ_ONOFD1, BIT(3) },
+	.btn_def[1] = { MC13892_IRQ_ONOFD2, BIT(4) },
+	.btn_def[2] = { MC13892_IRQ_ONOFD3, BIT(2) }
+};
+
 static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
 	{ "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
+	{ "mc13892-pwrbutton", (kernel_ulong_t)&mc13892_pwrb_devtype },
 	{ }
 };
 MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
@@ -194,6 +202,6 @@ static struct platform_driver mc13xxx_pwrbutton_driver = {
 };
 module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
 
-MODULE_DESCRIPTION("MC13783 Power Button");
+MODULE_DESCRIPTION("MC13XXX Power Button");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Philippe Retornaz");
diff --git a/include/linux/mfd/mc13892.h b/include/linux/mfd/mc13892.h
index a00f2be..bdc3baf 100644
--- a/include/linux/mfd/mc13892.h
+++ b/include/linux/mfd/mc13892.h
@@ -36,4 +36,8 @@
 #define MC13892_PWGT2SPI	22
 #define MC13892_VCOINCELL	23
 
+#define MC13892_IRQ_ONOFD3	26
+#define MC13892_IRQ_ONOFD1	27
+#define MC13892_IRQ_ONOFD2	28
+
 #endif
-- 
1.8.1.5


^ permalink raw reply related

* [PATCH v3 1/3] input: mc13783: Prepare driver to support MC13892 and OF
From: Alexander Shiyan @ 2013-07-20  5:41 UTC (permalink / raw)
  To: linux-input
  Cc: Grant Likely, Rob Herring, Sascha Hauer, Dmitry Torokhov,
	Alexander Shiyan

This patch is a preparation mc13xxx powerbutton driver to support
MC13892 and support the probe through the DT.

Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
 arch/arm/mach-imx/mach-mx31moboard.c   |   9 +-
 drivers/input/misc/mc13783-pwrbutton.c | 332 +++++++++++++--------------------
 include/linux/mfd/mc13xxx.h            |  28 +--
 3 files changed, 151 insertions(+), 218 deletions(-)

diff --git a/arch/arm/mach-imx/mach-mx31moboard.c b/arch/arm/mach-imx/mach-mx31moboard.c
index 6f424ec..2a8aa43 100644
--- a/arch/arm/mach-imx/mach-mx31moboard.c
+++ b/arch/arm/mach-imx/mach-mx31moboard.c
@@ -276,9 +276,12 @@ static struct mc13xxx_leds_platform_data moboard_leds = {
 };
 
 static struct mc13xxx_buttons_platform_data moboard_buttons = {
-	.b1on_flags = MC13783_BUTTON_DBNC_750MS | MC13783_BUTTON_ENABLE |
-			MC13783_BUTTON_POL_INVERT,
-	.b1on_key = KEY_POWER,
+	.buttons[0] = {
+		.keycode	= KEY_POWER,
+		.flags		= MC13XXX_BUTTON_ENABLE |
+				  MC13XXX_BUTTON_DBNC_750MS |
+				  MC13XXX_BUTTON_POL_INVERT,
+	},
 };
 
 static struct mc13xxx_codec_platform_data moboard_codec = {
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index d0277a7..aaaacef 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -24,248 +24,176 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/input.h>
-#include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/mc13783.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-struct mc13783_pwrb {
-	struct input_dev *pwr;
-	struct mc13xxx *mc13783;
-#define MC13783_PWRB_B1_POL_INVERT	(1 << 0)
-#define MC13783_PWRB_B2_POL_INVERT	(1 << 1)
-#define MC13783_PWRB_B3_POL_INVERT	(1 << 2)
-	int flags;
-	unsigned short keymap[3];
+
+struct mc13xxx_button_def {
+	unsigned int	irq;
+	unsigned int	sense_bit;
 };
 
-#define MC13783_REG_INTERRUPT_SENSE_1		5
-#define MC13783_IRQSENSE1_ONOFD1S		(1 << 3)
-#define MC13783_IRQSENSE1_ONOFD2S		(1 << 4)
-#define MC13783_IRQSENSE1_ONOFD3S		(1 << 5)
+struct mc13xxx_pwrb_devtype {
+	struct mc13xxx_button_def	btn_def[MAX13XXX_NUM_BUTTONS];
+};
 
-#define MC13783_REG_POWER_CONTROL_2		15
-#define MC13783_POWER_CONTROL_2_ON1BDBNC	4
-#define MC13783_POWER_CONTROL_2_ON2BDBNC	6
-#define MC13783_POWER_CONTROL_2_ON3BDBNC	8
-#define MC13783_POWER_CONTROL_2_ON1BRSTEN	(1 << 1)
-#define MC13783_POWER_CONTROL_2_ON2BRSTEN	(1 << 2)
-#define MC13783_POWER_CONTROL_2_ON3BRSTEN	(1 << 3)
+struct mc13xxx_pwrb {
+	struct mc13xxx_pwrb_devtype	*devtype;
+	unsigned int			enabled;
+	unsigned int			inverted;
+	u16				btn_code[MAX13XXX_NUM_BUTTONS];
+	struct input_dev		*input;
+	struct mc13xxx			*mc13xxx;
+};
 
-static irqreturn_t button_irq(int irq, void *_priv)
-{
-	struct mc13783_pwrb *priv = _priv;
-	int val;
-
-	mc13xxx_irq_ack(priv->mc13783, irq);
-	mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val);
-
-	switch (irq) {
-	case MC13783_IRQ_ONOFD1:
-		val = val & MC13783_IRQSENSE1_ONOFD1S ? 1 : 0;
-		if (priv->flags & MC13783_PWRB_B1_POL_INVERT)
-			val ^= 1;
-		input_report_key(priv->pwr, priv->keymap[0], val);
-		break;
-
-	case MC13783_IRQ_ONOFD2:
-		val = val & MC13783_IRQSENSE1_ONOFD2S ? 1 : 0;
-		if (priv->flags & MC13783_PWRB_B2_POL_INVERT)
-			val ^= 1;
-		input_report_key(priv->pwr, priv->keymap[1], val);
-		break;
-
-	case MC13783_IRQ_ONOFD3:
-		val = val & MC13783_IRQSENSE1_ONOFD3S ? 1 : 0;
-		if (priv->flags & MC13783_PWRB_B3_POL_INVERT)
-			val ^= 1;
-		input_report_key(priv->pwr, priv->keymap[2], val);
-		break;
-	}
+#define MC13XXX_REG_INTERRUPT_SENSE_1	5
+#define MC13XXX_REG_POWER_CONTROL_2	15
 
-	input_sync(priv->pwr);
+static irqreturn_t mc13xxx_pwrbutton_irq(int irq, void *data)
+{
+	struct mc13xxx_pwrb *priv = data;
+	unsigned int i, val;
+
+	mc13xxx_irq_ack(priv->mc13xxx, irq);
+	mc13xxx_reg_read(priv->mc13xxx, MC13XXX_REG_INTERRUPT_SENSE_1, &val);
+
+	for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+		if (irq == priv->devtype->btn_def[i].irq) {
+			val = !!(val & priv->devtype->btn_def[i].sense_bit);
+			if (priv->inverted & BIT(i))
+				val = !val;
+			input_report_key(priv->input, priv->btn_code[i], val);
+			input_sync(priv->input);
+			break;
+		}
 
 	return IRQ_HANDLED;
 }
 
-static int mc13783_pwrbutton_probe(struct platform_device *pdev)
+static int __init mc13xxx_pwrbutton_probe(struct platform_device *pdev)
 {
-	const struct mc13xxx_buttons_platform_data *pdata;
-	struct mc13xxx *mc13783 = dev_get_drvdata(pdev->dev.parent);
-	struct input_dev *pwr;
-	struct mc13783_pwrb *priv;
-	int err = 0;
-	int reg = 0;
-
-	pdata = dev_get_platdata(&pdev->dev);
+	struct mc13xxx_buttons_platform_data *pdata =
+		dev_get_platdata(&pdev->dev);
+	struct mc13xxx *mc13xxx = dev_get_drvdata(pdev->dev.parent);
+	struct mc13xxx_pwrb_devtype *devtype =
+		(struct mc13xxx_pwrb_devtype *)pdev->id_entry->driver_data;
+	struct mc13xxx_pwrb *priv;
+	int i, reg = 0, ret = -EINVAL;
+
 	if (!pdata) {
-		dev_err(&pdev->dev, "missing platform data\n");
+		dev_err(&pdev->dev, "Missing platform data\n");
 		return -ENODEV;
 	}
 
-	pwr = input_allocate_device();
-	if (!pwr) {
-		dev_dbg(&pdev->dev, "Can't allocate power button\n");
+	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
 		return -ENOMEM;
-	}
-
-	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
-	if (!priv) {
-		err = -ENOMEM;
-		dev_dbg(&pdev->dev, "Can't allocate power button\n");
-		goto free_input_dev;
-	}
-
-	reg |= (pdata->b1on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON1BDBNC;
-	reg |= (pdata->b2on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON2BDBNC;
-	reg |= (pdata->b3on_flags & 0x3) << MC13783_POWER_CONTROL_2_ON3BDBNC;
-
-	priv->pwr = pwr;
-	priv->mc13783 = mc13783;
 
-	mc13xxx_lock(mc13783);
-
-	if (pdata->b1on_flags & MC13783_BUTTON_ENABLE) {
-		priv->keymap[0] = pdata->b1on_key;
-		if (pdata->b1on_key != KEY_RESERVED)
-			__set_bit(pdata->b1on_key, pwr->keybit);
-
-		if (pdata->b1on_flags & MC13783_BUTTON_POL_INVERT)
-			priv->flags |= MC13783_PWRB_B1_POL_INVERT;
+	priv->input = devm_input_allocate_device(&pdev->dev);
+	if (!priv->input)
+		return -ENOMEM;
 
-		if (pdata->b1on_flags & MC13783_BUTTON_RESET_EN)
-			reg |= MC13783_POWER_CONTROL_2_ON1BRSTEN;
+	priv->mc13xxx = mc13xxx;
+	priv->devtype = devtype;
+	platform_set_drvdata(pdev, priv);
 
-		err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD1,
-					  button_irq, "b1on", priv);
-		if (err) {
-			dev_dbg(&pdev->dev, "Can't request irq\n");
-			goto free_priv;
-		}
+	for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++) {
+		u16 code, invert, reset, debounce;
+
+		if (!(pdata->buttons[i].flags & MC13XXX_BUTTON_ENABLE))
+			continue;
+		code = pdata->buttons[i].keycode;
+		invert = !!(pdata->buttons[i].flags &
+			    MC13XXX_BUTTON_POL_INVERT);
+		reset = !!(pdata->buttons[i].flags &
+			   MC13XXX_BUTTON_RESET_EN);
+		debounce = pdata->buttons[i].flags;
+
+		priv->btn_code[i] = code;
+		if (code != KEY_RESERVED)
+			__set_bit(code, priv->input->keybit);
+
+		priv->enabled |= BIT(i);
+		priv->inverted |= invert << i;
+		reg |= reset << (i + 1);
+		reg |= (debounce & 0x03) << (4 + i * 2);
 	}
 
-	if (pdata->b2on_flags & MC13783_BUTTON_ENABLE) {
-		priv->keymap[1] = pdata->b2on_key;
-		if (pdata->b2on_key != KEY_RESERVED)
-			__set_bit(pdata->b2on_key, pwr->keybit);
-
-		if (pdata->b2on_flags & MC13783_BUTTON_POL_INVERT)
-			priv->flags |= MC13783_PWRB_B2_POL_INVERT;
-
-		if (pdata->b2on_flags & MC13783_BUTTON_RESET_EN)
-			reg |= MC13783_POWER_CONTROL_2_ON2BRSTEN;
-
-		err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD2,
-					  button_irq, "b2on", priv);
-		if (err) {
-			dev_dbg(&pdev->dev, "Can't request irq\n");
-			goto free_irq_b1;
+	mc13xxx_lock(mc13xxx);
+
+	mc13xxx_reg_rmw(mc13xxx, MC13XXX_REG_POWER_CONTROL_2, 0x3fe, reg);
+
+	for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+		if (priv->enabled & BIT(i)) {
+			ret = mc13xxx_irq_request(mc13xxx,
+						  devtype->btn_def[i].irq,
+						  mc13xxx_pwrbutton_irq, NULL,
+						  priv);
+			if (ret) {
+				dev_err(&pdev->dev, "Can't request IRQ%i: %i\n",
+					devtype->btn_def[i].irq, ret);
+				priv->enabled &= ~BIT(i);
+			}
 		}
-	}
 
-	if (pdata->b3on_flags & MC13783_BUTTON_ENABLE) {
-		priv->keymap[2] = pdata->b3on_key;
-		if (pdata->b3on_key != KEY_RESERVED)
-			__set_bit(pdata->b3on_key, pwr->keybit);
+	mc13xxx_unlock(mc13xxx);
 
-		if (pdata->b3on_flags & MC13783_BUTTON_POL_INVERT)
-			priv->flags |= MC13783_PWRB_B3_POL_INVERT;
+	priv->input->name		= "mc13xxx_pwrbutton";
+	priv->input->phys		= "mc13xxx_pwrbutton/input0";
+	priv->input->id.bustype		= BUS_HOST;
+	priv->input->id.vendor		= 0x0001;
+	priv->input->id.product		= 0x0001;
+	priv->input->id.version		= 0x0100;
+	priv->input->keycode		= priv->btn_code;
+	priv->input->keycodemax		= ARRAY_SIZE(priv->btn_code);
+	priv->input->keycodesize	= sizeof(priv->btn_code[0]);
+	__set_bit(EV_KEY, priv->input->evbit);
 
-		if (pdata->b3on_flags & MC13783_BUTTON_RESET_EN)
-			reg |= MC13783_POWER_CONTROL_2_ON3BRSTEN;
-
-		err = mc13xxx_irq_request(mc13783, MC13783_IRQ_ONOFD3,
-					  button_irq, "b3on", priv);
-		if (err) {
-			dev_dbg(&pdev->dev, "Can't request irq: %d\n", err);
-			goto free_irq_b2;
-		}
-	}
+	input_set_drvdata(priv->input, priv);
 
-	mc13xxx_reg_rmw(mc13783, MC13783_REG_POWER_CONTROL_2, 0x3FE, reg);
+	ret = input_register_device(priv->input);
+	if (ret)
+		dev_err(&pdev->dev, "Can't register input device: %i\n", ret);
 
-	mc13xxx_unlock(mc13783);
-
-	pwr->name = "mc13783_pwrbutton";
-	pwr->phys = "mc13783_pwrbutton/input0";
-	pwr->dev.parent = &pdev->dev;
-
-	pwr->keycode = priv->keymap;
-	pwr->keycodemax = ARRAY_SIZE(priv->keymap);
-	pwr->keycodesize = sizeof(priv->keymap[0]);
-	__set_bit(EV_KEY, pwr->evbit);
-
-	err = input_register_device(pwr);
-	if (err) {
-		dev_dbg(&pdev->dev, "Can't register power button: %d\n", err);
-		goto free_irq;
-	}
-
-	platform_set_drvdata(pdev, priv);
-
-	return 0;
-
-free_irq:
-	mc13xxx_lock(mc13783);
-
-	if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
-		mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD3, priv);
-
-free_irq_b2:
-	if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
-		mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD2, priv);
-
-free_irq_b1:
-	if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
-		mc13xxx_irq_free(mc13783, MC13783_IRQ_ONOFD1, priv);
-
-free_priv:
-	mc13xxx_unlock(mc13783);
-	kfree(priv);
-
-free_input_dev:
-	input_free_device(pwr);
-
-	return err;
+	return ret;
 }
 
-static int mc13783_pwrbutton_remove(struct platform_device *pdev)
+static int mc13xxx_pwrbutton_remove(struct platform_device *pdev)
 {
-	struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
-	const struct mc13xxx_buttons_platform_data *pdata;
-
-	pdata = dev_get_platdata(&pdev->dev);
-
-	mc13xxx_lock(priv->mc13783);
-
-	if (pdata->b3on_flags & MC13783_BUTTON_ENABLE)
-		mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD3, priv);
-	if (pdata->b2on_flags & MC13783_BUTTON_ENABLE)
-		mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD2, priv);
-	if (pdata->b1on_flags & MC13783_BUTTON_ENABLE)
-		mc13xxx_irq_free(priv->mc13783, MC13783_IRQ_ONOFD1, priv);
+	struct mc13xxx_pwrb *priv = platform_get_drvdata(pdev);
+	int i;
 
-	mc13xxx_unlock(priv->mc13783);
-
-	input_unregister_device(priv->pwr);
-	kfree(priv);
+	mc13xxx_lock(priv->mc13xxx);
+	for (i = 0; i < MAX13XXX_NUM_BUTTONS; i++)
+		if (priv->enabled & BIT(i))
+			mc13xxx_irq_free(priv->mc13xxx,
+					 priv->devtype->btn_def[i].irq, priv);
+	mc13xxx_unlock(priv->mc13xxx);
 
 	return 0;
 }
 
-static struct platform_driver mc13783_pwrbutton_driver = {
-	.probe		= mc13783_pwrbutton_probe,
-	.remove		= mc13783_pwrbutton_remove,
-	.driver		= {
-		.name	= "mc13783-pwrbutton",
+static const struct mc13xxx_pwrb_devtype mc13783_pwrb_devtype = {
+	.btn_def[0] = { MC13783_IRQ_ONOFD1, BIT(3) },
+	.btn_def[1] = { MC13783_IRQ_ONOFD2, BIT(4) },
+	.btn_def[2] = { MC13783_IRQ_ONOFD3, BIT(5) }
+};
+
+static const struct platform_device_id mc13xxx_pwrbutton_id_table[] = {
+	{ "mc13783-pwrbutton", (kernel_ulong_t)&mc13783_pwrb_devtype },
+	{ }
+};
+MODULE_DEVICE_TABLE(platform, mc13xxx_pwrbutton_id_table);
+
+static struct platform_driver mc13xxx_pwrbutton_driver = {
+	.driver	= {
+		.name	= "mc13xxx-pwrbutton",
 		.owner	= THIS_MODULE,
 	},
+	.remove		= mc13xxx_pwrbutton_remove,
+	.id_table	= mc13xxx_pwrbutton_id_table,
 };
+module_platform_driver_probe(mc13xxx_pwrbutton_driver, mc13xxx_pwrbutton_probe);
 
-module_platform_driver(mc13783_pwrbutton_driver);
-
-MODULE_ALIAS("platform:mc13783-pwrbutton");
 MODULE_DESCRIPTION("MC13783 Power Button");
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Philippe Retornaz");
diff --git a/include/linux/mfd/mc13xxx.h b/include/linux/mfd/mc13xxx.h
index 41ed592..b895538 100644
--- a/include/linux/mfd/mc13xxx.h
+++ b/include/linux/mfd/mc13xxx.h
@@ -142,20 +142,22 @@ struct mc13xxx_leds_platform_data {
 	u32 led_control[MAX_LED_CONTROL_REGS];
 };
 
+#define MAX13XXX_NUM_BUTTONS	3
+
+struct mc13xxx_button {
+	u16		keycode;
+	unsigned int	flags;
+#define MC13XXX_BUTTON_DBNC_0MS		0
+#define MC13XXX_BUTTON_DBNC_30MS	1
+#define MC13XXX_BUTTON_DBNC_150MS	2
+#define MC13XXX_BUTTON_DBNC_750MS	3
+#define MC13XXX_BUTTON_ENABLE		(1 << 2)
+#define MC13XXX_BUTTON_POL_INVERT	(1 << 3)
+#define MC13XXX_BUTTON_RESET_EN		(1 << 4)
+};
+
 struct mc13xxx_buttons_platform_data {
-#define MC13783_BUTTON_DBNC_0MS		0
-#define MC13783_BUTTON_DBNC_30MS	1
-#define MC13783_BUTTON_DBNC_150MS	2
-#define MC13783_BUTTON_DBNC_750MS	3
-#define MC13783_BUTTON_ENABLE		(1 << 2)
-#define MC13783_BUTTON_POL_INVERT	(1 << 3)
-#define MC13783_BUTTON_RESET_EN		(1 << 4)
-	int b1on_flags;
-	unsigned short b1on_key;
-	int b2on_flags;
-	unsigned short b2on_key;
-	int b3on_flags;
-	unsigned short b3on_key;
+	struct mc13xxx_button	buttons[MAX13XXX_NUM_BUTTONS];
 };
 
 struct mc13xxx_ts_platform_data {
-- 
1.8.1.5


^ permalink raw reply related

* [PATCH] input : wacom - Integrate resolution calculation
From: Ping Cheng @ 2013-07-19 23:10 UTC (permalink / raw)
  To: linux-input; +Cc: dmitry.torokhov, Ping Cheng

Reviewed-by: Jason Gerecke <killertofu@gmail.com>
Tested-by: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Ping Cheng <pingc@wacom.com>
---
 drivers/input/tablet/wacom_sys.c | 75 ++++++++++++++++++----------------------
 drivers/input/tablet/wacom_wac.c | 19 +++-------
 2 files changed, 37 insertions(+), 57 deletions(-)

diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
index aaf23ae..0ca248a 100644
--- a/drivers/input/tablet/wacom_sys.c
+++ b/drivers/input/tablet/wacom_sys.c
@@ -221,39 +221,6 @@ static int wacom_calc_hid_res(int logical_extents, int physical_extents,
 	return logical_extents / physical_extents;
 }
 
-/*
- * The physical dimension specified by the HID descriptor is likely not in
- * the "100th of a mm" units expected by wacom_calculate_touch_res. This
- * function adjusts the value of [xy]_phy based on the unit and exponent
- * provided by the HID descriptor. If an error occurs durring conversion
- * (e.g. from the unit being left unspecified) [xy]_phy is not modified.
- */
-static void wacom_fix_phy_from_hid(struct wacom_features *features)
-{
-	int xres = wacom_calc_hid_res(features->x_max, features->x_phy,
-					features->unit, features->unitExpo);
-	int yres = wacom_calc_hid_res(features->y_max, features->y_phy,
-					features->unit, features->unitExpo);
-
-	if (xres > 0 && yres > 0) {
-		features->x_phy = (100 * features->x_max) / xres;
-		features->y_phy = (100 * features->y_max) / yres;
-	}
-}
-
-/*
- * Static values for max X/Y and resolution of Pen interface is stored in
- * features. This mean physical size of active area can be computed.
- * This is useful to do when Pen and Touch have same active area of tablet.
- * This means for Touch device, we only need to find max X/Y value and we
- * have enough information to compute resolution of touch.
- */
-static void wacom_set_phy_from_res(struct wacom_features *features)
-{
-	features->x_phy = (features->x_max * 100) / features->x_resolution;
-	features->y_phy = (features->y_max * 100) / features->y_resolution;
-}
-
 static int wacom_parse_logical_collection(unsigned char *report,
 					  struct wacom_features *features)
 {
@@ -265,8 +232,6 @@ static int wacom_parse_logical_collection(unsigned char *report,
 		features->pktlen = WACOM_PKGLEN_BBTOUCH3;
 		features->device_type = BTN_TOOL_FINGER;
 
-		wacom_set_phy_from_res(features);
-
 		features->x_max = features->y_max =
 			get_unaligned_le16(&report[10]);
 
@@ -640,9 +605,6 @@ static int wacom_retrieve_hid_descriptor(struct usb_interface *intf,
 		}
 	}
 	error = wacom_parse_hid(intf, hid_desc, features);
-	if (error)
-		goto out;
-	wacom_fix_phy_from_hid(features);
 
  out:
 	return error;
@@ -1228,7 +1190,6 @@ static void wacom_wireless_work(struct work_struct *work)
 			*((struct wacom_features *)id->driver_info);
 		wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3;
 		wacom_wac2->features.device_type = BTN_TOOL_FINGER;
-		wacom_set_phy_from_res(&wacom_wac2->features);
 		wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096;
 		error = wacom_register_input(wacom2);
 		if (error)
@@ -1251,6 +1212,29 @@ fail1:
 	return;
 }
 
+/*
+ * Not all devices report physical dimensions from HID.
+ * Compute the default from hardcoded logical dimension
+ * and resolution before driver overwrites them.
+ */
+static void wacom_set_default_phy(struct wacom_features *features)
+{
+	if (features->x_resolution) {
+		features->x_phy = (features->x_max * 100) / features->x_resolution;
+		features->y_phy = (features->y_max * 100) / features->y_resolution;
+	}
+}
+
+static void wacom_calculate_res(struct wacom_features *features)
+{
+	features->x_resolution = wacom_calc_hid_res(features->x_max,
+				 features->x_phy, features->unit,
+				 features->unitExpo);
+	features->y_resolution = wacom_calc_hid_res(features->y_max,
+				 features->y_phy, features->unit,
+				 features->unitExpo);
+}
+
 static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -1297,6 +1281,9 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 
 	endpoint = &intf->cur_altsetting->endpoint[0].desc;
 
+	/* set the default size in case we do not get them from hid */
+	wacom_set_default_phy(features);
+
 	/* Retrieve the physical and logical size for touch devices */
 	error = wacom_retrieve_hid_descriptor(intf, features);
 	if (error)
@@ -1312,8 +1299,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 			features->device_type = BTN_TOOL_FINGER;
 			features->pktlen = WACOM_PKGLEN_BBTOUCH3;
 
-			wacom_set_phy_from_res(features);
-
 			features->x_max = 4096;
 			features->y_max = 4096;
 		} else {
@@ -1323,6 +1308,13 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 
 	wacom_setup_device_quirks(features);
 
+	/* set unit to "100th of a mm" for devices not reported by HID */
+	if (!features->unit) {
+		features->unit = 0x11;
+		features->unitExpo = 16-3;
+	}
+	wacom_calculate_res(features);
+
 	strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
 
 	if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
@@ -1334,7 +1326,6 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
 				" Pen" : " Finger",
 			sizeof(wacom_wac->name));
 
-
 		other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);
 		if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
 			other_dev = dev;
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 384fbcd..7d691a5 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -1445,13 +1445,6 @@ void wacom_setup_device_quirks(struct wacom_features *features)
 	}
 }
 
-static unsigned int wacom_calculate_touch_res(unsigned int logical_max,
-					      unsigned int physical_max)
-{
-       /* Touch physical dimensions are in 100th of mm */
-       return (logical_max * 100) / physical_max;
-}
-
 static void wacom_abs_set_axis(struct input_dev *input_dev,
 			       struct wacom_wac *wacom_wac)
 {
@@ -1475,11 +1468,9 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,
 			input_set_abs_params(input_dev, ABS_Y, 0,
 				features->y_max, features->y_fuzz, 0);
 			input_abs_set_res(input_dev, ABS_X,
-				wacom_calculate_touch_res(features->x_max,
-							features->x_phy));
+				features->x_resolution);
 			input_abs_set_res(input_dev, ABS_Y,
-				wacom_calculate_touch_res(features->y_max,
-							features->y_phy));
+				features->y_resolution);
 		}
 
 		if (features->touch_max > 1) {
@@ -1488,11 +1479,9 @@ static void wacom_abs_set_axis(struct input_dev *input_dev,
 			input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
 				features->y_max, features->y_fuzz, 0);
 			input_abs_set_res(input_dev, ABS_MT_POSITION_X,
-				wacom_calculate_touch_res(features->x_max,
-							features->x_phy));
+				features->x_resolution);
 			input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
-				wacom_calculate_touch_res(features->y_max,
-							features->y_phy));
+				features->y_resolution);
 		}
 	}
 }
-- 
1.8.1.2


^ permalink raw reply related


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