diff options
Diffstat (limited to 'drivers/input')
133 files changed, 4087 insertions, 985 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 735f90b74ee5..3bdbd34314b3 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -168,7 +168,7 @@ config INPUT_EVBUG config INPUT_KUNIT_TEST tristate "KUnit tests for Input" if !KUNIT_ALL_TESTS - depends on INPUT && KUNIT=y + depends on INPUT && KUNIT default KUNIT_ALL_TESTS help Say Y here if you want to build the KUnit tests for the input diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig index 5a2c2fb3217d..fe73b26e647a 100644 --- a/drivers/input/gameport/Kconfig +++ b/drivers/input/gameport/Kconfig @@ -25,6 +25,7 @@ if GAMEPORT config GAMEPORT_NS558 tristate "Classic ISA and PnP gameport support" + depends on ISA help Say Y here if you have an ISA or PnP gameport. @@ -35,6 +36,7 @@ config GAMEPORT_NS558 config GAMEPORT_L4 tristate "PDPI Lightning 4 gamecard support" + depends on ISA help Say Y here if you have a PDPI Lightning 4 gamecard. @@ -53,7 +55,7 @@ config GAMEPORT_EMU10K1 config GAMEPORT_FM801 tristate "ForteMedia FM801 gameport support" - depends on PCI + depends on PCI && HAS_IOPORT help Say Y here if you have ForteMedia FM801 PCI audio controller (Abit AU10, Genius Sound Maker, HP Workstation zx2000, diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c index db58a01b23d3..34f416a3ebcb 100644 --- a/drivers/input/gameport/gameport.c +++ b/drivers/input/gameport/gameport.c @@ -11,6 +11,7 @@ #include <linux/stddef.h> #include <linux/module.h> +#include <linux/io.h> #include <linux/ioport.h> #include <linux/init.h> #include <linux/gameport.h> @@ -21,8 +22,6 @@ #include <linux/mutex.h> #include <linux/timekeeping.h> -/*#include <asm/io.h>*/ - MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); MODULE_DESCRIPTION("Generic gameport layer"); MODULE_LICENSE("GPL"); @@ -518,6 +517,36 @@ void gameport_set_phys(struct gameport *gameport, const char *fmt, ...) } EXPORT_SYMBOL(gameport_set_phys); +static void gameport_default_trigger(struct gameport *gameport) +{ +#ifdef CONFIG_HAS_IOPORT + outb(0xff, gameport->io); +#endif +} + +static unsigned char gameport_default_read(struct gameport *gameport) +{ +#ifdef CONFIG_HAS_IOPORT + return inb(gameport->io); +#else + return 0xff; +#endif +} + +static void gameport_setup_default_handlers(struct gameport *gameport) +{ + if ((!gameport->trigger || !gameport->read) && + !IS_ENABLED(CONFIG_HAS_IOPORT)) + dev_err(&gameport->dev, + "I/O port access is required for %s (%s) but is not available\n", + gameport->phys, gameport->name); + + if (!gameport->trigger) + gameport->trigger = gameport_default_trigger; + if (!gameport->read) + gameport->read = gameport_default_read; +} + /* * Prepare gameport port for registration. */ @@ -536,6 +565,7 @@ static void gameport_init_port(struct gameport *gameport) if (gameport->parent) gameport->dev.parent = &gameport->parent->dev; + gameport_setup_default_handlers(gameport); INIT_LIST_HEAD(&gameport->node); spin_lock_init(&gameport->timer_lock); timer_setup(&gameport->poll_timer, gameport_run_poll_handler, 0); diff --git a/drivers/input/input.c b/drivers/input/input.c index 641eb86f276e..8c5fdb0f858a 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -190,6 +190,7 @@ static int input_handle_abs_event(struct input_dev *dev, unsigned int code, int *pval) { struct input_mt *mt = dev->mt; + bool is_new_slot = false; bool is_mt_event; int *pold; @@ -210,6 +211,7 @@ static int input_handle_abs_event(struct input_dev *dev, pold = &dev->absinfo[code].value; } else if (mt) { pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST]; + is_new_slot = mt->slot != dev->absinfo[ABS_MT_SLOT].value; } else { /* * Bypass filtering for multi-touch events when @@ -228,8 +230,8 @@ static int input_handle_abs_event(struct input_dev *dev, } /* Flush pending "slot" event */ - if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { - input_abs_set_val(dev, ABS_MT_SLOT, mt->slot); + if (is_new_slot) { + dev->absinfo[ABS_MT_SLOT].value = mt->slot; return INPUT_PASS_TO_HANDLERS | INPUT_SLOT; } diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 04ca3d1c2816..ac6925ce8366 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -292,33 +292,33 @@ config JOYSTICK_JOYDUMP module will be called joydump. config JOYSTICK_XPAD - tristate "X-Box gamepad support" + tristate "Xbox gamepad support" depends on USB_ARCH_HAS_HCD select USB help - Say Y here if you want to use the X-Box pad with your computer. + Say Y here if you want to use Xbox pads with your computer. Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV) and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. - For information about how to connect the X-Box pad to USB, see + For information about how to connect the Xbox pad to USB, see <file:Documentation/input/devices/xpad.rst>. To compile this driver as a module, choose M here: the module will be called xpad. config JOYSTICK_XPAD_FF - bool "X-Box gamepad rumble support" + bool "Xbox gamepad rumble support" depends on JOYSTICK_XPAD && INPUT select INPUT_FF_MEMLESS help - Say Y here if you want to take advantage of xbox 360 rumble features. + Say Y here if you want to take advantage of Xbox 360 rumble features. config JOYSTICK_XPAD_LEDS - bool "LED Support for Xbox360 controller 'BigX' LED" + bool "LED Support for the Xbox 360 controller Guide button" depends on JOYSTICK_XPAD && (LEDS_CLASS=y || LEDS_CLASS=JOYSTICK_XPAD) help This option enables support for the LED which surrounds the Big X on - XBox 360 controller. + Xbox 360 controllers. config JOYSTICK_WALKERA0701 tristate "Walkera WK-0701 RC transmitter" diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c index 3b88f0b49e01..bf8b1cc0ea9c 100644 --- a/drivers/input/joystick/as5011.c +++ b/drivers/input/joystick/as5011.c @@ -348,7 +348,7 @@ static struct i2c_driver as5011_driver = { .driver = { .name = "as5011", }, - .probe_new = as5011_probe, + .probe = as5011_probe, .remove = as5011_remove, .id_table = as5011_id, }; diff --git a/drivers/input/joystick/qwiic-joystick.c b/drivers/input/joystick/qwiic-joystick.c index d4da31c0616c..7d88d76b14d6 100644 --- a/drivers/input/joystick/qwiic-joystick.c +++ b/drivers/input/joystick/qwiic-joystick.c @@ -137,7 +137,7 @@ static struct i2c_driver qwiic_driver = { .of_match_table = of_match_ptr(of_qwiic_match), }, .id_table = qwiic_id_table, - .probe_new = qwiic_probe, + .probe = qwiic_probe, }; module_i2c_driver(qwiic_driver); diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index f33622fe946f..ede380551e55 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * X-Box gamepad driver + * Xbox gamepad driver * * Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de> * 2004 Oliver Schwartz <Oliver.Schwartz@gmx.de>, @@ -23,8 +23,8 @@ * - ITO Takayuki for providing essential xpad information on his website * - Vojtech Pavlik - iforce driver / input subsystem * - Greg Kroah-Hartman - usb-skeleton driver - * - XBOX Linux project - extra USB id's - * - Pekka Pöyry (quantus) - Xbox One controller reverse engineering + * - Xbox Linux project - extra USB IDs + * - Pekka Pöyry (quantus) - Xbox One controller reverse-engineering * * TODO: * - fine tune axes (especially trigger axes) @@ -52,7 +52,7 @@ * 2002-07-17 - 0.0.5 : simplified d-pad handling * * 2004-10-02 - 0.0.6 : DDR pad support - * - borrowed from the XBOX linux kernel + * - borrowed from the Xbox Linux kernel * - USB id's for commonly used dance pads are present * - dance pads will map D-PAD to buttons, not axes * - pass the module paramater 'dpad_to_buttons' to force @@ -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 }, @@ -365,6 +366,7 @@ static const struct xpad_device { { 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 }, { 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 }, { 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 }, + { 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 }, { 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX }, { 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX }, { 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN } @@ -454,51 +456,53 @@ static const signed short xpad_btn_paddles[] = { { XPAD_XBOXONE_VENDOR_PROTOCOL((vend), 208) } static const struct usb_device_id xpad_table[] = { - { USB_INTERFACE_INFO('X', 'B', 0) }, /* X-Box USB-IF not approved class */ - XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 Controller */ + { USB_INTERFACE_INFO('X', 'B', 0) }, /* Xbox USB-IF not-approved class */ + XPAD_XBOX360_VENDOR(0x0079), /* GPD Win 2 controller */ XPAD_XBOX360_VENDOR(0x03eb), /* Wooting Keyboards (Legacy) */ - XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster X-Box 360 controllers */ - XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */ - XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */ - XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ + XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster Xbox 360 controllers */ + XPAD_XBOX360_VENDOR(0x045e), /* Microsoft Xbox 360 controllers */ + XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft Xbox One controllers */ + XPAD_XBOX360_VENDOR(0x046d), /* Logitech Xbox 360-style controllers */ XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */ XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */ - XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz Xbox 360 controllers */ { USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */ XPAD_XBOXONE_VENDOR(0x0738), /* Mad Catz FightStick TE 2 */ - XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz GamePad */ + XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz Gamepad */ XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */ - XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ - XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f X-Box One controllers */ - XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ - XPAD_XBOXONE_VENDOR(0x0f0d), /* Hori Controllers */ - XPAD_XBOX360_VENDOR(0x1038), /* SteelSeries Controllers */ + XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f Xbox 360 controllers */ + XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f Xbox One controllers */ + 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 */ - XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ - XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ + XPAD_XBOX360_VENDOR(0x12ab), /* Xbox 360 dance pads */ + XPAD_XBOX360_VENDOR(0x1430), /* RedOctane Xbox 360 controllers */ + XPAD_XBOX360_VENDOR(0x146b), /* Bigben Interactive controllers */ XPAD_XBOX360_VENDOR(0x1532), /* Razer Sabertooth */ XPAD_XBOXONE_VENDOR(0x1532), /* Razer Wildcat */ - XPAD_XBOX360_VENDOR(0x15e4), /* Numark X-Box 360 controllers */ - XPAD_XBOX360_VENDOR(0x162e), /* Joytech X-Box 360 controllers */ + XPAD_XBOX360_VENDOR(0x15e4), /* Numark Xbox 360 controllers */ + XPAD_XBOX360_VENDOR(0x162e), /* Joytech Xbox 360 controllers */ XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */ XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */ - XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */ - XPAD_XBOX360_VENDOR(0x20d6), /* PowerA Controllers */ - XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA Controllers */ - XPAD_XBOX360_VENDOR(0x24c6), /* PowerA Controllers */ - XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA Controllers */ + XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */ + XPAD_XBOX360_VENDOR(0x20d6), /* PowerA controllers */ + XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA controllers */ + XPAD_XBOX360_VENDOR(0x24c6), /* PowerA controllers */ + 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 */ - XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */ + XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Duke Xbox One pad */ + XPAD_XBOX360_VENDOR(0x2f24), /* GameSir controllers */ XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */ XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */ + XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */ + XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */ { } }; @@ -724,7 +728,7 @@ static void xpad360w_poweroff_controller(struct usb_xpad *xpad); * Completes a request by converting the data into events for the * input subsystem. * - * The used report descriptor was taken from ITO Takayukis website: + * The used report descriptor was taken from ITO Takayuki's website: * http://euc.jp/periphs/xbox-controller.ja.html */ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data) @@ -1569,7 +1573,7 @@ struct xpad_led { }; /* - * set the LEDs on Xbox360 / Wireless Controllers + * set the LEDs on Xbox 360 / Wireless Controllers * @param command * 0: off * 1: all blink, then previous setting @@ -1720,6 +1724,27 @@ static int xpad_start_input(struct usb_xpad *xpad) return error; } } + 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(xpad->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); + } return 0; } @@ -2229,5 +2254,5 @@ static struct usb_driver xpad_driver = { module_usb_driver(xpad_driver); MODULE_AUTHOR("Marko Friedemann <mfr@bmx-chemnitz.de>"); -MODULE_DESCRIPTION("X-Box pad driver"); +MODULE_DESCRIPTION("Xbox pad driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c index 72ae5ce72956..61e8e43e9c2b 100644 --- a/drivers/input/keyboard/adp5588-keys.c +++ b/drivers/input/keyboard/adp5588-keys.c @@ -713,17 +713,11 @@ static int adp5588_fw_parse(struct adp5588_kpad *kpad) return 0; } -static void adp5588_disable_regulator(void *reg) -{ - regulator_disable(reg); -} - static int adp5588_probe(struct i2c_client *client) { struct adp5588_kpad *kpad; struct input_dev *input; struct gpio_desc *gpio; - struct regulator *vcc; unsigned int revid; int ret; int error; @@ -749,16 +743,7 @@ static int adp5588_probe(struct i2c_client *client) if (error) return error; - vcc = devm_regulator_get(&client->dev, "vcc"); - if (IS_ERR(vcc)) - return PTR_ERR(vcc); - - error = regulator_enable(vcc); - if (error) - return error; - - error = devm_add_action_or_reset(&client->dev, - adp5588_disable_regulator, vcc); + error = devm_regulator_get_enable(&client->dev, "vcc"); if (error) return error; @@ -866,7 +851,7 @@ static struct i2c_driver adp5588_driver = { .of_match_table = adp5588_of_match, .pm = pm_sleep_ptr(&adp5588_dev_pm_ops), }, - .probe_new = adp5588_probe, + .probe = adp5588_probe, .remove = adp5588_remove, .id_table = adp5588_id, }; diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 38d7073863a8..8996e00cd63a 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1054,7 +1054,7 @@ static struct i2c_driver adp5589_driver = { .name = KBUILD_MODNAME, .pm = pm_sleep_ptr(&adp5589_dev_pm_ops), }, - .probe_new = adp5589_probe, + .probe = adp5589_probe, .id_table = adp5589_id, }; diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c index 246958795f60..c92e544c792d 100644 --- a/drivers/input/keyboard/atkbd.c +++ b/drivers/input/keyboard/atkbd.c @@ -309,12 +309,19 @@ static ssize_t atkbd_show_function_row_physmap(struct atkbd *atkbd, char *buf) return vivaldi_function_row_physmap_show(&atkbd->vdata, buf); } +static struct atkbd *atkbd_from_serio(struct serio *serio) +{ + struct ps2dev *ps2dev = serio_get_drvdata(serio); + + return container_of(ps2dev, struct atkbd, ps2dev); +} + static umode_t atkbd_attr_is_visible(struct kobject *kobj, struct attribute *attr, int i) { struct device *dev = kobj_to_dev(kobj); struct serio *serio = to_serio_port(dev); - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); if (attr == &atkbd_attr_function_row_physmap.attr && !atkbd->vdata.num_function_row_keys) @@ -392,46 +399,60 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code } /* - * atkbd_interrupt(). Here takes place processing of data received from - * the keyboard into events. + * Tries to handle frame or parity error by requesting the keyboard controller + * to resend the last byte. This historically not done on x86 as controllers + * there typically do not implement this command. */ - -static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, - unsigned int flags) +static bool __maybe_unused atkbd_handle_frame_error(struct ps2dev *ps2dev, + u8 data, unsigned int flags) { - struct atkbd *atkbd = serio_get_drvdata(serio); - struct input_dev *dev = atkbd->dev; - unsigned int code = data; - int scroll = 0, hscroll = 0, click = -1; - int value; - unsigned short keycode; - - dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); + struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev); + struct serio *serio = ps2dev->serio; -#if !defined(__i386__) && !defined (__x86_64__) - if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { + if ((flags & (SERIO_FRAME | SERIO_PARITY)) && + (~flags & SERIO_TIMEOUT) && + !atkbd->resend && atkbd->write) { dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags); serio_write(serio, ATKBD_CMD_RESEND); atkbd->resend = true; - goto out; + return true; } if (!flags && data == ATKBD_RET_ACK) atkbd->resend = false; + + return false; +} + +static enum ps2_disposition atkbd_pre_receive_byte(struct ps2dev *ps2dev, + u8 data, unsigned int flags) +{ + struct serio *serio = ps2dev->serio; + + dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); + +#if !defined(__i386__) && !defined (__x86_64__) + if (atkbd_handle_frame_error(ps2dev, data, flags)) + return PS2_IGNORE; #endif - if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) - if (ps2_handle_ack(&atkbd->ps2dev, data)) - goto out; + return PS2_PROCESS; +} - if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD)) - if (ps2_handle_response(&atkbd->ps2dev, data)) - goto out; +static void atkbd_receive_byte(struct ps2dev *ps2dev, u8 data) +{ + struct serio *serio = ps2dev->serio; + struct atkbd *atkbd = container_of(ps2dev, struct atkbd, ps2dev); + struct input_dev *dev = atkbd->dev; + unsigned int code = data; + int scroll = 0, hscroll = 0, click = -1; + int value; + unsigned short keycode; pm_wakeup_event(&serio->dev, 0); if (!atkbd->enabled) - goto out; + return; input_event(dev, EV_MSC, MSC_RAW, code); @@ -453,16 +474,16 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, case ATKBD_RET_BAT: atkbd->enabled = false; serio_reconnect(atkbd->ps2dev.serio); - goto out; + return; case ATKBD_RET_EMUL0: atkbd->emul = 1; - goto out; + return; case ATKBD_RET_EMUL1: atkbd->emul = 2; - goto out; + return; case ATKBD_RET_RELEASE: atkbd->release = true; - goto out; + return; case ATKBD_RET_ACK: case ATKBD_RET_NAK: if (printk_ratelimit()) @@ -470,18 +491,18 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, "Spurious %s on %s. " "Some program might be trying to access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); - goto out; + return; case ATKBD_RET_ERR: atkbd->err_count++; dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n", serio->phys); - goto out; + return; } code = atkbd_compat_scancode(atkbd, code); if (atkbd->emul && --atkbd->emul) - goto out; + return; keycode = atkbd->keycode[code]; @@ -557,8 +578,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, } atkbd->release = false; -out: - return IRQ_HANDLED; } static int atkbd_set_repeat_rate(struct atkbd *atkbd) @@ -909,7 +928,7 @@ static int atkbd_reset_state(struct atkbd *atkbd) static void atkbd_cleanup(struct serio *serio) { - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); atkbd_disable(atkbd); ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF); @@ -922,7 +941,7 @@ static void atkbd_cleanup(struct serio *serio) static void atkbd_disconnect(struct serio *serio) { - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); atkbd_disable(atkbd); @@ -1188,7 +1207,7 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd) static void atkbd_parse_fwnode_data(struct serio *serio) { - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); struct device *dev = &serio->dev; int n; @@ -1222,7 +1241,8 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) goto fail1; atkbd->dev = dev; - ps2_init(&atkbd->ps2dev, serio); + ps2_init(&atkbd->ps2dev, serio, + atkbd_pre_receive_byte, atkbd_receive_byte); INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work); mutex_init(&atkbd->mutex); @@ -1295,7 +1315,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv) static int atkbd_reconnect(struct serio *serio) { - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); struct serio_driver *drv = serio->drv; int retval = -1; @@ -1378,7 +1398,7 @@ static struct serio_driver atkbd_drv = { }, .description = DRIVER_DESC, .id_table = atkbd_serio_ids, - .interrupt = atkbd_interrupt, + .interrupt = ps2_interrupt, .connect = atkbd_connect, .reconnect = atkbd_reconnect, .disconnect = atkbd_disconnect, @@ -1389,7 +1409,7 @@ static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, ssize_t (*handler)(struct atkbd *, char *)) { struct serio *serio = to_serio_port(dev); - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); return handler(atkbd, buf); } @@ -1398,7 +1418,7 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t ssize_t (*handler)(struct atkbd *, const char *, size_t)) { struct serio *serio = to_serio_port(dev); - struct atkbd *atkbd = serio_get_drvdata(serio); + struct atkbd *atkbd = atkbd_from_serio(serio); int retval; retval = mutex_lock_interruptible(&atkbd->mutex); diff --git a/drivers/input/keyboard/bcm-keypad.c b/drivers/input/keyboard/bcm-keypad.c index 56a919ec23b5..f3c3746acd4c 100644 --- a/drivers/input/keyboard/bcm-keypad.c +++ b/drivers/input/keyboard/bcm-keypad.c @@ -307,7 +307,6 @@ static int bcm_kp_probe(struct platform_device *pdev) { struct bcm_kp *kp; struct input_dev *input_dev; - struct resource *res; int error; kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); @@ -353,29 +352,16 @@ static int bcm_kp_probe(struct platform_device *pdev) return error; } - /* Get the KEYPAD base address */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Missing keypad base address resource\n"); - return -ENODEV; - } - - kp->base = devm_ioremap_resource(&pdev->dev, res); + kp->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kp->base)) return PTR_ERR(kp->base); /* Enable clock */ - kp->clk = devm_clk_get(&pdev->dev, "peri_clk"); + kp->clk = devm_clk_get_optional(&pdev->dev, "peri_clk"); if (IS_ERR(kp->clk)) { - error = PTR_ERR(kp->clk); - if (error != -ENOENT) { - if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to get clock\n"); - return error; - } - dev_dbg(&pdev->dev, - "No clock specified. Assuming it's enabled\n"); - kp->clk = NULL; + return dev_err_probe(&pdev->dev, PTR_ERR(kp->clk), "Failed to get clock\n"); + } else if (!kp->clk) { + dev_dbg(&pdev->dev, "No clock specified. Assuming it's enabled\n"); } else { unsigned int desired_rate; long actual_rate; diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index 040696d0e49c..1b4937dce672 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -518,7 +518,7 @@ static struct i2c_driver cap11xx_i2c_driver = { .of_match_table = cap11xx_dt_ids, }, .id_table = cap11xx_i2c_ids, - .probe_new = cap11xx_i2c_probe, + .probe = cap11xx_i2c_probe, }; module_i2c_driver(cap11xx_i2c_driver); diff --git a/drivers/input/keyboard/cypress-sf.c b/drivers/input/keyboard/cypress-sf.c index 686388f40317..2bacd9d80ecf 100644 --- a/drivers/input/keyboard/cypress-sf.c +++ b/drivers/input/keyboard/cypress-sf.c @@ -229,7 +229,7 @@ static struct i2c_driver cypress_sf_driver = { .of_match_table = of_match_ptr(cypress_sf_of_match), }, .id_table = cypress_sf_id_table, - .probe_new = cypress_sf_probe, + .probe = cypress_sf_probe, }; module_i2c_driver(cypress_sf_driver); diff --git a/drivers/input/keyboard/dlink-dir685-touchkeys.c b/drivers/input/keyboard/dlink-dir685-touchkeys.c index ddba2bc861da..6c065eff5a5a 100644 --- a/drivers/input/keyboard/dlink-dir685-touchkeys.c +++ b/drivers/input/keyboard/dlink-dir685-touchkeys.c @@ -145,7 +145,7 @@ static struct i2c_driver dir685_tk_i2c_driver = { .name = "dlink-dir685-touchkeys", .of_match_table = of_match_ptr(dir685_tk_of_match), }, - .probe_new = dir685_tk_probe, + .probe = dir685_tk_probe, .id_table = dir685_tk_id, }; module_i2c_driver(dir685_tk_i2c_driver); diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index c42f86ad0766..c928829a8b0c 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -456,7 +456,7 @@ static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t) struct input_dev *input = bdata->input; if (bdata->key_pressed) { - input_event(input, EV_KEY, *bdata->code, 0); + input_report_key(input, *bdata->code, 0); input_sync(input); bdata->key_pressed = false; } @@ -478,11 +478,11 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id) if (bdata->button->wakeup) pm_wakeup_event(bdata->input->dev.parent, 0); - input_event(input, EV_KEY, *bdata->code, 1); + input_report_key(input, *bdata->code, 1); input_sync(input); if (!bdata->release_delay) { - input_event(input, EV_KEY, *bdata->code, 0); + input_report_key(input, *bdata->code, 0); input_sync(input); goto out; } diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index c3937d2fc744..ba00ecfbd343 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -299,13 +299,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) NULL, GPIOD_IN, button->desc); if (IS_ERR(bdata->gpiod)) { - error = PTR_ERR(bdata->gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, - "failed to get gpio: %d\n", - error); fwnode_handle_put(child); - return error; + return dev_err_probe(dev, PTR_ERR(bdata->gpiod), + "failed to get gpio\n"); } } else if (gpio_is_valid(button->gpio)) { /* diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c index 5df4d5a7ed9e..3964f6e0f6af 100644 --- a/drivers/input/keyboard/lm8323.c +++ b/drivers/input/keyboard/lm8323.c @@ -826,7 +826,7 @@ static struct i2c_driver lm8323_i2c_driver = { .name = "lm8323", .pm = pm_sleep_ptr(&lm8323_pm_ops), }, - .probe_new = lm8323_probe, + .probe = lm8323_probe, .remove = lm8323_remove, .id_table = lm8323_id, }; diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 7457c3220f90..c9f05764e36d 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -218,7 +218,7 @@ static struct i2c_driver lm8333_driver = { .driver = { .name = "lm8333", }, - .probe_new = lm8333_probe, + .probe = lm8333_probe, .remove = lm8333_remove, .id_table = lm8333_id, }; diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 911e1181cd6f..322a87807159 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -160,17 +160,10 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) { struct lpc32xx_kscan_drv *kscandat; struct input_dev *input; - struct resource *res; size_t keymap_size; int error; int irq; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform I/O memory\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return -EINVAL; @@ -221,7 +214,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) input_set_drvdata(kscandat->input, kscandat); - kscandat->kscan_base = devm_ioremap_resource(&pdev->dev, res); + kscandat->kscan_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kscandat->kscan_base)) return PTR_ERR(kscandat->kscan_base); diff --git a/drivers/input/keyboard/max7359_keypad.c b/drivers/input/keyboard/max7359_keypad.c index b363749d02e2..faab7691c219 100644 --- a/drivers/input/keyboard/max7359_keypad.c +++ b/drivers/input/keyboard/max7359_keypad.c @@ -280,7 +280,7 @@ static struct i2c_driver max7359_i2c_driver = { .name = "max7359", .pm = pm_sleep_ptr(&max7359_pm), }, - .probe_new = max7359_probe, + .probe = max7359_probe, .id_table = max7359_ids, }; diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index d414e19e4559..de312d8eb974 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -258,7 +258,7 @@ static struct i2c_driver mcs_touchkey_driver = { .name = "mcs_touchkey", .pm = pm_sleep_ptr(&mcs_touchkey_pm_ops), }, - .probe_new = mcs_touchkey_probe, + .probe = mcs_touchkey_probe, .remove = mcs_touchkey_remove, .shutdown = mcs_touchkey_shutdown, .id_table = mcs_touchkey_id, diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 74ad353462a3..d434753afab1 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -389,7 +389,7 @@ static struct i2c_driver mpr_touchkey_driver = { .of_match_table = of_match_ptr(mpr121_touchkey_dt_match_table), }, .id_table = mpr121_id, - .probe_new = mpr_touchkey_probe, + .probe = mpr_touchkey_probe, }; module_i2c_driver(mpr_touchkey_driver); diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c index 970f2a671c2e..b3ccc97f61e1 100644 --- a/drivers/input/keyboard/nomadik-ske-keypad.c +++ b/drivers/input/keyboard/nomadik-ske-keypad.c @@ -221,13 +221,20 @@ static irqreturn_t ske_keypad_irq(int irq, void *dev_id) return IRQ_HANDLED; } +static void ske_keypad_board_exit(void *data) +{ + struct ske_keypad *keypad = data; + + keypad->board->exit(); +} + static int __init ske_keypad_probe(struct platform_device *pdev) { const struct ske_keypad_platform_data *plat = dev_get_platdata(&pdev->dev); + struct device *dev = &pdev->dev; struct ske_keypad *keypad; struct input_dev *input; - struct resource *res; int irq; int error; @@ -238,20 +245,14 @@ static int __init ske_keypad_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return -EINVAL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "missing platform resources\n"); - return -EINVAL; - } + return irq; - keypad = kzalloc(sizeof(struct ske_keypad), GFP_KERNEL); - input = input_allocate_device(); + keypad = devm_kzalloc(dev, sizeof(struct ske_keypad), + GFP_KERNEL); + input = devm_input_allocate_device(dev); if (!keypad || !input) { dev_err(&pdev->dev, "failed to allocate keypad memory\n"); - error = -ENOMEM; - goto err_free_mem; + return -ENOMEM; } keypad->irq = irq; @@ -259,31 +260,20 @@ static int __init ske_keypad_probe(struct platform_device *pdev) keypad->input = input; spin_lock_init(&keypad->ske_keypad_lock); - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - dev_err(&pdev->dev, "failed to request I/O memory\n"); - error = -EBUSY; - goto err_free_mem; - } - - keypad->reg_base = ioremap(res->start, resource_size(res)); - if (!keypad->reg_base) { - dev_err(&pdev->dev, "failed to remap I/O memory\n"); - error = -ENXIO; - goto err_free_mem_region; - } + keypad->reg_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(keypad->reg_base)) + return PTR_ERR(keypad->reg_base); - keypad->pclk = clk_get(&pdev->dev, "apb_pclk"); + keypad->pclk = devm_clk_get_enabled(dev, "apb_pclk"); if (IS_ERR(keypad->pclk)) { dev_err(&pdev->dev, "failed to get pclk\n"); - error = PTR_ERR(keypad->pclk); - goto err_iounmap; + return PTR_ERR(keypad->pclk); } - keypad->clk = clk_get(&pdev->dev, NULL); + keypad->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(keypad->clk)) { dev_err(&pdev->dev, "failed to get clk\n"); - error = PTR_ERR(keypad->clk); - goto err_pclk; + return PTR_ERR(keypad->clk); } input->id.bustype = BUS_HOST; @@ -295,48 +285,43 @@ static int __init ske_keypad_probe(struct platform_device *pdev) keypad->keymap, input); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); - goto err_clk; + return error; } input_set_capability(input, EV_MSC, MSC_SCAN); if (!plat->no_autorepeat) __set_bit(EV_REP, input->evbit); - error = clk_prepare_enable(keypad->pclk); - if (error) { - dev_err(&pdev->dev, "Failed to prepare/enable pclk\n"); - goto err_clk; - } - - error = clk_prepare_enable(keypad->clk); - if (error) { - dev_err(&pdev->dev, "Failed to prepare/enable clk\n"); - goto err_pclk_disable; - } - - /* go through board initialization helpers */ if (keypad->board->init) keypad->board->init(); + if (keypad->board->exit) { + error = devm_add_action_or_reset(dev, ske_keypad_board_exit, + keypad); + if (error) + return error; + } + error = ske_keypad_chip_init(keypad); if (error) { dev_err(&pdev->dev, "unable to init keypad hardware\n"); - goto err_clk_disable; + return error; } - error = request_threaded_irq(keypad->irq, NULL, ske_keypad_irq, - IRQF_ONESHOT, "ske-keypad", keypad); + error = devm_request_threaded_irq(dev, keypad->irq, + NULL, ske_keypad_irq, + IRQF_ONESHOT, "ske-keypad", keypad); if (error) { dev_err(&pdev->dev, "allocate irq %d failed\n", keypad->irq); - goto err_clk_disable; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, - "unable to register input device: %d\n", error); - goto err_free_irq; + "unable to register input device: %d\n", error); + return error; } if (plat->wakeup_enable) @@ -345,47 +330,6 @@ static int __init ske_keypad_probe(struct platform_device *pdev) platform_set_drvdata(pdev, keypad); return 0; - -err_free_irq: - free_irq(keypad->irq, keypad); -err_clk_disable: - clk_disable_unprepare(keypad->clk); -err_pclk_disable: - clk_disable_unprepare(keypad->pclk); -err_clk: - clk_put(keypad->clk); -err_pclk: - clk_put(keypad->pclk); -err_iounmap: - iounmap(keypad->reg_base); -err_free_mem_region: - release_mem_region(res->start, resource_size(res)); -err_free_mem: - input_free_device(input); - kfree(keypad); - return error; -} - -static int ske_keypad_remove(struct platform_device *pdev) -{ - struct ske_keypad *keypad = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - free_irq(keypad->irq, keypad); - - input_unregister_device(keypad->input); - - clk_disable_unprepare(keypad->clk); - clk_put(keypad->clk); - - if (keypad->board->exit) - keypad->board->exit(); - - iounmap(keypad->reg_base); - release_mem_region(res->start, resource_size(res)); - kfree(keypad); - - return 0; } static int ske_keypad_suspend(struct device *dev) @@ -424,7 +368,6 @@ static struct platform_driver ske_keypad_driver = { .name = "nmk-ske-keypad", .pm = pm_sleep_ptr(&ske_keypad_dev_pm_ops), }, - .remove = ske_keypad_remove, }; module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe); diff --git a/drivers/input/keyboard/nspire-keypad.c b/drivers/input/keyboard/nspire-keypad.c index e9fa1423f136..096c18d7bca1 100644 --- a/drivers/input/keyboard/nspire-keypad.c +++ b/drivers/input/keyboard/nspire-keypad.c @@ -186,8 +186,7 @@ static int nspire_keypad_probe(struct platform_device *pdev) return PTR_ERR(keypad->clk); } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - keypad->reg_base = devm_ioremap_resource(&pdev->dev, res); + keypad->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(keypad->reg_base)) return PTR_ERR(keypad->reg_base); diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c index 9f085d5679db..773e55eed88b 100644 --- a/drivers/input/keyboard/omap4-keypad.c +++ b/drivers/input/keyboard/omap4-keypad.c @@ -341,17 +341,10 @@ static int omap4_keypad_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct omap4_keypad *keypad_data; struct input_dev *input_dev; - struct resource *res; unsigned int max_keys; int irq; int error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "no base address specified\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; @@ -370,7 +363,7 @@ static int omap4_keypad_probe(struct platform_device *pdev) if (error) return error; - keypad_data->base = devm_ioremap_resource(dev, res); + keypad_data->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad_data->base)) return PTR_ERR(keypad_data->base); diff --git a/drivers/input/keyboard/opencores-kbd.c b/drivers/input/keyboard/opencores-kbd.c index b0ea387414c1..7ffe1a70c856 100644 --- a/drivers/input/keyboard/opencores-kbd.c +++ b/drivers/input/keyboard/opencores-kbd.c @@ -39,15 +39,8 @@ static int opencores_kbd_probe(struct platform_device *pdev) { struct input_dev *input; struct opencores_kbd *opencores_kbd; - struct resource *res; int irq, i, error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "missing board memory resource\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return -EINVAL; @@ -65,7 +58,7 @@ static int opencores_kbd_probe(struct platform_device *pdev) opencores_kbd->input = input; - opencores_kbd->addr = devm_ioremap_resource(&pdev->dev, res); + opencores_kbd->addr = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(opencores_kbd->addr)) return PTR_ERR(opencores_kbd->addr); diff --git a/drivers/input/keyboard/pinephone-keyboard.c b/drivers/input/keyboard/pinephone-keyboard.c index 5548699b8b38..147b1f288a33 100644 --- a/drivers/input/keyboard/pinephone-keyboard.c +++ b/drivers/input/keyboard/pinephone-keyboard.c @@ -318,40 +318,22 @@ static void ppkb_close(struct input_dev *input) ppkb_set_scan(client, false); } -static void ppkb_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int ppkb_probe(struct i2c_client *client) { struct device *dev = &client->dev; unsigned int phys_rows, phys_cols; struct pinephone_keyboard *ppkb; - struct regulator *vbat_supply; u8 info[PPKB_MATRIX_SIZE + 1]; struct device_node *i2c_bus; int ret; int error; - vbat_supply = devm_regulator_get(dev, "vbat"); - error = PTR_ERR_OR_ZERO(vbat_supply); + error = devm_regulator_get_enable(dev, "vbat"); if (error) { dev_err(dev, "Failed to get VBAT supply: %d\n", error); return error; } - error = regulator_enable(vbat_supply); - if (error) { - dev_err(dev, "Failed to enable VBAT: %d\n", error); - return error; - } - - error = devm_add_action_or_reset(dev, ppkb_regulator_disable, - vbat_supply); - if (error) - return error; - ret = i2c_smbus_read_i2c_block_data(client, 0, sizeof(info), info); if (ret != sizeof(info)) { error = ret < 0 ? ret : -EIO; @@ -455,7 +437,7 @@ static const struct of_device_id ppkb_of_match[] = { MODULE_DEVICE_TABLE(of, ppkb_of_match); static struct i2c_driver ppkb_driver = { - .probe_new = ppkb_probe, + .probe = ppkb_probe, .driver = { .name = DRV_NAME, .of_match_table = ppkb_of_match, diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index 871f858d0ba7..3724363d140e 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -717,7 +717,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct pxa27x_keypad *keypad; struct input_dev *input_dev; - struct resource *res; int irq, error; /* Driver need build keycode from device tree or pdata */ @@ -728,12 +727,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) if (irq < 0) return -ENXIO; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res == NULL) { - dev_err(&pdev->dev, "failed to get I/O memory\n"); - return -ENXIO; - } - keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL); if (!keypad) @@ -747,7 +740,7 @@ static int pxa27x_keypad_probe(struct platform_device *pdev) keypad->input_dev = input_dev; keypad->irq = irq; - keypad->mmio_base = devm_ioremap_resource(&pdev->dev, res); + keypad->mmio_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(keypad->mmio_base)) return PTR_ERR(keypad->mmio_base); diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c index 317fe2b1f827..6953097db445 100644 --- a/drivers/input/keyboard/qt1050.c +++ b/drivers/input/keyboard/qt1050.c @@ -588,7 +588,7 @@ static struct i2c_driver qt1050_driver = { .of_match_table = of_match_ptr(qt1050_of_match), .pm = pm_sleep_ptr(&qt1050_pm_ops), }, - .probe_new = qt1050_probe, + .probe = qt1050_probe, }; module_i2c_driver(qt1050_driver); diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index fabb50bde844..91aaa9fc43a4 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -271,7 +271,7 @@ static struct i2c_driver qt1070_driver = { .pm = pm_sleep_ptr(&qt1070_pm_ops), }, .id_table = qt1070_id, - .probe_new = qt1070_probe, + .probe = qt1070_probe, .remove = qt1070_remove, }; diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 04d2ee6ff577..599ea85cfd30 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -460,7 +460,7 @@ static struct i2c_driver qt2160_driver = { }, .id_table = qt2160_idtable, - .probe_new = qt2160_probe, + .probe = qt2160_probe, .remove = qt2160_remove, }; diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c index 15c15c0958b0..95d927cc8b7e 100644 --- a/drivers/input/keyboard/sun4i-lradc-keys.c +++ b/drivers/input/keyboard/sun4i-lradc-keys.c @@ -307,8 +307,7 @@ static int sun4i_lradc_probe(struct platform_device *pdev) input_set_drvdata(lradc->input, lradc); - lradc->base = devm_ioremap_resource(dev, - platform_get_resource(pdev, IORESOURCE_MEM, 0)); + lradc->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(lradc->base)) return PTR_ERR(lradc->base); diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c index 673b905af6fe..2f745cabf4f2 100644 --- a/drivers/input/keyboard/tca6416-keypad.c +++ b/drivers/input/keyboard/tca6416-keypad.c @@ -350,7 +350,7 @@ static struct i2c_driver tca6416_keypad_driver = { .name = "tca6416-keypad", .pm = pm_sleep_ptr(&tca6416_keypad_dev_pm_ops), }, - .probe_new = tca6416_keypad_probe, + .probe = tca6416_keypad_probe, .remove = tca6416_keypad_remove, .id_table = tca6416_id, }; diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 3d7492f38337..76fc19ffe21d 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -370,7 +370,7 @@ static struct i2c_driver tca8418_keypad_driver = { .name = "tca8418_keypad", .of_match_table = tca8418_dt_ids, }, - .probe_new = tca8418_keypad_probe, + .probe = tca8418_keypad_probe, .id_table = tca8418_id, }; diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c index d5a6c7d8eb25..c9a823ea45d0 100644 --- a/drivers/input/keyboard/tegra-kbc.c +++ b/drivers/input/keyboard/tegra-kbc.c @@ -640,7 +640,7 @@ static int tegra_kbc_probe(struct platform_device *pdev) timer_setup(&kbc->timer, tegra_kbc_keypress_timer, 0); - kbc->mmio = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + kbc->mmio = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(kbc->mmio)) return PTR_ERR(kbc->mmio); diff --git a/drivers/input/keyboard/tm2-touchkey.c b/drivers/input/keyboard/tm2-touchkey.c index 4e20571cb4c3..75bd3ea51194 100644 --- a/drivers/input/keyboard/tm2-touchkey.c +++ b/drivers/input/keyboard/tm2-touchkey.c @@ -356,7 +356,7 @@ static struct i2c_driver tm2_touchkey_driver = { .pm = pm_sleep_ptr(&tm2_touchkey_pm_ops), .of_match_table = tm2_touchkey_of_match, }, - .probe_new = tm2_touchkey_probe, + .probe = tm2_touchkey_probe, .id_table = tm2_touchkey_id_table, }; module_i2c_driver(tm2_touchkey_driver); diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 81a54a59e13c..c47eecc6f83b 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -791,10 +791,10 @@ config INPUT_IQS626A module will be called iqs626a. config INPUT_IQS7222 - tristate "Azoteq IQS7222A/B/C capacitive touch controller" + tristate "Azoteq IQS7222A/B/C/D capacitive touch controller" depends on I2C help - Say Y to enable support for the Azoteq IQS7222A/B/C family + Say Y to enable support for the Azoteq IQS7222A/B/C/D family of capacitive touch controllers. To compile this driver as a module, choose M here: the diff --git a/drivers/input/misc/ad714x-i2c.c b/drivers/input/misc/ad714x-i2c.c index d8e39f4a57ac..679fcfea942c 100644 --- a/drivers/input/misc/ad714x-i2c.c +++ b/drivers/input/misc/ad714x-i2c.c @@ -86,7 +86,7 @@ static struct i2c_driver ad714x_i2c_driver = { .name = "ad714x_captouch", .pm = pm_sleep_ptr(&ad714x_pm), }, - .probe_new = ad714x_i2c_probe, + .probe = ad714x_i2c_probe, .id_table = ad714x_id, }; diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index 1c75d98c85a7..6b880e282d99 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -135,7 +135,7 @@ static struct i2c_driver adxl34x_driver = { .pm = pm_sleep_ptr(&adxl34x_pm), .of_match_table = adxl34x_of_id, }, - .probe_new = adxl34x_i2c_probe, + .probe = adxl34x_i2c_probe, .remove = adxl34x_i2c_remove, .id_table = adxl34x_id, }; diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c index eecca671b588..a3f45e0ee0c7 100644 --- a/drivers/input/misc/adxl34x.c +++ b/drivers/input/misc/adxl34x.c @@ -817,8 +817,7 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq, AC_WRITE(ac, POWER_CTL, 0); err = request_threaded_irq(ac->irq, NULL, adxl34x_irq, - IRQF_TRIGGER_HIGH | IRQF_ONESHOT, - dev_name(dev), ac); + IRQF_ONESHOT, dev_name(dev), ac); if (err) { dev_err(dev, "irq %d busy?\n", ac->irq); goto err_free_mem; diff --git a/drivers/input/misc/apanel.c b/drivers/input/misc/apanel.c index f42d3219cdcc..b5219bbe856d 100644 --- a/drivers/input/misc/apanel.c +++ b/drivers/input/misc/apanel.c @@ -201,7 +201,7 @@ static struct i2c_driver apanel_driver = { .driver = { .name = APANEL, }, - .probe_new = apanel_probe, + .probe = apanel_probe, .shutdown = apanel_shutdown, .id_table = apanel_id, }; diff --git a/drivers/input/misc/atmel_captouch.c b/drivers/input/misc/atmel_captouch.c index d9704b174d3a..b6a30044e814 100644 --- a/drivers/input/misc/atmel_captouch.c +++ b/drivers/input/misc/atmel_captouch.c @@ -263,7 +263,7 @@ static const struct i2c_device_id atmel_captouch_id[] = { MODULE_DEVICE_TABLE(i2c, atmel_captouch_id); static struct i2c_driver atmel_captouch_driver = { - .probe_new = atmel_captouch_probe, + .probe = atmel_captouch_probe, .id_table = atmel_captouch_id, .driver = { .name = "atmel_captouch", diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index 3f9da5c3cb53..0fb4cc628f29 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -551,7 +551,7 @@ static struct i2c_driver bma150_driver = { }, .class = I2C_CLASS_HWMON, .id_table = bma150_id, - .probe_new = bma150_probe, + .probe = bma150_probe, .remove = bma150_remove, }; diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index 136eb3715870..a4dfb3052dc0 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -97,7 +97,7 @@ static const struct i2c_device_id cma3000_i2c_id[] = { MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id); static struct i2c_driver cma3000_i2c_driver = { - .probe_new = cma3000_i2c_probe, + .probe = cma3000_i2c_probe, .remove = cma3000_i2c_remove, .id_table = cma3000_i2c_id, .driver = { diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c index b85a19e3554f..ce82548916bb 100644 --- a/drivers/input/misc/da7280.c +++ b/drivers/input/misc/da7280.c @@ -1321,7 +1321,7 @@ static struct i2c_driver da7280_driver = { .of_match_table = of_match_ptr(da7280_of_match), .pm = pm_sleep_ptr(&da7280_pm_ops), }, - .probe_new = da7280_probe, + .probe = da7280_probe, .id_table = da7280_i2c_id, }; module_i2c_driver(da7280_driver); diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 8a9ebfc04a2d..6717e3c9549b 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -149,7 +149,7 @@ /* Control 3 Register */ #define DRV260X_LRA_OPEN_LOOP (1 << 0) -#define DRV260X_ANANLOG_IN (1 << 1) +#define DRV260X_ANALOG_IN (1 << 1) #define DRV260X_LRA_DRV_MODE (1 << 2) #define DRV260X_RTP_UNSIGNED_DATA (1 << 3) #define DRV260X_SUPPLY_COMP_DIS (1 << 4) @@ -186,51 +186,13 @@ struct drv260x_data { struct work_struct work; struct gpio_desc *enable_gpio; struct regulator *regulator; - u32 magnitude; + u8 magnitude; u32 mode; u32 library; int rated_voltage; int overdrive_voltage; }; -static const struct reg_default drv260x_reg_defs[] = { - { DRV260X_STATUS, 0xe0 }, - { DRV260X_MODE, 0x40 }, - { DRV260X_RT_PB_IN, 0x00 }, - { DRV260X_LIB_SEL, 0x00 }, - { DRV260X_WV_SEQ_1, 0x01 }, - { DRV260X_WV_SEQ_2, 0x00 }, - { DRV260X_WV_SEQ_3, 0x00 }, - { DRV260X_WV_SEQ_4, 0x00 }, - { DRV260X_WV_SEQ_5, 0x00 }, - { DRV260X_WV_SEQ_6, 0x00 }, - { DRV260X_WV_SEQ_7, 0x00 }, - { DRV260X_WV_SEQ_8, 0x00 }, - { DRV260X_GO, 0x00 }, - { DRV260X_OVERDRIVE_OFF, 0x00 }, - { DRV260X_SUSTAIN_P_OFF, 0x00 }, - { DRV260X_SUSTAIN_N_OFF, 0x00 }, - { DRV260X_BRAKE_OFF, 0x00 }, - { DRV260X_A_TO_V_CTRL, 0x05 }, - { DRV260X_A_TO_V_MIN_INPUT, 0x19 }, - { DRV260X_A_TO_V_MAX_INPUT, 0xff }, - { DRV260X_A_TO_V_MIN_OUT, 0x19 }, - { DRV260X_A_TO_V_MAX_OUT, 0xff }, - { DRV260X_RATED_VOLT, 0x3e }, - { DRV260X_OD_CLAMP_VOLT, 0x8c }, - { DRV260X_CAL_COMP, 0x0c }, - { DRV260X_CAL_BACK_EMF, 0x6c }, - { DRV260X_FEEDBACK_CTRL, 0x36 }, - { DRV260X_CTRL1, 0x93 }, - { DRV260X_CTRL2, 0xfa }, - { DRV260X_CTRL3, 0xa0 }, - { DRV260X_CTRL4, 0x20 }, - { DRV260X_CTRL5, 0x80 }, - { DRV260X_LRA_LOOP_PERIOD, 0x33 }, - { DRV260X_VBAT_MON, 0x00 }, - { DRV260X_LRA_RES_PERIOD, 0x00 }, -}; - #define DRV260X_DEF_RATED_VOLT 0x90 #define DRV260X_DEF_OD_CLAMP_VOLT 0x90 @@ -275,10 +237,11 @@ static int drv260x_haptics_play(struct input_dev *input, void *data, haptics->mode = DRV260X_LRA_NO_CAL_MODE; + /* Scale u16 magnitude into u8 register value */ if (effect->u.rumble.strong_magnitude > 0) - haptics->magnitude = effect->u.rumble.strong_magnitude; + haptics->magnitude = effect->u.rumble.strong_magnitude >> 8; else if (effect->u.rumble.weak_magnitude > 0) - haptics->magnitude = effect->u.rumble.weak_magnitude; + haptics->magnitude = effect->u.rumble.weak_magnitude >> 8; else haptics->magnitude = 0; @@ -304,7 +267,7 @@ static void drv260x_close(struct input_dev *input) static const struct reg_sequence drv260x_lra_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, - { DRV260X_CTRL3, DRV260X_NG_THRESH_2 }, + { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA }, { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH }, }; @@ -322,7 +285,7 @@ static const struct reg_sequence drv260x_lra_init_regs[] = { DRV260X_BEMF_GAIN_3 }, { DRV260X_CTRL1, DRV260X_STARTUP_BOOST }, { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 }, - { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ANANLOG_IN }, + { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA | DRV260X_ANALOG_IN }, { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, }; @@ -337,7 +300,7 @@ static const struct reg_sequence drv260x_erm_cal_regs[] = { { DRV260X_CTRL1, DRV260X_STARTUP_BOOST }, { DRV260X_CTRL2, DRV260X_SAMP_TIME_250 | DRV260X_BLANK_TIME_75 | DRV260X_IDISS_TIME_75 }, - { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ERM_OPEN_LOOP }, + { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA }, { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, }; @@ -435,6 +398,7 @@ static int drv260x_init(struct drv260x_data *haptics) } do { + usleep_range(15000, 15500); error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf); if (error) { dev_err(&haptics->client->dev, @@ -452,8 +416,6 @@ static const struct regmap_config drv260x_regmap_config = { .val_bits = 8, .max_register = DRV260X_MAX_REG, - .reg_defaults = drv260x_reg_defs, - .num_reg_defaults = ARRAY_SIZE(drv260x_reg_defs), .cache_type = REGCACHE_NONE, }; @@ -653,7 +615,7 @@ static const struct of_device_id drv260x_of_match[] = { MODULE_DEVICE_TABLE(of, drv260x_of_match); static struct i2c_driver drv260x_driver = { - .probe_new = drv260x_probe, + .probe = drv260x_probe, .driver = { .name = "drv260x-haptics", .of_match_table = drv260x_of_match, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 9145096f80ea..de27e6079d84 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -297,7 +297,7 @@ MODULE_DEVICE_TABLE(of, drv2665_of_match); #endif static struct i2c_driver drv2665_driver = { - .probe_new = drv2665_probe, + .probe = drv2665_probe, .driver = { .name = "drv2665-haptics", .of_match_table = of_match_ptr(drv2665_of_match), diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index 88b4dbe3e5b5..11c5855256e8 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -474,7 +474,7 @@ MODULE_DEVICE_TABLE(of, drv2667_of_match); #endif static struct i2c_driver drv2667_driver = { - .probe_new = drv2667_probe, + .probe = drv2667_probe, .driver = { .name = "drv2667-haptics", .of_match_table = of_match_ptr(drv2667_of_match), diff --git a/drivers/input/misc/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c index 134a1309ba92..c1c3ba5960dd 100644 --- a/drivers/input/misc/gpio-vibra.c +++ b/drivers/input/misc/gpio-vibra.c @@ -113,22 +113,14 @@ static int gpio_vibrator_probe(struct platform_device *pdev) return -ENOMEM; vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc"); - err = PTR_ERR_OR_ZERO(vibrator->vcc); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request regulator: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->vcc)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc), + "Failed to request regulator\n"); vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW); - err = PTR_ERR_OR_ZERO(vibrator->gpio); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request main gpio: %d\n", - err); - return err; - } + if (IS_ERR(vibrator->gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->gpio), + "Failed to request main gpio\n"); INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work); diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c index 3969ffc1bc8d..867ac7aa10d2 100644 --- a/drivers/input/misc/ibm-panel.c +++ b/drivers/input/misc/ibm-panel.c @@ -189,7 +189,7 @@ static struct i2c_driver ibm_panel_driver = { .name = DEVICE_NAME, .of_match_table = ibm_panel_match, }, - .probe_new = ibm_panel_probe, + .probe = ibm_panel_probe, .remove = ibm_panel_remove, }; module_i2c_driver(ibm_panel_driver); diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c index f4c3aff3895b..1272ef7b5794 100644 --- a/drivers/input/misc/iqs269a.c +++ b/drivers/input/misc/iqs269a.c @@ -1746,7 +1746,7 @@ static struct i2c_driver iqs269_i2c_driver = { .of_match_table = iqs269_of_match, .pm = pm_sleep_ptr(&iqs269_pm), }, - .probe_new = iqs269_probe, + .probe = iqs269_probe, }; module_i2c_driver(iqs269_i2c_driver); diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c index 90f997a905b5..50035c25c3f7 100644 --- a/drivers/input/misc/iqs626a.c +++ b/drivers/input/misc/iqs626a.c @@ -1822,7 +1822,7 @@ static struct i2c_driver iqs626_i2c_driver = { .of_match_table = iqs626_of_match, .pm = pm_sleep_ptr(&iqs626_pm), }, - .probe_new = iqs626_probe, + .probe = iqs626_probe, }; module_i2c_driver(iqs626_i2c_driver); diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c index e47ab6c1177f..a9c1dba1e8c1 100644 --- a/drivers/input/misc/iqs7222.c +++ b/drivers/input/misc/iqs7222.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Azoteq IQS7222A/B/C Capacitive Touch Controller + * Azoteq IQS7222A/B/C/D Capacitive Touch Controller * * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com> */ @@ -12,6 +12,7 @@ #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/input/touchscreen.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/ktime.h> @@ -25,6 +26,7 @@ #define IQS7222_PROD_NUM_A 840 #define IQS7222_PROD_NUM_B 698 #define IQS7222_PROD_NUM_C 863 +#define IQS7222_PROD_NUM_D 1046 #define IQS7222_SYS_STATUS 0x10 #define IQS7222_SYS_STATUS_RESET BIT(3) @@ -54,6 +56,7 @@ #define IQS7222_EVENT_MASK_ATI BIT(12) #define IQS7222_EVENT_MASK_SLDR BIT(10) +#define IQS7222_EVENT_MASK_TPAD IQS7222_EVENT_MASK_SLDR #define IQS7222_EVENT_MASK_TOUCH BIT(1) #define IQS7222_EVENT_MASK_PROX BIT(0) @@ -71,6 +74,7 @@ #define IQS7222_MAX_COLS_CHAN 6 #define IQS7222_MAX_COLS_FILT 2 #define IQS7222_MAX_COLS_SLDR 11 +#define IQS7222_MAX_COLS_TPAD 24 #define IQS7222_MAX_COLS_GPIO 3 #define IQS7222_MAX_COLS_SYS 13 @@ -102,16 +106,18 @@ enum iqs7222_reg_grp_id { IQS7222_REG_GRP_BTN, IQS7222_REG_GRP_CHAN, IQS7222_REG_GRP_SLDR, + IQS7222_REG_GRP_TPAD, IQS7222_REG_GRP_GPIO, IQS7222_REG_GRP_SYS, IQS7222_NUM_REG_GRPS }; static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = { - [IQS7222_REG_GRP_CYCLE] = "cycle", - [IQS7222_REG_GRP_CHAN] = "channel", - [IQS7222_REG_GRP_SLDR] = "slider", - [IQS7222_REG_GRP_GPIO] = "gpio", + [IQS7222_REG_GRP_CYCLE] = "cycle-%d", + [IQS7222_REG_GRP_CHAN] = "channel-%d", + [IQS7222_REG_GRP_SLDR] = "slider-%d", + [IQS7222_REG_GRP_TPAD] = "trackpad", + [IQS7222_REG_GRP_GPIO] = "gpio-%d", }; static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = { @@ -122,6 +128,7 @@ static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = { [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN, [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT, [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR, + [IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD, [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO, [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS, }; @@ -130,8 +137,10 @@ static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, }; struct iqs7222_event_desc { const char *name; + u16 link; u16 mask; u16 val; + u16 strict; u16 enable; enum iqs7222_reg_key_id reg_key; }; @@ -188,6 +197,93 @@ static const struct iqs7222_event_desc iqs7222_sl_events[] = { }, }; +static const struct iqs7222_event_desc iqs7222_tp_events[] = { + { + .name = "event-press", + .link = BIT(7), + }, + { + .name = "event-tap", + .link = BIT(0), + .mask = BIT(0), + .val = BIT(0), + .enable = BIT(0), + .reg_key = IQS7222_REG_KEY_TAP, + }, + { + .name = "event-swipe-x-pos", + .link = BIT(2), + .mask = BIT(2) | BIT(1), + .val = BIT(2), + .strict = BIT(4), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-swipe-y-pos", + .link = BIT(3), + .mask = BIT(3) | BIT(1), + .val = BIT(3), + .strict = BIT(3), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-swipe-x-neg", + .link = BIT(4), + .mask = BIT(4) | BIT(1), + .val = BIT(4), + .strict = BIT(4), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-swipe-y-neg", + .link = BIT(5), + .mask = BIT(5) | BIT(1), + .val = BIT(5), + .strict = BIT(3), + .enable = BIT(1), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-x-pos", + .link = BIT(2), + .mask = BIT(2) | BIT(1), + .val = BIT(2) | BIT(1), + .strict = BIT(4), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-y-pos", + .link = BIT(3), + .mask = BIT(3) | BIT(1), + .val = BIT(3) | BIT(1), + .strict = BIT(3), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-x-neg", + .link = BIT(4), + .mask = BIT(4) | BIT(1), + .val = BIT(4) | BIT(1), + .strict = BIT(4), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, + { + .name = "event-flick-y-neg", + .link = BIT(5), + .mask = BIT(5) | BIT(1), + .val = BIT(5) | BIT(1), + .strict = BIT(3), + .enable = BIT(2), + .reg_key = IQS7222_REG_KEY_AXIAL, + }, +}; + struct iqs7222_reg_grp_desc { u16 base; int num_row; @@ -524,6 +620,62 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = { }, }, }, + { + .prod_num = IQS7222_PROD_NUM_D, + .fw_major = 0, + .fw_minor = 37, + .touch_link = 1770, + .allow_offset = 9, + .event_offset = 10, + .comms_offset = 11, + .reg_grps = { + [IQS7222_REG_GRP_STAT] = { + .base = IQS7222_SYS_STATUS, + .num_row = 1, + .num_col = 7, + }, + [IQS7222_REG_GRP_CYCLE] = { + .base = 0x8000, + .num_row = 7, + .num_col = 2, + }, + [IQS7222_REG_GRP_GLBL] = { + .base = 0x8700, + .num_row = 1, + .num_col = 3, + }, + [IQS7222_REG_GRP_BTN] = { + .base = 0x9000, + .num_row = 14, + .num_col = 3, + }, + [IQS7222_REG_GRP_CHAN] = { + .base = 0xA000, + .num_row = 14, + .num_col = 4, + }, + [IQS7222_REG_GRP_FILT] = { + .base = 0xAE00, + .num_row = 1, + .num_col = 2, + }, + [IQS7222_REG_GRP_TPAD] = { + .base = 0xB000, + .num_row = 1, + .num_col = 24, + }, + [IQS7222_REG_GRP_GPIO] = { + .base = 0xC000, + .num_row = 3, + .num_col = 3, + }, + [IQS7222_REG_GRP_SYS] = { + .base = IQS7222_SYS_SETUP, + .num_row = 1, + .num_col = 12, + }, + }, + }, }; struct iqs7222_prop_desc { @@ -1009,6 +1161,123 @@ static const struct iqs7222_prop_desc iqs7222_props[] = { .label = "maximum gesture time", }, { + .name = "azoteq,num-rows", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 0, + .reg_shift = 4, + .reg_width = 4, + .val_min = 1, + .val_max = 12, + .label = "number of rows", + }, + { + .name = "azoteq,num-cols", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 0, + .reg_shift = 0, + .reg_width = 4, + .val_min = 1, + .val_max = 12, + .label = "number of columns", + }, + { + .name = "azoteq,lower-cal-y", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 1, + .reg_shift = 8, + .reg_width = 8, + .label = "lower vertical calibration", + }, + { + .name = "azoteq,lower-cal-x", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 1, + .reg_shift = 0, + .reg_width = 8, + .label = "lower horizontal calibration", + }, + { + .name = "azoteq,upper-cal-y", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 2, + .reg_shift = 8, + .reg_width = 8, + .label = "upper vertical calibration", + }, + { + .name = "azoteq,upper-cal-x", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 2, + .reg_shift = 0, + .reg_width = 8, + .label = "upper horizontal calibration", + }, + { + .name = "azoteq,top-speed", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 3, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 4, + .label = "top speed", + }, + { + .name = "azoteq,bottom-speed", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_offset = 3, + .reg_shift = 0, + .reg_width = 8, + .label = "bottom speed", + }, + { + .name = "azoteq,gesture-min-ms", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_TAP, + .reg_offset = 20, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 16, + .label = "minimum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_AXIAL, + .reg_offset = 21, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 16, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_TAP, + .reg_offset = 21, + .reg_shift = 0, + .reg_width = 8, + .val_pitch = 16, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-dist", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_TAP, + .reg_offset = 22, + .reg_shift = 0, + .reg_width = 16, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist", + .reg_grp = IQS7222_REG_GRP_TPAD, + .reg_key = IQS7222_REG_KEY_AXIAL, + .reg_offset = 23, + .reg_shift = 0, + .reg_width = 16, + .label = "gesture distance", + }, + { .name = "drive-open-drain", .reg_grp = IQS7222_REG_GRP_GPIO, .reg_offset = 0, @@ -1091,16 +1360,19 @@ struct iqs7222_private { struct gpio_desc *irq_gpio; struct i2c_client *client; struct input_dev *keypad; + struct touchscreen_properties prop; unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)]; unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)]; unsigned int sl_axis[IQS7222_MAX_SLDR]; + unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)]; u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE]; u16 glbl_setup[IQS7222_MAX_COLS_GLBL]; u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN]; u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN]; u16 filt_setup[IQS7222_MAX_COLS_FILT]; u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR]; + u16 tpad_setup[IQS7222_MAX_COLS_TPAD]; u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO]; u16 sys_setup[IQS7222_MAX_COLS_SYS]; }; @@ -1127,6 +1399,9 @@ static u16 *iqs7222_setup(struct iqs7222_private *iqs7222, case IQS7222_REG_GRP_SLDR: return iqs7222->sldr_setup[row]; + case IQS7222_REG_GRP_TPAD: + return iqs7222->tpad_setup; + case IQS7222_REG_GRP_GPIO: return iqs7222->gpio_setup[row]; @@ -1381,9 +1656,6 @@ static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222) if (error) return error; - sys_setup &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK; - sys_setup &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK; - for (i = 0; i < IQS7222_NUM_RETRIES; i++) { /* * Trigger ATI from streaming and normal-power modes so that @@ -1561,8 +1833,11 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir) return error; } - if (dir == READ) + if (dir == READ) { + iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK; + iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK; return 0; + } return iqs7222_ati_trigger(iqs7222); } @@ -1936,6 +2211,14 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222, ref_setup[4] = dev_desc->touch_link; if (fwnode_property_present(chan_node, "azoteq,use-prox")) ref_setup[4] -= 2; + } else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row && + fwnode_property_present(chan_node, + "azoteq,counts-filt-enable")) { + /* + * In the case of IQS7222D, however, the reference mode field + * is partially repurposed as a counts filter enable control. + */ + chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF; } if (fwnode_property_present(chan_node, "azoteq,rx-enable")) { @@ -2278,6 +2561,136 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222, IQS7222_REG_KEY_NO_WHEEL); } +static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222, + struct fwnode_handle *tpad_node, int tpad_index) +{ + const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc; + struct touchscreen_properties *prop = &iqs7222->prop; + struct i2c_client *client = iqs7222->client; + int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row; + int count, error, i; + u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset]; + u16 *tpad_setup = iqs7222->tpad_setup; + unsigned int chan_sel[12]; + + error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index, + IQS7222_REG_GRP_TPAD, + IQS7222_REG_KEY_NONE); + if (error) + return error; + + count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select"); + if (count < 0) { + dev_err(&client->dev, "Failed to count %s channels: %d\n", + fwnode_get_name(tpad_node), count); + return count; + } else if (!count || count > ARRAY_SIZE(chan_sel)) { + dev_err(&client->dev, "Invalid number of %s channels\n", + fwnode_get_name(tpad_node)); + return -EINVAL; + } + + error = fwnode_property_read_u32_array(tpad_node, + "azoteq,channel-select", + chan_sel, count); + if (error) { + dev_err(&client->dev, "Failed to read %s channels: %d\n", + fwnode_get_name(tpad_node), error); + return error; + } + + tpad_setup[6] &= ~GENMASK(num_chan - 1, 0); + + for (i = 0; i < ARRAY_SIZE(chan_sel); i++) { + tpad_setup[8 + i] = 0; + if (i >= count || chan_sel[i] == U8_MAX) + continue; + + if (chan_sel[i] >= num_chan) { + dev_err(&client->dev, "Invalid %s channel: %u\n", + fwnode_get_name(tpad_node), chan_sel[i]); + return -EINVAL; + } + + /* + * The following fields indicate which channels participate in + * the trackpad, as well as each channel's relative placement. + */ + tpad_setup[6] |= BIT(chan_sel[i]); + tpad_setup[8 + i] = chan_sel[i] * 34 + 1072; + } + + tpad_setup[7] = dev_desc->touch_link; + if (fwnode_property_present(tpad_node, "azoteq,use-prox")) + tpad_setup[7] -= 2; + + for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) + tpad_setup[20] &= ~(iqs7222_tp_events[i].strict | + iqs7222_tp_events[i].enable); + + for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) { + const char *event_name = iqs7222_tp_events[i].name; + struct fwnode_handle *event_node; + + event_node = fwnode_get_named_child_node(tpad_node, event_name); + if (!event_node) + continue; + + if (fwnode_property_present(event_node, + "azoteq,gesture-angle-tighten")) + tpad_setup[20] |= iqs7222_tp_events[i].strict; + + tpad_setup[20] |= iqs7222_tp_events[i].enable; + + error = iqs7222_parse_event(iqs7222, event_node, tpad_index, + IQS7222_REG_GRP_TPAD, + iqs7222_tp_events[i].reg_key, + iqs7222_tp_events[i].link, 1566, + NULL, + &iqs7222->tp_code[i]); + fwnode_handle_put(event_node); + if (error) + return error; + + if (!dev_desc->event_offset) + continue; + + /* + * The press/release event is determined based on whether the + * coordinate fields report 0xFFFF and solely relies on touch + * or proximity interrupts to be unmasked. + */ + if (i) + *event_mask |= IQS7222_EVENT_MASK_TPAD; + else if (tpad_setup[7] == dev_desc->touch_link) + *event_mask |= IQS7222_EVENT_MASK_TOUCH; + else + *event_mask |= IQS7222_EVENT_MASK_PROX; + } + + if (!iqs7222->tp_code[0]) + return 0; + + input_set_abs_params(iqs7222->keypad, ABS_X, + 0, (tpad_setup[4] ? : 1) - 1, 0, 0); + + input_set_abs_params(iqs7222->keypad, ABS_Y, + 0, (tpad_setup[5] ? : 1) - 1, 0, 0); + + touchscreen_parse_properties(iqs7222->keypad, false, prop); + + if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { + dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", + prop->max_x, prop->max_y); + return -EINVAL; + } + + tpad_setup[4] = prop->max_x + 1; + tpad_setup[5] = prop->max_y + 1; + + return 0; +} + static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS]) (struct iqs7222_private *iqs7222, struct fwnode_handle *reg_grp_node, @@ -2285,6 +2698,7 @@ static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS]) [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle, [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan, [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr, + [IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad, }; static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, @@ -2298,7 +2712,7 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222, if (iqs7222_reg_grp_names[reg_grp]) { char reg_grp_name[16]; - snprintf(reg_grp_name, sizeof(reg_grp_name), "%s-%d", + snprintf(reg_grp_name, sizeof(reg_grp_name), iqs7222_reg_grp_names[reg_grp], reg_grp_index); reg_grp_node = device_get_named_child_node(&client->dev, @@ -2346,8 +2760,8 @@ static int iqs7222_parse_all(struct iqs7222_private *iqs7222) continue; /* - * The IQS7222C exposes multiple GPIO and must be informed - * as to which GPIO this group represents. + * The IQS7222C and IQS7222D expose multiple GPIO and must be + * informed as to which GPIO this group represents. */ for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++) gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]); @@ -2480,6 +2894,41 @@ static int iqs7222_report(struct iqs7222_private *iqs7222) iqs7222->sl_code[i][j], 0); } + for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) { + u16 tpad_pos_x = le16_to_cpu(status[4]); + u16 tpad_pos_y = le16_to_cpu(status[5]); + u16 state = le16_to_cpu(status[6]); + + input_report_key(iqs7222->keypad, iqs7222->tp_code[0], + tpad_pos_x < U16_MAX); + + if (tpad_pos_x < U16_MAX) + touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop, + tpad_pos_x, tpad_pos_y, false); + + if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD)) + continue; + + /* + * Skip the press/release event, as it does not have separate + * status fields and is handled separately. + */ + for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) { + u16 mask = iqs7222_tp_events[j].mask; + u16 val = iqs7222_tp_events[j].val; + + input_report_key(iqs7222->keypad, + iqs7222->tp_code[j], + (state & mask) == val); + } + + input_sync(iqs7222->keypad); + + for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) + input_report_key(iqs7222->keypad, + iqs7222->tp_code[j], 0); + } + input_sync(iqs7222->keypad); return 0; @@ -2584,6 +3033,7 @@ static const struct of_device_id iqs7222_of_match[] = { { .compatible = "azoteq,iqs7222a" }, { .compatible = "azoteq,iqs7222b" }, { .compatible = "azoteq,iqs7222c" }, + { .compatible = "azoteq,iqs7222d" }, { } }; MODULE_DEVICE_TABLE(of, iqs7222_of_match); @@ -2593,10 +3043,10 @@ static struct i2c_driver iqs7222_i2c_driver = { .name = "iqs7222", .of_match_table = iqs7222_of_match, }, - .probe_new = iqs7222_probe, + .probe = iqs7222_probe, }; module_i2c_driver(iqs7222_i2c_driver); MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); -MODULE_DESCRIPTION("Azoteq IQS7222A/B/C Capacitive Touch Controller"); +MODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 4e806d56c55d..912e614d039d 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -538,7 +538,7 @@ static struct i2c_driver kxtj9_driver = { .name = NAME, .pm = pm_sleep_ptr(&kxtj9_pm_ops), }, - .probe_new = kxtj9_probe, + .probe = kxtj9_probe, .id_table = kxtj9_id, }; diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c index b12152536976..76a190b2220b 100644 --- a/drivers/input/misc/mma8450.c +++ b/drivers/input/misc/mma8450.c @@ -202,7 +202,7 @@ static struct i2c_driver mma8450_driver = { .name = MMA8450_DRV_NAME, .of_match_table = mma8450_dt_ids, }, - .probe_new = mma8450_probe, + .probe = mma8450_probe, .id_table = mma8450_id, }; diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 6323c3d37ef7..536cedeb38e6 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -199,7 +199,7 @@ static struct i2c_driver pcf8574_kp_driver = { .name = DRV_NAME, .pm = pm_sleep_ptr(&pcf8574_kp_pm_ops), }, - .probe_new = pcf8574_kp_probe, + .probe = pcf8574_kp_probe, .remove = pcf8574_kp_remove, .id_table = pcf8574_kp_id, }; diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c index b6a27ebae977..74d77d8aaeff 100644 --- a/drivers/input/misc/pm8941-pwrkey.c +++ b/drivers/input/misc/pm8941-pwrkey.c @@ -50,7 +50,10 @@ #define PON_RESIN_PULL_UP BIT(0) #define PON_DBC_CTL 0x71 -#define PON_DBC_DELAY_MASK 0x7 +#define PON_DBC_DELAY_MASK_GEN1 0x7 +#define PON_DBC_DELAY_MASK_GEN2 0xf +#define PON_DBC_SHIFT_GEN1 6 +#define PON_DBC_SHIFT_GEN2 14 struct pm8941_data { unsigned int pull_up_bit; @@ -247,7 +250,7 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev) struct device *parent; struct device_node *regmap_node; const __be32 *addr; - u32 req_delay; + u32 req_delay, mask, delay_shift; int error; if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay)) @@ -336,12 +339,20 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev) pwrkey->input->phys = pwrkey->data->phys; if (pwrkey->data->supports_debounce_config) { - req_delay = (req_delay << 6) / USEC_PER_SEC; + if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY) { + mask = PON_DBC_DELAY_MASK_GEN2; + delay_shift = PON_DBC_SHIFT_GEN2; + } else { + mask = PON_DBC_DELAY_MASK_GEN1; + delay_shift = PON_DBC_SHIFT_GEN1; + } + + req_delay = (req_delay << delay_shift) / USEC_PER_SEC; req_delay = ilog2(req_delay); error = regmap_update_bits(pwrkey->regmap, pwrkey->baseaddr + PON_DBC_CTL, - PON_DBC_DELAY_MASK, + mask, req_delay); if (error) { dev_err(&pdev->dev, "failed to set debounce: %d\n", diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index 3cf1812384e6..1e731d8397c6 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -132,13 +132,8 @@ static int pwm_beeper_probe(struct platform_device *pdev) return -ENOMEM; beeper->pwm = devm_pwm_get(dev, NULL); - if (IS_ERR(beeper->pwm)) { - error = PTR_ERR(beeper->pwm); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to request PWM device: %d\n", - error); - return error; - } + if (IS_ERR(beeper->pwm)) + return dev_err_probe(dev, PTR_ERR(beeper->pwm), "Failed to request PWM device\n"); /* Sync up PWM state and ensure it is off. */ pwm_init_state(beeper->pwm, &state); @@ -151,13 +146,9 @@ static int pwm_beeper_probe(struct platform_device *pdev) } beeper->amplifier = devm_regulator_get(dev, "amp"); - if (IS_ERR(beeper->amplifier)) { - error = PTR_ERR(beeper->amplifier); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'amp' regulator: %d\n", - error); - return error; - } + if (IS_ERR(beeper->amplifier)) + return dev_err_probe(dev, PTR_ERR(beeper->amplifier), + "Failed to get 'amp' regulator\n"); INIT_WORK(&beeper->work, pwm_beeper_work); diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c index d0e58a7cdfa3..a3cde30ee8d2 100644 --- a/drivers/input/misc/pwm-vibra.c +++ b/drivers/input/misc/pwm-vibra.c @@ -11,6 +11,7 @@ * Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de> */ +#include <linux/gpio/consumer.h> #include <linux/input.h> #include <linux/kernel.h> #include <linux/module.h> @@ -23,6 +24,7 @@ struct pwm_vibrator { struct input_dev *input; + struct gpio_desc *enable_gpio; struct pwm_device *pwm; struct pwm_device *pwm_dir; struct regulator *vcc; @@ -42,19 +44,21 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) if (!vibrator->vcc_on) { err = regulator_enable(vibrator->vcc); if (err) { - dev_err(pdev, "failed to enable regulator: %d", err); + dev_err(pdev, "failed to enable regulator: %d\n", err); return err; } vibrator->vcc_on = true; } + gpiod_set_value_cansleep(vibrator->enable_gpio, 1); + pwm_get_state(vibrator->pwm, &state); pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff); state.enabled = true; err = pwm_apply_state(vibrator->pwm, &state); if (err) { - dev_err(pdev, "failed to apply pwm state: %d", err); + dev_err(pdev, "failed to apply pwm state: %d\n", err); return err; } @@ -65,7 +69,7 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator) err = pwm_apply_state(vibrator->pwm_dir, &state); if (err) { - dev_err(pdev, "failed to apply dir-pwm state: %d", err); + dev_err(pdev, "failed to apply dir-pwm state: %d\n", err); pwm_disable(vibrator->pwm); return err; } @@ -80,6 +84,8 @@ static void pwm_vibrator_stop(struct pwm_vibrator *vibrator) pwm_disable(vibrator->pwm_dir); pwm_disable(vibrator->pwm); + gpiod_set_value_cansleep(vibrator->enable_gpio, 0); + if (vibrator->vcc_on) { regulator_disable(vibrator->vcc); vibrator->vcc_on = false; @@ -134,22 +140,20 @@ static int pwm_vibrator_probe(struct platform_device *pdev) return -ENOMEM; vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc"); - err = PTR_ERR_OR_ZERO(vibrator->vcc); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request regulator: %d", - err); - return err; - } + if (IS_ERR(vibrator->vcc)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc), + "Failed to request regulator\n"); + + vibrator->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + GPIOD_OUT_LOW); + if (IS_ERR(vibrator->enable_gpio)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->enable_gpio), + "Failed to request enable gpio\n"); vibrator->pwm = devm_pwm_get(&pdev->dev, "enable"); - err = PTR_ERR_OR_ZERO(vibrator->pwm); - if (err) { - if (err != -EPROBE_DEFER) - dev_err(&pdev->dev, "Failed to request main pwm: %d", - err); - return err; - } + if (IS_ERR(vibrator->pwm)) + return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->pwm), + "Failed to request main pwm\n"); INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work); @@ -158,7 +162,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) state.enabled = false; err = pwm_apply_state(vibrator->pwm, &state); if (err) { - dev_err(&pdev->dev, "failed to apply initial PWM state: %d", + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", err); return err; } @@ -172,7 +176,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) state.enabled = false; err = pwm_apply_state(vibrator->pwm_dir, &state); if (err) { - dev_err(&pdev->dev, "failed to apply initial PWM state: %d", + dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n", err); return err; } @@ -189,7 +193,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev) break; default: - dev_err(&pdev->dev, "Failed to request direction pwm: %d", err); + dev_err(&pdev->dev, "Failed to request direction pwm: %d\n", err); fallthrough; case -EPROBE_DEFER: @@ -207,13 +211,13 @@ static int pwm_vibrator_probe(struct platform_device *pdev) err = input_ff_create_memless(vibrator->input, NULL, pwm_vibrator_play_effect); if (err) { - dev_err(&pdev->dev, "Couldn't create FF dev: %d", err); + dev_err(&pdev->dev, "Couldn't create FF dev: %d\n", err); return err; } err = input_register_device(vibrator->input); if (err) { - dev_err(&pdev->dev, "Couldn't register input dev: %d", err); + dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err); return err; } diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 22ec62083065..e94cab8133be 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -236,12 +236,8 @@ static int rotary_encoder_probe(struct platform_device *pdev) device_property_read_bool(dev, "rotary-encoder,relative-axis"); encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN); - if (IS_ERR(encoder->gpios)) { - err = PTR_ERR(encoder->gpios); - if (err != -EPROBE_DEFER) - dev_err(dev, "unable to get gpios: %d\n", err); - return err; - } + if (IS_ERR(encoder->gpios)) + return dev_err_probe(dev, PTR_ERR(encoder->gpios), "unable to get gpios\n"); if (encoder->gpios->ndescs < 2) { dev_err(dev, "not enough gpios found\n"); return -EINVAL; @@ -255,7 +251,6 @@ static int rotary_encoder_probe(struct platform_device *pdev) input->name = pdev->name; input->id.bustype = BUS_HOST; - input->dev.parent = dev; if (encoder->relative_axis) input_set_capability(input, EV_REL, encoder->axis); diff --git a/drivers/input/misc/tps65219-pwrbutton.c b/drivers/input/misc/tps65219-pwrbutton.c index 245134bdb59e..eeb9f2334ab4 100644 --- a/drivers/input/misc/tps65219-pwrbutton.c +++ b/drivers/input/misc/tps65219-pwrbutton.c @@ -117,14 +117,16 @@ static int tps65219_pb_probe(struct platform_device *pdev) return 0; } -static int tps65219_pb_remove(struct platform_device *pdev) +static void tps65219_pb_remove(struct platform_device *pdev) { struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent); + int ret; /* Disable interrupt for the pushbutton */ - return regmap_update_bits(tps->regmap, TPS65219_REG_MASK_CONFIG, - TPS65219_REG_MASK_INT_FOR_PB_MASK, - TPS65219_REG_MASK_INT_FOR_PB_MASK); + ret = regmap_set_bits(tps->regmap, TPS65219_REG_MASK_CONFIG, + TPS65219_REG_MASK_INT_FOR_PB_MASK); + if (ret) + dev_warn(&pdev->dev, "Failed to disable irq (%pe)\n", ERR_PTR(ret)); } static const struct platform_device_id tps65219_pwrbtn_id_table[] = { @@ -135,7 +137,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table); static struct platform_driver tps65219_pb_driver = { .probe = tps65219_pb_probe, - .remove = tps65219_pb_remove, + .remove_new = tps65219_pb_remove, .driver = { .name = "tps65219_pwrbutton", }, diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index f2593133e524..d98212d55108 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -33,6 +33,7 @@ #define UINPUT_NAME "uinput" #define UINPUT_BUFFER_SIZE 16 #define UINPUT_NUM_REQUESTS 16 +#define UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS 10 enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED }; @@ -569,11 +570,40 @@ static int uinput_setup_device_legacy(struct uinput_device *udev, return retval; } +/* + * Returns true if the given timestamp is valid (i.e., if all the following + * conditions are satisfied), false otherwise. + * 1) given timestamp is positive + * 2) it's within the allowed offset before the current time + * 3) it's not in the future + */ +static bool is_valid_timestamp(const ktime_t timestamp) +{ + ktime_t zero_time; + ktime_t current_time; + ktime_t min_time; + ktime_t offset; + + zero_time = ktime_set(0, 0); + if (ktime_compare(zero_time, timestamp) >= 0) + return false; + + current_time = ktime_get(); + offset = ktime_set(UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS, 0); + min_time = ktime_sub(current_time, offset); + + if (ktime_after(min_time, timestamp) || ktime_after(timestamp, current_time)) + return false; + + return true; +} + static ssize_t uinput_inject_events(struct uinput_device *udev, const char __user *buffer, size_t count) { struct input_event ev; size_t bytes = 0; + ktime_t timestamp; if (count != 0 && count < input_event_size()) return -EINVAL; @@ -588,6 +618,10 @@ static ssize_t uinput_inject_events(struct uinput_device *udev, if (input_event_from_user(buffer + bytes, &ev)) return -EFAULT; + timestamp = ktime_set(ev.input_event_sec, ev.input_event_usec * NSEC_PER_USEC); + if (is_valid_timestamp(timestamp)) + input_set_timestamp(udev->dev, timestamp); + input_event(udev->dev, ev.type, ev.code, ev.value); bytes += input_event_size(); cond_resched(); diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index dd7b0d70d791..05851bc32541 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1489,7 +1489,7 @@ static struct i2c_driver cyapa_driver = { .of_match_table = of_match_ptr(cyapa_of_match), }, - .probe_new = cyapa_probe, + .probe = cyapa_probe, .id_table = cyapa_id_table, }; diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 5f0d75a45c80..148a601396f9 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1221,13 +1221,8 @@ static int elan_probe(struct i2c_client *client) mutex_init(&data->sysfs_mutex); data->vcc = devm_regulator_get(dev, "vcc"); - if (IS_ERR(data->vcc)) { - error = PTR_ERR(data->vcc); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'vcc' regulator: %d\n", - error); - return error; - } + if (IS_ERR(data->vcc)) + return dev_err_probe(dev, PTR_ERR(data->vcc), "Failed to get 'vcc' regulator\n"); error = regulator_enable(data->vcc); if (error) { @@ -1424,7 +1419,7 @@ static struct i2c_driver elan_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, .dev_groups = elan_sysfs_groups, }, - .probe_new = elan_probe, + .probe = elan_probe, .id_table = elan_id, }; diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index c9a7e87b273e..a0aac76b1e41 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -116,6 +116,13 @@ static DEFINE_MUTEX(psmouse_mutex); static struct workqueue_struct *kpsmoused_wq; +struct psmouse *psmouse_from_serio(struct serio *serio) +{ + struct ps2dev *ps2dev = serio_get_drvdata(serio); + + return container_of(ps2dev, struct psmouse, ps2dev); +} + void psmouse_report_standard_buttons(struct input_dev *dev, u8 buttons) { input_report_key(dev, BTN_LEFT, buttons & BIT(0)); @@ -329,17 +336,14 @@ static void psmouse_handle_oob_data(struct psmouse *psmouse, u8 data) } } -/* - * psmouse_interrupt() handles incoming characters, either passing them - * for normal processing or gathering them as command response. - */ -static irqreturn_t psmouse_interrupt(struct serio *serio, - u8 data, unsigned int flags) +static enum ps2_disposition psmouse_pre_receive_byte(struct ps2dev *ps2dev, + u8 data, + unsigned int flags) { - struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = container_of(ps2dev, struct psmouse, ps2dev); if (psmouse->state == PSMOUSE_IGNORE) - goto out; + return PS2_IGNORE; if (unlikely((flags & SERIO_TIMEOUT) || ((flags & SERIO_PARITY) && @@ -350,27 +354,25 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, "bad data from KBC -%s%s\n", flags & SERIO_TIMEOUT ? " timeout" : "", flags & SERIO_PARITY ? " bad parity" : ""); - ps2_cmd_aborted(&psmouse->ps2dev); - goto out; + return PS2_ERROR; } if (flags & SERIO_OOB_DATA) { psmouse_handle_oob_data(psmouse, data); - goto out; + return PS2_IGNORE; } - if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK)) - if (ps2_handle_ack(&psmouse->ps2dev, data)) - goto out; + return PS2_PROCESS; +} - if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD)) - if (ps2_handle_response(&psmouse->ps2dev, data)) - goto out; +static void psmouse_receive_byte(struct ps2dev *ps2dev, u8 data) +{ + struct psmouse *psmouse = container_of(ps2dev, struct psmouse, ps2dev); - pm_wakeup_event(&serio->dev, 0); + pm_wakeup_event(&ps2dev->serio->dev, 0); if (psmouse->state <= PSMOUSE_RESYNCING) - goto out; + return; if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { @@ -379,7 +381,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); psmouse_queue_work(psmouse, &psmouse->resync_work, 0); - goto out; + return; } psmouse->packet[psmouse->pktcnt++] = data; @@ -388,21 +390,21 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { if (psmouse->pktcnt == 1) { psmouse->last = jiffies; - goto out; + return; } if (psmouse->packet[1] == PSMOUSE_RET_ID || (psmouse->protocol->type == PSMOUSE_HGPK && psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - serio_reconnect(serio); - goto out; + serio_reconnect(ps2dev->serio); + return; } /* Not a new device, try processing first byte normally */ psmouse->pktcnt = 1; if (psmouse_handle_byte(psmouse)) - goto out; + return; psmouse->packet[psmouse->pktcnt++] = data; } @@ -417,14 +419,11 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); psmouse_queue_work(psmouse, &psmouse->resync_work, 0); - goto out; + return; } psmouse->last = jiffies; psmouse_handle_byte(psmouse); - - out: - return IRQ_HANDLED; } /* @@ -1344,7 +1343,7 @@ static void psmouse_resync(struct work_struct *work) goto out; if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); psmouse_deactivate(parent); } @@ -1428,13 +1427,13 @@ static void psmouse_resync(struct work_struct *work) */ static void psmouse_cleanup(struct serio *serio) { - struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = psmouse_from_serio(serio); struct psmouse *parent = NULL; mutex_lock(&psmouse_mutex); if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); psmouse_deactivate(parent); } @@ -1476,7 +1475,7 @@ static void psmouse_cleanup(struct serio *serio) */ static void psmouse_disconnect(struct serio *serio) { - struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = psmouse_from_serio(serio); struct psmouse *parent = NULL; mutex_lock(&psmouse_mutex); @@ -1489,7 +1488,7 @@ static void psmouse_disconnect(struct serio *serio) mutex_lock(&psmouse_mutex); if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); psmouse_deactivate(parent); } @@ -1588,7 +1587,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) * connected to this port can be successfully identified */ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); psmouse_deactivate(parent); } @@ -1597,15 +1596,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (!psmouse || !input_dev) goto err_free; - ps2_init(&psmouse->ps2dev, serio); + ps2_init(&psmouse->ps2dev, serio, + psmouse_pre_receive_byte, psmouse_receive_byte); INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync); psmouse->dev = input_dev; snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - serio_set_drvdata(serio, psmouse); - error = serio_open(serio, drv); if (error) goto err_clear_drvdata; @@ -1676,7 +1674,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) { - struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = psmouse_from_serio(serio); struct psmouse *parent = NULL; int (*reconnect_handler)(struct psmouse *); enum psmouse_type type; @@ -1695,7 +1693,7 @@ static int __psmouse_reconnect(struct serio *serio, bool fast_reconnect) } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); psmouse_deactivate(parent); } @@ -1781,7 +1779,7 @@ static struct serio_driver psmouse_drv = { }, .description = DRIVER_DESC, .id_table = psmouse_serio_ids, - .interrupt = psmouse_interrupt, + .interrupt = ps2_interrupt, .connect = psmouse_connect, .reconnect = psmouse_reconnect, .fast_reconnect = psmouse_fast_reconnect, @@ -1794,7 +1792,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de { struct serio *serio = to_serio_port(dev); struct psmouse_attribute *attr = to_psmouse_attr(devattr); - struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = psmouse_from_serio(serio); if (psmouse->protocol->smbus_companion && devattr != &psmouse_attr_protocol.dattr) @@ -1815,7 +1813,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev if (retval) goto out; - psmouse = serio_get_drvdata(serio); + psmouse = psmouse_from_serio(serio); if (psmouse->protocol->smbus_companion && devattr != &psmouse_attr_protocol.dattr) { @@ -1830,7 +1828,7 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); psmouse_deactivate(parent); } @@ -1925,7 +1923,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co } if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); + parent = psmouse_from_serio(serio->parent); if (parent->pt_deactivate) parent->pt_deactivate(parent); } diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 64c3a5d3fb3e..4d8acfe0d82a 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -130,6 +130,8 @@ struct psmouse { void (*pt_deactivate)(struct psmouse *psmouse); }; +struct psmouse *psmouse_from_serio(struct serio *serio); + void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, unsigned long delay); int psmouse_reset(struct psmouse *psmouse); diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index fa021af8506e..ada299ec5bba 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -628,7 +628,7 @@ static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) ****************************************************************************/ static int synaptics_pt_write(struct serio *serio, u8 c) { - struct psmouse *parent = serio_get_drvdata(serio->parent); + struct psmouse *parent = psmouse_from_serio(serio->parent); u8 rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ int error; @@ -645,7 +645,7 @@ static int synaptics_pt_write(struct serio *serio, u8 c) static int synaptics_pt_start(struct serio *serio) { - struct psmouse *parent = serio_get_drvdata(serio->parent); + struct psmouse *parent = psmouse_from_serio(serio->parent); struct synaptics_data *priv = parent->private; serio_pause_rx(parent->ps2dev.serio); @@ -657,7 +657,7 @@ static int synaptics_pt_start(struct serio *serio) static void synaptics_pt_stop(struct serio *serio) { - struct psmouse *parent = serio_get_drvdata(serio->parent); + struct psmouse *parent = psmouse_from_serio(serio->parent); struct synaptics_data *priv = parent->private; serio_pause_rx(parent->ps2dev.serio); @@ -672,7 +672,7 @@ static int synaptics_is_pt_packet(u8 *buf) static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet) { - struct psmouse *child = serio_get_drvdata(ptport); + struct psmouse *child = psmouse_from_serio(ptport); if (child && child->state == PSMOUSE_ACTIVATED) { serio_interrupt(ptport, packet[1], 0); @@ -688,7 +688,7 @@ static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet) static void synaptics_pt_activate(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - struct psmouse *child = serio_get_drvdata(priv->pt_port); + struct psmouse *child = psmouse_from_serio(priv->pt_port); /* adjust the touchpad to child's choice of protocol */ if (child) { diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index 068692a8aba5..af5cc64c622d 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -650,7 +650,7 @@ static struct i2c_driver synaptics_i2c_driver = { .pm = pm_sleep_ptr(&synaptics_i2c_pm), }, - .probe_new = synaptics_i2c_probe, + .probe = synaptics_i2c_probe, .remove = synaptics_i2c_remove, .id_table = synaptics_i2c_id_table, diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 4a86b3e31d3b..5f6643b69a2c 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -216,7 +216,7 @@ static umode_t trackpoint_is_attr_visible(struct kobject *kobj, { struct device *dev = kobj_to_dev(kobj); struct serio *serio = to_serio_port(dev); - struct psmouse *psmouse = serio_get_drvdata(serio); + struct psmouse *psmouse = psmouse_from_serio(serio); return trackpoint_is_attr_available(psmouse, attr) ? attr->mode : 0; } diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index d69569ce8d8d..091d4e23b629 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -377,7 +377,7 @@ static struct i2c_driver rmi_i2c_driver = { .of_match_table = of_match_ptr(rmi_i2c_of_match), }, .id_table = rmi_id, - .probe_new = rmi_i2c_probe, + .probe = rmi_i2c_probe, }; module_i2c_driver(rmi_i2c_driver); diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c index 4bf0e1df6a4a..7059a2762aeb 100644 --- a/drivers/input/rmi4/rmi_smbus.c +++ b/drivers/input/rmi4/rmi_smbus.c @@ -418,7 +418,7 @@ static struct i2c_driver rmi_smb_driver = { .pm = pm_ptr(&rmi_smb_pm), }, .id_table = rmi_id, - .probe_new = rmi_smb_probe, + .probe = rmi_smb_probe, .remove = rmi_smb_remove, }; diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig index f39b7b3f7942..17edc1597446 100644 --- a/drivers/input/serio/Kconfig +++ b/drivers/input/serio/Kconfig @@ -148,6 +148,7 @@ config HIL_MLC config SERIO_PCIPS2 tristate "PCI PS/2 keyboard and PS/2 mouse controller" depends on PCI + depends on HAS_IOPORT help Say Y here if you have a Mobility Docking station with PS/2 keyboard and mice ports. diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c index 3e19344eda93..6d78a1fe00c1 100644 --- a/drivers/input/serio/libps2.c +++ b/drivers/input/serio/libps2.c @@ -19,9 +19,26 @@ #define DRIVER_DESC "PS/2 driver library" -MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); -MODULE_DESCRIPTION("PS/2 driver library"); -MODULE_LICENSE("GPL"); +#define PS2_CMD_SETSCALE11 0x00e6 +#define PS2_CMD_SETRES 0x10e8 +#define PS2_CMD_EX_SETLEDS 0x20eb +#define PS2_CMD_SETLEDS 0x10ed +#define PS2_CMD_GETID 0x02f2 +#define PS2_CMD_SETREP 0x10f3 /* Set repeat rate/set report rate */ +#define PS2_CMD_RESET_BAT 0x02ff + +#define PS2_RET_BAT 0xaa +#define PS2_RET_ID 0x00 +#define PS2_RET_ACK 0xfa +#define PS2_RET_NAK 0xfe +#define PS2_RET_ERR 0xfc + +#define PS2_FLAG_ACK BIT(0) /* Waiting for ACK/NAK */ +#define PS2_FLAG_CMD BIT(1) /* Waiting for a command to finish */ +#define PS2_FLAG_CMD1 BIT(2) /* Waiting for the first byte of command response */ +#define PS2_FLAG_WAITID BIT(3) /* Command executing is GET ID */ +#define PS2_FLAG_NAK BIT(4) /* Last transmission was NAKed */ +#define PS2_FLAG_PASS_NOACK BIT(5) /* Pass non-ACK byte to receive handler */ static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout, unsigned int max_attempts) @@ -76,14 +93,17 @@ static int ps2_do_sendbyte(struct ps2dev *ps2dev, u8 byte, return error; } -/* - * ps2_sendbyte() sends a byte to the device and waits for acknowledge. - * It doesn't handle retransmission, the caller is expected to handle +/** + * ps2_sendbyte - sends a byte to the device and wait for acknowledgement + * @ps2dev: a PS/2 device to send the data to + * @byte: data to be sent to the device + * @timeout: timeout for sending the data and receiving an acknowledge + * + * The function doesn't handle retransmission, the caller is expected to handle * it when needed. * * ps2_sendbyte() can only be called from a process context. */ - int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) { int retval; @@ -99,6 +119,13 @@ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout) } EXPORT_SYMBOL(ps2_sendbyte); +/** + * ps2_begin_command - mark beginning of execution of a complex command + * @ps2dev: a PS/2 device executing the command + * + * Serializes a complex/compound command. Once command is finished + * ps2_end_command() should be called. + */ void ps2_begin_command(struct ps2dev *ps2dev) { struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; @@ -107,6 +134,10 @@ void ps2_begin_command(struct ps2dev *ps2dev) } EXPORT_SYMBOL(ps2_begin_command); +/** + * ps2_end_command - mark end of execution of a complex command + * @ps2dev: a PS/2 device executing the command + */ void ps2_end_command(struct ps2dev *ps2dev) { struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; @@ -115,11 +146,13 @@ void ps2_end_command(struct ps2dev *ps2dev) } EXPORT_SYMBOL(ps2_end_command); -/* - * ps2_drain() waits for device to transmit requested number of bytes - * and discards them. +/** + * ps2_drain - waits for device to transmit requested number of bytes + * and discards them + * @ps2dev: the PS/2 device that should be drained + * @maxbytes: maximum number of bytes to be drained + * @timeout: time to drain the device */ - void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout) { if (maxbytes > sizeof(ps2dev->cmdbuf)) { @@ -142,11 +175,11 @@ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout) } EXPORT_SYMBOL(ps2_drain); -/* - * ps2_is_keyboard_id() checks received ID byte against the list of - * known keyboard IDs. +/** + * ps2_is_keyboard_id - checks received ID byte against the list of + * known keyboard IDs + * @id_byte: data byte that should be checked */ - bool ps2_is_keyboard_id(u8 id_byte) { static const u8 keyboard_ids[] = { @@ -167,7 +200,6 @@ EXPORT_SYMBOL(ps2_is_keyboard_id); * response and tries to reduce remaining timeout to speed up command * completion. */ - static int ps2_adjust_timeout(struct ps2dev *ps2dev, unsigned int command, unsigned int timeout) { @@ -217,13 +249,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, return timeout; } -/* - * ps2_command() sends a command and its parameters to the mouse, - * then waits for the response and puts it in the param array. +/** + * __ps2_command - send a command to PS/2 device + * @ps2dev: the PS/2 device that should execute the command + * @param: a buffer containing parameters to be sent along with the command, + * or place where the results of the command execution will be deposited, + * or both + * @command: command word that encodes the command itself, as well as number of + * additional parameter bytes that should be sent to the device and expected + * length of the command response * - * ps2_command() can only be called from a process context + * Not serialized. Callers should use ps2_begin_command() and ps2_end_command() + * to ensure proper serialization for complex commands. */ - int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) { unsigned int timeout; @@ -247,17 +285,38 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) serio_pause_rx(ps2dev->serio); - ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; ps2dev->cmdcnt = receive; - if (receive && param) - for (i = 0; i < receive; i++) - ps2dev->cmdbuf[(receive - 1) - i] = param[i]; - /* Signal that we are sending the command byte */ - ps2dev->flags |= PS2_FLAG_ACK_CMD; + switch (command) { + case PS2_CMD_GETID: + /* + * Some mice do not ACK the "get ID" command, prepare to + * handle this. + */ + ps2dev->flags = PS2_FLAG_WAITID; + break; + + case PS2_CMD_SETLEDS: + case PS2_CMD_EX_SETLEDS: + case PS2_CMD_SETREP: + ps2dev->flags = PS2_FLAG_PASS_NOACK; + break; + + default: + ps2dev->flags = 0; + break; + } + + if (receive) { + /* Indicate that we expect response to the command. */ + ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; + if (param) + for (i = 0; i < receive; i++) + ps2dev->cmdbuf[(receive - 1) - i] = param[i]; + } /* - * Some devices (Synaptics) peform the reset before + * Some devices (Synaptics) perform the reset before * ACKing the reset command, and so it can take a long * time before the ACK arrives. */ @@ -267,9 +326,7 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) if (rc) goto out_reset_flags; - /* Now we are sending command parameters, if any */ - ps2dev->flags &= ~PS2_FLAG_ACK_CMD; - + /* Send command parameters, if any. */ for (i = 0; i < send; i++) { rc = ps2_do_sendbyte(ps2dev, param[i], 200, 2); if (rc) @@ -327,6 +384,20 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) } EXPORT_SYMBOL(__ps2_command); +/** + * ps2_command - send a command to PS/2 device + * @ps2dev: the PS/2 device that should execute the command + * @param: a buffer containing parameters to be sent along with the command, + * or place where the results of the command execution will be deposited, + * or both + * @command: command word that encodes the command itself, as well as number of + * additional parameter bytes that should be sent to the device and expected + * length of the command response + * + * Note: ps2_command() serializes the command execution so that only one + * command can be executed at a time for either individual port or the entire + * 8042 controller. + */ int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) { int rc; @@ -339,14 +410,16 @@ int ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command) } EXPORT_SYMBOL(ps2_command); -/* - * ps2_sliced_command() sends an extended PS/2 command to the mouse - * using sliced syntax, understood by advanced devices, such as Logitech - * or Synaptics touchpads. The command is encoded as: +/** + * ps2_sliced_command - sends an extended PS/2 command to a mouse + * @ps2dev: the PS/2 device that should execute the command + * @command: command byte + * + * The command is sent using "sliced" syntax understood by advanced devices, + * such as Logitech or Synaptics touchpads. The command is encoded as: * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu * is the command. */ - int ps2_sliced_command(struct ps2dev *ps2dev, u8 command) { int i; @@ -372,25 +445,60 @@ out: } EXPORT_SYMBOL(ps2_sliced_command); -/* - * ps2_init() initializes ps2dev structure +/** + * ps2_init - initializes ps2dev structure + * @ps2dev: structure to be initialized + * @serio: serio port associated with the PS/2 device + * @pre_receive_handler: validation handler to check basic communication state + * @receive_handler: main protocol handler + * + * Prepares ps2dev structure for use in drivers for PS/2 devices. */ - -void ps2_init(struct ps2dev *ps2dev, struct serio *serio) +void ps2_init(struct ps2dev *ps2dev, struct serio *serio, + ps2_pre_receive_handler_t pre_receive_handler, + ps2_receive_handler_t receive_handler) { + ps2dev->pre_receive_handler = pre_receive_handler; + ps2dev->receive_handler = receive_handler; + mutex_init(&ps2dev->cmd_mutex); lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth); init_waitqueue_head(&ps2dev->wait); ps2dev->serio = serio; + serio_set_drvdata(serio, ps2dev); } EXPORT_SYMBOL(ps2_init); /* - * ps2_handle_ack() is supposed to be used in interrupt handler - * to properly process ACK/NAK of a command from a PS/2 device. + * ps2_handle_response() stores device's response to a command and notifies + * the process waiting for completion of the command. Note that there is a + * distinction between waiting for the first byte of the response, and + * waiting for subsequent bytes. It is done so that callers could shorten + * timeouts once first byte of response is received. */ +static void ps2_handle_response(struct ps2dev *ps2dev, u8 data) +{ + if (ps2dev->cmdcnt) + ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; + + if (ps2dev->flags & PS2_FLAG_CMD1) { + ps2dev->flags &= ~PS2_FLAG_CMD1; + if (ps2dev->cmdcnt) + wake_up(&ps2dev->wait); + } + + if (!ps2dev->cmdcnt) { + ps2dev->flags &= ~PS2_FLAG_CMD; + wake_up(&ps2dev->wait); + } +} -bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data) +/* + * ps2_handle_ack() processes ACK/NAK of a command from a PS/2 device, + * possibly applying workarounds for mice not acknowledging the "get ID" + * command. + */ +static void ps2_handle_ack(struct ps2dev *ps2dev, u8 data) { switch (data) { case PS2_RET_ACK: @@ -427,68 +535,89 @@ bool ps2_handle_ack(struct ps2dev *ps2dev, u8 data) * Do not signal errors if we get unexpected reply while * waiting for an ACK to the initial (first) command byte: * the device might not be quiesced yet and continue - * delivering data. + * delivering data. For certain commands (such as set leds and + * set repeat rate) that can be used during normal device + * operation, we even pass this data byte to the normal receive + * handler. * Note that we reset PS2_FLAG_WAITID flag, so the workaround * for mice not acknowledging the Get ID command only triggers * on the 1st byte; if device spews data we really want to see * a real ACK from it. */ dev_dbg(&ps2dev->serio->dev, "unexpected %#02x\n", data); - ps2dev->flags &= ~PS2_FLAG_WAITID; - return ps2dev->flags & PS2_FLAG_ACK_CMD; + if (ps2dev->flags & PS2_FLAG_PASS_NOACK) + ps2dev->receive_handler(ps2dev, data); + ps2dev->flags &= ~(PS2_FLAG_WAITID | PS2_FLAG_PASS_NOACK); + return; } - if (!ps2dev->nak) { + if (!ps2dev->nak) ps2dev->flags &= ~PS2_FLAG_NAK; - if (ps2dev->cmdcnt) - ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; - } ps2dev->flags &= ~PS2_FLAG_ACK; - wake_up(&ps2dev->wait); - if (data != PS2_RET_ACK) + if (!ps2dev->nak && data != PS2_RET_ACK) ps2_handle_response(ps2dev, data); - - return true; + else + wake_up(&ps2dev->wait); } -EXPORT_SYMBOL(ps2_handle_ack); /* - * ps2_handle_response() is supposed to be used in interrupt handler - * to properly store device's response to a command and notify process - * waiting for completion of the command. + * Clears state of PS/2 device after communication error by resetting majority + * of flags and waking up waiters, if any. */ - -bool ps2_handle_response(struct ps2dev *ps2dev, u8 data) +static void ps2_cleanup(struct ps2dev *ps2dev) { - if (ps2dev->cmdcnt) - ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; + unsigned long old_flags = ps2dev->flags; - if (ps2dev->flags & PS2_FLAG_CMD1) { - ps2dev->flags &= ~PS2_FLAG_CMD1; - if (ps2dev->cmdcnt) - wake_up(&ps2dev->wait); - } + /* reset all flags except last nak */ + ps2dev->flags &= PS2_FLAG_NAK; - if (!ps2dev->cmdcnt) { - ps2dev->flags &= ~PS2_FLAG_CMD; - wake_up(&ps2dev->wait); - } + if (old_flags & PS2_FLAG_ACK) + ps2dev->nak = 1; - return true; + if (old_flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) + wake_up(&ps2dev->wait); } -EXPORT_SYMBOL(ps2_handle_response); -void ps2_cmd_aborted(struct ps2dev *ps2dev) -{ - if (ps2dev->flags & PS2_FLAG_ACK) - ps2dev->nak = 1; +/** + * ps2_interrupt - common interrupt handler for PS/2 devices + * @serio: serio port for the device + * @data: a data byte received from the device + * @flags: flags such as %SERIO_PARITY or %SERIO_TIMEOUT indicating state of + * the data transfer + * + * ps2_interrupt() invokes pre-receive handler, optionally handles command + * acknowledgement and response from the device, and finally passes the data + * to the main protocol handler for future processing. + */ +irqreturn_t ps2_interrupt(struct serio *serio, u8 data, unsigned int flags) { + struct ps2dev *ps2dev = serio_get_drvdata(serio); + enum ps2_disposition rc; + + rc = ps2dev->pre_receive_handler(ps2dev, data, flags); + switch (rc) { + case PS2_ERROR: + ps2_cleanup(ps2dev); + break; - if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) - wake_up(&ps2dev->wait); + case PS2_IGNORE: + break; - /* reset all flags except last nack */ - ps2dev->flags &= PS2_FLAG_NAK; + case PS2_PROCESS: + if (ps2dev->flags & PS2_FLAG_ACK) + ps2_handle_ack(ps2dev, data); + else if (ps2dev->flags & PS2_FLAG_CMD) + ps2_handle_response(ps2dev, data); + else + ps2dev->receive_handler(ps2dev, data); + break; + } + + return IRQ_HANDLED; } -EXPORT_SYMBOL(ps2_cmd_aborted); +EXPORT_SYMBOL(ps2_interrupt); + +MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>"); +MODULE_DESCRIPTION("PS/2 driver library"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/tests/input_test.c b/drivers/input/tests/input_test.c index e5a6c1ad2167..2fa5b725ae0a 100644 --- a/drivers/input/tests/input_test.c +++ b/drivers/input/tests/input_test.c @@ -43,8 +43,8 @@ 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); + if (input_dev) + input_unregister_device(input_dev); } static void input_test_poll(struct input_dev *input) { } @@ -87,7 +87,7 @@ static void input_test_timestamp(struct kunit *test) static void input_test_match_device_id(struct kunit *test) { struct input_dev *input_dev = test->priv; - struct input_device_id id; + struct input_device_id id = { 0 }; /* * Must match when the input device bus, vendor, product, version @@ -130,10 +130,42 @@ static void input_test_match_device_id(struct kunit *test) KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); } +static void input_test_grab(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + struct input_handle test_handle; + struct input_handler handler; + struct input_handle handle; + struct input_device_id id; + int res; + + handler.name = "handler"; + handler.id_table = &id; + + handle.dev = input_get_device(input_dev); + handle.name = dev_name(&input_dev->dev); + handle.handler = &handler; + res = input_grab_device(&handle); + KUNIT_ASSERT_TRUE(test, res == 0); + + test_handle.dev = input_get_device(input_dev); + test_handle.name = dev_name(&input_dev->dev); + test_handle.handler = &handler; + res = input_grab_device(&test_handle); + KUNIT_ASSERT_EQ(test, res, -EBUSY); + + input_release_device(&handle); + input_put_device(input_dev); + res = input_grab_device(&test_handle); + KUNIT_ASSERT_TRUE(test, res == 0); + input_put_device(input_dev); +} + static struct kunit_case input_tests[] = { KUNIT_CASE(input_test_polling), KUNIT_CASE(input_test_timestamp), KUNIT_CASE(input_test_match_device_id), + KUNIT_CASE(input_test_grab), { /* sentinel */ } }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 143ff43c67ae..e3e2324547b9 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -655,10 +655,10 @@ config TOUCHSCREEN_MTOUCH module will be called mtouch. config TOUCHSCREEN_NOVATEK_NVT_TS - tristate "Novatek NVT-ts touchscreen support" + tristate "Novatek NT11205 touchscreen support" depends on I2C help - Say Y here if you have a Novatek NVT-ts touchscreen. + Say Y here if you have a Novatek NT11205 touchscreen. If unsure, say N. To compile this driver as a module, choose M here: the @@ -700,6 +700,7 @@ config TOUCHSCREEN_INEXIO config TOUCHSCREEN_MK712 tristate "ICS MicroClock MK712 touchscreen" + depends on ISA help Say Y here if you have the ICS MicroClock MK712 touchscreen controller chip in your system. @@ -1364,6 +1365,16 @@ config TOUCHSCREEN_IQS5XX To compile this driver as a module, choose M here: the module will be called iqs5xx. +config TOUCHSCREEN_IQS7211 + tristate "Azoteq IQS7210A/7211A/E trackpad/touchscreen controller" + depends on I2C + help + Say Y to enable support for the Azoteq IQS7210A/7211A/E + family of trackpad/touchscreen controllers. + + To compile this driver as a module, choose M here: the + module will be called iqs7211. + config TOUCHSCREEN_ZINITIX tristate "Zinitix touchscreen support" depends on I2C diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 159cd5136fdb..62bd24f3ac8e 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -115,5 +115,6 @@ obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_RASPBERRYPI_FW) += raspberrypi-ts.o obj-$(CONFIG_TOUCHSCREEN_IQS5XX) += iqs5xx.o +obj-$(CONFIG_TOUCHSCREEN_IQS7211) += iqs7211.o obj-$(CONFIG_TOUCHSCREEN_ZINITIX) += zinitix.o obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX83112B) += himax_hx83112b.o diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index dd8f31737bb8..feaa6f8b01ed 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -62,7 +62,7 @@ static struct i2c_driver ad7879_i2c_driver = { .pm = &ad7879_pm_ops, .of_match_table = of_match_ptr(ad7879_i2c_dt_ids), }, - .probe_new = ad7879_i2c_probe, + .probe = ad7879_i2c_probe, .id_table = ad7879_id, }; diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index 3a5b65cae360..64dfb749386f 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -182,7 +182,7 @@ static struct i2c_driver ar1021_i2c_driver = { .of_match_table = ar1021_i2c_of_match, }, - .probe_new = ar1021_i2c_probe, + .probe = ar1021_i2c_probe, .id_table = ar1021_i2c_id, }; module_i2c_driver(ar1021_i2c_driver); diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index 996bf434e1cb..20094b9899f0 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -55,6 +55,7 @@ #define MXT_TOUCH_KEYARRAY_T15 15 #define MXT_TOUCH_PROXIMITY_T23 23 #define MXT_TOUCH_PROXKEY_T52 52 +#define MXT_TOUCH_PTC_KEYS_T97 97 #define MXT_PROCI_GRIPFACE_T20 20 #define MXT_PROCG_NOISE_T22 22 #define MXT_PROCI_ONETOUCH_T24 24 @@ -326,9 +327,13 @@ struct mxt_data { u16 T71_address; u8 T9_reportid_min; u8 T9_reportid_max; + u8 T15_reportid_min; + u8 T15_reportid_max; u16 T18_address; u8 T19_reportid; u16 T44_address; + u8 T97_reportid_min; + u8 T97_reportid_max; u8 T100_reportid_min; u8 T100_reportid_max; @@ -344,6 +349,9 @@ struct mxt_data { u32 *t19_keymap; unsigned int t19_num_keys; + u32 *t15_keymap; + unsigned int t15_num_keys; + enum mxt_suspend_mode suspend_mode; u32 wakeup_method; @@ -375,6 +383,7 @@ static bool mxt_object_readable(unsigned int type) case MXT_TOUCH_KEYARRAY_T15: case MXT_TOUCH_PROXIMITY_T23: case MXT_TOUCH_PROXKEY_T52: + case MXT_TOUCH_PTC_KEYS_T97: case MXT_TOUCH_MULTITOUCHSCREEN_T100: case MXT_PROCI_GRIPFACE_T20: case MXT_PROCG_NOISE_T22: @@ -891,6 +900,24 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message) data->update_input = true; } +static void mxt_proc_t15_messages(struct mxt_data *data, u8 *message) +{ + struct input_dev *input_dev = data->input_dev; + unsigned long keystates = get_unaligned_le32(&message[2]); + int key; + + for (key = 0; key < data->t15_num_keys; key++) + input_report_key(input_dev, data->t15_keymap[key], + keystates & BIT(key)); + + data->update_input = true; +} + +static void mxt_proc_t97_messages(struct mxt_data *data, u8 *message) +{ + mxt_proc_t15_messages(data, message); +} + static void mxt_proc_t100_message(struct mxt_data *data, u8 *message) { struct device *dev = &data->client->dev; @@ -1017,6 +1044,12 @@ static int mxt_proc_message(struct mxt_data *data, u8 *message) } else if (report_id >= data->T9_reportid_min && report_id <= data->T9_reportid_max) { mxt_proc_t9_message(data, message); + } else if (report_id >= data->T15_reportid_min && + report_id <= data->T15_reportid_max) { + mxt_proc_t15_messages(data, message); + } else if (report_id >= data->T97_reportid_min && + report_id <= data->T97_reportid_max) { + mxt_proc_t97_messages(data, message); } else if (report_id >= data->T100_reportid_min && report_id <= data->T100_reportid_max) { mxt_proc_t100_message(data, message); @@ -1689,9 +1722,13 @@ static void mxt_free_object_table(struct mxt_data *data) data->T71_address = 0; data->T9_reportid_min = 0; data->T9_reportid_max = 0; + data->T15_reportid_min = 0; + data->T15_reportid_max = 0; data->T18_address = 0; data->T19_reportid = 0; data->T44_address = 0; + data->T97_reportid_min = 0; + data->T97_reportid_max = 0; data->T100_reportid_min = 0; data->T100_reportid_max = 0; data->max_reportid = 0; @@ -1764,6 +1801,10 @@ static int mxt_parse_object_table(struct mxt_data *data, object->num_report_ids - 1; data->num_touchids = object->num_report_ids; break; + case MXT_TOUCH_KEYARRAY_T15: + data->T15_reportid_min = min_id; + data->T15_reportid_max = max_id; + break; case MXT_SPT_COMMSCONFIG_T18: data->T18_address = object->start_address; break; @@ -1773,6 +1814,10 @@ static int mxt_parse_object_table(struct mxt_data *data, case MXT_SPT_GPIOPWM_T19: data->T19_reportid = min_id; break; + case MXT_TOUCH_PTC_KEYS_T97: + data->T97_reportid_min = min_id; + data->T97_reportid_max = max_id; + break; case MXT_TOUCH_MULTITOUCHSCREEN_T100: data->multitouch = MXT_TOUCH_MULTITOUCHSCREEN_T100; data->T100_reportid_min = min_id; @@ -2050,6 +2095,7 @@ static int mxt_initialize_input_device(struct mxt_data *data) int error; unsigned int num_mt_slots; unsigned int mt_flags = 0; + int i; switch (data->multitouch) { case MXT_TOUCH_MULTI_T9: @@ -2095,6 +2141,10 @@ static int mxt_initialize_input_device(struct mxt_data *data) input_dev->open = mxt_input_open; input_dev->close = mxt_input_close; + input_dev->keycode = data->t15_keymap; + input_dev->keycodemax = data->t15_num_keys; + input_dev->keycodesize = sizeof(data->t15_keymap[0]); + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); /* For single touch */ @@ -2162,6 +2212,13 @@ static int mxt_initialize_input_device(struct mxt_data *data) 0, 255, 0, 0); } + /* For T15 and T97 Key Array */ + if (data->T15_reportid_min || data->T97_reportid_min) { + for (i = 0; i < data->t15_num_keys; i++) + input_set_capability(input_dev, + EV_KEY, data->t15_keymap[i]); + } + input_set_drvdata(input_dev, data); error = input_register_device(input_dev); @@ -3080,8 +3137,10 @@ static void mxt_input_close(struct input_dev *dev) static int mxt_parse_device_properties(struct mxt_data *data) { static const char keymap_property[] = "linux,gpio-keymap"; + static const char buttons_property[] = "linux,keycodes"; struct device *dev = &data->client->dev; u32 *keymap; + u32 *buttonmap; int n_keys; int error; @@ -3111,6 +3170,32 @@ static int mxt_parse_device_properties(struct mxt_data *data) data->t19_num_keys = n_keys; } + if (device_property_present(dev, buttons_property)) { + n_keys = device_property_count_u32(dev, buttons_property); + if (n_keys <= 0) { + error = n_keys < 0 ? n_keys : -EINVAL; + dev_err(dev, "invalid/malformed '%s' property: %d\n", + buttons_property, error); + return error; + } + + buttonmap = devm_kmalloc_array(dev, n_keys, sizeof(*buttonmap), + GFP_KERNEL); + if (!buttonmap) + return -ENOMEM; + + error = device_property_read_u32_array(dev, buttons_property, + buttonmap, n_keys); + if (error) { + dev_err(dev, "failed to parse '%s' property: %d\n", + buttons_property, error); + return error; + } + + data->t15_keymap = buttonmap; + data->t15_num_keys = n_keys; + } + return 0; } @@ -3377,7 +3462,7 @@ static struct i2c_driver mxt_driver = { .acpi_match_table = ACPI_PTR(mxt_acpi_id), .pm = pm_sleep_ptr(&mxt_pm_ops), }, - .probe_new = mxt_probe, + .probe = mxt_probe, .remove = mxt_remove, .id_table = mxt_id, }; diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 5359efc80b2b..90c682e7407f 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -636,7 +636,7 @@ static struct i2c_driver auo_pixcir_driver = { .pm = pm_sleep_ptr(&auo_pixcir_pm_ops), .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable), }, - .probe_new = auo_pixcir_probe, + .probe = auo_pixcir_probe, .id_table = auo_pixcir_idtable, }; diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index c994ab6f4e58..652439a79e21 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -410,31 +410,32 @@ static int bu21013_probe(struct i2c_client *client) struct input_dev *in_dev; struct input_absinfo *info; u32 max_x = 0, max_y = 0; + struct device *dev = &client->dev; int error; if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, "i2c smbus byte data not supported\n"); + dev_err(dev, "i2c smbus byte data not supported\n"); return -EIO; } if (!client->irq) { - dev_err(&client->dev, "No IRQ set up\n"); + dev_err(dev, "No IRQ set up\n"); return -EINVAL; } - ts = devm_kzalloc(&client->dev, sizeof(*ts), GFP_KERNEL); + ts = devm_kzalloc(dev, sizeof(*ts), GFP_KERNEL); if (!ts) return -ENOMEM; ts->client = client; - ts->x_flip = device_property_read_bool(&client->dev, "rohm,flip-x"); - ts->y_flip = device_property_read_bool(&client->dev, "rohm,flip-y"); + ts->x_flip = device_property_read_bool(dev, "rohm,flip-x"); + ts->y_flip = device_property_read_bool(dev, "rohm,flip-y"); - in_dev = devm_input_allocate_device(&client->dev); + in_dev = devm_input_allocate_device(dev); if (!in_dev) { - dev_err(&client->dev, "device memory alloc failed\n"); + dev_err(dev, "device memory alloc failed\n"); return -ENOMEM; } ts->in_dev = in_dev; @@ -444,8 +445,8 @@ static int bu21013_probe(struct i2c_client *client) in_dev->name = DRIVER_TP; in_dev->id.bustype = BUS_I2C; - device_property_read_u32(&client->dev, "rohm,touch-max-x", &max_x); - device_property_read_u32(&client->dev, "rohm,touch-max-y", &max_y); + device_property_read_u32(dev, "rohm,touch-max-x", &max_x); + device_property_read_u32(dev, "rohm,touch-max-y", &max_y); input_set_abs_params(in_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0); input_set_abs_params(in_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0); @@ -454,14 +455,14 @@ static int bu21013_probe(struct i2c_client *client) /* Adjust for the legacy "flip" properties, if present */ if (!ts->props.invert_x && - device_property_read_bool(&client->dev, "rohm,flip-x")) { + device_property_read_bool(dev, "rohm,flip-x")) { info = &in_dev->absinfo[ABS_MT_POSITION_X]; info->maximum -= info->minimum; info->minimum = 0; } if (!ts->props.invert_y && - device_property_read_bool(&client->dev, "rohm,flip-y")) { + device_property_read_bool(dev, "rohm,flip-y")) { info = &in_dev->absinfo[ABS_MT_POSITION_Y]; info->maximum -= info->minimum; info->minimum = 0; @@ -471,55 +472,46 @@ static int bu21013_probe(struct i2c_client *client) INPUT_MT_DIRECT | INPUT_MT_TRACK | INPUT_MT_DROP_UNUSED); if (error) { - dev_err(&client->dev, "failed to initialize MT slots"); + dev_err(dev, "failed to initialize MT slots"); return error; } - ts->regulator = devm_regulator_get(&client->dev, "avdd"); + ts->regulator = devm_regulator_get(dev, "avdd"); if (IS_ERR(ts->regulator)) { - dev_err(&client->dev, "regulator_get failed\n"); + dev_err(dev, "regulator_get failed\n"); return PTR_ERR(ts->regulator); } error = regulator_enable(ts->regulator); if (error) { - dev_err(&client->dev, "regulator enable failed\n"); + dev_err(dev, "regulator enable failed\n"); return error; } - error = devm_add_action_or_reset(&client->dev, bu21013_power_off, ts); + error = devm_add_action_or_reset(dev, bu21013_power_off, ts); if (error) { - dev_err(&client->dev, "failed to install power off handler\n"); + dev_err(dev, "failed to install power off handler\n"); return error; } /* Named "CS" on the chip, DT binding is "reset" */ - ts->cs_gpiod = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); - error = PTR_ERR_OR_ZERO(ts->cs_gpiod); - if (error) { - if (error != -EPROBE_DEFER) - dev_err(&client->dev, "failed to get CS GPIO\n"); - return error; - } + ts->cs_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(ts->cs_gpiod)) + return dev_err_probe(dev, PTR_ERR(ts->cs_gpiod), "failed to get CS GPIO\n"); + gpiod_set_consumer_name(ts->cs_gpiod, "BU21013 CS"); - error = devm_add_action_or_reset(&client->dev, - bu21013_disable_chip, ts); + error = devm_add_action_or_reset(dev, bu21013_disable_chip, ts); if (error) { - dev_err(&client->dev, - "failed to install chip disable handler\n"); + dev_err(dev, "failed to install chip disable handler\n"); return error; } /* Named "INT" on the chip, DT binding is "touch" */ - ts->int_gpiod = devm_gpiod_get_optional(&client->dev, - "touch", GPIOD_IN); + ts->int_gpiod = devm_gpiod_get_optional(dev, "touch", GPIOD_IN); error = PTR_ERR_OR_ZERO(ts->int_gpiod); - if (error) { - if (error != -EPROBE_DEFER) - dev_err(&client->dev, "failed to get INT GPIO\n"); - return error; - } + if (error) + return dev_err_probe(dev, error, "failed to get INT GPIO\n"); if (ts->int_gpiod) gpiod_set_consumer_name(ts->int_gpiod, "BU21013 INT"); @@ -527,22 +519,20 @@ static int bu21013_probe(struct i2c_client *client) /* configure the touch panel controller */ error = bu21013_init_chip(ts); if (error) { - dev_err(&client->dev, "error in bu21013 config\n"); + dev_err(dev, "error in bu21013 config\n"); return error; } - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, bu21013_gpio_irq, + error = devm_request_threaded_irq(dev, client->irq, NULL, bu21013_gpio_irq, IRQF_ONESHOT, DRIVER_TP, ts); if (error) { - dev_err(&client->dev, "request irq %d failed\n", - client->irq); + dev_err(dev, "request irq %d failed\n", client->irq); return error; } error = input_register_device(in_dev); if (error) { - dev_err(&client->dev, "failed to register input device\n"); + dev_err(dev, "failed to register input device\n"); return error; } @@ -617,7 +607,7 @@ static struct i2c_driver bu21013_driver = { .name = DRIVER_TP, .pm = pm_sleep_ptr(&bu21013_dev_pm_ops), }, - .probe_new = bu21013_probe, + .probe = bu21013_probe, .remove = bu21013_remove, .id_table = bu21013_id, }; diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c index 8f1442894ff9..e1dfbd92ab64 100644 --- a/drivers/input/touchscreen/bu21029_ts.c +++ b/drivers/input/touchscreen/bu21029_ts.c @@ -333,6 +333,7 @@ static void bu21029_stop_chip(struct input_dev *dev) static int bu21029_probe(struct i2c_client *client) { + struct device *dev = &client->dev; struct bu21029_ts_data *bu21029; struct input_dev *in_dev; int error; @@ -341,45 +342,33 @@ static int bu21029_probe(struct i2c_client *client) I2C_FUNC_SMBUS_WRITE_BYTE | I2C_FUNC_SMBUS_WRITE_BYTE_DATA | I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { - dev_err(&client->dev, - "i2c functionality support is not sufficient\n"); + dev_err(dev, "i2c functionality support is not sufficient\n"); return -EIO; } - bu21029 = devm_kzalloc(&client->dev, sizeof(*bu21029), GFP_KERNEL); + bu21029 = devm_kzalloc(dev, sizeof(*bu21029), GFP_KERNEL); if (!bu21029) return -ENOMEM; - error = device_property_read_u32(&client->dev, "rohm,x-plate-ohms", - &bu21029->x_plate_ohms); + error = device_property_read_u32(dev, "rohm,x-plate-ohms", &bu21029->x_plate_ohms); if (error) { - dev_err(&client->dev, - "invalid 'x-plate-ohms' supplied: %d\n", error); + dev_err(dev, "invalid 'x-plate-ohms' supplied: %d\n", error); return error; } - bu21029->vdd = devm_regulator_get(&client->dev, "vdd"); - if (IS_ERR(bu21029->vdd)) { - error = PTR_ERR(bu21029->vdd); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to acquire 'vdd' supply: %d\n", error); - return error; - } + bu21029->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(bu21029->vdd)) + return dev_err_probe(dev, PTR_ERR(bu21029->vdd), + "failed to acquire 'vdd' supply\n"); - bu21029->reset_gpios = devm_gpiod_get_optional(&client->dev, - "reset", GPIOD_OUT_HIGH); - if (IS_ERR(bu21029->reset_gpios)) { - error = PTR_ERR(bu21029->reset_gpios); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to acquire 'reset' gpio: %d\n", error); - return error; - } + bu21029->reset_gpios = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(bu21029->reset_gpios)) + return dev_err_probe(dev, PTR_ERR(bu21029->reset_gpios), + "failed to acquire 'reset' gpio\n"); - in_dev = devm_input_allocate_device(&client->dev); + in_dev = devm_input_allocate_device(dev); if (!in_dev) { - dev_err(&client->dev, "unable to allocate input device\n"); + dev_err(dev, "unable to allocate input device\n"); return -ENOMEM; } @@ -400,20 +389,18 @@ static int bu21029_probe(struct i2c_client *client) input_set_drvdata(in_dev, bu21029); - error = devm_request_threaded_irq(&client->dev, client->irq, - NULL, bu21029_touch_soft_irq, + error = devm_request_threaded_irq(dev, client->irq, NULL, + bu21029_touch_soft_irq, IRQF_ONESHOT | IRQF_NO_AUTOEN, DRIVER_NAME, bu21029); if (error) { - dev_err(&client->dev, - "unable to request touch irq: %d\n", error); + dev_err(dev, "unable to request touch irq: %d\n", error); return error; } error = input_register_device(in_dev); if (error) { - dev_err(&client->dev, - "unable to register input device: %d\n", error); + dev_err(dev, "unable to register input device: %d\n", error); return error; } @@ -474,7 +461,7 @@ static struct i2c_driver bu21029_driver = { .pm = pm_sleep_ptr(&bu21029_pm_ops), }, .id_table = bu21029_ids, - .probe_new = bu21029_probe, + .probe = bu21029_probe, }; module_i2c_driver(bu21029_driver); diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index 32b714a6ed2d..d6876d10b252 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -191,12 +191,8 @@ static int icn8318_probe(struct i2c_client *client) return -ENOMEM; data->wake_gpio = devm_gpiod_get(dev, "wake", GPIOD_OUT_LOW); - if (IS_ERR(data->wake_gpio)) { - error = PTR_ERR(data->wake_gpio); - if (error != -EPROBE_DEFER) - dev_err(dev, "Error getting wake gpio: %d\n", error); - return error; - } + if (IS_ERR(data->wake_gpio)) + return dev_err_probe(dev, PTR_ERR(data->wake_gpio), "Error getting wake gpio\n"); input = devm_input_allocate_device(dev); if (!input) @@ -264,7 +260,7 @@ static struct i2c_driver icn8318_driver = { .pm = pm_sleep_ptr(&icn8318_pm_ops), .of_match_table = icn8318_of_match, }, - .probe_new = icn8318_probe, + .probe = icn8318_probe, .id_table = icn8318_i2c_id, }; diff --git a/drivers/input/touchscreen/chipone_icn8505.c b/drivers/input/touchscreen/chipone_icn8505.c index 246bee0bee53..b56954830b33 100644 --- a/drivers/input/touchscreen/chipone_icn8505.c +++ b/drivers/input/touchscreen/chipone_icn8505.c @@ -498,7 +498,7 @@ static struct i2c_driver icn8505_driver = { .pm = pm_sleep_ptr(&icn8505_pm_ops), .acpi_match_table = icn8505_acpi_match, }, - .probe_new = icn8505_probe, + .probe = icn8505_probe, }; module_i2c_driver(icn8505_driver); diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c index cd86477d971a..ea3895167b82 100644 --- a/drivers/input/touchscreen/cy8ctma140.c +++ b/drivers/input/touchscreen/cy8ctma140.c @@ -258,12 +258,8 @@ static int cy8ctma140_probe(struct i2c_client *client) ts->regulators[1].supply = "vdd"; error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators), ts->regulators); - if (error) { - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get regulators %d\n", - error); - return error; - } + if (error) + return dev_err_probe(dev, error, "Failed to get regulators\n"); error = cy8ctma140_power_up(ts); if (error) @@ -344,7 +340,7 @@ static struct i2c_driver cy8ctma140_driver = { .of_match_table = cy8ctma140_of_match, }, .id_table = cy8ctma140_idtable, - .probe_new = cy8ctma140_probe, + .probe = cy8ctma140_probe, }; module_i2c_driver(cy8ctma140_driver); diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index dcf50fbf6dc7..54d6c4869eb0 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -279,7 +279,7 @@ static struct i2c_driver cy8ctmg110_driver = { .pm = pm_sleep_ptr(&cy8ctmg110_pm), }, .id_table = cy8ctmg110_idtable, - .probe_new = cy8ctmg110_probe, + .probe = cy8ctmg110_probe, }; module_i2c_driver(cy8ctmg110_driver); diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c index 0cd6f626adec..7cb26929dc73 100644 --- a/drivers/input/touchscreen/cyttsp4_core.c +++ b/drivers/input/touchscreen/cyttsp4_core.c @@ -1263,9 +1263,8 @@ static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd) * Ensure we wait until the watchdog timer * running on a different CPU finishes */ - del_timer_sync(&cd->watchdog_timer); + timer_shutdown_sync(&cd->watchdog_timer); cancel_work_sync(&cd->watchdog_work); - del_timer_sync(&cd->watchdog_timer); } static void cyttsp4_watchdog_timer(struct timer_list *t) diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index ec7a4779f3fb..80a6890cd45a 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -60,7 +60,7 @@ static struct i2c_driver cyttsp4_i2c_driver = { .name = CYTTSP4_I2C_NAME, .pm = pm_ptr(&cyttsp4_pm_ops), }, - .probe_new = cyttsp4_i2c_probe, + .probe = cyttsp4_i2c_probe, .remove = cyttsp4_i2c_remove, .id_table = cyttsp4_i2c_id, }; diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c index 3c9d07218f48..b461ded946fc 100644 --- a/drivers/input/touchscreen/cyttsp5.c +++ b/drivers/input/touchscreen/cyttsp5.c @@ -43,6 +43,7 @@ #define HID_DESC_REG 0x1 #define HID_INPUT_REG 0x3 #define HID_OUTPUT_REG 0x4 +#define HID_COMMAND_REG 0x5 #define REPORT_ID_TOUCH 0x1 #define REPORT_ID_BTN 0x3 @@ -68,6 +69,7 @@ #define HID_APP_OUTPUT_REPORT_ID 0x2F #define HID_BL_RESPONSE_REPORT_ID 0x30 #define HID_BL_OUTPUT_REPORT_ID 0x40 +#define HID_RESPONSE_REPORT_ID 0xF0 #define HID_OUTPUT_RESPONSE_REPORT_OFFSET 2 #define HID_OUTPUT_RESPONSE_CMD_OFFSET 4 @@ -78,9 +80,15 @@ #define HID_SYSINFO_BTN_MASK GENMASK(7, 0) #define HID_SYSINFO_MAX_BTN 8 +#define HID_CMD_SET_POWER 0x8 + +#define HID_POWER_ON 0x0 +#define HID_POWER_SLEEP 0x1 + #define CY_HID_OUTPUT_TIMEOUT_MS 200 #define CY_HID_OUTPUT_GET_SYSINFO_TIMEOUT_MS 3000 #define CY_HID_GET_HID_DESCRIPTOR_TIMEOUT_MS 4000 +#define CY_HID_SET_POWER_TIMEOUT 500 /* maximum number of concurrent tracks */ #define TOUCH_REPORT_SIZE 10 @@ -100,6 +108,14 @@ #define TOUCH_REPORT_USAGE_PG_MIN 0xFF010063 #define TOUCH_COL_USAGE_PG 0x000D0022 +#define SET_CMD_LOW(byte, bits) \ + ((byte) = (((byte) & 0xF0) | ((bits) & 0x0F))) +#define SET_CMD_HIGH(byte, bits)\ + ((byte) = (((byte) & 0x0F) | ((bits) & 0xF0))) +#define SET_CMD_OPCODE(byte, opcode) SET_CMD_LOW(byte, opcode) +#define SET_CMD_REPORT_TYPE(byte, type) SET_CMD_HIGH(byte, ((type) << 4)) +#define SET_CMD_REPORT_ID(byte, id) SET_CMD_LOW(byte, id) + /* System Information interface definitions */ struct cyttsp5_sensing_conf_data_dev { u8 electrodes_x; @@ -557,6 +573,40 @@ static int cyttsp5_hid_output_get_sysinfo(struct cyttsp5 *ts) return cyttsp5_get_sysinfo_regs(ts); } +static int cyttsp5_power_control(struct cyttsp5 *ts, bool on) +{ + u8 state = on ? HID_POWER_ON : HID_POWER_SLEEP; + u8 cmd[2] = { 0 }; + int rc; + + SET_CMD_REPORT_TYPE(cmd[0], 0); + SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP); + SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER); + + rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd)); + if (rc) { + dev_err(ts->dev, "Failed to write power command %d", rc); + return rc; + } + + rc = wait_for_completion_interruptible_timeout(&ts->cmd_done, + msecs_to_jiffies(CY_HID_SET_POWER_TIMEOUT)); + if (rc <= 0) { + dev_err(ts->dev, "HID power cmd execution timed out\n"); + return -ETIMEDOUT; + } + + if (ts->response_buf[2] != HID_RESPONSE_REPORT_ID || + (ts->response_buf[3] & 0x03) != state || + (ts->response_buf[4] & 0x0f) != HID_CMD_SET_POWER) { + dev_err(ts->dev, "Validation of the %s response failed\n", + on ? "wakeup" : "sleep"); + return -EINVAL; + } + + return 0; +} + static int cyttsp5_hid_output_bl_launch_app(struct cyttsp5 *ts) { int rc; @@ -601,12 +651,7 @@ static int cyttsp5_get_hid_descriptor(struct cyttsp5 *ts, struct cyttsp5_hid_desc *desc) { struct device *dev = ts->dev; - __le16 hid_desc_register = cpu_to_le16(HID_DESC_REG); int rc; - u8 cmd[2]; - - /* Set HID descriptor register */ - memcpy(cmd, &hid_desc_register, sizeof(hid_desc_register)); rc = cyttsp5_write(ts, HID_DESC_REG, NULL, 0); if (rc) { @@ -675,6 +720,10 @@ static irqreturn_t cyttsp5_handle_irq(int irq, void *handle) case HID_BTN_REPORT_ID: cyttsp5_btn_attention(ts->dev); break; + case HID_RESPONSE_REPORT_ID: + memcpy(ts->response_buf, ts->input_buf, size); + complete(&ts->cmd_done); + break; default: /* It is not an input but a command response */ memcpy(ts->response_buf, ts->input_buf, size); @@ -886,12 +935,35 @@ static const struct i2c_device_id cyttsp5_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, cyttsp5_i2c_id); +static int __maybe_unused cyttsp5_suspend(struct device *dev) +{ + struct cyttsp5 *ts = dev_get_drvdata(dev); + + if (!device_may_wakeup(dev)) + cyttsp5_power_control(ts, false); + + return 0; +} + +static int __maybe_unused cyttsp5_resume(struct device *dev) +{ + struct cyttsp5 *ts = dev_get_drvdata(dev); + + if (!device_may_wakeup(dev)) + cyttsp5_power_control(ts, true); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(cyttsp5_pm, cyttsp5_suspend, cyttsp5_resume); + static struct i2c_driver cyttsp5_i2c_driver = { .driver = { .name = CYTTSP5_NAME, .of_match_table = cyttsp5_of_match, + .pm = &cyttsp5_pm, }, - .probe_new = cyttsp5_i2c_probe, + .probe = cyttsp5_i2c_probe, .id_table = cyttsp5_i2c_id, }; module_i2c_driver(cyttsp5_i2c_driver); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 3f91cb43ec82..127a8fda1da4 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -66,7 +66,7 @@ static struct i2c_driver cyttsp_i2c_driver = { .pm = pm_sleep_ptr(&cyttsp_pm_ops), .of_match_table = cyttsp_of_i2c_match, }, - .probe_new = cyttsp_i2c_probe, + .probe = cyttsp_i2c_probe, .id_table = cyttsp_i2c_id, }; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 24ab9e9f5b21..457d53337fbb 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1168,13 +1168,9 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) tsdata->max_support_points = chip_data->max_support_points; tsdata->vcc = devm_regulator_get(&client->dev, "vcc"); - if (IS_ERR(tsdata->vcc)) { - error = PTR_ERR(tsdata->vcc); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to request regulator: %d\n", error); - return error; - } + if (IS_ERR(tsdata->vcc)) + return dev_err_probe(&client->dev, PTR_ERR(tsdata->vcc), + "failed to request regulator\n"); tsdata->iovcc = devm_regulator_get(&client->dev, "iovcc"); if (IS_ERR(tsdata->iovcc)) { @@ -1241,6 +1237,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client) if (tsdata->wake_gpio) { usleep_range(5000, 6000); gpiod_set_value_cansleep(tsdata->wake_gpio, 1); + usleep_range(5000, 6000); } if (tsdata->reset_gpio) { @@ -1510,7 +1507,7 @@ static struct i2c_driver edt_ft5x06_ts_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = edt_ft5x06_ts_id, - .probe_new = edt_ft5x06_ts_probe, + .probe = edt_ft5x06_ts_probe, .remove = edt_ft5x06_ts_remove, }; diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c index 56fa21688bdb..5e4167f6c63e 100644 --- a/drivers/input/touchscreen/eeti_ts.c +++ b/drivers/input/touchscreen/eeti_ts.c @@ -291,7 +291,7 @@ static struct i2c_driver eeti_ts_driver = { .pm = pm_sleep_ptr(&eeti_ts_pm), .of_match_table = of_match_ptr(of_eeti_ts_match), }, - .probe_new = eeti_ts_probe, + .probe = eeti_ts_probe, .id_table = eeti_ts_id, }; diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 1a9805938e6d..a7f7e7308267 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -264,7 +264,7 @@ static struct i2c_driver egalax_ts_driver = { .of_match_table = egalax_ts_dt_ids, }, .id_table = egalax_ts_id, - .probe_new = egalax_ts_probe, + .probe = egalax_ts_probe, }; module_i2c_driver(egalax_ts_driver); diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c index e6f1e46d003d..cc3103b9cbfb 100644 --- a/drivers/input/touchscreen/ektf2127.c +++ b/drivers/input/touchscreen/ektf2127.c @@ -264,12 +264,8 @@ static int ektf2127_probe(struct i2c_client *client) /* This requests the gpio *and* turns on the touchscreen controller */ ts->power_gpios = devm_gpiod_get(dev, "power", GPIOD_OUT_HIGH); - if (IS_ERR(ts->power_gpios)) { - error = PTR_ERR(ts->power_gpios); - if (error != -EPROBE_DEFER) - dev_err(dev, "Error getting power gpio: %d\n", error); - return error; - } + if (IS_ERR(ts->power_gpios)) + return dev_err_probe(dev, PTR_ERR(ts->power_gpios), "Error getting power gpio\n"); input = devm_input_allocate_device(dev); if (!input) @@ -351,7 +347,7 @@ static struct i2c_driver ektf2127_driver = { .pm = pm_sleep_ptr(&ektf2127_pm_ops), .of_match_table = of_match_ptr(ektf2127_of_match), }, - .probe_new = ektf2127_probe, + .probe = ektf2127_probe, .id_table = ektf2127_i2c_id, }; module_i2c_driver(ektf2127_driver); diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 8a16eb51481f..a1af3de9f310 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1438,24 +1438,14 @@ static int elants_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, ts); ts->vcc33 = devm_regulator_get(&client->dev, "vcc33"); - if (IS_ERR(ts->vcc33)) { - error = PTR_ERR(ts->vcc33); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'vcc33' regulator: %d\n", - error); - return error; - } + if (IS_ERR(ts->vcc33)) + return dev_err_probe(&client->dev, PTR_ERR(ts->vcc33), + "Failed to get 'vcc33' regulator\n"); ts->vccio = devm_regulator_get(&client->dev, "vccio"); - if (IS_ERR(ts->vccio)) { - error = PTR_ERR(ts->vccio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'vccio' regulator: %d\n", - error); - return error; - } + if (IS_ERR(ts->vccio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->vccio), + "Failed to get 'vccio' regulator\n"); ts->reset_gpio = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(ts->reset_gpio)) { @@ -1673,7 +1663,7 @@ MODULE_DEVICE_TABLE(of, elants_of_match); #endif static struct i2c_driver elants_i2c_driver = { - .probe_new = elants_i2c_probe, + .probe = elants_i2c_probe, .id_table = elants_i2c_id, .driver = { .name = DEVICE_NAME, diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c index 69eae79e2087..e3f6d21b3c1b 100644 --- a/drivers/input/touchscreen/exc3000.c +++ b/drivers/input/touchscreen/exc3000.c @@ -18,6 +18,7 @@ #include <linux/interrupt.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/regulator/consumer.h> #include <linux/sizes.h> #include <linux/timer.h> #include <asm/unaligned.h> @@ -360,6 +361,12 @@ static int exc3000_probe(struct i2c_client *client) if (IS_ERR(data->reset)) return PTR_ERR(data->reset); + /* For proper reset sequence, enable power while reset asserted */ + error = devm_regulator_get_enable(&client->dev, "vdd"); + if (error && error != -ENODEV) + return dev_err_probe(&client->dev, error, + "failed to request vdd regulator\n"); + if (data->reset) { msleep(EXC3000_RESET_MS); gpiod_set_value_cansleep(data->reset, 0); @@ -460,7 +467,7 @@ static struct i2c_driver exc3000_driver = { .of_match_table = of_match_ptr(exc3000_of_match), }, .id_table = exc3000_id, - .probe_new = exc3000_probe, + .probe = exc3000_probe, }; module_i2c_driver(exc3000_driver); diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index d77f116680a0..85d4249f1065 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -935,7 +935,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts) */ static int goodix_get_gpio_config(struct goodix_ts_data *ts) { - int error; struct device *dev; struct gpio_desc *gpiod; bool added_acpi_mappings = false; @@ -951,33 +950,20 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts) ts->gpiod_rst_flags = GPIOD_IN; ts->avdd28 = devm_regulator_get(dev, "AVDD28"); - if (IS_ERR(ts->avdd28)) { - error = PTR_ERR(ts->avdd28); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get AVDD28 regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->avdd28)) + return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n"); ts->vddio = devm_regulator_get(dev, "VDDIO"); - if (IS_ERR(ts->vddio)) { - error = PTR_ERR(ts->vddio); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get VDDIO regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->vddio)) + return dev_err_probe(dev, PTR_ERR(ts->vddio), "Failed to get VDDIO regulator\n"); retry_get_irq_gpio: /* Get the interrupt GPIO pin number */ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_INT_NAME, GPIOD_IN); - if (IS_ERR(gpiod)) { - error = PTR_ERR(gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s GPIO: %d\n", - GOODIX_GPIO_INT_NAME, error); - return error; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", + GOODIX_GPIO_INT_NAME); + if (!gpiod && has_acpi_companion(dev) && !added_acpi_mappings) { added_acpi_mappings = true; if (goodix_add_acpi_gpio_mappings(ts) == 0) @@ -988,13 +974,9 @@ retry_get_irq_gpio: /* Get the reset line GPIO pin number */ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags); - if (IS_ERR(gpiod)) { - error = PTR_ERR(gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get %s GPIO: %d\n", - GOODIX_GPIO_RST_NAME, error); - return error; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n", + GOODIX_GPIO_RST_NAME); ts->gpiod_rst = gpiod; @@ -1544,7 +1526,7 @@ MODULE_DEVICE_TABLE(of, goodix_of_match); #endif static struct i2c_driver goodix_ts_driver = { - .probe_new = goodix_ts_probe, + .probe = goodix_ts_probe, .remove = goodix_ts_remove, .id_table = goodix_ts_id, .driver = { diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c index 7c7020099b0f..404153338df7 100644 --- a/drivers/input/touchscreen/hideep.c +++ b/drivers/input/touchscreen/hideep.c @@ -1136,7 +1136,7 @@ static struct i2c_driver hideep_driver = { .pm = pm_sleep_ptr(&hideep_pm_ops), }, .id_table = hideep_i2c_id, - .probe_new = hideep_probe, + .probe = hideep_probe, }; module_i2c_driver(hideep_driver); diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c index e96150d80a48..4f6609dcdef3 100644 --- a/drivers/input/touchscreen/himax_hx83112b.c +++ b/drivers/input/touchscreen/himax_hx83112b.c @@ -349,7 +349,7 @@ MODULE_DEVICE_TABLE(of, himax_of_match); #endif static struct i2c_driver himax_ts_driver = { - .probe_new = himax_probe, + .probe = himax_probe, .id_table = himax_ts_id, .driver = { .name = "Himax-hx83112b-TS", diff --git a/drivers/input/touchscreen/hycon-hy46xx.c b/drivers/input/touchscreen/hycon-hy46xx.c index 8f4989aba9a4..2450cfa14de9 100644 --- a/drivers/input/touchscreen/hycon-hy46xx.c +++ b/drivers/input/touchscreen/hycon-hy46xx.c @@ -580,7 +580,7 @@ static struct i2c_driver hycon_hy46xx_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = hycon_hy46xx_id, - .probe_new = hycon_hy46xx_probe, + .probe = hycon_hy46xx_probe, }; module_i2c_driver(hycon_hy46xx_driver); diff --git a/drivers/input/touchscreen/hynitron_cstxxx.c b/drivers/input/touchscreen/hynitron_cstxxx.c index e86c85addb38..05946fee4fd4 100644 --- a/drivers/input/touchscreen/hynitron_cstxxx.c +++ b/drivers/input/touchscreen/hynitron_cstxxx.c @@ -488,7 +488,7 @@ static struct i2c_driver hynitron_i2c_driver = { .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, .id_table = hyn_tpd_id, - .probe_new = hyn_probe, + .probe = hyn_probe, }; module_i2c_driver(hynitron_i2c_driver); diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index 4897fafa4204..f7cd773f7292 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -370,22 +370,33 @@ static int ili251x_firmware_update_resolution(struct device *dev) /* The firmware update blob might have changed the resolution. */ error = priv->chip->read_reg(client, REG_PANEL_INFO, &rs, sizeof(rs)); - if (error) - return error; + if (!error) { + resx = le16_to_cpup((__le16 *)rs); + resy = le16_to_cpup((__le16 *)(rs + 2)); - resx = le16_to_cpup((__le16 *)rs); - resy = le16_to_cpup((__le16 *)(rs + 2)); + /* The value reported by the firmware is invalid. */ + if (!resx || resx == 0xffff || !resy || resy == 0xffff) + error = -EINVAL; + } - /* The value reported by the firmware is invalid. */ - if (!resx || resx == 0xffff || !resy || resy == 0xffff) - return -EINVAL; + /* + * In case of error, the firmware might be stuck in bootloader mode, + * e.g. after a failed firmware update. Set maximum resolution, but + * do not fail to probe, so the user can re-trigger the firmware + * update and recover the touch controller. + */ + if (error) { + dev_warn(dev, "Invalid resolution reported by controller.\n"); + resx = 16384; + resy = 16384; + } input_abs_set_max(priv->input, ABS_X, resx - 1); input_abs_set_max(priv->input, ABS_Y, resy - 1); input_abs_set_max(priv->input, ABS_MT_POSITION_X, resx - 1); input_abs_set_max(priv->input, ABS_MT_POSITION_Y, resy - 1); - return 0; + return error; } static ssize_t ili251x_firmware_update_firmware_version(struct device *dev) @@ -977,11 +988,10 @@ static int ili210x_i2c_probe(struct i2c_client *client) if (priv->chip->has_pressure_reg) input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xa, 0, 0); error = ili251x_firmware_update_cached_state(dev); - if (error) { - dev_err(dev, "Unable to cache firmware information, err: %d\n", - error); - return error; - } + if (error) + dev_warn(dev, "Unable to cache firmware information, err: %d\n", + error); + touchscreen_parse_properties(input, true, &priv->prop); error = input_mt_init_slots(input, priv->chip->max_touches, @@ -1043,7 +1053,7 @@ static struct i2c_driver ili210x_ts_driver = { .of_match_table = ili210x_dt_ids, }, .id_table = ili210x_i2c_id, - .probe_new = ili210x_i2c_probe, + .probe = ili210x_i2c_probe, }; module_i2c_driver(ili210x_ts_driver); diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c index d69809338498..2f872e95fbba 100644 --- a/drivers/input/touchscreen/ilitek_ts_i2c.c +++ b/drivers/input/touchscreen/ilitek_ts_i2c.c @@ -679,7 +679,7 @@ static struct i2c_driver ilitek_ts_i2c_driver = { .of_match_table = of_match_ptr(ilitek_ts_i2c_match), .acpi_match_table = ACPI_PTR(ilitekts_acpi_id), }, - .probe_new = ilitek_ts_i2c_probe, + .probe = ilitek_ts_i2c_probe, .id_table = ilitek_ts_i2c_id, }; module_i2c_driver(ilitek_ts_i2c_driver); diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c index de1b16e94bb8..07111ca24455 100644 --- a/drivers/input/touchscreen/imagis.c +++ b/drivers/input/touchscreen/imagis.c @@ -357,7 +357,7 @@ static struct i2c_driver imagis_ts_driver = { .pm = pm_sleep_ptr(&imagis_pm_ops), .of_match_table = of_match_ptr(imagis_of_match), }, - .probe_new = imagis_probe, + .probe = imagis_probe, }; module_i2c_driver(imagis_ts_driver); diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c index c73e9c5c0077..0aa9d6492df8 100644 --- a/drivers/input/touchscreen/iqs5xx.c +++ b/drivers/input/touchscreen/iqs5xx.c @@ -1093,7 +1093,7 @@ static struct i2c_driver iqs5xx_i2c_driver = { .pm = pm_sleep_ptr(&iqs5xx_pm), }, .id_table = iqs5xx_id, - .probe_new = iqs5xx_probe, + .probe = iqs5xx_probe, }; module_i2c_driver(iqs5xx_i2c_driver); diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c new file mode 100644 index 000000000000..dc084f873762 --- /dev/null +++ b/drivers/input/touchscreen/iqs7211.c @@ -0,0 +1,2557 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller + * + * Copyright (C) 2023 Jeff LaBundy <jeff@labundy.com> + */ + +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/input.h> +#include <linux/input/mt.h> +#include <linux/input/touchscreen.h> +#include <linux/interrupt.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <asm/unaligned.h> + +#define IQS7211_PROD_NUM 0x00 + +#define IQS7211_EVENT_MASK_ALL GENMASK(14, 8) +#define IQS7211_EVENT_MASK_ALP BIT(13) +#define IQS7211_EVENT_MASK_BTN BIT(12) +#define IQS7211_EVENT_MASK_ATI BIT(11) +#define IQS7211_EVENT_MASK_MOVE BIT(10) +#define IQS7211_EVENT_MASK_GSTR BIT(9) +#define IQS7211_EVENT_MODE BIT(8) + +#define IQS7211_COMMS_ERROR 0xEEEE +#define IQS7211_COMMS_RETRY_MS 50 +#define IQS7211_COMMS_SLEEP_US 100 +#define IQS7211_COMMS_TIMEOUT_US (100 * USEC_PER_MSEC) +#define IQS7211_RESET_TIMEOUT_MS 150 +#define IQS7211_START_TIMEOUT_US (1 * USEC_PER_SEC) + +#define IQS7211_NUM_RETRIES 5 +#define IQS7211_NUM_CRX 8 +#define IQS7211_MAX_CTX 13 + +#define IQS7211_MAX_CONTACTS 2 +#define IQS7211_MAX_CYCLES 21 + +/* + * The following delay is used during instances that must wait for the open- + * drain RDY pin to settle. Its value is calculated as 5*R*C, where R and C + * represent typical datasheet values of 4.7k and 100 nF, respectively. + */ +#define iqs7211_irq_wait() usleep_range(2500, 2600) + +enum iqs7211_dev_id { + IQS7210A, + IQS7211A, + IQS7211E, +}; + +enum iqs7211_comms_mode { + IQS7211_COMMS_MODE_WAIT, + IQS7211_COMMS_MODE_FREE, + IQS7211_COMMS_MODE_FORCE, +}; + +struct iqs7211_reg_field_desc { + struct list_head list; + u8 addr; + u16 mask; + u16 val; +}; + +enum iqs7211_reg_key_id { + IQS7211_REG_KEY_NONE, + IQS7211_REG_KEY_PROX, + IQS7211_REG_KEY_TOUCH, + IQS7211_REG_KEY_TAP, + IQS7211_REG_KEY_HOLD, + IQS7211_REG_KEY_PALM, + IQS7211_REG_KEY_AXIAL_X, + IQS7211_REG_KEY_AXIAL_Y, + IQS7211_REG_KEY_RESERVED +}; + +enum iqs7211_reg_grp_id { + IQS7211_REG_GRP_TP, + IQS7211_REG_GRP_BTN, + IQS7211_REG_GRP_ALP, + IQS7211_REG_GRP_SYS, + IQS7211_NUM_REG_GRPS +}; + +static const char * const iqs7211_reg_grp_names[IQS7211_NUM_REG_GRPS] = { + [IQS7211_REG_GRP_TP] = "trackpad", + [IQS7211_REG_GRP_BTN] = "button", + [IQS7211_REG_GRP_ALP] = "alp", +}; + +static const u16 iqs7211_reg_grp_masks[IQS7211_NUM_REG_GRPS] = { + [IQS7211_REG_GRP_TP] = IQS7211_EVENT_MASK_GSTR, + [IQS7211_REG_GRP_BTN] = IQS7211_EVENT_MASK_BTN, + [IQS7211_REG_GRP_ALP] = IQS7211_EVENT_MASK_ALP, +}; + +struct iqs7211_event_desc { + const char *name; + u16 mask; + u16 enable; + enum iqs7211_reg_grp_id reg_grp; + enum iqs7211_reg_key_id reg_key; +}; + +static const struct iqs7211_event_desc iqs7210a_kp_events[] = { + { + .mask = BIT(10), + .enable = BIT(13) | BIT(12), + .reg_grp = IQS7211_REG_GRP_ALP, + }, + { + .name = "event-prox", + .mask = BIT(2), + .enable = BIT(5) | BIT(4), + .reg_grp = IQS7211_REG_GRP_BTN, + .reg_key = IQS7211_REG_KEY_PROX, + }, + { + .name = "event-touch", + .mask = BIT(3), + .enable = BIT(5) | BIT(4), + .reg_grp = IQS7211_REG_GRP_BTN, + .reg_key = IQS7211_REG_KEY_TOUCH, + }, + { + .name = "event-tap", + .mask = BIT(0), + .enable = BIT(0), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-hold", + .mask = BIT(1), + .enable = BIT(1), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-x-neg", + .mask = BIT(2), + .enable = BIT(2), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-x-pos", + .mask = BIT(3), + .enable = BIT(3), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-y-pos", + .mask = BIT(4), + .enable = BIT(4), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-y-neg", + .mask = BIT(5), + .enable = BIT(5), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, +}; + +static const struct iqs7211_event_desc iqs7211a_kp_events[] = { + { + .mask = BIT(14), + .reg_grp = IQS7211_REG_GRP_ALP, + }, + { + .name = "event-tap", + .mask = BIT(0), + .enable = BIT(0), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-hold", + .mask = BIT(1), + .enable = BIT(1), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-x-neg", + .mask = BIT(2), + .enable = BIT(2), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-x-pos", + .mask = BIT(3), + .enable = BIT(3), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-y-pos", + .mask = BIT(4), + .enable = BIT(4), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-y-neg", + .mask = BIT(5), + .enable = BIT(5), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, +}; + +static const struct iqs7211_event_desc iqs7211e_kp_events[] = { + { + .mask = BIT(14), + .reg_grp = IQS7211_REG_GRP_ALP, + }, + { + .name = "event-tap", + .mask = BIT(0), + .enable = BIT(0), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-tap-double", + .mask = BIT(1), + .enable = BIT(1), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-tap-triple", + .mask = BIT(2), + .enable = BIT(2), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_TAP, + }, + { + .name = "event-hold", + .mask = BIT(3), + .enable = BIT(3), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-palm", + .mask = BIT(4), + .enable = BIT(4), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_PALM, + }, + { + .name = "event-swipe-x-pos", + .mask = BIT(8), + .enable = BIT(8), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-x-neg", + .mask = BIT(9), + .enable = BIT(9), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_X, + }, + { + .name = "event-swipe-y-pos", + .mask = BIT(10), + .enable = BIT(10), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-y-neg", + .mask = BIT(11), + .enable = BIT(11), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + }, + { + .name = "event-swipe-x-pos-hold", + .mask = BIT(12), + .enable = BIT(12), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-x-neg-hold", + .mask = BIT(13), + .enable = BIT(13), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-y-pos-hold", + .mask = BIT(14), + .enable = BIT(14), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, + { + .name = "event-swipe-y-neg-hold", + .mask = BIT(15), + .enable = BIT(15), + .reg_grp = IQS7211_REG_GRP_TP, + .reg_key = IQS7211_REG_KEY_HOLD, + }, +}; + +struct iqs7211_dev_desc { + const char *tp_name; + const char *kp_name; + u16 prod_num; + u16 show_reset; + u16 ati_error[IQS7211_NUM_REG_GRPS]; + u16 ati_start[IQS7211_NUM_REG_GRPS]; + u16 suspend; + u16 ack_reset; + u16 comms_end; + u16 comms_req; + int charge_shift; + int info_offs; + int gesture_offs; + int contact_offs; + u8 sys_stat; + u8 sys_ctrl; + u8 alp_config; + u8 tp_config; + u8 exp_file; + u8 kp_enable[IQS7211_NUM_REG_GRPS]; + u8 gesture_angle; + u8 rx_tx_map; + u8 cycle_alloc[2]; + u8 cycle_limit[2]; + const struct iqs7211_event_desc *kp_events; + int num_kp_events; + int min_crx_alp; + int num_ctx; +}; + +static const struct iqs7211_dev_desc iqs7211_devs[] = { + [IQS7210A] = { + .tp_name = "iqs7210a_trackpad", + .kp_name = "iqs7210a_keys", + .prod_num = 944, + .show_reset = BIT(15), + .ati_error = { + [IQS7211_REG_GRP_TP] = BIT(12), + [IQS7211_REG_GRP_BTN] = BIT(0), + [IQS7211_REG_GRP_ALP] = BIT(8), + }, + .ati_start = { + [IQS7211_REG_GRP_TP] = BIT(13), + [IQS7211_REG_GRP_BTN] = BIT(1), + [IQS7211_REG_GRP_ALP] = BIT(9), + }, + .suspend = BIT(11), + .ack_reset = BIT(7), + .comms_end = BIT(2), + .comms_req = BIT(1), + .charge_shift = 4, + .info_offs = 0, + .gesture_offs = 1, + .contact_offs = 4, + .sys_stat = 0x0A, + .sys_ctrl = 0x35, + .alp_config = 0x39, + .tp_config = 0x4E, + .exp_file = 0x57, + .kp_enable = { + [IQS7211_REG_GRP_TP] = 0x58, + [IQS7211_REG_GRP_BTN] = 0x37, + [IQS7211_REG_GRP_ALP] = 0x37, + }, + .gesture_angle = 0x5F, + .rx_tx_map = 0x60, + .cycle_alloc = { 0x66, 0x75, }, + .cycle_limit = { 10, 6, }, + .kp_events = iqs7210a_kp_events, + .num_kp_events = ARRAY_SIZE(iqs7210a_kp_events), + .min_crx_alp = 4, + .num_ctx = IQS7211_MAX_CTX - 1, + }, + [IQS7211A] = { + .tp_name = "iqs7211a_trackpad", + .kp_name = "iqs7211a_keys", + .prod_num = 763, + .show_reset = BIT(7), + .ati_error = { + [IQS7211_REG_GRP_TP] = BIT(3), + [IQS7211_REG_GRP_ALP] = BIT(5), + }, + .ati_start = { + [IQS7211_REG_GRP_TP] = BIT(5), + [IQS7211_REG_GRP_ALP] = BIT(6), + }, + .ack_reset = BIT(7), + .comms_req = BIT(4), + .charge_shift = 0, + .info_offs = 0, + .gesture_offs = 1, + .contact_offs = 4, + .sys_stat = 0x10, + .sys_ctrl = 0x50, + .tp_config = 0x60, + .alp_config = 0x72, + .exp_file = 0x74, + .kp_enable = { + [IQS7211_REG_GRP_TP] = 0x80, + }, + .gesture_angle = 0x87, + .rx_tx_map = 0x90, + .cycle_alloc = { 0xA0, 0xB0, }, + .cycle_limit = { 10, 8, }, + .kp_events = iqs7211a_kp_events, + .num_kp_events = ARRAY_SIZE(iqs7211a_kp_events), + .num_ctx = IQS7211_MAX_CTX - 1, + }, + [IQS7211E] = { + .tp_name = "iqs7211e_trackpad", + .kp_name = "iqs7211e_keys", + .prod_num = 1112, + .show_reset = BIT(7), + .ati_error = { + [IQS7211_REG_GRP_TP] = BIT(3), + [IQS7211_REG_GRP_ALP] = BIT(5), + }, + .ati_start = { + [IQS7211_REG_GRP_TP] = BIT(5), + [IQS7211_REG_GRP_ALP] = BIT(6), + }, + .suspend = BIT(11), + .ack_reset = BIT(7), + .comms_end = BIT(6), + .comms_req = BIT(4), + .charge_shift = 0, + .info_offs = 1, + .gesture_offs = 0, + .contact_offs = 2, + .sys_stat = 0x0E, + .sys_ctrl = 0x33, + .tp_config = 0x41, + .alp_config = 0x36, + .exp_file = 0x4A, + .kp_enable = { + [IQS7211_REG_GRP_TP] = 0x4B, + }, + .gesture_angle = 0x55, + .rx_tx_map = 0x56, + .cycle_alloc = { 0x5D, 0x6C, }, + .cycle_limit = { 10, 11, }, + .kp_events = iqs7211e_kp_events, + .num_kp_events = ARRAY_SIZE(iqs7211e_kp_events), + .num_ctx = IQS7211_MAX_CTX, + }, +}; + +struct iqs7211_prop_desc { + const char *name; + enum iqs7211_reg_key_id reg_key; + u8 reg_addr[IQS7211_NUM_REG_GRPS][ARRAY_SIZE(iqs7211_devs)]; + int reg_shift; + int reg_width; + int val_pitch; + int val_min; + int val_max; + const char *label; +}; + +static const struct iqs7211_prop_desc iqs7211_props[] = { + { + .name = "azoteq,ati-frac-div-fine", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1E, + [IQS7211A] = 0x30, + [IQS7211E] = 0x21, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x22, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x23, + [IQS7211A] = 0x36, + [IQS7211E] = 0x25, + }, + }, + .reg_shift = 9, + .reg_width = 5, + .label = "ATI fine fractional divider", + }, + { + .name = "azoteq,ati-frac-mult-coarse", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1E, + [IQS7211A] = 0x30, + [IQS7211E] = 0x21, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x22, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x23, + [IQS7211A] = 0x36, + [IQS7211E] = 0x25, + }, + }, + .reg_shift = 5, + .reg_width = 4, + .label = "ATI coarse fractional multiplier", + }, + { + .name = "azoteq,ati-frac-div-coarse", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1E, + [IQS7211A] = 0x30, + [IQS7211E] = 0x21, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x22, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x23, + [IQS7211A] = 0x36, + [IQS7211E] = 0x25, + }, + }, + .reg_shift = 0, + .reg_width = 5, + .label = "ATI coarse fractional divider", + }, + { + .name = "azoteq,ati-comp-div", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x1F, + [IQS7211E] = 0x22, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x24, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7211E] = 0x26, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .val_max = 31, + .label = "ATI compensation divider", + }, + { + .name = "azoteq,ati-comp-div", + .reg_addr = { + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x24, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .val_max = 31, + .label = "ATI compensation divider", + }, + { + .name = "azoteq,ati-comp-div", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7211A] = 0x31, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7211A] = 0x37, + }, + }, + .val_max = 31, + .label = "ATI compensation divider", + }, + { + .name = "azoteq,ati-target", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x20, + [IQS7211A] = 0x32, + [IQS7211E] = 0x23, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x27, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x28, + [IQS7211A] = 0x38, + [IQS7211E] = 0x27, + }, + }, + .label = "ATI target", + }, + { + .name = "azoteq,ati-base", + .reg_addr[IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x26, + }, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 8, + .label = "ATI base", + }, + { + .name = "azoteq,ati-base", + .reg_addr[IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x26, + }, + .reg_shift = 0, + .reg_width = 8, + .val_pitch = 8, + .label = "ATI base", + }, + { + .name = "azoteq,rate-active-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x29, + [IQS7211A] = 0x40, + [IQS7211E] = 0x28, + }, + .label = "active mode report rate", + }, + { + .name = "azoteq,rate-touch-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2A, + [IQS7211A] = 0x41, + [IQS7211E] = 0x29, + }, + .label = "idle-touch mode report rate", + }, + { + .name = "azoteq,rate-idle-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2B, + [IQS7211A] = 0x42, + [IQS7211E] = 0x2A, + }, + .label = "idle mode report rate", + }, + { + .name = "azoteq,rate-lp1-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2C, + [IQS7211A] = 0x43, + [IQS7211E] = 0x2B, + }, + .label = "low-power mode 1 report rate", + }, + { + .name = "azoteq,rate-lp2-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2D, + [IQS7211A] = 0x44, + [IQS7211E] = 0x2C, + }, + .label = "low-power mode 2 report rate", + }, + { + .name = "azoteq,timeout-active-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2E, + [IQS7211A] = 0x45, + [IQS7211E] = 0x2D, + }, + .val_pitch = 1000, + .label = "active mode timeout", + }, + { + .name = "azoteq,timeout-touch-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x2F, + [IQS7211A] = 0x46, + [IQS7211E] = 0x2E, + }, + .val_pitch = 1000, + .label = "idle-touch mode timeout", + }, + { + .name = "azoteq,timeout-idle-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x30, + [IQS7211A] = 0x47, + [IQS7211E] = 0x2F, + }, + .val_pitch = 1000, + .label = "idle mode timeout", + }, + { + .name = "azoteq,timeout-lp1-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x31, + [IQS7211A] = 0x48, + [IQS7211E] = 0x30, + }, + .val_pitch = 1000, + .label = "low-power mode 1 timeout", + }, + { + .name = "azoteq,timeout-lp2-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x32, + [IQS7211E] = 0x31, + }, + .reg_shift = 8, + .reg_width = 8, + .val_pitch = 1000, + .val_max = 60000, + .label = "trackpad reference value update rate", + }, + { + .name = "azoteq,timeout-lp2-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x49, + }, + .val_pitch = 1000, + .val_max = 60000, + .label = "trackpad reference value update rate", + }, + { + .name = "azoteq,timeout-ati-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x32, + [IQS7211E] = 0x31, + }, + .reg_width = 8, + .val_pitch = 1000, + .val_max = 60000, + .label = "ATI error timeout", + }, + { + .name = "azoteq,timeout-ati-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x35, + }, + .val_pitch = 1000, + .val_max = 60000, + .label = "ATI error timeout", + }, + { + .name = "azoteq,timeout-comms-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x33, + [IQS7211A] = 0x4A, + [IQS7211E] = 0x32, + }, + .label = "communication timeout", + }, + { + .name = "azoteq,timeout-press-ms", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x34, + }, + .reg_width = 8, + .val_pitch = 1000, + .val_max = 60000, + .label = "press timeout", + }, + { + .name = "azoteq,ati-mode", + .reg_addr[IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x37, + }, + .reg_shift = 15, + .reg_width = 1, + .label = "ATI mode", + }, + { + .name = "azoteq,ati-mode", + .reg_addr[IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x37, + }, + .reg_shift = 7, + .reg_width = 1, + .label = "ATI mode", + }, + { + .name = "azoteq,sense-mode", + .reg_addr[IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x37, + [IQS7211A] = 0x72, + [IQS7211E] = 0x36, + }, + .reg_shift = 8, + .reg_width = 1, + .label = "sensing mode", + }, + { + .name = "azoteq,sense-mode", + .reg_addr[IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x37, + }, + .reg_shift = 0, + .reg_width = 2, + .val_max = 2, + .label = "sensing mode", + }, + { + .name = "azoteq,fosc-freq", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x38, + [IQS7211A] = 0x52, + [IQS7211E] = 0x35, + }, + .reg_shift = 4, + .reg_width = 1, + .label = "core clock frequency selection", + }, + { + .name = "azoteq,fosc-trim", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x38, + [IQS7211A] = 0x52, + [IQS7211E] = 0x35, + }, + .reg_shift = 0, + .reg_width = 4, + .label = "core clock frequency trim", + }, + { + .name = "azoteq,touch-exit", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x3B, + [IQS7211A] = 0x53, + [IQS7211E] = 0x38, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3E, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "touch exit factor", + }, + { + .name = "azoteq,touch-enter", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x3B, + [IQS7211A] = 0x53, + [IQS7211E] = 0x38, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3E, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "touch entrance factor", + }, + { + .name = "azoteq,thresh", + .reg_addr = { + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3C, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x3D, + [IQS7211A] = 0x54, + [IQS7211E] = 0x39, + }, + }, + .label = "threshold", + }, + { + .name = "azoteq,debounce-exit", + .reg_addr = { + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3F, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x40, + [IQS7211A] = 0x56, + [IQS7211E] = 0x3A, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "debounce exit factor", + }, + { + .name = "azoteq,debounce-enter", + .reg_addr = { + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x3F, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x40, + [IQS7211A] = 0x56, + [IQS7211E] = 0x3A, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "debounce entrance factor", + }, + { + .name = "azoteq,conv-frac", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x48, + [IQS7211A] = 0x58, + [IQS7211E] = 0x3D, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x49, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x4A, + [IQS7211A] = 0x59, + [IQS7211E] = 0x3E, + }, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "conversion frequency fractional divider", + }, + { + .name = "azoteq,conv-period", + .reg_addr = { + [IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x48, + [IQS7211A] = 0x58, + [IQS7211E] = 0x3D, + }, + [IQS7211_REG_GRP_BTN] = { + [IQS7210A] = 0x49, + }, + [IQS7211_REG_GRP_ALP] = { + [IQS7210A] = 0x4A, + [IQS7211A] = 0x59, + [IQS7211E] = 0x3E, + }, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "conversion period", + }, + { + .name = "azoteq,thresh", + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x55, + [IQS7211A] = 0x67, + [IQS7211E] = 0x48, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "threshold", + }, + { + .name = "azoteq,contact-split", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x55, + [IQS7211A] = 0x67, + [IQS7211E] = 0x48, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "contact split factor", + }, + { + .name = "azoteq,trim-x", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x56, + [IQS7211E] = 0x49, + }, + .reg_shift = 0, + .reg_width = 8, + .label = "horizontal trim width", + }, + { + .name = "azoteq,trim-x", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x68, + }, + .label = "horizontal trim width", + }, + { + .name = "azoteq,trim-y", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7210A] = 0x56, + [IQS7211E] = 0x49, + }, + .reg_shift = 8, + .reg_width = 8, + .label = "vertical trim height", + }, + { + .name = "azoteq,trim-y", + .reg_addr[IQS7211_REG_GRP_SYS] = { + [IQS7211A] = 0x69, + }, + .label = "vertical trim height", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_key = IQS7211_REG_KEY_TAP, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x59, + [IQS7211A] = 0x81, + [IQS7211E] = 0x4C, + }, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-mid-ms", + .reg_key = IQS7211_REG_KEY_TAP, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x4D, + }, + .label = "repeated gesture time", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_TAP, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5A, + [IQS7211A] = 0x82, + [IQS7211E] = 0x4E, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_HOLD, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5A, + [IQS7211A] = 0x82, + [IQS7211E] = 0x4E, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-min-ms", + .reg_key = IQS7211_REG_KEY_HOLD, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5B, + [IQS7211A] = 0x83, + [IQS7211E] = 0x4F, + }, + .label = "minimum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_key = IQS7211_REG_KEY_AXIAL_X, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5C, + [IQS7211A] = 0x84, + [IQS7211E] = 0x50, + }, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-max-ms", + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5C, + [IQS7211A] = 0x84, + [IQS7211E] = 0x50, + }, + .label = "maximum gesture time", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_AXIAL_X, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5D, + [IQS7211A] = 0x85, + [IQS7211E] = 0x51, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist", + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7210A] = 0x5E, + [IQS7211A] = 0x86, + [IQS7211E] = 0x52, + }, + .label = "gesture distance", + }, + { + .name = "azoteq,gesture-dist-rep", + .reg_key = IQS7211_REG_KEY_AXIAL_X, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x53, + }, + .label = "repeated gesture distance", + }, + { + .name = "azoteq,gesture-dist-rep", + .reg_key = IQS7211_REG_KEY_AXIAL_Y, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x54, + }, + .label = "repeated gesture distance", + }, + { + .name = "azoteq,thresh", + .reg_key = IQS7211_REG_KEY_PALM, + .reg_addr[IQS7211_REG_GRP_TP] = { + [IQS7211E] = 0x55, + }, + .reg_shift = 8, + .reg_width = 8, + .val_max = 42, + .label = "threshold", + }, +}; + +static const u8 iqs7211_gesture_angle[] = { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x0C, + 0x0E, 0x0F, 0x10, 0x11, + 0x12, 0x14, 0x15, 0x16, + 0x17, 0x19, 0x1A, 0x1B, + 0x1C, 0x1E, 0x1F, 0x21, + 0x22, 0x23, 0x25, 0x26, + 0x28, 0x2A, 0x2B, 0x2D, + 0x2E, 0x30, 0x32, 0x34, + 0x36, 0x38, 0x3A, 0x3C, + 0x3E, 0x40, 0x42, 0x45, + 0x47, 0x4A, 0x4C, 0x4F, + 0x52, 0x55, 0x58, 0x5B, + 0x5F, 0x63, 0x66, 0x6B, + 0x6F, 0x73, 0x78, 0x7E, + 0x83, 0x89, 0x90, 0x97, + 0x9E, 0xA7, 0xB0, 0xBA, + 0xC5, 0xD1, 0xDF, 0xEF, +}; + +struct iqs7211_ver_info { + __le16 prod_num; + __le16 major; + __le16 minor; + __le32 patch; +} __packed; + +struct iqs7211_touch_data { + __le16 abs_x; + __le16 abs_y; + __le16 pressure; + __le16 area; +} __packed; + +struct iqs7211_tp_config { + u8 tp_settings; + u8 total_rx; + u8 total_tx; + u8 num_contacts; + __le16 max_x; + __le16 max_y; +} __packed; + +struct iqs7211_private { + const struct iqs7211_dev_desc *dev_desc; + struct gpio_desc *reset_gpio; + struct gpio_desc *irq_gpio; + struct i2c_client *client; + struct input_dev *tp_idev; + struct input_dev *kp_idev; + struct iqs7211_ver_info ver_info; + struct iqs7211_tp_config tp_config; + struct touchscreen_properties prop; + struct list_head reg_field_head; + enum iqs7211_comms_mode comms_init; + enum iqs7211_comms_mode comms_mode; + unsigned int num_contacts; + unsigned int kp_code[ARRAY_SIZE(iqs7211e_kp_events)]; + u8 rx_tx_map[IQS7211_MAX_CTX + 1]; + u8 cycle_alloc[2][33]; + u8 exp_file[2]; + u16 event_mask; + u16 ati_start; + u16 gesture_cache; +}; + +static int iqs7211_irq_poll(struct iqs7211_private *iqs7211, u64 timeout_us) +{ + int error, val; + + error = readx_poll_timeout(gpiod_get_value_cansleep, iqs7211->irq_gpio, + val, val, IQS7211_COMMS_SLEEP_US, timeout_us); + + return val < 0 ? val : error; +} + +static int iqs7211_hard_reset(struct iqs7211_private *iqs7211) +{ + if (!iqs7211->reset_gpio) + return 0; + + gpiod_set_value_cansleep(iqs7211->reset_gpio, 1); + + /* + * The following delay ensures the shared RDY/MCLR pin is sampled in + * between periodic assertions by the device and assumes the default + * communication timeout has not been overwritten in OTP memory. + */ + if (iqs7211->reset_gpio == iqs7211->irq_gpio) + msleep(IQS7211_RESET_TIMEOUT_MS); + else + usleep_range(1000, 1100); + + gpiod_set_value_cansleep(iqs7211->reset_gpio, 0); + if (iqs7211->reset_gpio == iqs7211->irq_gpio) + iqs7211_irq_wait(); + + return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); +} + +static int iqs7211_force_comms(struct iqs7211_private *iqs7211) +{ + u8 msg_buf[] = { 0xFF, }; + int ret; + + switch (iqs7211->comms_mode) { + case IQS7211_COMMS_MODE_WAIT: + return iqs7211_irq_poll(iqs7211, IQS7211_START_TIMEOUT_US); + + case IQS7211_COMMS_MODE_FREE: + return 0; + + case IQS7211_COMMS_MODE_FORCE: + break; + + default: + return -EINVAL; + } + + /* + * The device cannot communicate until it asserts its interrupt (RDY) + * pin. Attempts to do so while RDY is deasserted return an ACK; how- + * ever all write data is ignored, and all read data returns 0xEE. + * + * Unsolicited communication must be preceded by a special force com- + * munication command, after which the device eventually asserts its + * RDY pin and agrees to communicate. + * + * Regardless of whether communication is forced or the result of an + * interrupt, the device automatically deasserts its RDY pin once it + * detects an I2C stop condition, or a timeout expires. + */ + ret = gpiod_get_value_cansleep(iqs7211->irq_gpio); + if (ret < 0) + return ret; + else if (ret > 0) + return 0; + + ret = i2c_master_send(iqs7211->client, msg_buf, sizeof(msg_buf)); + if (ret < (int)sizeof(msg_buf)) { + if (ret >= 0) + ret = -EIO; + + msleep(IQS7211_COMMS_RETRY_MS); + return ret; + } + + iqs7211_irq_wait(); + + return iqs7211_irq_poll(iqs7211, IQS7211_COMMS_TIMEOUT_US); +} + +static int iqs7211_read_burst(struct iqs7211_private *iqs7211, + u8 reg, void *val, u16 val_len) +{ + int ret, i; + struct i2c_client *client = iqs7211->client; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .len = sizeof(reg), + .buf = ®, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = val_len, + .buf = (u8 *)val, + }, + }; + + /* + * The following loop protects against an edge case in which the RDY + * pin is automatically deasserted just as the read is initiated. In + * that case, the read must be retried using forced communication. + */ + for (i = 0; i < IQS7211_NUM_RETRIES; i++) { + ret = iqs7211_force_comms(iqs7211); + if (ret < 0) + continue; + + ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg)); + if (ret < (int)ARRAY_SIZE(msg)) { + if (ret >= 0) + ret = -EIO; + + msleep(IQS7211_COMMS_RETRY_MS); + continue; + } + + if (get_unaligned_le16(msg[1].buf) == IQS7211_COMMS_ERROR) { + ret = -ENODATA; + continue; + } + + ret = 0; + break; + } + + iqs7211_irq_wait(); + + if (ret < 0) + dev_err(&client->dev, + "Failed to read from address 0x%02X: %d\n", reg, ret); + + return ret; +} + +static int iqs7211_read_word(struct iqs7211_private *iqs7211, u8 reg, u16 *val) +{ + __le16 val_buf; + int error; + + error = iqs7211_read_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); + if (error) + return error; + + *val = le16_to_cpu(val_buf); + + return 0; +} + +static int iqs7211_write_burst(struct iqs7211_private *iqs7211, + u8 reg, const void *val, u16 val_len) +{ + int msg_len = sizeof(reg) + val_len; + int ret, i; + struct i2c_client *client = iqs7211->client; + u8 *msg_buf; + + msg_buf = kzalloc(msg_len, GFP_KERNEL); + if (!msg_buf) + return -ENOMEM; + + *msg_buf = reg; + memcpy(msg_buf + sizeof(reg), val, val_len); + + /* + * The following loop protects against an edge case in which the RDY + * pin is automatically asserted just before the force communication + * command is sent. + * + * In that case, the subsequent I2C stop condition tricks the device + * into preemptively deasserting the RDY pin and the command must be + * sent again. + */ + for (i = 0; i < IQS7211_NUM_RETRIES; i++) { + ret = iqs7211_force_comms(iqs7211); + if (ret < 0) + continue; + + ret = i2c_master_send(client, msg_buf, msg_len); + if (ret < msg_len) { + if (ret >= 0) + ret = -EIO; + + msleep(IQS7211_COMMS_RETRY_MS); + continue; + } + + ret = 0; + break; + } + + kfree(msg_buf); + + iqs7211_irq_wait(); + + if (ret < 0) + dev_err(&client->dev, + "Failed to write to address 0x%02X: %d\n", reg, ret); + + return ret; +} + +static int iqs7211_write_word(struct iqs7211_private *iqs7211, u8 reg, u16 val) +{ + __le16 val_buf = cpu_to_le16(val); + + return iqs7211_write_burst(iqs7211, reg, &val_buf, sizeof(val_buf)); +} + +static int iqs7211_start_comms(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + bool forced_comms; + unsigned int val; + u16 comms_setup; + int error; + + /* + * Until forced communication can be enabled, the host must wait for a + * communication window each time it intends to elicit a response from + * the device. + * + * Forced communication is not necessary, however, if the host adapter + * can support clock stretching. In that case, the device freely clock + * stretches until all pending conversions are complete. + */ + forced_comms = device_property_present(&client->dev, + "azoteq,forced-comms"); + + error = device_property_read_u32(&client->dev, + "azoteq,forced-comms-default", &val); + if (error == -EINVAL) { + iqs7211->comms_init = IQS7211_COMMS_MODE_WAIT; + } else if (error) { + dev_err(&client->dev, + "Failed to read default communication mode: %d\n", + error); + return error; + } else if (val) { + iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_FORCE + : IQS7211_COMMS_MODE_WAIT; + } else { + iqs7211->comms_init = forced_comms ? IQS7211_COMMS_MODE_WAIT + : IQS7211_COMMS_MODE_FREE; + } + + iqs7211->comms_mode = iqs7211->comms_init; + + error = iqs7211_hard_reset(iqs7211); + if (error) { + dev_err(&client->dev, "Failed to reset device: %d\n", error); + return error; + } + + error = iqs7211_read_burst(iqs7211, IQS7211_PROD_NUM, + &iqs7211->ver_info, + sizeof(iqs7211->ver_info)); + if (error) + return error; + + if (le16_to_cpu(iqs7211->ver_info.prod_num) != dev_desc->prod_num) { + dev_err(&client->dev, "Invalid product number: %u\n", + le16_to_cpu(iqs7211->ver_info.prod_num)); + return -EINVAL; + } + + error = iqs7211_read_word(iqs7211, dev_desc->sys_ctrl + 1, + &comms_setup); + if (error) + return error; + + if (forced_comms) + comms_setup |= dev_desc->comms_req; + else + comms_setup &= ~dev_desc->comms_req; + + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, + comms_setup | dev_desc->comms_end); + if (error) + return error; + + if (forced_comms) + iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; + else + iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; + + error = iqs7211_read_burst(iqs7211, dev_desc->exp_file, + iqs7211->exp_file, + sizeof(iqs7211->exp_file)); + if (error) + return error; + + error = iqs7211_read_burst(iqs7211, dev_desc->tp_config, + &iqs7211->tp_config, + sizeof(iqs7211->tp_config)); + if (error) + return error; + + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, + comms_setup); + if (error) + return error; + + iqs7211->event_mask = comms_setup & ~IQS7211_EVENT_MASK_ALL; + iqs7211->event_mask |= (IQS7211_EVENT_MASK_ATI | IQS7211_EVENT_MODE); + + return 0; +} + +static int iqs7211_init_device(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct iqs7211_reg_field_desc *reg_field; + __le16 sys_ctrl[] = { + cpu_to_le16(dev_desc->ack_reset), + cpu_to_le16(iqs7211->event_mask), + }; + int error, i; + + /* + * Acknowledge reset before writing any registers in case the device + * suffers a spurious reset during initialization. The communication + * mode is configured at this time as well. + */ + error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, + sizeof(sys_ctrl)); + if (error) + return error; + + if (iqs7211->event_mask & dev_desc->comms_req) + iqs7211->comms_mode = IQS7211_COMMS_MODE_FORCE; + else + iqs7211->comms_mode = IQS7211_COMMS_MODE_FREE; + + /* + * Take advantage of the stop-bit disable function, if available, to + * save the trouble of having to reopen a communication window after + * each read or write. + */ + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl + 1, + iqs7211->event_mask | dev_desc->comms_end); + if (error) + return error; + + list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { + u16 new_val = reg_field->val; + + if (reg_field->mask < U16_MAX) { + u16 old_val; + + error = iqs7211_read_word(iqs7211, reg_field->addr, + &old_val); + if (error) + return error; + + new_val = old_val & ~reg_field->mask; + new_val |= reg_field->val; + + if (new_val == old_val) + continue; + } + + error = iqs7211_write_word(iqs7211, reg_field->addr, new_val); + if (error) + return error; + } + + error = iqs7211_write_burst(iqs7211, dev_desc->tp_config, + &iqs7211->tp_config, + sizeof(iqs7211->tp_config)); + if (error) + return error; + + if (**iqs7211->cycle_alloc) { + error = iqs7211_write_burst(iqs7211, dev_desc->rx_tx_map, + &iqs7211->rx_tx_map, + dev_desc->num_ctx); + if (error) + return error; + + for (i = 0; i < sizeof(dev_desc->cycle_limit); i++) { + error = iqs7211_write_burst(iqs7211, + dev_desc->cycle_alloc[i], + iqs7211->cycle_alloc[i], + dev_desc->cycle_limit[i] * 3); + if (error) + return error; + } + } + + *sys_ctrl = cpu_to_le16(iqs7211->ati_start); + + return iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, + sizeof(sys_ctrl)); +} + +static int iqs7211_add_field(struct iqs7211_private *iqs7211, + struct iqs7211_reg_field_desc new_field) +{ + struct i2c_client *client = iqs7211->client; + struct iqs7211_reg_field_desc *reg_field; + + if (!new_field.addr) + return 0; + + list_for_each_entry(reg_field, &iqs7211->reg_field_head, list) { + if (reg_field->addr != new_field.addr) + continue; + + reg_field->mask |= new_field.mask; + reg_field->val |= new_field.val; + return 0; + } + + reg_field = devm_kzalloc(&client->dev, sizeof(*reg_field), GFP_KERNEL); + if (!reg_field) + return -ENOMEM; + + reg_field->addr = new_field.addr; + reg_field->mask = new_field.mask; + reg_field->val = new_field.val; + + list_add(®_field->list, &iqs7211->reg_field_head); + + return 0; +} + +static int iqs7211_parse_props(struct iqs7211_private *iqs7211, + struct fwnode_handle *reg_grp_node, + enum iqs7211_reg_grp_id reg_grp, + enum iqs7211_reg_key_id reg_key) +{ + struct i2c_client *client = iqs7211->client; + int i; + + for (i = 0; i < ARRAY_SIZE(iqs7211_props); i++) { + const char *name = iqs7211_props[i].name; + u8 reg_addr = iqs7211_props[i].reg_addr[reg_grp] + [iqs7211->dev_desc - + iqs7211_devs]; + int reg_shift = iqs7211_props[i].reg_shift; + int reg_width = iqs7211_props[i].reg_width ? : 16; + int val_pitch = iqs7211_props[i].val_pitch ? : 1; + int val_min = iqs7211_props[i].val_min; + int val_max = iqs7211_props[i].val_max; + const char *label = iqs7211_props[i].label ? : name; + struct iqs7211_reg_field_desc reg_field; + unsigned int val; + int error; + + if (iqs7211_props[i].reg_key != reg_key) + continue; + + if (!reg_addr) + continue; + + error = fwnode_property_read_u32(reg_grp_node, name, &val); + if (error == -EINVAL) { + continue; + } else if (error) { + dev_err(&client->dev, "Failed to read %s %s: %d\n", + fwnode_get_name(reg_grp_node), label, error); + return error; + } + + if (!val_max) + val_max = GENMASK(reg_width - 1, 0) * val_pitch; + + if (val < val_min || val > val_max) { + dev_err(&client->dev, "Invalid %s: %u\n", label, val); + return -EINVAL; + } + + reg_field.addr = reg_addr; + reg_field.mask = GENMASK(reg_shift + reg_width - 1, reg_shift); + reg_field.val = val / val_pitch << reg_shift; + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } + + return 0; +} + +static int iqs7211_parse_event(struct iqs7211_private *iqs7211, + struct fwnode_handle *event_node, + enum iqs7211_reg_grp_id reg_grp, + enum iqs7211_reg_key_id reg_key, + unsigned int *event_code) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + struct iqs7211_reg_field_desc reg_field; + unsigned int val; + int error; + + error = iqs7211_parse_props(iqs7211, event_node, reg_grp, reg_key); + if (error) + return error; + + if (reg_key == IQS7211_REG_KEY_AXIAL_X || + reg_key == IQS7211_REG_KEY_AXIAL_Y) { + error = fwnode_property_read_u32(event_node, + "azoteq,gesture-angle", &val); + if (!error) { + if (val >= ARRAY_SIZE(iqs7211_gesture_angle)) { + dev_err(&client->dev, + "Invalid %s gesture angle: %u\n", + fwnode_get_name(event_node), val); + return -EINVAL; + } + + reg_field.addr = dev_desc->gesture_angle; + reg_field.mask = U8_MAX; + reg_field.val = iqs7211_gesture_angle[val]; + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } else if (error != -EINVAL) { + dev_err(&client->dev, + "Failed to read %s gesture angle: %d\n", + fwnode_get_name(event_node), error); + return error; + } + } + + error = fwnode_property_read_u32(event_node, "linux,code", event_code); + if (error == -EINVAL) + error = 0; + else if (error) + dev_err(&client->dev, "Failed to read %s code: %d\n", + fwnode_get_name(event_node), error); + + return error; +} + +static int iqs7211_parse_cycles(struct iqs7211_private *iqs7211, + struct fwnode_handle *tp_node) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + int num_cycles = dev_desc->cycle_limit[0] + dev_desc->cycle_limit[1]; + int error, count, i, j, k, cycle_start; + unsigned int cycle_alloc[IQS7211_MAX_CYCLES][2]; + u8 total_rx = iqs7211->tp_config.total_rx; + u8 total_tx = iqs7211->tp_config.total_tx; + + for (i = 0; i < IQS7211_MAX_CYCLES * 2; i++) + *(cycle_alloc[0] + i) = U8_MAX; + + count = fwnode_property_count_u32(tp_node, "azoteq,channel-select"); + if (count == -EINVAL) { + /* + * Assign each sensing cycle's slots (0 and 1) to a channel, + * defined as the intersection between two CRx and CTx pins. + * A channel assignment of 255 means the slot is unused. + */ + for (i = 0, cycle_start = 0; i < total_tx; i++) { + int cycle_stop = 0; + + for (j = 0; j < total_rx; j++) { + /* + * Channels formed by CRx0-3 and CRx4-7 are + * bound to slots 0 and 1, respectively. + */ + int slot = iqs7211->rx_tx_map[j] < 4 ? 0 : 1; + int chan = i * total_rx + j; + + for (k = cycle_start; k < num_cycles; k++) { + if (cycle_alloc[k][slot] < U8_MAX) + continue; + + cycle_alloc[k][slot] = chan; + break; + } + + if (k < num_cycles) { + cycle_stop = max(k, cycle_stop); + continue; + } + + dev_err(&client->dev, + "Insufficient number of cycles\n"); + return -EINVAL; + } + + /* + * Sensing cycles cannot straddle more than one CTx + * pin. As such, the next row's starting cycle must + * be greater than the previous row's highest cycle. + */ + cycle_start = cycle_stop + 1; + } + } else if (count < 0) { + dev_err(&client->dev, "Failed to count channels: %d\n", count); + return count; + } else if (count > num_cycles * 2) { + dev_err(&client->dev, "Insufficient number of cycles\n"); + return -EINVAL; + } else if (count > 0) { + error = fwnode_property_read_u32_array(tp_node, + "azoteq,channel-select", + cycle_alloc[0], count); + if (error) { + dev_err(&client->dev, "Failed to read channels: %d\n", + error); + return error; + } + + for (i = 0; i < count; i++) { + int chan = *(cycle_alloc[0] + i); + + if (chan == U8_MAX) + continue; + + if (chan >= total_rx * total_tx) { + dev_err(&client->dev, "Invalid channel: %d\n", + chan); + return -EINVAL; + } + + for (j = 0; j < count; j++) { + if (j == i || *(cycle_alloc[0] + j) != chan) + continue; + + dev_err(&client->dev, "Duplicate channel: %d\n", + chan); + return -EINVAL; + } + } + } + + /* + * Once the raw channel assignments have been derived, they must be + * packed according to the device's register map. + */ + for (i = 0, cycle_start = 0; i < sizeof(dev_desc->cycle_limit); i++) { + int offs = 0; + + for (j = cycle_start; + j < cycle_start + dev_desc->cycle_limit[i]; j++) { + iqs7211->cycle_alloc[i][offs++] = 0x05; + iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][0]; + iqs7211->cycle_alloc[i][offs++] = cycle_alloc[j][1]; + } + + cycle_start += dev_desc->cycle_limit[i]; + } + + return 0; +} + +static int iqs7211_parse_tp(struct iqs7211_private *iqs7211, + struct fwnode_handle *tp_node) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + unsigned int pins[IQS7211_MAX_CTX]; + int error, count, i, j; + + count = fwnode_property_count_u32(tp_node, "azoteq,rx-enable"); + if (count == -EINVAL) { + return 0; + } else if (count < 0) { + dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); + return count; + } else if (count > IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid number of CRx pins\n"); + return -EINVAL; + } + + error = fwnode_property_read_u32_array(tp_node, "azoteq,rx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CRx pins: %d\n", error); + return error; + } + + for (i = 0; i < count; i++) { + if (pins[i] >= IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid CRx pin: %u\n", pins[i]); + return -EINVAL; + } + + iqs7211->rx_tx_map[i] = pins[i]; + } + + iqs7211->tp_config.total_rx = count; + + count = fwnode_property_count_u32(tp_node, "azoteq,tx-enable"); + if (count < 0) { + dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); + return count; + } else if (count > dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid number of CTx pins\n"); + return -EINVAL; + } + + error = fwnode_property_read_u32_array(tp_node, "azoteq,tx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CTx pins: %d\n", error); + return error; + } + + for (i = 0; i < count; i++) { + if (pins[i] >= dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid CTx pin: %u\n", pins[i]); + return -EINVAL; + } + + for (j = 0; j < iqs7211->tp_config.total_rx; j++) { + if (iqs7211->rx_tx_map[j] != pins[i]) + continue; + + dev_err(&client->dev, "Conflicting CTx pin: %u\n", + pins[i]); + return -EINVAL; + } + + iqs7211->rx_tx_map[iqs7211->tp_config.total_rx + i] = pins[i]; + } + + iqs7211->tp_config.total_tx = count; + + return iqs7211_parse_cycles(iqs7211, tp_node); +} + +static int iqs7211_parse_alp(struct iqs7211_private *iqs7211, + struct fwnode_handle *alp_node) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + struct iqs7211_reg_field_desc reg_field; + int error, count, i; + + count = fwnode_property_count_u32(alp_node, "azoteq,rx-enable"); + if (count < 0 && count != -EINVAL) { + dev_err(&client->dev, "Failed to count CRx pins: %d\n", count); + return count; + } else if (count > IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid number of CRx pins\n"); + return -EINVAL; + } else if (count >= 0) { + unsigned int pins[IQS7211_NUM_CRX]; + + error = fwnode_property_read_u32_array(alp_node, + "azoteq,rx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CRx pins: %d\n", + error); + return error; + } + + reg_field.addr = dev_desc->alp_config; + reg_field.mask = GENMASK(IQS7211_NUM_CRX - 1, 0); + reg_field.val = 0; + + for (i = 0; i < count; i++) { + if (pins[i] < dev_desc->min_crx_alp || + pins[i] >= IQS7211_NUM_CRX) { + dev_err(&client->dev, "Invalid CRx pin: %u\n", + pins[i]); + return -EINVAL; + } + + reg_field.val |= BIT(pins[i]); + } + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } + + count = fwnode_property_count_u32(alp_node, "azoteq,tx-enable"); + if (count < 0 && count != -EINVAL) { + dev_err(&client->dev, "Failed to count CTx pins: %d\n", count); + return count; + } else if (count > dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid number of CTx pins\n"); + return -EINVAL; + } else if (count >= 0) { + unsigned int pins[IQS7211_MAX_CTX]; + + error = fwnode_property_read_u32_array(alp_node, + "azoteq,tx-enable", + pins, count); + if (error) { + dev_err(&client->dev, "Failed to read CTx pins: %d\n", + error); + return error; + } + + reg_field.addr = dev_desc->alp_config + 1; + reg_field.mask = GENMASK(dev_desc->num_ctx - 1, 0); + reg_field.val = 0; + + for (i = 0; i < count; i++) { + if (pins[i] >= dev_desc->num_ctx) { + dev_err(&client->dev, "Invalid CTx pin: %u\n", + pins[i]); + return -EINVAL; + } + + reg_field.val |= BIT(pins[i]); + } + + error = iqs7211_add_field(iqs7211, reg_field); + if (error) + return error; + } + + return 0; +} + +static int (*iqs7211_parse_extra[IQS7211_NUM_REG_GRPS]) + (struct iqs7211_private *iqs7211, + struct fwnode_handle *reg_grp_node) = { + [IQS7211_REG_GRP_TP] = iqs7211_parse_tp, + [IQS7211_REG_GRP_ALP] = iqs7211_parse_alp, +}; + +static int iqs7211_parse_reg_grp(struct iqs7211_private *iqs7211, + struct fwnode_handle *reg_grp_node, + enum iqs7211_reg_grp_id reg_grp) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct iqs7211_reg_field_desc reg_field; + int error, i; + + error = iqs7211_parse_props(iqs7211, reg_grp_node, reg_grp, + IQS7211_REG_KEY_NONE); + if (error) + return error; + + if (iqs7211_parse_extra[reg_grp]) { + error = iqs7211_parse_extra[reg_grp](iqs7211, reg_grp_node); + if (error) + return error; + } + + iqs7211->ati_start |= dev_desc->ati_start[reg_grp]; + + reg_field.addr = dev_desc->kp_enable[reg_grp]; + reg_field.mask = 0; + reg_field.val = 0; + + for (i = 0; i < dev_desc->num_kp_events; i++) { + const char *event_name = dev_desc->kp_events[i].name; + struct fwnode_handle *event_node; + + if (dev_desc->kp_events[i].reg_grp != reg_grp) + continue; + + reg_field.mask |= dev_desc->kp_events[i].enable; + + if (event_name) + event_node = fwnode_get_named_child_node(reg_grp_node, + event_name); + else + event_node = fwnode_handle_get(reg_grp_node); + + if (!event_node) + continue; + + error = iqs7211_parse_event(iqs7211, event_node, + dev_desc->kp_events[i].reg_grp, + dev_desc->kp_events[i].reg_key, + &iqs7211->kp_code[i]); + fwnode_handle_put(event_node); + if (error) + return error; + + reg_field.val |= dev_desc->kp_events[i].enable; + + iqs7211->event_mask |= iqs7211_reg_grp_masks[reg_grp]; + } + + return iqs7211_add_field(iqs7211, reg_field); +} + +static int iqs7211_register_kp(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct input_dev *kp_idev = iqs7211->kp_idev; + struct i2c_client *client = iqs7211->client; + int error, i; + + for (i = 0; i < dev_desc->num_kp_events; i++) + if (iqs7211->kp_code[i]) + break; + + if (i == dev_desc->num_kp_events) + return 0; + + kp_idev = devm_input_allocate_device(&client->dev); + if (!kp_idev) + return -ENOMEM; + + iqs7211->kp_idev = kp_idev; + + kp_idev->name = dev_desc->kp_name; + kp_idev->id.bustype = BUS_I2C; + + for (i = 0; i < dev_desc->num_kp_events; i++) + if (iqs7211->kp_code[i]) + input_set_capability(iqs7211->kp_idev, EV_KEY, + iqs7211->kp_code[i]); + + error = input_register_device(kp_idev); + if (error) + dev_err(&client->dev, "Failed to register %s: %d\n", + kp_idev->name, error); + + return error; +} + +static int iqs7211_register_tp(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct touchscreen_properties *prop = &iqs7211->prop; + struct input_dev *tp_idev = iqs7211->tp_idev; + struct i2c_client *client = iqs7211->client; + int error; + + error = device_property_read_u32(&client->dev, "azoteq,num-contacts", + &iqs7211->num_contacts); + if (error == -EINVAL) { + return 0; + } else if (error) { + dev_err(&client->dev, "Failed to read number of contacts: %d\n", + error); + return error; + } else if (iqs7211->num_contacts > IQS7211_MAX_CONTACTS) { + dev_err(&client->dev, "Invalid number of contacts: %u\n", + iqs7211->num_contacts); + return -EINVAL; + } + + iqs7211->tp_config.num_contacts = iqs7211->num_contacts ? : 1; + + if (!iqs7211->num_contacts) + return 0; + + iqs7211->event_mask |= IQS7211_EVENT_MASK_MOVE; + + tp_idev = devm_input_allocate_device(&client->dev); + if (!tp_idev) + return -ENOMEM; + + iqs7211->tp_idev = tp_idev; + + tp_idev->name = dev_desc->tp_name; + tp_idev->id.bustype = BUS_I2C; + + input_set_abs_params(tp_idev, ABS_MT_POSITION_X, + 0, le16_to_cpu(iqs7211->tp_config.max_x), 0, 0); + + input_set_abs_params(tp_idev, ABS_MT_POSITION_Y, + 0, le16_to_cpu(iqs7211->tp_config.max_y), 0, 0); + + input_set_abs_params(tp_idev, ABS_MT_PRESSURE, 0, U16_MAX, 0, 0); + + touchscreen_parse_properties(tp_idev, true, prop); + + /* + * The device reserves 0xFFFF for coordinates that correspond to slots + * which are not in a state of touch. + */ + if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) { + dev_err(&client->dev, "Invalid trackpad size: %u*%u\n", + prop->max_x, prop->max_y); + return -EINVAL; + } + + iqs7211->tp_config.max_x = cpu_to_le16(prop->max_x); + iqs7211->tp_config.max_y = cpu_to_le16(prop->max_y); + + error = input_mt_init_slots(tp_idev, iqs7211->num_contacts, + INPUT_MT_DIRECT); + if (error) { + dev_err(&client->dev, "Failed to initialize slots: %d\n", + error); + return error; + } + + error = input_register_device(tp_idev); + if (error) + dev_err(&client->dev, "Failed to register %s: %d\n", + tp_idev->name, error); + + return error; +} + +static int iqs7211_report(struct iqs7211_private *iqs7211) +{ + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + struct i2c_client *client = iqs7211->client; + struct iqs7211_touch_data *touch_data; + u16 info_flags, charge_mode, gesture_flags; + __le16 status[12]; + int error, i; + + error = iqs7211_read_burst(iqs7211, dev_desc->sys_stat, status, + dev_desc->contact_offs * sizeof(__le16) + + iqs7211->num_contacts * sizeof(*touch_data)); + if (error) + return error; + + info_flags = le16_to_cpu(status[dev_desc->info_offs]); + + if (info_flags & dev_desc->show_reset) { + dev_err(&client->dev, "Unexpected device reset\n"); + + /* + * The device may or may not expect forced communication after + * it exits hardware reset, so the corresponding state machine + * must be reset as well. + */ + iqs7211->comms_mode = iqs7211->comms_init; + + return iqs7211_init_device(iqs7211); + } + + for (i = 0; i < ARRAY_SIZE(dev_desc->ati_error); i++) { + if (!(info_flags & dev_desc->ati_error[i])) + continue; + + dev_err(&client->dev, "Unexpected %s ATI error\n", + iqs7211_reg_grp_names[i]); + return 0; + } + + for (i = 0; i < iqs7211->num_contacts; i++) { + u16 pressure; + + touch_data = (struct iqs7211_touch_data *) + &status[dev_desc->contact_offs] + i; + pressure = le16_to_cpu(touch_data->pressure); + + input_mt_slot(iqs7211->tp_idev, i); + if (input_mt_report_slot_state(iqs7211->tp_idev, MT_TOOL_FINGER, + pressure != 0)) { + touchscreen_report_pos(iqs7211->tp_idev, &iqs7211->prop, + le16_to_cpu(touch_data->abs_x), + le16_to_cpu(touch_data->abs_y), + true); + input_report_abs(iqs7211->tp_idev, ABS_MT_PRESSURE, + pressure); + } + } + + if (iqs7211->num_contacts) { + input_mt_sync_frame(iqs7211->tp_idev); + input_sync(iqs7211->tp_idev); + } + + if (!iqs7211->kp_idev) + return 0; + + charge_mode = info_flags & GENMASK(dev_desc->charge_shift + 2, + dev_desc->charge_shift); + charge_mode >>= dev_desc->charge_shift; + + /* + * A charging mode higher than 2 (idle mode) indicates the device last + * operated in low-power mode and intends to express an ALP event. + */ + if (info_flags & dev_desc->kp_events->mask && charge_mode > 2) { + input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 1); + input_sync(iqs7211->kp_idev); + + input_report_key(iqs7211->kp_idev, *iqs7211->kp_code, 0); + } + + for (i = 0; i < dev_desc->num_kp_events; i++) { + if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_BTN) + continue; + + input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], + info_flags & dev_desc->kp_events[i].mask); + } + + gesture_flags = le16_to_cpu(status[dev_desc->gesture_offs]); + + for (i = 0; i < dev_desc->num_kp_events; i++) { + enum iqs7211_reg_key_id reg_key = dev_desc->kp_events[i].reg_key; + u16 mask = dev_desc->kp_events[i].mask; + + if (dev_desc->kp_events[i].reg_grp != IQS7211_REG_GRP_TP) + continue; + + if ((gesture_flags ^ iqs7211->gesture_cache) & mask) + input_report_key(iqs7211->kp_idev, iqs7211->kp_code[i], + gesture_flags & mask); + + iqs7211->gesture_cache &= ~mask; + + /* + * Hold and palm gestures persist while the contact remains in + * place; all others are momentary and hence are followed by a + * complementary release event. + */ + if (reg_key == IQS7211_REG_KEY_HOLD || + reg_key == IQS7211_REG_KEY_PALM) { + iqs7211->gesture_cache |= gesture_flags & mask; + gesture_flags &= ~mask; + } + } + + if (gesture_flags) { + input_sync(iqs7211->kp_idev); + + for (i = 0; i < dev_desc->num_kp_events; i++) + if (dev_desc->kp_events[i].reg_grp == IQS7211_REG_GRP_TP && + gesture_flags & dev_desc->kp_events[i].mask) + input_report_key(iqs7211->kp_idev, + iqs7211->kp_code[i], 0); + } + + input_sync(iqs7211->kp_idev); + + return 0; +} + +static irqreturn_t iqs7211_irq(int irq, void *context) +{ + struct iqs7211_private *iqs7211 = context; + + return iqs7211_report(iqs7211) ? IRQ_NONE : IRQ_HANDLED; +} + +static int iqs7211_suspend(struct device *dev) +{ + struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + int error; + + if (!dev_desc->suspend || device_may_wakeup(dev)) + return 0; + + /* + * I2C communication prompts the device to assert its RDY pin if it is + * not already asserted. As such, the interrupt must be disabled so as + * to prevent reentrant interrupts. + */ + disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + error = iqs7211_write_word(iqs7211, dev_desc->sys_ctrl, + dev_desc->suspend); + + enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + return error; +} + +static int iqs7211_resume(struct device *dev) +{ + struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); + const struct iqs7211_dev_desc *dev_desc = iqs7211->dev_desc; + __le16 sys_ctrl[] = { + 0, + cpu_to_le16(iqs7211->event_mask), + }; + int error; + + if (!dev_desc->suspend || device_may_wakeup(dev)) + return 0; + + disable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + /* + * Forced communication, if in use, must be explicitly enabled as part + * of the wake-up command. + */ + error = iqs7211_write_burst(iqs7211, dev_desc->sys_ctrl, sys_ctrl, + sizeof(sys_ctrl)); + + enable_irq(gpiod_to_irq(iqs7211->irq_gpio)); + + return error; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(iqs7211_pm, iqs7211_suspend, iqs7211_resume); + +static ssize_t fw_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iqs7211_private *iqs7211 = dev_get_drvdata(dev); + + return scnprintf(buf, PAGE_SIZE, "%u.%u.%u.%u:%u.%u\n", + le16_to_cpu(iqs7211->ver_info.prod_num), + le32_to_cpu(iqs7211->ver_info.patch), + le16_to_cpu(iqs7211->ver_info.major), + le16_to_cpu(iqs7211->ver_info.minor), + iqs7211->exp_file[1], iqs7211->exp_file[0]); +} + +static DEVICE_ATTR_RO(fw_info); + +static struct attribute *iqs7211_attrs[] = { + &dev_attr_fw_info.attr, + NULL +}; +ATTRIBUTE_GROUPS(iqs7211); + +static const struct of_device_id iqs7211_of_match[] = { + { + .compatible = "azoteq,iqs7210a", + .data = &iqs7211_devs[IQS7210A], + }, + { + .compatible = "azoteq,iqs7211a", + .data = &iqs7211_devs[IQS7211A], + }, + { + .compatible = "azoteq,iqs7211e", + .data = &iqs7211_devs[IQS7211E], + }, + { } +}; +MODULE_DEVICE_TABLE(of, iqs7211_of_match); + +static int iqs7211_probe(struct i2c_client *client) +{ + struct iqs7211_private *iqs7211; + enum iqs7211_reg_grp_id reg_grp; + unsigned long irq_flags; + bool shared_irq; + int error, irq; + + iqs7211 = devm_kzalloc(&client->dev, sizeof(*iqs7211), GFP_KERNEL); + if (!iqs7211) + return -ENOMEM; + + i2c_set_clientdata(client, iqs7211); + iqs7211->client = client; + + INIT_LIST_HEAD(&iqs7211->reg_field_head); + + iqs7211->dev_desc = device_get_match_data(&client->dev); + if (!iqs7211->dev_desc) + return -ENODEV; + + shared_irq = iqs7211->dev_desc->num_ctx == IQS7211_MAX_CTX; + + /* + * The RDY pin behaves as an interrupt, but must also be polled ahead + * of unsolicited I2C communication. As such, it is first opened as a + * GPIO and then passed to gpiod_to_irq() to register the interrupt. + * + * If an extra CTx pin is present, the RDY and MCLR pins are combined + * into a single bidirectional pin. In that case, the platform's GPIO + * must be configured as an open-drain output. + */ + iqs7211->irq_gpio = devm_gpiod_get(&client->dev, "irq", + shared_irq ? GPIOD_OUT_LOW + : GPIOD_IN); + if (IS_ERR(iqs7211->irq_gpio)) { + error = PTR_ERR(iqs7211->irq_gpio); + dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n", + error); + return error; + } + + if (shared_irq) { + iqs7211->reset_gpio = iqs7211->irq_gpio; + } else { + iqs7211->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(iqs7211->reset_gpio)) { + error = PTR_ERR(iqs7211->reset_gpio); + dev_err(&client->dev, + "Failed to request reset GPIO: %d\n", error); + return error; + } + } + + error = iqs7211_start_comms(iqs7211); + if (error) + return error; + + for (reg_grp = 0; reg_grp < IQS7211_NUM_REG_GRPS; reg_grp++) { + const char *reg_grp_name = iqs7211_reg_grp_names[reg_grp]; + struct fwnode_handle *reg_grp_node; + + if (reg_grp_name) + reg_grp_node = device_get_named_child_node(&client->dev, + reg_grp_name); + else + reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev)); + + if (!reg_grp_node) + continue; + + error = iqs7211_parse_reg_grp(iqs7211, reg_grp_node, reg_grp); + fwnode_handle_put(reg_grp_node); + if (error) + return error; + } + + error = iqs7211_register_kp(iqs7211); + if (error) + return error; + + error = iqs7211_register_tp(iqs7211); + if (error) + return error; + + error = iqs7211_init_device(iqs7211); + if (error) + return error; + + irq = gpiod_to_irq(iqs7211->irq_gpio); + if (irq < 0) + return irq; + + irq_flags = gpiod_is_active_low(iqs7211->irq_gpio) ? IRQF_TRIGGER_LOW + : IRQF_TRIGGER_HIGH; + irq_flags |= IRQF_ONESHOT; + + error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7211_irq, + irq_flags, client->name, iqs7211); + if (error) + dev_err(&client->dev, "Failed to request IRQ: %d\n", error); + + return error; +} + +static struct i2c_driver iqs7211_i2c_driver = { + .probe = iqs7211_probe, + .driver = { + .name = "iqs7211", + .of_match_table = iqs7211_of_match, + .dev_groups = iqs7211_groups, + .pm = pm_sleep_ptr(&iqs7211_pm), + }, +}; +module_i2c_driver(iqs7211_i2c_driver); + +MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>"); +MODULE_DESCRIPTION("Azoteq IQS7210A/7211A/E Trackpad/Touchscreen Controller"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/lpc32xx_ts.c b/drivers/input/touchscreen/lpc32xx_ts.c index 15b5cb763526..9bad8b93c039 100644 --- a/drivers/input/touchscreen/lpc32xx_ts.c +++ b/drivers/input/touchscreen/lpc32xx_ts.c @@ -198,54 +198,36 @@ static void lpc32xx_ts_close(struct input_dev *dev) static int lpc32xx_ts_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct lpc32xx_tsc *tsc; struct input_dev *input; - struct resource *res; - resource_size_t size; int irq; int error; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "Can't get memory resource\n"); - return -ENOENT; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - tsc = kzalloc(sizeof(*tsc), GFP_KERNEL); - input = input_allocate_device(); - if (!tsc || !input) { - dev_err(&pdev->dev, "failed allocating memory\n"); - error = -ENOMEM; - goto err_free_mem; - } + tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL); + if (!tsc) + return -ENOMEM; - tsc->dev = input; tsc->irq = irq; - size = resource_size(res); - - if (!request_mem_region(res->start, size, pdev->name)) { - dev_err(&pdev->dev, "TSC registers are not free\n"); - error = -EBUSY; - goto err_free_mem; - } + tsc->tsc_base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(tsc->tsc_base)) + return PTR_ERR(tsc->tsc_base); - tsc->tsc_base = ioremap(res->start, size); - if (!tsc->tsc_base) { - dev_err(&pdev->dev, "Can't map memory\n"); - error = -ENOMEM; - goto err_release_mem; - } - - tsc->clk = clk_get(&pdev->dev, NULL); + tsc->clk = devm_clk_get(dev, NULL); if (IS_ERR(tsc->clk)) { dev_err(&pdev->dev, "failed getting clock\n"); - error = PTR_ERR(tsc->clk); - goto err_unmap; + return PTR_ERR(tsc->clk); + } + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(&pdev->dev, "failed allocating input device\n"); + return -ENOMEM; } input->name = MOD_NAME; @@ -254,68 +236,33 @@ static int lpc32xx_ts_probe(struct platform_device *pdev) input->id.vendor = 0x0001; input->id.product = 0x0002; input->id.version = 0x0100; - input->dev.parent = &pdev->dev; input->open = lpc32xx_ts_open; input->close = lpc32xx_ts_close; - input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - input->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); + input_set_capability(input, EV_KEY, BTN_TOUCH); input_set_abs_params(input, ABS_X, LPC32XX_TSC_MIN_XY_VAL, LPC32XX_TSC_MAX_XY_VAL, 0, 0); input_set_abs_params(input, ABS_Y, LPC32XX_TSC_MIN_XY_VAL, LPC32XX_TSC_MAX_XY_VAL, 0, 0); input_set_drvdata(input, tsc); + tsc->dev = input; - error = request_irq(tsc->irq, lpc32xx_ts_interrupt, - 0, pdev->name, tsc); + error = devm_request_irq(dev, tsc->irq, lpc32xx_ts_interrupt, + 0, pdev->name, tsc); if (error) { dev_err(&pdev->dev, "failed requesting interrupt\n"); - goto err_put_clock; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, "failed registering input device\n"); - goto err_free_irq; + return error; } platform_set_drvdata(pdev, tsc); - device_init_wakeup(&pdev->dev, 1); - - return 0; - -err_free_irq: - free_irq(tsc->irq, tsc); -err_put_clock: - clk_put(tsc->clk); -err_unmap: - iounmap(tsc->tsc_base); -err_release_mem: - release_mem_region(res->start, size); -err_free_mem: - input_free_device(input); - kfree(tsc); - - return error; -} - -static int lpc32xx_ts_remove(struct platform_device *pdev) -{ - struct lpc32xx_tsc *tsc = platform_get_drvdata(pdev); - struct resource *res; - - free_irq(tsc->irq, tsc); - - input_unregister_device(tsc->dev); - - clk_put(tsc->clk); - - iounmap(tsc->tsc_base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - kfree(tsc); + device_init_wakeup(&pdev->dev, true); return 0; } @@ -384,7 +331,6 @@ MODULE_DEVICE_TABLE(of, lpc32xx_tsc_of_match); static struct platform_driver lpc32xx_ts_driver = { .probe = lpc32xx_ts_probe, - .remove = lpc32xx_ts_remove, .driver = { .name = MOD_NAME, .pm = LPC32XX_TS_PM_OPS, diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index 461023fd6a09..8be6dade118c 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -230,7 +230,7 @@ static struct i2c_driver max11801_ts_driver = { .of_match_table = max11801_ts_dt_ids, }, .id_table = max11801_ts_id, - .probe_new = max11801_ts_probe, + .probe = max11801_ts_probe, }; module_i2c_driver(max11801_ts_driver); diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c index 704e36087ca2..ac28019ba4c3 100644 --- a/drivers/input/touchscreen/mcs5000_ts.c +++ b/drivers/input/touchscreen/mcs5000_ts.c @@ -272,7 +272,7 @@ static const struct i2c_device_id mcs5000_ts_id[] = { MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id); static struct i2c_driver mcs5000_ts_driver = { - .probe_new = mcs5000_ts_probe, + .probe = mcs5000_ts_probe, .driver = { .name = "mcs5000_ts", .pm = pm_sleep_ptr(&mcs5000_ts_pm), diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 89b6020a9a61..2ac4483fbc25 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1451,13 +1451,8 @@ static int mip4_probe(struct i2c_client *client) ts->gpio_ce = devm_gpiod_get_optional(&client->dev, "ce", GPIOD_OUT_LOW); - if (IS_ERR(ts->gpio_ce)) { - error = PTR_ERR(ts->gpio_ce); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get gpio: %d\n", error); - return error; - } + if (IS_ERR(ts->gpio_ce)) + return dev_err_probe(&client->dev, PTR_ERR(ts->gpio_ce), "Failed to get gpio\n"); error = mip4_power_on(ts); if (error) @@ -1591,7 +1586,7 @@ MODULE_DEVICE_TABLE(i2c, mip4_i2c_ids); static struct i2c_driver mip4_driver = { .id_table = mip4_i2c_ids, - .probe_new = mip4_probe, + .probe = mip4_probe, .driver = { .name = MIP4_DEVICE_NAME, .of_match_table = of_match_ptr(mip4_of_match), diff --git a/drivers/input/touchscreen/migor_ts.c b/drivers/input/touchscreen/migor_ts.c index 69fcc88d4f80..2384ea69a3f8 100644 --- a/drivers/input/touchscreen/migor_ts.c +++ b/drivers/input/touchscreen/migor_ts.c @@ -221,7 +221,7 @@ static struct i2c_driver migor_ts_driver = { .name = "migor_ts", .pm = pm_sleep_ptr(&migor_ts_pm), }, - .probe_new = migor_ts_probe, + .probe = migor_ts_probe, .remove = migor_ts_remove, .id_table = migor_ts_id, }; diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 4dbca1aad89d..ac12494c7930 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -638,7 +638,7 @@ static struct i2c_driver mms114_driver = { .pm = pm_sleep_ptr(&mms114_pm_ops), .of_match_table = of_match_ptr(mms114_dt_match), }, - .probe_new = mms114_probe, + .probe = mms114_probe, .id_table = mms114_id, }; diff --git a/drivers/input/touchscreen/msg2638.c b/drivers/input/touchscreen/msg2638.c index b23db689d995..a38af3fee34a 100644 --- a/drivers/input/touchscreen/msg2638.c +++ b/drivers/input/touchscreen/msg2638.c @@ -492,7 +492,7 @@ static const struct of_device_id msg2638_of_match[] = { MODULE_DEVICE_TABLE(of, msg2638_of_match); static struct i2c_driver msg2638_ts_driver = { - .probe_new = msg2638_ts_probe, + .probe = msg2638_ts_probe, .driver = { .name = "MStar-TS", .pm = pm_sleep_ptr(&msg2638_pm_ops), diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c index 3e551f9d31d7..1a797e410a3f 100644 --- a/drivers/input/touchscreen/novatek-nvt-ts.c +++ b/drivers/input/touchscreen/novatek-nvt-ts.c @@ -1,9 +1,7 @@ // 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. + * Driver for Novatek NT11205 i2c touchscreen controller as found + * on the Acer Iconia One 7 B1-750 tablet. * * Copyright (c) 2023 Hans de Goede <hdegoede@redhat.com> */ @@ -272,7 +270,7 @@ static int nvt_ts_probe(struct i2c_client *client) error = input_register_device(input); if (error) { - dev_err(dev, "failed to request irq: %d\n", error); + dev_err(dev, "failed to register input device: %d\n", error); return error; } @@ -290,12 +288,12 @@ static struct i2c_driver nvt_ts_driver = { .name = "novatek-nvt-ts", .pm = pm_sleep_ptr(&nvt_ts_pm_ops), }, - .probe_new = nvt_ts_probe, + .probe = nvt_ts_probe, .id_table = nvt_ts_i2c_id, }; module_i2c_driver(nvt_ts_driver); -MODULE_DESCRIPTION("Novatek NVT-ts touchscreen driver"); +MODULE_DESCRIPTION("Novatek NT11205 touchscreen driver"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index f09f4831bad4..0b4576091dac 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -515,41 +515,27 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client) input_set_drvdata(input, tsdata); tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); - if (IS_ERR(tsdata->gpio_attb)) { - error = PTR_ERR(tsdata->gpio_attb); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to request ATTB gpio: %d\n", - error); - return error; - } + if (IS_ERR(tsdata->gpio_attb)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_attb), + "Failed to request ATTB gpio\n"); tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(tsdata->gpio_reset)) { - error = PTR_ERR(tsdata->gpio_reset); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to request RESET gpio: %d\n", - error); - return error; - } + if (IS_ERR(tsdata->gpio_reset)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_reset), + "Failed to request RESET gpio\n"); tsdata->gpio_wake = devm_gpiod_get_optional(dev, "wake", GPIOD_OUT_HIGH); - if (IS_ERR(tsdata->gpio_wake)) { - error = PTR_ERR(tsdata->gpio_wake); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get wake gpio: %d\n", error); - return error; - } + if (IS_ERR(tsdata->gpio_wake)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_wake), + "Failed to get wake gpio\n"); tsdata->gpio_enable = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); - if (IS_ERR(tsdata->gpio_enable)) { - error = PTR_ERR(tsdata->gpio_enable); - if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get enable gpio: %d\n", error); - return error; - } + if (IS_ERR(tsdata->gpio_enable)) + return dev_err_probe(dev, PTR_ERR(tsdata->gpio_enable), + "Failed to get enable gpio\n"); if (tsdata->gpio_enable) msleep(100); @@ -617,7 +603,7 @@ static struct i2c_driver pixcir_i2c_ts_driver = { .pm = pm_sleep_ptr(&pixcir_dev_pm_ops), .of_match_table = of_match_ptr(pixcir_of_match), }, - .probe_new = pixcir_i2c_ts_probe, + .probe = pixcir_i2c_ts_probe, .id_table = pixcir_i2c_ts_id, }; diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index 49a06d3876cf..78dd3059d585 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -1087,32 +1087,20 @@ static int raydium_i2c_probe(struct i2c_client *client) i2c_set_clientdata(client, ts); ts->avdd = devm_regulator_get(&client->dev, "avdd"); - if (IS_ERR(ts->avdd)) { - error = PTR_ERR(ts->avdd); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'avdd' regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->avdd)) + return dev_err_probe(&client->dev, PTR_ERR(ts->avdd), + "Failed to get 'avdd' regulator\n"); ts->vccio = devm_regulator_get(&client->dev, "vccio"); - if (IS_ERR(ts->vccio)) { - error = PTR_ERR(ts->vccio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get 'vccio' regulator: %d\n", error); - return error; - } + if (IS_ERR(ts->vccio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->vccio), + "Failed to get 'vccio' regulator\n"); ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ts->reset_gpio)) { - error = PTR_ERR(ts->reset_gpio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "failed to get reset gpio: %d\n", error); - return error; - } + if (IS_ERR(ts->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio), + "Failed to get reset gpio\n"); error = raydium_i2c_power_on(ts); if (error) @@ -1273,7 +1261,7 @@ MODULE_DEVICE_TABLE(of, raydium_of_match); #endif static struct i2c_driver raydium_i2c_driver = { - .probe_new = raydium_i2c_probe, + .probe = raydium_i2c_probe, .id_table = raydium_i2c_id, .driver = { .name = "raydium_ts", diff --git a/drivers/input/touchscreen/resistive-adc-touch.c b/drivers/input/touchscreen/resistive-adc-touch.c index 6f754a8d30b1..7e761ec73273 100644 --- a/drivers/input/touchscreen/resistive-adc-touch.c +++ b/drivers/input/touchscreen/resistive-adc-touch.c @@ -210,12 +210,8 @@ static int grts_probe(struct platform_device *pdev) /* get the channels from IIO device */ st->iio_chans = devm_iio_channel_get_all(dev); - if (IS_ERR(st->iio_chans)) { - error = PTR_ERR(st->iio_chans); - if (error != -EPROBE_DEFER) - dev_err(dev, "can't get iio channels.\n"); - return error; - } + if (IS_ERR(st->iio_chans)) + return dev_err_probe(dev, PTR_ERR(st->iio_chans), "can't get iio channels\n"); if (!device_property_present(dev, "io-channel-names")) return -ENODEV; diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c index 833422e5fd6d..240424f06b98 100644 --- a/drivers/input/touchscreen/rohm_bu21023.c +++ b/drivers/input/touchscreen/rohm_bu21023.c @@ -1183,7 +1183,7 @@ static struct i2c_driver rohm_bu21023_i2c_driver = { .driver = { .name = BU21023_NAME, }, - .probe_new = rohm_bu21023_i2c_probe, + .probe = rohm_bu21023_i2c_probe, .id_table = rohm_bu21023_i2c_id, }; module_i2c_driver(rohm_bu21023_i2c_driver); diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c index 371cf4848ad5..998d99d18911 100644 --- a/drivers/input/touchscreen/s6sy761.c +++ b/drivers/input/touchscreen/s6sy761.c @@ -538,7 +538,7 @@ static struct i2c_driver s6sy761_driver = { .of_match_table = of_match_ptr(s6sy761_of_match), .pm = pm_ptr(&s6sy761_pm_ops), }, - .probe_new = s6sy761_probe, + .probe = s6sy761_probe, .remove = s6sy761_remove, .id_table = s6sy761_id, }; diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index a37fac089010..62f562ad5026 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -706,11 +706,9 @@ static int silead_ts_probe(struct i2c_client *client) /* Power GPIO pin */ data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); - if (IS_ERR(data->gpio_power)) { - if (PTR_ERR(data->gpio_power) != -EPROBE_DEFER) - dev_err(dev, "Shutdown GPIO request failed\n"); - return PTR_ERR(data->gpio_power); - } + if (IS_ERR(data->gpio_power)) + return dev_err_probe(dev, PTR_ERR(data->gpio_power), + "Shutdown GPIO request failed\n"); error = silead_ts_setup(client); if (error) @@ -826,7 +824,7 @@ MODULE_DEVICE_TABLE(of, silead_ts_of_match); #endif static struct i2c_driver silead_ts_driver = { - .probe_new = silead_ts_probe, + .probe = silead_ts_probe, .id_table = silead_ts_id, .driver = { .name = SILEAD_TS_NAME, diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c index 5a493b15b25d..ed56cb546f39 100644 --- a/drivers/input/touchscreen/sis_i2c.c +++ b/drivers/input/touchscreen/sis_i2c.c @@ -310,23 +310,15 @@ static int sis_ts_probe(struct i2c_client *client) ts->attn_gpio = devm_gpiod_get_optional(&client->dev, "attn", GPIOD_IN); - if (IS_ERR(ts->attn_gpio)) { - error = PTR_ERR(ts->attn_gpio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get attention GPIO: %d\n", error); - return error; - } + if (IS_ERR(ts->attn_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->attn_gpio), + "Failed to get attention GPIO\n"); ts->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); - if (IS_ERR(ts->reset_gpio)) { - error = PTR_ERR(ts->reset_gpio); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, - "Failed to get reset GPIO: %d\n", error); - return error; - } + if (IS_ERR(ts->reset_gpio)) + return dev_err_probe(&client->dev, PTR_ERR(ts->reset_gpio), + "Failed to get reset GPIO\n"); sis_ts_reset(ts); @@ -393,7 +385,7 @@ static struct i2c_driver sis_ts_driver = { .name = SIS_I2C_NAME, .of_match_table = of_match_ptr(sis_ts_dt_ids), }, - .probe_new = sis_ts_probe, + .probe = sis_ts_probe, .id_table = sis_ts_id, }; module_i2c_driver(sis_ts_driver); diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index f49566dc96f8..6475084aee1b 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -384,7 +384,7 @@ static const struct of_device_id st1232_ts_dt_ids[] = { MODULE_DEVICE_TABLE(of, st1232_ts_dt_ids); static struct i2c_driver st1232_ts_driver = { - .probe_new = st1232_ts_probe, + .probe = st1232_ts_probe, .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, diff --git a/drivers/input/touchscreen/stmfts.c b/drivers/input/touchscreen/stmfts.c index fdbf5e68943c..56e371fd88fa 100644 --- a/drivers/input/touchscreen/stmfts.c +++ b/drivers/input/touchscreen/stmfts.c @@ -808,7 +808,7 @@ static struct i2c_driver stmfts_driver = { .pm = pm_ptr(&stmfts_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, - .probe_new = stmfts_probe, + .probe = stmfts_probe, .remove = stmfts_remove, .id_table = stmfts_id, }; diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c index 31d140248f2e..7efbcd0fde4f 100644 --- a/drivers/input/touchscreen/surface3_spi.c +++ b/drivers/input/touchscreen/surface3_spi.c @@ -221,7 +221,6 @@ static void surface3_spi_power(struct surface3_ts_data *data, bool on) */ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) { - int error; struct device *dev; struct gpio_desc *gpiod; int i; @@ -231,15 +230,9 @@ static int surface3_spi_get_gpio_config(struct surface3_ts_data *data) /* Get the reset lines GPIO pin number */ for (i = 0; i < 2; i++) { gpiod = devm_gpiod_get_index(dev, NULL, i, GPIOD_OUT_LOW); - if (IS_ERR(gpiod)) { - error = PTR_ERR(gpiod); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get power GPIO %d: %d\n", - i, - error); - return error; - } + if (IS_ERR(gpiod)) + return dev_err_probe(dev, PTR_ERR(gpiod), + "Failed to get power GPIO %d\n", i); data->gpiod_rst[i] = gpiod; } diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c index 52ae73035830..f5c5881cef6b 100644 --- a/drivers/input/touchscreen/sx8654.c +++ b/drivers/input/touchscreen/sx8654.c @@ -323,13 +323,9 @@ static int sx8654_probe(struct i2c_client *client) sx8654->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(sx8654->gpio_reset)) { - error = PTR_ERR(sx8654->gpio_reset); - if (error != -EPROBE_DEFER) - dev_err(&client->dev, "unable to get reset-gpio: %d\n", - error); - return error; - } + if (IS_ERR(sx8654->gpio_reset)) + return dev_err_probe(&client->dev, PTR_ERR(sx8654->gpio_reset), + "unable to get reset-gpio\n"); dev_dbg(&client->dev, "got GPIO reset pin\n"); sx8654->data = device_get_match_data(&client->dev); @@ -470,7 +466,7 @@ static struct i2c_driver sx8654_driver = { .of_match_table = of_match_ptr(sx8654_of_match), }, .id_table = sx8654_id_table, - .probe_new = sx8654_probe, + .probe = sx8654_probe, }; module_i2c_driver(sx8654_driver); diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c index 45f39eb20638..b5e904c5b7c4 100644 --- a/drivers/input/touchscreen/tsc2004.c +++ b/drivers/input/touchscreen/tsc2004.c @@ -68,7 +68,7 @@ static struct i2c_driver tsc2004_driver = { .pm = pm_sleep_ptr(&tsc200x_pm_ops), }, .id_table = tsc2004_idtable, - .probe_new = tsc2004_probe, + .probe = tsc2004_probe, .remove = tsc2004_remove, }; module_i2c_driver(tsc2004_driver); diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c index 21916a30fb76..b3655250d4a7 100644 --- a/drivers/input/touchscreen/tsc2007_core.c +++ b/drivers/input/touchscreen/tsc2007_core.c @@ -418,7 +418,7 @@ static struct i2c_driver tsc2007_driver = { .of_match_table = tsc2007_of_match, }, .id_table = tsc2007_idtable, - .probe_new = tsc2007_probe, + .probe = tsc2007_probe, }; module_i2c_driver(tsc2007_driver); diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index a145b9105255..f389f9c004a9 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -264,7 +264,7 @@ static struct i2c_driver wacom_i2c_driver = { .pm = pm_sleep_ptr(&wacom_i2c_pm), }, - .probe_new = wacom_i2c_probe, + .probe = wacom_i2c_probe, .id_table = wacom_i2c_id, }; module_i2c_driver(wacom_i2c_driver); diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 771962af3d0a..cbc4750c53f9 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -1169,7 +1169,7 @@ static const struct acpi_device_id wdt87xx_acpi_id[] = { MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id); static struct i2c_driver wdt87xx_driver = { - .probe_new = wdt87xx_ts_probe, + .probe = wdt87xx_ts_probe, .id_table = wdt87xx_dev_id, .driver = { .name = WDT87XX_NAME, diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c index bfa0c637d569..1a034471f103 100644 --- a/drivers/input/touchscreen/zet6223.c +++ b/drivers/input/touchscreen/zet6223.c @@ -248,7 +248,7 @@ static struct i2c_driver zet6223_driver = { .name = "zet6223", .of_match_table = zet6223_of_match, }, - .probe_new = zet6223_probe, + .probe = zet6223_probe, .id_table = zet6223_id }; module_i2c_driver(zet6223_driver); diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 76b194285e1c..5be5112845e1 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -944,7 +944,7 @@ static struct i2c_driver zforce_driver = { .pm = pm_sleep_ptr(&zforce_pm_ops), .of_match_table = of_match_ptr(zforce_dt_idtable), }, - .probe_new = zforce_probe, + .probe = zforce_probe, .id_table = zforce_idtable, }; diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c index b6ece47151b8..1b4807ba4624 100644 --- a/drivers/input/touchscreen/zinitix.c +++ b/drivers/input/touchscreen/zinitix.c @@ -617,7 +617,7 @@ MODULE_DEVICE_TABLE(of, zinitix_of_match); #endif static struct i2c_driver zinitix_ts_driver = { - .probe_new = zinitix_ts_probe, + .probe = zinitix_ts_probe, .driver = { .name = "Zinitix-TS", .pm = pm_sleep_ptr(&zinitix_pm_ops), |