Message ID | 1405073193-21448-1-git-send-email-zonque@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, Jul 11, 2014 at 11:06:33AM +0100, Daniel Mack 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> > --- > 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. s/interrupt/interrupts/ This is a _property_, not a node. I take it the device only has a single interrupt line? > + > +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. Does the official documentation describe this in absolute terms? > + > +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. What are those subnodes, and how are they told apart? Name, compatible? I strongly recommend against relying on the order of the DT. It's very easy for that to get messed up and makes things hard to read. Is is not possible to use linux,keymap and treat the buttons as a matrix keypad? Then you don't need subnodes at all, and you can have a sparse keymap if you want. [...] > +struct cap1106_priv { > + struct regmap *regmap; > + struct input_dev *idev; > + struct work_struct work; > + spinlock_t lock; > + bool closed:1; I don't think you're saving anything here by trying to have a bool bitfield. [...] > + 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++; > + } I don't think that it is a good idea to rely on the order of sub-nodes in the DTB. [...] > + if (of_get_property(node, "autorepeat", NULL)) > + __set_bit(EV_REP, priv->idev->evbit); Use of_property_read_bool. /me mutters usual grumblings about the autorepeat property. Thanks, Mark. -- 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
Hi Mark, thanks a lot for your feedback! Much appreciated. On 07/14/2014 11:52 AM, Mark Rutland wrote: > On Fri, Jul 11, 2014 at 11:06:33AM +0100, Daniel Mack wrote: >> +++ 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. > > s/interrupt/interrupts/ > > This is a _property_, not a node. Yes, I reworded that description a couple of times. Together with interrupt-parent, it's actually a property referencing a node ;) Will fix. > I take it the device only has a single interrupt line? Yes. >> + >> +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. > > Does the official documentation describe this in absolute terms? The documentation describes the gain feature as "1, 2, 4, or 8", so I kept it like this in the bindings. Internally, the register stores that value in 2 bits. The driver takes care for the translation. >> +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. > > What are those subnodes, and how are they told apart? Name, compatible? > > I strongly recommend against relying on the order of the DT. It's very > easy for that to get messed up and makes things hard to read. > > Is is not possible to use linux,keymap and treat the buttons as a > matrix keypad? Then you don't need subnodes at all, and you can have a > sparse keymap if you want. Hmm, I thought about that, but there are - in theory - more details that could be specified per channel. I left those functions out for the first version, as I have no good way to test them. Hence, my idea was to have everything related to one channel nicely grouped in a subnode. I've also seen bindings that rely on the order of subnodes before, for example in regulator drivers. But I agree with you that it makes board definitions error-prone. linux,keycode feels a bit overkill here though, so I'd rather go for a fixed-size linux,keycodes property. The number of entries is fixed, anyway. Would you be fine with that? >> +struct cap1106_priv { >> + struct regmap *regmap; >> + struct input_dev *idev; >> + struct work_struct work; >> + spinlock_t lock; >> + bool closed:1; > > I don't think you're saving anything here by trying to have a bool > bitfield. That variable has been dropped in v3 already :) >> + 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++; >> + } > > I don't think that it is a good idea to rely on the order of sub-nodes > in the DTB. Jup, I agree. As mentioned above, I'd like to solve that with linux,keycode for now. > [...] > >> + if (of_get_property(node, "autorepeat", NULL)) >> + __set_bit(EV_REP, priv->idev->evbit); > > Use of_property_read_bool. Will do, thanks. > /me mutters usual grumblings about the autorepeat property. I took that from the gpio-keys driver. Is there a better way to denote such a feature? Thanks, Daniel -- 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
On Mon, Jul 14, 2014 at 11:20:17AM +0100, Daniel Mack wrote: > Hi Mark, > > thanks a lot for your feedback! Much appreciated. > > On 07/14/2014 11:52 AM, Mark Rutland wrote: > > On Fri, Jul 11, 2014 at 11:06:33AM +0100, Daniel Mack wrote: > > >> +++ 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. > > > > s/interrupt/interrupts/ > > > > This is a _property_, not a node. > > Yes, I reworded that description a couple of times. Together with > interrupt-parent, it's actually a property referencing a node ;) Will fix. > > > I take it the device only has a single interrupt line? > > Yes. Ok, that sounds fine then. > >> + > >> +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. > > > > Does the official documentation describe this in absolute terms? > > The documentation describes the gain feature as "1, 2, 4, or 8", so I > kept it like this in the bindings. Internally, the register stores that > value in 2 bits. The driver takes care for the translation. That sounds fine. > >> +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. > > > > What are those subnodes, and how are they told apart? Name, compatible? > > > > I strongly recommend against relying on the order of the DT. It's very > > easy for that to get messed up and makes things hard to read. > > > > Is is not possible to use linux,keymap and treat the buttons as a > > matrix keypad? Then you don't need subnodes at all, and you can have a > > sparse keymap if you want. > > Hmm, I thought about that, but there are - in theory - more details that > could be specified per channel. I left those functions out for the first > version, as I have no good way to test them. Ok. Could you elaborate on what those details might be? It might make sense to have these as nodes if there are arbitrary properties to describe for each button, but I'm not familiar enough with the hardware to make a call either way. > Hence, my idea was to have everything related to one channel nicely > grouped in a subnode. I've also seen bindings that rely on the order of > subnodes before, for example in regulator drivers. Sure. There's plenty of bad practice in DT bindings and code. There's just too much of it going on to get everything sane, and it's not always possible to fix the insane stuff if people are already using it. > But I agree with you that it makes board definitions error-prone. > > linux,keycode feels a bit overkill here though, so I'd rather go for a > fixed-size linux,keycodes property. The number of entries is fixed, > anyway. Would you be fine with that? Assuming no-one's likely to want a sparse keymap (i.e. one where some keys do nothing) then that's probably ok. > >> +struct cap1106_priv { > >> + struct regmap *regmap; > >> + struct input_dev *idev; > >> + struct work_struct work; > >> + spinlock_t lock; > >> + bool closed:1; > > > > I don't think you're saving anything here by trying to have a bool > > bitfield. > > That variable has been dropped in v3 already :) > > >> + 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++; > >> + } > > > > I don't think that it is a good idea to rely on the order of sub-nodes > > in the DTB. > > Jup, I agree. As mentioned above, I'd like to solve that with > linux,keycode for now. > > > [...] > > > >> + if (of_get_property(node, "autorepeat", NULL)) > >> + __set_bit(EV_REP, priv->idev->evbit); > > > > Use of_property_read_bool. > > Will do, thanks. > > > /me mutters usual grumblings about the autorepeat property. > > I took that from the gpio-keys driver. Is there a better way to denote > such a feature? Unfortunately not, given current practice. My gripe is that it's a Linux detail that were describing rather than a property of the device. We can forget about that for now. Thanks, Mark. -- 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
On 07/15/2014 10:51 AM, Mark Rutland wrote: > On Mon, Jul 14, 2014 at 11:20:17AM +0100, Daniel Mack wrote: >> Hmm, I thought about that, but there are - in theory - more details that >> could be specified per channel. I left those functions out for the first >> version, as I have no good way to test them. > > Ok. Could you elaborate on what those details might be? It might make > sense to have these as nodes if there are arbitrary properties to > describe for each button, but I'm not familiar enough with the hardware > to make a call either way. No, there are just settings that can be made for each indvidual channel/button, such as sensitivity settings for instance. But they can of course be specified in a similar manner as the keycodes, in a fixed-size array. That's completely ok I think. >> linux,keycode feels a bit overkill here though, so I'd rather go for a >> fixed-size linux,keycodes property. The number of entries is fixed, >> anyway. Would you be fine with that? > > Assuming no-one's likely to want a sparse keymap (i.e. one where some > keys do nothing) then that's probably ok. If such a setup occurs, support for disabling channels could easily be added, and in such cases, the keycode is simple ignored. I don't think a sparse matrix keymap makes much sense here, especially as the buttons are not organized in rows and columns. >>> /me mutters usual grumblings about the autorepeat property. >> >> I took that from the gpio-keys driver. Is there a better way to denote >> such a feature? > > Unfortunately not, given current practice. My gripe is that it's a Linux > detail that were describing rather than a property of the device. We can > forget about that for now. I see, so I'll leave it as it is. I'll drop the input device unregister call as Dmitry said, and repost v5. Thanks again! Daniel -- 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
On Tue, Jul 15, 2014 at 10:12:22AM +0100, Daniel Mack wrote: > On 07/15/2014 10:51 AM, Mark Rutland wrote: > > On Mon, Jul 14, 2014 at 11:20:17AM +0100, Daniel Mack wrote: > > >> Hmm, I thought about that, but there are - in theory - more details that > >> could be specified per channel. I left those functions out for the first > >> version, as I have no good way to test them. > > > > Ok. Could you elaborate on what those details might be? It might make > > sense to have these as nodes if there are arbitrary properties to > > describe for each button, but I'm not familiar enough with the hardware > > to make a call either way. > > No, there are just settings that can be made for each indvidual > channel/button, such as sensitivity settings for instance. But they can > of course be specified in a similar manner as the keycodes, in a > fixed-size array. That's completely ok I think. > > >> linux,keycode feels a bit overkill here though, so I'd rather go for a > >> fixed-size linux,keycodes property. The number of entries is fixed, > >> anyway. Would you be fine with that? > > > > Assuming no-one's likely to want a sparse keymap (i.e. one where some > > keys do nothing) then that's probably ok. > > If such a setup occurs, support for disabling channels could easily be > added, and in such cases, the keycode is simple ignored. I don't think a > sparse matrix keymap makes much sense here, especially as the buttons > are not organized in rows and columns. > > >>> /me mutters usual grumblings about the autorepeat property. > >> > >> I took that from the gpio-keys driver. Is there a better way to denote > >> such a feature? > > > > Unfortunately not, given current practice. My gripe is that it's a Linux > > detail that were describing rather than a property of the device. We can > > forget about that for now. > > I see, so I'll leave it as it is. > > I'll drop the input device unregister call as Dmitry said, and repost v5. Sure, that all sounds fine. Cheers, Mark. -- 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
Hi Mark, On Tue, Jul 15, 2014 at 09:51:38AM +0100, Mark Rutland wrote: > On Mon, Jul 14, 2014 at 11:20:17AM +0100, Daniel Mack wrote: > > > > linux,keycode feels a bit overkill here though, so I'd rather go for a > > fixed-size linux,keycodes property. The number of entries is fixed, > > anyway. Would you be fine with that? > > Assuming no-one's likely to want a sparse keymap (i.e. one where some > keys do nothing) then that's probably ok. For such a small keymap, if one does not want to use some of the buttons, setting corresponding entries to KEY_RESERVED should work well. > > > > I took that from the gpio-keys driver. Is there a better way to denote > > such a feature? > > Unfortunately not, given current practice. My gripe is that it's a Linux > detail that were describing rather than a property of the device. We can > forget about that for now. I prefer looking at it as user expressing the desired behavior of the driver; it is up to OS to deliver such behavior ;) Thanks.
On Tue, Jul 15, 2014 at 05:41:49PM +0100, Dmitry Torokhov wrote: > Hi Mark, > > On Tue, Jul 15, 2014 at 09:51:38AM +0100, Mark Rutland wrote: > > On Mon, Jul 14, 2014 at 11:20:17AM +0100, Daniel Mack wrote: > > > > > > linux,keycode feels a bit overkill here though, so I'd rather go for a > > > fixed-size linux,keycodes property. The number of entries is fixed, > > > anyway. Would you be fine with that? > > > > Assuming no-one's likely to want a sparse keymap (i.e. one where some > > keys do nothing) then that's probably ok. > > > For such a small keymap, if one does not want to use some of the > buttons, setting corresponding entries to KEY_RESERVED should work well. Ah, I was not aware of KEY_RESERVED. That sounds perfect then. > > > > > > I took that from the gpio-keys driver. Is there a better way to denote > > > such a feature? > > > > Unfortunately not, given current practice. My gripe is that it's a Linux > > detail that were describing rather than a property of the device. We can > > forget about that for now. > > I prefer looking at it as user expressing the desired behavior of the > driver; it is up to OS to deliver such behavior ;) Sure, but the user and DTB author are not the same, and may have different preferences. Additionally autorepeat as a property only tells half the story; I might prefer a 1ms delay while my neighbour Joe might like a 3 billion year delay (he's a bit like that, Joe is). He also only wants the esc key to repeat and can't figure out how to express that in this DTB thing he's never heard of. We can just leave this with me grumbling if you prefer ;) Thanks, Mark. -- 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
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");
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