From 40e40fdfec3faf08951c2a600177e23f4d43fc32 Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Tue, 21 Feb 2023 11:41:45 -0800 Subject: [PATCH 01/42] Input: bbnsm_pwrkey - add bbnsm power key support The ON/OFF logic inside the BBNSM allows for connecting directly into a PMIC or other voltage regulator device. The module has an button input signal and a wakeup request input signal. It also has two interrupts (set_pwr_off_irq and set_pwr_on_irq) and an active-low PMIC enable (pmic_en_b) output. Add the power key support for the ON/OFF button function found in BBNSM module. Signed-off-by: Jacky Bai Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20230215024117.3357341-2-ping.bai@nxp.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 11 ++ drivers/input/misc/Makefile | 1 + drivers/input/misc/nxp-bbnsm-pwrkey.c | 193 ++++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100644 drivers/input/misc/nxp-bbnsm-pwrkey.c diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 5c2d0c06d2a5..81a54a59e13c 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -119,6 +119,17 @@ config INPUT_ATMEL_CAPTOUCH To compile this driver as a module, choose M here: the module will be called atmel_captouch. +config INPUT_BBNSM_PWRKEY + tristate "NXP BBNSM Power Key Driver" + depends on ARCH_MXC || COMPILE_TEST + depends on OF + help + This is the bbnsm powerkey driver for the NXP i.MX application + processors. + + To compile this driver as a module, choose M here; the + module will be called bbnsm_pwrkey. + config INPUT_BMA150 tristate "BMA150/SMB380 acceleration sensor support" depends on I2C diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 61949263300d..04296a4abe8e 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o +obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o obj-$(CONFIG_INPUT_BMA150) += bma150.o obj-$(CONFIG_INPUT_CM109) += cm109.o obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o diff --git a/drivers/input/misc/nxp-bbnsm-pwrkey.c b/drivers/input/misc/nxp-bbnsm-pwrkey.c new file mode 100644 index 000000000000..1d99206dd3a8 --- /dev/null +++ b/drivers/input/misc/nxp-bbnsm-pwrkey.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2022 NXP. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BBNSM_CTRL 0x8 +#define BBNSM_INT_EN 0x10 +#define BBNSM_EVENTS 0x14 +#define BBNSM_PAD_CTRL 0x24 + +#define BBNSM_BTN_PRESSED BIT(7) +#define BBNSM_PWR_ON BIT(6) +#define BBNSM_BTN_OFF BIT(5) +#define BBNSM_EMG_OFF BIT(4) +#define BBNSM_PWRKEY_EVENTS (BBNSM_PWR_ON | BBNSM_BTN_OFF | BBNSM_EMG_OFF) +#define BBNSM_DP_EN BIT(24) + +#define DEBOUNCE_TIME 30 +#define REPEAT_INTERVAL 60 + +struct bbnsm_pwrkey { + struct regmap *regmap; + int irq; + int keycode; + int keystate; /* 1:pressed */ + struct timer_list check_timer; + struct input_dev *input; +}; + +static void bbnsm_pwrkey_check_for_events(struct timer_list *t) +{ + struct bbnsm_pwrkey *bbnsm = from_timer(bbnsm, t, check_timer); + struct input_dev *input = bbnsm->input; + u32 state; + + regmap_read(bbnsm->regmap, BBNSM_EVENTS, &state); + + state = state & BBNSM_BTN_PRESSED ? 1 : 0; + + /* only report new event if status changed */ + if (state ^ bbnsm->keystate) { + bbnsm->keystate = state; + input_event(input, EV_KEY, bbnsm->keycode, state); + input_sync(input); + pm_relax(bbnsm->input->dev.parent); + } + + /* repeat check if pressed long */ + if (state) + mod_timer(&bbnsm->check_timer, + jiffies + msecs_to_jiffies(REPEAT_INTERVAL)); +} + +static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id) +{ + struct platform_device *pdev = dev_id; + struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev); + u32 event; + + regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event); + if (!(event & BBNSM_BTN_OFF)) + return IRQ_NONE; + + pm_wakeup_event(bbnsm->input->dev.parent, 0); + + mod_timer(&bbnsm->check_timer, + jiffies + msecs_to_jiffies(DEBOUNCE_TIME)); + + /* clear PWR OFF */ + regmap_write(bbnsm->regmap, BBNSM_EVENTS, BBNSM_BTN_OFF); + + return IRQ_HANDLED; +} + +static void bbnsm_pwrkey_act(void *pdata) +{ + struct bbnsm_pwrkey *bbnsm = pdata; + + timer_shutdown_sync(&bbnsm->check_timer); +} + +static int bbnsm_pwrkey_probe(struct platform_device *pdev) +{ + struct bbnsm_pwrkey *bbnsm; + struct input_dev *input; + struct device_node *np = pdev->dev.of_node; + int error; + + bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL); + if (!bbnsm) + return -ENOMEM; + + bbnsm->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(bbnsm->regmap)) { + dev_err(&pdev->dev, "bbnsm pwerkey get regmap failed\n"); + return PTR_ERR(bbnsm->regmap); + } + + if (device_property_read_u32(&pdev->dev, "linux,code", + &bbnsm->keycode)) { + bbnsm->keycode = KEY_POWER; + dev_warn(&pdev->dev, "key code is not specified, using default KEY_POWER\n"); + } + + bbnsm->irq = platform_get_irq(pdev, 0); + if (bbnsm->irq < 0) + return -EINVAL; + + /* config the BBNSM power related register */ + regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, BBNSM_DP_EN, BBNSM_DP_EN); + + /* clear the unexpected interrupt before driver ready */ + regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, BBNSM_PWRKEY_EVENTS, + BBNSM_PWRKEY_EVENTS); + + timer_setup(&bbnsm->check_timer, bbnsm_pwrkey_check_for_events, 0); + + input = devm_input_allocate_device(&pdev->dev); + if (!input) { + dev_err(&pdev->dev, "failed to allocate the input device\n"); + return -ENOMEM; + } + + input->name = pdev->name; + input->phys = "bbnsm-pwrkey/input0"; + input->id.bustype = BUS_HOST; + + input_set_capability(input, EV_KEY, bbnsm->keycode); + + /* input customer action to cancel release timer */ + error = devm_add_action(&pdev->dev, bbnsm_pwrkey_act, bbnsm); + if (error) { + dev_err(&pdev->dev, "failed to register remove action\n"); + return error; + } + + bbnsm->input = input; + platform_set_drvdata(pdev, bbnsm); + + error = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_pwrkey_interrupt, + IRQF_SHARED, pdev->name, pdev); + if (error) { + dev_err(&pdev->dev, "interrupt not available.\n"); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(&pdev->dev, "failed to register input device\n"); + return error; + } + + device_init_wakeup(&pdev->dev, true); + error = dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq); + if (error) + dev_warn(&pdev->dev, "irq wake enable failed.\n"); + + return 0; +} + +static const struct of_device_id bbnsm_pwrkey_ids[] = { + { .compatible = "nxp,imx93-bbnsm-pwrkey" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, bbnsm_pwrkey_ids); + +static struct platform_driver bbnsm_pwrkey_driver = { + .driver = { + .name = "bbnsm_pwrkey", + .of_match_table = bbnsm_pwrkey_ids, + }, + .probe = bbnsm_pwrkey_probe, +}; +module_platform_driver(bbnsm_pwrkey_driver); + +MODULE_AUTHOR("Jacky Bai "); +MODULE_DESCRIPTION("NXP bbnsm power key Driver"); +MODULE_LICENSE("GPL"); From 4b665e1781e2cd64b3b9492e49156925ba02bfa9 Mon Sep 17 00:00:00 2001 From: Gergo Koteles Date: Tue, 21 Feb 2023 11:47:48 -0800 Subject: [PATCH 02/42] Input: gpio-keys - add support for linux,input-value DTS property Allows setting the value of EV_ABS events from DTS. This property is included in the gpio-keys.yaml scheme, but was only implemented for gpio-keys-polled. Signed-off-by: Gergo Koteles Link: https://lore.kernel.org/r/3519a11b0ef5324a2befbd137cd2aa0cb8fd057d.1676850819.git.soyer@irl.hu Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 5496482a38c1..c42f86ad0766 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -770,6 +770,9 @@ gpio_keys_get_devtree_pdata(struct device *dev) &button->type)) button->type = EV_KEY; + fwnode_property_read_u32(child, "linux,input-value", + (u32 *)&button->value); + button->wakeup = fwnode_property_read_bool(child, "wakeup-source") || /* legacy name */ From c6f3b684c2c4e8d4700fe8c4a173c0a70df6cc14 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 21 Feb 2023 13:25:17 -0800 Subject: [PATCH 03/42] dt-bindings: google,cros-ec-keyb: Fix spelling error The dependency had an obvious spelling error. Fix it. Signed-off-by: Linus Walleij Reviewed-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230220135531.1987351-1-linus.walleij@linaro.org Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/google,cros-ec-keyb.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml index e05690b3e963..a8abdb39623b 100644 --- a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml +++ b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml @@ -45,7 +45,7 @@ properties: when the keyboard has a custom design for the top row keys. dependencies: - function-row-phsymap: [ 'linux,keymap' ] + function-row-physmap: [ 'linux,keymap' ] google,needs-ghost-filter: [ 'linux,keymap' ] required: From 586dc36226dd748b197eea8642c087cae611129b Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 9 Feb 2023 16:44:06 -0800 Subject: [PATCH 04/42] Input: hp_sdc_rtc - mark an unused function as __maybe_unused When CONFIG_PROC_FS is not set, one procfs-related function is not used, causing a build error or warning. Mark this function as __maybe_unused to quieten the build. ../drivers/input/misc/hp_sdc_rtc.c:268:12: warning: 'hp_sdc_rtc_proc_show' defined but not used [-Wunused-function] 268 | static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) | ^~~~~~~~~~~~~~~~~~~~ Fixes: c18bd9a1ff47 ("hp_sdc_rtc: Don't use create_proc_read_entry()") Signed-off-by: Randy Dunlap Reviewed-by: Geert Uytterhoeven Link: https://lore.kernel.org/r/20230209010125.23690-1-rdunlap@infradead.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/hp_sdc_rtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c index 199bc17ddb1d..afc0d6dc5787 100644 --- a/drivers/input/misc/hp_sdc_rtc.c +++ b/drivers/input/misc/hp_sdc_rtc.c @@ -265,7 +265,7 @@ static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) { return 0; } -static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) +static int __maybe_unused hp_sdc_rtc_proc_show(struct seq_file *m, void *v) { #define YN(bit) ("no") #define NY(bit) ("yes") From 9e03024ce27625e42d3a9a76af37f5369db652cd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Feb 2023 22:11:21 -0800 Subject: [PATCH 05/42] ARM: spitz: include header defining input event codes The board file for Sharp SL-Cxx00 Series of PDAs uses various KEY_* defines, but does not include the relevant header directly and instead relies on other headers to include it indirectly. With the upcoming cleanup of matrix_keypad.h this indirection is now broken and we should include the relevant header directly. Reported: Guenter Roeck Acked-by: Arnd Bergmann Link: https://lore.kernel.org/r/Y/U+3PZsbLw++SnG@google.com Signed-off-by: Dmitry Torokhov --- arch/arm/mach-pxa/spitz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 9964729cd428..75634ef6688d 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include From d5f7638eb5fed0eb12e45a127764c4111b11c50e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 24 Oct 2022 05:34:14 -0700 Subject: [PATCH 06/42] Input: matrix_keypad - replace header inclusions by forward declarations When the data structure is only referred by pointer, compiler may not need to see the contents of the data type. Thus, we may replace header inclusions by respective forward declarations. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20220923184632.2157-2-andriy.shevchenko@linux.intel.com Signed-off-by: Dmitry Torokhov --- include/linux/input/matrix_keypad.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/input/matrix_keypad.h b/include/linux/input/matrix_keypad.h index 9476768c3b90..b8d8d69eba29 100644 --- a/include/linux/input/matrix_keypad.h +++ b/include/linux/input/matrix_keypad.h @@ -3,8 +3,9 @@ #define _MATRIX_KEYPAD_H #include -#include -#include + +struct device; +struct input_dev; #define MATRIX_MAX_ROWS 32 #define MATRIX_MAX_COLS 32 From 5af7a77acd0ff23fe06d93c3c7d0e0aa7a264fa7 Mon Sep 17 00:00:00 2001 From: Yang Li Date: Fri, 10 Mar 2023 20:36:17 -0800 Subject: [PATCH 07/42] Input: hideep - clean up some inconsistent indenting Turn the space into a tab to Eliminate the follow smatch warning: drivers/input/touchscreen/hideep.c:470 hideep_program_nvm() warn: inconsistent indenting Reported-by: Abaci Robot Signed-off-by: Yang Li Link: https://lore.kernel.org/r/20220429070103.4747-1-yang.lee@linux.alibaba.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/hideep.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index bd454d93f1f7..05998e83c36a 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -467,9 +467,9 @@ static int hideep_program_nvm(struct hideep_ts *ts, u32 addr = 0; int error; - error = hideep_nvm_unlock(ts); - if (error) - return error; + error = hideep_nvm_unlock(ts); + if (error) + return error; while (ucode_len > 0) { xfer_len = min_t(size_t, ucode_len, HIDEEP_NVM_PAGE_SIZE); From 10b0a455f4378330de41e280ce7839997d24297d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 17 Mar 2023 03:48:07 -0700 Subject: [PATCH 08/42] Input: hideep - silence error in SW_RESET() On some models the first HIDEEP_SYSCON_WDT_CON write alone is enough to cause the controller to reset, causing the second write to fail: i2c-hideep_ts: write to register 0x52000014 (0x000001) failed: -121 Switch this write to a raw hideep_pgm_w_mem() to avoid an error getting logged in this case. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230311114726.182789-2-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/hideep.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index 05998e83c36a..b47feb63cfb8 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -271,9 +271,14 @@ static int hideep_pgm_w_reg(struct hideep_ts *ts, u32 addr, u32 val) #define SW_RESET_IN_PGM(clk) \ { \ + __be32 data = cpu_to_be32(0x01); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CNT, (clk)); \ hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x03); \ - hideep_pgm_w_reg(ts, HIDEEP_SYSCON_WDT_CON, 0x01); \ + /* \ + * The first write may already cause a reset, use a raw \ + * write for the second write to avoid error logging. \ + */ \ + hideep_pgm_w_mem(ts, HIDEEP_SYSCON_WDT_CON, &data, 1); \ } #define SET_FLASH_PIO(ce) \ From 007e50eb5dbe7b33a43a1449a0d9c29e8dcf1c67 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 17 Mar 2023 03:50:27 -0700 Subject: [PATCH 09/42] Input: hideep - optionally reset controller work mode to native HiDeep protocol The HiDeep IST940E touchscreen controller used on the Lenovo Yoga Book X90F convertible comes up in HID mode by default. This works well on the X91F Windows model where the touchscreen is correctly described in ACPI and ACPI takes care of controlling the reset GPIO and regulators. But the X90F ships with Android and the ACPI tables on this model don't describe the touchscreen. Instead this is hardcoded in the vendor kernel. The vendor kernel uses the touchscreen in native HiDeep 20 (2.0?) protocol mode and switches the controller to this mode by writing 0 to reg 0x081e. Adjusting the i2c-hid code to deal with the reset-gpio and regulators on this non devicetree (but rather broken ACPI) convertible is somewhat tricky and the native protocol reports ABS_MT_PRESSURE and ABS_MT_TOUCH_MAJOR which are not reported in HID mode, so it is preferable to use the native mode. Add support to the hideep driver to reset the work-mode to the native HiDeep protocol to allow using it on the Lenovo Yoga Book X90F. This is guarded behind a new "hideep,force-native-protocol" boolean property, to avoid changing behavior on other devices. For the record: I did test using the i2c-hid driver with some quick hacks and it does work. The I2C-HID descriptor is available from address 0x0020, just like on the X91F Windows model. So far the new "hideep,force-native-protocol" property is only used on x86/ACPI (non devicetree) devs. IOW it is not used in actual devicetree files. The devicetree-bindings maintainers have requested properties like these to not be added to the devicetree-bindings, so the new property is deliberately not added to the existing devicetree-bindings. Signed-off-by: Hans de Goede Link: https://lore.kernel.org/r/20230311114726.182789-3-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/hideep.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index b47feb63cfb8..7c7020099b0f 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -35,6 +35,7 @@ #define HIDEEP_EVENT_ADDR 0x240 /* command list */ +#define HIDEEP_WORK_MODE 0x081e #define HIDEEP_RESET_CMD 0x9800 /* event bit */ @@ -964,6 +965,21 @@ static const struct attribute_group hideep_ts_attr_group = { .attrs = hideep_ts_sysfs_entries, }; +static void hideep_set_work_mode(struct hideep_ts *ts) +{ + /* + * Reset touch report format to the native HiDeep 20 protocol if requested. + * This is necessary to make touchscreens which come up in I2C-HID mode + * work with this driver. + * + * Note this is a kernel internal device-property set by x86 platform code, + * this MUST not be used in devicetree files without first adding it to + * the DT bindings. + */ + if (device_property_read_bool(&ts->client->dev, "hideep,force-native-protocol")) + regmap_write(ts->reg, HIDEEP_WORK_MODE, 0x00); +} + static int hideep_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -987,6 +1003,8 @@ static int hideep_resume(struct device *dev) return error; } + hideep_set_work_mode(ts); + enable_irq(client->irq); return 0; @@ -1063,6 +1081,8 @@ static int hideep_probe(struct i2c_client *client) return error; } + hideep_set_work_mode(ts); + error = hideep_init_input(ts); if (error) return error; From 12c7d0aeb3beecc8b8f570d82c4d8509def71a6e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 20:27:10 -0800 Subject: [PATCH 10/42] Input: Use of_property_read_bool() for boolean properties It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. Convert reading boolean properties to of_property_read_bool(). Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230310144708.1542751-1-robh@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/matrix_keypad.c | 6 ++---- drivers/input/keyboard/omap4-keypad.c | 3 +-- drivers/input/keyboard/samsung-keypad.c | 3 +-- drivers/input/keyboard/tegra-kbc.c | 3 +-- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index 203310727d88..a1b037891af2 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -425,14 +425,12 @@ matrix_keypad_parse_dt(struct device *dev) return ERR_PTR(-EINVAL); } - if (of_get_property(np, "linux,no-autorepeat", NULL)) - pdata->no_autorepeat = true; + pdata->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); pdata->wakeup = of_property_read_bool(np, "wakeup-source") || of_property_read_bool(np, "linux,wakeup"); /* legacy */ - if (of_get_property(np, "gpio-activelow", NULL)) - pdata->active_low = true; + pdata->active_low = of_property_read_bool(np, "gpio-activelow"); pdata->drive_inactive_cols = of_property_read_bool(np, "drive-inactive-cols"); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 4426120398b0..9f085d5679db 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -274,8 +274,7 @@ static int omap4_keypad_parse_dt(struct device *dev, if (err) return err; - if (of_get_property(np, "linux,input-no-autorepeat", NULL)) - keypad_data->no_autorepeat = true; + keypad_data->no_autorepeat = of_property_read_bool(np, "linux,input-no-autorepeat"); return 0; } diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 09e883ea1352..d85dd2489293 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -291,8 +291,7 @@ samsung_keypad_parse_dt(struct device *dev) *keymap++ = KEY(row, col, key_code); } - if (of_get_property(np, "linux,input-no-autorepeat", NULL)) - pdata->no_autorepeat = true; + pdata->no_autorepeat = of_property_read_bool(np, "linux,input-no-autorepeat"); pdata->wakeup = of_property_read_bool(np, "wakeup-source") || /* legacy name */ diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index da4019cf0c83..d5a6c7d8eb25 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -504,8 +504,7 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc) if (!of_property_read_u32(np, "nvidia,repeat-delay-ms", &prop)) kbc->repeat_cnt = prop; - if (of_find_property(np, "nvidia,needs-ghost-filter", NULL)) - kbc->use_ghost_filter = true; + kbc->use_ghost_filter = of_property_present(np, "nvidia,needs-ghost-filter"); if (of_property_read_bool(np, "wakeup-source") || of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */ From eaedf192f65fc4e3e2001b8e09940386cc494bd5 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 10 Mar 2023 20:26:21 -0800 Subject: [PATCH 11/42] Input: zinitix - use of_property_present() for testing DT property presence It is preferred to use typed property access functions (i.e. of_property_read_ functions) rather than low-level of_get_property/of_find_property functions for reading properties. As part of this, convert of_get_property/of_find_property calls to the recently added of_property_present() helper when we just want to test for presence of a property and nothing more. Signed-off-by: Rob Herring Link: https://lore.kernel.org/r/20230310144708.1542682-1-robh@kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zinitix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index cdf9bcd744db..b6ece47151b8 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -260,7 +260,7 @@ static int zinitix_init_regulators(struct bt541_ts_data *bt541) * so check if "vddo" is present and in that case use these names. * Else use the proper supply names on the component. */ - if (of_find_property(dev->of_node, "vddo-supply", NULL)) { + if (of_property_present(dev->of_node, "vddo-supply")) { bt541->supplies[0].supply = "vdd"; bt541->supplies[1].supply = "vddo"; } else { From bb5e4f3e1abf0e45d2d7b96875f05fa81fa1de0f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 17 Mar 2023 04:14:33 -0700 Subject: [PATCH 12/42] Input: st-keyscan - drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). This also fixes !CONFIG_OF error: drivers/input/keyboard/st-keyscan.c:251:34: error: ‘keyscan_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230312131514.351603-1-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/st-keyscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c index b6e83324f97a..0d27324af809 100644 --- a/drivers/input/keyboard/st-keyscan.c +++ b/drivers/input/keyboard/st-keyscan.c @@ -259,7 +259,7 @@ static struct platform_driver keyscan_device_driver = { .driver = { .name = "st-keyscan", .pm = pm_sleep_ptr(&keyscan_dev_pm_ops), - .of_match_table = of_match_ptr(keyscan_of_match), + .of_match_table = keyscan_of_match, } }; From 27e54d5193b914f5c29108adffdf10a253b8b40e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 17 Mar 2023 04:14:50 -0700 Subject: [PATCH 13/42] Input: tm2-touchkey - drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver will match mostly by DT table (even thought there is regular ID table) so there is little benefit in of_match_ptr (this also allows ACPI matching via PRP0001, even though it might not be relevant here). This also fixes !CONFIG_OF error: drivers/input/keyboard/tm2-touchkey.c:335:34: error: ‘tm2_touchkey_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230312131514.351603-2-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tm2-touchkey.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 6627e65f06e5..4e20571cb4c3 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -354,7 +354,7 @@ static struct i2c_driver tm2_touchkey_driver = { .driver = { .name = TM2_TOUCHKEY_DEV_NAME, .pm = pm_sleep_ptr(&tm2_touchkey_pm_ops), - .of_match_table = of_match_ptr(tm2_touchkey_of_match), + .of_match_table = tm2_touchkey_of_match, }, .probe_new = tm2_touchkey_probe, .id_table = tm2_touchkey_id_table, From f92dd6d074555edfe499ef6667a25b286e312ee3 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 17 Mar 2023 04:15:11 -0700 Subject: [PATCH 14/42] Input: sun4i-ts - drop of_match_ptr for ID table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). This also fixes !CONFIG_OF error: drivers/input/touchscreen/sun4i-ts.c:392:34: error: ‘sun4i_ts_of_match’ defined but not used [-Werror=unused-const-variable=] Signed-off-by: Krzysztof Kozlowski Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20230312131514.351603-3-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sun4i-ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c index 73eb8f80be6e..b990c951c486 100644 --- a/drivers/input/touchscreen/sun4i-ts.c +++ b/drivers/input/touchscreen/sun4i-ts.c @@ -400,7 +400,7 @@ MODULE_DEVICE_TABLE(of, sun4i_ts_of_match); static struct platform_driver sun4i_ts_driver = { .driver = { .name = "sun4i-ts", - .of_match_table = of_match_ptr(sun4i_ts_of_match), + .of_match_table = sun4i_ts_of_match, }, .probe = sun4i_ts_probe, .remove = sun4i_ts_remove, From f1e96f0617fc578f74319a5ba46473773035594f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 17 Mar 2023 04:15:49 -0700 Subject: [PATCH 15/42] Input: bcm_iproc_tsc - drop of_match_ptr for ID table The driver can match only via the DT table so the table should be always used and the of_match_ptr does not have any sense (this also allows ACPI matching via PRP0001, even though it might not be relevant here). This also fixes !CONFIG_OF error: Signed-off-by: Krzysztof Kozlowski Link: https://lore.kernel.org/r/20230312131514.351603-4-krzysztof.kozlowski@linaro.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/bcm_iproc_tsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c index 35e2fe9911a4..9c84235327bf 100644 --- a/drivers/input/touchscreen/bcm_iproc_tsc.c +++ b/drivers/input/touchscreen/bcm_iproc_tsc.c @@ -511,7 +511,7 @@ static struct platform_driver iproc_ts_driver = { .probe = iproc_ts_probe, .driver = { .name = IPROC_TS_NAME, - .of_match_table = of_match_ptr(iproc_ts_of_match), + .of_match_table = iproc_ts_of_match, }, }; From 6906f5060d39f95aa0be30e998e0cc1179ba3d04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Sun, 19 Mar 2023 21:23:25 -0700 Subject: [PATCH 16/42] Input: iqs62x-keys - suppress duplicated error message in .remove() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a platform driver's remove callback returns non-zero the driver core emits an error message. In such a case however iqs62x_keys_remove() already issued a (better) message. So return zero to suppress the generic message. This patch has no other side effects as platform_remove() ignores the return value of .remove() after the warning. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20230318225110.261439-1-u.kleine-koenig@pengutronix.de Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/iqs62x-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/keyboard/iqs62x-keys.c b/drivers/input/keyboard/iqs62x-keys.c index db793a550c25..02ceebad7bda 100644 --- a/drivers/input/keyboard/iqs62x-keys.c +++ b/drivers/input/keyboard/iqs62x-keys.c @@ -320,7 +320,7 @@ static int iqs62x_keys_remove(struct platform_device *pdev) if (ret) dev_err(&pdev->dev, "Failed to unregister notifier: %d\n", ret); - return ret; + return 0; } static struct platform_driver iqs62x_keys_platform_driver = { From 907d73bc0b0a00a9cc3254d14351fc239899473f Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 23 Mar 2023 18:31:40 -0700 Subject: [PATCH 17/42] Input: xpad - remove unused field in VID/PID table The list of specific VID/PID combinations for various controllers recently added a new field "xtype". However, this field isn't used, nor filled in the table itself, and was likely added by mistake and overlooked during review. Since this field isn't used, it's safe to remove. Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230225012147.276489-3-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f642ec8e92dd..a1f23da7d72c 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -126,7 +126,6 @@ static const struct xpad_device { char *name; u8 mapping; u8 xtype; - u8 packet_type; } xpad_device[] = { { 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 }, { 0x03eb, 0xff01, "Wooting One (Legacy)", 0, XTYPE_XBOX360 }, From 1999a6b12a3b5c8953fc9ec74863ebc75a1b851d Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 23 Mar 2023 18:32:43 -0700 Subject: [PATCH 18/42] Input: xpad - add VID for Turtle Beach controllers This adds support for the Turtle Beach REACT-R and Recon Xbox controllers Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230225012147.276489-4-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index a1f23da7d72c..49ae963e5f9d 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -474,6 +474,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */ + XPAD_XBOXONE_VENDOR(0x10f5), /* Turtle Beach Controllers */ XPAD_XBOX360_VENDOR(0x11c9), /* Nacon GC100XF */ XPAD_XBOX360_VENDOR(0x1209), /* Ardwiino Controllers */ XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ From 77987b872fcfeaf36b4760fe5d77a0cf9ac7fdbe Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 21 Mar 2023 11:54:15 -0700 Subject: [PATCH 19/42] dt-bindings: input: Drop unneeded quotes Cleanup bindings dropping unneeded quotes. Once all these are fixed, checking for this can be enabled in yamllint. Signed-off-by: Rob Herring Reviewed-by: Krzysztof Kozlowski Reviewed-by: Mattijs Korpershoek # for mediatek,mt6779-keypad.yaml Link: https://lore.kernel.org/r/20230320234718.2930154-1-robh@kernel.org Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/adc-joystick.yaml | 4 ++-- .../devicetree/bindings/input/google,cros-ec-keyb.yaml | 2 +- Documentation/devicetree/bindings/input/imx-keypad.yaml | 2 +- Documentation/devicetree/bindings/input/matrix-keymap.yaml | 2 +- .../devicetree/bindings/input/mediatek,mt6779-keypad.yaml | 2 +- .../devicetree/bindings/input/microchip,cap11xx.yaml | 4 ++-- Documentation/devicetree/bindings/input/pwm-vibrator.yaml | 4 ++-- Documentation/devicetree/bindings/input/regulator-haptic.yaml | 4 ++-- .../bindings/input/touchscreen/elan,elants_i2c.yaml | 4 ++-- 9 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Documentation/devicetree/bindings/input/adc-joystick.yaml b/Documentation/devicetree/bindings/input/adc-joystick.yaml index da0f8dfca8bf..6c244d66f8ce 100644 --- a/Documentation/devicetree/bindings/input/adc-joystick.yaml +++ b/Documentation/devicetree/bindings/input/adc-joystick.yaml @@ -2,8 +2,8 @@ # Copyright 2019-2020 Artur Rojek %YAML 1.2 --- -$id: "http://devicetree.org/schemas/input/adc-joystick.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/input/adc-joystick.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: ADC attached joystick diff --git a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml index a8abdb39623b..fefaaf46a240 100644 --- a/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml +++ b/Documentation/devicetree/bindings/input/google,cros-ec-keyb.yaml @@ -57,7 +57,7 @@ if: contains: const: google,cros-ec-keyb then: - $ref: "/schemas/input/matrix-keymap.yaml#" + $ref: /schemas/input/matrix-keymap.yaml# required: - keypad,num-rows - keypad,num-columns diff --git a/Documentation/devicetree/bindings/input/imx-keypad.yaml b/Documentation/devicetree/bindings/input/imx-keypad.yaml index 7514df62b592..b110eb1f3358 100644 --- a/Documentation/devicetree/bindings/input/imx-keypad.yaml +++ b/Documentation/devicetree/bindings/input/imx-keypad.yaml @@ -10,7 +10,7 @@ maintainers: - Liu Ying allOf: - - $ref: "/schemas/input/matrix-keymap.yaml#" + - $ref: /schemas/input/matrix-keymap.yaml# description: | The KPP is designed to interface with a keypad matrix with 2-point contact diff --git a/Documentation/devicetree/bindings/input/matrix-keymap.yaml b/Documentation/devicetree/bindings/input/matrix-keymap.yaml index 4d6dbe91646d..a715c2a773fe 100644 --- a/Documentation/devicetree/bindings/input/matrix-keymap.yaml +++ b/Documentation/devicetree/bindings/input/matrix-keymap.yaml @@ -21,7 +21,7 @@ description: | properties: linux,keymap: - $ref: '/schemas/types.yaml#/definitions/uint32-array' + $ref: /schemas/types.yaml#/definitions/uint32-array description: | An array of packed 1-cell entries containing the equivalent of row, column and linux key-code. The 32-bit big endian cell is packed as: diff --git a/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml b/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml index d768c30f48fb..47aac8794b68 100644 --- a/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml +++ b/Documentation/devicetree/bindings/input/mediatek,mt6779-keypad.yaml @@ -10,7 +10,7 @@ maintainers: - Mattijs Korpershoek allOf: - - $ref: "/schemas/input/matrix-keymap.yaml#" + - $ref: /schemas/input/matrix-keymap.yaml# description: | Mediatek's Keypad controller is used to interface a SoC with a matrix-type diff --git a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml index 5fa625b5c5fb..5b5d4f7d3482 100644 --- a/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml +++ b/Documentation/devicetree/bindings/input/microchip,cap11xx.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/input/microchip,cap11xx.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/input/microchip,cap11xx.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Microchip CAP11xx based capacitive touch sensors diff --git a/Documentation/devicetree/bindings/input/pwm-vibrator.yaml b/Documentation/devicetree/bindings/input/pwm-vibrator.yaml index a70a636ee112..d32716c604fe 100644 --- a/Documentation/devicetree/bindings/input/pwm-vibrator.yaml +++ b/Documentation/devicetree/bindings/input/pwm-vibrator.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/input/pwm-vibrator.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/input/pwm-vibrator.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: PWM vibrator diff --git a/Documentation/devicetree/bindings/input/regulator-haptic.yaml b/Documentation/devicetree/bindings/input/regulator-haptic.yaml index 627891e1ef55..cf63f834dd7d 100644 --- a/Documentation/devicetree/bindings/input/regulator-haptic.yaml +++ b/Documentation/devicetree/bindings/input/regulator-haptic.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: GPL-2.0 %YAML 1.2 --- -$id: "http://devicetree.org/schemas/input/regulator-haptic.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/input/regulator-haptic.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Regulator Haptic diff --git a/Documentation/devicetree/bindings/input/touchscreen/elan,elants_i2c.yaml b/Documentation/devicetree/bindings/input/touchscreen/elan,elants_i2c.yaml index f9053e5e9b24..3255c2c8951a 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/elan,elants_i2c.yaml +++ b/Documentation/devicetree/bindings/input/touchscreen/elan,elants_i2c.yaml @@ -1,8 +1,8 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2 --- -$id: "http://devicetree.org/schemas/input/touchscreen/elan,elants_i2c.yaml#" -$schema: "http://devicetree.org/meta-schemas/core.yaml#" +$id: http://devicetree.org/schemas/input/touchscreen/elan,elants_i2c.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# title: Elantech I2C Touchscreen From 8fb1bcd0baffd42fc44e6fb6f0633914cd48ec8d Mon Sep 17 00:00:00 2001 From: "Pierre-Loup A. Griffais" Date: Fri, 24 Mar 2023 10:40:39 -0700 Subject: [PATCH 20/42] Input: xpad - treat Qanba controllers as Xbox360 controllers They act that way in PC mode. Reviewed-by: Lyude Paul Signed-off-by: Pierre-Loup A. Griffais Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230324040446.3487725-2-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 49ae963e5f9d..c2c688156b2e 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -493,6 +493,7 @@ static const struct usb_device_id xpad_table[] = { XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */ XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */ XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */ + XPAD_XBOX360_VENDOR(0x2c22), /* Qanba Controllers */ XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller */ XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Pro 2 Wired Controller for Xbox */ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke X-Box One pad */ From db7220c48d8d71476f881a7ae1285e1df4105409 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Fri, 24 Mar 2023 10:42:27 -0700 Subject: [PATCH 21/42] Input: xpad - fix support for some third-party controllers Some third-party controllers, such as the HORPIAD FPS for Nintendo Switch and Gamesir-G3w, require a specific packet that the first-party XInput driver sends before it will start sending reports. It's not currently known what this packet does, but since the first-party driver always sends it's unlikely that this could cause issues with existing controllers. Co-authored-by: Andrey Smirnov Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230324040446.3487725-3-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index c2c688156b2e..260f91fef427 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -264,6 +264,7 @@ static const struct xpad_device { { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, + { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, @@ -2013,6 +2014,28 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto err_free_in_urb; } + if (xpad->xtype == XTYPE_XBOX360) { + /* + * Some third-party controllers Xbox 360-style controllers + * require this message to finish initialization. + */ + u8 dummy[20]; + + error = usb_control_msg_recv(udev, 0, + /* bRequest */ 0x01, + /* bmRequestType */ + USB_TYPE_VENDOR | USB_DIR_IN | + USB_RECIP_INTERFACE, + /* wValue */ 0x100, + /* wIndex */ 0x00, + dummy, sizeof(dummy), + 25, GFP_KERNEL); + if (error) + dev_warn(&xpad->dev->dev, + "unable to receive magic message: %d\n", + error); + } + ep_irq_in = ep_irq_out = NULL; for (i = 0; i < 2; i++) { From 57d94d150d17754ae1b4e87e9a883155cbb3ab05 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sat, 1 Apr 2023 14:21:43 -0700 Subject: [PATCH 22/42] Input: add a new Novatek NVT-ts driver Add a new driver for the Novatek i2c touchscreen controller as found on the Acer Iconia One 7 B1-750 tablet. Unfortunately the touchscreen controller model-number is unknown. Even with the tablet opened up it is impossible to read the model-number. Android calls this a "NVT-ts" touchscreen, but that may apply to other Novatek controller models too. This appears to be the same controller as the one supported by https://github.com/advx9600/android/blob/master/touchscreen/NVTtouch_Android4.0/NVTtouch.c but unfortunately that does not give us a model-number either. Signed-off-by: Hans de Goede Reviewed-by: Jeff LaBundy Link: https://lore.kernel.org/r/20230326212308.55730-1-hdegoede@redhat.com Signed-off-by: Dmitry Torokhov --- MAINTAINERS | 6 + drivers/input/touchscreen/Kconfig | 10 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/novatek-nvt-ts.c | 301 +++++++++++++++++++++ 4 files changed, 318 insertions(+) create mode 100644 drivers/input/touchscreen/novatek-nvt-ts.c diff --git a/MAINTAINERS b/MAINTAINERS index ec57c42ed544..2b073facf399 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -14781,6 +14781,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/wtarreau/nolibc.git F: tools/include/nolibc/ F: tools/testing/selftests/nolibc/ +NOVATEK NVT-TS I2C TOUCHSCREEN DRIVER +M: Hans de Goede +L: linux-input@vger.kernel.org +S: Maintained +F: drivers/input/touchscreen/novatek-nvt-ts.c + NSDEPS M: Matthias Maennich S: Maintained diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1a2049b336a6..1feecd7ed3cb 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -654,6 +654,16 @@ config TOUCHSCREEN_MTOUCH To compile this driver as a module, choose M here: the module will be called mtouch. +config TOUCHSCREEN_NOVATEK_NVT_TS + tristate "Novatek NVT-ts touchscreen support" + depends on I2C + help + Say Y here if you have a Novatek NVT-ts touchscreen. + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called novatek-nvt-ts. + config TOUCHSCREEN_IMAGIS tristate "Imagis touchscreen support" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index f2fd28cc34a6..159cd5136fdb 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o obj-$(CONFIG_TOUCHSCREEN_MSG2638) += msg2638.o obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o +obj-$(CONFIG_TOUCHSCREEN_NOVATEK_NVT_TS) += novatek-nvt-ts.o obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o obj-$(CONFIG_TOUCHSCREEN_HP7XX) += jornada720_ts.o obj-$(CONFIG_TOUCHSCREEN_IPAQ_MICRO) += ipaq-micro-ts.o diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c new file mode 100644 index 000000000000..3e551f9d31d7 --- /dev/null +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -0,0 +1,301 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Novatek i2c touchscreen controller as found on + * the Acer Iconia One 7 B1-750 tablet. The Touchscreen controller + * model-number is unknown. Android calls this a "NVT-ts" touchscreen, + * but that may apply to other Novatek controller models too. + * + * Copyright (c) 2023 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NVT_TS_TOUCH_START 0x00 +#define NVT_TS_TOUCH_SIZE 6 + +#define NVT_TS_PARAMETERS_START 0x78 +/* These are offsets from NVT_TS_PARAMETERS_START */ +#define NVT_TS_PARAMS_WIDTH 0x04 +#define NVT_TS_PARAMS_HEIGHT 0x06 +#define NVT_TS_PARAMS_MAX_TOUCH 0x09 +#define NVT_TS_PARAMS_MAX_BUTTONS 0x0a +#define NVT_TS_PARAMS_IRQ_TYPE 0x0b +#define NVT_TS_PARAMS_WAKE_TYPE 0x0c +#define NVT_TS_PARAMS_CHIP_ID 0x0e +#define NVT_TS_PARAMS_SIZE 0x0f + +#define NVT_TS_SUPPORTED_WAKE_TYPE 0x05 +#define NVT_TS_SUPPORTED_CHIP_ID 0x05 + +#define NVT_TS_MAX_TOUCHES 10 +#define NVT_TS_MAX_SIZE 4096 + +#define NVT_TS_TOUCH_INVALID 0xff +#define NVT_TS_TOUCH_SLOT_SHIFT 3 +#define NVT_TS_TOUCH_TYPE_MASK GENMASK(2, 0) +#define NVT_TS_TOUCH_NEW 1 +#define NVT_TS_TOUCH_UPDATE 2 +#define NVT_TS_TOUCH_RELEASE 3 + +static const int nvt_ts_irq_type[4] = { + IRQF_TRIGGER_RISING, + IRQF_TRIGGER_FALLING, + IRQF_TRIGGER_LOW, + IRQF_TRIGGER_HIGH +}; + +struct nvt_ts_data { + struct i2c_client *client; + struct input_dev *input; + struct gpio_desc *reset_gpio; + struct touchscreen_properties prop; + int max_touches; + u8 buf[NVT_TS_TOUCH_SIZE * NVT_TS_MAX_TOUCHES]; +}; + +static int nvt_ts_read_data(struct i2c_client *client, u8 reg, u8 *data, int count) +{ + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .len = 1, + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = count, + .buf = data, + } + }; + int ret; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret != ARRAY_SIZE(msg)) { + dev_err(&client->dev, "Error reading from 0x%02x: %d\n", reg, ret); + return (ret < 0) ? ret : -EIO; + } + + return 0; +} + +static irqreturn_t nvt_ts_irq(int irq, void *dev_id) +{ + struct nvt_ts_data *data = dev_id; + struct device *dev = &data->client->dev; + int i, error, slot, x, y; + bool active; + u8 *touch; + + error = nvt_ts_read_data(data->client, NVT_TS_TOUCH_START, data->buf, + data->max_touches * NVT_TS_TOUCH_SIZE); + if (error) + return IRQ_HANDLED; + + for (i = 0; i < data->max_touches; i++) { + touch = &data->buf[i * NVT_TS_TOUCH_SIZE]; + + if (touch[0] == NVT_TS_TOUCH_INVALID) + continue; + + slot = touch[0] >> NVT_TS_TOUCH_SLOT_SHIFT; + if (slot < 1 || slot > data->max_touches) { + dev_warn(dev, "slot %d out of range, ignoring\n", slot); + continue; + } + + switch (touch[0] & NVT_TS_TOUCH_TYPE_MASK) { + case NVT_TS_TOUCH_NEW: + case NVT_TS_TOUCH_UPDATE: + active = true; + break; + case NVT_TS_TOUCH_RELEASE: + active = false; + break; + default: + dev_warn(dev, "slot %d unknown state %d\n", slot, touch[0] & 7); + continue; + } + + slot--; + x = (touch[1] << 4) | (touch[3] >> 4); + y = (touch[2] << 4) | (touch[3] & 0x0f); + + input_mt_slot(data->input, slot); + input_mt_report_slot_state(data->input, MT_TOOL_FINGER, active); + touchscreen_report_pos(data->input, &data->prop, x, y, true); + } + + input_mt_sync_frame(data->input); + input_sync(data->input); + + return IRQ_HANDLED; +} + +static int nvt_ts_start(struct input_dev *dev) +{ + struct nvt_ts_data *data = input_get_drvdata(dev); + + enable_irq(data->client->irq); + gpiod_set_value_cansleep(data->reset_gpio, 0); + + return 0; +} + +static void nvt_ts_stop(struct input_dev *dev) +{ + struct nvt_ts_data *data = input_get_drvdata(dev); + + disable_irq(data->client->irq); + gpiod_set_value_cansleep(data->reset_gpio, 1); +} + +static int nvt_ts_suspend(struct device *dev) +{ + struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&data->input->mutex); + if (input_device_enabled(data->input)) + nvt_ts_stop(data->input); + mutex_unlock(&data->input->mutex); + + return 0; +} + +static int nvt_ts_resume(struct device *dev) +{ + struct nvt_ts_data *data = i2c_get_clientdata(to_i2c_client(dev)); + + mutex_lock(&data->input->mutex); + if (input_device_enabled(data->input)) + nvt_ts_start(data->input); + mutex_unlock(&data->input->mutex); + + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(nvt_ts_pm_ops, nvt_ts_suspend, nvt_ts_resume); + +static int nvt_ts_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + int error, width, height, irq_type; + struct nvt_ts_data *data; + struct input_dev *input; + + if (!client->irq) { + dev_err(dev, "Error no irq specified\n"); + return -EINVAL; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->client = client; + i2c_set_clientdata(client, data); + + data->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + error = PTR_ERR_OR_ZERO(data->reset_gpio); + if (error) { + dev_err(dev, "failed to request reset GPIO: %d\n", error); + return error; + } + + /* Wait for controller to come out of reset before params read */ + msleep(100); + error = nvt_ts_read_data(data->client, NVT_TS_PARAMETERS_START, + data->buf, NVT_TS_PARAMS_SIZE); + gpiod_set_value_cansleep(data->reset_gpio, 1); /* Put back in reset */ + if (error) + return error; + + width = get_unaligned_be16(&data->buf[NVT_TS_PARAMS_WIDTH]); + height = get_unaligned_be16(&data->buf[NVT_TS_PARAMS_HEIGHT]); + data->max_touches = data->buf[NVT_TS_PARAMS_MAX_TOUCH]; + irq_type = data->buf[NVT_TS_PARAMS_IRQ_TYPE]; + + if (width > NVT_TS_MAX_SIZE || height >= NVT_TS_MAX_SIZE || + data->max_touches > NVT_TS_MAX_TOUCHES || + irq_type >= ARRAY_SIZE(nvt_ts_irq_type) || + data->buf[NVT_TS_PARAMS_WAKE_TYPE] != NVT_TS_SUPPORTED_WAKE_TYPE || + data->buf[NVT_TS_PARAMS_CHIP_ID] != NVT_TS_SUPPORTED_CHIP_ID) { + dev_err(dev, "Unsupported touchscreen parameters: %*ph\n", + NVT_TS_PARAMS_SIZE, data->buf); + return -EIO; + } + + dev_dbg(dev, "Detected %dx%d touchscreen with %d max touches\n", + width, height, data->max_touches); + + if (data->buf[NVT_TS_PARAMS_MAX_BUTTONS]) + dev_warn(dev, "Touchscreen buttons are not supported\n"); + + input = devm_input_allocate_device(dev); + if (!input) + return -ENOMEM; + + input->name = client->name; + input->id.bustype = BUS_I2C; + input->open = nvt_ts_start; + input->close = nvt_ts_stop; + + input_set_abs_params(input, ABS_MT_POSITION_X, 0, width - 1, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, height - 1, 0, 0); + touchscreen_parse_properties(input, true, &data->prop); + + error = input_mt_init_slots(input, data->max_touches, + INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED); + if (error) + return error; + + data->input = input; + input_set_drvdata(input, data); + + error = devm_request_threaded_irq(dev, client->irq, NULL, nvt_ts_irq, + IRQF_ONESHOT | IRQF_NO_AUTOEN | + nvt_ts_irq_type[irq_type], + client->name, data); + if (error) { + dev_err(dev, "failed to request irq: %d\n", error); + return error; + } + + error = input_register_device(input); + if (error) { + dev_err(dev, "failed to request irq: %d\n", error); + return error; + } + + return 0; +} + +static const struct i2c_device_id nvt_ts_i2c_id[] = { + { "NVT-ts" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id); + +static struct i2c_driver nvt_ts_driver = { + .driver = { + .name = "novatek-nvt-ts", + .pm = pm_sleep_ptr(&nvt_ts_pm_ops), + }, + .probe_new = nvt_ts_probe, + .id_table = nvt_ts_i2c_id, +}; + +module_i2c_driver(nvt_ts_driver); + +MODULE_DESCRIPTION("Novatek NVT-ts touchscreen driver"); +MODULE_AUTHOR("Hans de Goede "); +MODULE_LICENSE("GPL"); From fdefcbdd6f3618410a0afb2ac0071c04036f9602 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 1 Apr 2023 22:45:09 -0700 Subject: [PATCH 23/42] Input: Add KUnit tests for some of the input core helper functions The input subsystem doesn't currently have any unit tests, let's add a CONFIG_INPUT_KUNIT_TEST option that builds a test suite to be executed with the KUnit test infrastructure. For now, only three tests were added for some of the input core helper functions that are trivial to test: * input_test_polling: set/get poll interval and set-up a poll handler. * input_test_timestamp: set/get input event timestamps. * input_test_match_device_id: match a device by bus, vendor, product, version and events capable of handling. But having the minimal KUnit support allows to add more tests and suites as follow-up changes. The tests can be run with the following command: $ ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/input/tests/ Signed-off-by: Javier Martinez Canillas Tested-by: Enric Balletbo i Serra config: powerpc-allnoconfig (https://download.01.org/0day-ci/archive/20230330/202303301815.kRKFM3NH-lkp@intel.com/config) Link: https://lore.kernel.org/r/20230330081831.2291351-1-javierm@redhat.com Signed-off-by: Dmitry Torokhov --- drivers/input/Kconfig | 10 +++ drivers/input/Makefile | 1 + drivers/input/tests/.kunitconfig | 3 + drivers/input/tests/Makefile | 3 + drivers/input/tests/input_test.c | 150 +++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+) create mode 100644 drivers/input/tests/.kunitconfig create mode 100644 drivers/input/tests/Makefile create mode 100644 drivers/input/tests/input_test.c diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e2752f7364bc..735f90b74ee5 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -166,6 +166,16 @@ config INPUT_EVBUG To compile this driver as a module, choose M here: the module will be called evbug. +config INPUT_KUNIT_TEST + tristate "KUnit tests for Input" if !KUNIT_ALL_TESTS + depends on INPUT && KUNIT=y + default KUNIT_ALL_TESTS + help + Say Y here if you want to build the KUnit tests for the input + subsystem. + + If in doubt, say "N". + config INPUT_APMPOWER tristate "Input Power Event -> APM Bridge" if EXPERT depends on INPUT && APM_EMULATION diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2266c7d010ef..c78753274921 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ +obj-$(CONFIG_INPUT_KUNIT_TEST) += tests/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o diff --git a/drivers/input/tests/.kunitconfig b/drivers/input/tests/.kunitconfig new file mode 100644 index 000000000000..2f5bedf8028e --- /dev/null +++ b/drivers/input/tests/.kunitconfig @@ -0,0 +1,3 @@ +CONFIG_KUNIT=y +CONFIG_INPUT=y +CONFIG_INPUT_KUNIT_TEST=y diff --git a/drivers/input/tests/Makefile b/drivers/input/tests/Makefile new file mode 100644 index 000000000000..90cf954181bc --- /dev/null +++ b/drivers/input/tests/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_INPUT_KUNIT_TEST) += input_test.o diff --git a/drivers/input/tests/input_test.c b/drivers/input/tests/input_test.c new file mode 100644 index 000000000000..e5a6c1ad2167 --- /dev/null +++ b/drivers/input/tests/input_test.c @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for the input core. + * + * Copyright (c) 2023 Red Hat Inc + */ + +#include +#include + +#include + +#define POLL_INTERVAL 100 + +static int input_test_init(struct kunit *test) +{ + struct input_dev *input_dev; + int ret; + + input_dev = input_allocate_device(); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, input_dev); + + input_dev->name = "Test input device"; + input_dev->id.bustype = BUS_VIRTUAL; + input_dev->id.vendor = 1; + input_dev->id.product = 1; + input_dev->id.version = 1; + input_set_capability(input_dev, EV_KEY, BTN_LEFT); + input_set_capability(input_dev, EV_KEY, BTN_RIGHT); + + ret = input_register_device(input_dev); + if (ret) { + input_free_device(input_dev); + KUNIT_ASSERT_FAILURE(test, "Register device failed: %d", ret); + } + + test->priv = input_dev; + + return 0; +} + +static void input_test_exit(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + + input_unregister_device(input_dev); + input_free_device(input_dev); +} + +static void input_test_poll(struct input_dev *input) { } + +static void input_test_polling(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + + /* Must fail because a poll handler has not been set-up yet */ + KUNIT_ASSERT_EQ(test, input_get_poll_interval(input_dev), -EINVAL); + + KUNIT_ASSERT_EQ(test, input_setup_polling(input_dev, input_test_poll), 0); + + input_set_poll_interval(input_dev, POLL_INTERVAL); + + /* Must succeed because poll handler was set-up and poll interval set */ + KUNIT_ASSERT_EQ(test, input_get_poll_interval(input_dev), POLL_INTERVAL); +} + +static void input_test_timestamp(struct kunit *test) +{ + const ktime_t invalid_timestamp = ktime_set(0, 0); + struct input_dev *input_dev = test->priv; + ktime_t *timestamp, time; + + timestamp = input_get_timestamp(input_dev); + time = timestamp[INPUT_CLK_MONO]; + + /* The returned timestamp must always be valid */ + KUNIT_ASSERT_EQ(test, ktime_compare(time, invalid_timestamp), 1); + + time = ktime_get(); + input_set_timestamp(input_dev, time); + + timestamp = input_get_timestamp(input_dev); + /* The timestamp must be the same than set before */ + KUNIT_ASSERT_EQ(test, ktime_compare(timestamp[INPUT_CLK_MONO], time), 0); +} + +static void input_test_match_device_id(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + struct input_device_id id; + + /* + * Must match when the input device bus, vendor, product, version + * and events capable of handling are the same and fail to match + * otherwise. + */ + id.flags = INPUT_DEVICE_ID_MATCH_BUS; + id.bustype = BUS_VIRTUAL; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.bustype = BUS_I2C; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_VENDOR; + id.vendor = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.vendor = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_PRODUCT; + id.product = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.product = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_VERSION; + id.version = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.version = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_EVBIT; + __set_bit(EV_KEY, id.evbit); + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + __set_bit(EV_ABS, id.evbit); + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); +} + +static struct kunit_case input_tests[] = { + KUNIT_CASE(input_test_polling), + KUNIT_CASE(input_test_timestamp), + KUNIT_CASE(input_test_match_device_id), + { /* sentinel */ } +}; + +static struct kunit_suite input_test_suite = { + .name = "input_core", + .init = input_test_init, + .exit = input_test_exit, + .test_cases = input_tests, +}; + +kunit_test_suite(input_test_suite); + +MODULE_AUTHOR("Javier Martinez Canillas "); +MODULE_LICENSE("GPL"); From 1661f60adc3b7e6864b4cb6790d579b468bd243f Mon Sep 17 00:00:00 2001 From: Benjamin Bara Date: Sun, 2 Apr 2023 16:55:27 -0700 Subject: [PATCH 24/42] Input: tsc2007 - enable cansleep pendown GPIO When a hard IRQ is triggered, the soft IRQ, which decides if an actual pen down happened, should always be triggered. This enables the usage of "can_sleep" GPIO chips as "pen down" GPIO, as the value is not read during the hard IRQ anymore. This might be the case if the GPIO chip is an expander behind i2c. Signed-off-by: Benjamin Bara Signed-off-by: Richard Leitner Link: https://lore.kernel.org/r/20230328-tsc2007-sleep-v5-1-fc55e76d0ced@skidata.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2007_core.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 3c793fb70a0e..21916a30fb76 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -172,19 +172,6 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle) return IRQ_HANDLED; } -static irqreturn_t tsc2007_hard_irq(int irq, void *handle) -{ - struct tsc2007 *ts = handle; - - if (tsc2007_is_pen_down(ts)) - return IRQ_WAKE_THREAD; - - if (ts->clear_penirq) - ts->clear_penirq(); - - return IRQ_HANDLED; -} - static void tsc2007_stop(struct tsc2007 *ts) { ts->stopped = true; @@ -226,7 +213,7 @@ static int tsc2007_get_pendown_state_gpio(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct tsc2007 *ts = i2c_get_clientdata(client); - return gpiod_get_value(ts->gpiod); + return gpiod_get_value_cansleep(ts->gpiod); } static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts) @@ -376,7 +363,7 @@ static int tsc2007_probe(struct i2c_client *client) } err = devm_request_threaded_irq(&client->dev, ts->irq, - tsc2007_hard_irq, tsc2007_soft_irq, + NULL, tsc2007_soft_irq, IRQF_ONESHOT, client->dev.driver->name, ts); if (err) { From d19ec82c74a50aec614530b0e7d795913be77221 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 16:57:04 -0700 Subject: [PATCH 25/42] Input: edt-ft5x06 - fix indentation Matches the alignment to the open parenthesis as suggested by checkpatch. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-2-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 36 ++++++++++++++------------ 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 2746649561c7..daba6472fc65 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -241,11 +241,11 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) /* M09/M12 does not send header or CRC */ if (tsdata->version == EDT_M06) { if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || - rdbuf[2] != datalen) { + rdbuf[2] != datalen) { tsdata->header_errors++; dev_err_ratelimited(dev, - "Unexpected header: %02x%02x%02x!\n", - rdbuf[0], rdbuf[1], rdbuf[2]); + "Unexpected header: %02x%02x%02x!\n", + rdbuf[0], rdbuf[1], rdbuf[2]); goto out; } @@ -618,7 +618,7 @@ static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, - tsdata->report_rate); + tsdata->report_rate); } @@ -757,7 +757,8 @@ DEFINE_SIMPLE_ATTRIBUTE(debugfs_mode_fops, edt_ft5x06_debugfs_mode_get, edt_ft5x06_debugfs_mode_set, "%llu\n"); static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, - char __user *buf, size_t count, loff_t *off) + char __user *buf, size_t count, + loff_t *off) { struct edt_ft5x06_ts_data *tsdata = file->private_data; struct i2c_client *client = tsdata->client; @@ -965,12 +966,12 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, case 0x70: /* EDT EP0700M09 */ tsdata->version = EDT_M09; snprintf(model_name, EDT_NAME_LEN, "EP0%i%i0M09", - rdbuf[0] >> 4, rdbuf[0] & 0x0F); + rdbuf[0] >> 4, rdbuf[0] & 0x0F); break; case 0xa1: /* EDT EP1010ML00 */ tsdata->version = EDT_M09; snprintf(model_name, EDT_NAME_LEN, "EP%i%i0ML00", - rdbuf[0] >> 4, rdbuf[0] & 0x0F); + rdbuf[0] >> 4, rdbuf[0] & 0x0F); break; case 0x5a: /* Solomon Goldentek Display */ snprintf(model_name, EDT_NAME_LEN, "GKTW50SCED1R0"); @@ -1051,14 +1052,17 @@ static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) tsdata->offset = edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); if (reg_addr->reg_offset_x != NO_REGISTER) - tsdata->offset_x = edt_ft5x06_register_read(tsdata, - reg_addr->reg_offset_x); + tsdata->offset_x = + edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_x); if (reg_addr->reg_offset_y != NO_REGISTER) - tsdata->offset_y = edt_ft5x06_register_read(tsdata, - reg_addr->reg_offset_y); + tsdata->offset_y = + edt_ft5x06_register_read(tsdata, + reg_addr->reg_offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) - tsdata->report_rate = edt_ft5x06_register_read(tsdata, - reg_addr->reg_report_rate); + tsdata->report_rate = + edt_ft5x06_register_read(tsdata, + reg_addr->reg_report_rate); tsdata->num_x = EDT_DEFAULT_NUM_X; if (reg_addr->reg_num_x != NO_REGISTER) tsdata->num_x = edt_ft5x06_register_read(tsdata, @@ -1306,7 +1310,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) touchscreen_parse_properties(input, true, &tsdata->prop); error = input_mt_init_slots(input, tsdata->max_support_points, - INPUT_MT_DIRECT); + INPUT_MT_DIRECT); if (error) { dev_err(&client->dev, "Unable to init MT slots.\n"); return error; @@ -1320,8 +1324,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) irq_flags |= IRQF_ONESHOT; error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, edt_ft5x06_ts_isr, irq_flags, - client->name, tsdata); + NULL, edt_ft5x06_ts_isr, irq_flags, + client->name, tsdata); if (error) { dev_err(&client->dev, "Unable to request touchscreen IRQ.\n"); return error; From 6114f4749b4662d4f444e2a184e236d9d9df9115 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 16:58:14 -0700 Subject: [PATCH 26/42] Input: edt-ft5x06 - remove unnecessary blank lines It removes unnecessary blank lines so that checkpatch doesn't complain anymore. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-3-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index daba6472fc65..c0ad3e4b6662 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -619,7 +619,6 @@ static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) if (reg_addr->reg_report_rate != NO_REGISTER) edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, tsdata->report_rate); - } #ifdef CONFIG_DEBUG_FS @@ -1459,7 +1458,6 @@ static int edt_ft5x06_ts_resume(struct device *dev) gpiod_set_value_cansleep(wake_gpio, 1); } - return ret; } From f8a2257056d9e60e4339072e8e89a5a708a99d40 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 16:58:29 -0700 Subject: [PATCH 27/42] Input: edt-ft5x06 - add spaces to ensure format specification It adds spaces around '-' as recommended by the Linux coding style. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-4-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index c0ad3e4b6662..c96fe6520578 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -183,11 +183,11 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, for (i = 0; i < buflen - 1; i++) crc ^= buf[i]; - if (crc != buf[buflen-1]) { + if (crc != buf[buflen - 1]) { tsdata->crc_errors++; dev_err_ratelimited(&tsdata->client->dev, "crc error: 0x%02x expected, got 0x%02x\n", - crc, buf[buflen-1]); + crc, buf[buflen - 1]); return false; } From 38e8cf7b97612a7e615e498987bd0758a65633c6 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 21:27:34 -0700 Subject: [PATCH 28/42] Input: edt-ft5x06 - don't recalculate the CRC There is no need to recalculate the CRC when the data has not changed. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-5-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index c96fe6520578..d4f39724b259 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -319,7 +319,7 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, u8 addr) { - u8 wrbuf[2], rdbuf[2]; + u8 wrbuf[2], rdbuf[2], crc; int error; switch (tsdata->version) { @@ -333,11 +333,11 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, if (error) return error; - if ((wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]) != rdbuf[1]) { + crc = wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]; + if (crc != rdbuf[1]) { dev_err(&tsdata->client->dev, "crc error: 0x%02x expected, got 0x%02x\n", - wrbuf[0] ^ wrbuf[1] ^ rdbuf[0], - rdbuf[1]); + crc, rdbuf[1]); return -EIO; } break; From 65c67985a0305f444f3f88f3506c6e7ee237423b Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 21:27:48 -0700 Subject: [PATCH 29/42] Input: edt-ft5x06 - remove code duplication The use of the macros M06_REG_ADDR and M06_REG_CMD avoids code duplication without impacting the application load, and reduces the chances of errors or mistakes. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-6-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index d4f39724b259..7d82f412ab15 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -75,6 +75,9 @@ #define EDT_DEFAULT_NUM_X 1024 #define EDT_DEFAULT_NUM_Y 1024 +#define M06_REG_CMD(factory) ((factory) ? 0xf3 : 0xfc) +#define M06_REG_ADDR(factory, addr) ((factory) ? (addr) & 0x7f : (addr) & 0x3f) + enum edt_pmode { EDT_PMODE_NOT_SUPPORTED, EDT_PMODE_HIBERNATE, @@ -294,8 +297,8 @@ static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, switch (tsdata->version) { case EDT_M06: - wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; - wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; + wrbuf[0] = M06_REG_CMD(tsdata->factory_mode); + wrbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); wrbuf[2] = value; wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; return edt_ft5x06_ts_readwrite(tsdata->client, 4, @@ -324,8 +327,8 @@ static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, switch (tsdata->version) { case EDT_M06: - wrbuf[0] = tsdata->factory_mode ? 0xf3 : 0xfc; - wrbuf[1] = tsdata->factory_mode ? addr & 0x7f : addr & 0x3f; + wrbuf[0] = M06_REG_CMD(tsdata->factory_mode); + wrbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, From 24642661e956b268459bea31e11cbc3bc8dda136 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 21:36:12 -0700 Subject: [PATCH 30/42] Input: edt-ft5x06 - don't print error messages with dev_dbg() In some parts of the code, error messages were improperly printed with dev_dbg() calls. In those cases, dev_dbg() has been replaced with dev_err(). Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-7-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 7d82f412ab15..89958881fca1 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -783,7 +783,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, error = edt_ft5x06_register_write(tsdata, 0x08, 0x01); if (error) { - dev_dbg(&client->dev, + dev_err(&client->dev, "failed to write 0x08 register, error %d\n", error); goto out; } @@ -797,13 +797,13 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, if (val < 0) { error = val; - dev_dbg(&client->dev, + dev_err(&client->dev, "failed to read 0x08 register, error %d\n", error); goto out; } if (retries == 0) { - dev_dbg(&client->dev, + dev_err(&client->dev, "timed out waiting for register to settle\n"); error = -ETIMEDOUT; goto out; From 9dfd9708ffba1e7969af5e4ecda660151146de98 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 21:36:23 -0700 Subject: [PATCH 31/42] Input: edt-ft5x06 - convert to use regmap API It replaces custom read/write functions with regmap API, making the driver code more generic. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-8-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 424 +++++++++++++------------ 1 file changed, 214 insertions(+), 210 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 89958881fca1..8aae4c1e6b73 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -3,6 +3,7 @@ * Copyright (C) 2012 Simon Budig, * Daniel Wagener (M09 firmware support) * Lothar Waßmann (DT support) + * Dario Binacchi (regmap support) */ /* @@ -26,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -115,6 +117,8 @@ struct edt_ft5x06_ts_data { struct gpio_desc *reset_gpio; struct gpio_desc *wake_gpio; + struct regmap *regmap; + #if defined(CONFIG_DEBUG_FS) struct dentry *debug_dir; u8 *raw_buffer; @@ -145,37 +149,10 @@ struct edt_i2c_chip_data { int max_support_points; }; -static int edt_ft5x06_ts_readwrite(struct i2c_client *client, - u16 wr_len, u8 *wr_buf, - u16 rd_len, u8 *rd_buf) -{ - struct i2c_msg wrmsg[2]; - int i = 0; - int ret; - - if (wr_len) { - wrmsg[i].addr = client->addr; - wrmsg[i].flags = 0; - wrmsg[i].len = wr_len; - wrmsg[i].buf = wr_buf; - i++; - } - if (rd_len) { - wrmsg[i].addr = client->addr; - wrmsg[i].flags = I2C_M_RD; - wrmsg[i].len = rd_len; - wrmsg[i].buf = rd_buf; - i++; - } - - ret = i2c_transfer(client->adapter, wrmsg, i); - if (ret < 0) - return ret; - if (ret != i) - return -EIO; - - return 0; -} +static const struct regmap_config edt_ft5x06_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, u8 *buf, int buflen) @@ -197,6 +174,127 @@ static bool edt_ft5x06_ts_check_crc(struct edt_ft5x06_ts_data *tsdata, return true; } +static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size, + void *val_buf, size_t val_size) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); + struct i2c_msg xfer[2]; + bool reg_read = false; + u8 addr; + u8 wlen; + u8 wbuf[4], rbuf[3]; + int ret; + + addr = *((u8 *)reg_buf); + wbuf[0] = addr; + switch (addr) { + case 0xf5: + wlen = 3; + wbuf[0] = 0xf5; + wbuf[1] = 0xe; + wbuf[2] = *((u8 *)val_buf); + break; + case 0xf9: + wlen = 1; + break; + default: + wlen = 2; + reg_read = true; + wbuf[0] = M06_REG_CMD(tsdata->factory_mode); + wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); + wbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; + } + + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = wlen; + xfer[0].buf = wbuf; + + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = reg_read ? 2 : val_size; + xfer[1].buf = reg_read ? rbuf : val_buf; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + if (ret < 0) + return ret; + + return -EIO; + } + + if (addr == 0xf9) { + u8 *buf = (u8 *)val_buf; + + if (buf[0] != 0xaa || buf[1] != 0xaa || + buf[2] != val_size) { + tsdata->header_errors++; + dev_err_ratelimited(dev, + "Unexpected header: %02x%02x%02x\n", + buf[0], buf[1], buf[2]); + return -EIO; + } + + if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size)) + return -EIO; + } else if (reg_read) { + u8 crc = wbuf[0] ^ wbuf[1] ^ rbuf[0]; + + if (crc != rbuf[1]) { + dev_err(dev, "crc error: 0x%02x expected, got 0x%02x\n", + crc, rbuf[1]); + return -EIO; + } + + *((u8 *)val_buf) = rbuf[0]; + } + + return 0; +} + +static int edt_M06_i2c_write(void *context, const void *data, size_t count) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(i2c); + u8 addr, val; + u8 wbuf[4]; + struct i2c_msg xfer; + int ret; + + addr = *((u8 *)data); + val = *((u8 *)data + 1); + + wbuf[0] = M06_REG_CMD(tsdata->factory_mode); + wbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); + wbuf[2] = val; + wbuf[3] = wbuf[0] ^ wbuf[1] ^ wbuf[2]; + + xfer.addr = i2c->addr; + xfer.flags = 0; + xfer.len = 4; + xfer.buf = wbuf; + + ret = i2c_transfer(i2c->adapter, &xfer, 1); + if (ret != 1) { + if (ret < 0) + return ret; + + return -EIO; + } + + return 0; +} + +static const struct regmap_config edt_M06_i2c_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .read = edt_M06_i2c_read, + .write = edt_M06_i2c_write, +}; + static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) { struct edt_ft5x06_ts_data *tsdata = dev_id; @@ -232,30 +330,13 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) memset(rdbuf, 0, sizeof(rdbuf)); datalen = tplen * tsdata->max_support_points + offset + crclen; - error = edt_ft5x06_ts_readwrite(tsdata->client, - sizeof(cmd), &cmd, - datalen, rdbuf); + error = regmap_bulk_read(tsdata->regmap, cmd, rdbuf, datalen); if (error) { dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", error); goto out; } - /* M09/M12 does not send header or CRC */ - if (tsdata->version == EDT_M06) { - if (rdbuf[0] != 0xaa || rdbuf[1] != 0xaa || - rdbuf[2] != datalen) { - tsdata->header_errors++; - dev_err_ratelimited(dev, - "Unexpected header: %02x%02x%02x!\n", - rdbuf[0], rdbuf[1], rdbuf[2]); - goto out; - } - - if (!edt_ft5x06_ts_check_crc(tsdata, rdbuf, datalen)) - goto out; - } - for (i = 0; i < tsdata->max_support_points; i++) { u8 *buf = &rdbuf[i * tplen + offset]; @@ -290,79 +371,6 @@ out: return IRQ_HANDLED; } -static int edt_ft5x06_register_write(struct edt_ft5x06_ts_data *tsdata, - u8 addr, u8 value) -{ - u8 wrbuf[4]; - - switch (tsdata->version) { - case EDT_M06: - wrbuf[0] = M06_REG_CMD(tsdata->factory_mode); - wrbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); - wrbuf[2] = value; - wrbuf[3] = wrbuf[0] ^ wrbuf[1] ^ wrbuf[2]; - return edt_ft5x06_ts_readwrite(tsdata->client, 4, - wrbuf, 0, NULL); - - case EDT_M09: - case EDT_M12: - case EV_FT: - case GENERIC_FT: - wrbuf[0] = addr; - wrbuf[1] = value; - - return edt_ft5x06_ts_readwrite(tsdata->client, 2, - wrbuf, 0, NULL); - - default: - return -EINVAL; - } -} - -static int edt_ft5x06_register_read(struct edt_ft5x06_ts_data *tsdata, - u8 addr) -{ - u8 wrbuf[2], rdbuf[2], crc; - int error; - - switch (tsdata->version) { - case EDT_M06: - wrbuf[0] = M06_REG_CMD(tsdata->factory_mode); - wrbuf[1] = M06_REG_ADDR(tsdata->factory_mode, addr); - wrbuf[1] |= tsdata->factory_mode ? 0x80 : 0x40; - - error = edt_ft5x06_ts_readwrite(tsdata->client, 2, wrbuf, 2, - rdbuf); - if (error) - return error; - - crc = wrbuf[0] ^ wrbuf[1] ^ rdbuf[0]; - if (crc != rdbuf[1]) { - dev_err(&tsdata->client->dev, - "crc error: 0x%02x expected, got 0x%02x\n", - crc, rdbuf[1]); - return -EIO; - } - break; - - case EDT_M09: - case EDT_M12: - case EV_FT: - case GENERIC_FT: - wrbuf[0] = addr; - error = edt_ft5x06_ts_readwrite(tsdata->client, 1, - wrbuf, 1, rdbuf); - if (error) - return error; - break; - - default: - return -EINVAL; - } - - return rdbuf[0]; -} - struct edt_ft5x06_attribute { struct device_attribute dattr; size_t field_offset; @@ -396,7 +404,7 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, struct edt_ft5x06_attribute *attr = container_of(dattr, struct edt_ft5x06_attribute, dattr); u8 *field = (u8 *)tsdata + attr->field_offset; - int val; + unsigned int val; size_t count = 0; int error = 0; u8 addr; @@ -429,9 +437,8 @@ static ssize_t edt_ft5x06_setting_show(struct device *dev, } if (addr != NO_REGISTER) { - val = edt_ft5x06_register_read(tsdata, addr); - if (val < 0) { - error = val; + error = regmap_read(tsdata->regmap, addr, &val); + if (error) { dev_err(&tsdata->client->dev, "Failed to fetch attribute %s, error %d\n", dattr->attr.name, error); @@ -504,7 +511,7 @@ static ssize_t edt_ft5x06_setting_store(struct device *dev, } if (addr != NO_REGISTER) { - error = edt_ft5x06_register_write(tsdata, addr, val); + error = regmap_write(tsdata->regmap, addr, val); if (error) { dev_err(&tsdata->client->dev, "Failed to update attribute %s, error: %d\n", @@ -605,23 +612,19 @@ static const struct attribute_group edt_ft5x06_attr_group = { static void edt_ft5x06_restore_reg_parameters(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + struct regmap *regmap = tsdata->regmap; - edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, - tsdata->threshold); - edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, - tsdata->gain); + regmap_write(regmap, reg_addr->reg_threshold, tsdata->threshold); + regmap_write(regmap, reg_addr->reg_gain, tsdata->gain); if (reg_addr->reg_offset != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset, - tsdata->offset); + regmap_write(regmap, reg_addr->reg_offset, tsdata->offset); if (reg_addr->reg_offset_x != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_x, - tsdata->offset_x); + regmap_write(regmap, reg_addr->reg_offset_x, tsdata->offset_x); if (reg_addr->reg_offset_y != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_offset_y, - tsdata->offset_y); + regmap_write(regmap, reg_addr->reg_offset_y, tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) - edt_ft5x06_register_write(tsdata, reg_addr->reg_report_rate, - tsdata->report_rate); + regmap_write(regmap, reg_addr->reg_report_rate, + tsdata->report_rate); } #ifdef CONFIG_DEBUG_FS @@ -629,7 +632,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) { struct i2c_client *client = tsdata->client; int retries = EDT_SWITCH_MODE_RETRIES; - int ret; + unsigned int val; int error; if (tsdata->version != EDT_M06) { @@ -651,7 +654,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) } /* mode register is 0x3c when in the work mode */ - error = edt_ft5x06_register_write(tsdata, WORK_REGISTER_OPMODE, 0x03); + error = regmap_write(tsdata->regmap, WORK_REGISTER_OPMODE, 0x03); if (error) { dev_err(&client->dev, "failed to switch to factory mode, error %d\n", error); @@ -662,8 +665,9 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata) do { mdelay(EDT_SWITCH_MODE_DELAY); /* mode register is 0x01 when in factory mode */ - ret = edt_ft5x06_register_read(tsdata, FACTORY_REGISTER_OPMODE); - if (ret == 0x03) + error = regmap_read(tsdata->regmap, FACTORY_REGISTER_OPMODE, + &val); + if (!error && val == 0x03) break; } while (--retries > 0); @@ -689,11 +693,11 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) { struct i2c_client *client = tsdata->client; int retries = EDT_SWITCH_MODE_RETRIES; - int ret; + unsigned int val; int error; /* mode register is 0x01 when in the factory mode */ - error = edt_ft5x06_register_write(tsdata, FACTORY_REGISTER_OPMODE, 0x1); + error = regmap_write(tsdata->regmap, FACTORY_REGISTER_OPMODE, 0x1); if (error) { dev_err(&client->dev, "failed to switch to work mode, error: %d\n", error); @@ -705,8 +709,8 @@ static int edt_ft5x06_work_mode(struct edt_ft5x06_ts_data *tsdata) do { mdelay(EDT_SWITCH_MODE_DELAY); /* mode register is 0x01 when in factory mode */ - ret = edt_ft5x06_register_read(tsdata, WORK_REGISTER_OPMODE); - if (ret == 0x01) + error = regmap_read(tsdata->regmap, WORK_REGISTER_OPMODE, &val); + if (!error && val == 0x01) break; } while (--retries > 0); @@ -765,10 +769,10 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, struct edt_ft5x06_ts_data *tsdata = file->private_data; struct i2c_client *client = tsdata->client; int retries = EDT_RAW_DATA_RETRIES; - int val, i, error; + unsigned int val; + int i, error; size_t read = 0; int colbytes; - char wrbuf[3]; u8 *rdbuf; if (*off < 0 || *off >= tsdata->raw_bufsize) @@ -781,7 +785,7 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, goto out; } - error = edt_ft5x06_register_write(tsdata, 0x08, 0x01); + error = regmap_write(tsdata->regmap, 0x08, 0x01); if (error) { dev_err(&client->dev, "failed to write 0x08 register, error %d\n", error); @@ -790,18 +794,18 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, do { usleep_range(EDT_RAW_DATA_DELAY, EDT_RAW_DATA_DELAY + 100); - val = edt_ft5x06_register_read(tsdata, 0x08); - if (val < 1) + error = regmap_read(tsdata->regmap, 0x08, &val); + if (error) { + dev_err(&client->dev, + "failed to read 0x08 register, error %d\n", + error); + goto out; + } + + if (val == 1) break; } while (--retries > 0); - if (val < 0) { - error = val; - dev_err(&client->dev, - "failed to read 0x08 register, error %d\n", error); - goto out; - } - if (retries == 0) { dev_err(&client->dev, "timed out waiting for register to settle\n"); @@ -812,13 +816,9 @@ static ssize_t edt_ft5x06_debugfs_raw_data_read(struct file *file, rdbuf = tsdata->raw_buffer; colbytes = tsdata->num_y * sizeof(u16); - wrbuf[0] = 0xf5; - wrbuf[1] = 0x0e; for (i = 0; i < tsdata->num_x; i++) { - wrbuf[2] = i; /* column index */ - error = edt_ft5x06_ts_readwrite(tsdata->client, - sizeof(wrbuf), wrbuf, - colbytes, rdbuf); + rdbuf[0] = i; /* column index */ + error = regmap_bulk_read(tsdata->regmap, 0xf5, rdbuf, colbytes); if (error) goto out; @@ -894,8 +894,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, * to have garbage in there */ memset(rdbuf, 0, sizeof(rdbuf)); - error = edt_ft5x06_ts_readwrite(client, 1, "\xBB", - EDT_NAME_LEN - 1, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0xBB, rdbuf, EDT_NAME_LEN - 1); if (error) return error; @@ -917,6 +916,14 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, *p++ = '\0'; strscpy(model_name, rdbuf + 1, EDT_NAME_LEN); strscpy(fw_version, p ? p : "", EDT_NAME_LEN); + + regmap_exit(tsdata->regmap); + tsdata->regmap = regmap_init_i2c(client, + &edt_M06_i2c_regmap_config); + if (IS_ERR(tsdata->regmap)) { + dev_err(&client->dev, "regmap allocation failed\n"); + return PTR_ERR(tsdata->regmap); + } } else if (!strncasecmp(rdbuf, "EP0", 3)) { tsdata->version = EDT_M12; @@ -943,15 +950,13 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, */ tsdata->version = GENERIC_FT; - error = edt_ft5x06_ts_readwrite(client, 1, "\xA6", - 2, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0xA6, rdbuf, 2); if (error) return error; strscpy(fw_version, rdbuf, 2); - error = edt_ft5x06_ts_readwrite(client, 1, "\xA8", - 1, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0xA8, rdbuf, 1); if (error) return error; @@ -980,8 +985,7 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client, break; case 0x59: /* Evervision Display with FT5xx6 TS */ tsdata->version = EV_FT; - error = edt_ft5x06_ts_readwrite(client, 1, "\x53", - 1, rdbuf); + error = regmap_bulk_read(tsdata->regmap, 0x53, rdbuf, 1); if (error) return error; strscpy(fw_version, rdbuf, 1); @@ -1003,42 +1007,40 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + struct regmap *regmap = tsdata->regmap; u32 val; int error; error = device_property_read_u32(dev, "threshold", &val); if (!error) { - edt_ft5x06_register_write(tsdata, reg_addr->reg_threshold, val); + regmap_write(regmap, reg_addr->reg_threshold, val); tsdata->threshold = val; } error = device_property_read_u32(dev, "gain", &val); if (!error) { - edt_ft5x06_register_write(tsdata, reg_addr->reg_gain, val); + regmap_write(regmap, reg_addr->reg_gain, val); tsdata->gain = val; } error = device_property_read_u32(dev, "offset", &val); if (!error) { if (reg_addr->reg_offset != NO_REGISTER) - edt_ft5x06_register_write(tsdata, - reg_addr->reg_offset, val); + regmap_write(regmap, reg_addr->reg_offset, val); tsdata->offset = val; } error = device_property_read_u32(dev, "offset-x", &val); if (!error) { if (reg_addr->reg_offset_x != NO_REGISTER) - edt_ft5x06_register_write(tsdata, - reg_addr->reg_offset_x, val); + regmap_write(regmap, reg_addr->reg_offset_x, val); tsdata->offset_x = val; } error = device_property_read_u32(dev, "offset-y", &val); if (!error) { if (reg_addr->reg_offset_y != NO_REGISTER) - edt_ft5x06_register_write(tsdata, - reg_addr->reg_offset_y, val); + regmap_write(regmap, reg_addr->reg_offset_y, val); tsdata->offset_y = val; } } @@ -1046,33 +1048,30 @@ static void edt_ft5x06_ts_get_defaults(struct device *dev, static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; + struct regmap *regmap = tsdata->regmap; + unsigned int val; - tsdata->threshold = edt_ft5x06_register_read(tsdata, - reg_addr->reg_threshold); - tsdata->gain = edt_ft5x06_register_read(tsdata, reg_addr->reg_gain); + regmap_read(regmap, reg_addr->reg_threshold, &tsdata->threshold); + regmap_read(regmap, reg_addr->reg_gain, &tsdata->gain); if (reg_addr->reg_offset != NO_REGISTER) - tsdata->offset = - edt_ft5x06_register_read(tsdata, reg_addr->reg_offset); + regmap_read(regmap, reg_addr->reg_offset, &tsdata->offset); if (reg_addr->reg_offset_x != NO_REGISTER) - tsdata->offset_x = - edt_ft5x06_register_read(tsdata, - reg_addr->reg_offset_x); + regmap_read(regmap, reg_addr->reg_offset_x, &tsdata->offset_x); if (reg_addr->reg_offset_y != NO_REGISTER) - tsdata->offset_y = - edt_ft5x06_register_read(tsdata, - reg_addr->reg_offset_y); + regmap_read(regmap, reg_addr->reg_offset_y, &tsdata->offset_y); if (reg_addr->reg_report_rate != NO_REGISTER) - tsdata->report_rate = - edt_ft5x06_register_read(tsdata, - reg_addr->reg_report_rate); + regmap_read(regmap, reg_addr->reg_report_rate, + &tsdata->report_rate); tsdata->num_x = EDT_DEFAULT_NUM_X; - if (reg_addr->reg_num_x != NO_REGISTER) - tsdata->num_x = edt_ft5x06_register_read(tsdata, - reg_addr->reg_num_x); + if (reg_addr->reg_num_x != NO_REGISTER) { + if (!regmap_read(regmap, reg_addr->reg_num_x, &val)) + tsdata->num_x = val; + } tsdata->num_y = EDT_DEFAULT_NUM_Y; - if (reg_addr->reg_num_y != NO_REGISTER) - tsdata->num_y = edt_ft5x06_register_read(tsdata, - reg_addr->reg_num_y); + if (reg_addr->reg_num_y != NO_REGISTER) { + if (!regmap_read(regmap, reg_addr->reg_num_y, &val)) + tsdata->num_y = val; + } } static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) @@ -1142,7 +1141,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) const struct i2c_device_id *id = i2c_client_get_device_id(client); const struct edt_i2c_chip_data *chip_data; struct edt_ft5x06_ts_data *tsdata; - u8 buf[2] = { 0xfc, 0x00 }; + unsigned int val; struct input_dev *input; unsigned long irq_flags; int error; @@ -1156,6 +1155,12 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) return -ENOMEM; } + tsdata->regmap = regmap_init_i2c(client, &edt_ft5x06_i2c_regmap_config); + if (IS_ERR(tsdata->regmap)) { + dev_err(&client->dev, "regmap allocation failed\n"); + return PTR_ERR(tsdata->regmap); + } + chip_data = device_get_match_data(&client->dev); if (!chip_data) chip_data = (const struct edt_i2c_chip_data *)id->driver_data; @@ -1258,6 +1263,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) tsdata->client = client; tsdata->input = input; tsdata->factory_mode = false; + i2c_set_clientdata(client, tsdata); error = edt_ft5x06_ts_identify(client, tsdata); if (error) { @@ -1269,7 +1275,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) * Dummy read access. EP0700MLP1 returns bogus data on the first * register read access and ignores writes. */ - edt_ft5x06_ts_readwrite(tsdata->client, 2, buf, 2, buf); + regmap_read(tsdata->regmap, 0x00, &val); edt_ft5x06_ts_set_regs(tsdata); edt_ft5x06_ts_get_defaults(&client->dev, tsdata); @@ -1291,9 +1297,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) if (tsdata->version == EDT_M06) tsdata->report_rate /= 10; - edt_ft5x06_register_write(tsdata, - tsdata->reg_addr.reg_report_rate, - tsdata->report_rate); + regmap_write(tsdata->regmap, tsdata->reg_addr.reg_report_rate, + tsdata->report_rate); } dev_dbg(&client->dev, @@ -1318,8 +1323,6 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) return error; } - i2c_set_clientdata(client, tsdata); - irq_flags = irq_get_trigger_type(client->irq); if (irq_flags == IRQF_TRIGGER_NONE) irq_flags = IRQF_TRIGGER_FALLING; @@ -1357,6 +1360,7 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client) struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client); edt_ft5x06_ts_teardown_debugfs(tsdata); + regmap_exit(tsdata->regmap); } static int edt_ft5x06_ts_suspend(struct device *dev) @@ -1373,8 +1377,8 @@ static int edt_ft5x06_ts_suspend(struct device *dev) return 0; /* Enter hibernate mode. */ - ret = edt_ft5x06_register_write(tsdata, PMOD_REGISTER_OPMODE, - PMOD_REGISTER_HIBERNATE); + ret = regmap_write(tsdata->regmap, PMOD_REGISTER_OPMODE, + PMOD_REGISTER_HIBERNATE); if (ret) dev_warn(dev, "Failed to set hibernate mode\n"); From 079e60a53c25aeb1920e783fa7f7390eabb6afc0 Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 21:36:33 -0700 Subject: [PATCH 32/42] Input: edt-ft5x06 - unify the crc check With this patch, the CRC is always verified by the same function, even in the case of accessing registers where the number of bytes is minimal. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-9-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 8aae4c1e6b73..fdb32e3591be 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -240,13 +240,10 @@ static int edt_M06_i2c_read(void *context, const void *reg_buf, size_t reg_size, if (!edt_ft5x06_ts_check_crc(tsdata, val_buf, val_size)) return -EIO; } else if (reg_read) { - u8 crc = wbuf[0] ^ wbuf[1] ^ rbuf[0]; - - if (crc != rbuf[1]) { - dev_err(dev, "crc error: 0x%02x expected, got 0x%02x\n", - crc, rbuf[1]); + wbuf[2] = rbuf[0]; + wbuf[3] = rbuf[1]; + if (!edt_ft5x06_ts_check_crc(tsdata, wbuf, 4)) return -EIO; - } *((u8 *)val_buf) = rbuf[0]; } From 0df28e7166e803028c380c59dda530ffada0503c Mon Sep 17 00:00:00 2001 From: Dario Binacchi Date: Sun, 2 Apr 2023 21:36:46 -0700 Subject: [PATCH 33/42] Input: edt-ft5x06 - calculate points data length only once It is pointless and expensive to calculate data in the interrupt that depends on the type of touchscreen, which is detected on the driver probe and cannot then be changed. So calculate the size of the data buffer on the driver probe, as well as the data retrieval command, and then use them in the ISR. Signed-off-by: Dario Binacchi Link: https://lore.kernel.org/r/20230402200951.1032513-10-dario.binacchi@amarulasolutions.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/edt-ft5x06.c | 56 +++++++++++++------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index fdb32e3591be..24ab9e9f5b21 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -135,6 +135,10 @@ struct edt_ft5x06_ts_data { int offset_y; int report_rate; int max_support_points; + int point_len; + u8 tdata_cmd; + int tdata_len; + int tdata_offset; char name[EDT_NAME_LEN]; char fw_version[EDT_NAME_LEN]; @@ -296,38 +300,13 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) { struct edt_ft5x06_ts_data *tsdata = dev_id; struct device *dev = &tsdata->client->dev; - u8 cmd; u8 rdbuf[63]; int i, type, x, y, id; - int offset, tplen, datalen, crclen; int error; - switch (tsdata->version) { - case EDT_M06: - cmd = 0xf9; /* tell the controller to send touch data */ - offset = 5; /* where the actual touch data starts */ - tplen = 4; /* data comes in so called frames */ - crclen = 1; /* length of the crc data */ - break; - - case EDT_M09: - case EDT_M12: - case EV_FT: - case GENERIC_FT: - cmd = 0x0; - offset = 3; - tplen = 6; - crclen = 0; - break; - - default: - goto out; - } - memset(rdbuf, 0, sizeof(rdbuf)); - datalen = tplen * tsdata->max_support_points + offset + crclen; - - error = regmap_bulk_read(tsdata->regmap, cmd, rdbuf, datalen); + error = regmap_bulk_read(tsdata->regmap, tsdata->tdata_cmd, rdbuf, + tsdata->tdata_len); if (error) { dev_err_ratelimited(dev, "Unable to fetch data, error: %d\n", error); @@ -335,7 +314,7 @@ static irqreturn_t edt_ft5x06_ts_isr(int irq, void *dev_id) } for (i = 0; i < tsdata->max_support_points; i++) { - u8 *buf = &rdbuf[i * tplen + offset]; + u8 *buf = &rdbuf[i * tsdata->point_len + tsdata->tdata_offset]; type = buf[0] >> 6; /* ignore Reserved events */ @@ -1071,6 +1050,26 @@ static void edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata) } } +static void edt_ft5x06_ts_set_tdata_parameters(struct edt_ft5x06_ts_data *tsdata) +{ + int crclen; + + if (tsdata->version == EDT_M06) { + tsdata->tdata_cmd = 0xf9; + tsdata->tdata_offset = 5; + tsdata->point_len = 4; + crclen = 1; + } else { + tsdata->tdata_cmd = 0x0; + tsdata->tdata_offset = 3; + tsdata->point_len = 6; + crclen = 0; + } + + tsdata->tdata_len = tsdata->point_len * tsdata->max_support_points + + tsdata->tdata_offset + crclen; +} + static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata) { struct edt_reg_addr *reg_addr = &tsdata->reg_addr; @@ -1274,6 +1273,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) */ regmap_read(tsdata->regmap, 0x00, &val); + edt_ft5x06_ts_set_tdata_parameters(tsdata); edt_ft5x06_ts_set_regs(tsdata); edt_ft5x06_ts_get_defaults(&client->dev, tsdata); edt_ft5x06_ts_get_parameters(tsdata); From cd7cd6f386df21725eeab5d803226d4f74177203 Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Sun, 9 Apr 2023 19:10:24 -0700 Subject: [PATCH 34/42] Input: cma3000_d0x - remove unneeded code Function input_set_abs_params() has already set EV_ABS bit for us. drivers/input/misc/cma3000_d0x.c:328 cma3000_init() warn: inconsistent indenting. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230407021343.63512-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Dmitry Torokhov --- drivers/input/misc/cma3000_d0x.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c index e6feb73bb52b..1772846708d2 100644 --- a/drivers/input/misc/cma3000_d0x.c +++ b/drivers/input/misc/cma3000_d0x.c @@ -325,8 +325,6 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq, input_dev->open = cma3000_open; input_dev->close = cma3000_close; - __set_bit(EV_ABS, input_dev->evbit); - input_set_abs_params(input_dev, ABS_X, -data->g_range, data->g_range, pdata->fuzz_x, 0); input_set_abs_params(input_dev, ABS_Y, From 210f8cab0751eb95dc56453e3dbf8a962d4d1e17 Mon Sep 17 00:00:00 2001 From: JungHoon Hyun Date: Sun, 9 Apr 2023 19:36:57 -0700 Subject: [PATCH 35/42] Input: melfas_mip4 - report palm touches The driver had the code to differentiate between finger and palm touches, but did not use this information when reporting contacts. Change it so that proper "tool" type is assigned to reported contacts. Signed-off-by: JungHoon Hyun Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index acdfbdea2b6e..89b6020a9a61 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -466,7 +466,7 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet) { int id; bool __always_unused hover; - bool __always_unused palm; + bool palm; bool state; u16 x, y; u8 __always_unused pressure_stage = 0; @@ -522,21 +522,21 @@ static void mip4_report_touch(struct mip4_ts *ts, u8 *packet) if (unlikely(id < 0 || id >= MIP4_MAX_FINGERS)) { dev_err(&ts->client->dev, "Screen - invalid slot ID: %d\n", id); - } else if (state) { - /* Press or Move event */ - input_mt_slot(ts->input, id); - input_mt_report_slot_state(ts->input, MT_TOOL_FINGER, true); + goto out; + } + + input_mt_slot(ts->input, id); + if (input_mt_report_slot_state(ts->input, + palm ? MT_TOOL_PALM : MT_TOOL_FINGER, + state)) { input_report_abs(ts->input, ABS_MT_POSITION_X, x); input_report_abs(ts->input, ABS_MT_POSITION_Y, y); input_report_abs(ts->input, ABS_MT_PRESSURE, pressure); input_report_abs(ts->input, ABS_MT_TOUCH_MAJOR, touch_major); input_report_abs(ts->input, ABS_MT_TOUCH_MINOR, touch_minor); - } else { - /* Release event */ - input_mt_slot(ts->input, id); - input_mt_report_slot_inactive(ts->input); } +out: input_mt_sync_frame(ts->input); } @@ -1483,6 +1483,7 @@ static int mip4_probe(struct i2c_client *client) input->keycodesize = sizeof(*ts->key_code); input->keycodemax = ts->key_num; + input_set_abs_params(input, ABS_MT_TOOL_TYPE, 0, MT_TOOL_PALM, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, ts->max_x, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, ts->max_y, 0, 0); input_set_abs_params(input, ABS_MT_PRESSURE, From 483a14418661878d89216be0f02918892227833b Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Mon, 10 Apr 2023 16:55:44 -0700 Subject: [PATCH 36/42] Input: edt-ft5x06 - select REGMAP_I2C After starting to use regmap API to access registers the edt-ft5x06 driver depends on symbols provided by REGMAP_I2C: edt-ft5x06.o: in function `edt_ft5x06_ts_probe': edt-ft5x06.c:1154: undefined reference to `__regmap_init_i2c' edt-ft5x06.o: in function `edt_ft5x06_ts_identify': edt-ft5x06.c:897: undefined reference to `__regmap_init_i2c' Make sure support for I2C regmap is actually selected by adding this dependency to Kconfig. Fixes: 9dfd9708ffba ("Input: edt-ft5x06 - convert to use regmap API") Signed-off-by: Daniel Golle Link: https://lore.kernel.org/r/ZDRBExF1xmxalMZc@makrotopia.org Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 1feecd7ed3cb..143ff43c67ae 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -768,6 +768,7 @@ config TOUCHSCREEN_PENMOUNT config TOUCHSCREEN_EDT_FT5X06 tristate "EDT FocalTech FT5x06 I2C Touchscreen support" depends on I2C + select REGMAP_I2C help Say Y here if you have an EDT "Polytouch" touchscreen based on the FocalTech FT5x06 family of controllers connected to From 5bca3688bdbc3b58a2894b8671a8e2378efe28bd Mon Sep 17 00:00:00 2001 From: Miaoqian Lin Date: Thu, 13 Apr 2023 23:05:20 -0700 Subject: [PATCH 37/42] Input: raspberrypi-ts - fix refcount leak in rpi_ts_probe rpi_firmware_get() take reference, we need to release it in error paths as well. Use devm_rpi_firmware_get() helper to handling the resources. Also remove the existing rpi_firmware_put(). Fixes: 0b9f28fed3f7 ("Input: add official Raspberry Pi's touchscreen driver") Fixes: 3b8ddff780b7 ("input: raspberrypi-ts: Release firmware handle when not needed") Signed-off-by: Miaoqian Lin Reviewed-by: Mattijs Korpershoek Link: https://lore.kernel.org/r/20221223074657.810346-1-linmq006@gmail.com Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raspberrypi-ts.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c index 5000f5fd9ec3..45c575df994e 100644 --- a/drivers/input/touchscreen/raspberrypi-ts.c +++ b/drivers/input/touchscreen/raspberrypi-ts.c @@ -134,7 +134,7 @@ static int rpi_ts_probe(struct platform_device *pdev) return -ENOENT; } - fw = rpi_firmware_get(fw_node); + fw = devm_rpi_firmware_get(&pdev->dev, fw_node); of_node_put(fw_node); if (!fw) return -EPROBE_DEFER; @@ -160,7 +160,6 @@ static int rpi_ts_probe(struct platform_device *pdev) touchbuf = (u32)ts->fw_regs_phys; error = rpi_firmware_property(fw, RPI_FIRMWARE_FRAMEBUFFER_SET_TOUCHBUF, &touchbuf, sizeof(touchbuf)); - rpi_firmware_put(fw); if (error || touchbuf != 0) { dev_warn(dev, "Failed to set touchbuf, %d\n", error); return error; From d6e680837ec568818eff275c15709231ce2e2b4f Mon Sep 17 00:00:00 2001 From: Jiapeng Chong Date: Thu, 13 Apr 2023 23:23:29 -0700 Subject: [PATCH 38/42] Input: synaptics-rmi4 - fix function name in kerneldoc No functional modification involved. drivers/input/rmi4/rmi_bus.c:300: warning: expecting prototype for rmi_register_function_handler(). Prototype was for __rmi_register_function_handler() instead. Reported-by: Abaci Robot Signed-off-by: Jiapeng Chong Link: https://lore.kernel.org/r/20230209040710.111456-1-jiapeng.chong@linux.alibaba.com Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 50a0134b6901..f2e093b0b998 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -285,7 +285,7 @@ void rmi_unregister_function(struct rmi_function *fn) } /** - * rmi_register_function_handler - register a handler for an RMI function + * __rmi_register_function_handler - register a handler for an RMI function * @handler: RMI handler that should be registered. * @owner: pointer to module that implements the handler * @mod_name: name of the module implementing the handler From f9b2e603c6216824e34dc9a67205d98ccc9a41ca Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 13 Apr 2023 23:57:42 -0700 Subject: [PATCH 39/42] Input: xpad - add constants for GIP interface numbers Wired GIP devices present multiple interfaces with the same USB identification other than the interface number. This adds constants for differentiating two of them and uses them where appropriate Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230411031650.960322-2-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 260f91fef427..6ea9c10dfb8a 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -561,6 +561,9 @@ struct xboxone_init_packet { #define GIP_MOTOR_LT BIT(3) #define GIP_MOTOR_ALL (GIP_MOTOR_R | GIP_MOTOR_L | GIP_MOTOR_RT | GIP_MOTOR_LT) +#define GIP_WIRED_INTF_DATA 0 +#define GIP_WIRED_INTF_AUDIO 1 + /* * This packet is required for all Xbox One pads with 2015 * or later firmware installed (or present from the factory). @@ -2004,7 +2007,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id } if (xpad->xtype == XTYPE_XBOXONE && - intf->cur_altsetting->desc.bInterfaceNumber != 0) { + intf->cur_altsetting->desc.bInterfaceNumber != GIP_WIRED_INTF_DATA) { /* * The Xbox One controller lists three interfaces all with the * same interface class, subclass and protocol. Differentiate by From cf5950187319346d7cdc62522f90479dfefd9235 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Thu, 13 Apr 2023 23:58:12 -0700 Subject: [PATCH 40/42] Input: xpad - fix PowerA EnWired Controller guide button This commit explicitly disables the audio interface the same way the official driver does. This is needed for some controllers, such as the PowerA Enhanced Wired Controller for Series X|S (0x20d6:0x200e) to report the guide button. Signed-off-by: Vicki Pfau Link: https://lore.kernel.org/r/20230411031650.960322-3-vi@endrift.com Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 6ea9c10dfb8a..138e4a9f341f 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1396,6 +1396,21 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad) unsigned long flags; int retval; + if (usb_ifnum_to_if(xpad->udev, GIP_WIRED_INTF_AUDIO)) { + /* + * Explicitly disable the audio interface. This is needed + * for some controllers, such as the PowerA Enhanced Wired + * Controller for Series X|S (0x20d6:0x200e) to report the + * guide button. + */ + retval = usb_set_interface(xpad->udev, + GIP_WIRED_INTF_AUDIO, 0); + if (retval) + dev_warn(&xpad->dev->dev, + "unable to disable audio interface: %d\n", + retval); + } + spin_lock_irqsave(&xpad->odata_lock, flags); /* From c55d84fb2bd89fe2ad56768ead90eb1050581d29 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Thu, 13 Apr 2023 23:35:26 -0700 Subject: [PATCH 41/42] dt-bindings: input: pwm-beeper: convert to dt schema Convert the binding doc to dt schema, and also fixed the example from fixed-regulator to regulator-fixed. Signed-off-by: Peng Fan Reviewed-by: Rob Herring Link: https://lore.kernel.org/r/20230407075259.1593739-1-peng.fan@oss.nxp.com Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/pwm-beeper.txt | 24 ----------- .../devicetree/bindings/input/pwm-beeper.yaml | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 24 deletions(-) delete mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.txt create mode 100644 Documentation/devicetree/bindings/input/pwm-beeper.yaml diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.txt b/Documentation/devicetree/bindings/input/pwm-beeper.txt deleted file mode 100644 index 8fc0e48c20db..000000000000 --- a/Documentation/devicetree/bindings/input/pwm-beeper.txt +++ /dev/null @@ -1,24 +0,0 @@ -* PWM beeper device tree bindings - -Registers a PWM device as beeper. - -Required properties: -- compatible: should be "pwm-beeper" -- pwms: phandle to the physical PWM device - -Optional properties: -- amp-supply: phandle to a regulator that acts as an amplifier for the beeper -- beeper-hz: bell frequency in Hz - -Example: - -beeper_amp: amplifier { - compatible = "fixed-regulator"; - gpios = <&gpio0 1 GPIO_ACTIVE_HIGH>; -}; - -beeper { - compatible = "pwm-beeper"; - pwms = <&pwm0>; - amp-supply = <&beeper_amp>; -}; diff --git a/Documentation/devicetree/bindings/input/pwm-beeper.yaml b/Documentation/devicetree/bindings/input/pwm-beeper.yaml new file mode 100644 index 000000000000..a7611c206989 --- /dev/null +++ b/Documentation/devicetree/bindings/input/pwm-beeper.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/pwm-beeper.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: PWM beeper + +maintainers: + - Sascha Hauer + +properties: + compatible: + const: pwm-beeper + + pwms: + maxItems: 1 + + amp-supply: + description: an amplifier for the beeper + + beeper-hz: + description: bell frequency in Hz + minimum: 10 + maximum: 10000 + +required: + - compatible + - pwms + +unevaluatedProperties: false + +examples: + - | + #include + beeper { + compatible = "pwm-beeper"; + pwms = <&pwm0>; + amp-supply = <&beeper_amp>; + beeper-hz = <1000>; + }; From 53bea86b5712c7491bb3dae12e271666df0a308c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 1 May 2023 15:11:55 -0700 Subject: [PATCH 42/42] Revert "Input: xpad - fix support for some third-party controllers" This reverts commit db7220c48d8d71476f881a7ae1285e1df4105409 because it causes crashes when trying to dereference xpad->dev->dev in xpad_probe() which has not been set up yet. Reported-by: syzbot+a3f758b8d8cb7e49afec@syzkaller.appspotmail.com Reported-by: Dongliang Mu Link: https://groups.google.com/g/syzkaller-bugs/c/iMhTgpGuIbM Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 138e4a9f341f..50ecff681b89 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -264,7 +264,6 @@ static const struct xpad_device { { 0x0f0d, 0x0067, "HORIPAD ONE", 0, XTYPE_XBOXONE }, { 0x0f0d, 0x0078, "Hori Real Arcade Pro V Kai Xbox One", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, { 0x0f0d, 0x00c5, "Hori Fighting Commander ONE", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE }, - { 0x0f0d, 0x00dc, "HORIPAD FPS for Nintendo Switch", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX }, { 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX }, { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, @@ -2032,28 +2031,6 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id goto err_free_in_urb; } - if (xpad->xtype == XTYPE_XBOX360) { - /* - * Some third-party controllers Xbox 360-style controllers - * require this message to finish initialization. - */ - u8 dummy[20]; - - error = usb_control_msg_recv(udev, 0, - /* bRequest */ 0x01, - /* bmRequestType */ - USB_TYPE_VENDOR | USB_DIR_IN | - USB_RECIP_INTERFACE, - /* wValue */ 0x100, - /* wIndex */ 0x00, - dummy, sizeof(dummy), - 25, GFP_KERNEL); - if (error) - dev_warn(&xpad->dev->dev, - "unable to receive magic message: %d\n", - error); - } - ep_irq_in = ep_irq_out = NULL; for (i = 0; i < 2; i++) {