* Re: [PATCH] Input: Add Acer Aspire 5710 to nomux blacklist
From: Dmitry Torokhov @ 2014-07-10 21:11 UTC (permalink / raw)
To: Hans de Goede; +Cc: Vojtech Pavlik, Jiri Kosina, linux-input
In-Reply-To: <53BEAF57.30409@redhat.com>
On Thu, Jul 10, 2014 at 05:20:55PM +0200, Hans de Goede wrote:
> Hi,
>
> On 07/10/2014 10:45 AM, Vojtech Pavlik wrote:
> > On Thu, Jul 10, 2014 at 09:32:16AM +0200, Hans de Goede wrote:
> >
> >>>>> I also expect
> >>>>> that most of external PS/2 mice are dead by now, so number of cases when
> >>>>
> >>>> One would at least hope so. Sadly, internal mice and PS/2 keyboards
> >>>> aren't going to go away any soon, due to larger power consumption of USB
> >>>> devices.
> >>>
> >>> Right, but we are not talking about mouse vs keyboard, they use separate
> >>> ports anyway, it is touchpad plus external PS/2 mouse case where active
> >>> MUX might help.
> >>
> >> What about laptops with both a touchpad and a trackpoint ? I think in most
> >> cases the trackpoint works through some sort of pass-through mode of the
> >> touchpad (or is outright part of the touchpad ps/2 device), but are we
> >> sure there are no cases where the trackpoint and touchpad are really
> >> separate ps/2 devices hookedup through an active mux ?
> >
> > I'm not aware of any current machines using active multiplexing for
> > that. There are basically two touchpad manufacturers: Synaptics and
> > ALPS.
>
> And elantech
>
> > Synaptics has a nearly transparent passthrough mode and
> > touchpoints are connected through that. ALPS basically manufactures a
> > touchpad+touchpoint combo device and thus doesn't need a fully
> > transparent passthrough.
>
> Elantech now a days also produces a combo like alps.
They still wire it up internally and route all data through AUX port and
not use active MUX for that.
>
> > Active multiplexing was typically used for external PS/2 ports on
> > laptops, because the manufacturer couldn't anticipate the protocol of
> > the externally connected device.
>
> Right, but what about users who still have a laptop with an external
> ps/2 port which they happen to also still use ?
The assertion that it works well now, which is a stretch. As far as I
know Windows by default does not activate it, so manufacturers rarely
test it.
>
>
>
> >
> >>>>> we have users with PS/2 touchpad + external PS/2 mouse + working active
> >>>>> MUX is exceedingly small.
> >>>>>
> >>>>> Let's pull Vojtech in ;)
> >>>>
> >>>> What I'd prefer is to, based on DMI data, report but not enable by
> >>>> default Active MUX mode on any machine manufactured after a certain
> >>>> date. Plus have a DMI-based whitelist for machines that absolutely
> >>>> needed, if any are found later.
> >>>
> >>> Looking at the changes to nomux blacklist sometimes even trying MUX
> >>> messes up KBC. Instead of playing date games I'd rather simply make
> >>> i8042.nomux default. I'm fine with having whitelist for boxes that
> >>> actually need and support muxing properly.
> >>
> >> I'm a bit skeptical about making this change, see above.
> >
> > I'm not too keen about it either, as it could break existing setups.
> >
> > But I have to concede that any working hardware still using both
> > external and internal PS/2 and thus needing Active Multiplexing is most
> > likely to be found in museums today.
> >
> > So the risk of breakage isn't all that big.
>
> One of the nice things about Linux is that in general we've pretty
> decent support for older hardware, so if we decide to flip the nomux
> default, I think we should really do so based on some BIOS cut-off
> date, so as to not break older model laptops.
I think historically IBM and HPs had working MUX support while other's
did might advertise support and fail miserably when we would try
activating it.
Given that now majority of mice are USB even if we select wrong default
on some older box I think it would be acceptable as opposed to a newer
box not having touchpad at all...
Thanks.
--
Dmitry
^ permalink raw reply
* [PATCH] PM / sleep / irq: Do not suspend wakeup interrupts
From: Rafael J. Wysocki @ 2014-07-10 21:37 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Li, Aubrey, Dmitry Torokhov, linux-input@vger.kernel.org, LKML,
One Thousand Gnomes, Linux PM list
In-Reply-To: <1614271.1peg23gJZx@vostro.rjw.lan>
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
If an IRQ has been configured for wakeup via enable_irq_wake(), the
driver who has done that must be prepared for receiving interrupts
after suspend_device_irqs() has returned, so there is no need to
"suspend" such IRQs. Moreover, if drivers using enable_irq_wake()
actually want to receive interrupts after suspend_device_irqs() has
returned, they need to add IRQF_NO_SUSPEND to the IRQ flags while
requesting the IRQs, which shouldn't be necessary (it also goes a bit
too far, as IRQF_NO_SUSPEND causes the IRQ to be ignored by
suspend_device_irqs() all the time regardless of whether or not it
has been configured for signaling wakeup).
For the above reasons, make __disable_irq() ignore IRQ descriptors
with IRQD_WAKEUP_STATE set when its suspend argument is true which
effectively causes them to behave like IRQs with IRQF_NO_SUSPEND
set.
This also allows IRQs configured for wakeup via enable_irq_wake()
to work as wakeup interrupts for the "freeze" (suspend-to-idle)
sleep mode automatically just like for any other sleep states.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
kernel/irq/manage.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: linux-pm/kernel/irq/manage.c
===================================================================
--- linux-pm.orig/kernel/irq/manage.c
+++ linux-pm/kernel/irq/manage.c
@@ -385,7 +385,8 @@ setup_affinity(unsigned int irq, struct
void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend)
{
if (suspend) {
- if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND))
+ if (!desc->action || (desc->action->flags & IRQF_NO_SUSPEND)
+ || irqd_has_set(&desc->irq_data, IRQD_WAKEUP_STATE))
return;
desc->istate |= IRQS_SUSPENDED;
}
^ permalink raw reply
* Re: [Linuxwacom-devel] [PATCH 00/15] Input - Wacom: switch from an USB to a HID driver
From: Przemo Firszt @ 2014-07-10 21:30 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Jason Gerecke,
linuxwacom-devel, linux-kernel, linux-input
In-Reply-To: <1404163586-29582-1-git-send-email-benjamin.tissoires@redhat.com>
Hi Benjamin,
I'm having some problems to cleanly apply your patches - can you double
check that they are OK?
--
Regards,
Przemo
^ permalink raw reply
* Re: [PATCH 0/5] Input - wacom: battery enhancements and unifying hid-wacom and wacom
From: Przemo Firszt @ 2014-07-10 21:14 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Jason Gerecke,
linux-kernel, linux-input
In-Reply-To: <1405017900-16024-1-git-send-email-benjamin.tissoires@redhat.com>
Dnia 2014-07-10, czw o godzinie 14:44 -0400, Benjamin Tissoires pisze:
[..]
Hi Benjamin,
> However, I did not backport the speed attribute and the ac power
> device (which
> is infered by the battery status). I don't know if there are users of
> those two,
> so I let them aside for now. Przemo, any ideas if this is actually
> used?
Both tablets that I had (Graphire Wireless and Intuos4 Wireless)
supports slow and fast reporting. Slow reporting is necessary with older
bluetooth receivers otherwise the lag between pen movement and cursor
movement made devices unusable.
I tried to expose all events reported by hardware and I think AC
reporting should stay in the kernel.
Intuos4 Wireless
AC power disconnected:
bash-4.2$ cat /sys/class/power_supply/wacom_ac/uevent
POWER_SUPPLY_NAME=wacom_ac
POWER_SUPPLY_PRESENT=0
POWER_SUPPLY_ONLINE=0
POWER_SUPPLY_SCOPE=Device
bash-4.2$ cat /sys/class/power_supply/wacom_battery/uevent
POWER_SUPPLY_NAME=wacom_battery
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_CAPACITY=85
POWER_SUPPLY_SCOPE=Device
POWER_SUPPLY_STATUS=Discharging
AC power connected:
bash-4.2$ cat /sys/class/power_supply/wacom_ac/uevent
POWER_SUPPLY_NAME=wacom_ac
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_ONLINE=1
POWER_SUPPLY_SCOPE=Device
bash-4.2$ cat /sys/class/power_supply/wacom_battery/uevent
POWER_SUPPLY_NAME=wacom_battery
POWER_SUPPLY_PRESENT=1
POWER_SUPPLY_CAPACITY=85
POWER_SUPPLY_SCOPE=Device
POWER_SUPPLY_STATUS=Charging
--
Kind regards,
Przemo Firszt
^ permalink raw reply
* Re: [PATCH 08/15] Input - wacom: remove usb dependency for siblings devices
From: Jason Gerecke @ 2014-07-11 0:10 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Linux Input,
linux-kernel, linuxwacom-devel
In-Reply-To: <1404163586-29582-9-git-send-email-benjamin.tissoires@redhat.com>
On Mon, Jun 30, 2014 at 2:26 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> Wacom tablets can share different physical sensors on one physical device.
> These are called siblings in the code. The current way of implementation
> relies on the USB topology to be able to share data amongs those sensors.
>
> We can replace the code to match a HID subsystem, without involving the USB
> topology:
> - the first probed sensor does not find any siblings in the list
> wacom_udev_list, so it creates its own wacom_hdev_data with its own
> struct hid_device
> - the other sensor checks the current list of siblings in wacom_hdev_data,
> and if there is a match, it associates itself to the matched device.
>
> To be sure that we are not associating different sensors from different
> physical devices, we also check for the phys path of the hid device which
> contains the USB topology.
>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> ---
> drivers/input/tablet/wacom_sys.c | 75 +++++++++++++++++++---------------------
> 1 file changed, 35 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
> index 0d0397d..6fe7a6c 100644
> --- a/drivers/input/tablet/wacom_sys.c
> +++ b/drivers/input/tablet/wacom_sys.c
> @@ -488,46 +488,45 @@ static int wacom_retrieve_hid_descriptor(struct hid_device *hdev,
> return error;
> }
>
> -struct wacom_usbdev_data {
> +struct wacom_hdev_data {
> struct list_head list;
> struct kref kref;
> - struct usb_device *dev;
> + struct hid_device *dev;
> struct wacom_shared shared;
> };
>
> static LIST_HEAD(wacom_udev_list);
> static DEFINE_MUTEX(wacom_udev_list_lock);
>
> -static struct usb_device *wacom_get_sibling(struct usb_device *dev, int vendor, int product)
> +static bool wacom_are_sibling(struct hid_device *hdev,
> + struct hid_device *sibling)
> {
> - int port1;
> - struct usb_device *sibling;
> -
> - if (vendor == 0 && product == 0)
> - return dev;
> -
> - if (dev->parent == NULL)
> - return NULL;
> -
> - usb_hub_for_each_child(dev->parent, port1, sibling) {
> - struct usb_device_descriptor *d;
> - if (sibling == NULL)
> - continue;
> + struct wacom *wacom = hid_get_drvdata(hdev);
> + struct wacom_features *features = &wacom->wacom_wac.features;
> + int vid = features->oVid;
> + int pid = features->oPid;
>
> - d = &sibling->descriptor;
> - if (d->idVendor == vendor && d->idProduct == product)
> - return sibling;
> + if (vid == 0 && pid == 0) {
> + vid = hdev->vendor;
> + pid = hdev->product;
> }
>
> - return NULL;
> + if (vid != sibling->vendor || pid != sibling->product)
> + return false;
> +
> + /*
> + * Compare the physical path.
> + * Dump the last two chars which should contain the input number.
> + */
> + return !strncmp(hdev->phys, sibling->phys, strlen(hdev->phys) - 2);
Good idea, but this implementation doesn't work. "Siblings" (such as
you'd find on a 24HDT) are separate USB devices but share the same USB
hub. Trimming off just the input number isn't sufficient since the USB
path preceding it is going to be different for the two devices. For
example, I the touch and pen interfaces on my 24HDT show up as
"usb-0000:00:1d.0-1.4.3/input0" and "usb-0000:00:1d.0-1.4.2/input1".
Something like the following could work though:
int n1 = strrchr(hdev->phys, '.') - hdev->phys;
int n2 = strrchr(sibling->phys, '.') - sibling->phys;
if (n1 != n2 || n1 <= 0 || n2 <= 0)
return false;
else
return !strncmp(hdev->phys, sibling->phys, n1);
Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
> }
>
> -static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
> +static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
> {
> - struct wacom_usbdev_data *data;
> + struct wacom_hdev_data *data;
>
> list_for_each_entry(data, &wacom_udev_list, list) {
> - if (data->dev == dev) {
> + if (wacom_are_sibling(hdev, data->dev)) {
> kref_get(&data->kref);
> return data;
> }
> @@ -536,28 +535,29 @@ static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
> return NULL;
> }
>
> -static int wacom_add_shared_data(struct wacom_wac *wacom,
> - struct usb_device *dev)
> +static int wacom_add_shared_data(struct hid_device *hdev)
> {
> - struct wacom_usbdev_data *data;
> + struct wacom *wacom = hid_get_drvdata(hdev);
> + struct wacom_wac *wacom_wac = &wacom->wacom_wac;
> + struct wacom_hdev_data *data;
> int retval = 0;
>
> mutex_lock(&wacom_udev_list_lock);
>
> - data = wacom_get_usbdev_data(dev);
> + data = wacom_get_hdev_data(hdev);
> if (!data) {
> - data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL);
> + data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
> if (!data) {
> retval = -ENOMEM;
> goto out;
> }
>
> kref_init(&data->kref);
> - data->dev = dev;
> + data->dev = hdev;
> list_add_tail(&data->list, &wacom_udev_list);
> }
>
> - wacom->shared = &data->shared;
> + wacom_wac->shared = &data->shared;
>
> out:
> mutex_unlock(&wacom_udev_list_lock);
> @@ -566,8 +566,8 @@ out:
>
> static void wacom_release_shared_data(struct kref *kref)
> {
> - struct wacom_usbdev_data *data =
> - container_of(kref, struct wacom_usbdev_data, kref);
> + struct wacom_hdev_data *data =
> + container_of(kref, struct wacom_hdev_data, kref);
>
> mutex_lock(&wacom_udev_list_lock);
> list_del(&data->list);
> @@ -578,10 +578,10 @@ static void wacom_release_shared_data(struct kref *kref)
>
> static void wacom_remove_shared_data(struct wacom_wac *wacom)
> {
> - struct wacom_usbdev_data *data;
> + struct wacom_hdev_data *data;
>
> if (wacom->shared) {
> - data = container_of(wacom->shared, struct wacom_usbdev_data, shared);
> + data = container_of(wacom->shared, struct wacom_hdev_data, shared);
> kref_put(&data->kref, wacom_release_shared_data);
> wacom->shared = NULL;
> }
> @@ -1311,8 +1311,6 @@ static int wacom_probe(struct hid_device *hdev,
> "%s Pad", features->name);
>
> if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
> - struct usb_device *other_dev;
> -
> /* Append the device type to the name */
> if (features->device_type != BTN_TOOL_FINGER)
> strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
> @@ -1321,10 +1319,7 @@ static int wacom_probe(struct hid_device *hdev,
> else
> strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
>
> - other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);
> - if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
> - other_dev = dev;
> - error = wacom_add_shared_data(wacom_wac, other_dev);
> + error = wacom_add_shared_data(hdev);
> if (error)
> goto fail1;
> }
> --
> 2.0.0
>
--
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
* Re: [PATCH 1/5] Input - wacom: create a separate input device for pads
From: Jason Gerecke @ 2014-07-11 0:18 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Ping Cheng, Linux Input, linux-kernel,
linuxwacom-devel
In-Reply-To: <1403557039-1487-2-git-send-email-benjamin.tissoires@redhat.com>
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.
>
> 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.
>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
> ---
> drivers/input/tablet/wacom.h | 2 ++
> drivers/input/tablet/wacom_sys.c | 63 +++++++++++++++++++++++++++++++++++-----
> drivers/input/tablet/wacom_wac.c | 27 ++++++++++++++++-
> drivers/input/tablet/wacom_wac.h | 2 ++
> 4 files changed, 85 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
> index 9ebf0ed..caa59ca 100644
> --- a/drivers/input/tablet/wacom.h
> +++ b/drivers/input/tablet/wacom.h
> @@ -136,4 +136,6 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
> void wacom_setup_device_quirks(struct wacom_features *features);
> int wacom_setup_input_capabilities(struct input_dev *input_dev,
> struct wacom_wac *wacom_wac);
> +int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
> + struct wacom_wac *wacom_wac);
> #endif
> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
> index c993eee..b9bf37e 100644
> --- a/drivers/input/tablet/wacom_sys.c
> +++ b/drivers/input/tablet/wacom_sys.c
> @@ -135,6 +135,9 @@ static int wacom_open(struct input_dev *dev)
>
> mutex_lock(&wacom->lock);
>
> + if (wacom->open)
> + goto out;
> +
> if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
> retval = -EIO;
> goto out;
> @@ -157,9 +160,14 @@ static void wacom_close(struct input_dev *dev)
> autopm_error = usb_autopm_get_interface(wacom->intf);
>
> mutex_lock(&wacom->lock);
> + if (!wacom->open)
> + goto out;
> +
> usb_kill_urb(wacom->irq);
> wacom->open = false;
> wacom->intf->needs_remote_wakeup = 0;
> +
> +out:
> mutex_unlock(&wacom->lock);
>
> if (!autopm_error)
> @@ -1109,19 +1117,16 @@ static void wacom_destroy_battery(struct wacom *wacom)
> }
> }
>
> -static int wacom_register_input(struct wacom *wacom)
> +static struct input_dev *wacom_allocate_input(struct wacom *wacom)
> {
> struct input_dev *input_dev;
> struct usb_interface *intf = wacom->intf;
> struct usb_device *dev = interface_to_usbdev(intf);
> struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
> - int error;
>
> input_dev = input_allocate_device();
> - if (!input_dev) {
> - error = -ENOMEM;
> - goto fail1;
> - }
> + if (!input_dev)
> + return NULL;
>
> input_dev->name = wacom_wac->name;
> input_dev->phys = wacom->phys;
> @@ -1131,21 +1136,59 @@ static int wacom_register_input(struct wacom *wacom)
> usb_to_input_id(dev, &input_dev->id);
> input_set_drvdata(input_dev, wacom);
>
> + return input_dev;
> +}
> +
> +static int wacom_register_input(struct wacom *wacom)
> +{
> + struct input_dev *input_dev, *pad_input_dev;
> + struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
> + int error;
> +
> + input_dev = wacom_allocate_input(wacom);
> + pad_input_dev = wacom_allocate_input(wacom);
> + if (!input_dev || !pad_input_dev) {
> + error = -ENOMEM;
> + goto fail1;
> + }
> +
> wacom_wac->input = input_dev;
> + wacom_wac->pad_input = pad_input_dev;
> + wacom_wac->pad_input->name = wacom_wac->pad_name;
> +
> error = wacom_setup_input_capabilities(input_dev, wacom_wac);
> if (error)
> - goto fail1;
> + goto fail2;
>
> error = input_register_device(input_dev);
> if (error)
> goto fail2;
>
> + error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
> + if (error) {
> + /* no pad in use on this interface */
> + input_free_device(pad_input_dev);
> + wacom_wac->pad_input = NULL;
> + pad_input_dev = NULL;
> + } else {
> + error = input_register_device(pad_input_dev);
> + if (error)
> + goto fail3;
> + }
> +
> return 0;
>
> +fail3:
> + input_unregister_device(input_dev);
> + input_dev = NULL;
> fail2:
> - input_free_device(input_dev);
> wacom_wac->input = NULL;
> + wacom_wac->pad_input = NULL;
> fail1:
> + if (input_dev)
> + input_free_device(input_dev);
> + if (pad_input_dev)
> + input_free_device(pad_input_dev);
> return error;
> }
>
> @@ -1364,6 +1407,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
> wacom_calculate_res(features);
>
> strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
> + snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
> + "%s Pad", features->name);
This may cause some heartburn for some users that have xsetwacom
scripts (or use similar tools that need a device name). Our X driver
already appends a " pad" suffix to the device name, so this results in
X devices now having the double-suffix " Pad pad". I agree with adding
the suffix here though, so I think I'll write a patch to fix this in
xf86-input-wacom.
Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
>
> if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
> struct usb_device *other_dev;
> @@ -1438,6 +1483,8 @@ static void wacom_disconnect(struct usb_interface *intf)
> cancel_work_sync(&wacom->work);
> if (wacom->wacom_wac.input)
> input_unregister_device(wacom->wacom_wac.input);
> + if (wacom->wacom_wac.pad_input)
> + input_unregister_device(wacom->wacom_wac.pad_input);
> wacom_destroy_battery(wacom);
> wacom_destroy_leds(wacom);
> usb_free_urb(wacom->irq);
> diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
> index 977d05c..4b16a34 100644
> --- a/drivers/input/tablet/wacom_wac.c
> +++ b/drivers/input/tablet/wacom_wac.c
> @@ -1489,8 +1489,11 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
> break;
> }
>
> - if (sync)
> + if (sync) {
> input_sync(wacom_wac->input);
> + if (wacom_wac->pad_input)
> + input_sync(wacom_wac->pad_input);
> + }
> }
>
> static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
> @@ -1939,6 +1942,28 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
> return 0;
> }
>
> +int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
> + struct wacom_wac *wacom_wac)
> +{
> + struct wacom_features *features = &wacom_wac->features;
> +
> + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
> +
> + /* kept for making legacy xf86-input-wacom working with the wheels */
> + __set_bit(ABS_MISC, input_dev->absbit);
> +
> + /* kept for making legacy xf86-input-wacom accepting the pad */
> + input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
> + input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
> +
> + switch (features->type) {
> + default:
> + /* no pad supported */
> + return 1;
> + }
> + return 0;
> +}
> +
> static const struct wacom_features wacom_features_0x00 =
> { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255,
> 0, PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
> diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
> index b2c9a9c..f48164c 100644
> --- a/drivers/input/tablet/wacom_wac.h
> +++ b/drivers/input/tablet/wacom_wac.h
> @@ -150,6 +150,7 @@ struct wacom_shared {
>
> struct wacom_wac {
> char name[WACOM_NAME_MAX];
> + char pad_name[WACOM_NAME_MAX];
> unsigned char *data;
> int tool[2];
> int id[2];
> @@ -157,6 +158,7 @@ struct wacom_wac {
> struct wacom_features features;
> struct wacom_shared *shared;
> struct input_dev *input;
> + struct input_dev *pad_input;
> int pid;
> int battery_capacity;
> int num_contacts_left;
> --
> 1.9.0
>
--
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
* Re: [PATCH 05/15] Input - wacom: compute the HID report size to get the actual packet size
From: Jason Gerecke @ 2014-07-11 1:09 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Linux Input,
linux-kernel, linuxwacom-devel
In-Reply-To: <1404163586-29582-6-git-send-email-benjamin.tissoires@redhat.com>
On Mon, Jun 30, 2014 at 2:26 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> This removes an USB dependency and is more accurate: the computed pktlen
> is the actual maximum size of the reports forwarded by the device.
>
> Given that the pktlen is correctly computed/validated, we can store it now
> in the features struct instead of having a special handling in the rest of
> the code.
>
> Likewise, this information is not mandatory anymore in the description
> of devices in wacom_wac.c. They will be removed in a separate patch.
>
> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
I'm concerned this new function could be fooled if we release a tablet
that has one report which is longer than the desired report, but none
of the hardware I tested was like this and it would be fairly easy to
address even if it did happen. Thought I should mention it though.
Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
> ---
> drivers/input/tablet/wacom_sys.c | 58 ++++++++++++++++++----------------------
> 1 file changed, 26 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
> index cd3d936..3f1cee6 100644
> --- a/drivers/input/tablet/wacom_sys.c
> +++ b/drivers/input/tablet/wacom_sys.c
> @@ -149,7 +149,6 @@ static int wacom_parse_logical_collection(unsigned char *report,
> if (features->type == BAMBOO_PT) {
>
> /* Logical collection is only used by 3rd gen Bamboo Touch */
> - features->pktlen = WACOM_PKGLEN_BBTOUCH3;
> features->device_type = BTN_TOOL_FINGER;
>
> features->x_max = features->y_max =
> @@ -240,29 +239,6 @@ static int wacom_parse_hid(struct hid_device *hdev,
> features->device_type = BTN_TOOL_FINGER;
> /* touch device at least supports one touch point */
> touch_max = 1;
> - switch (features->type) {
> - case TABLETPC2FG:
> - features->pktlen = WACOM_PKGLEN_TPC2FG;
> - break;
> -
> - case MTSCREEN:
> - case WACOM_24HDT:
> - features->pktlen = WACOM_PKGLEN_MTOUCH;
> - break;
> -
> - case MTTPC:
> - case MTTPC_B:
> - features->pktlen = WACOM_PKGLEN_MTTPC;
> - break;
> -
> - case BAMBOO_PT:
> - features->pktlen = WACOM_PKGLEN_BBTOUCH;
> - break;
> -
> - default:
> - features->pktlen = WACOM_PKGLEN_GRAPHIRE;
> - break;
> - }
>
> switch (features->type) {
> case BAMBOO_PT:
> @@ -305,8 +281,6 @@ static int wacom_parse_hid(struct hid_device *hdev,
> }
> } else if (pen) {
> /* penabled only accepts exact bytes of data */
> - if (features->type >= TABLETPC)
> - features->pktlen = WACOM_PKGLEN_GRAPHIRE;
> features->device_type = BTN_TOOL_PEN;
> features->x_max =
> get_unaligned_le16(&report[i + 3]);
> @@ -1227,12 +1201,34 @@ static void wacom_calculate_res(struct wacom_features *features)
> features->unitExpo);
> }
>
> +static int wacom_hid_report_len(struct hid_report *report)
> +{
> + /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
> + return ((report->size - 1) >> 3) + 1 + (report->id > 0);
> +}
> +
> +static size_t wacom_compute_pktlen(struct hid_device *hdev)
> +{
> + struct hid_report_enum *report_enum;
> + struct hid_report *report;
> + size_t size = 0;
> +
> + report_enum = hdev->report_enum + HID_INPUT_REPORT;
> +
> + list_for_each_entry(report, &report_enum->report_list, list) {
> + size_t report_size = wacom_hid_report_len(report);
> + if (report_size > size)
> + size = report_size;
> + }
> +
> + return size;
> +}
> +
> static int wacom_probe(struct hid_device *hdev,
> const struct hid_device_id *id)
> {
> struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
> struct usb_device *dev = interface_to_usbdev(intf);
> - struct usb_endpoint_descriptor *endpoint;
> struct wacom *wacom;
> struct wacom_wac *wacom_wac;
> struct wacom_features *features;
> @@ -1258,6 +1254,7 @@ static int wacom_probe(struct hid_device *hdev,
> wacom_wac = &wacom->wacom_wac;
> wacom_wac->features = *((struct wacom_features *)id->driver_data);
> features = &wacom_wac->features;
> + features->pktlen = wacom_compute_pktlen(hdev);
> if (features->pktlen > WACOM_PKGLEN_MAX) {
> error = -EINVAL;
> goto fail1;
> @@ -1275,8 +1272,6 @@ static int wacom_probe(struct hid_device *hdev,
> usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
> strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
>
> - endpoint = &intf->cur_altsetting->endpoint[0].desc;
> -
> /* set the default size in case we do not get them from hid */
> wacom_set_default_phy(features);
>
> @@ -1287,13 +1282,12 @@ static int wacom_probe(struct hid_device *hdev,
>
> /*
> * Intuos5 has no useful data about its touch interface in its
> - * HID descriptor. If this is the touch interface (wMaxPacketSize
> + * HID descriptor. If this is the touch interface (PacketSize
> * of WACOM_PKGLEN_BBTOUCH3), override the table values.
> */
> if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
> - if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
> + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
> features->device_type = BTN_TOOL_FINGER;
> - features->pktlen = WACOM_PKGLEN_BBTOUCH3;
>
> features->x_max = 4096;
> features->y_max = 4096;
> --
> 2.0.0
>
--
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
* Re: [PATCH 00/15] Input - Wacom: switch from an USB to a HID driver
From: Jason Gerecke @ 2014-07-11 1:17 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Jiri Kosina, Ping Cheng, Linux Input,
linux-kernel, linuxwacom-devel
In-Reply-To: <CANRwn3S9NwAET06sttcniN2391fY5+W-ZGAmvOqr1c_6AJ=J6g@mail.gmail.com>
On Wed, Jul 2, 2014 at 4:33 PM, Jason Gerecke <killertofu@gmail.com> wrote:
> On Mon, Jun 30, 2014 at 2:26 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
>> Hi guys,
>>
>> this patch series is a cleanup for the Wacom USB driver.
>>
>> I started working on this topic when I saw patches floating around which
>> implemented a report descriptor parser within the wacom.ko module.
>> However, we already have a nice HID subsystem which is more generic than the
>> HID implementation we can find in this USB driver.
>> Further details of the benefits (code reduction, regression tests) are hopefully
>> explained in the commit messages of the corresponding patches.
>>
>> Also, I am working on a way to handle the new Wacom tablets in a more generic
>> way in the hid tree, so consider this patch series as a first step in this
>> direction.
>>
>> This patch series transfers the wacom.ko driver from the input tree into the hid
>> tree. I did not made the corresponding move of the files in the series hoping
>> that we will find a way to achieve it if this step is validated.
>>
>> IMO, the smoothest path would be that Jiri takes care of the wacom driver
>> in the input tree (and that we move into into the hid subfolder). This can be
>> achieve if the current pending wacom patches are applied in the hid tree too.
>>
>> Another solution could be to keep the wacom changes in the input tree and put the
>> hid changes in the hid tree by using separate commits. Once 3.17 is out, we can
>> then change the module into the hid subfolder.
>>
>> I wanted to send this patch series right now so we can figure out how we will
>> handle the transition.
>>
>> I am pretty confident the patch series does not break any existing device
>> (except for the required user space changes which can be handled correctly if
>> we tackle them right now). The USB commands are executed in the same way,
>> and the protocol handling is also done in the same way.
>>
>> Anyway, the net difference in lines of code (-307) should be enough to be of
>> interest.
>>
>> Note: This patch series requires the current pending wacom patches to be applied.
>> I set up a tree with all the patch applied if anyone wants to give a try:
>> https://github.com/bentiss/linux/commits/hid-wacom-legacy-3.16-rc3
>>
>> Cheers,
>> Benjamin
>>
>> Benjamin Tissoires (15):
>> Input - wacom: include and use linux/hid.h
>> Input - wacom: switch from an USB driver to a HID driver
>> Input - wacom: use hid communication instead of plain usb
>> Input - wacom: use HID core to actually fetch the report descriptor
>> Input - wacom: compute the HID report size to get the actual packet
>> size
>> Input - wacom: install LED/OLED sysfs files in the HID device instead
>> of USB
>> Input - wacom: register the input devices on top of the HID one
>> Input - wacom: remove usb dependency for siblings devices
>> Input - wacom: register power device at the HID level
>> Input - wacom: use hid_info instead of plain dev_info
>> HID: uhid: add and set HID_TYPE_UHID for uhid devices
>> Input - wacom: use in-kernel HID parser
>> Input - wacom: use hidinput_calc_abs_res instead of duplicating its
>> code
>> Input - wacom: remove field pktlen declaration in the list of devices
>> Input - wacom: keep wacom_ids ordered
>>
>> drivers/hid/hid-core.c | 15 +-
>> drivers/hid/hid-wacom.c | 2 +-
>> drivers/hid/uhid.c | 2 +
>> drivers/input/tablet/wacom.h | 7 +-
>> drivers/input/tablet/wacom_sys.c | 908 +++++++++++++--------------------------
>> drivers/input/tablet/wacom_wac.c | 647 ++++++++++++++--------------
>> drivers/input/tablet/wacom_wac.h | 10 +-
>> include/linux/hid.h | 4 +-
>> 8 files changed, 644 insertions(+), 951 deletions(-)
>>
>> --
>> 2.0.0
>>
>
> *cracks knuckles*
>
> Well, guess I better get to work poking and prodding at these and the
> pad patches. A very quick review doesn't raise any significant flags,
> though I do have a question or two that I might have for you in the
> next few days (need to read through the code more carefully to be sure
> I understand it correctly). My 24HDT is having some trouble
> initializing with the patches applied, but I'll need some time to
> track down the cause. Not sure how much I'll get done this week
> (holiday weekend) but next week I should have some feedback.
>
> Jason
> ---
> Now instead of four in the eights place /
> you’ve got three, ‘Cause you added one /
> (That is to say, eight) to the two, /
> But you can’t take seven from three, /
> So you look at the sixty-fours....
I've had a chance to try out a dozen tablets with these modifications
and for the most part things seem to work fine. The 24HDT issue I
mentioned above was due to a conflict with some other patches I was
testing and can be ignored. Aside from the other known issues you've
already mentioned (and my inline comments), there's not much that I
can say (other than that I found some odd [but apparently unrelated]
issues with wacom_w8001 and isdv4-serial-inputattach...)
Reviewed-by: Jason Gerecke <killertofu@gmail.com>
Tested-by: Jason Gerecke <killertofu@gmail.com>
Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
--
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
* Re: [PATCH 0/5] Input - wacom: split out pad data from the stylus input device
From: Jason Gerecke @ 2014-07-11 1:21 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Dmitry Torokhov, Ping Cheng, Linux Input, linux-kernel,
linuxwacom-devel
In-Reply-To: <1403557039-1487-1-git-send-email-benjamin.tissoires@redhat.com>
On Mon, Jun 23, 2014 at 1:57 PM, Benjamin Tissoires
<benjamin.tissoires@redhat.com> wrote:
> Hi,
>
> This patch series aims at simplifying the handling of Wacom devices from the user
> space point of view. As mentioned in the commit message from 1/5, the pad data
> are interleaved into the stylus input for some devices, and into the touch input
> for others.
>
> It doesn't makes real sense to interleave pad with stylus because pad data are
> not linked to the absolute position of a stylus (or its presence). It is a
> device by itself which should have its own input node.
>
> It will also help the handling of the old Wacom Graphire 4 which shares its
> BTN_LEFT and BTN_RIGHT in its pad and in the mouse.
>
> Again, it's not a problem right now because the user space is currently dealing
> with it, but for the Wayland libinput implementation, having something clear
> will really help.
>
> This patch series does not break current X11 behavior, the only change from the
> user will be that an input device will appear as "Wacom ... Pad pad".
>
> I tried to test/debug it as extensively as possible, but I do not guarantee any
> mistake :(
>
> Tested on:
> - Bamboo 16FG 4x5
> - Bamboo 2FG
> - BambooFun 4x5
> - Bamboo
> - Cintiq 12WX
> - Cintiq 21UX2
> - Cintiq 21UX
> - Cintiq 22HD
> - Cintiq 22HDT
> - Cintiq 24HD
> - DTU2231
> - Graphire3
> - Intuos3 9x12
> - Intuos4 WL
> - Intuos5 touch M
> - Intuos Pro S
>
> Note: this patch series might requesting to apply the patch for input->phys
> I just sent:
> https://patchwork.kernel.org/patch/4404391/
>
>
> Cheers,
> Benjamin
>
> Benjamin Tissoires (5):
> Input - wacom: create a separate input device for pads
> Input - wacom: split out the pad device for Intuos/Cintiq
> Input - wacom: split out the pad device for Bamboos
> Input - wacom: split out the pad device for DTUS
> Input - wacom: split out the pad device for Graphire G4 and MO
>
> drivers/input/tablet/wacom.h | 2 +
> drivers/input/tablet/wacom_sys.c | 63 +++++++-
> drivers/input/tablet/wacom_wac.c | 328 ++++++++++++++++++++++++---------------
> drivers/input/tablet/wacom_wac.h | 2 +
> 4 files changed, 259 insertions(+), 136 deletions(-)
>
> --
> 1.9.0
>
These look fine to me as well (aside from the one minor comment):
Reviewed-by: Jason Gerecke <killertofu@gmail.com>
Jason
---
Now instead of four in the eights place /
you’ve got three, ‘Cause you added one /
(That is to say, eight) to the two, /
But you can’t take seven from three, /
So you look at the sixty-fours....
--
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
* Re: [PATCH] Input: Add Acer Aspire 5710 to nomux blacklist
From: Hans de Goede @ 2014-07-11 7:10 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Vojtech Pavlik, Jiri Kosina, linux-input
In-Reply-To: <20140710211113.GB37059@core.coreip.homeip.net>
Hi,
On 07/10/2014 11:11 PM, Dmitry Torokhov wrote:
<snip>
>>> I'm not aware of any current machines using active multiplexing for
>>> that. There are basically two touchpad manufacturers: Synaptics and
>>> ALPS.
>>
>> And elantech
>>
>>> Synaptics has a nearly transparent passthrough mode and
>>> touchpoints are connected through that. ALPS basically manufactures a
>>> touchpad+touchpoint combo device and thus doesn't need a fully
>>> transparent passthrough.
>>
>> Elantech now a days also produces a combo like alps.
>
> They still wire it up internally and route all data through AUX port and
> not use active MUX for that.
Right, that is what I was trying to say with "like alps", sorry if that
was not clear. This was not meant as an argument against changing the
nomux default, just meant to complete the list.
<offtopic>
BTW while completing the list, there now is a new player called Focaltech,
used at least in the Asus X450 and Asus X550. These new devices don't
even work in mouse emulation mode unless psmouse.proto=bare is used.
I'm working on a pnp-id based patch to detect this and switch to
psmouse.proto=bare before we upset them (no idea about the native protocol)
Although native support would be better of course, so if anyone has a
contact at Focaltech that would be great.
But for some reason my patch ain't working. I'll send it upstream as soon
as I've worked out the kinks, this is being tracked here:
https://bugzilla.redhat.com/show_bug.cgi?id=1110011
</offtopic>
<snip>
>> One of the nice things about Linux is that in general we've pretty
>> decent support for older hardware, so if we decide to flip the nomux
>> default, I think we should really do so based on some BIOS cut-off
>> date, so as to not break older model laptops.
>
> I think historically IBM and HPs had working MUX support while other's
> did might advertise support and fail miserably when we would try
> activating it.
>
> Given that now majority of mice are USB even if we select wrong default
> on some older box I think it would be acceptable as opposed to a newer
> box not having touchpad at all...
I'm still not 100% sure if having some curt-off date would not be better,
but if you prefer just flipping the default everywhere lets go for that.
<semi-random-related-idea>
I guess that for anything except really really old boxes, the ps/2
will be part of the superio chip. super-io chips are relatively
easy to identify / probe in a safe manner. So do you know if the
ps/2 muxing is usually part of the super-io, or if it is an
extra chip?
If it is part of the superio then building a whitelist based on
superio ids may be an idea (once we get whitelist requests).
</semi-random-related-idea>
Regards,
Hans
^ permalink raw reply
* [PATCH] Input: Add driver for Microchip's CAP1106
From: Daniel Mack @ 2014-07-11 7:42 UTC (permalink / raw)
To: dtor; +Cc: linux-input, broonie, devicetree, Daniel Mack
This patch adds a driver for Microchips CAP1106, an I2C driven, 6-channel
capacitive touch sensor.
For now, only the capacitive buttons are supported, and no specific
settings that can be tweaked for individual channels, except for the
device-wide sensitivity gain. The defaults seem to work just fine out of
the box, so I'll leave configurable parameters for someone who's in need
of them and who can actually measure the impact. All registers are
prepared, however. Many of them are just not used for now.
The implementation does not make any attempt to be compatible to platform
data driven boards, but fully depends on CONFIG_OF.
Power management functions are also left for volounteers with the ability
to actually test them.
Signed-off-by: Daniel Mack <zonque@gmail.com>
---
.../devicetree/bindings/input/cap1106.txt | 63 ++++
drivers/input/keyboard/Kconfig | 10 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/cap1106.c | 376 +++++++++++++++++++++
4 files changed, 450 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/cap1106.txt
create mode 100644 drivers/input/keyboard/cap1106.c
diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt
new file mode 100644
index 0000000..57f5af3
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/cap1106.txt
@@ -0,0 +1,63 @@
+Device tree bindings for Microchip CAP1106, 6 channel capacitive touch sensor
+
+The node for this driver must be a child of a I2C controller node, as the
+device communication via I2C only.
+
+Required properties:
+
+ compatible: Must be "microchip,cap1106"
+ reg: The I2C slave address of the device.
+ Only 0x28 is valid.
+ interrupt: Node describing the interrupt line the device's
+ ALERT#/CM_IRQ# pin is connected to.
+
+Optional properties:
+
+ autorepeat: Enables the Linux input system's autorepeat
+ feature on the input device.
+ microchip,sensor-gain: Defines the gain of the sensor circuitry. This
+ effectively controls the sensitivity, as a
+ smaller delta capacitance is required to
+ generate the same delta count values.
+ Valid values are 1, 2, 4, and 8.
+ By default, a gain of 1 is set.
+
+To define details of each individual button channel, six subnodes can be
+specified. Inside each of those, the following property is valid:
+
+ linux,keycode: Specify the numeric identifier of the keycode to be
+ generated when this channel is activated. If this
+ property is omitted, KEY_A, KEY_B, etc are used as
+ defaults.
+
+Example:
+
+i2c_controller {
+ cap1106@28 {
+ compatible = "microchip,cap1106";
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 0>;
+ reg = <0x28>;
+ autorepeat;
+ microchip,sensor-gain = <2>;
+
+ up {
+ linux,keycode = <103>; /* KEY_UP */
+ };
+ right {
+ linux,keycode = <106>; /* KEY_RIGHT */
+ };
+ down {
+ linux,keycode = <108>; /* KEY_DOWN */
+ };
+ left {
+ linux,keycode = <105>; /* KEY_LEFT */
+ };
+ pagedown {
+ linux,keycode = <109>; /* KEY_PAGEDOWN */
+ };
+ pageup {
+ linux,keycode = <104>; /* KEY_PAGEUP */
+ };
+ };
+}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f7e79b4..a3958c6 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -665,4 +665,14 @@ config KEYBOARD_CROS_EC
To compile this driver as a module, choose M here: the
module will be called cros_ec_keyb.
+config KEYBOARD_CAP1106
+ tristate "Microchip CAP1106 touch sensor"
+ depends on OF && I2C
+ select REGMAP_I2C
+ help
+ Say Y here to enable the CAP1106 touch sensor driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cap1106.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 7504ae1..0a33456 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
+obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c
new file mode 100644
index 0000000..ad0f0fb
--- /dev/null
+++ b/drivers/input/keyboard/cap1106.c
@@ -0,0 +1,376 @@
+/*
+ * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor
+ *
+ * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106
+ *
+ * (c) 2014 Daniel Mack <linux@zonque.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/gpio/consumer.h>
+
+#define CAP1106_REG_MAIN_CONTROL 0x00
+#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6)
+#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
+#define CAP1106_REG_MAIN_CONTROL_DLSEEP BIT(4)
+#define CAP1106_REG_GENERAL_STATUS 0x02
+#define CAP1106_REG_SENSOR_INPUT 0x03
+#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a
+#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X))
+#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f
+#define CAP1106_REG_CONFIG 0x20
+#define CAP1106_REG_SENSOR_ENABLE 0x21
+#define CAP1106_REG_SENSOR_CONFIG 0x22
+#define CAP1106_REG_SENSOR_CONFIG2 0x23
+#define CAP1106_REG_SAMPLING_CONFIG 0x24
+#define CAP1106_REG_CALIBRATION 0x25
+#define CAP1106_REG_INT_ENABLE 0x26
+#define CAP1106_REG_REPEAT_RATE 0x28
+#define CAP1106_REG_MT_CONFIG 0x2a
+#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
+#define CAP1106_REG_MT_PATTERN 0x2d
+#define CAP1106_REG_RECALIB_CONFIG 0x2f
+#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X))
+#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38
+#define CAP1106_REG_STANDBY_CHANNEL 0x40
+#define CAP1106_REG_STANDBY_CONFIG 0x41
+#define CAP1106_REG_STANDBY_SENSITIVITY 0x42
+#define CAP1106_REG_STANDBY_THRESH 0x43
+#define CAP1106_REG_CONFIG2 0x44
+#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
+#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X))
+#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9
+#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba
+#define CAP1106_REG_PRODUCT_ID 0xfd
+#define CAP1106_REG_MANUFACTURER_ID 0xfe
+#define CAP1106_REG_REVISION 0xff
+
+#define CAP1106_NUM_CHN 6
+#define CAP1106_PRODUCT_ID 0x55
+#define CAP1106_MANUFACTURER_ID 0x5d
+
+struct cap1106_priv {
+ struct regmap *regmap;
+ struct input_dev *idev;
+ struct work_struct work;
+ spinlock_t lock;
+ int irq;
+
+ /* config */
+ unsigned int keycodes[CAP1106_NUM_CHN];
+};
+
+static const struct reg_default cap1106_reg_defaults[] = {
+ { CAP1106_REG_MAIN_CONTROL, 0x00 },
+ { CAP1106_REG_GENERAL_STATUS, 0x00 },
+ { CAP1106_REG_SENSOR_INPUT, 0x00 },
+ { CAP1106_REG_NOISE_FLAG_STATUS, 0x00 },
+ { CAP1106_REG_SENSITIVITY_CONTROL, 0x2f },
+ { CAP1106_REG_CONFIG, 0x20 },
+ { CAP1106_REG_SENSOR_ENABLE, 0x3f },
+ { CAP1106_REG_SENSOR_CONFIG, 0xa4 },
+ { CAP1106_REG_SENSOR_CONFIG2, 0x07 },
+ { CAP1106_REG_SAMPLING_CONFIG, 0x39 },
+ { CAP1106_REG_CALIBRATION, 0x00 },
+ { CAP1106_REG_INT_ENABLE, 0x3f },
+ { CAP1106_REG_REPEAT_RATE, 0x3f },
+ { CAP1106_REG_MT_CONFIG, 0x80 },
+ { CAP1106_REG_MT_PATTERN_CONFIG, 0x00 },
+ { CAP1106_REG_MT_PATTERN, 0x3f },
+ { CAP1106_REG_RECALIB_CONFIG, 0x8a },
+ { CAP1106_REG_SENSOR_THRESH(0), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(1), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(2), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(3), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(4), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(5), 0x40 },
+ { CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 },
+ { CAP1106_REG_STANDBY_CHANNEL, 0x00 },
+ { CAP1106_REG_STANDBY_CONFIG, 0x39 },
+ { CAP1106_REG_STANDBY_SENSITIVITY, 0x02 },
+ { CAP1106_REG_STANDBY_THRESH, 0x40 },
+ { CAP1106_REG_CONFIG2, 0x40 },
+ { CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 },
+ { CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 },
+};
+
+static bool cap1106_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CAP1106_REG_MAIN_CONTROL:
+ case CAP1106_REG_SENSOR_INPUT:
+ case CAP1106_REG_SENOR_DELTA(0):
+ case CAP1106_REG_SENOR_DELTA(1):
+ case CAP1106_REG_SENOR_DELTA(2):
+ case CAP1106_REG_SENOR_DELTA(3):
+ case CAP1106_REG_SENOR_DELTA(4):
+ case CAP1106_REG_SENOR_DELTA(5):
+ case CAP1106_REG_PRODUCT_ID:
+ case CAP1106_REG_MANUFACTURER_ID:
+ case CAP1106_REG_REVISION:
+ return true;
+ }
+
+ return false;
+}
+
+static const struct regmap_config cap1106_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CAP1106_REG_REVISION,
+ .reg_defaults = cap1106_reg_defaults,
+
+ .num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = cap1106_volatile_reg,
+};
+
+static void cap1106_work(struct work_struct *w)
+{
+ struct cap1106_priv *priv = container_of(w, struct cap1106_priv, work);
+ unsigned int status;
+ int ret, i;
+
+ spin_lock(&priv->lock);
+
+ /*
+ * Deassert interrupt. This needs to be done before reading the status
+ * registers, which will not carry valid values otherwise.
+ */
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0);
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < CAP1106_NUM_CHN; i++)
+ input_report_key(priv->idev, priv->keycodes[i],
+ status & (1 << i));
+
+ input_sync(priv->idev);
+
+out:
+ enable_irq(priv->irq);
+ spin_unlock(&priv->lock);
+}
+
+static irqreturn_t cap1106_isr(int irq_num, void *data)
+{
+ struct cap1106_priv *priv = data;
+
+ spin_lock(&priv->lock);
+ disable_irq_nosync(priv->irq);
+ schedule_work(&priv->work);
+ spin_unlock(&priv->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int cap1106_open(struct input_dev *input_dev)
+{
+ struct cap1106_priv *priv = input_get_drvdata(input_dev);
+ int ret;
+
+ /* disable deep sleep */
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_DLSEEP, 0);
+
+ enable_irq(priv->irq);
+
+ return ret;
+}
+
+static void cap1106_close(struct input_dev *input_dev)
+{
+ struct cap1106_priv *priv = input_get_drvdata(input_dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ disable_irq(priv->irq);
+ cancel_work_sync(&priv->work);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* enable deep sleep */
+ regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_DLSEEP,
+ CAP1106_REG_MAIN_CONTROL_DLSEEP);
+}
+
+static int cap1106_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c_client->dev;
+ struct device_node *child, *node;
+ struct cap1106_priv *priv;
+ unsigned int val, rev;
+ u8 gain = 0;
+ int i, ret;
+ u32 tmp32;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != CAP1106_PRODUCT_ID) {
+ dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
+ val, CAP1106_PRODUCT_ID);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != CAP1106_MANUFACTURER_ID) {
+ dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
+ val, CAP1106_MANUFACTURER_ID);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev);
+ i2c_set_clientdata(i2c_client, priv);
+ INIT_WORK(&priv->work, cap1106_work);
+ spin_lock_init(&priv->lock);
+ node = dev->of_node;
+
+ if (!of_property_read_u32(node, "microchip,sensor-gain", &tmp32)) {
+ if (is_power_of_2(tmp32) && tmp32 <= 8)
+ gain = ilog2(tmp32);
+ else
+ dev_err(dev, "Invalid sensor-gain value %d\n", tmp32);
+ }
+
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_GAIN_MASK,
+ gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ /* disable autorepeat. The Linux input system has its own handling. */
+ ret = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* set the defaults */
+ for (i = 0; i < CAP1106_NUM_CHN; i++)
+ priv->keycodes[i] = KEY_A + i;
+
+ i = 0;
+ for_each_child_of_node(node, child) {
+ if (i == CAP1106_NUM_CHN) {
+ dev_err(dev, "Too many button nodes.\n");
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(child, "linux,keycode", &tmp32))
+ priv->keycodes[i] = tmp32;
+
+ i++;
+ }
+
+ priv->idev = devm_input_allocate_device(dev);
+ if (!priv->idev)
+ return -ENOMEM;
+
+ priv->idev->name = "CAP1106 capacitive touch sensor";
+ priv->idev->id.bustype = BUS_I2C;
+ priv->idev->evbit[0] = BIT_MASK(EV_KEY);
+
+ if (of_get_property(node, "autorepeat", NULL))
+ __set_bit(EV_REP, priv->idev->evbit);
+
+ for (i = 0; i < CAP1106_NUM_CHN; i++) {
+ unsigned int code = priv->keycodes[i];
+ priv->idev->keybit[BIT_WORD(code)] |= BIT_MASK(code);
+ }
+
+ priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
+ priv->idev->id.product = CAP1106_PRODUCT_ID;
+ priv->idev->id.version = rev;
+
+ priv->idev->open = cap1106_open;
+ priv->idev->close = cap1106_close;
+
+ input_set_drvdata(priv->idev, priv);
+
+ ret = input_register_device(priv->idev);
+ if (ret < 0)
+ return ret;
+
+ priv->irq = irq_of_parse_and_map(node, 0);
+ if (!priv->irq) {
+ dev_err(dev, "Unable to parse or map IRQ\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(dev, priv->irq, cap1106_isr, IRQF_DISABLED,
+ dev_name(dev), priv);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cap1106_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cap1106_priv *priv = i2c_get_clientdata(i2c_client);
+
+ input_unregister_device(priv->idev);
+
+ return 0;
+}
+
+static const struct of_device_id cap1106_dt_ids[] = {
+ { .compatible = "microchip,cap1106", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cap1106_dt_ids);
+
+static const struct i2c_device_id cap1106_i2c_ids[] = {
+ { "cap1106", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids);
+
+static struct i2c_driver cap1106_i2c_driver = {
+ .driver = {
+ .name = "cap1106",
+ .owner = THIS_MODULE,
+ .of_match_table = cap1106_dt_ids,
+ },
+ .id_table = cap1106_i2c_ids,
+ .probe = cap1106_i2c_probe,
+ .remove = cap1106_i2c_remove,
+};
+
+module_i2c_driver(cap1106_i2c_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DESCRIPTION("Microchip CAP1106 driver");
+MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
+MODULE_LICENSE("GPL v2");
--
1.9.3
^ permalink raw reply related
* Re: [PATCH] Input: Add driver for Microchip's CAP1106
From: David Herrmann @ 2014-07-11 9:43 UTC (permalink / raw)
To: Daniel Mack; +Cc: dtor, open list:HID CORE LAYER, Mark Brown, devicetree
In-Reply-To: <1405064550-12222-1-git-send-email-zonque@gmail.com>
Hi
On Fri, Jul 11, 2014 at 9:42 AM, Daniel Mack <zonque@gmail.com> wrote:
> This patch adds a driver for Microchips CAP1106, an I2C driven, 6-channel
> capacitive touch sensor.
>
> For now, only the capacitive buttons are supported, and no specific
> settings that can be tweaked for individual channels, except for the
> device-wide sensitivity gain. The defaults seem to work just fine out of
> the box, so I'll leave configurable parameters for someone who's in need
> of them and who can actually measure the impact. All registers are
> prepared, however. Many of them are just not used for now.
>
> The implementation does not make any attempt to be compatible to platform
> data driven boards, but fully depends on CONFIG_OF.
>
> Power management functions are also left for volounteers with the ability
> to actually test them.
>
> Signed-off-by: Daniel Mack <zonque@gmail.com>
> ---
> .../devicetree/bindings/input/cap1106.txt | 63 ++++
> drivers/input/keyboard/Kconfig | 10 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/cap1106.c | 376 +++++++++++++++++++++
> 4 files changed, 450 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/input/cap1106.txt
> create mode 100644 drivers/input/keyboard/cap1106.c
>
> diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt
> new file mode 100644
> index 0000000..57f5af3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/cap1106.txt
> @@ -0,0 +1,63 @@
> +Device tree bindings for Microchip CAP1106, 6 channel capacitive touch sensor
> +
> +The node for this driver must be a child of a I2C controller node, as the
> +device communication via I2C only.
> +
> +Required properties:
> +
> + compatible: Must be "microchip,cap1106"
> + reg: The I2C slave address of the device.
> + Only 0x28 is valid.
> + interrupt: Node describing the interrupt line the device's
> + ALERT#/CM_IRQ# pin is connected to.
> +
> +Optional properties:
> +
> + autorepeat: Enables the Linux input system's autorepeat
> + feature on the input device.
> + microchip,sensor-gain: Defines the gain of the sensor circuitry. This
> + effectively controls the sensitivity, as a
> + smaller delta capacitance is required to
> + generate the same delta count values.
> + Valid values are 1, 2, 4, and 8.
> + By default, a gain of 1 is set.
> +
> +To define details of each individual button channel, six subnodes can be
> +specified. Inside each of those, the following property is valid:
> +
> + linux,keycode: Specify the numeric identifier of the keycode to be
> + generated when this channel is activated. If this
> + property is omitted, KEY_A, KEY_B, etc are used as
> + defaults.
> +
> +Example:
> +
> +i2c_controller {
> + cap1106@28 {
> + compatible = "microchip,cap1106";
> + interrupt-parent = <&gpio1>;
> + interrupts = <0 0>;
> + reg = <0x28>;
> + autorepeat;
> + microchip,sensor-gain = <2>;
> +
> + up {
> + linux,keycode = <103>; /* KEY_UP */
> + };
> + right {
> + linux,keycode = <106>; /* KEY_RIGHT */
> + };
> + down {
> + linux,keycode = <108>; /* KEY_DOWN */
> + };
> + left {
> + linux,keycode = <105>; /* KEY_LEFT */
> + };
> + pagedown {
> + linux,keycode = <109>; /* KEY_PAGEDOWN */
> + };
> + pageup {
> + linux,keycode = <104>; /* KEY_PAGEUP */
> + };
> + };
> +}
> diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
> index f7e79b4..a3958c6 100644
> --- a/drivers/input/keyboard/Kconfig
> +++ b/drivers/input/keyboard/Kconfig
> @@ -665,4 +665,14 @@ config KEYBOARD_CROS_EC
> To compile this driver as a module, choose M here: the
> module will be called cros_ec_keyb.
>
> +config KEYBOARD_CAP1106
> + tristate "Microchip CAP1106 touch sensor"
> + depends on OF && I2C
> + select REGMAP_I2C
> + help
> + Say Y here to enable the CAP1106 touch sensor driver.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called cap1106.
> +
> endif
> diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
> index 7504ae1..0a33456 100644
> --- a/drivers/input/keyboard/Makefile
> +++ b/drivers/input/keyboard/Makefile
> @@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
> obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
> obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
> obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
> +obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o
> obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
> obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
> obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
> diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c
> new file mode 100644
> index 0000000..ad0f0fb
> --- /dev/null
> +++ b/drivers/input/keyboard/cap1106.c
> @@ -0,0 +1,376 @@
> +/*
> + * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor
> + *
> + * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106
> + *
> + * (c) 2014 Daniel Mack <linux@zonque.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/interrupt.h>
> +#include <linux/input.h>
> +#include <linux/of_irq.h>
> +#include <linux/regmap.h>
> +#include <linux/i2c.h>
> +#include <linux/gpio/consumer.h>
> +
> +#define CAP1106_REG_MAIN_CONTROL 0x00
> +#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6)
> +#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
> +#define CAP1106_REG_MAIN_CONTROL_DLSEEP BIT(4)
> +#define CAP1106_REG_GENERAL_STATUS 0x02
> +#define CAP1106_REG_SENSOR_INPUT 0x03
> +#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a
> +#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X))
> +#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f
> +#define CAP1106_REG_CONFIG 0x20
> +#define CAP1106_REG_SENSOR_ENABLE 0x21
> +#define CAP1106_REG_SENSOR_CONFIG 0x22
> +#define CAP1106_REG_SENSOR_CONFIG2 0x23
> +#define CAP1106_REG_SAMPLING_CONFIG 0x24
> +#define CAP1106_REG_CALIBRATION 0x25
> +#define CAP1106_REG_INT_ENABLE 0x26
> +#define CAP1106_REG_REPEAT_RATE 0x28
> +#define CAP1106_REG_MT_CONFIG 0x2a
> +#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
> +#define CAP1106_REG_MT_PATTERN 0x2d
> +#define CAP1106_REG_RECALIB_CONFIG 0x2f
> +#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X))
> +#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38
> +#define CAP1106_REG_STANDBY_CHANNEL 0x40
> +#define CAP1106_REG_STANDBY_CONFIG 0x41
> +#define CAP1106_REG_STANDBY_SENSITIVITY 0x42
> +#define CAP1106_REG_STANDBY_THRESH 0x43
> +#define CAP1106_REG_CONFIG2 0x44
> +#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
> +#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X))
> +#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9
> +#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba
> +#define CAP1106_REG_PRODUCT_ID 0xfd
> +#define CAP1106_REG_MANUFACTURER_ID 0xfe
> +#define CAP1106_REG_REVISION 0xff
> +
> +#define CAP1106_NUM_CHN 6
> +#define CAP1106_PRODUCT_ID 0x55
> +#define CAP1106_MANUFACTURER_ID 0x5d
> +
> +struct cap1106_priv {
> + struct regmap *regmap;
> + struct input_dev *idev;
> + struct work_struct work;
> + spinlock_t lock;
> + int irq;
> +
> + /* config */
> + unsigned int keycodes[CAP1106_NUM_CHN];
> +};
> +
> +static const struct reg_default cap1106_reg_defaults[] = {
> + { CAP1106_REG_MAIN_CONTROL, 0x00 },
> + { CAP1106_REG_GENERAL_STATUS, 0x00 },
> + { CAP1106_REG_SENSOR_INPUT, 0x00 },
> + { CAP1106_REG_NOISE_FLAG_STATUS, 0x00 },
> + { CAP1106_REG_SENSITIVITY_CONTROL, 0x2f },
> + { CAP1106_REG_CONFIG, 0x20 },
> + { CAP1106_REG_SENSOR_ENABLE, 0x3f },
> + { CAP1106_REG_SENSOR_CONFIG, 0xa4 },
> + { CAP1106_REG_SENSOR_CONFIG2, 0x07 },
> + { CAP1106_REG_SAMPLING_CONFIG, 0x39 },
> + { CAP1106_REG_CALIBRATION, 0x00 },
> + { CAP1106_REG_INT_ENABLE, 0x3f },
> + { CAP1106_REG_REPEAT_RATE, 0x3f },
> + { CAP1106_REG_MT_CONFIG, 0x80 },
> + { CAP1106_REG_MT_PATTERN_CONFIG, 0x00 },
> + { CAP1106_REG_MT_PATTERN, 0x3f },
> + { CAP1106_REG_RECALIB_CONFIG, 0x8a },
> + { CAP1106_REG_SENSOR_THRESH(0), 0x40 },
> + { CAP1106_REG_SENSOR_THRESH(1), 0x40 },
> + { CAP1106_REG_SENSOR_THRESH(2), 0x40 },
> + { CAP1106_REG_SENSOR_THRESH(3), 0x40 },
> + { CAP1106_REG_SENSOR_THRESH(4), 0x40 },
> + { CAP1106_REG_SENSOR_THRESH(5), 0x40 },
> + { CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 },
> + { CAP1106_REG_STANDBY_CHANNEL, 0x00 },
> + { CAP1106_REG_STANDBY_CONFIG, 0x39 },
> + { CAP1106_REG_STANDBY_SENSITIVITY, 0x02 },
> + { CAP1106_REG_STANDBY_THRESH, 0x40 },
> + { CAP1106_REG_CONFIG2, 0x40 },
> + { CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 },
> + { CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 },
> +};
> +
> +static bool cap1106_volatile_reg(struct device *dev, unsigned int reg)
> +{
> + switch (reg) {
> + case CAP1106_REG_MAIN_CONTROL:
> + case CAP1106_REG_SENSOR_INPUT:
> + case CAP1106_REG_SENOR_DELTA(0):
> + case CAP1106_REG_SENOR_DELTA(1):
> + case CAP1106_REG_SENOR_DELTA(2):
> + case CAP1106_REG_SENOR_DELTA(3):
> + case CAP1106_REG_SENOR_DELTA(4):
> + case CAP1106_REG_SENOR_DELTA(5):
> + case CAP1106_REG_PRODUCT_ID:
> + case CAP1106_REG_MANUFACTURER_ID:
> + case CAP1106_REG_REVISION:
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static const struct regmap_config cap1106_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 8,
> +
> + .max_register = CAP1106_REG_REVISION,
> + .reg_defaults = cap1106_reg_defaults,
> +
> + .num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults),
> + .cache_type = REGCACHE_RBTREE,
> + .volatile_reg = cap1106_volatile_reg,
> +};
> +
> +static void cap1106_work(struct work_struct *w)
> +{
> + struct cap1106_priv *priv = container_of(w, struct cap1106_priv, work);
> + unsigned int status;
> + int ret, i;
> +
> + spin_lock(&priv->lock);
If your worker started and is _about_ to take the spinlock, you might
dead-lock with cap1106_close(). They might already hold the spinlock
and then call cancel_work_sync(), thus waiting for this task to take
the lock end exit..
How about you add "bool closed : 1;" to your cap1106_priv structure
and drop the lock here, but..
> +
> + /*
> + * Deassert interrupt. This needs to be done before reading the status
> + * registers, which will not carry valid values otherwise.
> + */
> + ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0);
> + if (ret < 0)
> + goto out;
> +
> + ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status);
> + if (ret < 0)
> + goto out;
> +
> + for (i = 0; i < CAP1106_NUM_CHN; i++)
> + input_report_key(priv->idev, priv->keycodes[i],
> + status & (1 << i));
> +
> + input_sync(priv->idev);
> +
> +out:
> + enable_irq(priv->irq);
> + spin_unlock(&priv->lock);
...change this to:
spin_lock(&priv->lock);
if (!priv->closed)
enable_irq(priv->irq);
spin_unlock(&priv->lock);
> +}
> +
> +static irqreturn_t cap1106_isr(int irq_num, void *data)
> +{
> + struct cap1106_priv *priv = data;
> +
> + spin_lock(&priv->lock);
> + disable_irq_nosync(priv->irq);
> + schedule_work(&priv->work);
> + spin_unlock(&priv->lock);
Locks here can be simply dropped. The IRQ is always stopped
synchronously before any worker is stopped, so this cannot race.
> +
> + return IRQ_HANDLED;
> +}
> +
> +static int cap1106_open(struct input_dev *input_dev)
> +{
> + struct cap1106_priv *priv = input_get_drvdata(input_dev);
> + int ret;
> +
> + /* disable deep sleep */
> + ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
> + CAP1106_REG_MAIN_CONTROL_DLSEEP, 0);
> +
You'd have to add:
priv->closed = false;
No need for locking as enable_irq and work-structs work as barriers.
> + enable_irq(priv->irq);
> +
> + return ret;
> +}
> +
> +static void cap1106_close(struct input_dev *input_dev)
> +{
> + struct cap1106_priv *priv = input_get_drvdata(input_dev);
> + unsigned long flags;
> +
> + spin_lock_irqsave(&priv->lock, flags);
> + disable_irq(priv->irq);
> + cancel_work_sync(&priv->work);
> + spin_unlock_irqrestore(&priv->lock, flags);
This would become:
spin_lock(&priv->lock);
priv->closed = true;
disable_irq(priv->irq);
spin_unlock(&priv->lock);
cancel_work_sync(&priv->work);
Btw., no need for irqsave/irqrestore here, ->closed is called in user-context.
Everything else looks good to me:
Thanks
David
> +
> + /* enable deep sleep */
> + regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
> + CAP1106_REG_MAIN_CONTROL_DLSEEP,
> + CAP1106_REG_MAIN_CONTROL_DLSEEP);
> +}
> +
> +static int cap1106_i2c_probe(struct i2c_client *i2c_client,
> + const struct i2c_device_id *id)
> +{
> + struct device *dev = &i2c_client->dev;
> + struct device_node *child, *node;
> + struct cap1106_priv *priv;
> + unsigned int val, rev;
> + u8 gain = 0;
> + int i, ret;
> + u32 tmp32;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config);
> + if (IS_ERR(priv->regmap))
> + return PTR_ERR(priv->regmap);
> +
> + ret = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val);
> + if (ret < 0)
> + return ret;
> +
> + if (val != CAP1106_PRODUCT_ID) {
> + dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
> + val, CAP1106_PRODUCT_ID);
> + return -ENODEV;
> + }
> +
> + ret = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val);
> + if (ret < 0)
> + return ret;
> +
> + if (val != CAP1106_MANUFACTURER_ID) {
> + dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
> + val, CAP1106_MANUFACTURER_ID);
> + return -ENODEV;
> + }
> +
> + ret = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev);
> + if (ret < 0)
> + return ret;
> +
> + dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev);
> + i2c_set_clientdata(i2c_client, priv);
> + INIT_WORK(&priv->work, cap1106_work);
> + spin_lock_init(&priv->lock);
> + node = dev->of_node;
> +
> + if (!of_property_read_u32(node, "microchip,sensor-gain", &tmp32)) {
> + if (is_power_of_2(tmp32) && tmp32 <= 8)
> + gain = ilog2(tmp32);
> + else
> + dev_err(dev, "Invalid sensor-gain value %d\n", tmp32);
> + }
> +
> + ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
> + CAP1106_REG_MAIN_CONTROL_GAIN_MASK,
> + gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT);
> + if (ret < 0)
> + return ret;
> +
> + /* disable autorepeat. The Linux input system has its own handling. */
> + ret = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0);
> + if (ret < 0)
> + return ret;
> +
> + /* set the defaults */
> + for (i = 0; i < CAP1106_NUM_CHN; i++)
> + priv->keycodes[i] = KEY_A + i;
> +
> + i = 0;
> + for_each_child_of_node(node, child) {
> + if (i == CAP1106_NUM_CHN) {
> + dev_err(dev, "Too many button nodes.\n");
> + return -EINVAL;
> + }
> +
> + if (!of_property_read_u32(child, "linux,keycode", &tmp32))
> + priv->keycodes[i] = tmp32;
> +
> + i++;
> + }
> +
> + priv->idev = devm_input_allocate_device(dev);
> + if (!priv->idev)
> + return -ENOMEM;
> +
> + priv->idev->name = "CAP1106 capacitive touch sensor";
> + priv->idev->id.bustype = BUS_I2C;
> + priv->idev->evbit[0] = BIT_MASK(EV_KEY);
> +
> + if (of_get_property(node, "autorepeat", NULL))
> + __set_bit(EV_REP, priv->idev->evbit);
> +
> + for (i = 0; i < CAP1106_NUM_CHN; i++) {
> + unsigned int code = priv->keycodes[i];
> + priv->idev->keybit[BIT_WORD(code)] |= BIT_MASK(code);
> + }
> +
> + priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
> + priv->idev->id.product = CAP1106_PRODUCT_ID;
> + priv->idev->id.version = rev;
> +
> + priv->idev->open = cap1106_open;
> + priv->idev->close = cap1106_close;
> +
> + input_set_drvdata(priv->idev, priv);
> +
> + ret = input_register_device(priv->idev);
> + if (ret < 0)
> + return ret;
> +
> + priv->irq = irq_of_parse_and_map(node, 0);
> + if (!priv->irq) {
> + dev_err(dev, "Unable to parse or map IRQ\n");
> + return -ENXIO;
> + }
> +
> + ret = devm_request_irq(dev, priv->irq, cap1106_isr, IRQF_DISABLED,
> + dev_name(dev), priv);
> + if (ret < 0)
> + return ret;
> +
> + return 0;
> +}
> +
> +static int cap1106_i2c_remove(struct i2c_client *i2c_client)
> +{
> + struct cap1106_priv *priv = i2c_get_clientdata(i2c_client);
> +
> + input_unregister_device(priv->idev);
> +
> + return 0;
> +}
> +
> +static const struct of_device_id cap1106_dt_ids[] = {
> + { .compatible = "microchip,cap1106", },
> + {}
> +};
> +MODULE_DEVICE_TABLE(of, cap1106_dt_ids);
> +
> +static const struct i2c_device_id cap1106_i2c_ids[] = {
> + { "cap1106", 0 },
> + {}
> +};
> +MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids);
> +
> +static struct i2c_driver cap1106_i2c_driver = {
> + .driver = {
> + .name = "cap1106",
> + .owner = THIS_MODULE,
> + .of_match_table = cap1106_dt_ids,
> + },
> + .id_table = cap1106_i2c_ids,
> + .probe = cap1106_i2c_probe,
> + .remove = cap1106_i2c_remove,
> +};
> +
> +module_i2c_driver(cap1106_i2c_driver);
> +
> +MODULE_ALIAS("platform:" DRV_NAME);
> +MODULE_DESCRIPTION("Microchip CAP1106 driver");
> +MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
> +MODULE_LICENSE("GPL v2");
> --
> 1.9.3
>
> --
> 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
* Re: [PATCH] Input: Add driver for Microchip's CAP1106
From: David Herrmann @ 2014-07-11 9:47 UTC (permalink / raw)
To: Daniel Mack; +Cc: dtor, open list:HID CORE LAYER, Mark Brown, devicetree
In-Reply-To: <1405064550-12222-1-git-send-email-zonque@gmail.com>
Hi
On Fri, Jul 11, 2014 at 9:42 AM, Daniel Mack <zonque@gmail.com> wrote:
> This patch adds a driver for Microchips CAP1106, an I2C driven, 6-channel
> capacitive touch sensor.
>
> For now, only the capacitive buttons are supported, and no specific
> settings that can be tweaked for individual channels, except for the
> device-wide sensitivity gain. The defaults seem to work just fine out of
> the box, so I'll leave configurable parameters for someone who's in need
> of them and who can actually measure the impact. All registers are
> prepared, however. Many of them are just not used for now.
>
> The implementation does not make any attempt to be compatible to platform
> data driven boards, but fully depends on CONFIG_OF.
>
> Power management functions are also left for volounteers with the ability
> to actually test them.
>
> Signed-off-by: Daniel Mack <zonque@gmail.com>
> ---
> .../devicetree/bindings/input/cap1106.txt | 63 ++++
> drivers/input/keyboard/Kconfig | 10 +
> drivers/input/keyboard/Makefile | 1 +
> drivers/input/keyboard/cap1106.c | 376 +++++++++++++++++++++
> 4 files changed, 450 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/input/cap1106.txt
> create mode 100644 drivers/input/keyboard/cap1106.c
>
> diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt
> new file mode 100644
> index 0000000..57f5af3
...
> + spin_lock_irqsave(&priv->lock, flags);
> + disable_irq(priv->irq);
> + cancel_work_sync(&priv->work);
> + spin_unlock_irqrestore(&priv->lock, flags);
Btw., cancel_work_sync() has a might_sleep() annotation, so you really
cannot call it while holding spinlocks (see start_flush_work() in
workqueue.c).
Cheers
David
^ permalink raw reply
* [PATCH v2] Input: Add driver for Microchip's CAP1106
From: Daniel Mack @ 2014-07-11 10:06 UTC (permalink / raw)
To: dtor; +Cc: linux-input, broonie, dh.herrmann, devicetree, Daniel Mack
This patch adds a driver for Microchips CAP1106, an I2C driven, 6-channel
capacitive touch sensor.
For now, only the capacitive buttons are supported, and no specific
settings that can be tweaked for individual channels, except for the
device-wide sensitivity gain. The defaults seem to work just fine out of
the box, so I'll leave configurable parameters for someone who's in need
of them and who can actually measure the impact. All registers are
prepared, however. Many of them are just not used for now.
The implementation does not make any attempt to be compatible to platform
data driven boards, but fully depends on CONFIG_OF.
Power management functions are also left for volounteers with the ability
to actually test them.
Signed-off-by: Daniel Mack <zonque@gmail.com>
---
v2:
* Fix potential deadlocks pointed out by David.
.../devicetree/bindings/input/cap1106.txt | 63 ++++
drivers/input/keyboard/Kconfig | 10 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/cap1106.c | 378 +++++++++++++++++++++
4 files changed, 452 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/cap1106.txt
create mode 100644 drivers/input/keyboard/cap1106.c
diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt
new file mode 100644
index 0000000..57f5af3
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/cap1106.txt
@@ -0,0 +1,63 @@
+Device tree bindings for Microchip CAP1106, 6 channel capacitive touch sensor
+
+The node for this driver must be a child of a I2C controller node, as the
+device communication via I2C only.
+
+Required properties:
+
+ compatible: Must be "microchip,cap1106"
+ reg: The I2C slave address of the device.
+ Only 0x28 is valid.
+ interrupt: Node describing the interrupt line the device's
+ ALERT#/CM_IRQ# pin is connected to.
+
+Optional properties:
+
+ autorepeat: Enables the Linux input system's autorepeat
+ feature on the input device.
+ microchip,sensor-gain: Defines the gain of the sensor circuitry. This
+ effectively controls the sensitivity, as a
+ smaller delta capacitance is required to
+ generate the same delta count values.
+ Valid values are 1, 2, 4, and 8.
+ By default, a gain of 1 is set.
+
+To define details of each individual button channel, six subnodes can be
+specified. Inside each of those, the following property is valid:
+
+ linux,keycode: Specify the numeric identifier of the keycode to be
+ generated when this channel is activated. If this
+ property is omitted, KEY_A, KEY_B, etc are used as
+ defaults.
+
+Example:
+
+i2c_controller {
+ cap1106@28 {
+ compatible = "microchip,cap1106";
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 0>;
+ reg = <0x28>;
+ autorepeat;
+ microchip,sensor-gain = <2>;
+
+ up {
+ linux,keycode = <103>; /* KEY_UP */
+ };
+ right {
+ linux,keycode = <106>; /* KEY_RIGHT */
+ };
+ down {
+ linux,keycode = <108>; /* KEY_DOWN */
+ };
+ left {
+ linux,keycode = <105>; /* KEY_LEFT */
+ };
+ pagedown {
+ linux,keycode = <109>; /* KEY_PAGEDOWN */
+ };
+ pageup {
+ linux,keycode = <104>; /* KEY_PAGEUP */
+ };
+ };
+}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f7e79b4..a3958c6 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -665,4 +665,14 @@ config KEYBOARD_CROS_EC
To compile this driver as a module, choose M here: the
module will be called cros_ec_keyb.
+config KEYBOARD_CAP1106
+ tristate "Microchip CAP1106 touch sensor"
+ depends on OF && I2C
+ select REGMAP_I2C
+ help
+ Say Y here to enable the CAP1106 touch sensor driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cap1106.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 7504ae1..0a33456 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
+obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c
new file mode 100644
index 0000000..b4741c5
--- /dev/null
+++ b/drivers/input/keyboard/cap1106.c
@@ -0,0 +1,378 @@
+/*
+ * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor
+ *
+ * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106
+ *
+ * (c) 2014 Daniel Mack <linux@zonque.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/gpio/consumer.h>
+
+#define CAP1106_REG_MAIN_CONTROL 0x00
+#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6)
+#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
+#define CAP1106_REG_MAIN_CONTROL_DLSEEP BIT(4)
+#define CAP1106_REG_GENERAL_STATUS 0x02
+#define CAP1106_REG_SENSOR_INPUT 0x03
+#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a
+#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X))
+#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f
+#define CAP1106_REG_CONFIG 0x20
+#define CAP1106_REG_SENSOR_ENABLE 0x21
+#define CAP1106_REG_SENSOR_CONFIG 0x22
+#define CAP1106_REG_SENSOR_CONFIG2 0x23
+#define CAP1106_REG_SAMPLING_CONFIG 0x24
+#define CAP1106_REG_CALIBRATION 0x25
+#define CAP1106_REG_INT_ENABLE 0x26
+#define CAP1106_REG_REPEAT_RATE 0x28
+#define CAP1106_REG_MT_CONFIG 0x2a
+#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
+#define CAP1106_REG_MT_PATTERN 0x2d
+#define CAP1106_REG_RECALIB_CONFIG 0x2f
+#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X))
+#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38
+#define CAP1106_REG_STANDBY_CHANNEL 0x40
+#define CAP1106_REG_STANDBY_CONFIG 0x41
+#define CAP1106_REG_STANDBY_SENSITIVITY 0x42
+#define CAP1106_REG_STANDBY_THRESH 0x43
+#define CAP1106_REG_CONFIG2 0x44
+#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
+#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X))
+#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9
+#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba
+#define CAP1106_REG_PRODUCT_ID 0xfd
+#define CAP1106_REG_MANUFACTURER_ID 0xfe
+#define CAP1106_REG_REVISION 0xff
+
+#define CAP1106_NUM_CHN 6
+#define CAP1106_PRODUCT_ID 0x55
+#define CAP1106_MANUFACTURER_ID 0x5d
+
+struct cap1106_priv {
+ struct regmap *regmap;
+ struct input_dev *idev;
+ struct work_struct work;
+ spinlock_t lock;
+ bool closed:1;
+ int irq;
+
+ /* config */
+ unsigned int keycodes[CAP1106_NUM_CHN];
+};
+
+static const struct reg_default cap1106_reg_defaults[] = {
+ { CAP1106_REG_MAIN_CONTROL, 0x00 },
+ { CAP1106_REG_GENERAL_STATUS, 0x00 },
+ { CAP1106_REG_SENSOR_INPUT, 0x00 },
+ { CAP1106_REG_NOISE_FLAG_STATUS, 0x00 },
+ { CAP1106_REG_SENSITIVITY_CONTROL, 0x2f },
+ { CAP1106_REG_CONFIG, 0x20 },
+ { CAP1106_REG_SENSOR_ENABLE, 0x3f },
+ { CAP1106_REG_SENSOR_CONFIG, 0xa4 },
+ { CAP1106_REG_SENSOR_CONFIG2, 0x07 },
+ { CAP1106_REG_SAMPLING_CONFIG, 0x39 },
+ { CAP1106_REG_CALIBRATION, 0x00 },
+ { CAP1106_REG_INT_ENABLE, 0x3f },
+ { CAP1106_REG_REPEAT_RATE, 0x3f },
+ { CAP1106_REG_MT_CONFIG, 0x80 },
+ { CAP1106_REG_MT_PATTERN_CONFIG, 0x00 },
+ { CAP1106_REG_MT_PATTERN, 0x3f },
+ { CAP1106_REG_RECALIB_CONFIG, 0x8a },
+ { CAP1106_REG_SENSOR_THRESH(0), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(1), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(2), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(3), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(4), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(5), 0x40 },
+ { CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 },
+ { CAP1106_REG_STANDBY_CHANNEL, 0x00 },
+ { CAP1106_REG_STANDBY_CONFIG, 0x39 },
+ { CAP1106_REG_STANDBY_SENSITIVITY, 0x02 },
+ { CAP1106_REG_STANDBY_THRESH, 0x40 },
+ { CAP1106_REG_CONFIG2, 0x40 },
+ { CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 },
+ { CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 },
+};
+
+static bool cap1106_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CAP1106_REG_MAIN_CONTROL:
+ case CAP1106_REG_SENSOR_INPUT:
+ case CAP1106_REG_SENOR_DELTA(0):
+ case CAP1106_REG_SENOR_DELTA(1):
+ case CAP1106_REG_SENOR_DELTA(2):
+ case CAP1106_REG_SENOR_DELTA(3):
+ case CAP1106_REG_SENOR_DELTA(4):
+ case CAP1106_REG_SENOR_DELTA(5):
+ case CAP1106_REG_PRODUCT_ID:
+ case CAP1106_REG_MANUFACTURER_ID:
+ case CAP1106_REG_REVISION:
+ return true;
+ }
+
+ return false;
+}
+
+static const struct regmap_config cap1106_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CAP1106_REG_REVISION,
+ .reg_defaults = cap1106_reg_defaults,
+
+ .num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = cap1106_volatile_reg,
+};
+
+static void cap1106_work(struct work_struct *w)
+{
+ struct cap1106_priv *priv = container_of(w, struct cap1106_priv, work);
+ unsigned int status;
+ int ret, i;
+
+ /*
+ * Deassert interrupt. This needs to be done before reading the status
+ * registers, which will not carry valid values otherwise.
+ */
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0);
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < CAP1106_NUM_CHN; i++)
+ input_report_key(priv->idev, priv->keycodes[i],
+ status & (1 << i));
+
+ input_sync(priv->idev);
+
+out:
+ spin_lock(&priv->lock);
+ if (!priv->closed)
+ enable_irq(priv->irq);
+ spin_unlock(&priv->lock);
+}
+
+static irqreturn_t cap1106_isr(int irq_num, void *data)
+{
+ struct cap1106_priv *priv = data;
+
+ disable_irq_nosync(priv->irq);
+ schedule_work(&priv->work);
+
+ return IRQ_HANDLED;
+}
+
+static int cap1106_open(struct input_dev *input_dev)
+{
+ struct cap1106_priv *priv = input_get_drvdata(input_dev);
+ int ret;
+
+ /* disable deep sleep */
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_DLSEEP, 0);
+
+ priv->closed = false;
+ enable_irq(priv->irq);
+
+ return ret;
+}
+
+static void cap1106_close(struct input_dev *input_dev)
+{
+ struct cap1106_priv *priv = input_get_drvdata(input_dev);
+
+ spin_lock(&priv->lock);
+ priv->closed = true;
+ disable_irq(priv->irq);
+ spin_unlock(&priv->lock);
+
+ cancel_work_sync(&priv->work);
+
+ /* enable deep sleep */
+ regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_DLSEEP,
+ CAP1106_REG_MAIN_CONTROL_DLSEEP);
+}
+
+static int cap1106_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c_client->dev;
+ struct device_node *child, *node;
+ struct cap1106_priv *priv;
+ unsigned int val, rev;
+ u8 gain = 0;
+ int i, ret;
+ u32 tmp32;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != CAP1106_PRODUCT_ID) {
+ dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
+ val, CAP1106_PRODUCT_ID);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != CAP1106_MANUFACTURER_ID) {
+ dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
+ val, CAP1106_MANUFACTURER_ID);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev);
+ i2c_set_clientdata(i2c_client, priv);
+ INIT_WORK(&priv->work, cap1106_work);
+ spin_lock_init(&priv->lock);
+ node = dev->of_node;
+
+ if (!of_property_read_u32(node, "microchip,sensor-gain", &tmp32)) {
+ if (is_power_of_2(tmp32) && tmp32 <= 8)
+ gain = ilog2(tmp32);
+ else
+ dev_err(dev, "Invalid sensor-gain value %d\n", tmp32);
+ }
+
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_GAIN_MASK,
+ gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ /* disable autorepeat. The Linux input system has its own handling. */
+ ret = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* set the defaults */
+ for (i = 0; i < CAP1106_NUM_CHN; i++)
+ priv->keycodes[i] = KEY_A + i;
+
+ i = 0;
+ for_each_child_of_node(node, child) {
+ if (i == CAP1106_NUM_CHN) {
+ dev_err(dev, "Too many button nodes.\n");
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(child, "linux,keycode", &tmp32))
+ priv->keycodes[i] = tmp32;
+
+ i++;
+ }
+
+ priv->idev = devm_input_allocate_device(dev);
+ if (!priv->idev)
+ return -ENOMEM;
+
+ priv->idev->name = "CAP1106 capacitive touch sensor";
+ priv->idev->id.bustype = BUS_I2C;
+ priv->idev->evbit[0] = BIT_MASK(EV_KEY);
+
+ if (of_get_property(node, "autorepeat", NULL))
+ __set_bit(EV_REP, priv->idev->evbit);
+
+ for (i = 0; i < CAP1106_NUM_CHN; i++) {
+ unsigned int code = priv->keycodes[i];
+ priv->idev->keybit[BIT_WORD(code)] |= BIT_MASK(code);
+ }
+
+ priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
+ priv->idev->id.product = CAP1106_PRODUCT_ID;
+ priv->idev->id.version = rev;
+
+ priv->idev->open = cap1106_open;
+ priv->idev->close = cap1106_close;
+
+ input_set_drvdata(priv->idev, priv);
+ priv->closed = true;
+
+ ret = input_register_device(priv->idev);
+ if (ret < 0)
+ return ret;
+
+ priv->irq = irq_of_parse_and_map(node, 0);
+ if (!priv->irq) {
+ dev_err(dev, "Unable to parse or map IRQ\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_irq(dev, priv->irq, cap1106_isr, IRQF_DISABLED,
+ dev_name(dev), priv);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cap1106_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cap1106_priv *priv = i2c_get_clientdata(i2c_client);
+
+ input_unregister_device(priv->idev);
+
+ return 0;
+}
+
+static const struct of_device_id cap1106_dt_ids[] = {
+ { .compatible = "microchip,cap1106", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cap1106_dt_ids);
+
+static const struct i2c_device_id cap1106_i2c_ids[] = {
+ { "cap1106", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids);
+
+static struct i2c_driver cap1106_i2c_driver = {
+ .driver = {
+ .name = "cap1106",
+ .owner = THIS_MODULE,
+ .of_match_table = cap1106_dt_ids,
+ },
+ .id_table = cap1106_i2c_ids,
+ .probe = cap1106_i2c_probe,
+ .remove = cap1106_i2c_remove,
+};
+
+module_i2c_driver(cap1106_i2c_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DESCRIPTION("Microchip CAP1106 driver");
+MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
+MODULE_LICENSE("GPL v2");
--
1.9.3
^ permalink raw reply related
* Re: [PATCH 0/5] Input - wacom: battery enhancements and unifying hid-wacom and wacom
From: Benjamin Tissoires @ 2014-07-11 13:13 UTC (permalink / raw)
To: Przemo Firszt
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Ping Cheng,
Jason Gerecke, linux-kernel@vger.kernel.org, linux-input
In-Reply-To: <1405026844.2613.15.camel@fedora-lan>
Hi Przemo,
On Thu, Jul 10, 2014 at 5:14 PM, Przemo Firszt <przemo@firszt.eu> wrote:
> Dnia 2014-07-10, czw o godzinie 14:44 -0400, Benjamin Tissoires pisze:
> [..]
> Hi Benjamin,
>> However, I did not backport the speed attribute and the ac power
>> device (which
>> is infered by the battery status). I don't know if there are users of
>> those two,
>> so I let them aside for now. Przemo, any ideas if this is actually
>> used?
> Both tablets that I had (Graphire Wireless and Intuos4 Wireless)
> supports slow and fast reporting. Slow reporting is necessary with older
> bluetooth receivers otherwise the lag between pen movement and cursor
> movement made devices unusable.
Alright
>
> I tried to expose all events reported by hardware and I think AC
> reporting should stay in the kernel.
Ok, I'll send a v2 next week with these two things fixed.
Cheers,
Benjamin
>
> Intuos4 Wireless
> AC power disconnected:
> bash-4.2$ cat /sys/class/power_supply/wacom_ac/uevent
> POWER_SUPPLY_NAME=wacom_ac
> POWER_SUPPLY_PRESENT=0
> POWER_SUPPLY_ONLINE=0
> POWER_SUPPLY_SCOPE=Device
> bash-4.2$ cat /sys/class/power_supply/wacom_battery/uevent
> POWER_SUPPLY_NAME=wacom_battery
> POWER_SUPPLY_PRESENT=1
> POWER_SUPPLY_CAPACITY=85
> POWER_SUPPLY_SCOPE=Device
> POWER_SUPPLY_STATUS=Discharging
>
> AC power connected:
> bash-4.2$ cat /sys/class/power_supply/wacom_ac/uevent
> POWER_SUPPLY_NAME=wacom_ac
> POWER_SUPPLY_PRESENT=1
> POWER_SUPPLY_ONLINE=1
> POWER_SUPPLY_SCOPE=Device
> bash-4.2$ cat /sys/class/power_supply/wacom_battery/uevent
> POWER_SUPPLY_NAME=wacom_battery
> POWER_SUPPLY_PRESENT=1
> POWER_SUPPLY_CAPACITY=85
> POWER_SUPPLY_SCOPE=Device
> POWER_SUPPLY_STATUS=Charging
> --
> Kind regards,
> Przemo Firszt
>
> --
> 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
* Re: [PATCH 08/15] Input - wacom: remove usb dependency for siblings devices
From: Benjamin Tissoires @ 2014-07-11 13:15 UTC (permalink / raw)
To: Jason Gerecke
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Ping Cheng,
Linux Input, linux-kernel@vger.kernel.org, linuxwacom-devel
In-Reply-To: <CANRwn3TJtBVfhHYoX6oqzo4-tHTXairquATnVYQNzt9pEtmWSA@mail.gmail.com>
On Thu, Jul 10, 2014 at 8:10 PM, Jason Gerecke <killertofu@gmail.com> wrote:
> On Mon, Jun 30, 2014 at 2:26 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
>> Wacom tablets can share different physical sensors on one physical device.
>> These are called siblings in the code. The current way of implementation
>> relies on the USB topology to be able to share data amongs those sensors.
>>
>> We can replace the code to match a HID subsystem, without involving the USB
>> topology:
>> - the first probed sensor does not find any siblings in the list
>> wacom_udev_list, so it creates its own wacom_hdev_data with its own
>> struct hid_device
>> - the other sensor checks the current list of siblings in wacom_hdev_data,
>> and if there is a match, it associates itself to the matched device.
>>
>> To be sure that we are not associating different sensors from different
>> physical devices, we also check for the phys path of the hid device which
>> contains the USB topology.
>>
>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>> ---
>> drivers/input/tablet/wacom_sys.c | 75 +++++++++++++++++++---------------------
>> 1 file changed, 35 insertions(+), 40 deletions(-)
>>
>> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
>> index 0d0397d..6fe7a6c 100644
>> --- a/drivers/input/tablet/wacom_sys.c
>> +++ b/drivers/input/tablet/wacom_sys.c
>> @@ -488,46 +488,45 @@ static int wacom_retrieve_hid_descriptor(struct hid_device *hdev,
>> return error;
>> }
>>
>> -struct wacom_usbdev_data {
>> +struct wacom_hdev_data {
>> struct list_head list;
>> struct kref kref;
>> - struct usb_device *dev;
>> + struct hid_device *dev;
>> struct wacom_shared shared;
>> };
>>
>> static LIST_HEAD(wacom_udev_list);
>> static DEFINE_MUTEX(wacom_udev_list_lock);
>>
>> -static struct usb_device *wacom_get_sibling(struct usb_device *dev, int vendor, int product)
>> +static bool wacom_are_sibling(struct hid_device *hdev,
>> + struct hid_device *sibling)
>> {
>> - int port1;
>> - struct usb_device *sibling;
>> -
>> - if (vendor == 0 && product == 0)
>> - return dev;
>> -
>> - if (dev->parent == NULL)
>> - return NULL;
>> -
>> - usb_hub_for_each_child(dev->parent, port1, sibling) {
>> - struct usb_device_descriptor *d;
>> - if (sibling == NULL)
>> - continue;
>> + struct wacom *wacom = hid_get_drvdata(hdev);
>> + struct wacom_features *features = &wacom->wacom_wac.features;
>> + int vid = features->oVid;
>> + int pid = features->oPid;
>>
>> - d = &sibling->descriptor;
>> - if (d->idVendor == vendor && d->idProduct == product)
>> - return sibling;
>> + if (vid == 0 && pid == 0) {
>> + vid = hdev->vendor;
>> + pid = hdev->product;
>> }
>>
>> - return NULL;
>> + if (vid != sibling->vendor || pid != sibling->product)
>> + return false;
>> +
>> + /*
>> + * Compare the physical path.
>> + * Dump the last two chars which should contain the input number.
>> + */
>> + return !strncmp(hdev->phys, sibling->phys, strlen(hdev->phys) - 2);
>
> Good idea, but this implementation doesn't work. "Siblings" (such as
> you'd find on a 24HDT) are separate USB devices but share the same USB
> hub. Trimming off just the input number isn't sufficient since the USB
> path preceding it is going to be different for the two devices. For
> example, I the touch and pen interfaces on my 24HDT show up as
> "usb-0000:00:1d.0-1.4.3/input0" and "usb-0000:00:1d.0-1.4.2/input1".
You are right. I thought I managed to make the 22HDT working with my
patches, but maybe I overlooked it
>
> Something like the following could work though:
>
> int n1 = strrchr(hdev->phys, '.') - hdev->phys;
> int n2 = strrchr(sibling->phys, '.') - sibling->phys;
> if (n1 != n2 || n1 <= 0 || n2 <= 0)
> return false;
> else
> return !strncmp(hdev->phys, sibling->phys, n1);
Seems fair. I'll give a try and update the patches.
Thanks!
Cheers,
Benjamin
>
> Jason
> ---
> Now instead of four in the eights place /
> you’ve got three, ‘Cause you added one /
> (That is to say, eight) to the two, /
> But you can’t take seven from three, /
> So you look at the sixty-fours....
>
>> }
>>
>> -static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
>> +static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
>> {
>> - struct wacom_usbdev_data *data;
>> + struct wacom_hdev_data *data;
>>
>> list_for_each_entry(data, &wacom_udev_list, list) {
>> - if (data->dev == dev) {
>> + if (wacom_are_sibling(hdev, data->dev)) {
>> kref_get(&data->kref);
>> return data;
>> }
>> @@ -536,28 +535,29 @@ static struct wacom_usbdev_data *wacom_get_usbdev_data(struct usb_device *dev)
>> return NULL;
>> }
>>
>> -static int wacom_add_shared_data(struct wacom_wac *wacom,
>> - struct usb_device *dev)
>> +static int wacom_add_shared_data(struct hid_device *hdev)
>> {
>> - struct wacom_usbdev_data *data;
>> + struct wacom *wacom = hid_get_drvdata(hdev);
>> + struct wacom_wac *wacom_wac = &wacom->wacom_wac;
>> + struct wacom_hdev_data *data;
>> int retval = 0;
>>
>> mutex_lock(&wacom_udev_list_lock);
>>
>> - data = wacom_get_usbdev_data(dev);
>> + data = wacom_get_hdev_data(hdev);
>> if (!data) {
>> - data = kzalloc(sizeof(struct wacom_usbdev_data), GFP_KERNEL);
>> + data = kzalloc(sizeof(struct wacom_hdev_data), GFP_KERNEL);
>> if (!data) {
>> retval = -ENOMEM;
>> goto out;
>> }
>>
>> kref_init(&data->kref);
>> - data->dev = dev;
>> + data->dev = hdev;
>> list_add_tail(&data->list, &wacom_udev_list);
>> }
>>
>> - wacom->shared = &data->shared;
>> + wacom_wac->shared = &data->shared;
>>
>> out:
>> mutex_unlock(&wacom_udev_list_lock);
>> @@ -566,8 +566,8 @@ out:
>>
>> static void wacom_release_shared_data(struct kref *kref)
>> {
>> - struct wacom_usbdev_data *data =
>> - container_of(kref, struct wacom_usbdev_data, kref);
>> + struct wacom_hdev_data *data =
>> + container_of(kref, struct wacom_hdev_data, kref);
>>
>> mutex_lock(&wacom_udev_list_lock);
>> list_del(&data->list);
>> @@ -578,10 +578,10 @@ static void wacom_release_shared_data(struct kref *kref)
>>
>> static void wacom_remove_shared_data(struct wacom_wac *wacom)
>> {
>> - struct wacom_usbdev_data *data;
>> + struct wacom_hdev_data *data;
>>
>> if (wacom->shared) {
>> - data = container_of(wacom->shared, struct wacom_usbdev_data, shared);
>> + data = container_of(wacom->shared, struct wacom_hdev_data, shared);
>> kref_put(&data->kref, wacom_release_shared_data);
>> wacom->shared = NULL;
>> }
>> @@ -1311,8 +1311,6 @@ static int wacom_probe(struct hid_device *hdev,
>> "%s Pad", features->name);
>>
>> if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
>> - struct usb_device *other_dev;
>> -
>> /* Append the device type to the name */
>> if (features->device_type != BTN_TOOL_FINGER)
>> strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX);
>> @@ -1321,10 +1319,7 @@ static int wacom_probe(struct hid_device *hdev,
>> else
>> strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX);
>>
>> - other_dev = wacom_get_sibling(dev, features->oVid, features->oPid);
>> - if (other_dev == NULL || wacom_get_usbdev_data(other_dev) == NULL)
>> - other_dev = dev;
>> - error = wacom_add_shared_data(wacom_wac, other_dev);
>> + error = wacom_add_shared_data(hdev);
>> if (error)
>> goto fail1;
>> }
>> --
>> 2.0.0
>>
> --
> 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
--
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
* Re: [Linuxwacom-devel] [PATCH 1/5] Input - wacom: create a separate input device for pads
From: Benjamin Tissoires @ 2014-07-11 13:17 UTC (permalink / raw)
To: Jason Gerecke
Cc: Benjamin Tissoires, linuxwacom-devel, Ping Cheng, Dmitry Torokhov,
linux-kernel@vger.kernel.org, Linux Input
In-Reply-To: <CANRwn3S-vhSf5tMSt1L_1CwkxttGx1qHKx=O+S5TcU+wjgtNBg@mail.gmail.com>
On Thu, Jul 10, 2014 at 8:18 PM, Jason Gerecke <killertofu@gmail.com> wrote:
> 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.
>>
>> 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.
>>
>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>> ---
>> drivers/input/tablet/wacom.h | 2 ++
>> drivers/input/tablet/wacom_sys.c | 63 +++++++++++++++++++++++++++++++++++-----
>> drivers/input/tablet/wacom_wac.c | 27 ++++++++++++++++-
>> drivers/input/tablet/wacom_wac.h | 2 ++
>> 4 files changed, 85 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/input/tablet/wacom.h b/drivers/input/tablet/wacom.h
>> index 9ebf0ed..caa59ca 100644
>> --- a/drivers/input/tablet/wacom.h
>> +++ b/drivers/input/tablet/wacom.h
>> @@ -136,4 +136,6 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len);
>> void wacom_setup_device_quirks(struct wacom_features *features);
>> int wacom_setup_input_capabilities(struct input_dev *input_dev,
>> struct wacom_wac *wacom_wac);
>> +int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
>> + struct wacom_wac *wacom_wac);
>> #endif
>> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
>> index c993eee..b9bf37e 100644
>> --- a/drivers/input/tablet/wacom_sys.c
>> +++ b/drivers/input/tablet/wacom_sys.c
>> @@ -135,6 +135,9 @@ static int wacom_open(struct input_dev *dev)
>>
>> mutex_lock(&wacom->lock);
>>
>> + if (wacom->open)
>> + goto out;
>> +
>> if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
>> retval = -EIO;
>> goto out;
>> @@ -157,9 +160,14 @@ static void wacom_close(struct input_dev *dev)
>> autopm_error = usb_autopm_get_interface(wacom->intf);
>>
>> mutex_lock(&wacom->lock);
>> + if (!wacom->open)
>> + goto out;
>> +
>> usb_kill_urb(wacom->irq);
>> wacom->open = false;
>> wacom->intf->needs_remote_wakeup = 0;
>> +
>> +out:
>> mutex_unlock(&wacom->lock);
>>
>> if (!autopm_error)
>> @@ -1109,19 +1117,16 @@ static void wacom_destroy_battery(struct wacom *wacom)
>> }
>> }
>>
>> -static int wacom_register_input(struct wacom *wacom)
>> +static struct input_dev *wacom_allocate_input(struct wacom *wacom)
>> {
>> struct input_dev *input_dev;
>> struct usb_interface *intf = wacom->intf;
>> struct usb_device *dev = interface_to_usbdev(intf);
>> struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
>> - int error;
>>
>> input_dev = input_allocate_device();
>> - if (!input_dev) {
>> - error = -ENOMEM;
>> - goto fail1;
>> - }
>> + if (!input_dev)
>> + return NULL;
>>
>> input_dev->name = wacom_wac->name;
>> input_dev->phys = wacom->phys;
>> @@ -1131,21 +1136,59 @@ static int wacom_register_input(struct wacom *wacom)
>> usb_to_input_id(dev, &input_dev->id);
>> input_set_drvdata(input_dev, wacom);
>>
>> + return input_dev;
>> +}
>> +
>> +static int wacom_register_input(struct wacom *wacom)
>> +{
>> + struct input_dev *input_dev, *pad_input_dev;
>> + struct wacom_wac *wacom_wac = &(wacom->wacom_wac);
>> + int error;
>> +
>> + input_dev = wacom_allocate_input(wacom);
>> + pad_input_dev = wacom_allocate_input(wacom);
>> + if (!input_dev || !pad_input_dev) {
>> + error = -ENOMEM;
>> + goto fail1;
>> + }
>> +
>> wacom_wac->input = input_dev;
>> + wacom_wac->pad_input = pad_input_dev;
>> + wacom_wac->pad_input->name = wacom_wac->pad_name;
>> +
>> error = wacom_setup_input_capabilities(input_dev, wacom_wac);
>> if (error)
>> - goto fail1;
>> + goto fail2;
>>
>> error = input_register_device(input_dev);
>> if (error)
>> goto fail2;
>>
>> + error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac);
>> + if (error) {
>> + /* no pad in use on this interface */
>> + input_free_device(pad_input_dev);
>> + wacom_wac->pad_input = NULL;
>> + pad_input_dev = NULL;
>> + } else {
>> + error = input_register_device(pad_input_dev);
>> + if (error)
>> + goto fail3;
>> + }
>> +
>> return 0;
>>
>> +fail3:
>> + input_unregister_device(input_dev);
>> + input_dev = NULL;
>> fail2:
>> - input_free_device(input_dev);
>> wacom_wac->input = NULL;
>> + wacom_wac->pad_input = NULL;
>> fail1:
>> + if (input_dev)
>> + input_free_device(input_dev);
>> + if (pad_input_dev)
>> + input_free_device(pad_input_dev);
>> return error;
>> }
>>
>> @@ -1364,6 +1407,8 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
>> wacom_calculate_res(features);
>>
>> strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name));
>> + snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name),
>> + "%s Pad", features->name);
>
> This may cause some heartburn for some users that have xsetwacom
> scripts (or use similar tools that need a device name). Our X driver
> already appends a " pad" suffix to the device name, so this results in
> X devices now having the double-suffix " Pad pad". I agree with adding
> the suffix here though, so I think I'll write a patch to fix this in
> xf86-input-wacom.
Yeah, but as there was already some part of the code which appended
such suffixes in some cases, I think fixing this in xf86-input-wacom
is the best solution.
Cheers,
Benjamin
>
> Jason
> ---
> Now instead of four in the eights place /
> you’ve got three, ‘Cause you added one /
> (That is to say, eight) to the two, /
> But you can’t take seven from three, /
> So you look at the sixty-fours....
>
>>
>> if (features->quirks & WACOM_QUIRK_MULTI_INPUT) {
>> struct usb_device *other_dev;
>> @@ -1438,6 +1483,8 @@ static void wacom_disconnect(struct usb_interface *intf)
>> cancel_work_sync(&wacom->work);
>> if (wacom->wacom_wac.input)
>> input_unregister_device(wacom->wacom_wac.input);
>> + if (wacom->wacom_wac.pad_input)
>> + input_unregister_device(wacom->wacom_wac.pad_input);
>> wacom_destroy_battery(wacom);
>> wacom_destroy_leds(wacom);
>> usb_free_urb(wacom->irq);
>> diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
>> index 977d05c..4b16a34 100644
>> --- a/drivers/input/tablet/wacom_wac.c
>> +++ b/drivers/input/tablet/wacom_wac.c
>> @@ -1489,8 +1489,11 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
>> break;
>> }
>>
>> - if (sync)
>> + if (sync) {
>> input_sync(wacom_wac->input);
>> + if (wacom_wac->pad_input)
>> + input_sync(wacom_wac->pad_input);
>> + }
>> }
>>
>> static void wacom_setup_cintiq(struct wacom_wac *wacom_wac)
>> @@ -1939,6 +1942,28 @@ int wacom_setup_input_capabilities(struct input_dev *input_dev,
>> return 0;
>> }
>>
>> +int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
>> + struct wacom_wac *wacom_wac)
>> +{
>> + struct wacom_features *features = &wacom_wac->features;
>> +
>> + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
>> +
>> + /* kept for making legacy xf86-input-wacom working with the wheels */
>> + __set_bit(ABS_MISC, input_dev->absbit);
>> +
>> + /* kept for making legacy xf86-input-wacom accepting the pad */
>> + input_set_abs_params(input_dev, ABS_X, 0, 1, 0, 0);
>> + input_set_abs_params(input_dev, ABS_Y, 0, 1, 0, 0);
>> +
>> + switch (features->type) {
>> + default:
>> + /* no pad supported */
>> + return 1;
>> + }
>> + return 0;
>> +}
>> +
>> static const struct wacom_features wacom_features_0x00 =
>> { "Wacom Penpartner", WACOM_PKGLEN_PENPRTN, 5040, 3780, 255,
>> 0, PENPARTNER, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES };
>> diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
>> index b2c9a9c..f48164c 100644
>> --- a/drivers/input/tablet/wacom_wac.h
>> +++ b/drivers/input/tablet/wacom_wac.h
>> @@ -150,6 +150,7 @@ struct wacom_shared {
>>
>> struct wacom_wac {
>> char name[WACOM_NAME_MAX];
>> + char pad_name[WACOM_NAME_MAX];
>> unsigned char *data;
>> int tool[2];
>> int id[2];
>> @@ -157,6 +158,7 @@ struct wacom_wac {
>> struct wacom_features features;
>> struct wacom_shared *shared;
>> struct input_dev *input;
>> + struct input_dev *pad_input;
>> int pid;
>> int battery_capacity;
>> int num_contacts_left;
>> --
>> 1.9.0
>>
>
> ------------------------------------------------------------------------------
> Open source business process management suite built on Java and Eclipse
> Turn processes into business applications with Bonita BPM Community Edition
> Quickly connect people, data, and systems into organized workflows
> Winner of BOSSIE, CODIE, OW2 and Gartner awards
> http://p.sf.net/sfu/Bonitasoft
> _______________________________________________
> Linuxwacom-devel mailing list
> Linuxwacom-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel
--
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
* Re: [PATCH 05/15] Input - wacom: compute the HID report size to get the actual packet size
From: Benjamin Tissoires @ 2014-07-11 13:20 UTC (permalink / raw)
To: Jason Gerecke
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Ping Cheng,
Linux Input, linux-kernel@vger.kernel.org, linuxwacom-devel
In-Reply-To: <CANRwn3R4LG0SoDR5hKC+LehTWxnmJsKsVsXdkkx4MrDxUwPZNQ@mail.gmail.com>
On Thu, Jul 10, 2014 at 9:09 PM, Jason Gerecke <killertofu@gmail.com> wrote:
> On Mon, Jun 30, 2014 at 2:26 PM, Benjamin Tissoires
> <benjamin.tissoires@redhat.com> wrote:
>> This removes an USB dependency and is more accurate: the computed pktlen
>> is the actual maximum size of the reports forwarded by the device.
>>
>> Given that the pktlen is correctly computed/validated, we can store it now
>> in the features struct instead of having a special handling in the rest of
>> the code.
>>
>> Likewise, this information is not mandatory anymore in the description
>> of devices in wacom_wac.c. They will be removed in a separate patch.
>>
>> Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>
> I'm concerned this new function could be fooled if we release a tablet
> that has one report which is longer than the desired report, but none
> of the hardware I tested was like this and it would be fairly easy to
> address even if it did happen. Thought I should mention it though.
>
You are right to mention it. But in the other hand, such a device
would violate the HID specification, and I am not sure the Windows
driver (which I don't know its internal) would be happy too.
Anyway, as you said, if there is such a device, we an use the report
descriptor fixup capability of HID to prevent this from happening.
Cheers,
Benjamin
> Jason
> ---
> Now instead of four in the eights place /
> you’ve got three, ‘Cause you added one /
> (That is to say, eight) to the two, /
> But you can’t take seven from three, /
> So you look at the sixty-fours....
>
>
>> ---
>> drivers/input/tablet/wacom_sys.c | 58 ++++++++++++++++++----------------------
>> 1 file changed, 26 insertions(+), 32 deletions(-)
>>
>> diff --git a/drivers/input/tablet/wacom_sys.c b/drivers/input/tablet/wacom_sys.c
>> index cd3d936..3f1cee6 100644
>> --- a/drivers/input/tablet/wacom_sys.c
>> +++ b/drivers/input/tablet/wacom_sys.c
>> @@ -149,7 +149,6 @@ static int wacom_parse_logical_collection(unsigned char *report,
>> if (features->type == BAMBOO_PT) {
>>
>> /* Logical collection is only used by 3rd gen Bamboo Touch */
>> - features->pktlen = WACOM_PKGLEN_BBTOUCH3;
>> features->device_type = BTN_TOOL_FINGER;
>>
>> features->x_max = features->y_max =
>> @@ -240,29 +239,6 @@ static int wacom_parse_hid(struct hid_device *hdev,
>> features->device_type = BTN_TOOL_FINGER;
>> /* touch device at least supports one touch point */
>> touch_max = 1;
>> - switch (features->type) {
>> - case TABLETPC2FG:
>> - features->pktlen = WACOM_PKGLEN_TPC2FG;
>> - break;
>> -
>> - case MTSCREEN:
>> - case WACOM_24HDT:
>> - features->pktlen = WACOM_PKGLEN_MTOUCH;
>> - break;
>> -
>> - case MTTPC:
>> - case MTTPC_B:
>> - features->pktlen = WACOM_PKGLEN_MTTPC;
>> - break;
>> -
>> - case BAMBOO_PT:
>> - features->pktlen = WACOM_PKGLEN_BBTOUCH;
>> - break;
>> -
>> - default:
>> - features->pktlen = WACOM_PKGLEN_GRAPHIRE;
>> - break;
>> - }
>>
>> switch (features->type) {
>> case BAMBOO_PT:
>> @@ -305,8 +281,6 @@ static int wacom_parse_hid(struct hid_device *hdev,
>> }
>> } else if (pen) {
>> /* penabled only accepts exact bytes of data */
>> - if (features->type >= TABLETPC)
>> - features->pktlen = WACOM_PKGLEN_GRAPHIRE;
>> features->device_type = BTN_TOOL_PEN;
>> features->x_max =
>> get_unaligned_le16(&report[i + 3]);
>> @@ -1227,12 +1201,34 @@ static void wacom_calculate_res(struct wacom_features *features)
>> features->unitExpo);
>> }
>>
>> +static int wacom_hid_report_len(struct hid_report *report)
>> +{
>> + /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */
>> + return ((report->size - 1) >> 3) + 1 + (report->id > 0);
>> +}
>> +
>> +static size_t wacom_compute_pktlen(struct hid_device *hdev)
>> +{
>> + struct hid_report_enum *report_enum;
>> + struct hid_report *report;
>> + size_t size = 0;
>> +
>> + report_enum = hdev->report_enum + HID_INPUT_REPORT;
>> +
>> + list_for_each_entry(report, &report_enum->report_list, list) {
>> + size_t report_size = wacom_hid_report_len(report);
>> + if (report_size > size)
>> + size = report_size;
>> + }
>> +
>> + return size;
>> +}
>> +
>> static int wacom_probe(struct hid_device *hdev,
>> const struct hid_device_id *id)
>> {
>> struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
>> struct usb_device *dev = interface_to_usbdev(intf);
>> - struct usb_endpoint_descriptor *endpoint;
>> struct wacom *wacom;
>> struct wacom_wac *wacom_wac;
>> struct wacom_features *features;
>> @@ -1258,6 +1254,7 @@ static int wacom_probe(struct hid_device *hdev,
>> wacom_wac = &wacom->wacom_wac;
>> wacom_wac->features = *((struct wacom_features *)id->driver_data);
>> features = &wacom_wac->features;
>> + features->pktlen = wacom_compute_pktlen(hdev);
>> if (features->pktlen > WACOM_PKGLEN_MAX) {
>> error = -EINVAL;
>> goto fail1;
>> @@ -1275,8 +1272,6 @@ static int wacom_probe(struct hid_device *hdev,
>> usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
>> strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
>>
>> - endpoint = &intf->cur_altsetting->endpoint[0].desc;
>> -
>> /* set the default size in case we do not get them from hid */
>> wacom_set_default_phy(features);
>>
>> @@ -1287,13 +1282,12 @@ static int wacom_probe(struct hid_device *hdev,
>>
>> /*
>> * Intuos5 has no useful data about its touch interface in its
>> - * HID descriptor. If this is the touch interface (wMaxPacketSize
>> + * HID descriptor. If this is the touch interface (PacketSize
>> * of WACOM_PKGLEN_BBTOUCH3), override the table values.
>> */
>> if (features->type >= INTUOS5S && features->type <= INTUOSHT) {
>> - if (endpoint->wMaxPacketSize == WACOM_PKGLEN_BBTOUCH3) {
>> + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) {
>> features->device_type = BTN_TOOL_FINGER;
>> - features->pktlen = WACOM_PKGLEN_BBTOUCH3;
>>
>> features->x_max = 4096;
>> features->y_max = 4096;
>> --
>> 2.0.0
>>
> --
> 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
--
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
* Re: [Linuxwacom-devel] [PATCH 00/15] Input - Wacom: switch from an USB to a HID driver
From: Benjamin Tissoires @ 2014-07-11 13:28 UTC (permalink / raw)
To: Przemo Firszt
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Ping Cheng,
Jason Gerecke, linuxwacom-devel, linux-kernel@vger.kernel.org,
linux-input
In-Reply-To: <1405027816.2613.17.camel@fedora-lan>
Hi Przemo,
On Thu, Jul 10, 2014 at 5:30 PM, Przemo Firszt <przemo@firszt.eu> wrote:
> Hi Benjamin,
> I'm having some problems to cleanly apply your patches - can you double
> check that they are OK?
These patches relies on a previous patchset I sent earlier. So they do
not apply cleanly on top of Dmitry's tree as long as the previous
patch set has not been merged :(
As I mentioned in the last series I sent, I pushed a git tree with the
various series applied:
https://github.com/bentiss/linux/commits/hid-wacom-legacy-3.16-rc4
First series is the split of the pad input + various cleanups:
719eaed64c...003c44a74840
Then this series:
71d0261b7b...9be3b169b23
And the last series I sent yesterday:
4fabeed121...f01c5684e6
This is not an ideal solution, but I hope we will figure out soon
enough the way we can merge this upstream (through the HID tree or the
Input tree).
Anyway, I am planing of re-sending the whole various patch series soon
so the maintainer can pick them directly instead of having to dig in
the linux-input archives.
Cheers,
Benjamin
> --
> Regards,
> Przemo
>
> --
> 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
* Re: [PATCH 00/15] Input - Wacom: switch from an USB to a HID driver
From: Benjamin Tissoires @ 2014-07-11 13:30 UTC (permalink / raw)
To: Jason Gerecke
Cc: Benjamin Tissoires, Dmitry Torokhov, Jiri Kosina, Ping Cheng,
Linux Input, linux-kernel@vger.kernel.org, linuxwacom-devel
In-Reply-To: <CANRwn3TP3ROaxU6AuzLobJt7cE1mAQViKhTUwg2aVw=2XoxDBg@mail.gmail.com>
Hi Jason,
On Thu, Jul 10, 2014 at 9:17 PM, Jason Gerecke <killertofu@gmail.com> wrote:
> On Wed, Jul 2, 2014 at 4:33 PM, Jason Gerecke <killertofu@gmail.com> wrote:
>> On Mon, Jun 30, 2014 at 2:26 PM, Benjamin Tissoires
>> <benjamin.tissoires@redhat.com> wrote:
>>> Hi guys,
>>>
>>> this patch series is a cleanup for the Wacom USB driver.
>>>
>>> I started working on this topic when I saw patches floating around which
>>> implemented a report descriptor parser within the wacom.ko module.
>>> However, we already have a nice HID subsystem which is more generic than the
>>> HID implementation we can find in this USB driver.
>>> Further details of the benefits (code reduction, regression tests) are hopefully
>>> explained in the commit messages of the corresponding patches.
>>>
>>> Also, I am working on a way to handle the new Wacom tablets in a more generic
>>> way in the hid tree, so consider this patch series as a first step in this
>>> direction.
>>>
>>> This patch series transfers the wacom.ko driver from the input tree into the hid
>>> tree. I did not made the corresponding move of the files in the series hoping
>>> that we will find a way to achieve it if this step is validated.
>>>
>>> IMO, the smoothest path would be that Jiri takes care of the wacom driver
>>> in the input tree (and that we move into into the hid subfolder). This can be
>>> achieve if the current pending wacom patches are applied in the hid tree too.
>>>
>>> Another solution could be to keep the wacom changes in the input tree and put the
>>> hid changes in the hid tree by using separate commits. Once 3.17 is out, we can
>>> then change the module into the hid subfolder.
>>>
>>> I wanted to send this patch series right now so we can figure out how we will
>>> handle the transition.
>>>
>>> I am pretty confident the patch series does not break any existing device
>>> (except for the required user space changes which can be handled correctly if
>>> we tackle them right now). The USB commands are executed in the same way,
>>> and the protocol handling is also done in the same way.
>>>
>>> Anyway, the net difference in lines of code (-307) should be enough to be of
>>> interest.
>>>
>>> Note: This patch series requires the current pending wacom patches to be applied.
>>> I set up a tree with all the patch applied if anyone wants to give a try:
>>> https://github.com/bentiss/linux/commits/hid-wacom-legacy-3.16-rc3
>>>
>>> Cheers,
>>> Benjamin
>>>
>>> Benjamin Tissoires (15):
>>> Input - wacom: include and use linux/hid.h
>>> Input - wacom: switch from an USB driver to a HID driver
>>> Input - wacom: use hid communication instead of plain usb
>>> Input - wacom: use HID core to actually fetch the report descriptor
>>> Input - wacom: compute the HID report size to get the actual packet
>>> size
>>> Input - wacom: install LED/OLED sysfs files in the HID device instead
>>> of USB
>>> Input - wacom: register the input devices on top of the HID one
>>> Input - wacom: remove usb dependency for siblings devices
>>> Input - wacom: register power device at the HID level
>>> Input - wacom: use hid_info instead of plain dev_info
>>> HID: uhid: add and set HID_TYPE_UHID for uhid devices
>>> Input - wacom: use in-kernel HID parser
>>> Input - wacom: use hidinput_calc_abs_res instead of duplicating its
>>> code
>>> Input - wacom: remove field pktlen declaration in the list of devices
>>> Input - wacom: keep wacom_ids ordered
>>>
>>> drivers/hid/hid-core.c | 15 +-
>>> drivers/hid/hid-wacom.c | 2 +-
>>> drivers/hid/uhid.c | 2 +
>>> drivers/input/tablet/wacom.h | 7 +-
>>> drivers/input/tablet/wacom_sys.c | 908 +++++++++++++--------------------------
>>> drivers/input/tablet/wacom_wac.c | 647 ++++++++++++++--------------
>>> drivers/input/tablet/wacom_wac.h | 10 +-
>>> include/linux/hid.h | 4 +-
>>> 8 files changed, 644 insertions(+), 951 deletions(-)
>>>
>>> --
>>> 2.0.0
>>>
>>
>> *cracks knuckles*
>>
>> Well, guess I better get to work poking and prodding at these and the
>> pad patches. A very quick review doesn't raise any significant flags,
>> though I do have a question or two that I might have for you in the
>> next few days (need to read through the code more carefully to be sure
>> I understand it correctly). My 24HDT is having some trouble
>> initializing with the patches applied, but I'll need some time to
>> track down the cause. Not sure how much I'll get done this week
>> (holiday weekend) but next week I should have some feedback.
>>
>> Jason
>> ---
>> Now instead of four in the eights place /
>> you’ve got three, ‘Cause you added one /
>> (That is to say, eight) to the two, /
>> But you can’t take seven from three, /
>> So you look at the sixty-fours....
>
> I've had a chance to try out a dozen tablets with these modifications
> and for the most part things seem to work fine. The 24HDT issue I
> mentioned above was due to a conflict with some other patches I was
> testing and can be ignored. Aside from the other known issues you've
> already mentioned (and my inline comments), there's not much that I
> can say (other than that I found some odd [but apparently unrelated]
> issues with wacom_w8001 and isdv4-serial-inputattach...)
>
> Reviewed-by: Jason Gerecke <killertofu@gmail.com>
> Tested-by: Jason Gerecke <killertofu@gmail.com>
>
Thanks Jason. That's really appreciated. As said I will resend a full
cleanup of these with your Rev-by and fixes, so Dmitry or Jiri can
take the various series.
Cheers,
Benjamin
--
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
* Re: [PATCH 00/15] Input - Wacom: switch from an USB to a HID driver
From: Jiri Kosina @ 2014-07-11 13:47 UTC (permalink / raw)
To: Benjamin Tissoires
Cc: Jason Gerecke, Benjamin Tissoires, Dmitry Torokhov, Ping Cheng,
Linux Input, linux-kernel@vger.kernel.org, linuxwacom-devel
In-Reply-To: <CAN+gG=FY7kVAWJWsPpNW8g_vcPekLVmVeH3tHfUzxR0nTTd87w@mail.gmail.com>
On Fri, 11 Jul 2014, Benjamin Tissoires wrote:
> Thanks Jason. That's really appreciated. As said I will resend a full
> cleanup of these with your Rev-by and fixes, so Dmitry or Jiri can
> take the various series.
Just for the record, I will be mostly offline for the upcoming 2 weeks.
--
Jiri Kosina
SUSE Labs
^ permalink raw reply
* Re: [PATCH] Input: Add driver for Microchip's CAP1106
From: Daniel Mack @ 2014-07-11 17:42 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: David Herrmann, list@mail.zonque.de: HID CORE LAYER, Mark Brown,
devicetree
In-Reply-To: <20140711173336.GA492@core.coreip.homeip.net>
On 07/11/2014 07:33 PM, Dmitry Torokhov wrote:
> On Fri, Jul 11, 2014 at 11:48:48AM +0200, Daniel Mack wrote:
>> On 07/11/2014 11:43 AM, David Herrmann wrote:
>>>> +static void cap1106_work(struct work_struct *w)
>>>>> +{
>>>>> + struct cap1106_priv *priv = container_of(w, struct cap1106_priv, work);
>>>>> + unsigned int status;
>>>>> + int ret, i;
>>>>> +
>>>>> + spin_lock(&priv->lock);
>>> If your worker started and is _about_ to take the spinlock, you might
>>> dead-lock with cap1106_close(). They might already hold the spinlock
>>> and then call cancel_work_sync(), thus waiting for this task to take
>>> the lock end exit..
>>>
>>> How about you add "bool closed : 1;" to your cap1106_priv structure
>>> and drop the lock here, but..
>>>
>>
>> Thanks for the review, David. Will look into it and send a v2 with these
>> changes soon.
>
> Why aren't you using threaded oneshot IRQ for this? Then you would not
> need all this dancing around with worker and enabling/disabling
> interrupt.
Ah, right, that's much nicer indeed.
Thanks for the pointer! I'll post v3 later.
Daniel
^ permalink raw reply
* [PATCH] HID: rmi: add additional checks for the existence of optional queries in order to compute the address of Query 12.
From: Andrew Duggan @ 2014-07-11 21:35 UTC (permalink / raw)
To: linux-input, linux-kernel; +Cc: Andrew Duggan, Jiri Kosina, Benjamin Tissoires
There are additional queries which are optional and may not be present depending on the configuration of the firmware. Knowing which queries are present is needed to properly compute the address of Query 12 and all subsequent queries. Additional bits in Query 1 are used to indicate the presence of these optional queries.
Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
---
drivers/hid/hid-rmi.c | 35 +++++++++++++++++++++++++----------
1 file changed, 25 insertions(+), 10 deletions(-)
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 578bbe6..3221a95 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -549,10 +549,12 @@ static int rmi_populate_f11(struct hid_device *hdev)
u8 buf[20];
int ret;
bool has_query9;
- bool has_query10;
+ bool has_query10 = false;
bool has_query11;
bool has_query12;
bool has_physical_props;
+ bool has_gestures;
+ bool has_rel;
unsigned x_size, y_size;
u16 query12_offset;
@@ -589,19 +591,32 @@ static int rmi_populate_f11(struct hid_device *hdev)
return -ENODEV;
}
- /* query 8 to find out if query 10 exists */
- ret = rmi_read(hdev, data->f11.query_base_addr + 8, buf);
- if (ret) {
- hid_err(hdev, "can not read gesture information: %d.\n", ret);
- return ret;
+ has_rel = !!(buf[0] & BIT(3));
+ has_gestures = !!(buf[0] & BIT(5));
+
+ if (has_gestures) {
+ /* query 8 to find out if query 10 exists */
+ ret = rmi_read(hdev, data->f11.query_base_addr + 8, buf);
+ if (ret) {
+ hid_err(hdev, "can not read gesture information: %d.\n",
+ ret);
+ return ret;
+ }
+ has_query10 = !!(buf[0] & BIT(2));
}
- has_query10 = !!(buf[0] & BIT(2));
/*
- * At least 8 queries are guaranteed to be present in F11
- * +1 for query12.
+ * At least 4 queries are guaranteed to be present in F11
+ * +1 for query 5 which is present since absolute events are
+ * reported and +1 for query 12.
*/
- query12_offset = 9;
+ query12_offset = 6;
+
+ if (has_rel)
+ ++query12_offset; /* query 6 is present */
+
+ if (has_gestures)
+ query12_offset += 2; /* query 7 and 8 are present */
if (has_query9)
++query12_offset;
--
1.9.1
^ permalink raw reply related
* [PATCH] HID: rmi: change logging level of log messages related to unexpected reports
From: Andrew Duggan @ 2014-07-11 21:35 UTC (permalink / raw)
To: linux-input, linux-kernel
Cc: Andrew Duggan, Jiri Kosina, Benjamin Tissoires
In-Reply-To: <1405114551-24354-1-git-send-email-aduggan@synaptics.com>
Userspace tools may use hidraw to perform operations on the device from userspace while
hid-rmi is bound to the device. This can cause hid-rmi to print error messages when its
->raw_event() callback gets called as the reports pass through the HID stack. In this case
receiving responses which were not initiated by hid-rmi is not actually an error so the resulting
error messages are incorrect and misleading. This patch changes the log messages to debug so
that the messages can be turned on in the event that there is a problem and there is not
a userspace tool running.
Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
---
drivers/hid/hid-rmi.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index 578bbe6..25f571a 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -377,7 +377,7 @@ static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
irq_mask |= hdata->f30.irq_mask;
if (data[1] & ~irq_mask)
- hid_warn(hdev, "unknown intr source:%02lx %s:%d\n",
+ hid_dbg(hdev, "unknown intr source:%02lx %s:%d\n",
data[1] & ~irq_mask, __FILE__, __LINE__);
if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) {
@@ -400,7 +400,7 @@ static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
struct rmi_data *hdata = hid_get_drvdata(hdev);
if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) {
- hid_err(hdev, "no read request pending\n");
+ hid_dbg(hdev, "no read request pending\n");
return 0;
}
--
1.9.1
^ permalink raw reply related
* [PATCH v3] Input: Add driver for Microchip's CAP1106
From: Daniel Mack @ 2014-07-11 22:49 UTC (permalink / raw)
To: dtor; +Cc: linux-input, broonie, dh.herrmann, devicetree, Daniel Mack
This patch adds a driver for Microchips CAP1106, an I2C driven, 6-channel
capacitive touch sensor.
For now, only the capacitive buttons are supported, and no specific
settings that can be tweaked for individual channels, except for the
device-wide sensitivity gain. The defaults seem to work just fine out of
the box, so I'll leave configurable parameters for someone who's in need
of them and who can actually measure the impact. All registers are
prepared, however. Many of them are just not used for now.
The implementation does not make any attempt to be compatible to platform
data driven boards, but fully depends on CONFIG_OF.
Power management functions are also left for volounteers with the ability
to actually test them.
Signed-off-by: Daniel Mack <zonque@gmail.com>
---
v2:
* Fix potential deadlocks pointed out by David.
v3:
* Use devm_request_threaded_irq() and get rid of the work struct.
* Drop ->open() and ->close() as it isn't actually needed for an
interrupt-driven device. This way, we can also get rid of the
locking entirely.
.../devicetree/bindings/input/cap1106.txt | 63 ++++
drivers/input/keyboard/Kconfig | 10 +
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/cap1106.c | 322 +++++++++++++++++++++
4 files changed, 396 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/cap1106.txt
create mode 100644 drivers/input/keyboard/cap1106.c
diff --git a/Documentation/devicetree/bindings/input/cap1106.txt b/Documentation/devicetree/bindings/input/cap1106.txt
new file mode 100644
index 0000000..57f5af3
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/cap1106.txt
@@ -0,0 +1,63 @@
+Device tree bindings for Microchip CAP1106, 6 channel capacitive touch sensor
+
+The node for this driver must be a child of a I2C controller node, as the
+device communication via I2C only.
+
+Required properties:
+
+ compatible: Must be "microchip,cap1106"
+ reg: The I2C slave address of the device.
+ Only 0x28 is valid.
+ interrupt: Node describing the interrupt line the device's
+ ALERT#/CM_IRQ# pin is connected to.
+
+Optional properties:
+
+ autorepeat: Enables the Linux input system's autorepeat
+ feature on the input device.
+ microchip,sensor-gain: Defines the gain of the sensor circuitry. This
+ effectively controls the sensitivity, as a
+ smaller delta capacitance is required to
+ generate the same delta count values.
+ Valid values are 1, 2, 4, and 8.
+ By default, a gain of 1 is set.
+
+To define details of each individual button channel, six subnodes can be
+specified. Inside each of those, the following property is valid:
+
+ linux,keycode: Specify the numeric identifier of the keycode to be
+ generated when this channel is activated. If this
+ property is omitted, KEY_A, KEY_B, etc are used as
+ defaults.
+
+Example:
+
+i2c_controller {
+ cap1106@28 {
+ compatible = "microchip,cap1106";
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 0>;
+ reg = <0x28>;
+ autorepeat;
+ microchip,sensor-gain = <2>;
+
+ up {
+ linux,keycode = <103>; /* KEY_UP */
+ };
+ right {
+ linux,keycode = <106>; /* KEY_RIGHT */
+ };
+ down {
+ linux,keycode = <108>; /* KEY_DOWN */
+ };
+ left {
+ linux,keycode = <105>; /* KEY_LEFT */
+ };
+ pagedown {
+ linux,keycode = <109>; /* KEY_PAGEDOWN */
+ };
+ pageup {
+ linux,keycode = <104>; /* KEY_PAGEUP */
+ };
+ };
+}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index f7e79b4..a3958c6 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -665,4 +665,14 @@ config KEYBOARD_CROS_EC
To compile this driver as a module, choose M here: the
module will be called cros_ec_keyb.
+config KEYBOARD_CAP1106
+ tristate "Microchip CAP1106 touch sensor"
+ depends on OF && I2C
+ select REGMAP_I2C
+ help
+ Say Y here to enable the CAP1106 touch sensor driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cap1106.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 7504ae1..0a33456 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
+obj-$(CONFIG_KEYBOARD_CAP1106) += cap1106.o
obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
diff --git a/drivers/input/keyboard/cap1106.c b/drivers/input/keyboard/cap1106.c
new file mode 100644
index 0000000..14142af
--- /dev/null
+++ b/drivers/input/keyboard/cap1106.c
@@ -0,0 +1,322 @@
+/*
+ * Input driver for Microchip CAP1106, 6 channel capacitive touch sensor
+ *
+ * http://www.microchip.com/wwwproducts/Devices.aspx?product=CAP1106
+ *
+ * (c) 2014 Daniel Mack <linux@zonque.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/input.h>
+#include <linux/of_irq.h>
+#include <linux/regmap.h>
+#include <linux/i2c.h>
+#include <linux/gpio/consumer.h>
+
+#define CAP1106_REG_MAIN_CONTROL 0x00
+#define CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT (6)
+#define CAP1106_REG_MAIN_CONTROL_GAIN_MASK (0xc0)
+#define CAP1106_REG_GENERAL_STATUS 0x02
+#define CAP1106_REG_SENSOR_INPUT 0x03
+#define CAP1106_REG_NOISE_FLAG_STATUS 0x0a
+#define CAP1106_REG_SENOR_DELTA(X) (0x10 + (X))
+#define CAP1106_REG_SENSITIVITY_CONTROL 0x1f
+#define CAP1106_REG_CONFIG 0x20
+#define CAP1106_REG_SENSOR_ENABLE 0x21
+#define CAP1106_REG_SENSOR_CONFIG 0x22
+#define CAP1106_REG_SENSOR_CONFIG2 0x23
+#define CAP1106_REG_SAMPLING_CONFIG 0x24
+#define CAP1106_REG_CALIBRATION 0x25
+#define CAP1106_REG_INT_ENABLE 0x26
+#define CAP1106_REG_REPEAT_RATE 0x28
+#define CAP1106_REG_MT_CONFIG 0x2a
+#define CAP1106_REG_MT_PATTERN_CONFIG 0x2b
+#define CAP1106_REG_MT_PATTERN 0x2d
+#define CAP1106_REG_RECALIB_CONFIG 0x2f
+#define CAP1106_REG_SENSOR_THRESH(X) (0x30 + (X))
+#define CAP1106_REG_SENSOR_NOISE_THRESH 0x38
+#define CAP1106_REG_STANDBY_CHANNEL 0x40
+#define CAP1106_REG_STANDBY_CONFIG 0x41
+#define CAP1106_REG_STANDBY_SENSITIVITY 0x42
+#define CAP1106_REG_STANDBY_THRESH 0x43
+#define CAP1106_REG_CONFIG2 0x44
+#define CAP1106_REG_SENSOR_BASE_CNT(X) (0x50 + (X))
+#define CAP1106_REG_SENSOR_CALIB (0xb1 + (X))
+#define CAP1106_REG_SENSOR_CALIB_LSB1 0xb9
+#define CAP1106_REG_SENSOR_CALIB_LSB2 0xba
+#define CAP1106_REG_PRODUCT_ID 0xfd
+#define CAP1106_REG_MANUFACTURER_ID 0xfe
+#define CAP1106_REG_REVISION 0xff
+
+#define CAP1106_NUM_CHN 6
+#define CAP1106_PRODUCT_ID 0x55
+#define CAP1106_MANUFACTURER_ID 0x5d
+
+struct cap1106_priv {
+ struct regmap *regmap;
+ struct input_dev *idev;
+
+ /* config */
+ unsigned int keycodes[CAP1106_NUM_CHN];
+};
+
+static const struct reg_default cap1106_reg_defaults[] = {
+ { CAP1106_REG_MAIN_CONTROL, 0x00 },
+ { CAP1106_REG_GENERAL_STATUS, 0x00 },
+ { CAP1106_REG_SENSOR_INPUT, 0x00 },
+ { CAP1106_REG_NOISE_FLAG_STATUS, 0x00 },
+ { CAP1106_REG_SENSITIVITY_CONTROL, 0x2f },
+ { CAP1106_REG_CONFIG, 0x20 },
+ { CAP1106_REG_SENSOR_ENABLE, 0x3f },
+ { CAP1106_REG_SENSOR_CONFIG, 0xa4 },
+ { CAP1106_REG_SENSOR_CONFIG2, 0x07 },
+ { CAP1106_REG_SAMPLING_CONFIG, 0x39 },
+ { CAP1106_REG_CALIBRATION, 0x00 },
+ { CAP1106_REG_INT_ENABLE, 0x3f },
+ { CAP1106_REG_REPEAT_RATE, 0x3f },
+ { CAP1106_REG_MT_CONFIG, 0x80 },
+ { CAP1106_REG_MT_PATTERN_CONFIG, 0x00 },
+ { CAP1106_REG_MT_PATTERN, 0x3f },
+ { CAP1106_REG_RECALIB_CONFIG, 0x8a },
+ { CAP1106_REG_SENSOR_THRESH(0), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(1), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(2), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(3), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(4), 0x40 },
+ { CAP1106_REG_SENSOR_THRESH(5), 0x40 },
+ { CAP1106_REG_SENSOR_NOISE_THRESH, 0x01 },
+ { CAP1106_REG_STANDBY_CHANNEL, 0x00 },
+ { CAP1106_REG_STANDBY_CONFIG, 0x39 },
+ { CAP1106_REG_STANDBY_SENSITIVITY, 0x02 },
+ { CAP1106_REG_STANDBY_THRESH, 0x40 },
+ { CAP1106_REG_CONFIG2, 0x40 },
+ { CAP1106_REG_SENSOR_CALIB_LSB1, 0x00 },
+ { CAP1106_REG_SENSOR_CALIB_LSB2, 0x00 },
+};
+
+static bool cap1106_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case CAP1106_REG_MAIN_CONTROL:
+ case CAP1106_REG_SENSOR_INPUT:
+ case CAP1106_REG_SENOR_DELTA(0):
+ case CAP1106_REG_SENOR_DELTA(1):
+ case CAP1106_REG_SENOR_DELTA(2):
+ case CAP1106_REG_SENOR_DELTA(3):
+ case CAP1106_REG_SENOR_DELTA(4):
+ case CAP1106_REG_SENOR_DELTA(5):
+ case CAP1106_REG_PRODUCT_ID:
+ case CAP1106_REG_MANUFACTURER_ID:
+ case CAP1106_REG_REVISION:
+ return true;
+ }
+
+ return false;
+}
+
+static const struct regmap_config cap1106_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = CAP1106_REG_REVISION,
+ .reg_defaults = cap1106_reg_defaults,
+
+ .num_reg_defaults = ARRAY_SIZE(cap1106_reg_defaults),
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = cap1106_volatile_reg,
+};
+
+static irqreturn_t cap1106_thread_func(int irq_num, void *data)
+{
+ struct cap1106_priv *priv = data;
+ unsigned int status;
+ int ret, i;
+
+ /*
+ * Deassert interrupt. This needs to be done before reading the status
+ * registers, which will not carry valid values otherwise.
+ */
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL, 1, 0);
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_SENSOR_INPUT, &status);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < CAP1106_NUM_CHN; i++)
+ input_report_key(priv->idev, priv->keycodes[i],
+ status & (1 << i));
+
+ input_sync(priv->idev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int cap1106_i2c_probe(struct i2c_client *i2c_client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &i2c_client->dev;
+ struct device_node *child, *node;
+ struct cap1106_priv *priv;
+ unsigned int val, rev;
+ int i, ret, irq;
+ u8 gain = 0;
+ u32 tmp32;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regmap = devm_regmap_init_i2c(i2c_client, &cap1106_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_PRODUCT_ID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != CAP1106_PRODUCT_ID) {
+ dev_err(dev, "Product ID: Got 0x%02x, expected 0x%02x\n",
+ val, CAP1106_PRODUCT_ID);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_MANUFACTURER_ID, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val != CAP1106_MANUFACTURER_ID) {
+ dev_err(dev, "Manufacturer ID: Got 0x%02x, expected 0x%02x\n",
+ val, CAP1106_MANUFACTURER_ID);
+ return -ENODEV;
+ }
+
+ ret = regmap_read(priv->regmap, CAP1106_REG_REVISION, &rev);
+ if (ret < 0)
+ return ret;
+
+ dev_info(dev, "CAP1106 detected, revision 0x%02x\n", rev);
+ i2c_set_clientdata(i2c_client, priv);
+ node = dev->of_node;
+
+ if (!of_property_read_u32(node, "microchip,sensor-gain", &tmp32)) {
+ if (is_power_of_2(tmp32) && tmp32 <= 8)
+ gain = ilog2(tmp32);
+ else
+ dev_err(dev, "Invalid sensor-gain value %d\n", tmp32);
+ }
+
+ ret = regmap_update_bits(priv->regmap, CAP1106_REG_MAIN_CONTROL,
+ CAP1106_REG_MAIN_CONTROL_GAIN_MASK,
+ gain << CAP1106_REG_MAIN_CONTROL_GAIN_SHIFT);
+ if (ret < 0)
+ return ret;
+
+ /* disable autorepeat. The Linux input system has its own handling. */
+ ret = regmap_write(priv->regmap, CAP1106_REG_REPEAT_RATE, 0);
+ if (ret < 0)
+ return ret;
+
+ /* set the defaults */
+ for (i = 0; i < CAP1106_NUM_CHN; i++)
+ priv->keycodes[i] = KEY_A + i;
+
+ i = 0;
+ for_each_child_of_node(node, child) {
+ if (i == CAP1106_NUM_CHN) {
+ dev_err(dev, "Too many button nodes.\n");
+ return -EINVAL;
+ }
+
+ if (!of_property_read_u32(child, "linux,keycode", &tmp32))
+ priv->keycodes[i] = tmp32;
+
+ i++;
+ }
+
+ priv->idev = devm_input_allocate_device(dev);
+ if (!priv->idev)
+ return -ENOMEM;
+
+ priv->idev->name = "CAP1106 capacitive touch sensor";
+ priv->idev->id.bustype = BUS_I2C;
+ priv->idev->evbit[0] = BIT_MASK(EV_KEY);
+
+ if (of_get_property(node, "autorepeat", NULL))
+ __set_bit(EV_REP, priv->idev->evbit);
+
+ for (i = 0; i < CAP1106_NUM_CHN; i++) {
+ unsigned int code = priv->keycodes[i];
+ priv->idev->keybit[BIT_WORD(code)] |= BIT_MASK(code);
+ }
+
+ priv->idev->id.vendor = CAP1106_MANUFACTURER_ID;
+ priv->idev->id.product = CAP1106_PRODUCT_ID;
+ priv->idev->id.version = rev;
+
+ input_set_drvdata(priv->idev, priv);
+
+ ret = input_register_device(priv->idev);
+ if (ret < 0)
+ return ret;
+
+ irq = irq_of_parse_and_map(node, 0);
+ if (!irq) {
+ dev_err(dev, "Unable to parse or map IRQ\n");
+ return -ENXIO;
+ }
+
+ ret = devm_request_threaded_irq(dev, irq, NULL, cap1106_thread_func,
+ IRQF_ONESHOT, dev_name(dev), priv);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int cap1106_i2c_remove(struct i2c_client *i2c_client)
+{
+ struct cap1106_priv *priv = i2c_get_clientdata(i2c_client);
+
+ input_unregister_device(priv->idev);
+
+ return 0;
+}
+
+static const struct of_device_id cap1106_dt_ids[] = {
+ { .compatible = "microchip,cap1106", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cap1106_dt_ids);
+
+static const struct i2c_device_id cap1106_i2c_ids[] = {
+ { "cap1106", 0 },
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, cap1106_i2c_ids);
+
+static struct i2c_driver cap1106_i2c_driver = {
+ .driver = {
+ .name = "cap1106",
+ .owner = THIS_MODULE,
+ .of_match_table = cap1106_dt_ids,
+ },
+ .id_table = cap1106_i2c_ids,
+ .probe = cap1106_i2c_probe,
+ .remove = cap1106_i2c_remove,
+};
+
+module_i2c_driver(cap1106_i2c_driver);
+
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DESCRIPTION("Microchip CAP1106 driver");
+MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
+MODULE_LICENSE("GPL v2");
--
1.9.3
^ 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