diff options
author | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-01-15 21:09:44 +0100 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2022-01-15 21:09:44 +0100 |
commit | 762f99f4f3cb41a775b5157dd761217beba65873 (patch) | |
tree | 2e93410a577dfff1202ea5b0d109460b97650e58 /drivers/input | |
parent | Input: zinitix - make sure the IRQ is allocated before it gets enabled (diff) | |
parent | Input: ti_am335x_tsc - fix a typo in a comment (diff) | |
download | linux-762f99f4f3cb41a775b5157dd761217beba65873.tar.xz linux-762f99f4f3cb41a775b5157dd761217beba65873.zip |
Merge branch 'next' into for-linus
Prepare input updates for 5.17 merge window.
Diffstat (limited to 'drivers/input')
-rw-r--r-- | drivers/input/Kconfig | 1 | ||||
-rw-r--r-- | drivers/input/ff-core.c | 2 | ||||
-rw-r--r-- | drivers/input/gameport/Kconfig | 1 | ||||
-rw-r--r-- | drivers/input/gameport/gameport.c | 3 | ||||
-rw-r--r-- | drivers/input/joystick/Kconfig | 1 | ||||
-rw-r--r-- | drivers/input/joystick/sidewinder.c | 1 | ||||
-rw-r--r-- | drivers/input/keyboard/Kconfig | 3 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 2 | ||||
-rw-r--r-- | drivers/input/keyboard/hilkbd.c | 4 | ||||
-rw-r--r-- | drivers/input/misc/axp20x-pek.c | 72 | ||||
-rw-r--r-- | drivers/input/misc/palmas-pwrbutton.c | 9 | ||||
-rw-r--r-- | drivers/input/mouse/byd.c | 2 | ||||
-rw-r--r-- | drivers/input/serio/gscps2.c | 3 | ||||
-rw-r--r-- | drivers/input/serio/serio.c | 3 | ||||
-rw-r--r-- | drivers/input/serio/serport.c | 8 | ||||
-rw-r--r-- | drivers/input/touchscreen/goodix.c | 179 | ||||
-rw-r--r-- | drivers/input/touchscreen/goodix.h | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/silead.c | 172 | ||||
-rw-r--r-- | drivers/input/touchscreen/ti_am335x_tsc.c | 20 | ||||
-rw-r--r-- | drivers/input/touchscreen/ucb1400_ts.c | 4 | ||||
-rw-r--r-- | drivers/input/touchscreen/wacom_i2c.c | 44 | ||||
-rw-r--r-- | drivers/input/touchscreen/zinitix.c | 22 |
22 files changed, 404 insertions, 153 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index ec0e861f185f..5baebf62df33 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -4,7 +4,6 @@ # menu "Input device support" - depends on !UML config INPUT tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 1cf5deda06e1..fa8d1a466014 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -67,7 +67,7 @@ static int compat_effect(struct ff_device *ff, struct ff_effect *effect) effect->type = FF_PERIODIC; effect->u.periodic.waveform = FF_SINE; effect->u.periodic.period = 50; - effect->u.periodic.magnitude = max(magnitude, 0x7fff); + effect->u.periodic.magnitude = magnitude; effect->u.periodic.offset = 0; effect->u.periodic.phase = 0; effect->u.periodic.envelope.attack_length = 0; diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 4761795cb49f..5a2c2fb3217d 100644 --- a/drivers/input/gameport/Kconfig +++ b/drivers/input/gameport/Kconfig @@ -4,6 +4,7 @@ # config GAMEPORT tristate "Gameport support" + depends on !UML help Gameport support is for the standard 15-pin PC gameport. If you have a joystick, gamepad, gameport card, a soundcard with a gameport diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index 61fa7e724172..db58a01b23d3 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -697,13 +697,12 @@ static int gameport_driver_probe(struct device *dev) return gameport->drv ? 0 : -ENODEV; } -static int gameport_driver_remove(struct device *dev) +static void gameport_driver_remove(struct device *dev) { struct gameport *gameport = to_gameport_port(dev); struct gameport_driver *drv = to_gameport_driver(dev->driver); drv->disconnect(gameport); - return 0; } static void gameport_attach_driver(struct gameport_driver *drv) diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 7dfe8ea90923..3b23078bc7b5 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -4,6 +4,7 @@ # menuconfig INPUT_JOYSTICK bool "Joysticks/Gamepads" + depends on !UML help If you have a joystick, 6dof controller, gamepad, steering wheel, weapon control system or something like that you can say Y here diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index fac91ea14f17..8e9672deb1eb 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -660,6 +660,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) fallthrough; case 45: /* Ambiguous packet length */ if (j <= 40) { /* ID length less or eq 40 -> FSP */ + fallthrough; case 43: sw->type = SW_ID_FSP; break; diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig index d3bf5c3f9add..0c607da9ee10 100644 --- a/drivers/input/keyboard/Kconfig +++ b/drivers/input/keyboard/Kconfig @@ -67,9 +67,6 @@ config KEYBOARD_AMIGA To compile this driver as a module, choose M here: the module will be called amikbd. -config ATARI_KBD_CORE - bool - config KEYBOARD_APPLESPI tristate "Apple SPI keyboard and trackpad" depends on ACPI && EFI diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 8dbf1e69c90a..d75a8b179a8a 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -247,7 +247,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, ssize_t error; int i; - bits = bitmap_zalloc(n_events, GFP_KERNEL); + bits = bitmap_alloc(n_events, GFP_KERNEL); if (!bits) return -ENOMEM; diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c index 62ccfebf2f60..c1a4d5055de6 100644 --- a/drivers/input/keyboard/hilkbd.c +++ b/drivers/input/keyboard/hilkbd.c @@ -316,11 +316,9 @@ static int __init hil_probe_chip(struct parisc_device *dev) return hil_keyb_init(); } -static int __exit hil_remove_chip(struct parisc_device *dev) +static void __exit hil_remove_chip(struct parisc_device *dev) { hil_keyb_exit(); - - return 0; } static const struct parisc_device_id hil_tbl[] __initconst = { diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c index 9c6386b2af33..c8f87df93a50 100644 --- a/drivers/input/misc/axp20x-pek.c +++ b/drivers/input/misc/axp20x-pek.c @@ -205,11 +205,8 @@ ATTRIBUTE_GROUPS(axp20x); static irqreturn_t axp20x_pek_irq(int irq, void *pwr) { - struct axp20x_pek *axp20x_pek = pwr; - struct input_dev *idev = axp20x_pek->input; - - if (!idev) - return IRQ_HANDLED; + struct input_dev *idev = pwr; + struct axp20x_pek *axp20x_pek = input_get_drvdata(idev); /* * The power-button is connected to ground so a falling edge (dbf) @@ -228,9 +225,22 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr) static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, struct platform_device *pdev) { + struct axp20x_dev *axp20x = axp20x_pek->axp20x; struct input_dev *idev; int error; + axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); + if (axp20x_pek->irq_dbr < 0) + return axp20x_pek->irq_dbr; + axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc, + axp20x_pek->irq_dbr); + + axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); + if (axp20x_pek->irq_dbf < 0) + return axp20x_pek->irq_dbf; + axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc, + axp20x_pek->irq_dbf); + axp20x_pek->input = devm_input_allocate_device(&pdev->dev); if (!axp20x_pek->input) return -ENOMEM; @@ -245,6 +255,24 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, input_set_drvdata(idev, axp20x_pek); + error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, + axp20x_pek_irq, 0, + "axp20x-pek-dbr", idev); + if (error < 0) { + dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", + axp20x_pek->irq_dbr, error); + return error; + } + + error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, + axp20x_pek_irq, 0, + "axp20x-pek-dbf", idev); + if (error < 0) { + dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", + axp20x_pek->irq_dbf, error); + return error; + } + error = input_register_device(idev); if (error) { dev_err(&pdev->dev, "Can't register input device: %d\n", @@ -252,6 +280,8 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek, return error; } + device_init_wakeup(&pdev->dev, true); + return 0; } @@ -309,18 +339,6 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent); - axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR"); - if (axp20x_pek->irq_dbr < 0) - return axp20x_pek->irq_dbr; - axp20x_pek->irq_dbr = regmap_irq_get_virq( - axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbr); - - axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF"); - if (axp20x_pek->irq_dbf < 0) - return axp20x_pek->irq_dbf; - axp20x_pek->irq_dbf = regmap_irq_get_virq( - axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbf); - if (axp20x_pek_should_register_input(axp20x_pek, pdev)) { error = axp20x_pek_probe_input_device(axp20x_pek, pdev); if (error) @@ -329,26 +347,6 @@ static int axp20x_pek_probe(struct platform_device *pdev) axp20x_pek->info = (struct axp20x_info *)match->driver_data; - error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr, - axp20x_pek_irq, 0, - "axp20x-pek-dbr", axp20x_pek); - if (error < 0) { - dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n", - axp20x_pek->irq_dbr, error); - return error; - } - - error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf, - axp20x_pek_irq, 0, - "axp20x-pek-dbf", axp20x_pek); - if (error < 0) { - dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n", - axp20x_pek->irq_dbf, error); - return error; - } - - device_init_wakeup(&pdev->dev, true); - platform_set_drvdata(pdev, axp20x_pek); return 0; diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c index f9b05cf09ff5..2213e06b611d 100644 --- a/drivers/input/misc/palmas-pwrbutton.c +++ b/drivers/input/misc/palmas-pwrbutton.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. */ +#include <linux/bitfield.h> #include <linux/init.h> #include <linux/input.h> #include <linux/interrupt.h> @@ -115,8 +116,8 @@ static void palmas_pwron_params_ofinit(struct device *dev, struct device_node *np; u32 val; int i, error; - u8 lpk_times[] = { 6, 8, 10, 12 }; - int pwr_on_deb_ms[] = { 15, 100, 500, 1000 }; + static const u8 lpk_times[] = { 6, 8, 10, 12 }; + static const int pwr_on_deb_ms[] = { 15, 100, 500, 1000 }; memset(config, 0, sizeof(*config)); @@ -192,8 +193,8 @@ static int palmas_pwron_probe(struct platform_device *pdev) * Setup default hardware shutdown option (long key press) * and debounce. */ - val = config.long_press_time_val << __ffs(PALMAS_LPK_TIME_MASK); - val |= config.pwron_debounce_val << __ffs(PALMAS_PWRON_DEBOUNCE_MASK); + val = FIELD_PREP(PALMAS_LPK_TIME_MASK, config.long_press_time_val) | + FIELD_PREP(PALMAS_PWRON_DEBOUNCE_MASK, config.pwron_debounce_val); error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE, PALMAS_LONG_PRESS_KEY, PALMAS_LPK_TIME_MASK | diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c index 6e0c5f5a2713..221a553f45cd 100644 --- a/drivers/input/mouse/byd.c +++ b/drivers/input/mouse/byd.c @@ -191,7 +191,7 @@ /* * The touchpad generates a mixture of absolute and relative packets, indicated - * by the the last byte of each packet being set to one of the following: + * by the last byte of each packet being set to one of the following: */ #define BYD_PACKET_ABSOLUTE 0xf8 #define BYD_PACKET_RELATIVE 0x00 diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c index 2f9775de3c5b..a9065c6ab550 100644 --- a/drivers/input/serio/gscps2.c +++ b/drivers/input/serio/gscps2.c @@ -411,7 +411,7 @@ fail_nomem: * @return: success/error report */ -static int __exit gscps2_remove(struct parisc_device *dev) +static void __exit gscps2_remove(struct parisc_device *dev) { struct gscps2port *ps2port = dev_get_drvdata(&dev->dev); @@ -425,7 +425,6 @@ static int __exit gscps2_remove(struct parisc_device *dev) #endif dev_set_drvdata(&dev->dev, NULL); kfree(ps2port); - return 0; } diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index 29f491082926..ec117be3d8d8 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -778,12 +778,11 @@ static int serio_driver_probe(struct device *dev) return serio_connect_driver(serio, drv); } -static int serio_driver_remove(struct device *dev) +static void serio_driver_remove(struct device *dev) { struct serio *serio = to_serio_port(dev); serio_disconnect_driver(serio); - return 0; } static void serio_cleanup(struct serio *serio) diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index 33e9d9bfd036..7fbbe00e3553 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -114,7 +114,8 @@ static void serport_ldisc_close(struct tty_struct *tty) * 'interrupt' routine. */ -static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) +static void serport_ldisc_receive(struct tty_struct *tty, + const unsigned char *cp, const char *fp, int count) { struct serport *serport = (struct serport*) tty->disc_data; unsigned long flags; @@ -273,6 +274,7 @@ static void serport_ldisc_write_wakeup(struct tty_struct * tty) static struct tty_ldisc_ops serport_ldisc = { .owner = THIS_MODULE, + .num = N_MOUSE, .name = "input", .open = serport_ldisc_open, .close = serport_ldisc_close, @@ -293,7 +295,7 @@ static struct tty_ldisc_ops serport_ldisc = { static int __init serport_init(void) { int retval; - retval = tty_register_ldisc(N_MOUSE, &serport_ldisc); + retval = tty_register_ldisc(&serport_ldisc); if (retval) printk(KERN_ERR "serport.c: Error registering line discipline.\n"); @@ -302,7 +304,7 @@ static int __init serport_init(void) static void __exit serport_exit(void) { - tty_unregister_ldisc(N_MOUSE); + tty_unregister_ldisc(&serport_ldisc); } module_init(serport_init); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index 87263eb9e5a4..a3bfc7a41679 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -119,51 +119,6 @@ static const unsigned long goodix_irq_flags[] = { IRQ_TYPE_LEVEL_HIGH, }; -/* - * Those tablets have their coordinates origin at the bottom right - * of the tablet, as if rotated 180 degrees - */ -static const struct dmi_system_id rotated_screen[] = { -#if defined(CONFIG_DMI) && defined(CONFIG_X86) - { - .ident = "Teclast X89", - .matches = { - /* tPAD is too generic, also match on bios date */ - DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), - DMI_MATCH(DMI_BOARD_NAME, "tPAD"), - DMI_MATCH(DMI_BIOS_DATE, "12/19/2014"), - }, - }, - { - .ident = "Teclast X98 Pro", - .matches = { - /* - * Only match BIOS date, because the manufacturers - * BIOS does not report the board name at all - * (sometimes)... - */ - DMI_MATCH(DMI_BOARD_VENDOR, "TECLAST"), - DMI_MATCH(DMI_BIOS_DATE, "10/28/2015"), - }, - }, - { - .ident = "WinBook TW100", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "WinBook"), - DMI_MATCH(DMI_PRODUCT_NAME, "TW100") - } - }, - { - .ident = "WinBook TW700", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "WinBook"), - DMI_MATCH(DMI_PRODUCT_NAME, "TW700") - }, - }, -#endif - {} -}; - static const struct dmi_system_id nine_bytes_report[] = { #if defined(CONFIG_DMI) && defined(CONFIG_X86) { @@ -342,6 +297,108 @@ static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data) return -ENOMSG; } +static struct input_dev *goodix_create_pen_input(struct goodix_ts_data *ts) +{ + struct device *dev = &ts->client->dev; + struct input_dev *input; + + input = devm_input_allocate_device(dev); + if (!input) + return NULL; + + input_alloc_absinfo(input); + if (!input->absinfo) { + input_free_device(input); + return NULL; + } + + input->absinfo[ABS_X] = ts->input_dev->absinfo[ABS_MT_POSITION_X]; + input->absinfo[ABS_Y] = ts->input_dev->absinfo[ABS_MT_POSITION_Y]; + __set_bit(ABS_X, input->absbit); + __set_bit(ABS_Y, input->absbit); + input_set_abs_params(input, ABS_PRESSURE, 0, 255, 0, 0); + + input_set_capability(input, EV_KEY, BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOOL_PEN); + input_set_capability(input, EV_KEY, BTN_STYLUS); + input_set_capability(input, EV_KEY, BTN_STYLUS2); + __set_bit(INPUT_PROP_DIRECT, input->propbit); + /* + * The resolution of these touchscreens is about 10 units/mm, the actual + * resolution does not matter much since we set INPUT_PROP_DIRECT. + * Userspace wants something here though, so just set it to 10 units/mm. + */ + input_abs_set_res(input, ABS_X, 10); + input_abs_set_res(input, ABS_Y, 10); + + input->name = "Goodix Active Pen"; + input->phys = "input/pen"; + input->id.bustype = BUS_I2C; + input->id.vendor = 0x0416; + if (kstrtou16(ts->id, 10, &input->id.product)) + input->id.product = 0x1001; + input->id.version = ts->version; + + if (input_register_device(input) != 0) { + input_free_device(input); + return NULL; + } + + return input; +} + +static void goodix_ts_report_pen_down(struct goodix_ts_data *ts, u8 *data) +{ + int input_x, input_y, input_w; + u8 key_value; + + if (!ts->input_pen) { + ts->input_pen = goodix_create_pen_input(ts); + if (!ts->input_pen) + return; + } + + if (ts->contact_size == 9) { + input_x = get_unaligned_le16(&data[4]); + input_y = get_unaligned_le16(&data[6]); + input_w = get_unaligned_le16(&data[8]); + } else { + input_x = get_unaligned_le16(&data[2]); + input_y = get_unaligned_le16(&data[4]); + input_w = get_unaligned_le16(&data[6]); + } + + touchscreen_report_pos(ts->input_pen, &ts->prop, input_x, input_y, false); + input_report_abs(ts->input_pen, ABS_PRESSURE, input_w); + + input_report_key(ts->input_pen, BTN_TOUCH, 1); + input_report_key(ts->input_pen, BTN_TOOL_PEN, 1); + + if (data[0] & GOODIX_HAVE_KEY) { + key_value = data[1 + ts->contact_size]; + input_report_key(ts->input_pen, BTN_STYLUS, key_value & 0x10); + input_report_key(ts->input_pen, BTN_STYLUS2, key_value & 0x20); + } else { + input_report_key(ts->input_pen, BTN_STYLUS, 0); + input_report_key(ts->input_pen, BTN_STYLUS2, 0); + } + + input_sync(ts->input_pen); +} + +static void goodix_ts_report_pen_up(struct goodix_ts_data *ts) +{ + if (!ts->input_pen) + return; + + input_report_key(ts->input_pen, BTN_TOUCH, 0); + input_report_key(ts->input_pen, BTN_TOOL_PEN, 0); + input_report_key(ts->input_pen, BTN_STYLUS, 0); + input_report_key(ts->input_pen, BTN_STYLUS2, 0); + + input_sync(ts->input_pen); +} + static void goodix_ts_report_touch_8b(struct goodix_ts_data *ts, u8 *coor_data) { int id = coor_data[0] & 0x0F; @@ -372,6 +429,14 @@ static void goodix_ts_report_touch_9b(struct goodix_ts_data *ts, u8 *coor_data) input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, input_w); } +static void goodix_ts_release_keys(struct goodix_ts_data *ts) +{ + int i; + + for (i = 0; i < GOODIX_MAX_KEYS; i++) + input_report_key(ts->input_dev, ts->keymap[i], 0); +} + static void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data) { int touch_num; @@ -386,8 +451,7 @@ static void goodix_ts_report_key(struct goodix_ts_data *ts, u8 *data) input_report_key(ts->input_dev, ts->keymap[i], 1); } else { - for (i = 0; i < GOODIX_MAX_KEYS; i++) - input_report_key(ts->input_dev, ts->keymap[i], 0); + goodix_ts_release_keys(ts); } } @@ -409,6 +473,15 @@ static void goodix_process_events(struct goodix_ts_data *ts) if (touch_num < 0) return; + /* The pen being down is always reported as a single touch */ + if (touch_num == 1 && (point_data[1] & 0x80)) { + goodix_ts_report_pen_down(ts, point_data); + goodix_ts_release_keys(ts); + goto sync; /* Release any previously registered touches */ + } else { + goodix_ts_report_pen_up(ts); + } + goodix_ts_report_key(ts, point_data); for (i = 0; i < touch_num; i++) @@ -419,6 +492,7 @@ static void goodix_process_events(struct goodix_ts_data *ts) goodix_ts_report_touch_8b(ts, &point_data[1 + ts->contact_size * i]); +sync: input_mt_sync_frame(ts->input_dev); input_sync(ts->input_dev); } @@ -902,7 +976,7 @@ retry_get_irq_gpio: if (IS_ERR(gpiod)) { error = PTR_ERR(gpiod); if (error != -EPROBE_DEFER) - dev_dbg(dev, "Failed to get %s GPIO: %d\n", + dev_err(dev, "Failed to get %s GPIO: %d\n", GOODIX_GPIO_INT_NAME, error); return error; } @@ -919,7 +993,7 @@ retry_get_irq_gpio: if (IS_ERR(gpiod)) { error = PTR_ERR(gpiod); if (error != -EPROBE_DEFER) - dev_dbg(dev, "Failed to get %s GPIO: %d\n", + dev_err(dev, "Failed to get %s GPIO: %d\n", GOODIX_GPIO_RST_NAME, error); return error; } @@ -1113,13 +1187,6 @@ static int goodix_configure_dev(struct goodix_ts_data *ts) ABS_MT_POSITION_Y, ts->prop.max_y); } - if (dmi_check_system(rotated_screen)) { - ts->prop.invert_x = true; - ts->prop.invert_y = true; - dev_dbg(&ts->client->dev, - "Applying '180 degrees rotated screen' quirk\n"); - } - if (dmi_check_system(nine_bytes_report)) { ts->contact_size = 9; diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h index 02065d1c3263..fa8602e78a64 100644 --- a/drivers/input/touchscreen/goodix.h +++ b/drivers/input/touchscreen/goodix.h @@ -76,6 +76,7 @@ struct goodix_chip_data { struct goodix_ts_data { struct i2c_client *client; struct input_dev *input_dev; + struct input_dev *input_pen; const struct goodix_chip_data *chip; const char *firmware_name; struct touchscreen_properties prop; diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index 1ee760bac0cf..3eef8c01090f 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -67,6 +67,7 @@ struct silead_ts_data { struct i2c_client *client; struct gpio_desc *gpio_power; struct input_dev *input; + struct input_dev *pen_input; struct regulator_bulk_data regulators[2]; char fw_name[64]; struct touchscreen_properties prop; @@ -75,6 +76,13 @@ struct silead_ts_data { struct input_mt_pos pos[SILEAD_MAX_FINGERS]; int slots[SILEAD_MAX_FINGERS]; int id[SILEAD_MAX_FINGERS]; + u32 efi_fw_min_max[4]; + bool efi_fw_min_max_set; + bool pen_supported; + bool pen_down; + u32 pen_x_res; + u32 pen_y_res; + int pen_up_count; }; struct silead_fw_data { @@ -82,6 +90,35 @@ struct silead_fw_data { u32 val; }; +static void silead_apply_efi_fw_min_max(struct silead_ts_data *data) +{ + struct input_absinfo *absinfo_x = &data->input->absinfo[ABS_MT_POSITION_X]; + struct input_absinfo *absinfo_y = &data->input->absinfo[ABS_MT_POSITION_Y]; + + if (!data->efi_fw_min_max_set) + return; + + absinfo_x->minimum = data->efi_fw_min_max[0]; + absinfo_x->maximum = data->efi_fw_min_max[1]; + absinfo_y->minimum = data->efi_fw_min_max[2]; + absinfo_y->maximum = data->efi_fw_min_max[3]; + + if (data->prop.invert_x) { + absinfo_x->maximum -= absinfo_x->minimum; + absinfo_x->minimum = 0; + } + + if (data->prop.invert_y) { + absinfo_y->maximum -= absinfo_y->minimum; + absinfo_y->minimum = 0; + } + + if (data->prop.swap_x_y) { + swap(absinfo_x->minimum, absinfo_y->minimum); + swap(absinfo_x->maximum, absinfo_y->maximum); + } +} + static int silead_ts_request_input_dev(struct silead_ts_data *data) { struct device *dev = &data->client->dev; @@ -97,6 +134,7 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data) input_set_abs_params(data->input, ABS_MT_POSITION_X, 0, 4095, 0, 0); input_set_abs_params(data->input, ABS_MT_POSITION_Y, 0, 4095, 0, 0); touchscreen_parse_properties(data->input, true, &data->prop); + silead_apply_efi_fw_min_max(data); input_mt_init_slots(data->input, data->max_fingers, INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED | @@ -112,6 +150,40 @@ static int silead_ts_request_input_dev(struct silead_ts_data *data) error = input_register_device(data->input); if (error) { dev_err(dev, "Failed to register input device: %d\n", error); + return error; + } + + return 0; +} + +static int silead_ts_request_pen_input_dev(struct silead_ts_data *data) +{ + struct device *dev = &data->client->dev; + int error; + + if (!data->pen_supported) + return 0; + + data->pen_input = devm_input_allocate_device(dev); + if (!data->pen_input) + return -ENOMEM; + + input_set_abs_params(data->pen_input, ABS_X, 0, 4095, 0, 0); + input_set_abs_params(data->pen_input, ABS_Y, 0, 4095, 0, 0); + input_set_capability(data->pen_input, EV_KEY, BTN_TOUCH); + input_set_capability(data->pen_input, EV_KEY, BTN_TOOL_PEN); + set_bit(INPUT_PROP_DIRECT, data->pen_input->propbit); + touchscreen_parse_properties(data->pen_input, false, &data->prop); + input_abs_set_res(data->pen_input, ABS_X, data->pen_x_res); + input_abs_set_res(data->pen_input, ABS_Y, data->pen_y_res); + + data->pen_input->name = SILEAD_TS_NAME " pen"; + data->pen_input->phys = "input/pen"; + data->input->id.bustype = BUS_I2C; + + error = input_register_device(data->pen_input); + if (error) { + dev_err(dev, "Failed to register pen input device: %d\n", error); return error; } @@ -129,6 +201,45 @@ static void silead_ts_set_power(struct i2c_client *client, } } +static bool silead_ts_handle_pen_data(struct silead_ts_data *data, u8 *buf) +{ + u8 *coord = buf + SILEAD_POINT_DATA_LEN; + struct input_mt_pos pos; + + if (!data->pen_supported || buf[2] != 0x00 || buf[3] != 0x00) + return false; + + if (buf[0] == 0x00 && buf[1] == 0x00 && data->pen_down) { + data->pen_up_count++; + if (data->pen_up_count == 6) { + data->pen_down = false; + goto sync; + } + return true; + } + + if (buf[0] == 0x01 && buf[1] == 0x08) { + touchscreen_set_mt_pos(&pos, &data->prop, + get_unaligned_le16(&coord[SILEAD_POINT_X_OFF]) & 0xfff, + get_unaligned_le16(&coord[SILEAD_POINT_Y_OFF]) & 0xfff); + + input_report_abs(data->pen_input, ABS_X, pos.x); + input_report_abs(data->pen_input, ABS_Y, pos.y); + + data->pen_up_count = 0; + data->pen_down = true; + goto sync; + } + + return false; + +sync: + input_report_key(data->pen_input, BTN_TOOL_PEN, data->pen_down); + input_report_key(data->pen_input, BTN_TOUCH, data->pen_down); + input_sync(data->pen_input); + return true; +} + static void silead_ts_read_data(struct i2c_client *client) { struct silead_ts_data *data = i2c_get_clientdata(client); @@ -151,6 +262,9 @@ static void silead_ts_read_data(struct i2c_client *client) buf[0] = data->max_fingers; } + if (silead_ts_handle_pen_data(data, buf)) + goto sync; /* Pen is down, release all previous touches */ + touch_nr = 0; bufp = buf + SILEAD_POINT_DATA_LEN; for (i = 0; i < buf[0]; i++, bufp += SILEAD_POINT_DATA_LEN) { @@ -193,6 +307,7 @@ static void silead_ts_read_data(struct i2c_client *client) data->pos[i].y, data->id[i], data->slots[i]); } +sync: input_mt_sync_frame(input); input_report_key(input, KEY_LEFTMETA, softbutton_pressed); input_sync(input); @@ -282,17 +397,56 @@ static int silead_ts_load_fw(struct i2c_client *client) { struct device *dev = &client->dev; struct silead_ts_data *data = i2c_get_clientdata(client); - unsigned int fw_size, i; - const struct firmware *fw; + const struct firmware *fw = NULL; struct silead_fw_data *fw_data; + unsigned int fw_size, i; int error; dev_dbg(dev, "Firmware file name: %s", data->fw_name); - error = firmware_request_platform(&fw, data->fw_name, dev); + /* + * Unfortunately, at the time of writing this comment, we have been unable to + * get permission from Silead, or from device OEMs, to distribute the necessary + * Silead firmware files in linux-firmware. + * + * On a whole bunch of devices the UEFI BIOS code contains a touchscreen driver, + * which contains an embedded copy of the firmware. The fw-loader code has a + * "platform" fallback mechanism, which together with info on the firmware + * from drivers/platform/x86/touchscreen_dmi.c will use the firmware from the + * UEFI driver when the firmware is missing from /lib/firmware. This makes the + * touchscreen work OOTB without users needing to manually download the firmware. + * + * The firmware bundled with the original Windows/Android is usually newer then + * the firmware in the UEFI driver and it is better calibrated. This better + * calibration can lead to significant differences in the reported min/max + * coordinates. + * + * To deal with this we first try to load the firmware without "platform" + * fallback. If that fails we retry with "platform" fallback and if that + * succeeds we apply an (optional) set of alternative min/max values from the + * "silead,efi-fw-min-max" property. + */ + error = firmware_request_nowarn(&fw, data->fw_name, dev); if (error) { - dev_err(dev, "Firmware request error %d\n", error); - return error; + error = firmware_request_platform(&fw, data->fw_name, dev); + if (error) { + dev_err(dev, "Firmware request error %d\n", error); + return error; + } + + error = device_property_read_u32_array(dev, "silead,efi-fw-min-max", + data->efi_fw_min_max, + ARRAY_SIZE(data->efi_fw_min_max)); + if (!error) + data->efi_fw_min_max_set = true; + + /* The EFI (platform) embedded fw does not have pen support */ + if (data->pen_supported) { + dev_warn(dev, "Warning loading '%s' from filesystem failed, using EFI embedded copy.\n", + data->fw_name); + dev_warn(dev, "Warning pen support is known to be broken in the EFI embedded fw version\n"); + data->pen_supported = false; + } } fw_size = fw->size / sizeof(*fw_data); @@ -450,6 +604,10 @@ static void silead_ts_read_props(struct i2c_client *client) "silead/%s", str); else dev_dbg(dev, "Firmware file name read error. Using default."); + + data->pen_supported = device_property_read_bool(dev, "silead,pen-supported"); + device_property_read_u32(dev, "silead,pen-resolution-x", &data->pen_x_res); + device_property_read_u32(dev, "silead,pen-resolution-y", &data->pen_y_res); } #ifdef CONFIG_ACPI @@ -562,6 +720,10 @@ static int silead_ts_probe(struct i2c_client *client, if (error) return error; + error = silead_ts_request_pen_input_dev(data); + if (error) + return error; + error = devm_request_threaded_irq(dev, client->irq, NULL, silead_ts_threaded_irq_handler, IRQF_ONESHOT, client->name, data); diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c index 83e685557a19..f2fb6a9a1a57 100644 --- a/drivers/input/touchscreen/ti_am335x_tsc.c +++ b/drivers/input/touchscreen/ti_am335x_tsc.c @@ -126,12 +126,13 @@ static int titsc_config_wires(struct titsc *ts_dev) static void titsc_step_config(struct titsc *ts_dev) { unsigned int config; - int i; + int i, n; int end_step, first_step, tsc_steps; u32 stepenable; config = STEPCONFIG_MODE_HWSYNC | - STEPCONFIG_AVG_16 | ts_dev->bit_xp; + STEPCONFIG_AVG_16 | ts_dev->bit_xp | + STEPCONFIG_INM_ADCREFM; switch (ts_dev->wires) { case 4: config |= STEPCONFIG_INP(ts_dev->inp_yp) | ts_dev->bit_xn; @@ -150,9 +151,11 @@ static void titsc_step_config(struct titsc *ts_dev) first_step = TOTAL_STEPS - tsc_steps; /* Steps 16 to 16-coordinate_readouts is for X */ end_step = first_step + tsc_steps; + n = 0; for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) { titsc_writel(ts_dev, REG_STEPCONFIG(i), config); - titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); + titsc_writel(ts_dev, REG_STEPDELAY(i), + n++ == 0 ? STEPCONFIG_OPENDLY : 0); } config = 0; @@ -174,9 +177,11 @@ static void titsc_step_config(struct titsc *ts_dev) /* 1 ... coordinate_readouts is for Y */ end_step = first_step + ts_dev->coordinate_readouts; + n = 0; for (i = first_step; i < end_step; i++) { titsc_writel(ts_dev, REG_STEPCONFIG(i), config); - titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY); + titsc_writel(ts_dev, REG_STEPDELAY(i), + n++ == 0 ? STEPCONFIG_OPENDLY : 0); } /* Make CHARGECONFIG same as IDLECONFIG */ @@ -195,7 +200,10 @@ static void titsc_step_config(struct titsc *ts_dev) STEPCONFIG_OPENDLY); end_step++; - config |= STEPCONFIG_INP(ts_dev->inp_yn); + config = STEPCONFIG_MODE_HWSYNC | + STEPCONFIG_AVG_16 | ts_dev->bit_yp | + ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM | + STEPCONFIG_INP(ts_dev->inp_yn); titsc_writel(ts_dev, REG_STEPCONFIG(end_step), config); titsc_writel(ts_dev, REG_STEPDELAY(end_step), STEPCONFIG_OPENDLY); @@ -310,7 +318,7 @@ static irqreturn_t titsc_irq(int irq, void *dev) /* * Calculate pressure using formula * Resistance(touch) = x plate resistance * - * x postion/4096 * ((z2 / z1) - 1) + * x position/4096 * ((z2 / z1) - 1) */ z = z1 - z2; z *= x; diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index e3f2c940ef3d..dfd3b35590c3 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c @@ -186,7 +186,6 @@ static irqreturn_t ucb1400_irq(int irqnr, void *devid) { struct ucb1400_ts *ucb = devid; unsigned int x, y, p; - bool penup; if (unlikely(irqnr != ucb->irq)) return IRQ_NONE; @@ -196,8 +195,7 @@ static irqreturn_t ucb1400_irq(int irqnr, void *devid) /* Start with a small delay before checking pendown state */ msleep(UCB1400_TS_POLL_PERIOD); - while (!ucb->stopped && !(penup = ucb1400_ts_pen_up(ucb))) { - + while (!ucb->stopped && !ucb1400_ts_pen_up(ucb)) { ucb1400_adc_enable(ucb->ac97); x = ucb1400_ts_read_xpos(ucb); y = ucb1400_ts_read_ypos(ucb); diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index fe4ea6204a4e..141754b2764c 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -24,12 +24,19 @@ #define WACOM_IN_PROXIMITY BIT(5) /* Registers */ -#define WACOM_CMD_QUERY0 0x04 -#define WACOM_CMD_QUERY1 0x00 -#define WACOM_CMD_QUERY2 0x33 -#define WACOM_CMD_QUERY3 0x02 -#define WACOM_CMD_THROW0 0x05 -#define WACOM_CMD_THROW1 0x00 +#define WACOM_COMMAND_LSB 0x04 +#define WACOM_COMMAND_MSB 0x00 + +#define WACOM_DATA_LSB 0x05 +#define WACOM_DATA_MSB 0x00 + +/* Report types */ +#define REPORT_FEATURE 0x30 + +/* Requests / operations */ +#define OPCODE_GET_REPORT 0x02 + +#define WACOM_QUERY_REPORT 3 #define WACOM_QUERY_SIZE 19 struct wacom_features { @@ -50,23 +57,24 @@ struct wacom_i2c { static int wacom_query_device(struct i2c_client *client, struct wacom_features *features) { - int ret; - u8 cmd1[] = { WACOM_CMD_QUERY0, WACOM_CMD_QUERY1, - WACOM_CMD_QUERY2, WACOM_CMD_QUERY3 }; - u8 cmd2[] = { WACOM_CMD_THROW0, WACOM_CMD_THROW1 }; + u8 get_query_data_cmd[] = { + WACOM_COMMAND_LSB, + WACOM_COMMAND_MSB, + REPORT_FEATURE | WACOM_QUERY_REPORT, + OPCODE_GET_REPORT, + WACOM_DATA_LSB, + WACOM_DATA_MSB, + }; u8 data[WACOM_QUERY_SIZE]; + int ret; + struct i2c_msg msgs[] = { + /* Request reading of feature ReportID: 3 (Pen Query Data) */ { .addr = client->addr, .flags = 0, - .len = sizeof(cmd1), - .buf = cmd1, - }, - { - .addr = client->addr, - .flags = 0, - .len = sizeof(cmd2), - .buf = cmd2, + .len = sizeof(get_query_data_cmd), + .buf = get_query_data_cmd, }, { .addr = client->addr, diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index 1e70b8d2a8d7..7c82c4f5fa6b 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -252,16 +252,27 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541) static int zinitix_init_regulators(struct bt541_ts_data *bt541) { - struct i2c_client *client = bt541->client; + struct device *dev = &bt541->client->dev; int error; - bt541->supplies[0].supply = "vdd"; - bt541->supplies[1].supply = "vddo"; - error = devm_regulator_bulk_get(&client->dev, + /* + * Some older device trees have erroneous names for the regulators, + * 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)) { + bt541->supplies[0].supply = "vdd"; + bt541->supplies[1].supply = "vddo"; + } else { + /* Else use the proper supply names */ + bt541->supplies[0].supply = "vcca"; + bt541->supplies[1].supply = "vdd"; + } + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(bt541->supplies), bt541->supplies); if (error < 0) { - dev_err(&client->dev, "Failed to get regulators: %d\n", error); + dev_err(dev, "Failed to get regulators: %d\n", error); return error; } @@ -560,6 +571,7 @@ static SIMPLE_DEV_PM_OPS(zinitix_pm_ops, zinitix_suspend, zinitix_resume); #ifdef CONFIG_OF static const struct of_device_id zinitix_of_match[] = { + { .compatible = "zinitix,bt532" }, { .compatible = "zinitix,bt541" }, { } }; |