diff options
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/input.c | 45 | ||||
-rw-r--r-- | drivers/input/joystick/xpad.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 12 | ||||
-rw-r--r-- | drivers/input/keyboard/Makefile | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/mt6779-keypad.c | 221 | ||||
-rw-r--r-- | drivers/input/keyboard/mtk-pmic-keys.c | 55 | ||||
-rw-r--r-- | drivers/input/misc/da9063_onkey.c | 13 | ||||
-rw-r--r-- | drivers/input/serio/ps2-gpio.c | 195 | ||||
-rw-r--r-- | drivers/input/touchscreen/goodix.c | 61 | ||||
-rw-r--r-- | drivers/input/touchscreen/goodix.h | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/tsc200x-core.c | 7 |
11 files changed, 490 insertions, 123 deletions
diff --git a/drivers/input/input.c b/drivers/input/input.c index c3139bc2aa0d..7c7e4042ec10 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -511,6 +511,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 +523,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 @@ -2085,9 +2121,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; 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..df1a029d029b 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -779,6 +779,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/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/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. + * + * ___ ______ ______ ______ ___ + * \ / \ / \ / \ / + * \ / \ / \ / \ / + * \______/ \______/ \______/ \______/ + * + * |-----------------| |--------| + * 60us/100us 30us/50us + */ +#define PS2_CLK_FREQ_MIN_HZ 10000 +#define PS2_CLK_FREQ_MAX_HZ 16700 +#define PS2_CLK_MIN_INTERVAL_US ((1000 * 1000) / PS2_CLK_FREQ_MAX_HZ) +#define PS2_CLK_MAX_INTERVAL_US ((1000 * 1000) / PS2_CLK_FREQ_MIN_HZ) +#define PS2_IRQ_MIN_INTERVAL_US (PS2_CLK_MIN_INTERVAL_US - 20) +#define PS2_IRQ_MAX_INTERVAL_US (PS2_CLK_MAX_INTERVAL_US + 20) + struct ps2_gpio_data { struct device *dev; struct serio *serio; @@ -52,19 +76,30 @@ struct ps2_gpio_data { struct gpio_desc *gpio_data; bool write_enable; int irq; - unsigned char rx_cnt; - unsigned char rx_byte; - unsigned char tx_cnt; - unsigned char tx_byte; - struct completion tx_done; - struct mutex tx_mutex; - struct delayed_work tx_work; + ktime_t t_irq_now; + ktime_t t_irq_last; + struct { + unsigned char cnt; + unsigned char byte; + } rx; + struct { + unsigned char cnt; + unsigned char byte; + ktime_t t_xfer_start; + ktime_t t_xfer_end; + struct completion complete; + struct mutex mutex; + struct delayed_work work; + } tx; }; static int ps2_gpio_open(struct serio *serio) { struct ps2_gpio_data *drvdata = serio->port_data; + drvdata->t_irq_last = 0; + drvdata->tx.t_xfer_end = 0; + enable_irq(drvdata->irq); return 0; } @@ -73,7 +108,7 @@ static void ps2_gpio_close(struct serio *serio) { struct ps2_gpio_data *drvdata = serio->port_data; - flush_delayed_work(&drvdata->tx_work); + flush_delayed_work(&drvdata->tx.work); disable_irq(drvdata->irq); } @@ -85,9 +120,9 @@ static int __ps2_gpio_write(struct serio *serio, unsigned char val) gpiod_direction_output(drvdata->gpio_clk, 0); drvdata->mode = PS2_MODE_TX; - drvdata->tx_byte = val; + drvdata->tx.byte = val; - schedule_delayed_work(&drvdata->tx_work, usecs_to_jiffies(200)); + schedule_delayed_work(&drvdata->tx.work, usecs_to_jiffies(200)); return 0; } @@ -98,12 +133,12 @@ static int ps2_gpio_write(struct serio *serio, unsigned char val) int ret = 0; if (in_task()) { - mutex_lock(&drvdata->tx_mutex); + mutex_lock(&drvdata->tx.mutex); __ps2_gpio_write(serio, val); - if (!wait_for_completion_timeout(&drvdata->tx_done, + if (!wait_for_completion_timeout(&drvdata->tx.complete, msecs_to_jiffies(10000))) ret = SERIO_TIMEOUT; - mutex_unlock(&drvdata->tx_mutex); + mutex_unlock(&drvdata->tx.mutex); } else { __ps2_gpio_write(serio, val); } @@ -115,9 +150,10 @@ static void ps2_gpio_tx_work_fn(struct work_struct *work) { struct delayed_work *dwork = to_delayed_work(work); struct ps2_gpio_data *drvdata = container_of(dwork, - struct ps2_gpio_data, - tx_work); + struct ps2_gpio_data, + tx.work); + drvdata->tx.t_xfer_start = ktime_get(); enable_irq(drvdata->irq); gpiod_direction_output(drvdata->gpio_data, 0); gpiod_direction_input(drvdata->gpio_clk); @@ -128,20 +164,31 @@ static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata) unsigned char byte, cnt; int data; int rxflags = 0; - static unsigned long old_jiffies; + s64 us_delta; - byte = drvdata->rx_byte; - cnt = drvdata->rx_cnt; + byte = drvdata->rx.byte; + cnt = drvdata->rx.cnt; - if (old_jiffies == 0) - old_jiffies = jiffies; + drvdata->t_irq_now = ktime_get(); + + /* + * We need to consider spurious interrupts happening right after + * a TX xfer finished. + */ + us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->tx.t_xfer_end); + if (unlikely(us_delta < PS2_IRQ_MIN_INTERVAL_US)) + goto end; - if ((jiffies - old_jiffies) > usecs_to_jiffies(100)) { + us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->t_irq_last); + if (us_delta > PS2_IRQ_MAX_INTERVAL_US && cnt) { dev_err(drvdata->dev, "RX: timeout, probably we missed an interrupt\n"); goto err; + } else if (unlikely(us_delta < PS2_IRQ_MIN_INTERVAL_US)) { + /* Ignore spurious IRQs. */ + goto end; } - old_jiffies = jiffies; + drvdata->t_irq_last = drvdata->t_irq_now; data = gpiod_get_value(drvdata->gpio_data); if (unlikely(data < 0)) { @@ -178,8 +225,16 @@ static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata) if (!drvdata->write_enable) goto err; } + break; + case PS2_STOP_BIT: + /* stop bit should be high */ + if (unlikely(!data)) { + dev_err(drvdata->dev, "RX: stop bit should be high\n"); + goto err; + } - /* Do not send spurious ACK's and NACK's when write fn is + /* + * Do not send spurious ACK's and NACK's when write fn is * not provided. */ if (!drvdata->write_enable) { @@ -189,23 +244,11 @@ static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata) break; } - /* Let's send the data without waiting for the stop bit to be - * sent. It may happen that we miss the stop bit. When this - * happens we have no way to recover from this, certainly - * missing the parity bit would be recognized when processing - * the stop bit. When missing both, data is lost. - */ serio_interrupt(drvdata->serio, byte, rxflags); dev_dbg(drvdata->dev, "RX: sending byte 0x%x\n", byte); - break; - case PS2_STOP_BIT: - /* stop bit should be high */ - if (unlikely(!data)) { - dev_err(drvdata->dev, "RX: stop bit should be high\n"); - goto err; - } + cnt = byte = 0; - old_jiffies = 0; + goto end; /* success */ default: dev_err(drvdata->dev, "RX: got out of sync with the device\n"); @@ -217,11 +260,10 @@ static irqreturn_t ps2_gpio_irq_rx(struct ps2_gpio_data *drvdata) err: cnt = byte = 0; - old_jiffies = 0; __ps2_gpio_write(drvdata->serio, PS2_CMD_RESEND); end: - drvdata->rx_cnt = cnt; - drvdata->rx_byte = byte; + drvdata->rx.cnt = cnt; + drvdata->rx.byte = byte; return IRQ_HANDLED; } @@ -229,20 +271,34 @@ static irqreturn_t ps2_gpio_irq_tx(struct ps2_gpio_data *drvdata) { unsigned char byte, cnt; int data; - static unsigned long old_jiffies; + s64 us_delta; + + cnt = drvdata->tx.cnt; + byte = drvdata->tx.byte; - cnt = drvdata->tx_cnt; - byte = drvdata->tx_byte; + drvdata->t_irq_now = ktime_get(); - if (old_jiffies == 0) - old_jiffies = jiffies; + /* + * There might be pending IRQs since we disabled IRQs in + * __ps2_gpio_write(). We can expect at least one clock period until + * the device generates the first falling edge after releasing the + * clock line. + */ + us_delta = ktime_us_delta(drvdata->t_irq_now, + drvdata->tx.t_xfer_start); + if (unlikely(us_delta < PS2_CLK_MIN_INTERVAL_US)) + goto end; - if ((jiffies - old_jiffies) > usecs_to_jiffies(100)) { + us_delta = ktime_us_delta(drvdata->t_irq_now, drvdata->t_irq_last); + if (us_delta > PS2_IRQ_MAX_INTERVAL_US && cnt > 1) { dev_err(drvdata->dev, "TX: timeout, probably we missed an interrupt\n"); goto err; + } else if (unlikely(us_delta < PS2_IRQ_MIN_INTERVAL_US)) { + /* Ignore spurious IRQs. */ + goto end; } - old_jiffies = jiffies; + drvdata->t_irq_last = drvdata->t_irq_now; switch (cnt) { case PS2_START_BIT: @@ -270,27 +326,22 @@ static irqreturn_t ps2_gpio_irq_tx(struct ps2_gpio_data *drvdata) /* release data line to generate stop bit */ gpiod_direction_input(drvdata->gpio_data); break; - case PS2_TX_TIMEOUT: - /* Devices generate one extra clock pulse before sending the - * acknowledgment. - */ - break; case PS2_ACK_BIT: - gpiod_direction_input(drvdata->gpio_data); data = gpiod_get_value(drvdata->gpio_data); if (data) { dev_warn(drvdata->dev, "TX: received NACK, retry\n"); goto err; } + drvdata->tx.t_xfer_end = ktime_get(); drvdata->mode = PS2_MODE_RX; - complete(&drvdata->tx_done); + complete(&drvdata->tx.complete); cnt = 1; - old_jiffies = 0; goto end; /* success */ default: - /* Probably we missed the stop bit. Therefore we release data + /* + * Probably we missed the stop bit. Therefore we release data * line and try again. */ gpiod_direction_input(drvdata->gpio_data); @@ -303,11 +354,10 @@ static irqreturn_t ps2_gpio_irq_tx(struct ps2_gpio_data *drvdata) err: cnt = 1; - old_jiffies = 0; gpiod_direction_input(drvdata->gpio_data); - __ps2_gpio_write(drvdata->serio, drvdata->tx_byte); + __ps2_gpio_write(drvdata->serio, drvdata->tx.byte); end: - drvdata->tx_cnt = cnt; + drvdata->tx.cnt = cnt; return IRQ_HANDLED; } @@ -322,14 +372,19 @@ static irqreturn_t ps2_gpio_irq(int irq, void *dev_id) static int ps2_gpio_get_props(struct device *dev, struct ps2_gpio_data *drvdata) { - drvdata->gpio_data = devm_gpiod_get(dev, "data", GPIOD_IN); + enum gpiod_flags gflags; + + /* Enforce open drain, since this is required by the PS/2 bus. */ + gflags = GPIOD_IN | GPIOD_FLAGS_BIT_OPEN_DRAIN; + + drvdata->gpio_data = devm_gpiod_get(dev, "data", gflags); if (IS_ERR(drvdata->gpio_data)) { dev_err(dev, "failed to request data gpio: %ld", PTR_ERR(drvdata->gpio_data)); return PTR_ERR(drvdata->gpio_data); } - drvdata->gpio_clk = devm_gpiod_get(dev, "clk", GPIOD_IN); + drvdata->gpio_clk = devm_gpiod_get(dev, "clk", gflags); if (IS_ERR(drvdata->gpio_clk)) { dev_err(dev, "failed to request clock gpio: %ld", PTR_ERR(drvdata->gpio_clk)); @@ -387,7 +442,8 @@ static int ps2_gpio_probe(struct platform_device *pdev) serio->id.type = SERIO_8042; serio->open = ps2_gpio_open; serio->close = ps2_gpio_close; - /* Write can be enabled in platform/dt data, but possibly it will not + /* + * Write can be enabled in platform/dt data, but possibly it will not * work because of the tough timings. */ serio->write = drvdata->write_enable ? ps2_gpio_write : NULL; @@ -400,14 +456,15 @@ static int ps2_gpio_probe(struct platform_device *pdev) drvdata->dev = dev; drvdata->mode = PS2_MODE_RX; - /* Tx count always starts at 1, as the start bit is sent implicitly by + /* + * Tx count always starts at 1, as the start bit is sent implicitly by * host-to-device communication initialization. */ - drvdata->tx_cnt = 1; + drvdata->tx.cnt = 1; - INIT_DELAYED_WORK(&drvdata->tx_work, ps2_gpio_tx_work_fn); - init_completion(&drvdata->tx_done); - mutex_init(&drvdata->tx_mutex); + INIT_DELAYED_WORK(&drvdata->tx.work, ps2_gpio_tx_work_fn); + init_completion(&drvdata->tx.complete); + mutex_init(&drvdata->tx.mutex); serio_register_port(serio); platform_set_drvdata(pdev, drvdata); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 752e8ba4fecb..3ad9870db108 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -298,32 +298,17 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) return -ENOMSG; } -static struct input_dev *goodix_create_pen_input(struct goodix_ts_data *ts) +static int goodix_create_pen_input(struct goodix_ts_data *ts) { struct device *dev = &ts->client->dev; struct input_dev *input; input = devm_input_allocate_device(dev); if (!input) - return NULL; - - input_alloc_absinfo(input); - if (!input->absinfo) { - input_free_device(input); - return NULL; - } - - input->absinfo[ABS_X] = ts->input_dev->absinfo[ABS_MT_POSITION_X]; - input->absinfo[ABS_Y] = ts->input_dev->absinfo[ABS_MT_POSITION_Y]; - __set_bit(ABS_X, input->absbit); - __set_bit(ABS_Y, input->absbit); - input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0); + return -ENOMEM; - input_set_capability(input, EV_KEY, BTN_TOUCH); - input_set_capability(input, EV_KEY, BTN_TOOL_PEN); - input_set_capability(input, EV_KEY, BTN_STYLUS); - input_set_capability(input, EV_KEY, BTN_STYLUS2); - __set_bit(INPUT_PROP_DIRECT, input->propbit); + input_copy_abs(input, ABS_X, ts->input_dev, ABS_MT_POSITION_X); + input_copy_abs(input, ABS_Y, ts->input_dev, ABS_MT_POSITION_Y); /* * The resolution of these touchscreens is about 10 units/mm, the actual * resolution does not matter much since we set INPUT_PROP_DIRECT. @@ -331,6 +316,13 @@ static struct input_dev *goodix_create_pen_input(struct goodix_ts_data *ts) */ input_abs_set_res(input, ABS_X, 10); input_abs_set_res(input, ABS_Y, 10); + input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0); + + input_set_capability(input, EV_KEY, BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOOL_PEN); + input_set_capability(input, EV_KEY, BTN_STYLUS); + input_set_capability(input, EV_KEY, BTN_STYLUS2); + __set_bit(INPUT_PROP_DIRECT, input->propbit); input->name = "Goodix Active Pen"; input->phys = "input/pen"; @@ -340,25 +332,23 @@ static struct input_dev *goodix_create_pen_input(struct goodix_ts_data *ts) input->id.product = 0x1001; input->id.version = ts->version; - if (input_register_device(input) != 0) { - input_free_device(input); - return NULL; - } - - return input; + ts->input_pen = input; + return 0; } static void goodix_ts_report_pen_down(struct goodix_ts_data *ts, u8 *data) { - int input_x, input_y, input_w; + int input_x, input_y, input_w, error; u8 key_value; - if (!ts->input_pen) { - ts->input_pen = goodix_create_pen_input(ts); - if (!ts->input_pen) - return; + if (!ts->pen_input_registered) { + error = input_register_device(ts->input_pen); + ts->pen_input_registered = (error == 0) ? 1 : error; } + if (ts->pen_input_registered < 0) + return; + if (ts->contact_size == 9) { input_x = get_unaligned_le16(&data[4]); input_y = get_unaligned_le16(&data[6]); @@ -1215,6 +1205,17 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) return error; } + /* + * Create the input_pen device before goodix_request_irq() calls + * devm_request_threaded_irq() so that the devm framework frees + * it after disabling the irq. + * Unfortunately there is no way to detect if the touchscreen has pen + * support, so registering the dev is delayed till the first pen event. + */ + error = goodix_create_pen_input(ts); + if (error) + return error; + ts->irq_flags = goodix_irq_flags[ts->int_trigger_type] | IRQF_ONESHOT; error = goodix_request_irq(ts); if (error) { diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index fa8602e78a64..87797cc88b32 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -94,6 +94,7 @@ struct goodix_ts_data { u16 version; bool reset_controller_at_probe; bool load_cfg_from_disk; + int pen_input_registered; struct completion firmware_loading_complete; unsigned long irq_flags; enum goodix_irq_pin_access_method irq_pin_access_method; diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c index 27810f6c69f6..72c7258b93a5 100644 --- a/drivers/input/touchscreen/tsc200x-core.c +++ b/drivers/input/touchscreen/tsc200x-core.c @@ -88,6 +88,8 @@ struct tsc200x { int in_z1; int in_z2; + struct touchscreen_properties prop; + spinlock_t lock; struct timer_list penup_timer; @@ -113,8 +115,7 @@ static void tsc200x_update_pen_state(struct tsc200x *ts, int x, int y, int pressure) { if (pressure) { - input_report_abs(ts->idev, ABS_X, x); - input_report_abs(ts->idev, ABS_Y, y); + touchscreen_report_pos(ts->idev, &ts->prop, x, y, false); input_report_abs(ts->idev, ABS_PRESSURE, pressure); if (!ts->pen_down) { input_report_key(ts->idev, BTN_TOUCH, !!pressure); @@ -533,7 +534,7 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id, input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT, TSC200X_DEF_P_FUZZ, 0); - touchscreen_parse_properties(input_dev, false, NULL); + touchscreen_parse_properties(input_dev, false, &ts->prop); /* Ensure the touchscreen is off */ tsc200x_stop_scan(ts); |