diff options
Diffstat (limited to 'drivers/input/keyboard')
| -rw-r--r-- | drivers/input/keyboard/Kconfig | 14 | ||||
| -rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
| -rw-r--r-- | drivers/input/keyboard/atkbd.c | 133 | ||||
| -rw-r--r-- | drivers/input/keyboard/charlieplex_keypad.c | 232 | ||||
| -rw-r--r-- | drivers/input/keyboard/cros_ec_keyb.c | 261 | ||||
| -rw-r--r-- | drivers/input/keyboard/imx_keypad.c | 4 | ||||
| -rw-r--r-- | drivers/input/keyboard/mpr121_touchkey.c | 8 | ||||
| -rw-r--r-- | drivers/input/keyboard/qt1050.c | 3 | ||||
| -rw-r--r-- | drivers/input/keyboard/qt1070.c | 3 |
9 files changed, 511 insertions, 148 deletions
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 2ff4fef322c2..9d1019ba0245 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -289,6 +289,20 @@ config KEYBOARD_MATRIX To compile this driver as a module, choose M here: the module will be called matrix_keypad. +config KEYBOARD_CHARLIEPLEX + tristate "GPIO driven charlieplex keypad support" + depends on GPIOLIB || COMPILE_TEST + select INPUT_MATRIXKMAP + help + Enable support for GPIO driven charlieplex keypad. A charlieplex + keypad allows to use fewer GPIO lines to interface to key switches. + For example, an N lines charlieplex keypad can be used to interface + to N^2-N different key switches. However, this type of keypad + cannot detect more than one key press at a time. + + To compile this driver as a module, choose M here: the + module will be called charlieplex_keypad. + config KEYBOARD_HIL_OLD tristate "HP HIL keyboard support (simple driver)" depends on GSC || HP300 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index 2d906e14f3e2..60bb7baf802f 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o +obj-$(CONFIG_KEYBOARD_CHARLIEPLEX) += charlieplex_keypad.o obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o obj-$(CONFIG_KEYBOARD_CYPRESS_SF) += cypress-sf.o diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 840cdf5878dc..c8ad55f26ea8 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -3,10 +3,7 @@ * AT and PS/2 keyboard driver * * Copyright (c) 1999-2002 Vojtech Pavlik - */ - - -/* + * * This driver can handle standard AT keyboards and PS/2 keyboards in * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb * input-only controllers and AT keyboards connected over a one way RS232 @@ -65,8 +62,8 @@ static bool atkbd_terminal; module_param_named(terminal, atkbd_terminal, bool, 0); MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2"); -#define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF) -#define KEYCODE(keymap) (keymap & 0xFFFF) +#define SCANCODE(keymap) (((keymap) >> 16) & 0xFFFF) +#define KEYCODE(keymap) ((keymap) & 0xFFFF) /* * Scancode to keycode tables. These are just the default setting, and @@ -76,7 +73,6 @@ MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard conne #define ATKBD_KEYMAP_SIZE 512 static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { - #ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES /* XXX: need a more general approach */ @@ -107,7 +103,6 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { }; static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { - 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, @@ -122,15 +117,15 @@ static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { 148,149,147,140 }; -static const unsigned short atkbd_unxlate_table[128] = { - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 +static const u8 atkbd_unxlate_table[128] = { + 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, + 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, + 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, + 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, + 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, + 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, + 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, + 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 }; #define ATKBD_CMD_SETLEDS 0x10ed @@ -184,7 +179,7 @@ static const unsigned short atkbd_unxlate_table[128] = { static const struct { unsigned short keycode; - unsigned char set2; + u8 set2; } atkbd_scroll_keys[] = { { ATKBD_SCR_1, 0xc5 }, { ATKBD_SCR_2, 0x9d }, @@ -200,7 +195,6 @@ static const struct { */ struct atkbd { - struct ps2dev ps2dev; struct input_dev *dev; @@ -211,7 +205,7 @@ struct atkbd { unsigned short id; unsigned short keycode[ATKBD_KEYMAP_SIZE]; DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); - unsigned char set; + u8 set; bool translated; bool extra; bool write; @@ -221,7 +215,7 @@ struct atkbd { bool enabled; /* Accessed only from interrupt */ - unsigned char emul; + u8 emul; bool resend; bool release; unsigned long xl_bit; @@ -253,9 +247,9 @@ static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned in static bool atkbd_skip_deactivate; static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct atkbd *, char *)); + ssize_t (*handler)(struct atkbd *, char *)); static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct atkbd *, const char *, size_t)); + ssize_t (*handler)(struct atkbd *, const char *, size_t)); #define ATKBD_DEFINE_ATTR(_name) \ static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ @@ -270,7 +264,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, \ return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ } \ static struct device_attribute atkbd_attr_##_name = \ - __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); + __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name) ATKBD_DEFINE_ATTR(extra); ATKBD_DEFINE_ATTR(force_release); @@ -287,7 +281,7 @@ static ssize_t atkbd_do_show_##_name(struct device *d, \ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ } \ static struct device_attribute atkbd_attr_##_name = \ - __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); + __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL) ATKBD_DEFINE_RO_ATTR(err_count); ATKBD_DEFINE_RO_ATTR(function_row_physmap); @@ -317,7 +311,7 @@ static struct atkbd *atkbd_from_serio(struct serio *serio) } static umode_t atkbd_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) + struct attribute *attr, int i) { struct device *dev = kobj_to_dev(kobj); struct serio *serio = to_serio_port(dev); @@ -337,7 +331,7 @@ static const struct attribute_group atkbd_attribute_group = { __ATTRIBUTE_GROUPS(atkbd_attribute); -static const unsigned int xl_table[] = { +static const u8 xl_table[] = { ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, }; @@ -346,7 +340,7 @@ static const unsigned int xl_table[] = { * Checks if we should mangle the scancode to extract 'release' bit * in translated mode. */ -static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) +static bool atkbd_need_xlate(unsigned long xl_bit, u8 code) { int i; @@ -365,7 +359,7 @@ static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) * between make/break pair of scancodes for select keys and PS/2 * protocol responses. */ -static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code) +static void atkbd_calculate_xl_bit(struct atkbd *atkbd, u8 code) { int i; @@ -389,7 +383,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code if (atkbd->set == 3) { if (atkbd->emul == 1) code |= 0x100; - } else { + } else { code = (code & 0x7f) | ((code & 0x80) << 1); if (atkbd->emul == 1) code |= 0x80; @@ -431,7 +425,7 @@ static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev, dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); -#if !defined(__i386__) && !defined (__x86_64__) +#if !defined(__i386__) && !defined(__x86_64__) if (atkbd_handle_frame_error(ps2dev, data, flags)) return PS2_IGNORE; #endif @@ -460,7 +454,6 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) code = atkbd_platform_scancode_fixup(atkbd, code); if (atkbd->translated) { - if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { atkbd->release = code >> 7; code &= 0x7f; @@ -486,11 +479,9 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) return; case ATKBD_RET_ACK: case ATKBD_RET_NAK: - if (printk_ratelimit()) - dev_warn(&serio->dev, - "Spurious %s on %s. " - "Some program might be trying to access hardware directly.\n", - data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); + dev_warn_ratelimited(&serio->dev, + "Spurious %s on %s. Some program might be trying to access hardware directly.\n", + data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); return; case ATKBD_RET_ERR: atkbd->err_count++; @@ -582,14 +573,14 @@ static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) static int atkbd_set_repeat_rate(struct atkbd *atkbd) { - const short period[32] = - { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, - 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; - const short delay[4] = - { 250, 500, 750, 1000 }; + const short period[32] = { + 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, + 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 + }; + const short delay[4] = { 250, 500, 750, 1000 }; struct input_dev *dev = atkbd->dev; - unsigned char param; + u8 param; int i = 0, j = 0; while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) @@ -607,7 +598,7 @@ static int atkbd_set_repeat_rate(struct atkbd *atkbd) static int atkbd_set_leds(struct atkbd *atkbd) { struct input_dev *dev = atkbd->dev; - unsigned char param[2]; + u8 param[2]; param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) | (test_bit(LED_NUML, dev->led) ? 2 : 0) @@ -648,8 +639,7 @@ static void atkbd_event_work(struct work_struct *work) * it may not be ready yet. In this case we need to keep * rescheduling till reconnect completes. */ - schedule_delayed_work(&atkbd->event_work, - msecs_to_jiffies(100)); + schedule_delayed_work(&atkbd->event_work, msecs_to_jiffies(100)); } else { if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) atkbd_set_leds(atkbd); @@ -683,7 +673,7 @@ static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit) */ static int atkbd_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) + unsigned int type, unsigned int code, int value) { struct atkbd *atkbd = input_get_drvdata(dev); @@ -691,7 +681,6 @@ static int atkbd_event(struct input_dev *dev, return -1; switch (type) { - case EV_LED: atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); return 0; @@ -808,7 +797,7 @@ static inline bool atkbd_skip_getid(struct atkbd *atkbd) { return false; } static int atkbd_probe(struct atkbd *atkbd) { struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; + u8 param[2]; /* * Some systems, where the bit-twiddling when testing the io-lines of the @@ -836,7 +825,6 @@ static int atkbd_probe(struct atkbd *atkbd) param[0] = param[1] = 0xa5; /* initialize with invalid values */ if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { - /* * If the get ID command failed, we check if we can at least set * the LEDs on the keyboard. This should work on every keyboard out there. @@ -856,8 +844,7 @@ static int atkbd_probe(struct atkbd *atkbd) if (atkbd->id == 0xaca1 && atkbd->translated) { dev_err(&ps2dev->serio->dev, - "NCD terminal keyboards are only supported on non-translating controllers. " - "Use i8042.direct=1 to disable translation.\n"); + "NCD terminal keyboards are only supported on non-translating controllers. Use i8042.direct=1 to disable translation.\n"); return -1; } @@ -881,7 +868,7 @@ deactivate_kbd: static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) { struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; + u8 param[2]; atkbd->extra = false; /* @@ -941,8 +928,8 @@ static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra static int atkbd_reset_state(struct atkbd *atkbd) { - struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[1]; + struct ps2dev *ps2dev = &atkbd->ps2dev; + u8 param[1]; /* * Set the LEDs to a predefined state (all off). @@ -967,7 +954,6 @@ static int atkbd_reset_state(struct atkbd *atkbd) * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a * reboot. */ - static void atkbd_cleanup(struct serio *serio) { struct atkbd *atkbd = atkbd_from_serio(serio); @@ -976,11 +962,9 @@ static void atkbd_cleanup(struct serio *serio) ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF); } - /* * atkbd_disconnect() closes and frees. */ - static void atkbd_disconnect(struct serio *serio) { struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1005,8 +989,7 @@ static void atkbd_disconnect(struct serio *serio) /* * generate release events for the keycodes given in data */ -static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd, - const void *data) +static void atkbd_apply_forced_release_keylist(struct atkbd *atkbd, const void *data) { const unsigned int *keys = data; unsigned int i; @@ -1088,7 +1071,6 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) { struct device *dev = &atkbd->ps2dev.serio->dev; int i, n; - u32 *ptr; u16 scancode, keycode; /* Parse "linux,keymap" property */ @@ -1096,13 +1078,12 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) if (n <= 0 || n > ATKBD_KEYMAP_SIZE) return -ENXIO; - ptr = kcalloc(n, sizeof(u32), GFP_KERNEL); + u32 *ptr __free(kfree) = kcalloc(n, sizeof(*ptr), GFP_KERNEL); if (!ptr) return -ENOMEM; if (device_property_read_u32_array(dev, "linux,keymap", ptr, n)) { dev_err(dev, "problem parsing FW keymap property\n"); - kfree(ptr); return -EINVAL; } @@ -1110,10 +1091,14 @@ static int atkbd_get_keymap_from_fwnode(struct atkbd *atkbd) for (i = 0; i < n; i++) { scancode = SCANCODE(ptr[i]); keycode = KEYCODE(ptr[i]); + if (scancode >= ATKBD_KEYMAP_SIZE) { + dev_warn(dev, "invalid scancode %#x in FW keymap entry %d\n", + scancode, i); + return -EINVAL; + } atkbd->keycode[scancode] = keycode; } - kfree(ptr); return 0; } @@ -1235,7 +1220,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) } input_dev->keycode = atkbd->keycode; - input_dev->keycodesize = sizeof(unsigned short); + input_dev->keycodesize = sizeof(atkbd->keycode[0]); input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) { @@ -1289,7 +1274,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) mutex_init(&atkbd->mutex); switch (serio->id.type) { - case SERIO_8042_XL: atkbd->translated = true; fallthrough; @@ -1314,7 +1298,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) goto fail2; if (atkbd->write) { - if (atkbd_probe(atkbd)) { err = -ENODEV; goto fail3; @@ -1354,7 +1337,6 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) * atkbd_reconnect() tries to restore keyboard into a sane state and is * most likely called on resume. */ - static int atkbd_reconnect(struct serio *serio) { struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1389,7 +1371,6 @@ static int atkbd_reconnect(struct serio *serio) atkbd_set_leds(atkbd); if (!atkbd->softrepeat) atkbd_set_repeat_rate(atkbd); - } /* @@ -1445,7 +1426,7 @@ static struct serio_driver atkbd_drv = { }; static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct atkbd *, char *)) + ssize_t (*handler)(struct atkbd *, char *)) { struct serio *serio = to_serio_port(dev); struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1454,7 +1435,7 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, } static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct atkbd *, const char *, size_t)) + ssize_t (*handler)(struct atkbd *, const char *, size_t)) { struct serio *serio = to_serio_port(dev); struct atkbd *atkbd = atkbd_from_serio(serio); @@ -1482,7 +1463,7 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun unsigned int value; int err; bool old_extra; - unsigned char old_set; + u8 old_set; if (!atkbd->write) return -EIO; @@ -1527,8 +1508,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun return err; } input_unregister_device(old_dev); - } + return count; } @@ -1544,7 +1525,7 @@ static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) } static ssize_t atkbd_set_force_release(struct atkbd *atkbd, - const char *buf, size_t count) + const char *buf, size_t count) { /* 64 bytes on stack should be acceptable */ DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); @@ -1558,7 +1539,6 @@ static ssize_t atkbd_set_force_release(struct atkbd *atkbd, return count; } - static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) { return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); @@ -1617,7 +1597,7 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) struct input_dev *old_dev, *new_dev; unsigned int value; int err; - unsigned char old_set; + u8 old_set; bool old_extra; if (!atkbd->write) @@ -1715,7 +1695,6 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t return count; } - static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) { return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); diff --git a/drivers/input/keyboard/charlieplex_keypad.c b/drivers/input/keyboard/charlieplex_keypad.c new file mode 100644 index 000000000000..6dbb5c183f02 --- /dev/null +++ b/drivers/input/keyboard/charlieplex_keypad.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * GPIO driven charlieplex keypad driver + * + * Copyright (c) 2026 Hugo Villeneuve <hvilleneuve@dimonoff.com> + * + * Based on matrix_keyboard.c + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/dev_printk.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/input.h> +#include <linux/input/matrix_keypad.h> +#include <linux/math.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/string_helpers.h> +#include <linux/types.h> + +struct charlieplex_keypad { + struct input_dev *input_dev; + struct gpio_descs *line_gpios; + unsigned int nlines; + unsigned int settling_time_us; + unsigned int debounce_threshold; + unsigned int debounce_count; + int debounce_code; + int current_code; +}; + +static void charlieplex_keypad_report_key(struct input_dev *input) +{ + struct charlieplex_keypad *keypad = input_get_drvdata(input); + const unsigned short *keycodes = input->keycode; + + if (keypad->current_code > 0) { + input_event(input, EV_MSC, MSC_SCAN, keypad->current_code); + input_report_key(input, keycodes[keypad->current_code], 0); + input_sync(input); + } + + if (keypad->debounce_code) { + input_event(input, EV_MSC, MSC_SCAN, keypad->debounce_code); + input_report_key(input, keycodes[keypad->debounce_code], 1); + input_sync(input); + } + + keypad->current_code = keypad->debounce_code; +} + +static void charlieplex_keypad_check_switch_change(struct input_dev *input, + unsigned int code) +{ + struct charlieplex_keypad *keypad = input_get_drvdata(input); + + if (code != keypad->debounce_code) { + keypad->debounce_count = 0; + keypad->debounce_code = code; + } + + if (keypad->debounce_code != keypad->current_code) { + if (keypad->debounce_count++ >= keypad->debounce_threshold) + charlieplex_keypad_report_key(input); + } +} + +static int charlieplex_keypad_scan_line(struct charlieplex_keypad *keypad, + unsigned int oline) +{ + struct gpio_descs *line_gpios = keypad->line_gpios; + DECLARE_BITMAP(values, MATRIX_MAX_ROWS); + int err; + + /* Activate only one line as output at a time. */ + gpiod_direction_output(line_gpios->desc[oline], 1); + + if (keypad->settling_time_us) + fsleep(keypad->settling_time_us); + + /* Read input on all other lines. */ + err = gpiod_get_array_value_cansleep(line_gpios->ndescs, line_gpios->desc, + line_gpios->info, values); + + gpiod_direction_input(line_gpios->desc[oline]); + + if (err) + return err; + + for (unsigned int iline = 0; iline < keypad->nlines; iline++) { + if (iline == oline) + continue; /* Do not read active output line. */ + + /* Check if GPIO is asserted. */ + if (test_bit(iline, values)) + return MATRIX_SCAN_CODE(oline, iline, + get_count_order(keypad->nlines)); + } + + return 0; +} + +static void charlieplex_keypad_poll(struct input_dev *input) +{ + struct charlieplex_keypad *keypad = input_get_drvdata(input); + int code = 0; + + for (unsigned int oline = 0; oline < keypad->nlines; oline++) { + code = charlieplex_keypad_scan_line(keypad, oline); + if (code != 0) + break; + } + + if (code >= 0) + charlieplex_keypad_check_switch_change(input, code); +} + +static int charlieplex_keypad_init_gpio(struct platform_device *pdev, + struct charlieplex_keypad *keypad) +{ + char **pin_names; + char label[32]; + + snprintf(label, sizeof(label), "%s-pin", pdev->name); + + keypad->line_gpios = devm_gpiod_get_array(&pdev->dev, "line", GPIOD_IN); + if (IS_ERR(keypad->line_gpios)) + return PTR_ERR(keypad->line_gpios); + + keypad->nlines = keypad->line_gpios->ndescs; + + if (keypad->nlines > MATRIX_MAX_ROWS) + return -EINVAL; + + pin_names = devm_kasprintf_strarray(&pdev->dev, label, keypad->nlines); + if (IS_ERR(pin_names)) + return PTR_ERR(pin_names); + + for (unsigned int i = 0; i < keypad->line_gpios->ndescs; i++) + gpiod_set_consumer_name(keypad->line_gpios->desc[i], pin_names[i]); + + return 0; +} + +static int charlieplex_keypad_probe(struct platform_device *pdev) +{ + struct charlieplex_keypad *keypad; + struct input_dev *input_dev; + unsigned int debounce_interval_ms = 5; + unsigned int poll_interval_ms; + int err; + + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + keypad->input_dev = input_dev; + + err = device_property_read_u32(&pdev->dev, "poll-interval", &poll_interval_ms); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to parse 'poll-interval' property\n"); + + if (poll_interval_ms == 0) + return dev_err_probe(&pdev->dev, -EINVAL, "invalid 'poll-interval' value\n"); + + device_property_read_u32(&pdev->dev, "debounce-delay-ms", &debounce_interval_ms); + device_property_read_u32(&pdev->dev, "settling-time-us", &keypad->settling_time_us); + + keypad->current_code = -1; + keypad->debounce_code = -1; + keypad->debounce_threshold = DIV_ROUND_UP(debounce_interval_ms, poll_interval_ms); + + err = charlieplex_keypad_init_gpio(pdev, keypad); + if (err) + return err; + + input_dev->name = pdev->name; + input_dev->id.bustype = BUS_HOST; + + err = matrix_keypad_build_keymap(NULL, NULL, keypad->nlines, + keypad->nlines, NULL, input_dev); + if (err) + return dev_err_probe(&pdev->dev, err, "failed to build keymap\n"); + + if (device_property_read_bool(&pdev->dev, "autorepeat")) + __set_bit(EV_REP, input_dev->evbit); + + input_set_capability(input_dev, EV_MSC, MSC_SCAN); + + err = input_setup_polling(input_dev, charlieplex_keypad_poll); + if (err) + return dev_err_probe(&pdev->dev, err, "unable to set up polling\n"); + + input_set_poll_interval(input_dev, poll_interval_ms); + + input_set_drvdata(input_dev, keypad); + + err = input_register_device(keypad->input_dev); + if (err) + return err; + + return 0; +} + +static const struct of_device_id charlieplex_keypad_dt_match[] = { + { .compatible = "gpio-charlieplex-keypad" }, + { } +}; +MODULE_DEVICE_TABLE(of, charlieplex_keypad_dt_match); + +static struct platform_driver charlieplex_keypad_driver = { + .probe = charlieplex_keypad_probe, + .driver = { + .name = "charlieplex-keypad", + .of_match_table = charlieplex_keypad_dt_match, + }, +}; +module_platform_driver(charlieplex_keypad_driver); + +MODULE_AUTHOR("Hugo Villeneuve <hvilleneuve@dimonoff.com>"); +MODULE_DESCRIPTION("GPIO driven charlieplex keypad driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index 2822c592880b..177e5d4a3382 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -29,6 +29,12 @@ #include <linux/unaligned.h> +/* + * Maximum size of the normal key matrix, this is limited by the host command + * key_matrix field defined in ec_response_get_next_data_v3 + */ +#define CROS_EC_KEYBOARD_COLS_MAX 18 + /** * struct cros_ec_keyb - Structure representing EC keyboard device * @@ -44,14 +50,17 @@ * @bs_idev: The input device for non-matrix buttons and switches (or NULL). * @notifier: interrupt event notifier for transport devices * @vdata: vivaldi function row data + * @has_fn_map: whether the driver uses an fn function-map layer + * @fn_active: tracks whether the function key is currently pressed + * @fn_combo_active: tracks whether another key was pressed while fn is active */ struct cros_ec_keyb { unsigned int rows; unsigned int cols; int row_shift; bool ghost_filter; - uint8_t *valid_keys; - uint8_t *old_kb_state; + u8 valid_keys[CROS_EC_KEYBOARD_COLS_MAX]; + u8 old_kb_state[CROS_EC_KEYBOARD_COLS_MAX]; struct device *dev; struct cros_ec_device *ec; @@ -61,6 +70,10 @@ struct cros_ec_keyb { struct notifier_block notifier; struct vivaldi_data vdata; + + bool has_fn_map; + bool fn_active; + bool fn_combo_active; }; /** @@ -132,11 +145,11 @@ static const struct cros_ec_bs_map cros_ec_keyb_bs[] = { * Returns true when there is at least one combination of pressed keys that * results in ghosting. */ -static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) +static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, u8 *buf) { int col1, col2, buf1, buf2; struct device *dev = ckdev->dev; - uint8_t *valid_keys = ckdev->valid_keys; + u8 *valid_keys = ckdev->valid_keys; /* * Ghosting happens if for any pressed key X there are other keys @@ -166,20 +179,108 @@ static bool cros_ec_keyb_has_ghosting(struct cros_ec_keyb *ckdev, uint8_t *buf) return false; } +static void cros_ec_emit_fn_key(struct input_dev *input, unsigned int pos) +{ + input_event(input, EV_MSC, MSC_SCAN, pos); + input_report_key(input, KEY_FN, true); + input_sync(input); + + input_event(input, EV_MSC, MSC_SCAN, pos); + input_report_key(input, KEY_FN, false); +} + +static void cros_ec_keyb_process_key_plain(struct cros_ec_keyb *ckdev, + int row, int col, bool state) +{ + struct input_dev *idev = ckdev->idev; + const unsigned short *keycodes = idev->keycode; + int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); + + input_event(idev, EV_MSC, MSC_SCAN, pos); + input_report_key(idev, keycodes[pos], state); +} + +static void cros_ec_keyb_process_key_fn_map(struct cros_ec_keyb *ckdev, + int row, int col, bool state) +{ + struct input_dev *idev = ckdev->idev; + const unsigned short *keycodes = idev->keycode; + unsigned int pos, fn_pos; + unsigned int code, fn_code; + + pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); + code = keycodes[pos]; + + if (code == KEY_FN) { + ckdev->fn_active = state; + if (state) { + ckdev->fn_combo_active = false; + } else if (!ckdev->fn_combo_active) { + /* + * Send both Fn press and release events if nothing + * else has been pressed together with Fn. + */ + cros_ec_emit_fn_key(idev, pos); + } + return; + } + + fn_pos = MATRIX_SCAN_CODE(row + ckdev->rows, col, ckdev->row_shift); + fn_code = keycodes[fn_pos]; + + if (state) { + if (ckdev->fn_active) { + ckdev->fn_combo_active = true; + if (!fn_code) + return; /* Discard if no Fn mapping exists */ + + pos = fn_pos; + code = fn_code; + } + } else { + /* + * If the Fn-remapped code is currently pressed, release it. + * Otherwise, release the standard code (if it was pressed). + */ + if (fn_code && test_bit(fn_code, idev->key)) { + pos = fn_pos; + code = fn_code; + } else if (!test_bit(code, idev->key)) { + return; /* Discard, key press code was not sent */ + } + } + + input_event(idev, EV_MSC, MSC_SCAN, pos); + input_report_key(idev, code, state); +} + +static void cros_ec_keyb_process_col(struct cros_ec_keyb *ckdev, int col, + u8 col_state, u8 changed) +{ + for (int row = 0; row < ckdev->rows; row++) { + if (changed & BIT(row)) { + u8 key_state = col_state & BIT(row); + + dev_dbg(ckdev->dev, "changed: [r%d c%d]: byte %02x\n", + row, col, key_state); + + if (ckdev->has_fn_map) + cros_ec_keyb_process_key_fn_map(ckdev, row, col, + key_state); + else + cros_ec_keyb_process_key_plain(ckdev, row, col, + key_state); + } + } +} /* * Compares the new keyboard state to the old one and produces key - * press/release events accordingly. The keyboard state is 13 bytes (one byte - * per column) + * press/release events accordingly. The keyboard state is one byte + * per column. */ -static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, - uint8_t *kb_state, int len) +static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, u8 *kb_state, int len) { - struct input_dev *idev = ckdev->idev; - int col, row; - int new_state; - int old_state; - if (ckdev->ghost_filter && cros_ec_keyb_has_ghosting(ckdev, kb_state)) { /* * Simple-minded solution: ignore this state. The obvious @@ -190,25 +291,15 @@ static void cros_ec_keyb_process(struct cros_ec_keyb *ckdev, return; } - for (col = 0; col < ckdev->cols; col++) { - for (row = 0; row < ckdev->rows; row++) { - int pos = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); - const unsigned short *keycodes = idev->keycode; - - new_state = kb_state[col] & (1 << row); - old_state = ckdev->old_kb_state[col] & (1 << row); - if (new_state != old_state) { - dev_dbg(ckdev->dev, - "changed: [r%d c%d]: byte %02x\n", - row, col, new_state); - - input_event(idev, EV_MSC, MSC_SCAN, pos); - input_report_key(idev, keycodes[pos], - new_state); - } - } - ckdev->old_kb_state[col] = kb_state[col]; + for (int col = 0; col < ckdev->cols; col++) { + u8 changed = kb_state[col] ^ ckdev->old_kb_state[col]; + + if (changed) + cros_ec_keyb_process_col(ckdev, col, kb_state[col], + changed); } + + memcpy(ckdev->old_kb_state, kb_state, sizeof(ckdev->old_kb_state)); input_sync(ckdev->idev); } @@ -246,8 +337,10 @@ static int cros_ec_keyb_work(struct notifier_block *nb, { struct cros_ec_keyb *ckdev = container_of(nb, struct cros_ec_keyb, notifier); - u32 val; + struct ec_response_get_next_event_v3 *event_data; + unsigned int event_size; unsigned int ev_type; + u32 val; /* * If not wake enabled, discard key state changes during @@ -257,32 +350,32 @@ static int cros_ec_keyb_work(struct notifier_block *nb, if (queued_during_suspend && !device_may_wakeup(ckdev->dev)) return NOTIFY_OK; - switch (ckdev->ec->event_data.event_type) { + event_data = &ckdev->ec->event_data; + event_size = ckdev->ec->event_size; + + switch (event_data->event_type) { case EC_MKBP_EVENT_KEY_MATRIX: pm_wakeup_event(ckdev->dev, 0); if (!ckdev->idev) { - dev_warn_once(ckdev->dev, - "Unexpected key matrix event\n"); + dev_warn_once(ckdev->dev, "Unexpected key matrix event\n"); return NOTIFY_OK; } - if (ckdev->ec->event_size != ckdev->cols) { + if (event_size != ckdev->cols) { dev_err(ckdev->dev, "Discarded key matrix event, unexpected length: %d != %d\n", ckdev->ec->event_size, ckdev->cols); return NOTIFY_OK; } - cros_ec_keyb_process(ckdev, - ckdev->ec->event_data.data.key_matrix, - ckdev->ec->event_size); + cros_ec_keyb_process(ckdev, event_data->data.key_matrix, event_size); break; case EC_MKBP_EVENT_SYSRQ: pm_wakeup_event(ckdev->dev, 0); - val = get_unaligned_le32(&ckdev->ec->event_data.data.sysrq); + val = get_unaligned_le32(&event_data->data.sysrq); dev_dbg(ckdev->dev, "sysrq code from EC: %#x\n", val); handle_sysrq(val); break; @@ -291,13 +384,11 @@ static int cros_ec_keyb_work(struct notifier_block *nb, case EC_MKBP_EVENT_SWITCH: pm_wakeup_event(ckdev->dev, 0); - if (ckdev->ec->event_data.event_type == EC_MKBP_EVENT_BUTTON) { - val = get_unaligned_le32( - &ckdev->ec->event_data.data.buttons); + if (event_data->event_type == EC_MKBP_EVENT_BUTTON) { + val = get_unaligned_le32(&event_data->data.buttons); ev_type = EV_KEY; } else { - val = get_unaligned_le32( - &ckdev->ec->event_data.data.switches); + val = get_unaligned_le32(&event_data->data.switches); ev_type = EV_SW; } cros_ec_keyb_report_bs(ckdev, ev_type, val); @@ -326,8 +417,8 @@ static void cros_ec_keyb_compute_valid_keys(struct cros_ec_keyb *ckdev) for (col = 0; col < ckdev->cols; col++) { for (row = 0; row < ckdev->rows; row++) { code = keymap[MATRIX_SCAN_CODE(row, col, row_shift)]; - if (code && (code != KEY_BATTERY)) - ckdev->valid_keys[col] |= 1 << row; + if (code != KEY_RESERVED && code != KEY_BATTERY) + ckdev->valid_keys[col] |= BIT(row); } dev_dbg(ckdev->dev, "valid_keys[%02d] = 0x%02x\n", col, ckdev->valid_keys[col]); @@ -583,6 +674,62 @@ static void cros_ec_keyb_parse_vivaldi_physmap(struct cros_ec_keyb *ckdev) ckdev->vdata.num_function_row_keys = n_physmap; } +/* Returns true if there is a KEY_FN code defined in the normal keymap */ +static bool cros_ec_keyb_has_fn_key(struct cros_ec_keyb *ckdev) +{ + const unsigned short *keycodes = ckdev->idev->keycode; + int i; + + for (i = 0; i < MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); i++) { + if (keycodes[i] == KEY_FN) + return true; + } + + return false; +} + +/* + * Returns true if there is a KEY_FN defined and at least one key in the fn + * layer keymap + */ +static bool cros_ec_keyb_has_fn_map(struct cros_ec_keyb *ckdev) +{ + struct input_dev *idev = ckdev->idev; + const unsigned short *keycodes = ckdev->idev->keycode; + int i; + + if (!cros_ec_keyb_has_fn_key(ckdev)) + return false; + + for (i = MATRIX_SCAN_CODE(ckdev->rows, 0, ckdev->row_shift); + i < idev->keycodemax; i++) { + if (keycodes[i] != KEY_RESERVED) + return true; + } + + return false; +} + +/* + * Custom handler for the set keycode ioctl, calls the default handler and + * recomputes has_fn_map. + */ +static int cros_ec_keyb_setkeycode(struct input_dev *idev, + const struct input_keymap_entry *ke, + unsigned int *old_keycode) +{ + struct cros_ec_keyb *ckdev = input_get_drvdata(idev); + int ret; + + ret = input_default_setkeycode(idev, ke, old_keycode); + if (ret) + return ret; + + ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev); + + return 0; +} + /** * cros_ec_keyb_register_matrix - Register matrix keys * @@ -604,13 +751,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) if (err) return err; - ckdev->valid_keys = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); - if (!ckdev->valid_keys) - return -ENOMEM; - - ckdev->old_kb_state = devm_kzalloc(dev, ckdev->cols, GFP_KERNEL); - if (!ckdev->old_kb_state) - return -ENOMEM; + if (ckdev->cols > CROS_EC_KEYBOARD_COLS_MAX) { + dev_err(dev, "keypad,num-columns too large: %d (max: %d)\n", + ckdev->cols, CROS_EC_KEYBOARD_COLS_MAX); + return -EINVAL; + } /* * We call the keyboard matrix 'input0'. Allocate phys before input @@ -632,11 +777,11 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) idev->id.version = 1; idev->id.product = 0; idev->dev.parent = dev; + idev->setkeycode = cros_ec_keyb_setkeycode; - ckdev->ghost_filter = device_property_read_bool(dev, - "google,needs-ghost-filter"); + ckdev->ghost_filter = device_property_read_bool(dev, "google,needs-ghost-filter"); - err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows, ckdev->cols, + err = matrix_keypad_build_keymap(NULL, NULL, ckdev->rows * 2, ckdev->cols, NULL, idev); if (err) { dev_err(dev, "cannot build key matrix\n"); @@ -651,6 +796,8 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) cros_ec_keyb_compute_valid_keys(ckdev); cros_ec_keyb_parse_vivaldi_physmap(ckdev); + ckdev->has_fn_map = cros_ec_keyb_has_fn_map(ckdev); + err = input_register_device(ckdev->idev); if (err) { dev_err(dev, "cannot register input device\n"); diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index 069c1d6376e1..ccde60cd6bb3 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -324,7 +324,7 @@ static void imx_keypad_config(struct imx_keypad *keypad) reg_val |= (keypad->cols_en_mask & 0xff) << 8; /* cols */ writew(reg_val, keypad->mmio_base + KPCR); - /* Write 0's to KPDR[15:8] (Colums) */ + /* Write 0's to KPDR[15:8] (Columns) */ reg_val = readw(keypad->mmio_base + KPDR); reg_val &= 0x00ff; writew(reg_val, keypad->mmio_base + KPDR); @@ -357,7 +357,7 @@ static void imx_keypad_inhibit(struct imx_keypad *keypad) reg_val |= KBD_STAT_KPKR | KBD_STAT_KPKD; writew(reg_val, keypad->mmio_base + KPSR); - /* Colums as open drain and disable all rows */ + /* Columns as open drain and disable all rows */ reg_val = (keypad->cols_en_mask & 0xff) << 8; writew(reg_val, keypad->mmio_base + KPCR); } diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index bd1a944ded46..47edc161ec77 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -295,8 +295,6 @@ static int mpr_touchkey_probe(struct i2c_client *client) return error; i2c_set_clientdata(client, mpr121); - device_init_wakeup(dev, - device_property_read_bool(dev, "wakeup-source")); return 0; } @@ -305,9 +303,6 @@ static int mpr_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - if (device_may_wakeup(&client->dev)) - enable_irq_wake(client->irq); - i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, 0x00); return 0; @@ -318,9 +313,6 @@ static int mpr_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct mpr121_touchkey *mpr121 = i2c_get_clientdata(client); - if (device_may_wakeup(&client->dev)) - disable_irq_wake(client->irq); - i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, mpr121->keycount); diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c index bce8157d1871..f9f480c91032 100644 --- a/drivers/input/keyboard/qt1050.c +++ b/drivers/input/keyboard/qt1050.c @@ -435,8 +435,7 @@ static int qt1050_probe(struct i2c_client *client) int err; /* Check basic functionality */ - err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); - if (!err) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { dev_err(&client->dev, "%s adapter not supported\n", dev_driver_string(&client->adapter->dev)); return -ENODEV; diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index b3db2c7d0957..b255b997e279 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -133,8 +133,7 @@ static int qt1070_probe(struct i2c_client *client) int i; int err; - err = i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE); - if (!err) { + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { dev_err(&client->dev, "%s adapter not supported\n", dev_driver_string(&client->adapter->dev)); return -ENODEV; |
