diff options
Diffstat (limited to 'drivers/input')
23 files changed, 976 insertions, 188 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 5baebf62df33..e2752f7364bc 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -77,6 +77,13 @@ config INPUT_MATRIXKMAP To compile this driver as a module, choose M here: the module will be called matrix-keymap. +config INPUT_VIVALDIFMAP + tristate + help + ChromeOS Vivaldi keymap support library. This is a hidden + option so that drivers can use common code to parse and + expose the vivaldi function row keymap. + comment "Userland interfaces" config INPUT_MOUSEDEV diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 037cc595106c..2266c7d010ef 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -12,6 +12,7 @@ input-core-y += touchscreen.o obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o +obj-$(CONFIG_INPUT_VIVALDIFMAP) += vivaldi-fmap.o obj-$(CONFIG_INPUT_LEDS) += input-leds.o obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o diff --git a/drivers/input/input.c b/drivers/input/input.c index c3139bc2aa0d..e5a668ce884d 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -47,6 +47,17 @@ static DEFINE_MUTEX(input_mutex); static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; +static const unsigned int input_max_code[EV_CNT] = { + [EV_KEY] = KEY_MAX, + [EV_REL] = REL_MAX, + [EV_ABS] = ABS_MAX, + [EV_MSC] = MSC_MAX, + [EV_SW] = SW_MAX, + [EV_LED] = LED_MAX, + [EV_SND] = SND_MAX, + [EV_FF] = FF_MAX, +}; + static inline int is_event_supported(unsigned int code, unsigned long *bm, unsigned int max) { @@ -511,6 +522,9 @@ void input_set_abs_params(struct input_dev *dev, unsigned int axis, { struct input_absinfo *absinfo; + __set_bit(EV_ABS, dev->evbit); + __set_bit(axis, dev->absbit); + input_alloc_absinfo(dev); if (!dev->absinfo) return; @@ -520,12 +534,45 @@ void input_set_abs_params(struct input_dev *dev, unsigned int axis, absinfo->maximum = max; absinfo->fuzz = fuzz; absinfo->flat = flat; - - __set_bit(EV_ABS, dev->evbit); - __set_bit(axis, dev->absbit); } EXPORT_SYMBOL(input_set_abs_params); +/** + * input_copy_abs - Copy absinfo from one input_dev to another + * @dst: Destination input device to copy the abs settings to + * @dst_axis: ABS_* value selecting the destination axis + * @src: Source input device to copy the abs settings from + * @src_axis: ABS_* value selecting the source axis + * + * Set absinfo for the selected destination axis by copying it from + * the specified source input device's source axis. + * This is useful to e.g. setup a pen/stylus input-device for combined + * touchscreen/pen hardware where the pen uses the same coordinates as + * the touchscreen. + */ +void input_copy_abs(struct input_dev *dst, unsigned int dst_axis, + const struct input_dev *src, unsigned int src_axis) +{ + /* src must have EV_ABS and src_axis set */ + if (WARN_ON(!(test_bit(EV_ABS, src->evbit) && + test_bit(src_axis, src->absbit)))) + return; + + /* + * input_alloc_absinfo() may have failed for the source. Our caller is + * expected to catch this when registering the input devices, which may + * happen after the input_copy_abs() call. + */ + if (!src->absinfo) + return; + + input_set_capability(dst, EV_ABS, dst_axis); + if (!dst->absinfo) + return; + + dst->absinfo[dst_axis] = src->absinfo[src_axis]; +} +EXPORT_SYMBOL(input_copy_abs); /** * input_grab_device - grabs device for exclusive use @@ -2074,6 +2121,14 @@ EXPORT_SYMBOL(input_get_timestamp); */ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) { + if (type < EV_CNT && input_max_code[type] && + code > input_max_code[type]) { + pr_err("%s: invalid code %u for type %u\n", __func__, code, + type); + dump_stack(); + return; + } + switch (type) { case EV_KEY: __set_bit(code, dev->keybit); @@ -2085,9 +2140,6 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int case EV_ABS: input_alloc_absinfo(dev); - if (!dev->absinfo) - return; - __set_bit(code, dev->absbit); break; @@ -2285,12 +2337,6 @@ int input_register_device(struct input_dev *dev) /* KEY_RESERVED is not supposed to be transmitted to userspace. */ __clear_bit(KEY_RESERVED, dev->keybit); - /* Buttonpads should not map BTN_RIGHT and/or BTN_MIDDLE. */ - if (test_bit(INPUT_PROP_BUTTONPAD, dev->propbit)) { - __clear_bit(BTN_RIGHT, dev->keybit); - __clear_bit(BTN_MIDDLE, dev->keybit); - } - /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ input_cleanse_bitmasks(dev); diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index 592c95b87f54..e10d57bf1180 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -123,7 +123,7 @@ static void adi_read_packet(struct adi_port *port) { struct adi *adi = port->adi; struct gameport *gameport = port->gameport; - unsigned char u, v, w, x, z; + unsigned char u, v, w, x; int t[2], s[2], i; unsigned long flags; @@ -136,7 +136,7 @@ static void adi_read_packet(struct adi_port *port) local_irq_save(flags); gameport_trigger(gameport); - v = z = gameport_read(gameport); + v = gameport_read(gameport); do { u = v; diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 4c914f75a902..18190b529bca 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -131,7 +131,7 @@ static const struct xpad_device { { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, - { 0x045e, 0x0b12, "Microsoft Xbox One X pad", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, + { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE }, { 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 }, { 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 }, { 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 }, diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index 9417ee0b1eff..4ea79db8f134 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -103,6 +103,7 @@ config KEYBOARD_ATKBD select SERIO_LIBPS2 select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO select SERIO_GSCPS2 if GSC + select INPUT_VIVALDIFMAP help Say Y here if you want to use a standard AT or PS/2 keyboard. Usually you'll need this, unless you have a different type keyboard (USB, ADB @@ -749,6 +750,7 @@ config KEYBOARD_XTKBD config KEYBOARD_CROS_EC tristate "ChromeOS EC keyboard" select INPUT_MATRIXKMAP + select INPUT_VIVALDIFMAP depends on CROS_EC help Say Y here to enable the matrix keyboard used by ChromeOS devices @@ -779,6 +781,18 @@ config KEYBOARD_BCM To compile this driver as a module, choose M here: the module will be called bcm-keypad. +config KEYBOARD_MT6779 + tristate "MediaTek Keypad Support" + depends on ARCH_MEDIATEK || COMPILE_TEST + select REGMAP_MMIO + select INPUT_MATRIXKMAP + help + Say Y here if you want to use the keypad on MediaTek SoCs. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called mt6779-keypad. + config KEYBOARD_MTK_PMIC tristate "MediaTek PMIC keys support" depends on MFD_MT6397 diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile index e3c8648f834e..721936e90290 100644 --- a/drivers/input/keyboard/Makefile +++ b/drivers/input/keyboard/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o +obj-$(CONFIG_KEYBOARD_MT6779) += mt6779-keypad.o obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index fbdef95291e9..d4131236d18c 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/init.h> #include <linux/input.h> +#include <linux/input/vivaldi-fmap.h> #include <linux/serio.h> #include <linux/workqueue.h> #include <linux/libps2.h> @@ -64,8 +65,6 @@ 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 MAX_FUNCTION_ROW_KEYS 24 - #define SCANCODE(keymap) ((keymap >> 16) & 0xFFFF) #define KEYCODE(keymap) (keymap & 0xFFFF) @@ -237,8 +236,7 @@ struct atkbd { /* Serializes reconnect(), attr->set() and event work */ struct mutex mutex; - u32 function_row_physmap[MAX_FUNCTION_ROW_KEYS]; - int num_function_row_keys; + struct vivaldi_data vdata; }; /* @@ -308,17 +306,7 @@ static struct attribute *atkbd_attributes[] = { static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf) { - ssize_t size = 0; - int i; - - if (!atkbd->num_function_row_keys) - return 0; - - for (i = 0; i < atkbd->num_function_row_keys; i++) - size += scnprintf(buf + size, PAGE_SIZE - size, "%02X ", - atkbd->function_row_physmap[i]); - size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); - return size; + return vivaldi_function_row_physmap_show(&atkbd->vdata, buf); } static umode_t atkbd_attr_is_visible(struct kobject *kobj, @@ -329,7 +317,7 @@ static umode_t atkbd_attr_is_visible(struct kobject *kobj, struct atkbd *atkbd = serio_get_drvdata(serio); if (attr == &atkbd_attr_function_row_physmap.attr && - !atkbd->num_function_row_keys) + !atkbd->vdata.num_function_row_keys) return 0; return attr->mode; @@ -1206,10 +1194,11 @@ static void atkbd_parse_fwnode_data(struct serio *serio) /* Parse "function-row-physmap" property */ n = device_property_count_u32(dev, "function-row-physmap"); - if (n > 0 && n <= MAX_FUNCTION_ROW_KEYS && + if (n > 0 && n <= VIVALDI_MAX_FUNCTION_ROW_KEYS && !device_property_read_u32_array(dev, "function-row-physmap", - atkbd->function_row_physmap, n)) { - atkbd->num_function_row_keys = n; + atkbd->vdata.function_row_physmap, + n)) { + atkbd->vdata.num_function_row_keys = n; dev_dbg(dev, "FW reported %d function-row key locations\n", n); } } diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c index fc02c540636e..6534dfca60b4 100644 --- a/drivers/input/keyboard/cros_ec_keyb.c +++ b/drivers/input/keyboard/cros_ec_keyb.c @@ -15,6 +15,7 @@ #include <linux/bitops.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/input/vivaldi-fmap.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/notifier.h> @@ -27,8 +28,6 @@ #include <asm/unaligned.h> -#define MAX_NUM_TOP_ROW_KEYS 15 - /** * struct cros_ec_keyb - Structure representing EC keyboard device * @@ -44,9 +43,7 @@ * @idev: The input device for the matrix keys. * @bs_idev: The input device for non-matrix buttons and switches (or NULL). * @notifier: interrupt event notifier for transport devices - * @function_row_physmap: An array of the encoded rows/columns for the top - * row function keys, in an order from left to right - * @num_function_row_keys: The number of top row keys in a custom keyboard + * @vdata: vivaldi function row data */ struct cros_ec_keyb { unsigned int rows; @@ -64,8 +61,7 @@ struct cros_ec_keyb { struct input_dev *bs_idev; struct notifier_block notifier; - u16 function_row_physmap[MAX_NUM_TOP_ROW_KEYS]; - size_t num_function_row_keys; + struct vivaldi_data vdata; }; /** @@ -537,9 +533,9 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) int err; struct property *prop; const __be32 *p; - u16 *physmap; + u32 *physmap; u32 key_pos; - int row, col; + unsigned int row, col, scancode, n_physmap; err = matrix_keypad_parse_properties(dev, &ckdev->rows, &ckdev->cols); if (err) @@ -591,20 +587,21 @@ static int cros_ec_keyb_register_matrix(struct cros_ec_keyb *ckdev) ckdev->idev = idev; cros_ec_keyb_compute_valid_keys(ckdev); - physmap = ckdev->function_row_physmap; + physmap = ckdev->vdata.function_row_physmap; + n_physmap = 0; of_property_for_each_u32(dev->of_node, "function-row-physmap", prop, p, key_pos) { - if (ckdev->num_function_row_keys == MAX_NUM_TOP_ROW_KEYS) { + if (n_physmap == VIVALDI_MAX_FUNCTION_ROW_KEYS) { dev_warn(dev, "Only support up to %d top row keys\n", - MAX_NUM_TOP_ROW_KEYS); + VIVALDI_MAX_FUNCTION_ROW_KEYS); break; } row = KEY_ROW(key_pos); col = KEY_COL(key_pos); - *physmap = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); - physmap++; - ckdev->num_function_row_keys++; + scancode = MATRIX_SCAN_CODE(row, col, ckdev->row_shift); + physmap[n_physmap++] = scancode; } + ckdev->vdata.num_function_row_keys = n_physmap; err = input_register_device(ckdev->idev); if (err) { @@ -619,18 +616,10 @@ static ssize_t function_row_physmap_show(struct device *dev, struct device_attribute *attr, char *buf) { - ssize_t size = 0; - int i; - struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); - u16 *physmap = ckdev->function_row_physmap; - - for (i = 0; i < ckdev->num_function_row_keys; i++) - size += scnprintf(buf + size, PAGE_SIZE - size, - "%s%02X", size ? " " : "", physmap[i]); - if (size) - size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); + const struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); + const struct vivaldi_data *data = &ckdev->vdata; - return size; + return vivaldi_function_row_physmap_show(data, buf); } static DEVICE_ATTR_RO(function_row_physmap); @@ -648,7 +637,7 @@ static umode_t cros_ec_keyb_attr_is_visible(struct kobject *kobj, struct cros_ec_keyb *ckdev = dev_get_drvdata(dev); if (attr == &dev_attr_function_row_physmap.attr && - !ckdev->num_function_row_keys) + !ckdev->vdata.num_function_row_keys) return 0; return attr->mode; diff --git a/drivers/input/keyboard/mt6779-keypad.c b/drivers/input/keyboard/mt6779-keypad.c new file mode 100644 index 000000000000..0dbbddc7f298 --- /dev/null +++ b/drivers/input/keyboard/mt6779-keypad.c @@ -0,0 +1,221 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 MediaTek Inc. + * Author Fengping Yu <fengping.yu@mediatek.com> + */ +#include <linux/bitops.h> +#include <linux/clk.h> +#include <linux/input/matrix_keypad.h> +#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/property.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> + +#define MTK_KPD_NAME "mt6779-keypad" +#define MTK_KPD_MEM 0x0004 +#define MTK_KPD_DEBOUNCE 0x0018 +#define MTK_KPD_DEBOUNCE_MASK GENMASK(13, 0) +#define MTK_KPD_DEBOUNCE_MAX_MS 256 +#define MTK_KPD_NUM_MEMS 5 +#define MTK_KPD_NUM_BITS 136 /* 4*32+8 MEM5 only use 8 BITS */ + +struct mt6779_keypad { + struct regmap *regmap; + struct input_dev *input_dev; + struct clk *clk; + void __iomem *base; + u32 n_rows; + u32 n_cols; + DECLARE_BITMAP(keymap_state, MTK_KPD_NUM_BITS); +}; + +static const struct regmap_config mt6779_keypad_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = 36, +}; + +static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id) +{ + struct mt6779_keypad *keypad = dev_id; + const unsigned short *keycode = keypad->input_dev->keycode; + DECLARE_BITMAP(new_state, MTK_KPD_NUM_BITS); + DECLARE_BITMAP(change, MTK_KPD_NUM_BITS); + unsigned int bit_nr; + unsigned int row, col; + unsigned int scancode; + unsigned int row_shift = get_count_order(keypad->n_cols); + bool pressed; + + regmap_bulk_read(keypad->regmap, MTK_KPD_MEM, + new_state, MTK_KPD_NUM_MEMS); + + bitmap_xor(change, new_state, keypad->keymap_state, MTK_KPD_NUM_BITS); + + for_each_set_bit(bit_nr, change, MTK_KPD_NUM_BITS) { + /* + * Registers are 32bits, but only bits [15:0] are used to + * indicate key status. + */ + if (bit_nr % 32 >= 16) + continue; + + row = bit_nr / 32; + col = bit_nr % 32; + scancode = MATRIX_SCAN_CODE(row, col, row_shift); + /* 1: not pressed, 0: pressed */ + pressed = !test_bit(bit_nr, new_state); + dev_dbg(&keypad->input_dev->dev, "%s", + pressed ? "pressed" : "released"); + + input_event(keypad->input_dev, EV_MSC, MSC_SCAN, scancode); + input_report_key(keypad->input_dev, keycode[scancode], pressed); + input_sync(keypad->input_dev); + + dev_dbg(&keypad->input_dev->dev, + "report Linux keycode = %d\n", keycode[scancode]); + } + + bitmap_copy(keypad->keymap_state, new_state, MTK_KPD_NUM_BITS); + + return IRQ_HANDLED; +} + +static void mt6779_keypad_clk_disable(void *data) +{ + clk_disable_unprepare(data); +} + +static int mt6779_keypad_pdrv_probe(struct platform_device *pdev) +{ + struct mt6779_keypad *keypad; + int irq; + u32 debounce; + bool wakeup; + int error; + + keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + keypad->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(keypad->base)) + return PTR_ERR(keypad->base); + + keypad->regmap = devm_regmap_init_mmio(&pdev->dev, keypad->base, + &mt6779_keypad_regmap_cfg); + if (IS_ERR(keypad->regmap)) { + dev_err(&pdev->dev, + "regmap init failed:%pe\n", keypad->regmap); + return PTR_ERR(keypad->regmap); + } + + bitmap_fill(keypad->keymap_state, MTK_KPD_NUM_BITS); + + keypad->input_dev = devm_input_allocate_device(&pdev->dev); + if (!keypad->input_dev) { + dev_err(&pdev->dev, "Failed to allocate input dev\n"); + return -ENOMEM; + } + + keypad->input_dev->name = MTK_KPD_NAME; + keypad->input_dev->id.bustype = BUS_HOST; + + error = matrix_keypad_parse_properties(&pdev->dev, &keypad->n_rows, + &keypad->n_cols); + if (error) { + dev_err(&pdev->dev, "Failed to parse keypad params\n"); + return error; + } + + if (device_property_read_u32(&pdev->dev, "debounce-delay-ms", + &debounce)) + debounce = 16; + + if (debounce > MTK_KPD_DEBOUNCE_MAX_MS) { + dev_err(&pdev->dev, + "Debounce time exceeds the maximum allowed time %dms\n", + MTK_KPD_DEBOUNCE_MAX_MS); + return -EINVAL; + } + + wakeup = device_property_read_bool(&pdev->dev, "wakeup-source"); + + dev_dbg(&pdev->dev, "n_row=%d n_col=%d debounce=%d\n", + keypad->n_rows, keypad->n_cols, debounce); + + error = matrix_keypad_build_keymap(NULL, NULL, + keypad->n_rows, keypad->n_cols, + NULL, keypad->input_dev); + if (error) { + dev_err(&pdev->dev, "Failed to build keymap\n"); + return error; + } + + input_set_capability(keypad->input_dev, EV_MSC, MSC_SCAN); + + regmap_write(keypad->regmap, MTK_KPD_DEBOUNCE, + (debounce * (1 << 5)) & MTK_KPD_DEBOUNCE_MASK); + + keypad->clk = devm_clk_get(&pdev->dev, "kpd"); + if (IS_ERR(keypad->clk)) + return PTR_ERR(keypad->clk); + + error = clk_prepare_enable(keypad->clk); + if (error) { + dev_err(&pdev->dev, "cannot prepare/enable keypad clock\n"); + return error; + } + + error = devm_add_action_or_reset(&pdev->dev, mt6779_keypad_clk_disable, + keypad->clk); + if (error) + return error; + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, mt6779_keypad_irq_handler, + IRQF_ONESHOT, MTK_KPD_NAME, keypad); + if (error) { + dev_err(&pdev->dev, "Failed to request IRQ#%d: %d\n", + irq, error); + return error; + } + + error = input_register_device(keypad->input_dev); + if (error) { + dev_err(&pdev->dev, "Failed to register device\n"); + return error; + } + + error = device_init_wakeup(&pdev->dev, wakeup); + if (error) + dev_warn(&pdev->dev, "device_init_wakeup() failed: %d\n", + error); + + return 0; +} + +static const struct of_device_id mt6779_keypad_of_match[] = { + { .compatible = "mediatek,mt6779-keypad" }, + { .compatible = "mediatek,mt6873-keypad" }, + { /* sentinel */ } +}; + +static struct platform_driver mt6779_keypad_pdrv = { + .probe = mt6779_keypad_pdrv_probe, + .driver = { + .name = MTK_KPD_NAME, + .of_match_table = mt6779_keypad_of_match, + }, +}; +module_platform_driver(mt6779_keypad_pdrv); + +MODULE_AUTHOR("Mediatek Corporation"); +MODULE_DESCRIPTION("MTK Keypad (KPD) Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c index 62391d6c7da6..c31ab4368388 100644 --- a/drivers/input/keyboard/mtk-pmic-keys.c +++ b/drivers/input/keyboard/mtk-pmic-keys.c @@ -9,6 +9,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/mfd/mt6323/registers.h> +#include <linux/mfd/mt6358/registers.h> #include <linux/mfd/mt6397/core.h> #include <linux/mfd/mt6397/registers.h> #include <linux/module.h> @@ -74,11 +75,22 @@ static const struct mtk_pmic_regs mt6323_regs = { .pmic_rst_reg = MT6323_TOP_RST_MISC, }; +static const struct mtk_pmic_regs mt6358_regs = { + .keys_regs[MTK_PMIC_PWRKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS, + 0x2, MT6358_PSC_TOP_INT_CON0, 0x5), + .keys_regs[MTK_PMIC_HOMEKEY_INDEX] = + MTK_PMIC_KEYS_REGS(MT6358_TOPSTATUS, + 0x8, MT6358_PSC_TOP_INT_CON0, 0xa), + .pmic_rst_reg = MT6358_TOP_RST_MISC, +}; + struct mtk_pmic_keys_info { struct mtk_pmic_keys *keys; const struct mtk_pmic_keys_regs *regs; unsigned int keycode; int irq; + int irq_r; /* optional: release irq if different */ bool wakeup:1; }; @@ -188,6 +200,18 @@ static int mtk_pmic_key_setup(struct mtk_pmic_keys *keys, return ret; } + if (info->irq_r > 0) { + ret = devm_request_threaded_irq(keys->dev, info->irq_r, NULL, + mtk_pmic_keys_irq_handler_thread, + IRQF_ONESHOT | IRQF_TRIGGER_HIGH, + "mtk-pmic-keys", info); + if (ret) { + dev_err(keys->dev, "Failed to request IRQ_r: %d: %d\n", + info->irq, ret); + return ret; + } + } + input_set_capability(keys->input_dev, EV_KEY, info->keycode); return 0; @@ -199,8 +223,11 @@ static int __maybe_unused mtk_pmic_keys_suspend(struct device *dev) int index; for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) { - if (keys->keys[index].wakeup) + if (keys->keys[index].wakeup) { enable_irq_wake(keys->keys[index].irq); + if (keys->keys[index].irq_r > 0) + enable_irq_wake(keys->keys[index].irq_r); + } } return 0; @@ -212,8 +239,11 @@ static int __maybe_unused mtk_pmic_keys_resume(struct device *dev) int index; for (index = 0; index < MTK_PMIC_MAX_KEY_COUNT; index++) { - if (keys->keys[index].wakeup) + if (keys->keys[index].wakeup) { disable_irq_wake(keys->keys[index].irq); + if (keys->keys[index].irq_r > 0) + disable_irq_wake(keys->keys[index].irq_r); + } } return 0; @@ -230,6 +260,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = { .compatible = "mediatek,mt6323-keys", .data = &mt6323_regs, }, { + .compatible = "mediatek,mt6358-keys", + .data = &mt6358_regs, + }, { /* sentinel */ } }; @@ -241,6 +274,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) unsigned int keycount; struct mt6397_chip *pmic_chip = dev_get_drvdata(pdev->dev.parent); struct device_node *node = pdev->dev.of_node, *child; + static const char *const irqnames[] = { "powerkey", "homekey" }; + static const char *const irqnames_r[] = { "powerkey_r", "homekey_r" }; struct mtk_pmic_keys *keys; const struct mtk_pmic_regs *mtk_pmic_regs; struct input_dev *input_dev; @@ -268,7 +303,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) input_dev->id.version = 0x0001; keycount = of_get_available_child_count(node); - if (keycount > MTK_PMIC_MAX_KEY_COUNT) { + if (keycount > MTK_PMIC_MAX_KEY_COUNT || + keycount > ARRAY_SIZE(irqnames)) { dev_err(keys->dev, "too many keys defined (%d)\n", keycount); return -EINVAL; } @@ -276,12 +312,23 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev) for_each_child_of_node(node, child) { keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index]; - keys->keys[index].irq = platform_get_irq(pdev, index); + keys->keys[index].irq = + platform_get_irq_byname(pdev, irqnames[index]); if (keys->keys[index].irq < 0) { of_node_put(child); return keys->keys[index].irq; } + if (of_device_is_compatible(node, "mediatek,mt6358-keys")) { + keys->keys[index].irq_r = platform_get_irq_byname(pdev, + irqnames_r[index]); + + if (keys->keys[index].irq_r < 0) { + of_node_put(child); + return keys->keys[index].irq_r; + } + } + error = of_property_read_u32(child, "linux,keycodes", &keys->keys[index].keycode); if (error) { diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index 79851923ee57..b14a389600c9 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -4,6 +4,7 @@ * Copyright (C) 2015 Dialog Semiconductor Ltd. */ +#include <linux/devm-helpers.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/input.h> @@ -182,13 +183,6 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data) return IRQ_HANDLED; } -static void da9063_cancel_poll(void *data) -{ - struct da9063_onkey *onkey = data; - - cancel_delayed_work_sync(&onkey->work); -} - static int da9063_onkey_probe(struct platform_device *pdev) { struct da9063_onkey *onkey; @@ -234,9 +228,8 @@ static int da9063_onkey_probe(struct platform_device *pdev) input_set_capability(onkey->input, EV_KEY, KEY_POWER); - INIT_DELAYED_WORK(&onkey->work, da9063_poll_on); - - error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey); + error = devm_delayed_work_autocancel(&pdev->dev, &onkey->work, + da9063_poll_on); if (error) { dev_err(&pdev->dev, "Failed to add cancel poll action: %d\n", diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index ffad142801b3..434d48ae4b12 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -186,6 +186,7 @@ static const char * const smbus_pnp_ids[] = { "LEN2044", /* L470 */ "LEN2054", /* E480 */ "LEN2055", /* E580 */ + "LEN2064", /* T14 Gen 1 AMD / P14s Gen 1 AMD */ "LEN2068", /* T14 Gen 1 */ "SYN3052", /* HP EliteBook 840 G4 */ "SYN3221", /* HP 15-ay000 */ diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c index 8970b49ea09a..9b02dd5dd2b9 100644 --- a/drivers/input/serio/ps2-gpio.c +++ b/drivers/input/serio/ps2-gpio.c @@ -19,6 +19,7 @@ #include <linux/of.h> #include <linux/jiffies.h> #include <linux/delay.h> +#include <linux/timekeeping.h> #define DRIVER_NAME "ps2-gpio" @@ -36,14 +37,37 @@ #define PS2_DATA_BIT7 8 #define PS2_PARITY_BIT 9 #define PS2_STOP_BIT 10 -#define PS2_TX_TIMEOUT 11 -#define PS2_ACK_BIT 12 +#define PS2_ACK_BIT 11 #define PS2_DEV_RET_ACK 0xfa #define PS2_DEV_RET_NACK 0xfe #define PS2_CMD_RESEND 0xfe +/* + * The PS2 protocol specifies a clock frequency between 10kHz and 16.7kHz, + * therefore the maximal interrupt interval should be 100us and the minimum + * interrupt interval should be ~60us. Let's allow +/- 20us for frequency + * deviations and interrupt latency. + * + * The data line must be samples after ~30us to 50us after the falling edge, + * since the device updates the data line at the rising edge. + * + * ___ ______ |
