* [PATCH 01/13] leds: add led-class attribute-group support
From: Johan Hovold @ 2014-06-25 17:08 UTC (permalink / raw)
To: Bryan Wu, Richard Purdie
Cc: Dmitry Torokhov, Greg Kroah-Hartman, linux-input, linux-kernel,
linux-leds, Janne Kanniainen, Jiri Kosina, Bjørn Mork,
Johan Hovold
In-Reply-To: <1403716136-32694-1-git-send-email-johan@kernel.org>
Allow led-class devices to be created with optional attribute groups.
This is needed in order to allow led drivers to create custom device
attributes in a race-free manner.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/leds/led-class.c | 5 +++--
include/linux/leds.h | 2 ++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index f37d63cf726b..aa29198fca3e 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -210,8 +210,9 @@ static const struct dev_pm_ops leds_class_dev_pm_ops = {
*/
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
- led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
- "%s", led_cdev->name);
+ led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
+ led_cdev, led_cdev->groups,
+ "%s", led_cdev->name);
if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 0287ab296689..e43686472197 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -63,6 +63,8 @@ struct led_classdev {
unsigned long *delay_off);
struct device *dev;
+ const struct attribute_group **groups;
+
struct list_head node; /* LED Device list */
const char *default_trigger; /* Trigger to use */
--
1.8.5.5
^ permalink raw reply related
* [PATCH 00/13] leds: fix attribute-creation races
From: Johan Hovold @ 2014-06-25 17:08 UTC (permalink / raw)
To: Bryan Wu, Richard Purdie
Cc: Dmitry Torokhov, Greg Kroah-Hartman, linux-input, linux-kernel,
linux-leds, Janne Kanniainen, Jiri Kosina, Bjørn Mork,
Johan Hovold
LED-class device attributes should be created using the attribute groups
of struct device, rather than be added manually after the device has
been registered in order to avoid racing with userspace.
The first patch adds an attribute groups field to struct led_classdev,
which is used during registration to add device attributes in a
race-free manner.
The remaining patches convert the current racy LED-device attribute
creations to use the new facility. Hopefully my grep-patterns have
caught most instances. Note that this also tends to simplify probe error
paths.
The lp55xx-common failed to remove the attribute group it is currently
creating, something which is fixed separately.
Note that this series include one driver from drivers/input/keyboard.
The individual led-driver patches have been compile tested only.
Johan
Johan Hovold (13):
leds: add led-class attribute-group support
leds: lm3550: fix attribute-creation race
leds: lm3533: fix attribute-creation race
leds: lm355x: fix attribute-creation race
leds: lm3642: fix attribute-creation race
leds: max8997: fix attribute-creation race
leds: netxbig: fix attribute-creation race
leds: ns2: fix attribute-creation race
leds: ss4200: fix attribute-creation race
leds: wm831x-status: fix attribute-creation race
input: lm8323: fix attribute-creation race
leds: lp55xx-common: fix sysfs entry leak
leds: lp55xx-common: fix attribute-creation race
drivers/input/keyboard/lm8323.c | 22 +++++++++-------------
drivers/leds/led-class.c | 5 +++--
drivers/leds/leds-lm3530.c | 20 +++++++-------------
drivers/leds/leds-lm3533.c | 20 ++++++++------------
drivers/leds/leds-lm355x.c | 21 +++++++++------------
drivers/leds/leds-lm3642.c | 30 ++++++++++++++----------------
drivers/leds/leds-lp55xx-common.c | 20 +++-----------------
drivers/leds/leds-max8997.c | 16 +++++++---------
drivers/leds/leds-netxbig.c | 26 ++++++++++++--------------
drivers/leds/leds-ns2.c | 16 +++++++---------
drivers/leds/leds-ss4200.c | 14 +++++++++-----
drivers/leds/leds-wm831x-status.c | 23 +++++++++--------------
include/linux/leds.h | 2 ++
13 files changed, 99 insertions(+), 136 deletions(-)
--
1.8.5.5
^ permalink raw reply
* [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver
From: Janne Kanniainen @ 2014-06-25 15:59 UTC (permalink / raw)
To: johan
Cc: greg, bjorn, jkosina, cooloney, linux-kernel, linux-leds,
linux-usb, linux-input, Janne Kanniainen
In-Reply-To: <20140625115541.GA1409@localhost>
Use attribute-groups to fix race condition.
Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com>
---
.../ABI/testing/sysfs-class-hid-driver-gt683r | 6 +++--
drivers/hid/hid-gt683r.c | 31 +++++++++++++---------
2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
index 317e9d5..c97970a 100644
--- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
+++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
@@ -1,9 +1,11 @@
-What: /sys/class/hidraw/<hidraw>/device/leds_mode
+What: /sys/class/leds/<led>/msi_mode
Date: Jun 2014
KernelVersion: 3.17
Contact: Janne Kanniainen <janne.kanniainen@gmail.com>
Description:
- Set the mode of LEDs
+ Set the mode of LEDs. You should notice that changing the mode
+ of one LED will update the mode of its two sibling devices as
+ well
0 - normal
1 - audio
diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c
index 073bd80..aba6636 100644
--- a/drivers/hid/hid-gt683r.c
+++ b/drivers/hid/hid-gt683r.c
@@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev,
}
}
-static ssize_t leds_mode_show(struct device *dev,
+static ssize_t msi_mode_show(struct device *led_dev,
struct device_attribute *attr,
char *buf)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = container_of(led_dev->parent,
+ struct hid_device, dev);
struct gt683r_led *led = hid_get_drvdata(hdev);
if (led->mode == GT683R_LED_NORMAL)
@@ -102,15 +103,15 @@ static ssize_t leds_mode_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode);
}
-static ssize_t leds_mode_store(struct device *dev,
+static ssize_t msi_mode_store(struct device *led_dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = container_of(led_dev->parent,
+ struct hid_device, dev);
struct gt683r_led *led = hid_get_drvdata(hdev);
-
if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2)
return -EINVAL;
@@ -212,7 +213,14 @@ fail:
mutex_unlock(&led->lock);
}
-static DEVICE_ATTR_RW(leds_mode);
+static DEVICE_ATTR_RW(msi_mode);
+
+static struct attribute *gt683r_led_attrs[] = {
+ &dev_attr_msi_mode.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(gt683r_led);
static int gt683r_led_probe(struct hid_device *hdev,
const struct hid_device_id *id)
@@ -261,6 +269,8 @@ static int gt683r_led_probe(struct hid_device *hdev,
led->led_devs[i].name = name;
led->led_devs[i].max_brightness = 1;
led->led_devs[i].brightness_set = gt683r_brightness_set;
+ led->led_devs[i].groups = gt683r_led_groups;
+
ret = led_classdev_register(&hdev->dev, &led->led_devs[i]);
if (ret) {
hid_err(hdev, "could not register led device\n");
@@ -268,17 +278,12 @@ static int gt683r_led_probe(struct hid_device *hdev,
}
}
- ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode);
- if (ret) {
- hid_err(hdev, "could not make mode attribute file\n");
- goto fail;
- }
-
return 0;
fail:
for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&led->led_devs[i]);
+
hid_hw_stop(hdev);
return ret;
}
@@ -288,9 +293,9 @@ static void gt683r_led_remove(struct hid_device *hdev)
int i;
struct gt683r_led *led = hid_get_drvdata(hdev);
- device_remove_file(&hdev->dev, &dev_attr_leds_mode);
for (i = 0; i < GT683R_LED_COUNT; i++)
led_classdev_unregister(&led->led_devs[i]);
+
flush_work(&led->work);
hid_hw_stop(hdev);
}
--
1.9.2
^ permalink raw reply related
* Re: [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver
From: Johan Hovold @ 2014-06-25 11:55 UTC (permalink / raw)
To: Greg KH
Cc: Janne Kanniainen, johan, bjorn, jkosina, cooloney, linux-kernel,
linux-leds, linux-usb, linux-input
In-Reply-To: <20140624195651.GA13694@kroah.com>
On Tue, Jun 24, 2014 at 03:56:51PM -0400, Greg KH wrote:
> On Tue, Jun 24, 2014 at 10:38:38PM +0300, Janne Kanniainen wrote:
> > static int gt683r_led_probe(struct hid_device *hdev,
> > const struct hid_device_id *id)
> > @@ -261,6 +272,7 @@ static int gt683r_led_probe(struct hid_device *hdev,
> > led->led_devs[i].name = name;
> > led->led_devs[i].max_brightness = 1;
> > led->led_devs[i].brightness_set = gt683r_brightness_set;
> > +
> > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]);
> > if (ret) {
> > hid_err(hdev, "could not register led device\n");
> > @@ -268,17 +280,29 @@ static int gt683r_led_probe(struct hid_device *hdev,
> > }
> > }
> >
> > - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode);
> > - if (ret) {
> > - hid_err(hdev, "could not make mode attribute file\n");
> > - goto fail;
> > + for (i = 0; i < GT683R_LED_COUNT; i++) {
> > + led->dev_attr_group[i] = >683r_group;
> > +
> > + ret = sysfs_create_group(&led->led_devs[i].dev->kobj,
> > + led->dev_attr_group[i]);
>
> why not use sysfs_create_groups()?
>
> And why are you doing it this way, the led device should have the
> attribute group and it should be created automatically by the driver
> core, no driver should need to create it like you are doing so here.
Turns out it was easier said than done when I asked Janne to move the
attribute. And all led drivers with custom attributes currently suffer
from this race.
Janne, you'll need to apply patch below and then set the groups field of
the led_devs before registering them. You can use the ATTRIBUTE_GROUPS
macro in the following way:
static struct attribute *gt683r_led_attrs[] = {
&dev_attr_msi_mode.attr,
NULL,
};
ATTRIBUTE_GROUPS(gt683r_led);
and then set .groups to gt683r_led_groups.
I have started fixing some of the other led drivers and I'll try to
submit a series (including the below patch) later today.
Thanks,
Johan
>From 226f1de5e094f2ec99f45d486652505ef915af73 Mon Sep 17 00:00:00 2001
From: Johan Hovold <johan@kernel.org>
Date: Wed, 25 Jun 2014 12:33:18 +0200
Subject: [PATCH] leds: add led-class attribute-group support
Allow led-class devices to be created with optional attribute groups.
This is needed in order to allow led drivers to create custom device
attributes in a race-free manner.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/leds/led-class.c | 5 +++--
include/linux/leds.h | 2 ++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index f37d63cf726b..aa29198fca3e 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -210,8 +210,9 @@ static const struct dev_pm_ops leds_class_dev_pm_ops = {
*/
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
- led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,
- "%s", led_cdev->name);
+ led_cdev->dev = device_create_with_groups(leds_class, parent, 0,
+ led_cdev, led_cdev->groups,
+ "%s", led_cdev->name);
if (IS_ERR(led_cdev->dev))
return PTR_ERR(led_cdev->dev);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index 0287ab296689..e43686472197 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -63,6 +63,8 @@ struct led_classdev {
unsigned long *delay_off);
struct device *dev;
+ const struct attribute_group **groups;
+
struct list_head node; /* LED Device list */
const char *default_trigger; /* Trigger to use */
--
1.8.5.5
^ permalink raw reply related
* [PATCH] Input: Add Acer Aspire 5710 to nomux blacklist
From: Jiri Kosina @ 2014-06-25 9:42 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input
Acer Aspire needs to be added to nomux blacklist, otherwise the touchpad
misbehaves rather randomly.
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
---
Hi Dmitry,
I've come across this a few year old patch originating from our internal
bugzilla, which was apparently been lost between the cracks somewhere.
We've been carrying it in our kernel tree for quite some time ... could
you please apply it? Thanks.
drivers/input/serio/i8042-x86ia64io.h | 7 +++++++
1 file changed, 7 insertions(+)
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -371,6 +371,13 @@ static const struct dmi_system_id __init
},
},
{
+ /* Acer Aspire 5710 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710"),
+ },
+ },
+ {
/* Gericom Bellagio */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Gericom"),
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* I want to invest.
From: Ms. Elizabeth Masula @ 2014-06-24 20:24 UTC (permalink / raw)
Please can you assist me to invest in your Country? if yes, then get back to
me, so I can give you details and areas you can participate and assist me.
Ms. Elizabeth.
^ permalink raw reply
* Re: [PATCH 1/2] lib: int_sqrt: add int64_sqrt routine
From: Andrew Morton @ 2014-06-24 20:25 UTC (permalink / raw)
To: Peter Meerwald
Cc: Yibo Cai, Barry Song, dmitry.torokhov@gmail.com, dtor@mail.ru,
linux-input@vger.kernel.org, DL-SHA-WorkGroupLinux, Barry Song
In-Reply-To: <alpine.DEB.2.01.1406240810260.31856@pmeerw.net>
On Tue, 24 Jun 2014 08:15:55 +0200 (CEST) Peter Meerwald <pmeerw@pmeerw.net> wrote:
> > > maybe the code could be #MACRO()'d to avoid duplication
> >
> > Do you mean to define int64_sqrt() directly as int_sqrt() on a 64 bit
> > platform where sizeof(long) == sizeof(long long)?
>
> something along the lines of
>
> #define INT_SQRT(name, type) \
> type name(type x) \
> type m, y = 0, b; \
> ...
>
> INT_SQRT(int_sqrt, unsigned long);
> INT_SQRT(int64_sqrt, unsigned long long);
>
> not sure if it is worth it
We have made smaller optimisations in the past ;)
But not a macro, please:
#ifdef CONFIG_64BIT
static inline unsigned long long int64_sqrt(unsigned long long x)
{
return int_sqrt(x);
}
#else
unsigned long long int64_sqrt(unsigned long long x);
#endif
^ permalink raw reply
* Re: [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver
From: Greg KH @ 2014-06-24 19:56 UTC (permalink / raw)
To: Janne Kanniainen
Cc: johan, bjorn, jkosina, cooloney, linux-kernel, linux-leds,
linux-usb, linux-input
In-Reply-To: <1403638718-11448-2-git-send-email-janne.kanniainen@gmail.com>
On Tue, Jun 24, 2014 at 10:38:38PM +0300, Janne Kanniainen wrote:
> Move led_mode attribute from HID device to led-class devices and rename it
> msi_mode.
>
> Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com>
> ---
> .../ABI/testing/sysfs-class-hid-driver-gt683r | 6 ++-
> drivers/hid/hid-gt683r.c | 50 +++++++++++++++++-----
> 2 files changed, 43 insertions(+), 13 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
> index 317e9d5..c97970a 100644
> --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
> +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
> @@ -1,9 +1,11 @@
> -What: /sys/class/hidraw/<hidraw>/device/leds_mode
> +What: /sys/class/leds/<led>/msi_mode
> Date: Jun 2014
> KernelVersion: 3.17
> Contact: Janne Kanniainen <janne.kanniainen@gmail.com>
> Description:
> - Set the mode of LEDs
> + Set the mode of LEDs. You should notice that changing the mode
> + of one LED will update the mode of its two sibling devices as
> + well
>
> 0 - normal
> 1 - audio
> diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c
> index 073bd80..1c942eb 100644
> --- a/drivers/hid/hid-gt683r.c
> +++ b/drivers/hid/hid-gt683r.c
> @@ -58,6 +58,7 @@ struct gt683r_led {
> struct work_struct work;
> enum led_brightness brightnesses[GT683R_LED_COUNT];
> enum gt683r_led_mode mode;
> + const struct attribute_group *dev_attr_group[GT683R_LED_COUNT];
> };
>
> static const struct hid_device_id gt683r_led_id[] = {
> @@ -84,12 +85,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev,
> }
> }
>
> -static ssize_t leds_mode_show(struct device *dev,
> +static ssize_t msi_mode_show(struct device *led_dev,
> struct device_attribute *attr,
> char *buf)
> {
> u8 sysfs_mode;
> - struct hid_device *hdev = container_of(dev, struct hid_device, dev);
> + struct hid_device *hdev = container_of(led_dev->parent,
> + struct hid_device, dev);
> struct gt683r_led *led = hid_get_drvdata(hdev);
>
> if (led->mode == GT683R_LED_NORMAL)
> @@ -102,15 +104,15 @@ static ssize_t leds_mode_show(struct device *dev,
> return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode);
> }
>
> -static ssize_t leds_mode_store(struct device *dev,
> +static ssize_t msi_mode_store(struct device *led_dev,
> struct device_attribute *attr,
> const char *buf, size_t count)
> {
> u8 sysfs_mode;
> - struct hid_device *hdev = container_of(dev, struct hid_device, dev);
> + struct hid_device *hdev = container_of(led_dev->parent,
> + struct hid_device, dev);
> struct gt683r_led *led = hid_get_drvdata(hdev);
>
> -
> if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2)
> return -EINVAL;
>
> @@ -212,7 +214,16 @@ fail:
> mutex_unlock(&led->lock);
> }
>
> -static DEVICE_ATTR_RW(leds_mode);
> +static DEVICE_ATTR_RW(msi_mode);
> +
> +static struct attribute *gt683r_attributes[] = {
> + &dev_attr_msi_mode.attr,
> + NULL
> +};
> +
> +static const struct attribute_group gt683r_group = {
> + .attrs = gt683r_attributes
> +};
>
> static int gt683r_led_probe(struct hid_device *hdev,
> const struct hid_device_id *id)
> @@ -261,6 +272,7 @@ static int gt683r_led_probe(struct hid_device *hdev,
> led->led_devs[i].name = name;
> led->led_devs[i].max_brightness = 1;
> led->led_devs[i].brightness_set = gt683r_brightness_set;
> +
> ret = led_classdev_register(&hdev->dev, &led->led_devs[i]);
> if (ret) {
> hid_err(hdev, "could not register led device\n");
> @@ -268,17 +280,29 @@ static int gt683r_led_probe(struct hid_device *hdev,
> }
> }
>
> - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode);
> - if (ret) {
> - hid_err(hdev, "could not make mode attribute file\n");
> - goto fail;
> + for (i = 0; i < GT683R_LED_COUNT; i++) {
> + led->dev_attr_group[i] = >683r_group;
> +
> + ret = sysfs_create_group(&led->led_devs[i].dev->kobj,
> + led->dev_attr_group[i]);
why not use sysfs_create_groups()?
And why are you doing it this way, the led device should have the
attribute group and it should be created automatically by the driver
core, no driver should need to create it like you are doing so here.
thanks,
greg k-h
^ permalink raw reply
* [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver
From: Janne Kanniainen @ 2014-06-24 19:38 UTC (permalink / raw)
To: johan
Cc: greg, bjorn, jkosina, cooloney, linux-kernel, linux-leds,
linux-usb, linux-input, Janne Kanniainen
In-Reply-To: <1403638718-11448-1-git-send-email-janne.kanniainen@gmail.com>
Move led_mode attribute from HID device to led-class devices and rename it
msi_mode.
Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com>
---
.../ABI/testing/sysfs-class-hid-driver-gt683r | 6 ++-
drivers/hid/hid-gt683r.c | 50 +++++++++++++++++-----
2 files changed, 43 insertions(+), 13 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
index 317e9d5..c97970a 100644
--- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
+++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r
@@ -1,9 +1,11 @@
-What: /sys/class/hidraw/<hidraw>/device/leds_mode
+What: /sys/class/leds/<led>/msi_mode
Date: Jun 2014
KernelVersion: 3.17
Contact: Janne Kanniainen <janne.kanniainen@gmail.com>
Description:
- Set the mode of LEDs
+ Set the mode of LEDs. You should notice that changing the mode
+ of one LED will update the mode of its two sibling devices as
+ well
0 - normal
1 - audio
diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c
index 073bd80..1c942eb 100644
--- a/drivers/hid/hid-gt683r.c
+++ b/drivers/hid/hid-gt683r.c
@@ -58,6 +58,7 @@ struct gt683r_led {
struct work_struct work;
enum led_brightness brightnesses[GT683R_LED_COUNT];
enum gt683r_led_mode mode;
+ const struct attribute_group *dev_attr_group[GT683R_LED_COUNT];
};
static const struct hid_device_id gt683r_led_id[] = {
@@ -84,12 +85,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev,
}
}
-static ssize_t leds_mode_show(struct device *dev,
+static ssize_t msi_mode_show(struct device *led_dev,
struct device_attribute *attr,
char *buf)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = container_of(led_dev->parent,
+ struct hid_device, dev);
struct gt683r_led *led = hid_get_drvdata(hdev);
if (led->mode == GT683R_LED_NORMAL)
@@ -102,15 +104,15 @@ static ssize_t leds_mode_show(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode);
}
-static ssize_t leds_mode_store(struct device *dev,
+static ssize_t msi_mode_store(struct device *led_dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
u8 sysfs_mode;
- struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct hid_device *hdev = container_of(led_dev->parent,
+ struct hid_device, dev);
struct gt683r_led *led = hid_get_drvdata(hdev);
-
if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2)
return -EINVAL;
@@ -212,7 +214,16 @@ fail:
mutex_unlock(&led->lock);
}
-static DEVICE_ATTR_RW(leds_mode);
+static DEVICE_ATTR_RW(msi_mode);
+
+static struct attribute *gt683r_attributes[] = {
+ &dev_attr_msi_mode.attr,
+ NULL
+};
+
+static const struct attribute_group gt683r_group = {
+ .attrs = gt683r_attributes
+};
static int gt683r_led_probe(struct hid_device *hdev,
const struct hid_device_id *id)
@@ -261,6 +272,7 @@ static int gt683r_led_probe(struct hid_device *hdev,
led->led_devs[i].name = name;
led->led_devs[i].max_brightness = 1;
led->led_devs[i].brightness_set = gt683r_brightness_set;
+
ret = led_classdev_register(&hdev->dev, &led->led_devs[i]);
if (ret) {
hid_err(hdev, "could not register led device\n");
@@ -268,17 +280,29 @@ static int gt683r_led_probe(struct hid_device *hdev,
}
}
- ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode);
- if (ret) {
- hid_err(hdev, "could not make mode attribute file\n");
- goto fail;
+ for (i = 0; i < GT683R_LED_COUNT; i++) {
+ led->dev_attr_group[i] = >683r_group;
+
+ ret = sysfs_create_group(&led->led_devs[i].dev->kobj,
+ led->dev_attr_group[i]);
+ if (ret) {
+ hid_err(hdev, "could not create attribute file\n");
+ goto sysfs_create_fail;
+ }
}
return 0;
+sysfs_create_fail:
+ for (i = i - 1; i >= 0; i--)
+ sysfs_remove_group(&led->led_devs[i].dev->kobj,
+ led->dev_attr_group[i]);
+
+ i = GT683R_LED_COUNT;
fail:
for (i = i - 1; i >= 0; i--)
led_classdev_unregister(&led->led_devs[i]);
+
hid_hw_stop(hdev);
return ret;
}
@@ -288,9 +312,13 @@ static void gt683r_led_remove(struct hid_device *hdev)
int i;
struct gt683r_led *led = hid_get_drvdata(hdev);
- device_remove_file(&hdev->dev, &dev_attr_leds_mode);
+ for (i = 0; i < GT683R_LED_COUNT; i++)
+ sysfs_remove_group(&led->led_devs[i].dev->kobj,
+ led->dev_attr_group[i]);
+
for (i = 0; i < GT683R_LED_COUNT; i++)
led_classdev_unregister(&led->led_devs[i]);
+
flush_work(&led->work);
hid_hw_stop(hdev);
}
--
1.9.2
^ permalink raw reply related
* [PATCH 1/2] HID: leds: fix race condition in MSI GT683R driver
From: Janne Kanniainen @ 2014-06-24 19:38 UTC (permalink / raw)
To: johan
Cc: greg, bjorn, jkosina, cooloney, linux-kernel, linux-leds,
linux-usb, linux-input, Janne Kanniainen
In-Reply-To: <20140624145003.GA6607@localhost>
This will fix race condition noticed by Oliver Neukum. Sysfs files are created
before mutex and work are initialized.
Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com>
---
drivers/hid/hid-gt683r.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c
index 077f7a1..073bd80 100644
--- a/drivers/hid/hid-gt683r.c
+++ b/drivers/hid/hid-gt683r.c
@@ -227,6 +227,9 @@ static int gt683r_led_probe(struct hid_device *hdev,
if (!led)
return -ENOMEM;
+ mutex_init(&led->lock);
+ INIT_WORK(&led->work, gt683r_led_work);
+
led->mode = GT683R_LED_NORMAL;
led->hdev = hdev;
hid_set_drvdata(hdev, led);
@@ -271,9 +274,6 @@ static int gt683r_led_probe(struct hid_device *hdev,
goto fail;
}
- mutex_init(&led->lock);
- INIT_WORK(&led->work, gt683r_led_work);
-
return 0;
fail:
--
1.9.2
^ permalink raw reply related
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels
From: Johan Hovold @ 2014-06-24 14:50 UTC (permalink / raw)
To: Bjørn Mork
Cc: Johan Hovold, Greg KH, Janne Kanniainen, jkosina, cooloney,
linux-kernel, linux-leds, linux-usb, linux-input
In-Reply-To: <871tuewizw.fsf@nemi.mork.no>
On Tue, Jun 24, 2014 at 03:10:43PM +0200, Bjørn Mork wrote:
> Johan Hovold <johan@kernel.org> writes:
>
> > This is a non-standard attribute of this particular laptop. It has three
> > individual LEDs that can be enabled separately (using standard LED class
> > attributes), but they will all three be in the same "mode" (which here
> > apparently means that they can be fully on, vary with the volume(?!), or
> > pulse synchronously when enabled).
> >
> > If we were to implement this mode attribute as a class attribute,
> > changing the mode of of one LED would also change the mode of the other
> > two devices (LEDs).
>
> Document this behaviour and it becomes a feature.
Yeah, you're right. That is probably the best way to handle this.
Janne, could you send two separate patches on top of v9 that fixes the
use-before-initialisation (reported by Oliver) and moves the led_mode
attribute from the parent HID device to the led-class devices (thereby
fixing the race reported by Greg)?
As the "led_"-prefix will then be redundant, you should probably rename
the attribute as "msi_mode" or similar (just "mode" might be too
generic).
Remember to update the ABI documentation as well, including mentioning
the fact that changing the mode of one LED will update the mode of its
two sibling devices as well (as suggested by Bjørn).
Thanks,
Johan
^ permalink raw reply
* [PATCH v4 3/6] iio: adc: fsl,imx25-gcq driver
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer, linux-arm-kernel, Lee Jones,
linux-input, linux-iio, Lars-Peter Clausen, Markus Pargmann,
devicetree, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Denis Carikli
In-Reply-To: <1403621195-9622-1-git-send-email-denis@eukrea.com>
From: Markus Pargmann <mpa@pengutronix.de>
This is a conversion queue driver for the mx25 SoC. It uses the central
ADC which is used by two seperate independent queues. This driver
prepares different conversion configurations for each possible input.
For a conversion it creates a conversionqueue of one item with the
correct configuration for the chosen channel. It then executes the queue
once and disables the conversion queue afterwards.
The reference voltages are configurable through devicetree subnodes,
depending on the connections of the ADC inputs.
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
Changelog v3->v4:
- Reworked the ADC reference voltage bindings.
- IIO_CHAN_INFO_SCALE is now handled.
- Lot of code and style cleanups.
- Tested by watching WIPER become 0 when the touchscreen is touched.
Changelog v2->v3:
- Fixed compilation: I forgott to tell that this IIO patch was untested
in the previous cover letter. Now it is tested at runtime:
I left the touchscreen connected but I configured the TSC as an ADC
instead, set the refp to internal reference, and the refn to ngnd_adc(3)
for the first 4 channels(xp,yp,xn,yn) and observed the values changing
while touching the resistive 4-wire touchscreen.
- MX25_IIO_CHAN now became MX25_GCQ_CHAN and its .address is now gone
and the code using it adapted.
- The instances of struct iio_dev were renamed from idev to indio_dev.
- regmap_read return value is now checked in mx25_gcq_read_raw.
- Comparisons with MX25_NUM_CFGS are now fixed
- Cosmetics fix in a multiline comment.
---
.../devicetree/bindings/iio/adc/fsl,imx25-gcq.txt | 51 +++
drivers/iio/adc/Kconfig | 7 +
drivers/iio/adc/Makefile | 1 +
drivers/iio/adc/fsl-imx25-gcq.c | 371 ++++++++++++++++++++
include/dt-bindings/iio/adc/fsl-imx25-gcq.h | 11 +
5 files changed, 441 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/adc/fsl,imx25-gcq.txt
create mode 100644 drivers/iio/adc/fsl-imx25-gcq.c
create mode 100644 include/dt-bindings/iio/adc/fsl-imx25-gcq.h
diff --git a/Documentation/devicetree/bindings/iio/adc/fsl,imx25-gcq.txt b/Documentation/devicetree/bindings/iio/adc/fsl,imx25-gcq.txt
new file mode 100644
index 0000000..e4a7170
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/fsl,imx25-gcq.txt
@@ -0,0 +1,51 @@
+Freescale i.MX25 ADC GCQ device
+
+This is a generic conversion queue device that can convert any of the
+analog inputs using the ADC unit of the i.MX25.
+
+Required properties:
+ - compatible: Should be "fsl,imx25-gcq".
+ - reg: Should be the register range of the module.
+ - interrupts: Should be the interrupt number of the module.
+ Typically this is <1>.
+ - interrupt-parent: phandle to the tsadc module of the i.MX25.
+ - #address-cells: Should be <1> (setting for the subnodes)
+ - #size-cells: Should be <0> (setting for the subnodes)
+
+Optional properties:
+ - vref-supply: The regulator supplying the ADC refrence voltage.
+ Required when at least one subnode uses the external reference.
+
+Sub-nodes:
+Optionally you can define subnodes which define the reference voltage
+for the analog inputs.
+
+Required properties for subnodes:
+ - reg: Should be the number of the analog input.
+ 0: xp
+ 1: yp
+ 2: xn
+ 3: yn
+ 4: wiper
+ 5: inaux0
+ 6: inaux1
+ 7: inaux2
+ - fsl,adc-ref: specifies the reference input as defined in
+ <dt-bindings/iio/adc/fsl-imx25-gcq.h>
+ MX25_ADC_REF_INT and MX25_ADC_REF_EXT flags are supported.
+
+Example:
+
+ adc: adc@50030800 {
+ compatible = "fsl,imx25-gcq";
+ reg = <0x50030800 0x60>;
+ interrupt-parent = <&tscadc>;
+ interrupts = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ inaux@5 {
+ reg = <5>;
+ fsl,adc-ref = <MX25_ADC_REF_INT>;
+ };
+ };
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index a80d236..58efb8d 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -125,6 +125,13 @@ config EXYNOS_ADC
of SoCs for drivers such as the touchscreen and hwmon to use to share
this resource.
+config FSL_MX25_ADC
+ tristate "Freescale MX25 ADC driver"
+ depends on MFD_MX25_TSADC
+ help
+ Generic Conversion Queue driver used for general purpose ADC in the
+ MX25. This driver supports single measurements using the MX25 ADC.
+
config LP8788_ADC
tristate "LP8788 ADC driver"
depends on MFD_LP8788
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 9d60f2d..2767fd6 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
+obj-$(CONFIG_FSL_MX25_ADC) += fsl-imx25-gcq.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1363) += max1363.o
obj-$(CONFIG_MCP320X) += mcp320x.o
diff --git a/drivers/iio/adc/fsl-imx25-gcq.c b/drivers/iio/adc/fsl-imx25-gcq.c
new file mode 100644
index 0000000..1e95553
--- /dev/null
+++ b/drivers/iio/adc/fsl-imx25-gcq.c
@@ -0,0 +1,371 @@
+/*
+ * Copyright 2014 Markus Pargmann, Pengutronix <mpa@pengutronix.de>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * This is the driver for the imx25 GCQ (Generic Conversion Queue)
+ * connected to the imx25 ADC.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/iio/iio.h>
+#include <linux/mfd/imx25-tsadc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <dt-bindings/iio/adc/fsl-imx25-gcq.h>
+
+#define MX25_GCQ_TIMEOUT (msecs_to_jiffies(2000))
+
+enum mx25_gcq_cfgs {
+ MX25_CFG_XP = 0,
+ MX25_CFG_YP,
+ MX25_CFG_XN,
+ MX25_CFG_YN,
+ MX25_CFG_WIPER,
+ MX25_CFG_INAUX0,
+ MX25_CFG_INAUX1,
+ MX25_CFG_INAUX2,
+ MX25_NUM_CFGS,
+};
+
+struct mx25_gcq_priv {
+ struct regmap *regs;
+ struct completion completed;
+ unsigned int settling_time;
+ struct clk *clk;
+ int irq;
+ struct regulator *ext_vref;
+ u32 channel_vref_mv[MX25_NUM_CFGS];
+};
+
+#define MX25_CQG_CHAN(chan, id) {\
+ .type = IIO_VOLTAGE,\
+ .indexed = 1,\
+ .channel = chan,\
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),\
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),\
+ .datasheet_name = id,\
+}
+
+static const struct iio_chan_spec mx25_gcq_channels[MX25_NUM_CFGS] = {
+ MX25_CQG_CHAN(0, "xp"),
+ MX25_CQG_CHAN(1, "yp"),
+ MX25_CQG_CHAN(2, "xn"),
+ MX25_CQG_CHAN(3, "yn"),
+ MX25_CQG_CHAN(4, "wiper"),
+ MX25_CQG_CHAN(5, "inaux0"),
+ MX25_CQG_CHAN(6, "inaux1"),
+ MX25_CQG_CHAN(7, "inaux2"),
+};
+
+static void mx25_gcq_disable_eoq(struct mx25_gcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_EOQ_IRQ,
+ MX25_ADCQ_MR_EOQ_IRQ);
+}
+
+static void mx25_gcq_enable_eoq(struct mx25_gcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_MR,
+ MX25_ADCQ_MR_EOQ_IRQ, 0);
+}
+
+static irqreturn_t mx25_gcq_irq(int irq, void *data)
+{
+ struct mx25_gcq_priv *priv = data;
+ u32 stats;
+
+ regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
+
+ if (stats & MX25_ADCQ_SR_EOQ) {
+ mx25_gcq_disable_eoq(priv);
+ complete(&priv->completed);
+ }
+
+ /* Disable conversion queue run */
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
+
+ /* Acknowledge all possible irqs */
+ regmap_write(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
+ MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR |
+ MX25_ADCQ_SR_EOQ | MX25_ADCQ_SR_PD);
+
+ return IRQ_HANDLED;
+}
+
+static int mx25_gcq_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ struct mx25_gcq_priv *priv = iio_priv(indio_dev);
+ long timeout;
+ u32 data;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&indio_dev->mlock);
+
+ /* Setup the configuration we want to use */
+ regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
+ MX25_ADCQ_ITEM(0, chan->channel));
+
+ mx25_gcq_enable_eoq(priv);
+
+ /* Trigger queue for one run */
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
+ MX25_ADCQ_CR_FQS);
+
+ timeout = wait_for_completion_interruptible_timeout(
+ &priv->completed, MX25_GCQ_TIMEOUT);
+ if (timeout < 0) {
+ dev_err(&indio_dev->dev,
+ "ADC wait for measurement failed\n");
+ ret = timeout;
+ goto out;
+ } else if (timeout == 0) {
+ dev_err(&indio_dev->dev, "ADC timed out\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ ret = regmap_read(priv->regs, MX25_ADCQ_FIFO, &data);
+ if (ret)
+ return ret;
+
+ *val = MX25_ADCQ_FIFO_DATA(data);
+ ret = IIO_VAL_INT;
+ goto out;
+
+ case IIO_CHAN_INFO_SCALE:
+ *val = priv->channel_vref_mv[chan->channel];
+ *val2 = 12;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+out:
+ mutex_unlock(&indio_dev->mlock);
+ return ret;
+}
+
+static const struct iio_info mx25_gcq_iio_info = {
+ .read_raw = mx25_gcq_read_raw,
+};
+
+static const struct regmap_config mx25_gcq_regconfig = {
+ .max_register = 0x5c,
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int mx25_gcq_setup_cfgs(struct platform_device *pdev,
+ struct mx25_gcq_priv *priv)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct device_node *child;
+ struct device *dev = &pdev->dev;
+ int ret, i;
+
+ /* Setup all configurations registers with a default conversion
+ * configuration for each input
+ */
+ for (i = 0; i < MX25_NUM_CFGS; ++i)
+ regmap_write(priv->regs, MX25_ADCQ_CFG(i),
+ MX25_ADCQ_CFG_YPLL_OFF |
+ MX25_ADCQ_CFG_XNUR_OFF |
+ MX25_ADCQ_CFG_XPUL_OFF |
+ MX25_ADCQ_CFG_REFP_INT |
+ (i << 4) |
+ MX25_ADCQ_CFG_REFN_NGND2);
+
+ for_each_child_of_node(np, child) {
+ u32 reg;
+ u32 refp;
+ u32 adc_ref;
+
+ ret = of_property_read_u32(child, "reg", ®);
+ if (ret) {
+ dev_err(dev, "Failed to get reg property\n");
+ return ret;
+ }
+
+ if (reg >= MX25_NUM_CFGS) {
+ dev_err(dev,
+ "reg value is greater than the number of available configuration registers\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32(child, "fsl,adc-ref", &adc_ref);
+ if (ret) {
+ dev_err(dev, "Failed to get fsl,adc-ref property\n");
+ return ret;
+ }
+
+ if (adc_ref != MX25_ADC_REF_INT &&
+ adc_ref != MX25_ADC_REF_EXT) {
+ dev_err(dev, "Invalid fsl,adc-refp property value %d\n",
+ adc_ref);
+ return -EINVAL;
+ }
+
+ switch (adc_ref) {
+ case MX25_ADC_REF_EXT:
+ if (IS_ERR_OR_NULL(priv->ext_vref)) {
+ dev_err(dev,
+ "No regulator found for the external vref\n");
+ return -EINVAL;
+ }
+ priv->channel_vref_mv[reg] =
+ regulator_get_voltage(priv->ext_vref);
+ refp = MX25_ADCQ_CFG_REFP_EXT;
+ break;
+ case MX25_ADC_REF_INT:
+ priv->channel_vref_mv[reg] = 2500;
+ refp = MX25_ADCQ_CFG_REFP_INT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_update_bits(priv->regs, MX25_ADCQ_CFG(reg),
+ MX25_ADCQ_CFG_REFP_MASK |
+ MX25_ADCQ_CFG_REFN_MASK, (refp << 7) |
+ (MX25_ADCQ_CFG_REFN_NGND << 2));
+ }
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR,
+ MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST,
+ MX25_ADCQ_CR_FRST | MX25_ADCQ_CR_QRST);
+
+ regmap_write(priv->regs, MX25_ADCQ_CR,
+ MX25_ADCQ_CR_PDMSK |
+ MX25_ADCQ_CR_QSM_FQS);
+
+ return 0;
+}
+
+static int mx25_gcq_probe(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev;
+ struct mx25_gcq_priv *priv;
+ struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ void __iomem *mem;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ priv = iio_priv(indio_dev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mem = devm_ioremap_resource(dev, res);
+ if (!mem)
+ return -ENOMEM;
+
+ priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_gcq_regconfig);
+ if (IS_ERR(priv->regs)) {
+ dev_err(dev, "Failed to initialize regmap\n");
+ return PTR_ERR(priv->regs);
+ }
+
+ init_completion(&priv->completed);
+
+ /* Optional external regulator */
+ priv->ext_vref = devm_regulator_get(&pdev->dev, "vref");
+ if (!IS_ERR_OR_NULL(priv->ext_vref)) {
+ ret = regulator_enable(priv->ext_vref);
+ if (ret)
+ return ret;
+ }
+
+ ret = mx25_gcq_setup_cfgs(pdev, priv);
+ if (ret)
+ return ret;
+
+ priv->clk = tsadc->clk;
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable clock\n");
+ return ret;
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0) {
+ dev_err(dev, "Failed to get IRQ\n");
+ ret = priv->irq;
+ goto err_clk_unprepare;
+ }
+
+ ret = request_irq(priv->irq, mx25_gcq_irq, 0, pdev->name, priv);
+ if (ret) {
+ dev_err(dev, "Failed requesting IRQ\n");
+ goto err_clk_unprepare;
+ }
+
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->channels = mx25_gcq_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mx25_gcq_channels);
+ indio_dev->info = &mx25_gcq_iio_info;
+
+ ret = iio_device_register(indio_dev);
+ if (ret) {
+ dev_err(dev, "Failed to register iio device\n");
+ goto err_irq_free;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+
+err_irq_free:
+ free_irq(priv->irq, (void *)priv);
+err_clk_unprepare:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int mx25_gcq_remove(struct platform_device *pdev)
+{
+ struct mx25_gcq_priv *priv = platform_get_drvdata(pdev);
+ struct iio_dev *indio_dev = iio_priv_to_dev(pdev);
+
+ iio_device_unregister(indio_dev);
+ free_irq(priv->irq, priv);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static struct of_device_id mx25_gcq_ids[] = {
+ { .compatible = "fsl,imx25-gcq", },
+ { /* Sentinel */ }
+};
+
+static struct platform_driver mx25_gcq_driver = {
+ .driver = {
+ .name = "mx25-gcq",
+ .owner = THIS_MODULE,
+ .of_match_table = mx25_gcq_ids,
+ },
+ .probe = mx25_gcq_probe,
+ .remove = mx25_gcq_remove,
+};
+module_platform_driver(mx25_gcq_driver);
+
+MODULE_DESCRIPTION("ADC driver for Freescale mx25");
+MODULE_AUTHOR("Markus Pargmann <mpa@pengutronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/iio/adc/fsl-imx25-gcq.h b/include/dt-bindings/iio/adc/fsl-imx25-gcq.h
new file mode 100644
index 0000000..486dce7
--- /dev/null
+++ b/include/dt-bindings/iio/adc/fsl-imx25-gcq.h
@@ -0,0 +1,11 @@
+/*
+ * This header provides constants for configuring the I.MX25 ADC
+ */
+
+#ifndef _DT_BINDINGS_IIO_ADC_FS_IMX25_GCQ_H
+#define _DT_BINDINGS_IIO_ADC_FS_IMX25_GCQ_H
+
+#define MX25_ADC_REF_INT 0 /* Internal voltage reference */
+#define MX25_ADC_REF_EXT 1 /* External voltage reference */
+
+#endif
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 6/6] ARM: imx_v4_v5_defconfig: Add I.MX25 Touchscreen controller and ADC support.
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer, linux-arm-kernel, Lee Jones,
linux-input, linux-iio, Lars-Peter Clausen, Markus Pargmann,
devicetree, Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Denis Carikli
In-Reply-To: <1403621195-9622-1-git-send-email-denis@eukrea.com>
Signed-off-by: Denis Carikli <denis@eukrea.com>
---
Changelog v3->v4:
- None
Changelog v2->v3:
- Added ADC support, splitting it would be overkill.
---
arch/arm/configs/imx_v4_v5_defconfig | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/configs/imx_v4_v5_defconfig b/arch/arm/configs/imx_v4_v5_defconfig
index 68abce9..43dd6e9 100644
--- a/arch/arm/configs/imx_v4_v5_defconfig
+++ b/arch/arm/configs/imx_v4_v5_defconfig
@@ -97,6 +97,7 @@ CONFIG_KEYBOARD_IMX=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_MX25=y
CONFIG_TOUCHSCREEN_MC13783=y
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_8250=m
@@ -117,6 +118,7 @@ CONFIG_HWMON=m
CONFIG_SENSORS_MC13783_ADC=m
CONFIG_WATCHDOG=y
CONFIG_IMX2_WDT=y
+CONFIG_MFD_MX25_TSADC=y
CONFIG_MFD_MC13XXX_SPI=y
CONFIG_REGULATOR=y
CONFIG_REGULATOR_FIXED_VOLTAGE=y
@@ -183,6 +185,8 @@ CONFIG_DMADEVICES=y
CONFIG_IMX_SDMA=y
CONFIG_IMX_DMA=y
# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_IIO=y
+CONFIG_FSL_MX25_ADC=y
CONFIG_EXT2_FS=y
CONFIG_EXT3_FS=y
CONFIG_EXT4_FS=y
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 5/6] ARM: dts: imx25: mbimxsd25: Add touchscreen support.
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Lee Jones,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Lars-Peter Clausen,
Markus Pargmann, devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Denis Carikli
In-Reply-To: <1403621195-9622-1-git-send-email-denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Denis Carikli <denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
---
Changelog v3->v4:
- None
Changelog v2->v3:
- Most of the non-board specific tsc and tscadc
parts were moved to imx25.dtsi. So this patch
was adapted to that.
- Thanks to a fix in the tsc driver, the
'fsl,pen-debounce = <100>;' is not necessary anymore.
---
.../imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts
index 68d0834..2f3bc3f 100644
--- a/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts
+++ b/arch/arm/boot/dts/imx25-eukrea-mbimxsd25-baseboard-cmo-qvga.dts
@@ -71,3 +71,11 @@
lcd-supply = <®_lcd_3v3>;
status = "okay";
};
+
+&tsc {
+ status = "okay";
+};
+
+&tscadc {
+ status = "okay";
+};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 4/6] ARM: dts: imx25: Add TSC and ADC support
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Lee Jones,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Lars-Peter Clausen,
Markus Pargmann, devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Denis Carikli
In-Reply-To: <1403621195-9622-1-git-send-email-denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
Signed-off-by: Denis Carikli <denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
---
Changelog v3->v4:
- None
Changelog v2->v3:
- Added ADC controller support: making a separate patch
for it would have been overkill.
- Moved the common TSC and ADC sub-nodes inside this patch
instead of having a copy in each dts using it.
---
arch/arm/boot/dts/imx25.dtsi | 30 +++++++++++++++++++++++++++---
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/arch/arm/boot/dts/imx25.dtsi b/arch/arm/boot/dts/imx25.dtsi
index c174039..358c78a 100644
--- a/arch/arm/boot/dts/imx25.dtsi
+++ b/arch/arm/boot/dts/imx25.dtsi
@@ -264,13 +264,37 @@
status = "disabled";
};
- tsc: tsc@50030000 {
- compatible = "fsl,imx25-adc", "fsl,imx21-tsc";
- reg = <0x50030000 0x4000>;
+ tscadc: tscadc@50030000 {
+ compatible = "fsl,imx25-tsadc";
+ reg = <0x50030000 0xc>;
interrupts = <46>;
clocks = <&clks 119>;
clock-names = "ipg";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
status = "disabled";
+
+ adc: adc@50030800 {
+ compatible = "fsl,imx25-gcq";
+ reg = <0x50030800 0x60>;
+ interrupt-parent = <&tscadc>;
+ interrupts = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ tsc: tcq@50030400 {
+ compatible = "fsl,imx25-tcq";
+ reg = <0x50030400 0x60>;
+ interrupt-parent = <&tscadc>;
+ interrupts = <0>;
+ fsl,wires = <4>;
+ status = "disabled";
+ };
};
ssi1: ssi@50034000 {
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 2/6] input: touchscreen: imx25 tcq driver
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Lee Jones,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Lars-Peter Clausen,
Markus Pargmann, devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Denis Carikli
In-Reply-To: <1403621195-9622-1-git-send-email-denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
From: Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This is a driver for the imx25 ADC/TSC module. It controls the
touchscreen conversion queue and creates a touchscreen input device.
The driver currently only supports 4 wire touchscreens. The driver uses
a simple conversion queue of precharge, touch detection, X measurement,
Y measurement, precharge and another touch detection.
This driver uses the regmap from the parent to setup some touch specific
settings in the core driver and setup a idle configuration with touch
detection.
Signed-off-by: Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Signed-off-by: Denis Carikli <denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
---
Changelog v3->v4:
- Reworked the probe to handle the IRQ and the clock removal order correctly.
- Some code and style cleanups.
Changelog v2->v3:
- Fixed the 'Senitel' typo.
- Fixed input_report_key to report 1 for BTN_TOUCH events.
- Removed useless explicit casts.
- Also disable clock when devm_request_threaded_irq failed.
---
.../bindings/input/touchscreen/fsl-mx25-tcq.txt | 29 +
drivers/input/touchscreen/Kconfig | 6 +
drivers/input/touchscreen/Makefile | 1 +
drivers/input/touchscreen/fsl-imx25-tcq.c | 584 ++++++++++++++++++++
4 files changed, 620 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/touchscreen/fsl-mx25-tcq.txt
create mode 100644 drivers/input/touchscreen/fsl-imx25-tcq.c
diff --git a/Documentation/devicetree/bindings/input/touchscreen/fsl-mx25-tcq.txt b/Documentation/devicetree/bindings/input/touchscreen/fsl-mx25-tcq.txt
new file mode 100644
index 0000000..4214a99
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/touchscreen/fsl-mx25-tcq.txt
@@ -0,0 +1,29 @@
+Freescale mx25 TS conversion queue module
+
+mx25 touchscreen conversion queue module which controls the ADC unit of the
+mx25 for attached touchscreens.
+
+Required properties:
+ - compatible: Should be "fsl,imx25-tcq".
+ - reg: Memory range of the device.
+ - interrupts: Should be the interrupt number associated with this module within
+ the tscadc unit (<0>).
+ - interrupt-parent: Should be a phandle to the tscadc unit.
+ - fsl,wires: Should be '<4>' or '<5>'
+
+Optional properties:
+ - fsl,pen-debounce: Pen debounce time.
+ - fsl,pen-threshold: Pen-down threshold for the touchscreen.
+ - fsl,settling-time: Settling time in nanoseconds.
+
+This device includes two conversion queues which can be added as subnodes.
+The first queue is for the touchscreen, the second for general purpose ADC.
+
+Example:
+ tsc: tcq@50030400 {
+ compatible = "fsl,imx25-tcq";
+ reg = <0x50030400 0x60>;
+ interrupt-parent = <&tscadc>;
+ interrupts = <0>;
+ fsl,wires = <4>;
+ };
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index a23a94b..a2290b9 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -699,6 +699,12 @@ config TOUCHSCREEN_USB_COMPOSITE
To compile this driver as a module, choose M here: the
module will be called usbtouchscreen.
+config TOUCHSCREEN_MX25
+ tristate "Freescale i.MX25 touchscreen input driver"
+ depends on MFD_MX25_TSADC
+ help
+ Enable support for touchscreen connected to your i.MX25.
+
config TOUCHSCREEN_MC13783
tristate "Freescale MC13783 touchscreen input driver"
depends on MFD_MC13XXX
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 126479d..537d591 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o
obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o
obj-$(CONFIG_TOUCHSCREEN_LPC32XX) += lpc32xx_ts.o
obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
+obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
new file mode 100644
index 0000000..5ebeff8
--- /dev/null
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -0,0 +1,584 @@
+/*
+ * Copyright 2014 Markus Pargmann, Pengutronix <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ * Based on driver from 2011:
+ * Juergen Beisert, Pengutronix <kernel-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * This is the driver for the imx25 TCQ (Touchscreen Conversion Queue)
+ * connected to the imx25 ADC.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/mfd/imx25-tsadc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+static const char mx25_tcq_name[] = "mx25-tcq";
+
+enum mx25_tcq_mode {
+ MX25_TS_4WIRE,
+};
+
+struct mx25_tcq_priv {
+ struct regmap *regs;
+ struct regmap *core_regs;
+ struct input_dev *idev;
+ enum mx25_tcq_mode mode;
+ unsigned int pen_threshold;
+ unsigned int sample_count;
+ unsigned int expected_samples;
+ unsigned int pen_debounce;
+ unsigned int settling_time;
+ struct clk *clk;
+ int irq;
+};
+
+static struct regmap_config mx25_tcq_regconfig = {
+ .fast_io = true,
+ .max_register = 0x5c,
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static struct of_device_id mx25_tcq_ids[] = {
+ { .compatible = "fsl,imx25-tcq", },
+ { /* Sentinel */ }
+};
+
+#define TSC_4WIRE_PRE_INDEX 0
+#define TSC_4WIRE_X_INDEX 1
+#define TSC_4WIRE_Y_INDEX 2
+#define TSC_4WIRE_POST_INDEX 3
+#define TSC_4WIRE_LEAVE 4
+
+#define MX25_TSC_DEF_THRESHOLD 80
+#define TSC_MAX_SAMPLES 16
+
+
+enum mx25_adc_configurations {
+ MX25_CFG_PRECHARGE = 0,
+ MX25_CFG_TOUCH_DETECT,
+ MX25_CFG_X_MEASUREMENT,
+ MX25_CFG_Y_MEASUREMENT,
+};
+
+#define MX25_PRECHARGE_VALUE (\
+ MX25_ADCQ_CFG_YPLL_OFF | \
+ MX25_ADCQ_CFG_XNUR_OFF | \
+ MX25_ADCQ_CFG_XPUL_HIGH | \
+ MX25_ADCQ_CFG_REFP_INT | \
+ MX25_ADCQ_CFG_IN_XP | \
+ MX25_ADCQ_CFG_REFN_NGND2 | \
+ MX25_ADCQ_CFG_IGS)
+
+#define MX25_TOUCH_DETECT_VALUE (\
+ MX25_ADCQ_CFG_YNLR | \
+ MX25_ADCQ_CFG_YPLL_OFF | \
+ MX25_ADCQ_CFG_XNUR_OFF | \
+ MX25_ADCQ_CFG_XPUL_OFF | \
+ MX25_ADCQ_CFG_REFP_INT | \
+ MX25_ADCQ_CFG_IN_XP | \
+ MX25_ADCQ_CFG_REFN_NGND2 | \
+ MX25_ADCQ_CFG_PENIACK)
+
+static void imx25_setup_queue_cfgs(struct mx25_tcq_priv *priv,
+ unsigned int settling_time)
+{
+ u32 precharge_cfg =
+ MX25_PRECHARGE_VALUE |
+ MX25_ADCQ_CFG_SETTLING_TIME(settling_time);
+ u32 touch_detect_cfg =
+ MX25_TOUCH_DETECT_VALUE |
+ MX25_ADCQ_CFG_NOS(1) |
+ MX25_ADCQ_CFG_SETTLING_TIME(settling_time);
+
+ regmap_write(priv->core_regs, MX25_TSC_TICR, precharge_cfg);
+
+ /* PRECHARGE */
+ regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_PRECHARGE),
+ precharge_cfg);
+
+ /* TOUCH_DETECT */
+ regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_TOUCH_DETECT),
+ touch_detect_cfg);
+
+ /* X Measurement */
+ regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_X_MEASUREMENT),
+ MX25_ADCQ_CFG_YPLL_OFF |
+ MX25_ADCQ_CFG_XNUR_LOW |
+ MX25_ADCQ_CFG_XPUL_HIGH |
+ MX25_ADCQ_CFG_REFP_XP |
+ MX25_ADCQ_CFG_IN_YP |
+ MX25_ADCQ_CFG_REFN_XN |
+ MX25_ADCQ_CFG_NOS(priv->sample_count) |
+ MX25_ADCQ_CFG_SETTLING_TIME(settling_time));
+
+ /* Y Measurement */
+ regmap_write(priv->regs, MX25_ADCQ_CFG(MX25_CFG_Y_MEASUREMENT),
+ MX25_ADCQ_CFG_YNLR |
+ MX25_ADCQ_CFG_YPLL_HIGH |
+ MX25_ADCQ_CFG_XNUR_OFF |
+ MX25_ADCQ_CFG_XPUL_OFF |
+ MX25_ADCQ_CFG_REFP_YP |
+ MX25_ADCQ_CFG_IN_XP |
+ MX25_ADCQ_CFG_REFN_YN |
+ MX25_ADCQ_CFG_NOS(priv->sample_count) |
+ MX25_ADCQ_CFG_SETTLING_TIME(settling_time));
+
+ /* Enable the touch detection right now */
+ regmap_write(priv->core_regs, MX25_TSC_TICR, touch_detect_cfg |
+ MX25_ADCQ_CFG_IGS);
+}
+
+static int imx25_setup_queue_4wire(struct mx25_tcq_priv *priv,
+ unsigned settling_time, int *items)
+{
+ imx25_setup_queue_cfgs(priv, settling_time);
+
+ /* Setup the conversion queue */
+ regmap_write(priv->regs, MX25_ADCQ_ITEM_7_0,
+ MX25_ADCQ_ITEM(0, MX25_CFG_PRECHARGE) |
+ MX25_ADCQ_ITEM(1, MX25_CFG_TOUCH_DETECT) |
+ MX25_ADCQ_ITEM(2, MX25_CFG_X_MEASUREMENT) |
+ MX25_ADCQ_ITEM(3, MX25_CFG_Y_MEASUREMENT) |
+ MX25_ADCQ_ITEM(4, MX25_CFG_PRECHARGE) |
+ MX25_ADCQ_ITEM(5, MX25_CFG_TOUCH_DETECT));
+
+ /* We measure X/Y with 'sample_count' number of samples and execute a
+ * touch detection twice, with 1 sample each */
+ priv->expected_samples = priv->sample_count * 2 + 2;
+ *items = 6;
+
+ return 0;
+}
+
+static void mx25_tcq_disable_touch_irq(struct mx25_tcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK,
+ MX25_ADCQ_CR_PDMSK);
+}
+
+static void mx25_tcq_enable_touch_irq(struct mx25_tcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_PDMSK, 0);
+}
+
+static void mx25_tcq_disable_fifo_irq(struct mx25_tcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ,
+ MX25_ADCQ_MR_FDRY_IRQ);
+}
+
+static void mx25_tcq_enable_fifo_irq(struct mx25_tcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_FDRY_IRQ, 0);
+}
+
+static void mx25_tcq_force_queue_start(struct mx25_tcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS,
+ MX25_ADCQ_CR_FQS);
+
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
+}
+
+static void mx25_tcq_force_queue_stop(struct mx25_tcq_priv *priv)
+{
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FQS, 0);
+}
+
+static void mx25_tcq_fifo_reset(struct mx25_tcq_priv *priv)
+{
+ u32 tcqcr;
+
+ regmap_read(priv->regs, MX25_ADCQ_CR, &tcqcr);
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST,
+ MX25_ADCQ_CR_FRST);
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_FRST,
+ 0);
+ regmap_write(priv->regs, MX25_ADCQ_CR, tcqcr);
+}
+
+static void mx25_tcq_re_enable_touch_detection(struct mx25_tcq_priv *priv)
+{
+ /* stop the queue from looping */
+ mx25_tcq_force_queue_stop(priv);
+
+ /* for a clean touch detection, preload the X plane */
+ regmap_write(priv->core_regs, MX25_TSC_TICR, MX25_PRECHARGE_VALUE);
+
+ /* waste some time now to pre-load the X plate to high voltage */
+ mx25_tcq_fifo_reset(priv);
+
+ /* re-enable the detection right now */
+ regmap_write(priv->core_regs, MX25_TSC_TICR, MX25_TOUCH_DETECT_VALUE |
+ MX25_ADCQ_CFG_IGS);
+
+ regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_PD,
+ MX25_ADCQ_SR_PD);
+
+ /* enable the pen down event to be a source for the interrupt */
+ regmap_update_bits(priv->regs, MX25_ADCQ_MR, MX25_ADCQ_MR_PD_IRQ, 0);
+
+ /* lets fire the next IRQ if someone touches the touchscreen */
+ mx25_tcq_enable_touch_irq(priv);
+}
+
+static int mx25_tcq_create_event_for_4wire(struct mx25_tcq_priv *priv,
+ u32 *sample_buf, int samples)
+{
+ unsigned int x_pos = 0;
+ unsigned int y_pos = 0;
+ unsigned int touch_pre = 0;
+ unsigned int touch_post = 0;
+ unsigned i;
+ int ret = 0;
+
+ for (i = 0; i < samples; i++) {
+ unsigned int index = MX25_ADCQ_FIFO_ID(sample_buf[i]);
+ unsigned int val = MX25_ADCQ_FIFO_DATA(sample_buf[i]);
+
+ switch (index) {
+ case 1:
+ touch_pre = val;
+ break;
+ case 2:
+ x_pos = val;
+ break;
+ case 3:
+ y_pos = val;
+ break;
+ case 5:
+ touch_post = val;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ if (ret == 0 && samples != 0) {
+ /*
+ * only if both touch measures are below a treshold,
+ * the position is valid
+ */
+ if (touch_pre < priv->pen_threshold &&
+ touch_post < priv->pen_threshold) {
+ /* valid samples, generate a report */
+ x_pos /= priv->sample_count;
+ y_pos /= priv->sample_count;
+ input_report_abs(priv->idev, ABS_X, x_pos);
+ input_report_abs(priv->idev, ABS_Y, y_pos);
+ input_report_key(priv->idev, BTN_TOUCH, 1);
+ input_sync(priv->idev);
+
+ /* get next sample */
+ mx25_tcq_force_queue_start(priv);
+ mx25_tcq_enable_fifo_irq(priv);
+ } else if (touch_pre >= priv->pen_threshold &&
+ touch_post >= priv->pen_threshold) {
+ /*
+ * if both samples are invalid,
+ * generate a release report
+ */
+ input_report_key(priv->idev, BTN_TOUCH, 0);
+ input_sync(priv->idev);
+ mx25_tcq_re_enable_touch_detection(priv);
+ } else {
+ /*
+ * if only one of both touch measurements are
+ * below the threshold, still some bouncing
+ * happens. Take additional samples in this
+ * case to be sure
+ */
+ mx25_tcq_force_queue_start(priv);
+ mx25_tcq_enable_fifo_irq(priv);
+ }
+ }
+
+ return ret;
+}
+
+static irqreturn_t mx25_tcq_irq_thread(int irq, void *dev_id)
+{
+ struct mx25_tcq_priv *priv = dev_id;
+ u32 sample_buf[TSC_MAX_SAMPLES];
+ int samples = 0;
+
+ /* read all samples */
+ while (1) {
+ u32 stats;
+
+ regmap_read(priv->regs, MX25_ADCQ_SR, &stats);
+ if (stats & MX25_ADCQ_SR_EMPT)
+ break;
+
+ if (samples < TSC_MAX_SAMPLES) {
+ regmap_read(priv->regs, MX25_ADCQ_FIFO,
+ &sample_buf[samples]);
+ ++samples;
+ } else {
+ u32 discarded;
+ /* discard samples */
+ regmap_read(priv->regs, MX25_ADCQ_FIFO, &discarded);
+ }
+ }
+
+ mx25_tcq_create_event_for_4wire(priv, sample_buf, samples);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mx25_tcq_irq(int irq, void *dev_id)
+{
+ struct mx25_tcq_priv *priv = dev_id;
+ u32 stat;
+ int ret = IRQ_HANDLED;
+
+ regmap_read(priv->regs, MX25_ADCQ_SR, &stat);
+
+ if (stat & (MX25_ADCQ_SR_FRR | MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR))
+ mx25_tcq_fifo_reset(priv);
+
+ if (stat & MX25_ADCQ_SR_PD) {
+ mx25_tcq_disable_touch_irq(priv);
+ mx25_tcq_force_queue_start(priv);
+ mx25_tcq_enable_fifo_irq(priv);
+ }
+
+ if (stat & MX25_ADCQ_SR_FDRY) {
+ mx25_tcq_disable_fifo_irq(priv);
+ ret = IRQ_WAKE_THREAD;
+ }
+
+ regmap_update_bits(priv->regs, MX25_ADCQ_SR, MX25_ADCQ_SR_FRR |
+ MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR | MX25_ADCQ_SR_PD |
+ MX25_ADCQ_SR_EOQ,
+ MX25_ADCQ_SR_FRR |
+ MX25_ADCQ_SR_FUR | MX25_ADCQ_SR_FOR | MX25_ADCQ_SR_PD |
+ MX25_ADCQ_SR_EOQ);
+
+ return ret;
+}
+
+/* configure the statemachine for a 4-wire touchscreen */
+static int mx25_tcq_init(struct mx25_tcq_priv *priv)
+{
+ u32 tgcr;
+ unsigned int ipg_div;
+ unsigned int adc_period;
+ unsigned int debounce_cnt;
+ unsigned int settling_time;
+ int itemct;
+ int ret;
+
+ regmap_read(priv->core_regs, MX25_TSC_TGCR, &tgcr);
+ ipg_div = max_t(unsigned int, 4, MX25_TGCR_GET_ADCCLK(tgcr));
+ adc_period = clk_get_rate(priv->clk) / (ipg_div * 2 + 2);
+ debounce_cnt = DIV_ROUND_UP(priv->pen_debounce, adc_period * 8) - 1;
+ settling_time = DIV_ROUND_UP(priv->settling_time, adc_period);
+
+
+ /* Reset */
+ regmap_write(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_QRST |
+ MX25_ADCQ_CR_FRST);
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_QRST |
+ MX25_ADCQ_CR_FRST, 0);
+
+ /* up to 128 * 8 ADC clocks are possible */
+ if (debounce_cnt > 127)
+ debounce_cnt = 127;
+
+ ret = imx25_setup_queue_4wire(priv, 0x0, &itemct);
+ if (ret)
+ return ret;
+
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_LITEMID_MASK |
+ MX25_ADCQ_CR_WMRK_MASK,
+ MX25_ADCQ_CR_LITEMID(itemct - 1) |
+ MX25_ADCQ_CR_WMRK(priv->expected_samples - 1));
+
+ /* setup debounce count */
+ regmap_update_bits(priv->core_regs, MX25_TSC_TGCR,
+ MX25_TGCR_PDBTIME_MASK,
+ MX25_TGCR_PDBTIME(debounce_cnt));
+
+ /* enable debounce */
+ regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDBEN,
+ MX25_TGCR_PDBEN);
+ regmap_update_bits(priv->core_regs, MX25_TSC_TGCR, MX25_TGCR_PDEN,
+ MX25_TGCR_PDEN);
+
+ /* enable the engine on demand */
+ regmap_update_bits(priv->regs, MX25_ADCQ_CR, MX25_ADCQ_CR_QSM_FQS,
+ MX25_ADCQ_CR_QSM_FQS);
+
+ mx25_tcq_re_enable_touch_detection(priv);
+
+ return 0;
+}
+
+static int mx25_tcq_parse_dt(struct platform_device *pdev,
+ struct mx25_tcq_priv *priv)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 wires;
+ int ret;
+
+ /* Setup defaults */
+ priv->pen_threshold = 500;
+ priv->sample_count = 3;
+ priv->pen_debounce = 1000000;
+ priv->settling_time = 250000;
+
+ ret = of_property_read_u32(np, "fsl,wires", &wires);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to find fsl,wires properties\n");
+ return ret;
+ }
+
+ if (wires == 4) {
+ priv->mode = MX25_TS_4WIRE;
+ } else {
+ dev_err(&pdev->dev, "%u-wire mode not supported\n", wires);
+ return -EINVAL;
+ }
+
+ /* These are optional, we don't care about the return values */
+ of_property_read_u32(np, "fsl,pen-threshold", &priv->pen_threshold);
+ of_property_read_u32(np, "fsl,settling-time", &priv->settling_time);
+ of_property_read_u32(np, "fsl,pen-debounce", &priv->pen_debounce);
+
+ return 0;
+}
+
+static int mx25_tcq_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct input_dev *idev;
+ struct mx25_tcq_priv *priv;
+ struct mx25_tsadc *tsadc = dev_get_drvdata(pdev->dev.parent);
+ struct resource *res;
+ void __iomem *mem;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mem = devm_ioremap_resource(dev, res);
+ if (!mem)
+ return -ENOMEM;
+
+ ret = mx25_tcq_parse_dt(pdev, priv);
+ if (ret)
+ return ret;
+
+ priv->regs = devm_regmap_init_mmio(dev, mem, &mx25_tcq_regconfig);
+ if (IS_ERR(priv->regs)) {
+ dev_err(dev, "Failed to initialize regmap\n");
+ return PTR_ERR(priv->regs);
+ }
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0) {
+ dev_err(dev, "Failed to get IRQ\n");
+ return priv->irq;
+ }
+
+ idev = devm_input_allocate_device(dev);
+ if (!idev) {
+ dev_err(dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+
+ idev->name = mx25_tcq_name;
+ idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
+ idev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
+ input_set_abs_params(idev, ABS_X, 0, 0xfff, 0, 0);
+ input_set_abs_params(idev, ABS_Y, 0, 0xfff, 0, 0);
+
+ idev->id.bustype = BUS_HOST;
+
+ ret = input_register_device(idev);
+ if (ret) {
+ dev_err(dev, "Failed to register input device\n");
+ return ret;
+ }
+
+ priv->idev = idev;
+
+ priv->core_regs = tsadc->regs;
+ if (!priv->core_regs)
+ return -EINVAL;
+
+ priv->clk = tsadc->clk;
+ if (!priv->clk)
+ return -EINVAL;
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret) {
+ dev_err(dev, "Failed to enable ipg clock\n");
+ return ret;
+ }
+
+ ret = request_threaded_irq(priv->irq, mx25_tcq_irq, mx25_tcq_irq_thread,
+ IRQF_ONESHOT, pdev->name, priv);
+ if (ret) {
+ dev_err(dev, "Failed requesting IRQ\n");
+ goto err_clk_unprepare;
+ }
+
+ ret = mx25_tcq_init(priv);
+ if (ret) {
+ dev_err(dev, "Failed to init tcq\n");
+ goto error_free_irq;
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+
+error_free_irq:
+ free_irq(priv->irq, priv);
+err_clk_unprepare:
+ clk_disable_unprepare(priv->clk);
+ return ret;
+}
+
+static int mx25_tcq_remove(struct platform_device *pdev)
+{
+ struct mx25_tcq_priv *priv = platform_get_drvdata(pdev);
+
+ free_irq(priv->irq, priv);
+ clk_disable_unprepare(priv->clk);
+
+ return 0;
+}
+
+static struct platform_driver mx25_tcq_driver = {
+ .driver = {
+ .name = "mx25-tcq",
+ .owner = THIS_MODULE,
+ .of_match_table = mx25_tcq_ids,
+ },
+ .probe = mx25_tcq_probe,
+ .remove = mx25_tcq_remove,
+};
+module_platform_driver(mx25_tcq_driver);
+
+MODULE_DESCRIPTION("TS input driver for Freescale mx25");
+MODULE_AUTHOR("Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 1/6] mfd: fsl imx25 Touchscreen ADC driver
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Lee Jones,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Lars-Peter Clausen,
Markus Pargmann, devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Denis Carikli
From: Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This is the core driver for imx25 touchscreen/adc driver. The module
has one shared ADC and two different conversion queues which use the
ADC. The two queues are identical. Both can be used for general purpose
ADC but one is meant to be used for touchscreens.
This driver is the core which manages the central components and
registers of the TSC/ADC unit. It manages the IRQs and forwards them to
the correct components.
Signed-off-by: Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Signed-off-by: Denis Carikli <denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Changelog v3->v4:
- Added Jonathan's Ack
- ARCH_MXC Kconfigdependency removed.
- mx25_tsadc_get_regmap and mx25_tsadc_get_ipg contents have been moved
in the caller function.
- mx25_tsadc_irq_chip has been removed.
- Register definitions are now more humain readable.
- Many other code and style cleanups.
Changelog v2->v3:
- None
---
.../devicetree/bindings/mfd/fsl-imx25-tsadc.txt | 46 ++++++
drivers/mfd/Kconfig | 8 +
drivers/mfd/Makefile | 2 +
drivers/mfd/fsl-imx25-tsadc.c | 170 ++++++++++++++++++++
include/linux/mfd/imx25-tsadc.h | 140 ++++++++++++++++
5 files changed, 366 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt
create mode 100644 drivers/mfd/fsl-imx25-tsadc.c
create mode 100644 include/linux/mfd/imx25-tsadc.h
diff --git a/Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt b/Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt
new file mode 100644
index 0000000..a857af0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt
@@ -0,0 +1,46 @@
+Freescale mx25 ADC/TSC multifunction device
+
+This device combines two general purpose conversion queues one used for general
+ADC and the other used for touchscreens.
+
+Required properties:
+ - compatible: Should be "fsl,imx25-tsadc".
+ - reg: Memory range of the device.
+ - interrupts: Interrupt for this device as described in
+ interrupts/interrupts.txt
+ - clocks: An 'ipg' clock defined as described in clocks/clock.txt
+ - interrupt-controller: This device is an interrupt controller. It controls
+ the interrupts of both conversion queues.
+ - #interrupt-cells: Should be '<1>'.
+ - #address-cells: Should be '<1>'.
+ - #size-cells: Should be '<1>'.
+ - ranges
+
+This device includes two conversion queues which can be added as subnodes.
+The first queue is for the touchscreen, the second for general purpose ADC.
+
+Example:
+ tscadc: tscadc@50030000 {
+ compatible = "fsl,imx25-tsadc";
+ reg = <0x50030000 0xc>;
+ interrupts = <46>;
+ clocks = <&clks 119>;
+ clock-names = "ipg";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ tsc: tcq@50030400 {
+ compatible = "fsl,imx25-tcq";
+ reg = <0x50030400 0x60>;
+ ...
+ };
+
+ adc: gcq@50030800 {
+ compatible = "fsl,imx25-gcq";
+ reg = <0x50030800 0x60>;
+ ...
+ };
+ };
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index af0e83f..d354547 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -183,6 +183,14 @@ config MFD_DA9063
Additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_MX25_TSADC
+ tristate "Freescale i.MX25 integrated Touchscreen and ADC unit"
+ select REGMAP_MMIO
+ help
+ Enable support for the integrated Touchscreen and ADC unit of the
+ i.MX25 processors. They consist of a conversion queue for general
+ purpose ADC and a queue for Touchscreens.
+
config MFD_MC13XXX
tristate
depends on (SPI_MASTER || I2C)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4e2bc25..34388c4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -78,6 +78,8 @@ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
obj-$(CONFIG_TWL6040_CORE) += twl6040.o
+obj-$(CONFIG_MFD_MX25_TSADC) += fsl-imx25-tsadc.o
+
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c
new file mode 100644
index 0000000..cebc291
--- /dev/null
+++ b/drivers/mfd/fsl-imx25-tsadc.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2014 Markus Pargmann, Pengutronix <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/mfd/imx25-tsadc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+static struct regmap_config mx25_tsadc_regmap_config = {
+ .fast_io = true,
+ .max_register = 8,
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static void mx25_tsadc_irq_handler(u32 irq, struct irq_desc *desc)
+{
+ struct mx25_tsadc *tsadc = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_get_chip(irq);
+ u32 status;
+
+ chained_irq_enter(chip, desc);
+
+ regmap_read(tsadc->regs, MX25_TSC_TGSR, &status);
+
+ if (status & MX25_TGSR_GCQ_INT)
+ generic_handle_irq(irq_find_mapping(tsadc->domain, 1));
+
+ if (status & MX25_TGSR_TCQ_INT)
+ generic_handle_irq(irq_find_mapping(tsadc->domain, 0));
+
+ chained_irq_exit(chip, desc);
+}
+
+static int mx25_tsadc_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct mx25_tsadc *tsadc = d->host_data;
+
+ irq_set_chip_data(irq, tsadc);
+ irq_set_chip_and_handler(irq, &dummy_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+
+ return 0;
+}
+
+static struct irq_domain_ops mx25_tsadc_domain_ops = {
+ .map = mx25_tsadc_domain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static int mx25_tsadc_setup_irq(struct platform_device *pdev,
+ struct mx25_tsadc *tsadc)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "Failed to get irq\n");
+ return irq;
+ }
+
+ tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops,
+ tsadc);
+ if (!tsadc->domain) {
+ dev_err(dev, "Failed to add irq domain\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler(irq, mx25_tsadc_irq_handler);
+ irq_set_handler_data(irq, tsadc);
+
+ return 0;
+}
+
+static int mx25_tsadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct mx25_tsadc *tsadc;
+ struct resource *res;
+ int ret;
+ void __iomem *iomem;
+
+ tsadc = devm_kzalloc(dev, sizeof(*tsadc), GFP_KERNEL);
+ if (!tsadc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iomem = devm_ioremap_resource(dev, res);
+ if (IS_ERR(iomem))
+ return PTR_ERR(iomem);
+
+ tsadc->regs = devm_regmap_init_mmio(dev, iomem,
+ &mx25_tsadc_regmap_config);
+ if (IS_ERR(tsadc->regs)) {
+ dev_err(dev, "Failed to initialize regmap\n");
+ return PTR_ERR(tsadc->regs);
+ }
+
+ tsadc->clk = devm_clk_get(dev, "ipg");
+ if (IS_ERR(tsadc->clk)) {
+ dev_err(dev, "Failed to get ipg clock\n");
+ return PTR_ERR(tsadc->clk);
+ }
+
+ /* Enable clock and reset the component */
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_CLK_EN,
+ MX25_TGCR_CLK_EN);
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_TSC_RST,
+ MX25_TGCR_TSC_RST);
+
+ /* Setup powersaving mode, but enable internal reference voltage */
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_POWERMODE_MASK,
+ MX25_TGCR_POWERMODE_SAVE);
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_INTREFEN,
+ MX25_TGCR_INTREFEN);
+
+ ret = mx25_tsadc_setup_irq(pdev, tsadc);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, tsadc);
+
+ of_platform_populate(np, NULL, NULL, dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mx25_tsadc_ids[] = {
+ { .compatible = "fsl,imx25-tsadc" },
+ { /* Sentinel */ }
+};
+#endif
+
+static struct platform_driver mx25_tsadc_driver = {
+ .driver = {
+ .name = "mx25-tsadc",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mx25_tsadc_ids),
+ },
+ .probe = mx25_tsadc_probe,
+};
+module_platform_driver(mx25_tsadc_driver);
+
+MODULE_DESCRIPTION("MFD for ADC/TSC for Freescale mx25");
+MODULE_AUTHOR("Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mx25-tsadc");
diff --git a/include/linux/mfd/imx25-tsadc.h b/include/linux/mfd/imx25-tsadc.h
new file mode 100644
index 0000000..207dc7b
--- /dev/null
+++ b/include/linux/mfd/imx25-tsadc.h
@@ -0,0 +1,140 @@
+#ifndef _LINUX_INCLUDE_INPUT_IMX25_TSADC_H_
+#define _LINUX_INCLUDE_INPUT_IMX25_TSADC_H_
+
+struct regmap;
+struct device;
+struct clk;
+
+struct mx25_tsadc {
+ struct regmap *regs;
+ struct irq_domain *domain;
+ struct clk *clk;
+};
+
+#define MX25_TSC_TGCR 0x00
+#define MX25_TSC_TGSR 0x04
+#define MX25_TSC_TICR 0x08
+
+/* The same register layout for TC and GC queue */
+#define MX25_ADCQ_FIFO 0x00
+#define MX25_ADCQ_CR 0x04
+#define MX25_ADCQ_SR 0x08
+#define MX25_ADCQ_MR 0x0c
+#define MX25_ADCQ_ITEM_7_0 0x20
+#define MX25_ADCQ_ITEM_15_8 0x24
+#define MX25_ADCQ_CFG(n) (0x40 + ((n) * 0x4))
+
+/* Register values */
+/* Queue Config register */
+#define MX25_ADCQ_MR_MASK 0xffffffff
+
+/* TGCR */
+#define MX25_TGCR_PDBTIME(x) ((x) << 25)
+#define MX25_TGCR_PDBTIME_MASK MX25_TGCR_PDBTIME(0x7f)
+#define MX25_TGCR_PDBEN BIT(24)
+#define MX25_TGCR_PDEN BIT(23)
+#define MX25_TGCR_ADCCLKCFG(x) ((x) << 16)
+#define MX25_TGCR_GET_ADCCLK(x) (((x) >> 16) & 0x1f)
+#define MX25_TGCR_INTREFEN BIT(10)
+#define MX25_TGCR_POWERMODE_MASK (3 << 8)
+#define MX25_TGCR_POWERMODE_SAVE BIT(8)
+#define MX25_TGCR_POWERMODE_ON (2 << 8)
+#define MX25_TGCR_STLC BIT(5)
+#define MX25_TGCR_SLPC BIT(4)
+#define MX25_TGCR_FUNC_RST BIT(2)
+#define MX25_TGCR_TSC_RST BIT(1)
+#define MX25_TGCR_CLK_EN BIT(0)
+
+/* TGSR */
+#define MX25_TGSR_SLP_INT BIT(2)
+#define MX25_TGSR_GCQ_INT BIT(1)
+#define MX25_TGSR_TCQ_INT BIT(0)
+
+/* ADCQ_ITEM_* */
+#define _MX25_ADCQ_ITEM(item, x) ((x) << ((item) * 4))
+#define MX25_ADCQ_ITEM(item, x) ((item) >= 8 ? \
+ _MX25_ADCQ_ITEM((item) - 8, (x)) : _MX25_ADCQ_ITEM((item), (x)))
+
+/* ADCQ_FIFO (TCQFIFO and GCQFIFO) */
+#define MX25_ADCQ_FIFO_DATA(x) (((x) >> 4) & 0xfff)
+#define MX25_ADCQ_FIFO_ID(x) ((x) & 0xf)
+
+/* ADCQ_CR (TCQR and GCQR) */
+#define MX25_ADCQ_CR_PDCFG_LEVEL BIT(19)
+#define MX25_ADCQ_CR_PDMSK BIT(18)
+#define MX25_ADCQ_CR_FRST BIT(17)
+#define MX25_ADCQ_CR_QRST BIT(16)
+#define MX25_ADCQ_CR_RWAIT_MASK (0xf << 12)
+#define MX25_ADCQ_CR_RWAIT(x) ((x) << 12)
+#define MX25_ADCQ_CR_WMRK_MASK (0xf << 8)
+#define MX25_ADCQ_CR_WMRK(x) ((x) << 8)
+#define MX25_ADCQ_CR_LITEMID_MASK (0xf << 4)
+#define MX25_ADCQ_CR_LITEMID(x) ((x) << 4)
+#define MX25_ADCQ_CR_RPT BIT(3)
+#define MX25_ADCQ_CR_FQS BIT(2)
+#define MX25_ADCQ_CR_QSM_MASK 0x3
+#define MX25_ADCQ_CR_QSM_PD 0x1
+#define MX25_ADCQ_CR_QSM_FQS 0x2
+#define MX25_ADCQ_CR_QSM_FQS_PD 0x3
+
+/* ADCQ_SR (TCQSR and GCQSR) */
+#define MX25_ADCQ_SR_FDRY BIT(15)
+#define MX25_ADCQ_SR_FULL BIT(14)
+#define MX25_ADCQ_SR_EMPT BIT(13)
+#define MX25_ADCQ_SR_FDN(x) (((x) >> 8) & 0x1f)
+#define MX25_ADCQ_SR_FRR BIT(6)
+#define MX25_ADCQ_SR_FUR BIT(5)
+#define MX25_ADCQ_SR_FOR BIT(4)
+#define MX25_ADCQ_SR_EOQ BIT(1)
+#define MX25_ADCQ_SR_PD BIT(0)
+
+/* ADCQ_MR (TCQMR and GCQMR) */
+#define MX25_ADCQ_MR_FDRY_DMA BIT(31)
+#define MX25_ADCQ_MR_FER_DMA BIT(22)
+#define MX25_ADCQ_MR_FUR_DMA BIT(21)
+#define MX25_ADCQ_MR_FOR_DMA BIT(20)
+#define MX25_ADCQ_MR_EOQ_DMA BIT(17)
+#define MX25_ADCQ_MR_PD_DMA BIT(16)
+#define MX25_ADCQ_MR_FDRY_IRQ BIT(15)
+#define MX25_ADCQ_MR_FER_IRQ BIT(6)
+#define MX25_ADCQ_MR_FUR_IRQ BIT(5)
+#define MX25_ADCQ_MR_FOR_IRQ BIT(4)
+#define MX25_ADCQ_MR_EOQ_IRQ BIT(1)
+#define MX25_ADCQ_MR_PD_IRQ BIT(0)
+
+/* ADCQ_CFG (TICR, TCC0-7,GCC0-7) */
+#define MX25_ADCQ_CFG_SETTLING_TIME(x) ((x) << 24)
+#define MX25_ADCQ_CFG_IGS BIT(20)
+#define MX25_ADCQ_CFG_NOS_MASK (0xf << 16)
+#define MX25_ADCQ_CFG_NOS(x) (((x) - 1) << 16)
+#define MX25_ADCQ_CFG_WIPER BIT(15)
+#define MX25_ADCQ_CFG_YNLR BIT(14)
+#define MX25_ADCQ_CFG_YPLL_HIGH 0
+#define MX25_ADCQ_CFG_YPLL_OFF BIT(12)
+#define MX25_ADCQ_CFG_YPLL_LOW (3 << 12)
+#define MX25_ADCQ_CFG_XNUR_HIGH 0
+#define MX25_ADCQ_CFG_XNUR_OFF BIT(10)
+#define MX25_ADCQ_CFG_XNUR_LOW (3 << 10)
+#define MX25_ADCQ_CFG_XPUL_OFF BIT(9)
+#define MX25_ADCQ_CFG_XPUL_HIGH 0
+#define MX25_ADCQ_CFG_REFP_YP 0
+#define MX25_ADCQ_CFG_REFP_XP BIT(7)
+#define MX25_ADCQ_CFG_REFP_EXT (2 << 7)
+#define MX25_ADCQ_CFG_REFP_INT (3 << 7)
+#define MX25_ADCQ_CFG_REFP_MASK (3 << 7)
+#define MX25_ADCQ_CFG_IN_XP 0
+#define MX25_ADCQ_CFG_IN_YP BIT(4)
+#define MX25_ADCQ_CFG_IN_XN (2 << 4)
+#define MX25_ADCQ_CFG_IN_YN (3 << 4)
+#define MX25_ADCQ_CFG_IN_WIPER (4 << 4)
+#define MX25_ADCQ_CFG_IN_AUX0 (5 << 4)
+#define MX25_ADCQ_CFG_IN_AUX1 (6 << 4)
+#define MX25_ADCQ_CFG_IN_AUX2 (7 << 4)
+#define MX25_ADCQ_CFG_REFN_XN 0
+#define MX25_ADCQ_CFG_REFN_YN BIT(2)
+#define MX25_ADCQ_CFG_REFN_NGND (2 << 2)
+#define MX25_ADCQ_CFG_REFN_NGND2 (3 << 2)
+#define MX25_ADCQ_CFG_REFN_MASK (3 << 2)
+#define MX25_ADCQ_CFG_PENIACK BIT(1)
+
+#endif /* _LINUX_INCLUDE_INPUT_IMX25_TSADC_H_ */
--
1.7.9.5
^ permalink raw reply related
* [PATCH v4 1/6] mfd: fsl imx25 Touchscreen ADC driver
From: Denis Carikli @ 2014-06-24 14:46 UTC (permalink / raw)
To: Shawn Guo, Samuel Ortiz, Dmitry Torokhov, Jonathan Cameron,
Fabio Estevam, Peter Meerwald, Hartmut Knaack
Cc: Eric Bénard, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Lee Jones,
linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA, Lars-Peter Clausen,
Markus Pargmann, devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring,
Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala, Denis Carikli
From: Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
This is the core driver for imx25 touchscreen/adc driver. The module
has one shared ADC and two different conversion queues which use the
ADC. The two queues are identical. Both can be used for general purpose
ADC but one is meant to be used for touchscreens.
This driver is the core which manages the central components and
registers of the TSC/ADC unit. It manages the IRQs and forwards them to
the correct components.
Signed-off-by: Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Signed-off-by: Denis Carikli <denis-fO0SIAKYzcbQT0dZR+AlfA@public.gmane.org>
Acked-by: Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
Changelog v3->v4:
- Added Jonathan's Ack
- ARCH_MXC Kconfigdependency removed.
- mx25_tsadc_get_regmap and mx25_tsadc_get_ipg contents have been moved
in the caller function.
- mx25_tsadc_irq_chip has been removed.
- Register definitions are now more humain readable.
- Many other code and style cleanups.
Changelog v2->v3:
- None
---
.../devicetree/bindings/mfd/fsl-imx25-tsadc.txt | 46 ++++++
drivers/mfd/Kconfig | 8 +
drivers/mfd/Makefile | 2 +
drivers/mfd/fsl-imx25-tsadc.c | 170 ++++++++++++++++++++
include/linux/mfd/imx25-tsadc.h | 140 ++++++++++++++++
5 files changed, 366 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt
create mode 100644 drivers/mfd/fsl-imx25-tsadc.c
create mode 100644 include/linux/mfd/imx25-tsadc.h
diff --git a/Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt b/Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt
new file mode 100644
index 0000000..a857af0e
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/fsl-imx25-tsadc.txt
@@ -0,0 +1,46 @@
+Freescale mx25 ADC/TSC multifunction device
+
+This device combines two general purpose conversion queues one used for general
+ADC and the other used for touchscreens.
+
+Required properties:
+ - compatible: Should be "fsl,imx25-tsadc".
+ - reg: Memory range of the device.
+ - interrupts: Interrupt for this device as described in
+ interrupts/interrupts.txt
+ - clocks: An 'ipg' clock defined as described in clocks/clock.txt
+ - interrupt-controller: This device is an interrupt controller. It controls
+ the interrupts of both conversion queues.
+ - #interrupt-cells: Should be '<1>'.
+ - #address-cells: Should be '<1>'.
+ - #size-cells: Should be '<1>'.
+ - ranges
+
+This device includes two conversion queues which can be added as subnodes.
+The first queue is for the touchscreen, the second for general purpose ADC.
+
+Example:
+ tscadc: tscadc@50030000 {
+ compatible = "fsl,imx25-tsadc";
+ reg = <0x50030000 0xc>;
+ interrupts = <46>;
+ clocks = <&clks 119>;
+ clock-names = "ipg";
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ tsc: tcq@50030400 {
+ compatible = "fsl,imx25-tcq";
+ reg = <0x50030400 0x60>;
+ ...
+ };
+
+ adc: gcq@50030800 {
+ compatible = "fsl,imx25-gcq";
+ reg = <0x50030800 0x60>;
+ ...
+ };
+ };
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index af0e83f..d354547 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -183,6 +183,14 @@ config MFD_DA9063
Additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_MX25_TSADC
+ tristate "Freescale i.MX25 integrated Touchscreen and ADC unit"
+ select REGMAP_MMIO
+ help
+ Enable support for the integrated Touchscreen and ADC unit of the
+ i.MX25 processors. They consist of a conversion queue for general
+ purpose ADC and a queue for Touchscreens.
+
config MFD_MC13XXX
tristate
depends on (SPI_MASTER || I2C)
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4e2bc25..34388c4 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -78,6 +78,8 @@ obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o
obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o
obj-$(CONFIG_TWL6040_CORE) += twl6040.o
+obj-$(CONFIG_MFD_MX25_TSADC) += fsl-imx25-tsadc.o
+
obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o
obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o
obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o
diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c
new file mode 100644
index 0000000..cebc291
--- /dev/null
+++ b/drivers/mfd/fsl-imx25-tsadc.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2014 Markus Pargmann, Pengutronix <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/irqdomain.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/mfd/imx25-tsadc.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+static struct regmap_config mx25_tsadc_regmap_config = {
+ .fast_io = true,
+ .max_register = 8,
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static void mx25_tsadc_irq_handler(u32 irq, struct irq_desc *desc)
+{
+ struct mx25_tsadc *tsadc = irq_desc_get_handler_data(desc);
+ struct irq_chip *chip = irq_get_chip(irq);
+ u32 status;
+
+ chained_irq_enter(chip, desc);
+
+ regmap_read(tsadc->regs, MX25_TSC_TGSR, &status);
+
+ if (status & MX25_TGSR_GCQ_INT)
+ generic_handle_irq(irq_find_mapping(tsadc->domain, 1));
+
+ if (status & MX25_TGSR_TCQ_INT)
+ generic_handle_irq(irq_find_mapping(tsadc->domain, 0));
+
+ chained_irq_exit(chip, desc);
+}
+
+static int mx25_tsadc_domain_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ struct mx25_tsadc *tsadc = d->host_data;
+
+ irq_set_chip_data(irq, tsadc);
+ irq_set_chip_and_handler(irq, &dummy_irq_chip,
+ handle_level_irq);
+ set_irq_flags(irq, IRQF_VALID);
+
+ return 0;
+}
+
+static struct irq_domain_ops mx25_tsadc_domain_ops = {
+ .map = mx25_tsadc_domain_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+static int mx25_tsadc_setup_irq(struct platform_device *pdev,
+ struct mx25_tsadc *tsadc)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ int irq;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "Failed to get irq\n");
+ return irq;
+ }
+
+ tsadc->domain = irq_domain_add_simple(np, 2, 0, &mx25_tsadc_domain_ops,
+ tsadc);
+ if (!tsadc->domain) {
+ dev_err(dev, "Failed to add irq domain\n");
+ return -ENOMEM;
+ }
+
+ irq_set_chained_handler(irq, mx25_tsadc_irq_handler);
+ irq_set_handler_data(irq, tsadc);
+
+ return 0;
+}
+
+static int mx25_tsadc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct mx25_tsadc *tsadc;
+ struct resource *res;
+ int ret;
+ void __iomem *iomem;
+
+ tsadc = devm_kzalloc(dev, sizeof(*tsadc), GFP_KERNEL);
+ if (!tsadc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iomem = devm_ioremap_resource(dev, res);
+ if (IS_ERR(iomem))
+ return PTR_ERR(iomem);
+
+ tsadc->regs = devm_regmap_init_mmio(dev, iomem,
+ &mx25_tsadc_regmap_config);
+ if (IS_ERR(tsadc->regs)) {
+ dev_err(dev, "Failed to initialize regmap\n");
+ return PTR_ERR(tsadc->regs);
+ }
+
+ tsadc->clk = devm_clk_get(dev, "ipg");
+ if (IS_ERR(tsadc->clk)) {
+ dev_err(dev, "Failed to get ipg clock\n");
+ return PTR_ERR(tsadc->clk);
+ }
+
+ /* Enable clock and reset the component */
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_CLK_EN,
+ MX25_TGCR_CLK_EN);
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_TSC_RST,
+ MX25_TGCR_TSC_RST);
+
+ /* Setup powersaving mode, but enable internal reference voltage */
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_POWERMODE_MASK,
+ MX25_TGCR_POWERMODE_SAVE);
+ regmap_update_bits(tsadc->regs, MX25_TSC_TGCR, MX25_TGCR_INTREFEN,
+ MX25_TGCR_INTREFEN);
+
+ ret = mx25_tsadc_setup_irq(pdev, tsadc);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, tsadc);
+
+ of_platform_populate(np, NULL, NULL, dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id mx25_tsadc_ids[] = {
+ { .compatible = "fsl,imx25-tsadc" },
+ { /* Sentinel */ }
+};
+#endif
+
+static struct platform_driver mx25_tsadc_driver = {
+ .driver = {
+ .name = "mx25-tsadc",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(mx25_tsadc_ids),
+ },
+ .probe = mx25_tsadc_probe,
+};
+module_platform_driver(mx25_tsadc_driver);
+
+MODULE_DESCRIPTION("MFD for ADC/TSC for Freescale mx25");
+MODULE_AUTHOR("Markus Pargmann <mpa-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:mx25-tsadc");
diff --git a/include/linux/mfd/imx25-tsadc.h b/include/linux/mfd/imx25-tsadc.h
new file mode 100644
index 0000000..207dc7b
--- /dev/null
+++ b/include/linux/mfd/imx25-tsadc.h
@@ -0,0 +1,140 @@
+#ifndef _LINUX_INCLUDE_INPUT_IMX25_TSADC_H_
+#define _LINUX_INCLUDE_INPUT_IMX25_TSADC_H_
+
+struct regmap;
+struct device;
+struct clk;
+
+struct mx25_tsadc {
+ struct regmap *regs;
+ struct irq_domain *domain;
+ struct clk *clk;
+};
+
+#define MX25_TSC_TGCR 0x00
+#define MX25_TSC_TGSR 0x04
+#define MX25_TSC_TICR 0x08
+
+/* The same register layout for TC and GC queue */
+#define MX25_ADCQ_FIFO 0x00
+#define MX25_ADCQ_CR 0x04
+#define MX25_ADCQ_SR 0x08
+#define MX25_ADCQ_MR 0x0c
+#define MX25_ADCQ_ITEM_7_0 0x20
+#define MX25_ADCQ_ITEM_15_8 0x24
+#define MX25_ADCQ_CFG(n) (0x40 + ((n) * 0x4))
+
+/* Register values */
+/* Queue Config register */
+#define MX25_ADCQ_MR_MASK 0xffffffff
+
+/* TGCR */
+#define MX25_TGCR_PDBTIME(x) ((x) << 25)
+#define MX25_TGCR_PDBTIME_MASK MX25_TGCR_PDBTIME(0x7f)
+#define MX25_TGCR_PDBEN BIT(24)
+#define MX25_TGCR_PDEN BIT(23)
+#define MX25_TGCR_ADCCLKCFG(x) ((x) << 16)
+#define MX25_TGCR_GET_ADCCLK(x) (((x) >> 16) & 0x1f)
+#define MX25_TGCR_INTREFEN BIT(10)
+#define MX25_TGCR_POWERMODE_MASK (3 << 8)
+#define MX25_TGCR_POWERMODE_SAVE BIT(8)
+#define MX25_TGCR_POWERMODE_ON (2 << 8)
+#define MX25_TGCR_STLC BIT(5)
+#define MX25_TGCR_SLPC BIT(4)
+#define MX25_TGCR_FUNC_RST BIT(2)
+#define MX25_TGCR_TSC_RST BIT(1)
+#define MX25_TGCR_CLK_EN BIT(0)
+
+/* TGSR */
+#define MX25_TGSR_SLP_INT BIT(2)
+#define MX25_TGSR_GCQ_INT BIT(1)
+#define MX25_TGSR_TCQ_INT BIT(0)
+
+/* ADCQ_ITEM_* */
+#define _MX25_ADCQ_ITEM(item, x) ((x) << ((item) * 4))
+#define MX25_ADCQ_ITEM(item, x) ((item) >= 8 ? \
+ _MX25_ADCQ_ITEM((item) - 8, (x)) : _MX25_ADCQ_ITEM((item), (x)))
+
+/* ADCQ_FIFO (TCQFIFO and GCQFIFO) */
+#define MX25_ADCQ_FIFO_DATA(x) (((x) >> 4) & 0xfff)
+#define MX25_ADCQ_FIFO_ID(x) ((x) & 0xf)
+
+/* ADCQ_CR (TCQR and GCQR) */
+#define MX25_ADCQ_CR_PDCFG_LEVEL BIT(19)
+#define MX25_ADCQ_CR_PDMSK BIT(18)
+#define MX25_ADCQ_CR_FRST BIT(17)
+#define MX25_ADCQ_CR_QRST BIT(16)
+#define MX25_ADCQ_CR_RWAIT_MASK (0xf << 12)
+#define MX25_ADCQ_CR_RWAIT(x) ((x) << 12)
+#define MX25_ADCQ_CR_WMRK_MASK (0xf << 8)
+#define MX25_ADCQ_CR_WMRK(x) ((x) << 8)
+#define MX25_ADCQ_CR_LITEMID_MASK (0xf << 4)
+#define MX25_ADCQ_CR_LITEMID(x) ((x) << 4)
+#define MX25_ADCQ_CR_RPT BIT(3)
+#define MX25_ADCQ_CR_FQS BIT(2)
+#define MX25_ADCQ_CR_QSM_MASK 0x3
+#define MX25_ADCQ_CR_QSM_PD 0x1
+#define MX25_ADCQ_CR_QSM_FQS 0x2
+#define MX25_ADCQ_CR_QSM_FQS_PD 0x3
+
+/* ADCQ_SR (TCQSR and GCQSR) */
+#define MX25_ADCQ_SR_FDRY BIT(15)
+#define MX25_ADCQ_SR_FULL BIT(14)
+#define MX25_ADCQ_SR_EMPT BIT(13)
+#define MX25_ADCQ_SR_FDN(x) (((x) >> 8) & 0x1f)
+#define MX25_ADCQ_SR_FRR BIT(6)
+#define MX25_ADCQ_SR_FUR BIT(5)
+#define MX25_ADCQ_SR_FOR BIT(4)
+#define MX25_ADCQ_SR_EOQ BIT(1)
+#define MX25_ADCQ_SR_PD BIT(0)
+
+/* ADCQ_MR (TCQMR and GCQMR) */
+#define MX25_ADCQ_MR_FDRY_DMA BIT(31)
+#define MX25_ADCQ_MR_FER_DMA BIT(22)
+#define MX25_ADCQ_MR_FUR_DMA BIT(21)
+#define MX25_ADCQ_MR_FOR_DMA BIT(20)
+#define MX25_ADCQ_MR_EOQ_DMA BIT(17)
+#define MX25_ADCQ_MR_PD_DMA BIT(16)
+#define MX25_ADCQ_MR_FDRY_IRQ BIT(15)
+#define MX25_ADCQ_MR_FER_IRQ BIT(6)
+#define MX25_ADCQ_MR_FUR_IRQ BIT(5)
+#define MX25_ADCQ_MR_FOR_IRQ BIT(4)
+#define MX25_ADCQ_MR_EOQ_IRQ BIT(1)
+#define MX25_ADCQ_MR_PD_IRQ BIT(0)
+
+/* ADCQ_CFG (TICR, TCC0-7,GCC0-7) */
+#define MX25_ADCQ_CFG_SETTLING_TIME(x) ((x) << 24)
+#define MX25_ADCQ_CFG_IGS BIT(20)
+#define MX25_ADCQ_CFG_NOS_MASK (0xf << 16)
+#define MX25_ADCQ_CFG_NOS(x) (((x) - 1) << 16)
+#define MX25_ADCQ_CFG_WIPER BIT(15)
+#define MX25_ADCQ_CFG_YNLR BIT(14)
+#define MX25_ADCQ_CFG_YPLL_HIGH 0
+#define MX25_ADCQ_CFG_YPLL_OFF BIT(12)
+#define MX25_ADCQ_CFG_YPLL_LOW (3 << 12)
+#define MX25_ADCQ_CFG_XNUR_HIGH 0
+#define MX25_ADCQ_CFG_XNUR_OFF BIT(10)
+#define MX25_ADCQ_CFG_XNUR_LOW (3 << 10)
+#define MX25_ADCQ_CFG_XPUL_OFF BIT(9)
+#define MX25_ADCQ_CFG_XPUL_HIGH 0
+#define MX25_ADCQ_CFG_REFP_YP 0
+#define MX25_ADCQ_CFG_REFP_XP BIT(7)
+#define MX25_ADCQ_CFG_REFP_EXT (2 << 7)
+#define MX25_ADCQ_CFG_REFP_INT (3 << 7)
+#define MX25_ADCQ_CFG_REFP_MASK (3 << 7)
+#define MX25_ADCQ_CFG_IN_XP 0
+#define MX25_ADCQ_CFG_IN_YP BIT(4)
+#define MX25_ADCQ_CFG_IN_XN (2 << 4)
+#define MX25_ADCQ_CFG_IN_YN (3 << 4)
+#define MX25_ADCQ_CFG_IN_WIPER (4 << 4)
+#define MX25_ADCQ_CFG_IN_AUX0 (5 << 4)
+#define MX25_ADCQ_CFG_IN_AUX1 (6 << 4)
+#define MX25_ADCQ_CFG_IN_AUX2 (7 << 4)
+#define MX25_ADCQ_CFG_REFN_XN 0
+#define MX25_ADCQ_CFG_REFN_YN BIT(2)
+#define MX25_ADCQ_CFG_REFN_NGND (2 << 2)
+#define MX25_ADCQ_CFG_REFN_NGND2 (3 << 2)
+#define MX25_ADCQ_CFG_REFN_MASK (3 << 2)
+#define MX25_ADCQ_CFG_PENIACK BIT(1)
+
+#endif /* _LINUX_INCLUDE_INPUT_IMX25_TSADC_H_ */
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH 1/5] Input - wacom: create a separate input device for pads
From: Benjamin Tissoires @ 2014-06-24 14:00 UTC (permalink / raw)
To: Ping Cheng
Cc: Dmitry Torokhov, Jason Gerecke, linux-input,
linux-kernel@vger.kernel.org, linuxwacom-devel
In-Reply-To: <CAF8JNhKxSuLNj2TXFu3FcgH9c1QsfprvX5LfMr1Aj1yoJRsT8g@mail.gmail.com>
Hi Ping,
On Jun 23 2014 or thereabouts, Ping Cheng wrote:
> Hi Benjamin,
>
> On Mon, Jun 23, 2014 at 1:57 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
> > Currently, the pad events are sent through the stylus input device
> > for the Intuos/Cintiqs, and through the touch input device for the
> > Bamboos.
> >
> > To differentiate the buttons pressed on the pad from the ones pressed
> > on the stylus, the Intuos/Cintiq uses MISC_SERIAL and ABS_MISC. This
> > lead to a multiplexing of the events into one device, which are then
> > splitted out in xf86-input-wacom. Bamboos are not using MISC events
> > because the pad is attached to the touch interface, and only BTN_TOUCH
> > is used for the finger (and DOUBLE_TAP, etc...). However, the user space
> > driver still splits out the pad from the touch interface in the same
> > way it does for the pro line devices.
> >
> > The other problem we can see with this fact is that some of the Intuos
> > and Cintiq have a wheel, and the effective range of the reported values
> > is [0..71]. Unfortunately, the airbrush stylus also sends wheel events
> > (there is a small wheel on it), but in the range [0..1023]. From the user
> > space point of view it is kind of difficult to understand that because
> > the wheel on the pad are quite common, while the airbrush tool is not.
> >
> > A solution to fix all of these problems is to split out the pad device
> > from the stylus/touch. This decision makes more sense because the pad is
> > not linked to the absolute position of the finger or pen, and usually, the
> > events from the pad are filtered out by the compositor, which then convert
> > them into actions or keyboard shortcuts.
>
> This is a very good solution. I like it.
>
> > For backward compatibility with current xf86-input-wacom, the pad devices
> > still present the ABS_X, ABS_Y and ABS_MISC events, but they can be
> > completely ignored in the new implementation.
>
> I do not think we need to keep ABS_X and ABS_Y for pad. We've already
> supported a tablet (Intuos pen small, a pen only tablet with buttons
> reported on touch interface) that does not set ABS_X and ABS_Y for
> pad.
Hmm, actually, when I tried removing X and Y, xf86-input-wacom
complained that max_x and max_y where set to 0, and it thus rejected the
device. Maybe there is a special quirk in the xorg driver for the device
you mentioned?
Anyway, it's not a big deal, and when both xorg and libinput will know
how to handle properly the pad device nodes, we can remove this.
>
> Unless you plan to use other means to tell userland those events are
> from PAD tool, ABS_MISC is necessary and is a reasonable way to group
Well, given that the pad now has its own input node, ABS_MISC could be
dropped. We just need to teach the users that whichever event comes from
this input device is a PAD event.
> PAD events. So, I do not think it is for backward compatibility. It is
> there to stay. With that said, the whole patchset is
>
> > Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>
> Reviewed-by: Ping Cheng <pingc@wacom.com>
>
Thanks, that is greatly appreciated!
> Thank you, Benjamin, for your support.
>
> Ping
>
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH 1/2] lib: int_sqrt: add int64_sqrt routine
From: Elias Vanderstuyft @ 2014-06-24 13:43 UTC (permalink / raw)
To: Barry Song
Cc: Dmitry Torokhov, dtor, akpm, open list:HID CORE LAYER,
workgroup.linux, Yibo Cai, Barry Song
In-Reply-To: <1403516581-12560-2-git-send-email-21cnbao@gmail.com>
On Mon, Jun 23, 2014 at 11:43 AM, Barry Song <21cnbao@gmail.com> wrote:
> From: Yibo Cai <yibo.cai@csr.com>
>
> Get square root of a 64-bit digit on 32bit platforms. CSR SiRFSoC
> touchscreen driver needs it.
>
> Signed-off-by: Yibo Cai <yibo.cai@csr.com>
> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> ---
> include/linux/kernel.h | 1 +
> lib/int_sqrt.c | 27 +++++++++++++++++++++++++++
> 2 files changed, 28 insertions(+)
>
> diff --git a/include/linux/kernel.h b/include/linux/kernel.h
> index 4c52907..6e63081 100644
> --- a/include/linux/kernel.h
> +++ b/include/linux/kernel.h
> @@ -418,6 +418,7 @@ struct pid;
> extern struct pid *session_of_pgrp(struct pid *pgrp);
>
> unsigned long int_sqrt(unsigned long);
> +unsigned long long int64_sqrt(unsigned long long);
>
> extern void bust_spinlocks(int yes);
> extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */
> diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c
> index 1ef4cc3..2aa9fcc 100644
> --- a/lib/int_sqrt.c
> +++ b/lib/int_sqrt.c
> @@ -36,3 +36,30 @@ unsigned long int_sqrt(unsigned long x)
> return y;
> }
> EXPORT_SYMBOL(int_sqrt);
> +
> +/*
> + * Square root of a 64-bit digit.
> + * Same as int_sqrt on 64-bit platforms where "long" equals "long long"
> + */
> +unsigned long long int64_sqrt(unsigned long long x)
> +{
> + unsigned long long m = 0, y = 0, b = 0;
> +
> + if (x <= 1)
> + return x;
> +
> + m = 1ULL << (BITS_PER_LONG_LONG - 2);
> + while (m != 0) {
> + b = y + m;
> + y >>= 1;
> +
> + if (x >= b) {
> + x -= b;
> + y += m;
> + }
> + m >>= 2;
> + }
> +
> + return y;
> +}
> +EXPORT_SYMBOL(int64_sqrt);
>
Maybe it's a stupid question (I'm new to kernel programming),
but why don't you use a for-loop instead of a while-loop?
(apart from following the already-existing code of int_sqrt.c)
E.g.:
for (m = 1ULL << (BITS_PER_LONG_LONG - 2); m != 0; m >>= 2) {
b = y + m;
y >>= 1;
if (x >= b) {
x -= b;
y += m;
}
}
Instead of:
m = 1ULL << (BITS_PER_LONG_LONG - 2);
while (m != 0) {
b = y + m;
y >>= 1;
if (x >= b) {
x -= b;
y += m;
}
m >>= 2;
}
Thanks,
Elias
^ permalink raw reply
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels
From: Bjørn Mork @ 2014-06-24 13:10 UTC (permalink / raw)
To: Johan Hovold
Cc: Greg KH, Janne Kanniainen, jkosina, cooloney, linux-kernel,
linux-leds, linux-usb, linux-input
In-Reply-To: <20140623204430.GC15945@localhost>
Johan Hovold <johan@kernel.org> writes:
> This is a non-standard attribute of this particular laptop. It has three
> individual LEDs that can be enabled separately (using standard LED class
> attributes), but they will all three be in the same "mode" (which here
> apparently means that they can be fully on, vary with the volume(?!), or
> pulse synchronously when enabled).
>
> If we were to implement this mode attribute as a class attribute,
> changing the mode of of one LED would also change the mode of the other
> two devices (LEDs).
Document this behaviour and it becomes a feature.
Bjørn
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 3/4] HID: sony: Format and comment sixaxis_rdesc
From: Antonio Ospite @ 2014-06-24 11:28 UTC (permalink / raw)
To: linux-input; +Cc: Antonio Ospite, Jiri Kosina, simon, Frank Praznik
In-Reply-To: <1403609323-27283-1-git-send-email-ao2@ao2.it>
Reformat sixaxis_rdesc to reflect its HID structure, and comment each
field. This will make it easier to validate changes to the descriptor in
the future.
No functional changes are introduced, the descriptor is exactly the same
as before byte by byte.
The heavy lifting has been done with the help of hidrd-convert:
https://github.com/DIGImend/hidrd
Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
drivers/hid/hid-sony.c | 93 +++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 74 insertions(+), 19 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 11026b5..22ba5dd 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -57,25 +57,80 @@
#define MAX_LEDS 4
static __u8 sixaxis_rdesc[] = {
- 0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02,
- 0x85, 0x01, 0x75, 0x08, 0x95, 0x01, 0x15, 0x00,
- 0x26, 0xff, 0x00, 0x81, 0x03, 0x75, 0x01, 0x95,
- 0x13, 0x15, 0x00, 0x25, 0x01, 0x35, 0x00, 0x45,
- 0x01, 0x05, 0x09, 0x19, 0x01, 0x29, 0x13, 0x81,
- 0x02, 0x75, 0x01, 0x95, 0x0d, 0x06, 0x00, 0xff,
- 0x81, 0x03, 0x15, 0x00, 0x26, 0xff, 0x00, 0x05,
- 0x01, 0x09, 0x01, 0xa1, 0x00, 0x75, 0x08, 0x95,
- 0x04, 0x35, 0x00, 0x46, 0xff, 0x00, 0x09, 0x30,
- 0x09, 0x31, 0x09, 0x32, 0x09, 0x35, 0x81, 0x02,
- 0xc0, 0x05, 0x01, 0x95, 0x13, 0x09, 0x01, 0x81,
- 0x02, 0x95, 0x0c, 0x81, 0x01, 0x75, 0x10, 0x95,
- 0x04, 0x26, 0xff, 0x03, 0x46, 0xff, 0x03, 0x09,
- 0x01, 0x81, 0x02, 0xc0, 0xa1, 0x02, 0x85, 0x02,
- 0x75, 0x08, 0x95, 0x30, 0x09, 0x01, 0xb1, 0x02,
- 0xc0, 0xa1, 0x02, 0x85, 0xee, 0x75, 0x08, 0x95,
- 0x30, 0x09, 0x01, 0xb1, 0x02, 0xc0, 0xa1, 0x02,
- 0x85, 0xef, 0x75, 0x08, 0x95, 0x30, 0x09, 0x01,
- 0xb1, 0x02, 0xc0, 0xc0,
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x04, /* Usage (Joystik), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x85, 0x01, /* Report ID (1), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x01, /* Report Count (1), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x13, /* Report Count (19), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x35, 0x00, /* Physical Minimum (0), */
+ 0x45, 0x01, /* Physical Maximum (1), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x13, /* Usage Maximum (13h), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x0D, /* Report Count (13), */
+ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
+ 0x81, 0x03, /* Input (Constant, Variable), */
+ 0x15, 0x00, /* Logical Minimum (0), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xA1, 0x00, /* Collection (Physical), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x04, /* Report Count (4), */
+ 0x35, 0x00, /* Physical Minimum (0), */
+ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x09, 0x32, /* Usage (Z), */
+ 0x09, 0x35, /* Usage (Rz), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x95, 0x13, /* Report Count (19), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x0C, /* Report Count (12), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x75, 0x10, /* Report Size (16), */
+ 0x95, 0x04, /* Report Count (4), */
+ 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
+ 0x46, 0xFF, 0x03, /* Physical Maximum (1023), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0xC0, /* End Collection, */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x85, 0x02, /* Report ID (2), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x30, /* Report Count (48), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x85, 0xEE, /* Report ID (238), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x30, /* Report Count (48), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x85, 0xEF, /* Report ID (239), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x30, /* Report Count (48), */
+ 0x09, 0x01, /* Usage (Pointer), */
+ 0xB1, 0x02, /* Feature (Variable), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
};
/*
--
2.0.0
^ permalink raw reply related
* [PATCH 0/4] HID: sony: Some cleanups
From: Antonio Ospite @ 2014-06-24 11:28 UTC (permalink / raw)
To: linux-input; +Cc: Antonio Ospite, Jiri Kosina, simon, Frank Praznik
Hi,
here are some cleanups for hid-sony.
The changes in patches 2 and 3 will prove useful if someday David
Hermann's ABS2 changes make it to mainline.
Ciao,
Antonio
Antonio Ospite (4):
HID: sony: Use the SIXAXIS_CONTROLLER constant when possible
HID: sony: Always override the Sixaxis descriptor
HID: sony: Format and comment sixaxis_rdesc
HID: sony: Remove an old and redundant comment
drivers/hid/hid-sony.c | 130 ++++++++++++++++++++++++++++++++-----------------
1 file changed, 85 insertions(+), 45 deletions(-)
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
^ permalink raw reply
* [PATCH 4/4] HID: sony: Remove an old and redundant comment
From: Antonio Ospite @ 2014-06-24 11:28 UTC (permalink / raw)
To: linux-input; +Cc: Antonio Ospite, Jiri Kosina, simon, Frank Praznik
In-Reply-To: <1403609323-27283-1-git-send-email-ao2@ao2.it>
Remove an old redundant comment before sony_report_fixup(), it must have
been a leftover from the first version of the driver:
sony_report_fixup() now handles all the supported devices, not only the
Sony Vaio VGX.
The comment is also redundant as the same information provided by it is
also present in the body of the function.
Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
drivers/hid/hid-sony.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 22ba5dd..bb1e969 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -875,8 +875,6 @@ static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
return 1;
}
-
-/* Sony Vaio VGX has wrongly mouse pointer declared as constant */
static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
--
2.0.0
^ permalink raw reply related
* [PATCH 2/4] HID: sony: Always override the Sixaxis descriptor
From: Antonio Ospite @ 2014-06-24 11:28 UTC (permalink / raw)
To: linux-input; +Cc: Antonio Ospite, Jiri Kosina, simon, Frank Praznik
In-Reply-To: <1403609323-27283-1-git-send-email-ao2@ao2.it>
Simplify the logic of overriding the Sixaxis HID descriptor, this will
make it easier to amend the descriptor in future commits.
The current code does this:
if (original sixaxis via USB or BT)
fixup only a part of the descriptor
else if (sixaxis compatible controller)
override the _whole_ descriptor
but the end result is exactly the same, except for the trailing zero in
the case of original BT controllers.
So let's just regularize the process, and always override the HID
descriptor.
Always overriding the descriptor changes the current semantic a little
bit, before this change the BT descriptor still had the trailing zero
byte, while now it is exactly the same as the descriptor of the
controller via USB, but that does not affect proper operation of the
device.
Note that overriding the whole descriptor for original devices is not
strictly necessary for now, but it simplifies the code and in the future
the report descriptor will be patched further and keys will be remapped,
so it's handy to have only one place to patch.
Signed-off-by: Antonio Ospite <ao2@ao2.it>
---
drivers/hid/hid-sony.c | 31 ++++++++++---------------------
1 file changed, 10 insertions(+), 21 deletions(-)
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index a77269b..11026b5 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -56,13 +56,7 @@
#define MAX_LEDS 4
-static const u8 sixaxis_rdesc_fixup[] = {
- 0x95, 0x13, 0x09, 0x01, 0x81, 0x02, 0x95, 0x0C,
- 0x81, 0x01, 0x75, 0x10, 0x95, 0x04, 0x26, 0xFF,
- 0x03, 0x46, 0xFF, 0x03, 0x09, 0x01, 0x81, 0x02
-};
-
-static const u8 sixaxis_rdesc_fixup2[] = {
+static __u8 sixaxis_rdesc[] = {
0x05, 0x01, 0x09, 0x04, 0xa1, 0x01, 0xa1, 0x02,
0x85, 0x01, 0x75, 0x08, 0x95, 0x01, 0x15, 0x00,
0x26, 0xff, 0x00, 0x81, 0x03, 0x75, 0x01, 0x95,
@@ -778,6 +772,13 @@ struct sony_sc {
__u8 led_count;
};
+static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ *rsize = sizeof(sixaxis_rdesc);
+ return sixaxis_rdesc;
+}
+
static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
@@ -857,20 +858,8 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
*rsize = sizeof(dualshock4_bt_rdesc);
}
- /* The HID descriptor exposed over BT has a trailing zero byte */
- if ((((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize == 148) ||
- ((sc->quirks & SIXAXIS_CONTROLLER_BT) && *rsize == 149)) &&
- rdesc[83] == 0x75) {
- hid_info(hdev, "Fixing up Sony Sixaxis report descriptor\n");
- memcpy((void *)&rdesc[83], (void *)&sixaxis_rdesc_fixup,
- sizeof(sixaxis_rdesc_fixup));
- } else if (sc->quirks & SIXAXIS_CONTROLLER_USB &&
- *rsize > sizeof(sixaxis_rdesc_fixup2)) {
- hid_info(hdev, "Sony Sixaxis clone detected. Using original report descriptor (size: %d clone; %d new)\n",
- *rsize, (int)sizeof(sixaxis_rdesc_fixup2));
- *rsize = sizeof(sixaxis_rdesc_fixup2);
- memcpy(rdesc, &sixaxis_rdesc_fixup2, *rsize);
- }
+ if (sc->quirks & SIXAXIS_CONTROLLER)
+ return sixaxis_fixup(hdev, rdesc, rsize);
if (sc->quirks & PS3REMOTE)
return ps3remote_fixup(hdev, rdesc, rsize);
--
2.0.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox