summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Kconfig14
-rw-r--r--drivers/input/Makefile3
-rw-r--r--drivers/input/evbug.c100
-rw-r--r--drivers/input/evdev.c32
-rw-r--r--drivers/input/ff-core.c93
-rw-r--r--drivers/input/ff-memless.c25
-rw-r--r--drivers/input/gameport/emu10k1-gp.c2
-rw-r--r--drivers/input/gameport/fm801-gp.c2
-rw-r--r--drivers/input/gameport/gameport.c14
-rw-r--r--drivers/input/gameport/ns558.c4
-rw-r--r--drivers/input/input-compat.c30
-rw-r--r--drivers/input/input-compat.h3
-rw-r--r--drivers/input/input-mt.c51
-rw-r--r--drivers/input/input-poller.c5
-rw-r--r--drivers/input/input.c663
-rw-r--r--drivers/input/joydev.c1
-rw-r--r--drivers/input/joystick/a3d.c2
-rw-r--r--drivers/input/joystick/adafruit-seesaw.c2
-rw-r--r--drivers/input/joystick/adc-joystick.c149
-rw-r--r--drivers/input/joystick/adi.c2
-rw-r--r--drivers/input/joystick/analog.c3
-rw-r--r--drivers/input/joystick/as5011.c2
-rw-r--r--drivers/input/joystick/cobra.c2
-rw-r--r--drivers/input/joystick/db9.c37
-rw-r--r--drivers/input/joystick/fsia6b.c2
-rw-r--r--drivers/input/joystick/gamecon.c29
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip.c3
-rw-r--r--drivers/input/joystick/grip_mp.c3
-rw-r--r--drivers/input/joystick/guillemot.c2
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c48
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c3
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c60
-rw-r--r--drivers/input/joystick/iforce/iforce-serio.c36
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c13
-rw-r--r--drivers/input/joystick/interact.c2
-rw-r--r--drivers/input/joystick/magellan.c4
-rw-r--r--drivers/input/joystick/maplecontrol.c2
-rw-r--r--drivers/input/joystick/n64joy.c39
-rw-r--r--drivers/input/joystick/psxpad-spi.c6
-rw-r--r--drivers/input/joystick/sidewinder.c5
-rw-r--r--drivers/input/joystick/spaceball.c4
-rw-r--r--drivers/input/joystick/spaceorb.c2
-rw-r--r--drivers/input/joystick/stinger.c2
-rw-r--r--drivers/input/joystick/tmdc.c3
-rw-r--r--drivers/input/joystick/turbografx.c29
-rw-r--r--drivers/input/joystick/twidjoy.c2
-rw-r--r--drivers/input/joystick/walkera0701.c4
-rw-r--r--drivers/input/joystick/warrior.c2
-rw-r--r--drivers/input/joystick/xpad.c318
-rw-r--r--drivers/input/joystick/zhenhua.c2
-rw-r--r--drivers/input/keyboard/Kconfig77
-rw-r--r--drivers/input/keyboard/Makefile7
-rw-r--r--drivers/input/keyboard/adc-keys.c5
-rw-r--r--drivers/input/keyboard/adp5520-keys.c2
-rw-r--r--drivers/input/keyboard/adp5585-keys.c371
-rw-r--r--drivers/input/keyboard/adp5588-keys.c112
-rw-r--r--drivers/input/keyboard/adp5589-keys.c1065
-rw-r--r--drivers/input/keyboard/applespi.c75
-rw-r--r--drivers/input/keyboard/atkbd.c65
-rw-r--r--drivers/input/keyboard/cap11xx.c137
-rw-r--r--drivers/input/keyboard/cros_ec_keyb.c16
-rw-r--r--drivers/input/keyboard/cypress-sf.c2
-rw-r--r--drivers/input/keyboard/dlink-dir685-touchkeys.c3
-rw-r--r--drivers/input/keyboard/ep93xx_keypad.c84
-rw-r--r--drivers/input/keyboard/gpio_keys.c72
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c16
-rw-r--r--drivers/input/keyboard/hilkbd.c4
-rw-r--r--drivers/input/keyboard/imx-sm-bbm-key.c225
-rw-r--r--drivers/input/keyboard/imx_keypad.c32
-rw-r--r--drivers/input/keyboard/imx_sc_key.c2
-rw-r--r--drivers/input/keyboard/ipaq-micro-keys.c17
-rw-r--r--drivers/input/keyboard/iqs62x-keys.c9
-rw-r--r--drivers/input/keyboard/lkkbd.c2
-rw-r--r--drivers/input/keyboard/lm8323.c52
-rw-r--r--drivers/input/keyboard/locomokbd.c9
-rw-r--r--drivers/input/keyboard/lpc32xx-keys.c18
-rw-r--r--drivers/input/keyboard/maple_keyb.c11
-rw-r--r--drivers/input/keyboard/matrix_keypad.c383
-rw-r--r--drivers/input/keyboard/max7360-keypad.c308
-rw-r--r--drivers/input/keyboard/mcs_touchkey.c268
-rw-r--r--drivers/input/keyboard/mpr121_touchkey.c45
-rw-r--r--drivers/input/keyboard/mt6779-keypad.c19
-rw-r--r--drivers/input/keyboard/mtk-pmic-keys.c43
-rw-r--r--drivers/input/keyboard/newtonkbd.c2
-rw-r--r--drivers/input/keyboard/nomadik-ske-keypad.c378
-rw-r--r--drivers/input/keyboard/omap-keypad.c39
-rw-r--r--drivers/input/keyboard/omap4-keypad.c6
-rw-r--r--drivers/input/keyboard/pmic8xxx-keypad.c8
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c546
-rw-r--r--drivers/input/keyboard/qt1050.c24
-rw-r--r--drivers/input/keyboard/samsung-keypad.c137
-rw-r--r--drivers/input/keyboard/sh_keysc.c2
-rw-r--r--drivers/input/keyboard/snvs_pwrkey.c54
-rw-r--r--drivers/input/keyboard/spear-keyboard.c96
-rw-r--r--drivers/input/keyboard/st-keyscan.c19
-rw-r--r--drivers/input/keyboard/stmpe-keypad.c2
-rw-r--r--drivers/input/keyboard/stowaway.c2
-rw-r--r--drivers/input/keyboard/sun4i-lradc-keys.c8
-rw-r--r--drivers/input/keyboard/sunkbd.c7
-rw-r--r--drivers/input/keyboard/tc3589x-keypad.c3
-rw-r--r--drivers/input/keyboard/tca6416-keypad.c305
-rw-r--r--drivers/input/keyboard/tca8418_keypad.c13
-rw-r--r--drivers/input/keyboard/tegra-kbc.c123
-rw-r--r--drivers/input/keyboard/twl4030_keypad.c35
-rw-r--r--drivers/input/keyboard/xtkbd.c2
-rw-r--r--drivers/input/matrix-keymap.c26
-rw-r--r--drivers/input/misc/88pm80x_onkey.c4
-rw-r--r--drivers/input/misc/88pm886-onkey.c98
-rw-r--r--drivers/input/misc/Kconfig84
-rw-r--r--drivers/input/misc/Makefile8
-rw-r--r--drivers/input/misc/ad714x.c13
-rw-r--r--drivers/input/misc/adxl34x-i2c.c9
-rw-r--r--drivers/input/misc/adxl34x-spi.c9
-rw-r--r--drivers/input/misc/adxl34x.c160
-rw-r--r--drivers/input/misc/adxl34x.h2
-rw-r--r--drivers/input/misc/arizona-haptics.c14
-rw-r--r--drivers/input/misc/ati_remote2.c107
-rw-r--r--drivers/input/misc/aw86927.c846
-rw-r--r--drivers/input/misc/cm109.c167
-rw-r--r--drivers/input/misc/cma3000_d0x.c19
-rw-r--r--drivers/input/misc/cs40l50-vibra.c558
-rw-r--r--drivers/input/misc/da7280.c26
-rw-r--r--drivers/input/misc/da9052_onkey.c4
-rw-r--r--drivers/input/misc/da9055_onkey.c4
-rw-r--r--drivers/input/misc/drv260x.c50
-rw-r--r--drivers/input/misc/drv2665.c46
-rw-r--r--drivers/input/misc/drv2667.c46
-rw-r--r--drivers/input/misc/gpio-beeper.c2
-rw-r--r--drivers/input/misc/hisi_powerkey.c2
-rw-r--r--drivers/input/misc/ibm-panel.c5
-rw-r--r--drivers/input/misc/ideapad_slidebar.c30
-rw-r--r--drivers/input/misc/ims-pcu.c207
-rw-r--r--drivers/input/misc/iqs269a.c62
-rw-r--r--drivers/input/misc/iqs626a.c24
-rw-r--r--drivers/input/misc/iqs7222.c92
-rw-r--r--drivers/input/misc/kxtj9.c16
-rw-r--r--drivers/input/misc/m68kspkr.c2
-rw-r--r--drivers/input/misc/max7360-rotary.c192
-rw-r--r--drivers/input/misc/max77693-haptic.c57
-rw-r--r--drivers/input/misc/max8997_haptic.c109
-rw-r--r--drivers/input/misc/mc13783-pwrbutton.c3
-rw-r--r--drivers/input/misc/mma8450.c16
-rw-r--r--drivers/input/misc/nxp-bbnsm-pwrkey.c48
-rw-r--r--drivers/input/misc/palmas-pwrbutton.c2
-rw-r--r--drivers/input/misc/pcap_keys.c4
-rw-r--r--drivers/input/misc/pcf50633-input.c113
-rw-r--r--drivers/input/misc/pcspkr.c2
-rw-r--r--drivers/input/misc/pf1550-onkey.c197
-rw-r--r--drivers/input/misc/pm8941-pwrkey.c18
-rw-r--r--drivers/input/misc/powermate.c13
-rw-r--r--drivers/input/misc/pwm-beeper.c12
-rw-r--r--drivers/input/misc/qnap-mcu-input.c153
-rw-r--r--drivers/input/misc/regulator-haptic.c27
-rw-r--r--drivers/input/misc/rotary_encoder.c23
-rw-r--r--drivers/input/misc/sgi_btns.c1
-rw-r--r--drivers/input/misc/soc_button_array.c5
-rw-r--r--drivers/input/misc/sparcspkr.c81
-rw-r--r--drivers/input/misc/tps65219-pwrbutton.c2
-rw-r--r--drivers/input/misc/tps6594-pwrbutton.c126
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c4
-rw-r--r--drivers/input/misc/twl4030-vibra.c11
-rw-r--r--drivers/input/misc/twl6040-vibra.c8
-rw-r--r--drivers/input/misc/uinput.c18
-rw-r--r--drivers/input/misc/wistron_btns.c10
-rw-r--r--drivers/input/misc/wm831x-on.c2
-rw-r--r--drivers/input/misc/yealink.c89
-rw-r--r--drivers/input/mouse/alps.c68
-rw-r--r--drivers/input/mouse/amimouse.c2
-rw-r--r--drivers/input/mouse/appletouch.c2
-rw-r--r--drivers/input/mouse/bcm5974.c37
-rw-r--r--drivers/input/mouse/byd.c9
-rw-r--r--drivers/input/mouse/cyapa.c4
-rw-r--r--drivers/input/mouse/cyapa_gen3.c2
-rw-r--r--drivers/input/mouse/cyapa_gen5.c2
-rw-r--r--drivers/input/mouse/cyapa_gen6.c2
-rw-r--r--drivers/input/mouse/cypress_ps2.c218
-rw-r--r--drivers/input/mouse/cypress_ps2.h6
-rw-r--r--drivers/input/mouse/elan_i2c_core.c231
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c16
-rw-r--r--drivers/input/mouse/elantech.c2
-rw-r--r--drivers/input/mouse/focaltech.c3
-rw-r--r--drivers/input/mouse/hgpk.c2
-rw-r--r--drivers/input/mouse/lifebook.c6
-rw-r--r--drivers/input/mouse/maplemouse.c2
-rw-r--r--drivers/input/mouse/psmouse-base.c4
-rw-r--r--drivers/input/mouse/psmouse-smbus.c28
-rw-r--r--drivers/input/mouse/sentelic.c2
-rw-r--r--drivers/input/mouse/sermouse.c2
-rw-r--r--drivers/input/mouse/synaptics.c74
-rw-r--r--drivers/input/mouse/synaptics.h3
-rw-r--r--drivers/input/mouse/synaptics_i2c.c2
-rw-r--r--drivers/input/mouse/vmmouse.c76
-rw-r--r--drivers/input/mouse/vsxxxaa.c2
-rw-r--r--drivers/input/rmi4/Kconfig15
-rw-r--r--drivers/input/rmi4/Makefile2
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.c1
-rw-r--r--drivers/input/rmi4/rmi_2d_sensor.h3
-rw-r--r--drivers/input/rmi4/rmi_bus.c13
-rw-r--r--drivers/input/rmi4/rmi_bus.h2
-rw-r--r--drivers/input/rmi4/rmi_driver.c3
-rw-r--r--drivers/input/rmi4/rmi_driver.h4
-rw-r--r--drivers/input/rmi4/rmi_f01.c2
-rw-r--r--drivers/input/rmi4/rmi_f03.c4
-rw-r--r--drivers/input/rmi4/rmi_f12.c43
-rw-r--r--drivers/input/rmi4/rmi_f1a.c143
-rw-r--r--drivers/input/rmi4/rmi_f21.c179
-rw-r--r--drivers/input/rmi4/rmi_f34.c174
-rw-r--r--drivers/input/rmi4/rmi_f34v7.c2
-rw-r--r--drivers/input/rmi4/rmi_f54.c2
-rw-r--r--drivers/input/serio/Kconfig4
-rw-r--r--drivers/input/serio/altera_ps2.c4
-rw-r--r--drivers/input/serio/ambakmi.c4
-rw-r--r--drivers/input/serio/ams_delta_serio.c2
-rw-r--r--drivers/input/serio/apbps2.c4
-rw-r--r--drivers/input/serio/arc_ps2.c4
-rw-r--r--drivers/input/serio/ct82c710.c4
-rw-r--r--drivers/input/serio/gscps2.c126
-rw-r--r--drivers/input/serio/hil_mlc.c3
-rw-r--r--drivers/input/serio/hp_sdc.c3
-rw-r--r--drivers/input/serio/hyperv-keyboard.c42
-rw-r--r--drivers/input/serio/i8042-acpipnpio.h191
-rw-r--r--drivers/input/serio/i8042-sparcio.h16
-rw-r--r--drivers/input/serio/i8042.c361
-rw-r--r--drivers/input/serio/ioc3kbd.c2
-rw-r--r--drivers/input/serio/libps2.c29
-rw-r--r--drivers/input/serio/maceps2.c4
-rw-r--r--drivers/input/serio/olpc_apsp.c6
-rw-r--r--drivers/input/serio/parkbd.c3
-rw-r--r--drivers/input/serio/pcips2.c4
-rw-r--r--drivers/input/serio/ps2-gpio.c18
-rw-r--r--drivers/input/serio/ps2mult.c27
-rw-r--r--drivers/input/serio/q40kbd.c16
-rw-r--r--drivers/input/serio/rpckbd.c4
-rw-r--r--drivers/input/serio/sa1111ps2.c12
-rw-r--r--drivers/input/serio/serio.c172
-rw-r--r--drivers/input/serio/serio_raw.c127
-rw-r--r--drivers/input/serio/serport.c31
-rw-r--r--drivers/input/serio/sun4i-ps2.c14
-rw-r--r--drivers/input/serio/userio.c142
-rw-r--r--drivers/input/serio/xilinx_ps2.c21
-rw-r--r--drivers/input/sparse-keymap.c4
-rw-r--r--drivers/input/tablet/acecad.c2
-rw-r--r--drivers/input/tablet/aiptek.c4
-rw-r--r--drivers/input/tablet/hanwang.c2
-rw-r--r--drivers/input/tablet/kbtab.c4
-rw-r--r--drivers/input/tablet/pegasus_notetaker.c95
-rw-r--r--drivers/input/tablet/wacom_serial4.c2
-rw-r--r--drivers/input/tests/input_test.c3
-rw-r--r--drivers/input/touch-overlay.c278
-rw-r--r--drivers/input/touchscreen.c1
-rw-r--r--drivers/input/touchscreen/88pm860x-ts.c20
-rw-r--r--drivers/input/touchscreen/Kconfig78
-rw-r--r--drivers/input/touchscreen/Makefile9
-rw-r--r--drivers/input/touchscreen/ad7877.c4
-rw-r--r--drivers/input/touchscreen/ad7879.c14
-rw-r--r--drivers/input/touchscreen/ads7846.c55
-rw-r--r--drivers/input/touchscreen/apple_z2.c477
-rw-r--r--drivers/input/touchscreen/atmel_mxt_ts.c33
-rw-r--r--drivers/input/touchscreen/auo-pixcir-ts.c2
-rw-r--r--drivers/input/touchscreen/bcm_iproc_tsc.c2
-rw-r--r--drivers/input/touchscreen/bu21029_ts.c5
-rw-r--r--drivers/input/touchscreen/chipone_icn8505.c2
-rw-r--r--drivers/input/touchscreen/colibri-vf50-ts.c10
-rw-r--r--drivers/input/touchscreen/cy8ctma140.c2
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c2174
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.h448
-rw-r--r--drivers/input/touchscreen/cyttsp4_i2c.c72
-rw-r--r--drivers/input/touchscreen/cyttsp4_spi.c187
-rw-r--r--drivers/input/touchscreen/cyttsp5.c9
-rw-r--r--drivers/input/touchscreen/cyttsp_core.c40
-rw-r--r--drivers/input/touchscreen/cyttsp_core.h5
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c.c55
-rw-r--r--drivers/input/touchscreen/cyttsp_i2c_common.c85
-rw-r--r--drivers/input/touchscreen/da9052_tsi.c4
-rw-r--r--drivers/input/touchscreen/dynapro.c2
-rw-r--r--drivers/input/touchscreen/edt-ft5x06.c56
-rw-r--r--drivers/input/touchscreen/eeti_ts.c2
-rw-r--r--drivers/input/touchscreen/egalax_ts.c3
-rw-r--r--drivers/input/touchscreen/egalax_ts_serial.c2
-rw-r--r--drivers/input/touchscreen/ektf2127.c36
-rw-r--r--drivers/input/touchscreen/elants_i2c.c2
-rw-r--r--drivers/input/touchscreen/elo.c10
-rw-r--r--drivers/input/touchscreen/exc3000.c13
-rw-r--r--drivers/input/touchscreen/fsl-imx25-tcq.c3
-rw-r--r--drivers/input/touchscreen/fujitsu_ts.c2
-rw-r--r--drivers/input/touchscreen/goodix.c80
-rw-r--r--drivers/input/touchscreen/goodix.h1
-rw-r--r--drivers/input/touchscreen/goodix_berlin.h17
-rw-r--r--drivers/input/touchscreen/goodix_berlin_core.c93
-rw-r--r--drivers/input/touchscreen/goodix_berlin_i2c.c15
-rw-r--r--drivers/input/touchscreen/goodix_berlin_spi.c69
-rw-r--r--drivers/input/touchscreen/gunze.c2
-rw-r--r--drivers/input/touchscreen/hampshire.c2
-rw-r--r--drivers/input/touchscreen/hideep.c2
-rw-r--r--drivers/input/touchscreen/himax_hx83112b.c125
-rw-r--r--drivers/input/touchscreen/himax_hx852x.c503
-rw-r--r--drivers/input/touchscreen/hycon-hy46xx.c2
-rw-r--r--drivers/input/touchscreen/hynitron-cst816x.c253
-rw-r--r--drivers/input/touchscreen/hynitron_cstxxx.c4
-rw-r--r--drivers/input/touchscreen/ili210x.c131
-rw-r--r--drivers/input/touchscreen/ilitek_ts_i2c.c21
-rw-r--r--drivers/input/touchscreen/imagis.c44
-rw-r--r--drivers/input/touchscreen/imx6ul_tsc.c121
-rw-r--r--drivers/input/touchscreen/inexio.c2
-rw-r--r--drivers/input/touchscreen/iqs5xx.c2
-rw-r--r--drivers/input/touchscreen/iqs7211.c2
-rw-r--r--drivers/input/touchscreen/mainstone-wm97xx.c2
-rw-r--r--drivers/input/touchscreen/mc13783_ts.c6
-rw-r--r--drivers/input/touchscreen/mcs5000_ts.c288
-rw-r--r--drivers/input/touchscreen/melfas_mip4.c4
-rw-r--r--drivers/input/touchscreen/mtouch.c2
-rw-r--r--drivers/input/touchscreen/novatek-nvt-ts.c69
-rw-r--r--drivers/input/touchscreen/pcap_ts.c2
-rw-r--r--drivers/input/touchscreen/penmount.c2
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c4
-rw-r--r--drivers/input/touchscreen/raspberrypi-ts.c4
-rw-r--r--drivers/input/touchscreen/raydium_i2c_ts.c2
-rw-r--r--drivers/input/touchscreen/rohm_bu21023.c99
-rw-r--r--drivers/input/touchscreen/s6sy761.c2
-rw-r--r--drivers/input/touchscreen/silead.c2
-rw-r--r--drivers/input/touchscreen/sis_i2c.c2
-rw-r--r--drivers/input/touchscreen/st1232.c35
-rw-r--r--drivers/input/touchscreen/stmpe-ts.c13
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c4
-rw-r--r--drivers/input/touchscreen/sur40.c4
-rw-r--r--drivers/input/touchscreen/surface3_spi.c2
-rw-r--r--drivers/input/touchscreen/sx8654.c4
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c4
-rw-r--r--drivers/input/touchscreen/touchit213.c2
-rw-r--r--drivers/input/touchscreen/touchright.c2
-rw-r--r--drivers/input/touchscreen/touchwin.c2
-rw-r--r--drivers/input/touchscreen/ts4800-ts.c5
-rw-r--r--drivers/input/touchscreen/tsc2004.c6
-rw-r--r--drivers/input/touchscreen/tsc2005.c6
-rw-r--r--drivers/input/touchscreen/tsc2007.h2
-rw-r--r--drivers/input/touchscreen/tsc2007_core.c44
-rw-r--r--drivers/input/touchscreen/tsc200x-core.c252
-rw-r--r--drivers/input/touchscreen/tsc200x-core.h1
-rw-r--r--drivers/input/touchscreen/tsc40.c2
-rw-r--r--drivers/input/touchscreen/usbtouchscreen.c971
-rw-r--r--drivers/input/touchscreen/wacom_i2c.c2
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c37
-rw-r--r--drivers/input/touchscreen/wdt87xx_i2c.c4
-rw-r--r--drivers/input/touchscreen/wm831x-ts.c2
-rw-r--r--drivers/input/touchscreen/wm9705.c1
-rw-r--r--drivers/input/touchscreen/wm9712.c1
-rw-r--r--drivers/input/touchscreen/wm9713.c1
-rw-r--r--drivers/input/touchscreen/wm97xx-core.c7
-rw-r--r--drivers/input/touchscreen/zet6223.c2
-rw-r--r--drivers/input/touchscreen/zforce_ts.c474
-rw-r--r--drivers/input/touchscreen/zinitix.c144
-rw-r--r--drivers/input/vivaldi-fmap.c1
353 files changed, 10850 insertions, 11608 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 3bdbd34314b3..88ecdf5218ee 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -152,20 +152,6 @@ config INPUT_EVDEV
To compile this driver as a module, choose M here: the
module will be called evdev.
-config INPUT_EVBUG
- tristate "Event debugging"
- help
- Say Y here if you have a problem with the input subsystem and
- want all events (keypresses, mouse movements), to be output to
- the system log. While this is useful for debugging, it's also
- a security threat - your keypresses include your passwords, of
- course.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called evbug.
-
config INPUT_KUNIT_TEST
tristate "KUnit tests for Input" if !KUNIT_ALL_TESTS
depends on INPUT && KUNIT
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index c78753274921..2cd6e1c9a778 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -7,7 +7,7 @@
obj-$(CONFIG_INPUT) += input-core.o
input-core-y := input.o input-compat.o input-mt.o input-poller.o ff-core.o
-input-core-y += touchscreen.o
+input-core-y += touchscreen.o touch-overlay.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o
@@ -18,7 +18,6 @@ obj-$(CONFIG_INPUT_LEDS) += input-leds.o
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
-obj-$(CONFIG_INPUT_EVBUG) += evbug.o
obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/
obj-$(CONFIG_INPUT_MOUSE) += mouse/
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
deleted file mode 100644
index e47bdf92088a..000000000000
--- a/drivers/input/evbug.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Copyright (c) 1999-2001 Vojtech Pavlik
- */
-
-/*
- * Input driver event debug module - dumps all events into syslog
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/init.h>
-#include <linux/device.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Input driver event debug module");
-MODULE_LICENSE("GPL");
-
-static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
-{
- printk(KERN_DEBUG pr_fmt("Event. Dev: %s, Type: %d, Code: %d, Value: %d\n"),
- dev_name(&handle->dev->dev), type, code, value);
-}
-
-static int evbug_connect(struct input_handler *handler, struct input_dev *dev,
- const struct input_device_id *id)
-{
- struct input_handle *handle;
- int error;
-
- handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- handle->dev = dev;
- handle->handler = handler;
- handle->name = "evbug";
-
- error = input_register_handle(handle);
- if (error)
- goto err_free_handle;
-
- error = input_open_device(handle);
- if (error)
- goto err_unregister_handle;
-
- printk(KERN_DEBUG pr_fmt("Connected device: %s (%s at %s)\n"),
- dev_name(&dev->dev),
- dev->name ?: "unknown",
- dev->phys ?: "unknown");
-
- return 0;
-
- err_unregister_handle:
- input_unregister_handle(handle);
- err_free_handle:
- kfree(handle);
- return error;
-}
-
-static void evbug_disconnect(struct input_handle *handle)
-{
- printk(KERN_DEBUG pr_fmt("Disconnected device: %s\n"),
- dev_name(&handle->dev->dev));
-
- input_close_device(handle);
- input_unregister_handle(handle);
- kfree(handle);
-}
-
-static const struct input_device_id evbug_ids[] = {
- { .driver_info = 1 }, /* Matches all devices */
- { }, /* Terminating zero entry */
-};
-
-MODULE_DEVICE_TABLE(input, evbug_ids);
-
-static struct input_handler evbug_handler = {
- .event = evbug_event,
- .connect = evbug_connect,
- .disconnect = evbug_disconnect,
- .name = "evbug",
- .id_table = evbug_ids,
-};
-
-static int __init evbug_init(void)
-{
- return input_register_handler(&evbug_handler);
-}
-
-static void __exit evbug_exit(void)
-{
- input_unregister_handler(&evbug_handler);
-}
-
-module_init(evbug_init);
-module_exit(evbug_exit);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 51e0c4954600..90ff6be85cf4 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -288,8 +288,8 @@ static void evdev_pass_values(struct evdev_client *client,
/*
* Pass incoming events to all connected clients.
*/
-static void evdev_events(struct input_handle *handle,
- const struct input_value *vals, unsigned int count)
+static unsigned int evdev_events(struct input_handle *handle,
+ struct input_value *vals, unsigned int count)
{
struct evdev *evdev = handle->private;
struct evdev_client *client;
@@ -306,17 +306,8 @@ static void evdev_events(struct input_handle *handle,
evdev_pass_values(client, vals, count, ev_time);
rcu_read_unlock();
-}
-
-/*
- * Pass incoming event to all connected clients.
- */
-static void evdev_event(struct input_handle *handle,
- unsigned int type, unsigned int code, int value)
-{
- struct input_value vals[] = { { type, code, value } };
- evdev_events(handle, vals, 1);
+ return count;
}
static int evdev_fasync(int fd, struct file *file, int on)
@@ -507,6 +498,13 @@ static ssize_t evdev_write(struct file *file, const char __user *buffer,
struct input_event event;
int retval = 0;
+ /*
+ * Limit amount of data we inject into the input subsystem so that
+ * we do not hold evdev->mutex for too long. 4096 bytes corresponds
+ * to 170 input events.
+ */
+ count = min(count, 4096);
+
if (count != 0 && count < input_event_size())
return -EINVAL;
@@ -1301,7 +1299,6 @@ static const struct file_operations evdev_fops = {
.compat_ioctl = evdev_ioctl_compat,
#endif
.fasync = evdev_fasync,
- .llseek = no_llseek,
};
/*
@@ -1411,14 +1408,17 @@ static void evdev_disconnect(struct input_handle *handle)
}
static const struct input_device_id evdev_ids[] = {
- { .driver_info = 1 }, /* Matches all devices */
- { }, /* Terminating zero entry */
+ {
+ /* Matches all devices */
+ .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+ .evbit = { BIT_MASK(EV_SYN) },
+ },
+ { } /* Terminating zero entry */
};
MODULE_DEVICE_TABLE(input, evdev_ids);
static struct input_handler evdev_handler = {
- .event = evdev_event,
.events = evdev_events,
.connect = evdev_connect,
.disconnect = evdev_disconnect,
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
index 609a5f01761b..66f7ffe8c7e0 100644
--- a/drivers/input/ff-core.c
+++ b/drivers/input/ff-core.c
@@ -8,9 +8,9 @@
/* #define DEBUG */
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/limits.h>
-#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/overflow.h>
#include <linux/sched.h>
@@ -93,7 +93,7 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
{
struct ff_device *ff = dev->ff;
struct ff_effect *old;
- int ret = 0;
+ int error;
int id;
if (!test_bit(EV_FF, dev->evbit))
@@ -114,22 +114,20 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
}
if (!test_bit(effect->type, ff->ffbit)) {
- ret = compat_effect(ff, effect);
- if (ret)
- return ret;
+ error = compat_effect(ff, effect);
+ if (error)
+ return error;
}
- mutex_lock(&ff->mutex);
+ guard(mutex)(&ff->mutex);
if (effect->id == -1) {
for (id = 0; id < ff->max_effects; id++)
if (!ff->effect_owners[id])
break;
- if (id >= ff->max_effects) {
- ret = -ENOSPC;
- goto out;
- }
+ if (id >= ff->max_effects)
+ return -ENOSPC;
effect->id = id;
old = NULL;
@@ -137,30 +135,26 @@ int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
} else {
id = effect->id;
- ret = check_effect_access(ff, id, file);
- if (ret)
- goto out;
+ error = check_effect_access(ff, id, file);
+ if (error)
+ return error;
old = &ff->effects[id];
- if (!check_effects_compatible(effect, old)) {
- ret = -EINVAL;
- goto out;
- }
+ if (!check_effects_compatible(effect, old))
+ return -EINVAL;
}
- ret = ff->upload(dev, effect, old);
- if (ret)
- goto out;
+ error = ff->upload(dev, effect, old);
+ if (error)
+ return error;
- spin_lock_irq(&dev->event_lock);
- ff->effects[id] = *effect;
- ff->effect_owners[id] = file;
- spin_unlock_irq(&dev->event_lock);
+ scoped_guard(spinlock_irq, &dev->event_lock) {
+ ff->effects[id] = *effect;
+ ff->effect_owners[id] = file;
+ }
- out:
- mutex_unlock(&ff->mutex);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(input_ff_upload);
@@ -178,17 +172,16 @@ static int erase_effect(struct input_dev *dev, int effect_id,
if (error)
return error;
- spin_lock_irq(&dev->event_lock);
- ff->playback(dev, effect_id, 0);
- ff->effect_owners[effect_id] = NULL;
- spin_unlock_irq(&dev->event_lock);
+ scoped_guard(spinlock_irq, &dev->event_lock) {
+ ff->playback(dev, effect_id, 0);
+ ff->effect_owners[effect_id] = NULL;
+ }
if (ff->erase) {
error = ff->erase(dev, effect_id);
if (error) {
- spin_lock_irq(&dev->event_lock);
- ff->effect_owners[effect_id] = file;
- spin_unlock_irq(&dev->event_lock);
+ scoped_guard(spinlock_irq, &dev->event_lock)
+ ff->effect_owners[effect_id] = file;
return error;
}
@@ -210,16 +203,12 @@ static int erase_effect(struct input_dev *dev, int effect_id,
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
{
struct ff_device *ff = dev->ff;
- int ret;
if (!test_bit(EV_FF, dev->evbit))
return -ENOSYS;
- mutex_lock(&ff->mutex);
- ret = erase_effect(dev, effect_id, file);
- mutex_unlock(&ff->mutex);
-
- return ret;
+ guard(mutex)(&ff->mutex);
+ return erase_effect(dev, effect_id, file);
}
EXPORT_SYMBOL_GPL(input_ff_erase);
@@ -239,13 +228,11 @@ int input_ff_flush(struct input_dev *dev, struct file *file)
dev_dbg(&dev->dev, "flushing now\n");
- mutex_lock(&ff->mutex);
+ guard(mutex)(&ff->mutex);
for (i = 0; i < ff->max_effects; i++)
erase_effect(dev, i, file);
- mutex_unlock(&ff->mutex);
-
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_flush);
@@ -303,8 +290,6 @@ EXPORT_SYMBOL_GPL(input_ff_event);
*/
int input_ff_create(struct input_dev *dev, unsigned int max_effects)
{
- struct ff_device *ff;
- size_t ff_dev_size;
int i;
if (!max_effects) {
@@ -317,25 +302,19 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects)
return -EINVAL;
}
- ff_dev_size = struct_size(ff, effect_owners, max_effects);
- if (ff_dev_size == SIZE_MAX) /* overflow */
- return -EINVAL;
-
- ff = kzalloc(ff_dev_size, GFP_KERNEL);
+ struct ff_device *ff __free(kfree) =
+ kzalloc(struct_size(ff, effect_owners, max_effects),
+ GFP_KERNEL);
if (!ff)
return -ENOMEM;
- ff->effects = kcalloc(max_effects, sizeof(struct ff_effect),
- GFP_KERNEL);
- if (!ff->effects) {
- kfree(ff);
+ ff->effects = kcalloc(max_effects, sizeof(*ff->effects), GFP_KERNEL);
+ if (!ff->effects)
return -ENOMEM;
- }
ff->max_effects = max_effects;
mutex_init(&ff->mutex);
- dev->ff = ff;
dev->flush = input_ff_flush;
dev->event = input_ff_event;
__set_bit(EV_FF, dev->evbit);
@@ -348,6 +327,8 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects)
if (test_bit(FF_PERIODIC, ff->ffbit))
__set_bit(FF_RUMBLE, dev->ffbit);
+ dev->ff = no_free_ptr(ff);
+
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_create);
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
index c321cdabd214..e0c1c61aae71 100644
--- a/drivers/input/ff-memless.c
+++ b/drivers/input/ff-memless.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/export.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
@@ -136,7 +137,7 @@ static void ml_schedule_timer(struct ml_device *ml)
if (!events) {
pr_debug("no actions\n");
- del_timer(&ml->timer);
+ timer_delete(&ml->timer);
} else {
pr_debug("timer set\n");
mod_timer(&ml->timer, earliest);
@@ -399,15 +400,13 @@ static void ml_play_effects(struct ml_device *ml)
static void ml_effect_timer(struct timer_list *t)
{
- struct ml_device *ml = from_timer(ml, t, timer);
+ struct ml_device *ml = timer_container_of(ml, t, timer);
struct input_dev *dev = ml->dev;
- unsigned long flags;
pr_debug("timer: updating effects\n");
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
ml_play_effects(ml);
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
/*
@@ -465,7 +464,7 @@ static int ml_ff_upload(struct input_dev *dev,
struct ml_device *ml = dev->ff->private;
struct ml_effect_state *state = &ml->states[effect->id];
- spin_lock_irq(&dev->event_lock);
+ guard(spinlock_irq)(&dev->event_lock);
if (test_bit(FF_EFFECT_STARTED, &state->flags)) {
__clear_bit(FF_EFFECT_PLAYING, &state->flags);
@@ -477,8 +476,6 @@ static int ml_ff_upload(struct input_dev *dev,
ml_schedule_timer(ml);
}
- spin_unlock_irq(&dev->event_lock);
-
return 0;
}
@@ -493,7 +490,7 @@ static void ml_ff_destroy(struct ff_device *ff)
* do not actually stop the timer, and therefore we should
* do it here.
*/
- del_timer_sync(&ml->timer);
+ timer_delete_sync(&ml->timer);
kfree(ml->private);
}
@@ -507,12 +504,11 @@ static void ml_ff_destroy(struct ff_device *ff)
int input_ff_create_memless(struct input_dev *dev, void *data,
int (*play_effect)(struct input_dev *, void *, struct ff_effect *))
{
- struct ml_device *ml;
struct ff_device *ff;
int error;
int i;
- ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL);
+ struct ml_device *ml __free(kfree) = kzalloc(sizeof(*ml), GFP_KERNEL);
if (!ml)
return -ENOMEM;
@@ -525,13 +521,10 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
set_bit(FF_GAIN, dev->ffbit);
error = input_ff_create(dev, FF_MEMLESS_EFFECTS);
- if (error) {
- kfree(ml);
+ if (error)
return error;
- }
ff = dev->ff;
- ff->private = ml;
ff->upload = ml_ff_upload;
ff->playback = ml_ff_playback;
ff->set_gain = ml_ff_set_gain;
@@ -548,6 +541,8 @@ int input_ff_create_memless(struct input_dev *dev, void *data,
for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
ml->states[i].effect = &ff->effects[i];
+ ff->private = no_free_ptr(ml);
+
return 0;
}
EXPORT_SYMBOL_GPL(input_ff_create_memless);
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
index 76ce41e58df0..4f4583048f24 100644
--- a/drivers/input/gameport/emu10k1-gp.c
+++ b/drivers/input/gameport/emu10k1-gp.c
@@ -43,7 +43,7 @@ static int emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct gameport *port;
int error;
- emu = kzalloc(sizeof(struct emu), GFP_KERNEL);
+ emu = kzalloc(sizeof(*emu), GFP_KERNEL);
port = gameport_allocate_port();
if (!emu || !port) {
printk(KERN_ERR "emu10k1-gp: Memory allocation failed\n");
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index e785d36b1926..7ae5009385cc 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -68,7 +68,7 @@ static int fm801_gp_probe(struct pci_dev *pci, const struct pci_device_id *id)
struct gameport *port;
int error;
- gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
+ gp = kzalloc(sizeof(*gp), GFP_KERNEL);
port = gameport_allocate_port();
if (!gp || !port) {
printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index cfcc81c47b50..f4f12dd00fff 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/export.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/io.h>
@@ -191,7 +192,7 @@ void gameport_stop_polling(struct gameport *gameport)
spin_lock(&gameport->timer_lock);
if (!--gameport->poll_cnt)
- del_timer(&gameport->poll_timer);
+ timer_delete(&gameport->poll_timer);
spin_unlock(&gameport->timer_lock);
}
@@ -199,7 +200,8 @@ EXPORT_SYMBOL(gameport_stop_polling);
static void gameport_run_poll_handler(struct timer_list *t)
{
- struct gameport *gameport = from_timer(gameport, t, poll_timer);
+ struct gameport *gameport = timer_container_of(gameport, t,
+ poll_timer);
gameport->poll_handler(gameport);
if (gameport->poll_cnt)
@@ -372,7 +374,7 @@ static int gameport_queue_event(void *object, struct module *owner,
}
}
- event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
+ event = kmalloc(sizeof(*event), GFP_ATOMIC);
if (!event) {
pr_err("Not enough memory to queue event %d\n", event_type);
retval = -ENOMEM;
@@ -806,9 +808,9 @@ start_over:
}
EXPORT_SYMBOL(gameport_unregister_driver);
-static int gameport_bus_match(struct device *dev, struct device_driver *drv)
+static int gameport_bus_match(struct device *dev, const struct device_driver *drv)
{
- struct gameport_driver *gameport_drv = to_gameport_driver(drv);
+ const struct gameport_driver *gameport_drv = to_gameport_driver(drv);
return !gameport_drv->ignore;
}
@@ -847,7 +849,7 @@ EXPORT_SYMBOL(gameport_open);
void gameport_close(struct gameport *gameport)
{
- del_timer_sync(&gameport->poll_timer);
+ timer_delete_sync(&gameport->poll_timer);
gameport->poll_handler = NULL;
gameport->poll_interval = 0;
gameport_set_drv(gameport, NULL);
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 91a8cd346e9b..880e714b49bc 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -120,7 +120,7 @@ static int ns558_isa_probe(int io)
return -EBUSY;
}
- ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
+ ns558 = kzalloc(sizeof(*ns558), GFP_KERNEL);
port = gameport_allocate_port();
if (!ns558 || !port) {
printk(KERN_ERR "ns558: Memory allocation failed.\n");
@@ -192,7 +192,7 @@ static int ns558_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *did)
if (!request_region(ioport, iolen, "ns558-pnp"))
return -EBUSY;
- ns558 = kzalloc(sizeof(struct ns558), GFP_KERNEL);
+ ns558 = kzalloc(sizeof(*ns558), GFP_KERNEL);
port = gameport_allocate_port();
if (!ns558 || !port) {
printk(KERN_ERR "ns558: Memory allocation failed\n");
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c
index 2ccd3eedbd67..a5043193ead8 100644
--- a/drivers/input/input-compat.c
+++ b/drivers/input/input-compat.c
@@ -6,6 +6,7 @@
*/
#include <linux/export.h>
+#include <linux/sprintf.h>
#include <linux/uaccess.h>
#include "input-compat.h"
@@ -94,6 +95,28 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size,
return 0;
}
+int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
+ bool skip_empty)
+{
+ int len = 0;
+
+ if (in_compat_syscall()) {
+ u32 dword = bits >> 32;
+ if (dword || !skip_empty)
+ len += snprintf(buf, buf_size, "%x ", dword);
+
+ dword = bits & 0xffffffffUL;
+ if (dword || !skip_empty || len)
+ len += snprintf(buf + len, max(buf_size - len, 0),
+ "%x", dword);
+ } else {
+ if (bits || !skip_empty)
+ len += snprintf(buf, buf_size, "%lx", bits);
+ }
+
+ return len;
+}
+
#else
int input_event_from_user(const char __user *buffer,
@@ -126,6 +149,13 @@ int input_ff_effect_from_user(const char __user *buffer, size_t size,
return 0;
}
+int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
+ bool skip_empty)
+{
+ return bits || !skip_empty ?
+ snprintf(buf, buf_size, "%lx", bits) : 0;
+}
+
#endif /* CONFIG_COMPAT */
EXPORT_SYMBOL_GPL(input_event_from_user);
diff --git a/drivers/input/input-compat.h b/drivers/input/input-compat.h
index 3b7bb12b023b..99c87ceb923d 100644
--- a/drivers/input/input-compat.h
+++ b/drivers/input/input-compat.h
@@ -75,4 +75,7 @@ int input_event_to_user(char __user *buffer,
int input_ff_effect_from_user(const char __user *buffer, size_t size,
struct ff_effect *effect);
+int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
+ bool skip_empty);
+
#endif /* _INPUT_COMPAT_H */
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index 14b53dac1253..09f518897d4a 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -39,17 +39,20 @@ static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src)
int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int flags)
{
- struct input_mt *mt = dev->mt;
- int i;
-
if (!num_slots)
return 0;
- if (mt)
- return mt->num_slots != num_slots ? -EINVAL : 0;
- mt = kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
+ if (dev->mt)
+ return dev->mt->num_slots != num_slots ? -EINVAL : 0;
+
+ /* Arbitrary limit for avoiding too large memory allocation. */
+ if (num_slots > 1024)
+ return -EINVAL;
+
+ struct input_mt *mt __free(kfree) =
+ kzalloc(struct_size(mt, slots, num_slots), GFP_KERNEL);
if (!mt)
- goto err_mem;
+ return -ENOMEM;
mt->num_slots = num_slots;
mt->flags = flags;
@@ -83,21 +86,18 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots,
unsigned int n2 = num_slots * num_slots;
mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL);
if (!mt->red)
- goto err_mem;
+ return -ENOMEM;
}
/* Mark slots as 'inactive' */
- for (i = 0; i < num_slots; i++)
+ for (unsigned int i = 0; i < num_slots; i++)
input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1);
/* Mark slots as 'unused' */
mt->frame = 1;
- dev->mt = mt;
+ dev->mt = no_free_ptr(mt);
return 0;
-err_mem:
- kfree(mt);
- return -ENOMEM;
}
EXPORT_SYMBOL(input_mt_init_slots);
@@ -198,6 +198,7 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
struct input_mt *mt = dev->mt;
struct input_mt_slot *oldest;
int oldid, count, i;
+ int p, reported_p = 0;
if (!mt)
return;
@@ -216,6 +217,13 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
oldest = ps;
oldid = id;
}
+ if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
+ p = input_mt_get_value(ps, ABS_MT_PRESSURE);
+ if (mt->flags & INPUT_MT_TOTAL_FORCE)
+ reported_p += p;
+ else if (oldid == id)
+ reported_p = p;
+ }
count++;
}
@@ -245,10 +253,8 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
input_event(dev, EV_ABS, ABS_X, x);
input_event(dev, EV_ABS, ABS_Y, y);
- if (test_bit(ABS_MT_PRESSURE, dev->absbit)) {
- int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
- input_event(dev, EV_ABS, ABS_PRESSURE, p);
- }
+ if (test_bit(ABS_MT_PRESSURE, dev->absbit))
+ input_event(dev, EV_ABS, ABS_PRESSURE, reported_p);
} else {
if (test_bit(ABS_MT_PRESSURE, dev->absbit))
input_event(dev, EV_ABS, ABS_PRESSURE, 0);
@@ -282,14 +288,10 @@ void input_mt_drop_unused(struct input_dev *dev)
struct input_mt *mt = dev->mt;
if (mt) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
__input_mt_drop_unused(dev, mt);
mt->frame++;
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_mt_drop_unused);
@@ -336,11 +338,8 @@ void input_mt_sync_frame(struct input_dev *dev)
return;
if (mt->flags & INPUT_MT_DROP_UNUSED) {
- unsigned long flags;
-
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
__input_mt_drop_unused(dev, mt);
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
diff --git a/drivers/input/input-poller.c b/drivers/input/input-poller.c
index 688e3cb1c2a0..1ce83d6521bb 100644
--- a/drivers/input/input-poller.c
+++ b/drivers/input/input-poller.c
@@ -4,6 +4,7 @@
*/
#include <linux/device.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
@@ -162,7 +163,7 @@ static ssize_t input_dev_set_poll_interval(struct device *dev,
if (interval > poller->poll_interval_max)
return -EINVAL;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
poller->poll_interval = interval;
@@ -172,8 +173,6 @@ static ssize_t input_dev_set_poll_interval(struct device *dev,
input_dev_poller_queue_work(poller);
}
- mutex_unlock(&input->mutex);
-
return count;
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index fd4997ba263c..a500e1e276c2 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt
+#include <linux/export.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/idr.h>
@@ -96,48 +97,16 @@ static void input_start_autorepeat(struct input_dev *dev, int code)
static void input_stop_autorepeat(struct input_dev *dev)
{
- del_timer(&dev->timer);
-}
-
-/*
- * Pass event first through all filters and then, if event has not been
- * filtered out, through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled.
- */
-static unsigned int input_to_handler(struct input_handle *handle,
- struct input_value *vals, unsigned int count)
-{
- struct input_handler *handler = handle->handler;
- struct input_value *end = vals;
- struct input_value *v;
-
- if (handler->filter) {
- for (v = vals; v != vals + count; v++) {
- if (handler->filter(handle, v->type, v->code, v->value))
- continue;
- if (end != v)
- *end = *v;
- end++;
- }
- count = end - vals;
- }
-
- if (!count)
- return 0;
-
- if (handler->events)
- handler->events(handle, vals, count);
- else if (handler->event)
- for (v = vals; v != vals + count; v++)
- handler->event(handle, v->type, v->code, v->value);
-
- return count;
+ timer_delete(&dev->timer);
}
/*
* Pass values first through all filters and then, if event has not been
- * filtered out, through all open handles. This function is called with
- * dev->event_lock held and interrupts disabled.
+ * filtered out, through all open handles. This order is achieved by placing
+ * filters at the head of the list of handles attached to the device, and
+ * placing regular handles at the tail of the list.
+ *
+ * This function is called with dev->event_lock held and interrupts disabled.
*/
static void input_pass_values(struct input_dev *dev,
struct input_value *vals, unsigned int count)
@@ -147,25 +116,23 @@ static void input_pass_values(struct input_dev *dev,
lockdep_assert_held(&dev->event_lock);
- if (!count)
- return;
-
- rcu_read_lock();
+ scoped_guard(rcu) {
+ handle = rcu_dereference(dev->grab);
+ if (handle) {
+ count = handle->handle_events(handle, vals, count);
+ break;
+ }
- handle = rcu_dereference(dev->grab);
- if (handle) {
- count = input_to_handler(handle, vals, count);
- } else {
- list_for_each_entry_rcu(handle, &dev->h_list, d_node)
+ list_for_each_entry_rcu(handle, &dev->h_list, d_node) {
if (handle->open) {
- count = input_to_handler(handle, vals, count);
+ count = handle->handle_events(handle, vals,
+ count);
if (!count)
break;
}
+ }
}
- rcu_read_unlock();
-
/* trigger auto repeat for key events */
if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
for (v = vals; v != vals + count; v++) {
@@ -354,9 +321,6 @@ static void input_event_dispose(struct input_dev *dev, int disposition,
if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event)
dev->event(dev, type, code, value);
- if (!dev->vals)
- return;
-
if (disposition & INPUT_PASS_TO_HANDLERS) {
struct input_value *v;
@@ -427,13 +391,9 @@ void input_handle_event(struct input_dev *dev,
void input_event(struct input_dev *dev,
unsigned int type, unsigned int code, int value)
{
- unsigned long flags;
-
if (is_event_supported(type, dev->evbit, EV_MAX)) {
-
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
input_handle_event(dev, type, code, value);
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_event);
@@ -454,18 +414,15 @@ void input_inject_event(struct input_handle *handle,
{
struct input_dev *dev = handle->dev;
struct input_handle *grab;
- unsigned long flags;
if (is_event_supported(type, dev->evbit, EV_MAX)) {
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
+ guard(rcu)();
- rcu_read_lock();
grab = rcu_dereference(dev->grab);
if (!grab || grab == handle)
input_handle_event(dev, type, code, value);
- rcu_read_unlock();
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
}
EXPORT_SYMBOL(input_inject_event);
@@ -563,22 +520,15 @@ EXPORT_SYMBOL(input_copy_abs);
int input_grab_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- int retval;
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ if (dev->grab)
+ return -EBUSY;
- if (dev->grab) {
- retval = -EBUSY;
- goto out;
+ rcu_assign_pointer(dev->grab, handle);
}
- rcu_assign_pointer(dev->grab, handle);
-
- out:
- mutex_unlock(&dev->mutex);
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_grab_device);
@@ -613,9 +563,8 @@ void input_release_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
__input_release_device(handle);
- mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_release_device);
@@ -629,64 +578,57 @@ EXPORT_SYMBOL(input_release_device);
int input_open_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- int retval;
+ int error;
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ if (dev->going_away)
+ return -ENODEV;
- if (dev->going_away) {
- retval = -ENODEV;
- goto out;
- }
+ handle->open++;
- handle->open++;
+ if (handle->handler->passive_observer)
+ return 0;
- if (dev->users++ || dev->inhibited) {
- /*
- * Device is already opened and/or inhibited,
- * so we can exit immediately and report success.
- */
- goto out;
- }
-
- if (dev->open) {
- retval = dev->open(dev);
- if (retval) {
- dev->users--;
- handle->open--;
+ if (dev->users++ || dev->inhibited) {
/*
- * Make sure we are not delivering any more events
- * through this handle
+ * Device is already opened and/or inhibited,
+ * so we can exit immediately and report success.
*/
- synchronize_rcu();
- goto out;
+ return 0;
}
- }
- if (dev->poller)
- input_dev_poller_start(dev->poller);
+ if (dev->open) {
+ error = dev->open(dev);
+ if (error) {
+ dev->users--;
+ handle->open--;
+ /*
+ * Make sure we are not delivering any more
+ * events through this handle.
+ */
+ synchronize_rcu();
+ return error;
+ }
+ }
- out:
- mutex_unlock(&dev->mutex);
- return retval;
+ if (dev->poller)
+ input_dev_poller_start(dev->poller);
+ }
+
+ return 0;
}
EXPORT_SYMBOL(input_open_device);
int input_flush_device(struct input_handle *handle, struct file *file)
{
struct input_dev *dev = handle->dev;
- int retval;
-
- retval = mutex_lock_interruptible(&dev->mutex);
- if (retval)
- return retval;
- if (dev->flush)
- retval = dev->flush(dev, file);
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ if (dev->flush)
+ return dev->flush(dev, file);
+ }
- mutex_unlock(&dev->mutex);
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_flush_device);
@@ -701,15 +643,17 @@ void input_close_device(struct input_handle *handle)
{
struct input_dev *dev = handle->dev;
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
__input_release_device(handle);
- if (!--dev->users && !dev->inhibited) {
- if (dev->poller)
- input_dev_poller_stop(dev->poller);
- if (dev->close)
- dev->close(dev);
+ if (!handle->handler->passive_observer) {
+ if (!--dev->users && !dev->inhibited) {
+ if (dev->poller)
+ input_dev_poller_stop(dev->poller);
+ if (dev->close)
+ dev->close(dev);
+ }
}
if (!--handle->open) {
@@ -720,8 +664,6 @@ void input_close_device(struct input_handle *handle)
*/
synchronize_rcu();
}
-
- mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_close_device);
@@ -758,11 +700,10 @@ static void input_disconnect_device(struct input_dev *dev)
* not to protect access to dev->going_away but rather to ensure
* that there are no threads in the middle of input_open_device()
*/
- mutex_lock(&dev->mutex);
- dev->going_away = true;
- mutex_unlock(&dev->mutex);
+ scoped_guard(mutex, &dev->mutex)
+ dev->going_away = true;
- spin_lock_irq(&dev->event_lock);
+ guard(spinlock_irq)(&dev->event_lock);
/*
* Simulate keyup events for all pressed keys so that handlers
@@ -775,8 +716,6 @@ static void input_disconnect_device(struct input_dev *dev)
list_for_each_entry(handle, &dev->h_list, d_node)
handle->open = 0;
-
- spin_unlock_irq(&dev->event_lock);
}
/**
@@ -933,14 +872,9 @@ static int input_default_setkeycode(struct input_dev *dev,
*/
int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke)
{
- unsigned long flags;
- int retval;
-
- spin_lock_irqsave(&dev->event_lock, flags);
- retval = dev->getkeycode(dev, ke);
- spin_unlock_irqrestore(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
- return retval;
+ return dev->getkeycode(dev, ke);
}
EXPORT_SYMBOL(input_get_keycode);
@@ -955,18 +889,17 @@ EXPORT_SYMBOL(input_get_keycode);
int input_set_keycode(struct input_dev *dev,
const struct input_keymap_entry *ke)
{
- unsigned long flags;
unsigned int old_keycode;
- int retval;
+ int error;
if (ke->keycode > KEY_MAX)
return -EINVAL;
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
- retval = dev->setkeycode(dev, ke, &old_keycode);
- if (retval)
- goto out;
+ error = dev->setkeycode(dev, ke, &old_keycode);
+ if (error)
+ return error;
/* Make sure KEY_RESERVED did not get enabled. */
__clear_bit(KEY_RESERVED, dev->keybit);
@@ -994,10 +927,7 @@ int input_set_keycode(struct input_dev *dev,
EV_SYN, SYN_REPORT, 1);
}
- out:
- spin_unlock_irqrestore(&dev->event_lock, flags);
-
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_set_keycode);
@@ -1042,7 +972,7 @@ static const struct input_device_id *input_match_device(struct input_handler *ha
{
const struct input_device_id *id;
- for (id = handler->id_table; id->flags || id->driver_info; id++) {
+ for (id = handler->id_table; id->flags; id++) {
if (input_match_device_id(dev, id) &&
(!handler->match || handler->match(handler, dev))) {
return id;
@@ -1069,41 +999,6 @@ static int input_attach_handler(struct input_dev *dev, struct input_handler *han
return error;
}
-#ifdef CONFIG_COMPAT
-
-static int input_bits_to_string(char *buf, int buf_size,
- unsigned long bits, bool skip_empty)
-{
- int len = 0;
-
- if (in_compat_syscall()) {
- u32 dword = bits >> 32;
- if (dword || !skip_empty)
- len += snprintf(buf, buf_size, "%x ", dword);
-
- dword = bits & 0xffffffffUL;
- if (dword || !skip_empty || len)
- len += snprintf(buf + len, max(buf_size - len, 0),
- "%x", dword);
- } else {
- if (bits || !skip_empty)
- len += snprintf(buf, buf_size, "%lx", bits);
- }
-
- return len;
-}
-
-#else /* !CONFIG_COMPAT */
-
-static int input_bits_to_string(char *buf, int buf_size,
- unsigned long bits, bool skip_empty)
-{
- return bits || !skip_empty ?
- snprintf(buf, buf_size, "%lx", bits) : 0;
-}
-
-#endif
-
#ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_bus_input_dir;
@@ -1116,33 +1011,31 @@ static inline void input_wakeup_procfs_readers(void)
wake_up(&input_devices_poll_wait);
}
+struct input_seq_state {
+ unsigned short pos;
+ bool mutex_acquired;
+ int input_devices_state;
+};
+
static __poll_t input_proc_devices_poll(struct file *file, poll_table *wait)
{
+ struct seq_file *seq = file->private_data;
+ struct input_seq_state *state = seq->private;
+
poll_wait(file, &input_devices_poll_wait, wait);
- if (file->f_version != input_devices_state) {
- file->f_version = input_devices_state;
+ if (state->input_devices_state != input_devices_state) {
+ state->input_devices_state = input_devices_state;
return EPOLLIN | EPOLLRDNORM;
}
return 0;
}
-union input_seq_state {
- struct {
- unsigned short pos;
- bool mutex_acquired;
- };
- void *p;
-};
-
static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
int error;
- /* We need to fit into seq->private pointer */
- BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
-
error = mutex_lock_interruptible(&input_mutex);
if (error) {
state->mutex_acquired = false;
@@ -1161,7 +1054,7 @@ static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static void input_seq_stop(struct seq_file *seq, void *v)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
if (state->mutex_acquired)
mutex_unlock(&input_mutex);
@@ -1247,7 +1140,8 @@ static const struct seq_operations input_devices_seq_ops = {
static int input_proc_devices_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &input_devices_seq_ops);
+ return seq_open_private(file, &input_devices_seq_ops,
+ sizeof(struct input_seq_state));
}
static const struct proc_ops input_devices_proc_ops = {
@@ -1255,17 +1149,14 @@ static const struct proc_ops input_devices_proc_ops = {
.proc_poll = input_proc_devices_poll,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
- .proc_release = seq_release,
+ .proc_release = seq_release_private,
};
static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
int error;
- /* We need to fit into seq->private pointer */
- BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private));
-
error = mutex_lock_interruptible(&input_mutex);
if (error) {
state->mutex_acquired = false;
@@ -1280,7 +1171,7 @@ static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos)
static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
state->pos = *pos + 1;
return seq_list_next(v, &input_handler_list, pos);
@@ -1289,7 +1180,7 @@ static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static int input_handlers_seq_show(struct seq_file *seq, void *v)
{
struct input_handler *handler = container_of(v, struct input_handler, node);
- union input_seq_state *state = (union input_seq_state *)&seq->private;
+ struct input_seq_state *state = seq->private;
seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name);
if (handler->filter)
@@ -1310,14 +1201,15 @@ static const struct seq_operations input_handlers_seq_ops = {
static int input_proc_handlers_open(struct inode *inode, struct file *file)
{
- return seq_open(file, &input_handlers_seq_ops);
+ return seq_open_private(file, &input_handlers_seq_ops,
+ sizeof(struct input_seq_state));
}
static const struct proc_ops input_handlers_proc_ops = {
.proc_open = input_proc_handlers_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
- .proc_release = seq_release,
+ .proc_release = seq_release_private,
};
static int __init input_proc_init(void)
@@ -1834,26 +1726,21 @@ static void input_dev_toggle(struct input_dev *dev, bool activate)
*/
void input_reset_device(struct input_dev *dev)
{
- unsigned long flags;
-
- mutex_lock(&dev->mutex);
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(mutex)(&dev->mutex);
+ guard(spinlock_irqsave)(&dev->event_lock);
input_dev_toggle(dev, true);
if (input_dev_release_keys(dev))
input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
- mutex_unlock(&dev->mutex);
}
EXPORT_SYMBOL(input_reset_device);
static int input_inhibit_device(struct input_dev *dev)
{
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
if (dev->inhibited)
- goto out;
+ return 0;
if (dev->users) {
if (dev->close)
@@ -1862,54 +1749,50 @@ static int input_inhibit_device(struct input_dev *dev)
input_dev_poller_stop(dev->poller);
}
- spin_lock_irq(&dev->event_lock);
- input_mt_release_slots(dev);
- input_dev_release_keys(dev);
- input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
- input_dev_toggle(dev, false);
- spin_unlock_irq(&dev->event_lock);
+ scoped_guard(spinlock_irq, &dev->event_lock) {
+ input_mt_release_slots(dev);
+ input_dev_release_keys(dev);
+ input_handle_event(dev, EV_SYN, SYN_REPORT, 1);
+ input_dev_toggle(dev, false);
+ }
dev->inhibited = true;
-out:
- mutex_unlock(&dev->mutex);
return 0;
}
static int input_uninhibit_device(struct input_dev *dev)
{
- int ret = 0;
+ int error;
- mutex_lock(&dev->mutex);
+ guard(mutex)(&dev->mutex);
if (!dev->inhibited)
- goto out;
+ return 0;
if (dev->users) {
if (dev->open) {
- ret = dev->open(dev);
- if (ret)
- goto out;
+ error = dev->open(dev);
+ if (error)
+ return error;
}
if (dev->poller)
input_dev_poller_start(dev->poller);
}
dev->inhibited = false;
- spin_lock_irq(&dev->event_lock);
- input_dev_toggle(dev, true);
- spin_unlock_irq(&dev->event_lock);
-out:
- mutex_unlock(&dev->mutex);
- return ret;
+ scoped_guard(spinlock_irq, &dev->event_lock)
+ input_dev_toggle(dev, true);
+
+ return 0;
}
static int input_dev_suspend(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/*
* Keys that are pressed now are unlikely to be
@@ -1921,8 +1804,6 @@ static int input_dev_suspend(struct device *dev)
/* Turn off LEDs and sounds, if any are active. */
input_dev_toggle(input_dev, false);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1930,13 +1811,11 @@ static int input_dev_resume(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/* Restore state of LEDs and sounds, if any were active. */
input_dev_toggle(input_dev, true);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1944,7 +1823,7 @@ static int input_dev_freeze(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/*
* Keys that are pressed now are unlikely to be
@@ -1953,8 +1832,6 @@ static int input_dev_freeze(struct device *dev)
if (input_dev_release_keys(input_dev))
input_handle_event(input_dev, EV_SYN, SYN_REPORT, 1);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -1962,13 +1839,11 @@ static int input_dev_poweroff(struct device *dev)
{
struct input_dev *input_dev = to_input_dev(dev);
- spin_lock_irq(&input_dev->event_lock);
+ guard(spinlock_irq)(&input_dev->event_lock);
/* Turn off LEDs and sounds, if any are active. */
input_dev_toggle(input_dev, false);
- spin_unlock_irq(&input_dev->event_lock);
-
return 0;
}
@@ -2013,22 +1888,41 @@ struct input_dev *input_allocate_device(void)
struct input_dev *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev) {
- dev->dev.type = &input_dev_type;
- dev->dev.class = &input_class;
- device_initialize(&dev->dev);
- mutex_init(&dev->mutex);
- spin_lock_init(&dev->event_lock);
- timer_setup(&dev->timer, NULL, 0);
- INIT_LIST_HEAD(&dev->h_list);
- INIT_LIST_HEAD(&dev->node);
-
- dev_set_name(&dev->dev, "input%lu",
- (unsigned long)atomic_inc_return(&input_no));
-
- __module_get(THIS_MODULE);
+ if (!dev)
+ return NULL;
+
+ /*
+ * Start with space for SYN_REPORT + 7 EV_KEY/EV_MSC events + 2 spare,
+ * see input_estimate_events_per_packet(). We will tune the number
+ * when we register the device.
+ */
+ dev->max_vals = 10;
+ dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
+ if (!dev->vals) {
+ kfree(dev);
+ return NULL;
}
+ mutex_init(&dev->mutex);
+ spin_lock_init(&dev->event_lock);
+ timer_setup(&dev->timer, NULL, 0);
+ INIT_LIST_HEAD(&dev->h_list);
+ INIT_LIST_HEAD(&dev->node);
+
+ dev->dev.type = &input_dev_type;
+ dev->dev.class = &input_class;
+ device_initialize(&dev->dev);
+ /*
+ * From this point on we can no longer simply "kfree(dev)", we need
+ * to use input_free_device() so that device core properly frees its
+ * resources associated with the input device.
+ */
+
+ dev_set_name(&dev->dev, "input%lu",
+ (unsigned long)atomic_inc_return(&input_no));
+
+ __module_get(THIS_MODULE);
+
return dev;
}
EXPORT_SYMBOL(input_allocate_device);
@@ -2242,7 +2136,7 @@ static unsigned int input_estimate_events_per_packet(struct input_dev *dev)
mt_slots = dev->mt->num_slots;
} else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) {
mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum -
- dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1,
+ dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1;
mt_slots = clamp(mt_slots, 2, 32);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
mt_slots = 2;
@@ -2290,18 +2184,16 @@ static void __input_unregister_device(struct input_dev *dev)
input_disconnect_device(dev);
- mutex_lock(&input_mutex);
-
- list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
- handle->handler->disconnect(handle);
- WARN_ON(!list_empty(&dev->h_list));
+ scoped_guard(mutex, &input_mutex) {
+ list_for_each_entry_safe(handle, next, &dev->h_list, d_node)
+ handle->handler->disconnect(handle);
+ WARN_ON(!list_empty(&dev->h_list));
- del_timer_sync(&dev->timer);
- list_del_init(&dev->node);
+ timer_delete_sync(&dev->timer);
+ list_del_init(&dev->node);
- input_wakeup_procfs_readers();
-
- mutex_unlock(&input_mutex);
+ input_wakeup_procfs_readers();
+ }
device_del(&dev->dev);
}
@@ -2323,10 +2215,9 @@ static void devm_input_device_unregister(struct device *dev, void *res)
*/
static void input_repeat_key(struct timer_list *t)
{
- struct input_dev *dev = from_timer(dev, t, timer);
- unsigned long flags;
+ struct input_dev *dev = timer_container_of(dev, t, timer);
- spin_lock_irqsave(&dev->event_lock, flags);
+ guard(spinlock_irqsave)(&dev->event_lock);
if (!dev->inhibited &&
test_bit(dev->repeat_key, dev->key) &&
@@ -2340,8 +2231,6 @@ static void input_repeat_key(struct timer_list *t)
mod_timer(&dev->timer, jiffies +
msecs_to_jiffies(dev->rep[REP_PERIOD]));
}
-
- spin_unlock_irqrestore(&dev->event_lock, flags);
}
/**
@@ -2368,6 +2257,35 @@ bool input_device_enabled(struct input_dev *dev)
}
EXPORT_SYMBOL_GPL(input_device_enabled);
+static int input_device_tune_vals(struct input_dev *dev)
+{
+ struct input_value *vals;
+ unsigned int packet_size;
+ unsigned int max_vals;
+
+ packet_size = input_estimate_events_per_packet(dev);
+ if (dev->hint_events_per_packet < packet_size)
+ dev->hint_events_per_packet = packet_size;
+
+ max_vals = dev->hint_events_per_packet + 2;
+ if (dev->max_vals >= max_vals)
+ return 0;
+
+ vals = kcalloc(max_vals, sizeof(*vals), GFP_KERNEL);
+ if (!vals)
+ return -ENOMEM;
+
+ scoped_guard(spinlock_irq, &dev->event_lock) {
+ dev->max_vals = max_vals;
+ swap(dev->vals, vals);
+ }
+
+ /* Because of swap() above, this frees the old vals memory */
+ kfree(vals);
+
+ return 0;
+}
+
/**
* input_register_device - register device with input core
* @dev: device to be registered
@@ -2395,7 +2313,6 @@ int input_register_device(struct input_dev *dev)
{
struct input_devres *devres = NULL;
struct input_handler *handler;
- unsigned int packet_size;
const char *path;
int error;
@@ -2423,16 +2340,9 @@ int input_register_device(struct input_dev *dev)
/* Make sure that bitmasks not mentioned in dev->evbit are clean. */
input_cleanse_bitmasks(dev);
- packet_size = input_estimate_events_per_packet(dev);
- if (dev->hint_events_per_packet < packet_size)
- dev->hint_events_per_packet = packet_size;
-
- dev->max_vals = dev->hint_events_per_packet + 2;
- dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL);
- if (!dev->vals) {
- error = -ENOMEM;
+ error = input_device_tune_vals(dev);
+ if (error)
goto err_devres_free;
- }
/*
* If delay and period are pre-set by the driver, then autorepeating
@@ -2452,7 +2362,7 @@ int input_register_device(struct input_dev *dev)
error = device_add(&dev->dev);
if (error)
- goto err_free_vals;
+ goto err_devres_free;
path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
pr_info("%s as %s\n",
@@ -2460,18 +2370,15 @@ int input_register_device(struct input_dev *dev)
path ? path : "N/A");
kfree(path);
- error = mutex_lock_interruptible(&input_mutex);
- if (error)
- goto err_device_del;
-
- list_add_tail(&dev->node, &input_dev_list);
-
- list_for_each_entry(handler, &input_handler_list, node)
- input_attach_handler(dev, handler);
+ error = -EINTR;
+ scoped_cond_guard(mutex_intr, goto err_device_del, &input_mutex) {
+ list_add_tail(&dev->node, &input_dev_list);
- input_wakeup_procfs_readers();
+ list_for_each_entry(handler, &input_handler_list, node)
+ input_attach_handler(dev, handler);
- mutex_unlock(&input_mutex);
+ input_wakeup_procfs_readers();
+ }
if (dev->devres_managed) {
dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n",
@@ -2482,9 +2389,6 @@ int input_register_device(struct input_dev *dev)
err_device_del:
device_del(&dev->dev);
-err_free_vals:
- kfree(dev->vals);
- dev->vals = NULL;
err_devres_free:
devres_free(devres);
return error;
@@ -2517,6 +2421,26 @@ void input_unregister_device(struct input_dev *dev)
}
EXPORT_SYMBOL(input_unregister_device);
+static int input_handler_check_methods(const struct input_handler *handler)
+{
+ int count = 0;
+
+ if (handler->filter)
+ count++;
+ if (handler->events)
+ count++;
+ if (handler->event)
+ count++;
+
+ if (count > 1) {
+ pr_err("%s: only one event processing method can be defined (%s)\n",
+ __func__, handler->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/**
* input_register_handler - register a new input handler
* @handler: handler to be registered
@@ -2530,20 +2454,21 @@ int input_register_handler(struct input_handler *handler)
struct input_dev *dev;
int error;
- error = mutex_lock_interruptible(&input_mutex);
+ error = input_handler_check_methods(handler);
if (error)
return error;
- INIT_LIST_HEAD(&handler->h_list);
+ scoped_cond_guard(mutex_intr, return -EINTR, &input_mutex) {
+ INIT_LIST_HEAD(&handler->h_list);
- list_add_tail(&handler->node, &input_handler_list);
+ list_add_tail(&handler->node, &input_handler_list);
- list_for_each_entry(dev, &input_dev_list, node)
- input_attach_handler(dev, handler);
+ list_for_each_entry(dev, &input_dev_list, node)
+ input_attach_handler(dev, handler);
- input_wakeup_procfs_readers();
+ input_wakeup_procfs_readers();
+ }
- mutex_unlock(&input_mutex);
return 0;
}
EXPORT_SYMBOL(input_register_handler);
@@ -2559,7 +2484,7 @@ void input_unregister_handler(struct input_handler *handler)
{
struct input_handle *handle, *next;
- mutex_lock(&input_mutex);
+ guard(mutex)(&input_mutex);
list_for_each_entry_safe(handle, next, &handler->h_list, h_node)
handler->disconnect(handle);
@@ -2568,8 +2493,6 @@ void input_unregister_handler(struct input_handler *handler)
list_del_init(&handler->node);
input_wakeup_procfs_readers();
-
- mutex_unlock(&input_mutex);
}
EXPORT_SYMBOL(input_unregister_handler);
@@ -2589,22 +2512,89 @@ int input_handler_for_each_handle(struct input_handler *handler, void *data,
int (*fn)(struct input_handle *, void *))
{
struct input_handle *handle;
- int retval = 0;
+ int retval;
- rcu_read_lock();
+ guard(rcu)();
list_for_each_entry_rcu(handle, &handler->h_list, h_node) {
retval = fn(handle, data);
if (retval)
- break;
+ return retval;
}
- rcu_read_unlock();
-
- return retval;
+ return 0;
}
EXPORT_SYMBOL(input_handler_for_each_handle);
+/*
+ * An implementation of input_handle's handle_events() method that simply
+ * invokes handler->event() method for each event one by one.
+ */
+static unsigned int input_handle_events_default(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *v;
+
+ for (v = vals; v != vals + count; v++)
+ handler->event(handle, v->type, v->code, v->value);
+
+ return count;
+}
+
+/*
+ * An implementation of input_handle's handle_events() method that invokes
+ * handler->filter() method for each event one by one and removes events
+ * that were filtered out from the "vals" array.
+ */
+static unsigned int input_handle_events_filter(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ struct input_handler *handler = handle->handler;
+ struct input_value *end = vals;
+ struct input_value *v;
+
+ for (v = vals; v != vals + count; v++) {
+ if (handler->filter(handle, v->type, v->code, v->value))
+ continue;
+ if (end != v)
+ *end = *v;
+ end++;
+ }
+
+ return end - vals;
+}
+
+/*
+ * An implementation of input_handle's handle_events() method that does nothing.
+ */
+static unsigned int input_handle_events_null(struct input_handle *handle,
+ struct input_value *vals,
+ unsigned int count)
+{
+ return count;
+}
+
+/*
+ * Sets up appropriate handle->event_handler based on the input_handler
+ * associated with the handle.
+ */
+static void input_handle_setup_event_handler(struct input_handle *handle)
+{
+ struct input_handler *handler = handle->handler;
+
+ if (handler->filter)
+ handle->handle_events = input_handle_events_filter;
+ else if (handler->event)
+ handle->handle_events = input_handle_events_default;
+ else if (handler->events)
+ handle->handle_events = handler->events;
+ else
+ handle->handle_events = input_handle_events_null;
+}
+
/**
* input_register_handle - register a new input handle
* @handle: handle to register
@@ -2620,26 +2610,22 @@ int input_register_handle(struct input_handle *handle)
{
struct input_handler *handler = handle->handler;
struct input_dev *dev = handle->dev;
- int error;
+ input_handle_setup_event_handler(handle);
/*
* We take dev->mutex here to prevent race with
* input_release_device().
*/
- error = mutex_lock_interruptible(&dev->mutex);
- if (error)
- return error;
-
- /*
- * Filters go to the head of the list, normal handlers
- * to the tail.
- */
- if (handler->filter)
- list_add_rcu(&handle->d_node, &dev->h_list);
- else
- list_add_tail_rcu(&handle->d_node, &dev->h_list);
-
- mutex_unlock(&dev->mutex);
+ scoped_cond_guard(mutex_intr, return -EINTR, &dev->mutex) {
+ /*
+ * Filters go to the head of the list, normal handlers
+ * to the tail.
+ */
+ if (handler->filter)
+ list_add_rcu(&handle->d_node, &dev->h_list);
+ else
+ list_add_tail_rcu(&handle->d_node, &dev->h_list);
+ }
/*
* Since we are supposed to be called from ->connect()
@@ -2675,9 +2661,8 @@ void input_unregister_handle(struct input_handle *handle)
/*
* Take dev->mutex to prevent race with input_release_device().
*/
- mutex_lock(&dev->mutex);
- list_del_rcu(&handle->d_node);
- mutex_unlock(&dev->mutex);
+ scoped_guard(mutex, &dev->mutex)
+ list_del_rcu(&handle->d_node);
synchronize_rcu();
}
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 5824bca02e5a..ba2b17288bcd 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -718,7 +718,6 @@ static const struct file_operations joydev_fops = {
.compat_ioctl = joydev_compat_ioctl,
#endif
.fasync = joydev_fasync,
- .llseek = no_llseek,
};
/*
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index fd1827baf27c..15182f16ed19 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -249,7 +249,7 @@ static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv)
int i;
int err;
- a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL);
+ a3d = kzalloc(sizeof(*a3d), GFP_KERNEL);
input_dev = input_allocate_device();
if (!a3d || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/joystick/adafruit-seesaw.c b/drivers/input/joystick/adafruit-seesaw.c
index 5c775ca886a5..c248c15b849d 100644
--- a/drivers/input/joystick/adafruit-seesaw.c
+++ b/drivers/input/joystick/adafruit-seesaw.c
@@ -15,7 +15,7 @@
* - Add interrupt support
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/i2c.h>
diff --git a/drivers/input/joystick/adc-joystick.c b/drivers/input/joystick/adc-joystick.c
index c0deff5d4282..ff44f9978b71 100644
--- a/drivers/input/joystick/adc-joystick.c
+++ b/drivers/input/joystick/adc-joystick.c
@@ -11,24 +11,30 @@
#include <linux/platform_device.h>
#include <linux/property.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
struct adc_joystick_axis {
u32 code;
- s32 range[2];
- s32 fuzz;
- s32 flat;
+ bool inverted;
};
struct adc_joystick {
struct input_dev *input;
struct iio_cb_buffer *buffer;
- struct adc_joystick_axis *axes;
struct iio_channel *chans;
- int num_chans;
- bool polled;
+ unsigned int num_chans;
+ struct adc_joystick_axis axes[] __counted_by(num_chans);
};
+static int adc_joystick_invert(struct input_dev *dev,
+ unsigned int axis, int val)
+{
+ int min = input_abs_get_min(dev, axis);
+ int max = input_abs_get_max(dev, axis);
+
+ return (max + min) - val;
+}
+
static void adc_joystick_poll(struct input_dev *input)
{
struct adc_joystick *joy = input_get_drvdata(input);
@@ -38,6 +44,8 @@ static void adc_joystick_poll(struct input_dev *input)
ret = iio_read_channel_raw(&joy->chans[i], &val);
if (ret < 0)
return;
+ if (joy->axes[i].inverted)
+ val = adc_joystick_invert(input, i, val);
input_report_abs(input, joy->axes[i].code, val);
}
input_sync(input);
@@ -86,6 +94,8 @@ static int adc_joystick_handle(const void *data, void *private)
val = sign_extend32(val, msb);
else
val &= GENMASK(msb, 0);
+ if (joy->axes[i].inverted)
+ val = adc_joystick_invert(joy->input, i, val);
input_report_abs(joy->input, joy->axes[i].code, val);
}
@@ -121,9 +131,10 @@ static void adc_joystick_cleanup(void *data)
static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
{
- struct adc_joystick_axis *axes;
- struct fwnode_handle *child;
- int num_axes, error, i;
+ struct adc_joystick_axis *axes = joy->axes;
+ s32 range[2], fuzz, flat;
+ unsigned int num_axes;
+ int error, i;
num_axes = device_get_child_node_count(dev);
if (!num_axes) {
@@ -137,72 +148,95 @@ static int adc_joystick_set_axes(struct device *dev, struct adc_joystick *joy)
return -EINVAL;
}
- axes = devm_kmalloc_array(dev, num_axes, sizeof(*axes), GFP_KERNEL);
- if (!axes)
- return -ENOMEM;
-
- device_for_each_child_node(dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
error = fwnode_property_read_u32(child, "reg", &i);
if (error) {
dev_err(dev, "reg invalid or missing\n");
- goto err_fwnode_put;
+ return error;
}
if (i >= num_axes) {
- error = -EINVAL;
dev_err(dev, "No matching axis for reg %d\n", i);
- goto err_fwnode_put;
+ return -EINVAL;
}
error = fwnode_property_read_u32(child, "linux,code",
&axes[i].code);
if (error) {
dev_err(dev, "linux,code invalid or missing\n");
- goto err_fwnode_put;
+ return error;
}
error = fwnode_property_read_u32_array(child, "abs-range",
- axes[i].range, 2);
+ range, 2);
if (error) {
dev_err(dev, "abs-range invalid or missing\n");
- goto err_fwnode_put;
+ return error;
+ }
+
+ if (range[0] > range[1]) {
+ dev_dbg(dev, "abs-axis %d inverted\n", i);
+ axes[i].inverted = true;
+ swap(range[0], range[1]);
}
- fwnode_property_read_u32(child, "abs-fuzz", &axes[i].fuzz);
- fwnode_property_read_u32(child, "abs-flat", &axes[i].flat);
+ if (fwnode_property_read_u32(child, "abs-fuzz", &fuzz))
+ fuzz = 0;
+
+ if (fwnode_property_read_u32(child, "abs-flat", &flat))
+ flat = 0;
input_set_abs_params(joy->input, axes[i].code,
- axes[i].range[0], axes[i].range[1],
- axes[i].fuzz, axes[i].flat);
- input_set_capability(joy->input, EV_ABS, axes[i].code);
+ range[0], range[1], fuzz, flat);
}
- joy->axes = axes;
-
return 0;
+}
+
+
+static int adc_joystick_count_channels(struct device *dev,
+ const struct iio_channel *chans,
+ bool polled,
+ unsigned int *num_chans)
+{
+ int bits;
+ int i;
+
+ /*
+ * Count how many channels we got. NULL terminated.
+ * Do not check the storage size if using polling.
+ */
+ for (i = 0; chans[i].indio_dev; i++) {
+ if (polled)
+ continue;
+ bits = chans[i].channel->scan_type.storagebits;
+ if (!bits || bits > 16) {
+ dev_err(dev, "Unsupported channel storage size\n");
+ return -EINVAL;
+ }
+ if (bits != chans[0].channel->scan_type.storagebits) {
+ dev_err(dev, "Channels must have equal storage size\n");
+ return -EINVAL;
+ }
+ }
-err_fwnode_put:
- fwnode_handle_put(child);
- return error;
+ *num_chans = i;
+ return 0;
}
static int adc_joystick_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
+ struct iio_channel *chans;
struct adc_joystick *joy;
struct input_dev *input;
+ unsigned int poll_interval = 0;
+ unsigned int num_chans;
int error;
- int bits;
- int i;
- unsigned int poll_interval;
-
- joy = devm_kzalloc(dev, sizeof(*joy), GFP_KERNEL);
- if (!joy)
- return -ENOMEM;
- joy->chans = devm_iio_channel_get_all(dev);
- if (IS_ERR(joy->chans)) {
- error = PTR_ERR(joy->chans);
+ chans = devm_iio_channel_get_all(dev);
+ error = PTR_ERR_OR_ZERO(chans);
+ if (error) {
if (error != -EPROBE_DEFER)
dev_err(dev, "Unable to get IIO channels");
return error;
@@ -216,28 +250,19 @@ static int adc_joystick_probe(struct platform_device *pdev)
} else if (poll_interval == 0) {
dev_err(dev, "Unable to get poll-interval\n");
return -EINVAL;
- } else {
- joy->polled = true;
}
- /*
- * Count how many channels we got. NULL terminated.
- * Do not check the storage size if using polling.
- */
- for (i = 0; joy->chans[i].indio_dev; i++) {
- if (joy->polled)
- continue;
- bits = joy->chans[i].channel->scan_type.storagebits;
- if (!bits || bits > 16) {
- dev_err(dev, "Unsupported channel storage size\n");
- return -EINVAL;
- }
- if (bits != joy->chans[0].channel->scan_type.storagebits) {
- dev_err(dev, "Channels must have equal storage size\n");
- return -EINVAL;
- }
- }
- joy->num_chans = i;
+ error = adc_joystick_count_channels(dev, chans, poll_interval != 0,
+ &num_chans);
+ if (error)
+ return error;
+
+ joy = devm_kzalloc(dev, struct_size(joy, axes, num_chans), GFP_KERNEL);
+ if (!joy)
+ return -ENOMEM;
+
+ joy->chans = chans;
+ joy->num_chans = num_chans;
input = devm_input_allocate_device(dev);
if (!input) {
@@ -253,7 +278,7 @@ static int adc_joystick_probe(struct platform_device *pdev)
if (error)
return error;
- if (joy->polled) {
+ if (poll_interval != 0) {
input_setup_polling(input, adc_joystick_poll);
input_set_poll_interval(input, poll_interval);
} else {
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index f1a720be458b..963250de24b7 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -456,7 +456,7 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
int i;
int err;
- port = kzalloc(sizeof(struct adi_port), GFP_KERNEL);
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 0c9e172a9818..c709b58d770a 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -582,7 +582,8 @@ static int analog_connect(struct gameport *gameport, struct gameport_driver *drv
int i;
int err;
- if (!(port = kzalloc(sizeof(struct analog_port), GFP_KERNEL)))
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
+ if (!port)
return -ENOMEM;
err = analog_init_port(gameport, drv, port);
diff --git a/drivers/input/joystick/as5011.c b/drivers/input/joystick/as5011.c
index 407062bcc84b..49a0dfbbeb49 100644
--- a/drivers/input/joystick/as5011.c
+++ b/drivers/input/joystick/as5011.c
@@ -237,7 +237,7 @@ static int as5011_probe(struct i2c_client *client)
return -ENODEV;
}
- as5011 = kmalloc(sizeof(struct as5011_device), GFP_KERNEL);
+ as5011 = kmalloc(sizeof(*as5011), GFP_KERNEL);
input_dev = input_allocate_device();
if (!as5011 || !input_dev) {
dev_err(&client->dev,
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
index 7ff78c9388bd..5a0ea3ad5efa 100644
--- a/drivers/input/joystick/cobra.c
+++ b/drivers/input/joystick/cobra.c
@@ -141,7 +141,7 @@ static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv)
int i, j;
int err;
- cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL);
+ cobra = kzalloc(sizeof(*cobra), GFP_KERNEL);
if (!cobra)
return -ENOMEM;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index 4fba28b1a1e7..d5c67a927404 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -351,7 +351,7 @@ static int db9_saturn(int mode, struct parport *port, struct input_dev *devs[])
static void db9_timer(struct timer_list *t)
{
- struct db9 *db9 = from_timer(db9, t, timer);
+ struct db9 *db9 = timer_container_of(db9, t, timer);
struct parport *port = db9->pd->port;
struct input_dev *dev = db9->dev[0];
struct input_dev *dev2 = db9->dev[1];
@@ -505,24 +505,22 @@ static int db9_open(struct input_dev *dev)
{
struct db9 *db9 = input_get_drvdata(dev);
struct parport *port = db9->pd->port;
- int err;
- err = mutex_lock_interruptible(&db9->mutex);
- if (err)
- return err;
-
- if (!db9->used++) {
- parport_claim(db9->pd);
- parport_write_data(port, 0xff);
- if (db9_modes[db9->mode].reverse) {
- parport_data_reverse(port);
- parport_write_control(port, DB9_NORMAL);
+ scoped_guard(mutex_intr, &db9->mutex) {
+ if (!db9->used++) {
+ parport_claim(db9->pd);
+ parport_write_data(port, 0xff);
+ if (db9_modes[db9->mode].reverse) {
+ parport_data_reverse(port);
+ parport_write_control(port, DB9_NORMAL);
+ }
+ mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
- mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+
+ return 0;
}
- mutex_unlock(&db9->mutex);
- return 0;
+ return -EINTR;
}
static void db9_close(struct input_dev *dev)
@@ -530,14 +528,14 @@ static void db9_close(struct input_dev *dev)
struct db9 *db9 = input_get_drvdata(dev);
struct parport *port = db9->pd->port;
- mutex_lock(&db9->mutex);
+ guard(mutex)(&db9->mutex);
+
if (!--db9->used) {
- del_timer_sync(&db9->timer);
+ timer_delete_sync(&db9->timer);
parport_write_control(port, 0x00);
parport_data_forward(port);
parport_release(db9->pd);
}
- mutex_unlock(&db9->mutex);
}
static void db9_attach(struct parport *pp)
@@ -587,7 +585,7 @@ static void db9_attach(struct parport *pp)
return;
}
- db9 = kzalloc(sizeof(struct db9), GFP_KERNEL);
+ db9 = kzalloc(sizeof(*db9), GFP_KERNEL);
if (!db9)
goto err_unreg_pardev;
@@ -673,7 +671,6 @@ static struct parport_driver db9_parport_driver = {
.name = "db9",
.match_port = db9_attach,
.detach = db9_detach,
- .devmodel = true,
};
static int __init db9_init(void)
diff --git a/drivers/input/joystick/fsia6b.c b/drivers/input/joystick/fsia6b.c
index 76ffdec5c183..7e3bc99d766f 100644
--- a/drivers/input/joystick/fsia6b.c
+++ b/drivers/input/joystick/fsia6b.c
@@ -149,7 +149,7 @@ static int fsia6b_serio_connect(struct serio *serio, struct serio_driver *drv)
}
fsia6b->dev = input_dev;
- snprintf(fsia6b->phys, sizeof(fsia6b->phys), "%s/input0", serio->phys);
+ scnprintf(fsia6b->phys, sizeof(fsia6b->phys), "%s/input0", serio->phys);
input_dev->name = DRIVER_DESC;
input_dev->phys = fsia6b->phys;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 41d5dac05448..ae95cb3d0ae9 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -726,7 +726,7 @@ static void gc_psx_process_packet(struct gc *gc)
static void gc_timer(struct timer_list *t)
{
- struct gc *gc = from_timer(gc, t, timer);
+ struct gc *gc = timer_container_of(gc, t, timer);
/*
* N64 pads - must be read first, any read confuses them for 200 us
@@ -765,33 +765,31 @@ static void gc_timer(struct timer_list *t)
static int gc_open(struct input_dev *dev)
{
struct gc *gc = input_get_drvdata(dev);
- int err;
- err = mutex_lock_interruptible(&gc->mutex);
- if (err)
- return err;
+ scoped_guard(mutex_intr, &gc->mutex) {
+ if (!gc->used++) {
+ parport_claim(gc->pd);
+ parport_write_control(gc->pd->port, 0x04);
+ mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+ }
- if (!gc->used++) {
- parport_claim(gc->pd);
- parport_write_control(gc->pd->port, 0x04);
- mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+ return 0;
}
- mutex_unlock(&gc->mutex);
- return 0;
+ return -EINTR;
}
static void gc_close(struct input_dev *dev)
{
struct gc *gc = input_get_drvdata(dev);
- mutex_lock(&gc->mutex);
+ guard(mutex)(&gc->mutex);
+
if (!--gc->used) {
- del_timer_sync(&gc->timer);
+ timer_delete_sync(&gc->timer);
parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd);
}
- mutex_unlock(&gc->mutex);
}
static int gc_setup_pad(struct gc *gc, int idx, int pad_type)
@@ -950,7 +948,7 @@ static void gc_attach(struct parport *pp)
return;
}
- gc = kzalloc(sizeof(struct gc), GFP_KERNEL);
+ gc = kzalloc(sizeof(*gc), GFP_KERNEL);
if (!gc) {
pr_err("Not enough memory\n");
goto err_unreg_pardev;
@@ -1016,7 +1014,6 @@ static struct parport_driver gc_parport_driver = {
.name = "gamecon",
.match_port = gc_attach,
.detach = gc_detach,
- .devmodel = true,
};
static int __init gc_init(void)
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index abefbd1484df..e7ff7bdb1a3a 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -222,7 +222,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
unsigned char data[GF2K_LENGTH];
int i, err;
- gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL);
+ gf2k = kzalloc(sizeof(*gf2k), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gf2k || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
index 0e86b269a90e..f339ce2b7a33 100644
--- a/drivers/input/joystick/grip.c
+++ b/drivers/input/joystick/grip.c
@@ -284,7 +284,8 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
int i, j, t;
int err;
- if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL)))
+ grip = kzalloc(sizeof(*grip), GFP_KERNEL);
+ if (!grip)
return -ENOMEM;
grip->gameport = gameport;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 056a89ac2bdf..5eadb5a3ca37 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -632,7 +632,8 @@ static int grip_connect(struct gameport *gameport, struct gameport_driver *drv)
struct grip_mp *grip;
int err;
- if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL)))
+ grip = kzalloc(sizeof(*grip), GFP_KERNEL);
+ if (!grip)
return -ENOMEM;
grip->gameport = gameport;
diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c
index 205eb6f8b84d..1c5a76f72239 100644
--- a/drivers/input/joystick/guillemot.c
+++ b/drivers/input/joystick/guillemot.c
@@ -163,7 +163,7 @@ static int guillemot_connect(struct gameport *gameport, struct gameport_driver *
int i, t;
int err;
- guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL);
+ guillemot = kzalloc(sizeof(*guillemot), GFP_KERNEL);
input_dev = input_allocate_device();
if (!guillemot || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 95c0348843e6..8c78cbe553c8 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -21,14 +21,13 @@ static int make_magnitude_modifier(struct iforce* iforce,
unsigned char data[3];
if (!no_alloc) {
- mutex_lock(&iforce->mem_mutex);
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- mutex_unlock(&iforce->mem_mutex);
+ guard(mutex)(&iforce->mem_mutex);
+
+ if (allocate_resource(&iforce->device_memory, mod_chunk, 2,
+ iforce->device_memory.start,
+ iforce->device_memory.end,
+ 2L, NULL, NULL))
return -ENOSPC;
- }
- mutex_unlock(&iforce->mem_mutex);
}
data[0] = LO(mod_chunk->start);
@@ -54,14 +53,13 @@ static int make_period_modifier(struct iforce* iforce,
period = TIME_SCALE(period);
if (!no_alloc) {
- mutex_lock(&iforce->mem_mutex);
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- mutex_unlock(&iforce->mem_mutex);
+ guard(mutex)(&iforce->mem_mutex);
+
+ if (allocate_resource(&iforce->device_memory, mod_chunk, 0x0c,
+ iforce->device_memory.start,
+ iforce->device_memory.end,
+ 2L, NULL, NULL))
return -ENOSPC;
- }
- mutex_unlock(&iforce->mem_mutex);
}
data[0] = LO(mod_chunk->start);
@@ -94,14 +92,13 @@ static int make_envelope_modifier(struct iforce* iforce,
fade_duration = TIME_SCALE(fade_duration);
if (!no_alloc) {
- mutex_lock(&iforce->mem_mutex);
+ guard(mutex)(&iforce->mem_mutex);
+
if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- mutex_unlock(&iforce->mem_mutex);
+ iforce->device_memory.start,
+ iforce->device_memory.end,
+ 2L, NULL, NULL))
return -ENOSPC;
- }
- mutex_unlock(&iforce->mem_mutex);
}
data[0] = LO(mod_chunk->start);
@@ -131,14 +128,13 @@ static int make_condition_modifier(struct iforce* iforce,
unsigned char data[10];
if (!no_alloc) {
- mutex_lock(&iforce->mem_mutex);
+ guard(mutex)(&iforce->mem_mutex);
+
if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- mutex_unlock(&iforce->mem_mutex);
+ iforce->device_memory.start,
+ iforce->device_memory.end,
+ 2L, NULL, NULL))
return -ENOSPC;
- }
- mutex_unlock(&iforce->mem_mutex);
}
data[0] = LO(mod_chunk->start);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 84b87526b7ba..86d09faa685c 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -6,7 +6,8 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-#include <asm/unaligned.h>
+#include <linux/export.h>
+#include <linux/unaligned.h>
#include "iforce.h"
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <johann.deneux@gmail.com>");
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 763642c8cee9..fd1cd731d781 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -6,7 +6,8 @@
* USB/RS232 I-Force joysticks and wheels.
*/
-#include <asm/unaligned.h>
+#include <linux/export.h>
+#include <linux/unaligned.h>
#include "iforce.h"
static struct {
@@ -31,49 +32,42 @@ int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
int c;
int empty;
int head, tail;
- unsigned long flags;
/*
* Update head and tail of xmit buffer
*/
- spin_lock_irqsave(&iforce->xmit_lock, flags);
-
- head = iforce->xmit.head;
- tail = iforce->xmit.tail;
-
-
- if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) {
- dev_warn(&iforce->dev->dev,
- "not enough space in xmit buffer to send new packet\n");
- spin_unlock_irqrestore(&iforce->xmit_lock, flags);
- return -1;
- }
+ scoped_guard(spinlock_irqsave, &iforce->xmit_lock) {
+ head = iforce->xmit.head;
+ tail = iforce->xmit.tail;
+
+ if (CIRC_SPACE(head, tail, XMIT_SIZE) < n + 2) {
+ dev_warn(&iforce->dev->dev,
+ "not enough space in xmit buffer to send new packet\n");
+ return -1;
+ }
- empty = head == tail;
- XMIT_INC(iforce->xmit.head, n+2);
+ empty = head == tail;
+ XMIT_INC(iforce->xmit.head, n + 2);
/*
* Store packet in xmit buffer
*/
- iforce->xmit.buf[head] = HI(cmd);
- XMIT_INC(head, 1);
- iforce->xmit.buf[head] = LO(cmd);
- XMIT_INC(head, 1);
-
- c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE);
- if (n < c) c=n;
-
- memcpy(&iforce->xmit.buf[head],
- data,
- c);
- if (n != c) {
- memcpy(&iforce->xmit.buf[0],
- data + c,
- n - c);
+ iforce->xmit.buf[head] = HI(cmd);
+ XMIT_INC(head, 1);
+ iforce->xmit.buf[head] = LO(cmd);
+ XMIT_INC(head, 1);
+
+ c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE);
+ if (n < c)
+ c = n;
+
+ memcpy(&iforce->xmit.buf[head], data, c);
+ if (n != c)
+ memcpy(&iforce->xmit.buf[0], data + c, n - c);
+
+ XMIT_INC(head, n);
}
- XMIT_INC(head, n);
- spin_unlock_irqrestore(&iforce->xmit_lock, flags);
/*
* If necessary, start the transmission
*/
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
index 2380546d7978..75b85c46dfa4 100644
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -28,45 +28,39 @@ static void iforce_serio_xmit(struct iforce *iforce)
iforce);
unsigned char cs;
int i;
- unsigned long flags;
if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) {
set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags);
return;
}
- spin_lock_irqsave(&iforce->xmit_lock, flags);
+ guard(spinlock_irqsave)(&iforce->xmit_lock);
-again:
- if (iforce->xmit.head == iforce->xmit.tail) {
- iforce_clear_xmit_and_wake(iforce);
- spin_unlock_irqrestore(&iforce->xmit_lock, flags);
- return;
- }
+ do {
+ if (iforce->xmit.head == iforce->xmit.tail)
+ break;
- cs = 0x2b;
+ cs = 0x2b;
- serio_write(iforce_serio->serio, 0x2b);
+ serio_write(iforce_serio->serio, 0x2b);
- serio_write(iforce_serio->serio, iforce->xmit.buf[iforce->xmit.tail]);
- cs ^= iforce->xmit.buf[iforce->xmit.tail];
- XMIT_INC(iforce->xmit.tail, 1);
-
- for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
serio_write(iforce_serio->serio,
iforce->xmit.buf[iforce->xmit.tail]);
cs ^= iforce->xmit.buf[iforce->xmit.tail];
XMIT_INC(iforce->xmit.tail, 1);
- }
- serio_write(iforce_serio->serio, cs);
+ for (i = iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) {
+ serio_write(iforce_serio->serio,
+ iforce->xmit.buf[iforce->xmit.tail]);
+ cs ^= iforce->xmit.buf[iforce->xmit.tail];
+ XMIT_INC(iforce->xmit.tail, 1);
+ }
- if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags))
- goto again;
+ serio_write(iforce_serio->serio, cs);
- iforce_clear_xmit_and_wake(iforce);
+ } while (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags));
- spin_unlock_irqrestore(&iforce->xmit_lock, flags);
+ iforce_clear_xmit_and_wake(iforce);
}
static int iforce_serio_get_id(struct iforce *iforce, u8 id,
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index cba92bd590a8..1f00f76b0174 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -25,13 +25,11 @@ static void __iforce_usb_xmit(struct iforce *iforce)
struct iforce_usb *iforce_usb = container_of(iforce, struct iforce_usb,
iforce);
int n, c;
- unsigned long flags;
- spin_lock_irqsave(&iforce->xmit_lock, flags);
+ guard(spinlock_irqsave)(&iforce->xmit_lock);
if (iforce->xmit.head == iforce->xmit.tail) {
iforce_clear_xmit_and_wake(iforce);
- spin_unlock_irqrestore(&iforce->xmit_lock, flags);
return;
}
@@ -45,7 +43,8 @@ static void __iforce_usb_xmit(struct iforce *iforce)
/* Copy rest of data then */
c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
- if (n < c) c=n;
+ if (n < c)
+ c = n;
memcpy(iforce_usb->out->transfer_buffer + 1,
&iforce->xmit.buf[iforce->xmit.tail],
@@ -53,11 +52,12 @@ static void __iforce_usb_xmit(struct iforce *iforce)
if (n != c) {
memcpy(iforce_usb->out->transfer_buffer + 1 + c,
&iforce->xmit.buf[0],
- n-c);
+ n - c);
}
XMIT_INC(iforce->xmit.tail, n);
- if ( (n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC)) ) {
+ n=usb_submit_urb(iforce_usb->out, GFP_ATOMIC);
+ if (n) {
dev_warn(&iforce_usb->intf->dev,
"usb_submit_urb failed %d\n", n);
iforce_clear_xmit_and_wake(iforce);
@@ -66,7 +66,6 @@ static void __iforce_usb_xmit(struct iforce *iforce)
/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
* As long as the urb completion handler is not called, the transmiting
* is considered to be running */
- spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
static void iforce_usb_xmit(struct iforce *iforce)
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
index 03a9f0829f7e..262f022e5695 100644
--- a/drivers/input/joystick/interact.c
+++ b/drivers/input/joystick/interact.c
@@ -192,7 +192,7 @@ static int interact_connect(struct gameport *gameport, struct gameport_driver *d
int i, t;
int err;
- interact = kzalloc(sizeof(struct interact), GFP_KERNEL);
+ interact = kzalloc(sizeof(*interact), GFP_KERNEL);
input_dev = input_allocate_device();
if (!interact || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 017ef8c6170b..7622638e5bb8 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -48,7 +48,7 @@ struct magellan {
static int magellan_crunch_nibbles(unsigned char *data, int count)
{
- static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
+ static const unsigned char nibbles[16] __nonstring = "0AB3D56GH9:K<MN?";
do {
if (data[count] == nibbles[data[count] & 0xf])
@@ -132,7 +132,7 @@ static int magellan_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- magellan = kzalloc(sizeof(struct magellan), GFP_KERNEL);
+ magellan = kzalloc(sizeof(*magellan), GFP_KERNEL);
input_dev = input_allocate_device();
if (!magellan || !input_dev)
goto fail1;
diff --git a/drivers/input/joystick/maplecontrol.c b/drivers/input/joystick/maplecontrol.c
index 3833ac47b2b8..8b54f9b18e7c 100644
--- a/drivers/input/joystick/maplecontrol.c
+++ b/drivers/input/joystick/maplecontrol.c
@@ -102,7 +102,7 @@ static int probe_maple_controller(struct device *dev)
struct input_dev *idev;
unsigned long data = be32_to_cpu(mdev->devinfo.function_data[0]);
- pad = kzalloc(sizeof(struct dc_pad), GFP_KERNEL);
+ pad = kzalloc(sizeof(*pad), GFP_KERNEL);
idev = input_allocate_device();
if (!pad || !idev) {
error = -ENOMEM;
diff --git a/drivers/input/joystick/n64joy.c b/drivers/input/joystick/n64joy.c
index 9dbca366613e..94d2f4e96fe6 100644
--- a/drivers/input/joystick/n64joy.c
+++ b/drivers/input/joystick/n64joy.c
@@ -191,35 +191,32 @@ static void n64joy_poll(struct timer_list *t)
static int n64joy_open(struct input_dev *dev)
{
struct n64joy_priv *priv = input_get_drvdata(dev);
- int err;
-
- err = mutex_lock_interruptible(&priv->n64joy_mutex);
- if (err)
- return err;
-
- if (!priv->n64joy_opened) {
- /*
- * We could use the vblank irq, but it's not important if
- * the poll point slightly changes.
- */
- timer_setup(&priv->timer, n64joy_poll, 0);
- mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
- }
- priv->n64joy_opened++;
+ scoped_guard(mutex_intr, &priv->n64joy_mutex) {
+ if (!priv->n64joy_opened) {
+ /*
+ * We could use the vblank irq, but it's not important
+ * if the poll point slightly changes.
+ */
+ timer_setup(&priv->timer, n64joy_poll, 0);
+ mod_timer(&priv->timer, jiffies + msecs_to_jiffies(16));
+ }
- mutex_unlock(&priv->n64joy_mutex);
- return err;
+ priv->n64joy_opened++;
+ return 0;
+ }
+
+ return -EINTR;
}
static void n64joy_close(struct input_dev *dev)
{
struct n64joy_priv *priv = input_get_drvdata(dev);
- mutex_lock(&priv->n64joy_mutex);
+ guard(mutex)(&priv->n64joy_mutex);
+
if (!--priv->n64joy_opened)
- del_timer_sync(&priv->timer);
- mutex_unlock(&priv->n64joy_mutex);
+ timer_delete_sync(&priv->timer);
}
static const u64 __initconst scandata[] ____cacheline_aligned = {
@@ -246,7 +243,7 @@ static int __init n64joy_probe(struct platform_device *pdev)
int err = 0;
u32 i, j, found = 0;
- priv = kzalloc(sizeof(struct n64joy_priv), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
mutex_init(&priv->n64joy_mutex);
diff --git a/drivers/input/joystick/psxpad-spi.c b/drivers/input/joystick/psxpad-spi.c
index c47fc5f34bd0..f902a56d011f 100644
--- a/drivers/input/joystick/psxpad-spi.c
+++ b/drivers/input/joystick/psxpad-spi.c
@@ -344,7 +344,11 @@ static int psxpad_spi_probe(struct spi_device *spi)
/* (PlayStation 1/2 joypad might be possible works 250kHz/500kHz) */
spi->controller->min_speed_hz = 125000;
spi->controller->max_speed_hz = 125000;
- spi_setup(spi);
+ err = spi_setup(spi);
+ if (err) {
+ dev_err(&spi->dev, "failed to set up SPI: %d\n", err);
+ return err;
+ }
/* pad settings */
psxpad_set_motor_level(pad, 0, 0);
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
index 7282301c3ae7..3a5873e5fcb3 100644
--- a/drivers/input/joystick/sidewinder.c
+++ b/drivers/input/joystick/sidewinder.c
@@ -14,6 +14,7 @@
#include <linux/input.h>
#include <linux/gameport.h>
#include <linux/jiffies.h>
+#include <linux/string_choices.h>
#define DRIVER_DESC "Microsoft SideWinder joystick family driver"
@@ -577,7 +578,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
comment[0] = 0;
- sw = kzalloc(sizeof(struct sw), GFP_KERNEL);
+ sw = kzalloc(sizeof(*sw), GFP_KERNEL);
buf = kmalloc(SW_LENGTH, GFP_KERNEL);
idbuf = kmalloc(SW_LENGTH, GFP_KERNEL);
if (!sw || !buf || !idbuf) {
@@ -677,7 +678,7 @@ static int sw_connect(struct gameport *gameport, struct gameport_driver *drv)
case 48: /* Ambiguous */
if (j == 14) { /* ID length 14*3 -> FFP */
sw->type = SW_ID_FFP;
- sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
+ sprintf(comment, " [AC %s]", str_off_on(sw_get_bits(idbuf,38,1,3)));
} else
sw->type = SW_ID_PP;
break;
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index fa8ec533cd69..4f2221001a95 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -16,7 +16,7 @@
#include <linux/module.h>
#include <linux/input.h>
#include <linux/serio.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define DRIVER_DESC "SpaceTec SpaceBall 2003/3003/4000 FLX driver"
@@ -199,7 +199,7 @@ static int spaceball_connect(struct serio *serio, struct serio_driver *drv)
if ((id = serio->id.id) > SPACEBALL_MAX_ID)
return -ENODEV;
- spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL);
+ spaceball = kmalloc(sizeof(*spaceball), GFP_KERNEL);
input_dev = input_allocate_device();
if (!spaceball || !input_dev)
goto fail1;
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index dbbc69f17c89..7250d74d62a1 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -147,7 +147,7 @@ static int spaceorb_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- spaceorb = kzalloc(sizeof(struct spaceorb), GFP_KERNEL);
+ spaceorb = kzalloc(sizeof(*spaceorb), GFP_KERNEL);
input_dev = input_allocate_device();
if (!spaceorb || !input_dev)
goto fail1;
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index 530de468cb61..1b24ea21aa30 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -118,7 +118,7 @@ static int stinger_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err = -ENOMEM;
- stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL);
+ stinger = kmalloc(sizeof(*stinger), GFP_KERNEL);
input_dev = input_allocate_device();
if (!stinger || !input_dev)
goto fail1;
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index 93562ecc0ca1..514b1026e379 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -348,7 +348,8 @@ static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv)
int i;
int err;
- if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL)))
+ tmdc = kzalloc(sizeof(*tmdc), GFP_KERNEL);
+ if (!tmdc)
return -ENOMEM;
tmdc->gameport = gameport;
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index dfb9c684651f..5f69aef01791 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -72,7 +72,7 @@ static struct tgfx {
static void tgfx_timer(struct timer_list *t)
{
- struct tgfx *tgfx = from_timer(tgfx, t, timer);
+ struct tgfx *tgfx = timer_container_of(tgfx, t, timer);
struct input_dev *dev;
int data1, data2, i;
@@ -103,33 +103,31 @@ static void tgfx_timer(struct timer_list *t)
static int tgfx_open(struct input_dev *dev)
{
struct tgfx *tgfx = input_get_drvdata(dev);
- int err;
- err = mutex_lock_interruptible(&tgfx->sem);
- if (err)
- return err;
+ scoped_guard(mutex_intr, &tgfx->sem) {
+ if (!tgfx->used++) {
+ parport_claim(tgfx->pd);
+ parport_write_control(tgfx->pd->port, 0x04);
+ mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+ }
- if (!tgfx->used++) {
- parport_claim(tgfx->pd);
- parport_write_control(tgfx->pd->port, 0x04);
- mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+ return 0;
}
- mutex_unlock(&tgfx->sem);
- return 0;
+ return -EINTR;
}
static void tgfx_close(struct input_dev *dev)
{
struct tgfx *tgfx = input_get_drvdata(dev);
- mutex_lock(&tgfx->sem);
+ guard(mutex)(&tgfx->sem);
+
if (!--tgfx->used) {
- del_timer_sync(&tgfx->timer);
+ timer_delete_sync(&tgfx->timer);
parport_write_control(tgfx->pd->port, 0x00);
parport_release(tgfx->pd);
}
- mutex_unlock(&tgfx->sem);
}
@@ -172,7 +170,7 @@ static void tgfx_attach(struct parport *pp)
return;
}
- tgfx = kzalloc(sizeof(struct tgfx), GFP_KERNEL);
+ tgfx = kzalloc(sizeof(*tgfx), GFP_KERNEL);
if (!tgfx) {
printk(KERN_ERR "turbografx.c: Not enough memory\n");
goto err_unreg_pardev;
@@ -274,7 +272,6 @@ static struct parport_driver tgfx_parport_driver = {
.name = "turbografx",
.match_port = tgfx_attach,
.detach = tgfx_detach,
- .devmodel = true,
};
static int __init tgfx_init(void)
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 9b6792ac27f1..ab99d76e5d8d 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -171,7 +171,7 @@ static int twidjoy_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- twidjoy = kzalloc(sizeof(struct twidjoy), GFP_KERNEL);
+ twidjoy = kzalloc(sizeof(*twidjoy), GFP_KERNEL);
input_dev = input_allocate_device();
if (!twidjoy || !input_dev)
goto fail1;
diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c
index 27d95d6cf56e..15370fb82317 100644
--- a/drivers/input/joystick/walkera0701.c
+++ b/drivers/input/joystick/walkera0701.c
@@ -232,8 +232,7 @@ static void walkera0701_attach(struct parport *pp)
goto err_unregister_device;
}
- hrtimer_init(&w->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- w->timer.function = timer_handler;
+ hrtimer_setup(&w->timer, timer_handler, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
w->input_dev = input_allocate_device();
if (!w->input_dev) {
@@ -293,7 +292,6 @@ static struct parport_driver walkera0701_parport_driver = {
.name = "walkera0701",
.match_port = walkera0701_attach,
.detach = walkera0701_detach,
- .devmodel = true,
};
module_parport_driver(walkera0701_parport_driver);
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index f66bddf145c2..ebeab441e9ec 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -124,7 +124,7 @@ static int warrior_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err = -ENOMEM;
- warrior = kzalloc(sizeof(struct warrior), GFP_KERNEL);
+ warrior = kzalloc(sizeof(*warrior), GFP_KERNEL);
input_dev = input_allocate_device();
if (!warrior || !input_dev)
goto fail1;
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index 2b8370ecf42a..d72e89c25e50 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -77,12 +77,13 @@
* xbox d-pads should map to buttons, as is required for DDR pads
* but we map them to axes when possible to simplify things
*/
-#define MAP_DPAD_TO_BUTTONS (1 << 0)
-#define MAP_TRIGGERS_TO_BUTTONS (1 << 1)
-#define MAP_STICKS_TO_NULL (1 << 2)
-#define MAP_SELECT_BUTTON (1 << 3)
-#define MAP_PADDLES (1 << 4)
-#define MAP_PROFILE_BUTTON (1 << 5)
+#define MAP_DPAD_TO_BUTTONS BIT(0)
+#define MAP_TRIGGERS_TO_BUTTONS BIT(1)
+#define MAP_STICKS_TO_NULL BIT(2)
+#define MAP_SHARE_BUTTON BIT(3)
+#define MAP_PADDLES BIT(4)
+#define MAP_PROFILE_BUTTON BIT(5)
+#define MAP_SHARE_OFFSET BIT(6)
#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \
MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
@@ -104,6 +105,8 @@
#define PKT_XBE2_FW_5_EARLY 3
#define PKT_XBE2_FW_5_11 4
+#define FLAG_DELAY_INIT BIT(0)
+
static bool dpad_to_buttons;
module_param(dpad_to_buttons, bool, S_IRUGO);
MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
@@ -126,6 +129,7 @@ static const struct xpad_device {
char *name;
u8 mapping;
u8 xtype;
+ u8 flags;
} xpad_device[] = {
/* Please keep this list sorted by vendor and product ID. */
{ 0x0079, 0x18d4, "GPD Win 2 X-Box Controller", 0, XTYPE_XBOX360 },
@@ -135,13 +139,14 @@ static const struct xpad_device {
{ 0x03f0, 0x048D, "HyperX Clutch", 0, XTYPE_XBOX360 }, /* wireless */
{ 0x03f0, 0x0495, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE },
{ 0x03f0, 0x07A0, "HyperX Clutch Gladiate RGB", 0, XTYPE_XBOXONE },
- { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", 0, XTYPE_XBOXONE }, /* v2 */
+ { 0x03f0, 0x08B6, "HyperX Clutch Gladiate", MAP_SHARE_BUTTON, XTYPE_XBOXONE }, /* v2 */
{ 0x03f0, 0x09B4, "HyperX Clutch Tanto", 0, XTYPE_XBOXONE },
{ 0x044f, 0x0f00, "Thrustmaster Wheel", 0, XTYPE_XBOX },
{ 0x044f, 0x0f03, "Thrustmaster Wheel", 0, XTYPE_XBOX },
{ 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX },
{ 0x044f, 0x0f10, "Thrustmaster Modena GT Wheel", 0, XTYPE_XBOX },
{ 0x044f, 0xb326, "Thrustmaster Gamepad GP XID", 0, XTYPE_XBOX360 },
+ { 0x044f, 0xd01e, "ThrustMaster, Inc. ESWAP X 2 ELDEN RING EDITION", 0, XTYPE_XBOXONE },
{ 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", 0, XTYPE_XBOX },
{ 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", 0, XTYPE_XBOX },
{ 0x045e, 0x0287, "Microsoft Xbox Controller S", 0, XTYPE_XBOX },
@@ -150,6 +155,7 @@ static const struct xpad_device {
{ 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 },
{ 0x045e, 0x028f, "Microsoft X-Box 360 pad v2", 0, XTYPE_XBOX360 },
{ 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
+ { 0x045e, 0x02a9, "Xbox 360 Wireless Receiver (Unofficial)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE },
{ 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", MAP_PADDLES, XTYPE_XBOXONE },
@@ -157,7 +163,7 @@ static const struct xpad_device {
{ 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W },
{ 0x045e, 0x0b00, "Microsoft X-Box One Elite 2 pad", MAP_PADDLES, XTYPE_XBOXONE },
{ 0x045e, 0x0b0a, "Microsoft X-Box Adaptive Controller", MAP_PROFILE_BUTTON, XTYPE_XBOXONE },
- { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SELECT_BUTTON, XTYPE_XBOXONE },
+ { 0x045e, 0x0b12, "Microsoft Xbox Series S|X Controller", MAP_SHARE_BUTTON | MAP_SHARE_OFFSET, XTYPE_XBOXONE },
{ 0x046d, 0xc21d, "Logitech Gamepad F310", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },
@@ -166,6 +172,7 @@ static const struct xpad_device {
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
{ 0x046d, 0xca8a, "Logitech Precision Vibration Feedback Wheel", 0, XTYPE_XBOX },
{ 0x046d, 0xcaa3, "Logitech DriveFx Racing Wheel", 0, XTYPE_XBOX360 },
+ { 0x0502, 0x1305, "Acer NGR200", 0, XTYPE_XBOX360 },
{ 0x056e, 0x2004, "Elecom JC-U3613M", 0, XTYPE_XBOX360 },
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
{ 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", 0, XTYPE_XBOX },
@@ -176,6 +183,7 @@ static const struct xpad_device {
{ 0x06a3, 0x0200, "Saitek Racing Wheel", 0, XTYPE_XBOX },
{ 0x06a3, 0x0201, "Saitek Adrenalin", 0, XTYPE_XBOX },
{ 0x06a3, 0xf51a, "Saitek P3600", 0, XTYPE_XBOX360 },
+ { 0x0738, 0x4503, "Mad Catz Racing Wheel", 0, XTYPE_XBOXONE },
{ 0x0738, 0x4506, "Mad Catz 4506 Wireless Controller", 0, XTYPE_XBOX },
{ 0x0738, 0x4516, "Mad Catz Control Pad", 0, XTYPE_XBOX },
{ 0x0738, 0x4520, "Mad Catz Control Pad Pro", 0, XTYPE_XBOX },
@@ -202,13 +210,13 @@ static const struct xpad_device {
{ 0x0738, 0x9871, "Mad Catz Portable Drum", 0, XTYPE_XBOX360 },
{ 0x0738, 0xb726, "Mad Catz Xbox controller - MW2", 0, XTYPE_XBOX360 },
{ 0x0738, 0xb738, "Mad Catz MVC2TE Stick 2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
- { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", XTYPE_XBOX360 },
+ { 0x0738, 0xbeef, "Mad Catz JOYTECH NEO SE Advanced GamePad", 0, XTYPE_XBOX360 },
{ 0x0738, 0xcb02, "Saitek Cyborg Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0738, 0xcb03, "Saitek P3200 Rumble Pad - PC/Xbox 360", 0, XTYPE_XBOX360 },
{ 0x0738, 0xcb29, "Saitek Aviator Stick AV8R02", 0, XTYPE_XBOX360 },
{ 0x0738, 0xf738, "Super SFIV FightStick TE S", 0, XTYPE_XBOX360 },
{ 0x07ff, 0xffff, "Mad Catz GamePad", 0, XTYPE_XBOX360 },
- { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", 0, XTYPE_XBOXONE },
+ { 0x0b05, 0x1a38, "ASUS ROG RAIKIRI", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x0b05, 0x1abb, "ASUS ROG RAIKIRI PRO", 0, XTYPE_XBOXONE },
{ 0x0c12, 0x0005, "Intec wireless", 0, XTYPE_XBOX },
{ 0x0c12, 0x8801, "Nyko Xbox Controller", 0, XTYPE_XBOX },
@@ -218,6 +226,7 @@ static const struct xpad_device {
{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", 0, XTYPE_XBOX },
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", 0, XTYPE_XBOX },
{ 0x0d2f, 0x0002, "Andamiro Pump It Up pad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
+ { 0x0db0, 0x1901, "Micro Star International Xbox360 Controller for Windows", 0, XTYPE_XBOX360 },
{ 0x0e4c, 0x1097, "Radica Gamester Controller", 0, XTYPE_XBOX },
{ 0x0e4c, 0x1103, "Radica Gamester Reflex", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX },
{ 0x0e4c, 0x2390, "Radica Games Jtech Controller", 0, XTYPE_XBOX },
@@ -236,6 +245,7 @@ static const struct xpad_device {
{ 0x0e6f, 0x0146, "Rock Candy Wired Controller for Xbox One", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0147, "PDP Marvel Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x015c, "PDP Xbox One Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOXONE },
+ { 0x0e6f, 0x015d, "PDP Mirror's Edge Official Wired Controller for Xbox One", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0161, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0162, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
{ 0x0e6f, 0x0163, "PDP Xbox One Controller", 0, XTYPE_XBOXONE },
@@ -274,12 +284,18 @@ static const struct xpad_device {
{ 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 },
+ { 0x0f0d, 0x0151, "Hori Racing Wheel Overdrive for Xbox Series X", 0, XTYPE_XBOXONE },
+ { 0x0f0d, 0x0152, "Hori Racing Wheel Overdrive for Xbox Series X", 0, XTYPE_XBOXONE },
+ { 0x0f0d, 0x01b2, "HORI Taiko No Tatsujin Drum Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x0f30, 0x010b, "Philips Recoil", 0, XTYPE_XBOX },
{ 0x0f30, 0x0202, "Joytech Advanced Controller", 0, XTYPE_XBOX },
{ 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX },
{ 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX },
{ 0x1038, 0x1430, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
{ 0x1038, 0x1431, "SteelSeries Stratus Duo", 0, XTYPE_XBOX360 },
+ { 0x10f5, 0x7005, "Turtle Beach Recon Controller", 0, XTYPE_XBOXONE },
+ { 0x10f5, 0x7008, "Turtle Beach Recon Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+ { 0x10f5, 0x7073, "Turtle Beach Stealth Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x11c9, 0x55f0, "Nacon GC-100XF", 0, XTYPE_XBOX360 },
{ 0x11ff, 0x0511, "PXN V900", 0, XTYPE_XBOX360 },
{ 0x1209, 0x2882, "Ardwiino Controller", 0, XTYPE_XBOX360 },
@@ -304,6 +320,7 @@ static const struct xpad_device {
{ 0x1689, 0xfe00, "Razer Sabertooth", 0, XTYPE_XBOX360 },
{ 0x17ef, 0x6182, "Lenovo Legion Controller for Windows", 0, XTYPE_XBOX360 },
{ 0x1949, 0x041a, "Amazon Game Controller", 0, XTYPE_XBOX360 },
+ { 0x1a86, 0xe310, "Legion Go S", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 },
{ 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x1bad, 0x0130, "Ion Drum Rocker", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 },
@@ -340,9 +357,13 @@ static const struct xpad_device {
{ 0x1bad, 0xfa01, "MadCatz GamePad", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd00, "Razer Onza TE", 0, XTYPE_XBOX360 },
{ 0x1bad, 0xfd01, "Razer Onza", 0, XTYPE_XBOX360 },
+ { 0x1ee9, 0x1590, "ZOTAC Gaming Zone", 0, XTYPE_XBOX360 },
{ 0x20d6, 0x2001, "BDA Xbox Series X Wired Controller", 0, XTYPE_XBOXONE },
{ 0x20d6, 0x2009, "PowerA Enhanced Wired Controller for Xbox Series X|S", 0, XTYPE_XBOXONE },
+ { 0x20d6, 0x2064, "PowerA Wired Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x20d6, 0x281f, "PowerA Wired Controller For Xbox 360", 0, XTYPE_XBOX360 },
+ { 0x20d6, 0x400b, "PowerA FUSION Pro 4 Wired Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+ { 0x20d6, 0x890b, "PowerA MOGA XP-Ultra Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x2345, 0xe00b, "Machenike G5 Pro Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5000, "Razer Atrox Arcade Stick", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x5300, "PowerA MINI PROEX Controller", 0, XTYPE_XBOX360 },
@@ -363,6 +384,7 @@ static const struct xpad_device {
{ 0x24c6, 0x5510, "Hori Fighting Commander ONE (Xbox 360/PC Mode)", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 },
{ 0x24c6, 0x551a, "PowerA FUSION Pro Controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x561a, "PowerA FUSION Controller", 0, XTYPE_XBOXONE },
+ { 0x24c6, 0x581a, "ThrustMaster XB1 Classic Controller", 0, XTYPE_XBOXONE },
{ 0x24c6, 0x5b00, "ThrustMaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5b02, "Thrustmaster, Inc. GPX Controller", 0, XTYPE_XBOX360 },
{ 0x24c6, 0x5b03, "Thrustmaster Ferrari 458 Racing Wheel", 0, XTYPE_XBOX360 },
@@ -371,18 +393,37 @@ static const struct xpad_device {
{ 0x2563, 0x058d, "OneXPlayer Gamepad", 0, XTYPE_XBOX360 },
{ 0x294b, 0x3303, "Snakebyte GAMEPAD BASE X", 0, XTYPE_XBOXONE },
{ 0x294b, 0x3404, "Snakebyte GAMEPAD RGB X", 0, XTYPE_XBOXONE },
+ { 0x2993, 0x2001, "TECNO Pocket Go", 0, XTYPE_XBOX360 },
{ 0x2dc8, 0x2000, "8BitDo Pro 2 Wired Controller fox Xbox", 0, XTYPE_XBOXONE },
- { 0x2dc8, 0x3106, "8BitDo Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
+ { 0x2dc8, 0x200f, "8BitDo Ultimate 3-mode Controller for Xbox", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
+ { 0x2dc8, 0x3106, "8BitDo Ultimate Wireless / Pro 2 Wired Controller", 0, XTYPE_XBOX360 },
+ { 0x2dc8, 0x3109, "8BitDo Ultimate Wireless Bluetooth", 0, XTYPE_XBOX360 },
+ { 0x2dc8, 0x310a, "8BitDo Ultimate 2C Wireless Controller", 0, XTYPE_XBOX360 },
+ { 0x2dc8, 0x310b, "8BitDo Ultimate 2 Wireless Controller", 0, XTYPE_XBOX360 },
+ { 0x2dc8, 0x6001, "8BitDo SN30 Pro", 0, XTYPE_XBOX360 },
+ { 0x2e24, 0x0423, "Hyperkin DuchesS Xbox One pad", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x2e24, 0x0652, "Hyperkin Duke X-Box One pad", 0, XTYPE_XBOXONE },
+ { 0x2e24, 0x1688, "Hyperkin X91 X-Box One pad", 0, XTYPE_XBOXONE },
+ { 0x2e95, 0x0504, "SCUF Gaming Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE },
{ 0x31e3, 0x1100, "Wooting One", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1200, "Wooting Two", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1210, "Wooting Lekker", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1220, "Wooting Two HE", 0, XTYPE_XBOX360 },
+ { 0x31e3, 0x1230, "Wooting Two HE (ARM)", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1300, "Wooting 60HE (AVR)", 0, XTYPE_XBOX360 },
{ 0x31e3, 0x1310, "Wooting 60HE (ARM)", 0, XTYPE_XBOX360 },
+ { 0x3285, 0x0603, "Nacon Pro Compact controller for Xbox", 0, XTYPE_XBOXONE },
{ 0x3285, 0x0607, "Nacon GC-100", 0, XTYPE_XBOX360 },
+ { 0x3285, 0x0614, "Nacon Pro Compact", 0, XTYPE_XBOXONE },
+ { 0x3285, 0x0646, "Nacon Pro Compact", 0, XTYPE_XBOXONE },
+ { 0x3285, 0x0662, "Nacon Revolution5 Pro", 0, XTYPE_XBOX360 },
+ { 0x3285, 0x0663, "Nacon Evol-X", 0, XTYPE_XBOXONE },
{ 0x3537, 0x1004, "GameSir T4 Kaleid", 0, XTYPE_XBOX360 },
+ { 0x3537, 0x1010, "GameSir G7 SE", 0, XTYPE_XBOXONE },
+ { 0x366c, 0x0005, "ByoWave Proteus Controller", MAP_SHARE_BUTTON, XTYPE_XBOXONE, FLAG_DELAY_INIT },
{ 0x3767, 0x0101, "Fanatec Speedster 3 Forceshock Wheel", 0, XTYPE_XBOX },
+ { 0x37d7, 0x2501, "Flydigi Apex 5", 0, XTYPE_XBOX360 },
+ { 0x413d, 0x2104, "Black Shark Green Ghost Gamepad", 0, XTYPE_XBOX360 },
{ 0xffff, 0xffff, "Chinese-made Xbox Controller", 0, XTYPE_XBOX },
{ 0x0000, 0x0000, "Generic X-Box pad", 0, XTYPE_UNKNOWN }
};
@@ -402,8 +443,8 @@ static const signed short xpad_btn[] = {
/* used when dpad is mapped to buttons */
static const signed short xpad_btn_pad[] = {
- BTN_TRIGGER_HAPPY1, BTN_TRIGGER_HAPPY2, /* d-pad left, right */
- BTN_TRIGGER_HAPPY3, BTN_TRIGGER_HAPPY4, /* d-pad up, down */
+ BTN_DPAD_LEFT, BTN_DPAD_RIGHT, /* d-pad left, right */
+ BTN_DPAD_UP, BTN_DPAD_DOWN, /* d-pad up, down */
-1 /* terminating entry */
};
@@ -439,8 +480,8 @@ static const signed short xpad_abs_triggers[] = {
/* used when the controller has extra paddle buttons */
static const signed short xpad_btn_paddles[] = {
- BTN_TRIGGER_HAPPY5, BTN_TRIGGER_HAPPY6, /* paddle upper right, lower right */
- BTN_TRIGGER_HAPPY7, BTN_TRIGGER_HAPPY8, /* paddle upper left, lower left */
+ BTN_GRIPR, BTN_GRIPR2, /* paddle upper right, lower right */
+ BTN_GRIPL, BTN_GRIPL2, /* paddle upper left, lower left */
-1 /* terminating entry */
};
@@ -481,9 +522,11 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x03f0), /* HP HyperX Xbox 360 controllers */
XPAD_XBOXONE_VENDOR(0x03f0), /* HP HyperX Xbox One controllers */
XPAD_XBOX360_VENDOR(0x044f), /* Thrustmaster Xbox 360 controllers */
+ XPAD_XBOXONE_VENDOR(0x044f), /* Thrustmaster Xbox One 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(0x0502), /* Acer Inc. Xbox 360 style controllers */
XPAD_XBOX360_VENDOR(0x056e), /* Elecom JC-U3613M */
XPAD_XBOX360_VENDOR(0x06a3), /* Saitek P3600 */
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz Xbox 360 controllers */
@@ -492,6 +535,7 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x07ff), /* Mad Catz Gamepad */
XPAD_XBOXONE_VENDOR(0x0b05), /* ASUS controllers */
XPAD_XBOX360_VENDOR(0x0c12), /* Zeroplus X-Box 360 controllers */
+ XPAD_XBOX360_VENDOR(0x0db0), /* Micro Star International X-Box 360 controllers */
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f Xbox 360 controllers */
XPAD_XBOXONE_VENDOR(0x0e6f), /* 0x0e6f Xbox One controllers */
XPAD_XBOX360_VENDOR(0x0f0d), /* Hori controllers */
@@ -511,7 +555,9 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x1689), /* Razer Onza */
XPAD_XBOX360_VENDOR(0x17ef), /* Lenovo */
XPAD_XBOX360_VENDOR(0x1949), /* Amazon controllers */
+ XPAD_XBOX360_VENDOR(0x1a86), /* Nanjing Qinheng Microelectronics (WCH) */
XPAD_XBOX360_VENDOR(0x1bad), /* Harmonix Rock Band guitar and drums */
+ XPAD_XBOX360_VENDOR(0x1ee9), /* ZOTAC Technology Limited */
XPAD_XBOX360_VENDOR(0x20d6), /* PowerA controllers */
XPAD_XBOXONE_VENDOR(0x20d6), /* PowerA controllers */
XPAD_XBOX360_VENDOR(0x2345), /* Machenike Controllers */
@@ -519,16 +565,22 @@ static const struct usb_device_id xpad_table[] = {
XPAD_XBOXONE_VENDOR(0x24c6), /* PowerA controllers */
XPAD_XBOX360_VENDOR(0x2563), /* OneXPlayer Gamepad */
XPAD_XBOX360_VENDOR(0x260d), /* Dareu H101 */
- XPAD_XBOXONE_VENDOR(0x294b), /* Snakebyte */
+ XPAD_XBOXONE_VENDOR(0x294b), /* Snakebyte */
+ XPAD_XBOX360_VENDOR(0x2993), /* TECNO Mobile */
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 Xbox One pad */
- XPAD_XBOX360_VENDOR(0x2f24), /* GameSir controllers */
+ XPAD_XBOX360_VENDOR(0x2dc8), /* 8BitDo Controllers */
+ XPAD_XBOXONE_VENDOR(0x2dc8), /* 8BitDo Controllers */
+ XPAD_XBOXONE_VENDOR(0x2e24), /* Hyperkin Controllers */
+ XPAD_XBOX360_VENDOR(0x2f24), /* GameSir Controllers */
+ XPAD_XBOXONE_VENDOR(0x2e95), /* SCUF Gaming Controller */
XPAD_XBOX360_VENDOR(0x31e3), /* Wooting Keyboards */
XPAD_XBOX360_VENDOR(0x3285), /* Nacon GC-100 */
+ XPAD_XBOXONE_VENDOR(0x3285), /* Nacon Evol-X */
XPAD_XBOX360_VENDOR(0x3537), /* GameSir Controllers */
XPAD_XBOXONE_VENDOR(0x3537), /* GameSir Controllers */
+ XPAD_XBOXONE_VENDOR(0x366c), /* ByoWave controllers */
+ XPAD_XBOX360_VENDOR(0x37d7), /* Flydigi Controllers */
+ XPAD_XBOX360_VENDOR(0x413d), /* Black Shark Green Ghost Controller */
{ }
};
@@ -556,6 +608,7 @@ struct xboxone_init_packet {
* - https://github.com/medusalix/xone/blob/master/bus/protocol.c
*/
#define GIP_CMD_ACK 0x01
+#define GIP_CMD_ANNOUNCE 0x02
#define GIP_CMD_IDENTIFY 0x04
#define GIP_CMD_POWER 0x05
#define GIP_CMD_AUTHENTICATE 0x06
@@ -630,20 +683,19 @@ static const u8 xboxone_hori_ack_id[] = {
};
/*
- * This packet is required for most (all?) of the PDP pads to start
- * sending input reports. These pads include: (0x0e6f:0x02ab),
- * (0x0e6f:0x02a4), (0x0e6f:0x02a6).
+ * This packet is sent by default on Windows, and is required for some pads to
+ * start sending input reports, including most (all?) of the PDP. These pads
+ * include: (0x0e6f:0x02ab), (0x0e6f:0x02a4), (0x0e6f:0x02a6).
*/
-static const u8 xboxone_pdp_led_on[] = {
- GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14
-};
+static const u8 xboxone_led_on[] = { GIP_CMD_LED, GIP_OPT_INTERNAL, GIP_SEQ0,
+GIP_PL_LEN(3), 0x00, GIP_LED_ON, 0x14 };
/*
* This packet is required for most (all?) of the PDP pads to start
* sending input reports. These pads include: (0x0e6f:0x02ab),
* (0x0e6f:0x02a4), (0x0e6f:0x02a6).
*/
-static const u8 xboxone_pdp_auth[] = {
+static const u8 xboxone_auth_done[] = {
GIP_CMD_AUTHENTICATE, GIP_OPT_INTERNAL, GIP_SEQ0, GIP_PL_LEN(2), 0x01, 0x00
};
@@ -680,8 +732,8 @@ static const struct xboxone_init_packet xboxone_init_packets[] = {
XBOXONE_INIT_PKT(0x045e, 0x02ea, xboxone_s_init),
XBOXONE_INIT_PKT(0x045e, 0x0b00, xboxone_s_init),
XBOXONE_INIT_PKT(0x045e, 0x0b00, extra_input_packet_init),
- XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_led_on),
- XBOXONE_INIT_PKT(0x0e6f, 0x0000, xboxone_pdp_auth),
+ XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_led_on),
+ XBOXONE_INIT_PKT(0x0000, 0x0000, xboxone_auth_done),
XBOXONE_INIT_PKT(0x24c6, 0x541a, xboxone_rumblebegin_init),
XBOXONE_INIT_PKT(0x24c6, 0x542a, xboxone_rumblebegin_init),
XBOXONE_INIT_PKT(0x24c6, 0x543a, xboxone_rumblebegin_init),
@@ -741,10 +793,13 @@ struct usb_xpad {
const char *name; /* name of the device */
struct work_struct work; /* init/remove device from callback */
time64_t mode_btn_down_ts;
+ bool delay_init; /* init packets should be delayed */
+ bool delayed_init_done;
};
static int xpad_init_input(struct usb_xpad *xpad);
static void xpad_deinit_input(struct usb_xpad *xpad);
+static int xpad_start_input(struct usb_xpad *xpad);
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num);
static void xpad360w_poweroff_controller(struct usb_xpad *xpad);
@@ -787,10 +842,10 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (left, right, up, down) */
- input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2));
- input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3));
- input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1));
+ input_report_key(dev, BTN_DPAD_LEFT, data[2] & BIT(2));
+ input_report_key(dev, BTN_DPAD_RIGHT, data[2] & BIT(3));
+ input_report_key(dev, BTN_DPAD_UP, data[2] & BIT(0));
+ input_report_key(dev, BTN_DPAD_DOWN, data[2] & BIT(1));
} else {
input_report_abs(dev, ABS_HAT0X,
!!(data[2] & 0x08) - !!(data[2] & 0x04));
@@ -838,10 +893,10 @@ static void xpad360_process_packet(struct usb_xpad *xpad, struct input_dev *dev,
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (left, right, up, down) */
- input_report_key(dev, BTN_TRIGGER_HAPPY1, data[2] & BIT(2));
- input_report_key(dev, BTN_TRIGGER_HAPPY2, data[2] & BIT(3));
- input_report_key(dev, BTN_TRIGGER_HAPPY3, data[2] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY4, data[2] & BIT(1));
+ input_report_key(dev, BTN_DPAD_LEFT, data[2] & BIT(2));
+ input_report_key(dev, BTN_DPAD_RIGHT, data[2] & BIT(3));
+ input_report_key(dev, BTN_DPAD_UP, data[2] & BIT(0));
+ input_report_key(dev, BTN_DPAD_DOWN, data[2] & BIT(1));
}
/*
@@ -992,7 +1047,7 @@ static void xpad360w_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned cha
* The report format was gleaned from
* https://github.com/kylelemons/xbox/blob/master/xbox.go
*/
-static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
+static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, u32 len)
{
struct input_dev *dev = xpad->dev;
bool do_sync = false;
@@ -1022,19 +1077,34 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
data[18] = 0;
/* Elite Series 2 split packet paddle bits */
- input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1));
- input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2));
- input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3));
+ input_report_key(dev, BTN_GRIPR, data[18] & BIT(0));
+ input_report_key(dev, BTN_GRIPR2, data[18] & BIT(1));
+ input_report_key(dev, BTN_GRIPL, data[18] & BIT(2));
+ input_report_key(dev, BTN_GRIPL2, data[18] & BIT(3));
do_sync = true;
}
+ } else if (data[0] == GIP_CMD_ANNOUNCE) {
+ int error;
+
+ if (xpad->delay_init && !xpad->delayed_init_done) {
+ xpad->delayed_init_done = true;
+ error = xpad_start_input(xpad);
+ if (error)
+ dev_warn(&xpad->dev->dev,
+ "unable to start delayed input: %d\n",
+ error);
+ }
} else if (data[0] == GIP_CMD_INPUT) { /* The main valid packet type for inputs */
/* menu/view buttons */
input_report_key(dev, BTN_START, data[4] & BIT(2));
input_report_key(dev, BTN_SELECT, data[4] & BIT(3));
- if (xpad->mapping & MAP_SELECT_BUTTON)
- input_report_key(dev, KEY_RECORD, data[22] & BIT(0));
+ if (xpad->mapping & MAP_SHARE_BUTTON) {
+ if (xpad->mapping & MAP_SHARE_OFFSET)
+ input_report_key(dev, KEY_RECORD, data[len - 26] & BIT(0));
+ else
+ input_report_key(dev, KEY_RECORD, data[len - 18] & BIT(0));
+ }
/* buttons A,B,X,Y */
input_report_key(dev, BTN_A, data[4] & BIT(4));
@@ -1045,10 +1115,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
/* digital pad */
if (xpad->mapping & MAP_DPAD_TO_BUTTONS) {
/* dpad as buttons (left, right, up, down) */
- input_report_key(dev, BTN_TRIGGER_HAPPY1, data[5] & BIT(2));
- input_report_key(dev, BTN_TRIGGER_HAPPY2, data[5] & BIT(3));
- input_report_key(dev, BTN_TRIGGER_HAPPY3, data[5] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY4, data[5] & BIT(1));
+ input_report_key(dev, BTN_DPAD_LEFT, data[5] & BIT(2));
+ input_report_key(dev, BTN_DPAD_RIGHT, data[5] & BIT(3));
+ input_report_key(dev, BTN_DPAD_UP, data[5] & BIT(0));
+ input_report_key(dev, BTN_DPAD_DOWN, data[5] & BIT(1));
} else {
input_report_abs(dev, ABS_HAT0X,
!!(data[5] & 0x08) - !!(data[5] & 0x04));
@@ -1107,10 +1177,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
data[32] = 0;
/* OG Elite Series Controller paddle bits */
- input_report_key(dev, BTN_TRIGGER_HAPPY5, data[32] & BIT(1));
- input_report_key(dev, BTN_TRIGGER_HAPPY6, data[32] & BIT(3));
- input_report_key(dev, BTN_TRIGGER_HAPPY7, data[32] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY8, data[32] & BIT(2));
+ input_report_key(dev, BTN_GRIPR, data[32] & BIT(1));
+ input_report_key(dev, BTN_GRIPR2, data[32] & BIT(3));
+ input_report_key(dev, BTN_GRIPL, data[32] & BIT(0));
+ input_report_key(dev, BTN_GRIPL2, data[32] & BIT(2));
} else if (xpad->packet_type == PKT_XBE2_FW_OLD) {
/* Mute paddles if controller has a custom mapping applied.
* Checked by comparing the current mapping
@@ -1120,10 +1190,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
data[18] = 0;
/* Elite Series 2 4.x firmware paddle bits */
- input_report_key(dev, BTN_TRIGGER_HAPPY5, data[18] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY6, data[18] & BIT(1));
- input_report_key(dev, BTN_TRIGGER_HAPPY7, data[18] & BIT(2));
- input_report_key(dev, BTN_TRIGGER_HAPPY8, data[18] & BIT(3));
+ input_report_key(dev, BTN_GRIPR, data[18] & BIT(0));
+ input_report_key(dev, BTN_GRIPR2, data[18] & BIT(1));
+ input_report_key(dev, BTN_GRIPL, data[18] & BIT(2));
+ input_report_key(dev, BTN_GRIPL2, data[18] & BIT(3));
} else if (xpad->packet_type == PKT_XBE2_FW_5_EARLY) {
/* Mute paddles if controller has a custom mapping applied.
* Checked by comparing the current mapping
@@ -1135,10 +1205,10 @@ static void xpadone_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char
/* Elite Series 2 5.x firmware paddle bits
* (before the packet was split)
*/
- input_report_key(dev, BTN_TRIGGER_HAPPY5, data[22] & BIT(0));
- input_report_key(dev, BTN_TRIGGER_HAPPY6, data[22] & BIT(1));
- input_report_key(dev, BTN_TRIGGER_HAPPY7, data[22] & BIT(2));
- input_report_key(dev, BTN_TRIGGER_HAPPY8, data[22] & BIT(3));
+ input_report_key(dev, BTN_GRIPR, data[22] & BIT(0));
+ input_report_key(dev, BTN_GRIPR2, data[22] & BIT(1));
+ input_report_key(dev, BTN_GRIPL, data[22] & BIT(2));
+ input_report_key(dev, BTN_GRIPL2, data[22] & BIT(3));
}
}
@@ -1182,7 +1252,7 @@ static void xpad_irq_in(struct urb *urb)
xpad360w_process_packet(xpad, 0, xpad->idata);
break;
case XTYPE_XBOXONE:
- xpadone_process_packet(xpad, 0, xpad->idata);
+ xpadone_process_packet(xpad, 0, xpad->idata, urb->actual_length);
break;
default:
xpad_process_packet(xpad, 0, xpad->idata);
@@ -1203,6 +1273,14 @@ static bool xpad_prepare_next_init_packet(struct usb_xpad *xpad)
if (xpad->xtype != XTYPE_XBOXONE)
return false;
+ /*
+ * Some dongles will discard init packets if they're sent before the
+ * controller connects. In these cases, we need to wait until we get
+ * an announce packet from them to send the init packet sequence.
+ */
+ if (xpad->delay_init && !xpad->delayed_init_done)
+ return false;
+
/* Perform initialization sequence for Xbox One pads that require it */
while (xpad->init_seq < ARRAY_SIZE(xboxone_init_packets)) {
init_packet = &xboxone_init_packets[xpad->init_seq++];
@@ -1270,11 +1348,12 @@ static int xpad_try_sending_next_out_packet(struct usb_xpad *xpad)
usb_anchor_urb(xpad->irq_out, &xpad->irq_out_anchor);
error = usb_submit_urb(xpad->irq_out, GFP_ATOMIC);
if (error) {
- dev_err(&xpad->intf->dev,
- "%s - usb_submit_urb failed with result %d\n",
- __func__, error);
+ if (error != -ENODEV)
+ dev_err(&xpad->intf->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, error);
usb_unanchor_urb(xpad->irq_out);
- return -EIO;
+ return error;
}
xpad->irq_out_active = true;
@@ -1289,9 +1368,8 @@ static void xpad_irq_out(struct urb *urb)
struct device *dev = &xpad->intf->dev;
int status = urb->status;
int error;
- unsigned long flags;
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
switch (status) {
case 0:
@@ -1325,8 +1403,6 @@ static void xpad_irq_out(struct urb *urb)
xpad->irq_out_active = false;
}
}
-
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad,
@@ -1391,10 +1467,8 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
{
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_CMD_IDX];
- unsigned long flags;
- int retval;
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
packet->data[0] = 0x08;
packet->data[1] = 0x00;
@@ -1413,17 +1487,12 @@ static int xpad_inquiry_pad_presence(struct usb_xpad *xpad)
/* Reset the sequence so we send out presence first */
xpad->last_out_packet = -1;
- retval = xpad_try_sending_next_out_packet(xpad);
-
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
-
- return retval;
+ return xpad_try_sending_next_out_packet(xpad);
}
static int xpad_start_xbox_one(struct usb_xpad *xpad)
{
- unsigned long flags;
- int retval;
+ int error;
if (usb_ifnum_to_if(xpad->udev, GIP_WIRED_INTF_AUDIO)) {
/*
@@ -1432,15 +1501,15 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad)
* Controller for Series X|S (0x20d6:0x200e) to report the
* guide button.
*/
- retval = usb_set_interface(xpad->udev,
- GIP_WIRED_INTF_AUDIO, 0);
- if (retval)
+ error = usb_set_interface(xpad->udev,
+ GIP_WIRED_INTF_AUDIO, 0);
+ if (error)
dev_warn(&xpad->dev->dev,
"unable to disable audio interface: %d\n",
- retval);
+ error);
}
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
/*
* Begin the init sequence by attempting to send a packet.
@@ -1448,16 +1517,11 @@ static int xpad_start_xbox_one(struct usb_xpad *xpad)
* sending any packets from the output ring.
*/
xpad->init_seq = 0;
- retval = xpad_try_sending_next_out_packet(xpad);
-
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
-
- return retval;
+ return xpad_try_sending_next_out_packet(xpad);
}
static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
{
- unsigned long flags;
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_CMD_IDX];
static const u8 mode_report_ack[] = {
@@ -1465,7 +1529,7 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
0x00, GIP_CMD_VIRTUAL_KEY, GIP_OPT_INTERNAL, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00
};
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
packet->len = sizeof(mode_report_ack);
memcpy(packet->data, mode_report_ack, packet->len);
@@ -1475,8 +1539,6 @@ static void xpadone_ack_mode_report(struct usb_xpad *xpad, u8 seq_num)
/* Reset the sequence so we send out the ack now */
xpad->last_out_packet = -1;
xpad_try_sending_next_out_packet(xpad);
-
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
#ifdef CONFIG_JOYSTICK_XPAD_FF
@@ -1486,8 +1548,6 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
struct xpad_output_packet *packet = &xpad->out_packets[XPAD_OUT_FF_IDX];
__u16 strong;
__u16 weak;
- int retval;
- unsigned long flags;
if (effect->type != FF_RUMBLE)
return 0;
@@ -1495,7 +1555,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
strong = effect->u.rumble.strong_magnitude;
weak = effect->u.rumble.weak_magnitude;
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
switch (xpad->xtype) {
case XTYPE_XBOX:
@@ -1561,15 +1621,10 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect
dev_dbg(&xpad->dev->dev,
"%s - rumble command sent to unsupported xpad type: %d\n",
__func__, xpad->xtype);
- retval = -EINVAL;
- goto out;
+ return -EINVAL;
}
- retval = xpad_try_sending_next_out_packet(xpad);
-
-out:
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
- return retval;
+ return xpad_try_sending_next_out_packet(xpad);
}
static int xpad_init_ff(struct usb_xpad *xpad)
@@ -1622,11 +1677,10 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
{
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_LED_IDX];
- unsigned long flags;
command %= 16;
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
switch (xpad->xtype) {
case XTYPE_XBOX360:
@@ -1656,8 +1710,6 @@ static void xpad_send_led_command(struct usb_xpad *xpad, int command)
}
xpad_try_sending_next_out_packet(xpad);
-
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
/*
@@ -1687,7 +1739,7 @@ static int xpad_led_probe(struct usb_xpad *xpad)
if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX360W)
return 0;
- xpad->led = led = kzalloc(sizeof(struct xpad_led), GFP_KERNEL);
+ xpad->led = led = kzalloc(sizeof(*led), GFP_KERNEL);
if (!led)
return -ENOMEM;
@@ -1782,11 +1834,10 @@ static void xpad_stop_input(struct usb_xpad *xpad)
static void xpad360w_poweroff_controller(struct usb_xpad *xpad)
{
- unsigned long flags;
struct xpad_output_packet *packet =
&xpad->out_packets[XPAD_OUT_CMD_IDX];
- spin_lock_irqsave(&xpad->odata_lock, flags);
+ guard(spinlock_irqsave)(&xpad->odata_lock);
packet->data[0] = 0x00;
packet->data[1] = 0x00;
@@ -1806,8 +1857,6 @@ static void xpad360w_poweroff_controller(struct usb_xpad *xpad)
/* Reset the sequence so we send out poweroff now */
xpad->last_out_packet = -1;
xpad_try_sending_next_out_packet(xpad);
-
- spin_unlock_irqrestore(&xpad->odata_lock, flags);
}
static int xpad360w_start_input(struct usb_xpad *xpad)
@@ -1939,7 +1988,7 @@ static int xpad_init_input(struct usb_xpad *xpad)
xpad->xtype == XTYPE_XBOXONE) {
for (i = 0; xpad360_btn[i] >= 0; i++)
input_set_capability(input_dev, EV_KEY, xpad360_btn[i]);
- if (xpad->mapping & MAP_SELECT_BUTTON)
+ if (xpad->mapping & MAP_SHARE_BUTTON)
input_set_capability(input_dev, EV_KEY, KEY_RECORD);
} else {
for (i = 0; xpad_btn[i] >= 0; i++)
@@ -2023,7 +2072,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
break;
}
- xpad = kzalloc(sizeof(struct usb_xpad), GFP_KERNEL);
+ xpad = kzalloc(sizeof(*xpad), GFP_KERNEL);
if (!xpad)
return -ENOMEM;
@@ -2048,6 +2097,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->mapping = xpad_device[i].mapping;
xpad->xtype = xpad_device[i].xtype;
xpad->name = xpad_device[i].name;
+ if (xpad_device[i].flags & FLAG_DELAY_INIT)
+ xpad->delay_init = true;
+
xpad->packet_type = PKT_XB;
INIT_WORK(&xpad->work, xpad_presence_work);
@@ -2231,10 +2283,10 @@ static int xpad_suspend(struct usb_interface *intf, pm_message_t message)
if (auto_poweroff && xpad->pad_present)
xpad360w_poweroff_controller(xpad);
} else {
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
+
if (input_device_enabled(input))
xpad_stop_input(xpad);
- mutex_unlock(&input->mutex);
}
xpad_stop_output(xpad);
@@ -2246,26 +2298,26 @@ static int xpad_resume(struct usb_interface *intf)
{
struct usb_xpad *xpad = usb_get_intfdata(intf);
struct input_dev *input = xpad->dev;
- int retval = 0;
- if (xpad->xtype == XTYPE_XBOX360W) {
- retval = xpad360w_start_input(xpad);
- } else {
- mutex_lock(&input->mutex);
- if (input_device_enabled(input)) {
- retval = xpad_start_input(xpad);
- } else if (xpad->xtype == XTYPE_XBOXONE) {
- /*
- * Even if there are no users, we'll send Xbox One pads
- * the startup sequence so they don't sit there and
- * blink until somebody opens the input device again.
- */
- retval = xpad_start_xbox_one(xpad);
- }
- mutex_unlock(&input->mutex);
+ xpad->delayed_init_done = false;
+ if (xpad->xtype == XTYPE_XBOX360W)
+ return xpad360w_start_input(xpad);
+
+ guard(mutex)(&input->mutex);
+
+ if (input_device_enabled(input))
+ return xpad_start_input(xpad);
+
+ if (xpad->xtype == XTYPE_XBOXONE) {
+ /*
+ * Even if there are no users, we'll send Xbox One pads
+ * the startup sequence so they don't sit there and
+ * blink until somebody opens the input device again.
+ */
+ return xpad_start_xbox_one(xpad);
}
- return retval;
+ return 0;
}
static struct usb_driver xpad_driver = {
diff --git a/drivers/input/joystick/zhenhua.c b/drivers/input/joystick/zhenhua.c
index 3f2460e2b095..cc0e2a77ac5e 100644
--- a/drivers/input/joystick/zhenhua.c
+++ b/drivers/input/joystick/zhenhua.c
@@ -131,7 +131,7 @@ static int zhenhua_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err = -ENOMEM;
- zhenhua = kzalloc(sizeof(struct zhenhua), GFP_KERNEL);
+ zhenhua = kzalloc(sizeof(*zhenhua), GFP_KERNEL);
input_dev = input_allocate_device();
if (!zhenhua || !input_dev)
goto fail1;
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index 1d0c5f4c0f99..2ff4fef322c2 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -37,6 +37,17 @@ config KEYBOARD_ADP5520
To compile this driver as a module, choose M here: the module will
be called adp5520-keys.
+config KEYBOARD_ADP5585
+ tristate "ADP558x keypad support"
+ depends on MFD_ADP5585
+ select INPUT_MATRIXKMAP
+ help
+ This option enables support for the KEYPAD function found in the Analog
+ Devices ADP5585 and similar devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called adp5585-keys.
+
config KEYBOARD_ADP5588
tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander"
depends on I2C
@@ -50,16 +61,6 @@ config KEYBOARD_ADP5588
To compile this driver as a module, choose M here: the
module will be called adp5588-keys.
-config KEYBOARD_ADP5589
- tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander"
- depends on I2C
- help
- Say Y here if you want to use a ADP5585/ADP5589 attached to your
- system I2C bus.
-
- To compile this driver as a module, choose M here: the
- module will be called adp5589-keys.
-
config KEYBOARD_AMIGA
tristate "Amiga keyboard"
depends on AMIGA
@@ -261,24 +262,6 @@ config KEYBOARD_GPIO_POLLED
To compile this driver as a module, choose M here: the
module will be called gpio_keys_polled.
-config KEYBOARD_TCA6416
- tristate "TCA6416/TCA6408A Keypad Support"
- depends on I2C
- help
- This driver implements basic keypad functionality
- for keys connected through TCA6416/TCA6408A IO expanders.
-
- Say Y here if your device has keys connected to
- TCA6416/TCA6408A IO expander. Your board-specific setup logic
- must also provide pin-mask details(of which TCA6416 pins
- are used for keypad).
-
- If enabled the entire TCA6416 device will be managed through
- this driver.
-
- To compile this driver as a module, choose M here: the
- module will be called tca6416_keypad.
-
config KEYBOARD_TCA8418
tristate "TCA8418 Keypad Support"
depends on I2C
@@ -421,17 +404,17 @@ config KEYBOARD_MAX7359
To compile this driver as a module, choose M here: the
module will be called max7359_keypad.
-config KEYBOARD_MCS
- tristate "MELFAS MCS Touchkey"
+config KEYBOARD_MAX7360
+ tristate "Maxim MAX7360 Key Switch Controller"
+ select INPUT_MATRIXKMAP
depends on I2C
+ depends on MFD_MAX7360
help
- Say Y here if you have the MELFAS MCS5000/5080 touchkey controller
- chip in your system.
+ If you say yes here you get support for the keypad controller on the
+ Maxim MAX7360 I/O Expander.
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called mcs_touchkey.
+ To compile this driver as a module, choose M here: the module will be
+ called max7360_keypad.
config KEYBOARD_MPR121
tristate "Freescale MPR121 Touchkey"
@@ -466,6 +449,17 @@ config KEYBOARD_IMX
To compile this driver as a module, choose M here: the
module will be called imx_keypad.
+config KEYBOARD_IMX_BBM_SCMI
+ tristate "IMX BBM SCMI Key Driver"
+ depends on IMX_SCMI_BBM_EXT || COMPILE_TEST
+ default y if ARCH_MXC
+ help
+ This is the BBM key driver for NXP i.MX SoCs managed through
+ SCMI protocol.
+
+ To compile this driver as a module, choose M here: the
+ module will be called scmi-imx-bbm-key.
+
config KEYBOARD_IMX_SC_KEY
tristate "IMX SCU Key Driver"
depends on IMX_SCU
@@ -485,17 +479,6 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the
module will be called newtonkbd.
-config KEYBOARD_NOMADIK
- tristate "ST-Ericsson Nomadik SKE keyboard"
- depends on (ARCH_NOMADIK || ARCH_U8500 || COMPILE_TEST)
- select INPUT_MATRIXKMAP
- help
- Say Y here if you want to use a keypad provided on the SKE controller
- used on the Ux500 and Nomadik platforms
-
- To compile this driver as a module, choose M here: the
- module will be called nmk-ske-keypad.
-
config KEYBOARD_NSPIRE
tristate "TI-NSPIRE built-in keyboard"
depends on ARCH_NSPIRE && OF
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index aecef00c5d09..2d906e14f3e2 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -7,8 +7,8 @@
obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o
obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o
+obj-$(CONFIG_KEYBOARD_ADP5585) += adp5585-keys.o
obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o
-obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_APPLESPI) += applespi.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
@@ -23,7 +23,6 @@ obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o
-obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o
obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
@@ -31,6 +30,7 @@ obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o
obj-$(CONFIG_KEYBOARD_IQS62X) += iqs62x-keys.o
obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o
obj-$(CONFIG_KEYBOARD_IMX_SC_KEY) += imx_sc_key.o
+obj-$(CONFIG_KEYBOARD_IMX_BBM_SCMI) += imx-sm-bbm-key.o
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o
obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o
@@ -41,12 +41,11 @@ obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o
obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o
obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o
obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o
-obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o
+obj-$(CONFIG_KEYBOARD_MAX7360) += max7360-keypad.o
obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o
obj-$(CONFIG_KEYBOARD_MT6779) += mt6779-keypad.o
obj-$(CONFIG_KEYBOARD_MTK_PMIC) += mtk-pmic-keys.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
-obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o
obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o
diff --git a/drivers/input/keyboard/adc-keys.c b/drivers/input/keyboard/adc-keys.c
index bf72ab8df817..f1753207429d 100644
--- a/drivers/input/keyboard/adc-keys.c
+++ b/drivers/input/keyboard/adc-keys.c
@@ -66,7 +66,6 @@ static void adc_keys_poll(struct input_dev *input)
static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
{
struct adc_keys_button *map;
- struct fwnode_handle *child;
int i;
st->num_keys = device_get_child_node_count(dev);
@@ -80,11 +79,10 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
return -ENOMEM;
i = 0;
- device_for_each_child_node(dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
if (fwnode_property_read_u32(child, "press-threshold-microvolt",
&map[i].voltage)) {
dev_err(dev, "Key with invalid or missing voltage\n");
- fwnode_handle_put(child);
return -EINVAL;
}
map[i].voltage /= 1000;
@@ -92,7 +90,6 @@ static int adc_keys_load_keymap(struct device *dev, struct adc_keys_state *st)
if (fwnode_property_read_u32(child, "linux,code",
&map[i].keycode)) {
dev_err(dev, "Key with invalid or missing linux,code\n");
- fwnode_handle_put(child);
return -EINVAL;
}
diff --git a/drivers/input/keyboard/adp5520-keys.c b/drivers/input/keyboard/adp5520-keys.c
index 10c248f0c1fc..980d739e45b8 100644
--- a/drivers/input/keyboard/adp5520-keys.c
+++ b/drivers/input/keyboard/adp5520-keys.c
@@ -181,7 +181,7 @@ static struct platform_driver adp5520_keys_driver = {
.name = "adp5520-keys",
},
.probe = adp5520_keys_probe,
- .remove_new = adp5520_keys_remove,
+ .remove = adp5520_keys_remove,
};
module_platform_driver(adp5520_keys_driver);
diff --git a/drivers/input/keyboard/adp5585-keys.c b/drivers/input/keyboard/adp5585-keys.c
new file mode 100644
index 000000000000..4208229e1356
--- /dev/null
+++ b/drivers/input/keyboard/adp5585-keys.c
@@ -0,0 +1,371 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Analog Devices ADP5585 Keys driver
+ *
+ * Copyright (C) 2025 Analog Devices, Inc.
+ */
+
+#include <linux/bitmap.h>
+#include <linux/container_of.h>
+#include <linux/device.h>
+#include <linux/find.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/adp5585.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/notifier.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+/* As needed for the matrix parsing code */
+#define ADP5589_MAX_KEYMAPSIZE 123
+
+struct adp5585_kpad_chip {
+ u8 key_ev_min;
+ u8 key_ev_max;
+ u8 max_rows;
+ u8 max_cols;
+};
+
+struct adp5585_kpad {
+ const struct adp5585_kpad_chip *info;
+ struct notifier_block nb;
+ struct input_dev *input;
+ unsigned short keycode[ADP5589_MAX_KEYMAPSIZE];
+ struct device *dev;
+ unsigned long keypad;
+ int row_shift;
+};
+
+static int adp5585_keys_validate_events(const struct adp5585_kpad *kpad,
+ const u32 *events, u32 n_events)
+{
+ unsigned int ev;
+ u32 row, col;
+
+ for (ev = 0; ev < n_events; ev++) {
+ if (events[ev] < kpad->info->key_ev_min ||
+ events[ev] > kpad->info->key_ev_max)
+ continue;
+
+ /*
+ * if the event is to be generated by the keymap, we need to make
+ * sure that the pins are part of it!
+ */
+ row = (events[ev] - 1) / kpad->info->max_cols;
+ col = (events[ev] - 1) % kpad->info->max_cols;
+
+ if (test_bit(row, &kpad->keypad) &&
+ test_bit(col + kpad->info->max_rows, &kpad->keypad))
+ continue;
+
+ return dev_err_probe(kpad->dev, -EINVAL,
+ "Invalid unlock/reset event(%u) not used in the keypad\n",
+ events[ev]);
+ }
+
+ return 0;
+}
+
+static int adp5585_keys_check_special_events(const struct adp5585_dev *adp5585,
+ const struct adp5585_kpad *kpad)
+{
+ int error;
+
+ error = adp5585_keys_validate_events(kpad, adp5585->unlock_keys,
+ adp5585->nkeys_unlock);
+ if (error)
+ return error;
+
+ error = adp5585_keys_validate_events(kpad, adp5585->reset1_keys,
+ adp5585->nkeys_reset1);
+ if (error)
+ return error;
+
+ return adp5585_keys_validate_events(kpad, adp5585->reset2_keys,
+ adp5585->nkeys_reset2);
+}
+
+static void adp5585_keys_pins_free(void *data)
+{
+ struct adp5585_kpad *kpad = data;
+ struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent);
+ unsigned int pin;
+
+ for_each_set_bit(pin, &kpad->keypad, adp5585->n_pins)
+ clear_bit(pin, adp5585->pin_usage);
+}
+
+static int adp5585_keys_parse_fw(const struct adp5585_dev *adp5585,
+ struct adp5585_kpad *kpad)
+{
+ struct device *dev = kpad->dev;
+ u32 cols = 0, rows = 0, pin;
+ int error, n_pins;
+
+ /*
+ * We do not check for errors (or no value) since the input device is
+ * only added if this property is present in the first place.
+ */
+ n_pins = device_property_count_u32(dev, "adi,keypad-pins");
+ if (n_pins > adp5585->n_pins)
+ return dev_err_probe(dev, -EINVAL,
+ "Too many keypad pins (%d) defined (max=%d)\n",
+ n_pins, adp5585->n_pins);
+
+ unsigned int *keypad_pins __free(kfree) = kcalloc(n_pins, sizeof(*keypad_pins),
+ GFP_KERNEL);
+ if (!keypad_pins)
+ return -ENOMEM;
+
+ error = device_property_read_u32_array(dev, "adi,keypad-pins",
+ keypad_pins, n_pins);
+ if (error)
+ return error;
+
+ /*
+ * We can add the action here since it makes the code easier and nothing
+ * "bad" will happen out of it. Worst case, it will be a no-op and no
+ * bit will set.
+ */
+ error = devm_add_action_or_reset(dev, adp5585_keys_pins_free, kpad);
+ if (error)
+ return error;
+
+ for (pin = 0; pin < n_pins; pin++) {
+ if (keypad_pins[pin] >= adp5585->n_pins)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid keypad pin(%u) defined\n",
+ keypad_pins[pin]);
+
+ if (test_and_set_bit(keypad_pins[pin], adp5585->pin_usage))
+ return dev_err_probe(dev, -EBUSY,
+ "Keypad pin(%u) already used\n",
+ keypad_pins[pin]);
+
+ __set_bit(keypad_pins[pin], &kpad->keypad);
+ }
+
+ /*
+ * Note that given that we get a mask (and the HW allows it), we
+ * can have holes in our keypad (eg: row0, row1 and row7 enabled).
+ * However, for the matrix parsing functions we need to pass the
+ * number of rows/cols as the maximum row/col used plus 1. This
+ * pretty much means we will also have holes in our SW keypad.
+ */
+
+ rows = find_last_bit(&kpad->keypad, kpad->info->max_rows) + 1;
+ if (rows == kpad->info->max_rows + 1)
+ return dev_err_probe(dev, -EINVAL,
+ "Now rows defined in the keypad!\n");
+
+ cols = find_last_bit(&kpad->keypad, kpad->info->max_cols + kpad->info->max_rows);
+ if (cols < kpad->info->max_rows)
+ return dev_err_probe(dev, -EINVAL,
+ "No columns defined in the keypad!\n");
+
+ cols = cols + 1 - kpad->info->max_rows;
+
+ error = matrix_keypad_build_keymap(NULL, NULL, rows, cols,
+ kpad->keycode, kpad->input);
+ if (error)
+ return error;
+
+ kpad->row_shift = get_count_order(cols);
+
+ if (device_property_read_bool(kpad->dev, "autorepeat"))
+ __set_bit(EV_REP, kpad->input->evbit);
+
+ error = adp5585_keys_check_special_events(adp5585, kpad);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int adp5585_keys_setup(const struct adp5585_dev *adp5585,
+ struct adp5585_kpad *kpad)
+{
+ unsigned long keys_bits, start = 0, nbits = kpad->info->max_rows;
+ const struct adp5585_regs *regs = adp5585->regs;
+ unsigned int i = 0, max_cols = kpad->info->max_cols;
+ int error;
+
+ /*
+ * Take care as the below assumes max_rows is always less or equal than
+ * 8 which is true for the supported devices. If we happen to add
+ * another device we need to make sure this still holds true. Although
+ * adding a new device is very unlikely.
+ */
+ do {
+ keys_bits = bitmap_read(&kpad->keypad, start, nbits);
+ if (keys_bits) {
+ error = regmap_write(adp5585->regmap, regs->pin_cfg_a + i,
+ keys_bits);
+ if (error)
+ return error;
+ }
+
+ start += nbits;
+ if (max_cols > 8) {
+ nbits = 8;
+ max_cols -= nbits;
+ } else {
+ nbits = max_cols;
+ }
+
+ i++;
+ } while (start < kpad->info->max_rows + kpad->info->max_cols);
+
+ return 0;
+}
+
+static int adp5585_keys_ev_handle(struct notifier_block *nb, unsigned long key,
+ void *data)
+{
+ struct adp5585_kpad *kpad = container_of(nb, struct adp5585_kpad, nb);
+ unsigned long key_press = (unsigned long)data;
+ unsigned int row, col, code;
+
+ /* make sure the event is for us */
+ if (key < kpad->info->key_ev_min || key > kpad->info->key_ev_max)
+ return NOTIFY_DONE;
+
+ /*
+ * Unlikely but lets be on the safe side! We do not return any error
+ * because the event was indeed for us but with some weird value. So,
+ * we still want the caller know that the right handler was called.
+ */
+ if (!key)
+ return NOTIFY_BAD;
+
+ row = (key - 1) / (kpad->info->max_cols);
+ col = (key - 1) % (kpad->info->max_cols);
+ code = MATRIX_SCAN_CODE(row, col, kpad->row_shift);
+
+ dev_dbg_ratelimited(kpad->dev, "report key(%lu) r(%d) c(%d) code(%d)\n",
+ key, row, col, kpad->keycode[code]);
+
+ input_report_key(kpad->input, kpad->keycode[code], key_press);
+ input_sync(kpad->input);
+
+ return NOTIFY_STOP;
+}
+
+static void adp5585_keys_unreg_notifier(void *data)
+{
+ struct adp5585_kpad *kpad = data;
+ struct adp5585_dev *adp5585 = dev_get_drvdata(kpad->dev->parent);
+
+ blocking_notifier_chain_unregister(&adp5585->event_notifier,
+ &kpad->nb);
+}
+
+static int adp5585_keys_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct adp5585_dev *adp5585 = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct adp5585_kpad *kpad;
+ unsigned int revid;
+ const char *phys;
+ int error;
+
+ kpad = devm_kzalloc(dev, sizeof(*kpad), GFP_KERNEL);
+ if (!kpad)
+ return -ENOMEM;
+
+ if (!adp5585->irq)
+ return dev_err_probe(dev, -EINVAL,
+ "IRQ is mandatory for the keypad\n");
+
+ kpad->dev = dev;
+
+ kpad->input = devm_input_allocate_device(dev);
+ if (!kpad->input)
+ return -ENOMEM;
+
+ kpad->info = (const struct adp5585_kpad_chip *)id->driver_data;
+ if (!kpad->info)
+ return -ENODEV;
+
+ error = regmap_read(adp5585->regmap, ADP5585_ID, &revid);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to read device ID\n");
+
+ phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", pdev->name);
+ if (!phys)
+ return -ENOMEM;
+
+ kpad->input->name = pdev->name;
+ kpad->input->phys = phys;
+
+ kpad->input->id.bustype = BUS_I2C;
+ kpad->input->id.vendor = 0x0001;
+ kpad->input->id.product = 0x0001;
+ kpad->input->id.version = revid & ADP5585_REV_ID_MASK;
+
+ device_set_of_node_from_dev(dev, dev->parent);
+
+ error = adp5585_keys_parse_fw(adp5585, kpad);
+ if (error)
+ return error;
+
+ error = adp5585_keys_setup(adp5585, kpad);
+ if (error)
+ return error;
+
+ kpad->nb.notifier_call = adp5585_keys_ev_handle;
+ error = blocking_notifier_chain_register(&adp5585->event_notifier,
+ &kpad->nb);
+ if (error)
+ return error;
+
+ error = devm_add_action_or_reset(dev, adp5585_keys_unreg_notifier, kpad);
+ if (error)
+ return error;
+
+ error = input_register_device(kpad->input);
+ if (error)
+ return dev_err_probe(dev, error,
+ "Failed to register input device\n");
+
+ return 0;
+}
+
+static const struct adp5585_kpad_chip adp5585_kpad_chip_info = {
+ .max_rows = 6,
+ .max_cols = 5,
+ .key_ev_min = ADP5585_ROW5_KEY_EVENT_START,
+ .key_ev_max = ADP5585_ROW5_KEY_EVENT_END,
+};
+
+static const struct adp5585_kpad_chip adp5589_kpad_chip_info = {
+ .max_rows = 8,
+ .max_cols = 11,
+ .key_ev_min = ADP5589_KEY_EVENT_START,
+ .key_ev_max = ADP5589_KEY_EVENT_END,
+};
+
+static const struct platform_device_id adp5585_keys_id_table[] = {
+ { "adp5585-keys", (kernel_ulong_t)&adp5585_kpad_chip_info },
+ { "adp5589-keys", (kernel_ulong_t)&adp5589_kpad_chip_info },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, adp5585_keys_id_table);
+
+static struct platform_driver adp5585_keys_driver = {
+ .driver = {
+ .name = "adp5585-keys",
+ },
+ .probe = adp5585_keys_probe,
+ .id_table = adp5585_keys_id_table,
+};
+module_platform_driver(adp5585_keys_driver);
+
+MODULE_AUTHOR("Nuno Sá <nuno.sa@analog.com>");
+MODULE_DESCRIPTION("ADP5585 Keys Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/adp5588-keys.c b/drivers/input/keyboard/adp5588-keys.c
index 1b0279393df4..414fbef4abf9 100644
--- a/drivers/input/keyboard/adp5588-keys.c
+++ b/drivers/input/keyboard/adp5588-keys.c
@@ -188,6 +188,7 @@ struct adp5588_kpad {
u32 cols;
u32 unlock_keys[2];
int nkeys_unlock;
+ bool gpio_only;
unsigned short keycode[ADP5588_KEYMAPSIZE];
unsigned char gpiomap[ADP5588_MAXGPIO];
struct gpio_chip gc;
@@ -221,35 +222,32 @@ static int adp5588_gpio_get_value(struct gpio_chip *chip, unsigned int off)
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
int val;
- mutex_lock(&kpad->gpio_lock);
+ guard(mutex)(&kpad->gpio_lock);
if (kpad->dir[bank] & bit)
val = kpad->dat_out[bank];
else
val = adp5588_read(kpad->client, GPIO_DAT_STAT1 + bank);
- mutex_unlock(&kpad->gpio_lock);
-
return !!(val & bit);
}
-static void adp5588_gpio_set_value(struct gpio_chip *chip,
- unsigned int off, int val)
+static int adp5588_gpio_set_value(struct gpio_chip *chip, unsigned int off,
+ int val)
{
struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
- mutex_lock(&kpad->gpio_lock);
+ guard(mutex)(&kpad->gpio_lock);
if (val)
kpad->dat_out[bank] |= bit;
else
kpad->dat_out[bank] &= ~bit;
- adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank, kpad->dat_out[bank]);
-
- mutex_unlock(&kpad->gpio_lock);
+ return adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+ kpad->dat_out[bank]);
}
static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off,
@@ -259,7 +257,6 @@ static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off,
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
bool pull_disable;
- int ret;
switch (pinconf_to_config_param(config)) {
case PIN_CONFIG_BIAS_PULL_UP:
@@ -272,19 +269,15 @@ static int adp5588_gpio_set_config(struct gpio_chip *chip, unsigned int off,
return -ENOTSUPP;
}
- mutex_lock(&kpad->gpio_lock);
+ guard(mutex)(&kpad->gpio_lock);
if (pull_disable)
kpad->pull_dis[bank] |= bit;
else
kpad->pull_dis[bank] &= bit;
- ret = adp5588_write(kpad->client, GPIO_PULL1 + bank,
- kpad->pull_dis[bank]);
-
- mutex_unlock(&kpad->gpio_lock);
-
- return ret;
+ return adp5588_write(kpad->client, GPIO_PULL1 + bank,
+ kpad->pull_dis[bank]);
}
static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned int off)
@@ -292,16 +285,11 @@ static int adp5588_gpio_direction_input(struct gpio_chip *chip, unsigned int off
struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
- int ret;
- mutex_lock(&kpad->gpio_lock);
+ guard(mutex)(&kpad->gpio_lock);
kpad->dir[bank] &= ~bit;
- ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
-
- mutex_unlock(&kpad->gpio_lock);
-
- return ret;
+ return adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
}
static int adp5588_gpio_direction_output(struct gpio_chip *chip,
@@ -310,9 +298,9 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
struct adp5588_kpad *kpad = gpiochip_get_data(chip);
unsigned int bank = ADP5588_BANK(kpad->gpiomap[off]);
unsigned int bit = ADP5588_BIT(kpad->gpiomap[off]);
- int ret;
+ int error;
- mutex_lock(&kpad->gpio_lock);
+ guard(mutex)(&kpad->gpio_lock);
kpad->dir[bank] |= bit;
@@ -321,17 +309,16 @@ static int adp5588_gpio_direction_output(struct gpio_chip *chip,
else
kpad->dat_out[bank] &= ~bit;
- ret = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
- kpad->dat_out[bank]);
- if (ret)
- goto out_unlock;
-
- ret = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
+ error = adp5588_write(kpad->client, GPIO_DAT_OUT1 + bank,
+ kpad->dat_out[bank]);
+ if (error)
+ return error;
-out_unlock:
- mutex_unlock(&kpad->gpio_lock);
+ error = adp5588_write(kpad->client, GPIO_DIR1 + bank, kpad->dir[bank]);
+ if (error)
+ return error;
- return ret;
+ return 0;
}
static int adp5588_build_gpiomap(struct adp5588_kpad *kpad)
@@ -446,10 +433,17 @@ static int adp5588_gpio_add(struct adp5588_kpad *kpad)
kpad->gc.label = kpad->client->name;
kpad->gc.owner = THIS_MODULE;
- girq = &kpad->gc.irq;
- gpio_irq_chip_set_chip(girq, &adp5588_irq_chip);
- girq->handler = handle_bad_irq;
- girq->threaded = true;
+ if (device_property_present(dev, "interrupt-controller")) {
+ if (!kpad->client->irq) {
+ dev_err(dev, "Unable to serve as interrupt controller without interrupt");
+ return -EINVAL;
+ }
+
+ girq = &kpad->gc.irq;
+ gpio_irq_chip_set_chip(girq, &adp5588_irq_chip);
+ girq->handler = handle_bad_irq;
+ girq->threaded = true;
+ }
mutex_init(&kpad->gpio_lock);
@@ -627,7 +621,7 @@ static int adp5588_setup(struct adp5588_kpad *kpad)
for (i = 0; i < KEYP_MAX_EVENT; i++) {
ret = adp5588_read(client, KEY_EVENTA);
- if (ret)
+ if (ret < 0)
return ret;
}
@@ -647,6 +641,18 @@ static int adp5588_fw_parse(struct adp5588_kpad *kpad)
struct i2c_client *client = kpad->client;
int ret, i;
+ /*
+ * Check if the device is to be operated purely in GPIO mode. To do
+ * so, check that no keypad rows or columns have been specified,
+ * since all GPINS should be configured as GPIO.
+ */
+ if (!device_property_present(&client->dev, "keypad,num-rows") &&
+ !device_property_present(&client->dev, "keypad,num-columns")) {
+ /* If purely GPIO, skip keypad setup */
+ kpad->gpio_only = true;
+ return 0;
+ }
+
ret = matrix_keypad_parse_properties(&client->dev, &kpad->rows,
&kpad->cols);
if (ret)
@@ -790,17 +796,19 @@ static int adp5588_probe(struct i2c_client *client)
if (error)
return error;
- error = devm_request_threaded_irq(&client->dev, client->irq,
- adp5588_hard_irq, adp5588_thread_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->dev.driver->name, kpad);
- if (error) {
- dev_err(&client->dev, "failed to request irq %d: %d\n",
- client->irq, error);
- return error;
+ if (client->irq) {
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ adp5588_hard_irq, adp5588_thread_irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->dev.driver->name, kpad);
+ if (error) {
+ dev_err(&client->dev, "failed to request irq %d: %d\n",
+ client->irq, error);
+ return error;
+ }
}
- dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
+ dev_info(&client->dev, "Rev.%d controller\n", revid);
return 0;
}
@@ -815,7 +823,8 @@ static int adp5588_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- disable_irq(client->irq);
+ if (client->irq)
+ disable_irq(client->irq);
return 0;
}
@@ -824,7 +833,8 @@ static int adp5588_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
- enable_irq(client->irq);
+ if (client->irq)
+ enable_irq(client->irq);
return 0;
}
diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c
deleted file mode 100644
index 8996e00cd63a..000000000000
--- a/drivers/input/keyboard/adp5589-keys.c
+++ /dev/null
@@ -1,1065 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Description: keypad driver for ADP5589, ADP5585
- * I2C QWERTY Keypad and IO Expander
- * Bugs: Enter bugs at http://blackfin.uclinux.org/
- *
- * Copyright (C) 2010-2011 Analog Devices Inc.
- */
-
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/workqueue.h>
-#include <linux/errno.h>
-#include <linux/pm.h>
-#include <linux/pm_wakeirq.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/i2c.h>
-#include <linux/gpio/driver.h>
-#include <linux/slab.h>
-
-#include <linux/input/adp5589.h>
-
-/* ADP5589/ADP5585 Common Registers */
-#define ADP5589_5_ID 0x00
-#define ADP5589_5_INT_STATUS 0x01
-#define ADP5589_5_STATUS 0x02
-#define ADP5589_5_FIFO_1 0x03
-#define ADP5589_5_FIFO_2 0x04
-#define ADP5589_5_FIFO_3 0x05
-#define ADP5589_5_FIFO_4 0x06
-#define ADP5589_5_FIFO_5 0x07
-#define ADP5589_5_FIFO_6 0x08
-#define ADP5589_5_FIFO_7 0x09
-#define ADP5589_5_FIFO_8 0x0A
-#define ADP5589_5_FIFO_9 0x0B
-#define ADP5589_5_FIFO_10 0x0C
-#define ADP5589_5_FIFO_11 0x0D
-#define ADP5589_5_FIFO_12 0x0E
-#define ADP5589_5_FIFO_13 0x0F
-#define ADP5589_5_FIFO_14 0x10
-#define ADP5589_5_FIFO_15 0x11
-#define ADP5589_5_FIFO_16 0x12
-#define ADP5589_5_GPI_INT_STAT_A 0x13
-#define ADP5589_5_GPI_INT_STAT_B 0x14
-
-/* ADP5589 Registers */
-#define ADP5589_GPI_INT_STAT_C 0x15
-#define ADP5589_GPI_STATUS_A 0x16
-#define ADP5589_GPI_STATUS_B 0x17
-#define ADP5589_GPI_STATUS_C 0x18
-#define ADP5589_RPULL_CONFIG_A 0x19
-#define ADP5589_RPULL_CONFIG_B 0x1A
-#define ADP5589_RPULL_CONFIG_C 0x1B
-#define ADP5589_RPULL_CONFIG_D 0x1C
-#define ADP5589_RPULL_CONFIG_E 0x1D
-#define ADP5589_GPI_INT_LEVEL_A 0x1E
-#define ADP5589_GPI_INT_LEVEL_B 0x1F
-#define ADP5589_GPI_INT_LEVEL_C 0x20
-#define ADP5589_GPI_EVENT_EN_A 0x21
-#define ADP5589_GPI_EVENT_EN_B 0x22
-#define ADP5589_GPI_EVENT_EN_C 0x23
-#define ADP5589_GPI_INTERRUPT_EN_A 0x24
-#define ADP5589_GPI_INTERRUPT_EN_B 0x25
-#define ADP5589_GPI_INTERRUPT_EN_C 0x26
-#define ADP5589_DEBOUNCE_DIS_A 0x27
-#define ADP5589_DEBOUNCE_DIS_B 0x28
-#define ADP5589_DEBOUNCE_DIS_C 0x29
-#define ADP5589_GPO_DATA_OUT_A 0x2A
-#define ADP5589_GPO_DATA_OUT_B 0x2B
-#define ADP5589_GPO_DATA_OUT_C 0x2C
-#define ADP5589_GPO_OUT_MODE_A 0x2D
-#define ADP5589_GPO_OUT_MODE_B 0x2E
-#define ADP5589_GPO_OUT_MODE_C 0x2F
-#define ADP5589_GPIO_DIRECTION_A 0x30
-#define ADP5589_GPIO_DIRECTION_B 0x31
-#define ADP5589_GPIO_DIRECTION_C 0x32
-#define ADP5589_UNLOCK1 0x33
-#define ADP5589_UNLOCK2 0x34
-#define ADP5589_EXT_LOCK_EVENT 0x35
-#define ADP5589_UNLOCK_TIMERS 0x36
-#define ADP5589_LOCK_CFG 0x37
-#define ADP5589_RESET1_EVENT_A 0x38
-#define ADP5589_RESET1_EVENT_B 0x39
-#define ADP5589_RESET1_EVENT_C 0x3A
-#define ADP5589_RESET2_EVENT_A 0x3B
-#define ADP5589_RESET2_EVENT_B 0x3C
-#define ADP5589_RESET_CFG 0x3D
-#define ADP5589_PWM_OFFT_LOW 0x3E
-#define ADP5589_PWM_OFFT_HIGH 0x3F
-#define ADP5589_PWM_ONT_LOW 0x40
-#define ADP5589_PWM_ONT_HIGH 0x41
-#define ADP5589_PWM_CFG 0x42
-#define ADP5589_CLOCK_DIV_CFG 0x43
-#define ADP5589_LOGIC_1_CFG 0x44
-#define ADP5589_LOGIC_2_CFG 0x45
-#define ADP5589_LOGIC_FF_CFG 0x46
-#define ADP5589_LOGIC_INT_EVENT_EN 0x47
-#define ADP5589_POLL_PTIME_CFG 0x48
-#define ADP5589_PIN_CONFIG_A 0x49
-#define ADP5589_PIN_CONFIG_B 0x4A
-#define ADP5589_PIN_CONFIG_C 0x4B
-#define ADP5589_PIN_CONFIG_D 0x4C
-#define ADP5589_GENERAL_CFG 0x4D
-#define ADP5589_INT_EN 0x4E
-
-/* ADP5585 Registers */
-#define ADP5585_GPI_STATUS_A 0x15
-#define ADP5585_GPI_STATUS_B 0x16
-#define ADP5585_RPULL_CONFIG_A 0x17
-#define ADP5585_RPULL_CONFIG_B 0x18
-#define ADP5585_RPULL_CONFIG_C 0x19
-#define ADP5585_RPULL_CONFIG_D 0x1A
-#define ADP5585_GPI_INT_LEVEL_A 0x1B
-#define ADP5585_GPI_INT_LEVEL_B 0x1C
-#define ADP5585_GPI_EVENT_EN_A 0x1D
-#define ADP5585_GPI_EVENT_EN_B 0x1E
-#define ADP5585_GPI_INTERRUPT_EN_A 0x1F
-#define ADP5585_GPI_INTERRUPT_EN_B 0x20
-#define ADP5585_DEBOUNCE_DIS_A 0x21
-#define ADP5585_DEBOUNCE_DIS_B 0x22
-#define ADP5585_GPO_DATA_OUT_A 0x23
-#define ADP5585_GPO_DATA_OUT_B 0x24
-#define ADP5585_GPO_OUT_MODE_A 0x25
-#define ADP5585_GPO_OUT_MODE_B 0x26
-#define ADP5585_GPIO_DIRECTION_A 0x27
-#define ADP5585_GPIO_DIRECTION_B 0x28
-#define ADP5585_RESET1_EVENT_A 0x29
-#define ADP5585_RESET1_EVENT_B 0x2A
-#define ADP5585_RESET1_EVENT_C 0x2B
-#define ADP5585_RESET2_EVENT_A 0x2C
-#define ADP5585_RESET2_EVENT_B 0x2D
-#define ADP5585_RESET_CFG 0x2E
-#define ADP5585_PWM_OFFT_LOW 0x2F
-#define ADP5585_PWM_OFFT_HIGH 0x30
-#define ADP5585_PWM_ONT_LOW 0x31
-#define ADP5585_PWM_ONT_HIGH 0x32
-#define ADP5585_PWM_CFG 0x33
-#define ADP5585_LOGIC_CFG 0x34
-#define ADP5585_LOGIC_FF_CFG 0x35
-#define ADP5585_LOGIC_INT_EVENT_EN 0x36
-#define ADP5585_POLL_PTIME_CFG 0x37
-#define ADP5585_PIN_CONFIG_A 0x38
-#define ADP5585_PIN_CONFIG_B 0x39
-#define ADP5585_PIN_CONFIG_D 0x3A
-#define ADP5585_GENERAL_CFG 0x3B
-#define ADP5585_INT_EN 0x3C
-
-/* ID Register */
-#define ADP5589_5_DEVICE_ID_MASK 0xF
-#define ADP5589_5_MAN_ID_MASK 0xF
-#define ADP5589_5_MAN_ID_SHIFT 4
-#define ADP5589_5_MAN_ID 0x02
-
-/* GENERAL_CFG Register */
-#define OSC_EN BIT(7)
-#define CORE_CLK(x) (((x) & 0x3) << 5)
-#define LCK_TRK_LOGIC BIT(4) /* ADP5589 only */
-#define LCK_TRK_GPI BIT(3) /* ADP5589 only */
-#define INT_CFG BIT(1)
-#define RST_CFG BIT(0)
-
-/* INT_EN Register */
-#define LOGIC2_IEN BIT(5) /* ADP5589 only */
-#define LOGIC1_IEN BIT(4)
-#define LOCK_IEN BIT(3) /* ADP5589 only */
-#define OVRFLOW_IEN BIT(2)
-#define GPI_IEN BIT(1)
-#define EVENT_IEN BIT(0)
-
-/* Interrupt Status Register */
-#define LOGIC2_INT BIT(5) /* ADP5589 only */
-#define LOGIC1_INT BIT(4)
-#define LOCK_INT BIT(3) /* ADP5589 only */
-#define OVRFLOW_INT BIT(2)
-#define GPI_INT BIT(1)
-#define EVENT_INT BIT(0)
-
-/* STATUS Register */
-#define LOGIC2_STAT BIT(7) /* ADP5589 only */
-#define LOGIC1_STAT BIT(6)
-#define LOCK_STAT BIT(5) /* ADP5589 only */
-#define KEC 0x1F
-
-/* PIN_CONFIG_D Register */
-#define C4_EXTEND_CFG BIT(6) /* RESET2 */
-#define R4_EXTEND_CFG BIT(5) /* RESET1 */
-
-/* LOCK_CFG */
-#define LOCK_EN BIT(0)
-
-#define PTIME_MASK 0x3
-#define LTIME_MASK 0x3 /* ADP5589 only */
-
-/* Key Event Register xy */
-#define KEY_EV_PRESSED BIT(7)
-#define KEY_EV_MASK 0x7F
-
-#define KEYP_MAX_EVENT 16
-#define ADP5589_MAXGPIO 19
-#define ADP5585_MAXGPIO 11 /* 10 on the ADP5585-01, 11 on ADP5585-02 */
-
-enum {
- ADP5589,
- ADP5585_01,
- ADP5585_02
-};
-
-struct adp_constants {
- u8 maxgpio;
- u8 keymapsize;
- u8 gpi_pin_row_base;
- u8 gpi_pin_row_end;
- u8 gpi_pin_col_base;
- u8 gpi_pin_base;
- u8 gpi_pin_end;
- u8 gpimapsize_max;
- u8 max_row_num;
- u8 max_col_num;
- u8 row_mask;
- u8 col_mask;
- u8 col_shift;
- u8 c4_extend_cfg;
- u8 (*bank) (u8 offset);
- u8 (*bit) (u8 offset);
- u8 (*reg) (u8 reg);
-};
-
-struct adp5589_kpad {
- struct i2c_client *client;
- struct input_dev *input;
- const struct adp_constants *var;
- unsigned short keycode[ADP5589_KEYMAPSIZE];
- const struct adp5589_gpi_map *gpimap;
- unsigned short gpimapsize;
- unsigned extend_cfg;
- bool is_adp5585;
- bool support_row5;
-#ifdef CONFIG_GPIOLIB
- unsigned char gpiomap[ADP5589_MAXGPIO];
- struct gpio_chip gc;
- struct mutex gpio_lock; /* Protect cached dir, dat_out */
- u8 dat_out[3];
- u8 dir[3];
-#endif
-};
-
-/*
- * ADP5589 / ADP5585 derivative / variant handling
- */
-
-
-/* ADP5589 */
-
-static unsigned char adp5589_bank(unsigned char offset)
-{
- return offset >> 3;
-}
-
-static unsigned char adp5589_bit(unsigned char offset)
-{
- return 1u << (offset & 0x7);
-}
-
-static unsigned char adp5589_reg(unsigned char reg)
-{
- return reg;
-}
-
-static const struct adp_constants const_adp5589 = {
- .maxgpio = ADP5589_MAXGPIO,
- .keymapsize = ADP5589_KEYMAPSIZE,
- .gpi_pin_row_base = ADP5589_GPI_PIN_ROW_BASE,
- .gpi_pin_row_end = ADP5589_GPI_PIN_ROW_END,
- .gpi_pin_col_base = ADP5589_GPI_PIN_COL_BASE,
- .gpi_pin_base = ADP5589_GPI_PIN_BASE,
- .gpi_pin_end = ADP5589_GPI_PIN_END,
- .gpimapsize_max = ADP5589_GPIMAPSIZE_MAX,
- .c4_extend_cfg = 12,
- .max_row_num = ADP5589_MAX_ROW_NUM,
- .max_col_num = ADP5589_MAX_COL_NUM,
- .row_mask = ADP5589_ROW_MASK,
- .col_mask = ADP5589_COL_MASK,
- .col_shift = ADP5589_COL_SHIFT,
- .bank = adp5589_bank,
- .bit = adp5589_bit,
- .reg = adp5589_reg,
-};
-
-/* ADP5585 */
-
-static unsigned char adp5585_bank(unsigned char offset)
-{
- return offset > ADP5585_MAX_ROW_NUM;
-}
-
-static unsigned char adp5585_bit(unsigned char offset)
-{
- return (offset > ADP5585_MAX_ROW_NUM) ?
- 1u << (offset - ADP5585_COL_SHIFT) : 1u << offset;
-}
-
-static const unsigned char adp5585_reg_lut[] = {
- [ADP5589_GPI_STATUS_A] = ADP5585_GPI_STATUS_A,
- [ADP5589_GPI_STATUS_B] = ADP5585_GPI_STATUS_B,
- [ADP5589_RPULL_CONFIG_A] = ADP5585_RPULL_CONFIG_A,
- [ADP5589_RPULL_CONFIG_B] = ADP5585_RPULL_CONFIG_B,
- [ADP5589_RPULL_CONFIG_C] = ADP5585_RPULL_CONFIG_C,
- [ADP5589_RPULL_CONFIG_D] = ADP5585_RPULL_CONFIG_D,
- [ADP5589_GPI_INT_LEVEL_A] = ADP5585_GPI_INT_LEVEL_A,
- [ADP5589_GPI_INT_LEVEL_B] = ADP5585_GPI_INT_LEVEL_B,
- [ADP5589_GPI_EVENT_EN_A] = ADP5585_GPI_EVENT_EN_A,
- [ADP5589_GPI_EVENT_EN_B] = ADP5585_GPI_EVENT_EN_B,
- [ADP5589_GPI_INTERRUPT_EN_A] = ADP5585_GPI_INTERRUPT_EN_A,
- [ADP5589_GPI_INTERRUPT_EN_B] = ADP5585_GPI_INTERRUPT_EN_B,
- [ADP5589_DEBOUNCE_DIS_A] = ADP5585_DEBOUNCE_DIS_A,
- [ADP5589_DEBOUNCE_DIS_B] = ADP5585_DEBOUNCE_DIS_B,
- [ADP5589_GPO_DATA_OUT_A] = ADP5585_GPO_DATA_OUT_A,
- [ADP5589_GPO_DATA_OUT_B] = ADP5585_GPO_DATA_OUT_B,
- [ADP5589_GPO_OUT_MODE_A] = ADP5585_GPO_OUT_MODE_A,
- [ADP5589_GPO_OUT_MODE_B] = ADP5585_GPO_OUT_MODE_B,
- [ADP5589_GPIO_DIRECTION_A] = ADP5585_GPIO_DIRECTION_A,
- [ADP5589_GPIO_DIRECTION_B] = ADP5585_GPIO_DIRECTION_B,
- [ADP5589_RESET1_EVENT_A] = ADP5585_RESET1_EVENT_A,
- [ADP5589_RESET1_EVENT_B] = ADP5585_RESET1_EVENT_B,
- [ADP5589_RESET1_EVENT_C] = ADP5585_RESET1_EVENT_C,
- [ADP5589_RESET2_EVENT_A] = ADP5585_RESET2_EVENT_A,
- [ADP5589_RESET2_EVENT_B] = ADP5585_RESET2_EVENT_B,
- [ADP5589_RESET_CFG] = ADP5585_RESET_CFG,
- [ADP5589_PWM_OFFT_LOW] = ADP5585_PWM_OFFT_LOW,
- [ADP5589_PWM_OFFT_HIGH] = ADP5585_PWM_OFFT_HIGH,
- [ADP5589_PWM_ONT_LOW] = ADP5585_PWM_ONT_LOW,
- [ADP5589_PWM_ONT_HIGH] = ADP5585_PWM_ONT_HIGH,
- [ADP5589_PWM_CFG] = ADP5585_PWM_CFG,
- [ADP5589_LOGIC_1_CFG] = ADP5585_LOGIC_CFG,
- [ADP5589_LOGIC_FF_CFG] = ADP5585_LOGIC_FF_CFG,
- [ADP5589_LOGIC_INT_EVENT_EN] = ADP5585_LOGIC_INT_EVENT_EN,
- [ADP5589_POLL_PTIME_CFG] = ADP5585_POLL_PTIME_CFG,
- [ADP5589_PIN_CONFIG_A] = ADP5585_PIN_CONFIG_A,
- [ADP5589_PIN_CONFIG_B] = ADP5585_PIN_CONFIG_B,
- [ADP5589_PIN_CONFIG_D] = ADP5585_PIN_CONFIG_D,
- [ADP5589_GENERAL_CFG] = ADP5585_GENERAL_CFG,
- [ADP5589_INT_EN] = ADP5585_INT_EN,
-};
-
-static unsigned char adp5585_reg(unsigned char reg)
-{
- return adp5585_reg_lut[reg];
-}
-
-static const struct adp_constants const_adp5585 = {
- .maxgpio = ADP5585_MAXGPIO,
- .keymapsize = ADP5585_KEYMAPSIZE,
- .gpi_pin_row_base = ADP5585_GPI_PIN_ROW_BASE,
- .gpi_pin_row_end = ADP5585_GPI_PIN_ROW_END,
- .gpi_pin_col_base = ADP5585_GPI_PIN_COL_BASE,
- .gpi_pin_base = ADP5585_GPI_PIN_BASE,
- .gpi_pin_end = ADP5585_GPI_PIN_END,
- .gpimapsize_max = ADP5585_GPIMAPSIZE_MAX,
- .c4_extend_cfg = 10,
- .max_row_num = ADP5585_MAX_ROW_NUM,
- .max_col_num = ADP5585_MAX_COL_NUM,
- .row_mask = ADP5585_ROW_MASK,
- .col_mask = ADP5585_COL_MASK,
- .col_shift = ADP5585_COL_SHIFT,
- .bank = adp5585_bank,
- .bit = adp5585_bit,
- .reg = adp5585_reg,
-};
-
-static int adp5589_read(struct i2c_client *client, u8 reg)
-{
- int ret = i2c_smbus_read_byte_data(client, reg);
-
- if (ret < 0)
- dev_err(&client->dev, "Read Error\n");
-
- return ret;
-}
-
-static int adp5589_write(struct i2c_client *client, u8 reg, u8 val)
-{
- return i2c_smbus_write_byte_data(client, reg, val);
-}
-
-#ifdef CONFIG_GPIOLIB
-static int adp5589_gpio_get_value(struct gpio_chip *chip, unsigned off)
-{
- struct adp5589_kpad *kpad = gpiochip_get_data(chip);
- unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
- unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
-
- return !!(adp5589_read(kpad->client,
- kpad->var->reg(ADP5589_GPI_STATUS_A) + bank) &
- bit);
-}
-
-static void adp5589_gpio_set_value(struct gpio_chip *chip,
- unsigned off, int val)
-{
- struct adp5589_kpad *kpad = gpiochip_get_data(chip);
- unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
- unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
-
- mutex_lock(&kpad->gpio_lock);
-
- if (val)
- kpad->dat_out[bank] |= bit;
- else
- kpad->dat_out[bank] &= ~bit;
-
- adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A) +
- bank, kpad->dat_out[bank]);
-
- mutex_unlock(&kpad->gpio_lock);
-}
-
-static int adp5589_gpio_direction_input(struct gpio_chip *chip, unsigned off)
-{
- struct adp5589_kpad *kpad = gpiochip_get_data(chip);
- unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
- unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
- int ret;
-
- mutex_lock(&kpad->gpio_lock);
-
- kpad->dir[bank] &= ~bit;
- ret = adp5589_write(kpad->client,
- kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank,
- kpad->dir[bank]);
-
- mutex_unlock(&kpad->gpio_lock);
-
- return ret;
-}
-
-static int adp5589_gpio_direction_output(struct gpio_chip *chip,
- unsigned off, int val)
-{
- struct adp5589_kpad *kpad = gpiochip_get_data(chip);
- unsigned int bank = kpad->var->bank(kpad->gpiomap[off]);
- unsigned int bit = kpad->var->bit(kpad->gpiomap[off]);
- int ret;
-
- mutex_lock(&kpad->gpio_lock);
-
- kpad->dir[bank] |= bit;
-
- if (val)
- kpad->dat_out[bank] |= bit;
- else
- kpad->dat_out[bank] &= ~bit;
-
- ret = adp5589_write(kpad->client, kpad->var->reg(ADP5589_GPO_DATA_OUT_A)
- + bank, kpad->dat_out[bank]);
- ret |= adp5589_write(kpad->client,
- kpad->var->reg(ADP5589_GPIO_DIRECTION_A) + bank,
- kpad->dir[bank]);
-
- mutex_unlock(&kpad->gpio_lock);
-
- return ret;
-}
-
-static int adp5589_build_gpiomap(struct adp5589_kpad *kpad,
- const struct adp5589_kpad_platform_data *pdata)
-{
- bool pin_used[ADP5589_MAXGPIO];
- int n_unused = 0;
- int i;
-
- memset(pin_used, false, sizeof(pin_used));
-
- for (i = 0; i < kpad->var->maxgpio; i++)
- if (pdata->keypad_en_mask & BIT(i))
- pin_used[i] = true;
-
- for (i = 0; i < kpad->gpimapsize; i++)
- pin_used[kpad->gpimap[i].pin - kpad->var->gpi_pin_base] = true;
-
- if (kpad->extend_cfg & R4_EXTEND_CFG)
- pin_used[4] = true;
-
- if (kpad->extend_cfg & C4_EXTEND_CFG)
- pin_used[kpad->var->c4_extend_cfg] = true;
-
- if (!kpad->support_row5)
- pin_used[5] = true;
-
- for (i = 0; i < kpad->var->maxgpio; i++)
- if (!pin_used[i])
- kpad->gpiomap[n_unused++] = i;
-
- return n_unused;
-}
-
-static int adp5589_gpio_add(struct adp5589_kpad *kpad)
-{
- struct device *dev = &kpad->client->dev;
- const struct adp5589_kpad_platform_data *pdata = dev_get_platdata(dev);
- const struct adp5589_gpio_platform_data *gpio_data = pdata->gpio_data;
- int i, error;
-
- if (!gpio_data)
- return 0;
-
- kpad->gc.parent = dev;
- kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata);
- if (kpad->gc.ngpio == 0) {
- dev_info(dev, "No unused gpios left to export\n");
- return 0;
- }
-
- kpad->gc.direction_input = adp5589_gpio_direction_input;
- kpad->gc.direction_output = adp5589_gpio_direction_output;
- kpad->gc.get = adp5589_gpio_get_value;
- kpad->gc.set = adp5589_gpio_set_value;
- kpad->gc.can_sleep = 1;
-
- kpad->gc.base = gpio_data->gpio_start;
- kpad->gc.label = kpad->client->name;
- kpad->gc.owner = THIS_MODULE;
-
- mutex_init(&kpad->gpio_lock);
-
- error = devm_gpiochip_add_data(dev, &kpad->gc, kpad);
- if (error)
- return error;
-
- for (i = 0; i <= kpad->var->bank(kpad->var->maxgpio); i++) {
- kpad->dat_out[i] = adp5589_read(kpad->client, kpad->var->reg(
- ADP5589_GPO_DATA_OUT_A) + i);
- kpad->dir[i] = adp5589_read(kpad->client, kpad->var->reg(
- ADP5589_GPIO_DIRECTION_A) + i);
- }
-
- return 0;
-}
-#else
-static inline int adp5589_gpio_add(struct adp5589_kpad *kpad)
-{
- return 0;
-}
-#endif
-
-static void adp5589_report_switches(struct adp5589_kpad *kpad,
- int key, int key_val)
-{
- int i;
-
- for (i = 0; i < kpad->gpimapsize; i++) {
- if (key_val == kpad->gpimap[i].pin) {
- input_report_switch(kpad->input,
- kpad->gpimap[i].sw_evt,
- key & KEY_EV_PRESSED);
- break;
- }
- }
-}
-
-static void adp5589_report_events(struct adp5589_kpad *kpad, int ev_cnt)
-{
- int i;
-
- for (i = 0; i < ev_cnt; i++) {
- int key = adp5589_read(kpad->client, ADP5589_5_FIFO_1 + i);
- int key_val = key & KEY_EV_MASK;
-
- if (key_val >= kpad->var->gpi_pin_base &&
- key_val <= kpad->var->gpi_pin_end) {
- adp5589_report_switches(kpad, key, key_val);
- } else {
- input_report_key(kpad->input,
- kpad->keycode[key_val - 1],
- key & KEY_EV_PRESSED);
- }
- }
-}
-
-static irqreturn_t adp5589_irq(int irq, void *handle)
-{
- struct adp5589_kpad *kpad = handle;
- struct i2c_client *client = kpad->client;
- int status, ev_cnt;
-
- status = adp5589_read(client, ADP5589_5_INT_STATUS);
-
- if (status & OVRFLOW_INT) /* Unlikely and should never happen */
- dev_err(&client->dev, "Event Overflow Error\n");
-
- if (status & EVENT_INT) {
- ev_cnt = adp5589_read(client, ADP5589_5_STATUS) & KEC;
- if (ev_cnt) {
- adp5589_report_events(kpad, ev_cnt);
- input_sync(kpad->input);
- }
- }
-
- adp5589_write(client, ADP5589_5_INT_STATUS, status); /* Status is W1C */
-
- return IRQ_HANDLED;
-}
-
-static int adp5589_get_evcode(struct adp5589_kpad *kpad, unsigned short key)
-{
- int i;
-
- for (i = 0; i < kpad->var->keymapsize; i++)
- if (key == kpad->keycode[i])
- return (i + 1) | KEY_EV_PRESSED;
-
- dev_err(&kpad->client->dev, "RESET/UNLOCK key not in keycode map\n");
-
- return -EINVAL;
-}
-
-static int adp5589_setup(struct adp5589_kpad *kpad)
-{
- struct i2c_client *client = kpad->client;
- const struct adp5589_kpad_platform_data *pdata =
- dev_get_platdata(&client->dev);
- u8 (*reg) (u8) = kpad->var->reg;
- unsigned char evt_mode1 = 0, evt_mode2 = 0, evt_mode3 = 0;
- unsigned char pull_mask = 0;
- int i, ret;
-
- ret = adp5589_write(client, reg(ADP5589_PIN_CONFIG_A),
- pdata->keypad_en_mask & kpad->var->row_mask);
- ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_B),
- (pdata->keypad_en_mask >> kpad->var->col_shift) &
- kpad->var->col_mask);
-
- if (!kpad->is_adp5585)
- ret |= adp5589_write(client, ADP5589_PIN_CONFIG_C,
- (pdata->keypad_en_mask >> 16) & 0xFF);
-
- if (!kpad->is_adp5585 && pdata->en_keylock) {
- ret |= adp5589_write(client, ADP5589_UNLOCK1,
- pdata->unlock_key1);
- ret |= adp5589_write(client, ADP5589_UNLOCK2,
- pdata->unlock_key2);
- ret |= adp5589_write(client, ADP5589_UNLOCK_TIMERS,
- pdata->unlock_timer & LTIME_MASK);
- ret |= adp5589_write(client, ADP5589_LOCK_CFG, LOCK_EN);
- }
-
- for (i = 0; i < KEYP_MAX_EVENT; i++)
- ret |= adp5589_read(client, ADP5589_5_FIFO_1 + i);
-
- for (i = 0; i < pdata->gpimapsize; i++) {
- unsigned short pin = pdata->gpimap[i].pin;
-
- if (pin <= kpad->var->gpi_pin_row_end) {
- evt_mode1 |= BIT(pin - kpad->var->gpi_pin_row_base);
- } else {
- evt_mode2 |=
- BIT(pin - kpad->var->gpi_pin_col_base) & 0xFF;
- if (!kpad->is_adp5585)
- evt_mode3 |=
- BIT(pin - kpad->var->gpi_pin_col_base) >> 8;
- }
- }
-
- if (pdata->gpimapsize) {
- ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_A),
- evt_mode1);
- ret |= adp5589_write(client, reg(ADP5589_GPI_EVENT_EN_B),
- evt_mode2);
- if (!kpad->is_adp5585)
- ret |= adp5589_write(client,
- reg(ADP5589_GPI_EVENT_EN_C),
- evt_mode3);
- }
-
- if (pdata->pull_dis_mask & pdata->pullup_en_100k &
- pdata->pullup_en_300k & pdata->pulldown_en_300k)
- dev_warn(&client->dev, "Conflicting pull resistor config\n");
-
- for (i = 0; i <= kpad->var->max_row_num; i++) {
- unsigned int val = 0, bit = BIT(i);
- if (pdata->pullup_en_300k & bit)
- val = 0;
- else if (pdata->pulldown_en_300k & bit)
- val = 1;
- else if (pdata->pullup_en_100k & bit)
- val = 2;
- else if (pdata->pull_dis_mask & bit)
- val = 3;
-
- pull_mask |= val << (2 * (i & 0x3));
-
- if (i % 4 == 3 || i == kpad->var->max_row_num) {
- ret |= adp5589_write(client, reg(ADP5585_RPULL_CONFIG_A)
- + (i >> 2), pull_mask);
- pull_mask = 0;
- }
- }
-
- for (i = 0; i <= kpad->var->max_col_num; i++) {
- unsigned int val = 0, bit = BIT(i + kpad->var->col_shift);
- if (pdata->pullup_en_300k & bit)
- val = 0;
- else if (pdata->pulldown_en_300k & bit)
- val = 1;
- else if (pdata->pullup_en_100k & bit)
- val = 2;
- else if (pdata->pull_dis_mask & bit)
- val = 3;
-
- pull_mask |= val << (2 * (i & 0x3));
-
- if (i % 4 == 3 || i == kpad->var->max_col_num) {
- ret |= adp5589_write(client,
- reg(ADP5585_RPULL_CONFIG_C) +
- (i >> 2), pull_mask);
- pull_mask = 0;
- }
- }
-
- if (pdata->reset1_key_1 && pdata->reset1_key_2 && pdata->reset1_key_3) {
- ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_A),
- adp5589_get_evcode(kpad,
- pdata->reset1_key_1));
- ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_B),
- adp5589_get_evcode(kpad,
- pdata->reset1_key_2));
- ret |= adp5589_write(client, reg(ADP5589_RESET1_EVENT_C),
- adp5589_get_evcode(kpad,
- pdata->reset1_key_3));
- kpad->extend_cfg |= R4_EXTEND_CFG;
- }
-
- if (pdata->reset2_key_1 && pdata->reset2_key_2) {
- ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_A),
- adp5589_get_evcode(kpad,
- pdata->reset2_key_1));
- ret |= adp5589_write(client, reg(ADP5589_RESET2_EVENT_B),
- adp5589_get_evcode(kpad,
- pdata->reset2_key_2));
- kpad->extend_cfg |= C4_EXTEND_CFG;
- }
-
- if (kpad->extend_cfg) {
- ret |= adp5589_write(client, reg(ADP5589_RESET_CFG),
- pdata->reset_cfg);
- ret |= adp5589_write(client, reg(ADP5589_PIN_CONFIG_D),
- kpad->extend_cfg);
- }
-
- ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_A),
- pdata->debounce_dis_mask & kpad->var->row_mask);
-
- ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_B),
- (pdata->debounce_dis_mask >> kpad->var->col_shift)
- & kpad->var->col_mask);
-
- if (!kpad->is_adp5585)
- ret |= adp5589_write(client, reg(ADP5589_DEBOUNCE_DIS_C),
- (pdata->debounce_dis_mask >> 16) & 0xFF);
-
- ret |= adp5589_write(client, reg(ADP5589_POLL_PTIME_CFG),
- pdata->scan_cycle_time & PTIME_MASK);
- ret |= adp5589_write(client, ADP5589_5_INT_STATUS,
- (kpad->is_adp5585 ? 0 : LOGIC2_INT) |
- LOGIC1_INT | OVRFLOW_INT |
- (kpad->is_adp5585 ? 0 : LOCK_INT) |
- GPI_INT | EVENT_INT); /* Status is W1C */
-
- ret |= adp5589_write(client, reg(ADP5589_GENERAL_CFG),
- INT_CFG | OSC_EN | CORE_CLK(3));
- ret |= adp5589_write(client, reg(ADP5589_INT_EN),
- OVRFLOW_IEN | GPI_IEN | EVENT_IEN);
-
- if (ret < 0) {
- dev_err(&client->dev, "Write Error\n");
- return ret;
- }
-
- return 0;
-}
-
-static void adp5589_report_switch_state(struct adp5589_kpad *kpad)
-{
- int gpi_stat_tmp, pin_loc;
- int i;
- int gpi_stat1 = adp5589_read(kpad->client,
- kpad->var->reg(ADP5589_GPI_STATUS_A));
- int gpi_stat2 = adp5589_read(kpad->client,
- kpad->var->reg(ADP5589_GPI_STATUS_B));
- int gpi_stat3 = !kpad->is_adp5585 ?
- adp5589_read(kpad->client, ADP5589_GPI_STATUS_C) : 0;
-
- for (i = 0; i < kpad->gpimapsize; i++) {
- unsigned short pin = kpad->gpimap[i].pin;
-
- if (pin <= kpad->var->gpi_pin_row_end) {
- gpi_stat_tmp = gpi_stat1;
- pin_loc = pin - kpad->var->gpi_pin_row_base;
- } else if ((pin - kpad->var->gpi_pin_col_base) < 8) {
- gpi_stat_tmp = gpi_stat2;
- pin_loc = pin - kpad->var->gpi_pin_col_base;
- } else {
- gpi_stat_tmp = gpi_stat3;
- pin_loc = pin - kpad->var->gpi_pin_col_base - 8;
- }
-
- if (gpi_stat_tmp < 0) {
- dev_err(&kpad->client->dev,
- "Can't read GPIO_DAT_STAT switch %d, default to OFF\n",
- pin);
- gpi_stat_tmp = 0;
- }
-
- input_report_switch(kpad->input,
- kpad->gpimap[i].sw_evt,
- !(gpi_stat_tmp & BIT(pin_loc)));
- }
-
- input_sync(kpad->input);
-}
-
-static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid)
-{
- struct i2c_client *client = kpad->client;
- const struct adp5589_kpad_platform_data *pdata =
- dev_get_platdata(&client->dev);
- struct input_dev *input;
- unsigned int i;
- int error;
-
- if (!((pdata->keypad_en_mask & kpad->var->row_mask) &&
- (pdata->keypad_en_mask >> kpad->var->col_shift)) ||
- !pdata->keymap) {
- dev_err(&client->dev, "no rows, cols or keymap from pdata\n");
- return -EINVAL;
- }
-
- if (pdata->keymapsize != kpad->var->keymapsize) {
- dev_err(&client->dev, "invalid keymapsize\n");
- return -EINVAL;
- }
-
- if (!pdata->gpimap && pdata->gpimapsize) {
- dev_err(&client->dev, "invalid gpimap from pdata\n");
- return -EINVAL;
- }
-
- if (pdata->gpimapsize > kpad->var->gpimapsize_max) {
- dev_err(&client->dev, "invalid gpimapsize\n");
- return -EINVAL;
- }
-
- for (i = 0; i < pdata->gpimapsize; i++) {
- unsigned short pin = pdata->gpimap[i].pin;
-
- if (pin < kpad->var->gpi_pin_base ||
- pin > kpad->var->gpi_pin_end) {
- dev_err(&client->dev, "invalid gpi pin data\n");
- return -EINVAL;
- }
-
- if (BIT(pin - kpad->var->gpi_pin_row_base) &
- pdata->keypad_en_mask) {
- dev_err(&client->dev, "invalid gpi row/col data\n");
- return -EINVAL;
- }
- }
-
- if (!client->irq) {
- dev_err(&client->dev, "no IRQ?\n");
- return -EINVAL;
- }
-
- input = devm_input_allocate_device(&client->dev);
- if (!input)
- return -ENOMEM;
-
- kpad->input = input;
-
- input->name = client->name;
- input->phys = "adp5589-keys/input0";
- input->dev.parent = &client->dev;
-
- input_set_drvdata(input, kpad);
-
- input->id.bustype = BUS_I2C;
- input->id.vendor = 0x0001;
- input->id.product = 0x0001;
- input->id.version = revid;
-
- input->keycodesize = sizeof(kpad->keycode[0]);
- input->keycodemax = pdata->keymapsize;
- input->keycode = kpad->keycode;
-
- memcpy(kpad->keycode, pdata->keymap,
- pdata->keymapsize * input->keycodesize);
-
- kpad->gpimap = pdata->gpimap;
- kpad->gpimapsize = pdata->gpimapsize;
-
- /* setup input device */
- __set_bit(EV_KEY, input->evbit);
-
- if (pdata->repeat)
- __set_bit(EV_REP, input->evbit);
-
- for (i = 0; i < input->keycodemax; i++)
- if (kpad->keycode[i] <= KEY_MAX)
- __set_bit(kpad->keycode[i], input->keybit);
- __clear_bit(KEY_RESERVED, input->keybit);
-
- if (kpad->gpimapsize)
- __set_bit(EV_SW, input->evbit);
- for (i = 0; i < kpad->gpimapsize; i++)
- __set_bit(kpad->gpimap[i].sw_evt, input->swbit);
-
- error = input_register_device(input);
- if (error) {
- dev_err(&client->dev, "unable to register input device\n");
- return error;
- }
-
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, adp5589_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->dev.driver->name, kpad);
- if (error) {
- dev_err(&client->dev, "unable to request irq %d\n", client->irq);
- return error;
- }
-
- return 0;
-}
-
-static void adp5589_clear_config(void *data)
-{
- struct i2c_client *client = data;
- struct adp5589_kpad *kpad = i2c_get_clientdata(client);
-
- adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0);
-}
-
-static int adp5589_probe(struct i2c_client *client)
-{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
- struct adp5589_kpad *kpad;
- const struct adp5589_kpad_platform_data *pdata =
- dev_get_platdata(&client->dev);
- unsigned int revid;
- int error, ret;
-
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
- return -EIO;
- }
-
- if (!pdata) {
- dev_err(&client->dev, "no platform data?\n");
- return -EINVAL;
- }
-
- kpad = devm_kzalloc(&client->dev, sizeof(*kpad), GFP_KERNEL);
- if (!kpad)
- return -ENOMEM;
-
- kpad->client = client;
-
- switch (id->driver_data) {
- case ADP5585_02:
- kpad->support_row5 = true;
- fallthrough;
- case ADP5585_01:
- kpad->is_adp5585 = true;
- kpad->var = &const_adp5585;
- break;
- case ADP5589:
- kpad->support_row5 = true;
- kpad->var = &const_adp5589;
- break;
- }
-
- error = devm_add_action_or_reset(&client->dev, adp5589_clear_config,
- client);
- if (error)
- return error;
-
- ret = adp5589_read(client, ADP5589_5_ID);
- if (ret < 0)
- return ret;
-
- revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK;
-
- if (pdata->keymapsize) {
- error = adp5589_keypad_add(kpad, revid);
- if (error)
- return error;
- }
-
- error = adp5589_setup(kpad);
- if (error)
- return error;
-
- if (kpad->gpimapsize)
- adp5589_report_switch_state(kpad);
-
- error = adp5589_gpio_add(kpad);
- if (error)
- return error;
-
- i2c_set_clientdata(client, kpad);
-
- dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq);
- return 0;
-}
-
-static int adp5589_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adp5589_kpad *kpad = i2c_get_clientdata(client);
-
- if (kpad->input)
- disable_irq(client->irq);
-
- return 0;
-}
-
-static int adp5589_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adp5589_kpad *kpad = i2c_get_clientdata(client);
-
- if (kpad->input)
- enable_irq(client->irq);
-
- return 0;
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(adp5589_dev_pm_ops, adp5589_suspend, adp5589_resume);
-
-static const struct i2c_device_id adp5589_id[] = {
- {"adp5589-keys", ADP5589},
- {"adp5585-keys", ADP5585_01},
- {"adp5585-02-keys", ADP5585_02}, /* Adds ROW5 to ADP5585 */
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, adp5589_id);
-
-static struct i2c_driver adp5589_driver = {
- .driver = {
- .name = KBUILD_MODNAME,
- .pm = pm_sleep_ptr(&adp5589_dev_pm_ops),
- },
- .probe = adp5589_probe,
- .id_table = adp5589_id,
-};
-
-module_i2c_driver(adp5589_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
-MODULE_DESCRIPTION("ADP5589/ADP5585 Keypad driver");
diff --git a/drivers/input/keyboard/applespi.c b/drivers/input/keyboard/applespi.c
index cf25177b4830..b5ff71cd5a70 100644
--- a/drivers/input/keyboard/applespi.c
+++ b/drivers/input/keyboard/applespi.c
@@ -57,7 +57,7 @@
#include <linux/workqueue.h>
#include <asm/barrier.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define CREATE_TRACE_POINTS
#include "applespi.h"
@@ -717,9 +717,7 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi);
static void applespi_msg_complete(struct applespi_data *applespi,
bool is_write_msg, bool is_read_compl)
{
- unsigned long flags;
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
if (is_read_compl)
applespi->read_active = false;
@@ -733,8 +731,6 @@ static void applespi_msg_complete(struct applespi_data *applespi,
applespi->cmd_msg_queued = 0;
applespi_send_cmd_msg(applespi);
}
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
}
static void applespi_async_write_complete(void *context)
@@ -888,33 +884,22 @@ static int applespi_send_cmd_msg(struct applespi_data *applespi)
static void applespi_init(struct applespi_data *applespi, bool is_resume)
{
- unsigned long flags;
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
if (is_resume)
applespi->want_mt_init_cmd = true;
else
applespi->want_tp_info_cmd = true;
applespi_send_cmd_msg(applespi);
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
}
static int applespi_set_capsl_led(struct applespi_data *applespi,
bool capslock_on)
{
- unsigned long flags;
- int sts;
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
applespi->want_cl_led_on = capslock_on;
- sts = applespi_send_cmd_msg(applespi);
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
-
- return sts;
+ return applespi_send_cmd_msg(applespi);
}
static void applespi_set_bl_level(struct led_classdev *led_cdev,
@@ -922,9 +907,8 @@ static void applespi_set_bl_level(struct led_classdev *led_cdev,
{
struct applespi_data *applespi =
container_of(led_cdev, struct applespi_data, backlight_info);
- unsigned long flags;
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
if (value == 0) {
applespi->want_bl_level = value;
@@ -940,8 +924,6 @@ static void applespi_set_bl_level(struct led_classdev *led_cdev,
}
applespi_send_cmd_msg(applespi);
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
}
static int applespi_event(struct input_dev *dev, unsigned int type,
@@ -1007,7 +989,6 @@ static const struct file_operations applespi_tp_dim_fops = {
.owner = THIS_MODULE,
.open = applespi_tp_dim_open,
.read = applespi_tp_dim_read,
- .llseek = no_llseek,
};
static void report_finger_data(struct input_dev *input, int slot,
@@ -1428,9 +1409,7 @@ static void applespi_got_data(struct applespi_data *applespi)
/* process packet header */
if (!applespi_verify_crc(applespi, applespi->rx_buffer,
APPLESPI_PACKET_SIZE)) {
- unsigned long flags;
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
if (applespi->drain) {
applespi->read_active = false;
@@ -1439,8 +1418,6 @@ static void applespi_got_data(struct applespi_data *applespi)
wake_up_all(&applespi->drain_complete);
}
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
-
return;
}
@@ -1573,11 +1550,10 @@ static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context)
{
struct applespi_data *applespi = context;
int sts;
- unsigned long flags;
trace_applespi_irq_received(ET_RD_IRQ, PT_READ);
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
if (!applespi->suspended) {
sts = applespi_async(applespi, &applespi->rd_m,
@@ -1590,8 +1566,6 @@ static u32 applespi_notify(acpi_handle gpe_device, u32 gpe, void *context)
applespi->read_active = true;
}
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
-
return ACPI_INTERRUPT_HANDLED;
}
@@ -1819,29 +1793,21 @@ static int applespi_probe(struct spi_device *spi)
static void applespi_drain_writes(struct applespi_data *applespi)
{
- unsigned long flags;
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
applespi->drain = true;
wait_event_lock_irq(applespi->drain_complete, !applespi->write_active,
applespi->cmd_msg_lock);
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
}
static void applespi_drain_reads(struct applespi_data *applespi)
{
- unsigned long flags;
-
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
+ guard(spinlock_irqsave)(&applespi->cmd_msg_lock);
wait_event_lock_irq(applespi->drain_complete, !applespi->read_active,
applespi->cmd_msg_lock);
applespi->suspended = true;
-
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
}
static void applespi_remove(struct spi_device *spi)
@@ -1908,21 +1874,18 @@ static int applespi_resume(struct device *dev)
struct spi_device *spi = to_spi_device(dev);
struct applespi_data *applespi = spi_get_drvdata(spi);
acpi_status acpi_sts;
- unsigned long flags;
/* ensure our flags and state reflect a newly resumed device */
- spin_lock_irqsave(&applespi->cmd_msg_lock, flags);
-
- applespi->drain = false;
- applespi->have_cl_led_on = false;
- applespi->have_bl_level = 0;
- applespi->cmd_msg_queued = 0;
- applespi->read_active = false;
- applespi->write_active = false;
-
- applespi->suspended = false;
+ scoped_guard(spinlock_irqsave, &applespi->cmd_msg_lock) {
+ applespi->drain = false;
+ applespi->have_cl_led_on = false;
+ applespi->have_bl_level = 0;
+ applespi->cmd_msg_queued = 0;
+ applespi->read_active = false;
+ applespi->write_active = false;
- spin_unlock_irqrestore(&applespi->cmd_msg_lock, flags);
+ applespi->suspended = false;
+ }
/* switch on the SPI interface */
applespi_enable_spi(applespi);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 7f67f9f2946b..6c999d89ee4b 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -37,7 +37,7 @@ static int atkbd_set = 2;
module_param_named(set, atkbd_set, int, 0);
MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)");
-#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) || defined(__loongarch__)
static bool atkbd_reset;
#else
static bool atkbd_reset = true;
@@ -84,12 +84,12 @@ static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = {
#include "hpps2atkbd.h" /* include the keyboard scancodes */
#else
- 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
- 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
- 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
- 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
- 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
- 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
+ 0, 67, 65, 63, 61, 59, 60, 88,183, 68, 66, 64, 62, 15, 41,117,
+ 184, 56, 42, 93, 29, 16, 2, 0,185, 0, 44, 31, 30, 17, 3, 0,
+ 186, 46, 45, 32, 18, 5, 4, 95,187, 57, 47, 33, 20, 19, 6,183,
+ 188, 49, 48, 35, 34, 21, 7,184,189, 0, 50, 36, 22, 8, 9,185,
+ 190, 51, 37, 23, 24, 11, 10, 0,191, 52, 53, 38, 39, 25, 12, 0,
+ 192, 89, 40, 0, 26, 13, 0,193, 58, 54, 28, 27, 0, 43, 0,194,
0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
@@ -639,7 +639,7 @@ static void atkbd_event_work(struct work_struct *work)
{
struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work);
- mutex_lock(&atkbd->mutex);
+ guard(mutex)(&atkbd->mutex);
if (!atkbd->enabled) {
/*
@@ -657,8 +657,6 @@ static void atkbd_event_work(struct work_struct *work)
if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask))
atkbd_set_repeat_rate(atkbd);
}
-
- mutex_unlock(&atkbd->mutex);
}
/*
@@ -715,9 +713,9 @@ static int atkbd_event(struct input_dev *dev,
static inline void atkbd_enable(struct atkbd *atkbd)
{
- serio_pause_rx(atkbd->ps2dev.serio);
+ guard(serio_pause_rx)(atkbd->ps2dev.serio);
+
atkbd->enabled = true;
- serio_continue_rx(atkbd->ps2dev.serio);
}
/*
@@ -727,9 +725,9 @@ static inline void atkbd_enable(struct atkbd *atkbd)
static inline void atkbd_disable(struct atkbd *atkbd)
{
- serio_pause_rx(atkbd->ps2dev.serio);
+ guard(serio_pause_rx)(atkbd->ps2dev.serio);
+
atkbd->enabled = false;
- serio_continue_rx(atkbd->ps2dev.serio);
}
static int atkbd_activate(struct atkbd *atkbd)
@@ -1193,8 +1191,8 @@ static void atkbd_set_device_attrs(struct atkbd *atkbd)
"AT %s Set %d keyboard",
atkbd->translated ? "Translated" : "Raw", atkbd->set);
- snprintf(atkbd->phys, sizeof(atkbd->phys),
- "%s/input0", atkbd->ps2dev.serio->phys);
+ scnprintf(atkbd->phys, sizeof(atkbd->phys),
+ "%s/input0", atkbd->ps2dev.serio->phys);
input_dev->name = atkbd->name;
input_dev->phys = atkbd->phys;
@@ -1279,7 +1277,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *dev;
int err = -ENOMEM;
- atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL);
+ atkbd = kzalloc(sizeof(*atkbd), GFP_KERNEL);
dev = input_allocate_device();
if (!atkbd || !dev)
goto fail1;
@@ -1361,7 +1359,7 @@ static int atkbd_reconnect(struct serio *serio)
{
struct atkbd *atkbd = atkbd_from_serio(serio);
struct serio_driver *drv = serio->drv;
- int retval = -1;
+ int error;
if (!atkbd || !drv) {
dev_dbg(&serio->dev,
@@ -1369,16 +1367,17 @@ static int atkbd_reconnect(struct serio *serio)
return -1;
}
- mutex_lock(&atkbd->mutex);
+ guard(mutex)(&atkbd->mutex);
atkbd_disable(atkbd);
if (atkbd->write) {
- if (atkbd_probe(atkbd))
- goto out;
+ error = atkbd_probe(atkbd);
+ if (error)
+ return error;
if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra))
- goto out;
+ return -EIO;
/*
* Restore LED state and repeat rate. While input core
@@ -1404,11 +1403,7 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->write)
atkbd_activate(atkbd);
- retval = 0;
-
- out:
- mutex_unlock(&atkbd->mutex);
- return retval;
+ return 0;
}
static const struct serio_device_id atkbd_serio_ids[] = {
@@ -1465,17 +1460,15 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t
struct atkbd *atkbd = atkbd_from_serio(serio);
int retval;
- retval = mutex_lock_interruptible(&atkbd->mutex);
- if (retval)
- return retval;
+ scoped_guard(mutex_intr, &atkbd->mutex) {
+ atkbd_disable(atkbd);
+ retval = handler(atkbd, buf, count);
+ atkbd_enable(atkbd);
- atkbd_disable(atkbd);
- retval = handler(atkbd, buf, count);
- atkbd_enable(atkbd);
-
- mutex_unlock(&atkbd->mutex);
+ return retval;
+ }
- return retval;
+ return -EINTR;
}
static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf)
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 52fba9ee7c1d..0c17cbaa3d27 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -86,7 +86,6 @@ struct cap11xx_priv {
struct device *dev;
struct input_dev *idev;
const struct cap11xx_hw_model *model;
- u8 id;
struct cap11xx_led *leds;
int num_leds;
@@ -104,27 +103,10 @@ struct cap11xx_hw_model {
u8 product_id;
unsigned int num_channels;
unsigned int num_leds;
- bool no_gain;
-};
-
-enum {
- CAP1106,
- CAP1126,
- CAP1188,
- CAP1203,
- CAP1206,
- CAP1293,
- CAP1298
-};
-
-static const struct cap11xx_hw_model cap11xx_devices[] = {
- [CAP1106] = { .product_id = 0x55, .num_channels = 6, .num_leds = 0, .no_gain = false },
- [CAP1126] = { .product_id = 0x53, .num_channels = 6, .num_leds = 2, .no_gain = false },
- [CAP1188] = { .product_id = 0x50, .num_channels = 8, .num_leds = 8, .no_gain = false },
- [CAP1203] = { .product_id = 0x6d, .num_channels = 3, .num_leds = 0, .no_gain = true },
- [CAP1206] = { .product_id = 0x67, .num_channels = 6, .num_leds = 0, .no_gain = true },
- [CAP1293] = { .product_id = 0x6f, .num_channels = 3, .num_leds = 0, .no_gain = false },
- [CAP1298] = { .product_id = 0x71, .num_channels = 8, .num_leds = 0, .no_gain = false },
+ bool has_gain;
+ bool has_irq_config;
+ bool has_sensitivity_control;
+ bool has_signal_guard;
};
static const struct reg_default cap11xx_reg_defaults[] = {
@@ -224,7 +206,7 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
}
if (!of_property_read_u32(node, "microchip,sensor-gain", &u32_val)) {
- if (priv->model->no_gain) {
+ if (!priv->model->has_gain) {
dev_warn(dev,
"This model doesn't support 'sensor-gain'\n");
} else if (is_power_of_2(u32_val) && u32_val <= 8) {
@@ -243,9 +225,7 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
}
if (of_property_read_bool(node, "microchip,irq-active-high")) {
- if (priv->id == CAP1106 ||
- priv->id == CAP1126 ||
- priv->id == CAP1188) {
+ if (priv->model->has_irq_config) {
error = regmap_update_bits(priv->regmap,
CAP11XX_REG_CONFIG2,
CAP11XX_REG_CONFIG2_ALT_POL,
@@ -296,7 +276,7 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
if (!of_property_read_u32_array(node, "microchip,calib-sensitivity",
priv->calib_sensitivities,
priv->model->num_channels)) {
- if (priv->id == CAP1293 || priv->id == CAP1298) {
+ if (priv->model->has_sensitivity_control) {
for (i = 0; i < priv->model->num_channels; i++) {
if (!is_power_of_2(priv->calib_sensitivities[i]) ||
priv->calib_sensitivities[i] > 4) {
@@ -311,7 +291,7 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
if (error)
return error;
- if (priv->id == CAP1298) {
+ if (priv->model->num_channels > 4) {
error = cap11xx_write_calib_sens_config_2(priv);
if (error)
return error;
@@ -333,7 +313,7 @@ static int cap11xx_init_keys(struct cap11xx_priv *priv)
}
if (priv->signal_guard_inputs_mask) {
- if (priv->id == CAP1293 || priv->id == CAP1298) {
+ if (priv->model->has_signal_guard) {
error = regmap_write(priv->regmap,
CAP11XX_REG_SIGNAL_GUARD_ENABLE,
priv->signal_guard_inputs_mask);
@@ -436,7 +416,7 @@ static int cap11xx_led_set(struct led_classdev *cdev,
static int cap11xx_init_leds(struct device *dev,
struct cap11xx_priv *priv, int num_leds)
{
- struct device_node *node = dev->of_node, *child;
+ struct device_node *node = dev->of_node;
struct cap11xx_led *led;
int cnt = of_get_child_count(node);
int error;
@@ -465,7 +445,7 @@ static int cap11xx_init_leds(struct device *dev,
if (error)
return error;
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
u32 reg;
led->cdev.name =
@@ -478,19 +458,15 @@ static int cap11xx_init_leds(struct device *dev,
led->cdev.brightness = LED_OFF;
error = of_property_read_u32(child, "reg", &reg);
- if (error != 0 || reg >= num_leds) {
- of_node_put(child);
+ if (error != 0 || reg >= num_leds)
return -EINVAL;
- }
led->reg = reg;
led->priv = priv;
error = devm_led_classdev_register(dev, &led->cdev);
- if (error) {
- of_node_put(child);
+ if (error)
return error;
- }
priv->num_leds++;
led++;
@@ -508,20 +484,16 @@ static int cap11xx_init_leds(struct device *dev,
static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(i2c_client);
+ const struct i2c_device_id *id;
+ const struct cap11xx_hw_model *cap;
struct device *dev = &i2c_client->dev;
struct cap11xx_priv *priv;
- const struct cap11xx_hw_model *cap;
int i, error;
unsigned int val, rev;
- if (id->driver_data >= ARRAY_SIZE(cap11xx_devices)) {
- dev_err(dev, "Invalid device ID %lu\n", id->driver_data);
- return -EINVAL;
- }
-
- cap = &cap11xx_devices[id->driver_data];
- if (!cap || !cap->num_channels) {
+ id = i2c_client_get_device_id(i2c_client);
+ cap = i2c_get_match_data(i2c_client);
+ if (!id || !cap || !cap->num_channels) {
dev_err(dev, "Invalid device configuration\n");
return -EINVAL;
}
@@ -566,7 +538,6 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
id->name, rev);
priv->model = cap;
- priv->id = id->driver_data;
dev_info(dev, "CAP11XX device detected, model %s, revision 0x%02x\n",
id->name, rev);
@@ -627,27 +598,67 @@ static int cap11xx_i2c_probe(struct i2c_client *i2c_client)
return 0;
}
+static const struct cap11xx_hw_model cap1106_model = {
+ .product_id = 0x55, .num_channels = 6, .num_leds = 0,
+ .has_gain = true,
+ .has_irq_config = true,
+};
+
+static const struct cap11xx_hw_model cap1126_model = {
+ .product_id = 0x53, .num_channels = 6, .num_leds = 2,
+ .has_gain = true,
+ .has_irq_config = true,
+};
+
+static const struct cap11xx_hw_model cap1188_model = {
+ .product_id = 0x50, .num_channels = 8, .num_leds = 8,
+ .has_gain = true,
+ .has_irq_config = true,
+};
+
+static const struct cap11xx_hw_model cap1203_model = {
+ .product_id = 0x6d, .num_channels = 3, .num_leds = 0,
+};
+
+static const struct cap11xx_hw_model cap1206_model = {
+ .product_id = 0x67, .num_channels = 6, .num_leds = 0,
+};
+
+static const struct cap11xx_hw_model cap1293_model = {
+ .product_id = 0x6f, .num_channels = 3, .num_leds = 0,
+ .has_gain = true,
+ .has_sensitivity_control = true,
+ .has_signal_guard = true,
+};
+
+static const struct cap11xx_hw_model cap1298_model = {
+ .product_id = 0x71, .num_channels = 8, .num_leds = 0,
+ .has_gain = true,
+ .has_sensitivity_control = true,
+ .has_signal_guard = true,
+};
+
static const struct of_device_id cap11xx_dt_ids[] = {
- { .compatible = "microchip,cap1106", },
- { .compatible = "microchip,cap1126", },
- { .compatible = "microchip,cap1188", },
- { .compatible = "microchip,cap1203", },
- { .compatible = "microchip,cap1206", },
- { .compatible = "microchip,cap1293", },
- { .compatible = "microchip,cap1298", },
- {}
+ { .compatible = "microchip,cap1106", .data = &cap1106_model },
+ { .compatible = "microchip,cap1126", .data = &cap1126_model },
+ { .compatible = "microchip,cap1188", .data = &cap1188_model },
+ { .compatible = "microchip,cap1203", .data = &cap1203_model },
+ { .compatible = "microchip,cap1206", .data = &cap1206_model },
+ { .compatible = "microchip,cap1293", .data = &cap1293_model },
+ { .compatible = "microchip,cap1298", .data = &cap1298_model },
+ { }
};
MODULE_DEVICE_TABLE(of, cap11xx_dt_ids);
static const struct i2c_device_id cap11xx_i2c_ids[] = {
- { "cap1106", CAP1106 },
- { "cap1126", CAP1126 },
- { "cap1188", CAP1188 },
- { "cap1203", CAP1203 },
- { "cap1206", CAP1206 },
- { "cap1293", CAP1293 },
- { "cap1298", CAP1298 },
- {}
+ { "cap1106", (kernel_ulong_t)&cap1106_model },
+ { "cap1126", (kernel_ulong_t)&cap1126_model },
+ { "cap1188", (kernel_ulong_t)&cap1188_model },
+ { "cap1203", (kernel_ulong_t)&cap1203_model },
+ { "cap1206", (kernel_ulong_t)&cap1206_model },
+ { "cap1293", (kernel_ulong_t)&cap1293_model },
+ { "cap1298", (kernel_ulong_t)&cap1298_model },
+ { }
};
MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids);
diff --git a/drivers/input/keyboard/cros_ec_keyb.c b/drivers/input/keyboard/cros_ec_keyb.c
index 12eb9df180ee..1c6b0461dc35 100644
--- a/drivers/input/keyboard/cros_ec_keyb.c
+++ b/drivers/input/keyboard/cros_ec_keyb.c
@@ -27,7 +27,7 @@
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/**
* struct cros_ec_keyb - Structure representing EC keyboard device
@@ -261,6 +261,12 @@ static int cros_ec_keyb_work(struct notifier_block *nb,
case EC_MKBP_EVENT_KEY_MATRIX:
pm_wakeup_event(ckdev->dev, 0);
+ if (!ckdev->idev) {
+ dev_warn_once(ckdev->dev,
+ "Unexpected key matrix event\n");
+ return NOTIFY_OK;
+ }
+
if (ckdev->ec->event_size != ckdev->cols) {
dev_err(ckdev->dev,
"Discarded incomplete key matrix event.\n");
@@ -705,6 +711,12 @@ static int cros_ec_keyb_probe(struct platform_device *pdev)
ec = dev_get_drvdata(pdev->dev.parent);
if (!ec)
return -EPROBE_DEFER;
+ /*
+ * Even if the cros_ec_device pointer is available, still need to check
+ * if the device is fully registered before using it.
+ */
+ if (!cros_ec_device_registered(ec))
+ return -EPROBE_DEFER;
ckdev = devm_kzalloc(dev, sizeof(*ckdev), GFP_KERNEL);
if (!ckdev)
@@ -770,7 +782,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(cros_ec_keyb_pm_ops, NULL, cros_ec_keyb_resume);
static struct platform_driver cros_ec_keyb_driver = {
.probe = cros_ec_keyb_probe,
- .remove_new = cros_ec_keyb_remove,
+ .remove = cros_ec_keyb_remove,
.driver = {
.name = "cros-ec-keyb",
.dev_groups = cros_ec_keyb_groups,
diff --git a/drivers/input/keyboard/cypress-sf.c b/drivers/input/keyboard/cypress-sf.c
index eb1d0720784d..335b72efc5aa 100644
--- a/drivers/input/keyboard/cypress-sf.c
+++ b/drivers/input/keyboard/cypress-sf.c
@@ -208,7 +208,7 @@ static int cypress_sf_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(cypress_sf_pm_ops,
cypress_sf_suspend, cypress_sf_resume);
-static struct i2c_device_id cypress_sf_id_table[] = {
+static const struct i2c_device_id cypress_sf_id_table[] = {
{ CYPRESS_SF_DEV_NAME },
{ }
};
diff --git a/drivers/input/keyboard/dlink-dir685-touchkeys.c b/drivers/input/keyboard/dlink-dir685-touchkeys.c
index 993cdbda509e..4184dd2eaeeb 100644
--- a/drivers/input/keyboard/dlink-dir685-touchkeys.c
+++ b/drivers/input/keyboard/dlink-dir685-touchkeys.c
@@ -14,6 +14,7 @@
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <linux/bitops.h>
struct dir685_touchkeys {
@@ -48,7 +49,7 @@ static irqreturn_t dir685_tk_irq_thread(int irq, void *data)
changed = tk->cur_key ^ key;
for_each_set_bit(i, &changed, num_bits) {
dev_dbg(tk->dev, "key %d is %s\n", i,
- test_bit(i, &key) ? "down" : "up");
+ str_down_up(test_bit(i, &key)));
input_report_key(tk->input, tk->codes[i], test_bit(i, &key));
}
diff --git a/drivers/input/keyboard/ep93xx_keypad.c b/drivers/input/keyboard/ep93xx_keypad.c
index 6b811d6bf625..817c23438f6e 100644
--- a/drivers/input/keyboard/ep93xx_keypad.c
+++ b/drivers/input/keyboard/ep93xx_keypad.c
@@ -6,20 +6,13 @@
*
* Based on the pxa27x matrix keypad controller by Rodolfo Giometti.
*
- * NOTE:
- *
- * The 3-key reset is triggered by pressing the 3 keys in
- * Row 0, Columns 2, 4, and 7 at the same time. This action can
- * be disabled by setting the EP93XX_KEYPAD_DISABLE_3_KEY flag.
- *
- * Normal operation for the matrix does not autorepeat the key press.
- * This action can be enabled by setting the EP93XX_KEYPAD_AUTOREPEAT
- * flag.
*/
#include <linux/bits.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/io.h>
@@ -27,7 +20,6 @@
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
#include <linux/soc/cirrus/ep93xx.h>
-#include <linux/platform_data/keypad-ep93xx.h>
#include <linux/pm_wakeirq.h>
/*
@@ -61,12 +53,16 @@
#define KEY_REG_KEY1_MASK GENMASK(5, 0)
#define KEY_REG_KEY1_SHIFT 0
+#define EP93XX_MATRIX_ROWS (8)
+#define EP93XX_MATRIX_COLS (8)
+
#define EP93XX_MATRIX_SIZE (EP93XX_MATRIX_ROWS * EP93XX_MATRIX_COLS)
struct ep93xx_keypad {
- struct ep93xx_keypad_platform_data *pdata;
struct input_dev *input_dev;
struct clk *clk;
+ unsigned int debounce;
+ u16 prescale;
void __iomem *mmio_base;
@@ -133,23 +129,11 @@ static irqreturn_t ep93xx_keypad_irq_handler(int irq, void *dev_id)
static void ep93xx_keypad_config(struct ep93xx_keypad *keypad)
{
- struct ep93xx_keypad_platform_data *pdata = keypad->pdata;
unsigned int val = 0;
- clk_set_rate(keypad->clk, pdata->clk_rate);
+ val |= (keypad->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK;
- if (pdata->flags & EP93XX_KEYPAD_DISABLE_3_KEY)
- val |= KEY_INIT_DIS3KY;
- if (pdata->flags & EP93XX_KEYPAD_DIAG_MODE)
- val |= KEY_INIT_DIAG;
- if (pdata->flags & EP93XX_KEYPAD_BACK_DRIVE)
- val |= KEY_INIT_BACK;
- if (pdata->flags & EP93XX_KEYPAD_TEST_MODE)
- val |= KEY_INIT_T2;
-
- val |= ((pdata->debounce << KEY_INIT_DBNC_SHIFT) & KEY_INIT_DBNC_MASK);
-
- val |= ((pdata->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK);
+ val |= (keypad->prescale << KEY_INIT_PRSCL_SHIFT) & KEY_INIT_PRSCL_MASK;
__raw_writel(val, keypad->mmio_base + KEY_INIT);
}
@@ -184,15 +168,13 @@ static int ep93xx_keypad_suspend(struct device *dev)
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (keypad->enabled) {
clk_disable(keypad->clk);
keypad->enabled = false;
}
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
@@ -202,7 +184,7 @@ static int ep93xx_keypad_resume(struct device *dev)
struct ep93xx_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev)) {
if (!keypad->enabled) {
@@ -212,25 +194,16 @@ static int ep93xx_keypad_resume(struct device *dev)
}
}
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(ep93xx_keypad_pm_ops,
ep93xx_keypad_suspend, ep93xx_keypad_resume);
-static void ep93xx_keypad_release_gpio_action(void *_pdev)
-{
- struct platform_device *pdev = _pdev;
-
- ep93xx_keypad_release_gpio(pdev);
-}
-
static int ep93xx_keypad_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
struct ep93xx_keypad *keypad;
- const struct matrix_keymap_data *keymap_data;
struct input_dev *input_dev;
int err;
@@ -238,14 +211,6 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
if (!keypad)
return -ENOMEM;
- keypad->pdata = dev_get_platdata(&pdev->dev);
- if (!keypad->pdata)
- return -EINVAL;
-
- keymap_data = keypad->pdata->keymap_data;
- if (!keymap_data)
- return -EINVAL;
-
keypad->irq = platform_get_irq(pdev, 0);
if (keypad->irq < 0)
return keypad->irq;
@@ -254,19 +219,13 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
if (IS_ERR(keypad->mmio_base))
return PTR_ERR(keypad->mmio_base);
- err = ep93xx_keypad_acquire_gpio(pdev);
- if (err)
- return err;
-
- err = devm_add_action_or_reset(&pdev->dev,
- ep93xx_keypad_release_gpio_action, pdev);
- if (err)
- return err;
-
keypad->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(keypad->clk))
return PTR_ERR(keypad->clk);
+ device_property_read_u32(dev, "debounce-delay-ms", &keypad->debounce);
+ device_property_read_u16(dev, "cirrus,prescale", &keypad->prescale);
+
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev)
return -ENOMEM;
@@ -278,13 +237,13 @@ static int ep93xx_keypad_probe(struct platform_device *pdev)
input_dev->open = ep93xx_keypad_open;
input_dev->close = ep93xx_keypad_close;
- err = matrix_keypad_build_keymap(keymap_data, NULL,
+ err = matrix_keypad_build_keymap(NULL, NULL,
EP93XX_MATRIX_ROWS, EP93XX_MATRIX_COLS,
keypad->keycodes, input_dev);
if (err)
return err;
- if (keypad->pdata->flags & EP93XX_KEYPAD_AUTOREPEAT)
+ if (device_property_read_bool(&pdev->dev, "autorepeat"))
__set_bit(EV_REP, input_dev->evbit);
input_set_drvdata(input_dev, keypad);
@@ -313,13 +272,20 @@ static void ep93xx_keypad_remove(struct platform_device *pdev)
dev_pm_clear_wake_irq(&pdev->dev);
}
+static const struct of_device_id ep93xx_keypad_of_ids[] = {
+ { .compatible = "cirrus,ep9307-keypad" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ep93xx_keypad_of_ids);
+
static struct platform_driver ep93xx_keypad_driver = {
.driver = {
.name = "ep93xx-keypad",
.pm = pm_sleep_ptr(&ep93xx_keypad_pm_ops),
+ .of_match_table = ep93xx_keypad_of_ids,
},
.probe = ep93xx_keypad_probe,
- .remove_new = ep93xx_keypad_remove,
+ .remove = ep93xx_keypad_remove,
};
module_platform_driver(ep93xx_keypad_driver);
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 9f3bcd41cf67..f9db86da0818 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -245,23 +245,20 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
{
int n_events = get_n_events_by_type(type);
const unsigned long *bitmap = get_bm_events_by_type(ddata->input, type);
- unsigned long *bits;
ssize_t error;
int i;
- bits = bitmap_alloc(n_events, GFP_KERNEL);
+ unsigned long *bits __free(bitmap) = bitmap_alloc(n_events, GFP_KERNEL);
if (!bits)
return -ENOMEM;
error = bitmap_parselist(buf, bits, n_events);
if (error)
- goto out;
+ return error;
/* First validate */
- if (!bitmap_subset(bits, bitmap, n_events)) {
- error = -EINVAL;
- goto out;
- }
+ if (!bitmap_subset(bits, bitmap, n_events))
+ return -EINVAL;
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
@@ -271,12 +268,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
if (test_bit(*bdata->code, bits) &&
!bdata->button->can_disable) {
- error = -EINVAL;
- goto out;
+ return -EINVAL;
}
}
- mutex_lock(&ddata->disable_lock);
+ guard(mutex)(&ddata->disable_lock);
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
@@ -290,11 +286,7 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata,
gpio_keys_enable_button(bdata);
}
- mutex_unlock(&ddata->disable_lock);
-
-out:
- bitmap_free(bits);
- return error;
+ return 0;
}
#define ATTR_SHOW_FN(name, type, only_disabled) \
@@ -457,6 +449,8 @@ static enum hrtimer_restart gpio_keys_irq_timer(struct hrtimer *t)
release_timer);
struct input_dev *input = bdata->input;
+ guard(spinlock_irqsave)(&bdata->lock);
+
if (bdata->key_pressed) {
input_report_key(input, *bdata->code, 0);
input_sync(input);
@@ -470,11 +464,10 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
{
struct gpio_button_data *bdata = dev_id;
struct input_dev *input = bdata->input;
- unsigned long flags;
BUG_ON(irq != bdata->irq);
- spin_lock_irqsave(&bdata->lock, flags);
+ guard(spinlock_irqsave)(&bdata->lock);
if (!bdata->key_pressed) {
if (bdata->button->wakeup)
@@ -495,9 +488,8 @@ static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
if (bdata->release_delay)
hrtimer_start(&bdata->release_timer,
ms_to_ktime(bdata->release_delay),
- HRTIMER_MODE_REL_HARD);
+ HRTIMER_MODE_REL);
out:
- spin_unlock_irqrestore(&bdata->lock, flags);
return IRQ_HANDLED;
}
@@ -541,12 +533,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
* Legacy GPIO number, so request the GPIO here and
* convert it to descriptor.
*/
- unsigned flags = GPIOF_IN;
-
- if (button->active_low)
- flags |= GPIOF_ACTIVE_LOW;
-
- error = devm_gpio_request_one(dev, button->gpio, flags, desc);
+ error = devm_gpio_request_one(dev, button->gpio, GPIOF_IN, desc);
if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error);
@@ -556,6 +543,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
bdata->gpiod = gpio_to_desc(button->gpio);
if (!bdata->gpiod)
return -EINVAL;
+
+ if (button->active_low ^ gpiod_is_active_low(bdata->gpiod))
+ gpiod_toggle_active_low(bdata->gpiod);
}
if (bdata->gpiod) {
@@ -602,9 +592,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func);
- hrtimer_init(&bdata->debounce_timer,
- CLOCK_REALTIME, HRTIMER_MODE_REL);
- bdata->debounce_timer.function = gpio_keys_debounce_timer;
+ hrtimer_setup(&bdata->debounce_timer, gpio_keys_debounce_timer,
+ CLOCK_REALTIME, HRTIMER_MODE_REL);
isr = gpio_keys_gpio_isr;
irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
@@ -640,9 +629,8 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
}
bdata->release_delay = button->debounce_interval;
- hrtimer_init(&bdata->release_timer,
- CLOCK_REALTIME, HRTIMER_MODE_REL_HARD);
- bdata->release_timer.function = gpio_keys_irq_timer;
+ hrtimer_setup(&bdata->release_timer, gpio_keys_irq_timer,
+ CLOCK_REALTIME, HRTIMER_MODE_REL);
isr = gpio_keys_irq_isr;
irqflags = 0;
@@ -768,7 +756,6 @@ gpio_keys_get_devtree_pdata(struct device *dev)
{
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
- struct fwnode_handle *child;
int nbuttons, irq;
nbuttons = device_get_child_node_count(dev);
@@ -790,7 +777,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
device_property_read_string(dev, "label", &pdata->name);
- device_for_each_child_node(dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
if (is_of_node(child)) {
irq = of_irq_get_byname(to_of_node(child), "irq");
if (irq > 0)
@@ -808,7 +795,6 @@ gpio_keys_get_devtree_pdata(struct device *dev)
if (fwnode_property_read_u32(child, "linux,code",
&button->code)) {
dev_err(dev, "Button without keycode\n");
- fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
@@ -1064,10 +1050,10 @@ static int gpio_keys_suspend(struct device *dev)
if (error)
return error;
} else {
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
+
if (input_device_enabled(input))
gpio_keys_close(input);
- mutex_unlock(&input->mutex);
}
return 0;
@@ -1077,20 +1063,20 @@ static int gpio_keys_resume(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
- int error = 0;
+ int error;
if (device_may_wakeup(dev)) {
gpio_keys_disable_wakeup(ddata);
} else {
- mutex_lock(&input->mutex);
- if (input_device_enabled(input))
+ guard(mutex)(&input->mutex);
+
+ if (input_device_enabled(input)) {
error = gpio_keys_open(input);
- mutex_unlock(&input->mutex);
+ if (error)
+ return error;
+ }
}
- if (error)
- return error;
-
gpio_keys_report_state(ddata);
return 0;
}
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index b41fd1240f43..e6707d72210e 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -144,7 +144,6 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
- struct fwnode_handle *child;
int nbuttons;
nbuttons = device_get_child_node_count(dev);
@@ -166,11 +165,10 @@ gpio_keys_polled_get_devtree_pdata(struct device *dev)
device_property_read_string(dev, "label", &pdata->name);
- device_for_each_child_node(dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
if (fwnode_property_read_u32(child, "linux,code",
&button->code)) {
dev_err(dev, "button without keycode\n");
- fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
@@ -308,13 +306,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
* Legacy GPIO number so request the GPIO here and
* convert it to descriptor.
*/
- unsigned flags = GPIOF_IN;
-
- if (button->active_low)
- flags |= GPIOF_ACTIVE_LOW;
-
- error = devm_gpio_request_one(dev, button->gpio,
- flags, button->desc ? : DRV_NAME);
+ error = devm_gpio_request_one(dev, button->gpio, GPIOF_IN,
+ button->desc ? : DRV_NAME);
if (error)
return dev_err_probe(dev, error,
"unable to claim gpio %u\n",
@@ -327,6 +320,9 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
button->gpio);
return -EINVAL;
}
+
+ if (button->active_low ^ gpiod_is_active_low(bdata->gpiod))
+ gpiod_toggle_active_low(bdata->gpiod);
}
bdata->last_state = -1;
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index c1a4d5055de6..c8d8d0ea35b0 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -180,9 +180,8 @@ static irqreturn_t hil_interrupt(int irq, void *handle)
/* send a command to the HIL */
static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
{
- unsigned long flags;
+ guard(spinlock_irqsave)(&hil_dev.lock);
- spin_lock_irqsave(&hil_dev.lock, flags);
while (hil_busy())
/* wait */;
hil_command(cmd);
@@ -191,7 +190,6 @@ static void hil_do(unsigned char cmd, unsigned char *data, unsigned int len)
/* wait */;
hil_write_data(*(data++));
}
- spin_unlock_irqrestore(&hil_dev.lock, flags);
}
diff --git a/drivers/input/keyboard/imx-sm-bbm-key.c b/drivers/input/keyboard/imx-sm-bbm-key.c
new file mode 100644
index 000000000000..96486bd23d60
--- /dev/null
+++ b/drivers/input/keyboard/imx-sm-bbm-key.c
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2024 NXP.
+ */
+
+#include <linux/input.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/scmi_protocol.h>
+#include <linux/scmi_imx_protocol.h>
+#include <linux/suspend.h>
+
+#define DEBOUNCE_TIME 30
+#define REPEAT_INTERVAL 60
+
+struct scmi_imx_bbm {
+ struct scmi_protocol_handle *ph;
+ const struct scmi_imx_bbm_proto_ops *ops;
+ struct notifier_block nb;
+ int keycode;
+ int keystate; /* 1:pressed */
+ bool suspended;
+ struct delayed_work check_work;
+ struct input_dev *input;
+};
+
+static void scmi_imx_bbm_pwrkey_check_for_events(struct work_struct *work)
+{
+ struct scmi_imx_bbm *bbnsm = container_of(to_delayed_work(work),
+ struct scmi_imx_bbm, check_work);
+ struct scmi_protocol_handle *ph = bbnsm->ph;
+ struct input_dev *input = bbnsm->input;
+ u32 state = 0;
+ int ret;
+
+ ret = bbnsm->ops->button_get(ph, &state);
+ if (ret) {
+ pr_err("%s: %d\n", __func__, ret);
+ return;
+ }
+
+ pr_debug("%s: state: %d, keystate %d\n", __func__, state, bbnsm->keystate);
+
+ /* only report new event if status changed */
+ if (state ^ bbnsm->keystate) {
+ bbnsm->keystate = state;
+ input_event(input, EV_KEY, bbnsm->keycode, state);
+ input_sync(input);
+ pm_relax(bbnsm->input->dev.parent);
+ pr_debug("EV_KEY: %x\n", bbnsm->keycode);
+ }
+
+ /* repeat check if pressed long */
+ if (state)
+ schedule_delayed_work(&bbnsm->check_work, msecs_to_jiffies(REPEAT_INTERVAL));
+}
+
+static int scmi_imx_bbm_pwrkey_event(struct scmi_imx_bbm *bbnsm)
+{
+ struct input_dev *input = bbnsm->input;
+
+ pm_wakeup_event(input->dev.parent, 0);
+
+ /*
+ * Directly report key event after resume to make no key press
+ * event is missed.
+ */
+ if (READ_ONCE(bbnsm->suspended)) {
+ bbnsm->keystate = 1;
+ input_event(input, EV_KEY, bbnsm->keycode, 1);
+ input_sync(input);
+ WRITE_ONCE(bbnsm->suspended, false);
+ }
+
+ schedule_delayed_work(&bbnsm->check_work, msecs_to_jiffies(DEBOUNCE_TIME));
+
+ return 0;
+}
+
+static void scmi_imx_bbm_pwrkey_act(void *pdata)
+{
+ struct scmi_imx_bbm *bbnsm = pdata;
+
+ cancel_delayed_work_sync(&bbnsm->check_work);
+}
+
+static int scmi_imx_bbm_key_notifier(struct notifier_block *nb, unsigned long event, void *data)
+{
+ struct scmi_imx_bbm *bbnsm = container_of(nb, struct scmi_imx_bbm, nb);
+ struct scmi_imx_bbm_notif_report *r = data;
+
+ if (r->is_button) {
+ pr_debug("BBM Button Power key pressed\n");
+ scmi_imx_bbm_pwrkey_event(bbnsm);
+ } else {
+ /* Should never reach here */
+ pr_err("Unexpected BBM event: %s\n", __func__);
+ }
+
+ return 0;
+}
+
+static int scmi_imx_bbm_pwrkey_init(struct scmi_device *sdev)
+{
+ const struct scmi_handle *handle = sdev->handle;
+ struct device *dev = &sdev->dev;
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+ struct input_dev *input;
+ int ret;
+
+ if (device_property_read_u32(dev, "linux,code", &bbnsm->keycode)) {
+ bbnsm->keycode = KEY_POWER;
+ dev_warn(dev, "key code is not specified, using default KEY_POWER\n");
+ }
+
+ INIT_DELAYED_WORK(&bbnsm->check_work, scmi_imx_bbm_pwrkey_check_for_events);
+
+ input = devm_input_allocate_device(dev);
+ if (!input) {
+ dev_err(dev, "failed to allocate the input device for SCMI IMX BBM\n");
+ return -ENOMEM;
+ }
+
+ input->name = dev_name(dev);
+ input->phys = "bbnsm-pwrkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ input_set_capability(input, EV_KEY, bbnsm->keycode);
+
+ ret = devm_add_action_or_reset(dev, scmi_imx_bbm_pwrkey_act, bbnsm);
+ if (ret) {
+ dev_err(dev, "failed to register remove action\n");
+ return ret;
+ }
+
+ bbnsm->input = input;
+
+ bbnsm->nb.notifier_call = &scmi_imx_bbm_key_notifier;
+ ret = handle->notify_ops->devm_event_notifier_register(sdev, SCMI_PROTOCOL_IMX_BBM,
+ SCMI_EVENT_IMX_BBM_BUTTON,
+ NULL, &bbnsm->nb);
+
+ if (ret)
+ dev_err(dev, "Failed to register BBM Button Events %d:", ret);
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(dev, "failed to register input device\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int scmi_imx_bbm_key_probe(struct scmi_device *sdev)
+{
+ const struct scmi_handle *handle = sdev->handle;
+ struct device *dev = &sdev->dev;
+ struct scmi_protocol_handle *ph;
+ struct scmi_imx_bbm *bbnsm;
+ int ret;
+
+ if (!handle)
+ return -ENODEV;
+
+ bbnsm = devm_kzalloc(dev, sizeof(*bbnsm), GFP_KERNEL);
+ if (!bbnsm)
+ return -ENOMEM;
+
+ bbnsm->ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_BBM, &ph);
+ if (IS_ERR(bbnsm->ops))
+ return PTR_ERR(bbnsm->ops);
+
+ bbnsm->ph = ph;
+
+ device_init_wakeup(dev, true);
+
+ dev_set_drvdata(dev, bbnsm);
+
+ ret = scmi_imx_bbm_pwrkey_init(sdev);
+ if (ret)
+ device_init_wakeup(dev, false);
+
+ return ret;
+}
+
+static int __maybe_unused scmi_imx_bbm_key_suspend(struct device *dev)
+{
+ struct scmi_imx_bbm *bbnsm = dev_get_drvdata(dev);
+
+ WRITE_ONCE(bbnsm->suspended, true);
+
+ return 0;
+}
+
+static int __maybe_unused scmi_imx_bbm_key_resume(struct device *dev)
+{
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(scmi_imx_bbm_pm_key_ops, scmi_imx_bbm_key_suspend,
+ scmi_imx_bbm_key_resume);
+
+static const struct scmi_device_id scmi_id_table[] = {
+ { SCMI_PROTOCOL_IMX_BBM, "imx-bbm-key" },
+ { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_imx_bbm_key_driver = {
+ .driver = {
+ .pm = &scmi_imx_bbm_pm_key_ops,
+ },
+ .name = "scmi-imx-bbm-key",
+ .probe = scmi_imx_bbm_key_probe,
+ .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_imx_bbm_key_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("IMX SM BBM Key driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index e15a93619e82..069c1d6376e1 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -183,7 +183,8 @@ static void imx_keypad_fire_events(struct imx_keypad *keypad,
*/
static void imx_keypad_check_for_events(struct timer_list *t)
{
- struct imx_keypad *keypad = from_timer(keypad, t, check_matrix_timer);
+ struct imx_keypad *keypad = timer_container_of(keypad, t,
+ check_matrix_timer);
unsigned short matrix_volatile_state[MAX_MATRIX_KEY_COLS];
unsigned short reg_val;
bool state_changed, is_zero_matrix;
@@ -370,7 +371,7 @@ static void imx_keypad_close(struct input_dev *dev)
/* Mark keypad as being inactive */
keypad->enabled = false;
synchronize_irq(keypad->irq);
- del_timer_sync(&keypad->check_matrix_timer);
+ timer_delete_sync(&keypad->check_matrix_timer);
imx_keypad_inhibit(keypad);
@@ -521,13 +522,11 @@ static int __maybe_unused imx_kbd_noirq_suspend(struct device *dev)
struct input_dev *input_dev = kbd->input_dev;
unsigned short reg_val = readw(kbd->mmio_base + KPSR);
- /* imx kbd can wake up system even clock is disabled */
- mutex_lock(&input_dev->mutex);
-
- if (input_device_enabled(input_dev))
- clk_disable_unprepare(kbd->clk);
-
- mutex_unlock(&input_dev->mutex);
+ scoped_guard(mutex, &input_dev->mutex) {
+ /* imx kbd can wake up system even clock is disabled */
+ if (input_device_enabled(input_dev))
+ clk_disable_unprepare(kbd->clk);
+ }
if (device_may_wakeup(&pdev->dev)) {
if (reg_val & KBD_STAT_KPKD)
@@ -547,23 +546,20 @@ static int __maybe_unused imx_kbd_noirq_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct imx_keypad *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input_dev;
- int ret = 0;
+ int error;
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(kbd->irq);
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev)) {
- ret = clk_prepare_enable(kbd->clk);
- if (ret)
- goto err_clk;
+ error = clk_prepare_enable(kbd->clk);
+ if (error)
+ return error;
}
-err_clk:
- mutex_unlock(&input_dev->mutex);
-
- return ret;
+ return 0;
}
static const struct dev_pm_ops imx_kbd_pm_ops = {
diff --git a/drivers/input/keyboard/imx_sc_key.c b/drivers/input/keyboard/imx_sc_key.c
index d18839f1f4f6..b620cd310cdb 100644
--- a/drivers/input/keyboard/imx_sc_key.c
+++ b/drivers/input/keyboard/imx_sc_key.c
@@ -158,7 +158,7 @@ static int imx_sc_key_probe(struct platform_device *pdev)
return error;
}
- error = devm_add_action_or_reset(&pdev->dev, imx_sc_key_action, &priv);
+ error = devm_add_action_or_reset(&pdev->dev, imx_sc_key_action, priv);
if (error)
return error;
diff --git a/drivers/input/keyboard/ipaq-micro-keys.c b/drivers/input/keyboard/ipaq-micro-keys.c
index 1d71dd79ffd2..ca7ec054b1ce 100644
--- a/drivers/input/keyboard/ipaq-micro-keys.c
+++ b/drivers/input/keyboard/ipaq-micro-keys.c
@@ -54,18 +54,18 @@ static void micro_key_receive(void *data, int len, unsigned char *msg)
static void micro_key_start(struct ipaq_micro_keys *keys)
{
- spin_lock(&keys->micro->lock);
+ guard(spinlock)(&keys->micro->lock);
+
keys->micro->key = micro_key_receive;
keys->micro->key_data = keys;
- spin_unlock(&keys->micro->lock);
}
static void micro_key_stop(struct ipaq_micro_keys *keys)
{
- spin_lock(&keys->micro->lock);
+ guard(spinlock)(&keys->micro->lock);
+
keys->micro->key = NULL;
keys->micro->key_data = NULL;
- spin_unlock(&keys->micro->lock);
}
static int micro_key_open(struct input_dev *input)
@@ -102,9 +102,8 @@ static int micro_key_probe(struct platform_device *pdev)
keys->input->keycodesize = sizeof(micro_keycodes[0]);
keys->input->keycodemax = ARRAY_SIZE(micro_keycodes);
- keys->codes = devm_kmemdup(&pdev->dev, micro_keycodes,
- keys->input->keycodesize * keys->input->keycodemax,
- GFP_KERNEL);
+ keys->codes = devm_kmemdup_array(&pdev->dev, micro_keycodes, keys->input->keycodemax,
+ keys->input->keycodesize, GFP_KERNEL);
if (!keys->codes)
return -ENOMEM;
@@ -141,13 +140,11 @@ static int micro_key_resume(struct device *dev)
struct ipaq_micro_keys *keys = dev_get_drvdata(dev);
struct input_dev *input = keys->input;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
if (input_device_enabled(input))
micro_key_start(keys);
- mutex_unlock(&input->mutex);
-
return 0;
}
diff --git a/drivers/input/keyboard/iqs62x-keys.c b/drivers/input/keyboard/iqs62x-keys.c
index 688d61244b5f..b086c7b28d5c 100644
--- a/drivers/input/keyboard/iqs62x-keys.c
+++ b/drivers/input/keyboard/iqs62x-keys.c
@@ -45,7 +45,6 @@ struct iqs62x_keys_private {
static int iqs62x_keys_parse_prop(struct platform_device *pdev,
struct iqs62x_keys_private *iqs62x_keys)
{
- struct fwnode_handle *child;
unsigned int val;
int ret, i;
@@ -68,7 +67,8 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev,
}
for (i = 0; i < ARRAY_SIZE(iqs62x_keys->switches); i++) {
- child = device_get_named_child_node(&pdev->dev,
+ struct fwnode_handle *child __free(fwnode_handle) =
+ device_get_named_child_node(&pdev->dev,
iqs62x_switch_names[i]);
if (!child)
continue;
@@ -77,7 +77,6 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev,
if (ret) {
dev_err(&pdev->dev, "Failed to read switch code: %d\n",
ret);
- fwnode_handle_put(child);
return ret;
}
iqs62x_keys->switches[i].code = val;
@@ -91,8 +90,6 @@ static int iqs62x_keys_parse_prop(struct platform_device *pdev,
iqs62x_keys->switches[i].flag = (i == IQS62X_SW_HALL_N ?
IQS62X_EVENT_HALL_N_T :
IQS62X_EVENT_HALL_S_T);
-
- fwnode_handle_put(child);
}
return 0;
@@ -326,7 +323,7 @@ static struct platform_driver iqs62x_keys_platform_driver = {
.name = "iqs62x-keys",
},
.probe = iqs62x_keys_probe,
- .remove_new = iqs62x_keys_remove,
+ .remove = iqs62x_keys_remove,
};
module_platform_driver(iqs62x_keys_platform_driver);
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 047b654b3752..c035216dd27c 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -608,7 +608,7 @@ static int lkkbd_connect(struct serio *serio, struct serio_driver *drv)
int i;
int err;
- lk = kzalloc(sizeof(struct lkkbd), GFP_KERNEL);
+ lk = kzalloc(sizeof(*lk), GFP_KERNEL);
input_dev = input_allocate_device();
if (!lk || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/keyboard/lm8323.c b/drivers/input/keyboard/lm8323.c
index cf67ba13477a..e19442c6f80f 100644
--- a/drivers/input/keyboard/lm8323.c
+++ b/drivers/input/keyboard/lm8323.c
@@ -21,6 +21,7 @@
#include <linux/platform_data/lm8323.h>
#include <linux/pm.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
/* Commands to send to the chip. */
#define LM8323_CMD_READ_ID 0x80 /* Read chip ID. */
@@ -269,7 +270,7 @@ static void process_keys(struct lm8323_chip *lm)
unsigned short keycode = lm->keymap[key];
dev_vdbg(&lm->client->dev, "key 0x%02x %s\n",
- key, isdown ? "down" : "up");
+ key, str_down_up(isdown));
if (lm->kp_enabled) {
input_event(lm->idev, EV_MSC, MSC_SCAN, key);
@@ -350,11 +351,11 @@ static int lm8323_configure(struct lm8323_chip *lm)
static void pwm_done(struct lm8323_pwm *pwm)
{
- mutex_lock(&pwm->lock);
+ guard(mutex)(&pwm->lock);
+
pwm->running = false;
if (pwm->desired_brightness != pwm->brightness)
schedule_work(&pwm->work);
- mutex_unlock(&pwm->lock);
}
/*
@@ -367,7 +368,7 @@ static irqreturn_t lm8323_irq(int irq, void *_lm)
u8 ints;
int i;
- mutex_lock(&lm->lock);
+ guard(mutex)(&lm->lock);
while ((lm8323_read(lm, LM8323_CMD_READ_INT, &ints, 1) == 1) && ints) {
if (likely(ints & INT_KEYPAD))
@@ -394,8 +395,6 @@ static irqreturn_t lm8323_irq(int irq, void *_lm)
}
}
- mutex_unlock(&lm->lock);
-
return IRQ_HANDLED;
}
@@ -445,7 +444,7 @@ static void lm8323_pwm_work(struct work_struct *work)
u16 pwm_cmds[3];
int num_cmds = 0;
- mutex_lock(&pwm->lock);
+ guard(mutex)(&pwm->lock);
/*
* Do nothing if we're already at the requested level,
@@ -454,7 +453,7 @@ static void lm8323_pwm_work(struct work_struct *work)
* finishes.
*/
if (pwm->running || pwm->desired_brightness == pwm->brightness)
- goto out;
+ return;
kill = (pwm->desired_brightness == 0);
up = (pwm->desired_brightness > pwm->brightness);
@@ -489,9 +488,6 @@ static void lm8323_pwm_work(struct work_struct *work)
lm8323_write_pwm(pwm, kill, num_cmds, pwm_cmds);
pwm->brightness = pwm->desired_brightness;
-
- out:
- mutex_unlock(&pwm->lock);
}
static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
@@ -500,9 +496,9 @@ static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
struct lm8323_pwm *pwm = cdev_to_pwm(led_cdev);
struct lm8323_chip *lm = pwm->chip;
- mutex_lock(&pwm->lock);
- pwm->desired_brightness = brightness;
- mutex_unlock(&pwm->lock);
+ scoped_guard(mutex, &pwm->lock) {
+ pwm->desired_brightness = brightness;
+ }
if (in_interrupt()) {
schedule_work(&pwm->work);
@@ -510,12 +506,12 @@ static void lm8323_pwm_set_brightness(struct led_classdev *led_cdev,
/*
* Schedule PWM work as usual unless we are going into suspend
*/
- mutex_lock(&lm->lock);
- if (likely(!lm->pm_suspend))
- schedule_work(&pwm->work);
- else
- lm8323_pwm_work(&pwm->work);
- mutex_unlock(&lm->lock);
+ scoped_guard(mutex, &lm->lock) {
+ if (likely(!lm->pm_suspend))
+ schedule_work(&pwm->work);
+ else
+ lm8323_pwm_work(&pwm->work);
+ }
}
}
@@ -608,9 +604,9 @@ static ssize_t lm8323_set_disable(struct device *dev,
if (ret)
return ret;
- mutex_lock(&lm->lock);
+ guard(mutex)(&lm->lock);
+
lm->kp_enabled = !i;
- mutex_unlock(&lm->lock);
return count;
}
@@ -758,9 +754,9 @@ static int lm8323_suspend(struct device *dev)
irq_set_irq_wake(client->irq, 0);
disable_irq(client->irq);
- mutex_lock(&lm->lock);
- lm->pm_suspend = true;
- mutex_unlock(&lm->lock);
+ scoped_guard(mutex, &lm->lock) {
+ lm->pm_suspend = true;
+ }
for (i = 0; i < 3; i++)
if (lm->pwm[i].enabled)
@@ -775,9 +771,9 @@ static int lm8323_resume(struct device *dev)
struct lm8323_chip *lm = i2c_get_clientdata(client);
int i;
- mutex_lock(&lm->lock);
- lm->pm_suspend = false;
- mutex_unlock(&lm->lock);
+ scoped_guard(mutex, &lm->lock) {
+ lm->pm_suspend = false;
+ }
for (i = 0; i < 3; i++)
if (lm->pwm[i].enabled)
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index f866c03b9d0e..58d4f2096cf9 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -112,11 +112,10 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
{
unsigned int row, col, rowd;
- unsigned long flags;
unsigned int num_pressed;
unsigned long membase = locomokbd->base;
- spin_lock_irqsave(&locomokbd->lock, flags);
+ guard(spinlock_irqsave)(&locomokbd->lock);
locomokbd_charge_all(membase);
@@ -167,8 +166,6 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL);
else
locomokbd->count_cancel = 0;
-
- spin_unlock_irqrestore(&locomokbd->lock, flags);
}
/*
@@ -197,7 +194,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
*/
static void locomokbd_timer_callback(struct timer_list *t)
{
- struct locomokbd *locomokbd = from_timer(locomokbd, t, timer);
+ struct locomokbd *locomokbd = timer_container_of(locomokbd, t, timer);
locomokbd_scankeyboard(locomokbd);
}
@@ -227,7 +224,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
struct input_dev *input_dev;
int i, err;
- locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL);
+ locomokbd = kzalloc(sizeof(*locomokbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!locomokbd || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c
index 423035be86fb..2392e7ec3b19 100644
--- a/drivers/input/keyboard/lpc32xx-keys.c
+++ b/drivers/input/keyboard/lpc32xx-keys.c
@@ -262,7 +262,7 @@ static int lpc32xx_kscan_suspend(struct device *dev)
struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev);
struct input_dev *input = kscandat->input;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
if (input_device_enabled(input)) {
/* Clear IRQ and disable clock */
@@ -270,7 +270,6 @@ static int lpc32xx_kscan_suspend(struct device *dev)
clk_disable_unprepare(kscandat->clk);
}
- mutex_unlock(&input->mutex);
return 0;
}
@@ -279,19 +278,20 @@ static int lpc32xx_kscan_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct lpc32xx_kscan_drv *kscandat = platform_get_drvdata(pdev);
struct input_dev *input = kscandat->input;
- int retval = 0;
+ int error;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
if (input_device_enabled(input)) {
/* Enable clock and clear IRQ */
- retval = clk_prepare_enable(kscandat->clk);
- if (retval == 0)
- writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));
+ error = clk_prepare_enable(kscandat->clk);
+ if (error)
+ return error;
+
+ writel(1, LPC32XX_KS_IRQ(kscandat->kscan_base));
}
- mutex_unlock(&input->mutex);
- return retval;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(lpc32xx_kscan_pm_ops, lpc32xx_kscan_suspend,
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index d08b565be24c..1a8f1fa53fbb 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -132,14 +132,11 @@ static void dc_kbd_callback(struct mapleq *mq)
* We should always get the lock because the only
* time it may be locked is if the driver is in the cleanup phase.
*/
- if (likely(mutex_trylock(&maple_keyb_mutex))) {
-
+ scoped_guard(mutex_try, &maple_keyb_mutex) {
if (buf[1] == mapledev->function) {
memcpy(kbd->new, buf + 2, 8);
dc_scan_kbd(kbd);
}
-
- mutex_unlock(&maple_keyb_mutex);
}
}
@@ -154,7 +151,7 @@ static int probe_maple_kbd(struct device *dev)
mdev = to_maple_dev(dev);
mdrv = to_maple_driver(dev->driver);
- kbd = kzalloc(sizeof(struct dc_kbd), GFP_KERNEL);
+ kbd = kzalloc(sizeof(*kbd), GFP_KERNEL);
if (!kbd) {
error = -ENOMEM;
goto fail;
@@ -211,14 +208,12 @@ static int remove_maple_kbd(struct device *dev)
struct maple_device *mdev = to_maple_dev(dev);
struct dc_kbd *kbd = maple_get_drvdata(mdev);
- mutex_lock(&maple_keyb_mutex);
+ guard(mutex)(&maple_keyb_mutex);
input_unregister_device(kbd->dev);
kfree(kbd);
maple_set_drvdata(mdev, NULL);
-
- mutex_unlock(&maple_keyb_mutex);
return 0;
}
diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c
index 7a56f3d3aacd..e50a6fea9a60 100644
--- a/drivers/input/keyboard/matrix_keypad.c
+++ b/drivers/input/keyboard/matrix_keypad.c
@@ -20,16 +20,24 @@
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
struct matrix_keypad {
- const struct matrix_keypad_platform_data *pdata;
struct input_dev *input_dev;
unsigned int row_shift;
+ unsigned int col_scan_delay_us;
+ unsigned int all_cols_on_delay_us;
+ /* key debounce interval in milli-second */
+ unsigned int debounce_ms;
+ bool drive_inactive_cols;
+
+ struct gpio_desc *row_gpios[MATRIX_MAX_ROWS];
+ unsigned int num_row_gpios;
+
+ struct gpio_desc *col_gpios[MATRIX_MAX_ROWS];
+ unsigned int num_col_gpios;
+
unsigned int row_irqs[MATRIX_MAX_ROWS];
- unsigned int num_row_irqs;
DECLARE_BITMAP(wakeup_enabled_irqs, MATRIX_MAX_ROWS);
uint32_t last_key_state[MATRIX_MAX_COLS];
@@ -45,50 +53,46 @@ struct matrix_keypad {
* columns. In that case it is configured here to be input, otherwise it is
* driven with the inactive value.
*/
-static void __activate_col(const struct matrix_keypad_platform_data *pdata,
- int col, bool on)
+static void __activate_col(struct matrix_keypad *keypad, int col, bool on)
{
- bool level_on = !pdata->active_low;
-
if (on) {
- gpio_direction_output(pdata->col_gpios[col], level_on);
+ gpiod_direction_output(keypad->col_gpios[col], 1);
} else {
- gpio_set_value_cansleep(pdata->col_gpios[col], !level_on);
- if (!pdata->drive_inactive_cols)
- gpio_direction_input(pdata->col_gpios[col]);
+ gpiod_set_value_cansleep(keypad->col_gpios[col], 0);
+ if (!keypad->drive_inactive_cols)
+ gpiod_direction_input(keypad->col_gpios[col]);
}
}
-static void activate_col(const struct matrix_keypad_platform_data *pdata,
- int col, bool on)
+static void activate_col(struct matrix_keypad *keypad, int col, bool on)
{
- __activate_col(pdata, col, on);
+ __activate_col(keypad, col, on);
- if (on && pdata->col_scan_delay_us)
- udelay(pdata->col_scan_delay_us);
+ if (on && keypad->col_scan_delay_us)
+ fsleep(keypad->col_scan_delay_us);
}
-static void activate_all_cols(const struct matrix_keypad_platform_data *pdata,
- bool on)
+static void activate_all_cols(struct matrix_keypad *keypad, bool on)
{
int col;
- for (col = 0; col < pdata->num_col_gpios; col++)
- __activate_col(pdata, col, on);
+ for (col = 0; col < keypad->num_col_gpios; col++)
+ __activate_col(keypad, col, on);
+
+ if (on && keypad->all_cols_on_delay_us)
+ fsleep(keypad->all_cols_on_delay_us);
}
-static bool row_asserted(const struct matrix_keypad_platform_data *pdata,
- int row)
+static bool row_asserted(struct matrix_keypad *keypad, int row)
{
- return gpio_get_value_cansleep(pdata->row_gpios[row]) ?
- !pdata->active_low : pdata->active_low;
+ return gpiod_get_value_cansleep(keypad->row_gpios[row]);
}
static void enable_row_irqs(struct matrix_keypad *keypad)
{
int i;
- for (i = 0; i < keypad->num_row_irqs; i++)
+ for (i = 0; i < keypad->num_row_gpios; i++)
enable_irq(keypad->row_irqs[i]);
}
@@ -96,10 +100,20 @@ static void disable_row_irqs(struct matrix_keypad *keypad)
{
int i;
- for (i = 0; i < keypad->num_row_irqs; i++)
+ for (i = 0; i < keypad->num_row_gpios; i++)
disable_irq_nosync(keypad->row_irqs[i]);
}
+static uint32_t read_row_state(struct matrix_keypad *keypad)
+{
+ int row;
+ u32 row_state = 0;
+
+ for (row = 0; row < keypad->num_row_gpios; row++)
+ row_state |= row_asserted(keypad, row) ? BIT(row) : 0;
+ return row_state;
+}
+
/*
* This gets the keys from keyboard and reports it to input subsystem
*/
@@ -109,39 +123,40 @@ static void matrix_keypad_scan(struct work_struct *work)
container_of(work, struct matrix_keypad, work.work);
struct input_dev *input_dev = keypad->input_dev;
const unsigned short *keycodes = input_dev->keycode;
- const struct matrix_keypad_platform_data *pdata = keypad->pdata;
uint32_t new_state[MATRIX_MAX_COLS];
int row, col, code;
+ u32 init_row_state, new_row_state;
+
+ /* read initial row state to detect changes between scan */
+ init_row_state = read_row_state(keypad);
/* de-activate all columns for scanning */
- activate_all_cols(pdata, false);
+ activate_all_cols(keypad, false);
memset(new_state, 0, sizeof(new_state));
- for (row = 0; row < pdata->num_row_gpios; row++)
- gpio_direction_input(pdata->row_gpios[row]);
+ for (row = 0; row < keypad->num_row_gpios; row++)
+ gpiod_direction_input(keypad->row_gpios[row]);
/* assert each column and read the row status out */
- for (col = 0; col < pdata->num_col_gpios; col++) {
+ for (col = 0; col < keypad->num_col_gpios; col++) {
- activate_col(pdata, col, true);
+ activate_col(keypad, col, true);
- for (row = 0; row < pdata->num_row_gpios; row++)
- new_state[col] |=
- row_asserted(pdata, row) ? (1 << row) : 0;
+ new_state[col] = read_row_state(keypad);
- activate_col(pdata, col, false);
+ activate_col(keypad, col, false);
}
- for (col = 0; col < pdata->num_col_gpios; col++) {
+ for (col = 0; col < keypad->num_col_gpios; col++) {
uint32_t bits_changed;
bits_changed = keypad->last_key_state[col] ^ new_state[col];
if (bits_changed == 0)
continue;
- for (row = 0; row < pdata->num_row_gpios; row++) {
- if ((bits_changed & (1 << row)) == 0)
+ for (row = 0; row < keypad->num_row_gpios; row++) {
+ if (!(bits_changed & BIT(row)))
continue;
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
@@ -155,21 +170,32 @@ static void matrix_keypad_scan(struct work_struct *work)
memcpy(keypad->last_key_state, new_state, sizeof(new_state));
- activate_all_cols(pdata, true);
+ activate_all_cols(keypad, true);
/* Enable IRQs again */
- spin_lock_irq(&keypad->lock);
- keypad->scan_pending = false;
- enable_row_irqs(keypad);
- spin_unlock_irq(&keypad->lock);
+ scoped_guard(spinlock_irq, &keypad->lock) {
+ keypad->scan_pending = false;
+ enable_row_irqs(keypad);
+ }
+
+ /* read new row state and detect if value has changed */
+ new_row_state = read_row_state(keypad);
+ if (init_row_state != new_row_state) {
+ guard(spinlock_irq)(&keypad->lock);
+ if (unlikely(keypad->scan_pending || keypad->stopped))
+ return;
+ disable_row_irqs(keypad);
+ keypad->scan_pending = true;
+ schedule_delayed_work(&keypad->work,
+ msecs_to_jiffies(keypad->debounce_ms));
+ }
}
static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
{
struct matrix_keypad *keypad = id;
- unsigned long flags;
- spin_lock_irqsave(&keypad->lock, flags);
+ guard(spinlock_irqsave)(&keypad->lock);
/*
* See if another IRQ beaten us to it and scheduled the
@@ -182,10 +208,9 @@ static irqreturn_t matrix_keypad_interrupt(int irq, void *id)
disable_row_irqs(keypad);
keypad->scan_pending = true;
schedule_delayed_work(&keypad->work,
- msecs_to_jiffies(keypad->pdata->debounce_ms));
+ msecs_to_jiffies(keypad->debounce_ms));
out:
- spin_unlock_irqrestore(&keypad->lock, flags);
return IRQ_HANDLED;
}
@@ -209,9 +234,9 @@ static void matrix_keypad_stop(struct input_dev *dev)
{
struct matrix_keypad *keypad = input_get_drvdata(dev);
- spin_lock_irq(&keypad->lock);
- keypad->stopped = true;
- spin_unlock_irq(&keypad->lock);
+ scoped_guard(spinlock_irq, &keypad->lock) {
+ keypad->stopped = true;
+ }
flush_delayed_work(&keypad->work);
/*
@@ -225,7 +250,8 @@ static void matrix_keypad_enable_wakeup(struct matrix_keypad *keypad)
{
int i;
- for_each_clear_bit(i, keypad->wakeup_enabled_irqs, keypad->num_row_irqs)
+ for_each_clear_bit(i, keypad->wakeup_enabled_irqs,
+ keypad->num_row_gpios)
if (enable_irq_wake(keypad->row_irqs[i]) == 0)
__set_bit(i, keypad->wakeup_enabled_irqs);
}
@@ -234,7 +260,8 @@ static void matrix_keypad_disable_wakeup(struct matrix_keypad *keypad)
{
int i;
- for_each_set_bit(i, keypad->wakeup_enabled_irqs, keypad->num_row_irqs) {
+ for_each_set_bit(i, keypad->wakeup_enabled_irqs,
+ keypad->num_row_gpios) {
disable_irq_wake(keypad->row_irqs[i]);
__clear_bit(i, keypad->wakeup_enabled_irqs);
}
@@ -272,182 +299,108 @@ static DEFINE_SIMPLE_DEV_PM_OPS(matrix_keypad_pm_ops,
static int matrix_keypad_init_gpio(struct platform_device *pdev,
struct matrix_keypad *keypad)
{
- const struct matrix_keypad_platform_data *pdata = keypad->pdata;
- int i, irq, err;
-
- /* initialized strobe lines as outputs, activated */
- for (i = 0; i < pdata->num_col_gpios; i++) {
- err = devm_gpio_request(&pdev->dev,
- pdata->col_gpios[i], "matrix_kbd_col");
- if (err) {
- dev_err(&pdev->dev,
- "failed to request GPIO%d for COL%d\n",
- pdata->col_gpios[i], i);
- return err;
- }
+ bool active_low;
+ int nrow, ncol;
+ int err;
+ int i;
- gpio_direction_output(pdata->col_gpios[i], !pdata->active_low);
+ nrow = gpiod_count(&pdev->dev, "row");
+ ncol = gpiod_count(&pdev->dev, "col");
+ if (nrow < 0 || ncol < 0) {
+ dev_err(&pdev->dev, "missing row or column GPIOs\n");
+ return -EINVAL;
}
- for (i = 0; i < pdata->num_row_gpios; i++) {
- err = devm_gpio_request(&pdev->dev,
- pdata->row_gpios[i], "matrix_kbd_row");
+ keypad->num_row_gpios = nrow;
+ keypad->num_col_gpios = ncol;
+
+ active_low = device_property_read_bool(&pdev->dev, "gpio-activelow");
+
+ /* initialize strobe lines as outputs, activated */
+ for (i = 0; i < keypad->num_col_gpios; i++) {
+ keypad->col_gpios[i] = devm_gpiod_get_index(&pdev->dev, "col",
+ i, GPIOD_ASIS);
+ err = PTR_ERR_OR_ZERO(keypad->col_gpios[i]);
if (err) {
dev_err(&pdev->dev,
- "failed to request GPIO%d for ROW%d\n",
- pdata->row_gpios[i], i);
+ "failed to request GPIO for COL%d: %d\n",
+ i, err);
return err;
}
- gpio_direction_input(pdata->row_gpios[i]);
+ gpiod_set_consumer_name(keypad->col_gpios[i], "matrix_kbd_col");
+
+ if (active_low ^ gpiod_is_active_low(keypad->col_gpios[i]))
+ gpiod_toggle_active_low(keypad->col_gpios[i]);
+
+ gpiod_direction_output(keypad->col_gpios[i], 1);
}
- if (pdata->clustered_irq > 0) {
- err = devm_request_any_context_irq(&pdev->dev,
- pdata->clustered_irq,
- matrix_keypad_interrupt,
- pdata->clustered_irq_flags,
- "matrix-keypad", keypad);
- if (err < 0) {
+ for (i = 0; i < keypad->num_row_gpios; i++) {
+ keypad->row_gpios[i] = devm_gpiod_get_index(&pdev->dev, "row",
+ i, GPIOD_IN);
+ err = PTR_ERR_OR_ZERO(keypad->row_gpios[i]);
+ if (err) {
dev_err(&pdev->dev,
- "Unable to acquire clustered interrupt\n");
+ "failed to request GPIO for ROW%d: %d\n",
+ i, err);
return err;
}
- keypad->row_irqs[0] = pdata->clustered_irq;
- keypad->num_row_irqs = 1;
- } else {
- for (i = 0; i < pdata->num_row_gpios; i++) {
- irq = gpio_to_irq(pdata->row_gpios[i]);
- if (irq < 0) {
- err = irq;
- dev_err(&pdev->dev,
- "Unable to convert GPIO line %i to irq: %d\n",
- pdata->row_gpios[i], err);
- return err;
- }
-
- err = devm_request_any_context_irq(&pdev->dev,
- irq,
- matrix_keypad_interrupt,
- IRQF_TRIGGER_RISING |
- IRQF_TRIGGER_FALLING,
- "matrix-keypad", keypad);
- if (err < 0) {
- dev_err(&pdev->dev,
- "Unable to acquire interrupt for GPIO line %i\n",
- pdata->row_gpios[i]);
- return err;
- }
-
- keypad->row_irqs[i] = irq;
- }
+ gpiod_set_consumer_name(keypad->row_gpios[i], "matrix_kbd_row");
- keypad->num_row_irqs = pdata->num_row_gpios;
+ if (active_low ^ gpiod_is_active_low(keypad->row_gpios[i]))
+ gpiod_toggle_active_low(keypad->row_gpios[i]);
}
- /* initialized as disabled - enabled by input->open */
- disable_row_irqs(keypad);
-
return 0;
}
-#ifdef CONFIG_OF
-static struct matrix_keypad_platform_data *
-matrix_keypad_parse_dt(struct device *dev)
+static int matrix_keypad_setup_interrupts(struct platform_device *pdev,
+ struct matrix_keypad *keypad)
{
- struct matrix_keypad_platform_data *pdata;
- struct device_node *np = dev->of_node;
- unsigned int *gpios;
- int ret, i, nrow, ncol;
-
- if (!np) {
- dev_err(dev, "device lacks DT data\n");
- return ERR_PTR(-ENODEV);
- }
-
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "could not allocate memory for platform data\n");
- return ERR_PTR(-ENOMEM);
- }
-
- pdata->num_row_gpios = nrow = gpiod_count(dev, "row");
- pdata->num_col_gpios = ncol = gpiod_count(dev, "col");
- if (nrow < 0 || ncol < 0) {
- dev_err(dev, "number of keypad rows/columns not specified\n");
- return ERR_PTR(-EINVAL);
- }
-
- pdata->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat");
-
- pdata->wakeup = of_property_read_bool(np, "wakeup-source") ||
- of_property_read_bool(np, "linux,wakeup"); /* legacy */
-
- pdata->active_low = of_property_read_bool(np, "gpio-activelow");
-
- pdata->drive_inactive_cols =
- of_property_read_bool(np, "drive-inactive-cols");
-
- of_property_read_u32(np, "debounce-delay-ms", &pdata->debounce_ms);
- of_property_read_u32(np, "col-scan-delay-us",
- &pdata->col_scan_delay_us);
+ int err;
+ int irq;
+ int i;
- gpios = devm_kcalloc(dev,
- pdata->num_row_gpios + pdata->num_col_gpios,
- sizeof(unsigned int),
- GFP_KERNEL);
- if (!gpios) {
- dev_err(dev, "could not allocate memory for gpios\n");
- return ERR_PTR(-ENOMEM);
- }
+ for (i = 0; i < keypad->num_row_gpios; i++) {
+ irq = gpiod_to_irq(keypad->row_gpios[i]);
+ if (irq < 0) {
+ err = irq;
+ dev_err(&pdev->dev,
+ "Unable to convert GPIO line %i to irq: %d\n",
+ i, err);
+ return err;
+ }
- for (i = 0; i < nrow; i++) {
- ret = of_get_named_gpio(np, "row-gpios", i);
- if (ret < 0)
- return ERR_PTR(ret);
- gpios[i] = ret;
- }
+ err = devm_request_any_context_irq(&pdev->dev, irq,
+ matrix_keypad_interrupt,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING,
+ "matrix-keypad", keypad);
+ if (err < 0) {
+ dev_err(&pdev->dev,
+ "Unable to acquire interrupt for row %i: %d\n",
+ i, err);
+ return err;
+ }
- for (i = 0; i < ncol; i++) {
- ret = of_get_named_gpio(np, "col-gpios", i);
- if (ret < 0)
- return ERR_PTR(ret);
- gpios[nrow + i] = ret;
+ keypad->row_irqs[i] = irq;
}
- pdata->row_gpios = gpios;
- pdata->col_gpios = &gpios[pdata->num_row_gpios];
-
- return pdata;
-}
-#else
-static inline struct matrix_keypad_platform_data *
-matrix_keypad_parse_dt(struct device *dev)
-{
- dev_err(dev, "no platform data defined\n");
+ /* initialized as disabled - enabled by input->open */
+ disable_row_irqs(keypad);
- return ERR_PTR(-EINVAL);
+ return 0;
}
-#endif
static int matrix_keypad_probe(struct platform_device *pdev)
{
- const struct matrix_keypad_platform_data *pdata;
struct matrix_keypad *keypad;
struct input_dev *input_dev;
+ bool wakeup;
int err;
- pdata = dev_get_platdata(&pdev->dev);
- if (!pdata) {
- pdata = matrix_keypad_parse_dt(&pdev->dev);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- } else if (!pdata->keymap_data) {
- dev_err(&pdev->dev, "no keymap data defined\n");
- return -EINVAL;
- }
-
keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad)
return -ENOMEM;
@@ -457,40 +410,58 @@ static int matrix_keypad_probe(struct platform_device *pdev)
return -ENOMEM;
keypad->input_dev = input_dev;
- keypad->pdata = pdata;
- keypad->row_shift = get_count_order(pdata->num_col_gpios);
keypad->stopped = true;
INIT_DELAYED_WORK(&keypad->work, matrix_keypad_scan);
spin_lock_init(&keypad->lock);
+ keypad->drive_inactive_cols =
+ device_property_read_bool(&pdev->dev, "drive-inactive-cols");
+ device_property_read_u32(&pdev->dev, "debounce-delay-ms",
+ &keypad->debounce_ms);
+ device_property_read_u32(&pdev->dev, "col-scan-delay-us",
+ &keypad->col_scan_delay_us);
+ device_property_read_u32(&pdev->dev, "all-cols-on-delay-us",
+ &keypad->all_cols_on_delay_us);
+
+ err = matrix_keypad_init_gpio(pdev, keypad);
+ if (err)
+ return err;
+
+ keypad->row_shift = get_count_order(keypad->num_col_gpios);
+
+ err = matrix_keypad_setup_interrupts(pdev, keypad);
+ if (err)
+ return err;
+
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->open = matrix_keypad_start;
input_dev->close = matrix_keypad_stop;
- err = matrix_keypad_build_keymap(pdata->keymap_data, NULL,
- pdata->num_row_gpios,
- pdata->num_col_gpios,
+ err = matrix_keypad_build_keymap(NULL, NULL,
+ keypad->num_row_gpios,
+ keypad->num_col_gpios,
NULL, input_dev);
if (err) {
dev_err(&pdev->dev, "failed to build keymap\n");
return -ENOMEM;
}
- if (!pdata->no_autorepeat)
+ if (!device_property_read_bool(&pdev->dev, "linux,no-autorepeat"))
__set_bit(EV_REP, input_dev->evbit);
+
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, keypad);
- err = matrix_keypad_init_gpio(pdev, keypad);
- if (err)
- return err;
-
err = input_register_device(keypad->input_dev);
if (err)
return err;
- device_init_wakeup(&pdev->dev, pdata->wakeup);
+ wakeup = device_property_read_bool(&pdev->dev, "wakeup-source") ||
+ /* legacy */
+ device_property_read_bool(&pdev->dev, "linux,wakeup");
+ device_init_wakeup(&pdev->dev, wakeup);
+
platform_set_drvdata(pdev, keypad);
return 0;
diff --git a/drivers/input/keyboard/max7360-keypad.c b/drivers/input/keyboard/max7360-keypad.c
new file mode 100644
index 000000000000..503be952b0a6
--- /dev/null
+++ b/drivers/input/keyboard/max7360-keypad.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025 Bootlin
+ *
+ * Author: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/dev_printk.h>
+#include <linux/device/devres.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max7360.h>
+#include <linux/mod_devicetable.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+
+struct max7360_keypad {
+ struct input_dev *input;
+ unsigned int rows;
+ unsigned int cols;
+ unsigned int debounce_ms;
+ int irq;
+ struct regmap *regmap;
+ unsigned short keycodes[MAX7360_MAX_KEY_ROWS * MAX7360_MAX_KEY_COLS];
+};
+
+static irqreturn_t max7360_keypad_irq(int irq, void *data)
+{
+ struct max7360_keypad *max7360_keypad = data;
+ struct device *dev = max7360_keypad->input->dev.parent;
+ unsigned int val;
+ unsigned int row, col;
+ unsigned int release;
+ unsigned int code;
+ int error;
+
+ error = regmap_read(max7360_keypad->regmap, MAX7360_REG_KEYFIFO, &val);
+ if (error) {
+ dev_err(dev, "Failed to read MAX7360 FIFO");
+ return IRQ_NONE;
+ }
+
+ /* FIFO overflow: ignore it and get next event. */
+ if (val == MAX7360_FIFO_OVERFLOW) {
+ dev_warn(dev, "max7360 FIFO overflow");
+ error = regmap_read_poll_timeout(max7360_keypad->regmap, MAX7360_REG_KEYFIFO,
+ val, val != MAX7360_FIFO_OVERFLOW, 0, 1000);
+ if (error) {
+ dev_err(dev, "Failed to empty MAX7360 FIFO");
+ return IRQ_NONE;
+ }
+ }
+
+ if (val == MAX7360_FIFO_EMPTY) {
+ dev_dbg(dev, "Got a spurious interrupt");
+
+ return IRQ_NONE;
+ }
+
+ row = FIELD_GET(MAX7360_FIFO_ROW, val);
+ col = FIELD_GET(MAX7360_FIFO_COL, val);
+ release = val & MAX7360_FIFO_RELEASE;
+
+ code = MATRIX_SCAN_CODE(row, col, get_count_order(max7360_keypad->cols));
+
+ dev_dbg(dev, "key[%d:%d] %s\n", row, col, release ? "release" : "press");
+
+ input_event(max7360_keypad->input, EV_MSC, MSC_SCAN, code);
+ input_report_key(max7360_keypad->input, max7360_keypad->keycodes[code], !release);
+ input_sync(max7360_keypad->input);
+
+ return IRQ_HANDLED;
+}
+
+static int max7360_keypad_open(struct input_dev *pdev)
+{
+ struct max7360_keypad *max7360_keypad = input_get_drvdata(pdev);
+ struct device *dev = max7360_keypad->input->dev.parent;
+ int error;
+
+ /* Somebody is using the device: get out of sleep. */
+ error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_CONFIG,
+ MAX7360_CFG_SLEEP, MAX7360_CFG_SLEEP);
+ if (error)
+ dev_err(dev, "Failed to write max7360 configuration: %d\n", error);
+
+ return error;
+}
+
+static void max7360_keypad_close(struct input_dev *pdev)
+{
+ struct max7360_keypad *max7360_keypad = input_get_drvdata(pdev);
+ struct device *dev = max7360_keypad->input->dev.parent;
+ int error;
+
+ /* Nobody is using the device anymore: go to sleep. */
+ error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_CONFIG, MAX7360_CFG_SLEEP, 0);
+ if (error)
+ dev_err(dev, "Failed to write max7360 configuration: %d\n", error);
+}
+
+static int max7360_keypad_hw_init(struct max7360_keypad *max7360_keypad)
+{
+ struct device *dev = max7360_keypad->input->dev.parent;
+ unsigned int val;
+ int error;
+
+ val = max7360_keypad->debounce_ms - MAX7360_DEBOUNCE_MIN;
+ error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_DEBOUNCE,
+ MAX7360_DEBOUNCE,
+ FIELD_PREP(MAX7360_DEBOUNCE, val));
+ if (error)
+ return dev_err_probe(dev, error,
+ "Failed to write max7360 debounce configuration\n");
+
+ error = regmap_write_bits(max7360_keypad->regmap, MAX7360_REG_INTERRUPT,
+ MAX7360_INTERRUPT_TIME_MASK,
+ FIELD_PREP(MAX7360_INTERRUPT_TIME_MASK, 1));
+ if (error)
+ return dev_err_probe(dev, error,
+ "Failed to write max7360 keypad interrupt configuration\n");
+
+ return 0;
+}
+
+static int max7360_keypad_build_keymap(struct max7360_keypad *max7360_keypad)
+{
+ struct input_dev *input_dev = max7360_keypad->input;
+ struct device *dev = input_dev->dev.parent->parent;
+ struct matrix_keymap_data keymap_data;
+ const char *propname = "linux,keymap";
+ unsigned int max_keys;
+ int error;
+ int size;
+
+ size = device_property_count_u32(dev, propname);
+ if (size <= 0) {
+ dev_err(dev, "missing or malformed property %s: %d\n", propname, size);
+ return size < 0 ? size : -EINVAL;
+ }
+
+ max_keys = max7360_keypad->cols * max7360_keypad->rows;
+ if (size > max_keys) {
+ dev_err(dev, "%s size overflow (%d vs max %u)\n", propname, size, max_keys);
+ return -EINVAL;
+ }
+
+ u32 *keys __free(kfree) = kmalloc_array(size, sizeof(*keys), GFP_KERNEL);
+ if (!keys)
+ return -ENOMEM;
+
+ error = device_property_read_u32_array(dev, propname, keys, size);
+ if (error) {
+ dev_err(dev, "failed to read %s property: %d\n", propname, error);
+ return error;
+ }
+
+ keymap_data.keymap = keys;
+ keymap_data.keymap_size = size;
+ error = matrix_keypad_build_keymap(&keymap_data, NULL,
+ max7360_keypad->rows, max7360_keypad->cols,
+ max7360_keypad->keycodes, max7360_keypad->input);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int max7360_keypad_parse_fw(struct device *dev,
+ struct max7360_keypad *max7360_keypad,
+ bool *autorepeat)
+{
+ int error;
+
+ error = matrix_keypad_parse_properties(dev->parent, &max7360_keypad->rows,
+ &max7360_keypad->cols);
+ if (error)
+ return error;
+
+ if (!max7360_keypad->rows || !max7360_keypad->cols ||
+ max7360_keypad->rows > MAX7360_MAX_KEY_ROWS ||
+ max7360_keypad->cols > MAX7360_MAX_KEY_COLS) {
+ dev_err(dev, "Invalid number of columns or rows (%ux%u)\n",
+ max7360_keypad->cols, max7360_keypad->rows);
+ return -EINVAL;
+ }
+
+ *autorepeat = device_property_read_bool(dev->parent, "autorepeat");
+
+ max7360_keypad->debounce_ms = MAX7360_DEBOUNCE_MIN;
+ error = device_property_read_u32(dev->parent, "keypad-debounce-delay-ms",
+ &max7360_keypad->debounce_ms);
+ if (error == -EINVAL) {
+ dev_info(dev, "Using default keypad-debounce-delay-ms: %u\n",
+ max7360_keypad->debounce_ms);
+ } else if (error < 0) {
+ dev_err(dev, "Failed to read keypad-debounce-delay-ms property\n");
+ return error;
+ }
+
+ if (!in_range(max7360_keypad->debounce_ms, MAX7360_DEBOUNCE_MIN,
+ MAX7360_DEBOUNCE_MAX - MAX7360_DEBOUNCE_MIN + 1)) {
+ dev_err(dev, "Invalid keypad-debounce-delay-ms: %u, should be between %u and %u.\n",
+ max7360_keypad->debounce_ms, MAX7360_DEBOUNCE_MIN, MAX7360_DEBOUNCE_MAX);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int max7360_keypad_probe(struct platform_device *pdev)
+{
+ struct max7360_keypad *max7360_keypad;
+ struct device *dev = &pdev->dev;
+ struct input_dev *input;
+ struct regmap *regmap;
+ bool autorepeat;
+ int error;
+ int irq;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "Could not get parent regmap\n");
+
+ irq = fwnode_irq_get_byname(dev_fwnode(dev->parent), "intk");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get IRQ\n");
+
+ max7360_keypad = devm_kzalloc(dev, sizeof(*max7360_keypad), GFP_KERNEL);
+ if (!max7360_keypad)
+ return -ENOMEM;
+
+ max7360_keypad->regmap = regmap;
+
+ error = max7360_keypad_parse_fw(dev, max7360_keypad, &autorepeat);
+ if (error)
+ return error;
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ max7360_keypad->input = input;
+
+ input->id.bustype = BUS_I2C;
+ input->name = pdev->name;
+ input->open = max7360_keypad_open;
+ input->close = max7360_keypad_close;
+
+ error = max7360_keypad_build_keymap(max7360_keypad);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to build keymap\n");
+
+ input_set_capability(input, EV_MSC, MSC_SCAN);
+ if (autorepeat)
+ __set_bit(EV_REP, input->evbit);
+
+ input_set_drvdata(input, max7360_keypad);
+
+ error = devm_request_threaded_irq(dev, irq, NULL, max7360_keypad_irq,
+ IRQF_ONESHOT,
+ "max7360-keypad", max7360_keypad);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to register interrupt\n");
+
+ error = input_register_device(input);
+ if (error)
+ return dev_err_probe(dev, error, "Could not register input device\n");
+
+ error = max7360_keypad_hw_init(max7360_keypad);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to initialize max7360 keypad\n");
+
+ device_init_wakeup(dev, true);
+ error = dev_pm_set_wake_irq(dev, irq);
+ if (error)
+ dev_warn(dev, "Failed to set up wakeup irq: %d\n", error);
+
+ return 0;
+}
+
+static void max7360_keypad_remove(struct platform_device *pdev)
+{
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+}
+
+static struct platform_driver max7360_keypad_driver = {
+ .driver = {
+ .name = "max7360-keypad",
+ },
+ .probe = max7360_keypad_probe,
+ .remove = max7360_keypad_remove,
+};
+module_platform_driver(max7360_keypad_driver);
+
+MODULE_DESCRIPTION("MAX7360 Keypad driver");
+MODULE_AUTHOR("Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c
deleted file mode 100644
index 2410f676c7f9..000000000000
--- a/drivers/input/keyboard/mcs_touchkey.c
+++ /dev/null
@@ -1,268 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Touchkey driver for MELFAS MCS5000/5080 controller
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: HeungJun Kim <riverful.kim@samsung.com>
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/irq.h>
-#include <linux/slab.h>
-#include <linux/platform_data/mcs.h>
-#include <linux/pm.h>
-
-/* MCS5000 Touchkey */
-#define MCS5000_TOUCHKEY_STATUS 0x04
-#define MCS5000_TOUCHKEY_STATUS_PRESS 7
-#define MCS5000_TOUCHKEY_FW 0x0a
-#define MCS5000_TOUCHKEY_BASE_VAL 0x61
-
-/* MCS5080 Touchkey */
-#define MCS5080_TOUCHKEY_STATUS 0x00
-#define MCS5080_TOUCHKEY_STATUS_PRESS 3
-#define MCS5080_TOUCHKEY_FW 0x01
-#define MCS5080_TOUCHKEY_BASE_VAL 0x1
-
-enum mcs_touchkey_type {
- MCS5000_TOUCHKEY,
- MCS5080_TOUCHKEY,
-};
-
-struct mcs_touchkey_chip {
- unsigned int status_reg;
- unsigned int pressbit;
- unsigned int press_invert;
- unsigned int baseval;
-};
-
-struct mcs_touchkey_data {
- void (*poweron)(bool);
-
- struct i2c_client *client;
- struct input_dev *input_dev;
- struct mcs_touchkey_chip chip;
- unsigned int key_code;
- unsigned int key_val;
- unsigned short keycodes[];
-};
-
-static irqreturn_t mcs_touchkey_interrupt(int irq, void *dev_id)
-{
- struct mcs_touchkey_data *data = dev_id;
- struct mcs_touchkey_chip *chip = &data->chip;
- struct i2c_client *client = data->client;
- struct input_dev *input = data->input_dev;
- unsigned int key_val;
- unsigned int pressed;
- int val;
-
- val = i2c_smbus_read_byte_data(client, chip->status_reg);
- if (val < 0) {
- dev_err(&client->dev, "i2c read error [%d]\n", val);
- goto out;
- }
-
- pressed = (val & (1 << chip->pressbit)) >> chip->pressbit;
- if (chip->press_invert)
- pressed ^= chip->press_invert;
-
- /* key_val is 0 when released, so we should use key_val of press. */
- if (pressed) {
- key_val = val & (0xff >> (8 - chip->pressbit));
- if (!key_val)
- goto out;
- key_val -= chip->baseval;
- data->key_code = data->keycodes[key_val];
- data->key_val = key_val;
- }
-
- input_event(input, EV_MSC, MSC_SCAN, data->key_val);
- input_report_key(input, data->key_code, pressed);
- input_sync(input);
-
- dev_dbg(&client->dev, "key %d %d %s\n", data->key_val, data->key_code,
- pressed ? "pressed" : "released");
-
- out:
- return IRQ_HANDLED;
-}
-
-static void mcs_touchkey_poweroff(void *data)
-{
- struct mcs_touchkey_data *touchkey = data;
-
- touchkey->poweron(false);
-}
-
-static int mcs_touchkey_probe(struct i2c_client *client)
-{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
- const struct mcs_platform_data *pdata;
- struct mcs_touchkey_data *data;
- struct input_dev *input_dev;
- unsigned int fw_reg;
- int fw_ver;
- int error;
- int i;
-
- pdata = dev_get_platdata(&client->dev);
- if (!pdata) {
- dev_err(&client->dev, "no platform data defined\n");
- return -EINVAL;
- }
-
- data = devm_kzalloc(&client->dev,
- struct_size(data, keycodes, pdata->key_maxval + 1),
- GFP_KERNEL);
- if (!data)
- return -ENOMEM;
-
- input_dev = devm_input_allocate_device(&client->dev);
- if (!input_dev) {
- dev_err(&client->dev, "Failed to allocate input device\n");
- return -ENOMEM;
- }
-
- data->client = client;
- data->input_dev = input_dev;
-
- if (id->driver_data == MCS5000_TOUCHKEY) {
- data->chip.status_reg = MCS5000_TOUCHKEY_STATUS;
- data->chip.pressbit = MCS5000_TOUCHKEY_STATUS_PRESS;
- data->chip.baseval = MCS5000_TOUCHKEY_BASE_VAL;
- fw_reg = MCS5000_TOUCHKEY_FW;
- } else {
- data->chip.status_reg = MCS5080_TOUCHKEY_STATUS;
- data->chip.pressbit = MCS5080_TOUCHKEY_STATUS_PRESS;
- data->chip.press_invert = 1;
- data->chip.baseval = MCS5080_TOUCHKEY_BASE_VAL;
- fw_reg = MCS5080_TOUCHKEY_FW;
- }
-
- fw_ver = i2c_smbus_read_byte_data(client, fw_reg);
- if (fw_ver < 0) {
- dev_err(&client->dev, "i2c read error[%d]\n", fw_ver);
- return fw_ver;
- }
- dev_info(&client->dev, "Firmware version: %d\n", fw_ver);
-
- input_dev->name = "MELFAS MCS Touchkey";
- input_dev->id.bustype = BUS_I2C;
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- if (!pdata->no_autorepeat)
- input_dev->evbit[0] |= BIT_MASK(EV_REP);
- input_dev->keycode = data->keycodes;
- input_dev->keycodesize = sizeof(data->keycodes[0]);
- input_dev->keycodemax = pdata->key_maxval + 1;
-
- for (i = 0; i < pdata->keymap_size; i++) {
- unsigned int val = MCS_KEY_VAL(pdata->keymap[i]);
- unsigned int code = MCS_KEY_CODE(pdata->keymap[i]);
-
- data->keycodes[val] = code;
- __set_bit(code, input_dev->keybit);
- }
-
- input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- input_set_drvdata(input_dev, data);
-
- if (pdata->cfg_pin)
- pdata->cfg_pin();
-
- if (pdata->poweron) {
- data->poweron = pdata->poweron;
- data->poweron(true);
-
- error = devm_add_action_or_reset(&client->dev,
- mcs_touchkey_poweroff, data);
- if (error)
- return error;
- }
-
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, mcs_touchkey_interrupt,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->dev.driver->name, data);
- if (error) {
- dev_err(&client->dev, "Failed to register interrupt\n");
- return error;
- }
-
- error = input_register_device(input_dev);
- if (error)
- return error;
-
- i2c_set_clientdata(client, data);
- return 0;
-}
-
-static void mcs_touchkey_shutdown(struct i2c_client *client)
-{
- struct mcs_touchkey_data *data = i2c_get_clientdata(client);
-
- if (data->poweron)
- data->poweron(false);
-}
-
-static int mcs_touchkey_suspend(struct device *dev)
-{
- struct mcs_touchkey_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
-
- /* Disable the work */
- disable_irq(client->irq);
-
- /* Finally turn off the power */
- if (data->poweron)
- data->poweron(false);
-
- return 0;
-}
-
-static int mcs_touchkey_resume(struct device *dev)
-{
- struct mcs_touchkey_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
-
- /* Enable the device first */
- if (data->poweron)
- data->poweron(true);
-
- /* Enable irq again */
- enable_irq(client->irq);
-
- return 0;
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(mcs_touchkey_pm_ops,
- mcs_touchkey_suspend, mcs_touchkey_resume);
-
-static const struct i2c_device_id mcs_touchkey_id[] = {
- { "mcs5000_touchkey", MCS5000_TOUCHKEY },
- { "mcs5080_touchkey", MCS5080_TOUCHKEY },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id);
-
-static struct i2c_driver mcs_touchkey_driver = {
- .driver = {
- .name = "mcs_touchkey",
- .pm = pm_sleep_ptr(&mcs_touchkey_pm_ops),
- },
- .probe = mcs_touchkey_probe,
- .shutdown = mcs_touchkey_shutdown,
- .id_table = mcs_touchkey_id,
-};
-
-module_i2c_driver(mcs_touchkey_driver);
-
-/* Module information */
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_AUTHOR("HeungJun Kim <riverful.kim@samsung.com>");
-MODULE_DESCRIPTION("Touchkey driver for MELFAS MCS5000/5080 controller");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c
index 21827d2497fa..bd1a944ded46 100644
--- a/drivers/input/keyboard/mpr121_touchkey.c
+++ b/drivers/input/keyboard/mpr121_touchkey.c
@@ -82,42 +82,6 @@ static const struct mpr121_init_register init_reg_table[] = {
{ AUTO_CONFIG_CTRL_ADDR, 0x0b },
};
-static void mpr121_vdd_supply_disable(void *data)
-{
- struct regulator *vdd_supply = data;
-
- regulator_disable(vdd_supply);
-}
-
-static struct regulator *mpr121_vdd_supply_init(struct device *dev)
-{
- struct regulator *vdd_supply;
- int err;
-
- vdd_supply = devm_regulator_get(dev, "vdd");
- if (IS_ERR(vdd_supply)) {
- dev_err(dev, "failed to get vdd regulator: %ld\n",
- PTR_ERR(vdd_supply));
- return vdd_supply;
- }
-
- err = regulator_enable(vdd_supply);
- if (err) {
- dev_err(dev, "failed to enable vdd regulator: %d\n", err);
- return ERR_PTR(err);
- }
-
- err = devm_add_action_or_reset(dev, mpr121_vdd_supply_disable,
- vdd_supply);
- if (err) {
- dev_err(dev, "failed to add disable regulator action: %d\n",
- err);
- return ERR_PTR(err);
- }
-
- return vdd_supply;
-}
-
static void mpr_touchkey_report(struct input_dev *dev)
{
struct mpr121_touchkey *mpr121 = input_get_drvdata(dev);
@@ -233,7 +197,6 @@ err_i2c_write:
static int mpr_touchkey_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
- struct regulator *vdd_supply;
int vdd_uv;
struct mpr121_touchkey *mpr121;
struct input_dev *input_dev;
@@ -241,11 +204,9 @@ static int mpr_touchkey_probe(struct i2c_client *client)
int error;
int i;
- vdd_supply = mpr121_vdd_supply_init(dev);
- if (IS_ERR(vdd_supply))
- return PTR_ERR(vdd_supply);
-
- vdd_uv = regulator_get_voltage(vdd_supply);
+ vdd_uv = devm_regulator_get_enable_read_voltage(dev, "vdd");
+ if (vdd_uv < 0)
+ return dev_err_probe(dev, vdd_uv, "failed to get vdd voltage\n");
mpr121 = devm_kzalloc(dev, sizeof(*mpr121), GFP_KERNEL);
if (!mpr121)
diff --git a/drivers/input/keyboard/mt6779-keypad.c b/drivers/input/keyboard/mt6779-keypad.c
index 19f69d167fbd..e5eb025c5e99 100644
--- a/drivers/input/keyboard/mt6779-keypad.c
+++ b/drivers/input/keyboard/mt6779-keypad.c
@@ -92,11 +92,6 @@ static irqreturn_t mt6779_keypad_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void mt6779_keypad_clk_disable(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static void mt6779_keypad_calc_row_col_single(unsigned int key,
unsigned int *row,
unsigned int *col)
@@ -213,21 +208,10 @@ static int mt6779_keypad_pdrv_probe(struct platform_device *pdev)
regmap_update_bits(keypad->regmap, MTK_KPD_SEL, MTK_KPD_SEL_COL,
MTK_KPD_SEL_COLMASK(keypad->n_cols));
- keypad->clk = devm_clk_get(&pdev->dev, "kpd");
+ keypad->clk = devm_clk_get_enabled(&pdev->dev, "kpd");
if (IS_ERR(keypad->clk))
return PTR_ERR(keypad->clk);
- error = clk_prepare_enable(keypad->clk);
- if (error) {
- dev_err(&pdev->dev, "cannot prepare/enable keypad clock\n");
- return error;
- }
-
- error = devm_add_action_or_reset(&pdev->dev, mt6779_keypad_clk_disable,
- keypad->clk);
- if (error)
- return error;
-
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
@@ -260,6 +244,7 @@ static const struct of_device_id mt6779_keypad_of_match[] = {
{ .compatible = "mediatek,mt6873-keypad" },
{ /* sentinel */ }
};
+MODULE_DEVICE_TABLE(of, mt6779_keypad_of_match);
static struct platform_driver mt6779_keypad_pdrv = {
.probe = mt6779_keypad_pdrv_probe,
diff --git a/drivers/input/keyboard/mtk-pmic-keys.c b/drivers/input/keyboard/mtk-pmic-keys.c
index 4364c3401ff1..c78d9f6d97c4 100644
--- a/drivers/input/keyboard/mtk-pmic-keys.c
+++ b/drivers/input/keyboard/mtk-pmic-keys.c
@@ -12,6 +12,7 @@
#include <linux/mfd/mt6331/registers.h>
#include <linux/mfd/mt6357/registers.h>
#include <linux/mfd/mt6358/registers.h>
+#include <linux/mfd/mt6359/registers.h>
#include <linux/mfd/mt6397/core.h>
#include <linux/mfd/mt6397/registers.h>
#include <linux/module.h>
@@ -54,6 +55,7 @@ struct mtk_pmic_regs {
const struct mtk_pmic_keys_regs keys_regs[MTK_PMIC_MAX_KEY_COUNT];
u32 pmic_rst_reg;
u32 rst_lprst_mask; /* Long-press reset timeout bitmask */
+ bool key_release_irq;
};
static const struct mtk_pmic_regs mt6397_regs = {
@@ -115,6 +117,21 @@ static const struct mtk_pmic_regs mt6358_regs = {
MTK_PMIC_HOMEKEY_RST),
.pmic_rst_reg = MT6358_TOP_RST_MISC,
.rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+ .key_release_irq = true,
+};
+
+static const struct mtk_pmic_regs mt6359_regs = {
+ .keys_regs[MTK_PMIC_PWRKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6359_TOPSTATUS,
+ 0x2, MT6359_PSC_TOP_INT_CON0, 0x5,
+ MTK_PMIC_PWRKEY_RST),
+ .keys_regs[MTK_PMIC_HOMEKEY_INDEX] =
+ MTK_PMIC_KEYS_REGS(MT6359_TOPSTATUS,
+ 0x8, MT6359_PSC_TOP_INT_CON0, 0xa,
+ MTK_PMIC_HOMEKEY_RST),
+ .pmic_rst_reg = MT6359_TOP_RST_MISC,
+ .rst_lprst_mask = MTK_PMIC_RST_DU_MASK,
+ .key_release_irq = true,
};
struct mtk_pmic_keys_info {
@@ -147,8 +164,8 @@ static void mtk_pmic_keys_lp_reset_setup(struct mtk_pmic_keys *keys,
u32 value, mask;
int error;
- kregs_home = keys->keys[MTK_PMIC_HOMEKEY_INDEX].regs;
- kregs_pwr = keys->keys[MTK_PMIC_PWRKEY_INDEX].regs;
+ kregs_home = &regs->keys_regs[MTK_PMIC_HOMEKEY_INDEX];
+ kregs_pwr = &regs->keys_regs[MTK_PMIC_PWRKEY_INDEX];
error = of_property_read_u32(keys->dev->of_node, "power-off-time-sec",
&long_press_debounce);
@@ -297,6 +314,9 @@ static const struct of_device_id of_mtk_pmic_keys_match_tbl[] = {
.compatible = "mediatek,mt6358-keys",
.data = &mt6358_regs,
}, {
+ .compatible = "mediatek,mt6359-keys",
+ .data = &mt6359_regs,
+ }, {
/* sentinel */
}
};
@@ -307,7 +327,7 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
int error, index = 0;
unsigned int keycount;
struct mt6397_chip *pmic_chip = dev_get_drvdata(pdev->dev.parent);
- struct device_node *node = pdev->dev.of_node, *child;
+ struct device_node *node = pdev->dev.of_node;
static const char *const irqnames[] = { "powerkey", "homekey" };
static const char *const irqnames_r[] = { "powerkey_r", "homekey_r" };
struct mtk_pmic_keys *keys;
@@ -343,24 +363,20 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
return -EINVAL;
}
- for_each_child_of_node(node, child) {
+ for_each_child_of_node_scoped(node, child) {
keys->keys[index].regs = &mtk_pmic_regs->keys_regs[index];
keys->keys[index].irq =
platform_get_irq_byname(pdev, irqnames[index]);
- if (keys->keys[index].irq < 0) {
- of_node_put(child);
+ if (keys->keys[index].irq < 0)
return keys->keys[index].irq;
- }
- if (of_device_is_compatible(node, "mediatek,mt6358-keys")) {
+ if (mtk_pmic_regs->key_release_irq) {
keys->keys[index].irq_r = platform_get_irq_byname(pdev,
irqnames_r[index]);
- if (keys->keys[index].irq_r < 0) {
- of_node_put(child);
+ if (keys->keys[index].irq_r < 0)
return keys->keys[index].irq_r;
- }
}
error = of_property_read_u32(child,
@@ -369,7 +385,6 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
dev_err(keys->dev,
"failed to read key:%d linux,keycode property: %d\n",
index, error);
- of_node_put(child);
return error;
}
@@ -377,10 +392,8 @@ static int mtk_pmic_keys_probe(struct platform_device *pdev)
keys->keys[index].wakeup = true;
error = mtk_pmic_key_setup(keys, &keys->keys[index]);
- if (error) {
- of_node_put(child);
+ if (error)
return error;
- }
index++;
}
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index df00a119aa9a..71e0a3f830dd 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -68,7 +68,7 @@ static int nkbd_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- nkbd = kzalloc(sizeof(struct nkbd), GFP_KERNEL);
+ nkbd = kzalloc(sizeof(*nkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!nkbd || !input_dev)
goto fail1;
diff --git a/drivers/input/keyboard/nomadik-ske-keypad.c b/drivers/input/keyboard/nomadik-ske-keypad.c
deleted file mode 100644
index b3ccc97f61e1..000000000000
--- a/drivers/input/keyboard/nomadik-ske-keypad.c
+++ /dev/null
@@ -1,378 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright (C) ST-Ericsson SA 2010
- *
- * Author: Naveen Kumar G <naveen.gaddipati@stericsson.com> for ST-Ericsson
- * Author: Sundar Iyer <sundar.iyer@stericsson.com> for ST-Ericsson
- *
- * Keypad controller driver for the SKE (Scroll Key Encoder) module used in
- * the Nomadik 8815 and Ux500 platforms.
- */
-
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/clk.h>
-#include <linux/module.h>
-
-#include <linux/platform_data/keypad-nomadik-ske.h>
-
-/* SKE_CR bits */
-#define SKE_KPMLT (0x1 << 6)
-#define SKE_KPCN (0x7 << 3)
-#define SKE_KPASEN (0x1 << 2)
-#define SKE_KPASON (0x1 << 7)
-
-/* SKE_IMSC bits */
-#define SKE_KPIMA (0x1 << 2)
-
-/* SKE_ICR bits */
-#define SKE_KPICS (0x1 << 3)
-#define SKE_KPICA (0x1 << 2)
-
-/* SKE_RIS bits */
-#define SKE_KPRISA (0x1 << 2)
-
-#define SKE_KEYPAD_ROW_SHIFT 3
-#define SKE_KPD_NUM_ROWS 8
-#define SKE_KPD_NUM_COLS 8
-
-/* keypad auto scan registers */
-#define SKE_ASR0 0x20
-#define SKE_ASR1 0x24
-#define SKE_ASR2 0x28
-#define SKE_ASR3 0x2C
-
-#define SKE_NUM_ASRX_REGISTERS (4)
-#define KEY_PRESSED_DELAY 10
-
-/**
- * struct ske_keypad - data structure used by keypad driver
- * @irq: irq no
- * @reg_base: ske registers base address
- * @input: pointer to input device object
- * @board: keypad platform device
- * @keymap: matrix scan code table for keycodes
- * @clk: clock structure pointer
- * @pclk: clock structure pointer
- * @ske_keypad_lock: spinlock protecting the keypad read/writes
- */
-struct ske_keypad {
- int irq;
- void __iomem *reg_base;
- struct input_dev *input;
- const struct ske_keypad_platform_data *board;
- unsigned short keymap[SKE_KPD_NUM_ROWS * SKE_KPD_NUM_COLS];
- struct clk *clk;
- struct clk *pclk;
- spinlock_t ske_keypad_lock;
-};
-
-static void ske_keypad_set_bits(struct ske_keypad *keypad, u16 addr,
- u8 mask, u8 data)
-{
- u32 ret;
-
- spin_lock(&keypad->ske_keypad_lock);
-
- ret = readl(keypad->reg_base + addr);
- ret &= ~mask;
- ret |= data;
- writel(ret, keypad->reg_base + addr);
-
- spin_unlock(&keypad->ske_keypad_lock);
-}
-
-/*
- * ske_keypad_chip_init: init keypad controller configuration
- *
- * Enable Multi key press detection, auto scan mode
- */
-static int __init ske_keypad_chip_init(struct ske_keypad *keypad)
-{
- u32 value;
- int timeout = keypad->board->debounce_ms;
-
- /* check SKE_RIS to be 0 */
- while ((readl(keypad->reg_base + SKE_RIS) != 0x00000000) && timeout--)
- cpu_relax();
-
- if (timeout == -1)
- return -EINVAL;
-
- /*
- * set debounce value
- * keypad dbounce is configured in DBCR[15:8]
- * dbounce value in steps of 32/32.768 ms
- */
- spin_lock(&keypad->ske_keypad_lock);
- value = readl(keypad->reg_base + SKE_DBCR);
- value = value & 0xff;
- value |= ((keypad->board->debounce_ms * 32000)/32768) << 8;
- writel(value, keypad->reg_base + SKE_DBCR);
- spin_unlock(&keypad->ske_keypad_lock);
-
- /* enable multi key detection */
- ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPMLT);
-
- /*
- * set up the number of columns
- * KPCN[5:3] defines no. of keypad columns to be auto scanned
- */
- value = (keypad->board->kcol - 1) << 3;
- ske_keypad_set_bits(keypad, SKE_CR, SKE_KPCN, value);
-
- /* clear keypad interrupt for auto(and pending SW) scans */
- ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA | SKE_KPICS);
-
- /* un-mask keypad interrupts */
- ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
-
- /* enable automatic scan */
- ske_keypad_set_bits(keypad, SKE_CR, 0x0, SKE_KPASEN);
-
- return 0;
-}
-
-static void ske_keypad_report(struct ske_keypad *keypad, u8 status, int col)
-{
- int row = 0, code, pos;
- struct input_dev *input = keypad->input;
- u32 ske_ris;
- int key_pressed;
- int num_of_rows;
-
- /* find out the row */
- num_of_rows = hweight8(status);
- do {
- pos = __ffs(status);
- row = pos;
- status &= ~(1 << pos);
-
- code = MATRIX_SCAN_CODE(row, col, SKE_KEYPAD_ROW_SHIFT);
- ske_ris = readl(keypad->reg_base + SKE_RIS);
- key_pressed = ske_ris & SKE_KPRISA;
-
- input_event(input, EV_MSC, MSC_SCAN, code);
- input_report_key(input, keypad->keymap[code], key_pressed);
- input_sync(input);
- num_of_rows--;
- } while (num_of_rows);
-}
-
-static void ske_keypad_read_data(struct ske_keypad *keypad)
-{
- u8 status;
- int col = 0;
- int ske_asr, i;
-
- /*
- * Read the auto scan registers
- *
- * Each SKE_ASRx (x=0 to x=3) contains two row values.
- * lower byte contains row value for column 2*x,
- * upper byte contains row value for column 2*x + 1
- */
- for (i = 0; i < SKE_NUM_ASRX_REGISTERS; i++) {
- ske_asr = readl(keypad->reg_base + SKE_ASR0 + (4 * i));
- if (!ske_asr)
- continue;
-
- /* now that ASRx is zero, find out the coloumn x and row y */
- status = ske_asr & 0xff;
- if (status) {
- col = i * 2;
- ske_keypad_report(keypad, status, col);
- }
- status = (ske_asr & 0xff00) >> 8;
- if (status) {
- col = (i * 2) + 1;
- ske_keypad_report(keypad, status, col);
- }
- }
-}
-
-static irqreturn_t ske_keypad_irq(int irq, void *dev_id)
-{
- struct ske_keypad *keypad = dev_id;
- int timeout = keypad->board->debounce_ms;
-
- /* disable auto scan interrupt; mask the interrupt generated */
- ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
- ske_keypad_set_bits(keypad, SKE_ICR, 0x0, SKE_KPICA);
-
- while ((readl(keypad->reg_base + SKE_CR) & SKE_KPASON) && --timeout)
- cpu_relax();
-
- /* SKEx registers are stable and can be read */
- ske_keypad_read_data(keypad);
-
- /* wait until raw interrupt is clear */
- while ((readl(keypad->reg_base + SKE_RIS)) && --timeout)
- msleep(KEY_PRESSED_DELAY);
-
- /* enable auto scan interrupts */
- ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
-
- 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;
- int irq;
- int error;
-
- if (!plat) {
- dev_err(&pdev->dev, "invalid keypad platform data\n");
- return -EINVAL;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- 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");
- return -ENOMEM;
- }
-
- keypad->irq = irq;
- keypad->board = plat;
- keypad->input = input;
- spin_lock_init(&keypad->ske_keypad_lock);
-
- keypad->reg_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(keypad->reg_base))
- return PTR_ERR(keypad->reg_base);
-
- keypad->pclk = devm_clk_get_enabled(dev, "apb_pclk");
- if (IS_ERR(keypad->pclk)) {
- dev_err(&pdev->dev, "failed to get pclk\n");
- return PTR_ERR(keypad->pclk);
- }
-
- keypad->clk = devm_clk_get_enabled(dev, NULL);
- if (IS_ERR(keypad->clk)) {
- dev_err(&pdev->dev, "failed to get clk\n");
- return PTR_ERR(keypad->clk);
- }
-
- input->id.bustype = BUS_HOST;
- input->name = "ux500-ske-keypad";
- input->dev.parent = &pdev->dev;
-
- error = matrix_keypad_build_keymap(plat->keymap_data, NULL,
- SKE_KPD_NUM_ROWS, SKE_KPD_NUM_COLS,
- keypad->keymap, input);
- if (error) {
- dev_err(&pdev->dev, "Failed to build keymap\n");
- return error;
- }
-
- input_set_capability(input, EV_MSC, MSC_SCAN);
- if (!plat->no_autorepeat)
- __set_bit(EV_REP, input->evbit);
-
- /* 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");
- return error;
- }
-
- 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);
- return error;
- }
-
- error = input_register_device(input);
- if (error) {
- dev_err(&pdev->dev,
- "unable to register input device: %d\n", error);
- return error;
- }
-
- if (plat->wakeup_enable)
- device_init_wakeup(&pdev->dev, true);
-
- platform_set_drvdata(pdev, keypad);
-
- return 0;
-}
-
-static int ske_keypad_suspend(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct ske_keypad *keypad = platform_get_drvdata(pdev);
- int irq = platform_get_irq(pdev, 0);
-
- if (device_may_wakeup(dev))
- enable_irq_wake(irq);
- else
- ske_keypad_set_bits(keypad, SKE_IMSC, ~SKE_KPIMA, 0x0);
-
- return 0;
-}
-
-static int ske_keypad_resume(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
- struct ske_keypad *keypad = platform_get_drvdata(pdev);
- int irq = platform_get_irq(pdev, 0);
-
- if (device_may_wakeup(dev))
- disable_irq_wake(irq);
- else
- ske_keypad_set_bits(keypad, SKE_IMSC, 0x0, SKE_KPIMA);
-
- return 0;
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(ske_keypad_dev_pm_ops,
- ske_keypad_suspend, ske_keypad_resume);
-
-static struct platform_driver ske_keypad_driver = {
- .driver = {
- .name = "nmk-ske-keypad",
- .pm = pm_sleep_ptr(&ske_keypad_dev_pm_ops),
- },
-};
-
-module_platform_driver_probe(ske_keypad_driver, ske_keypad_probe);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Naveen Kumar <naveen.gaddipati@stericsson.com> / Sundar Iyer <sundar.iyer@stericsson.com>");
-MODULE_DESCRIPTION("Nomadik Scroll-Key-Encoder Keypad Driver");
-MODULE_ALIAS("platform:nomadik-ske-keypad");
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
index 16f936db7305..9e13f3f70a81 100644
--- a/drivers/input/keyboard/omap-keypad.c
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -156,21 +156,27 @@ static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute
if ((state != 1) && (state != 0))
return -EINVAL;
- mutex_lock(&kp_enable_mutex);
- if (state != kp_enable) {
- if (state)
- enable_irq(omap_kp->irq);
- else
- disable_irq(omap_kp->irq);
- kp_enable = state;
+ scoped_guard(mutex, &kp_enable_mutex) {
+ if (state != kp_enable) {
+ if (state)
+ enable_irq(omap_kp->irq);
+ else
+ disable_irq(omap_kp->irq);
+ kp_enable = state;
+ }
}
- mutex_unlock(&kp_enable_mutex);
return strnlen(buf, count);
}
static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
+static struct attribute *omap_kp_attrs[] = {
+ &dev_attr_enable.attr,
+ NULL
+};
+ATTRIBUTE_GROUPS(omap_kp);
+
static int omap_kp_probe(struct platform_device *pdev)
{
struct omap_kp *omap_kp;
@@ -214,10 +220,6 @@ static int omap_kp_probe(struct platform_device *pdev)
kp_tasklet.data = (unsigned long) omap_kp;
tasklet_enable(&kp_tasklet);
- ret = device_create_file(&pdev->dev, &dev_attr_enable);
- if (ret < 0)
- goto err2;
-
/* setup input device */
input_dev->name = "omap-keypad";
input_dev->phys = "omap-keypad/input0";
@@ -235,12 +237,12 @@ static int omap_kp_probe(struct platform_device *pdev)
pdata->rows, pdata->cols,
omap_kp->keymap, input_dev);
if (ret < 0)
- goto err3;
+ goto err2;
ret = input_register_device(omap_kp->input);
if (ret < 0) {
printk(KERN_ERR "Unable to register omap-keypad input device\n");
- goto err3;
+ goto err2;
}
if (pdata->dbounce)
@@ -252,17 +254,15 @@ static int omap_kp_probe(struct platform_device *pdev)
if (omap_kp->irq >= 0) {
if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
"omap-keypad", omap_kp) < 0)
- goto err4;
+ goto err3;
}
omap_writew(0, OMAP1_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
return 0;
-err4:
+err3:
input_unregister_device(omap_kp->input);
input_dev = NULL;
-err3:
- device_remove_file(&pdev->dev, &dev_attr_enable);
err2:
kfree(omap_kp);
input_free_device(input_dev);
@@ -290,9 +290,10 @@ static void omap_kp_remove(struct platform_device *pdev)
static struct platform_driver omap_kp_driver = {
.probe = omap_kp_probe,
- .remove_new = omap_kp_remove,
+ .remove = omap_kp_remove,
.driver = {
.name = "omap-keypad",
+ .dev_groups = omap_kp_groups,
},
};
module_platform_driver(omap_kp_driver);
diff --git a/drivers/input/keyboard/omap4-keypad.c b/drivers/input/keyboard/omap4-keypad.c
index 040b340995d8..bffe89c0717a 100644
--- a/drivers/input/keyboard/omap4-keypad.c
+++ b/drivers/input/keyboard/omap4-keypad.c
@@ -144,7 +144,7 @@ static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys)
{
u64 changed;
- mutex_lock(&keypad_data->lock);
+ guard(mutex)(&keypad_data->lock);
changed = keys ^ keypad_data->keys;
@@ -158,8 +158,6 @@ static void omap4_keypad_scan_keys(struct omap4_keypad *keypad_data, u64 keys)
omap4_keypad_report_keys(keypad_data, changed & keys, true);
keypad_data->keys = keys;
-
- mutex_unlock(&keypad_data->lock);
}
/* Interrupt handlers */
@@ -487,7 +485,7 @@ MODULE_DEVICE_TABLE(of, omap_keypad_dt_match);
static struct platform_driver omap4_keypad_driver = {
.probe = omap4_keypad_probe,
- .remove_new = omap4_keypad_remove,
+ .remove = omap4_keypad_remove,
.driver = {
.name = "omap4-keypad",
.of_match_table = omap_keypad_dt_match,
diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c
index 26a005f9ace3..35d1aa2a22a5 100644
--- a/drivers/input/keyboard/pmic8xxx-keypad.c
+++ b/drivers/input/keyboard/pmic8xxx-keypad.c
@@ -630,12 +630,10 @@ static int pmic8xxx_kp_suspend(struct device *dev)
if (device_may_wakeup(dev)) {
enable_irq_wake(kp->key_sense_irq);
} else {
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
pmic8xxx_kp_disable(kp);
-
- mutex_unlock(&input_dev->mutex);
}
return 0;
@@ -650,12 +648,10 @@ static int pmic8xxx_kp_resume(struct device *dev)
if (device_may_wakeup(dev)) {
disable_irq_wake(kp->key_sense_irq);
} else {
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
pmic8xxx_kp_enable(kp);
-
- mutex_unlock(&input_dev->mutex);
}
return 0;
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index 3724363d140e..4519eecb317b 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -12,7 +12,8 @@
* on some suggestions by Nicolas Pitre <nico@fluxnic.net>.
*/
-
+#include <linux/bits.h>
+#include <linux/bitfield.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
@@ -20,124 +21,148 @@
#include <linux/io.h>
#include <linux/device.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/input/matrix_keypad.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/platform_data/keypad-pxa27x.h>
/*
* Keypad Controller registers
*/
-#define KPC 0x0000 /* Keypad Control register */
-#define KPDK 0x0008 /* Keypad Direct Key register */
-#define KPREC 0x0010 /* Keypad Rotary Encoder register */
-#define KPMK 0x0018 /* Keypad Matrix Key register */
-#define KPAS 0x0020 /* Keypad Automatic Scan register */
+#define KPC 0x0000 /* Keypad Control register */
+#define KPDK 0x0008 /* Keypad Direct Key register */
+#define KPREC 0x0010 /* Keypad Rotary Encoder register */
+#define KPMK 0x0018 /* Keypad Matrix Key register */
+#define KPAS 0x0020 /* Keypad Automatic Scan register */
/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
-#define KPASMKP0 0x0028
-#define KPASMKP1 0x0030
-#define KPASMKP2 0x0038
-#define KPASMKP3 0x0040
-#define KPKDI 0x0048
+#define KPASMKP0 0x0028
+#define KPASMKP1 0x0030
+#define KPASMKP2 0x0038
+#define KPASMKP3 0x0040
+#define KPKDI 0x0048
/* bit definitions */
-#define KPC_MKRN(n) ((((n) - 1) & 0x7) << 26) /* matrix key row number */
-#define KPC_MKCN(n) ((((n) - 1) & 0x7) << 23) /* matrix key column number */
-#define KPC_DKN(n) ((((n) - 1) & 0x7) << 6) /* direct key number */
-
-#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
-#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
-#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
-#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
-
-#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */
-#define KPC_MS_ALL (0xff << 13)
-
-#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
-#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
-#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
-#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
-#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
-#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
-#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
-#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
-#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
-
-#define KPDK_DKP (0x1 << 31)
-#define KPDK_DK(n) ((n) & 0xff)
-
-#define KPREC_OF1 (0x1 << 31)
-#define kPREC_UF1 (0x1 << 30)
-#define KPREC_OF0 (0x1 << 15)
-#define KPREC_UF0 (0x1 << 14)
-
-#define KPREC_RECOUNT0(n) ((n) & 0xff)
-#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff)
-
-#define KPMK_MKP (0x1 << 31)
-#define KPAS_SO (0x1 << 31)
-#define KPASMKPx_SO (0x1 << 31)
-
-#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
-#define KPAS_RP(n) (((n) >> 4) & 0xf)
-#define KPAS_CP(n) ((n) & 0xf)
-
-#define KPASMKP_MKC_MASK (0xff)
+#define KPC_MKRN_MASK GENMASK(28, 26)
+#define KPC_MKCN_MASK GENMASK(25, 23)
+#define KPC_DKN_MASK GENMASK(8, 6)
+#define KPC_MKRN(n) FIELD_PREP(KPC_MKRN_MASK, (n) - 1)
+#define KPC_MKCN(n) FIELD_PREP(KPC_MKCN_MASK, (n) - 1)
+#define KPC_DKN(n) FIELD_PREP(KPC_DKN_MASK, (n) - 1)
+
+#define KPC_AS BIT(30) /* Automatic Scan bit */
+#define KPC_ASACT BIT(29) /* Automatic Scan on Activity */
+#define KPC_MI BIT(22) /* Matrix interrupt bit */
+#define KPC_IMKP BIT(21) /* Ignore Multiple Key Press */
+
+#define KPC_MS(n) BIT(13 + (n)) /* Matrix scan line 'n' */
+#define KPC_MS_ALL GENMASK(20, 13)
+
+#define KPC_ME BIT(12) /* Matrix Keypad Enable */
+#define KPC_MIE BIT(11) /* Matrix Interrupt Enable */
+#define KPC_DK_DEB_SEL BIT(9) /* Direct Keypad Debounce Select */
+#define KPC_DI BIT(5) /* Direct key interrupt bit */
+#define KPC_RE_ZERO_DEB BIT(4) /* Rotary Encoder Zero Debounce */
+#define KPC_REE1 BIT(3) /* Rotary Encoder1 Enable */
+#define KPC_REE0 BIT(2) /* Rotary Encoder0 Enable */
+#define KPC_DE BIT(1) /* Direct Keypad Enable */
+#define KPC_DIE BIT(0) /* Direct Keypad interrupt Enable */
+
+#define KPDK_DKP BIT(31)
+#define KPDK_DK_MASK GENMASK(7, 0)
+#define KPDK_DK(n) FIELD_GET(KPDK_DK_MASK, n)
+
+#define KPREC_OF1 BIT(31)
+#define KPREC_UF1 BIT(30)
+#define KPREC_OF0 BIT(15)
+#define KPREC_UF0 BIT(14)
+
+#define KPREC_RECOUNT0_MASK GENMASK(7, 0)
+#define KPREC_RECOUNT1_MASK GENMASK(23, 16)
+#define KPREC_RECOUNT0(n) FIELD_GET(KPREC_RECOUNT0_MASK, n)
+#define KPREC_RECOUNT1(n) FIELD_GET(KPREC_RECOUNT1_MASK, n)
+
+#define KPMK_MKP BIT(31)
+#define KPAS_SO BIT(31)
+#define KPASMKPx_SO BIT(31)
+
+#define KPAS_MUKP_MASK GENMASK(30, 26)
+#define KPAS_RP_MASK GENMASK(7, 4)
+#define KPAS_CP_MASK GENMASK(3, 0)
+#define KPAS_MUKP(n) FIELD_GET(KPAS_MUKP_MASK, n)
+#define KPAS_RP(n) FIELD_GET(KPAS_RP_MASK, n)
+#define KPAS_CP(n) FIELD_GET(KPAS_CP_MASK, n)
+
+#define KPASMKP_MKC_MASK GENMASK(7, 0)
#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
+#define MAX_MATRIX_KEY_ROWS 8
+#define MAX_MATRIX_KEY_COLS 8
+#define MAX_DIRECT_KEY_NUM 8
+#define MAX_ROTARY_ENCODERS 2
+
#define MAX_MATRIX_KEY_NUM (MAX_MATRIX_KEY_ROWS * MAX_MATRIX_KEY_COLS)
#define MAX_KEYPAD_KEYS (MAX_MATRIX_KEY_NUM + MAX_DIRECT_KEY_NUM)
-struct pxa27x_keypad {
- const struct pxa27x_keypad_platform_data *pdata;
+struct pxa27x_keypad_rotary {
+ unsigned short *key_codes;
+ int rel_code;
+ bool enabled;
+};
+struct pxa27x_keypad {
struct clk *clk;
struct input_dev *input_dev;
void __iomem *mmio_base;
int irq;
- unsigned short keycodes[MAX_KEYPAD_KEYS];
- int rotary_rel_code[2];
-
+ unsigned int matrix_key_rows;
+ unsigned int matrix_key_cols;
unsigned int row_shift;
+ unsigned int direct_key_num;
+ unsigned int direct_key_mask;
+ bool direct_key_low_active;
+
+ /* key debounce interval */
+ unsigned int debounce_interval;
+
+ unsigned short keycodes[MAX_KEYPAD_KEYS];
+
/* state row bits of each column scan */
- uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
- uint32_t direct_key_state;
+ u32 matrix_key_state[MAX_MATRIX_KEY_COLS];
+ u32 direct_key_state;
- unsigned int direct_key_mask;
+ struct pxa27x_keypad_rotary rotary[MAX_ROTARY_ENCODERS];
};
-#ifdef CONFIG_OF
-static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
- struct pxa27x_keypad_platform_data *pdata)
+static int pxa27x_keypad_matrix_key_parse(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
- u32 rows, cols;
int error;
- error = matrix_keypad_parse_properties(dev, &rows, &cols);
+ error = matrix_keypad_parse_properties(dev, &keypad->matrix_key_rows,
+ &keypad->matrix_key_cols);
if (error)
return error;
- if (rows > MAX_MATRIX_KEY_ROWS || cols > MAX_MATRIX_KEY_COLS) {
+ if (keypad->matrix_key_rows > MAX_MATRIX_KEY_ROWS ||
+ keypad->matrix_key_cols > MAX_MATRIX_KEY_COLS) {
dev_err(dev, "rows or cols exceeds maximum value\n");
return -EINVAL;
}
- pdata->matrix_key_rows = rows;
- pdata->matrix_key_cols = cols;
+ keypad->row_shift = get_count_order(keypad->matrix_key_cols);
error = matrix_keypad_build_keymap(NULL, NULL,
- pdata->matrix_key_rows,
- pdata->matrix_key_cols,
+ keypad->matrix_key_rows,
+ keypad->matrix_key_cols,
keypad->keycodes, input_dev);
if (error)
return error;
@@ -145,20 +170,17 @@ static int pxa27x_keypad_matrix_key_parse_dt(struct pxa27x_keypad *keypad,
return 0;
}
-static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
- struct pxa27x_keypad_platform_data *pdata)
+static int pxa27x_keypad_direct_key_parse(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
- struct device_node *np = dev->of_node;
- const __be16 *prop;
unsigned short code;
- unsigned int proplen, size;
+ int count;
int i;
int error;
- error = of_property_read_u32(np, "marvell,direct-key-count",
- &pdata->direct_key_num);
+ error = device_property_read_u32(dev, "marvell,direct-key-count",
+ &keypad->direct_key_num);
if (error) {
/*
* If do not have marvel,direct-key-count defined,
@@ -167,151 +189,121 @@ static int pxa27x_keypad_direct_key_parse_dt(struct pxa27x_keypad *keypad,
return error == -EINVAL ? 0 : error;
}
- error = of_property_read_u32(np, "marvell,direct-key-mask",
- &pdata->direct_key_mask);
+ error = device_property_read_u32(dev, "marvell,direct-key-mask",
+ &keypad->direct_key_mask);
if (error) {
if (error != -EINVAL)
return error;
/*
* If marvell,direct-key-mask is not defined, driver will use
- * default value. Default value is set when configure the keypad.
+ * a default value based on number of direct keys set up.
+ * The default value is calculated in pxa27x_keypad_config().
*/
- pdata->direct_key_mask = 0;
+ keypad->direct_key_mask = 0;
}
- pdata->direct_key_low_active = of_property_read_bool(np,
- "marvell,direct-key-low-active");
+ keypad->direct_key_low_active =
+ device_property_read_bool(dev, "marvell,direct-key-low-active");
- prop = of_get_property(np, "marvell,direct-key-map", &proplen);
- if (!prop)
+ count = device_property_count_u16(dev, "marvell,direct-key-map");
+ if (count <= 0 || count > MAX_DIRECT_KEY_NUM)
return -EINVAL;
- if (proplen % sizeof(u16))
- return -EINVAL;
-
- size = proplen / sizeof(u16);
+ error = device_property_read_u16_array(dev, "marvell,direct-key-map",
+ &keypad->keycodes[MAX_MATRIX_KEY_NUM],
+ count);
- /* Only MAX_DIRECT_KEY_NUM is accepted.*/
- if (size > MAX_DIRECT_KEY_NUM)
- return -EINVAL;
-
- for (i = 0; i < size; i++) {
- code = be16_to_cpup(prop + i);
- keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = code;
+ for (i = 0; i < count; i++) {
+ code = keypad->keycodes[MAX_MATRIX_KEY_NUM + i];
__set_bit(code, input_dev->keybit);
}
return 0;
}
-static int pxa27x_keypad_rotary_parse_dt(struct pxa27x_keypad *keypad,
- struct pxa27x_keypad_platform_data *pdata)
+static int pxa27x_keypad_rotary_parse(struct pxa27x_keypad *keypad)
{
- const __be32 *prop;
- int i, relkey_ret;
- unsigned int code, proplen;
- const char *rotaryname[2] = {
- "marvell,rotary0", "marvell,rotary1"};
- const char relkeyname[] = {"marvell,rotary-rel-key"};
+ static const char * const rotaryname[] = { "marvell,rotary0", "marvell,rotary1" };
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
- struct device_node *np = dev->of_node;
-
- relkey_ret = of_property_read_u32(np, relkeyname, &code);
- /* if can read correct rotary key-code, we do not need this. */
- if (relkey_ret == 0) {
- unsigned short relcode;
+ struct pxa27x_keypad_rotary *encoder;
+ unsigned int code;
+ int i;
+ int error;
- /* rotary0 taks lower half, rotary1 taks upper half. */
- relcode = code & 0xffff;
- pdata->rotary0_rel_code = (code & 0xffff);
- __set_bit(relcode, input_dev->relbit);
+ error = device_property_read_u32(dev, "marvell,rotary-rel-key", &code);
+ if (!error) {
+ for (i = 0; i < MAX_ROTARY_ENCODERS; i++, code >>= 16) {
+ encoder = &keypad->rotary[i];
+ encoder->enabled = true;
+ encoder->rel_code = code & 0xffff;
+ input_set_capability(input_dev, EV_REL, encoder->rel_code);
+ }
- relcode = code >> 16;
- pdata->rotary1_rel_code = relcode;
- __set_bit(relcode, input_dev->relbit);
+ return 0;
}
- for (i = 0; i < 2; i++) {
- prop = of_get_property(np, rotaryname[i], &proplen);
+ for (i = 0; i < MAX_ROTARY_ENCODERS; i++) {
+ encoder = &keypad->rotary[i];
+
/*
* If the prop is not set, it means keypad does not need
* initialize the rotaryX.
*/
- if (!prop)
+ if (!device_property_present(dev, rotaryname[i]))
continue;
- code = be32_to_cpup(prop);
+ error = device_property_read_u32(dev, rotaryname[i], &code);
+ if (error)
+ return error;
+
/*
* Not all up/down key code are valid.
* Now we depends on direct-rel-code.
*/
- if ((!(code & 0xffff) || !(code >> 16)) && relkey_ret) {
- return relkey_ret;
- } else {
- unsigned int n = MAX_MATRIX_KEY_NUM + (i << 1);
- unsigned short keycode;
-
- keycode = code & 0xffff;
- keypad->keycodes[n] = keycode;
- __set_bit(keycode, input_dev->keybit);
-
- keycode = code >> 16;
- keypad->keycodes[n + 1] = keycode;
- __set_bit(keycode, input_dev->keybit);
-
- if (i == 0)
- pdata->rotary0_rel_code = -1;
- else
- pdata->rotary1_rel_code = -1;
- }
- if (i == 0)
- pdata->enable_rotary0 = 1;
- else
- pdata->enable_rotary1 = 1;
- }
+ if (!(code & 0xffff) || !(code >> 16))
+ return -EINVAL;
- keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
- keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
+ encoder->enabled = true;
+ encoder->rel_code = -1;
+ encoder->key_codes = &keypad->keycodes[MAX_MATRIX_KEY_NUM + i * 2];
+ encoder->key_codes[0] = code & 0xffff;
+ encoder->key_codes[1] = code >> 16;
+
+ input_set_capability(input_dev, EV_KEY, encoder->key_codes[0]);
+ input_set_capability(input_dev, EV_KEY, encoder->key_codes[1]);
+ }
return 0;
}
-static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
+static int pxa27x_keypad_parse_properties(struct pxa27x_keypad *keypad)
{
struct input_dev *input_dev = keypad->input_dev;
struct device *dev = input_dev->dev.parent;
- struct device_node *np = dev->of_node;
- struct pxa27x_keypad_platform_data *pdata;
int error;
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "failed to allocate memory for pdata\n");
- return -ENOMEM;
- }
-
- error = pxa27x_keypad_matrix_key_parse_dt(keypad, pdata);
+ error = pxa27x_keypad_matrix_key_parse(keypad);
if (error) {
dev_err(dev, "failed to parse matrix key\n");
return error;
}
- error = pxa27x_keypad_direct_key_parse_dt(keypad, pdata);
+ error = pxa27x_keypad_direct_key_parse(keypad);
if (error) {
dev_err(dev, "failed to parse direct key\n");
return error;
}
- error = pxa27x_keypad_rotary_parse_dt(keypad, pdata);
+ error = pxa27x_keypad_rotary_parse(keypad);
if (error) {
dev_err(dev, "failed to parse rotary key\n");
return error;
}
- error = of_property_read_u32(np, "marvell,debounce-interval",
- &pdata->debounce_interval);
+ error = device_property_read_u32(dev, "marvell,debounce-interval",
+ &keypad->debounce_interval);
if (error) {
dev_err(dev, "failed to parse debounce-interval\n");
return error;
@@ -323,95 +315,15 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
*/
input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
- keypad->pdata = pdata;
- return 0;
-}
-
-#else
-
-static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad)
-{
- dev_info(keypad->input_dev->dev.parent, "missing platform data\n");
-
- return -EINVAL;
-}
-
-#endif
-
-static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
-{
- const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
- struct input_dev *input_dev = keypad->input_dev;
- unsigned short keycode;
- int i;
- int error;
-
- error = matrix_keypad_build_keymap(pdata->matrix_keymap_data, NULL,
- pdata->matrix_key_rows,
- pdata->matrix_key_cols,
- keypad->keycodes, input_dev);
- if (error)
- return error;
-
- /*
- * The keycodes may not only include matrix keys but also the direct
- * or rotary keys.
- */
- input_dev->keycodemax = ARRAY_SIZE(keypad->keycodes);
-
- /* For direct keys. */
- for (i = 0; i < pdata->direct_key_num; i++) {
- keycode = pdata->direct_key_map[i];
- keypad->keycodes[MAX_MATRIX_KEY_NUM + i] = keycode;
- __set_bit(keycode, input_dev->keybit);
- }
-
- if (pdata->enable_rotary0) {
- if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
- keycode = pdata->rotary0_up_key;
- keypad->keycodes[MAX_MATRIX_KEY_NUM + 0] = keycode;
- __set_bit(keycode, input_dev->keybit);
-
- keycode = pdata->rotary0_down_key;
- keypad->keycodes[MAX_MATRIX_KEY_NUM + 1] = keycode;
- __set_bit(keycode, input_dev->keybit);
-
- keypad->rotary_rel_code[0] = -1;
- } else {
- keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
- __set_bit(pdata->rotary0_rel_code, input_dev->relbit);
- }
- }
-
- if (pdata->enable_rotary1) {
- if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
- keycode = pdata->rotary1_up_key;
- keypad->keycodes[MAX_MATRIX_KEY_NUM + 2] = keycode;
- __set_bit(keycode, input_dev->keybit);
-
- keycode = pdata->rotary1_down_key;
- keypad->keycodes[MAX_MATRIX_KEY_NUM + 3] = keycode;
- __set_bit(keycode, input_dev->keybit);
-
- keypad->rotary_rel_code[1] = -1;
- } else {
- keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
- __set_bit(pdata->rotary1_rel_code, input_dev->relbit);
- }
- }
-
- __clear_bit(KEY_RESERVED, input_dev->keybit);
-
return 0;
}
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
{
- const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
int row, col, num_keys_pressed = 0;
- uint32_t new_state[MAX_MATRIX_KEY_COLS];
- uint32_t kpas = keypad_readl(KPAS);
+ u32 new_state[MAX_MATRIX_KEY_COLS];
+ u32 kpas = keypad_readl(KPAS);
num_keys_pressed = KPAS_MUKP(kpas);
@@ -425,19 +337,19 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
row = KPAS_RP(kpas);
/* if invalid row/col, treat as no key pressed */
- if (col >= pdata->matrix_key_cols ||
- row >= pdata->matrix_key_rows)
+ if (col >= keypad->matrix_key_cols ||
+ row >= keypad->matrix_key_rows)
goto scan;
- new_state[col] = (1 << row);
+ new_state[col] = BIT(row);
goto scan;
}
if (num_keys_pressed > 1) {
- uint32_t kpasmkp0 = keypad_readl(KPASMKP0);
- uint32_t kpasmkp1 = keypad_readl(KPASMKP1);
- uint32_t kpasmkp2 = keypad_readl(KPASMKP2);
- uint32_t kpasmkp3 = keypad_readl(KPASMKP3);
+ u32 kpasmkp0 = keypad_readl(KPASMKP0);
+ u32 kpasmkp1 = keypad_readl(KPASMKP1);
+ u32 kpasmkp2 = keypad_readl(KPASMKP2);
+ u32 kpasmkp3 = keypad_readl(KPASMKP3);
new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK;
new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK;
@@ -449,23 +361,23 @@ static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
}
scan:
- for (col = 0; col < pdata->matrix_key_cols; col++) {
- uint32_t bits_changed;
+ for (col = 0; col < keypad->matrix_key_cols; col++) {
+ u32 bits_changed;
int code;
bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
if (bits_changed == 0)
continue;
- for (row = 0; row < pdata->matrix_key_rows; row++) {
- if ((bits_changed & (1 << row)) == 0)
+ for (row = 0; row < keypad->matrix_key_rows; row++) {
+ if ((bits_changed & BIT(row)) == 0)
continue;
code = MATRIX_SCAN_CODE(row, col, keypad->row_shift);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keypad->keycodes[code],
- new_state[col] & (1 << row));
+ new_state[col] & BIT(row));
}
}
input_sync(input_dev);
@@ -474,7 +386,7 @@ scan:
#define DEFAULT_KPREC (0x007f007f)
-static inline int rotary_delta(uint32_t kprec)
+static inline int rotary_delta(u32 kprec)
{
if (kprec & KPREC_OF0)
return (kprec & 0xff) + 0x7f;
@@ -486,14 +398,16 @@ static inline int rotary_delta(uint32_t kprec)
static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
{
+ struct pxa27x_keypad_rotary *encoder = &keypad->rotary[r];
struct input_dev *dev = keypad->input_dev;
- if (delta == 0)
+ if (!encoder->enabled || delta == 0)
return;
- if (keypad->rotary_rel_code[r] == -1) {
- int code = MAX_MATRIX_KEY_NUM + 2 * r + (delta > 0 ? 0 : 1);
- unsigned char keycode = keypad->keycodes[code];
+ if (encoder->rel_code == -1) {
+ int idx = delta > 0 ? 0 : 1;
+ int code = MAX_MATRIX_KEY_NUM + 2 * r + idx;
+ unsigned char keycode = encoder->key_codes[idx];
/* simulate a press-n-release */
input_event(dev, EV_MSC, MSC_SCAN, code);
@@ -503,45 +417,43 @@ static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
input_report_key(dev, keycode, 0);
input_sync(dev);
} else {
- input_report_rel(dev, keypad->rotary_rel_code[r], delta);
+ input_report_rel(dev, encoder->rel_code, delta);
input_sync(dev);
}
}
static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
{
- const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
- uint32_t kprec;
+ u32 kprec;
+ int i;
/* read and reset to default count value */
kprec = keypad_readl(KPREC);
keypad_writel(KPREC, DEFAULT_KPREC);
- if (pdata->enable_rotary0)
+ for (i = 0; i < MAX_ROTARY_ENCODERS; i++) {
report_rotary_event(keypad, 0, rotary_delta(kprec));
-
- if (pdata->enable_rotary1)
- report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
+ kprec >>= 16;
+ }
}
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
{
- const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
unsigned int new_state;
- uint32_t kpdk, bits_changed;
+ u32 kpdk, bits_changed;
int i;
kpdk = keypad_readl(KPDK);
- if (pdata->enable_rotary0 || pdata->enable_rotary1)
+ if (keypad->rotary[0].enabled || keypad->rotary[1].enabled)
pxa27x_keypad_scan_rotary(keypad);
/*
* The KPDR_DK only output the key pin level, so it relates to board,
* and low level may be active.
*/
- if (pdata->direct_key_low_active)
+ if (keypad->direct_key_low_active)
new_state = ~KPDK_DK(kpdk) & keypad->direct_key_mask;
else
new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
@@ -551,34 +463,24 @@ static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
if (bits_changed == 0)
return;
- for (i = 0; i < pdata->direct_key_num; i++) {
- if (bits_changed & (1 << i)) {
+ for (i = 0; i < keypad->direct_key_num; i++) {
+ if (bits_changed & BIT(i)) {
int code = MAX_MATRIX_KEY_NUM + i;
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, keypad->keycodes[code],
- new_state & (1 << i));
+ new_state & BIT(i));
}
}
input_sync(input_dev);
keypad->direct_key_state = new_state;
}
-static void clear_wakeup_event(struct pxa27x_keypad *keypad)
-{
- const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
-
- if (pdata->clear_wakeup_event)
- (pdata->clear_wakeup_event)();
-}
-
static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
{
struct pxa27x_keypad *keypad = dev_id;
unsigned long kpc = keypad_readl(KPC);
- clear_wakeup_event(keypad);
-
if (kpc & KPC_DI)
pxa27x_keypad_scan_direct(keypad);
@@ -590,7 +492,6 @@ static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
{
- const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
unsigned int mask = 0, direct_key_num = 0;
unsigned long kpc = 0;
@@ -598,36 +499,34 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
keypad_readl(KPC);
/* enable matrix keys with automatic scan */
- if (pdata->matrix_key_rows && pdata->matrix_key_cols) {
+ if (keypad->matrix_key_rows && keypad->matrix_key_cols) {
kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
- kpc |= KPC_MKRN(pdata->matrix_key_rows) |
- KPC_MKCN(pdata->matrix_key_cols);
+ kpc |= KPC_MKRN(keypad->matrix_key_rows) |
+ KPC_MKCN(keypad->matrix_key_cols);
}
/* enable rotary key, debounce interval same as direct keys */
- if (pdata->enable_rotary0) {
+ if (keypad->rotary[0].enabled) {
mask |= 0x03;
direct_key_num = 2;
kpc |= KPC_REE0;
}
- if (pdata->enable_rotary1) {
+ if (keypad->rotary[1].enabled) {
mask |= 0x0c;
direct_key_num = 4;
kpc |= KPC_REE1;
}
- if (pdata->direct_key_num > direct_key_num)
- direct_key_num = pdata->direct_key_num;
+ if (keypad->direct_key_num > direct_key_num)
+ direct_key_num = keypad->direct_key_num;
/*
* Direct keys usage may not start from KP_DKIN0, check the platfrom
* mask data to config the specific.
*/
- if (pdata->direct_key_mask)
- keypad->direct_key_mask = pdata->direct_key_mask;
- else
- keypad->direct_key_mask = ((1 << direct_key_num) - 1) & ~mask;
+ if (!keypad->direct_key_mask)
+ keypad->direct_key_mask = GENMASK(direct_key_num - 1, 0) & ~mask;
/* enable direct key */
if (direct_key_num)
@@ -635,7 +534,7 @@ static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB);
keypad_writel(KPREC, DEFAULT_KPREC);
- keypad_writel(KPKDI, pdata->debounce_interval);
+ keypad_writel(KPKDI, keypad->debounce_interval);
}
static int pxa27x_keypad_open(struct input_dev *dev)
@@ -682,7 +581,7 @@ static int pxa27x_keypad_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
- int ret = 0;
+ int error;
/*
* If the keypad is used as wake up source, the clock is not turned
@@ -691,37 +590,30 @@ static int pxa27x_keypad_resume(struct device *dev)
if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(keypad->irq);
} else {
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev)) {
/* Enable unit clock */
- ret = clk_prepare_enable(keypad->clk);
- if (!ret)
- pxa27x_keypad_config(keypad);
- }
+ error = clk_prepare_enable(keypad->clk);
+ if (error)
+ return error;
- mutex_unlock(&input_dev->mutex);
+ pxa27x_keypad_config(keypad);
+ }
}
- return ret;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(pxa27x_keypad_pm_ops,
pxa27x_keypad_suspend, pxa27x_keypad_resume);
-
static int pxa27x_keypad_probe(struct platform_device *pdev)
{
- const struct pxa27x_keypad_platform_data *pdata =
- dev_get_platdata(&pdev->dev);
- struct device_node *np = pdev->dev.of_node;
struct pxa27x_keypad *keypad;
struct input_dev *input_dev;
- int irq, error;
-
- /* Driver need build keycode from device tree or pdata */
- if (!np && !pdata)
- return -EINVAL;
+ int irq;
+ int error;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
@@ -736,7 +628,6 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
if (!input_dev)
return -ENOMEM;
- keypad->pdata = pdata;
keypad->input_dev = input_dev;
keypad->irq = irq;
@@ -765,29 +656,12 @@ static int pxa27x_keypad_probe(struct platform_device *pdev)
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
- if (pdata) {
- error = pxa27x_keypad_build_keycode(keypad);
- } else {
- error = pxa27x_keypad_build_keycode_from_dt(keypad);
- /*
- * Data that we get from DT resides in dynamically
- * allocated memory so we need to update our pdata
- * pointer.
- */
- pdata = keypad->pdata;
- }
+ error = pxa27x_keypad_parse_properties(keypad);
if (error) {
- dev_err(&pdev->dev, "failed to build keycode\n");
+ dev_err(&pdev->dev, "failed to parse keypad properties\n");
return error;
}
- keypad->row_shift = get_count_order(pdata->matrix_key_cols);
-
- if ((pdata->enable_rotary0 && keypad->rotary_rel_code[0] != -1) ||
- (pdata->enable_rotary1 && keypad->rotary_rel_code[1] != -1)) {
- input_dev->evbit[0] |= BIT_MASK(EV_REL);
- }
-
error = devm_request_irq(&pdev->dev, irq, pxa27x_keypad_irq_handler,
0, pdev->name, keypad);
if (error) {
diff --git a/drivers/input/keyboard/qt1050.c b/drivers/input/keyboard/qt1050.c
index b51dfcd76038..bce8157d1871 100644
--- a/drivers/input/keyboard/qt1050.c
+++ b/drivers/input/keyboard/qt1050.c
@@ -208,7 +208,7 @@ static const struct regmap_access_table qt1050_writeable_table = {
.n_yes_ranges = ARRAY_SIZE(qt1050_writeable_ranges),
};
-static struct regmap_config qt1050_regmap_config = {
+static const struct regmap_config qt1050_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = QT1050_RES_CAL,
@@ -226,7 +226,12 @@ static bool qt1050_identify(struct qt1050_priv *ts)
int err;
/* Read Chip ID */
- regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+ err = regmap_read(ts->regmap, QT1050_CHIP_ID, &val);
+ if (err) {
+ dev_err(&ts->client->dev, "Failed to read chip ID: %d\n", err);
+ return false;
+ }
+
if (val != QT1050_CHIP_ID_VER) {
dev_err(&ts->client->dev, "ID %d not supported\n", val);
return false;
@@ -341,35 +346,34 @@ static int qt1050_apply_fw_data(struct qt1050_priv *ts)
static int qt1050_parse_fw(struct qt1050_priv *ts)
{
struct device *dev = &ts->client->dev;
- struct fwnode_handle *child;
int nbuttons;
nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0 || nbuttons > QT1050_MAX_KEYS)
return -ENODEV;
- device_for_each_child_node(dev, child) {
+ device_for_each_child_node_scoped(dev, child) {
struct qt1050_key button;
/* Required properties */
if (fwnode_property_read_u32(child, "linux,code",
&button.keycode)) {
dev_err(dev, "Button without keycode\n");
- goto err;
+ return -EINVAL;
}
if (button.keycode >= KEY_MAX) {
dev_err(dev, "Invalid keycode 0x%x\n",
button.keycode);
- goto err;
+ return -EINVAL;
}
if (fwnode_property_read_u32(child, "reg",
&button.num)) {
dev_err(dev, "Button without pad number\n");
- goto err;
+ return -EINVAL;
}
if (button.num < 0 || button.num > QT1050_MAX_KEYS - 1)
- goto err;
+ return -EINVAL;
ts->reg_keys |= BIT(button.num);
@@ -419,10 +423,6 @@ static int qt1050_parse_fw(struct qt1050_priv *ts)
}
return 0;
-
-err:
- fwnode_handle_put(child);
- return -EINVAL;
}
static int qt1050_probe(struct i2c_client *client)
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index e212eff7687c..17127269e3f0 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -7,6 +7,7 @@
* Author: Donghwa Lee <dh09.lee@samsung.com>
*/
+#include <linux/bits.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
@@ -29,11 +30,11 @@
#define SAMSUNG_KEYIFFC 0x10
/* SAMSUNG_KEYIFCON */
-#define SAMSUNG_KEYIFCON_INT_F_EN (1 << 0)
-#define SAMSUNG_KEYIFCON_INT_R_EN (1 << 1)
-#define SAMSUNG_KEYIFCON_DF_EN (1 << 2)
-#define SAMSUNG_KEYIFCON_FC_EN (1 << 3)
-#define SAMSUNG_KEYIFCON_WAKEUPEN (1 << 4)
+#define SAMSUNG_KEYIFCON_INT_F_EN BIT(0)
+#define SAMSUNG_KEYIFCON_INT_R_EN BIT(1)
+#define SAMSUNG_KEYIFCON_DF_EN BIT(2)
+#define SAMSUNG_KEYIFCON_FC_EN BIT(3)
+#define SAMSUNG_KEYIFCON_WAKEUPEN BIT(4)
/* SAMSUNG_KEYIFSTSCLR */
#define SAMSUNG_KEYIFSTSCLR_P_INT_MASK (0xff << 0)
@@ -44,8 +45,7 @@
#define S5PV210_KEYIFSTSCLR_R_INT_OFFSET 16
/* SAMSUNG_KEYIFCOL */
-#define SAMSUNG_KEYIFCOL_MASK (0xff << 0)
-#define S5PV210_KEYIFCOLEN_MASK (0xff << 8)
+#define SAMSUNG_KEYIFCOL_MASK 0xff
/* SAMSUNG_KEYIFROW */
#define SAMSUNG_KEYIFROW_MASK (0xff << 0)
@@ -54,12 +54,12 @@
/* SAMSUNG_KEYIFFC */
#define SAMSUNG_KEYIFFC_MASK (0x3ff << 0)
-enum samsung_keypad_type {
- KEYPAD_TYPE_SAMSUNG,
- KEYPAD_TYPE_S5PV210,
+struct samsung_chip_info {
+ unsigned int column_shift;
};
struct samsung_keypad {
+ const struct samsung_chip_info *chip;
struct input_dev *input_dev;
struct platform_device *pdev;
struct clk *clk;
@@ -68,7 +68,6 @@ struct samsung_keypad {
bool stopped;
bool wake_enabled;
int irq;
- enum samsung_keypad_type type;
unsigned int row_shift;
unsigned int rows;
unsigned int cols;
@@ -83,19 +82,14 @@ static void samsung_keypad_scan(struct samsung_keypad *keypad,
unsigned int val;
for (col = 0; col < keypad->cols; col++) {
- if (keypad->type == KEYPAD_TYPE_S5PV210) {
- val = S5PV210_KEYIFCOLEN_MASK;
- val &= ~(1 << col) << 8;
- } else {
- val = SAMSUNG_KEYIFCOL_MASK;
- val &= ~(1 << col);
- }
+ val = SAMSUNG_KEYIFCOL_MASK & ~BIT(col);
+ val <<= keypad->chip->column_shift;
writel(val, keypad->base + SAMSUNG_KEYIFCOL);
mdelay(1);
val = readl(keypad->base + SAMSUNG_KEYIFROW);
- row_state[col] = ~val & ((1 << keypad->rows) - 1);
+ row_state[col] = ~val & GENMASK(keypad->rows - 1, 0);
}
/* KEYIFCOL reg clear */
@@ -119,10 +113,10 @@ static bool samsung_keypad_report(struct samsung_keypad *keypad,
continue;
for (row = 0; row < keypad->rows; row++) {
- if (!(changed & (1 << row)))
+ if (!(changed & BIT(row)))
continue;
- pressed = row_state[col] & (1 << row);
+ pressed = row_state[col] & BIT(row);
dev_dbg(&keypad->input_dev->dev,
"key %s, row: %d, col: %d\n",
@@ -314,11 +308,11 @@ static int samsung_keypad_probe(struct platform_device *pdev)
{
const struct samsung_keypad_platdata *pdata;
const struct matrix_keymap_data *keymap_data;
+ const struct platform_device_id *id;
struct samsung_keypad *keypad;
struct resource *res;
struct input_dev *input_dev;
unsigned int row_shift;
- unsigned int keymap_size;
int error;
pdata = dev_get_platdata(&pdev->dev);
@@ -345,12 +339,16 @@ static int samsung_keypad_probe(struct platform_device *pdev)
pdata->cfg_gpio(pdata->rows, pdata->cols);
row_shift = get_count_order(pdata->cols);
- keymap_size = (pdata->rows << row_shift) * sizeof(keypad->keycodes[0]);
- keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad) + keymap_size,
+ keypad = devm_kzalloc(&pdev->dev,
+ struct_size(keypad, keycodes,
+ pdata->rows << row_shift),
GFP_KERNEL);
+ if (!keypad)
+ return -ENOMEM;
+
input_dev = devm_input_allocate_device(&pdev->dev);
- if (!keypad || !input_dev)
+ if (!input_dev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -361,18 +359,12 @@ static int samsung_keypad_probe(struct platform_device *pdev)
if (!keypad->base)
return -EBUSY;
- keypad->clk = devm_clk_get(&pdev->dev, "keypad");
+ keypad->clk = devm_clk_get_prepared(&pdev->dev, "keypad");
if (IS_ERR(keypad->clk)) {
dev_err(&pdev->dev, "failed to get keypad clk\n");
return PTR_ERR(keypad->clk);
}
- error = clk_prepare(keypad->clk);
- if (error) {
- dev_err(&pdev->dev, "keypad clock prepare failed\n");
- return error;
- }
-
keypad->input_dev = input_dev;
keypad->pdev = pdev;
keypad->row_shift = row_shift;
@@ -381,15 +373,20 @@ static int samsung_keypad_probe(struct platform_device *pdev)
keypad->stopped = true;
init_waitqueue_head(&keypad->wait);
- if (pdev->dev.of_node)
- keypad->type = of_device_is_compatible(pdev->dev.of_node,
- "samsung,s5pv210-keypad");
- else
- keypad->type = platform_get_device_id(pdev)->driver_data;
+ keypad->chip = device_get_match_data(&pdev->dev);
+ if (!keypad->chip) {
+ id = platform_get_device_id(pdev);
+ if (id)
+ keypad->chip = (const void *)id->driver_data;
+ }
+
+ if (!keypad->chip) {
+ dev_err(&pdev->dev, "Unable to determine chip type");
+ return -EINVAL;
+ }
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
- input_dev->dev.parent = &pdev->dev;
input_dev->open = samsung_keypad_open;
input_dev->close = samsung_keypad_close;
@@ -399,7 +396,7 @@ static int samsung_keypad_probe(struct platform_device *pdev)
keypad->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "failed to build keymap\n");
- goto err_unprepare_clk;
+ return error;
}
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
@@ -411,7 +408,7 @@ static int samsung_keypad_probe(struct platform_device *pdev)
keypad->irq = platform_get_irq(pdev, 0);
if (keypad->irq < 0) {
error = keypad->irq;
- goto err_unprepare_clk;
+ return error;
}
error = devm_request_threaded_irq(&pdev->dev, keypad->irq, NULL,
@@ -419,16 +416,19 @@ static int samsung_keypad_probe(struct platform_device *pdev)
dev_name(&pdev->dev), keypad);
if (error) {
dev_err(&pdev->dev, "failed to register keypad interrupt\n");
- goto err_unprepare_clk;
+ return error;
}
device_init_wakeup(&pdev->dev, pdata->wakeup);
platform_set_drvdata(pdev, keypad);
- pm_runtime_enable(&pdev->dev);
+
+ error = devm_pm_runtime_enable(&pdev->dev);
+ if (error)
+ return error;
error = input_register_device(keypad->input_dev);
if (error)
- goto err_disable_runtime_pm;
+ return error;
if (pdev->dev.of_node) {
devm_kfree(&pdev->dev, (void *)pdata->keymap_data->keymap);
@@ -436,23 +436,6 @@ static int samsung_keypad_probe(struct platform_device *pdev)
devm_kfree(&pdev->dev, (void *)pdata);
}
return 0;
-
-err_disable_runtime_pm:
- pm_runtime_disable(&pdev->dev);
-err_unprepare_clk:
- clk_unprepare(keypad->clk);
- return error;
-}
-
-static void samsung_keypad_remove(struct platform_device *pdev)
-{
- struct samsung_keypad *keypad = platform_get_drvdata(pdev);
-
- pm_runtime_disable(&pdev->dev);
-
- input_unregister_device(keypad->input_dev);
-
- clk_unprepare(keypad->clk);
}
static int samsung_keypad_runtime_suspend(struct device *dev)
@@ -528,15 +511,13 @@ static int samsung_keypad_suspend(struct device *dev)
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
samsung_keypad_stop(keypad);
samsung_keypad_toggle_wakeup(keypad, true);
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
@@ -546,15 +527,13 @@ static int samsung_keypad_resume(struct device *dev)
struct samsung_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
samsung_keypad_toggle_wakeup(keypad, false);
if (input_device_enabled(input_dev))
samsung_keypad_start(keypad);
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
@@ -564,11 +543,24 @@ static const struct dev_pm_ops samsung_keypad_pm_ops = {
samsung_keypad_runtime_resume, NULL)
};
+static const struct samsung_chip_info samsung_s3c6410_chip_info = {
+ .column_shift = 0,
+};
+
+static const struct samsung_chip_info samsung_s5pv210_chip_info = {
+ .column_shift = 8,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id samsung_keypad_dt_match[] = {
- { .compatible = "samsung,s3c6410-keypad" },
- { .compatible = "samsung,s5pv210-keypad" },
- {},
+ {
+ .compatible = "samsung,s3c6410-keypad",
+ .data = &samsung_s3c6410_chip_info,
+ }, {
+ .compatible = "samsung,s5pv210-keypad",
+ .data = &samsung_s5pv210_chip_info,
+ },
+ { }
};
MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
#endif
@@ -576,18 +568,17 @@ MODULE_DEVICE_TABLE(of, samsung_keypad_dt_match);
static const struct platform_device_id samsung_keypad_driver_ids[] = {
{
.name = "samsung-keypad",
- .driver_data = KEYPAD_TYPE_SAMSUNG,
+ .driver_data = (kernel_ulong_t)&samsung_s3c6410_chip_info,
}, {
.name = "s5pv210-keypad",
- .driver_data = KEYPAD_TYPE_S5PV210,
+ .driver_data = (kernel_ulong_t)&samsung_s5pv210_chip_info,
},
- { },
+ { }
};
MODULE_DEVICE_TABLE(platform, samsung_keypad_driver_ids);
static struct platform_driver samsung_keypad_driver = {
.probe = samsung_keypad_probe,
- .remove_new = samsung_keypad_remove,
.driver = {
.name = "samsung-keypad",
.of_match_table = of_match_ptr(samsung_keypad_dt_match),
diff --git a/drivers/input/keyboard/sh_keysc.c b/drivers/input/keyboard/sh_keysc.c
index 4ea4fd25c5d2..159f41eedd41 100644
--- a/drivers/input/keyboard/sh_keysc.c
+++ b/drivers/input/keyboard/sh_keysc.c
@@ -319,7 +319,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(sh_keysc_dev_pm_ops,
static struct platform_driver sh_keysc_device_driver = {
.probe = sh_keysc_probe,
- .remove_new = sh_keysc_remove,
+ .remove = sh_keysc_remove,
.driver = {
.name = "sh_keysc",
.pm = pm_sleep_ptr(&sh_keysc_dev_pm_ops),
diff --git a/drivers/input/keyboard/snvs_pwrkey.c b/drivers/input/keyboard/snvs_pwrkey.c
index ad8660be0127..954055aaf6e2 100644
--- a/drivers/input/keyboard/snvs_pwrkey.c
+++ b/drivers/input/keyboard/snvs_pwrkey.c
@@ -27,6 +27,8 @@
#define SNVS_HPSR_BTN BIT(6)
#define SNVS_LPSR_SPO BIT(18)
#define SNVS_LPCR_DEP_EN BIT(5)
+#define SNVS_LPCR_BPT_SHIFT 16
+#define SNVS_LPCR_BPT_MASK (3 << SNVS_LPCR_BPT_SHIFT)
#define DEBOUNCE_TIME 30
#define REPEAT_INTERVAL 60
@@ -44,7 +46,8 @@ struct pwrkey_drv_data {
static void imx_imx_snvs_check_for_events(struct timer_list *t)
{
- struct pwrkey_drv_data *pdata = from_timer(pdata, t, check_timer);
+ struct pwrkey_drv_data *pdata = timer_container_of(pdata, t,
+ check_timer);
struct input_dev *input = pdata->input;
u32 state;
@@ -100,16 +103,11 @@ static irqreturn_t imx_snvs_pwrkey_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static void imx_snvs_pwrkey_disable_clk(void *data)
-{
- clk_disable_unprepare(data);
-}
-
static void imx_snvs_pwrkey_act(void *pdata)
{
struct pwrkey_drv_data *pd = pdata;
- del_timer_sync(&pd->check_timer);
+ timer_delete_sync(&pd->check_timer);
}
static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
@@ -119,6 +117,8 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
struct device_node *np;
struct clk *clk;
int error;
+ unsigned int val;
+ unsigned int bpt;
u32 vid;
/* Get SNVS register Page */
@@ -141,34 +141,39 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
dev_warn(&pdev->dev, "KEY_POWER without setting in dts\n");
}
- clk = devm_clk_get_optional(&pdev->dev, NULL);
+ clk = devm_clk_get_optional_enabled(&pdev->dev, NULL);
if (IS_ERR(clk)) {
dev_err(&pdev->dev, "Failed to get snvs clock (%pe)\n", clk);
return PTR_ERR(clk);
}
- error = clk_prepare_enable(clk);
- if (error) {
- dev_err(&pdev->dev, "Failed to enable snvs clock (%pe)\n",
- ERR_PTR(error));
- return error;
- }
-
- error = devm_add_action_or_reset(&pdev->dev,
- imx_snvs_pwrkey_disable_clk, clk);
- if (error) {
- dev_err(&pdev->dev,
- "Failed to register clock cleanup handler (%pe)\n",
- ERR_PTR(error));
- return error;
- }
-
pdata->wakeup = of_property_read_bool(np, "wakeup-source");
pdata->irq = platform_get_irq(pdev, 0);
if (pdata->irq < 0)
return -EINVAL;
+ error = of_property_read_u32(np, "power-off-time-sec", &val);
+ if (!error) {
+ switch (val) {
+ case 0:
+ bpt = 0x3;
+ break;
+ case 5:
+ case 10:
+ case 15:
+ bpt = (val / 5) - 1;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "power-off-time-sec %d out of range\n", val);
+ return -EINVAL;
+ }
+
+ regmap_update_bits(pdata->snvs, SNVS_LPCR_REG, SNVS_LPCR_BPT_MASK,
+ bpt << SNVS_LPCR_BPT_SHIFT);
+ }
+
regmap_read(pdata->snvs, SNVS_HPVIDR1_REG, &vid);
pdata->minor_rev = vid & 0xff;
@@ -204,7 +209,6 @@ static int imx_snvs_pwrkey_probe(struct platform_device *pdev)
error = devm_request_irq(&pdev->dev, pdata->irq,
imx_snvs_pwrkey_interrupt,
0, pdev->name, pdev);
-
if (error) {
dev_err(&pdev->dev, "interrupt not available.\n");
return error;
diff --git a/drivers/input/keyboard/spear-keyboard.c b/drivers/input/keyboard/spear-keyboard.c
index 557d00a667ce..53f3ac64c980 100644
--- a/drivers/input/keyboard/spear-keyboard.c
+++ b/drivers/input/keyboard/spear-keyboard.c
@@ -14,16 +14,15 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/input/matrix_keypad.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
-#include <linux/pm_wakeup.h>
#include <linux/slab.h>
#include <linux/types.h>
-#include <linux/platform_data/keyboard-spear.h>
/* Keyboard Registers */
#define MODE_CTL_REG 0x00
@@ -57,13 +56,12 @@ struct spear_kbd {
void __iomem *io_base;
struct clk *clk;
unsigned int irq;
- unsigned int mode;
- unsigned int suspended_rate;
+ u32 mode;
+ u32 suspended_rate;
+ u32 mode_ctl_reg;
unsigned short last_key;
unsigned short keycodes[NUM_ROWS * NUM_COLS];
- bool rep;
bool irq_wake_enabled;
- u32 mode_ctl_reg;
};
static irqreturn_t spear_kbd_interrupt(int irq, void *dev_id)
@@ -144,46 +142,8 @@ static void spear_kbd_close(struct input_dev *dev)
kbd->last_key = KEY_RESERVED;
}
-#ifdef CONFIG_OF
-static int spear_kbd_parse_dt(struct platform_device *pdev,
- struct spear_kbd *kbd)
-{
- struct device_node *np = pdev->dev.of_node;
- int error;
- u32 val, suspended_rate;
-
- if (!np) {
- dev_err(&pdev->dev, "Missing DT data\n");
- return -EINVAL;
- }
-
- if (of_property_read_bool(np, "autorepeat"))
- kbd->rep = true;
-
- if (of_property_read_u32(np, "suspended_rate", &suspended_rate))
- kbd->suspended_rate = suspended_rate;
-
- error = of_property_read_u32(np, "st,mode", &val);
- if (error) {
- dev_err(&pdev->dev, "DT: Invalid or missing mode\n");
- return error;
- }
-
- kbd->mode = val;
- return 0;
-}
-#else
-static inline int spear_kbd_parse_dt(struct platform_device *pdev,
- struct spear_kbd *kbd)
-{
- return -ENOSYS;
-}
-#endif
-
static int spear_kbd_probe(struct platform_device *pdev)
{
- struct kbd_platform_data *pdata = dev_get_platdata(&pdev->dev);
- const struct matrix_keymap_data *keymap = pdata ? pdata->keymap : NULL;
struct spear_kbd *kbd;
struct input_dev *input_dev;
int irq;
@@ -199,6 +159,14 @@ static int spear_kbd_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ error = device_property_read_u32(&pdev->dev, "st,mode", &kbd->mode);
+ if (error) {
+ dev_err(&pdev->dev, "Invalid or missing mode\n");
+ return error;
+ }
+
+ device_property_read_u32(&pdev->dev, "suspended_rate", &kbd->suspended_rate);
+
input_dev = devm_input_allocate_device(&pdev->dev);
if (!input_dev) {
dev_err(&pdev->dev, "unable to allocate input device\n");
@@ -208,21 +176,11 @@ static int spear_kbd_probe(struct platform_device *pdev)
kbd->input = input_dev;
kbd->irq = irq;
- if (!pdata) {
- error = spear_kbd_parse_dt(pdev, kbd);
- if (error)
- return error;
- } else {
- kbd->mode = pdata->mode;
- kbd->rep = pdata->rep;
- kbd->suspended_rate = pdata->suspended_rate;
- }
-
kbd->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
if (IS_ERR(kbd->io_base))
return PTR_ERR(kbd->io_base);
- kbd->clk = devm_clk_get(&pdev->dev, NULL);
+ kbd->clk = devm_clk_get_prepared(&pdev->dev, NULL);
if (IS_ERR(kbd->clk))
return PTR_ERR(kbd->clk);
@@ -235,34 +193,29 @@ static int spear_kbd_probe(struct platform_device *pdev)
input_dev->open = spear_kbd_open;
input_dev->close = spear_kbd_close;
- error = matrix_keypad_build_keymap(keymap, NULL, NUM_ROWS, NUM_COLS,
+ error = matrix_keypad_build_keymap(NULL, NULL, NUM_ROWS, NUM_COLS,
kbd->keycodes, input_dev);
if (error) {
dev_err(&pdev->dev, "Failed to build keymap\n");
return error;
}
- if (kbd->rep)
+ if (device_property_read_bool(&pdev->dev, "autorepeat"))
__set_bit(EV_REP, input_dev->evbit);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
input_set_drvdata(input_dev, kbd);
error = devm_request_irq(&pdev->dev, irq, spear_kbd_interrupt, 0,
- "keyboard", kbd);
+ "keyboard", kbd);
if (error) {
dev_err(&pdev->dev, "request_irq failed\n");
return error;
}
- error = clk_prepare(kbd->clk);
- if (error)
- return error;
-
error = input_register_device(input_dev);
if (error) {
dev_err(&pdev->dev, "Unable to register keyboard device\n");
- clk_unprepare(kbd->clk);
return error;
}
@@ -272,14 +225,6 @@ static int spear_kbd_probe(struct platform_device *pdev)
return 0;
}
-static void spear_kbd_remove(struct platform_device *pdev)
-{
- struct spear_kbd *kbd = platform_get_drvdata(pdev);
-
- input_unregister_device(kbd->input);
- clk_unprepare(kbd->clk);
-}
-
static int spear_kbd_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -287,7 +232,7 @@ static int spear_kbd_suspend(struct device *dev)
struct input_dev *input_dev = kbd->input;
unsigned int rate = 0, mode_ctl_reg, val;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
/* explicitly enable clock as we may program device */
clk_enable(kbd->clk);
@@ -328,8 +273,6 @@ static int spear_kbd_suspend(struct device *dev)
/* restore previous clk state */
clk_disable(kbd->clk);
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
@@ -339,7 +282,7 @@ static int spear_kbd_resume(struct device *dev)
struct spear_kbd *kbd = platform_get_drvdata(pdev);
struct input_dev *input_dev = kbd->input;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (device_may_wakeup(&pdev->dev)) {
if (kbd->irq_wake_enabled) {
@@ -355,8 +298,6 @@ static int spear_kbd_resume(struct device *dev)
if (input_device_enabled(input_dev))
writel_relaxed(kbd->mode_ctl_reg, kbd->io_base + MODE_CTL_REG);
- mutex_unlock(&input_dev->mutex);
-
return 0;
}
@@ -373,7 +314,6 @@ MODULE_DEVICE_TABLE(of, spear_kbd_id_table);
static struct platform_driver spear_kbd_driver = {
.probe = spear_kbd_probe,
- .remove_new = spear_kbd_remove,
.driver = {
.name = "keyboard",
.pm = pm_sleep_ptr(&spear_kbd_pm_ops),
diff --git a/drivers/input/keyboard/st-keyscan.c b/drivers/input/keyboard/st-keyscan.c
index 0d27324af809..e53ef4c670e4 100644
--- a/drivers/input/keyboard/st-keyscan.c
+++ b/drivers/input/keyboard/st-keyscan.c
@@ -216,14 +216,13 @@ static int keyscan_suspend(struct device *dev)
struct st_keyscan *keypad = platform_get_drvdata(pdev);
struct input_dev *input = keypad->input_dev;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
if (device_may_wakeup(dev))
enable_irq_wake(keypad->irq);
else if (input_device_enabled(input))
keyscan_stop(keypad);
- mutex_unlock(&input->mutex);
return 0;
}
@@ -232,17 +231,19 @@ static int keyscan_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct st_keyscan *keypad = platform_get_drvdata(pdev);
struct input_dev *input = keypad->input_dev;
- int retval = 0;
+ int error;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
- if (device_may_wakeup(dev))
+ if (device_may_wakeup(dev)) {
disable_irq_wake(keypad->irq);
- else if (input_device_enabled(input))
- retval = keyscan_start(keypad);
+ } else if (input_device_enabled(input)) {
+ error = keyscan_start(keypad);
+ if (error)
+ return error;
+ }
- mutex_unlock(&input->mutex);
- return retval;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(keyscan_dev_pm_ops,
diff --git a/drivers/input/keyboard/stmpe-keypad.c b/drivers/input/keyboard/stmpe-keypad.c
index ef2f44027894..0acded4fb9c9 100644
--- a/drivers/input/keyboard/stmpe-keypad.c
+++ b/drivers/input/keyboard/stmpe-keypad.c
@@ -414,7 +414,7 @@ static void stmpe_keypad_remove(struct platform_device *pdev)
static struct platform_driver stmpe_keypad_driver = {
.driver.name = "stmpe-keypad",
.probe = stmpe_keypad_probe,
- .remove_new = stmpe_keypad_remove,
+ .remove = stmpe_keypad_remove,
};
module_platform_driver(stmpe_keypad_driver);
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
index 56e784936059..7ef0b3f4f549 100644
--- a/drivers/input/keyboard/stowaway.c
+++ b/drivers/input/keyboard/stowaway.c
@@ -72,7 +72,7 @@ static int skbd_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL);
+ skbd = kzalloc(sizeof(*skbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!skbd || !input_dev)
goto fail1;
diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
index f304cab0ebdb..5730f08f82d7 100644
--- a/drivers/input/keyboard/sun4i-lradc-keys.c
+++ b/drivers/input/keyboard/sun4i-lradc-keys.c
@@ -24,7 +24,6 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
-#include <linux/pm_wakeup.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
@@ -202,7 +201,7 @@ static void sun4i_lradc_close(struct input_dev *dev)
static int sun4i_lradc_load_dt_keymap(struct device *dev,
struct sun4i_lradc_data *lradc)
{
- struct device_node *np, *pp;
+ struct device_node *np;
int i;
int error;
@@ -223,28 +222,25 @@ static int sun4i_lradc_load_dt_keymap(struct device *dev,
return -ENOMEM;
i = 0;
- for_each_child_of_node(np, pp) {
+ for_each_child_of_node_scoped(np, pp) {
struct sun4i_lradc_keymap *map = &lradc->chan0_map[i];
u32 channel;
error = of_property_read_u32(pp, "channel", &channel);
if (error || channel != 0) {
dev_err(dev, "%pOFn: Inval channel prop\n", pp);
- of_node_put(pp);
return -EINVAL;
}
error = of_property_read_u32(pp, "voltage", &map->voltage);
if (error) {
dev_err(dev, "%pOFn: Inval voltage prop\n", pp);
- of_node_put(pp);
return -EINVAL;
}
error = of_property_read_u32(pp, "linux,code", &map->keycode);
if (error) {
dev_err(dev, "%pOFn: Inval linux,code prop\n", pp);
- of_node_put(pp);
return -EINVAL;
}
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index b123a208ef36..3299e1919b37 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -241,9 +241,8 @@ static void sunkbd_reinit(struct work_struct *work)
static void sunkbd_enable(struct sunkbd *sunkbd, bool enable)
{
- serio_pause_rx(sunkbd->serio);
- sunkbd->enabled = enable;
- serio_continue_rx(sunkbd->serio);
+ scoped_guard(serio_pause_rx, sunkbd->serio)
+ sunkbd->enabled = enable;
if (!enable) {
wake_up_interruptible(&sunkbd->wait);
@@ -263,7 +262,7 @@ static int sunkbd_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- sunkbd = kzalloc(sizeof(struct sunkbd), GFP_KERNEL);
+ sunkbd = kzalloc(sizeof(*sunkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!sunkbd || !input_dev)
goto fail1;
diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c
index b0d86621c60a..11988cffdfae 100644
--- a/drivers/input/keyboard/tc3589x-keypad.c
+++ b/drivers/input/keyboard/tc3589x-keypad.c
@@ -325,7 +325,6 @@ tc3589x_keypad_of_probe(struct device *dev)
struct tc3589x_keypad_platform_data *plat;
u32 cols, rows;
u32 debounce_ms;
- int proplen;
if (!np)
return ERR_PTR(-ENODEV);
@@ -346,7 +345,7 @@ tc3589x_keypad_of_probe(struct device *dev)
return ERR_PTR(-EINVAL);
}
- if (!of_get_property(np, "linux,keymap", &proplen)) {
+ if (!of_property_present(np, "linux,keymap")) {
dev_err(dev, "property linux,keymap not found\n");
return ERR_PTR(-ENOENT);
}
diff --git a/drivers/input/keyboard/tca6416-keypad.c b/drivers/input/keyboard/tca6416-keypad.c
deleted file mode 100644
index fbc674d7b9f0..000000000000
--- a/drivers/input/keyboard/tca6416-keypad.c
+++ /dev/null
@@ -1,305 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Driver for keys on TCA6416 I2C IO expander
- *
- * Copyright (C) 2010 Texas Instruments
- *
- * Author : Sriramakrishnan.A.G. <srk@ti.com>
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/tca6416_keypad.h>
-
-#define TCA6416_INPUT 0
-#define TCA6416_OUTPUT 1
-#define TCA6416_INVERT 2
-#define TCA6416_DIRECTION 3
-
-#define TCA6416_POLL_INTERVAL 100 /* msec */
-
-static const struct i2c_device_id tca6416_id[] = {
- { "tca6416-keys", 16, },
- { "tca6408-keys", 8, },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tca6416_id);
-
-struct tca6416_keypad_chip {
- uint16_t reg_output;
- uint16_t reg_direction;
- uint16_t reg_input;
-
- struct i2c_client *client;
- struct input_dev *input;
- int io_size;
- u16 pinmask;
- bool use_polling;
- struct tca6416_button buttons[];
-};
-
-static int tca6416_write_reg(struct tca6416_keypad_chip *chip, int reg, u16 val)
-{
- int error;
-
- error = chip->io_size > 8 ?
- i2c_smbus_write_word_data(chip->client, reg << 1, val) :
- i2c_smbus_write_byte_data(chip->client, reg, val);
- if (error < 0) {
- dev_err(&chip->client->dev,
- "%s failed, reg: %d, val: %d, error: %d\n",
- __func__, reg, val, error);
- return error;
- }
-
- return 0;
-}
-
-static int tca6416_read_reg(struct tca6416_keypad_chip *chip, int reg, u16 *val)
-{
- int retval;
-
- retval = chip->io_size > 8 ?
- i2c_smbus_read_word_data(chip->client, reg << 1) :
- i2c_smbus_read_byte_data(chip->client, reg);
- if (retval < 0) {
- dev_err(&chip->client->dev, "%s failed, reg: %d, error: %d\n",
- __func__, reg, retval);
- return retval;
- }
-
- *val = (u16)retval;
- return 0;
-}
-
-static void tca6416_keys_scan(struct input_dev *input)
-{
- struct tca6416_keypad_chip *chip = input_get_drvdata(input);
- u16 reg_val, val;
- int error, i, pin_index;
-
- error = tca6416_read_reg(chip, TCA6416_INPUT, &reg_val);
- if (error)
- return;
-
- reg_val &= chip->pinmask;
-
- /* Figure out which lines have changed */
- val = reg_val ^ chip->reg_input;
- chip->reg_input = reg_val;
-
- for (i = 0, pin_index = 0; i < 16; i++) {
- if (val & (1 << i)) {
- struct tca6416_button *button = &chip->buttons[pin_index];
- unsigned int type = button->type ?: EV_KEY;
- int state = ((reg_val & (1 << i)) ? 1 : 0)
- ^ button->active_low;
-
- input_event(input, type, button->code, !!state);
- input_sync(input);
- }
-
- if (chip->pinmask & (1 << i))
- pin_index++;
- }
-}
-
-/*
- * This is threaded IRQ handler and this can (and will) sleep.
- */
-static irqreturn_t tca6416_keys_isr(int irq, void *dev_id)
-{
- tca6416_keys_scan(dev_id);
-
- return IRQ_HANDLED;
-}
-
-static int tca6416_keys_open(struct input_dev *dev)
-{
- struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
-
- if (!chip->use_polling) {
- /* Get initial device state in case it has switches */
- tca6416_keys_scan(dev);
- enable_irq(chip->client->irq);
- }
-
- return 0;
-}
-
-static void tca6416_keys_close(struct input_dev *dev)
-{
- struct tca6416_keypad_chip *chip = input_get_drvdata(dev);
-
- if (!chip->use_polling)
- disable_irq(chip->client->irq);
-}
-
-static int tca6416_setup_registers(struct tca6416_keypad_chip *chip)
-{
- int error;
-
- error = tca6416_read_reg(chip, TCA6416_OUTPUT, &chip->reg_output);
- if (error)
- return error;
-
- error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
- if (error)
- return error;
-
- /* ensure that keypad pins are set to input */
- error = tca6416_write_reg(chip, TCA6416_DIRECTION,
- chip->reg_direction | chip->pinmask);
- if (error)
- return error;
-
- error = tca6416_read_reg(chip, TCA6416_DIRECTION, &chip->reg_direction);
- if (error)
- return error;
-
- error = tca6416_read_reg(chip, TCA6416_INPUT, &chip->reg_input);
- if (error)
- return error;
-
- chip->reg_input &= chip->pinmask;
-
- return 0;
-}
-
-static int tca6416_keypad_probe(struct i2c_client *client)
-{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
- struct tca6416_keys_platform_data *pdata;
- struct tca6416_keypad_chip *chip;
- struct input_dev *input;
- int error;
- int i;
-
- /* Check functionality */
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
- dev_err(&client->dev, "%s adapter not supported\n",
- dev_driver_string(&client->adapter->dev));
- return -ENODEV;
- }
-
- pdata = dev_get_platdata(&client->dev);
- if (!pdata) {
- dev_dbg(&client->dev, "no platform data\n");
- return -EINVAL;
- }
-
- chip = devm_kzalloc(&client->dev,
- struct_size(chip, buttons, pdata->nbuttons),
- GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- input = devm_input_allocate_device(&client->dev);
- if (!input)
- return -ENOMEM;
-
- chip->client = client;
- chip->input = input;
- chip->io_size = id->driver_data;
- chip->pinmask = pdata->pinmask;
- chip->use_polling = pdata->use_polling;
-
- input->phys = "tca6416-keys/input0";
- input->name = client->name;
-
- input->open = tca6416_keys_open;
- input->close = tca6416_keys_close;
-
- input->id.bustype = BUS_HOST;
- input->id.vendor = 0x0001;
- input->id.product = 0x0001;
- input->id.version = 0x0100;
-
- /* Enable auto repeat feature of Linux input subsystem */
- if (pdata->rep)
- __set_bit(EV_REP, input->evbit);
-
- for (i = 0; i < pdata->nbuttons; i++) {
- unsigned int type;
-
- chip->buttons[i] = pdata->buttons[i];
- type = (pdata->buttons[i].type) ?: EV_KEY;
- input_set_capability(input, type, pdata->buttons[i].code);
- }
-
- input_set_drvdata(input, chip);
-
- /*
- * Initialize cached registers from their original values.
- * we can't share this chip with another i2c master.
- */
- error = tca6416_setup_registers(chip);
- if (error)
- return error;
-
- if (chip->use_polling) {
- error = input_setup_polling(input, tca6416_keys_scan);
- if (error) {
- dev_err(&client->dev, "Failed to setup polling\n");
- return error;
- }
-
- input_set_poll_interval(input, TCA6416_POLL_INTERVAL);
- } else {
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, tca6416_keys_isr,
- IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT |
- IRQF_NO_AUTOEN,
- "tca6416-keypad", input);
- if (error) {
- dev_dbg(&client->dev,
- "Unable to claim irq %d; error %d\n",
- client->irq, error);
- return error;
- }
- }
-
- error = input_register_device(input);
- if (error) {
- dev_dbg(&client->dev,
- "Unable to register input device, error: %d\n", error);
- return error;
- }
-
- i2c_set_clientdata(client, chip);
-
- return 0;
-}
-
-static struct i2c_driver tca6416_keypad_driver = {
- .driver = {
- .name = "tca6416-keypad",
- },
- .probe = tca6416_keypad_probe,
- .id_table = tca6416_id,
-};
-
-static int __init tca6416_keypad_init(void)
-{
- return i2c_add_driver(&tca6416_keypad_driver);
-}
-
-subsys_initcall(tca6416_keypad_init);
-
-static void __exit tca6416_keypad_exit(void)
-{
- i2c_del_driver(&tca6416_keypad_driver);
-}
-module_exit(tca6416_keypad_exit);
-
-MODULE_AUTHOR("Sriramakrishnan <srk@ti.com>");
-MODULE_DESCRIPTION("Keypad driver over tca6416 IO expander");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c
index 76fc19ffe21d..68c0afafee7b 100644
--- a/drivers/input/keyboard/tca8418_keypad.c
+++ b/drivers/input/keyboard/tca8418_keypad.c
@@ -373,18 +373,7 @@ static struct i2c_driver tca8418_keypad_driver = {
.probe = tca8418_keypad_probe,
.id_table = tca8418_id,
};
-
-static int __init tca8418_keypad_init(void)
-{
- return i2c_add_driver(&tca8418_keypad_driver);
-}
-subsys_initcall(tca8418_keypad_init);
-
-static void __exit tca8418_keypad_exit(void)
-{
- i2c_del_driver(&tca8418_keypad_driver);
-}
-module_exit(tca8418_keypad_exit);
+module_i2c_driver(tca8418_keypad_driver);
MODULE_AUTHOR("Kyle Manna <kyle.manna@fuel7.com>");
MODULE_DESCRIPTION("Keypad driver for TCA8418");
diff --git a/drivers/input/keyboard/tegra-kbc.c b/drivers/input/keyboard/tegra-kbc.c
index a1765ed8c825..bc1c80a456f2 100644
--- a/drivers/input/keyboard/tegra-kbc.c
+++ b/drivers/input/keyboard/tegra-kbc.c
@@ -240,12 +240,11 @@ static void tegra_kbc_set_fifo_interrupt(struct tegra_kbc *kbc, bool enable)
static void tegra_kbc_keypress_timer(struct timer_list *t)
{
- struct tegra_kbc *kbc = from_timer(kbc, t, timer);
- unsigned long flags;
+ struct tegra_kbc *kbc = timer_container_of(kbc, t, timer);
u32 val;
unsigned int i;
- spin_lock_irqsave(&kbc->lock, flags);
+ guard(spinlock_irqsave)(&kbc->lock);
val = (readl(kbc->mmio + KBC_INT_0) >> 4) & 0xf;
if (val) {
@@ -270,17 +269,14 @@ static void tegra_kbc_keypress_timer(struct timer_list *t)
/* All keys are released so enable the keypress interrupt */
tegra_kbc_set_fifo_interrupt(kbc, true);
}
-
- spin_unlock_irqrestore(&kbc->lock, flags);
}
static irqreturn_t tegra_kbc_isr(int irq, void *args)
{
struct tegra_kbc *kbc = args;
- unsigned long flags;
u32 val;
- spin_lock_irqsave(&kbc->lock, flags);
+ guard(spinlock_irqsave)(&kbc->lock);
/*
* Quickly bail out & reenable interrupts if the fifo threshold
@@ -301,8 +297,6 @@ static irqreturn_t tegra_kbc_isr(int irq, void *args)
kbc->keypress_caused_wake = true;
}
- spin_unlock_irqrestore(&kbc->lock, flags);
-
return IRQ_HANDLED;
}
@@ -413,17 +407,16 @@ static int tegra_kbc_start(struct tegra_kbc *kbc)
static void tegra_kbc_stop(struct tegra_kbc *kbc)
{
- unsigned long flags;
u32 val;
- spin_lock_irqsave(&kbc->lock, flags);
- val = readl(kbc->mmio + KBC_CONTROL_0);
- val &= ~1;
- writel(val, kbc->mmio + KBC_CONTROL_0);
- spin_unlock_irqrestore(&kbc->lock, flags);
+ scoped_guard(spinlock_irqsave, &kbc->lock) {
+ val = readl(kbc->mmio + KBC_CONTROL_0);
+ val &= ~1;
+ writel(val, kbc->mmio + KBC_CONTROL_0);
+ }
disable_irq(kbc->irq);
- del_timer_sync(&kbc->timer);
+ timer_delete_sync(&kbc->timer);
clk_disable_unprepare(kbc->clk);
}
@@ -491,12 +484,10 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
struct device_node *np = kbc->dev->of_node;
u32 prop;
int i;
- u32 num_rows = 0;
- u32 num_cols = 0;
+ int num_rows;
+ int num_cols;
u32 cols_cfg[KBC_MAX_GPIO];
u32 rows_cfg[KBC_MAX_GPIO];
- int proplen;
- int ret;
if (!of_property_read_u32(np, "nvidia,debounce-delay-ms", &prop))
kbc->debounce_cnt = prop;
@@ -510,56 +501,23 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
of_property_read_bool(np, "nvidia,wakeup-source")) /* legacy */
kbc->wakeup = true;
- if (!of_get_property(np, "nvidia,kbc-row-pins", &proplen)) {
- dev_err(kbc->dev, "property nvidia,kbc-row-pins not found\n");
- return -ENOENT;
- }
- num_rows = proplen / sizeof(u32);
-
- if (!of_get_property(np, "nvidia,kbc-col-pins", &proplen)) {
- dev_err(kbc->dev, "property nvidia,kbc-col-pins not found\n");
- return -ENOENT;
- }
- num_cols = proplen / sizeof(u32);
-
- if (num_rows > kbc->hw_support->max_rows) {
- dev_err(kbc->dev,
- "Number of rows is more than supported by hardware\n");
- return -EINVAL;
- }
-
- if (num_cols > kbc->hw_support->max_columns) {
- dev_err(kbc->dev,
- "Number of cols is more than supported by hardware\n");
- return -EINVAL;
- }
-
- if (!of_get_property(np, "linux,keymap", &proplen)) {
+ if (!of_property_present(np, "linux,keymap")) {
dev_err(kbc->dev, "property linux,keymap not found\n");
return -ENOENT;
}
- if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
- dev_err(kbc->dev,
- "keypad rows/columns not properly specified\n");
- return -EINVAL;
- }
-
/* Set all pins as non-configured */
for (i = 0; i < kbc->num_rows_and_columns; i++)
kbc->pin_cfg[i].type = PIN_CFG_IGNORE;
- ret = of_property_read_u32_array(np, "nvidia,kbc-row-pins",
- rows_cfg, num_rows);
- if (ret < 0) {
+ num_rows = of_property_read_variable_u32_array(np, "nvidia,kbc-row-pins",
+ rows_cfg, 1, KBC_MAX_GPIO);
+ if (num_rows < 0) {
dev_err(kbc->dev, "Rows configurations are not proper\n");
- return -EINVAL;
- }
-
- ret = of_property_read_u32_array(np, "nvidia,kbc-col-pins",
- cols_cfg, num_cols);
- if (ret < 0) {
- dev_err(kbc->dev, "Cols configurations are not proper\n");
+ return num_rows;
+ } else if (num_rows > kbc->hw_support->max_rows) {
+ dev_err(kbc->dev,
+ "Number of rows is more than supported by hardware\n");
return -EINVAL;
}
@@ -568,11 +526,28 @@ static int tegra_kbc_parse_dt(struct tegra_kbc *kbc)
kbc->pin_cfg[rows_cfg[i]].num = i;
}
+ num_cols = of_property_read_variable_u32_array(np, "nvidia,kbc-col-pins",
+ cols_cfg, 1, KBC_MAX_GPIO);
+ if (num_cols < 0) {
+ dev_err(kbc->dev, "Cols configurations are not proper\n");
+ return num_cols;
+ } else if (num_cols > kbc->hw_support->max_columns) {
+ dev_err(kbc->dev,
+ "Number of cols is more than supported by hardware\n");
+ return -EINVAL;
+ }
+
for (i = 0; i < num_cols; i++) {
kbc->pin_cfg[cols_cfg[i]].type = PIN_CFG_COL;
kbc->pin_cfg[cols_cfg[i]].num = i;
}
+ if (!num_rows || !num_cols || ((num_rows + num_cols) > KBC_MAX_GPIO)) {
+ dev_err(kbc->dev,
+ "keypad rows/columns not properly specified\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -724,10 +699,11 @@ static int tegra_kbc_suspend(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
- mutex_lock(&kbc->idev->mutex);
+ guard(mutex)(&kbc->idev->mutex);
+
if (device_may_wakeup(&pdev->dev)) {
disable_irq(kbc->irq);
- del_timer_sync(&kbc->timer);
+ timer_delete_sync(&kbc->timer);
tegra_kbc_set_fifo_interrupt(kbc, false);
/* Forcefully clear the interrupt status */
@@ -747,11 +723,9 @@ static int tegra_kbc_suspend(struct device *dev)
tegra_kbc_set_keypress_interrupt(kbc, true);
enable_irq(kbc->irq);
enable_irq_wake(kbc->irq);
- } else {
- if (input_device_enabled(kbc->idev))
- tegra_kbc_stop(kbc);
+ } else if (input_device_enabled(kbc->idev)) {
+ tegra_kbc_stop(kbc);
}
- mutex_unlock(&kbc->idev->mutex);
return 0;
}
@@ -760,9 +734,10 @@ static int tegra_kbc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tegra_kbc *kbc = platform_get_drvdata(pdev);
- int err = 0;
+ int err;
+
+ guard(mutex)(&kbc->idev->mutex);
- mutex_lock(&kbc->idev->mutex);
if (device_may_wakeup(&pdev->dev)) {
disable_irq_wake(kbc->irq);
tegra_kbc_setup_wakekeys(kbc, false);
@@ -787,13 +762,13 @@ static int tegra_kbc_resume(struct device *dev)
input_report_key(kbc->idev, kbc->wakeup_key, 0);
input_sync(kbc->idev);
}
- } else {
- if (input_device_enabled(kbc->idev))
- err = tegra_kbc_start(kbc);
+ } else if (input_device_enabled(kbc->idev)) {
+ err = tegra_kbc_start(kbc);
+ if (err)
+ return err;
}
- mutex_unlock(&kbc->idev->mutex);
- return err;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(tegra_kbc_pm_ops,
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 77e0743a3cf8..5e3d17c5dc9b 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -28,10 +28,6 @@
* an internal state machine that decodes pressed keys, including
* multi-key combinations.
*
- * This driver lets boards define what keycodes they wish to report for
- * which scancodes, as part of the "struct twl4030_keypad_data" used in
- * the probe() routine.
- *
* See the TPS65950 documentation; that's the general availability
* version of the TWL5030 second generation part.
*/
@@ -47,7 +43,6 @@
struct twl4030_keypad {
unsigned short keymap[TWL4030_KEYMAP_SIZE];
u16 kp_state[TWL4030_MAX_ROWS];
- bool autorepeat;
unsigned int n_rows;
unsigned int n_cols;
int irq;
@@ -322,8 +317,6 @@ static int twl4030_kp_program(struct twl4030_keypad *kp)
*/
static int twl4030_kp_probe(struct platform_device *pdev)
{
- struct twl4030_keypad_data *pdata = dev_get_platdata(&pdev->dev);
- const struct matrix_keymap_data *keymap_data = NULL;
struct twl4030_keypad *kp;
struct input_dev *input;
u8 reg;
@@ -350,24 +343,10 @@ static int twl4030_kp_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0003;
- if (pdata) {
- if (!pdata->rows || !pdata->cols || !pdata->keymap_data) {
- dev_err(&pdev->dev, "Missing platform_data\n");
- return -EINVAL;
- }
-
- kp->n_rows = pdata->rows;
- kp->n_cols = pdata->cols;
- kp->autorepeat = pdata->rep;
- keymap_data = pdata->keymap_data;
- } else {
- error = matrix_keypad_parse_properties(&pdev->dev, &kp->n_rows,
- &kp->n_cols);
- if (error)
- return error;
-
- kp->autorepeat = true;
- }
+ error = matrix_keypad_parse_properties(&pdev->dev,
+ &kp->n_rows, &kp->n_cols);
+ if (error)
+ return error;
if (kp->n_rows > TWL4030_MAX_ROWS || kp->n_cols > TWL4030_MAX_COLS) {
dev_err(&pdev->dev,
@@ -379,7 +358,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
if (kp->irq < 0)
return kp->irq;
- error = matrix_keypad_build_keymap(keymap_data, NULL,
+ error = matrix_keypad_build_keymap(NULL, NULL,
TWL4030_MAX_ROWS,
1 << TWL4030_ROW_SHIFT,
kp->keymap, input);
@@ -389,9 +368,7 @@ static int twl4030_kp_probe(struct platform_device *pdev)
}
input_set_capability(input, EV_MSC, MSC_SCAN);
- /* Enable auto repeat feature of Linux input subsystem */
- if (kp->autorepeat)
- __set_bit(EV_REP, input->evbit);
+ __set_bit(EV_REP, input->evbit);
error = input_register_device(input);
if (error) {
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index c9d7c2481726..befa713268ae 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -70,7 +70,7 @@ static int xtkbd_connect(struct serio *serio, struct serio_driver *drv)
int err = -ENOMEM;
int i;
- xtkbd = kmalloc(sizeof(struct xtkbd), GFP_KERNEL);
+ xtkbd = kmalloc(sizeof(*xtkbd), GFP_KERNEL);
input_dev = input_allocate_device();
if (!xtkbd || !input_dev)
goto fail1;
diff --git a/drivers/input/matrix-keymap.c b/drivers/input/matrix-keymap.c
index 4fa53423f56c..3bea3575a0a9 100644
--- a/drivers/input/matrix-keymap.c
+++ b/drivers/input/matrix-keymap.c
@@ -73,10 +73,9 @@ static int matrix_keypad_parse_keymap(const char *propname,
struct device *dev = input_dev->dev.parent;
unsigned int row_shift = get_count_order(cols);
unsigned int max_keys = rows << row_shift;
- u32 *keys;
int i;
int size;
- int retval;
+ int error;
if (!propname)
propname = "linux,keymap";
@@ -94,30 +93,24 @@ static int matrix_keypad_parse_keymap(const char *propname,
return -EINVAL;
}
- keys = kmalloc_array(size, sizeof(u32), GFP_KERNEL);
+ u32 *keys __free(kfree) = kmalloc_array(size, sizeof(*keys), GFP_KERNEL);
if (!keys)
return -ENOMEM;
- retval = device_property_read_u32_array(dev, propname, keys, size);
- if (retval) {
+ error = device_property_read_u32_array(dev, propname, keys, size);
+ if (error) {
dev_err(dev, "failed to read %s property: %d\n",
- propname, retval);
- goto out;
+ propname, error);
+ return error;
}
for (i = 0; i < size; i++) {
if (!matrix_keypad_map_key(input_dev, rows, cols,
- row_shift, keys[i])) {
- retval = -EINVAL;
- goto out;
- }
+ row_shift, keys[i]))
+ return -EINVAL;
}
- retval = 0;
-
-out:
- kfree(keys);
- return retval;
+ return 0;
}
/**
@@ -199,4 +192,5 @@ int matrix_keypad_build_keymap(const struct matrix_keymap_data *keymap_data,
}
EXPORT_SYMBOL(matrix_keypad_build_keymap);
+MODULE_DESCRIPTION("Helpers for matrix keyboard bindings");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c
index 4b0685f96113..9159b5fec129 100644
--- a/drivers/input/misc/88pm80x_onkey.c
+++ b/drivers/input/misc/88pm80x_onkey.c
@@ -57,7 +57,7 @@ static int pm80x_onkey_probe(struct platform_device *pdev)
struct pm80x_onkey_info *info;
int err;
- info = kzalloc(sizeof(struct pm80x_onkey_info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@@ -141,7 +141,7 @@ static struct platform_driver pm80x_onkey_driver = {
.pm = &pm80x_onkey_pm_ops,
},
.probe = pm80x_onkey_probe,
- .remove_new = pm80x_onkey_remove,
+ .remove = pm80x_onkey_remove,
};
module_platform_driver(pm80x_onkey_driver);
diff --git a/drivers/input/misc/88pm886-onkey.c b/drivers/input/misc/88pm886-onkey.c
new file mode 100644
index 000000000000..284ff5190b6e
--- /dev/null
+++ b/drivers/input/misc/88pm886-onkey.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#include <linux/mfd/88pm886.h>
+
+struct pm886_onkey {
+ struct input_dev *idev;
+ struct pm886_chip *chip;
+};
+
+static irqreturn_t pm886_onkey_irq_handler(int irq, void *data)
+{
+ struct pm886_onkey *onkey = data;
+ struct regmap *regmap = onkey->chip->regmap;
+ struct input_dev *idev = onkey->idev;
+ struct device *parent = idev->dev.parent;
+ unsigned int val;
+ int err;
+
+ err = regmap_read(regmap, PM886_REG_STATUS1, &val);
+ if (err) {
+ dev_err(parent, "Failed to read status: %d\n", err);
+ return IRQ_NONE;
+ }
+ val &= PM886_ONKEY_STS1;
+
+ input_report_key(idev, KEY_POWER, val);
+ input_sync(idev);
+
+ return IRQ_HANDLED;
+}
+
+static int pm886_onkey_probe(struct platform_device *pdev)
+{
+ struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct pm886_onkey *onkey;
+ struct input_dev *idev;
+ int irq, err;
+
+ onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ onkey->chip = chip;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get IRQ\n");
+
+ idev = devm_input_allocate_device(dev);
+ if (!idev) {
+ dev_err(dev, "Failed to allocate input device\n");
+ return -ENOMEM;
+ }
+ onkey->idev = idev;
+
+ idev->name = "88pm886-onkey";
+ idev->phys = "88pm886-onkey/input0";
+ idev->id.bustype = BUS_I2C;
+
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ err = devm_request_threaded_irq(dev, irq, NULL, pm886_onkey_irq_handler,
+ IRQF_ONESHOT | IRQF_NO_SUSPEND, "onkey",
+ onkey);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to request IRQ\n");
+
+ err = input_register_device(idev);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to register input device\n");
+
+ return 0;
+}
+
+static const struct platform_device_id pm886_onkey_id_table[] = {
+ { "88pm886-onkey", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, pm886_onkey_id_table);
+
+static struct platform_driver pm886_onkey_driver = {
+ .driver = {
+ .name = "88pm886-onkey",
+ },
+ .probe = pm886_onkey_probe,
+ .id_table = pm886_onkey_id_table,
+};
+module_platform_driver(pm886_onkey_driver);
+
+MODULE_DESCRIPTION("Marvell 88PM886 onkey driver");
+MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 6ba984d7f0b1..94a753fcb64f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -33,6 +33,13 @@ config INPUT_88PM80X_ONKEY
To compile this driver as a module, choose M here: the module
will be called 88pm80x_onkey.
+config INPUT_88PM886_ONKEY
+ tristate "Marvell 88PM886 onkey support"
+ depends on MFD_88PM886_PMIC
+ help
+ Support the onkey of Marvell 88PM886 PMIC as an input device
+ reporting power button status.
+
config INPUT_AB8500_PONKEY
tristate "AB8500 Pon (PowerOn) Key"
depends on AB8500_CORE
@@ -119,6 +126,17 @@ config INPUT_ATMEL_CAPTOUCH
To compile this driver as a module, choose M here: the
module will be called atmel_captouch.
+config INPUT_AW86927
+ tristate "Awinic AW86927 Haptic Driver Support"
+ depends on I2C && INPUT
+ select INPUT_FF_MEMLESS
+ select REGMAP_I2C
+ help
+ Say Y here if you have an Awinic AW86927 haptic chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called aw86927.
+
config INPUT_BBNSM_PWRKEY
tristate "NXP BBNSM Power Key Driver"
depends on ARCH_MXC || COMPILE_TEST
@@ -140,6 +158,16 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_CS40L50_VIBRA
+ tristate "CS40L50 Haptic Driver support"
+ depends on MFD_CS40L50_CORE
+ help
+ Say Y here to enable support for Cirrus Logic's CS40L50
+ haptic driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cs40l50-vibra.
+
config INPUT_E3X0_BUTTON
tristate "NI Ettus Research USRP E3xx Button support."
default n
@@ -162,6 +190,17 @@ config INPUT_PCSPKR
To compile this driver as a module, choose M here: the
module will be called pcspkr.
+config INPUT_PF1550_ONKEY
+ tristate "NXP PF1550 Onkey support"
+ depends on MFD_PF1550
+ help
+ Say Y here if you want support for PF1550 PMIC. Onkey can trigger
+ release and 1s(push hold), 2s, 3s, 4s, 8s interrupt for long press
+ detect.
+
+ To compile this driver as a module, choose M here. The module will be
+ called pf1550-onkey.
+
config INPUT_PM8941_PWRKEY
tristate "Qualcomm PM8941 power key support"
depends on MFD_SPMI_PMIC
@@ -213,6 +252,16 @@ config INPUT_M68K_BEEP
tristate "M68k Beeper support"
depends on M68K
+config INPUT_MAX7360_ROTARY
+ tristate "Maxim MAX7360 Rotary Encoder"
+ depends on MFD_MAX7360
+ help
+ If you say yes here you get support for the rotary encoder on the
+ Maxim MAX7360 I/O Expander.
+
+ To compile this driver as a module, choose M here: the module will be
+ called max7360_rotary.
+
config INPUT_MAX77650_ONKEY
tristate "Maxim MAX77650 ONKEY support"
depends on MFD_MAX77650
@@ -223,12 +272,12 @@ config INPUT_MAX77650_ONKEY
will be called max77650-onkey.
config INPUT_MAX77693_HAPTIC
- tristate "MAXIM MAX77693/MAX77843 haptic controller support"
- depends on (MFD_MAX77693 || MFD_MAX77843) && PWM
+ tristate "MAXIM MAX77693/MAX77705/MAX77843 haptic controller support"
+ depends on (MFD_MAX77693 || MFD_MAX77705 || MFD_MAX77843) && PWM
select INPUT_FF_MEMLESS
help
This option enables support for the haptic controller on
- MAXIM MAX77693 and MAX77843 chips.
+ MAXIM MAX77693, MAX77705 and MAX77843 chips.
To compile this driver as module, choose M here: the
module will be called max77693-haptic.
@@ -489,6 +538,16 @@ config INPUT_TPS65219_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called tps65219-pwrbutton.
+config INPUT_TPS6594_PWRBUTTON
+ tristate "TPS6594 Power button driver"
+ depends on MFD_TPS6594
+ help
+ Say Y here if you want to enable power button reporting for
+ TPS6594 Power Management IC devices.
+
+ To compile this driver as a module, choose M here. The module will
+ be called tps6594-pwrbutton.
+
config INPUT_AXP20X_PEK
tristate "X-Powers AXP20X power button driver"
depends on MFD_AXP20X
@@ -567,13 +626,6 @@ config INPUT_PALMAS_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called palmas_pwrbutton.
-config INPUT_PCF50633_PMU
- tristate "PCF50633 PMU events"
- depends on MFD_PCF50633
- help
- Say Y to include support for delivering PMU events via input
- layer on NXP PCF50633.
-
config INPUT_PCF8574
tristate "PCF8574 Keypad input device"
depends on I2C
@@ -900,6 +952,18 @@ config INPUT_HISI_POWERKEY
To compile this driver as a module, choose M here: the
module will be called hisi_powerkey.
+config INPUT_QNAP_MCU
+ tristate "Input Support for QNAP MCU controllers"
+ depends on MFD_QNAP_MCU
+ help
+ This option enables support for input elements available on
+ embedded controllers used in QNAP NAS devices.
+
+ This includes a polled power-button as well as a beeper.
+
+ To compile this driver as a module, choose M here: the
+ module will be called qnap-mcu-input.
+
config INPUT_RAVE_SP_PWRBUTTON
tristate "RAVE SP Power button Driver"
depends on RAVE_SP_CORE
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 04296a4abe8e..415fc4e2918b 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -7,6 +7,7 @@
obj-$(CONFIG_INPUT_88PM860X_ONKEY) += 88pm860x_onkey.o
obj-$(CONFIG_INPUT_88PM80X_ONKEY) += 88pm80x_onkey.o
+obj-$(CONFIG_INPUT_88PM886_ONKEY) += 88pm886-onkey.o
obj-$(CONFIG_INPUT_AB8500_PONKEY) += ab8500-ponkey.o
obj-$(CONFIG_INPUT_AD714X) += ad714x.o
obj-$(CONFIG_INPUT_AD714X_I2C) += ad714x-i2c.o
@@ -21,6 +22,7 @@ obj-$(CONFIG_INPUT_ATC260X_ONKEY) += atc260x-onkey.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o
+obj-$(CONFIG_INPUT_AW86927) += aw86927.o
obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o
obj-$(CONFIG_INPUT_BMA150) += bma150.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
@@ -28,6 +30,7 @@ obj-$(CONFIG_INPUT_CMA3000) += cma3000_d0x.o
obj-$(CONFIG_INPUT_CMA3000_I2C) += cma3000_d0x_i2c.o
obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_CPCAP_PWRBUTTON) += cpcap-pwrbutton.o
+obj-$(CONFIG_INPUT_CS40L50_VIBRA) += cs40l50-vibra.o
obj-$(CONFIG_INPUT_DA7280_HAPTICS) += da7280.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
@@ -49,6 +52,7 @@ obj-$(CONFIG_INPUT_IQS7222) += iqs7222.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
+obj-$(CONFIG_INPUT_MAX7360_ROTARY) += max7360-rotary.o
obj-$(CONFIG_INPUT_MAX77650_ONKEY) += max77650-onkey.o
obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
@@ -57,15 +61,16 @@ obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
obj-$(CONFIG_INPUT_MMA8450) += mma8450.o
obj-$(CONFIG_INPUT_PALMAS_PWRBUTTON) += palmas-pwrbutton.o
obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o
-obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o
obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o
obj-$(CONFIG_INPUT_PCSPKR) += pcspkr.o
+obj-$(CONFIG_INPUT_PF1550_ONKEY) += pf1550-onkey.o
obj-$(CONFIG_INPUT_PM8941_PWRKEY) += pm8941-pwrkey.o
obj-$(CONFIG_INPUT_PM8XXX_VIBRATOR) += pm8xxx-vibrator.o
obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_PWM_VIBRA) += pwm-vibra.o
+obj-$(CONFIG_INPUT_QNAP_MCU) += qnap-mcu-input.o
obj-$(CONFIG_INPUT_RAVE_SP_PWRBUTTON) += rave-sp-pwrbutton.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
@@ -81,6 +86,7 @@ obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o
obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o
obj-$(CONFIG_INPUT_TPS65219_PWRBUTTON) += tps65219-pwrbutton.o
+obj-$(CONFIG_INPUT_TPS6594_PWRBUTTON) += tps6594-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index 1acd8429c56c..c9fa789337ba 100644
--- a/drivers/input/misc/ad714x.c
+++ b/drivers/input/misc/ad714x.c
@@ -6,6 +6,7 @@
*/
#include <linux/device.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
@@ -941,7 +942,7 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
struct ad714x_chip *ad714x = data;
int i;
- mutex_lock(&ad714x->mutex);
+ guard(mutex)(&ad714x->mutex);
ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
@@ -954,8 +955,6 @@ static irqreturn_t ad714x_interrupt_thread(int irq, void *data)
for (i = 0; i < ad714x->hw->touchpad_num; i++)
ad714x_touchpad_state_machine(ad714x, i);
- mutex_unlock(&ad714x->mutex);
-
return IRQ_HANDLED;
}
@@ -1169,13 +1168,11 @@ static int ad714x_suspend(struct device *dev)
dev_dbg(ad714x->dev, "%s enter\n", __func__);
- mutex_lock(&ad714x->mutex);
+ guard(mutex)(&ad714x->mutex);
data = ad714x->hw->sys_cfg_reg[AD714X_PWR_CTRL] | 0x3;
ad714x->write(ad714x, AD714X_PWR_CTRL, data);
- mutex_unlock(&ad714x->mutex);
-
return 0;
}
@@ -1184,7 +1181,7 @@ static int ad714x_resume(struct device *dev)
struct ad714x_chip *ad714x = dev_get_drvdata(dev);
dev_dbg(ad714x->dev, "%s enter\n", __func__);
- mutex_lock(&ad714x->mutex);
+ guard(mutex)(&ad714x->mutex);
/* resume to non-shutdown mode */
@@ -1197,8 +1194,6 @@ static int ad714x_resume(struct device *dev)
ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
- mutex_unlock(&ad714x->mutex);
-
return 0;
}
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index d4014e367c77..c05d898898e8 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -98,13 +98,6 @@ static int adxl34x_i2c_probe(struct i2c_client *client)
return 0;
}
-static void adxl34x_i2c_remove(struct i2c_client *client)
-{
- struct adxl34x *ac = i2c_get_clientdata(client);
-
- adxl34x_remove(ac);
-}
-
static const struct i2c_device_id adxl34x_id[] = {
{ "adxl34x" },
{ }
@@ -132,11 +125,11 @@ MODULE_DEVICE_TABLE(of, adxl34x_of_id);
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
+ .dev_groups = adxl34x_groups,
.pm = pm_sleep_ptr(&adxl34x_pm),
.of_match_table = adxl34x_of_id,
},
.probe = adxl34x_i2c_probe,
- .remove = adxl34x_i2c_remove,
.id_table = adxl34x_id,
};
diff --git a/drivers/input/misc/adxl34x-spi.c b/drivers/input/misc/adxl34x-spi.c
index f1094a8ccdd5..fd716d861832 100644
--- a/drivers/input/misc/adxl34x-spi.c
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -87,20 +87,13 @@ static int adxl34x_spi_probe(struct spi_device *spi)
return 0;
}
-static void adxl34x_spi_remove(struct spi_device *spi)
-{
- struct adxl34x *ac = spi_get_drvdata(spi);
-
- adxl34x_remove(ac);
-}
-
static struct spi_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
+ .dev_groups = adxl34x_groups,
.pm = pm_sleep_ptr(&adxl34x_pm),
},
.probe = adxl34x_spi_probe,
- .remove = adxl34x_spi_remove,
};
module_spi_driver(adxl34x_driver);
diff --git a/drivers/input/misc/adxl34x.c b/drivers/input/misc/adxl34x.c
index a3f45e0ee0c7..ac7674647c09 100644
--- a/drivers/input/misc/adxl34x.c
+++ b/drivers/input/misc/adxl34x.c
@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -241,7 +242,8 @@ static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
ac->bops->read_block(ac->dev, DATAX0, DATAZ1 - DATAX0 + 1, buf);
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
+
ac->saved.x = (s16) le16_to_cpu(buf[0]);
axis->x = ac->saved.x;
@@ -250,7 +252,6 @@ static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
ac->saved.z = (s16) le16_to_cpu(buf[2]);
axis->z = ac->saved.z;
- mutex_unlock(&ac->mutex);
}
static void adxl34x_service_ev_fifo(struct adxl34x *ac)
@@ -416,15 +417,13 @@ static int adxl34x_suspend(struct device *dev)
{
struct adxl34x *ac = dev_get_drvdata(dev);
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
if (!ac->suspended && !ac->disabled && ac->opened)
__adxl34x_disable(ac);
ac->suspended = true;
- mutex_unlock(&ac->mutex);
-
return 0;
}
@@ -432,15 +431,13 @@ static int adxl34x_resume(struct device *dev)
{
struct adxl34x *ac = dev_get_drvdata(dev);
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
if (ac->suspended && !ac->disabled && ac->opened)
__adxl34x_enable(ac);
ac->suspended = false;
- mutex_unlock(&ac->mutex);
-
return 0;
}
@@ -464,7 +461,7 @@ static ssize_t adxl34x_disable_store(struct device *dev,
if (error)
return error;
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
if (!ac->suspended && ac->opened) {
if (val) {
@@ -478,8 +475,6 @@ static ssize_t adxl34x_disable_store(struct device *dev,
ac->disabled = !!val;
- mutex_unlock(&ac->mutex);
-
return count;
}
@@ -489,16 +484,13 @@ static ssize_t adxl34x_calibrate_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adxl34x *ac = dev_get_drvdata(dev);
- ssize_t count;
- mutex_lock(&ac->mutex);
- count = sprintf(buf, "%d,%d,%d\n",
- ac->hwcal.x * 4 + ac->swcal.x,
- ac->hwcal.y * 4 + ac->swcal.y,
- ac->hwcal.z * 4 + ac->swcal.z);
- mutex_unlock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
- return count;
+ return sprintf(buf, "%d,%d,%d\n",
+ ac->hwcal.x * 4 + ac->swcal.x,
+ ac->hwcal.y * 4 + ac->swcal.y,
+ ac->hwcal.z * 4 + ac->swcal.z);
}
static ssize_t adxl34x_calibrate_store(struct device *dev,
@@ -512,7 +504,8 @@ static ssize_t adxl34x_calibrate_store(struct device *dev,
* We use HW calibration and handle the remaining bits in SW. (4mg/LSB)
*/
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
+
ac->hwcal.x -= (ac->saved.x / 4);
ac->swcal.x = ac->saved.x % 4;
@@ -525,7 +518,6 @@ static ssize_t adxl34x_calibrate_store(struct device *dev,
AC_WRITE(ac, OFSX, (s8) ac->hwcal.x);
AC_WRITE(ac, OFSY, (s8) ac->hwcal.y);
AC_WRITE(ac, OFSZ, (s8) ac->hwcal.z);
- mutex_unlock(&ac->mutex);
return count;
}
@@ -553,15 +545,13 @@ static ssize_t adxl34x_rate_store(struct device *dev,
if (error)
return error;
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
ac->pdata.data_rate = RATE(val);
AC_WRITE(ac, BW_RATE,
ac->pdata.data_rate |
(ac->pdata.low_power_mode ? LOW_POWER : 0));
- mutex_unlock(&ac->mutex);
-
return count;
}
@@ -588,7 +578,7 @@ static ssize_t adxl34x_autosleep_store(struct device *dev,
if (error)
return error;
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
if (val)
ac->pdata.power_mode |= (PCTL_AUTO_SLEEP | PCTL_LINK);
@@ -598,8 +588,6 @@ static ssize_t adxl34x_autosleep_store(struct device *dev,
if (!ac->disabled && !ac->suspended && ac->opened)
AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
- mutex_unlock(&ac->mutex);
-
return count;
}
@@ -610,14 +598,11 @@ static ssize_t adxl34x_position_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct adxl34x *ac = dev_get_drvdata(dev);
- ssize_t count;
- mutex_lock(&ac->mutex);
- count = sprintf(buf, "(%d, %d, %d)\n",
- ac->saved.x, ac->saved.y, ac->saved.z);
- mutex_unlock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
- return count;
+ return sprintf(buf, "(%d, %d, %d)\n",
+ ac->saved.x, ac->saved.y, ac->saved.z);
}
static DEVICE_ATTR(position, S_IRUGO, adxl34x_position_show, NULL);
@@ -638,9 +623,8 @@ static ssize_t adxl34x_write_store(struct device *dev,
if (error)
return error;
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
AC_WRITE(ac, val >> 8, val & 0xFF);
- mutex_unlock(&ac->mutex);
return count;
}
@@ -664,19 +648,23 @@ static const struct attribute_group adxl34x_attr_group = {
.attrs = adxl34x_attributes,
};
+const struct attribute_group *adxl34x_groups[] = {
+ &adxl34x_attr_group,
+ NULL
+};
+EXPORT_SYMBOL_GPL(adxl34x_groups);
+
static int adxl34x_input_open(struct input_dev *input)
{
struct adxl34x *ac = input_get_drvdata(input);
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
if (!ac->suspended && !ac->disabled)
__adxl34x_enable(ac);
ac->opened = true;
- mutex_unlock(&ac->mutex);
-
return 0;
}
@@ -684,14 +672,12 @@ static void adxl34x_input_close(struct input_dev *input)
{
struct adxl34x *ac = input_get_drvdata(input);
- mutex_lock(&ac->mutex);
+ guard(mutex)(&ac->mutex);
if (!ac->suspended && !ac->disabled)
__adxl34x_disable(ac);
ac->opened = false;
-
- mutex_unlock(&ac->mutex);
}
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
@@ -701,21 +687,21 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
struct adxl34x *ac;
struct input_dev *input_dev;
const struct adxl34x_platform_data *pdata;
- int err, range, i;
+ int error, range, i;
int revid;
if (!irq) {
dev_err(dev, "no IRQ?\n");
- err = -ENODEV;
- goto err_out;
+ return ERR_PTR(-ENODEV);
}
- ac = kzalloc(sizeof(*ac), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ac || !input_dev) {
- err = -ENOMEM;
- goto err_free_mem;
- }
+ ac = devm_kzalloc(dev, sizeof(*ac), GFP_KERNEL);
+ if (!ac)
+ return ERR_PTR(-ENOMEM);
+
+ input_dev = devm_input_allocate_device(dev);
+ if (!input_dev)
+ return ERR_PTR(-ENOMEM);
ac->fifo_delay = fifo_delay_default;
@@ -748,14 +734,12 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
break;
default:
dev_err(dev, "Failed to probe %s\n", input_dev->name);
- err = -ENODEV;
- goto err_free_mem;
+ return ERR_PTR(-ENODEV);
}
snprintf(ac->phys, sizeof(ac->phys), "%s/input0", dev_name(dev));
input_dev->phys = ac->phys;
- input_dev->dev.parent = dev;
input_dev->id.product = ac->model;
input_dev->id.bustype = bops->bustype;
input_dev->open = adxl34x_input_open;
@@ -763,18 +747,12 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
input_set_drvdata(input_dev, ac);
- __set_bit(ac->pdata.ev_type, input_dev->evbit);
-
if (ac->pdata.ev_type == EV_REL) {
- __set_bit(REL_X, input_dev->relbit);
- __set_bit(REL_Y, input_dev->relbit);
- __set_bit(REL_Z, input_dev->relbit);
+ input_set_capability(input_dev, EV_REL, REL_X);
+ input_set_capability(input_dev, EV_REL, REL_Y);
+ input_set_capability(input_dev, EV_REL, REL_Z);
} else {
/* EV_ABS */
- __set_bit(ABS_X, input_dev->absbit);
- __set_bit(ABS_Y, input_dev->absbit);
- __set_bit(ABS_Z, input_dev->absbit);
-
if (pdata->data_range & FULL_RES)
range = ADXL_FULLRES_MAX_VAL; /* Signed 13-bit */
else
@@ -785,18 +763,18 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
input_set_abs_params(input_dev, ABS_Z, -range, range, 3, 3);
}
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(pdata->ev_code_tap[ADXL_X_AXIS], input_dev->keybit);
- __set_bit(pdata->ev_code_tap[ADXL_Y_AXIS], input_dev->keybit);
- __set_bit(pdata->ev_code_tap[ADXL_Z_AXIS], input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, pdata->ev_code_tap[ADXL_X_AXIS]);
+ input_set_capability(input_dev, EV_KEY, pdata->ev_code_tap[ADXL_Y_AXIS]);
+ input_set_capability(input_dev, EV_KEY, pdata->ev_code_tap[ADXL_Z_AXIS]);
if (pdata->ev_code_ff) {
ac->int_mask = FREE_FALL;
- __set_bit(pdata->ev_code_ff, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY, pdata->ev_code_ff);
}
if (pdata->ev_code_act_inactivity)
- __set_bit(pdata->ev_code_act_inactivity, input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY,
+ pdata->ev_code_act_inactivity);
ac->int_mask |= ACTIVITY | INACTIVITY;
@@ -816,20 +794,16 @@ 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_ONESHOT, dev_name(dev), ac);
- if (err) {
+ error = devm_request_threaded_irq(dev, ac->irq, NULL, adxl34x_irq,
+ IRQF_ONESHOT, dev_name(dev), ac);
+ if (error) {
dev_err(dev, "irq %d busy?\n", ac->irq);
- goto err_free_mem;
+ return ERR_PTR(error);
}
- err = sysfs_create_group(&dev->kobj, &adxl34x_attr_group);
- if (err)
- goto err_free_irq;
-
- err = input_register_device(input_dev);
- if (err)
- goto err_remove_attr;
+ error = input_register_device(input_dev);
+ if (error)
+ return ERR_PTR(error);
AC_WRITE(ac, OFSX, pdata->x_axis_offset);
ac->hwcal.x = pdata->x_axis_offset;
@@ -872,13 +846,13 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
if (pdata->orientation_enable & ADXL_EN_ORIENTATION_3D)
for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_3d); i++)
- __set_bit(pdata->ev_codes_orient_3d[i],
- input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY,
+ pdata->ev_codes_orient_3d[i]);
if (pdata->orientation_enable & ADXL_EN_ORIENTATION_2D)
for (i = 0; i < ARRAY_SIZE(pdata->ev_codes_orient_2d); i++)
- __set_bit(pdata->ev_codes_orient_2d[i],
- input_dev->keybit);
+ input_set_capability(input_dev, EV_KEY,
+ pdata->ev_codes_orient_2d[i]);
} else {
ac->pdata.orientation_enable = 0;
}
@@ -888,29 +862,9 @@ struct adxl34x *adxl34x_probe(struct device *dev, int irq,
ac->pdata.power_mode &= (PCTL_AUTO_SLEEP | PCTL_LINK);
return ac;
-
- err_remove_attr:
- sysfs_remove_group(&dev->kobj, &adxl34x_attr_group);
- err_free_irq:
- free_irq(ac->irq, ac);
- err_free_mem:
- input_free_device(input_dev);
- kfree(ac);
- err_out:
- return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(adxl34x_probe);
-void adxl34x_remove(struct adxl34x *ac)
-{
- sysfs_remove_group(&ac->dev->kobj, &adxl34x_attr_group);
- free_irq(ac->irq, ac);
- input_unregister_device(ac->input);
- dev_dbg(ac->dev, "unregistered accelerometer\n");
- kfree(ac);
-}
-EXPORT_SYMBOL_GPL(adxl34x_remove);
-
EXPORT_GPL_SIMPLE_DEV_PM_OPS(adxl34x_pm, adxl34x_suspend, adxl34x_resume);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
index f9272a2e7a96..718e90c2046d 100644
--- a/drivers/input/misc/adxl34x.h
+++ b/drivers/input/misc/adxl34x.h
@@ -23,8 +23,8 @@ struct adxl34x_bus_ops {
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
bool fifo_delay_default,
const struct adxl34x_bus_ops *bops);
-void adxl34x_remove(struct adxl34x *ac);
extern const struct dev_pm_ops adxl34x_pm;
+extern const struct attribute_group *adxl34x_groups[];
#endif
diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c
index 5fa1c9438a85..bb1544d63c51 100644
--- a/drivers/input/misc/arizona-haptics.c
+++ b/drivers/input/misc/arizona-haptics.c
@@ -34,8 +34,6 @@ static void arizona_haptics_work(struct work_struct *work)
struct arizona_haptics,
work);
struct arizona *arizona = haptics->arizona;
- struct snd_soc_component *component =
- snd_soc_dapm_to_component(arizona->dapm);
int ret;
if (!haptics->arizona->dapm) {
@@ -65,7 +63,7 @@ static void arizona_haptics_work(struct work_struct *work)
return;
}
- ret = snd_soc_component_enable_pin(component, "HAPTICS");
+ ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS");
if (ret != 0) {
dev_err(arizona->dev, "Failed to start HAPTICS: %d\n",
ret);
@@ -80,7 +78,7 @@ static void arizona_haptics_work(struct work_struct *work)
}
} else {
/* This disable sequence will be a noop if already enabled */
- ret = snd_soc_component_disable_pin(component, "HAPTICS");
+ ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS");
if (ret != 0) {
dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n",
ret);
@@ -139,14 +137,12 @@ static int arizona_haptics_play(struct input_dev *input, void *data,
static void arizona_haptics_close(struct input_dev *input)
{
struct arizona_haptics *haptics = input_get_drvdata(input);
- struct snd_soc_component *component;
+ struct snd_soc_dapm_context *dapm = haptics->arizona->dapm;
cancel_work_sync(&haptics->work);
- if (haptics->arizona->dapm) {
- component = snd_soc_dapm_to_component(haptics->arizona->dapm);
- snd_soc_component_disable_pin(component, "HAPTICS");
- }
+ if (dapm)
+ snd_soc_dapm_disable_pin(dapm, "HAPTICS");
}
static int arizona_haptics_probe(struct platform_device *pdev)
diff --git a/drivers/input/misc/ati_remote2.c b/drivers/input/misc/ati_remote2.c
index 946bf75aa106..e84649af801d 100644
--- a/drivers/input/misc/ati_remote2.c
+++ b/drivers/input/misc/ati_remote2.c
@@ -204,26 +204,7 @@ struct ati_remote2 {
unsigned int mode_mask;
};
-static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
-static void ati_remote2_disconnect(struct usb_interface *interface);
-static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);
-static int ati_remote2_resume(struct usb_interface *interface);
-static int ati_remote2_reset_resume(struct usb_interface *interface);
-static int ati_remote2_pre_reset(struct usb_interface *interface);
-static int ati_remote2_post_reset(struct usb_interface *interface);
-
-static struct usb_driver ati_remote2_driver = {
- .name = "ati_remote2",
- .probe = ati_remote2_probe,
- .disconnect = ati_remote2_disconnect,
- .id_table = ati_remote2_id_table,
- .suspend = ati_remote2_suspend,
- .resume = ati_remote2_resume,
- .reset_resume = ati_remote2_reset_resume,
- .pre_reset = ati_remote2_pre_reset,
- .post_reset = ati_remote2_post_reset,
- .supports_autosuspend = 1,
-};
+static struct usb_driver ati_remote2_driver;
static int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
{
@@ -263,29 +244,21 @@ static int ati_remote2_open(struct input_dev *idev)
if (r) {
dev_err(&ar2->intf[0]->dev,
"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
- goto fail1;
+ return r;
}
- mutex_lock(&ati_remote2_mutex);
+ scoped_guard(mutex, &ati_remote2_mutex) {
+ if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
+ r = ati_remote2_submit_urbs(ar2);
+ if (r)
+ break;
+ }
- if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
- r = ati_remote2_submit_urbs(ar2);
- if (r)
- goto fail2;
+ ar2->flags |= ATI_REMOTE2_OPENED;
}
- ar2->flags |= ATI_REMOTE2_OPENED;
-
- mutex_unlock(&ati_remote2_mutex);
-
usb_autopm_put_interface(ar2->intf[0]);
- return 0;
-
- fail2:
- mutex_unlock(&ati_remote2_mutex);
- usb_autopm_put_interface(ar2->intf[0]);
- fail1:
return r;
}
@@ -295,14 +268,12 @@ static void ati_remote2_close(struct input_dev *idev)
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
- mutex_lock(&ati_remote2_mutex);
+ guard(mutex)(&ati_remote2_mutex);
if (!(ar2->flags & ATI_REMOTE2_SUSPENDED))
ati_remote2_kill_urbs(ar2);
ar2->flags &= ~ATI_REMOTE2_OPENED;
-
- mutex_unlock(&ati_remote2_mutex);
}
static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
@@ -732,16 +703,14 @@ static ssize_t ati_remote2_store_channel_mask(struct device *dev,
return r;
}
- mutex_lock(&ati_remote2_mutex);
-
- if (mask != ar2->channel_mask) {
- r = ati_remote2_setup(ar2, mask);
- if (!r)
- ar2->channel_mask = mask;
+ scoped_guard(mutex, &ati_remote2_mutex) {
+ if (mask != ar2->channel_mask) {
+ r = ati_remote2_setup(ar2, mask);
+ if (!r)
+ ar2->channel_mask = mask;
+ }
}
- mutex_unlock(&ati_remote2_mutex);
-
usb_autopm_put_interface(ar2->intf[0]);
return r ? r : count;
@@ -791,10 +760,7 @@ static struct attribute *ati_remote2_attrs[] = {
&dev_attr_mode_mask.attr,
NULL,
};
-
-static struct attribute_group ati_remote2_attr_group = {
- .attrs = ati_remote2_attrs,
-};
+ATTRIBUTE_GROUPS(ati_remote2);
static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
@@ -861,13 +827,9 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
strlcat(ar2->name, "ATI Remote Wonder II", sizeof(ar2->name));
- r = sysfs_create_group(&udev->dev.kobj, &ati_remote2_attr_group);
- if (r)
- goto fail3;
-
r = ati_remote2_input_init(ar2);
if (r)
- goto fail4;
+ goto fail3;
usb_set_intfdata(interface, ar2);
@@ -875,8 +837,6 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
return 0;
- fail4:
- sysfs_remove_group(&udev->dev.kobj, &ati_remote2_attr_group);
fail3:
ati_remote2_urb_cleanup(ar2);
fail2:
@@ -900,8 +860,6 @@ static void ati_remote2_disconnect(struct usb_interface *interface)
input_unregister_device(ar2->idev);
- sysfs_remove_group(&ar2->udev->dev.kobj, &ati_remote2_attr_group);
-
ati_remote2_urb_cleanup(ar2);
usb_driver_release_interface(&ati_remote2_driver, ar2->intf[1]);
@@ -922,15 +880,13 @@ static int ati_remote2_suspend(struct usb_interface *interface,
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
- mutex_lock(&ati_remote2_mutex);
+ guard(mutex)(&ati_remote2_mutex);
if (ar2->flags & ATI_REMOTE2_OPENED)
ati_remote2_kill_urbs(ar2);
ar2->flags |= ATI_REMOTE2_SUSPENDED;
- mutex_unlock(&ati_remote2_mutex);
-
return 0;
}
@@ -947,7 +903,7 @@ static int ati_remote2_resume(struct usb_interface *interface)
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
- mutex_lock(&ati_remote2_mutex);
+ guard(mutex)(&ati_remote2_mutex);
if (ar2->flags & ATI_REMOTE2_OPENED)
r = ati_remote2_submit_urbs(ar2);
@@ -955,8 +911,6 @@ static int ati_remote2_resume(struct usb_interface *interface)
if (!r)
ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
- mutex_unlock(&ati_remote2_mutex);
-
return r;
}
@@ -973,11 +927,11 @@ static int ati_remote2_reset_resume(struct usb_interface *interface)
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
- mutex_lock(&ati_remote2_mutex);
+ guard(mutex)(&ati_remote2_mutex);
r = ati_remote2_setup(ar2, ar2->channel_mask);
if (r)
- goto out;
+ return r;
if (ar2->flags & ATI_REMOTE2_OPENED)
r = ati_remote2_submit_urbs(ar2);
@@ -985,9 +939,6 @@ static int ati_remote2_reset_resume(struct usb_interface *interface)
if (!r)
ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
- out:
- mutex_unlock(&ati_remote2_mutex);
-
return r;
}
@@ -1032,4 +983,18 @@ static int ati_remote2_post_reset(struct usb_interface *interface)
return r;
}
+static struct usb_driver ati_remote2_driver = {
+ .name = "ati_remote2",
+ .probe = ati_remote2_probe,
+ .disconnect = ati_remote2_disconnect,
+ .dev_groups = ati_remote2_groups,
+ .id_table = ati_remote2_id_table,
+ .suspend = ati_remote2_suspend,
+ .resume = ati_remote2_resume,
+ .reset_resume = ati_remote2_reset_resume,
+ .pre_reset = ati_remote2_pre_reset,
+ .post_reset = ati_remote2_post_reset,
+ .supports_autosuspend = 1,
+};
+
module_usb_driver(ati_remote2_driver);
diff --git a/drivers/input/misc/aw86927.c b/drivers/input/misc/aw86927.c
new file mode 100644
index 000000000000..8ad361239cfe
--- /dev/null
+++ b/drivers/input/misc/aw86927.c
@@ -0,0 +1,846 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
+ *
+ * Partially based on vendor driver:
+ * Copyright (c) 2021 AWINIC Technology CO., LTD
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+#define AW86927_RSTCFG_REG 0x00
+#define AW86927_RSTCFG_SOFTRST 0xaa
+
+#define AW86927_SYSINT_REG 0x02
+#define AW86927_SYSINT_BST_SCPI BIT(7)
+#define AW86927_SYSINT_BST_OVPI BIT(6)
+#define AW86927_SYSINT_UVLI BIT(5)
+#define AW86927_SYSINT_FF_AEI BIT(4)
+#define AW86927_SYSINT_FF_AFI BIT(3)
+#define AW86927_SYSINT_OCDI BIT(2)
+#define AW86927_SYSINT_OTI BIT(1)
+#define AW86927_SYSINT_DONEI BIT(0)
+
+#define AW86927_SYSINTM_REG 0x03
+#define AW86927_SYSINTM_BST_OVPM BIT(6)
+#define AW86927_SYSINTM_FF_AEM BIT(4)
+#define AW86927_SYSINTM_FF_AFM BIT(3)
+#define AW86927_SYSINTM_DONEM BIT(0)
+
+#define AW86927_PLAYCFG1_REG 0x06
+#define AW86927_PLAYCFG1_BST_MODE_MASK GENMASK(7, 7)
+#define AW86927_PLAYCFG1_BST_MODE_BYPASS 0
+#define AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK GENMASK(6, 0)
+#define AW86927_PLAYCFG1_BST_8500MV 0x50
+
+#define AW86927_PLAYCFG2_REG 0x07
+
+#define AW86927_PLAYCFG3_REG 0x08
+#define AW86927_PLAYCFG3_AUTO_BST_MASK GENMASK(4, 4)
+#define AW86927_PLAYCFG3_AUTO_BST_ENABLE 1
+#define AW86927_PLAYCFG3_AUTO_BST_DISABLE 0
+#define AW86927_PLAYCFG3_PLAY_MODE_MASK GENMASK(1, 0)
+#define AW86927_PLAYCFG3_PLAY_MODE_RAM 0
+
+#define AW86927_PLAYCFG4_REG 0x09
+#define AW86927_PLAYCFG4_STOP BIT(1)
+#define AW86927_PLAYCFG4_GO BIT(0)
+
+#define AW86927_WAVCFG1_REG 0x0a
+#define AW86927_WAVCFG1_WAVSEQ1_MASK GENMASK(6, 0)
+
+#define AW86927_WAVCFG2_REG 0x0b
+#define AW86927_WAVCFG2_WAVSEQ2_MASK GENMASK(6, 0)
+
+#define AW86927_WAVCFG9_REG 0x12
+#define AW86927_WAVCFG9_SEQ1LOOP_MASK GENMASK(7, 4)
+#define AW86927_WAVCFG9_SEQ1LOOP_INFINITELY 0x0f
+
+#define AW86927_CONTCFG1_REG 0x18
+#define AW86927_CONTCFG1_BRK_BST_MD_MASK GENMASK(6, 6)
+
+#define AW86927_CONTCFG5_REG 0x1c
+#define AW86927_CONTCFG5_BST_BRK_GAIN_MASK GENMASK(7, 4)
+#define AW86927_CONTCFG5_BRK_GAIN_MASK GENMASK(3, 0)
+
+#define AW86927_CONTCFG10_REG 0x21
+#define AW86927_CONTCFG10_BRK_TIME_MASK GENMASK(7, 0)
+#define AW86927_CONTCFG10_BRK_TIME_DEFAULT 8
+
+#define AW86927_CONTCFG13_REG 0x24
+#define AW86927_CONTCFG13_TSET_MASK GENMASK(7, 4)
+#define AW86927_CONTCFG13_BEME_SET_MASK GENMASK(3, 0)
+
+#define AW86927_BASEADDRH_REG 0x2d
+#define AW86927_BASEADDRL_REG 0x2e
+
+#define AW86927_GLBRD5_REG 0x3f
+#define AW86927_GLBRD5_STATE_MASK GENMASK(3, 0)
+#define AW86927_GLBRD5_STATE_STANDBY 0
+
+#define AW86927_RAMADDRH_REG 0x40
+
+#define AW86927_RAMADDRL_REG 0x41
+
+#define AW86927_RAMDATA_REG 0x42
+
+#define AW86927_SYSCTRL3_REG 0x45
+#define AW86927_SYSCTRL3_STANDBY_MASK GENMASK(5, 5)
+#define AW86927_SYSCTRL3_STANDBY_ON 1
+#define AW86927_SYSCTRL3_STANDBY_OFF 0
+#define AW86927_SYSCTRL3_EN_RAMINIT_MASK GENMASK(2, 2)
+#define AW86927_SYSCTRL3_EN_RAMINIT_ON 1
+#define AW86927_SYSCTRL3_EN_RAMINIT_OFF 0
+
+#define AW86927_SYSCTRL4_REG 0x46
+#define AW86927_SYSCTRL4_WAVDAT_MODE_MASK GENMASK(6, 5)
+#define AW86927_SYSCTRL4_WAVDAT_24K 0
+#define AW86927_SYSCTRL4_INT_EDGE_MODE_MASK GENMASK(4, 4)
+#define AW86927_SYSCTRL4_INT_EDGE_MODE_POS 0
+#define AW86927_SYSCTRL4_INT_MODE_MASK GENMASK(3, 3)
+#define AW86927_SYSCTRL4_INT_MODE_EDGE 1
+#define AW86927_SYSCTRL4_GAIN_BYPASS_MASK GENMASK(0, 0)
+
+#define AW86927_PWMCFG1_REG 0x48
+#define AW86927_PWMCFG1_PRC_EN_MASK GENMASK(7, 7)
+#define AW86927_PWMCFG1_PRC_DISABLE 0
+
+#define AW86927_PWMCFG3_REG 0x4a
+#define AW86927_PWMCFG3_PR_EN_MASK GENMASK(7, 7)
+#define AW86927_PWMCFG3_PRCTIME_MASK GENMASK(6, 0)
+
+#define AW86927_PWMCFG4_REG 0x4b
+#define AW86927_PWMCFG4_PRTIME_MASK GENMASK(7, 0)
+
+#define AW86927_VBATCTRL_REG 0x4c
+#define AW86927_VBATCTRL_VBAT_MODE_MASK GENMASK(6, 6)
+#define AW86927_VBATCTRL_VBAT_MODE_SW 0
+
+#define AW86927_DETCFG1_REG 0x4d
+#define AW86927_DETCFG1_DET_GO_MASK GENMASK(1, 0)
+#define AW86927_DETCFG1_DET_GO_DET_SEQ0 1
+#define AW86927_DETCFG1_DET_GO_NA 0
+
+#define AW86927_DETCFG2_REG 0x4e
+#define AW86927_DETCFG2_DET_SEQ0_MASK GENMASK(6, 3)
+#define AW86927_DETCFG2_DET_SEQ0_VBAT 0
+#define AW86927_DETCFG2_D2S_GAIN_MASK GENMASK(2, 0)
+#define AW86927_DETCFG2_D2S_GAIN_10 4
+
+#define AW86927_CHIPIDH_REG 0x57
+#define AW86927_CHIPIDL_REG 0x58
+#define AW86927_CHIPID 0x9270
+
+#define AW86927_TMCFG_REG 0x5b
+#define AW86927_TMCFG_UNLOCK 0x7d
+#define AW86927_TMCFG_LOCK 0x00
+
+#define AW86927_ANACFG11_REG 0x70
+
+#define AW86927_ANACFG12_REG 0x71
+#define AW86927_ANACFG12_BST_SKIP_MASK GENMASK(7, 7)
+#define AW86927_ANACFG12_BST_SKIP_SHUTDOWN 1
+
+#define AW86927_ANACFG13_REG 0x72
+#define AW86927_ANACFG13_BST_PC_MASK GENMASK(7, 4)
+#define AW86927_ANACFG13_BST_PEAKCUR_3P45A 6
+
+#define AW86927_ANACFG15_REG 0x74
+#define AW86927_ANACFG15_BST_PEAK_MODE_MASK GENMASK(7, 7)
+#define AW86927_ANACFG15_BST_PEAK_BACK 1
+
+#define AW86927_ANACFG16_REG 0x75
+#define AW86927_ANACFG16_BST_SRC_MASK GENMASK(4, 4)
+#define AW86927_ANACFG16_BST_SRC_3NS 0
+
+/* default value of base addr */
+#define AW86927_RAM_BASE_ADDR 0x800
+#define AW86927_BASEADDRH_VAL 0x08
+#define AW86927_BASEADDRL_VAL 0x00
+
+enum aw86927_work_mode {
+ AW86927_STANDBY_MODE,
+ AW86927_RAM_MODE,
+};
+
+struct aw86927_data {
+ struct work_struct play_work;
+ struct device *dev;
+ struct input_dev *input_dev;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct gpio_desc *reset_gpio;
+ bool running;
+};
+
+static const struct regmap_config aw86927_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_NONE,
+ .max_register = 0x80,
+};
+
+/*
+ * Sine wave representing the magnitude of the drive to be used.
+ * Data is encoded in two's complement.
+ * round(84 * sin(x / 16.25))
+ */
+static const u8 aw86927_waveform[] = {
+ 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x1a, 0x1f, 0x23, 0x28, 0x2d, 0x31, 0x35,
+ 0x39, 0x3d, 0x41, 0x44, 0x47, 0x4a, 0x4c, 0x4f, 0x51, 0x52, 0x53, 0x54,
+ 0x55, 0x55, 0x55, 0x55, 0x55, 0x54, 0x52, 0x51, 0x4f, 0x4d, 0x4a, 0x47,
+ 0x44, 0x41, 0x3d, 0x3a, 0x36, 0x31, 0x2d, 0x28, 0x24, 0x1f, 0x1a, 0x15,
+ 0x10, 0x0a, 0x05, 0x00, 0xfc, 0xf6, 0xf1, 0xec, 0xe7, 0xe2, 0xdd, 0xd8,
+ 0xd4, 0xcf, 0xcb, 0xc7, 0xc3, 0xbf, 0xbc, 0xb9, 0xb6, 0xb4, 0xb1, 0xb0,
+ 0xae, 0xad, 0xac, 0xab, 0xab, 0xab, 0xab, 0xab, 0xac, 0xae, 0xaf, 0xb1,
+ 0xb3, 0xb6, 0xb8, 0xbc, 0xbf, 0xc2, 0xc6, 0xca, 0xce, 0xd3, 0xd7, 0xdc,
+ 0xe1, 0xe6, 0xeb, 0xf0, 0xf5, 0xfb
+};
+
+struct aw86927_sram_waveform_header {
+ u8 version;
+ __be16 start_address;
+ __be16 end_address;
+} __packed;
+
+static const struct aw86927_sram_waveform_header sram_waveform_header = {
+ .version = 0x01,
+ .start_address = cpu_to_be16(AW86927_RAM_BASE_ADDR +
+ sizeof(struct aw86927_sram_waveform_header)),
+ .end_address = cpu_to_be16(AW86927_RAM_BASE_ADDR +
+ sizeof(struct aw86927_sram_waveform_header) +
+ ARRAY_SIZE(aw86927_waveform) - 1),
+};
+
+static int aw86927_wait_enter_standby(struct aw86927_data *haptics)
+{
+ unsigned int reg_val;
+ int err;
+
+ err = regmap_read_poll_timeout(haptics->regmap, AW86927_GLBRD5_REG, reg_val,
+ (FIELD_GET(AW86927_GLBRD5_STATE_MASK, reg_val) ==
+ AW86927_GLBRD5_STATE_STANDBY),
+ 2500, 2500 * 100);
+
+ if (err) {
+ dev_err(haptics->dev, "did not enter standby: %d\n", err);
+ return err;
+ }
+ return 0;
+}
+
+static int aw86927_play_mode(struct aw86927_data *haptics, u8 play_mode)
+{
+ int err;
+
+ switch (play_mode) {
+ case AW86927_STANDBY_MODE:
+ /* Briefly toggle standby, then toggle back to standby off */
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_SYSCTRL3_REG,
+ AW86927_SYSCTRL3_STANDBY_MASK,
+ FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK,
+ AW86927_SYSCTRL3_STANDBY_ON));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_SYSCTRL3_REG,
+ AW86927_SYSCTRL3_STANDBY_MASK,
+ FIELD_PREP(AW86927_SYSCTRL3_STANDBY_MASK,
+ AW86927_SYSCTRL3_STANDBY_OFF));
+ if (err)
+ return err;
+
+ break;
+
+ case AW86927_RAM_MODE:
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PLAYCFG3_REG,
+ AW86927_PLAYCFG3_PLAY_MODE_MASK,
+ FIELD_PREP(AW86927_PLAYCFG3_PLAY_MODE_MASK,
+ AW86927_PLAYCFG3_PLAY_MODE_RAM));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PLAYCFG1_REG,
+ AW86927_PLAYCFG1_BST_MODE_MASK,
+ FIELD_PREP(AW86927_PLAYCFG1_BST_MODE_MASK,
+ AW86927_PLAYCFG1_BST_MODE_BYPASS));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_VBATCTRL_REG,
+ AW86927_VBATCTRL_VBAT_MODE_MASK,
+ FIELD_PREP(AW86927_VBATCTRL_VBAT_MODE_MASK,
+ AW86927_VBATCTRL_VBAT_MODE_SW));
+ if (err)
+ return err;
+
+ break;
+ }
+
+ return 0;
+}
+
+static int aw86927_stop(struct aw86927_data *haptics)
+{
+ int err;
+
+ err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_STOP);
+ if (err) {
+ dev_err(haptics->dev, "Failed to stop playback: %d\n", err);
+ return err;
+ }
+
+ err = aw86927_wait_enter_standby(haptics);
+ if (err) {
+ dev_err(haptics->dev, "Failed to enter standby, trying to force it\n");
+ err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int aw86927_haptics_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+ struct aw86927_data *haptics = input_get_drvdata(dev);
+ int level;
+
+ level = effect->u.rumble.strong_magnitude;
+ if (!level)
+ level = effect->u.rumble.weak_magnitude;
+
+ /* If already running, don't restart playback */
+ if (haptics->running && level)
+ return 0;
+
+ haptics->running = level;
+ schedule_work(&haptics->play_work);
+
+ return 0;
+}
+
+static int aw86927_play_sine(struct aw86927_data *haptics)
+{
+ int err;
+
+ err = aw86927_stop(haptics);
+ if (err)
+ return err;
+
+ err = aw86927_play_mode(haptics, AW86927_RAM_MODE);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap, AW86927_PLAYCFG3_REG,
+ AW86927_PLAYCFG3_AUTO_BST_MASK,
+ FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK,
+ AW86927_PLAYCFG3_AUTO_BST_ENABLE));
+ if (err)
+ return err;
+
+ /* Set waveseq 1 to the first wave */
+ err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG1_REG,
+ AW86927_WAVCFG1_WAVSEQ1_MASK,
+ FIELD_PREP(AW86927_WAVCFG1_WAVSEQ1_MASK, 1));
+ if (err)
+ return err;
+
+ /* set wavseq 2 to zero */
+ err = regmap_update_bits(haptics->regmap, AW86927_WAVCFG2_REG,
+ AW86927_WAVCFG2_WAVSEQ2_MASK,
+ FIELD_PREP(AW86927_WAVCFG2_WAVSEQ2_MASK, 0));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_WAVCFG9_REG,
+ AW86927_WAVCFG9_SEQ1LOOP_MASK,
+ FIELD_PREP(AW86927_WAVCFG9_SEQ1LOOP_MASK,
+ AW86927_WAVCFG9_SEQ1LOOP_INFINITELY));
+ if (err)
+ return err;
+
+ /* set gain to value lower than 0x80 to avoid distorted playback */
+ err = regmap_write(haptics->regmap, AW86927_PLAYCFG2_REG, 0x7c);
+ if (err)
+ return err;
+
+ /* Start playback */
+ err = regmap_write(haptics->regmap, AW86927_PLAYCFG4_REG, AW86927_PLAYCFG4_GO);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static void aw86927_close(struct input_dev *input)
+{
+ struct aw86927_data *haptics = input_get_drvdata(input);
+ struct device *dev = &haptics->client->dev;
+ int err;
+
+ cancel_work_sync(&haptics->play_work);
+
+ err = aw86927_stop(haptics);
+ if (err)
+ dev_err(dev, "Failed to close the Driver: %d\n", err);
+}
+
+static void aw86927_haptics_play_work(struct work_struct *work)
+{
+ struct aw86927_data *haptics =
+ container_of(work, struct aw86927_data, play_work);
+ struct device *dev = &haptics->client->dev;
+ int err;
+
+ if (haptics->running)
+ err = aw86927_play_sine(haptics);
+ else
+ err = aw86927_stop(haptics);
+
+ if (err)
+ dev_err(dev, "Failed to execute work command: %d\n", err);
+}
+
+static void aw86927_hw_reset(struct aw86927_data *haptics)
+{
+ /* Assert reset */
+ gpiod_set_value_cansleep(haptics->reset_gpio, 1);
+ /* Wait ~1ms */
+ usleep_range(1000, 2000);
+ /* Deassert reset */
+ gpiod_set_value_cansleep(haptics->reset_gpio, 0);
+ /* Wait ~8ms until I2C is accessible */
+ usleep_range(8000, 8500);
+}
+
+static int aw86927_haptic_init(struct aw86927_data *haptics)
+{
+ int err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_SYSCTRL4_REG,
+ AW86927_SYSCTRL4_WAVDAT_MODE_MASK,
+ FIELD_PREP(AW86927_SYSCTRL4_WAVDAT_MODE_MASK,
+ AW86927_SYSCTRL4_WAVDAT_24K));
+ if (err)
+ return err;
+
+ /* enable gain bypass */
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_SYSCTRL4_REG,
+ AW86927_SYSCTRL4_GAIN_BYPASS_MASK,
+ FIELD_PREP(AW86927_SYSCTRL4_GAIN_BYPASS_MASK,
+ 0x01));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK);
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap, AW86927_ANACFG11_REG, 0x0f);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_ANACFG12_REG,
+ AW86927_ANACFG12_BST_SKIP_MASK,
+ FIELD_PREP(AW86927_ANACFG12_BST_SKIP_MASK,
+ AW86927_ANACFG12_BST_SKIP_SHUTDOWN));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_ANACFG15_REG,
+ AW86927_ANACFG15_BST_PEAK_MODE_MASK,
+ FIELD_PREP(AW86927_ANACFG15_BST_PEAK_MODE_MASK,
+ AW86927_ANACFG15_BST_PEAK_BACK));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_ANACFG16_REG,
+ AW86927_ANACFG16_BST_SRC_MASK,
+ FIELD_PREP(AW86927_ANACFG16_BST_SRC_MASK,
+ AW86927_ANACFG16_BST_SRC_3NS));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_TMCFG_REG, AW86927_TMCFG_LOCK);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_CONTCFG1_REG,
+ AW86927_CONTCFG1_BRK_BST_MD_MASK,
+ FIELD_PREP(AW86927_CONTCFG1_BRK_BST_MD_MASK, 0x00));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_CONTCFG5_REG,
+ FIELD_PREP(AW86927_CONTCFG5_BST_BRK_GAIN_MASK, 0x05) |
+ FIELD_PREP(AW86927_CONTCFG5_BRK_GAIN_MASK, 0x08));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap, AW86927_CONTCFG10_REG,
+ AW86927_CONTCFG10_BRK_TIME_MASK,
+ FIELD_PREP(AW86927_CONTCFG10_BRK_TIME_MASK,
+ AW86927_CONTCFG10_BRK_TIME_DEFAULT));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_CONTCFG13_REG,
+ FIELD_PREP(AW86927_CONTCFG13_TSET_MASK, 0x06) |
+ FIELD_PREP(AW86927_CONTCFG13_BEME_SET_MASK, 0x02));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_DETCFG2_REG,
+ AW86927_DETCFG2_D2S_GAIN_MASK,
+ FIELD_PREP(AW86927_DETCFG2_D2S_GAIN_MASK,
+ AW86927_DETCFG2_D2S_GAIN_10));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PWMCFG1_REG,
+ AW86927_PWMCFG1_PRC_EN_MASK,
+ FIELD_PREP(AW86927_PWMCFG1_PRC_EN_MASK,
+ AW86927_PWMCFG1_PRC_DISABLE));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_PWMCFG3_REG,
+ FIELD_PREP(AW86927_PWMCFG3_PR_EN_MASK, 0x01) |
+ FIELD_PREP(AW86927_PWMCFG3_PRCTIME_MASK, 0x3f));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PWMCFG4_REG,
+ AW86927_PWMCFG4_PRTIME_MASK,
+ FIELD_PREP(AW86927_PWMCFG4_PRTIME_MASK, 0x32));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_TMCFG_REG, AW86927_TMCFG_UNLOCK);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_ANACFG13_REG,
+ AW86927_ANACFG13_BST_PC_MASK,
+ FIELD_PREP(AW86927_ANACFG13_BST_PC_MASK,
+ AW86927_ANACFG13_BST_PEAKCUR_3P45A));
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_TMCFG_REG, AW86927_TMCFG_LOCK);
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PLAYCFG1_REG,
+ AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+ FIELD_PREP(AW86927_PLAYCFG1_BST_VOUT_VREFSET_MASK,
+ AW86927_PLAYCFG1_BST_8500MV));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_PLAYCFG3_REG,
+ AW86927_PLAYCFG3_AUTO_BST_MASK,
+ FIELD_PREP(AW86927_PLAYCFG3_AUTO_BST_MASK,
+ AW86927_PLAYCFG3_AUTO_BST_DISABLE));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int aw86927_ram_init(struct aw86927_data *haptics)
+{
+ int err;
+
+ err = aw86927_wait_enter_standby(haptics);
+ if (err)
+ return err;
+
+ /* Enable SRAM init */
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_SYSCTRL3_REG,
+ AW86927_SYSCTRL3_EN_RAMINIT_MASK,
+ FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
+ AW86927_SYSCTRL3_EN_RAMINIT_ON));
+
+ /* Set base address for the start of the SRAM waveforms */
+ err = regmap_write(haptics->regmap,
+ AW86927_BASEADDRH_REG, AW86927_BASEADDRH_VAL);
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_BASEADDRL_REG, AW86927_BASEADDRL_VAL);
+ if (err)
+ return err;
+
+ /* Set start of SRAM, before the data is written it will be the same as the base */
+ err = regmap_write(haptics->regmap,
+ AW86927_RAMADDRH_REG, AW86927_BASEADDRH_VAL);
+ if (err)
+ return err;
+
+ err = regmap_write(haptics->regmap,
+ AW86927_RAMADDRL_REG, AW86927_BASEADDRL_VAL);
+ if (err)
+ return err;
+
+ /* Write waveform header to SRAM */
+ err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG,
+ &sram_waveform_header, sizeof(sram_waveform_header));
+ if (err)
+ return err;
+
+ /* Write waveform to SRAM */
+ err = regmap_noinc_write(haptics->regmap, AW86927_RAMDATA_REG,
+ aw86927_waveform, ARRAY_SIZE(aw86927_waveform));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_DETCFG2_REG,
+ AW86927_DETCFG2_DET_SEQ0_MASK,
+ FIELD_PREP(AW86927_DETCFG2_DET_SEQ0_MASK,
+ AW86927_DETCFG2_DET_SEQ0_VBAT));
+ if (err)
+ return err;
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_DETCFG1_REG,
+ AW86927_DETCFG1_DET_GO_MASK,
+ FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK,
+ AW86927_DETCFG1_DET_GO_DET_SEQ0));
+ if (err)
+ return err;
+
+ usleep_range(3000, 3500);
+
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_DETCFG1_REG,
+ AW86927_DETCFG1_DET_GO_MASK,
+ FIELD_PREP(AW86927_DETCFG1_DET_GO_MASK,
+ AW86927_DETCFG1_DET_GO_NA));
+ if (err)
+ return err;
+
+ /* Disable SRAM init */
+ err = regmap_update_bits(haptics->regmap,
+ AW86927_SYSCTRL3_REG,
+ AW86927_SYSCTRL3_EN_RAMINIT_MASK,
+ FIELD_PREP(AW86927_SYSCTRL3_EN_RAMINIT_MASK,
+ AW86927_SYSCTRL3_EN_RAMINIT_OFF));
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static irqreturn_t aw86927_irq(int irq, void *data)
+{
+ struct aw86927_data *haptics = data;
+ struct device *dev = &haptics->client->dev;
+ unsigned int reg_val;
+ int err;
+
+ err = regmap_read(haptics->regmap, AW86927_SYSINT_REG, &reg_val);
+ if (err) {
+ dev_err(dev, "Failed to read SYSINT register: %d\n", err);
+ return IRQ_NONE;
+ }
+
+ if (reg_val & AW86927_SYSINT_BST_SCPI)
+ dev_err(dev, "Received a Short Circuit Protection interrupt\n");
+ if (reg_val & AW86927_SYSINT_BST_OVPI)
+ dev_err(dev, "Received an Over Voltage Protection interrupt\n");
+ if (reg_val & AW86927_SYSINT_UVLI)
+ dev_err(dev, "Received an Under Voltage Lock Out interrupt\n");
+ if (reg_val & AW86927_SYSINT_OCDI)
+ dev_err(dev, "Received an Over Current interrupt\n");
+ if (reg_val & AW86927_SYSINT_OTI)
+ dev_err(dev, "Received an Over Temperature interrupt\n");
+
+ if (reg_val & AW86927_SYSINT_DONEI)
+ dev_dbg(dev, "Chip playback done!\n");
+ if (reg_val & AW86927_SYSINT_FF_AFI)
+ dev_dbg(dev, "The RTP mode FIFO is almost full!\n");
+ if (reg_val & AW86927_SYSINT_FF_AEI)
+ dev_dbg(dev, "The RTP mode FIFO is almost empty!\n");
+
+ return IRQ_HANDLED;
+}
+
+static int aw86927_detect(struct aw86927_data *haptics)
+{
+ __be16 read_buf;
+ u16 chip_id;
+ int err;
+
+ err = regmap_bulk_read(haptics->regmap, AW86927_CHIPIDH_REG, &read_buf, 2);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to read CHIPID registers\n");
+
+ chip_id = be16_to_cpu(read_buf);
+
+ if (chip_id != AW86927_CHIPID) {
+ dev_err(haptics->dev, "Unexpected CHIPID value 0x%x\n", chip_id);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int aw86927_probe(struct i2c_client *client)
+{
+ struct aw86927_data *haptics;
+ int err;
+
+ haptics = devm_kzalloc(&client->dev, sizeof(struct aw86927_data), GFP_KERNEL);
+ if (!haptics)
+ return -ENOMEM;
+
+ haptics->dev = &client->dev;
+ haptics->client = client;
+
+ i2c_set_clientdata(client, haptics);
+
+ haptics->regmap = devm_regmap_init_i2c(client, &aw86927_regmap_config);
+ if (IS_ERR(haptics->regmap))
+ return dev_err_probe(haptics->dev, PTR_ERR(haptics->regmap),
+ "Failed to allocate register map\n");
+
+ haptics->input_dev = devm_input_allocate_device(haptics->dev);
+ if (!haptics->input_dev)
+ return -ENOMEM;
+
+ haptics->reset_gpio = devm_gpiod_get(haptics->dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(haptics->reset_gpio))
+ return dev_err_probe(haptics->dev, PTR_ERR(haptics->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ /* Hardware reset */
+ aw86927_hw_reset(haptics);
+
+ /* Software reset */
+ err = regmap_write(haptics->regmap, AW86927_RSTCFG_REG, AW86927_RSTCFG_SOFTRST);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed Software reset\n");
+
+ /* Wait ~3ms until I2C is accessible */
+ usleep_range(3000, 3500);
+
+ err = aw86927_detect(haptics);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to find chip\n");
+
+ /* IRQ config */
+ err = regmap_write(haptics->regmap, AW86927_SYSCTRL4_REG,
+ FIELD_PREP(AW86927_SYSCTRL4_INT_MODE_MASK,
+ AW86927_SYSCTRL4_INT_MODE_EDGE) |
+ FIELD_PREP(AW86927_SYSCTRL4_INT_EDGE_MODE_MASK,
+ AW86927_SYSCTRL4_INT_EDGE_MODE_POS));
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to configure interrupt modes\n");
+
+ err = regmap_write(haptics->regmap, AW86927_SYSINTM_REG,
+ AW86927_SYSINTM_BST_OVPM |
+ AW86927_SYSINTM_FF_AEM |
+ AW86927_SYSINTM_FF_AFM |
+ AW86927_SYSINTM_DONEM);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to configure interrupt masks\n");
+
+ err = devm_request_threaded_irq(haptics->dev, client->irq, NULL,
+ aw86927_irq, IRQF_ONESHOT, NULL, haptics);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to request threaded irq\n");
+
+ INIT_WORK(&haptics->play_work, aw86927_haptics_play_work);
+
+ haptics->input_dev->name = "aw86927-haptics";
+ haptics->input_dev->close = aw86927_close;
+
+ input_set_drvdata(haptics->input_dev, haptics);
+ input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE);
+
+ err = input_ff_create_memless(haptics->input_dev, NULL, aw86927_haptics_play);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to create FF dev\n");
+
+ /* Set up registers */
+ err = aw86927_play_mode(haptics, AW86927_STANDBY_MODE);
+ if (err)
+ return dev_err_probe(haptics->dev, err,
+ "Failed to enter standby for Haptic init\n");
+
+ err = aw86927_haptic_init(haptics);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Haptic init failed\n");
+
+ /* RAM init, upload the waveform for playback */
+ err = aw86927_ram_init(haptics);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to init aw86927 sram\n");
+
+ err = input_register_device(haptics->input_dev);
+ if (err)
+ return dev_err_probe(haptics->dev, err, "Failed to register input device\n");
+
+ return 0;
+}
+
+static const struct of_device_id aw86927_of_id[] = {
+ { .compatible = "awinic,aw86927" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, aw86927_of_id);
+
+static struct i2c_driver aw86927_driver = {
+ .driver = {
+ .name = "aw86927-haptics",
+ .of_match_table = aw86927_of_id,
+ },
+ .probe = aw86927_probe,
+};
+
+module_i2c_driver(aw86927_driver);
+
+MODULE_AUTHOR("Griffin Kroah-Hartman <griffin.kroah@fairphone.com>");
+MODULE_DESCRIPTION("AWINIC AW86927 LRA Haptic Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index 728325a2d574..0cfe5d4a573c 100644
--- a/drivers/input/misc/cm109.c
+++ b/drivers/input/misc/cm109.c
@@ -355,6 +355,35 @@ static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
__func__, error);
}
+static void cm109_submit_ctl(struct cm109_dev *dev)
+{
+ int error;
+
+ guard(spinlock_irqsave)(&dev->ctl_submit_lock);
+
+ dev->irq_urb_pending = 0;
+
+ if (unlikely(dev->shutdown))
+ return;
+
+ if (dev->buzzer_state)
+ dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
+ else
+ dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
+
+ dev->ctl_data->byte[HID_OR1] = dev->keybit;
+ dev->ctl_data->byte[HID_OR2] = dev->keybit;
+
+ dev->buzzer_pending = 0;
+ dev->ctl_urb_pending = 1;
+
+ error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
+ if (error)
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_ctl) failed %d\n",
+ __func__, error);
+}
+
/*
* IRQ handler
*/
@@ -362,8 +391,6 @@ static void cm109_urb_irq_callback(struct urb *urb)
{
struct cm109_dev *dev = urb->context;
const int status = urb->status;
- int error;
- unsigned long flags;
dev_dbg(&dev->intf->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
dev->irq_data->byte[0],
@@ -401,32 +428,7 @@ static void cm109_urb_irq_callback(struct urb *urb)
}
out:
-
- spin_lock_irqsave(&dev->ctl_submit_lock, flags);
-
- dev->irq_urb_pending = 0;
-
- if (likely(!dev->shutdown)) {
-
- if (dev->buzzer_state)
- dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
- else
- dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
-
- dev->ctl_data->byte[HID_OR1] = dev->keybit;
- dev->ctl_data->byte[HID_OR2] = dev->keybit;
-
- dev->buzzer_pending = 0;
- dev->ctl_urb_pending = 1;
-
- error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
- if (error)
- dev_err(&dev->intf->dev,
- "%s: usb_submit_urb (urb_ctl) failed %d\n",
- __func__, error);
- }
-
- spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
+ cm109_submit_ctl(dev);
}
static void cm109_urb_ctl_callback(struct urb *urb)
@@ -434,7 +436,6 @@ static void cm109_urb_ctl_callback(struct urb *urb)
struct cm109_dev *dev = urb->context;
const int status = urb->status;
int error;
- unsigned long flags;
dev_dbg(&dev->intf->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
dev->ctl_data->byte[0],
@@ -449,35 +450,31 @@ static void cm109_urb_ctl_callback(struct urb *urb)
__func__, status);
}
- spin_lock_irqsave(&dev->ctl_submit_lock, flags);
+ guard(spinlock_irqsave)(&dev->ctl_submit_lock);
dev->ctl_urb_pending = 0;
- if (likely(!dev->shutdown)) {
-
- if (dev->buzzer_pending || status) {
- dev->buzzer_pending = 0;
- dev->ctl_urb_pending = 1;
- cm109_submit_buzz_toggle(dev);
- } else if (likely(!dev->irq_urb_pending)) {
- /* ask for key data */
- dev->irq_urb_pending = 1;
- error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
- if (error)
- dev_err(&dev->intf->dev,
- "%s: usb_submit_urb (urb_irq) failed %d\n",
- __func__, error);
- }
- }
+ if (unlikely(dev->shutdown))
+ return;
- spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
+ if (dev->buzzer_pending || status) {
+ dev->buzzer_pending = 0;
+ dev->ctl_urb_pending = 1;
+ cm109_submit_buzz_toggle(dev);
+ } else if (likely(!dev->irq_urb_pending)) {
+ /* ask for key data */
+ dev->irq_urb_pending = 1;
+ error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
+ if (error)
+ dev_err(&dev->intf->dev,
+ "%s: usb_submit_urb (urb_irq) failed %d\n",
+ __func__, error);
+ }
}
static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
{
- unsigned long flags;
-
- spin_lock_irqsave(&dev->ctl_submit_lock, flags);
+ guard(spinlock_irqsave)(&dev->ctl_submit_lock);
if (dev->ctl_urb_pending) {
/* URB completion will resubmit */
@@ -486,8 +483,6 @@ static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
dev->ctl_urb_pending = 1;
cm109_submit_buzz_toggle(dev);
}
-
- spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
}
static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
@@ -556,32 +551,30 @@ static int cm109_input_open(struct input_dev *idev)
return error;
}
- mutex_lock(&dev->pm_mutex);
-
- dev->buzzer_state = 0;
- dev->key_code = -1; /* no keys pressed */
- dev->keybit = 0xf;
+ scoped_guard(mutex, &dev->pm_mutex) {
+ dev->buzzer_state = 0;
+ dev->key_code = -1; /* no keys pressed */
+ dev->keybit = 0xf;
- /* issue INIT */
- dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
- dev->ctl_data->byte[HID_OR1] = dev->keybit;
- dev->ctl_data->byte[HID_OR2] = dev->keybit;
- dev->ctl_data->byte[HID_OR3] = 0x00;
+ /* issue INIT */
+ dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
+ dev->ctl_data->byte[HID_OR1] = dev->keybit;
+ dev->ctl_data->byte[HID_OR2] = dev->keybit;
+ dev->ctl_data->byte[HID_OR3] = 0x00;
- dev->ctl_urb_pending = 1;
- error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
- if (error) {
- dev->ctl_urb_pending = 0;
- dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
- __func__, error);
- } else {
- dev->open = 1;
+ dev->ctl_urb_pending = 1;
+ error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
+ if (!error) {
+ dev->open = 1;
+ return 0;
+ }
}
- mutex_unlock(&dev->pm_mutex);
+ dev->ctl_urb_pending = 0;
+ usb_autopm_put_interface(dev->intf);
- if (error)
- usb_autopm_put_interface(dev->intf);
+ dev_err(&dev->intf->dev, "%s: usb_submit_urb (urb_ctl) failed %d\n",
+ __func__, error);
return error;
}
@@ -590,17 +583,15 @@ static void cm109_input_close(struct input_dev *idev)
{
struct cm109_dev *dev = input_get_drvdata(idev);
- mutex_lock(&dev->pm_mutex);
-
- /*
- * Once we are here event delivery is stopped so we
- * don't need to worry about someone starting buzzer
- * again
- */
- cm109_stop_traffic(dev);
- dev->open = 0;
-
- mutex_unlock(&dev->pm_mutex);
+ scoped_guard(mutex, &dev->pm_mutex) {
+ /*
+ * Once we are here event delivery is stopped so we
+ * don't need to worry about someone starting buzzer
+ * again
+ */
+ cm109_stop_traffic(dev);
+ dev->open = 0;
+ }
usb_autopm_put_interface(dev->intf);
}
@@ -823,9 +814,9 @@ static int cm109_usb_suspend(struct usb_interface *intf, pm_message_t message)
dev_info(&intf->dev, "cm109: usb_suspend (event=%d)\n", message.event);
- mutex_lock(&dev->pm_mutex);
+ guard(mutex)(&dev->pm_mutex);
+
cm109_stop_traffic(dev);
- mutex_unlock(&dev->pm_mutex);
return 0;
}
@@ -836,9 +827,9 @@ static int cm109_usb_resume(struct usb_interface *intf)
dev_info(&intf->dev, "cm109: usb_resume\n");
- mutex_lock(&dev->pm_mutex);
+ guard(mutex)(&dev->pm_mutex);
+
cm109_restore_state(dev);
- mutex_unlock(&dev->pm_mutex);
return 0;
}
diff --git a/drivers/input/misc/cma3000_d0x.c b/drivers/input/misc/cma3000_d0x.c
index 1772846708d2..b4232b0a3957 100644
--- a/drivers/input/misc/cma3000_d0x.c
+++ b/drivers/input/misc/cma3000_d0x.c
@@ -6,6 +6,7 @@
* Author: Hemanth V <hemanthv@ti.com>
*/
+#include <linux/export.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -217,15 +218,13 @@ static int cma3000_open(struct input_dev *input_dev)
{
struct cma3000_accl_data *data = input_get_drvdata(input_dev);
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
if (!data->suspended)
cma3000_poweron(data);
data->opened = true;
- mutex_unlock(&data->mutex);
-
return 0;
}
@@ -233,40 +232,34 @@ static void cma3000_close(struct input_dev *input_dev)
{
struct cma3000_accl_data *data = input_get_drvdata(input_dev);
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
if (!data->suspended)
cma3000_poweroff(data);
data->opened = false;
-
- mutex_unlock(&data->mutex);
}
void cma3000_suspend(struct cma3000_accl_data *data)
{
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
if (!data->suspended && data->opened)
cma3000_poweroff(data);
data->suspended = true;
-
- mutex_unlock(&data->mutex);
}
EXPORT_SYMBOL(cma3000_suspend);
void cma3000_resume(struct cma3000_accl_data *data)
{
- mutex_lock(&data->mutex);
+ guard(mutex)(&data->mutex);
if (data->suspended && data->opened)
cma3000_poweron(data);
data->suspended = false;
-
- mutex_unlock(&data->mutex);
}
EXPORT_SYMBOL(cma3000_resume);
@@ -292,7 +285,7 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
goto err_out;
}
- data = kzalloc(sizeof(struct cma3000_accl_data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
input_dev = input_allocate_device();
if (!data || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/misc/cs40l50-vibra.c b/drivers/input/misc/cs40l50-vibra.c
new file mode 100644
index 000000000000..7aa7d577e01b
--- /dev/null
+++ b/drivers/input/misc/cs40l50-vibra.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * CS40L50 Advanced Haptic Driver with waveform memory,
+ * integrated DSP, and closed-loop algorithms
+ *
+ * Copyright 2024 Cirrus Logic, Inc.
+ *
+ * Author: James Ogletree <james.ogletree@cirrus.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/input.h>
+#include <linux/mfd/cs40l50.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* Wavetables */
+#define CS40L50_RAM_INDEX_START 0x1000000
+#define CS40L50_RAM_INDEX_END 0x100007F
+#define CS40L50_RTH_INDEX_START 0x1400000
+#define CS40L50_RTH_INDEX_END 0x1400001
+#define CS40L50_ROM_INDEX_START 0x1800000
+#define CS40L50_ROM_INDEX_END 0x180001A
+#define CS40L50_TYPE_PCM 8
+#define CS40L50_TYPE_PWLE 12
+#define CS40L50_PCM_ID 0x0
+#define CS40L50_OWT_CUSTOM_DATA_SIZE 2
+#define CS40L50_CUSTOM_DATA_MASK 0xFFFFU
+
+/* DSP */
+#define CS40L50_GPIO_BASE 0x2804140
+#define CS40L50_OWT_BASE 0x2805C34
+#define CS40L50_OWT_SIZE 0x2805C38
+#define CS40L50_OWT_NEXT 0x2805C3C
+#define CS40L50_EFFECTS_MAX 1
+
+/* GPIO */
+#define CS40L50_GPIO_NUM_MASK GENMASK(14, 12)
+#define CS40L50_GPIO_EDGE_MASK BIT(15)
+#define CS40L50_GPIO_MAPPING_NONE 0
+#define CS40L50_GPIO_DISABLE 0x1FF
+
+enum cs40l50_bank_type {
+ CS40L50_WVFRM_BANK_RAM,
+ CS40L50_WVFRM_BANK_ROM,
+ CS40L50_WVFRM_BANK_OWT,
+ CS40L50_WVFRM_BANK_NUM,
+};
+
+/* Describes an area in DSP memory populated by effects */
+struct cs40l50_bank {
+ enum cs40l50_bank_type type;
+ u32 base_index;
+ u32 max_index;
+};
+
+struct cs40l50_effect {
+ enum cs40l50_bank_type type;
+ struct list_head list;
+ u32 gpio_reg;
+ u32 index;
+ int id;
+};
+
+/* Describes haptic interface of loaded DSP firmware */
+struct cs40l50_vibra_dsp {
+ struct cs40l50_bank *banks;
+ u32 gpio_base_reg;
+ u32 owt_offset_reg;
+ u32 owt_size_reg;
+ u32 owt_base_reg;
+ u32 push_owt_cmd;
+ u32 delete_owt_cmd;
+ u32 stop_cmd;
+ int (*write)(struct device *dev, struct regmap *regmap, u32 val);
+};
+
+/* Describes configuration and state of haptic operations */
+struct cs40l50_vibra {
+ struct device *dev;
+ struct regmap *regmap;
+ struct input_dev *input;
+ struct workqueue_struct *vib_wq;
+ struct list_head effect_head;
+ struct cs40l50_vibra_dsp dsp;
+};
+
+struct cs40l50_work {
+ struct cs40l50_vibra *vib;
+ struct ff_effect *effect;
+ struct work_struct work;
+ s16 *custom_data;
+ int custom_len;
+ int count;
+ int error;
+};
+
+static struct cs40l50_bank cs40l50_banks[] = {
+ {
+ .type = CS40L50_WVFRM_BANK_RAM,
+ .base_index = CS40L50_RAM_INDEX_START,
+ .max_index = CS40L50_RAM_INDEX_END,
+ },
+ {
+ .type = CS40L50_WVFRM_BANK_ROM,
+ .base_index = CS40L50_ROM_INDEX_START,
+ .max_index = CS40L50_ROM_INDEX_END,
+ },
+ {
+ .type = CS40L50_WVFRM_BANK_OWT,
+ .base_index = CS40L50_RTH_INDEX_START,
+ .max_index = CS40L50_RTH_INDEX_END,
+ },
+};
+
+static struct cs40l50_vibra_dsp cs40l50_dsp = {
+ .banks = cs40l50_banks,
+ .gpio_base_reg = CS40L50_GPIO_BASE,
+ .owt_base_reg = CS40L50_OWT_BASE,
+ .owt_offset_reg = CS40L50_OWT_NEXT,
+ .owt_size_reg = CS40L50_OWT_SIZE,
+ .push_owt_cmd = CS40L50_OWT_PUSH,
+ .delete_owt_cmd = CS40L50_OWT_DELETE,
+ .stop_cmd = CS40L50_STOP_PLAYBACK,
+ .write = cs40l50_dsp_write,
+};
+
+static struct cs40l50_effect *cs40l50_find_effect(int id, struct list_head *effect_head)
+{
+ struct cs40l50_effect *effect;
+
+ list_for_each_entry(effect, effect_head, list)
+ if (effect->id == id)
+ return effect;
+
+ return NULL;
+}
+
+static int cs40l50_effect_bank_set(struct cs40l50_work *work_data,
+ struct cs40l50_effect *effect)
+{
+ s16 bank_type = work_data->custom_data[0] & CS40L50_CUSTOM_DATA_MASK;
+
+ if (bank_type >= CS40L50_WVFRM_BANK_NUM) {
+ dev_err(work_data->vib->dev, "Invalid bank (%d)\n", bank_type);
+ return -EINVAL;
+ }
+
+ if (work_data->custom_len > CS40L50_OWT_CUSTOM_DATA_SIZE)
+ effect->type = CS40L50_WVFRM_BANK_OWT;
+ else
+ effect->type = bank_type;
+
+ return 0;
+}
+
+static int cs40l50_effect_index_set(struct cs40l50_work *work_data,
+ struct cs40l50_effect *effect)
+{
+ struct cs40l50_vibra *vib = work_data->vib;
+ struct cs40l50_effect *owt_effect;
+ u32 base_index, max_index;
+
+ base_index = vib->dsp.banks[effect->type].base_index;
+ max_index = vib->dsp.banks[effect->type].max_index;
+
+ effect->index = base_index;
+
+ switch (effect->type) {
+ case CS40L50_WVFRM_BANK_OWT:
+ list_for_each_entry(owt_effect, &vib->effect_head, list)
+ if (owt_effect->type == CS40L50_WVFRM_BANK_OWT)
+ effect->index++;
+ break;
+ case CS40L50_WVFRM_BANK_ROM:
+ case CS40L50_WVFRM_BANK_RAM:
+ effect->index += work_data->custom_data[1] & CS40L50_CUSTOM_DATA_MASK;
+ break;
+ default:
+ dev_err(vib->dev, "Bank type %d not supported\n", effect->type);
+ return -EINVAL;
+ }
+
+ if (effect->index > max_index || effect->index < base_index) {
+ dev_err(vib->dev, "Index out of bounds: %u\n", effect->index);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+static int cs40l50_effect_gpio_mapping_set(struct cs40l50_work *work_data,
+ struct cs40l50_effect *effect)
+{
+ u16 gpio_edge, gpio_num, button = work_data->effect->trigger.button;
+ struct cs40l50_vibra *vib = work_data->vib;
+
+ if (button) {
+ gpio_num = FIELD_GET(CS40L50_GPIO_NUM_MASK, button);
+ gpio_edge = FIELD_GET(CS40L50_GPIO_EDGE_MASK, button);
+ effect->gpio_reg = vib->dsp.gpio_base_reg + (gpio_num * 8) - gpio_edge;
+
+ return regmap_write(vib->regmap, effect->gpio_reg, button);
+ }
+
+ effect->gpio_reg = CS40L50_GPIO_MAPPING_NONE;
+
+ return 0;
+}
+
+struct cs40l50_owt_header {
+ u32 type;
+ u32 data_words;
+ u32 offset;
+} __packed;
+
+static int cs40l50_upload_owt(struct cs40l50_work *work_data)
+{
+ u8 *new_owt_effect_data __free(kfree) = NULL;
+ struct cs40l50_vibra *vib = work_data->vib;
+ size_t len = work_data->custom_len * 2;
+ struct cs40l50_owt_header header;
+ u32 offset, size;
+ int error;
+
+ error = regmap_read(vib->regmap, vib->dsp.owt_size_reg, &size);
+ if (error)
+ return error;
+
+ if ((size * sizeof(u32)) < sizeof(header) + len) {
+ dev_err(vib->dev, "No space in open wavetable for effect\n");
+ return -ENOSPC;
+ }
+
+ header.type = work_data->custom_data[0] == CS40L50_PCM_ID ? CS40L50_TYPE_PCM :
+ CS40L50_TYPE_PWLE;
+ header.offset = sizeof(header) / sizeof(u32);
+ header.data_words = len / sizeof(u32);
+
+ new_owt_effect_data = kmalloc(sizeof(header) + len, GFP_KERNEL);
+ if (!new_owt_effect_data)
+ return -ENOMEM;
+
+ memcpy(new_owt_effect_data, &header, sizeof(header));
+ memcpy(new_owt_effect_data + sizeof(header), work_data->custom_data, len);
+
+ error = regmap_read(vib->regmap, vib->dsp.owt_offset_reg, &offset);
+ if (error)
+ return error;
+
+ error = regmap_bulk_write(vib->regmap, vib->dsp.owt_base_reg +
+ (offset * sizeof(u32)), new_owt_effect_data,
+ sizeof(header) + len);
+ if (error)
+ return error;
+
+ error = vib->dsp.write(vib->dev, vib->regmap, vib->dsp.push_owt_cmd);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void cs40l50_add_worker(struct work_struct *work)
+{
+ struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
+ struct cs40l50_vibra *vib = work_data->vib;
+ struct cs40l50_effect *effect;
+ bool is_new = false;
+ int error;
+
+ error = pm_runtime_resume_and_get(vib->dev);
+ if (error)
+ goto err_exit;
+
+ /* Update effect if already uploaded, otherwise create new effect */
+ effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head);
+ if (!effect) {
+ effect = kzalloc(sizeof(*effect), GFP_KERNEL);
+ if (!effect) {
+ error = -ENOMEM;
+ goto err_pm;
+ }
+
+ effect->id = work_data->effect->id;
+ is_new = true;
+ }
+
+ error = cs40l50_effect_bank_set(work_data, effect);
+ if (error)
+ goto err_free;
+
+ error = cs40l50_effect_index_set(work_data, effect);
+ if (error)
+ goto err_free;
+
+ error = cs40l50_effect_gpio_mapping_set(work_data, effect);
+ if (error)
+ goto err_free;
+
+ if (effect->type == CS40L50_WVFRM_BANK_OWT)
+ error = cs40l50_upload_owt(work_data);
+err_free:
+ if (is_new) {
+ if (error)
+ kfree(effect);
+ else
+ list_add(&effect->list, &vib->effect_head);
+ }
+err_pm:
+ pm_runtime_mark_last_busy(vib->dev);
+ pm_runtime_put_autosuspend(vib->dev);
+err_exit:
+ work_data->error = error;
+}
+
+static int cs40l50_add(struct input_dev *dev, struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ struct ff_periodic_effect *periodic = &effect->u.periodic;
+ struct cs40l50_vibra *vib = input_get_drvdata(dev);
+ struct cs40l50_work work_data;
+
+ if (effect->type != FF_PERIODIC || periodic->waveform != FF_CUSTOM) {
+ dev_err(vib->dev, "Type (%#X) or waveform (%#X) unsupported\n",
+ effect->type, periodic->waveform);
+ return -EINVAL;
+ }
+
+ work_data.custom_data = memdup_array_user(effect->u.periodic.custom_data,
+ effect->u.periodic.custom_len,
+ sizeof(s16));
+ if (IS_ERR(work_data.custom_data))
+ return PTR_ERR(work_data.custom_data);
+
+ work_data.custom_len = effect->u.periodic.custom_len;
+ work_data.vib = vib;
+ work_data.effect = effect;
+ INIT_WORK_ONSTACK(&work_data.work, cs40l50_add_worker);
+
+ /* Push to the workqueue to serialize with playbacks */
+ queue_work(vib->vib_wq, &work_data.work);
+ flush_work(&work_data.work);
+ destroy_work_on_stack(&work_data.work);
+
+ kfree(work_data.custom_data);
+
+ return work_data.error;
+}
+
+static void cs40l50_start_worker(struct work_struct *work)
+{
+ struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
+ struct cs40l50_vibra *vib = work_data->vib;
+ struct cs40l50_effect *start_effect;
+
+ if (pm_runtime_resume_and_get(vib->dev) < 0)
+ goto err_free;
+
+ start_effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head);
+ if (start_effect) {
+ while (--work_data->count >= 0) {
+ vib->dsp.write(vib->dev, vib->regmap, start_effect->index);
+ usleep_range(work_data->effect->replay.length,
+ work_data->effect->replay.length + 100);
+ }
+ } else {
+ dev_err(vib->dev, "Effect to play not found\n");
+ }
+
+ pm_runtime_mark_last_busy(vib->dev);
+ pm_runtime_put_autosuspend(vib->dev);
+err_free:
+ kfree(work_data);
+}
+
+static void cs40l50_stop_worker(struct work_struct *work)
+{
+ struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
+ struct cs40l50_vibra *vib = work_data->vib;
+
+ if (pm_runtime_resume_and_get(vib->dev) < 0)
+ return;
+
+ vib->dsp.write(vib->dev, vib->regmap, vib->dsp.stop_cmd);
+
+ pm_runtime_mark_last_busy(vib->dev);
+ pm_runtime_put_autosuspend(vib->dev);
+
+ kfree(work_data);
+}
+
+static int cs40l50_playback(struct input_dev *dev, int effect_id, int val)
+{
+ struct cs40l50_vibra *vib = input_get_drvdata(dev);
+ struct cs40l50_work *work_data;
+
+ work_data = kzalloc(sizeof(*work_data), GFP_ATOMIC);
+ if (!work_data)
+ return -ENOMEM;
+
+ work_data->vib = vib;
+
+ if (val > 0) {
+ work_data->effect = &dev->ff->effects[effect_id];
+ work_data->count = val;
+ INIT_WORK(&work_data->work, cs40l50_start_worker);
+ } else {
+ /* Stop the amplifier as device drives only one effect */
+ INIT_WORK(&work_data->work, cs40l50_stop_worker);
+ }
+
+ queue_work(vib->vib_wq, &work_data->work);
+
+ return 0;
+}
+
+static void cs40l50_erase_worker(struct work_struct *work)
+{
+ struct cs40l50_work *work_data = container_of(work, struct cs40l50_work, work);
+ struct cs40l50_effect *erase_effect, *owt_effect;
+ struct cs40l50_vibra *vib = work_data->vib;
+ int error;
+
+ error = pm_runtime_resume_and_get(vib->dev);
+ if (error)
+ goto err_exit;
+
+ erase_effect = cs40l50_find_effect(work_data->effect->id, &vib->effect_head);
+ if (!erase_effect) {
+ dev_err(vib->dev, "Effect to erase not found\n");
+ error = -EINVAL;
+ goto err_pm;
+ }
+
+ if (erase_effect->gpio_reg != CS40L50_GPIO_MAPPING_NONE) {
+ error = regmap_write(vib->regmap, erase_effect->gpio_reg,
+ CS40L50_GPIO_DISABLE);
+ if (error)
+ goto err_pm;
+ }
+
+ if (erase_effect->type == CS40L50_WVFRM_BANK_OWT) {
+ error = vib->dsp.write(vib->dev, vib->regmap,
+ vib->dsp.delete_owt_cmd |
+ (erase_effect->index & 0xFF));
+ if (error)
+ goto err_pm;
+
+ list_for_each_entry(owt_effect, &vib->effect_head, list)
+ if (owt_effect->type == CS40L50_WVFRM_BANK_OWT &&
+ owt_effect->index > erase_effect->index)
+ owt_effect->index--;
+ }
+
+ list_del(&erase_effect->list);
+ kfree(erase_effect);
+err_pm:
+ pm_runtime_mark_last_busy(vib->dev);
+ pm_runtime_put_autosuspend(vib->dev);
+err_exit:
+ work_data->error = error;
+}
+
+static int cs40l50_erase(struct input_dev *dev, int effect_id)
+{
+ struct cs40l50_vibra *vib = input_get_drvdata(dev);
+ struct cs40l50_work work_data;
+
+ work_data.vib = vib;
+ work_data.effect = &dev->ff->effects[effect_id];
+
+ INIT_WORK_ONSTACK(&work_data.work, cs40l50_erase_worker);
+
+ /* Push to workqueue to serialize with playbacks */
+ queue_work(vib->vib_wq, &work_data.work);
+ flush_work(&work_data.work);
+ destroy_work_on_stack(&work_data.work);
+
+ return work_data.error;
+}
+
+static void cs40l50_remove_wq(void *data)
+{
+ destroy_workqueue(data);
+}
+
+static int cs40l50_vibra_probe(struct platform_device *pdev)
+{
+ struct cs40l50 *cs40l50 = dev_get_drvdata(pdev->dev.parent);
+ struct cs40l50_vibra *vib;
+ int error;
+
+ vib = devm_kzalloc(pdev->dev.parent, sizeof(*vib), GFP_KERNEL);
+ if (!vib)
+ return -ENOMEM;
+
+ vib->dev = cs40l50->dev;
+ vib->regmap = cs40l50->regmap;
+ vib->dsp = cs40l50_dsp;
+
+ vib->input = devm_input_allocate_device(vib->dev);
+ if (!vib->input)
+ return -ENOMEM;
+
+ vib->input->id.product = cs40l50->devid;
+ vib->input->id.version = cs40l50->revid;
+ vib->input->name = "cs40l50_vibra";
+
+ input_set_drvdata(vib->input, vib);
+ input_set_capability(vib->input, EV_FF, FF_PERIODIC);
+ input_set_capability(vib->input, EV_FF, FF_CUSTOM);
+
+ error = input_ff_create(vib->input, CS40L50_EFFECTS_MAX);
+ if (error) {
+ dev_err(vib->dev, "Failed to create input device\n");
+ return error;
+ }
+
+ vib->input->ff->upload = cs40l50_add;
+ vib->input->ff->playback = cs40l50_playback;
+ vib->input->ff->erase = cs40l50_erase;
+
+ INIT_LIST_HEAD(&vib->effect_head);
+
+ vib->vib_wq = alloc_ordered_workqueue("vib_wq", WQ_HIGHPRI);
+ if (!vib->vib_wq)
+ return -ENOMEM;
+
+ error = devm_add_action_or_reset(vib->dev, cs40l50_remove_wq, vib->vib_wq);
+ if (error)
+ return error;
+
+ error = input_register_device(vib->input);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static const struct platform_device_id cs40l50_vibra_id_match[] = {
+ { "cs40l50-vibra", },
+ {}
+};
+MODULE_DEVICE_TABLE(platform, cs40l50_vibra_id_match);
+
+static struct platform_driver cs40l50_vibra_driver = {
+ .probe = cs40l50_vibra_probe,
+ .id_table = cs40l50_vibra_id_match,
+ .driver = {
+ .name = "cs40l50-vibra",
+ },
+};
+module_platform_driver(cs40l50_vibra_driver);
+
+MODULE_DESCRIPTION("CS40L50 Advanced Haptic Driver");
+MODULE_AUTHOR("James Ogletree, Cirrus Logic Inc. <james.ogletree@cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/da7280.c b/drivers/input/misc/da7280.c
index 1629b7ea4cbd..e4a605c6af15 100644
--- a/drivers/input/misc/da7280.c
+++ b/drivers/input/misc/da7280.c
@@ -1263,39 +1263,37 @@ static int da7280_suspend(struct device *dev)
{
struct da7280_haptic *haptics = dev_get_drvdata(dev);
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
/*
* Make sure no new requests will be submitted while device is
* suspended.
*/
- spin_lock_irq(&haptics->input_dev->event_lock);
- haptics->suspended = true;
- spin_unlock_irq(&haptics->input_dev->event_lock);
+ scoped_guard(spinlock_irq, &haptics->input_dev->event_lock) {
+ haptics->suspended = true;
+ }
da7280_haptic_stop(haptics);
- mutex_unlock(&haptics->input_dev->mutex);
-
return 0;
}
static int da7280_resume(struct device *dev)
{
struct da7280_haptic *haptics = dev_get_drvdata(dev);
- int retval;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
- retval = da7280_haptic_start(haptics);
- if (!retval) {
- spin_lock_irq(&haptics->input_dev->event_lock);
+ error = da7280_haptic_start(haptics);
+ if (error)
+ return error;
+
+ scoped_guard(spinlock_irq, &haptics->input_dev->event_lock) {
haptics->suspended = false;
- spin_unlock_irq(&haptics->input_dev->event_lock);
}
- mutex_unlock(&haptics->input_dev->mutex);
- return retval;
+ return 0;
}
#ifdef CONFIG_OF
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
index 7a1122e1efb9..cc23625019e3 100644
--- a/drivers/input/misc/da9052_onkey.c
+++ b/drivers/input/misc/da9052_onkey.c
@@ -140,8 +140,8 @@ static void da9052_onkey_remove(struct platform_device *pdev)
static struct platform_driver da9052_onkey_driver = {
.probe = da9052_onkey_probe,
- .remove_new = da9052_onkey_remove,
- .driver = {
+ .remove = da9052_onkey_remove,
+ .driver = {
.name = "da9052-onkey",
},
};
diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c
index 871812f1b398..3e4fc2f01011 100644
--- a/drivers/input/misc/da9055_onkey.c
+++ b/drivers/input/misc/da9055_onkey.c
@@ -145,8 +145,8 @@ static void da9055_onkey_remove(struct platform_device *pdev)
static struct platform_driver da9055_onkey_driver = {
.probe = da9055_onkey_probe,
- .remove_new = da9055_onkey_remove,
- .driver = {
+ .remove = da9055_onkey_remove,
+ .driver = {
.name = "da9055-onkey",
},
};
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 61b503835aa6..96cd6a078c8a 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -537,64 +537,62 @@ static int drv260x_probe(struct i2c_client *client)
static int drv260x_suspend(struct device *dev)
{
struct drv260x_data *haptics = dev_get_drvdata(dev);
- int ret = 0;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
if (input_device_enabled(haptics->input_dev)) {
- ret = regmap_update_bits(haptics->regmap,
- DRV260X_MODE,
- DRV260X_STANDBY_MASK,
- DRV260X_STANDBY);
- if (ret) {
+ error = regmap_update_bits(haptics->regmap,
+ DRV260X_MODE,
+ DRV260X_STANDBY_MASK,
+ DRV260X_STANDBY);
+ if (error) {
dev_err(dev, "Failed to set standby mode\n");
- goto out;
+ return error;
}
gpiod_set_value(haptics->enable_gpio, 0);
- ret = regulator_disable(haptics->regulator);
- if (ret) {
+ error = regulator_disable(haptics->regulator);
+ if (error) {
dev_err(dev, "Failed to disable regulator\n");
regmap_update_bits(haptics->regmap,
DRV260X_MODE,
DRV260X_STANDBY_MASK, 0);
+ return error;
}
}
-out:
- mutex_unlock(&haptics->input_dev->mutex);
- return ret;
+
+ return 0;
}
static int drv260x_resume(struct device *dev)
{
struct drv260x_data *haptics = dev_get_drvdata(dev);
- int ret = 0;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
if (input_device_enabled(haptics->input_dev)) {
- ret = regulator_enable(haptics->regulator);
- if (ret) {
+ error = regulator_enable(haptics->regulator);
+ if (error) {
dev_err(dev, "Failed to enable regulator\n");
- goto out;
+ return error;
}
- ret = regmap_update_bits(haptics->regmap,
- DRV260X_MODE,
- DRV260X_STANDBY_MASK, 0);
- if (ret) {
+ error = regmap_update_bits(haptics->regmap,
+ DRV260X_MODE,
+ DRV260X_STANDBY_MASK, 0);
+ if (error) {
dev_err(dev, "Failed to unset standby mode\n");
regulator_disable(haptics->regulator);
- goto out;
+ return error;
}
gpiod_set_value(haptics->enable_gpio, 1);
}
-out:
- mutex_unlock(&haptics->input_dev->mutex);
- return ret;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index f98e4d765307..46842cb8ddd7 100644
--- a/drivers/input/misc/drv2665.c
+++ b/drivers/input/misc/drv2665.c
@@ -15,7 +15,7 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-/* Contol registers */
+/* Control registers */
#define DRV2665_STATUS 0x00
#define DRV2665_CTRL_1 0x01
#define DRV2665_CTRL_2 0x02
@@ -225,59 +225,57 @@ static int drv2665_probe(struct i2c_client *client)
static int drv2665_suspend(struct device *dev)
{
struct drv2665_data *haptics = dev_get_drvdata(dev);
- int ret = 0;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
if (input_device_enabled(haptics->input_dev)) {
- ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
- DRV2665_STANDBY, DRV2665_STANDBY);
- if (ret) {
+ error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+ DRV2665_STANDBY, DRV2665_STANDBY);
+ if (error) {
dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator);
- goto out;
+ return error;
}
- ret = regulator_disable(haptics->regulator);
- if (ret) {
+ error = regulator_disable(haptics->regulator);
+ if (error) {
dev_err(dev, "Failed to disable regulator\n");
regmap_update_bits(haptics->regmap,
DRV2665_CTRL_2,
DRV2665_STANDBY, 0);
+ return error;
}
}
-out:
- mutex_unlock(&haptics->input_dev->mutex);
- return ret;
+
+ return 0;
}
static int drv2665_resume(struct device *dev)
{
struct drv2665_data *haptics = dev_get_drvdata(dev);
- int ret = 0;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
if (input_device_enabled(haptics->input_dev)) {
- ret = regulator_enable(haptics->regulator);
- if (ret) {
+ error = regulator_enable(haptics->regulator);
+ if (error) {
dev_err(dev, "Failed to enable regulator\n");
- goto out;
+ return error;
}
- ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
- DRV2665_STANDBY, 0);
- if (ret) {
+ error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2,
+ DRV2665_STANDBY, 0);
+ if (error) {
dev_err(dev, "Failed to unset standby mode\n");
regulator_disable(haptics->regulator);
- goto out;
+ return error;
}
}
-out:
- mutex_unlock(&haptics->input_dev->mutex);
- return ret;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index ad49845374b9..f952a24ec595 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -16,7 +16,7 @@
#include <linux/delay.h>
#include <linux/regulator/consumer.h>
-/* Contol registers */
+/* Control registers */
#define DRV2667_STATUS 0x00
#define DRV2667_CTRL_1 0x01
#define DRV2667_CTRL_2 0x02
@@ -402,59 +402,57 @@ static int drv2667_probe(struct i2c_client *client)
static int drv2667_suspend(struct device *dev)
{
struct drv2667_data *haptics = dev_get_drvdata(dev);
- int ret = 0;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
if (input_device_enabled(haptics->input_dev)) {
- ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
- DRV2667_STANDBY, DRV2667_STANDBY);
- if (ret) {
+ error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
+ DRV2667_STANDBY, DRV2667_STANDBY);
+ if (error) {
dev_err(dev, "Failed to set standby mode\n");
regulator_disable(haptics->regulator);
- goto out;
+ return error;
}
- ret = regulator_disable(haptics->regulator);
- if (ret) {
+ error = regulator_disable(haptics->regulator);
+ if (error) {
dev_err(dev, "Failed to disable regulator\n");
regmap_update_bits(haptics->regmap,
DRV2667_CTRL_2,
DRV2667_STANDBY, 0);
+ return error;
}
}
-out:
- mutex_unlock(&haptics->input_dev->mutex);
- return ret;
+
+ return 0;
}
static int drv2667_resume(struct device *dev)
{
struct drv2667_data *haptics = dev_get_drvdata(dev);
- int ret = 0;
+ int error;
- mutex_lock(&haptics->input_dev->mutex);
+ guard(mutex)(&haptics->input_dev->mutex);
if (input_device_enabled(haptics->input_dev)) {
- ret = regulator_enable(haptics->regulator);
- if (ret) {
+ error = regulator_enable(haptics->regulator);
+ if (error) {
dev_err(dev, "Failed to enable regulator\n");
- goto out;
+ return error;
}
- ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
- DRV2667_STANDBY, 0);
- if (ret) {
+ error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2,
+ DRV2667_STANDBY, 0);
+ if (error) {
dev_err(dev, "Failed to unset standby mode\n");
regulator_disable(haptics->regulator);
- goto out;
+ return error;
}
}
-out:
- mutex_unlock(&haptics->input_dev->mutex);
- return ret;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
diff --git a/drivers/input/misc/gpio-beeper.c b/drivers/input/misc/gpio-beeper.c
index d2d2954e2f79..3d65cb4f4ef3 100644
--- a/drivers/input/misc/gpio-beeper.c
+++ b/drivers/input/misc/gpio-beeper.c
@@ -94,7 +94,7 @@ static int gpio_beeper_probe(struct platform_device *pdev)
#ifdef CONFIG_OF
static const struct of_device_id gpio_beeper_of_match[] = {
- { .compatible = BEEPER_MODNAME, },
+ { .compatible = "gpio-beeper", },
{ }
};
MODULE_DEVICE_TABLE(of, gpio_beeper_of_match);
diff --git a/drivers/input/misc/hisi_powerkey.c b/drivers/input/misc/hisi_powerkey.c
index d3c293a95d32..d315017324d9 100644
--- a/drivers/input/misc/hisi_powerkey.c
+++ b/drivers/input/misc/hisi_powerkey.c
@@ -30,7 +30,7 @@ static irqreturn_t hi65xx_power_press_isr(int irq, void *q)
{
struct input_dev *input = q;
- pm_wakeup_event(input->dev.parent, MAX_HELD_TIME);
+ pm_wakeup_dev_event(input->dev.parent, MAX_HELD_TIME, true);
input_report_key(input, KEY_POWER, 1);
input_sync(input);
diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c
index 867ac7aa10d2..aa48f62d7ea0 100644
--- a/drivers/input/misc/ibm-panel.c
+++ b/drivers/input/misc/ibm-panel.c
@@ -77,12 +77,11 @@ static void ibm_panel_process_command(struct ibm_panel *panel)
static int ibm_panel_i2c_slave_cb(struct i2c_client *client,
enum i2c_slave_event event, u8 *val)
{
- unsigned long flags;
struct ibm_panel *panel = i2c_get_clientdata(client);
dev_dbg(&panel->input->dev, "event: %u data: %02x\n", event, *val);
- spin_lock_irqsave(&panel->lock, flags);
+ guard(spinlock_irqsave)(&panel->lock);
switch (event) {
case I2C_SLAVE_STOP:
@@ -114,8 +113,6 @@ static int ibm_panel_i2c_slave_cb(struct i2c_client *client,
break;
}
- spin_unlock_irqrestore(&panel->lock, flags);
-
return 0;
}
diff --git a/drivers/input/misc/ideapad_slidebar.c b/drivers/input/misc/ideapad_slidebar.c
index fa4e7f67d713..ab2e0a401904 100644
--- a/drivers/input/misc/ideapad_slidebar.c
+++ b/drivers/input/misc/ideapad_slidebar.c
@@ -23,7 +23,7 @@
*
* The value is in byte range, however, I only figured out
* how bits 0b10011001 work. Some other bits, probably,
- * are meaningfull too.
+ * are meaningful too.
*
* Possible states:
*
@@ -95,45 +95,33 @@ static struct platform_device *slidebar_platform_dev;
static u8 slidebar_pos_get(void)
{
- u8 res;
- unsigned long flags;
+ guard(spinlock_irqsave)(&io_lock);
- spin_lock_irqsave(&io_lock, flags);
outb(0xf4, 0xff29);
outb(0xbf, 0xff2a);
- res = inb(0xff2b);
- spin_unlock_irqrestore(&io_lock, flags);
-
- return res;
+ return inb(0xff2b);
}
static u8 slidebar_mode_get(void)
{
- u8 res;
- unsigned long flags;
+ guard(spinlock_irqsave)(&io_lock);
- spin_lock_irqsave(&io_lock, flags);
outb(0xf7, 0xff29);
outb(0x8b, 0xff2a);
- res = inb(0xff2b);
- spin_unlock_irqrestore(&io_lock, flags);
-
- return res;
+ return inb(0xff2b);
}
static void slidebar_mode_set(u8 mode)
{
- unsigned long flags;
+ guard(spinlock_irqsave)(&io_lock);
- spin_lock_irqsave(&io_lock, flags);
outb(0xf7, 0xff29);
outb(0x8b, 0xff2a);
outb(mode, 0xff2b);
- spin_unlock_irqrestore(&io_lock, flags);
}
static bool slidebar_i8042_filter(unsigned char data, unsigned char str,
- struct serio *port)
+ struct serio *port, void *context)
{
static bool extended = false;
@@ -231,7 +219,7 @@ static int __init ideapad_probe(struct platform_device* pdev)
input_set_capability(slidebar_input_dev, EV_ABS, ABS_X);
input_set_abs_params(slidebar_input_dev, ABS_X, 0, 0xff, 0, 0);
- err = i8042_install_filter(slidebar_i8042_filter);
+ err = i8042_install_filter(slidebar_i8042_filter, NULL);
if (err) {
dev_err(&pdev->dev,
"Failed to install i8042 filter: %d\n", err);
@@ -267,7 +255,7 @@ static struct platform_driver slidebar_drv = {
.driver = {
.name = "ideapad_slidebar",
},
- .remove_new = ideapad_remove,
+ .remove = ideapad_remove,
};
static int __init ideapad_dmi_check(const struct dmi_system_id *id)
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 80d16c92a08b..4581f1c53644 100644
--- a/drivers/input/misc/ims-pcu.c
+++ b/drivers/input/misc/ims-pcu.c
@@ -17,7 +17,7 @@
#include <linux/types.h>
#include <linux/usb/input.h>
#include <linux/usb/cdc.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define IMS_PCU_KEYMAP_LEN 32
@@ -207,8 +207,7 @@ static int ims_pcu_setup_buttons(struct ims_pcu *pcu,
input = input_allocate_device();
if (!input) {
- dev_err(pcu->dev,
- "Not enough memory for input input device\n");
+ dev_err(pcu->dev, "Not enough memory for input device\n");
return -ENOMEM;
}
@@ -287,7 +286,7 @@ static int ims_pcu_setup_gamepad(struct ims_pcu *pcu)
struct input_dev *input;
int error;
- gamepad = kzalloc(sizeof(struct ims_pcu_gamepad), GFP_KERNEL);
+ gamepad = kzalloc(sizeof(*gamepad), GFP_KERNEL);
input = input_allocate_device();
if (!gamepad || !input) {
dev_err(pcu->dev,
@@ -740,7 +739,7 @@ static int ims_pcu_switch_to_bootloader(struct ims_pcu *pcu)
{
int error;
- /* Execute jump to the bootoloader */
+ /* Execute jump to the bootloader */
error = ims_pcu_execute_command(pcu, JUMP_TO_BTLDR, NULL, 0);
if (error) {
dev_err(pcu->dev,
@@ -761,7 +760,7 @@ static int ims_pcu_switch_to_bootloader(struct ims_pcu *pcu)
struct ims_pcu_flash_fmt {
__le32 addr;
u8 len;
- u8 data[];
+ u8 data[] __counted_by(len);
};
static unsigned int ims_pcu_count_fw_records(const struct firmware *fw)
@@ -845,6 +844,12 @@ static int ims_pcu_flash_firmware(struct ims_pcu *pcu,
addr = be32_to_cpu(rec->addr) / 2;
len = be16_to_cpu(rec->len);
+ if (len > sizeof(pcu->cmd_buf) - 1 - sizeof(*fragment)) {
+ dev_err(pcu->dev,
+ "Invalid record length in firmware: %d\n", len);
+ return -EINVAL;
+ }
+
fragment = (void *)&pcu->cmd_buf[1];
put_unaligned_le32(addr, &fragment->addr);
fragment->len = len;
@@ -928,9 +933,8 @@ static void ims_pcu_process_async_firmware(const struct firmware *fw,
goto out;
}
- mutex_lock(&pcu->cmd_mutex);
- ims_pcu_handle_firmware_update(pcu, fw);
- mutex_unlock(&pcu->cmd_mutex);
+ scoped_guard(mutex, &pcu->cmd_mutex)
+ ims_pcu_handle_firmware_update(pcu, fw);
release_firmware(fw);
@@ -954,7 +958,7 @@ static int ims_pcu_backlight_set_brightness(struct led_classdev *cdev,
__le16 br_val = cpu_to_le16(value);
int error;
- mutex_lock(&pcu->cmd_mutex);
+ guard(mutex)(&pcu->cmd_mutex);
error = ims_pcu_execute_command(pcu, SET_BRIGHTNESS,
&br_val, sizeof(br_val));
@@ -963,8 +967,6 @@ static int ims_pcu_backlight_set_brightness(struct led_classdev *cdev,
"Failed to set desired brightness %u, error: %d\n",
value, error);
- mutex_unlock(&pcu->cmd_mutex);
-
return error;
}
@@ -978,7 +980,7 @@ ims_pcu_backlight_get_brightness(struct led_classdev *cdev)
int brightness;
int error;
- mutex_lock(&pcu->cmd_mutex);
+ guard(mutex)(&pcu->cmd_mutex);
error = ims_pcu_execute_query(pcu, GET_BRIGHTNESS);
if (error) {
@@ -992,8 +994,6 @@ ims_pcu_backlight_get_brightness(struct led_classdev *cdev)
get_unaligned_le16(&pcu->cmd_buf[IMS_PCU_DATA_OFFSET]);
}
- mutex_unlock(&pcu->cmd_mutex);
-
return brightness;
}
@@ -1073,24 +1073,23 @@ static ssize_t ims_pcu_attribute_store(struct device *dev,
if (data_len > attr->field_length)
return -EINVAL;
- error = mutex_lock_interruptible(&pcu->cmd_mutex);
- if (error)
- return error;
-
- memset(field, 0, attr->field_length);
- memcpy(field, buf, data_len);
+ scoped_cond_guard(mutex_intr, return -EINTR, &pcu->cmd_mutex) {
+ memset(field, 0, attr->field_length);
+ memcpy(field, buf, data_len);
- error = ims_pcu_set_info(pcu);
+ error = ims_pcu_set_info(pcu);
- /*
- * Even if update failed, let's fetch the info again as we just
- * clobbered one of the fields.
- */
- ims_pcu_get_info(pcu);
+ /*
+ * Even if update failed, let's fetch the info again as we just
+ * clobbered one of the fields.
+ */
+ ims_pcu_get_info(pcu);
- mutex_unlock(&pcu->cmd_mutex);
+ if (error)
+ return error;
+ }
- return error < 0 ? error : count;
+ return count;
}
#define IMS_PCU_ATTR(_field, _mode) \
@@ -1153,7 +1152,6 @@ static ssize_t ims_pcu_update_firmware_store(struct device *dev,
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
- const struct firmware *fw = NULL;
int value;
int error;
@@ -1164,35 +1162,33 @@ static ssize_t ims_pcu_update_firmware_store(struct device *dev,
if (value != 1)
return -EINVAL;
- error = mutex_lock_interruptible(&pcu->cmd_mutex);
- if (error)
- return error;
-
+ const struct firmware *fw __free(firmware) = NULL;
error = request_ihex_firmware(&fw, IMS_PCU_FIRMWARE_NAME, pcu->dev);
if (error) {
dev_err(pcu->dev, "Failed to request firmware %s, error: %d\n",
IMS_PCU_FIRMWARE_NAME, error);
- goto out;
+ return error;
}
- /*
- * If we are already in bootloader mode we can proceed with
- * flashing the firmware.
- *
- * If we are in application mode, then we need to switch into
- * bootloader mode, which will cause the device to disconnect
- * and reconnect as different device.
- */
- if (pcu->bootloader_mode)
- error = ims_pcu_handle_firmware_update(pcu, fw);
- else
- error = ims_pcu_switch_to_bootloader(pcu);
+ scoped_cond_guard(mutex_intr, return -EINTR, &pcu->cmd_mutex) {
+ /*
+ * If we are already in bootloader mode we can proceed with
+ * flashing the firmware.
+ *
+ * If we are in application mode, then we need to switch into
+ * bootloader mode, which will cause the device to disconnect
+ * and reconnect as different device.
+ */
+ if (pcu->bootloader_mode)
+ error = ims_pcu_handle_firmware_update(pcu, fw);
+ else
+ error = ims_pcu_switch_to_bootloader(pcu);
- release_firmware(fw);
+ if (error)
+ return error;
+ }
-out:
- mutex_unlock(&pcu->cmd_mutex);
- return error ?: count;
+ return count;
}
static DEVICE_ATTR(update_firmware, S_IWUSR,
@@ -1302,12 +1298,11 @@ static ssize_t ims_pcu_ofn_reg_data_show(struct device *dev,
int error;
u8 data;
- mutex_lock(&pcu->cmd_mutex);
- error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
- mutex_unlock(&pcu->cmd_mutex);
-
- if (error)
- return error;
+ scoped_guard(mutex, &pcu->cmd_mutex) {
+ error = ims_pcu_read_ofn_config(pcu, pcu->ofn_reg_addr, &data);
+ if (error)
+ return error;
+ }
return sysfs_emit(buf, "%x\n", data);
}
@@ -1325,11 +1320,13 @@ static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
if (error)
return error;
- mutex_lock(&pcu->cmd_mutex);
+ guard(mutex)(&pcu->cmd_mutex);
+
error = ims_pcu_write_ofn_config(pcu, pcu->ofn_reg_addr, value);
- mutex_unlock(&pcu->cmd_mutex);
+ if (error)
+ return error;
- return error ?: count;
+ return count;
}
static DEVICE_ATTR(reg_data, S_IRUGO | S_IWUSR,
@@ -1341,13 +1338,10 @@ static ssize_t ims_pcu_ofn_reg_addr_show(struct device *dev,
{
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
- int error;
- mutex_lock(&pcu->cmd_mutex);
- error = sysfs_emit(buf, "%x\n", pcu->ofn_reg_addr);
- mutex_unlock(&pcu->cmd_mutex);
+ guard(mutex)(&pcu->cmd_mutex);
- return error;
+ return sysfs_emit(buf, "%x\n", pcu->ofn_reg_addr);
}
static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
@@ -1363,9 +1357,9 @@ static ssize_t ims_pcu_ofn_reg_addr_store(struct device *dev,
if (error)
return error;
- mutex_lock(&pcu->cmd_mutex);
+ guard(mutex)(&pcu->cmd_mutex);
+
pcu->ofn_reg_addr = value;
- mutex_unlock(&pcu->cmd_mutex);
return count;
}
@@ -1390,12 +1384,11 @@ static ssize_t ims_pcu_ofn_bit_show(struct device *dev,
int error;
u8 data;
- mutex_lock(&pcu->cmd_mutex);
- error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
- mutex_unlock(&pcu->cmd_mutex);
-
- if (error)
- return error;
+ scoped_guard(mutex, &pcu->cmd_mutex) {
+ error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
+ if (error)
+ return error;
+ }
return sysfs_emit(buf, "%d\n", !!(data & (1 << attr->nr)));
}
@@ -1419,21 +1412,22 @@ static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
if (value > 1)
return -EINVAL;
- mutex_lock(&pcu->cmd_mutex);
+ scoped_guard(mutex, &pcu->cmd_mutex) {
+ error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
+ if (error)
+ return error;
- error = ims_pcu_read_ofn_config(pcu, attr->addr, &data);
- if (!error) {
if (value)
data |= 1U << attr->nr;
else
data &= ~(1U << attr->nr);
error = ims_pcu_write_ofn_config(pcu, attr->addr, data);
+ if (error)
+ return error;
}
- mutex_unlock(&pcu->cmd_mutex);
-
- return error ?: count;
+ return count;
}
#define IMS_PCU_OFN_BIT_ATTR(_field, _addr, _nr) \
@@ -1466,9 +1460,27 @@ static struct attribute *ims_pcu_ofn_attrs[] = {
NULL
};
+static umode_t ims_pcu_ofn_is_attr_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct ims_pcu *pcu = usb_get_intfdata(intf);
+ umode_t mode = attr->mode;
+
+ /*
+ * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor.
+ */
+ if (pcu->bootloader_mode || pcu->device_id == IMS_PCU_PCU_B_DEVICE_ID)
+ mode = 0;
+
+ return mode;
+}
+
static const struct attribute_group ims_pcu_ofn_attr_group = {
- .name = "ofn",
- .attrs = ims_pcu_ofn_attrs,
+ .name = "ofn",
+ .is_visible = ims_pcu_ofn_is_attr_visible,
+ .attrs = ims_pcu_ofn_attrs,
};
static void ims_pcu_irq(struct urb *urb)
@@ -1890,16 +1902,6 @@ static int ims_pcu_init_application_mode(struct ims_pcu *pcu)
/* Device appears to be operable, complete initialization */
pcu->device_no = atomic_inc_return(&device_no);
- /*
- * PCU-B devices, both GEN_1 and GEN_2 do not have OFN sensor
- */
- if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID) {
- error = sysfs_create_group(&pcu->dev->kobj,
- &ims_pcu_ofn_attr_group);
- if (error)
- return error;
- }
-
error = ims_pcu_setup_backlight(pcu);
if (error)
return error;
@@ -1936,10 +1938,6 @@ static void ims_pcu_destroy_application_mode(struct ims_pcu *pcu)
ims_pcu_destroy_gamepad(pcu);
ims_pcu_destroy_buttons(pcu);
ims_pcu_destroy_backlight(pcu);
-
- if (pcu->device_id != IMS_PCU_PCU_B_DEVICE_ID)
- sysfs_remove_group(&pcu->dev->kobj,
- &ims_pcu_ofn_attr_group);
}
}
@@ -1993,7 +1991,7 @@ static int ims_pcu_probe(struct usb_interface *intf,
struct ims_pcu *pcu;
int error;
- pcu = kzalloc(sizeof(struct ims_pcu), GFP_KERNEL);
+ pcu = kzalloc(sizeof(*pcu), GFP_KERNEL);
if (!pcu)
return -ENOMEM;
@@ -2031,20 +2029,14 @@ static int ims_pcu_probe(struct usb_interface *intf,
if (error)
goto err_stop_io;
- error = sysfs_create_group(&intf->dev.kobj, &ims_pcu_attr_group);
- if (error)
- goto err_stop_io;
-
error = pcu->bootloader_mode ?
ims_pcu_init_bootloader_mode(pcu) :
ims_pcu_init_application_mode(pcu);
if (error)
- goto err_remove_sysfs;
+ goto err_stop_io;
return 0;
-err_remove_sysfs:
- sysfs_remove_group(&intf->dev.kobj, &ims_pcu_attr_group);
err_stop_io:
ims_pcu_stop_io(pcu);
err_free_buffers:
@@ -2070,8 +2062,6 @@ static void ims_pcu_disconnect(struct usb_interface *intf)
if (alt->desc.bInterfaceClass != USB_CLASS_COMM)
return;
- sysfs_remove_group(&intf->dev.kobj, &ims_pcu_attr_group);
-
ims_pcu_stop_io(pcu);
if (pcu->bootloader_mode)
@@ -2130,9 +2120,16 @@ static const struct usb_device_id ims_pcu_id_table[] = {
{ }
};
+static const struct attribute_group *ims_pcu_sysfs_groups[] = {
+ &ims_pcu_attr_group,
+ &ims_pcu_ofn_attr_group,
+ NULL
+};
+
static struct usb_driver ims_pcu_driver = {
.name = "ims_pcu",
.id_table = ims_pcu_id_table,
+ .dev_groups = ims_pcu_sysfs_groups,
.probe = ims_pcu_probe,
.disconnect = ims_pcu_disconnect,
#ifdef CONFIG_PM
diff --git a/drivers/input/misc/iqs269a.c b/drivers/input/misc/iqs269a.c
index cd14ff9f57cf..1851848e2cd3 100644
--- a/drivers/input/misc/iqs269a.c
+++ b/drivers/input/misc/iqs269a.c
@@ -365,7 +365,7 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
if (mode > IQS269_CHx_ENG_A_ATI_MODE_MAX)
return -EINVAL;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
@@ -375,8 +375,6 @@ static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return 0;
}
@@ -389,9 +387,9 @@ static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
+
engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
- mutex_unlock(&iqs269->lock);
engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK;
*mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
@@ -429,7 +427,7 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269,
return -EINVAL;
}
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
@@ -439,8 +437,6 @@ static int iqs269_ati_base_set(struct iqs269_private *iqs269,
ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return 0;
}
@@ -453,9 +449,9 @@ static int iqs269_ati_base_get(struct iqs269_private *iqs269,
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
+
engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
- mutex_unlock(&iqs269->lock);
switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) {
case IQS269_CHx_ENG_B_ATI_BASE_75:
@@ -491,7 +487,7 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269,
if (target > IQS269_CHx_ENG_B_ATI_TARGET_MAX)
return -EINVAL;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
@@ -501,8 +497,6 @@ static int iqs269_ati_target_set(struct iqs269_private *iqs269,
ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return 0;
}
@@ -515,10 +509,9 @@ static int iqs269_ati_target_get(struct iqs269_private *iqs269,
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
- mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
- mutex_unlock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
*target = (engine_b & IQS269_CHx_ENG_B_ATI_TARGET_MASK) * 32;
return 0;
@@ -557,7 +550,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
const struct fwnode_handle *ch_node)
{
struct i2c_client *client = iqs269->client;
- struct fwnode_handle *ev_node;
struct iqs269_ch_reg *ch_reg;
u16 engine_a, engine_b;
unsigned int reg, val;
@@ -734,8 +726,9 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
}
for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
- ev_node = fwnode_get_named_child_node(ch_node,
- iqs269_events[i].name);
+ struct fwnode_handle *ev_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(ch_node,
+ iqs269_events[i].name);
if (!ev_node)
continue;
@@ -744,7 +737,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
dev_err(&client->dev,
"Invalid channel %u threshold: %u\n",
reg, val);
- fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -758,7 +750,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
dev_err(&client->dev,
"Invalid channel %u hysteresis: %u\n",
reg, val);
- fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -774,7 +765,6 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
}
error = fwnode_property_read_u32(ev_node, "linux,code", &val);
- fwnode_handle_put(ev_node);
if (error == -EINVAL) {
continue;
} else if (error) {
@@ -811,7 +801,6 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
{
struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
struct i2c_client *client = iqs269->client;
- struct fwnode_handle *ch_node;
u16 general, misc_a, misc_b;
unsigned int val;
int error;
@@ -1049,12 +1038,10 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
sys_reg->event_mask = ~((u8)IQS269_EVENT_MASK_SYS);
- device_for_each_child_node(&client->dev, ch_node) {
+ device_for_each_child_node_scoped(&client->dev, ch_node) {
error = iqs269_parse_chan(iqs269, ch_node);
- if (error) {
- fwnode_handle_put(ch_node);
+ if (error)
return error;
- }
}
/*
@@ -1202,7 +1189,7 @@ static int iqs269_dev_init(struct iqs269_private *iqs269)
{
int error;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
/*
* Early revisions of silicon require the following workaround in order
@@ -1213,19 +1200,19 @@ static int iqs269_dev_init(struct iqs269_private *iqs269)
error = regmap_multi_reg_write(iqs269->regmap, iqs269_tws_init,
ARRAY_SIZE(iqs269_tws_init));
if (error)
- goto err_mutex;
+ return error;
}
error = regmap_update_bits(iqs269->regmap, IQS269_HALL_UI,
IQS269_HALL_UI_ENABLE,
iqs269->hall_enable ? ~0 : 0);
if (error)
- goto err_mutex;
+ return error;
error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS,
&iqs269->sys_reg, sizeof(iqs269->sys_reg));
if (error)
- goto err_mutex;
+ return error;
/*
* The following delay gives the device time to deassert its RDY output
@@ -1235,10 +1222,7 @@ static int iqs269_dev_init(struct iqs269_private *iqs269)
iqs269->ati_current = true;
-err_mutex:
- mutex_unlock(&iqs269->lock);
-
- return error;
+ return 0;
}
static int iqs269_input_init(struct iqs269_private *iqs269)
@@ -1583,13 +1567,11 @@ static ssize_t hall_enable_store(struct device *dev,
if (error)
return error;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
iqs269->hall_enable = val;
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return count;
}
@@ -1646,13 +1628,11 @@ static ssize_t rx_enable_store(struct device *dev,
if (val > 0xFF)
return -EINVAL;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
ch_reg[iqs269->ch_num].rx_enable = val;
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return count;
}
diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c
index 0dab54d3a060..7fba4a8edceb 100644
--- a/drivers/input/misc/iqs626a.c
+++ b/drivers/input/misc/iqs626a.c
@@ -462,7 +462,6 @@ iqs626_parse_events(struct iqs626_private *iqs626,
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
- struct fwnode_handle *ev_node;
const char *ev_name;
u8 *thresh, *hyst;
unsigned int val;
@@ -501,6 +500,7 @@ iqs626_parse_events(struct iqs626_private *iqs626,
if (!iqs626_channels[ch_id].events[i])
continue;
+ struct fwnode_handle *ev_node __free(fwnode_handle) = NULL;
if (ch_id == IQS626_CH_TP_2 || ch_id == IQS626_CH_TP_3) {
/*
* Trackpad touch events are simply described under the
@@ -530,7 +530,6 @@ iqs626_parse_events(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid input type: %u\n",
val);
- fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -545,7 +544,6 @@ iqs626_parse_events(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid %s channel hysteresis: %u\n",
fwnode_get_name(ch_node), val);
- fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -566,7 +564,6 @@ iqs626_parse_events(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid %s channel threshold: %u\n",
fwnode_get_name(ch_node), val);
- fwnode_handle_put(ev_node);
return -EINVAL;
}
@@ -575,8 +572,6 @@ iqs626_parse_events(struct iqs626_private *iqs626,
else
*(thresh + iqs626_events[i].th_offs) = val;
}
-
- fwnode_handle_put(ev_node);
}
return 0;
@@ -774,12 +769,12 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
for (i = 0; i < iqs626_channels[ch_id].num_ch; i++) {
u8 *ati_base = &sys_reg->tp_grp_reg.ch_reg_tp[i].ati_base;
u8 *thresh = &sys_reg->tp_grp_reg.ch_reg_tp[i].thresh;
- struct fwnode_handle *tc_node;
char tc_name[10];
- snprintf(tc_name, sizeof(tc_name), "channel-%d", i);
+ scnprintf(tc_name, sizeof(tc_name), "channel-%d", i);
- tc_node = fwnode_get_named_child_node(ch_node, tc_name);
+ struct fwnode_handle *tc_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(ch_node, tc_name);
if (!tc_node)
continue;
@@ -790,7 +785,6 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid %s %s ATI base: %u\n",
fwnode_get_name(ch_node), tc_name, val);
- fwnode_handle_put(tc_node);
return -EINVAL;
}
@@ -803,14 +797,11 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
dev_err(&client->dev,
"Invalid %s %s threshold: %u\n",
fwnode_get_name(ch_node), tc_name, val);
- fwnode_handle_put(tc_node);
return -EINVAL;
}
*thresh = val;
}
-
- fwnode_handle_put(tc_node);
}
if (!fwnode_property_present(ch_node, "linux,keycodes"))
@@ -1233,7 +1224,6 @@ static int iqs626_parse_prop(struct iqs626_private *iqs626)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
- struct fwnode_handle *ch_node;
unsigned int val;
int error, i;
u16 general;
@@ -1375,13 +1365,13 @@ static int iqs626_parse_prop(struct iqs626_private *iqs626)
sys_reg->active = 0;
for (i = 0; i < ARRAY_SIZE(iqs626_channels); i++) {
- ch_node = device_get_named_child_node(&client->dev,
- iqs626_channels[i].name);
+ struct fwnode_handle *ch_node __free(fwnode_handle) =
+ device_get_named_child_node(&client->dev,
+ iqs626_channels[i].name);
if (!ch_node)
continue;
error = iqs626_parse_channel(iqs626, ch_node, i);
- fwnode_handle_put(ch_node);
if (error)
return error;
diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c
index 9ca5a743f19f..ff23219a582a 100644
--- a/drivers/input/misc/iqs7222.c
+++ b/drivers/input/misc/iqs7222.c
@@ -20,7 +20,7 @@
#include <linux/module.h>
#include <linux/property.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define IQS7222_PROD_NUM 0x00
#define IQS7222_PROD_NUM_A 840
@@ -100,11 +100,11 @@ enum iqs7222_reg_key_id {
enum iqs7222_reg_grp_id {
IQS7222_REG_GRP_STAT,
- IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_CYCLE,
IQS7222_REG_GRP_GLBL,
IQS7222_REG_GRP_BTN,
IQS7222_REG_GRP_CHAN,
+ IQS7222_REG_GRP_FILT,
IQS7222_REG_GRP_SLDR,
IQS7222_REG_GRP_TPAD,
IQS7222_REG_GRP_GPIO,
@@ -286,6 +286,7 @@ static const struct iqs7222_event_desc iqs7222_tp_events[] = {
struct iqs7222_reg_grp_desc {
u16 base;
+ u16 val_len;
int num_row;
int num_col;
};
@@ -300,6 +301,7 @@ struct iqs7222_dev_desc {
int allow_offset;
int event_offset;
int comms_offset;
+ int ext_chan;
bool legacy_gesture;
struct iqs7222_reg_grp_desc reg_grps[IQS7222_NUM_REG_GRPS];
};
@@ -314,6 +316,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
.allow_offset = 9,
.event_offset = 10,
.comms_offset = 12,
+ .ext_chan = 10,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
.base = IQS7222_SYS_STATUS,
@@ -342,6 +345,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAC00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -371,6 +375,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
.allow_offset = 9,
.event_offset = 10,
.comms_offset = 12,
+ .ext_chan = 10,
.legacy_gesture = true,
.reg_grps = {
[IQS7222_REG_GRP_STAT] = {
@@ -400,6 +405,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAC00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -454,6 +460,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xC400,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -496,6 +503,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xC400,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -543,6 +551,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAA00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -600,6 +609,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAA00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -656,6 +666,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -712,6 +723,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -768,6 +780,7 @@ static const struct iqs7222_dev_desc iqs7222_devs[] = {
},
[IQS7222_REG_GRP_FILT] = {
.base = 0xAE00,
+ .val_len = 3,
.num_row = 1,
.num_col = 2,
},
@@ -1604,7 +1617,7 @@ static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
}
static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
- u16 reg, void *val, u16 num_val)
+ u16 reg, void *val, u16 val_len)
{
u8 reg_buf[sizeof(__be16)];
int ret, i;
@@ -1619,7 +1632,7 @@ static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
{
.addr = client->addr,
.flags = I2C_M_RD,
- .len = num_val * sizeof(__le16),
+ .len = val_len,
.buf = (u8 *)val,
},
};
@@ -1675,7 +1688,7 @@ static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
__le16 val_buf;
int error;
- error = iqs7222_read_burst(iqs7222, reg, &val_buf, 1);
+ error = iqs7222_read_burst(iqs7222, reg, &val_buf, sizeof(val_buf));
if (error)
return error;
@@ -1685,10 +1698,9 @@ static int iqs7222_read_word(struct iqs7222_private *iqs7222, u16 reg, u16 *val)
}
static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
- u16 reg, const void *val, u16 num_val)
+ u16 reg, const void *val, u16 val_len)
{
int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
- int val_len = num_val * sizeof(__le16);
int msg_len = reg_len + val_len;
int ret, i;
struct i2c_client *client = iqs7222->client;
@@ -1747,7 +1759,7 @@ static int iqs7222_write_word(struct iqs7222_private *iqs7222, u16 reg, u16 val)
{
__le16 val_buf = cpu_to_le16(val);
- return iqs7222_write_burst(iqs7222, reg, &val_buf, 1);
+ return iqs7222_write_burst(iqs7222, reg, &val_buf, sizeof(val_buf));
}
static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
@@ -1831,30 +1843,14 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
/*
* Acknowledge reset before writing any registers in case the device
- * suffers a spurious reset during initialization. Because this step
- * may change the reserved fields of the second filter beta register,
- * its cache must be updated.
- *
- * Writing the second filter beta register, in turn, may clobber the
- * system status register. As such, the filter beta register pair is
- * written first to protect against this hazard.
+ * suffers a spurious reset during initialization.
*/
if (dir == WRITE) {
- u16 reg = dev_desc->reg_grps[IQS7222_REG_GRP_FILT].base + 1;
- u16 filt_setup;
-
error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
iqs7222->sys_setup[0] |
IQS7222_SYS_SETUP_ACK_RESET);
if (error)
return error;
-
- error = iqs7222_read_word(iqs7222, reg, &filt_setup);
- if (error)
- return error;
-
- iqs7222->filt_setup[1] &= GENMASK(7, 0);
- iqs7222->filt_setup[1] |= (filt_setup & ~GENMASK(7, 0));
}
/*
@@ -1883,6 +1879,7 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
int num_col = dev_desc->reg_grps[i].num_col;
u16 reg = dev_desc->reg_grps[i].base;
__le16 *val_buf;
+ u16 val_len = dev_desc->reg_grps[i].val_len ? : num_col * sizeof(*val_buf);
u16 *val;
if (!num_col)
@@ -1900,7 +1897,7 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
switch (dir) {
case READ:
error = iqs7222_read_burst(iqs7222, reg,
- val_buf, num_col);
+ val_buf, val_len);
for (k = 0; k < num_col; k++)
val[k] = le16_to_cpu(val_buf[k]);
break;
@@ -1909,7 +1906,7 @@ static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
for (k = 0; k < num_col; k++)
val_buf[k] = cpu_to_le16(val[k]);
error = iqs7222_write_burst(iqs7222, reg,
- val_buf, num_col);
+ val_buf, val_len);
break;
default:
@@ -1962,7 +1959,7 @@ static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
int error, i;
error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
- ARRAY_SIZE(dev_id));
+ sizeof(dev_id));
if (error)
return error;
@@ -2250,7 +2247,7 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
struct i2c_client *client = iqs7222->client;
int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
- int ext_chan = rounddown(num_chan, 10);
+ int ext_chan = dev_desc->ext_chan ? : num_chan;
int error, i;
u16 *chan_setup = iqs7222->chan_setup[chan_index];
u16 *sys_setup = iqs7222->sys_setup;
@@ -2385,9 +2382,9 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
for (i = 0; i < ARRAY_SIZE(iqs7222_kp_events); i++) {
const char *event_name = iqs7222_kp_events[i].name;
u16 event_enable = iqs7222_kp_events[i].enable;
- struct fwnode_handle *event_node;
- event_node = fwnode_get_named_child_node(chan_node, event_name);
+ struct fwnode_handle *event_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(chan_node, event_name);
if (!event_node)
continue;
@@ -2408,7 +2405,6 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
dev_err(&client->dev,
"Invalid %s press timeout: %u\n",
fwnode_get_name(event_node), val);
- fwnode_handle_put(event_node);
return -EINVAL;
}
@@ -2418,7 +2414,6 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
dev_err(&client->dev,
"Failed to read %s press timeout: %d\n",
fwnode_get_name(event_node), error);
- fwnode_handle_put(event_node);
return error;
}
@@ -2429,10 +2424,12 @@ static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
dev_desc->touch_link - (i ? 0 : 2),
&iqs7222->kp_type[chan_index][i],
&iqs7222->kp_code[chan_index][i]);
- fwnode_handle_put(event_node);
if (error)
return error;
+ if (!iqs7222->kp_type[chan_index][i])
+ continue;
+
if (!dev_desc->event_offset)
continue;
@@ -2454,7 +2451,7 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
struct i2c_client *client = iqs7222->client;
int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
- int ext_chan = rounddown(num_chan, 10);
+ int ext_chan = dev_desc->ext_chan ? : num_chan;
int count, error, reg_offset, i;
u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
u16 *sldr_setup = iqs7222->sldr_setup[sldr_index];
@@ -2604,10 +2601,10 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
const char *event_name = iqs7222_sl_events[i].name;
- struct fwnode_handle *event_node;
enum iqs7222_reg_key_id reg_key;
- event_node = fwnode_get_named_child_node(sldr_node, event_name);
+ struct fwnode_handle *event_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(sldr_node, event_name);
if (!event_node)
continue;
@@ -2639,7 +2636,6 @@ static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
: sldr_setup[4 + reg_offset],
NULL,
&iqs7222->sl_code[sldr_index][i]);
- fwnode_handle_put(event_node);
if (error)
return error;
@@ -2742,9 +2738,9 @@ static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222,
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);
+ struct fwnode_handle *event_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(tpad_node, event_name);
if (!event_node)
continue;
@@ -2760,7 +2756,6 @@ static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222,
iqs7222_tp_events[i].link, 1566,
NULL,
&iqs7222->tp_code[i]);
- fwnode_handle_put(event_node);
if (error)
return error;
@@ -2818,9 +2813,9 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
int reg_grp_index)
{
struct i2c_client *client = iqs7222->client;
- struct fwnode_handle *reg_grp_node;
int error;
+ struct fwnode_handle *reg_grp_node __free(fwnode_handle) = NULL;
if (iqs7222_reg_grp_names[reg_grp]) {
char reg_grp_name[16];
@@ -2838,14 +2833,17 @@ static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index,
reg_grp, IQS7222_REG_KEY_NONE);
+ if (error)
+ return error;
- if (!error && iqs7222_parse_extra[reg_grp])
+ if (iqs7222_parse_extra[reg_grp]) {
error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node,
reg_grp_index);
+ if (error)
+ return error;
+ }
- fwnode_handle_put(reg_grp_node);
-
- return error;
+ return 0;
}
static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
@@ -2917,7 +2915,7 @@ static int iqs7222_report(struct iqs7222_private *iqs7222)
__le16 status[IQS7222_MAX_COLS_STAT];
error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
- num_stat);
+ num_stat * sizeof(*status));
if (error)
return error;
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index 837682cb2a7d..eb9788ea5215 100644
--- a/drivers/input/misc/kxtj9.c
+++ b/drivers/input/misc/kxtj9.c
@@ -25,7 +25,7 @@
/* CONTROL REGISTER 1 BITS */
#define PC1_OFF 0x7F
#define PC1_ON (1 << 7)
-/* Data ready funtion enable bit: set during probe if using irq mode */
+/* Data ready function enable bit: set during probe if using irq mode */
#define DRDYE (1 << 5)
/* DATA CONTROL REGISTER BITS */
#define ODR12_5F 0
@@ -314,9 +314,8 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr,
return error;
/* Lock the device to prevent races with open/close (and itself) */
- mutex_lock(&input_dev->mutex);
-
- disable_irq(client->irq);
+ guard(mutex)(&input_dev->mutex);
+ guard(disable_irq)(&client->irq);
/*
* Set current interval to the greater of the minimum interval or
@@ -326,9 +325,6 @@ static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr,
kxtj9_update_odr(tj9, tj9->last_poll_interval);
- enable_irq(client->irq);
- mutex_unlock(&input_dev->mutex);
-
return count;
}
@@ -504,12 +500,11 @@ static int kxtj9_suspend(struct device *dev)
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
struct input_dev *input_dev = tj9->input_dev;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
kxtj9_disable(tj9);
- mutex_unlock(&input_dev->mutex);
return 0;
}
@@ -519,12 +514,11 @@ static int kxtj9_resume(struct device *dev)
struct kxtj9_data *tj9 = i2c_get_clientdata(client);
struct input_dev *input_dev = tj9->input_dev;
- mutex_lock(&input_dev->mutex);
+ guard(mutex)(&input_dev->mutex);
if (input_device_enabled(input_dev))
kxtj9_enable(tj9);
- mutex_unlock(&input_dev->mutex);
return 0;
}
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 3fe0a85c45e0..0542334df624 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -95,7 +95,7 @@ static struct platform_driver m68kspkr_platform_driver = {
.name = "m68kspkr",
},
.probe = m68kspkr_probe,
- .remove_new = m68kspkr_remove,
+ .remove = m68kspkr_remove,
.shutdown = m68kspkr_shutdown,
};
diff --git a/drivers/input/misc/max7360-rotary.c b/drivers/input/misc/max7360-rotary.c
new file mode 100644
index 000000000000..385831ef34b6
--- /dev/null
+++ b/drivers/input/misc/max7360-rotary.c
@@ -0,0 +1,192 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2025 Bootlin
+ *
+ * Author: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/device/devres.h>
+#include <linux/dev_printk.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/max7360.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+#define MAX7360_ROTARY_DEFAULT_STEPS 24
+
+struct max7360_rotary {
+ struct input_dev *input;
+ struct regmap *regmap;
+ unsigned int debounce_ms;
+
+ unsigned int pos;
+
+ u32 steps;
+ u32 axis;
+ bool relative_axis;
+ bool rollover;
+};
+
+static void max7360_rotary_report_event(struct max7360_rotary *max7360_rotary, int steps)
+{
+ if (max7360_rotary->relative_axis) {
+ input_report_rel(max7360_rotary->input, max7360_rotary->axis, steps);
+ } else {
+ int pos = max7360_rotary->pos;
+ int maxval = max7360_rotary->steps;
+
+ /*
+ * Add steps to the position.
+ * Make sure added steps are always in ]-maxval; maxval[
+ * interval, so (pos + maxval) is always >= 0.
+ * Then set back pos to the [0; maxval[ interval.
+ */
+ pos += steps % maxval;
+ if (max7360_rotary->rollover)
+ pos = (pos + maxval) % maxval;
+ else
+ pos = clamp(pos, 0, maxval - 1);
+
+ max7360_rotary->pos = pos;
+ input_report_abs(max7360_rotary->input, max7360_rotary->axis, max7360_rotary->pos);
+ }
+
+ input_sync(max7360_rotary->input);
+}
+
+static irqreturn_t max7360_rotary_irq(int irq, void *data)
+{
+ struct max7360_rotary *max7360_rotary = data;
+ struct device *dev = max7360_rotary->input->dev.parent;
+ unsigned int val;
+ int error;
+
+ error = regmap_read(max7360_rotary->regmap, MAX7360_REG_RTR_CNT, &val);
+ if (error < 0) {
+ dev_err(dev, "Failed to read rotary counter\n");
+ return IRQ_NONE;
+ }
+
+ if (val == 0)
+ return IRQ_NONE;
+
+ max7360_rotary_report_event(max7360_rotary, sign_extend32(val, 7));
+
+ return IRQ_HANDLED;
+}
+
+static int max7360_rotary_hw_init(struct max7360_rotary *max7360_rotary)
+{
+ struct device *dev = max7360_rotary->input->dev.parent;
+ int val;
+ int error;
+
+ val = FIELD_PREP(MAX7360_ROT_DEBOUNCE, max7360_rotary->debounce_ms) |
+ FIELD_PREP(MAX7360_ROT_INTCNT, 1) | MAX7360_ROT_INTCNT_DLY;
+ error = regmap_write(max7360_rotary->regmap, MAX7360_REG_RTRCFG, val);
+ if (error)
+ dev_err(dev, "Failed to set max7360 rotary encoder configuration\n");
+
+ return error;
+}
+
+static int max7360_rotary_probe(struct platform_device *pdev)
+{
+ struct max7360_rotary *max7360_rotary;
+ struct device *dev = &pdev->dev;
+ struct input_dev *input;
+ struct regmap *regmap;
+ int irq;
+ int error;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return dev_err_probe(dev, -ENODEV, "Could not get parent regmap\n");
+
+ irq = fwnode_irq_get_byname(dev_fwnode(dev->parent), "inti");
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "Failed to get IRQ\n");
+
+ max7360_rotary = devm_kzalloc(dev, sizeof(*max7360_rotary), GFP_KERNEL);
+ if (!max7360_rotary)
+ return -ENOMEM;
+
+ max7360_rotary->regmap = regmap;
+
+ device_property_read_u32(dev->parent, "linux,axis", &max7360_rotary->axis);
+ max7360_rotary->rollover = device_property_read_bool(dev->parent,
+ "rotary-encoder,rollover");
+ max7360_rotary->relative_axis =
+ device_property_read_bool(dev->parent, "rotary-encoder,relative-axis");
+
+ error = device_property_read_u32(dev->parent, "rotary-encoder,steps",
+ &max7360_rotary->steps);
+ if (error)
+ max7360_rotary->steps = MAX7360_ROTARY_DEFAULT_STEPS;
+
+ device_property_read_u32(dev->parent, "rotary-debounce-delay-ms",
+ &max7360_rotary->debounce_ms);
+ if (max7360_rotary->debounce_ms > MAX7360_ROT_DEBOUNCE_MAX)
+ return dev_err_probe(dev, -EINVAL, "Invalid debounce timing: %u\n",
+ max7360_rotary->debounce_ms);
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
+
+ max7360_rotary->input = input;
+
+ input->id.bustype = BUS_I2C;
+ input->name = pdev->name;
+
+ if (max7360_rotary->relative_axis)
+ input_set_capability(input, EV_REL, max7360_rotary->axis);
+ else
+ input_set_abs_params(input, max7360_rotary->axis, 0, max7360_rotary->steps, 0, 1);
+
+ error = devm_request_threaded_irq(dev, irq, NULL, max7360_rotary_irq,
+ IRQF_ONESHOT | IRQF_SHARED,
+ "max7360-rotary", max7360_rotary);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to register interrupt\n");
+
+ error = input_register_device(input);
+ if (error)
+ return dev_err_probe(dev, error, "Could not register input device\n");
+
+ error = max7360_rotary_hw_init(max7360_rotary);
+ if (error)
+ return dev_err_probe(dev, error, "Failed to initialize max7360 rotary\n");
+
+ device_init_wakeup(dev, true);
+ error = dev_pm_set_wake_irq(dev, irq);
+ if (error)
+ dev_warn(dev, "Failed to set up wakeup irq: %d\n", error);
+
+ return 0;
+}
+
+static void max7360_rotary_remove(struct platform_device *pdev)
+{
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+}
+
+static struct platform_driver max7360_rotary_driver = {
+ .driver = {
+ .name = "max7360-rotary",
+ },
+ .probe = max7360_rotary_probe,
+ .remove = max7360_rotary_remove,
+};
+module_platform_driver(max7360_rotary_driver);
+
+MODULE_DESCRIPTION("MAX7360 Rotary driver");
+MODULE_AUTHOR("Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
index 0e646f1b257b..5d45680d74a4 100644
--- a/drivers/input/misc/max77693-haptic.c
+++ b/drivers/input/misc/max77693-haptic.c
@@ -18,11 +18,13 @@
#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <linux/workqueue.h>
#include <linux/regulator/consumer.h>
#include <linux/mfd/max77693.h>
#include <linux/mfd/max77693-common.h>
#include <linux/mfd/max77693-private.h>
+#include <linux/mfd/max77705-private.h>
#include <linux/mfd/max77843-private.h>
#define MAX_MAGNITUDE_SHIFT 16
@@ -66,15 +68,16 @@ struct max77693_haptic {
static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
{
- struct pwm_args pargs;
- int delta;
+ struct pwm_state state;
int error;
- pwm_get_args(haptic->pwm_dev, &pargs);
- delta = (pargs.period + haptic->pwm_duty) / 2;
- error = pwm_config(haptic->pwm_dev, delta, pargs.period);
+ pwm_init_state(haptic->pwm_dev, &state);
+ state.duty_cycle = (state.period + haptic->pwm_duty) / 2;
+
+ error = pwm_apply_might_sleep(haptic->pwm_dev, &state);
if (error) {
- dev_err(haptic->dev, "failed to configure pwm: %d\n", error);
+ dev_err(haptic->dev,
+ "failed to set pwm duty cycle: %d\n", error);
return error;
}
@@ -94,7 +97,7 @@ static int max77843_haptic_bias(struct max77693_haptic *haptic, bool on)
on << MAINCTRL1_BIASEN_SHIFT);
if (error) {
dev_err(haptic->dev, "failed to %s bias: %d\n",
- on ? "enable" : "disable", error);
+ str_enable_disable(on), error);
return error;
}
@@ -115,6 +118,13 @@ static int max77693_haptic_configure(struct max77693_haptic *haptic,
MAX77693_HAPTIC_PWM_DIVISOR_128);
config_reg = MAX77693_HAPTIC_REG_CONFIG2;
break;
+ case TYPE_MAX77705:
+ value = ((haptic->type << MAX77693_CONFIG2_MODE) |
+ (enable << MAX77693_CONFIG2_MEN) |
+ (haptic->mode << MAX77693_CONFIG2_HTYP) |
+ MAX77693_HAPTIC_PWM_DIVISOR_128);
+ config_reg = MAX77705_PMIC_REG_MCONFIG;
+ break;
case TYPE_MAX77843:
value = (haptic->type << MCONFIG_MODE_SHIFT) |
(enable << MCONFIG_MEN_SHIFT) |
@@ -157,12 +167,17 @@ static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable)
static void max77693_haptic_enable(struct max77693_haptic *haptic)
{
+ struct pwm_state state;
int error;
if (haptic->enabled)
return;
- error = pwm_enable(haptic->pwm_dev);
+ pwm_init_state(haptic->pwm_dev, &state);
+ state.duty_cycle = (state.period + haptic->pwm_duty) / 2;
+ state.enabled = true;
+
+ error = pwm_apply_might_sleep(haptic->pwm_dev, &state);
if (error) {
dev_err(haptic->dev,
"failed to enable haptic pwm device: %d\n", error);
@@ -215,18 +230,13 @@ static void max77693_haptic_play_work(struct work_struct *work)
{
struct max77693_haptic *haptic =
container_of(work, struct max77693_haptic, work);
- int error;
- error = max77693_haptic_set_duty_cycle(haptic);
- if (error) {
- dev_err(haptic->dev, "failed to set duty cycle: %d\n", error);
- return;
- }
-
- if (haptic->magnitude)
- max77693_haptic_enable(haptic);
- else
+ if (!haptic->magnitude)
max77693_haptic_disable(haptic);
+ else if (haptic->enabled)
+ max77693_haptic_set_duty_cycle(haptic);
+ else
+ max77693_haptic_enable(haptic);
}
static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
@@ -312,6 +322,7 @@ static int max77693_haptic_probe(struct platform_device *pdev)
case TYPE_MAX77693:
haptic->regmap_haptic = max77693->regmap_haptic;
break;
+ case TYPE_MAX77705:
case TYPE_MAX77843:
haptic->regmap_haptic = max77693->regmap;
break;
@@ -330,12 +341,6 @@ static int max77693_haptic_probe(struct platform_device *pdev)
return PTR_ERR(haptic->pwm_dev);
}
- /*
- * FIXME: pwm_apply_args() should be removed when switching to the
- * atomic PWM API.
- */
- pwm_apply_args(haptic->pwm_dev);
-
haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
if (IS_ERR(haptic->motor_reg)) {
dev_err(&pdev->dev, "failed to get regulator\n");
@@ -407,6 +412,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
static const struct platform_device_id max77693_haptic_id[] = {
{ "max77693-haptic", },
+ { "max77705-haptic", },
{ "max77843-haptic", },
{},
};
@@ -414,6 +420,7 @@ MODULE_DEVICE_TABLE(platform, max77693_haptic_id);
static const struct of_device_id of_max77693_haptic_dt_match[] = {
{ .compatible = "maxim,max77693-haptic", },
+ { .compatible = "maxim,max77705-haptic", },
{ .compatible = "maxim,max77843-haptic", },
{ /* sentinel */ },
};
@@ -432,5 +439,5 @@ module_platform_driver(max77693_haptic_driver);
MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>");
-MODULE_DESCRIPTION("MAXIM 77693/77843 Haptic driver");
+MODULE_DESCRIPTION("MAXIM 77693/77705/77843 Haptic driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c
index 8861a67be575..d5e051a25a74 100644
--- a/drivers/input/misc/max8997_haptic.c
+++ b/drivers/input/misc/max8997_haptic.c
@@ -53,40 +53,30 @@ struct max8997_haptic {
unsigned int pattern_signal_period;
};
-static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
+static void max8997_haptic_set_internal_duty_cycle(struct max8997_haptic *chip)
{
- int ret = 0;
+ u8 duty_index = DIV_ROUND_UP(chip->level * 64, 100);
- if (chip->mode == MAX8997_EXTERNAL_MODE) {
- unsigned int duty = chip->pwm_period * chip->level / 100;
- ret = pwm_config(chip->pwm, duty, chip->pwm_period);
- } else {
- u8 duty_index = 0;
-
- duty_index = DIV_ROUND_UP(chip->level * 64, 100);
-
- switch (chip->internal_mode_pattern) {
- case 0:
- max8997_write_reg(chip->client,
- MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
- break;
- case 1:
- max8997_write_reg(chip->client,
- MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
- break;
- case 2:
- max8997_write_reg(chip->client,
- MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
- break;
- case 3:
- max8997_write_reg(chip->client,
- MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
- break;
- default:
- break;
- }
+ switch (chip->internal_mode_pattern) {
+ case 0:
+ max8997_write_reg(chip->client,
+ MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
+ break;
+ case 1:
+ max8997_write_reg(chip->client,
+ MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
+ break;
+ case 2:
+ max8997_write_reg(chip->client,
+ MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
+ break;
+ case 3:
+ max8997_write_reg(chip->client,
+ MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
+ break;
+ default:
+ break;
}
- return ret;
}
static void max8997_haptic_configure(struct max8997_haptic *chip)
@@ -153,39 +143,49 @@ static void max8997_haptic_enable(struct max8997_haptic *chip)
{
int error;
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
- error = max8997_haptic_set_duty_cycle(chip);
- if (error) {
- dev_err(chip->dev, "set_pwm_cycle failed, error: %d\n", error);
- goto out;
- }
+ if (chip->mode != MAX8997_EXTERNAL_MODE)
+ max8997_haptic_set_internal_duty_cycle(chip);
if (!chip->enabled) {
error = regulator_enable(chip->regulator);
if (error) {
dev_err(chip->dev, "Failed to enable regulator\n");
- goto out;
+ return;
}
max8997_haptic_configure(chip);
- if (chip->mode == MAX8997_EXTERNAL_MODE) {
- error = pwm_enable(chip->pwm);
- if (error) {
- dev_err(chip->dev, "Failed to enable PWM\n");
- regulator_disable(chip->regulator);
- goto out;
- }
+ }
+
+ /*
+ * It would be more straight forward to configure the external PWM
+ * earlier i.e. when the internal duty_cycle is setup in internal mode.
+ * But historically this is done only after the regulator was enabled
+ * and max8997_haptic_configure() set the enable bit in
+ * MAX8997_HAPTIC_REG_CONF2. So better keep it this way.
+ */
+ if (chip->mode == MAX8997_EXTERNAL_MODE) {
+ struct pwm_state state;
+
+ pwm_init_state(chip->pwm, &state);
+ state.period = chip->pwm_period;
+ state.duty_cycle = chip->pwm_period * chip->level / 100;
+ state.enabled = true;
+
+ error = pwm_apply_might_sleep(chip->pwm, &state);
+ if (error) {
+ dev_err(chip->dev, "Failed to enable PWM\n");
+ regulator_disable(chip->regulator);
+ return;
}
- chip->enabled = true;
}
-out:
- mutex_unlock(&chip->mutex);
+ chip->enabled = true;
}
static void max8997_haptic_disable(struct max8997_haptic *chip)
{
- mutex_lock(&chip->mutex);
+ guard(mutex)(&chip->mutex);
if (chip->enabled) {
chip->enabled = false;
@@ -194,8 +194,6 @@ static void max8997_haptic_disable(struct max8997_haptic *chip)
pwm_disable(chip->pwm);
regulator_disable(chip->regulator);
}
-
- mutex_unlock(&chip->mutex);
}
static void max8997_haptic_play_effect_work(struct work_struct *work)
@@ -249,7 +247,7 @@ static int max8997_haptic_probe(struct platform_device *pdev)
return -EINVAL;
}
- chip = kzalloc(sizeof(struct max8997_haptic), GFP_KERNEL);
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
input_dev = input_allocate_device();
if (!chip || !input_dev) {
dev_err(&pdev->dev, "unable to allocate memory\n");
@@ -287,11 +285,6 @@ static int max8997_haptic_probe(struct platform_device *pdev)
goto err_free_mem;
}
- /*
- * FIXME: pwm_apply_args() should be removed when switching to
- * the atomic PWM API.
- */
- pwm_apply_args(chip->pwm);
break;
default:
@@ -389,7 +382,7 @@ static struct platform_driver max8997_haptic_driver = {
.pm = pm_sleep_ptr(&max8997_haptic_pm_ops),
},
.probe = max8997_haptic_probe,
- .remove_new = max8997_haptic_remove,
+ .remove = max8997_haptic_remove,
.id_table = max8997_haptic_id,
};
module_platform_driver(max8997_haptic_driver);
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index 1c8c939638f6..b83d762ae2e9 100644
--- a/drivers/input/misc/mc13783-pwrbutton.c
+++ b/drivers/input/misc/mc13783-pwrbutton.c
@@ -57,7 +57,6 @@ static irqreturn_t button_irq(int irq, void *_priv)
struct mc13783_pwrb *priv = _priv;
int val;
- mc13xxx_irq_ack(priv->mc13783, irq);
mc13xxx_reg_read(priv->mc13783, MC13783_REG_INTERRUPT_SENSE_1, &val);
switch (irq) {
@@ -253,7 +252,7 @@ static void mc13783_pwrbutton_remove(struct platform_device *pdev)
static struct platform_driver mc13783_pwrbutton_driver = {
.probe = mc13783_pwrbutton_probe,
- .remove_new = mc13783_pwrbutton_remove,
+ .remove = mc13783_pwrbutton_remove,
.driver = {
.name = "mc13783-pwrbutton",
},
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 08412239b8e6..0c661140fb88 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -38,6 +38,8 @@
#define MMA8450_CTRL_REG1 0x38
#define MMA8450_CTRL_REG2 0x39
+#define MMA8450_ID 0xc6
+#define MMA8450_WHO_AM_I 0x0f
static int mma8450_read(struct i2c_client *c, unsigned int off)
{
@@ -148,8 +150,20 @@ static void mma8450_close(struct input_dev *input)
*/
static int mma8450_probe(struct i2c_client *c)
{
+ struct i2c_adapter *adapter = c->adapter;
struct input_dev *input;
- int err;
+ int err, client_id;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA))
+ return dev_err_probe(&c->dev, -EINVAL,
+ "I2C adapter doesn't support SMBUS BYTE");
+
+ client_id = i2c_smbus_read_byte_data(c, MMA8450_WHO_AM_I);
+ if (client_id != MMA8450_ID)
+ return dev_err_probe(&c->dev, -EINVAL,
+ "unexpected chip ID 0x%x (vs 0x%x)\n",
+ client_id, MMA8450_ID);
input = devm_input_allocate_device(&c->dev);
if (!input)
diff --git a/drivers/input/misc/nxp-bbnsm-pwrkey.c b/drivers/input/misc/nxp-bbnsm-pwrkey.c
index 1d99206dd3a8..0c7b8f8ef4a5 100644
--- a/drivers/input/misc/nxp-bbnsm-pwrkey.c
+++ b/drivers/input/misc/nxp-bbnsm-pwrkey.c
@@ -38,13 +38,14 @@ struct bbnsm_pwrkey {
int irq;
int keycode;
int keystate; /* 1:pressed */
+ bool suspended;
struct timer_list check_timer;
struct input_dev *input;
};
static void bbnsm_pwrkey_check_for_events(struct timer_list *t)
{
- struct bbnsm_pwrkey *bbnsm = from_timer(bbnsm, t, check_timer);
+ struct bbnsm_pwrkey *bbnsm = timer_container_of(bbnsm, t, check_timer);
struct input_dev *input = bbnsm->input;
u32 state;
@@ -70,6 +71,7 @@ static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
+ struct input_dev *input = bbnsm->input;
u32 event;
regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event);
@@ -78,6 +80,18 @@ static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id)
pm_wakeup_event(bbnsm->input->dev.parent, 0);
+ /*
+ * Directly report key event after resume to make sure key press
+ * event is never missed.
+ */
+ if (bbnsm->suspended) {
+ bbnsm->keystate = 1;
+ input_event(input, EV_KEY, bbnsm->keycode, 1);
+ input_sync(input);
+ /* Fire at most once per suspend/resume cycle */
+ bbnsm->suspended = false;
+ }
+
mod_timer(&bbnsm->check_timer,
jiffies + msecs_to_jiffies(DEBOUNCE_TIME));
@@ -173,6 +187,35 @@ static int bbnsm_pwrkey_probe(struct platform_device *pdev)
return 0;
}
+static void bbnsm_pwrkey_remove(struct platform_device *pdev)
+{
+ dev_pm_clear_wake_irq(&pdev->dev);
+ device_init_wakeup(&pdev->dev, false);
+}
+
+static int __maybe_unused bbnsm_pwrkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
+
+ bbnsm->suspended = true;
+
+ return 0;
+}
+
+static int __maybe_unused bbnsm_pwrkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
+
+ bbnsm->suspended = false;
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(bbnsm_pwrkey_pm_ops, bbnsm_pwrkey_suspend,
+ bbnsm_pwrkey_resume);
+
static const struct of_device_id bbnsm_pwrkey_ids[] = {
{ .compatible = "nxp,imx93-bbnsm-pwrkey" },
{ /* sentinel */ }
@@ -182,9 +225,12 @@ MODULE_DEVICE_TABLE(of, bbnsm_pwrkey_ids);
static struct platform_driver bbnsm_pwrkey_driver = {
.driver = {
.name = "bbnsm_pwrkey",
+ .pm = &bbnsm_pwrkey_pm_ops,
.of_match_table = bbnsm_pwrkey_ids,
},
.probe = bbnsm_pwrkey_probe,
+ .remove = bbnsm_pwrkey_remove,
+
};
module_platform_driver(bbnsm_pwrkey_driver);
diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c
index 06d5972e8e84..39fc451c56e9 100644
--- a/drivers/input/misc/palmas-pwrbutton.c
+++ b/drivers/input/misc/palmas-pwrbutton.c
@@ -310,7 +310,7 @@ MODULE_DEVICE_TABLE(of, of_palmas_pwr_match);
static struct platform_driver palmas_pwron_driver = {
.probe = palmas_pwron_probe,
- .remove_new = palmas_pwron_remove,
+ .remove = palmas_pwron_remove,
.driver = {
.name = "palmas_pwrbutton",
.of_match_table = of_match_ptr(of_palmas_pwr_match),
diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c
index 8a7e9ada5952..fe43fd72ba7b 100644
--- a/drivers/input/misc/pcap_keys.c
+++ b/drivers/input/misc/pcap_keys.c
@@ -49,7 +49,7 @@ static int pcap_keys_probe(struct platform_device *pdev)
struct pcap_keys *pcap_keys;
struct input_dev *input_dev;
- pcap_keys = kmalloc(sizeof(struct pcap_keys), GFP_KERNEL);
+ pcap_keys = kmalloc(sizeof(*pcap_keys), GFP_KERNEL);
if (!pcap_keys)
return err;
@@ -112,7 +112,7 @@ static void pcap_keys_remove(struct platform_device *pdev)
static struct platform_driver pcap_keys_device_driver = {
.probe = pcap_keys_probe,
- .remove_new = pcap_keys_remove,
+ .remove = pcap_keys_remove,
.driver = {
.name = "pcap-keys",
}
diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c
deleted file mode 100644
index c5c5fe236c18..000000000000
--- a/drivers/input/misc/pcf50633-input.c
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/* NXP PCF50633 Input Driver
- *
- * (C) 2006-2008 by Openmoko, Inc.
- * Author: Balaji Rao <balajirrao@openmoko.org>
- * All rights reserved.
- *
- * Broken down from monstrous PCF50633 driver mainly by
- * Harald Welte, Andy Green and Werner Almesberger
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-
-#include <linux/mfd/pcf50633/core.h>
-
-#define PCF50633_OOCSTAT_ONKEY 0x01
-#define PCF50633_REG_OOCSTAT 0x12
-#define PCF50633_REG_OOCMODE 0x10
-
-struct pcf50633_input {
- struct pcf50633 *pcf;
- struct input_dev *input_dev;
-};
-
-static void
-pcf50633_input_irq(int irq, void *data)
-{
- struct pcf50633_input *input;
- int onkey_released;
-
- input = data;
-
- /* We report only one event depending on the key press status */
- onkey_released = pcf50633_reg_read(input->pcf, PCF50633_REG_OOCSTAT)
- & PCF50633_OOCSTAT_ONKEY;
-
- if (irq == PCF50633_IRQ_ONKEYF && !onkey_released)
- input_report_key(input->input_dev, KEY_POWER, 1);
- else if (irq == PCF50633_IRQ_ONKEYR && onkey_released)
- input_report_key(input->input_dev, KEY_POWER, 0);
-
- input_sync(input->input_dev);
-}
-
-static int pcf50633_input_probe(struct platform_device *pdev)
-{
- struct pcf50633_input *input;
- struct input_dev *input_dev;
- int ret;
-
-
- input = kzalloc(sizeof(*input), GFP_KERNEL);
- if (!input)
- return -ENOMEM;
-
- input_dev = input_allocate_device();
- if (!input_dev) {
- kfree(input);
- return -ENOMEM;
- }
-
- platform_set_drvdata(pdev, input);
- input->pcf = dev_to_pcf50633(pdev->dev.parent);
- input->input_dev = input_dev;
-
- input_dev->name = "PCF50633 PMU events";
- input_dev->id.bustype = BUS_I2C;
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_PWR);
- set_bit(KEY_POWER, input_dev->keybit);
-
- ret = input_register_device(input_dev);
- if (ret) {
- input_free_device(input_dev);
- kfree(input);
- return ret;
- }
- pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYR,
- pcf50633_input_irq, input);
- pcf50633_register_irq(input->pcf, PCF50633_IRQ_ONKEYF,
- pcf50633_input_irq, input);
-
- return 0;
-}
-
-static void pcf50633_input_remove(struct platform_device *pdev)
-{
- struct pcf50633_input *input = platform_get_drvdata(pdev);
-
- pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYR);
- pcf50633_free_irq(input->pcf, PCF50633_IRQ_ONKEYF);
-
- input_unregister_device(input->input_dev);
- kfree(input);
-}
-
-static struct platform_driver pcf50633_input_driver = {
- .driver = {
- .name = "pcf50633-input",
- },
- .probe = pcf50633_input_probe,
- .remove_new = pcf50633_input_remove,
-};
-module_platform_driver(pcf50633_input_driver);
-
-MODULE_AUTHOR("Balaji Rao <balajirrao@openmoko.org>");
-MODULE_DESCRIPTION("PCF50633 input driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:pcf50633-input");
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 897854fd245f..0467808402f2 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -127,7 +127,7 @@ static struct platform_driver pcspkr_platform_driver = {
.pm = &pcspkr_pm_ops,
},
.probe = pcspkr_probe,
- .remove_new = pcspkr_remove,
+ .remove = pcspkr_remove,
.shutdown = pcspkr_shutdown,
};
module_platform_driver(pcspkr_platform_driver);
diff --git a/drivers/input/misc/pf1550-onkey.c b/drivers/input/misc/pf1550-onkey.c
new file mode 100644
index 000000000000..9be6377151cb
--- /dev/null
+++ b/drivers/input/misc/pf1550-onkey.c
@@ -0,0 +1,197 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the PF1550 ONKEY
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Portions Copyright (c) 2025 Savoir-faire Linux Inc.
+ * Samuel Kayode <samuel.kayode@savoirfairelinux.com>
+ */
+
+#include <linux/err.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/pf1550.h>
+#include <linux/platform_device.h>
+
+#define PF1550_ONKEY_IRQ_NR 6
+
+struct onkey_drv_data {
+ struct device *dev;
+ const struct pf1550_ddata *pf1550;
+ bool wakeup;
+ struct input_dev *input;
+};
+
+static irqreturn_t pf1550_onkey_irq_handler(int irq, void *data)
+{
+ struct onkey_drv_data *onkey = data;
+ struct platform_device *pdev = to_platform_device(onkey->dev);
+ int i, state, irq_type = -1;
+
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++)
+ if (irq == platform_get_irq(pdev, i))
+ irq_type = i;
+
+ switch (irq_type) {
+ case PF1550_ONKEY_IRQ_PUSHI:
+ state = 0;
+ break;
+ case PF1550_ONKEY_IRQ_1SI:
+ case PF1550_ONKEY_IRQ_2SI:
+ case PF1550_ONKEY_IRQ_3SI:
+ case PF1550_ONKEY_IRQ_4SI:
+ case PF1550_ONKEY_IRQ_8SI:
+ state = 1;
+ break;
+ default:
+ dev_err(onkey->dev, "onkey interrupt: irq %d occurred\n",
+ irq_type);
+ return IRQ_HANDLED;
+ }
+
+ input_event(onkey->input, EV_KEY, KEY_POWER, state);
+ input_sync(onkey->input);
+
+ return IRQ_HANDLED;
+}
+
+static int pf1550_onkey_probe(struct platform_device *pdev)
+{
+ struct onkey_drv_data *onkey;
+ struct input_dev *input;
+ bool key_power = false;
+ int i, irq, error;
+
+ onkey = devm_kzalloc(&pdev->dev, sizeof(*onkey), GFP_KERNEL);
+ if (!onkey)
+ return -ENOMEM;
+
+ onkey->dev = &pdev->dev;
+
+ onkey->pf1550 = dev_get_drvdata(pdev->dev.parent);
+ if (!onkey->pf1550->regmap)
+ return dev_err_probe(&pdev->dev, -ENODEV,
+ "failed to get regmap\n");
+
+ onkey->wakeup = device_property_read_bool(pdev->dev.parent,
+ "wakeup-source");
+
+ if (device_property_read_bool(pdev->dev.parent,
+ "nxp,disable-key-power")) {
+ error = regmap_clear_bits(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_PWRCTRL1,
+ PF1550_ONKEY_RST_EN);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed: disable turn system off");
+ } else {
+ key_power = true;
+ }
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return dev_err_probe(&pdev->dev, -ENOMEM,
+ "failed to allocate the input device\n");
+
+ input->name = pdev->name;
+ input->phys = "pf1550-onkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ if (key_power)
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+ onkey->input = input;
+ platform_set_drvdata(pdev, onkey);
+
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq < 0)
+ return irq;
+
+ error = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ pf1550_onkey_irq_handler,
+ IRQF_NO_SUSPEND,
+ "pf1550-onkey", onkey);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed: irq request (IRQ: %d)\n",
+ i);
+ }
+
+ error = input_register_device(input);
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "failed to register input device\n");
+
+ device_init_wakeup(&pdev->dev, onkey->wakeup);
+
+ return 0;
+}
+
+static int pf1550_onkey_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+ int i, irq;
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI | ONKEY_IRQ_2SI |
+ ONKEY_IRQ_3SI | ONKEY_IRQ_4SI | ONKEY_IRQ_8SI);
+ else
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ enable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static int pf1550_onkey_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct onkey_drv_data *onkey = platform_get_drvdata(pdev);
+ int i, irq;
+
+ if (!device_may_wakeup(&pdev->dev))
+ regmap_write(onkey->pf1550->regmap,
+ PF1550_PMIC_REG_ONKEY_INT_MASK0,
+ ~((u8)(ONKEY_IRQ_PUSHI | ONKEY_IRQ_1SI |
+ ONKEY_IRQ_2SI | ONKEY_IRQ_3SI | ONKEY_IRQ_4SI |
+ ONKEY_IRQ_8SI)));
+ else
+ for (i = 0; i < PF1550_ONKEY_IRQ_NR; i++) {
+ irq = platform_get_irq(pdev, i);
+ if (irq > 0)
+ disable_irq_wake(irq);
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(pf1550_onkey_pm_ops, pf1550_onkey_suspend,
+ pf1550_onkey_resume);
+
+static const struct platform_device_id pf1550_onkey_id[] = {
+ { "pf1550-onkey", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, pf1550_onkey_id);
+
+static struct platform_driver pf1550_onkey_driver = {
+ .driver = {
+ .name = "pf1550-onkey",
+ .pm = pm_sleep_ptr(&pf1550_onkey_pm_ops),
+ },
+ .probe = pf1550_onkey_probe,
+ .id_table = pf1550_onkey_id,
+};
+module_platform_driver(pf1550_onkey_driver);
+
+MODULE_AUTHOR("Freescale Semiconductor");
+MODULE_DESCRIPTION("PF1550 onkey Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/pm8941-pwrkey.c b/drivers/input/misc/pm8941-pwrkey.c
index bab710023d8f..53249d2c081f 100644
--- a/drivers/input/misc/pm8941-pwrkey.c
+++ b/drivers/input/misc/pm8941-pwrkey.c
@@ -60,6 +60,7 @@ struct pm8941_data {
bool supports_ps_hold_poff_config;
bool supports_debounce_config;
bool has_pon_pbs;
+ bool wakeup_source_default;
const char *name;
const char *phys;
};
@@ -154,8 +155,8 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
if (pwrkey->sw_debounce_time_us) {
if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) {
dev_dbg(pwrkey->dev,
- "ignoring key event received before debounce end %llu us\n",
- pwrkey->sw_debounce_end_time);
+ "ignoring key event received before debounce end %lld us\n",
+ ktime_to_us(pwrkey->sw_debounce_end_time));
return IRQ_HANDLED;
}
}
@@ -245,7 +246,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
static int pm8941_pwrkey_probe(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey;
- bool pull_up;
+ bool pull_up, wakeup;
struct device *parent;
struct device_node *regmap_node;
const __be32 *addr;
@@ -402,8 +403,11 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
}
}
+ wakeup = pwrkey->data->wakeup_source_default ||
+ of_property_read_bool(pdev->dev.of_node, "wakeup-source");
+
platform_set_drvdata(pdev, pwrkey);
- device_init_wakeup(&pdev->dev, 1);
+ device_init_wakeup(&pdev->dev, wakeup);
return 0;
}
@@ -424,6 +428,7 @@ static const struct pm8941_data pwrkey_data = {
.supports_ps_hold_poff_config = true,
.supports_debounce_config = true,
.has_pon_pbs = false,
+ .wakeup_source_default = true,
};
static const struct pm8941_data resin_data = {
@@ -434,6 +439,7 @@ static const struct pm8941_data resin_data = {
.supports_ps_hold_poff_config = true,
.supports_debounce_config = true,
.has_pon_pbs = false,
+ .wakeup_source_default = false,
};
static const struct pm8941_data pon_gen3_pwrkey_data = {
@@ -443,6 +449,7 @@ static const struct pm8941_data pon_gen3_pwrkey_data = {
.supports_ps_hold_poff_config = false,
.supports_debounce_config = false,
.has_pon_pbs = true,
+ .wakeup_source_default = true,
};
static const struct pm8941_data pon_gen3_resin_data = {
@@ -452,6 +459,7 @@ static const struct pm8941_data pon_gen3_resin_data = {
.supports_ps_hold_poff_config = false,
.supports_debounce_config = false,
.has_pon_pbs = true,
+ .wakeup_source_default = false,
};
static const struct of_device_id pm8941_pwr_key_id_table[] = {
@@ -465,7 +473,7 @@ MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
static struct platform_driver pm8941_pwrkey_driver = {
.probe = pm8941_pwrkey_probe,
- .remove_new = pm8941_pwrkey_remove,
+ .remove = pm8941_pwrkey_remove,
.driver = {
.name = "pm8941-pwrkey",
.pm = pm_sleep_ptr(&pm8941_pwr_key_pm_ops),
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index db2ba89adaef..ecb92ee5ebbc 100644
--- a/drivers/input/misc/powermate.c
+++ b/drivers/input/misc/powermate.c
@@ -194,22 +194,18 @@ static void powermate_sync_state(struct powermate_device *pm)
static void powermate_config_complete(struct urb *urb)
{
struct powermate_device *pm = urb->context;
- unsigned long flags;
if (urb->status)
printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
- spin_lock_irqsave(&pm->lock, flags);
+ guard(spinlock_irqsave)(&pm->lock);
powermate_sync_state(pm);
- spin_unlock_irqrestore(&pm->lock, flags);
}
/* Set the LED up as described and begin the sync with the hardware if required */
static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
int pulse_table, int pulse_asleep, int pulse_awake)
{
- unsigned long flags;
-
if (pulse_speed < 0)
pulse_speed = 0;
if (pulse_table < 0)
@@ -222,8 +218,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
pulse_asleep = !!pulse_asleep;
pulse_awake = !!pulse_awake;
-
- spin_lock_irqsave(&pm->lock, flags);
+ guard(spinlock_irqsave)(&pm->lock);
/* mark state updates which are required */
if (static_brightness != pm->static_brightness) {
@@ -245,8 +240,6 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
}
powermate_sync_state(pm);
-
- spin_unlock_irqrestore(&pm->lock, flags);
}
/* Callback from the Input layer when an event arrives from userspace to configure the LED */
@@ -320,7 +313,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
0, interface->desc.bInterfaceNumber, NULL, 0,
USB_CTRL_SET_TIMEOUT);
- pm = kzalloc(sizeof(struct powermate_device), GFP_KERNEL);
+ pm = kzalloc(sizeof(*pm), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pm || !input_dev)
goto fail1;
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index 5b9aedf4362f..0e19e97d98ec 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -203,9 +203,9 @@ static int pwm_beeper_suspend(struct device *dev)
* beeper->suspended, but to ensure that pwm_beeper_event
* does not re-submit work once flag is set.
*/
- spin_lock_irq(&beeper->input->event_lock);
- beeper->suspended = true;
- spin_unlock_irq(&beeper->input->event_lock);
+ scoped_guard(spinlock_irq, &beeper->input->event_lock) {
+ beeper->suspended = true;
+ }
pwm_beeper_stop(beeper);
@@ -216,9 +216,9 @@ static int pwm_beeper_resume(struct device *dev)
{
struct pwm_beeper *beeper = dev_get_drvdata(dev);
- spin_lock_irq(&beeper->input->event_lock);
- beeper->suspended = false;
- spin_unlock_irq(&beeper->input->event_lock);
+ scoped_guard(spinlock_irq, &beeper->input->event_lock) {
+ beeper->suspended = false;
+ }
/* Let worker figure out if we should resume beeping */
schedule_work(&beeper->work);
diff --git a/drivers/input/misc/qnap-mcu-input.c b/drivers/input/misc/qnap-mcu-input.c
new file mode 100644
index 000000000000..76e62f0816c1
--- /dev/null
+++ b/drivers/input/misc/qnap-mcu-input.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+/*
+ * Driver for input events on QNAP-MCUs
+ *
+ * Copyright (C) 2024 Heiko Stuebner <heiko@sntech.de>
+ */
+
+#include <linux/input.h>
+#include <linux/mfd/qnap-mcu.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <uapi/linux/input-event-codes.h>
+
+/*
+ * The power-key needs to be pressed for a while to create an event,
+ * so there is no use for overly frequent polling.
+ */
+#define POLL_INTERVAL 500
+
+struct qnap_mcu_input_dev {
+ struct input_dev *input;
+ struct qnap_mcu *mcu;
+ struct device *dev;
+
+ struct work_struct beep_work;
+ int beep_type;
+};
+
+static void qnap_mcu_input_poll(struct input_dev *input)
+{
+ struct qnap_mcu_input_dev *idev = input_get_drvdata(input);
+ static const u8 cmd[] = { '@', 'C', 'V' };
+ u8 reply[4];
+ int state, ret;
+
+ /* poll the power button */
+ ret = qnap_mcu_exec(idev->mcu, cmd, sizeof(cmd), reply, sizeof(reply));
+ if (ret)
+ return;
+
+ /* First bytes must mirror the sent command */
+ if (memcmp(cmd, reply, sizeof(cmd))) {
+ dev_err(idev->dev, "malformed data received\n");
+ return;
+ }
+
+ state = reply[3] - 0x30;
+ input_event(input, EV_KEY, KEY_POWER, state);
+ input_sync(input);
+}
+
+static void qnap_mcu_input_beeper_work(struct work_struct *work)
+{
+ struct qnap_mcu_input_dev *idev =
+ container_of(work, struct qnap_mcu_input_dev, beep_work);
+ const u8 cmd[] = { '@', 'C', (idev->beep_type == SND_TONE) ? '3' : '2' };
+
+ qnap_mcu_exec_with_ack(idev->mcu, cmd, sizeof(cmd));
+}
+
+static int qnap_mcu_input_event(struct input_dev *input, unsigned int type,
+ unsigned int code, int value)
+{
+ struct qnap_mcu_input_dev *idev = input_get_drvdata(input);
+
+ if (type != EV_SND || (code != SND_BELL && code != SND_TONE))
+ return -EOPNOTSUPP;
+
+ if (value < 0)
+ return -EINVAL;
+
+ /* beep runtime is determined by the MCU */
+ if (value == 0)
+ return 0;
+
+ /* Schedule work to actually turn the beeper on */
+ idev->beep_type = code;
+ schedule_work(&idev->beep_work);
+
+ return 0;
+}
+
+static void qnap_mcu_input_close(struct input_dev *input)
+{
+ struct qnap_mcu_input_dev *idev = input_get_drvdata(input);
+
+ cancel_work_sync(&idev->beep_work);
+}
+
+static int qnap_mcu_input_probe(struct platform_device *pdev)
+{
+ struct qnap_mcu *mcu = dev_get_drvdata(pdev->dev.parent);
+ struct qnap_mcu_input_dev *idev;
+ struct device *dev = &pdev->dev;
+ struct input_dev *input;
+ int ret;
+
+ idev = devm_kzalloc(dev, sizeof(*idev), GFP_KERNEL);
+ if (!idev)
+ return -ENOMEM;
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return dev_err_probe(dev, -ENOMEM, "no memory for input device\n");
+
+ idev->input = input;
+ idev->dev = dev;
+ idev->mcu = mcu;
+
+ input_set_drvdata(input, idev);
+
+ input->name = "qnap-mcu";
+ input->phys = "qnap-mcu-input/input0";
+ input->id.bustype = BUS_HOST;
+ input->id.vendor = 0x0001;
+ input->id.product = 0x0001;
+ input->id.version = 0x0100;
+ input->event = qnap_mcu_input_event;
+ input->close = qnap_mcu_input_close;
+
+ input_set_capability(input, EV_KEY, KEY_POWER);
+ input_set_capability(input, EV_SND, SND_BELL);
+ input_set_capability(input, EV_SND, SND_TONE);
+
+ INIT_WORK(&idev->beep_work, qnap_mcu_input_beeper_work);
+
+ ret = input_setup_polling(input, qnap_mcu_input_poll);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to set up polling\n");
+
+ input_set_poll_interval(input, POLL_INTERVAL);
+
+ ret = input_register_device(input);
+ if (ret)
+ return dev_err_probe(dev, ret, "unable to register input device\n");
+
+ return 0;
+}
+
+static struct platform_driver qnap_mcu_input_driver = {
+ .probe = qnap_mcu_input_probe,
+ .driver = {
+ .name = "qnap-mcu-input",
+ },
+};
+module_platform_driver(qnap_mcu_input_driver);
+
+MODULE_ALIAS("platform:qnap-mcu-input");
+MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>");
+MODULE_DESCRIPTION("QNAP MCU input driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c
index 02f73b7c0462..9711f5c7c78a 100644
--- a/drivers/input/misc/regulator-haptic.c
+++ b/drivers/input/misc/regulator-haptic.c
@@ -14,6 +14,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#define MAX_MAGNITUDE_SHIFT 16
@@ -44,7 +45,7 @@ static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on)
if (error) {
dev_err(haptic->dev,
"failed to switch regulator %s: %d\n",
- on ? "on" : "off", error);
+ str_on_off(on), error);
return error;
}
@@ -83,12 +84,10 @@ static void regulator_haptic_work(struct work_struct *work)
struct regulator_haptic *haptic = container_of(work,
struct regulator_haptic, work);
- mutex_lock(&haptic->mutex);
+ guard(mutex)(&haptic->mutex);
if (!haptic->suspended)
regulator_haptic_set_voltage(haptic, haptic->magnitude);
-
- mutex_unlock(&haptic->mutex);
}
static int regulator_haptic_play_effect(struct input_dev *input, void *data,
@@ -205,19 +204,15 @@ static int regulator_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct regulator_haptic *haptic = platform_get_drvdata(pdev);
- int error;
- error = mutex_lock_interruptible(&haptic->mutex);
- if (error)
- return error;
-
- regulator_haptic_set_voltage(haptic, 0);
+ scoped_guard(mutex_intr, &haptic->mutex) {
+ regulator_haptic_set_voltage(haptic, 0);
+ haptic->suspended = true;
- haptic->suspended = true;
-
- mutex_unlock(&haptic->mutex);
+ return 0;
+ }
- return 0;
+ return -EINTR;
}
static int regulator_haptic_resume(struct device *dev)
@@ -226,7 +221,7 @@ static int regulator_haptic_resume(struct device *dev)
struct regulator_haptic *haptic = platform_get_drvdata(pdev);
unsigned int magnitude;
- mutex_lock(&haptic->mutex);
+ guard(mutex)(&haptic->mutex);
haptic->suspended = false;
@@ -234,8 +229,6 @@ static int regulator_haptic_resume(struct device *dev)
if (magnitude)
regulator_haptic_set_voltage(haptic, magnitude);
- mutex_unlock(&haptic->mutex);
-
return 0;
}
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index e94cab8133be..f706e1997417 100644
--- a/drivers/input/misc/rotary_encoder.c
+++ b/drivers/input/misc/rotary_encoder.c
@@ -106,7 +106,7 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
struct rotary_encoder *encoder = dev_id;
unsigned int state;
- mutex_lock(&encoder->access_mutex);
+ guard(mutex)(&encoder->access_mutex);
state = rotary_encoder_get_state(encoder);
@@ -129,8 +129,6 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
break;
}
- mutex_unlock(&encoder->access_mutex);
-
return IRQ_HANDLED;
}
@@ -139,7 +137,7 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
struct rotary_encoder *encoder = dev_id;
unsigned int state;
- mutex_lock(&encoder->access_mutex);
+ guard(mutex)(&encoder->access_mutex);
state = rotary_encoder_get_state(encoder);
@@ -152,8 +150,6 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
}
}
- mutex_unlock(&encoder->access_mutex);
-
return IRQ_HANDLED;
}
@@ -162,22 +158,19 @@ static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
struct rotary_encoder *encoder = dev_id;
unsigned int state;
- mutex_lock(&encoder->access_mutex);
+ guard(mutex)(&encoder->access_mutex);
state = rotary_encoder_get_state(encoder);
- if ((encoder->last_stable + 1) % 4 == state)
+ if ((encoder->last_stable + 1) % 4 == state) {
encoder->dir = 1;
- else if (encoder->last_stable == (state + 1) % 4)
+ rotary_encoder_report_event(encoder);
+ } else if (encoder->last_stable == (state + 1) % 4) {
encoder->dir = -1;
- else
- goto out;
-
- rotary_encoder_report_event(encoder);
+ rotary_encoder_report_event(encoder);
+ }
-out:
encoder->last_stable = state;
- mutex_unlock(&encoder->access_mutex);
return IRQ_HANDLED;
}
diff --git a/drivers/input/misc/sgi_btns.c b/drivers/input/misc/sgi_btns.c
index 0657d785b3cc..39c2882b8e1a 100644
--- a/drivers/input/misc/sgi_btns.c
+++ b/drivers/input/misc/sgi_btns.c
@@ -128,4 +128,5 @@ static struct platform_driver sgi_buttons_driver = {
};
module_platform_driver(sgi_buttons_driver);
+MODULE_DESCRIPTION("SGI Indy/O2 volume button interface driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index f6d060377d18..b8cad415c62c 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -515,7 +515,7 @@ static const struct soc_device_data soc_device_INT33D3 = {
};
/*
- * Button info for Microsoft Surface 3 (non pro), this is indentical to
+ * Button info for Microsoft Surface 3 (non pro), this is identical to
* the PNP0C40 info except that the home button is active-high.
*
* The Surface 3 Pro also has a MSHW0028 ACPI device, but that uses a custom
@@ -612,7 +612,7 @@ MODULE_DEVICE_TABLE(acpi, soc_button_acpi_match);
static struct platform_driver soc_button_driver = {
.probe = soc_button_probe,
- .remove_new = soc_button_remove,
+ .remove = soc_button_remove,
.driver = {
.name = KBUILD_MODNAME,
.acpi_match_table = ACPI_PTR(soc_button_acpi_match),
@@ -620,4 +620,5 @@ static struct platform_driver soc_button_driver = {
};
module_platform_driver(soc_button_driver);
+MODULE_DESCRIPTION("Windows-compatible SoC Button Array driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c
index 20020cbc0752..1cfadd73829f 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -69,15 +69,19 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
struct bbc_beep_info *info = &state->u.bbc;
unsigned int count = 0;
- unsigned long flags;
if (type != EV_SND)
return -1;
switch (code) {
- case SND_BELL: if (value) value = 1000;
- case SND_TONE: break;
- default: return -1;
+ case SND_BELL:
+ if (value)
+ value = 1000;
+ break;
+ case SND_TONE:
+ break;
+ default:
+ return -1;
}
if (value > 20 && value < 32767)
@@ -85,7 +89,7 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
count = bbc_count_to_reg(info, count);
- spin_lock_irqsave(&state->lock, flags);
+ guard(spinlock_irqsave)(&state->lock);
if (count) {
sbus_writeb(0x01, info->regs + 0);
@@ -97,8 +101,6 @@ static int bbc_spkr_event(struct input_dev *dev, unsigned int type, unsigned int
sbus_writeb(0x00, info->regs + 0);
}
- spin_unlock_irqrestore(&state->lock, flags);
-
return 0;
}
@@ -107,21 +109,25 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned
struct sparcspkr_state *state = dev_get_drvdata(dev->dev.parent);
struct grover_beep_info *info = &state->u.grover;
unsigned int count = 0;
- unsigned long flags;
if (type != EV_SND)
return -1;
switch (code) {
- case SND_BELL: if (value) value = 1000;
- case SND_TONE: break;
- default: return -1;
+ case SND_BELL:
+ if (value)
+ value = 1000;
+ break;
+ case SND_TONE:
+ break;
+ default:
+ return -1;
}
if (value > 20 && value < 32767)
count = 1193182 / value;
- spin_lock_irqsave(&state->lock, flags);
+ guard(spinlock_irqsave)(&state->lock);
if (count) {
/* enable counter 2 */
@@ -136,8 +142,6 @@ static int grover_spkr_event(struct input_dev *dev, unsigned int type, unsigned
sbus_writeb(sbus_readb(info->enable_reg) & 0xFC, info->enable_reg);
}
- spin_unlock_irqrestore(&state->lock, flags);
-
return 0;
}
@@ -188,47 +192,38 @@ static int bbc_beep_probe(struct platform_device *op)
{
struct sparcspkr_state *state;
struct bbc_beep_info *info;
- struct device_node *dp;
- int err = -ENOMEM;
+ int err;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = devm_kzalloc(&op->dev, sizeof(*state), GFP_KERNEL);
if (!state)
- goto out_err;
+ return -ENOMEM;
state->name = "Sparc BBC Speaker";
state->event = bbc_spkr_event;
spin_lock_init(&state->lock);
- dp = of_find_node_by_path("/");
- err = -ENODEV;
+ struct device_node *dp __free(device_node) = of_find_node_by_path("/");
if (!dp)
- goto out_free;
+ return -ENODEV;
info = &state->u.bbc;
info->clock_freq = of_getintprop_default(dp, "clock-frequency", 0);
- of_node_put(dp);
if (!info->clock_freq)
- goto out_free;
+ return -ENODEV;
info->regs = of_ioremap(&op->resource[0], 0, 6, "bbc beep");
if (!info->regs)
- goto out_free;
+ return -ENODEV;
platform_set_drvdata(op, state);
err = sparcspkr_probe(&op->dev);
- if (err)
- goto out_clear_drvdata;
+ if (err) {
+ of_iounmap(&op->resource[0], info->regs, 6);
+ return err;
+ }
return 0;
-
-out_clear_drvdata:
- of_iounmap(&op->resource[0], info->regs, 6);
-
-out_free:
- kfree(state);
-out_err:
- return err;
}
static void bbc_remove(struct platform_device *op)
@@ -243,8 +238,6 @@ static void bbc_remove(struct platform_device *op)
input_unregister_device(input_dev);
of_iounmap(&op->resource[0], info->regs, 6);
-
- kfree(state);
}
static const struct of_device_id bbc_beep_match[] = {
@@ -262,7 +255,7 @@ static struct platform_driver bbc_beep_driver = {
.of_match_table = bbc_beep_match,
},
.probe = bbc_beep_probe,
- .remove_new = bbc_remove,
+ .remove = bbc_remove,
.shutdown = sparcspkr_shutdown,
};
@@ -272,9 +265,9 @@ static int grover_beep_probe(struct platform_device *op)
struct grover_beep_info *info;
int err = -ENOMEM;
- state = kzalloc(sizeof(*state), GFP_KERNEL);
+ state = devm_kzalloc(&op->dev, sizeof(*state), GFP_KERNEL);
if (!state)
- goto out_err;
+ return err;
state->name = "Sparc Grover Speaker";
state->event = grover_spkr_event;
@@ -283,7 +276,7 @@ static int grover_beep_probe(struct platform_device *op)
info = &state->u.grover;
info->freq_regs = of_ioremap(&op->resource[2], 0, 2, "grover beep freq");
if (!info->freq_regs)
- goto out_free;
+ return err;
info->enable_reg = of_ioremap(&op->resource[3], 0, 1, "grover beep enable");
if (!info->enable_reg)
@@ -302,9 +295,7 @@ out_clear_drvdata:
out_unmap_freq_regs:
of_iounmap(&op->resource[2], info->freq_regs, 2);
-out_free:
- kfree(state);
-out_err:
+
return err;
}
@@ -321,8 +312,6 @@ static void grover_remove(struct platform_device *op)
of_iounmap(&op->resource[3], info->enable_reg, 1);
of_iounmap(&op->resource[2], info->freq_regs, 2);
-
- kfree(state);
}
static const struct of_device_id grover_beep_match[] = {
@@ -340,7 +329,7 @@ static struct platform_driver grover_beep_driver = {
.of_match_table = grover_beep_match,
},
.probe = grover_beep_probe,
- .remove_new = grover_remove,
+ .remove = grover_remove,
.shutdown = sparcspkr_shutdown,
};
diff --git a/drivers/input/misc/tps65219-pwrbutton.c b/drivers/input/misc/tps65219-pwrbutton.c
index eeb9f2334ab4..7a58bae4f1a0 100644
--- a/drivers/input/misc/tps65219-pwrbutton.c
+++ b/drivers/input/misc/tps65219-pwrbutton.c
@@ -137,7 +137,7 @@ MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table);
static struct platform_driver tps65219_pb_driver = {
.probe = tps65219_pb_probe,
- .remove_new = tps65219_pb_remove,
+ .remove = tps65219_pb_remove,
.driver = {
.name = "tps65219_pwrbutton",
},
diff --git a/drivers/input/misc/tps6594-pwrbutton.c b/drivers/input/misc/tps6594-pwrbutton.c
new file mode 100644
index 000000000000..cd039b3866dc
--- /dev/null
+++ b/drivers/input/misc/tps6594-pwrbutton.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * power button driver for TI TPS6594 PMICs
+ *
+ * Copyright (C) 2025 Critical Link LLC - https://www.criticallink.com/
+ */
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps6594.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct tps6594_pwrbutton {
+ struct device *dev;
+ struct input_dev *idev;
+ char phys[32];
+};
+
+static irqreturn_t tps6594_pb_push_irq(int irq, void *_pwr)
+{
+ struct tps6594_pwrbutton *pwr = _pwr;
+
+ input_report_key(pwr->idev, KEY_POWER, 1);
+ pm_wakeup_event(pwr->dev, 0);
+ input_sync(pwr->idev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t tps6594_pb_release_irq(int irq, void *_pwr)
+{
+ struct tps6594_pwrbutton *pwr = _pwr;
+
+ input_report_key(pwr->idev, KEY_POWER, 0);
+ input_sync(pwr->idev);
+
+ return IRQ_HANDLED;
+}
+
+static int tps6594_pb_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct tps6594_pwrbutton *pwr;
+ struct input_dev *idev;
+ int error;
+ int push_irq;
+ int release_irq;
+
+ pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
+ if (!pwr)
+ return -ENOMEM;
+
+ idev = devm_input_allocate_device(dev);
+ if (!idev)
+ return -ENOMEM;
+
+ idev->name = pdev->name;
+ snprintf(pwr->phys, sizeof(pwr->phys), "%s/input0",
+ pdev->name);
+ idev->phys = pwr->phys;
+ idev->id.bustype = BUS_I2C;
+
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ pwr->dev = dev;
+ pwr->idev = idev;
+ device_init_wakeup(dev, true);
+
+ push_irq = platform_get_irq(pdev, 0);
+ if (push_irq < 0)
+ return -EINVAL;
+
+ release_irq = platform_get_irq(pdev, 1);
+ if (release_irq < 0)
+ return -EINVAL;
+
+ error = devm_request_threaded_irq(dev, push_irq, NULL,
+ tps6594_pb_push_irq,
+ IRQF_ONESHOT,
+ pdev->resource[0].name, pwr);
+ if (error) {
+ dev_err(dev, "failed to request push IRQ #%d: %d\n", push_irq,
+ error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, release_irq, NULL,
+ tps6594_pb_release_irq,
+ IRQF_ONESHOT,
+ pdev->resource[1].name, pwr);
+ if (error) {
+ dev_err(dev, "failed to request release IRQ #%d: %d\n",
+ release_irq, error);
+ return error;
+ }
+
+ error = input_register_device(idev);
+ if (error) {
+ dev_err(dev, "Can't register power button: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id tps6594_pwrbtn_id_table[] = {
+ { "tps6594-pwrbutton", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps6594_pwrbtn_id_table);
+
+static struct platform_driver tps6594_pb_driver = {
+ .probe = tps6594_pb_probe,
+ .driver = {
+ .name = "tps6594_pwrbutton",
+ },
+ .id_table = tps6594_pwrbtn_id_table,
+};
+module_platform_driver(tps6594_pb_driver);
+
+MODULE_DESCRIPTION("TPS6594 Power Button");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/twl4030-pwrbutton.c b/drivers/input/misc/twl4030-pwrbutton.c
index e3ee0638ffba..f85cc289c053 100644
--- a/drivers/input/misc/twl4030-pwrbutton.c
+++ b/drivers/input/misc/twl4030-pwrbutton.c
@@ -1,5 +1,5 @@
-/**
- * twl4030-pwrbutton.c - TWL4030 Power Button Input Driver
+/*
+ * TWL4030 Power Button Input Driver
*
* Copyright (C) 2008-2009 Nokia Corporation
*
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index 101548b35ee3..5fa7d4a7da36 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -165,15 +165,10 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
static bool twl4030_vibra_check_coexist(struct device_node *parent)
{
- struct device_node *node;
+ struct device_node *node __free(device_node) =
+ of_get_child_by_name(parent, "codec");
- node = of_get_child_by_name(parent, "codec");
- if (node) {
- of_node_put(node);
- return true;
- }
-
- return false;
+ return node != NULL;
}
static int twl4030_vibra_probe(struct platform_device *pdev)
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index 78f0b63e5c20..afed9af65bf9 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -229,14 +229,13 @@ static DEFINE_SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops,
static int twl6040_vibra_probe(struct platform_device *pdev)
{
struct device *twl6040_core_dev = pdev->dev.parent;
- struct device_node *twl6040_core_node;
struct vibra_info *info;
int vddvibl_uV = 0;
int vddvibr_uV = 0;
int error;
- twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node,
- "vibra");
+ struct device_node *twl6040_core_node __free(device_node) =
+ of_get_child_by_name(twl6040_core_dev->of_node, "vibra");
if (!twl6040_core_node) {
dev_err(&pdev->dev, "parent of node is missing?\n");
return -EINVAL;
@@ -244,7 +243,6 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info) {
- of_node_put(twl6040_core_node);
dev_err(&pdev->dev, "couldn't allocate memory\n");
return -ENOMEM;
}
@@ -264,8 +262,6 @@ static int twl6040_vibra_probe(struct platform_device *pdev)
of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", &vddvibl_uV);
of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", &vddvibr_uV);
- of_node_put(twl6040_core_node);
-
if ((!info->vibldrv_res && !info->viblmotor_res) ||
(!info->vibrdrv_res && !info->vibrmotor_res)) {
dev_err(info->dev, "invalid vibra driver/motor resistance\n");
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index d98212d55108..13336a2fd49c 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -379,7 +379,7 @@ static int uinput_open(struct inode *inode, struct file *file)
{
struct uinput_device *newdev;
- newdev = kzalloc(sizeof(struct uinput_device), GFP_KERNEL);
+ newdev = kzalloc(sizeof(*newdev), GFP_KERNEL);
if (!newdev)
return -ENOMEM;
@@ -417,6 +417,20 @@ static int uinput_validate_absinfo(struct input_dev *dev, unsigned int code,
return -EINVAL;
}
+ /*
+ * Limit number of contacts to a reasonable value (100). This
+ * ensures that we need less than 2 pages for struct input_mt
+ * (we are not using in-kernel slot assignment so not going to
+ * allocate memory for the "red" table), and we should have no
+ * trouble getting this much memory.
+ */
+ if (code == ABS_MT_SLOT && max > 99) {
+ printk(KERN_DEBUG
+ "%s: unreasonably large number of slots requested: %d\n",
+ UINPUT_NAME, max);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -761,6 +775,7 @@ static int uinput_ff_upload_to_user(char __user *buffer,
if (in_compat_syscall()) {
struct uinput_ff_upload_compat ff_up_compat;
+ memset(&ff_up_compat, 0, sizeof(ff_up_compat));
ff_up_compat.request_id = ff_up->request_id;
ff_up_compat.retval = ff_up->retval;
/*
@@ -1118,7 +1133,6 @@ static const struct file_operations uinput_fops = {
#ifdef CONFIG_COMPAT
.compat_ioctl = uinput_compat_ioctl,
#endif
- .llseek = no_llseek,
};
static struct miscdevice uinput_misc = {
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index 5c4956678cd0..1b2bd2139aaa 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -271,7 +271,7 @@ static struct key_entry keymap_fs_amilo_pro_v8210[] __initdata = {
{ KE_BLUETOOTH, 0x30 }, /* Fn+F10 */
{ KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */
{ KE_KEY, 0x36, {KEY_WWW} }, /* www button */
- { KE_WIFI, 0x78 }, /* satelite dish button */
+ { KE_WIFI, 0x78 }, /* satellite dish button */
{ KE_END, FE_WIFI_LED }
};
@@ -990,8 +990,8 @@ static int __init copy_keymap(void)
for (key = keymap; key->type != KE_END; key++)
length++;
- new_keymap = kmemdup(keymap, length * sizeof(struct key_entry),
- GFP_KERNEL);
+ new_keymap = kmemdup_array(keymap, length, sizeof(struct key_entry),
+ GFP_KERNEL);
if (!new_keymap)
return -ENOMEM;
@@ -1075,7 +1075,7 @@ static void wistron_led_init(struct device *parent)
}
if (leds_present & FE_MAIL_LED) {
- /* bios_get_default_setting(MAIL) always retuns 0, so just turn the led off */
+ /* bios_get_default_setting(MAIL) always returns 0, so just turn the led off */
wistron_mail_led.brightness = LED_OFF;
if (led_classdev_register(parent, &wistron_mail_led))
leds_present &= ~FE_MAIL_LED;
@@ -1334,7 +1334,7 @@ static struct platform_driver wistron_driver = {
.pm = pm_sleep_ptr(&wistron_pm_ops),
},
.probe = wistron_probe,
- .remove_new = wistron_remove,
+ .remove = wistron_remove,
};
static int __init wb_module_init(void)
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index e4a06c73b72d..18eb319bc6f7 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -134,7 +134,7 @@ static void wm831x_on_remove(struct platform_device *pdev)
static struct platform_driver wm831x_on_driver = {
.probe = wm831x_on_probe,
- .remove_new = wm831x_on_remove,
+ .remove = wm831x_on_remove,
.driver = {
.name = "wm831x-on",
},
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 69420781db30..08dc53ae1b3c 100644
--- a/drivers/input/misc/yealink.c
+++ b/drivers/input/misc/yealink.c
@@ -36,7 +36,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <linux/rwsem.h>
+#include <linux/mutex.h>
#include <linux/usb/input.h>
#include <linux/map_to_7segment.h>
@@ -103,6 +103,8 @@ struct yealink_dev {
u8 lcdMap[ARRAY_SIZE(lcdMap)]; /* state of LCD, LED ... */
int key_code; /* last reported key */
+ struct mutex sysfs_mutex;
+
unsigned int shutdown:1;
int stat_ix;
@@ -375,7 +377,7 @@ send_update:
if (len > sizeof(yld->ctl_data->data))
len = sizeof(yld->ctl_data->data);
- /* Combine up to <len> consecutive LCD bytes in a singe request
+ /* Combine up to <len> consecutive LCD bytes in a single request
*/
yld->ctl_data->cmd = CMD_LCD;
yld->ctl_data->offset = cpu_to_be16(ix);
@@ -548,8 +550,6 @@ static void input_close(struct input_dev *dev)
* sysfs interface
******************************************************************************/
-static DECLARE_RWSEM(sysfs_rwsema);
-
/* Interface to the 7-segments translation table aka. char set.
*/
static ssize_t show_map(struct device *dev, struct device_attribute *attr,
@@ -580,15 +580,10 @@ static ssize_t store_map(struct device *dev, struct device_attribute *attr,
*/
static ssize_t show_line(struct device *dev, char *buf, int a, int b)
{
- struct yealink_dev *yld;
+ struct yealink_dev *yld = dev_get_drvdata(dev);
int i;
- down_read(&sysfs_rwsema);
- yld = dev_get_drvdata(dev);
- if (yld == NULL) {
- up_read(&sysfs_rwsema);
- return -ENODEV;
- }
+ guard(mutex)(&yld->sysfs_mutex);
for (i = a; i < b; i++)
*buf++ = lcdMap[i].type;
@@ -598,7 +593,6 @@ static ssize_t show_line(struct device *dev, char *buf, int a, int b)
*buf++ = '\n';
*buf = 0;
- up_read(&sysfs_rwsema);
return 3 + ((b - a) << 1);
}
@@ -620,7 +614,7 @@ static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
return show_line(dev, buf, LCD_LINE3_OFFSET, LCD_LINE4_OFFSET);
}
-/* Writing to /sys/../lineX will set the coresponding LCD line.
+/* Writing to /sys/../lineX will set the corresponding LCD line.
* - Excess characters are ignored.
* - If less characters are written than allowed, the remaining digits are
* unchanged.
@@ -630,22 +624,16 @@ static ssize_t show_line3(struct device *dev, struct device_attribute *attr,
static ssize_t store_line(struct device *dev, const char *buf, size_t count,
int el, size_t len)
{
- struct yealink_dev *yld;
+ struct yealink_dev *yld = dev_get_drvdata(dev);
int i;
- down_write(&sysfs_rwsema);
- yld = dev_get_drvdata(dev);
- if (yld == NULL) {
- up_write(&sysfs_rwsema);
- return -ENODEV;
- }
+ guard(mutex)(&yld->sysfs_mutex);
if (len > count)
len = count;
for (i = 0; i < len; i++)
setChar(yld, el++, buf[i]);
- up_write(&sysfs_rwsema);
return count;
}
@@ -675,15 +663,10 @@ static ssize_t store_line3(struct device *dev, struct device_attribute *attr,
static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
char *buf)
{
- struct yealink_dev *yld;
+ struct yealink_dev *yld = dev_get_drvdata(dev);
int i, ret = 1;
- down_read(&sysfs_rwsema);
- yld = dev_get_drvdata(dev);
- if (yld == NULL) {
- up_read(&sysfs_rwsema);
- return -ENODEV;
- }
+ guard(mutex)(&yld->sysfs_mutex);
for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
if (lcdMap[i].type != '.')
@@ -692,7 +675,7 @@ static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
yld->lcdMap[i] == ' ' ? " " : "on",
lcdMap[i].u.p.name);
}
- up_read(&sysfs_rwsema);
+
return ret;
}
@@ -700,15 +683,10 @@ static ssize_t get_icons(struct device *dev, struct device_attribute *attr,
static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
int chr)
{
- struct yealink_dev *yld;
+ struct yealink_dev *yld = dev_get_drvdata(dev);
int i;
- down_write(&sysfs_rwsema);
- yld = dev_get_drvdata(dev);
- if (yld == NULL) {
- up_write(&sysfs_rwsema);
- return -ENODEV;
- }
+ guard(mutex)(&yld->sysfs_mutex);
for (i = 0; i < ARRAY_SIZE(lcdMap); i++) {
if (lcdMap[i].type != '.')
@@ -719,7 +697,6 @@ static ssize_t set_icon(struct device *dev, const char *buf, size_t count,
}
}
- up_write(&sysfs_rwsema);
return count;
}
@@ -739,22 +716,16 @@ static ssize_t hide_icon(struct device *dev, struct device_attribute *attr,
*/
/* Stores raw ringtone data in the phone */
-static ssize_t store_ringtone(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t store_ringtone(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
- struct yealink_dev *yld;
+ struct yealink_dev *yld = dev_get_drvdata(dev);
- down_write(&sysfs_rwsema);
- yld = dev_get_drvdata(dev);
- if (yld == NULL) {
- up_write(&sysfs_rwsema);
- return -ENODEV;
- }
+ guard(mutex)(&yld->sysfs_mutex);
/* TODO locking with async usb control interface??? */
yealink_set_ringtone(yld, (char *)buf, count);
- up_write(&sysfs_rwsema);
+
return count;
}
@@ -771,7 +742,7 @@ static DEVICE_ATTR(show_icon , _M220, NULL , show_icon );
static DEVICE_ATTR(hide_icon , _M220, NULL , hide_icon );
static DEVICE_ATTR(ringtone , _M220, NULL , store_ringtone);
-static struct attribute *yld_attributes[] = {
+static struct attribute *yld_attrs[] = {
&dev_attr_line1.attr,
&dev_attr_line2.attr,
&dev_attr_line3.attr,
@@ -782,10 +753,7 @@ static struct attribute *yld_attributes[] = {
&dev_attr_ringtone.attr,
NULL
};
-
-static const struct attribute_group yld_attr_group = {
- .attrs = yld_attributes
-};
+ATTRIBUTE_GROUPS(yld);
/*******************************************************************************
* Linux interface and usb initialisation
@@ -838,15 +806,10 @@ static int usb_cleanup(struct yealink_dev *yld, int err)
static void usb_disconnect(struct usb_interface *intf)
{
- struct yealink_dev *yld;
-
- down_write(&sysfs_rwsema);
- yld = usb_get_intfdata(intf);
- sysfs_remove_group(&intf->dev.kobj, &yld_attr_group);
- usb_set_intfdata(intf, NULL);
- up_write(&sysfs_rwsema);
+ struct yealink_dev *yld = usb_get_intfdata(intf);
usb_cleanup(yld, 0);
+ usb_set_intfdata(intf, NULL);
}
static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -868,12 +831,13 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
- yld = kzalloc(sizeof(struct yealink_dev), GFP_KERNEL);
+ yld = kzalloc(sizeof(*yld), GFP_KERNEL);
if (!yld)
return -ENOMEM;
yld->udev = udev;
yld->intf = intf;
+ mutex_init(&yld->sysfs_mutex);
yld->idev = input_dev = input_allocate_device();
if (!input_dev)
@@ -975,8 +939,6 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
store_line3(&intf->dev, NULL,
DRIVER_VERSION, sizeof(DRIVER_VERSION));
- /* Register sysfs hooks (don't care about failure) */
- ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
return 0;
}
@@ -985,6 +947,7 @@ static struct usb_driver yealink_driver = {
.probe = usb_probe,
.disconnect = usb_disconnect,
.id_table = usb_table,
+ .dev_groups = yld_groups,
};
module_usb_driver(yealink_driver);
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index e2c11d9f3868..d0cb9fb94821 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -1396,29 +1396,21 @@ static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
static DEFINE_MUTEX(alps_mutex);
-static void alps_register_bare_ps2_mouse(struct work_struct *work)
+static int alps_do_register_bare_ps2_mouse(struct alps_data *priv)
{
- struct alps_data *priv =
- container_of(work, struct alps_data, dev3_register_work.work);
struct psmouse *psmouse = priv->psmouse;
struct input_dev *dev3;
- int error = 0;
-
- mutex_lock(&alps_mutex);
-
- if (priv->dev3)
- goto out;
+ int error;
dev3 = input_allocate_device();
if (!dev3) {
psmouse_err(psmouse, "failed to allocate secondary device\n");
- error = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
- snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s",
- psmouse->ps2dev.serio->phys,
- (priv->dev2 ? "input2" : "input1"));
+ scnprintf(priv->phys3, sizeof(priv->phys3), "%s/%s",
+ psmouse->ps2dev.serio->phys,
+ (priv->dev2 ? "input2" : "input1"));
dev3->phys = priv->phys3;
/*
@@ -1446,21 +1438,35 @@ static void alps_register_bare_ps2_mouse(struct work_struct *work)
psmouse_err(psmouse,
"failed to register secondary device: %d\n",
error);
- input_free_device(dev3);
- goto out;
+ goto err_free_input;
}
priv->dev3 = dev3;
+ return 0;
-out:
- /*
- * Save the error code so that we can detect that we
- * already tried to create the device.
- */
- if (error)
- priv->dev3 = ERR_PTR(error);
+err_free_input:
+ input_free_device(dev3);
+ return error;
+}
- mutex_unlock(&alps_mutex);
+static void alps_register_bare_ps2_mouse(struct work_struct *work)
+{
+ struct alps_data *priv = container_of(work, struct alps_data,
+ dev3_register_work.work);
+ int error;
+
+ guard(mutex)(&alps_mutex);
+
+ if (!priv->dev3) {
+ error = alps_do_register_bare_ps2_mouse(priv);
+ if (error) {
+ /*
+ * Save the error code so that we can detect that we
+ * already tried to create the device.
+ */
+ priv->dev3 = ERR_PTR(error);
+ }
+ }
}
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
@@ -1513,7 +1519,7 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
return PSMOUSE_GOOD_DATA;
}
- del_timer(&priv->timer);
+ timer_delete(&priv->timer);
if (psmouse->packet[6] & 0x80) {
@@ -1576,10 +1582,10 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
static void alps_flush_packet(struct timer_list *t)
{
- struct alps_data *priv = from_timer(priv, t, timer);
+ struct alps_data *priv = timer_container_of(priv, t, timer);
struct psmouse *psmouse = priv->psmouse;
- serio_pause_rx(psmouse->ps2dev.serio);
+ guard(serio_pause_rx)(psmouse->ps2dev.serio);
if (psmouse->pktcnt == psmouse->pktsize) {
@@ -1599,8 +1605,6 @@ static void alps_flush_packet(struct timer_list *t)
}
psmouse->pktcnt = 0;
}
-
- serio_continue_rx(psmouse->ps2dev.serio);
}
static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
@@ -3099,8 +3103,8 @@ int alps_init(struct psmouse *psmouse)
goto init_fail;
}
- snprintf(priv->phys2, sizeof(priv->phys2), "%s/input1",
- psmouse->ps2dev.serio->phys);
+ scnprintf(priv->phys2, sizeof(priv->phys2), "%s/input1",
+ psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys2;
/*
@@ -3201,7 +3205,7 @@ int alps_detect(struct psmouse *psmouse, bool set_properties)
*/
psmouse_reset(psmouse);
- priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 2fbbaeb76d70..d203c2a6c438 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -139,7 +139,7 @@ static void __exit amimouse_remove(struct platform_device *pdev)
* triggering a section mismatch warning.
*/
static struct platform_driver amimouse_driver __refdata = {
- .remove_new = __exit_p(amimouse_remove),
+ .remove = __exit_p(amimouse_remove),
.driver = {
.name = "amiga-mouse",
},
diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c
index 627048bc6a12..e669f86f1882 100644
--- a/drivers/input/mouse/appletouch.c
+++ b/drivers/input/mouse/appletouch.c
@@ -855,7 +855,7 @@ static int atp_probe(struct usb_interface *iface,
}
/* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(struct atp), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
dev_err(&iface->dev, "Out of memory\n");
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index ca150618d32f..dfdfb59cc8b5 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -834,13 +834,11 @@ static int bcm5974_open(struct input_dev *input)
if (error)
return error;
- mutex_lock(&dev->pm_mutex);
-
- error = bcm5974_start_traffic(dev);
- if (!error)
- dev->opened = 1;
-
- mutex_unlock(&dev->pm_mutex);
+ scoped_guard(mutex, &dev->pm_mutex) {
+ error = bcm5974_start_traffic(dev);
+ if (!error)
+ dev->opened = 1;
+ }
if (error)
usb_autopm_put_interface(dev->intf);
@@ -852,12 +850,10 @@ static void bcm5974_close(struct input_dev *input)
{
struct bcm5974 *dev = input_get_drvdata(input);
- mutex_lock(&dev->pm_mutex);
-
- bcm5974_pause_traffic(dev);
- dev->opened = 0;
-
- mutex_unlock(&dev->pm_mutex);
+ scoped_guard(mutex, &dev->pm_mutex) {
+ bcm5974_pause_traffic(dev);
+ dev->opened = 0;
+ }
usb_autopm_put_interface(dev->intf);
}
@@ -866,29 +862,24 @@ static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
- mutex_lock(&dev->pm_mutex);
+ guard(mutex)(&dev->pm_mutex);
if (dev->opened)
bcm5974_pause_traffic(dev);
- mutex_unlock(&dev->pm_mutex);
-
return 0;
}
static int bcm5974_resume(struct usb_interface *iface)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
- int error = 0;
- mutex_lock(&dev->pm_mutex);
+ guard(mutex)(&dev->pm_mutex);
if (dev->opened)
- error = bcm5974_start_traffic(dev);
+ return bcm5974_start_traffic(dev);
- mutex_unlock(&dev->pm_mutex);
-
- return error;
+ return 0;
}
static int bcm5974_probe(struct usb_interface *iface,
@@ -904,7 +895,7 @@ static int bcm5974_probe(struct usb_interface *iface,
cfg = bcm5974_get_config(udev);
/* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
dev_err(&iface->dev, "out of memory\n");
diff --git a/drivers/input/mouse/byd.c b/drivers/input/mouse/byd.c
index 221a553f45cd..71aa23dd7d8d 100644
--- a/drivers/input/mouse/byd.c
+++ b/drivers/input/mouse/byd.c
@@ -251,16 +251,15 @@ static void byd_report_input(struct psmouse *psmouse)
static void byd_clear_touch(struct timer_list *t)
{
- struct byd_data *priv = from_timer(priv, t, timer);
+ struct byd_data *priv = timer_container_of(priv, t, timer);
struct psmouse *psmouse = priv->psmouse;
- serio_pause_rx(psmouse->ps2dev.serio);
+ guard(serio_pause_rx)(psmouse->ps2dev.serio);
+
priv->touch = false;
byd_report_input(psmouse);
- serio_continue_rx(psmouse->ps2dev.serio);
-
/*
* Move cursor back to center of pad when we lose touch - this
* specifically improves user experience when moving cursor with one
@@ -426,7 +425,7 @@ static void byd_disconnect(struct psmouse *psmouse)
struct byd_data *priv = psmouse->private;
if (priv) {
- del_timer(&priv->timer);
+ timer_delete(&priv->timer);
kfree(psmouse->private);
psmouse->private = NULL;
}
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 2f2d925a55d7..00c87c0532a6 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -1080,8 +1080,8 @@ static ssize_t cyapa_update_fw_store(struct device *dev,
char fw_name[NAME_MAX];
int ret, error;
- if (count >= NAME_MAX) {
- dev_err(dev, "File name too long\n");
+ if (!count || count >= NAME_MAX) {
+ dev_err(dev, "Bad file name size\n");
return -EINVAL;
}
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
index 60c83bc71d84..fc3fb954523b 100644
--- a/drivers/input/mouse/cyapa_gen3.c
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -20,7 +20,7 @@
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "cyapa.h"
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
index 2e6bcb07257e..3b4439f10635 100644
--- a/drivers/input/mouse/cyapa_gen5.c
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -17,7 +17,7 @@
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/crc-itu-t.h>
#include <linux/pm_runtime.h>
#include "cyapa.h"
diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c
index 4ffe08fee10c..570c06dcef78 100644
--- a/drivers/input/mouse/cyapa_gen6.c
+++ b/drivers/input/mouse/cyapa_gen6.c
@@ -17,7 +17,7 @@
#include <linux/mutex.h>
#include <linux/completion.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/crc-itu-t.h>
#include "cyapa.h"
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index d272f1ec27ba..9446657a5f35 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -32,33 +32,30 @@ static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n)
cytp->pkt_size = n;
}
-static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200};
-static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
+static const u8 cytp_rate[] = {10, 20, 40, 60, 100, 200};
+static const u8 cytp_resolution[] = {0x00, 0x01, 0x02, 0x03};
-static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value)
+static int cypress_ps2_sendbyte(struct psmouse *psmouse, u8 cmd)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
+ int error;
- if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) {
+ error = ps2_sendbyte(ps2dev, cmd, CYTP_CMD_TIMEOUT);
+ if (error) {
psmouse_dbg(psmouse,
- "sending command 0x%02x failed, resp 0x%02x\n",
- value & 0xff, ps2dev->nak);
- if (ps2dev->nak == CYTP_PS2_RETRY)
- return CYTP_PS2_RETRY;
- else
- return CYTP_PS2_ERROR;
+ "sending command 0x%02x failed, resp 0x%02x, error %d\n",
+ cmd, ps2dev->nak, error);
+ return error;
}
#ifdef CYTP_DEBUG_VERBOSE
- psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n",
- value & 0xff);
+ psmouse_dbg(psmouse, "sending command 0x%02x succeeded\n", cmd);
#endif
return 0;
}
-static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
- unsigned char data)
+static int cypress_ps2_ext_cmd(struct psmouse *psmouse, u8 prefix, u8 nibble)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int tries = CYTP_PS2_CMD_TRIES;
@@ -72,71 +69,29 @@ static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd,
* If sending the command fails, send recovery command
* to make the device return to the ready state.
*/
- rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff);
- if (rc == CYTP_PS2_RETRY) {
+ rc = cypress_ps2_sendbyte(psmouse, prefix);
+ if (rc == -EAGAIN) {
rc = cypress_ps2_sendbyte(psmouse, 0x00);
- if (rc == CYTP_PS2_RETRY)
+ if (rc == -EAGAIN)
rc = cypress_ps2_sendbyte(psmouse, 0x0a);
}
- if (rc == CYTP_PS2_ERROR)
- continue;
-
- rc = cypress_ps2_sendbyte(psmouse, data);
- if (rc == CYTP_PS2_RETRY)
- rc = cypress_ps2_sendbyte(psmouse, data);
- if (rc == CYTP_PS2_ERROR)
- continue;
- else
- break;
- } while (--tries > 0);
-
- ps2_end_command(ps2dev);
-
- return rc;
-}
-
-static int cypress_ps2_read_cmd_status(struct psmouse *psmouse,
- unsigned char cmd,
- unsigned char *param)
-{
- int rc;
- struct ps2dev *ps2dev = &psmouse->ps2dev;
- enum psmouse_state old_state;
- int pktsize;
-
- ps2_begin_command(ps2dev);
- old_state = psmouse->state;
- psmouse->state = PSMOUSE_CMD_MODE;
- psmouse->pktcnt = 0;
+ if (!rc) {
+ rc = cypress_ps2_sendbyte(psmouse, nibble);
+ if (rc == -EAGAIN)
+ rc = cypress_ps2_sendbyte(psmouse, nibble);
- pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3;
- memset(param, 0, pktsize);
-
- rc = cypress_ps2_sendbyte(psmouse, 0xe9);
- if (rc < 0)
- goto out;
-
- wait_event_timeout(ps2dev->wait,
- (psmouse->pktcnt >= pktsize),
- msecs_to_jiffies(CYTP_CMD_TIMEOUT));
-
- memcpy(param, psmouse->packet, pktsize);
-
- psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n",
- cmd, pktsize, param);
-
-out:
- psmouse->state = old_state;
- psmouse->pktcnt = 0;
+ if (!rc)
+ break;
+ }
+ } while (--tries > 0);
ps2_end_command(ps2dev);
return rc;
}
-static bool cypress_verify_cmd_state(struct psmouse *psmouse,
- unsigned char cmd, unsigned char *param)
+static bool cypress_verify_cmd_state(struct psmouse *psmouse, u8 cmd, u8* param)
{
bool rate_match = false;
bool resolution_match = false;
@@ -166,33 +121,36 @@ static bool cypress_verify_cmd_state(struct psmouse *psmouse,
return false;
}
-static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
- unsigned char *param)
+static int cypress_send_ext_cmd(struct psmouse *psmouse, u8 cmd, u8 *param)
{
+ u8 cmd_prefix = PSMOUSE_CMD_SETRES & 0xff;
+ unsigned int resp_size = cmd == CYTP_CMD_READ_TP_METRICS ? 8 : 3;
+ unsigned int ps2_cmd = (PSMOUSE_CMD_GETINFO & 0xff) | (resp_size << 8);
int tries = CYTP_PS2_CMD_TRIES;
- int rc;
+ int error;
psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n",
cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd),
DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd));
do {
- cypress_ps2_ext_cmd(psmouse,
- PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd));
- cypress_ps2_ext_cmd(psmouse,
- PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd));
- cypress_ps2_ext_cmd(psmouse,
- PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd));
- cypress_ps2_ext_cmd(psmouse,
- PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd));
-
- rc = cypress_ps2_read_cmd_status(psmouse, cmd, param);
- if (rc)
- continue;
-
- if (cypress_verify_cmd_state(psmouse, cmd, param))
- return 0;
-
+ cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_DD(cmd));
+ cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_CC(cmd));
+ cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_BB(cmd));
+ cypress_ps2_ext_cmd(psmouse, cmd_prefix, DECODE_CMD_AA(cmd));
+
+ error = ps2_command(&psmouse->ps2dev, param, ps2_cmd);
+ if (error) {
+ psmouse_dbg(psmouse, "Command 0x%02x failed: %d\n",
+ cmd, error);
+ } else {
+ psmouse_dbg(psmouse,
+ "Command 0x%02x response data (0x): %*ph\n",
+ cmd, resp_size, param);
+
+ if (cypress_verify_cmd_state(psmouse, cmd, param))
+ return 0;
+ }
} while (--tries > 0);
return -EIO;
@@ -200,7 +158,7 @@ static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd,
int cypress_detect(struct psmouse *psmouse, bool set_properties)
{
- unsigned char param[3];
+ u8 param[3];
if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
return -ENODEV;
@@ -220,7 +178,7 @@ int cypress_detect(struct psmouse *psmouse, bool set_properties)
static int cypress_read_fw_version(struct psmouse *psmouse)
{
struct cytp_data *cytp = psmouse->private;
- unsigned char param[3];
+ u8 param[3];
if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param))
return -ENODEV;
@@ -249,7 +207,7 @@ static int cypress_read_fw_version(struct psmouse *psmouse)
static int cypress_read_tp_metrics(struct psmouse *psmouse)
{
struct cytp_data *cytp = psmouse->private;
- unsigned char param[8];
+ u8 param[8];
/* set default values for tp metrics. */
cytp->tp_width = CYTP_DEFAULT_WIDTH;
@@ -321,15 +279,15 @@ static int cypress_read_tp_metrics(struct psmouse *psmouse)
static int cypress_query_hardware(struct psmouse *psmouse)
{
- int ret;
+ int error;
- ret = cypress_read_fw_version(psmouse);
- if (ret)
- return ret;
+ error = cypress_read_fw_version(psmouse);
+ if (error)
+ return error;
- ret = cypress_read_tp_metrics(psmouse);
- if (ret)
- return ret;
+ error = cypress_read_tp_metrics(psmouse);
+ if (error)
+ return error;
return 0;
}
@@ -337,10 +295,13 @@ static int cypress_query_hardware(struct psmouse *psmouse)
static int cypress_set_absolute_mode(struct psmouse *psmouse)
{
struct cytp_data *cytp = psmouse->private;
- unsigned char param[3];
+ u8 param[3];
+ int error;
- if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0)
- return -1;
+ error = cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE,
+ param);
+ if (error)
+ return error;
cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK)
| CYTP_BIT_ABS_PRESSURE;
@@ -365,7 +326,7 @@ static void cypress_reset(struct psmouse *psmouse)
static int cypress_set_input_params(struct input_dev *input,
struct cytp_data *cytp)
{
- int ret;
+ int error;
if (!cytp->tp_res_x || !cytp->tp_res_y)
return -EINVAL;
@@ -382,10 +343,10 @@ static int cypress_set_input_params(struct input_dev *input,
input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0);
input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
- ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
- INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK);
- if (ret < 0)
- return ret;
+ error = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS,
+ INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK);
+ if (error)
+ return error;
__set_bit(INPUT_PROP_SEMI_MT, input->propbit);
@@ -414,9 +375,9 @@ static int cypress_set_input_params(struct input_dev *input,
return 0;
}
-static int cypress_get_finger_count(unsigned char header_byte)
+static int cypress_get_finger_count(u8 header_byte)
{
- unsigned char bits6_7;
+ u8 bits6_7;
int finger_count;
bits6_7 = header_byte >> 6;
@@ -441,10 +402,11 @@ static int cypress_get_finger_count(unsigned char header_byte)
static int cypress_parse_packet(struct psmouse *psmouse,
- struct cytp_data *cytp, struct cytp_report_data *report_data)
+ struct cytp_data *cytp,
+ struct cytp_report_data *report_data)
{
- unsigned char *packet = psmouse->packet;
- unsigned char header_byte = packet[0];
+ u8 *packet = psmouse->packet;
+ u8 header_byte = packet[0];
memset(report_data, 0, sizeof(struct cytp_report_data));
@@ -559,7 +521,7 @@ static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse)
{
int contact_cnt;
int index = psmouse->pktcnt - 1;
- unsigned char *packet = psmouse->packet;
+ u8 *packet = psmouse->packet;
struct cytp_data *cytp = psmouse->private;
if (index < 0 || index > cytp->pkt_size)
@@ -612,6 +574,7 @@ static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse)
static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
{
struct cytp_data *cytp = psmouse->private;
+ u8 rate_param;
if (rate >= 80) {
psmouse->rate = 80;
@@ -621,8 +584,8 @@ static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate)
cytp->mode &= ~CYTP_BIT_HIGH_RATE;
}
- ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate,
- PSMOUSE_CMD_SETRATE);
+ rate_param = (u8)rate;
+ ps2_command(&psmouse->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE);
}
static void cypress_disconnect(struct psmouse *psmouse)
@@ -635,21 +598,22 @@ static void cypress_disconnect(struct psmouse *psmouse)
static int cypress_reconnect(struct psmouse *psmouse)
{
int tries = CYTP_PS2_CMD_TRIES;
- int rc;
+ int error;
do {
cypress_reset(psmouse);
- rc = cypress_detect(psmouse, false);
- } while (rc && (--tries > 0));
+ error = cypress_detect(psmouse, false);
+ } while (error && (--tries > 0));
- if (rc) {
+ if (error) {
psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n");
- return -1;
+ return error;
}
- if (cypress_set_absolute_mode(psmouse)) {
+ error = cypress_set_absolute_mode(psmouse);
+ if (error) {
psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n");
- return -1;
+ return error;
}
return 0;
@@ -658,8 +622,9 @@ static int cypress_reconnect(struct psmouse *psmouse)
int cypress_init(struct psmouse *psmouse)
{
struct cytp_data *cytp;
+ int error;
- cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL);
+ cytp = kzalloc(sizeof(*cytp), GFP_KERNEL);
if (!cytp)
return -ENOMEM;
@@ -668,17 +633,20 @@ int cypress_init(struct psmouse *psmouse)
cypress_reset(psmouse);
- if (cypress_query_hardware(psmouse)) {
+ error = cypress_query_hardware(psmouse);
+ if (error) {
psmouse_err(psmouse, "Unable to query Trackpad hardware.\n");
goto err_exit;
}
- if (cypress_set_absolute_mode(psmouse)) {
+ error = cypress_set_absolute_mode(psmouse);
+ if (error) {
psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n");
goto err_exit;
}
- if (cypress_set_input_params(psmouse->dev, cytp) < 0) {
+ error = cypress_set_input_params(psmouse->dev, cytp);
+ if (error) {
psmouse_err(psmouse, "init: Unable to set input params.\n");
goto err_exit;
}
@@ -703,5 +671,5 @@ err_exit:
psmouse->private = NULL;
kfree(cytp);
- return -1;
+ return error;
}
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h
index bb4979d06bf9..47d538a49089 100644
--- a/drivers/input/mouse/cypress_ps2.h
+++ b/drivers/input/mouse/cypress_ps2.h
@@ -72,12 +72,6 @@
#define CYTP_DATA_TIMEOUT 30
#define CYTP_EXT_CMD 0xe8
-#define CYTP_PS2_RETRY 0xfe
-#define CYTP_PS2_ERROR 0xfc
-
-#define CYTP_RESP_RETRY 0x01
-#define CYTP_RESP_ERROR 0xfe
-
#define CYTP_105001_WIDTH 97 /* Dell XPS 13 */
#define CYTP_105001_HIGH 59
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index c2aec5c360b3..fee1796da3d0 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -28,6 +28,7 @@
#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/string_choices.h>
#include <linux/input.h>
#include <linux/uaccess.h>
#include <linux/jiffies.h>
@@ -36,7 +37,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "elan_i2c.h"
@@ -199,7 +200,7 @@ static int elan_set_power(struct elan_tp_data *data, bool on)
} while (--repeat > 0);
dev_err(&data->client->dev, "failed to set power %s: %d\n",
- on ? "on" : "off", error);
+ str_on_off(on), error);
return error;
}
@@ -541,7 +542,8 @@ static int elan_update_firmware(struct elan_tp_data *data,
dev_dbg(&client->dev, "Starting firmware update....\n");
- disable_irq(client->irq);
+ guard(disable_irq)(&client->irq);
+
data->in_fw_update = true;
retval = __elan_update_firmware(data, fw);
@@ -555,7 +557,6 @@ static int elan_update_firmware(struct elan_tp_data *data,
}
data->in_fw_update = false;
- enable_irq(client->irq);
return retval;
}
@@ -621,8 +622,6 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
const char *buf, size_t count)
{
struct elan_tp_data *data = dev_get_drvdata(dev);
- const struct firmware *fw;
- char *fw_name;
int error;
const u8 *fw_signature;
static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
@@ -631,15 +630,16 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
return -EINVAL;
/* Look for a firmware with the product id appended. */
- fw_name = kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id);
+ const char *fw_name __free(kfree) =
+ kasprintf(GFP_KERNEL, ETP_FW_NAME, data->product_id);
if (!fw_name) {
dev_err(dev, "failed to allocate memory for firmware name\n");
return -ENOMEM;
}
dev_info(dev, "requesting fw '%s'\n", fw_name);
+ const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, fw_name, dev);
- kfree(fw_name);
if (error) {
dev_err(dev, "failed to request firmware: %d\n", error);
return error;
@@ -651,46 +651,36 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
(int)sizeof(signature), signature,
(int)sizeof(signature), fw_signature);
- error = -EBADF;
- goto out_release_fw;
+ return -EBADF;
}
- error = mutex_lock_interruptible(&data->sysfs_mutex);
- if (error)
- goto out_release_fw;
-
- error = elan_update_firmware(data, fw);
-
- mutex_unlock(&data->sysfs_mutex);
+ scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) {
+ error = elan_update_firmware(data, fw);
+ if (error)
+ return error;
+ }
-out_release_fw:
- release_firmware(fw);
- return error ?: count;
+ return count;
}
-static ssize_t calibrate_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int elan_calibrate(struct elan_tp_data *data)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct elan_tp_data *data = i2c_get_clientdata(client);
+ struct i2c_client *client = data->client;
+ struct device *dev = &client->dev;
int tries = 20;
int retval;
int error;
u8 val[ETP_CALIBRATE_MAX_LEN];
- retval = mutex_lock_interruptible(&data->sysfs_mutex);
- if (retval)
- return retval;
-
- disable_irq(client->irq);
+ guard(disable_irq)(&client->irq);
data->mode |= ETP_ENABLE_CALIBRATE;
retval = data->ops->set_mode(client, data->mode);
if (retval) {
+ data->mode &= ~ETP_ENABLE_CALIBRATE;
dev_err(dev, "failed to enable calibration mode: %d\n",
retval);
- goto out;
+ return retval;
}
retval = data->ops->calibrate(client);
@@ -728,10 +718,24 @@ out_disable_calibrate:
if (!retval)
retval = error;
}
-out:
- enable_irq(client->irq);
- mutex_unlock(&data->sysfs_mutex);
- return retval ?: count;
+ return retval;
+}
+
+static ssize_t calibrate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct elan_tp_data *data = i2c_get_clientdata(client);
+ int error;
+
+ scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) {
+ error = elan_calibrate(data);
+ if (error)
+ return error;
+ }
+
+ return count;
}
static ssize_t elan_sysfs_read_mode(struct device *dev,
@@ -743,16 +747,11 @@ static ssize_t elan_sysfs_read_mode(struct device *dev,
int error;
enum tp_mode mode;
- error = mutex_lock_interruptible(&data->sysfs_mutex);
- if (error)
- return error;
-
- error = data->ops->iap_get_mode(data->client, &mode);
-
- mutex_unlock(&data->sysfs_mutex);
-
- if (error)
- return error;
+ scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) {
+ error = data->ops->iap_get_mode(data->client, &mode);
+ if (error)
+ return error;
+ }
return sysfs_emit(buf, "%d\n", (int)mode);
}
@@ -783,44 +782,40 @@ static const struct attribute_group elan_sysfs_group = {
.attrs = elan_sysfs_entries,
};
-static ssize_t acquire_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static int elan_acquire_baseline(struct elan_tp_data *data)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct elan_tp_data *data = i2c_get_clientdata(client);
- int error;
+ struct i2c_client *client = data->client;
+ struct device *dev = &client->dev;
int retval;
+ int error;
- retval = mutex_lock_interruptible(&data->sysfs_mutex);
- if (retval)
- return retval;
-
- disable_irq(client->irq);
+ guard(disable_irq)(&client->irq);
data->baseline_ready = false;
data->mode |= ETP_ENABLE_CALIBRATE;
- retval = data->ops->set_mode(data->client, data->mode);
+ retval = data->ops->set_mode(client, data->mode);
if (retval) {
+ data->mode &= ~ETP_ENABLE_CALIBRATE;
dev_err(dev, "Failed to enable calibration mode to get baseline: %d\n",
retval);
- goto out;
+ return retval;
}
msleep(250);
- retval = data->ops->get_baseline_data(data->client, true,
+ retval = data->ops->get_baseline_data(client, true,
&data->max_baseline);
if (retval) {
- dev_err(dev, "Failed to read max baseline form device: %d\n",
+ dev_err(dev, "Failed to read max baseline from device: %d\n",
retval);
goto out_disable_calibrate;
}
- retval = data->ops->get_baseline_data(data->client, false,
+ retval = data->ops->get_baseline_data(client, false,
&data->min_baseline);
if (retval) {
- dev_err(dev, "Failed to read min baseline form device: %d\n",
+ dev_err(dev, "Failed to read min baseline from device: %d\n",
retval);
goto out_disable_calibrate;
}
@@ -829,17 +824,31 @@ static ssize_t acquire_store(struct device *dev, struct device_attribute *attr,
out_disable_calibrate:
data->mode &= ~ETP_ENABLE_CALIBRATE;
- error = data->ops->set_mode(data->client, data->mode);
+ error = data->ops->set_mode(client, data->mode);
if (error) {
dev_err(dev, "Failed to disable calibration mode after acquiring baseline: %d\n",
error);
if (!retval)
retval = error;
}
-out:
- enable_irq(client->irq);
- mutex_unlock(&data->sysfs_mutex);
- return retval ?: count;
+
+ return retval;
+}
+
+static ssize_t acquire_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct elan_tp_data *data = i2c_get_clientdata(client);
+ int error;
+
+ scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) {
+ error = elan_acquire_baseline(data);
+ if (error)
+ return error;
+ }
+
+ return count;
}
static ssize_t min_show(struct device *dev,
@@ -847,22 +856,15 @@ static ssize_t min_show(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
- int retval;
- retval = mutex_lock_interruptible(&data->sysfs_mutex);
- if (retval)
- return retval;
+ scoped_guard(mutex_intr, &data->sysfs_mutex) {
+ if (!data->baseline_ready)
+ return -ENODATA;
- if (!data->baseline_ready) {
- retval = -ENODATA;
- goto out;
+ return sysfs_emit(buf, "%d", data->min_baseline);
}
- retval = sysfs_emit(buf, "%d", data->min_baseline);
-
-out:
- mutex_unlock(&data->sysfs_mutex);
- return retval;
+ return -EINTR;
}
static ssize_t max_show(struct device *dev,
@@ -870,25 +872,17 @@ static ssize_t max_show(struct device *dev,
{
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
- int retval;
- retval = mutex_lock_interruptible(&data->sysfs_mutex);
- if (retval)
- return retval;
+ scoped_guard(mutex_intr, &data->sysfs_mutex) {
+ if (!data->baseline_ready)
+ return -ENODATA;
- if (!data->baseline_ready) {
- retval = -ENODATA;
- goto out;
+ return sysfs_emit(buf, "%d", data->max_baseline);
}
- retval = sysfs_emit(buf, "%d", data->max_baseline);
-
-out:
- mutex_unlock(&data->sysfs_mutex);
- return retval;
+ return -EINTR;
}
-
static DEVICE_ATTR_WO(acquire);
static DEVICE_ATTR_RO(min);
static DEVICE_ATTR_RO(max);
@@ -1323,41 +1317,54 @@ static int elan_probe(struct i2c_client *client)
return 0;
}
+static int __elan_suspend(struct elan_tp_data *data)
+{
+ struct i2c_client *client = data->client;
+ int error;
+
+ if (device_may_wakeup(&client->dev))
+ return elan_sleep(data);
+
+ /* Touchpad is not a wakeup source */
+ error = elan_set_power(data, false);
+ if (error)
+ return error;
+
+ error = regulator_disable(data->vcc);
+ if (error) {
+ dev_err(&client->dev,
+ "failed to disable regulator when suspending: %d\n",
+ error);
+ /* Attempt to power the chip back up */
+ elan_set_power(data, true);
+ return error;
+ }
+
+ return 0;
+}
+
static int elan_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct elan_tp_data *data = i2c_get_clientdata(client);
- int ret;
+ int error;
/*
* We are taking the mutex to make sure sysfs operations are
* complete before we attempt to bring the device into low[er]
* power mode.
*/
- ret = mutex_lock_interruptible(&data->sysfs_mutex);
- if (ret)
- return ret;
-
- disable_irq(client->irq);
+ scoped_cond_guard(mutex_intr, return -EINTR, &data->sysfs_mutex) {
+ disable_irq(client->irq);
- if (device_may_wakeup(dev)) {
- ret = elan_sleep(data);
- } else {
- ret = elan_set_power(data, false);
- if (ret)
- goto err;
-
- ret = regulator_disable(data->vcc);
- if (ret) {
- dev_err(dev, "error %d disabling regulator\n", ret);
- /* Attempt to power the chip back up */
- elan_set_power(data, true);
+ error = __elan_suspend(data);
+ if (error) {
+ enable_irq(client->irq);
+ return error;
}
}
-err:
- mutex_unlock(&data->sysfs_mutex);
- return ret;
+ return 0;
}
static int elan_resume(struct device *dev)
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index 13dc097eb6c6..a9057d124a88 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -21,7 +21,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/sched.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "elan_i2c.h"
@@ -628,12 +628,11 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size,
const u8 *page, u16 checksum, int idx)
{
struct device *dev = &client->dev;
- u8 *page_store;
u8 val[3];
u16 result;
int ret, error;
- page_store = kmalloc(fw_page_size + 4, GFP_KERNEL);
+ u8 *page_store __free(kfree) = kmalloc(fw_page_size + 4, GFP_KERNEL);
if (!page_store)
return -ENOMEM;
@@ -647,7 +646,7 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size,
if (ret != fw_page_size + 4) {
error = ret < 0 ? ret : -EIO;
dev_err(dev, "Failed to write page %d: %d\n", idx, error);
- goto exit;
+ return error;
}
/* Wait for F/W to update one page ROM data. */
@@ -656,20 +655,17 @@ static int elan_i2c_write_fw_block(struct i2c_client *client, u16 fw_page_size,
error = elan_i2c_read_cmd(client, ETP_I2C_IAP_CTRL_CMD, val);
if (error) {
dev_err(dev, "Failed to read IAP write result: %d\n", error);
- goto exit;
+ return error;
}
result = le16_to_cpup((__le16 *)val);
if (result & (ETP_FW_IAP_PAGE_ERR | ETP_FW_IAP_INTF_ERR)) {
dev_err(dev, "IAP reports failed write: %04hx\n",
result);
- error = -EIO;
- goto exit;
+ return -EIO;
}
-exit:
- kfree(page_store);
- return error;
+ return 0;
}
static int elan_i2c_finish_fw_update(struct i2c_client *client,
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index b4723ea395eb..79ad98cc1e79 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/serio.h>
#include <linux/libps2.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "psmouse.h"
#include "elantech.h"
#include "elan_i2c.h"
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index c74b99077d16..356b99d48544 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -408,8 +408,7 @@ int focaltech_init(struct psmouse *psmouse)
struct focaltech_data *priv;
int error;
- psmouse->private = priv = kzalloc(sizeof(struct focaltech_data),
- GFP_KERNEL);
+ psmouse->private = priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c
index 3c8310da0b05..6125652e5ad8 100644
--- a/drivers/input/mouse/hgpk.c
+++ b/drivers/input/mouse/hgpk.c
@@ -981,7 +981,7 @@ int hgpk_init(struct psmouse *psmouse)
struct hgpk_data *priv;
int err;
- priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
err = -ENOMEM;
goto alloc_fail;
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index bd9955730176..283ef46f039f 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -273,14 +273,14 @@ static int lifebook_create_relative_device(struct psmouse *psmouse)
struct lifebook_data *priv;
int error = -ENOMEM;
- priv = kzalloc(sizeof(struct lifebook_data), GFP_KERNEL);
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
dev2 = input_allocate_device();
if (!priv || !dev2)
goto err_out;
priv->dev2 = dev2;
- snprintf(priv->phys, sizeof(priv->phys),
- "%s/input1", psmouse->ps2dev.serio->phys);
+ scnprintf(priv->phys, sizeof(priv->phys),
+ "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
dev2->name = "LBPS/2 Fujitsu Lifebook Touchpad";
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index 2de64d6a04d1..baef4be14b54 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -73,7 +73,7 @@ static int probe_maple_mouse(struct device *dev)
struct input_dev *input_dev;
struct dc_mouse *mse;
- mse = kzalloc(sizeof(struct dc_mouse), GFP_KERNEL);
+ mse = kzalloc(sizeof(*mse), GFP_KERNEL);
if (!mse) {
error = -ENOMEM;
goto fail;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index a0aac76b1e41..77ea7da3b1c5 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1591,7 +1591,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse_deactivate(parent);
}
- psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL);
+ psmouse = kzalloc(sizeof(*psmouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!psmouse || !input_dev)
goto err_free;
@@ -1600,7 +1600,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
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);
+ scnprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
diff --git a/drivers/input/mouse/psmouse-smbus.c b/drivers/input/mouse/psmouse-smbus.c
index 2a2459b1b4f2..93420f07b7d0 100644
--- a/drivers/input/mouse/psmouse-smbus.c
+++ b/drivers/input/mouse/psmouse-smbus.c
@@ -35,7 +35,7 @@ static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter)
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY))
return;
- mutex_lock(&psmouse_smbus_mutex);
+ guard(mutex)(&psmouse_smbus_mutex);
list_for_each_entry(smbdev, &psmouse_smbus_list, node) {
if (smbdev->dead)
@@ -55,15 +55,13 @@ static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter)
"SMBus candidate adapter appeared, triggering rescan\n");
serio_rescan(smbdev->psmouse->ps2dev.serio);
}
-
- mutex_unlock(&psmouse_smbus_mutex);
}
static void psmouse_smbus_detach_i2c_client(struct i2c_client *client)
{
struct psmouse_smbus_dev *smbdev, *tmp;
- mutex_lock(&psmouse_smbus_mutex);
+ guard(mutex)(&psmouse_smbus_mutex);
list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) {
if (smbdev->client != client)
@@ -85,8 +83,6 @@ static void psmouse_smbus_detach_i2c_client(struct i2c_client *client)
kfree(smbdev);
}
}
-
- mutex_unlock(&psmouse_smbus_mutex);
}
static int psmouse_smbus_notifier_call(struct notifier_block *nb,
@@ -171,7 +167,7 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse)
{
struct psmouse_smbus_dev *smbdev = psmouse->private;
- mutex_lock(&psmouse_smbus_mutex);
+ guard(mutex)(&psmouse_smbus_mutex);
if (smbdev->dead) {
list_del(&smbdev->node);
@@ -186,8 +182,6 @@ static void psmouse_smbus_disconnect(struct psmouse *psmouse)
psmouse_smbus_schedule_remove(smbdev->client);
}
- mutex_unlock(&psmouse_smbus_mutex);
-
psmouse->private = NULL;
}
@@ -219,7 +213,7 @@ void psmouse_smbus_cleanup(struct psmouse *psmouse)
{
struct psmouse_smbus_dev *smbdev, *tmp;
- mutex_lock(&psmouse_smbus_mutex);
+ guard(mutex)(&psmouse_smbus_mutex);
list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) {
if (psmouse == smbdev->psmouse) {
@@ -227,8 +221,6 @@ void psmouse_smbus_cleanup(struct psmouse *psmouse)
kfree(smbdev);
}
}
-
- mutex_unlock(&psmouse_smbus_mutex);
}
int psmouse_smbus_init(struct psmouse *psmouse,
@@ -267,9 +259,9 @@ int psmouse_smbus_init(struct psmouse *psmouse,
psmouse->disconnect = psmouse_smbus_disconnect;
psmouse->resync_time = 0;
- mutex_lock(&psmouse_smbus_mutex);
- list_add_tail(&smbdev->node, &psmouse_smbus_list);
- mutex_unlock(&psmouse_smbus_mutex);
+ scoped_guard(mutex, &psmouse_smbus_mutex) {
+ list_add_tail(&smbdev->node, &psmouse_smbus_list);
+ }
/* Bind to already existing adapters right away */
error = i2c_for_each_dev(smbdev, psmouse_smbus_create_companion);
@@ -293,9 +285,9 @@ int psmouse_smbus_init(struct psmouse *psmouse,
smbdev->board.platform_data = NULL;
if (error < 0 || !leave_breadcrumbs) {
- mutex_lock(&psmouse_smbus_mutex);
- list_del(&smbdev->node);
- mutex_unlock(&psmouse_smbus_mutex);
+ scoped_guard(mutex, &psmouse_smbus_mutex) {
+ list_del(&smbdev->node);
+ }
kfree(smbdev);
}
diff --git a/drivers/input/mouse/sentelic.c b/drivers/input/mouse/sentelic.c
index 2716d2ba386a..44b136fc29aa 100644
--- a/drivers/input/mouse/sentelic.c
+++ b/drivers/input/mouse/sentelic.c
@@ -1028,7 +1028,7 @@ int fsp_init(struct psmouse *psmouse)
"Finger Sensing Pad, hw: %d.%d.%d, sn: %x, sw: %s\n",
ver >> 4, ver & 0x0F, rev, sn, fsp_drv_ver);
- psmouse->private = priv = kzalloc(sizeof(struct fsp_data), GFP_KERNEL);
+ psmouse->private = priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 993f90333380..218c8432a13b 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -231,7 +231,7 @@ static int sermouse_connect(struct serio *serio, struct serio_driver *drv)
unsigned char c = serio->id.extra;
int err = -ENOMEM;
- sermouse = kzalloc(sizeof(struct sermouse), GFP_KERNEL);
+ sermouse = kzalloc(sizeof(*sermouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!sermouse || !input_dev)
goto fail1;
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 7a303a9d6bf7..c5c88a75a019 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -161,8 +161,10 @@ static const char * const topbuttonpad_pnp_ids[] = {
NULL
};
+#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_SMBUS
static const char * const smbus_pnp_ids[] = {
/* all of the topbuttonpad_pnp_ids are valid, we just add some extras */
+ "DLL060d", /* Dell Precision M3800 */
"LEN0048", /* X1 Carbon 3 */
"LEN0046", /* X250 */
"LEN0049", /* Yoga 11e */
@@ -189,12 +191,18 @@ static const char * const smbus_pnp_ids[] = {
"LEN2054", /* E480 */
"LEN2055", /* E580 */
"LEN2068", /* T14 Gen 1 */
+ "SYN1221", /* TUXEDO InfinityBook Pro 14 v5 */
+ "SYN3003", /* HP EliteBook 850 G1 */
+ "SYN3015", /* HP EliteBook 840 G2 */
"SYN3052", /* HP EliteBook 840 G4 */
"SYN3221", /* HP 15-ay000 */
"SYN323d", /* HP Spectre X360 13-w013dx */
"SYN3257", /* HP Envy 13-ad105ng */
+ "TOS01f6", /* Dynabook Portege X30L-G */
+ "TOS0213", /* Dynabook Portege X30-D */
NULL
};
+#endif
static const char * const forcepad_pnp_ids[] = {
"SYN300D",
@@ -649,9 +657,8 @@ static int synaptics_pt_start(struct serio *serio)
struct psmouse *parent = psmouse_from_serio(serio->parent);
struct synaptics_data *priv = parent->private;
- serio_pause_rx(parent->ps2dev.serio);
+ guard(serio_pause_rx)(parent->ps2dev.serio);
priv->pt_port = serio;
- serio_continue_rx(parent->ps2dev.serio);
return 0;
}
@@ -661,9 +668,28 @@ static void synaptics_pt_stop(struct serio *serio)
struct psmouse *parent = psmouse_from_serio(serio->parent);
struct synaptics_data *priv = parent->private;
- serio_pause_rx(parent->ps2dev.serio);
+ guard(serio_pause_rx)(parent->ps2dev.serio);
priv->pt_port = NULL;
- serio_continue_rx(parent->ps2dev.serio);
+}
+
+static int synaptics_pt_open(struct serio *serio)
+{
+ struct psmouse *parent = psmouse_from_serio(serio->parent);
+ struct synaptics_data *priv = parent->private;
+
+ guard(serio_pause_rx)(parent->ps2dev.serio);
+ priv->pt_port_open = true;
+
+ return 0;
+}
+
+static void synaptics_pt_close(struct serio *serio)
+{
+ struct psmouse *parent = psmouse_from_serio(serio->parent);
+ struct synaptics_data *priv = parent->private;
+
+ guard(serio_pause_rx)(parent->ps2dev.serio);
+ priv->pt_port_open = false;
}
static int synaptics_is_pt_packet(u8 *buf)
@@ -671,18 +697,25 @@ static int synaptics_is_pt_packet(u8 *buf)
return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4;
}
-static void synaptics_pass_pt_packet(struct serio *ptport, u8 *packet)
+static void synaptics_pass_pt_packet(struct synaptics_data *priv, u8 *packet)
{
- struct psmouse *child = psmouse_from_serio(ptport);
+ struct serio *ptport;
- if (child && child->state == PSMOUSE_ACTIVATED) {
- serio_interrupt(ptport, packet[1], 0);
- serio_interrupt(ptport, packet[4], 0);
- serio_interrupt(ptport, packet[5], 0);
- if (child->pktsize == 4)
- serio_interrupt(ptport, packet[2], 0);
- } else {
- serio_interrupt(ptport, packet[1], 0);
+ ptport = priv->pt_port;
+ if (!ptport)
+ return;
+
+ serio_interrupt(ptport, packet[1], 0);
+
+ if (priv->pt_port_open) {
+ struct psmouse *child = psmouse_from_serio(ptport);
+
+ if (child->state == PSMOUSE_ACTIVATED) {
+ serio_interrupt(ptport, packet[4], 0);
+ serio_interrupt(ptport, packet[5], 0);
+ if (child->pktsize == 4)
+ serio_interrupt(ptport, packet[2], 0);
+ }
}
}
@@ -708,7 +741,7 @@ static void synaptics_pt_create(struct psmouse *psmouse)
{
struct serio *serio;
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!serio) {
psmouse_err(psmouse,
"not enough memory for pass-through port\n");
@@ -721,6 +754,8 @@ static void synaptics_pt_create(struct psmouse *psmouse)
serio->write = synaptics_pt_write;
serio->start = synaptics_pt_start;
serio->stop = synaptics_pt_stop;
+ serio->open = synaptics_pt_open;
+ serio->close = synaptics_pt_close;
serio->parent = psmouse->ps2dev.serio;
psmouse->pt_activate = synaptics_pt_activate;
@@ -1217,11 +1252,10 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
if (SYN_CAP_PASS_THROUGH(priv->info.capabilities) &&
synaptics_is_pt_packet(psmouse->packet)) {
- if (priv->pt_port)
- synaptics_pass_pt_packet(priv->pt_port,
- psmouse->packet);
- } else
+ synaptics_pass_pt_packet(priv, psmouse->packet);
+ } else {
synaptics_process_packet(psmouse);
+ }
return PSMOUSE_FULL_PACKET;
}
@@ -1563,7 +1597,7 @@ static int synaptics_init_ps2(struct psmouse *psmouse,
synaptics_apply_quirks(psmouse, info);
- psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL);
+ psmouse->private = priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 08533d1b1b16..3853165b6b3a 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -21,7 +21,7 @@
#define SYN_QUE_EXT_MIN_COORDS 0x0f
#define SYN_QUE_MEXT_CAPAB_10 0x10
-/* synatics modes */
+/* synaptics modes */
#define SYN_BIT_ABSOLUTE_MODE BIT(7)
#define SYN_BIT_HIGH_RATE BIT(6)
#define SYN_BIT_SLEEP_MODE BIT(3)
@@ -188,6 +188,7 @@ struct synaptics_data {
bool disable_gesture; /* disable gestures */
struct serio *pt_port; /* Pass-through serio port */
+ bool pt_port_open;
/*
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c
index 56e9ba396858..a0d707e47d93 100644
--- a/drivers/input/mouse/synaptics_i2c.c
+++ b/drivers/input/mouse/synaptics_i2c.c
@@ -508,7 +508,7 @@ static struct synaptics_i2c *synaptics_i2c_touch_create(struct i2c_client *clien
{
struct synaptics_i2c *touch;
- touch = kzalloc(sizeof(struct synaptics_i2c), GFP_KERNEL);
+ touch = kzalloc(sizeof(*touch), GFP_KERNEL);
if (!touch)
return NULL;
diff --git a/drivers/input/mouse/vmmouse.c b/drivers/input/mouse/vmmouse.c
index ea9eff7c8099..fb1d986a6895 100644
--- a/drivers/input/mouse/vmmouse.c
+++ b/drivers/input/mouse/vmmouse.c
@@ -21,19 +21,16 @@
#include "psmouse.h"
#include "vmmouse.h"
-#define VMMOUSE_PROTO_MAGIC 0x564D5868U
-
/*
* Main commands supported by the vmmouse hypervisor port.
*/
-#define VMMOUSE_PROTO_CMD_GETVERSION 10
-#define VMMOUSE_PROTO_CMD_ABSPOINTER_DATA 39
-#define VMMOUSE_PROTO_CMD_ABSPOINTER_STATUS 40
-#define VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND 41
-#define VMMOUSE_PROTO_CMD_ABSPOINTER_RESTRICT 86
+#define VMWARE_CMD_ABSPOINTER_DATA 39
+#define VMWARE_CMD_ABSPOINTER_STATUS 40
+#define VMWARE_CMD_ABSPOINTER_COMMAND 41
+#define VMWARE_CMD_ABSPOINTER_RESTRICT 86
/*
- * Subcommands for VMMOUSE_PROTO_CMD_ABSPOINTER_COMMAND
+ * Subcommands for VMWARE_CMD_ABSPOINTER_COMMAND
*/
#define VMMOUSE_CMD_ENABLE 0x45414552U
#define VMMOUSE_CMD_DISABLE 0x000000f5U
@@ -76,28 +73,6 @@ struct vmmouse_data {
char dev_name[128];
};
-/*
- * Hypervisor-specific bi-directional communication channel
- * implementing the vmmouse protocol. Should never execute on
- * bare metal hardware.
- */
-#define VMMOUSE_CMD(cmd, in1, out1, out2, out3, out4) \
-({ \
- unsigned long __dummy1, __dummy2; \
- __asm__ __volatile__ (VMWARE_HYPERCALL : \
- "=a"(out1), \
- "=b"(out2), \
- "=c"(out3), \
- "=d"(out4), \
- "=S"(__dummy1), \
- "=D"(__dummy2) : \
- "a"(VMMOUSE_PROTO_MAGIC), \
- "b"(in1), \
- "c"(VMMOUSE_PROTO_CMD_##cmd), \
- "d"(0) : \
- "memory"); \
-})
-
/**
* vmmouse_report_button - report button state on the correct input device
*
@@ -145,14 +120,12 @@ static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse)
struct input_dev *abs_dev = priv->abs_dev;
struct input_dev *pref_dev;
u32 status, x, y, z;
- u32 dummy1, dummy2, dummy3;
unsigned int queue_length;
unsigned int count = 255;
while (count--) {
/* See if we have motion data. */
- VMMOUSE_CMD(ABSPOINTER_STATUS, 0,
- status, dummy1, dummy2, dummy3);
+ status = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_STATUS, 0);
if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) {
psmouse_err(psmouse, "failed to fetch status data\n");
/*
@@ -172,7 +145,8 @@ static psmouse_ret_t vmmouse_report_events(struct psmouse *psmouse)
}
/* Now get it */
- VMMOUSE_CMD(ABSPOINTER_DATA, 4, status, x, y, z);
+ status = vmware_hypercall4(VMWARE_CMD_ABSPOINTER_DATA, 4,
+ &x, &y, &z);
/*
* And report what we've got. Prefer to report button
@@ -247,14 +221,10 @@ static psmouse_ret_t vmmouse_process_byte(struct psmouse *psmouse)
static void vmmouse_disable(struct psmouse *psmouse)
{
u32 status;
- u32 dummy1, dummy2, dummy3, dummy4;
-
- VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE,
- dummy1, dummy2, dummy3, dummy4);
- VMMOUSE_CMD(ABSPOINTER_STATUS, 0,
- status, dummy1, dummy2, dummy3);
+ vmware_hypercall1(VMWARE_CMD_ABSPOINTER_COMMAND, VMMOUSE_CMD_DISABLE);
+ status = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_STATUS, 0);
if ((status & VMMOUSE_ERROR) != VMMOUSE_ERROR)
psmouse_warn(psmouse, "failed to disable vmmouse device\n");
}
@@ -271,26 +241,24 @@ static void vmmouse_disable(struct psmouse *psmouse)
static int vmmouse_enable(struct psmouse *psmouse)
{
u32 status, version;
- u32 dummy1, dummy2, dummy3, dummy4;
/*
* Try enabling the device. If successful, we should be able to
* read valid version ID back from it.
*/
- VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE,
- dummy1, dummy2, dummy3, dummy4);
+ vmware_hypercall1(VMWARE_CMD_ABSPOINTER_COMMAND, VMMOUSE_CMD_ENABLE);
/*
* See if version ID can be retrieved.
*/
- VMMOUSE_CMD(ABSPOINTER_STATUS, 0, status, dummy1, dummy2, dummy3);
+ status = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_STATUS, 0);
if ((status & 0x0000ffff) == 0) {
psmouse_dbg(psmouse, "empty flags - assuming no device\n");
return -ENXIO;
}
- VMMOUSE_CMD(ABSPOINTER_DATA, 1 /* single item */,
- version, dummy1, dummy2, dummy3);
+ version = vmware_hypercall1(VMWARE_CMD_ABSPOINTER_DATA,
+ 1 /* single item */);
if (version != VMMOUSE_VERSION_ID) {
psmouse_dbg(psmouse, "Unexpected version value: %u vs %u\n",
(unsigned) version, VMMOUSE_VERSION_ID);
@@ -301,11 +269,11 @@ static int vmmouse_enable(struct psmouse *psmouse)
/*
* Restrict ioport access, if possible.
*/
- VMMOUSE_CMD(ABSPOINTER_RESTRICT, VMMOUSE_RESTRICT_CPL0,
- dummy1, dummy2, dummy3, dummy4);
+ vmware_hypercall1(VMWARE_CMD_ABSPOINTER_RESTRICT,
+ VMMOUSE_RESTRICT_CPL0);
- VMMOUSE_CMD(ABSPOINTER_COMMAND, VMMOUSE_CMD_REQUEST_ABSOLUTE,
- dummy1, dummy2, dummy3, dummy4);
+ vmware_hypercall1(VMWARE_CMD_ABSPOINTER_COMMAND,
+ VMMOUSE_CMD_REQUEST_ABSOLUTE);
return 0;
}
@@ -342,7 +310,7 @@ static bool vmmouse_check_hypervisor(void)
*/
int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
{
- u32 response, version, dummy1, dummy2;
+ u32 response, version, type;
if (!vmmouse_check_hypervisor()) {
psmouse_dbg(psmouse,
@@ -351,9 +319,9 @@ int vmmouse_detect(struct psmouse *psmouse, bool set_properties)
}
/* Check if the device is present */
- response = ~VMMOUSE_PROTO_MAGIC;
- VMMOUSE_CMD(GETVERSION, 0, version, response, dummy1, dummy2);
- if (response != VMMOUSE_PROTO_MAGIC || version == 0xffffffffU)
+ response = ~VMWARE_HYPERVISOR_MAGIC;
+ version = vmware_hypercall3(VMWARE_CMD_GETVERSION, 0, &response, &type);
+ if (response != VMWARE_HYPERVISOR_MAGIC || version == 0xffffffffU)
return -ENXIO;
if (set_properties) {
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index 8af8e4a15f95..707cd28f4ba6 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -456,7 +456,7 @@ static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err = -ENOMEM;
- mouse = kzalloc(sizeof(struct vsxxxaa), GFP_KERNEL);
+ mouse = kzalloc(sizeof(*mouse), GFP_KERNEL);
input_dev = input_allocate_device();
if (!mouse || !input_dev)
goto fail1;
diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig
index c0163b983ce6..5db58fc9e11b 100644
--- a/drivers/input/rmi4/Kconfig
+++ b/drivers/input/rmi4/Kconfig
@@ -82,6 +82,21 @@ config RMI4_F12
touchpads. For sensors that support relative pointing, F12 also
provides mouse input.
+config RMI4_F1A
+ bool "RMI4 Function 1A (0D pointing)"
+ help
+ Say Y here if you want to add support for RMI4 function 1A.
+
+ Function 1A provides capacitive keys support for RMI4 devices.
+
+config RMI4_F21
+ bool "RMI4 Function 21 (PRESSURE)"
+ help
+ Say Y here if you want to add support for RMI4 function 21.
+
+ Function 21 provides buttons/pressure handling for RMI4 devices.
+ This includes support for buttons/pressure on PressurePad.
+
config RMI4_F30
bool "RMI4 Function 30 (GPIO LED)"
help
diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile
index 02f14c846861..35ae29f72497 100644
--- a/drivers/input/rmi4/Makefile
+++ b/drivers/input/rmi4/Makefile
@@ -8,6 +8,8 @@ rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o
rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o
rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o
rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o
+rmi_core-$(CONFIG_RMI4_F1A) += rmi_f1a.o
+rmi_core-$(CONFIG_RMI4_F21) += rmi_f21.o
rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o
rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o
rmi_core-$(CONFIG_RMI4_F3A) += rmi_f3a.o
diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c
index b7fe6eb35a4e..ea3eb87a89af 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.c
+++ b/drivers/input/rmi4/rmi_2d_sensor.c
@@ -4,6 +4,7 @@
* Copyright (c) 2011 Unixphere
*/
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/of.h>
diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h
index 7d335d809710..61a99c8a7a26 100644
--- a/drivers/input/rmi4/rmi_2d_sensor.h
+++ b/drivers/input/rmi4/rmi_2d_sensor.h
@@ -7,6 +7,9 @@
#ifndef _RMI_2D_SENSOR_H
#define _RMI_2D_SENSOR_H
+#include <linux/rmi.h>
+#include <linux/types.h>
+
enum rmi_2d_sensor_object_type {
RMI_2D_OBJECT_NONE,
RMI_2D_OBJECT_FINGER,
diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c
index 343030290d78..b85ee9db87b0 100644
--- a/drivers/input/rmi4/rmi_bus.c
+++ b/drivers/input/rmi4/rmi_bus.c
@@ -4,6 +4,7 @@
* Copyright (c) 2011 Unixphere
*/
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/irq.h>
@@ -144,9 +145,9 @@ bool rmi_is_function_device(struct device *dev)
return dev->type == &rmi_function_type;
}
-static int rmi_function_match(struct device *dev, struct device_driver *drv)
+static int rmi_function_match(struct device *dev, const struct device_driver *drv)
{
- struct rmi_function_handler *handler = to_rmi_function_handler(drv);
+ const struct rmi_function_handler *handler = to_rmi_function_handler(drv);
struct rmi_function *fn = to_rmi_function(dev);
return fn->fd.function_number == handler->func;
@@ -333,7 +334,7 @@ EXPORT_SYMBOL_GPL(rmi_unregister_function_handler);
/* Bus specific stuff */
-static int rmi_bus_match(struct device *dev, struct device_driver *drv)
+static int rmi_bus_match(struct device *dev, const struct device_driver *drv)
{
bool physical = rmi_is_physical_device(dev);
@@ -360,6 +361,12 @@ static struct rmi_function_handler *fn_handlers[] = {
#ifdef CONFIG_RMI4_F12
&rmi_f12_handler,
#endif
+#ifdef CONFIG_RMI4_F1A
+ &rmi_f1a_handler,
+#endif
+#ifdef CONFIG_RMI4_F21
+ &rmi_f21_handler,
+#endif
#ifdef CONFIG_RMI4_F30
&rmi_f30_handler,
#endif
diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h
index ea46ad9447ec..d4d0d82c69aa 100644
--- a/drivers/input/rmi4/rmi_bus.h
+++ b/drivers/input/rmi4/rmi_bus.h
@@ -87,7 +87,7 @@ struct rmi_function_handler {
};
#define to_rmi_function_handler(d) \
- container_of(d, struct rmi_function_handler, driver)
+ container_of_const(d, struct rmi_function_handler, driver)
int __must_check __rmi_register_function_handler(struct rmi_function_handler *,
struct module *, const char *);
diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c
index ef9ea295f9e0..ccd9338a44db 100644
--- a/drivers/input/rmi4/rmi_driver.c
+++ b/drivers/input/rmi4/rmi_driver.c
@@ -21,6 +21,7 @@
#include <linux/irqdomain.h>
#include <uapi/linux/input.h>
#include <linux/rmi.h>
+#include <linux/export.h>
#include "rmi_bus.h"
#include "rmi_driver.h"
@@ -1258,7 +1259,7 @@ static struct rmi_driver rmi_physical_driver = {
.set_input_params = rmi_driver_set_input_params,
};
-bool rmi_is_physical_driver(struct device_driver *drv)
+bool rmi_is_physical_driver(const struct device_driver *drv)
{
return drv == &rmi_physical_driver.driver;
}
diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h
index 1c6c6086c0e5..e84495caab15 100644
--- a/drivers/input/rmi4/rmi_driver.h
+++ b/drivers/input/rmi4/rmi_driver.h
@@ -84,7 +84,7 @@ int rmi_register_desc_calc_reg_offset(
bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item,
u8 subpacket);
-bool rmi_is_physical_driver(struct device_driver *);
+bool rmi_is_physical_driver(const struct device_driver *);
int rmi_register_physical_driver(void);
void rmi_unregister_physical_driver(void);
void rmi_free_function_list(struct rmi_device *rmi_dev);
@@ -133,6 +133,8 @@ extern struct rmi_function_handler rmi_f01_handler;
extern struct rmi_function_handler rmi_f03_handler;
extern struct rmi_function_handler rmi_f11_handler;
extern struct rmi_function_handler rmi_f12_handler;
+extern struct rmi_function_handler rmi_f1a_handler;
+extern struct rmi_function_handler rmi_f21_handler;
extern struct rmi_function_handler rmi_f30_handler;
extern struct rmi_function_handler rmi_f34_handler;
extern struct rmi_function_handler rmi_f3a_handler;
diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c
index cc1d4b424640..47be64284b25 100644
--- a/drivers/input/rmi4/rmi_f01.c
+++ b/drivers/input/rmi4/rmi_f01.c
@@ -9,7 +9,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/of.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "rmi_driver.h"
#define RMI_PRODUCT_ID_LENGTH 10
diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c
index 1e11ea30d7bd..e1157ff0f00a 100644
--- a/drivers/input/rmi4/rmi_f03.c
+++ b/drivers/input/rmi4/rmi_f03.c
@@ -61,14 +61,14 @@ void rmi_f03_commit_buttons(struct rmi_function *fn)
struct f03_data *f03 = dev_get_drvdata(&fn->dev);
struct serio *serio = f03->serio;
- serio_pause_rx(serio);
+ guard(serio_pause_rx)(serio);
+
if (serio->drv) {
serio->drv->interrupt(serio, PSMOUSE_OOB_EXTRA_BTNS,
SERIO_OOB_DATA);
serio->drv->interrupt(serio, f03->overwrite_buttons,
SERIO_OOB_DATA);
}
- serio_continue_rx(serio);
}
static int rmi_f03_pt_write(struct serio *id, unsigned char val)
diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c
index 7e97944f7616..8246fe77114b 100644
--- a/drivers/input/rmi4/rmi_f12.c
+++ b/drivers/input/rmi4/rmi_f12.c
@@ -24,6 +24,7 @@ enum rmi_f12_object_type {
};
#define F12_DATA1_BYTES_PER_OBJ 8
+#define RMI_F12_QUERY_RESOLUTION 29
struct f12_data {
struct rmi_2d_sensor sensor;
@@ -73,6 +74,8 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
int pitch_y = 0;
int rx_receivers = 0;
int tx_receivers = 0;
+ u16 query_dpm_addr = 0;
+ int dpm_resolution = 0;
item = rmi_get_register_desc_item(&f12->control_reg_desc, 8);
if (!item) {
@@ -122,18 +125,38 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12)
offset += 4;
}
- if (rmi_register_desc_has_subpacket(item, 3)) {
- rx_receivers = buf[offset];
- tx_receivers = buf[offset + 1];
- offset += 2;
- }
+ /*
+ * Use the Query DPM feature when the resolution query register
+ * exists.
+ */
+ if (rmi_get_register_desc_item(&f12->query_reg_desc,
+ RMI_F12_QUERY_RESOLUTION)) {
+ offset = rmi_register_desc_calc_reg_offset(&f12->query_reg_desc,
+ RMI_F12_QUERY_RESOLUTION);
+ query_dpm_addr = fn->fd.query_base_addr + offset;
+ ret = rmi_read(fn->rmi_dev, query_dpm_addr, buf);
+ if (ret < 0) {
+ dev_err(&fn->dev, "Failed to read DPM value: %d\n", ret);
+ return -ENODEV;
+ }
+ dpm_resolution = buf[0];
- /* Skip over sensor flags */
- if (rmi_register_desc_has_subpacket(item, 4))
- offset += 1;
+ sensor->x_mm = sensor->max_x / dpm_resolution;
+ sensor->y_mm = sensor->max_y / dpm_resolution;
+ } else {
+ if (rmi_register_desc_has_subpacket(item, 3)) {
+ rx_receivers = buf[offset];
+ tx_receivers = buf[offset + 1];
+ offset += 2;
+ }
- sensor->x_mm = (pitch_x * rx_receivers) >> 12;
- sensor->y_mm = (pitch_y * tx_receivers) >> 12;
+ /* Skip over sensor flags */
+ if (rmi_register_desc_has_subpacket(item, 4))
+ offset += 1;
+
+ sensor->x_mm = (pitch_x * rx_receivers) >> 12;
+ sensor->y_mm = (pitch_y * tx_receivers) >> 12;
+ }
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x_mm: %d y_mm: %d\n", __func__,
sensor->x_mm, sensor->y_mm);
diff --git a/drivers/input/rmi4/rmi_f1a.c b/drivers/input/rmi4/rmi_f1a.c
new file mode 100644
index 000000000000..765e9eae4cdc
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f1a.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 André Apitzsch <git@apitzsch.eu>
+ */
+
+#include <linux/input.h>
+#include <linux/property.h>
+#include "rmi_driver.h"
+
+struct f1a_data {
+ struct input_dev *input;
+
+ u32 *keymap;
+ unsigned int num_keys;
+};
+
+static int rmi_f1a_parse_device_properties(struct rmi_function *fn, struct f1a_data *f1a)
+{
+ static const char buttons_property[] = "linux,keycodes";
+ struct device *dev = &fn->dev;
+ u32 *buttonmap;
+ int n_keys;
+ int error;
+
+ if (!device_property_present(dev, buttons_property))
+ return 0;
+
+ 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;
+ }
+
+ f1a->keymap = buttonmap;
+ f1a->num_keys = n_keys;
+
+ return 0;
+}
+
+static irqreturn_t rmi_f1a_attention(int irq, void *ctx)
+{
+ struct rmi_function *fn = ctx;
+ struct f1a_data *f1a = dev_get_drvdata(&fn->dev);
+ char button_bitmask;
+ int key;
+ int error;
+
+ error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
+ &button_bitmask, sizeof(button_bitmask));
+ if (error) {
+ dev_err(&fn->dev, "Failed to read object data. Code: %d.\n",
+ error);
+ return IRQ_RETVAL(error);
+ }
+
+ for (key = 0; key < f1a->num_keys; key++)
+ input_report_key(f1a->input, f1a->keymap[key],
+ button_bitmask & BIT(key));
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_f1a_config(struct rmi_function *fn)
+{
+ struct f1a_data *f1a = dev_get_drvdata(&fn->dev);
+ struct rmi_driver *drv = fn->rmi_dev->driver;
+
+ if (f1a->num_keys)
+ drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f1a_initialize(struct rmi_function *fn, struct f1a_data *f1a)
+{
+ int error;
+ int i;
+
+ error = rmi_f1a_parse_device_properties(fn, f1a);
+ if (error)
+ return error;
+
+ for (i = 0; i < f1a->num_keys; i++)
+ input_set_capability(f1a->input, EV_KEY, f1a->keymap[i]);
+
+ f1a->input->keycode = f1a->keymap;
+ f1a->input->keycodemax = f1a->num_keys;
+ f1a->input->keycodesize = sizeof(f1a->keymap[0]);
+
+ return 0;
+}
+
+static int rmi_f1a_probe(struct rmi_function *fn)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ struct f1a_data *f1a;
+ int error;
+
+ if (!drv_data->input) {
+ dev_info(&fn->dev, "F1A: no input device found, ignoring\n");
+ return -ENXIO;
+ }
+
+ f1a = devm_kzalloc(&fn->dev, sizeof(*f1a), GFP_KERNEL);
+ if (!f1a)
+ return -ENOMEM;
+
+ f1a->input = drv_data->input;
+
+ error = rmi_f1a_initialize(fn, f1a);
+ if (error)
+ return error;
+
+ dev_set_drvdata(&fn->dev, f1a);
+
+ return 0;
+}
+
+struct rmi_function_handler rmi_f1a_handler = {
+ .driver = {
+ .name = "rmi4_f1a",
+ },
+ .func = 0x1a,
+ .probe = rmi_f1a_probe,
+ .config = rmi_f1a_config,
+ .attention = rmi_f1a_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f21.c b/drivers/input/rmi4/rmi_f21.c
new file mode 100644
index 000000000000..e3a9dfc3f0ec
--- /dev/null
+++ b/drivers/input/rmi4/rmi_f21.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2012-2025 Synaptics Incorporated
+ */
+
+#include <linux/bits.h>
+#include <linux/dev_printk.h>
+#include <linux/kernel.h>
+#include <linux/rmi.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include "rmi_driver.h"
+
+#define RMI_F21_SENSOR_COUNT_MASK GENMASK(3, 0)
+#define RMI_F21_FINGER_COUNT_PRESENT BIT(5)
+#define RMI_F21_NEW_REPORT_FORMAT BIT(6)
+
+#define RMI_F21_FINGER_COUNT_MASK GENMASK(3, 0)
+
+#define RMI_F21_MAX_SENSORS 16
+#define RMI_F21_MAX_FINGERS 16
+#define RMI_F21_DATA_REGS_MAX_SIZE (RMI_F21_MAX_SENSORS * 2 + \
+ RMI_F21_MAX_FINGERS * 2 + 1)
+
+#define RMI_F21_FORCE_CLICK_BIT BIT(0)
+
+#define RMI_F21_FORCEPAD_BUTTON_COUNT 1
+
+struct f21_data {
+ struct input_dev *input;
+ u16 key_code;
+
+ unsigned int attn_data_size;
+ unsigned int attn_data_button_offset;
+
+ unsigned int data_reg_size;
+ unsigned int data_reg_button_offset;
+ u8 data_regs[RMI_F21_DATA_REGS_MAX_SIZE];
+};
+
+static irqreturn_t rmi_f21_attention(int irq, void *ctx)
+{
+ struct rmi_function *fn = ctx;
+ struct f21_data *f21 = dev_get_drvdata(&fn->dev);
+ struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev);
+ u8 *pdata;
+ int error;
+ bool pressed;
+
+ if (drvdata->attn_data.data) {
+ if (drvdata->attn_data.size < f21->attn_data_size) {
+ dev_warn(&fn->dev, "f21 interrupt, but data is missing\n");
+ return IRQ_HANDLED;
+ }
+
+ pdata = drvdata->attn_data.data + f21->attn_data_button_offset;
+
+ drvdata->attn_data.data += f21->attn_data_size;
+ drvdata->attn_data.size -= f21->attn_data_size;
+ } else {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.data_base_addr,
+ f21->data_regs, f21->data_reg_size);
+ if (error) {
+ dev_err(&fn->dev, "failed to read f21 data registers: %d\n",
+ error);
+ return IRQ_RETVAL(error);
+ }
+
+ pdata = f21->data_regs + f21->data_reg_button_offset;
+ }
+
+ pressed = *pdata & RMI_F21_FORCE_CLICK_BIT;
+ input_report_key(f21->input, f21->key_code, pressed);
+
+ return IRQ_HANDLED;
+}
+
+static int rmi_f21_config(struct rmi_function *fn)
+{
+ struct rmi_driver *drv = fn->rmi_dev->driver;
+
+ drv->set_irq_bits(fn->rmi_dev, fn->irq_mask);
+
+ return 0;
+}
+
+static int rmi_f21_initialize(struct rmi_function *fn, struct f21_data *f21)
+{
+ struct input_dev *input = f21->input;
+
+ f21->key_code = BTN_LEFT;
+
+ input->keycode = &f21->key_code;
+ input->keycodesize = sizeof(f21->key_code);
+ input->keycodemax = RMI_F21_FORCEPAD_BUTTON_COUNT;
+
+ input_set_capability(input, EV_KEY, f21->key_code);
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+ return 0;
+}
+
+static int rmi_f21_probe(struct rmi_function *fn)
+{
+ struct rmi_device *rmi_dev = fn->rmi_dev;
+ struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev);
+ struct f21_data *f21;
+ unsigned int sensor_count;
+ unsigned int max_fingers;
+ unsigned int query15_offset;
+ u8 query15_data;
+ int error;
+
+ if (!drv_data->input) {
+ dev_info(&fn->dev, "f21: no input device found, ignoring\n");
+ return -ENXIO;
+ }
+
+ f21 = devm_kzalloc(&fn->dev, sizeof(*f21), GFP_KERNEL);
+ if (!f21)
+ return -ENOMEM;
+
+ f21->input = drv_data->input;
+
+ error = rmi_f21_initialize(fn, f21);
+ if (error)
+ return error;
+
+ dev_set_drvdata(&fn->dev, f21);
+
+ sensor_count = fn->fd.query_base_addr & RMI_F21_SENSOR_COUNT_MASK;
+ if (fn->fd.query_base_addr & RMI_F21_FINGER_COUNT_PRESENT) {
+ query15_offset = fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT ? 2 : 1;
+ error = rmi_read_block(fn->rmi_dev,
+ fn->fd.query_base_addr + query15_offset,
+ &query15_data, sizeof(query15_data));
+ if (error)
+ return dev_err_probe(&fn->dev, error,
+ "failed to read 'query15' data");
+
+ max_fingers = query15_data & RMI_F21_FINGER_COUNT_MASK;
+ } else {
+ max_fingers = 5;
+ }
+
+ if (fn->fd.query_base_addr & RMI_F21_NEW_REPORT_FORMAT) {
+ /* Each finger uses one byte, and the button state uses one byte.*/
+ f21->attn_data_size = max_fingers + 1;
+ f21->attn_data_button_offset = f21->attn_data_size - 1;
+ /*
+ * Each sensor uses two bytes, the button state uses one byte,
+ * and each finger uses two bytes.
+ */
+ f21->data_reg_size = sensor_count * 2 + 1 + max_fingers * 2;
+ f21->data_reg_button_offset = sensor_count * 2;
+ } else {
+ /*
+ * Regardless of the transport each finger uses two bytes,
+ * and the button state uses one byte.
+ */
+ f21->attn_data_size = sensor_count * 2 + 1;
+ f21->attn_data_button_offset = sensor_count * 2;
+
+ f21->data_reg_size = f21->attn_data_size;
+ f21->data_reg_button_offset = f21->attn_data_button_offset;
+ }
+
+ return 0;
+}
+
+struct rmi_function_handler rmi_f21_handler = {
+ .driver = {
+ .name = "rmi4_f21",
+ },
+ .func = 0x21,
+ .probe = rmi_f21_probe,
+ .config = rmi_f21_config,
+ .attention = rmi_f21_attention,
+};
diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c
index 3b3ac71e53dc..f1947f03b06a 100644
--- a/drivers/input/rmi4/rmi_f34.c
+++ b/drivers/input/rmi4/rmi_f34.c
@@ -4,10 +4,11 @@
* Copyright (C) 2016 Zodiac Inflight Innovations
*/
+#include "linux/device.h"
#include <linux/kernel.h>
#include <linux/rmi.h>
#include <linux/firmware.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/bitops.h>
#include "rmi_driver.h"
@@ -246,7 +247,6 @@ static int rmi_f34_update_firmware(struct f34_data *f34,
(const struct rmi_f34_firmware *)fw->data;
u32 image_size = le32_to_cpu(syn_fw->image_size);
u32 config_size = le32_to_cpu(syn_fw->config_size);
- int ret;
BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) !=
F34_FW_IMAGE_OFFSET);
@@ -267,8 +267,7 @@ static int rmi_f34_update_firmware(struct f34_data *f34,
dev_err(&f34->fn->dev,
"Bad firmware image: fw size %d, expected %d\n",
image_size, f34->v5.fw_blocks * f34->v5.block_size);
- ret = -EILSEQ;
- goto out;
+ return -EILSEQ;
}
if (config_size &&
@@ -277,36 +276,18 @@ static int rmi_f34_update_firmware(struct f34_data *f34,
"Bad firmware image: config size %d, expected %d\n",
config_size,
f34->v5.config_blocks * f34->v5.block_size);
- ret = -EILSEQ;
- goto out;
+ return -EILSEQ;
}
if (image_size && !config_size) {
dev_err(&f34->fn->dev, "Bad firmware image: no config data\n");
- ret = -EILSEQ;
- goto out;
+ return -EILSEQ;
}
dev_info(&f34->fn->dev, "Firmware image OK\n");
- mutex_lock(&f34->v5.flash_mutex);
-
- ret = rmi_f34_flash_firmware(f34, syn_fw);
-
- mutex_unlock(&f34->v5.flash_mutex);
-out:
- return ret;
-}
-
-static int rmi_f34_status(struct rmi_function *fn)
-{
- struct f34_data *f34 = dev_get_drvdata(&fn->dev);
-
- /*
- * The status is the percentage complete, or once complete,
- * zero for success or a negative return code.
- */
- return f34->update_status;
+ guard(mutex)(&f34->v5.flash_mutex);
+ return rmi_f34_flash_firmware(f34, syn_fw);
}
static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
@@ -314,23 +295,25 @@ static ssize_t rmi_driver_bootloader_id_show(struct device *dev,
char *buf)
{
struct rmi_driver_data *data = dev_get_drvdata(dev);
- struct rmi_function *fn = data->f34_container;
+ struct rmi_function *fn;
struct f34_data *f34;
- if (fn) {
- f34 = dev_get_drvdata(&fn->dev);
-
- if (f34->bl_version == 5)
- return sysfs_emit(buf, "%c%c\n",
- f34->bootloader_id[0],
- f34->bootloader_id[1]);
- else
- return sysfs_emit(buf, "V%d.%d\n",
- f34->bootloader_id[1],
- f34->bootloader_id[0]);
- }
+ fn = data->f34_container;
+ if (!fn)
+ return -ENODEV;
- return 0;
+ f34 = dev_get_drvdata(&fn->dev);
+ if (!f34)
+ return -ENODEV;
+
+ if (f34->bl_version == 5)
+ return sysfs_emit(buf, "%c%c\n",
+ f34->bootloader_id[0],
+ f34->bootloader_id[1]);
+ else
+ return sysfs_emit(buf, "V%d.%d\n",
+ f34->bootloader_id[1],
+ f34->bootloader_id[0]);
}
static DEVICE_ATTR(bootloader_id, 0444, rmi_driver_bootloader_id_show, NULL);
@@ -343,13 +326,16 @@ static ssize_t rmi_driver_configuration_id_show(struct device *dev,
struct rmi_function *fn = data->f34_container;
struct f34_data *f34;
- if (fn) {
- f34 = dev_get_drvdata(&fn->dev);
+ fn = data->f34_container;
+ if (!fn)
+ return -ENODEV;
- return sysfs_emit(buf, "%s\n", f34->configuration_id);
- }
+ f34 = dev_get_drvdata(&fn->dev);
+ if (!f34)
+ return -ENODEV;
- return 0;
+
+ return sysfs_emit(buf, "%s\n", f34->configuration_id);
}
static DEVICE_ATTR(configuration_id, 0444,
@@ -365,10 +351,14 @@ static int rmi_firmware_update(struct rmi_driver_data *data,
if (!data->f34_container) {
dev_warn(dev, "%s: No F34 present!\n", __func__);
- return -EINVAL;
+ return -ENODEV;
}
f34 = dev_get_drvdata(&data->f34_container->dev);
+ if (!f34) {
+ dev_warn(dev, "%s: No valid F34 present!\n", __func__);
+ return -ENODEV;
+ }
if (f34->bl_version >= 7) {
if (data->pdt_props & HAS_BSR) {
@@ -461,9 +451,8 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev,
{
struct rmi_driver_data *data = dev_get_drvdata(dev);
char fw_name[NAME_MAX];
- const struct firmware *fw;
size_t copy_count = count;
- int ret;
+ int error;
if (count == 0 || count >= NAME_MAX)
return -EINVAL;
@@ -474,17 +463,18 @@ static ssize_t rmi_driver_update_fw_store(struct device *dev,
memcpy(fw_name, buf, copy_count);
fw_name[copy_count] = '\0';
- ret = request_firmware(&fw, fw_name, dev);
- if (ret)
- return ret;
+ const struct firmware *fw __free(firmware) = NULL;
+ error = request_firmware(&fw, fw_name, dev);
+ if (error)
+ return error;
dev_info(dev, "Flashing %s\n", fw_name);
- ret = rmi_firmware_update(data, fw);
+ error = rmi_firmware_update(data, fw);
+ if (error)
+ return error;
- release_firmware(fw);
-
- return ret ?: count;
+ return count;
}
static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store);
@@ -494,10 +484,18 @@ static ssize_t rmi_driver_update_fw_status_show(struct device *dev,
char *buf)
{
struct rmi_driver_data *data = dev_get_drvdata(dev);
- int update_status = 0;
+ struct f34_data *f34;
+ int update_status = -ENODEV;
- if (data->f34_container)
- update_status = rmi_f34_status(data->f34_container);
+ /*
+ * The status is the percentage complete, or once complete,
+ * zero for success or a negative return code.
+ */
+ if (data->f34_container) {
+ f34 = dev_get_drvdata(&data->f34_container->dev);
+ if (f34)
+ update_status = f34->update_status;
+ }
return sysfs_emit(buf, "%d\n", update_status);
}
@@ -517,33 +515,21 @@ static const struct attribute_group rmi_firmware_attr_group = {
.attrs = rmi_firmware_attrs,
};
-static int rmi_f34_probe(struct rmi_function *fn)
+static int rmi_f34v5_probe(struct f34_data *f34)
{
- struct f34_data *f34;
- unsigned char f34_queries[9];
+ struct rmi_function *fn = f34->fn;
+ u8 f34_queries[9];
bool has_config_id;
- u8 version = fn->fd.function_version;
- int ret;
-
- f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
- if (!f34)
- return -ENOMEM;
-
- f34->fn = fn;
- dev_set_drvdata(&fn->dev, f34);
-
- /* v5 code only supported version 0, try V7 probe */
- if (version > 0)
- return rmi_f34v7_probe(f34);
+ int error;
f34->bl_version = 5;
- ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
- f34_queries, sizeof(f34_queries));
- if (ret) {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (error) {
dev_err(&fn->dev, "%s: Failed to query properties\n",
__func__);
- return ret;
+ return error;
}
snprintf(f34->bootloader_id, sizeof(f34->bootloader_id),
@@ -569,11 +555,11 @@ static int rmi_f34_probe(struct rmi_function *fn)
f34->v5.config_blocks);
if (has_config_id) {
- ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
- f34_queries, sizeof(f34_queries));
- if (ret) {
+ error = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr,
+ f34_queries, sizeof(f34_queries));
+ if (error) {
dev_err(&fn->dev, "Failed to read F34 config ID\n");
- return ret;
+ return error;
}
snprintf(f34->configuration_id, sizeof(f34->configuration_id),
@@ -582,12 +568,34 @@ static int rmi_f34_probe(struct rmi_function *fn)
f34_queries[2], f34_queries[3]);
rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n",
- f34->configuration_id);
+ f34->configuration_id);
}
return 0;
}
+static int rmi_f34_probe(struct rmi_function *fn)
+{
+ struct f34_data *f34;
+ u8 version = fn->fd.function_version;
+ int error;
+
+ f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL);
+ if (!f34)
+ return -ENOMEM;
+
+ f34->fn = fn;
+
+ /* v5 code only supported version 0 */
+ error = version == 0 ? rmi_f34v5_probe(f34) : rmi_f34v7_probe(f34);
+ if (error)
+ return error;
+
+ dev_set_drvdata(&fn->dev, f34);
+
+ return 0;
+}
+
int rmi_f34_create_sysfs(struct rmi_device *rmi_dev)
{
return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group);
diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c
index 886557b01eba..fd49acc02071 100644
--- a/drivers/input/rmi4/rmi_f34v7.c
+++ b/drivers/input/rmi4/rmi_f34v7.c
@@ -13,7 +13,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "rmi_driver.h"
#include "rmi_f34.h"
diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c
index 5c3da910b5b2..ac4041a69fcd 100644
--- a/drivers/input/rmi4/rmi_f54.c
+++ b/drivers/input/rmi4/rmi_f54.c
@@ -372,8 +372,6 @@ static const struct vb2_ops rmi_f54_queue_ops = {
.queue_setup = rmi_f54_queue_setup,
.buf_queue = rmi_f54_buffer_queue,
.stop_streaming = rmi_f54_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue rmi_f54_queue = {
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 17edc1597446..c7ef347a4dff 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -276,8 +276,8 @@ config SERIO_OLPC_APSP
config HYPERV_KEYBOARD
tristate "Microsoft Synthetic Keyboard driver"
- depends on HYPERV
- default HYPERV
+ depends on HYPERV_VMBUS
+ default HYPERV_VMBUS
help
Select this option to enable the Hyper-V Keyboard driver.
diff --git a/drivers/input/serio/altera_ps2.c b/drivers/input/serio/altera_ps2.c
index c5b634940cfc..aa445b1941e9 100644
--- a/drivers/input/serio/altera_ps2.c
+++ b/drivers/input/serio/altera_ps2.c
@@ -100,7 +100,7 @@ static int altera_ps2_probe(struct platform_device *pdev)
return error;
}
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
@@ -146,7 +146,7 @@ MODULE_DEVICE_TABLE(of, altera_ps2_match);
*/
static struct platform_driver altera_ps2_driver = {
.probe = altera_ps2_probe,
- .remove_new = altera_ps2_remove,
+ .remove = altera_ps2_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(altera_ps2_match),
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 496bb7a312d2..de4b3915c37d 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -114,8 +114,8 @@ static int amba_kmi_probe(struct amba_device *dev,
if (ret)
return ret;
- kmi = kzalloc(sizeof(struct amba_kmi_port), GFP_KERNEL);
- io = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ kmi = kzalloc(sizeof(*kmi), GFP_KERNEL);
+ io = kzalloc(sizeof(*io), GFP_KERNEL);
if (!kmi || !io) {
ret = -ENOMEM;
goto out;
diff --git a/drivers/input/serio/ams_delta_serio.c b/drivers/input/serio/ams_delta_serio.c
index 0bd6ae106809..81b3a053df81 100644
--- a/drivers/input/serio/ams_delta_serio.c
+++ b/drivers/input/serio/ams_delta_serio.c
@@ -182,7 +182,7 @@ static void ams_delta_serio_exit(struct platform_device *pdev)
static struct platform_driver ams_delta_serio_driver = {
.probe = ams_delta_serio_init,
- .remove_new = ams_delta_serio_exit,
+ .remove = ams_delta_serio_exit,
.driver = {
.name = DRIVER_NAME
},
diff --git a/drivers/input/serio/apbps2.c b/drivers/input/serio/apbps2.c
index dbbb10251520..b815337be2f4 100644
--- a/drivers/input/serio/apbps2.c
+++ b/drivers/input/serio/apbps2.c
@@ -165,7 +165,7 @@ static int apbps2_of_probe(struct platform_device *ofdev)
/* Set reload register to core freq in kHz/10 */
iowrite32be(freq_hz / 10000, &priv->regs->reload);
- priv->io = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ priv->io = kzalloc(sizeof(*priv->io), GFP_KERNEL);
if (!priv->io)
return -ENOMEM;
@@ -208,7 +208,7 @@ static struct platform_driver apbps2_of_driver = {
.of_match_table = apbps2_of_match,
},
.probe = apbps2_of_probe,
- .remove_new = apbps2_of_remove,
+ .remove = apbps2_of_remove,
};
module_platform_driver(apbps2_of_driver);
diff --git a/drivers/input/serio/arc_ps2.c b/drivers/input/serio/arc_ps2.c
index 9d8726830140..e991c72296c9 100644
--- a/drivers/input/serio/arc_ps2.c
+++ b/drivers/input/serio/arc_ps2.c
@@ -155,7 +155,7 @@ static int arc_ps2_create_port(struct platform_device *pdev,
struct arc_ps2_port *port = &arc_ps2->port[index];
struct serio *io;
- io = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ io = kzalloc(sizeof(*io), GFP_KERNEL);
if (!io)
return -ENOMEM;
@@ -260,7 +260,7 @@ static struct platform_driver arc_ps2_driver = {
.of_match_table = of_match_ptr(arc_ps2_match),
},
.probe = arc_ps2_probe,
- .remove_new = arc_ps2_remove,
+ .remove = arc_ps2_remove,
};
module_platform_driver(arc_ps2_driver);
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index d5c9bb3d0103..053a15988c45 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -158,7 +158,7 @@ static int __init ct82c710_detect(void)
static int ct82c710_probe(struct platform_device *dev)
{
- ct82c710_port = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ ct82c710_port = kzalloc(sizeof(*ct82c710_port), GFP_KERNEL);
if (!ct82c710_port)
return -ENOMEM;
@@ -190,7 +190,7 @@ static struct platform_driver ct82c710_driver = {
.name = "ct82c710",
},
.probe = ct82c710_probe,
- .remove_new = ct82c710_remove,
+ .remove = ct82c710_remove,
};
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 633c7de49d67..9c6ff04c46cf 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -145,7 +145,6 @@ static void gscps2_flush(struct gscps2port *ps2port)
static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
{
- unsigned long flags;
char __iomem *addr = ps2port->addr;
if (!wait_TBE(addr)) {
@@ -156,9 +155,8 @@ static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
while (gscps2_readb_status(addr) & GSC_STAT_RBNE)
/* wait */;
- spin_lock_irqsave(&ps2port->lock, flags);
- writeb(data, addr+GSC_XMTDATA);
- spin_unlock_irqrestore(&ps2port->lock, flags);
+ scoped_guard(spinlock_irqsave, &ps2port->lock)
+ writeb(data, addr+GSC_XMTDATA);
/* this is ugly, but due to timing of the port it seems to be necessary. */
mdelay(6);
@@ -177,19 +175,19 @@ static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
static void gscps2_enable(struct gscps2port *ps2port, int enable)
{
- unsigned long flags;
u8 data;
/* now enable/disable the port */
- spin_lock_irqsave(&ps2port->lock, flags);
- gscps2_flush(ps2port);
- data = gscps2_readb_control(ps2port->addr);
- if (enable)
- data |= GSC_CTRL_ENBL;
- else
- data &= ~GSC_CTRL_ENBL;
- gscps2_writeb_control(data, ps2port->addr);
- spin_unlock_irqrestore(&ps2port->lock, flags);
+ scoped_guard(spinlock_irqsave, &ps2port->lock) {
+ gscps2_flush(ps2port);
+ data = gscps2_readb_control(ps2port->addr);
+ if (enable)
+ data |= GSC_CTRL_ENBL;
+ else
+ data &= ~GSC_CTRL_ENBL;
+ gscps2_writeb_control(data, ps2port->addr);
+ }
+
wait_TBE(ps2port->addr);
gscps2_flush(ps2port);
}
@@ -200,20 +198,61 @@ static void gscps2_enable(struct gscps2port *ps2port, int enable)
static void gscps2_reset(struct gscps2port *ps2port)
{
- unsigned long flags;
-
/* reset the interface */
- spin_lock_irqsave(&ps2port->lock, flags);
+ guard(spinlock_irqsave)(&ps2port->lock);
gscps2_flush(ps2port);
writeb(0xff, ps2port->addr + GSC_RESET);
gscps2_flush(ps2port);
- spin_unlock_irqrestore(&ps2port->lock, flags);
}
static LIST_HEAD(ps2port_list);
+static void gscps2_read_data(struct gscps2port *ps2port)
+{
+ u8 status;
+
+ do {
+ status = gscps2_readb_status(ps2port->addr);
+ if (!(status & GSC_STAT_RBNE))
+ break;
+
+ ps2port->buffer[ps2port->append].str = status;
+ ps2port->buffer[ps2port->append].data =
+ gscps2_readb_input(ps2port->addr);
+ } while (true);
+}
+
+static bool gscps2_report_data(struct gscps2port *ps2port)
+{
+ unsigned int rxflags;
+ u8 data, status;
+
+ while (ps2port->act != ps2port->append) {
+ /*
+ * Did new data arrived while we read existing data ?
+ * If yes, exit now and let the new irq handler start
+ * over again.
+ */
+ if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR)
+ return true;
+
+ status = ps2port->buffer[ps2port->act].str;
+ data = ps2port->buffer[ps2port->act].data;
+
+ ps2port->act = (ps2port->act + 1) & BUFFER_SIZE;
+ rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
+ ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 );
+
+ serio_interrupt(ps2port->port, data, rxflags);
+ }
+
+ return false;
+}
+
/**
* gscps2_interrupt() - Interruption service routine
+ * @irq: interrupt number which triggered (unused)
+ * @dev: device pointer (unused)
*
* This function reads received PS/2 bytes and processes them on
* all interfaces.
@@ -229,47 +268,18 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev)
struct gscps2port *ps2port;
list_for_each_entry(ps2port, &ps2port_list, node) {
+ guard(spinlock_irqsave)(&ps2port->lock);
- unsigned long flags;
- spin_lock_irqsave(&ps2port->lock, flags);
-
- while ( (ps2port->buffer[ps2port->append].str =
- gscps2_readb_status(ps2port->addr)) & GSC_STAT_RBNE ) {
- ps2port->buffer[ps2port->append].data =
- gscps2_readb_input(ps2port->addr);
- ps2port->append = ((ps2port->append+1) & BUFFER_SIZE);
- }
-
- spin_unlock_irqrestore(&ps2port->lock, flags);
-
+ gscps2_read_data(ps2port);
} /* list_for_each_entry */
/* all data was read from the ports - now report the data to upper layer */
-
list_for_each_entry(ps2port, &ps2port_list, node) {
-
- while (ps2port->act != ps2port->append) {
-
- unsigned int rxflags;
- u8 data, status;
-
- /* Did new data arrived while we read existing data ?
- If yes, exit now and let the new irq handler start over again */
- if (gscps2_readb_status(ps2port->addr) & GSC_STAT_CMPINTR)
- return IRQ_HANDLED;
-
- status = ps2port->buffer[ps2port->act].str;
- data = ps2port->buffer[ps2port->act].data;
-
- ps2port->act = ((ps2port->act+1) & BUFFER_SIZE);
- rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
- ((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 );
-
- serio_interrupt(ps2port->port, data, rxflags);
-
- } /* while() */
-
- } /* list_for_each_entry */
+ if (gscps2_report_data(ps2port)) {
+ /* More data ready - break early to restart interrupt */
+ break;
+ }
+ }
return IRQ_HANDLED;
}
@@ -321,6 +331,8 @@ static void gscps2_close(struct serio *port)
/**
* gscps2_probe() - Probes PS2 devices
+ * @dev: pointer to parisc_device struct which will be probed
+ *
* @return: success/error report
*/
@@ -338,8 +350,8 @@ static int __init gscps2_probe(struct parisc_device *dev)
if (dev->id.sversion == 0x96)
hpa += GSC_DINO_OFFSET;
- ps2port = kzalloc(sizeof(struct gscps2port), GFP_KERNEL);
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2port = kzalloc(sizeof(*ps2port), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!ps2port || !serio) {
ret = -ENOMEM;
goto fail_nomem;
@@ -412,6 +424,8 @@ fail_nomem:
/**
* gscps2_remove() - Removes PS2 devices
+ * @dev: pointer to parisc_device which shall be removed
+ *
* @return: success/error report
*/
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index d36e89d6fc54..3fedfc5abc73 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -54,6 +54,7 @@
#include <linux/hil_mlc.h>
#include <linux/errno.h>
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -1017,7 +1018,7 @@ static int __init hil_mlc_init(void)
static void __exit hil_mlc_exit(void)
{
- del_timer_sync(&hil_mlcs_kicker);
+ timer_delete_sync(&hil_mlcs_kicker);
tasklet_kill(&hil_mlcs_tasklet);
}
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index 13eacf6ab431..1461ef319f92 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -63,6 +63,7 @@
#include <linux/hp_sdc.h>
#include <linux/errno.h>
+#include <linux/export.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
@@ -980,7 +981,7 @@ static void hp_sdc_exit(void)
free_irq(hp_sdc.irq, &hp_sdc);
write_unlock_irq(&hp_sdc.lock);
- del_timer_sync(&hp_sdc.kicker);
+ timer_delete_sync(&hp_sdc.kicker);
tasklet_kill(&hp_sdc.task);
diff --git a/drivers/input/serio/hyperv-keyboard.c b/drivers/input/serio/hyperv-keyboard.c
index 31def6ce5157..0ee7505427ac 100644
--- a/drivers/input/serio/hyperv-keyboard.c
+++ b/drivers/input/serio/hyperv-keyboard.c
@@ -102,7 +102,6 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
{
struct hv_kbd_dev *kbd_dev = hv_get_drvdata(hv_dev);
struct synth_kbd_keystroke *ks_msg;
- unsigned long flags;
u32 msg_type = __le32_to_cpu(msg->header.type);
u32 info;
u16 scan_code;
@@ -147,21 +146,22 @@ static void hv_kbd_on_receive(struct hv_device *hv_dev,
/*
* Inject the information through the serio interrupt.
*/
- spin_lock_irqsave(&kbd_dev->lock, flags);
- if (kbd_dev->started) {
- if (info & IS_E0)
- serio_interrupt(kbd_dev->hv_serio,
- XTKBD_EMUL0, 0);
- if (info & IS_E1)
- serio_interrupt(kbd_dev->hv_serio,
- XTKBD_EMUL1, 0);
- scan_code = __le16_to_cpu(ks_msg->make_code);
- if (info & IS_BREAK)
- scan_code |= XTKBD_RELEASE;
+ scoped_guard(spinlock_irqsave, &kbd_dev->lock) {
+ if (kbd_dev->started) {
+ if (info & IS_E0)
+ serio_interrupt(kbd_dev->hv_serio,
+ XTKBD_EMUL0, 0);
+ if (info & IS_E1)
+ serio_interrupt(kbd_dev->hv_serio,
+ XTKBD_EMUL1, 0);
+ scan_code = __le16_to_cpu(ks_msg->make_code);
+ if (info & IS_BREAK)
+ scan_code |= XTKBD_RELEASE;
- serio_interrupt(kbd_dev->hv_serio, scan_code, 0);
+ serio_interrupt(kbd_dev->hv_serio,
+ scan_code, 0);
+ }
}
- spin_unlock_irqrestore(&kbd_dev->lock, flags);
/*
* Only trigger a wakeup on key down, otherwise
@@ -292,11 +292,10 @@ static int hv_kbd_connect_to_vsp(struct hv_device *hv_dev)
static int hv_kbd_start(struct serio *serio)
{
struct hv_kbd_dev *kbd_dev = serio->port_data;
- unsigned long flags;
- spin_lock_irqsave(&kbd_dev->lock, flags);
+ guard(spinlock_irqsave)(&kbd_dev->lock);
+
kbd_dev->started = true;
- spin_unlock_irqrestore(&kbd_dev->lock, flags);
return 0;
}
@@ -304,11 +303,10 @@ static int hv_kbd_start(struct serio *serio)
static void hv_kbd_stop(struct serio *serio)
{
struct hv_kbd_dev *kbd_dev = serio->port_data;
- unsigned long flags;
- spin_lock_irqsave(&kbd_dev->lock, flags);
+ guard(spinlock_irqsave)(&kbd_dev->lock);
+
kbd_dev->started = false;
- spin_unlock_irqrestore(&kbd_dev->lock, flags);
}
static int hv_kbd_probe(struct hv_device *hv_dev,
@@ -318,8 +316,8 @@ static int hv_kbd_probe(struct hv_device *hv_dev,
struct serio *hv_serio;
int error;
- kbd_dev = kzalloc(sizeof(struct hv_kbd_dev), GFP_KERNEL);
- hv_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ kbd_dev = kzalloc(sizeof(*kbd_dev), GFP_KERNEL);
+ hv_serio = kzalloc(sizeof(*hv_serio), GFP_KERNEL);
if (!kbd_dev || !hv_serio) {
error = -ENOMEM;
goto err_free_mem;
diff --git a/drivers/input/serio/i8042-acpipnpio.h b/drivers/input/serio/i8042-acpipnpio.h
index 5b50475ec414..1caa6c4ca435 100644
--- a/drivers/input/serio/i8042-acpipnpio.h
+++ b/drivers/input/serio/i8042-acpipnpio.h
@@ -83,13 +83,14 @@ static inline void i8042_write_command(int val)
#define SERIO_QUIRK_KBDRESET BIT(12)
#define SERIO_QUIRK_DRITEK BIT(13)
#define SERIO_QUIRK_NOPNP BIT(14)
+#define SERIO_QUIRK_FORCENORESTORE BIT(15)
/* Quirk table for different mainboards. Options similar or identical to i8042
* module parameters.
* ORDERING IS IMPORTANT! The first match will be apllied and the rest ignored.
* This allows entries to overwrite vendor wide quirks on a per device basis.
* Where this is irrelevant, entries are sorted case sensitive by DMI_SYS_VENDOR
- * and/or DMI_BOARD_VENDOR to make it easier to avoid dublicate entries.
+ * and/or DMI_BOARD_VENDOR to make it easier to avoid duplicate entries.
*/
static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
{
@@ -627,6 +628,15 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.driver_data = (void *)(SERIO_QUIRK_NOMUX)
},
{
+ /* Fujitsu Lifebook E756 */
+ /* https://bugzilla.suse.com/show_bug.cgi?id=1229056 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E756"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_NOMUX)
+ },
+ {
/* Fujitsu Lifebook E5411 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU CLIENT COMPUTING LIMITED"),
@@ -1070,16 +1080,14 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "AURA1501"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "TUXEDO"),
DMI_MATCH(DMI_BOARD_NAME, "EDUBOOK1502"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/* Mivvy M310 */
@@ -1111,84 +1119,111 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.driver_data = (void *)(SERIO_QUIRK_NOLOOP)
},
/*
- * A lot of modern Clevo barebones have touchpad and/or keyboard issues
- * after suspend fixable with nomux + reset + noloop + nopnp. Luckily,
- * none of them have an external PS/2 port so this can safely be set for
- * all of them.
- * Clevo barebones come with board_vendor and/or system_vendor set to
- * either the very generic string "Notebook" and/or a different value
- * for each individual reseller. The only somewhat universal way to
- * identify them is by board_name.
+ * Some TongFang barebones have touchpad and/or keyboard issues after
+ * suspend fixable with nomux + reset + noloop + nopnp. Luckily, none of
+ * them have an external PS/2 port so this can safely be set for all of
+ * them.
+ * TongFang barebones come with board_vendor and/or system_vendor set to
+ * a different value for each individual reseller. The only somewhat
+ * universal way to identify them is by board_name.
*/
{
.matches = {
- DMI_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
+ DMI_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
- DMI_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
+ DMI_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
- DMI_MATCH(DMI_BOARD_NAME, "N140CU"),
+ DMI_MATCH(DMI_BOARD_NAME, "GMxXGxX"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
- DMI_MATCH(DMI_BOARD_NAME, "N141CU"),
+ DMI_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
- /*
- * Setting SERIO_QUIRK_NOMUX or SERIO_QUIRK_RESET_ALWAYS makes
- * the keyboard very laggy for ~5 seconds after boot and
- * sometimes also after resume.
- * However both are required for the keyboard to not fail
- * completely sometimes after boot or resume.
- */
.matches = {
- DMI_MATCH(DMI_BOARD_NAME, "N150CU"),
+ DMI_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
{
.matches = {
- DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
+ DMI_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
},
.driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
},
+ /*
+ * A lot of modern Clevo barebones have touchpad and/or keyboard issues
+ * after suspend fixable with the forcenorestore quirk.
+ * Clevo barebones come with board_vendor and/or system_vendor set to
+ * either the very generic string "Notebook" and/or a different value
+ * for each individual reseller. The only somewhat universal way to
+ * identify them is by board_name.
+ */
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "N140CU"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "N141CU"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "N150CU"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "NH5xAx"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
{
- /*
- * Setting SERIO_QUIRK_NOMUX or SERIO_QUIRK_RESET_ALWAYS makes
- * the keyboard very laggy for ~5 seconds after boot and
- * sometimes also after resume.
- * However both are required for the keyboard to not fail
- * completely sometimes after boot or resume.
- */
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NHxxRZQ"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NL5xRU"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
/*
* At least one modern Clevo barebone has the touchpad connected both
@@ -1204,17 +1239,15 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NS50MU"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX |
- SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
- SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_NOAUX |
+ SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NS50_70MU"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOAUX | SERIO_QUIRK_NOMUX |
- SERIO_QUIRK_RESET_ALWAYS | SERIO_QUIRK_NOLOOP |
- SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_NOAUX |
+ SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
@@ -1226,8 +1259,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "NJ50_70CU"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "P640RE"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/*
@@ -1238,16 +1276,14 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "P65xH"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/* Clevo P650RS, 650RP6, Sager NP8152-S, and others */
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "P65xRP"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/*
@@ -1258,8 +1294,7 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "P65_P67H"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/*
@@ -1270,8 +1305,7 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "P65_67RP"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/*
@@ -1282,8 +1316,7 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "P65_67RS"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/*
@@ -1294,22 +1327,43 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "P67xRP"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "PB50_70DFx,DDx"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "PB51RF"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "PB71RD"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "PC70DR"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "PCX0DX"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
+ },
+ {
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "PCX0DX_GN20"),
+ },
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
/* See comment on TUXEDO InfinityBook S17 Gen6 / Clevo NS70MU above */
{
@@ -1322,15 +1376,13 @@ static const struct dmi_system_id i8042_dmi_quirk_table[] __initconst = {
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "X170SM"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "X170KM-G"),
},
- .driver_data = (void *)(SERIO_QUIRK_NOMUX | SERIO_QUIRK_RESET_ALWAYS |
- SERIO_QUIRK_NOLOOP | SERIO_QUIRK_NOPNP)
+ .driver_data = (void *)(SERIO_QUIRK_FORCENORESTORE)
},
{
/*
@@ -1685,6 +1737,8 @@ static void __init i8042_check_quirks(void)
if (quirks & SERIO_QUIRK_NOPNP)
i8042_nopnp = true;
#endif
+ if (quirks & SERIO_QUIRK_FORCENORESTORE)
+ i8042_forcenorestore = true;
}
#else
static inline void i8042_check_quirks(void) {}
@@ -1718,7 +1772,7 @@ static int __init i8042_platform_init(void)
i8042_check_quirks();
- pr_debug("Active quirks (empty means none):%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ pr_debug("Active quirks (empty means none):%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
i8042_nokbd ? " nokbd" : "",
i8042_noaux ? " noaux" : "",
i8042_nomux ? " nomux" : "",
@@ -1738,10 +1792,11 @@ static int __init i8042_platform_init(void)
"",
#endif
#ifdef CONFIG_PNP
- i8042_nopnp ? " nopnp" : "");
+ i8042_nopnp ? " nopnp" : "",
#else
- "");
+ "",
#endif
+ i8042_forcenorestore ? " forcenorestore" : "");
retval = i8042_pnp_init();
if (retval)
diff --git a/drivers/input/serio/i8042-sparcio.h b/drivers/input/serio/i8042-sparcio.h
index c2fda54dc384..0f97158fd14e 100644
--- a/drivers/input/serio/i8042-sparcio.h
+++ b/drivers/input/serio/i8042-sparcio.h
@@ -101,23 +101,15 @@ static struct platform_driver sparc_i8042_driver = {
.of_match_table = sparc_i8042_match,
},
.probe = sparc_i8042_probe,
- .remove_new = sparc_i8042_remove,
+ .remove = sparc_i8042_remove,
};
static bool i8042_is_mr_coffee(void)
{
- struct device_node *root;
- const char *name;
- bool is_mr_coffee;
+ struct device_node *root __free(device_node) = of_find_node_by_path("/");
+ const char *name = of_get_property(root, "name", NULL);
- root = of_find_node_by_path("/");
-
- name = of_get_property(root, "name", NULL);
- is_mr_coffee = name && !strcmp(name, "SUNW,JavaStation-1");
-
- of_node_put(root);
-
- return is_mr_coffee;
+ return name && !strcmp(name, "SUNW,JavaStation-1");
}
static int __init i8042_platform_init(void)
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 9fbb8d31575a..c135254665b6 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -10,6 +10,7 @@
#include <linux/types.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
@@ -115,6 +116,10 @@ module_param_named(nopnp, i8042_nopnp, bool, 0);
MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings");
#endif
+static bool i8042_forcenorestore;
+module_param_named(forcenorestore, i8042_forcenorestore, bool, 0);
+MODULE_PARM_DESC(forcenorestore, "Force no restore on s3 resume, copying s2idle behaviour");
+
#define DEBUG
#ifdef DEBUG
static bool i8042_debug;
@@ -174,9 +179,9 @@ static unsigned char i8042_suppress_kbd_ack;
static struct platform_device *i8042_platform_device;
static struct notifier_block i8042_kbd_bind_notifier_block;
-static irqreturn_t i8042_interrupt(int irq, void *dev_id);
-static bool (*i8042_platform_filter)(unsigned char data, unsigned char str,
- struct serio *serio);
+static bool i8042_handle_data(int irq);
+static i8042_filter_t i8042_platform_filter;
+static void *i8042_platform_filter_context;
void i8042_lock_chip(void)
{
@@ -190,45 +195,29 @@ void i8042_unlock_chip(void)
}
EXPORT_SYMBOL(i8042_unlock_chip);
-int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str,
- struct serio *serio))
+int i8042_install_filter(i8042_filter_t filter, void *context)
{
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&i8042_lock, flags);
+ guard(spinlock_irqsave)(&i8042_lock);
- if (i8042_platform_filter) {
- ret = -EBUSY;
- goto out;
- }
+ if (i8042_platform_filter)
+ return -EBUSY;
i8042_platform_filter = filter;
-
-out:
- spin_unlock_irqrestore(&i8042_lock, flags);
- return ret;
+ i8042_platform_filter_context = context;
+ return 0;
}
EXPORT_SYMBOL(i8042_install_filter);
-int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str,
- struct serio *port))
+int i8042_remove_filter(i8042_filter_t filter)
{
- unsigned long flags;
- int ret = 0;
+ guard(spinlock_irqsave)(&i8042_lock);
- spin_lock_irqsave(&i8042_lock, flags);
-
- if (i8042_platform_filter != filter) {
- ret = -EINVAL;
- goto out;
- }
+ if (i8042_platform_filter != filter)
+ return -EINVAL;
i8042_platform_filter = NULL;
-
-out:
- spin_unlock_irqrestore(&i8042_lock, flags);
- return ret;
+ i8042_platform_filter_context = NULL;
+ return 0;
}
EXPORT_SYMBOL(i8042_remove_filter);
@@ -267,28 +256,22 @@ static int i8042_wait_write(void)
static int i8042_flush(void)
{
- unsigned long flags;
unsigned char data, str;
int count = 0;
- int retval = 0;
- spin_lock_irqsave(&i8042_lock, flags);
+ guard(spinlock_irqsave)(&i8042_lock);
while ((str = i8042_read_status()) & I8042_STR_OBF) {
- if (count++ < I8042_BUFFER_SIZE) {
- udelay(50);
- data = i8042_read_data();
- dbg("%02x <- i8042 (flush, %s)\n",
- data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
- } else {
- retval = -EIO;
- break;
- }
- }
+ if (count++ >= I8042_BUFFER_SIZE)
+ return -EIO;
- spin_unlock_irqrestore(&i8042_lock, flags);
+ udelay(50);
+ data = i8042_read_data();
+ dbg("%02x <- i8042 (flush, %s)\n",
+ data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
+ }
- return retval;
+ return 0;
}
/*
@@ -345,17 +328,12 @@ static int __i8042_command(unsigned char *param, int command)
int i8042_command(unsigned char *param, int command)
{
- unsigned long flags;
- int retval;
-
if (!i8042_present)
return -1;
- spin_lock_irqsave(&i8042_lock, flags);
- retval = __i8042_command(param, command);
- spin_unlock_irqrestore(&i8042_lock, flags);
+ guard(spinlock_irqsave)(&i8042_lock);
- return retval;
+ return __i8042_command(param, command);
}
EXPORT_SYMBOL(i8042_command);
@@ -365,19 +343,18 @@ EXPORT_SYMBOL(i8042_command);
static int i8042_kbd_write(struct serio *port, unsigned char c)
{
- unsigned long flags;
- int retval = 0;
+ int error;
- spin_lock_irqsave(&i8042_lock, flags);
+ guard(spinlock_irqsave)(&i8042_lock);
- if (!(retval = i8042_wait_write())) {
- dbg("%02x -> i8042 (kbd-data)\n", c);
- i8042_write_data(c);
- }
+ error = i8042_wait_write();
+ if (error)
+ return error;
- spin_unlock_irqrestore(&i8042_lock, flags);
+ dbg("%02x -> i8042 (kbd-data)\n", c);
+ i8042_write_data(c);
- return retval;
+ return 0;
}
/*
@@ -430,7 +407,7 @@ static void i8042_port_close(struct serio *serio)
* See if there is any data appeared while we were messing with
* port state.
*/
- i8042_interrupt(0, NULL);
+ i8042_handle_data(0);
}
/*
@@ -456,9 +433,8 @@ static int i8042_start(struct serio *serio)
device_set_wakeup_enable(&serio->dev, true);
}
- spin_lock_irq(&i8042_lock);
+ guard(spinlock_irq)(&i8042_lock);
port->exists = true;
- spin_unlock_irq(&i8042_lock);
return 0;
}
@@ -472,10 +448,10 @@ static void i8042_stop(struct serio *serio)
{
struct i8042_port *port = serio->port_data;
- spin_lock_irq(&i8042_lock);
- port->exists = false;
- port->serio = NULL;
- spin_unlock_irq(&i8042_lock);
+ scoped_guard(spinlock_irq, &i8042_lock) {
+ port->exists = false;
+ port->serio = NULL;
+ }
/*
* We need to make sure that interrupt handler finishes using
@@ -505,7 +481,10 @@ static bool i8042_filter(unsigned char data, unsigned char str,
}
}
- if (i8042_platform_filter && i8042_platform_filter(data, str, serio)) {
+ if (!i8042_platform_filter)
+ return false;
+
+ if (i8042_platform_filter(data, str, serio, i8042_platform_filter_context)) {
dbg("Filtered out by platform filter\n");
return true;
}
@@ -514,44 +493,10 @@ static bool i8042_filter(unsigned char data, unsigned char str,
}
/*
- * i8042_interrupt() is the most important function in this driver -
- * it handles the interrupts from the i8042, and sends incoming bytes
- * to the upper layers.
- */
-
-static irqreturn_t i8042_interrupt(int irq, void *dev_id)
-{
- struct i8042_port *port;
- struct serio *serio;
- unsigned long flags;
- unsigned char str, data;
- unsigned int dfl;
- unsigned int port_no;
- bool filtered;
- int ret = 1;
-
- spin_lock_irqsave(&i8042_lock, flags);
-
- str = i8042_read_status();
- if (unlikely(~str & I8042_STR_OBF)) {
- spin_unlock_irqrestore(&i8042_lock, flags);
- if (irq)
- dbg("Interrupt %d, without any data\n", irq);
- ret = 0;
- goto out;
- }
-
- data = i8042_read_data();
-
- if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
- static unsigned long last_transmit;
- static unsigned char last_str;
-
- dfl = 0;
- if (str & I8042_STR_MUXERR) {
- dbg("MUX error, status is %02x, data is %02x\n",
- str, data);
-/*
+ * i8042_handle_mux() handles case when data is coming from one of
+ * the multiplexed ports. It would be simple if not for quirks with
+ * handling errors:
+ *
* When MUXERR condition is signalled the data register can only contain
* 0xfd, 0xfe or 0xff if implementation follows the spec. Unfortunately
* it is not always the case. Some KBCs also report 0xfc when there is
@@ -563,50 +508,106 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id)
* rest assume that the data came from the same serio last byte
* was transmitted (if transmission happened not too long ago).
*/
-
- switch (data) {
- default:
- if (time_before(jiffies, last_transmit + HZ/10)) {
- str = last_str;
- break;
- }
- fallthrough; /* report timeout */
- case 0xfc:
- case 0xfd:
- case 0xfe: dfl = SERIO_TIMEOUT; data = 0xfe; break;
- case 0xff: dfl = SERIO_PARITY; data = 0xfe; break;
+static int i8042_handle_mux(u8 str, u8 *data, unsigned int *dfl)
+{
+ static unsigned long last_transmit;
+ static unsigned long last_port;
+ unsigned int mux_port;
+
+ mux_port = (str >> 6) & 3;
+ *dfl = 0;
+
+ if (str & I8042_STR_MUXERR) {
+ dbg("MUX error, status is %02x, data is %02x\n",
+ str, *data);
+
+ switch (*data) {
+ default:
+ if (time_before(jiffies, last_transmit + HZ/10)) {
+ mux_port = last_port;
+ break;
}
+ fallthrough; /* report timeout */
+ case 0xfc:
+ case 0xfd:
+ case 0xfe:
+ *dfl = SERIO_TIMEOUT;
+ *data = 0xfe;
+ break;
+ case 0xff:
+ *dfl = SERIO_PARITY;
+ *data = 0xfe;
+ break;
}
+ }
- port_no = I8042_MUX_PORT_NO + ((str >> 6) & 3);
- last_str = str;
- last_transmit = jiffies;
- } else {
+ last_port = mux_port;
+ last_transmit = jiffies;
- dfl = ((str & I8042_STR_PARITY) ? SERIO_PARITY : 0) |
- ((str & I8042_STR_TIMEOUT && !i8042_notimeout) ? SERIO_TIMEOUT : 0);
+ return I8042_MUX_PORT_NO + mux_port;
+}
- port_no = (str & I8042_STR_AUXDATA) ?
- I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
- }
+/*
+ * i8042_handle_data() is the most important function in this driver -
+ * it reads the data from the i8042, determines its destination serio
+ * port, and sends received byte to the upper layers.
+ *
+ * Returns true if there was data waiting, false otherwise.
+ */
+static bool i8042_handle_data(int irq)
+{
+ struct i8042_port *port;
+ struct serio *serio;
+ unsigned char str, data;
+ unsigned int dfl;
+ unsigned int port_no;
+ bool filtered;
+
+ scoped_guard(spinlock_irqsave, &i8042_lock) {
+ str = i8042_read_status();
+ if (unlikely(~str & I8042_STR_OBF))
+ return false;
- port = &i8042_ports[port_no];
- serio = port->exists ? port->serio : NULL;
+ data = i8042_read_data();
- filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n",
- port_no, irq,
- dfl & SERIO_PARITY ? ", bad parity" : "",
- dfl & SERIO_TIMEOUT ? ", timeout" : "");
+ if (i8042_mux_present && (str & I8042_STR_AUXDATA)) {
+ port_no = i8042_handle_mux(str, &data, &dfl);
+ } else {
- filtered = i8042_filter(data, str, serio);
+ dfl = (str & I8042_STR_PARITY) ? SERIO_PARITY : 0;
+ if ((str & I8042_STR_TIMEOUT) && !i8042_notimeout)
+ dfl |= SERIO_TIMEOUT;
- spin_unlock_irqrestore(&i8042_lock, flags);
+ port_no = (str & I8042_STR_AUXDATA) ?
+ I8042_AUX_PORT_NO : I8042_KBD_PORT_NO;
+ }
+
+ port = &i8042_ports[port_no];
+ serio = port->exists ? port->serio : NULL;
+
+ filter_dbg(port->driver_bound,
+ data, "<- i8042 (interrupt, %d, %d%s%s)\n",
+ port_no, irq,
+ dfl & SERIO_PARITY ? ", bad parity" : "",
+ dfl & SERIO_TIMEOUT ? ", timeout" : "");
+
+ filtered = i8042_filter(data, str, serio);
+ }
if (likely(serio && !filtered))
serio_interrupt(serio, data, dfl);
- out:
- return IRQ_RETVAL(ret);
+ return true;
+}
+
+static irqreturn_t i8042_interrupt(int irq, void *dev_id)
+{
+ if (unlikely(!i8042_handle_data(irq))) {
+ dbg("Interrupt %d, without any data\n", irq);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
}
/*
@@ -749,24 +750,22 @@ static bool i8042_irq_being_tested;
static irqreturn_t i8042_aux_test_irq(int irq, void *dev_id)
{
- unsigned long flags;
unsigned char str, data;
- int ret = 0;
- spin_lock_irqsave(&i8042_lock, flags);
+ guard(spinlock_irqsave)(&i8042_lock);
+
str = i8042_read_status();
- if (str & I8042_STR_OBF) {
- data = i8042_read_data();
- dbg("%02x <- i8042 (aux_test_irq, %s)\n",
- data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
- if (i8042_irq_being_tested &&
- data == 0xa5 && (str & I8042_STR_AUXDATA))
- complete(&i8042_aux_irq_delivered);
- ret = 1;
- }
- spin_unlock_irqrestore(&i8042_lock, flags);
+ if (!(str & I8042_STR_OBF))
+ return IRQ_NONE;
+
+ data = i8042_read_data();
+ dbg("%02x <- i8042 (aux_test_irq, %s)\n",
+ data, str & I8042_STR_AUXDATA ? "aux" : "kbd");
+
+ if (i8042_irq_being_tested && data == 0xa5 && (str & I8042_STR_AUXDATA))
+ complete(&i8042_aux_irq_delivered);
- return IRQ_RETVAL(ret);
+ return IRQ_HANDLED;
}
/*
@@ -807,7 +806,6 @@ static int i8042_check_aux(void)
int retval = -1;
bool irq_registered = false;
bool aux_loop_broken = false;
- unsigned long flags;
unsigned char param;
/*
@@ -891,18 +889,15 @@ static int i8042_check_aux(void)
if (i8042_enable_aux_port())
goto out;
- spin_lock_irqsave(&i8042_lock, flags);
-
- init_completion(&i8042_aux_irq_delivered);
- i8042_irq_being_tested = true;
+ scoped_guard(spinlock_irqsave, &i8042_lock) {
+ init_completion(&i8042_aux_irq_delivered);
+ i8042_irq_being_tested = true;
- param = 0xa5;
- retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
-
- spin_unlock_irqrestore(&i8042_lock, flags);
-
- if (retval)
- goto out;
+ param = 0xa5;
+ retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
+ if (retval)
+ goto out;
+ }
if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
msecs_to_jiffies(250)) == 0) {
@@ -990,7 +985,6 @@ static int i8042_controller_selftest(void)
static int i8042_controller_init(void)
{
- unsigned long flags;
int n = 0;
unsigned char ctr[2];
@@ -1027,14 +1021,14 @@ static int i8042_controller_init(void)
* Handle keylock.
*/
- spin_lock_irqsave(&i8042_lock, flags);
- if (~i8042_read_status() & I8042_STR_KEYLOCK) {
- if (i8042_unlock)
- i8042_ctr |= I8042_CTR_IGNKEYLOCK;
- else
- pr_warn("Warning: Keylock active\n");
+ scoped_guard(spinlock_irqsave, &i8042_lock) {
+ if (~i8042_read_status() & I8042_STR_KEYLOCK) {
+ if (i8042_unlock)
+ i8042_ctr |= I8042_CTR_IGNKEYLOCK;
+ else
+ pr_warn("Warning: Keylock active\n");
+ }
}
- spin_unlock_irqrestore(&i8042_lock, flags);
/*
* If the chip is configured into nontranslated mode by the BIOS, don't
@@ -1212,13 +1206,14 @@ static int i8042_controller_resume(bool s2r_wants_reset)
if (i8042_mux_present) {
if (i8042_set_mux_mode(true, NULL) || i8042_enable_mux_ports())
pr_warn("failed to resume active multiplexor, mouse won't work\n");
- } else if (i8042_ports[I8042_AUX_PORT_NO].serio)
+ } else if (i8042_ports[I8042_AUX_PORT_NO].serio) {
i8042_enable_aux_port();
+ }
if (i8042_ports[I8042_KBD_PORT_NO].serio)
i8042_enable_kbd_port();
- i8042_interrupt(0, NULL);
+ i8042_handle_data(0);
return 0;
}
@@ -1232,7 +1227,7 @@ static int i8042_pm_suspend(struct device *dev)
{
int i;
- if (pm_suspend_via_firmware())
+ if (!i8042_forcenorestore && pm_suspend_via_firmware())
i8042_controller_reset(true);
/* Set up serio interrupts for system wakeup. */
@@ -1248,8 +1243,8 @@ static int i8042_pm_suspend(struct device *dev)
static int i8042_pm_resume_noirq(struct device *dev)
{
- if (!pm_resume_via_firmware())
- i8042_interrupt(0, NULL);
+ if (i8042_forcenorestore || !pm_resume_via_firmware())
+ i8042_handle_data(0);
return 0;
}
@@ -1271,7 +1266,7 @@ static int i8042_pm_resume(struct device *dev)
* not restore the controller state to whatever it had been at boot
* time, so we do not need to do anything.
*/
- if (!pm_suspend_via_firmware())
+ if (i8042_forcenorestore || !pm_suspend_via_firmware())
return 0;
/*
@@ -1286,7 +1281,7 @@ static int i8042_pm_resume(struct device *dev)
static int i8042_pm_thaw(struct device *dev)
{
- i8042_interrupt(0, NULL);
+ i8042_handle_data(0);
return 0;
}
@@ -1329,7 +1324,7 @@ static int i8042_create_kbd_port(void)
struct serio *serio;
struct i8042_port *port = &i8042_ports[I8042_KBD_PORT_NO];
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
@@ -1359,7 +1354,7 @@ static int i8042_create_aux_port(int idx)
int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
struct i8042_port *port = &i8042_ports[port_no];
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
@@ -1599,7 +1594,7 @@ static struct platform_driver i8042_driver = {
#endif
},
.probe = i8042_probe,
- .remove_new = i8042_remove,
+ .remove = i8042_remove,
.shutdown = i8042_shutdown,
};
diff --git a/drivers/input/serio/ioc3kbd.c b/drivers/input/serio/ioc3kbd.c
index 676b0bda3d72..d2c7ffb9a946 100644
--- a/drivers/input/serio/ioc3kbd.c
+++ b/drivers/input/serio/ioc3kbd.c
@@ -208,7 +208,7 @@ MODULE_DEVICE_TABLE(platform, ioc3kbd_id_table);
static struct platform_driver ioc3kbd_driver = {
.probe = ioc3kbd_probe,
- .remove_new = ioc3kbd_remove,
+ .remove = ioc3kbd_remove,
.id_table = ioc3kbd_id_table,
.driver = {
.name = "ioc3-kbd",
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index 6d78a1fe00c1..269df83a167d 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -8,6 +8,7 @@
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
@@ -108,13 +109,11 @@ int ps2_sendbyte(struct ps2dev *ps2dev, u8 byte, unsigned int timeout)
{
int retval;
- serio_pause_rx(ps2dev->serio);
+ guard(serio_pause_rx)(ps2dev->serio);
retval = ps2_do_sendbyte(ps2dev, byte, timeout, 1);
dev_dbg(&ps2dev->serio->dev, "%02x - %x\n", byte, ps2dev->nak);
- serio_continue_rx(ps2dev->serio);
-
return retval;
}
EXPORT_SYMBOL(ps2_sendbyte);
@@ -162,10 +161,10 @@ void ps2_drain(struct ps2dev *ps2dev, size_t maxbytes, unsigned int timeout)
ps2_begin_command(ps2dev);
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = PS2_FLAG_CMD;
- ps2dev->cmdcnt = maxbytes;
- serio_continue_rx(ps2dev->serio);
+ scoped_guard(serio_pause_rx, ps2dev->serio) {
+ ps2dev->flags = PS2_FLAG_CMD;
+ ps2dev->cmdcnt = maxbytes;
+ }
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD),
@@ -224,9 +223,9 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev,
* use alternative probe to detect it.
*/
if (ps2dev->cmdbuf[1] == 0xaa) {
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = 0;
- serio_continue_rx(ps2dev->serio);
+ scoped_guard(serio_pause_rx, ps2dev->serio)
+ ps2dev->flags = 0;
+
timeout = 0;
}
@@ -235,9 +234,9 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev,
* won't be 2nd byte of ID response.
*/
if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = ps2dev->cmdcnt = 0;
- serio_continue_rx(ps2dev->serio);
+ scoped_guard(serio_pause_rx, ps2dev->serio)
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+
timeout = 0;
}
break;
@@ -283,6 +282,10 @@ int __ps2_command(struct ps2dev *ps2dev, u8 *param, unsigned int command)
memcpy(send_param, param, send);
+ /*
+ * Not using guard notation because we need to break critical
+ * section below while waiting for the response.
+ */
serio_pause_rx(ps2dev->serio);
ps2dev->cmdcnt = receive;
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index 5ccfb82759b3..3d28a5cddd61 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -117,7 +117,7 @@ static struct serio *maceps2_allocate_port(int idx)
{
struct serio *serio;
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (serio) {
serio->id.type = SERIO_8042;
serio->write = maceps2_write;
@@ -159,7 +159,7 @@ static struct platform_driver maceps2_driver = {
.name = "maceps2",
},
.probe = maceps2_probe,
- .remove_new = maceps2_remove,
+ .remove = maceps2_remove,
};
static int __init maceps2_init(void)
diff --git a/drivers/input/serio/olpc_apsp.c b/drivers/input/serio/olpc_apsp.c
index 240a714f7081..a24324830021 100644
--- a/drivers/input/serio/olpc_apsp.c
+++ b/drivers/input/serio/olpc_apsp.c
@@ -188,7 +188,7 @@ static int olpc_apsp_probe(struct platform_device *pdev)
return priv->irq;
/* KEYBOARD */
- kb_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ kb_serio = kzalloc(sizeof(*kb_serio), GFP_KERNEL);
if (!kb_serio)
return -ENOMEM;
kb_serio->id.type = SERIO_8042_XL;
@@ -203,7 +203,7 @@ static int olpc_apsp_probe(struct platform_device *pdev)
serio_register_port(kb_serio);
/* TOUCHPAD */
- pad_serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ pad_serio = kzalloc(sizeof(*pad_serio), GFP_KERNEL);
if (!pad_serio) {
error = -ENOMEM;
goto err_pad;
@@ -256,7 +256,7 @@ MODULE_DEVICE_TABLE(of, olpc_apsp_dt_ids);
static struct platform_driver olpc_apsp_driver = {
.probe = olpc_apsp_probe,
- .remove_new = olpc_apsp_remove,
+ .remove = olpc_apsp_remove,
.driver = {
.name = "olpc-apsp",
.of_match_table = olpc_apsp_dt_ids,
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index 0d54895428f5..22fe55490572 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -165,7 +165,7 @@ static struct serio *parkbd_allocate_serio(void)
{
struct serio *serio;
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (serio) {
serio->id.type = parkbd_mode;
serio->write = parkbd_write;
@@ -218,6 +218,5 @@ static struct parport_driver parkbd_parport_driver = {
.name = "parkbd",
.match_port = parkbd_attach,
.detach = parkbd_detach,
- .devmodel = true,
};
module_parport_driver(parkbd_parport_driver);
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index 05878750f2c2..6b9abb2e18c9 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -137,8 +137,8 @@ static int pcips2_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (ret)
goto disable;
- ps2if = kzalloc(sizeof(struct pcips2_data), GFP_KERNEL);
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2if = kzalloc(sizeof(*ps2if), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM;
goto release;
diff --git a/drivers/input/serio/ps2-gpio.c b/drivers/input/serio/ps2-gpio.c
index c3ff60859a03..46fb7667b244 100644
--- a/drivers/input/serio/ps2-gpio.c
+++ b/drivers/input/serio/ps2-gpio.c
@@ -50,7 +50,7 @@
* interrupt interval should be ~60us. Let's allow +/- 20us for frequency
* deviations and interrupt latency.
*
- * The data line must be samples after ~30us to 50us after the falling edge,
+ * The data line must be sampled after ~30us to 50us after the falling edge,
* since the device updates the data line at the rising edge.
*
* ___ ______ ______ ______ ___
@@ -133,12 +133,12 @@ static int ps2_gpio_write(struct serio *serio, unsigned char val)
int ret = 0;
if (in_task()) {
- mutex_lock(&drvdata->tx.mutex);
+ guard(mutex)(&drvdata->tx.mutex);
+
__ps2_gpio_write(serio, val);
if (!wait_for_completion_timeout(&drvdata->tx.complete,
msecs_to_jiffies(10000)))
ret = SERIO_TIMEOUT;
- mutex_unlock(&drvdata->tx.mutex);
} else {
__ps2_gpio_write(serio, val);
}
@@ -404,8 +404,8 @@ static int ps2_gpio_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int error;
- drvdata = devm_kzalloc(dev, sizeof(struct ps2_gpio_data), GFP_KERNEL);
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!drvdata || !serio) {
error = -ENOMEM;
goto err_free_serio;
@@ -429,16 +429,14 @@ static int ps2_gpio_probe(struct platform_device *pdev)
}
error = devm_request_irq(dev, drvdata->irq, ps2_gpio_irq,
- IRQF_NO_THREAD, DRIVER_NAME, drvdata);
+ IRQF_NO_THREAD | IRQF_NO_AUTOEN, DRIVER_NAME,
+ drvdata);
if (error) {
dev_err(dev, "failed to request irq %d: %d\n",
drvdata->irq, error);
goto err_free_serio;
}
- /* Keep irq disabled until serio->open is called. */
- disable_irq(drvdata->irq);
-
serio->id.type = SERIO_8042;
serio->open = ps2_gpio_open;
serio->close = ps2_gpio_close;
@@ -493,7 +491,7 @@ MODULE_DEVICE_TABLE(of, ps2_gpio_match);
static struct platform_driver ps2_gpio_driver = {
.probe = ps2_gpio_probe,
- .remove_new = ps2_gpio_remove,
+ .remove = ps2_gpio_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(ps2_gpio_match),
diff --git a/drivers/input/serio/ps2mult.c b/drivers/input/serio/ps2mult.c
index 902e81826fbf..b96cee52fc52 100644
--- a/drivers/input/serio/ps2mult.c
+++ b/drivers/input/serio/ps2mult.c
@@ -76,9 +76,8 @@ static int ps2mult_serio_write(struct serio *serio, unsigned char data)
struct ps2mult *psm = serio_get_drvdata(mx_port);
struct ps2mult_port *port = serio->port_data;
bool need_escape;
- unsigned long flags;
- spin_lock_irqsave(&psm->lock, flags);
+ guard(spinlock_irqsave)(&psm->lock);
if (psm->out_port != port)
ps2mult_select_port(psm, port);
@@ -93,8 +92,6 @@ static int ps2mult_serio_write(struct serio *serio, unsigned char data)
serio_write(mx_port, data);
- spin_unlock_irqrestore(&psm->lock, flags);
-
return 0;
}
@@ -102,11 +99,10 @@ static int ps2mult_serio_start(struct serio *serio)
{
struct ps2mult *psm = serio_get_drvdata(serio->parent);
struct ps2mult_port *port = serio->port_data;
- unsigned long flags;
- spin_lock_irqsave(&psm->lock, flags);
+ guard(spinlock_irqsave)(&psm->lock);
+
port->registered = true;
- spin_unlock_irqrestore(&psm->lock, flags);
return 0;
}
@@ -115,11 +111,10 @@ static void ps2mult_serio_stop(struct serio *serio)
{
struct ps2mult *psm = serio_get_drvdata(serio->parent);
struct ps2mult_port *port = serio->port_data;
- unsigned long flags;
- spin_lock_irqsave(&psm->lock, flags);
+ guard(spinlock_irqsave)(&psm->lock);
+
port->registered = false;
- spin_unlock_irqrestore(&psm->lock, flags);
}
static int ps2mult_create_port(struct ps2mult *psm, int i)
@@ -127,7 +122,7 @@ static int ps2mult_create_port(struct ps2mult *psm, int i)
struct serio *mx_serio = psm->mx_serio;
struct serio *serio;
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
@@ -148,16 +143,12 @@ static int ps2mult_create_port(struct ps2mult *psm, int i)
static void ps2mult_reset(struct ps2mult *psm)
{
- unsigned long flags;
-
- spin_lock_irqsave(&psm->lock, flags);
+ guard(spinlock_irqsave)(&psm->lock);
serio_write(psm->mx_serio, PS2MULT_SESSION_END);
serio_write(psm->mx_serio, PS2MULT_SESSION_START);
ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
-
- spin_unlock_irqrestore(&psm->lock, flags);
}
static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
@@ -234,11 +225,10 @@ static irqreturn_t ps2mult_interrupt(struct serio *serio,
{
struct ps2mult *psm = serio_get_drvdata(serio);
struct ps2mult_port *in_port;
- unsigned long flags;
dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
- spin_lock_irqsave(&psm->lock, flags);
+ guard(spinlock_irqsave)(&psm->lock);
if (psm->escape) {
psm->escape = false;
@@ -285,7 +275,6 @@ static irqreturn_t ps2mult_interrupt(struct serio *serio,
}
out:
- spin_unlock_irqrestore(&psm->lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index 3f81f8749cd5..ae55c4de092f 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -39,17 +39,14 @@ struct q40kbd {
static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
{
struct q40kbd *q40kbd = dev_id;
- unsigned long flags;
- spin_lock_irqsave(&q40kbd->lock, flags);
+ guard(spinlock_irqsave)(&q40kbd->lock);
if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
serio_interrupt(q40kbd->port, master_inb(KEYCODE_REG), 0);
master_outb(-1, KEYBOARD_UNLOCK_REG);
- spin_unlock_irqrestore(&q40kbd->lock, flags);
-
return IRQ_HANDLED;
}
@@ -60,14 +57,11 @@ static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
static void q40kbd_flush(struct q40kbd *q40kbd)
{
int maxread = 100;
- unsigned long flags;
- spin_lock_irqsave(&q40kbd->lock, flags);
+ guard(spinlock_irqsave)(&q40kbd->lock);
while (maxread-- && (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG)))
master_inb(KEYCODE_REG);
-
- spin_unlock_irqrestore(&q40kbd->lock, flags);
}
static void q40kbd_stop(void)
@@ -108,8 +102,8 @@ static int q40kbd_probe(struct platform_device *pdev)
struct serio *port;
int error;
- q40kbd = kzalloc(sizeof(struct q40kbd), GFP_KERNEL);
- port = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ q40kbd = kzalloc(sizeof(*q40kbd), GFP_KERNEL);
+ port = kzalloc(sizeof(*port), GFP_KERNEL);
if (!q40kbd || !port) {
error = -ENOMEM;
goto err_free_mem;
@@ -166,7 +160,7 @@ static struct platform_driver q40kbd_driver = {
.driver = {
.name = "q40kbd",
},
- .remove_new = q40kbd_remove,
+ .remove = q40kbd_remove,
};
module_platform_driver_probe(q40kbd_driver, q40kbd_probe);
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 9bbfefd092c0..c65c552b0c45 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -108,7 +108,7 @@ static int rpckbd_probe(struct platform_device *dev)
if (tx_irq < 0)
return tx_irq;
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
rpckbd = kzalloc(sizeof(*rpckbd), GFP_KERNEL);
if (!serio || !rpckbd) {
kfree(rpckbd);
@@ -144,7 +144,7 @@ static void rpckbd_remove(struct platform_device *dev)
static struct platform_driver rpckbd_driver = {
.probe = rpckbd_probe,
- .remove_new = rpckbd_remove,
+ .remove = rpckbd_remove,
.driver = {
.name = "kart",
},
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index 2724c3aa512c..375c6f5f905c 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -92,7 +92,8 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
struct ps2if *ps2if = dev_id;
unsigned int status;
- spin_lock(&ps2if->lock);
+ guard(spinlock)(&ps2if->lock);
+
status = readl_relaxed(ps2if->base + PS2STAT);
if (ps2if->head == ps2if->tail) {
disable_irq_nosync(irq);
@@ -101,7 +102,6 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
writel_relaxed(ps2if->buf[ps2if->tail], ps2if->base + PS2DATA);
ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
}
- spin_unlock(&ps2if->lock);
return IRQ_HANDLED;
}
@@ -113,10 +113,9 @@ static irqreturn_t ps2_txint(int irq, void *dev_id)
static int ps2_write(struct serio *io, unsigned char val)
{
struct ps2if *ps2if = io->port_data;
- unsigned long flags;
unsigned int head;
- spin_lock_irqsave(&ps2if->lock, flags);
+ guard(spinlock_irqsave)(&ps2if->lock);
/*
* If the TX register is empty, we can go straight out.
@@ -133,7 +132,6 @@ static int ps2_write(struct serio *io, unsigned char val)
}
}
- spin_unlock_irqrestore(&ps2if->lock, flags);
return 0;
}
@@ -256,8 +254,8 @@ static int ps2_probe(struct sa1111_dev *dev)
struct serio *serio;
int ret;
- ps2if = kzalloc(sizeof(struct ps2if), GFP_KERNEL);
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ ps2if = kzalloc(sizeof(*ps2if), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!ps2if || !serio) {
ret = -ENOMEM;
goto free;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index a8838b522627..2b5ddc5dac19 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -9,6 +9,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/export.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/serio.h>
@@ -38,33 +39,27 @@ static void serio_attach_driver(struct serio_driver *drv);
static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
{
- int retval;
-
- mutex_lock(&serio->drv_mutex);
- retval = drv->connect(serio, drv);
- mutex_unlock(&serio->drv_mutex);
+ guard(mutex)(&serio->drv_mutex);
- return retval;
+ return drv->connect(serio, drv);
}
static int serio_reconnect_driver(struct serio *serio)
{
- int retval = -1;
+ guard(mutex)(&serio->drv_mutex);
- mutex_lock(&serio->drv_mutex);
if (serio->drv && serio->drv->reconnect)
- retval = serio->drv->reconnect(serio);
- mutex_unlock(&serio->drv_mutex);
+ return serio->drv->reconnect(serio);
- return retval;
+ return -1;
}
static void serio_disconnect_driver(struct serio *serio)
{
- mutex_lock(&serio->drv_mutex);
+ guard(mutex)(&serio->drv_mutex);
+
if (serio->drv)
serio->drv->disconnect(serio);
- mutex_unlock(&serio->drv_mutex);
}
static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
@@ -147,9 +142,8 @@ static LIST_HEAD(serio_event_list);
static struct serio_event *serio_get_event(void)
{
struct serio_event *event = NULL;
- unsigned long flags;
- spin_lock_irqsave(&serio_event_lock, flags);
+ guard(spinlock_irqsave)(&serio_event_lock);
if (!list_empty(&serio_event_list)) {
event = list_first_entry(&serio_event_list,
@@ -157,7 +151,6 @@ static struct serio_event *serio_get_event(void)
list_del_init(&event->node);
}
- spin_unlock_irqrestore(&serio_event_lock, flags);
return event;
}
@@ -171,9 +164,8 @@ static void serio_remove_duplicate_events(void *object,
enum serio_event_type type)
{
struct serio_event *e, *next;
- unsigned long flags;
- spin_lock_irqsave(&serio_event_lock, flags);
+ guard(spinlock_irqsave)(&serio_event_lock);
list_for_each_entry_safe(e, next, &serio_event_list, node) {
if (object == e->object) {
@@ -189,15 +181,13 @@ static void serio_remove_duplicate_events(void *object,
serio_free_event(e);
}
}
-
- spin_unlock_irqrestore(&serio_event_lock, flags);
}
static void serio_handle_event(struct work_struct *work)
{
struct serio_event *event;
- mutex_lock(&serio_mutex);
+ guard(mutex)(&serio_mutex);
while ((event = serio_get_event())) {
@@ -228,8 +218,6 @@ static void serio_handle_event(struct work_struct *work)
serio_remove_duplicate_events(event->object, event->type);
serio_free_event(event);
}
-
- mutex_unlock(&serio_mutex);
}
static DECLARE_WORK(serio_event_work, serio_handle_event);
@@ -237,11 +225,9 @@ static DECLARE_WORK(serio_event_work, serio_handle_event);
static int serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type)
{
- unsigned long flags;
struct serio_event *event;
- int retval = 0;
- spin_lock_irqsave(&serio_event_lock, flags);
+ guard(spinlock_irqsave)(&serio_event_lock);
/*
* Scan event list for the other events for the same serio port,
@@ -253,24 +239,22 @@ static int serio_queue_event(void *object, struct module *owner,
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
- goto out;
+ return 0;
break;
}
}
- event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC);
+ event = kmalloc(sizeof(*event), GFP_ATOMIC);
if (!event) {
pr_err("Not enough memory to queue event %d\n", event_type);
- retval = -ENOMEM;
- goto out;
+ return -ENOMEM;
}
if (!try_module_get(owner)) {
pr_warn("Can't get module reference, dropping event %d\n",
event_type);
kfree(event);
- retval = -EINVAL;
- goto out;
+ return -EINVAL;
}
event->type = event_type;
@@ -280,9 +264,7 @@ static int serio_queue_event(void *object, struct module *owner,
list_add_tail(&event->node, &serio_event_list);
queue_work(system_long_wq, &serio_event_work);
-out:
- spin_unlock_irqrestore(&serio_event_lock, flags);
- return retval;
+ return 0;
}
/*
@@ -292,9 +274,8 @@ out:
static void serio_remove_pending_events(void *object)
{
struct serio_event *event, *next;
- unsigned long flags;
- spin_lock_irqsave(&serio_event_lock, flags);
+ guard(spinlock_irqsave)(&serio_event_lock);
list_for_each_entry_safe(event, next, &serio_event_list, node) {
if (event->object == object) {
@@ -302,8 +283,6 @@ static void serio_remove_pending_events(void *object)
serio_free_event(event);
}
}
-
- spin_unlock_irqrestore(&serio_event_lock, flags);
}
/*
@@ -315,23 +294,19 @@ static void serio_remove_pending_events(void *object)
static struct serio *serio_get_pending_child(struct serio *parent)
{
struct serio_event *event;
- struct serio *serio, *child = NULL;
- unsigned long flags;
+ struct serio *serio;
- spin_lock_irqsave(&serio_event_lock, flags);
+ guard(spinlock_irqsave)(&serio_event_lock);
list_for_each_entry(event, &serio_event_list, node) {
if (event->type == SERIO_REGISTER_PORT) {
serio = event->object;
- if (serio->parent == parent) {
- child = serio;
- break;
- }
+ if (serio->parent == parent)
+ return serio;
}
}
- spin_unlock_irqrestore(&serio_event_lock, flags);
- return child;
+ return NULL;
}
/*
@@ -382,29 +357,27 @@ static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, c
struct device_driver *drv;
int error;
- error = mutex_lock_interruptible(&serio_mutex);
- if (error)
- return error;
-
- if (!strncmp(buf, "none", count)) {
- serio_disconnect_port(serio);
- } else if (!strncmp(buf, "reconnect", count)) {
- serio_reconnect_subtree(serio);
- } else if (!strncmp(buf, "rescan", count)) {
- serio_disconnect_port(serio);
- serio_find_driver(serio);
- serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
- } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
- serio_disconnect_port(serio);
- error = serio_bind_driver(serio, to_serio_driver(drv));
- serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
- } else {
- error = -EINVAL;
+ scoped_cond_guard(mutex_intr, return -EINTR, &serio_mutex) {
+ if (!strncmp(buf, "none", count)) {
+ serio_disconnect_port(serio);
+ } else if (!strncmp(buf, "reconnect", count)) {
+ serio_reconnect_subtree(serio);
+ } else if (!strncmp(buf, "rescan", count)) {
+ serio_disconnect_port(serio);
+ serio_find_driver(serio);
+ serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
+ } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
+ serio_disconnect_port(serio);
+ error = serio_bind_driver(serio, to_serio_driver(drv));
+ serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
+ if (error)
+ return error;
+ } else {
+ return -EINVAL;
+ }
}
- mutex_unlock(&serio_mutex);
-
- return error ? error : count;
+ return count;
}
static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf)
@@ -526,9 +499,9 @@ static void serio_add_port(struct serio *serio)
int error;
if (parent) {
- serio_pause_rx(parent);
+ guard(serio_pause_rx)(parent);
+
list_add_tail(&serio->child_node, &parent->children);
- serio_continue_rx(parent);
}
list_add_tail(&serio->node, &serio_list);
@@ -560,9 +533,9 @@ static void serio_destroy_port(struct serio *serio)
serio->stop(serio);
if (serio->parent) {
- serio_pause_rx(serio->parent);
+ guard(serio_pause_rx)(serio->parent);
+
list_del_init(&serio->child_node);
- serio_continue_rx(serio->parent);
serio->parent = NULL;
}
@@ -701,10 +674,10 @@ EXPORT_SYMBOL(__serio_register_port);
*/
void serio_unregister_port(struct serio *serio)
{
- mutex_lock(&serio_mutex);
+ guard(mutex)(&serio_mutex);
+
serio_disconnect_port(serio);
serio_destroy_port(serio);
- mutex_unlock(&serio_mutex);
}
EXPORT_SYMBOL(serio_unregister_port);
@@ -715,12 +688,12 @@ void serio_unregister_child_port(struct serio *serio)
{
struct serio *s, *next;
- mutex_lock(&serio_mutex);
+ guard(mutex)(&serio_mutex);
+
list_for_each_entry_safe(s, next, &serio->children, child_node) {
serio_disconnect_port(s);
serio_destroy_port(s);
}
- mutex_unlock(&serio_mutex);
}
EXPORT_SYMBOL(serio_unregister_child_port);
@@ -784,10 +757,10 @@ static void serio_driver_remove(struct device *dev)
static void serio_cleanup(struct serio *serio)
{
- mutex_lock(&serio->drv_mutex);
+ guard(mutex)(&serio->drv_mutex);
+
if (serio->drv && serio->drv->cleanup)
serio->drv->cleanup(serio);
- mutex_unlock(&serio->drv_mutex);
}
static void serio_shutdown(struct device *dev)
@@ -850,7 +823,7 @@ void serio_unregister_driver(struct serio_driver *drv)
{
struct serio *serio;
- mutex_lock(&serio_mutex);
+ guard(mutex)(&serio_mutex);
drv->manual_bind = true; /* so serio_find_driver ignores it */
serio_remove_pending_events(drv);
@@ -866,21 +839,20 @@ start_over:
}
driver_unregister(&drv->driver);
- mutex_unlock(&serio_mutex);
}
EXPORT_SYMBOL(serio_unregister_driver);
static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
- serio_pause_rx(serio);
+ guard(serio_pause_rx)(serio);
+
serio->drv = drv;
- serio_continue_rx(serio);
}
-static int serio_bus_match(struct device *dev, struct device_driver *drv)
+static int serio_bus_match(struct device *dev, const struct device_driver *drv)
{
struct serio *serio = to_serio_port(dev);
- struct serio_driver *serio_drv = to_serio_driver(drv);
+ const struct serio_driver *serio_drv = to_serio_driver(drv);
if (serio->manual_bind || serio_drv->manual_bind)
return 0;
@@ -935,14 +907,14 @@ static int serio_resume(struct device *dev)
struct serio *serio = to_serio_port(dev);
int error = -ENOENT;
- mutex_lock(&serio->drv_mutex);
- if (serio->drv && serio->drv->fast_reconnect) {
- error = serio->drv->fast_reconnect(serio);
- if (error && error != -ENOENT)
- dev_warn(dev, "fast reconnect failed with error %d\n",
- error);
+ scoped_guard(mutex, &serio->drv_mutex) {
+ if (serio->drv && serio->drv->fast_reconnect) {
+ error = serio->drv->fast_reconnect(serio);
+ if (error && error != -ENOENT)
+ dev_warn(dev, "fast reconnect failed with error %d\n",
+ error);
+ }
}
- mutex_unlock(&serio->drv_mutex);
if (error) {
/*
@@ -989,21 +961,17 @@ EXPORT_SYMBOL(serio_close);
irqreturn_t serio_interrupt(struct serio *serio,
unsigned char data, unsigned int dfl)
{
- unsigned long flags;
- irqreturn_t ret = IRQ_NONE;
+ guard(spinlock_irqsave)(&serio->lock);
- spin_lock_irqsave(&serio->lock, flags);
+ if (likely(serio->drv))
+ return serio->drv->interrupt(serio, data, dfl);
- if (likely(serio->drv)) {
- ret = serio->drv->interrupt(serio, data, dfl);
- } else if (!dfl && device_is_registered(&serio->dev)) {
+ if (!dfl && device_is_registered(&serio->dev)) {
serio_rescan(serio);
- ret = IRQ_HANDLED;
+ return IRQ_HANDLED;
}
- spin_unlock_irqrestore(&serio->lock, flags);
-
- return ret;
+ return IRQ_NONE;
}
EXPORT_SYMBOL(serio_interrupt);
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 1e4770094415..4d6395088986 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -29,7 +29,7 @@ struct serio_raw {
unsigned char queue[SERIO_RAW_QUEUE_LEN];
unsigned int tail, head;
- char name[16];
+ char name[20];
struct kref kref;
struct serio *serio;
struct miscdevice dev;
@@ -75,41 +75,31 @@ static int serio_raw_open(struct inode *inode, struct file *file)
{
struct serio_raw *serio_raw;
struct serio_raw_client *client;
- int retval;
- retval = mutex_lock_interruptible(&serio_raw_mutex);
- if (retval)
- return retval;
+ scoped_guard(mutex_intr, &serio_raw_mutex) {
+ serio_raw = serio_raw_locate(iminor(inode));
+ if (!serio_raw)
+ return -ENODEV;
- serio_raw = serio_raw_locate(iminor(inode));
- if (!serio_raw) {
- retval = -ENODEV;
- goto out;
- }
+ if (serio_raw->dead)
+ return -ENODEV;
- if (serio_raw->dead) {
- retval = -ENODEV;
- goto out;
- }
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (!client)
+ return -ENOMEM;
- client = kzalloc(sizeof(struct serio_raw_client), GFP_KERNEL);
- if (!client) {
- retval = -ENOMEM;
- goto out;
- }
+ client->serio_raw = serio_raw;
+ file->private_data = client;
- client->serio_raw = serio_raw;
- file->private_data = client;
+ kref_get(&serio_raw->kref);
- kref_get(&serio_raw->kref);
+ scoped_guard(serio_pause_rx, serio_raw->serio)
+ list_add_tail(&client->node, &serio_raw->client_list);
- serio_pause_rx(serio_raw->serio);
- list_add_tail(&client->node, &serio_raw->client_list);
- serio_continue_rx(serio_raw->serio);
+ return 0;
+ }
-out:
- mutex_unlock(&serio_raw_mutex);
- return retval;
+ return -EINTR;
}
static void serio_raw_free(struct kref *kref)
@@ -126,9 +116,8 @@ static int serio_raw_release(struct inode *inode, struct file *file)
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
- serio_pause_rx(serio_raw->serio);
- list_del(&client->node);
- serio_continue_rx(serio_raw->serio);
+ scoped_guard(serio_pause_rx, serio_raw->serio)
+ list_del(&client->node);
kfree(client);
@@ -139,19 +128,15 @@ static int serio_raw_release(struct inode *inode, struct file *file)
static bool serio_raw_fetch_byte(struct serio_raw *serio_raw, char *c)
{
- bool empty;
+ guard(serio_pause_rx)(serio_raw->serio);
- serio_pause_rx(serio_raw->serio);
-
- empty = serio_raw->head == serio_raw->tail;
- if (!empty) {
- *c = serio_raw->queue[serio_raw->tail];
- serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
- }
+ if (serio_raw->head == serio_raw->tail)
+ return false; /* queue is empty */
- serio_continue_rx(serio_raw->serio);
+ *c = serio_raw->queue[serio_raw->tail];
+ serio_raw->tail = (serio_raw->tail + 1) % SERIO_RAW_QUEUE_LEN;
- return !empty;
+ return true;
}
static ssize_t serio_raw_read(struct file *file, char __user *buffer,
@@ -200,40 +185,32 @@ static ssize_t serio_raw_write(struct file *file, const char __user *buffer,
{
struct serio_raw_client *client = file->private_data;
struct serio_raw *serio_raw = client->serio_raw;
- int retval = 0;
+ int written = 0;
unsigned char c;
- retval = mutex_lock_interruptible(&serio_raw_mutex);
- if (retval)
- return retval;
+ scoped_guard(mutex_intr, &serio_raw_mutex) {
+ if (serio_raw->dead)
+ return -ENODEV;
- if (serio_raw->dead) {
- retval = -ENODEV;
- goto out;
- }
+ if (count > 32)
+ count = 32;
- if (count > 32)
- count = 32;
+ while (count--) {
+ if (get_user(c, buffer++))
+ return -EFAULT;
- while (count--) {
- if (get_user(c, buffer++)) {
- retval = -EFAULT;
- goto out;
- }
+ if (serio_write(serio_raw->serio, c)) {
+ /* Either signal error or partial write */
+ return written ?: -EIO;
+ }
- if (serio_write(serio_raw->serio, c)) {
- /* Either signal error or partial write */
- if (retval == 0)
- retval = -EIO;
- goto out;
+ written++;
}
- retval++;
+ return written;
}
-out:
- mutex_unlock(&serio_raw_mutex);
- return retval;
+ return -EINTR;
}
static __poll_t serio_raw_poll(struct file *file, poll_table *wait)
@@ -293,14 +270,14 @@ static int serio_raw_connect(struct serio *serio, struct serio_driver *drv)
struct serio_raw *serio_raw;
int err;
- serio_raw = kzalloc(sizeof(struct serio_raw), GFP_KERNEL);
+ serio_raw = kzalloc(sizeof(*serio_raw), GFP_KERNEL);
if (!serio_raw) {
dev_dbg(&serio->dev, "can't allocate memory for a device\n");
return -ENOMEM;
}
snprintf(serio_raw->name, sizeof(serio_raw->name),
- "serio_raw%ld", (long)atomic_inc_return(&serio_raw_no));
+ "serio_raw%u", atomic_inc_return(&serio_raw_no));
kref_init(&serio_raw->kref);
INIT_LIST_HEAD(&serio_raw->client_list);
init_waitqueue_head(&serio_raw->wait);
@@ -379,10 +356,10 @@ static void serio_raw_hangup(struct serio_raw *serio_raw)
{
struct serio_raw_client *client;
- serio_pause_rx(serio_raw->serio);
- list_for_each_entry(client, &serio_raw->client_list, node)
- kill_fasync(&client->fasync, SIGIO, POLL_HUP);
- serio_continue_rx(serio_raw->serio);
+ scoped_guard(serio_pause_rx, serio_raw->serio) {
+ list_for_each_entry(client, &serio_raw->client_list, node)
+ kill_fasync(&client->fasync, SIGIO, POLL_HUP);
+ }
wake_up_interruptible(&serio_raw->wait);
}
@@ -394,10 +371,10 @@ static void serio_raw_disconnect(struct serio *serio)
misc_deregister(&serio_raw->dev);
- mutex_lock(&serio_raw_mutex);
- serio_raw->dead = true;
- list_del_init(&serio_raw->node);
- mutex_unlock(&serio_raw_mutex);
+ scoped_guard(mutex, &serio_raw_mutex) {
+ serio_raw->dead = true;
+ list_del_init(&serio_raw->node);
+ }
serio_raw_hangup(serio_raw);
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 1db3f30011c4..74ac88796187 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -50,11 +50,9 @@ static int serport_serio_write(struct serio *serio, unsigned char data)
static int serport_serio_open(struct serio *serio)
{
struct serport *serport = serio->port_data;
- unsigned long flags;
- spin_lock_irqsave(&serport->lock, flags);
+ guard(spinlock_irqsave)(&serport->lock);
set_bit(SERPORT_ACTIVE, &serport->flags);
- spin_unlock_irqrestore(&serport->lock, flags);
return 0;
}
@@ -63,11 +61,9 @@ static int serport_serio_open(struct serio *serio)
static void serport_serio_close(struct serio *serio)
{
struct serport *serport = serio->port_data;
- unsigned long flags;
- spin_lock_irqsave(&serport->lock, flags);
+ guard(spinlock_irqsave)(&serport->lock);
clear_bit(SERPORT_ACTIVE, &serport->flags);
- spin_unlock_irqrestore(&serport->lock, flags);
}
/*
@@ -82,7 +78,7 @@ static int serport_ldisc_open(struct tty_struct *tty)
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- serport = kzalloc(sizeof(struct serport), GFP_KERNEL);
+ serport = kzalloc(sizeof(*serport), GFP_KERNEL);
if (!serport)
return -ENOMEM;
@@ -118,14 +114,13 @@ static void serport_ldisc_receive(struct tty_struct *tty, const u8 *cp,
const u8 *fp, size_t count)
{
struct serport *serport = tty->disc_data;
- unsigned long flags;
unsigned int ch_flags = 0;
int i;
- spin_lock_irqsave(&serport->lock, flags);
+ guard(spinlock_irqsave)(&serport->lock);
if (!test_bit(SERPORT_ACTIVE, &serport->flags))
- goto out;
+ return;
for (i = 0; i < count; i++) {
if (fp) {
@@ -146,9 +141,6 @@ static void serport_ldisc_receive(struct tty_struct *tty, const u8 *cp,
serio_interrupt(serport->serio, cp[i], ch_flags);
}
-
-out:
- spin_unlock_irqrestore(&serport->lock, flags);
}
/*
@@ -167,7 +159,7 @@ static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file,
if (test_and_set_bit(SERPORT_BUSY, &serport->flags))
return -EBUSY;
- serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ serport->serio = serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!serio)
return -ENOMEM;
@@ -246,11 +238,9 @@ static int serport_ldisc_compat_ioctl(struct tty_struct *tty,
static void serport_ldisc_hangup(struct tty_struct *tty)
{
struct serport *serport = tty->disc_data;
- unsigned long flags;
- spin_lock_irqsave(&serport->lock, flags);
- set_bit(SERPORT_DEAD, &serport->flags);
- spin_unlock_irqrestore(&serport->lock, flags);
+ scoped_guard(spinlock_irqsave, &serport->lock)
+ set_bit(SERPORT_DEAD, &serport->flags);
wake_up_interruptible(&serport->wait);
}
@@ -258,12 +248,11 @@ static void serport_ldisc_hangup(struct tty_struct *tty)
static void serport_ldisc_write_wakeup(struct tty_struct * tty)
{
struct serport *serport = tty->disc_data;
- unsigned long flags;
- spin_lock_irqsave(&serport->lock, flags);
+ guard(spinlock_irqsave)(&serport->lock);
+
if (test_bit(SERPORT_ACTIVE, &serport->flags))
serio_drv_write_wakeup(serport->serio);
- spin_unlock_irqrestore(&serport->lock, flags);
}
/*
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
index aec66d9f5176..524929ce1cae 100644
--- a/drivers/input/serio/sun4i-ps2.c
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -101,7 +101,7 @@ static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
unsigned int rxflags = 0;
u32 rval;
- spin_lock(&drvdata->lock);
+ guard(spinlock)(&drvdata->lock);
/* Get the PS/2 interrupts and clear them */
intr_status = readl(drvdata->reg_base + PS2_REG_LSTS);
@@ -134,8 +134,6 @@ static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
- spin_unlock(&drvdata->lock);
-
return IRQ_HANDLED;
}
@@ -146,7 +144,6 @@ static int sun4i_ps2_open(struct serio *serio)
u32 clk_scdf;
u32 clk_pcdf;
u32 rval;
- unsigned long flags;
/* Set line control and enable interrupt */
rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
@@ -171,9 +168,8 @@ static int sun4i_ps2_open(struct serio *serio)
rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
| PS2_GCTL_BUSEN;
- spin_lock_irqsave(&drvdata->lock, flags);
+ guard(spinlock_irqsave)(&drvdata->lock);
writel(rval, drvdata->reg_base + PS2_REG_GCTL);
- spin_unlock_irqrestore(&drvdata->lock, flags);
return 0;
}
@@ -213,8 +209,8 @@ static int sun4i_ps2_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
int error;
- drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL);
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!drvdata || !serio) {
error = -ENOMEM;
goto err_free_mem;
@@ -322,7 +318,7 @@ MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
static struct platform_driver sun4i_ps2_driver = {
.probe = sun4i_ps2_probe,
- .remove_new = sun4i_ps2_remove,
+ .remove = sun4i_ps2_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = sun4i_ps2_match,
diff --git a/drivers/input/serio/userio.c b/drivers/input/serio/userio.c
index 9ab5c45c3a9f..7f627b08055e 100644
--- a/drivers/input/serio/userio.c
+++ b/drivers/input/serio/userio.c
@@ -55,18 +55,15 @@ struct userio_device {
static int userio_device_write(struct serio *id, unsigned char val)
{
struct userio_device *userio = id->port_data;
- unsigned long flags;
- spin_lock_irqsave(&userio->buf_lock, flags);
+ scoped_guard(spinlock_irqsave, &userio->buf_lock) {
+ userio->buf[userio->head] = val;
+ userio->head = (userio->head + 1) % USERIO_BUFSIZE;
- userio->buf[userio->head] = val;
- userio->head = (userio->head + 1) % USERIO_BUFSIZE;
-
- if (userio->head == userio->tail)
- dev_warn(userio_misc.this_device,
- "Buffer overflowed, userio client isn't keeping up");
-
- spin_unlock_irqrestore(&userio->buf_lock, flags);
+ if (userio->head == userio->tail)
+ dev_warn(userio_misc.this_device,
+ "Buffer overflowed, userio client isn't keeping up");
+ }
wake_up_interruptible(&userio->waitq);
@@ -75,9 +72,8 @@ static int userio_device_write(struct serio *id, unsigned char val)
static int userio_char_open(struct inode *inode, struct file *file)
{
- struct userio_device *userio;
-
- userio = kzalloc(sizeof(struct userio_device), GFP_KERNEL);
+ struct userio_device *userio __free(kfree) =
+ kzalloc(sizeof(*userio), GFP_KERNEL);
if (!userio)
return -ENOMEM;
@@ -85,16 +81,14 @@ static int userio_char_open(struct inode *inode, struct file *file)
spin_lock_init(&userio->buf_lock);
init_waitqueue_head(&userio->waitq);
- userio->serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
- if (!userio->serio) {
- kfree(userio);
+ userio->serio = kzalloc(sizeof(*userio->serio), GFP_KERNEL);
+ if (!userio->serio)
return -ENOMEM;
- }
userio->serio->write = userio_device_write;
userio->serio->port_data = userio;
- file->private_data = userio;
+ file->private_data = no_free_ptr(userio);
return 0;
}
@@ -118,14 +112,32 @@ static int userio_char_release(struct inode *inode, struct file *file)
return 0;
}
+static size_t userio_fetch_data(struct userio_device *userio, u8 *buf,
+ size_t count, size_t *copylen)
+{
+ size_t available, len;
+
+ guard(spinlock_irqsave)(&userio->buf_lock);
+
+ available = CIRC_CNT_TO_END(userio->head, userio->tail,
+ USERIO_BUFSIZE);
+ len = min(available, count);
+ if (len) {
+ memcpy(buf, &userio->buf[userio->tail], len);
+ userio->tail = (userio->tail + len) % USERIO_BUFSIZE;
+ }
+
+ *copylen = len;
+ return available;
+}
+
static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
size_t count, loff_t *ppos)
{
struct userio_device *userio = file->private_data;
int error;
- size_t nonwrap_len, copylen;
- unsigned char buf[USERIO_BUFSIZE];
- unsigned long flags;
+ size_t available, copylen;
+ u8 buf[USERIO_BUFSIZE];
/*
* By the time we get here, the data that was waiting might have
@@ -135,21 +147,8 @@ static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
* of course).
*/
for (;;) {
- spin_lock_irqsave(&userio->buf_lock, flags);
-
- nonwrap_len = CIRC_CNT_TO_END(userio->head,
- userio->tail,
- USERIO_BUFSIZE);
- copylen = min(nonwrap_len, count);
- if (copylen) {
- memcpy(buf, &userio->buf[userio->tail], copylen);
- userio->tail = (userio->tail + copylen) %
- USERIO_BUFSIZE;
- }
-
- spin_unlock_irqrestore(&userio->buf_lock, flags);
-
- if (nonwrap_len)
+ available = userio_fetch_data(userio, buf, count, &copylen);
+ if (available)
break;
/* buffer was/is empty */
@@ -176,40 +175,21 @@ static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
return copylen;
}
-static ssize_t userio_char_write(struct file *file, const char __user *buffer,
- size_t count, loff_t *ppos)
+static int userio_execute_cmd(struct userio_device *userio,
+ const struct userio_cmd *cmd)
{
- struct userio_device *userio = file->private_data;
- struct userio_cmd cmd;
- int error;
-
- if (count != sizeof(cmd)) {
- dev_warn(userio_misc.this_device, "Invalid payload size\n");
- return -EINVAL;
- }
-
- if (copy_from_user(&cmd, buffer, sizeof(cmd)))
- return -EFAULT;
-
- error = mutex_lock_interruptible(&userio->mutex);
- if (error)
- return error;
-
- switch (cmd.type) {
+ switch (cmd->type) {
case USERIO_CMD_REGISTER:
if (!userio->serio->id.type) {
dev_warn(userio_misc.this_device,
"No port type given on /dev/userio\n");
-
- error = -EINVAL;
- goto out;
+ return -EINVAL;
}
if (userio->running) {
dev_warn(userio_misc.this_device,
"Begin command sent, but we're already running\n");
- error = -EBUSY;
- goto out;
+ return -EBUSY;
}
userio->running = true;
@@ -220,32 +200,51 @@ static ssize_t userio_char_write(struct file *file, const char __user *buffer,
if (userio->running) {
dev_warn(userio_misc.this_device,
"Can't change port type on an already running userio instance\n");
- error = -EBUSY;
- goto out;
+ return -EBUSY;
}
- userio->serio->id.type = cmd.data;
+ userio->serio->id.type = cmd->data;
break;
case USERIO_CMD_SEND_INTERRUPT:
if (!userio->running) {
dev_warn(userio_misc.this_device,
"The device must be registered before sending interrupts\n");
- error = -ENODEV;
- goto out;
+ return -ENODEV;
}
- serio_interrupt(userio->serio, cmd.data, 0);
+ serio_interrupt(userio->serio, cmd->data, 0);
break;
default:
- error = -EOPNOTSUPP;
- goto out;
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static ssize_t userio_char_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct userio_device *userio = file->private_data;
+ struct userio_cmd cmd;
+ int error;
+
+ if (count != sizeof(cmd)) {
+ dev_warn(userio_misc.this_device, "Invalid payload size\n");
+ return -EINVAL;
+ }
+
+ if (copy_from_user(&cmd, buffer, sizeof(cmd)))
+ return -EFAULT;
+
+ scoped_cond_guard(mutex_intr, return -EINTR, &userio->mutex) {
+ error = userio_execute_cmd(userio, &cmd);
+ if (error)
+ return error;
}
-out:
- mutex_unlock(&userio->mutex);
- return error ?: count;
+ return count;
}
static __poll_t userio_char_poll(struct file *file, poll_table *wait)
@@ -267,7 +266,6 @@ static const struct file_operations userio_fops = {
.read = userio_char_read,
.write = userio_char_write,
.poll = userio_char_poll,
- .llseek = no_llseek,
};
static struct miscdevice userio_misc = {
diff --git a/drivers/input/serio/xilinx_ps2.c b/drivers/input/serio/xilinx_ps2.c
index bb758346a33d..01433f0b48f1 100644
--- a/drivers/input/serio/xilinx_ps2.c
+++ b/drivers/input/serio/xilinx_ps2.c
@@ -155,22 +155,17 @@ static irqreturn_t xps2_interrupt(int irq, void *dev_id)
static int sxps2_write(struct serio *pserio, unsigned char c)
{
struct xps2data *drvdata = pserio->port_data;
- unsigned long flags;
u32 sr;
- int status = -1;
- spin_lock_irqsave(&drvdata->lock, flags);
+ guard(spinlock_irqsave)(&drvdata->lock);
/* If the PS/2 transmitter is empty send a byte of data */
sr = in_be32(drvdata->base_address + XPS2_STATUS_OFFSET);
- if (!(sr & XPS2_STATUS_TX_FULL)) {
- out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c);
- status = 0;
- }
+ if (sr & XPS2_STATUS_TX_FULL)
+ return -EAGAIN;
- spin_unlock_irqrestore(&drvdata->lock, flags);
-
- return status;
+ out_be32(drvdata->base_address + XPS2_TX_DATA_OFFSET, c);
+ return 0;
}
/**
@@ -252,8 +247,8 @@ static int xps2_of_probe(struct platform_device *ofdev)
return -ENODEV;
}
- drvdata = kzalloc(sizeof(struct xps2data), GFP_KERNEL);
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+ serio = kzalloc(sizeof(*serio), GFP_KERNEL);
if (!drvdata || !serio) {
error = -ENOMEM;
goto failed1;
@@ -358,7 +353,7 @@ static struct platform_driver xps2_of_driver = {
.of_match_table = xps2_of_match,
},
.probe = xps2_of_probe,
- .remove_new = xps2_of_remove,
+ .remove = xps2_of_remove,
};
module_platform_driver(xps2_of_driver);
diff --git a/drivers/input/sparse-keymap.c b/drivers/input/sparse-keymap.c
index 25bf8be6e711..164f8fcfd1aa 100644
--- a/drivers/input/sparse-keymap.c
+++ b/drivers/input/sparse-keymap.c
@@ -10,6 +10,7 @@
* Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
*/
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/module.h>
@@ -176,8 +177,7 @@ int sparse_keymap_setup(struct input_dev *dev,
for (e = keymap; e->type != KE_END; e++)
map_size++;
- map = devm_kmemdup(&dev->dev, keymap, map_size * sizeof(*map),
- GFP_KERNEL);
+ map = devm_kmemdup_array(&dev->dev, keymap, map_size, sizeof(*keymap), GFP_KERNEL);
if (!map)
return -ENOMEM;
diff --git a/drivers/input/tablet/acecad.c b/drivers/input/tablet/acecad.c
index b20e5a1afbcc..0ac16f32b31f 100644
--- a/drivers/input/tablet/acecad.c
+++ b/drivers/input/tablet/acecad.c
@@ -129,7 +129,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe);
- acecad = kzalloc(sizeof(struct usb_acecad), GFP_KERNEL);
+ acecad = kzalloc(sizeof(*acecad), GFP_KERNEL);
input_dev = input_allocate_device();
if (!acecad || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c
index baabc51547b8..2b3fbb0455d5 100644
--- a/drivers/input/tablet/aiptek.c
+++ b/drivers/input/tablet/aiptek.c
@@ -63,7 +63,7 @@
#include <linux/module.h>
#include <linux/usb/input.h>
#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/*
* Aiptek status packet:
@@ -1673,7 +1673,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
*/
speeds[0] = programmableDelay;
- aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL);
+ aiptek = kzalloc(sizeof(*aiptek), GFP_KERNEL);
inputdev = input_allocate_device();
if (!aiptek || !inputdev) {
dev_warn(&intf->dev,
diff --git a/drivers/input/tablet/hanwang.c b/drivers/input/tablet/hanwang.c
index 9bc631518b92..42c1e5eaddd5 100644
--- a/drivers/input/tablet/hanwang.c
+++ b/drivers/input/tablet/hanwang.c
@@ -322,7 +322,7 @@ static int hanwang_probe(struct usb_interface *intf, const struct usb_device_id
if (intf->cur_altsetting->desc.bNumEndpoints < 1)
return -ENODEV;
- hanwang = kzalloc(sizeof(struct hanwang), GFP_KERNEL);
+ hanwang = kzalloc(sizeof(*hanwang), GFP_KERNEL);
input_dev = input_allocate_device();
if (!hanwang || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/tablet/kbtab.c b/drivers/input/tablet/kbtab.c
index aa577898e952..794caa102909 100644
--- a/drivers/input/tablet/kbtab.c
+++ b/drivers/input/tablet/kbtab.c
@@ -3,7 +3,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb/input.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/*
* Pressure-threshold modules param code from Alex Perry <alex.perry@ieee.org>
@@ -121,7 +121,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
- kbtab = kzalloc(sizeof(struct kbtab), GFP_KERNEL);
+ kbtab = kzalloc(sizeof(*kbtab), GFP_KERNEL);
input_dev = input_allocate_device();
if (!kbtab || !input_dev)
goto fail1;
diff --git a/drivers/input/tablet/pegasus_notetaker.c b/drivers/input/tablet/pegasus_notetaker.c
index a68da2988f9c..eabb4a0b8a0d 100644
--- a/drivers/input/tablet/pegasus_notetaker.c
+++ b/drivers/input/tablet/pegasus_notetaker.c
@@ -63,6 +63,9 @@
#define BUTTON_PRESSED 0xb5
#define COMMAND_VERSION 0xa9
+/* 1 Status + 1 Color + 2 X + 2 Y = 6 bytes */
+#define NOTETAKER_PACKET_SIZE 6
+
/* in xy data packet */
#define BATTERY_NO_REPORT 0x40
#define BATTERY_LOW 0x41
@@ -214,6 +217,28 @@ static void pegasus_init(struct work_struct *work)
error);
}
+static int __pegasus_open(struct pegasus *pegasus)
+{
+ int error;
+
+ guard(mutex)(&pegasus->pm_mutex);
+
+ pegasus->irq->dev = pegasus->usbdev;
+ if (usb_submit_urb(pegasus->irq, GFP_KERNEL))
+ return -EIO;
+
+ error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE);
+ if (error) {
+ usb_kill_urb(pegasus->irq);
+ cancel_work_sync(&pegasus->init);
+ return error;
+ }
+
+ pegasus->is_open = true;
+
+ return 0;
+}
+
static int pegasus_open(struct input_dev *dev)
{
struct pegasus *pegasus = input_get_drvdata(dev);
@@ -223,39 +248,25 @@ static int pegasus_open(struct input_dev *dev)
if (error)
return error;
- mutex_lock(&pegasus->pm_mutex);
- pegasus->irq->dev = pegasus->usbdev;
- if (usb_submit_urb(pegasus->irq, GFP_KERNEL)) {
- error = -EIO;
- goto err_autopm_put;
+ error = __pegasus_open(pegasus);
+ if (error) {
+ usb_autopm_put_interface(pegasus->intf);
+ return error;
}
- error = pegasus_set_mode(pegasus, PEN_MODE_XY, NOTETAKER_LED_MOUSE);
- if (error)
- goto err_kill_urb;
-
- pegasus->is_open = true;
- mutex_unlock(&pegasus->pm_mutex);
return 0;
-
-err_kill_urb:
- usb_kill_urb(pegasus->irq);
- cancel_work_sync(&pegasus->init);
-err_autopm_put:
- mutex_unlock(&pegasus->pm_mutex);
- usb_autopm_put_interface(pegasus->intf);
- return error;
}
static void pegasus_close(struct input_dev *dev)
{
struct pegasus *pegasus = input_get_drvdata(dev);
- mutex_lock(&pegasus->pm_mutex);
- usb_kill_urb(pegasus->irq);
- cancel_work_sync(&pegasus->init);
- pegasus->is_open = false;
- mutex_unlock(&pegasus->pm_mutex);
+ scoped_guard(mutex, &pegasus->pm_mutex) {
+ usb_kill_urb(pegasus->irq);
+ cancel_work_sync(&pegasus->init);
+
+ pegasus->is_open = false;
+ }
usb_autopm_put_interface(pegasus->intf);
}
@@ -303,6 +314,12 @@ static int pegasus_probe(struct usb_interface *intf,
}
pegasus->data_len = usb_maxpacket(dev, pipe);
+ if (pegasus->data_len < NOTETAKER_PACKET_SIZE) {
+ dev_err(&intf->dev, "packet size is too small (%d)\n",
+ pegasus->data_len);
+ error = -EINVAL;
+ goto err_free_mem;
+ }
pegasus->data = usb_alloc_coherent(dev, pegasus->data_len, GFP_KERNEL,
&pegasus->data_dma);
@@ -411,10 +428,10 @@ static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
- mutex_lock(&pegasus->pm_mutex);
+ guard(mutex)(&pegasus->pm_mutex);
+
usb_kill_urb(pegasus->irq);
cancel_work_sync(&pegasus->init);
- mutex_unlock(&pegasus->pm_mutex);
return 0;
}
@@ -422,31 +439,33 @@ static int pegasus_suspend(struct usb_interface *intf, pm_message_t message)
static int pegasus_resume(struct usb_interface *intf)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
- int retval = 0;
- mutex_lock(&pegasus->pm_mutex);
+ guard(mutex)(&pegasus->pm_mutex);
+
if (pegasus->is_open && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
- retval = -EIO;
- mutex_unlock(&pegasus->pm_mutex);
+ return -EIO;
- return retval;
+ return 0;
}
static int pegasus_reset_resume(struct usb_interface *intf)
{
struct pegasus *pegasus = usb_get_intfdata(intf);
- int retval = 0;
+ int error;
+
+ guard(mutex)(&pegasus->pm_mutex);
- mutex_lock(&pegasus->pm_mutex);
if (pegasus->is_open) {
- retval = pegasus_set_mode(pegasus, PEN_MODE_XY,
+ error = pegasus_set_mode(pegasus, PEN_MODE_XY,
NOTETAKER_LED_MOUSE);
- if (!retval && usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
- retval = -EIO;
+ if (error)
+ return error;
+
+ if (usb_submit_urb(pegasus->irq, GFP_NOIO) < 0)
+ return -EIO;
}
- mutex_unlock(&pegasus->pm_mutex);
- return retval;
+ return 0;
}
static const struct usb_device_id pegasus_ids[] = {
diff --git a/drivers/input/tablet/wacom_serial4.c b/drivers/input/tablet/wacom_serial4.c
index 1cedb45ba497..cf7cea77dabc 100644
--- a/drivers/input/tablet/wacom_serial4.c
+++ b/drivers/input/tablet/wacom_serial4.c
@@ -521,7 +521,7 @@ static int wacom_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err = -ENOMEM;
- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom = kzalloc(sizeof(*wacom), GFP_KERNEL);
input_dev = input_allocate_device();
if (!wacom || !input_dev)
goto free_device;
diff --git a/drivers/input/tests/input_test.c b/drivers/input/tests/input_test.c
index 2fa5b725ae0a..e105ce71a920 100644
--- a/drivers/input/tests/input_test.c
+++ b/drivers/input/tests/input_test.c
@@ -31,7 +31,7 @@ static int input_test_init(struct kunit *test)
ret = input_register_device(input_dev);
if (ret) {
input_free_device(input_dev);
- KUNIT_ASSERT_FAILURE(test, "Register device failed: %d", ret);
+ KUNIT_FAIL_AND_ABORT(test, "Register device failed: %d", ret);
}
test->priv = input_dev;
@@ -179,4 +179,5 @@ static struct kunit_suite input_test_suite = {
kunit_test_suite(input_test_suite);
MODULE_AUTHOR("Javier Martinez Canillas <javierm@redhat.com>");
+MODULE_DESCRIPTION("KUnit test for the input core");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touch-overlay.c b/drivers/input/touch-overlay.c
new file mode 100644
index 000000000000..b9fd82c4829d
--- /dev/null
+++ b/drivers/input/touch-overlay.c
@@ -0,0 +1,278 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Helper functions for overlay objects on touchscreens
+ *
+ * Copyright (c) 2023 Javier Carrasco <javier.carrasco@wolfvision.net>
+ */
+
+#include <linux/export.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touch-overlay.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/property.h>
+
+struct touch_overlay_segment {
+ struct list_head list;
+ u32 x_origin;
+ u32 y_origin;
+ u32 x_size;
+ u32 y_size;
+ u32 key;
+ bool pressed;
+ int slot;
+};
+
+static int touch_overlay_get_segment(struct fwnode_handle *segment_node,
+ struct touch_overlay_segment *segment,
+ struct input_dev *input)
+{
+ int error;
+
+ error = fwnode_property_read_u32(segment_node, "x-origin",
+ &segment->x_origin);
+ if (error)
+ return error;
+
+ error = fwnode_property_read_u32(segment_node, "y-origin",
+ &segment->y_origin);
+ if (error)
+ return error;
+
+ error = fwnode_property_read_u32(segment_node, "x-size",
+ &segment->x_size);
+ if (error)
+ return error;
+
+ error = fwnode_property_read_u32(segment_node, "y-size",
+ &segment->y_size);
+ if (error)
+ return error;
+
+ error = fwnode_property_read_u32(segment_node, "linux,code",
+ &segment->key);
+ if (!error)
+ input_set_capability(input, EV_KEY, segment->key);
+ else if (error != -EINVAL)
+ return error;
+
+ return 0;
+}
+
+/**
+ * touch_overlay_map - map overlay objects from the device tree and set
+ * key capabilities if buttons are defined.
+ * @list: pointer to the list that will hold the segments
+ * @input: pointer to the already allocated input_dev
+ *
+ * Returns 0 on success and error number otherwise.
+ *
+ * If buttons are defined, key capabilities are set accordingly.
+ */
+int touch_overlay_map(struct list_head *list, struct input_dev *input)
+{
+ struct fwnode_handle *fw_segment;
+ struct device *dev = input->dev.parent;
+ struct touch_overlay_segment *segment;
+ int error;
+
+ struct fwnode_handle *overlay __free(fwnode_handle) =
+ device_get_named_child_node(dev, "touch-overlay");
+ if (!overlay)
+ return 0;
+
+ fwnode_for_each_available_child_node(overlay, fw_segment) {
+ segment = devm_kzalloc(dev, sizeof(*segment), GFP_KERNEL);
+ if (!segment) {
+ fwnode_handle_put(fw_segment);
+ return -ENOMEM;
+ }
+ error = touch_overlay_get_segment(fw_segment, segment, input);
+ if (error) {
+ fwnode_handle_put(fw_segment);
+ return error;
+ }
+ list_add_tail(&segment->list, list);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(touch_overlay_map);
+
+/**
+ * touch_overlay_get_touchscreen_abs - get abs size from the touchscreen area.
+ * @list: pointer to the list that holds the segments
+ * @x: horizontal abs
+ * @y: vertical abs
+ */
+void touch_overlay_get_touchscreen_abs(struct list_head *list, u16 *x, u16 *y)
+{
+ struct touch_overlay_segment *segment;
+ struct list_head *ptr;
+
+ list_for_each(ptr, list) {
+ segment = list_entry(ptr, struct touch_overlay_segment, list);
+ if (!segment->key) {
+ *x = segment->x_size - 1;
+ *y = segment->y_size - 1;
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(touch_overlay_get_touchscreen_abs);
+
+static bool touch_overlay_segment_event(struct touch_overlay_segment *seg,
+ struct input_mt_pos *pos)
+{
+ if (pos->x >= seg->x_origin && pos->x < (seg->x_origin + seg->x_size) &&
+ pos->y >= seg->y_origin && pos->y < (seg->y_origin + seg->y_size))
+ return true;
+
+ return false;
+}
+
+/**
+ * touch_overlay_mapped_touchscreen - check if a touchscreen area is mapped
+ * @list: pointer to the list that holds the segments
+ *
+ * Returns true if a touchscreen area is mapped or false otherwise.
+ */
+bool touch_overlay_mapped_touchscreen(struct list_head *list)
+{
+ struct touch_overlay_segment *segment;
+ struct list_head *ptr;
+
+ list_for_each(ptr, list) {
+ segment = list_entry(ptr, struct touch_overlay_segment, list);
+ if (!segment->key)
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL(touch_overlay_mapped_touchscreen);
+
+static bool touch_overlay_event_on_ts(struct list_head *list,
+ struct input_mt_pos *pos)
+{
+ struct touch_overlay_segment *segment;
+ struct list_head *ptr;
+
+ list_for_each(ptr, list) {
+ segment = list_entry(ptr, struct touch_overlay_segment, list);
+ if (segment->key)
+ continue;
+
+ if (touch_overlay_segment_event(segment, pos)) {
+ pos->x -= segment->x_origin;
+ pos->y -= segment->y_origin;
+ return true;
+ }
+ /* ignore touch events outside the defined area */
+ return false;
+ }
+
+ return true;
+}
+
+static bool touch_overlay_button_event(struct input_dev *input,
+ struct touch_overlay_segment *segment,
+ struct input_mt_pos *pos, int slot)
+{
+ struct input_mt *mt = input->mt;
+ struct input_mt_slot *s = &mt->slots[slot];
+ bool button_contact = touch_overlay_segment_event(segment, pos);
+
+ if (segment->slot == slot && segment->pressed) {
+ /* sliding out of the button releases it */
+ if (!button_contact) {
+ input_report_key(input, segment->key, false);
+ segment->pressed = false;
+ /* keep available for a possible touch event */
+ return false;
+ }
+ /* ignore sliding on the button while pressed */
+ s->frame = mt->frame;
+ return true;
+ } else if (button_contact) {
+ input_report_key(input, segment->key, true);
+ s->frame = mt->frame;
+ segment->slot = slot;
+ segment->pressed = true;
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * touch_overlay_sync_frame - update the status of the segments and report
+ * buttons whose tracked slot is unused.
+ * @list: pointer to the list that holds the segments
+ * @input: pointer to the input device associated to the contact
+ */
+void touch_overlay_sync_frame(struct list_head *list, struct input_dev *input)
+{
+ struct touch_overlay_segment *segment;
+ struct input_mt *mt = input->mt;
+ struct input_mt_slot *s;
+ struct list_head *ptr;
+
+ list_for_each(ptr, list) {
+ segment = list_entry(ptr, struct touch_overlay_segment, list);
+ if (!segment->key)
+ continue;
+
+ s = &mt->slots[segment->slot];
+ if (!input_mt_is_used(mt, s) && segment->pressed) {
+ input_report_key(input, segment->key, false);
+ segment->pressed = false;
+ }
+ }
+}
+EXPORT_SYMBOL(touch_overlay_sync_frame);
+
+/**
+ * touch_overlay_process_contact - process contacts according to the overlay
+ * mapping. This function acts as a filter to release the calling driver
+ * from the contacts that are either related to overlay buttons or out of the
+ * overlay touchscreen area, if defined.
+ * @list: pointer to the list that holds the segments
+ * @input: pointer to the input device associated to the contact
+ * @pos: pointer to the contact position
+ * @slot: slot associated to the contact (0 if multitouch is not supported)
+ *
+ * Returns true if the contact was processed (reported for valid key events
+ * and dropped for contacts outside the overlay touchscreen area) or false
+ * if the contact must be processed by the caller. In that case this function
+ * shifts the (x,y) coordinates to the overlay touchscreen axis if required.
+ */
+bool touch_overlay_process_contact(struct list_head *list,
+ struct input_dev *input,
+ struct input_mt_pos *pos, int slot)
+{
+ struct touch_overlay_segment *segment;
+ struct list_head *ptr;
+
+ /*
+ * buttons must be prioritized over overlay touchscreens to account for
+ * overlappings e.g. a button inside the touchscreen area.
+ */
+ list_for_each(ptr, list) {
+ segment = list_entry(ptr, struct touch_overlay_segment, list);
+ if (segment->key &&
+ touch_overlay_button_event(input, segment, pos, slot))
+ return true;
+ }
+
+ /*
+ * valid contacts on the overlay touchscreen are left for the client
+ * to be processed/reported according to its (possibly) unique features.
+ */
+ return !touch_overlay_event_on_ts(list, pos);
+}
+EXPORT_SYMBOL(touch_overlay_process_contact);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Helper functions for overlay objects on touch devices");
diff --git a/drivers/input/touchscreen.c b/drivers/input/touchscreen.c
index 4620e20d0190..d699b24bb548 100644
--- a/drivers/input/touchscreen.c
+++ b/drivers/input/touchscreen.c
@@ -6,6 +6,7 @@
* Copyright (c) 2014 Sebastian Reichel <sre@kernel.org>
*/
+#include <linux/export.h>
#include <linux/property.h>
#include <linux/input.h>
#include <linux/input/mt.h>
diff --git a/drivers/input/touchscreen/88pm860x-ts.c b/drivers/input/touchscreen/88pm860x-ts.c
index 81a3ea4b9a3d..0468ce2b216f 100644
--- a/drivers/input/touchscreen/88pm860x-ts.c
+++ b/drivers/input/touchscreen/88pm860x-ts.c
@@ -117,13 +117,14 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,
struct pm860x_chip *chip,
int *res_x)
{
- struct device_node *np = pdev->dev.parent->of_node;
struct i2c_client *i2c = (chip->id == CHIP_PM8607) ? chip->client \
: chip->companion;
int data, n, ret;
- if (!np)
+ if (!pdev->dev.parent->of_node)
return -ENODEV;
- np = of_get_child_by_name(np, "touch");
+
+ struct device_node *np __free(device_node) =
+ of_get_child_by_name(pdev->dev.parent->of_node, "touch");
if (!np) {
dev_err(&pdev->dev, "Can't find touch node\n");
return -EINVAL;
@@ -141,13 +142,13 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,
if (data) {
ret = pm860x_reg_write(i2c, PM8607_GPADC_MISC1, data);
if (ret < 0)
- goto err_put_node;
+ return -EINVAL;
}
/* set tsi prebias time */
if (!of_property_read_u32(np, "marvell,88pm860x-tsi-prebias", &data)) {
ret = pm860x_reg_write(i2c, PM8607_TSI_PREBIAS, data);
if (ret < 0)
- goto err_put_node;
+ return -EINVAL;
}
/* set prebias & prechg time of pen detect */
data = 0;
@@ -158,18 +159,11 @@ static int pm860x_touch_dt_init(struct platform_device *pdev,
if (data) {
ret = pm860x_reg_write(i2c, PM8607_PD_PREBIAS, data);
if (ret < 0)
- goto err_put_node;
+ return -EINVAL;
}
of_property_read_u32(np, "marvell,88pm860x-resistor-X", res_x);
- of_node_put(np);
-
return 0;
-
-err_put_node:
- of_node_put(np);
-
- return -EINVAL;
}
#else
#define pm860x_touch_dt_init(x, y, z) (-1)
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index c821fe3ee794..7d5b72ee07fa 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -103,6 +103,18 @@ config TOUCHSCREEN_ADC
To compile this driver as a module, choose M here: the
module will be called resistive-adc-touch.ko.
+config TOUCHSCREEN_APPLE_Z2
+ tristate "Apple Z2 touchscreens"
+ depends on SPI && (ARCH_APPLE || COMPILE_TEST)
+ help
+ Say Y here if you have an ARM Apple device with
+ a touchscreen or a touchbar.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called apple_z2.
+
config TOUCHSCREEN_AR1021_I2C
tristate "Microchip AR1020/1021 i2c touchscreen"
depends on I2C && OF
@@ -254,36 +266,6 @@ config TOUCHSCREEN_CYTTSP_SPI
To compile this driver as a module, choose M here: the
module will be called cyttsp_spi.
-config TOUCHSCREEN_CYTTSP4_CORE
- tristate "Cypress TrueTouch Gen4 Touchscreen Driver"
- help
- Core driver for Cypress TrueTouch(tm) Standard Product
- Generation4 touchscreen controllers.
-
- Say Y here if you have a Cypress Gen4 touchscreen.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here.
-
-config TOUCHSCREEN_CYTTSP4_I2C
- tristate "support I2C bus connection"
- depends on TOUCHSCREEN_CYTTSP4_CORE && I2C
- help
- Say Y here if the touchscreen is connected via I2C bus.
-
- To compile this driver as a module, choose M here: the
- module will be called cyttsp4_i2c.
-
-config TOUCHSCREEN_CYTTSP4_SPI
- tristate "support SPI bus connection"
- depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER
- help
- Say Y here if the touchscreen is connected via SPI bus.
-
- To compile this driver as a module, choose M here: the
- module will be called cyttsp4_spi.
-
config TOUCHSCREEN_CYTTSP5
tristate "Cypress TrueTouch Gen5 Touchscreen Driver"
depends on I2C
@@ -450,6 +432,7 @@ config TOUCHSCREEN_GOODIX_BERLIN_SPI
config TOUCHSCREEN_HIDEEP
tristate "HiDeep Touch IC"
depends on I2C
+ select REGMAP_I2C
help
Say Y here if you have a touchscreen using HiDeep.
@@ -458,9 +441,20 @@ config TOUCHSCREEN_HIDEEP
To compile this driver as a module, choose M here : the
module will be called hideep_ts.
+config TOUCHSCREEN_HIMAX_HX852X
+ tristate "Himax HX852x(ES) touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a Himax HX852x(ES) touchscreen.
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module
+ will be called himax_hx852x.
+
config TOUCHSCREEN_HYCON_HY46XX
tristate "Hycon hy46xx touchscreen support"
depends on I2C
+ select REGMAP_I2C
help
Say Y here if you have a touchscreen using Hycon hy46xx
@@ -481,6 +475,18 @@ config TOUCHSCREEN_HYNITRON_CSTXXX
To compile this driver as a module, choose M here: the
module will be called hynitron-cstxxx.
+config TOUCHSCREEN_HYNITRON_CST816X
+ tristate "Hynitron CST816x touchscreen"
+ depends on I2C
+ help
+ Say Y here if you have a touchscreen using a Hynitron
+ CST816x series touchscreen controller.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hynitron-cst816x.
+
config TOUCHSCREEN_ILI210X
tristate "Ilitek ILI210X based touchscreen"
depends on I2C
@@ -626,18 +632,6 @@ config TOUCHSCREEN_MAX11801
To compile this driver as a module, choose M here: the
module will be called max11801_ts.
-config TOUCHSCREEN_MCS5000
- tristate "MELFAS MCS-5000 touchscreen"
- depends on I2C
- help
- Say Y here if you have the MELFAS MCS-5000 touchscreen controller
- chip in your system.
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called mcs5000_ts.
-
config TOUCHSCREEN_MMS114
tristate "MELFAS MMS114 touchscreen"
depends on I2C
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index a81cb5aa21a5..ab9abd151078 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_TOUCHSCREEN_AD7879_I2C) += ad7879-i2c.o
obj-$(CONFIG_TOUCHSCREEN_AD7879_SPI) += ad7879-spi.o
obj-$(CONFIG_TOUCHSCREEN_ADC) += resistive-adc-touch.o
obj-$(CONFIG_TOUCHSCREEN_ADS7846) += ads7846.o
+obj-$(CONFIG_TOUCHSCREEN_APPLE_Z2) += apple_z2.o
obj-$(CONFIG_TOUCHSCREEN_AR1021_I2C) += ar1021_i2c.o
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MXT) += atmel_mxt_ts.o
obj-$(CONFIG_TOUCHSCREEN_AUO_PIXCIR) += auo-pixcir-ts.o
@@ -25,11 +26,8 @@ obj-$(CONFIG_TOUCHSCREEN_CHIPONE_ICN8505) += chipone_icn8505.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMA140) += cy8ctma140.o
obj-$(CONFIG_TOUCHSCREEN_CY8CTMG110) += cy8ctmg110_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_CORE) += cyttsp_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o cyttsp_i2c_common.o
+obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp_i2c.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_SPI) += cyttsp_spi.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_CORE) += cyttsp4_core.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_I2C) += cyttsp4_i2c.o cyttsp_i2c_common.o
-obj-$(CONFIG_TOUCHSCREEN_CYTTSP4_SPI) += cyttsp4_spi.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP5) += cyttsp5.o
obj-$(CONFIG_TOUCHSCREEN_DA9034) += da9034-ts.o
obj-$(CONFIG_TOUCHSCREEN_DA9052) += da9052_tsi.o
@@ -51,7 +49,9 @@ obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_CORE) += goodix_berlin_core.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_I2C) += goodix_berlin_i2c.o
obj-$(CONFIG_TOUCHSCREEN_GOODIX_BERLIN_SPI) += goodix_berlin_spi.o
obj-$(CONFIG_TOUCHSCREEN_HIDEEP) += hideep.o
+obj-$(CONFIG_TOUCHSCREEN_HIMAX_HX852X) += himax_hx852x.o
obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CSTXXX) += hynitron_cstxxx.o
+obj-$(CONFIG_TOUCHSCREEN_HYNITRON_CST816X) += hynitron-cst816x.o
obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o
obj-$(CONFIG_TOUCHSCREEN_ILITEK) += ilitek_ts_i2c.o
obj-$(CONFIG_TOUCHSCREEN_IMAGIS) += imagis.o
@@ -63,7 +63,6 @@ obj-$(CONFIG_TOUCHSCREEN_MAX11801) += max11801_ts.o
obj-$(CONFIG_TOUCHSCREEN_MXS_LRADC) += mxs-lradc-ts.o
obj-$(CONFIG_TOUCHSCREEN_MX25) += fsl-imx25-tcq.o
obj-$(CONFIG_TOUCHSCREEN_MC13783) += mc13783_ts.o
-obj-$(CONFIG_TOUCHSCREEN_MCS5000) += mcs5000_ts.o
obj-$(CONFIG_TOUCHSCREEN_MELFAS_MIP4) += melfas_mip4.o
obj-$(CONFIG_TOUCHSCREEN_MIGOR) += migor_ts.o
obj-$(CONFIG_TOUCHSCREEN_MMS114) += mms114.o
diff --git a/drivers/input/touchscreen/ad7877.c b/drivers/input/touchscreen/ad7877.c
index a0598e9c7aff..c9aa1847265a 100644
--- a/drivers/input/touchscreen/ad7877.c
+++ b/drivers/input/touchscreen/ad7877.c
@@ -375,7 +375,7 @@ static inline void ad7877_ts_event_release(struct ad7877 *ts)
static void ad7877_timer(struct timer_list *t)
{
- struct ad7877 *ts = from_timer(ts, t, timer);
+ struct ad7877 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -415,7 +415,7 @@ static void ad7877_disable(void *data)
ts->disabled = true;
disable_irq(ts->spi->irq);
- if (del_timer_sync(&ts->timer))
+ if (timer_delete_sync(&ts->timer))
ad7877_ts_event_release(ts);
}
diff --git a/drivers/input/touchscreen/ad7879.c b/drivers/input/touchscreen/ad7879.c
index e5d69bf2276e..4c448f39bf57 100644
--- a/drivers/input/touchscreen/ad7879.c
+++ b/drivers/input/touchscreen/ad7879.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -237,7 +238,7 @@ static void ad7879_ts_event_release(struct ad7879 *ts)
static void ad7879_timer(struct timer_list *t)
{
- struct ad7879 *ts = from_timer(ts, t, timer);
+ struct ad7879 *ts = timer_container_of(ts, t, timer);
ad7879_ts_event_release(ts);
}
@@ -273,7 +274,7 @@ static void __ad7879_disable(struct ad7879 *ts)
AD7879_PM(AD7879_PM_SHUTDOWN);
disable_irq(ts->irq);
- if (del_timer_sync(&ts->timer))
+ if (timer_delete_sync(&ts->timer))
ad7879_ts_event_release(ts);
ad7879_write(ts, AD7879_REG_CTRL2, reg);
@@ -444,10 +445,11 @@ static int ad7879_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
return !!(val & AD7879_GPIO_DATA);
}
-static void ad7879_gpio_set_value(struct gpio_chip *chip,
- unsigned gpio, int value)
+static int ad7879_gpio_set_value(struct gpio_chip *chip, unsigned int gpio,
+ int value)
{
struct ad7879 *ts = gpiochip_get_data(chip);
+ int ret;
mutex_lock(&ts->mutex);
if (value)
@@ -455,8 +457,10 @@ static void ad7879_gpio_set_value(struct gpio_chip *chip,
else
ts->cmd_crtl2 &= ~AD7879_GPIO_DATA;
- ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
+ ret = ad7879_write(ts, AD7879_REG_CTRL2, ts->cmd_crtl2);
mutex_unlock(&ts->mutex);
+
+ return ret;
}
static int ad7879_gpio_add(struct ad7879 *ts)
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 4d13db13b9e5..67264c5b49cb 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -30,7 +30,7 @@
#include <linux/spi/ads7846.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/*
* This code has been heavily tested on a Nokia 770, and lightly
@@ -138,6 +138,7 @@ struct ads7846 {
void *filter_data;
int (*get_pendown_state)(void);
struct gpio_desc *gpio_pendown;
+ struct gpio_desc *gpio_hsync;
void (*wait_for_sync)(void);
};
@@ -330,7 +331,7 @@ struct ser_req {
u8 ref_off;
u16 scratch;
struct spi_message msg;
- struct spi_transfer xfer[6];
+ struct spi_transfer xfer[8];
/*
* DMA (thus cache coherency maintenance) requires the
* transfer buffers to live in their own cache lines.
@@ -404,9 +405,19 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
req->xfer[5].rx_buf = &req->scratch;
req->xfer[5].len = 2;
- CS_CHANGE(req->xfer[5]);
spi_message_add_tail(&req->xfer[5], &req->msg);
+ /* clear the command register */
+ req->scratch = 0;
+ req->xfer[6].tx_buf = &req->scratch;
+ req->xfer[6].len = 1;
+ spi_message_add_tail(&req->xfer[6], &req->msg);
+
+ req->xfer[7].rx_buf = &req->scratch;
+ req->xfer[7].len = 2;
+ CS_CHANGE(req->xfer[7]);
+ spi_message_add_tail(&req->xfer[7], &req->msg);
+
mutex_lock(&ts->lock);
ads7846_stop(ts);
status = spi_sync(spi, &req->msg);
@@ -634,10 +645,6 @@ ATTRIBUTE_GROUPS(ads784x);
/*--------------------------------------------------------------------------*/
-static void null_wait_for_sync(void)
-{
-}
-
static int ads7846_debounce_filter(void *ads, int data_idx, int *val)
{
struct ads7846 *ts = ads;
@@ -790,6 +797,28 @@ static int ads7846_filter(struct ads7846 *ts)
return 0;
}
+static void ads7846_wait_for_hsync(struct ads7846 *ts)
+{
+ if (ts->wait_for_sync) {
+ ts->wait_for_sync();
+ return;
+ }
+
+ if (!ts->gpio_hsync)
+ return;
+
+ /*
+ * Wait for HSYNC to assert the line should be flagged
+ * as active low so here we are waiting for it to assert
+ */
+ while (!gpiod_get_value(ts->gpio_hsync))
+ cpu_relax();
+
+ /* Then we wait for it do de-assert */
+ while (gpiod_get_value(ts->gpio_hsync))
+ cpu_relax();
+}
+
static void ads7846_read_state(struct ads7846 *ts)
{
struct ads7846_packet *packet = ts->packet;
@@ -800,12 +829,12 @@ static void ads7846_read_state(struct ads7846 *ts)
packet->last_cmd_idx = 0;
while (true) {
- ts->wait_for_sync();
+ ads7846_wait_for_hsync(ts);
m = &ts->msg[msg_idx];
error = spi_sync(ts->spi, m);
if (error) {
- dev_err(&ts->spi->dev, "spi_sync --> %d\n", error);
+ dev_err_ratelimited(&ts->spi->dev, "spi_sync --> %d\n", error);
packet->ignore = true;
return;
}
@@ -992,7 +1021,7 @@ static int ads7846_setup_pendown(struct spi_device *spi,
if (pdata->get_pendown_state) {
ts->get_pendown_state = pdata->get_pendown_state;
} else {
- ts->gpio_pendown = gpiod_get(&spi->dev, "pendown", GPIOD_IN);
+ ts->gpio_pendown = devm_gpiod_get(&spi->dev, "pendown", GPIOD_IN);
if (IS_ERR(ts->gpio_pendown)) {
dev_err(&spi->dev, "failed to request pendown GPIO\n");
return PTR_ERR(ts->gpio_pendown);
@@ -1268,7 +1297,11 @@ static int ads7846_probe(struct spi_device *spi)
ts->penirq_recheck_delay_usecs =
pdata->penirq_recheck_delay_usecs;
- ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
+ ts->wait_for_sync = pdata->wait_for_sync;
+
+ ts->gpio_hsync = devm_gpiod_get_optional(dev, "ti,hsync", GPIOD_IN);
+ if (IS_ERR(ts->gpio_hsync))
+ return PTR_ERR(ts->gpio_hsync);
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(dev));
snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
diff --git a/drivers/input/touchscreen/apple_z2.c b/drivers/input/touchscreen/apple_z2.c
new file mode 100644
index 000000000000..0de161eae59a
--- /dev/null
+++ b/drivers/input/touchscreen/apple_z2.c
@@ -0,0 +1,477 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Apple Z2 touchscreen driver
+ *
+ * Copyright (C) The Asahi Linux Contributors
+ */
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spi/spi.h>
+#include <linux/unaligned.h>
+
+#define APPLE_Z2_NUM_FINGERS_OFFSET 16
+#define APPLE_Z2_FINGERS_OFFSET 24
+#define APPLE_Z2_TOUCH_STARTED 3
+#define APPLE_Z2_TOUCH_MOVED 4
+#define APPLE_Z2_CMD_READ_INTERRUPT_DATA 0xEB
+#define APPLE_Z2_HBPP_CMD_BLOB 0x3001
+#define APPLE_Z2_FW_MAGIC 0x5746325A
+#define LOAD_COMMAND_INIT_PAYLOAD 0
+#define LOAD_COMMAND_SEND_BLOB 1
+#define LOAD_COMMAND_SEND_CALIBRATION 2
+#define CAL_PROP_NAME "apple,z2-cal-blob"
+
+struct apple_z2 {
+ struct spi_device *spidev;
+ struct gpio_desc *reset_gpio;
+ struct input_dev *input_dev;
+ struct completion boot_irq;
+ bool booted;
+ int index_parity;
+ struct touchscreen_properties props;
+ const char *fw_name;
+ u8 *tx_buf;
+ u8 *rx_buf;
+};
+
+struct apple_z2_finger {
+ u8 finger;
+ u8 state;
+ __le16 unknown2;
+ __le16 abs_x;
+ __le16 abs_y;
+ __le16 rel_x;
+ __le16 rel_y;
+ __le16 tool_major;
+ __le16 tool_minor;
+ __le16 orientation;
+ __le16 touch_major;
+ __le16 touch_minor;
+ __le16 unused[2];
+ __le16 pressure;
+ __le16 multi;
+} __packed;
+
+struct apple_z2_hbpp_blob_hdr {
+ __le16 cmd;
+ __le16 len;
+ __le32 addr;
+ __le16 checksum;
+};
+
+struct apple_z2_fw_hdr {
+ __le32 magic;
+ __le32 version;
+};
+
+struct apple_z2_read_interrupt_cmd {
+ u8 cmd;
+ u8 counter;
+ u8 unused[12];
+ __le16 checksum;
+};
+
+static void apple_z2_parse_touches(struct apple_z2 *z2,
+ const u8 *msg, size_t msg_len)
+{
+ int i;
+ int nfingers;
+ int slot;
+ int slot_valid;
+ struct apple_z2_finger *fingers;
+
+ if (msg_len <= APPLE_Z2_NUM_FINGERS_OFFSET)
+ return;
+ nfingers = msg[APPLE_Z2_NUM_FINGERS_OFFSET];
+ fingers = (struct apple_z2_finger *)(msg + APPLE_Z2_FINGERS_OFFSET);
+ for (i = 0; i < nfingers; i++) {
+ slot = input_mt_get_slot_by_key(z2->input_dev, fingers[i].finger);
+ if (slot < 0) {
+ dev_warn(&z2->spidev->dev, "unable to get slot for finger\n");
+ continue;
+ }
+ slot_valid = fingers[i].state == APPLE_Z2_TOUCH_STARTED ||
+ fingers[i].state == APPLE_Z2_TOUCH_MOVED;
+ input_mt_slot(z2->input_dev, slot);
+ if (!input_mt_report_slot_state(z2->input_dev, MT_TOOL_FINGER, slot_valid))
+ continue;
+ touchscreen_report_pos(z2->input_dev, &z2->props,
+ le16_to_cpu(fingers[i].abs_x),
+ le16_to_cpu(fingers[i].abs_y),
+ true);
+ input_report_abs(z2->input_dev, ABS_MT_WIDTH_MAJOR,
+ le16_to_cpu(fingers[i].tool_major));
+ input_report_abs(z2->input_dev, ABS_MT_WIDTH_MINOR,
+ le16_to_cpu(fingers[i].tool_minor));
+ input_report_abs(z2->input_dev, ABS_MT_ORIENTATION,
+ le16_to_cpu(fingers[i].orientation));
+ input_report_abs(z2->input_dev, ABS_MT_TOUCH_MAJOR,
+ le16_to_cpu(fingers[i].touch_major));
+ input_report_abs(z2->input_dev, ABS_MT_TOUCH_MINOR,
+ le16_to_cpu(fingers[i].touch_minor));
+ }
+ input_mt_sync_frame(z2->input_dev);
+ input_sync(z2->input_dev);
+}
+
+static int apple_z2_read_packet(struct apple_z2 *z2)
+{
+ struct apple_z2_read_interrupt_cmd *len_cmd = (void *)z2->tx_buf;
+ struct spi_transfer xfer;
+ int error;
+ size_t pkt_len;
+
+ memset(&xfer, 0, sizeof(xfer));
+ len_cmd->cmd = APPLE_Z2_CMD_READ_INTERRUPT_DATA;
+ len_cmd->counter = z2->index_parity + 1;
+ len_cmd->checksum =
+ cpu_to_le16(APPLE_Z2_CMD_READ_INTERRUPT_DATA + len_cmd->counter);
+ z2->index_parity = !z2->index_parity;
+ xfer.tx_buf = z2->tx_buf;
+ xfer.rx_buf = z2->rx_buf;
+ xfer.len = sizeof(*len_cmd);
+
+ error = spi_sync_transfer(z2->spidev, &xfer, 1);
+ if (error)
+ return error;
+
+ pkt_len = (get_unaligned_le16(z2->rx_buf + 1) + 8) & 0xfffffffc;
+
+ error = spi_read(z2->spidev, z2->rx_buf, pkt_len);
+ if (error)
+ return error;
+
+ apple_z2_parse_touches(z2, z2->rx_buf + 5, pkt_len - 5);
+
+ return 0;
+}
+
+static irqreturn_t apple_z2_irq(int irq, void *data)
+{
+ struct apple_z2 *z2 = data;
+
+ if (unlikely(!z2->booted))
+ complete(&z2->boot_irq);
+ else
+ apple_z2_read_packet(z2);
+
+ return IRQ_HANDLED;
+}
+
+/* Build calibration blob, caller is responsible for freeing the blob data. */
+static const u8 *apple_z2_build_cal_blob(struct apple_z2 *z2,
+ u32 address, size_t *size)
+{
+ u8 *cal_data;
+ int cal_size;
+ size_t blob_size;
+ u32 checksum;
+ u16 checksum_hdr;
+ int i;
+ struct apple_z2_hbpp_blob_hdr *hdr;
+ int error;
+
+ if (!device_property_present(&z2->spidev->dev, CAL_PROP_NAME))
+ return NULL;
+
+ cal_size = device_property_count_u8(&z2->spidev->dev, CAL_PROP_NAME);
+ if (cal_size < 0)
+ return ERR_PTR(cal_size);
+
+ blob_size = sizeof(struct apple_z2_hbpp_blob_hdr) + cal_size + sizeof(__le32);
+ u8 *blob_data __free(kfree) = kzalloc(blob_size, GFP_KERNEL);
+ if (!blob_data)
+ return ERR_PTR(-ENOMEM);
+
+ hdr = (struct apple_z2_hbpp_blob_hdr *)blob_data;
+ hdr->cmd = cpu_to_le16(APPLE_Z2_HBPP_CMD_BLOB);
+ hdr->len = cpu_to_le16(round_up(cal_size, 4) / 4);
+ hdr->addr = cpu_to_le32(address);
+
+ checksum_hdr = 0;
+ for (i = 2; i < 8; i++)
+ checksum_hdr += blob_data[i];
+ hdr->checksum = cpu_to_le16(checksum_hdr);
+
+ cal_data = blob_data + sizeof(struct apple_z2_hbpp_blob_hdr);
+ error = device_property_read_u8_array(&z2->spidev->dev, CAL_PROP_NAME,
+ cal_data, cal_size);
+ if (error)
+ return ERR_PTR(error);
+
+ checksum = 0;
+ for (i = 0; i < cal_size; i++)
+ checksum += cal_data[i];
+ put_unaligned_le32(checksum, cal_data + cal_size);
+
+ *size = blob_size;
+ return no_free_ptr(blob_data);
+}
+
+static int apple_z2_send_firmware_blob(struct apple_z2 *z2, const u8 *data,
+ u32 size, bool init)
+{
+ struct spi_message msg;
+ struct spi_transfer blob_xfer, ack_xfer;
+ int error;
+
+ z2->tx_buf[0] = 0x1a;
+ z2->tx_buf[1] = 0xa1;
+
+ spi_message_init(&msg);
+ memset(&blob_xfer, 0, sizeof(blob_xfer));
+ memset(&ack_xfer, 0, sizeof(ack_xfer));
+
+ blob_xfer.tx_buf = data;
+ blob_xfer.len = size;
+ blob_xfer.bits_per_word = init ? 8 : 16;
+ spi_message_add_tail(&blob_xfer, &msg);
+
+ ack_xfer.tx_buf = z2->tx_buf;
+ ack_xfer.len = 2;
+ spi_message_add_tail(&ack_xfer, &msg);
+
+ reinit_completion(&z2->boot_irq);
+ error = spi_sync(z2->spidev, &msg);
+ if (error)
+ return error;
+
+ /* Irq only happens sometimes, but the thing boots reliably nonetheless */
+ wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20));
+
+ return 0;
+}
+
+static int apple_z2_upload_firmware(struct apple_z2 *z2)
+{
+ const struct apple_z2_fw_hdr *fw_hdr;
+ size_t fw_idx = sizeof(struct apple_z2_fw_hdr);
+ int error;
+ u32 load_cmd;
+ u32 address;
+ bool init;
+ size_t size;
+
+ const struct firmware *fw __free(firmware) = NULL;
+ error = request_firmware(&fw, z2->fw_name, &z2->spidev->dev);
+ if (error) {
+ dev_err(&z2->spidev->dev, "unable to load firmware\n");
+ return error;
+ }
+
+ fw_hdr = (const struct apple_z2_fw_hdr *)fw->data;
+ if (le32_to_cpu(fw_hdr->magic) != APPLE_Z2_FW_MAGIC || le32_to_cpu(fw_hdr->version) != 1) {
+ dev_err(&z2->spidev->dev, "invalid firmware header\n");
+ return -EINVAL;
+ }
+
+ /*
+ * This will interrupt the upload half-way if the file is malformed
+ * As the device has no non-volatile storage to corrupt, and gets reset
+ * on boot anyway, this is fine.
+ */
+ while (fw_idx < fw->size) {
+ if (fw->size - fw_idx < 8) {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+
+ load_cmd = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+ if (load_cmd == LOAD_COMMAND_INIT_PAYLOAD || load_cmd == LOAD_COMMAND_SEND_BLOB) {
+ size = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+ if (fw->size - fw_idx < size) {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+ init = load_cmd == LOAD_COMMAND_INIT_PAYLOAD;
+ error = apple_z2_send_firmware_blob(z2, fw->data + fw_idx,
+ size, init);
+ if (error)
+ return error;
+ fw_idx += size;
+ } else if (load_cmd == LOAD_COMMAND_SEND_CALIBRATION) {
+ address = le32_to_cpup((__force __le32 *)(fw->data + fw_idx));
+ fw_idx += sizeof(u32);
+
+ const u8 *data __free(kfree) =
+ apple_z2_build_cal_blob(z2, address, &size);
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ if (data) {
+ error = apple_z2_send_firmware_blob(z2, data, size, false);
+ if (error)
+ return error;
+ }
+ } else {
+ dev_err(&z2->spidev->dev, "firmware malformed\n");
+ return -EINVAL;
+ }
+ fw_idx = round_up(fw_idx, 4);
+ }
+
+
+ z2->booted = true;
+ apple_z2_read_packet(z2);
+ return 0;
+}
+
+static int apple_z2_boot(struct apple_z2 *z2)
+{
+ int error;
+
+ reinit_completion(&z2->boot_irq);
+ enable_irq(z2->spidev->irq);
+ gpiod_set_value(z2->reset_gpio, 0);
+ if (!wait_for_completion_timeout(&z2->boot_irq, msecs_to_jiffies(20)))
+ return -ETIMEDOUT;
+
+ error = apple_z2_upload_firmware(z2);
+ if (error) {
+ gpiod_set_value(z2->reset_gpio, 1);
+ disable_irq(z2->spidev->irq);
+ return error;
+ }
+
+ return 0;
+}
+
+static int apple_z2_probe(struct spi_device *spi)
+{
+ struct device *dev = &spi->dev;
+ struct apple_z2 *z2;
+ int error;
+
+ z2 = devm_kzalloc(dev, sizeof(*z2), GFP_KERNEL);
+ if (!z2)
+ return -ENOMEM;
+
+ z2->tx_buf = devm_kzalloc(dev, sizeof(struct apple_z2_read_interrupt_cmd), GFP_KERNEL);
+ if (!z2->tx_buf)
+ return -ENOMEM;
+ /* 4096 will end up being rounded up to 8192 due to devres header */
+ z2->rx_buf = devm_kzalloc(dev, 4000, GFP_KERNEL);
+ if (!z2->rx_buf)
+ return -ENOMEM;
+
+ z2->spidev = spi;
+ init_completion(&z2->boot_irq);
+ spi_set_drvdata(spi, z2);
+
+ /* Reset the device on boot */
+ z2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(z2->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(z2->reset_gpio), "unable to get reset\n");
+
+ error = devm_request_threaded_irq(dev, z2->spidev->irq, NULL, apple_z2_irq,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN,
+ "apple-z2-irq", z2);
+ if (error)
+ return dev_err_probe(dev, error, "unable to request irq\n");
+
+ error = device_property_read_string(dev, "firmware-name", &z2->fw_name);
+ if (error)
+ return dev_err_probe(dev, error, "unable to get firmware name\n");
+
+ z2->input_dev = devm_input_allocate_device(dev);
+ if (!z2->input_dev)
+ return -ENOMEM;
+
+ z2->input_dev->name = (char *)spi_get_device_id(spi)->driver_data;
+ z2->input_dev->phys = "apple_z2";
+ z2->input_dev->id.bustype = BUS_SPI;
+
+ /* Allocate the axes before setting from DT */
+ input_set_abs_params(z2->input_dev, ABS_MT_POSITION_X, 0, 0, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_POSITION_Y, 0, 0, 0, 0);
+ touchscreen_parse_properties(z2->input_dev, true, &z2->props);
+ input_abs_set_res(z2->input_dev, ABS_MT_POSITION_X, 100);
+ input_abs_set_res(z2->input_dev, ABS_MT_POSITION_Y, 100);
+ input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MAJOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_WIDTH_MINOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MAJOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_TOUCH_MINOR, 0, 65535, 0, 0);
+ input_set_abs_params(z2->input_dev, ABS_MT_ORIENTATION, -32768, 32767, 0, 0);
+
+ error = input_mt_init_slots(z2->input_dev, 256, INPUT_MT_DIRECT);
+ if (error)
+ return dev_err_probe(dev, error, "unable to initialize multitouch slots\n");
+
+ error = input_register_device(z2->input_dev);
+ if (error)
+ return dev_err_probe(dev, error, "unable to register input device\n");
+
+ /* Wait for device reset to finish */
+ usleep_range(5000, 10000);
+ error = apple_z2_boot(z2);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static void apple_z2_shutdown(struct spi_device *spi)
+{
+ struct apple_z2 *z2 = spi_get_drvdata(spi);
+
+ disable_irq(z2->spidev->irq);
+ gpiod_direction_output(z2->reset_gpio, 1);
+ z2->booted = false;
+}
+
+static int apple_z2_suspend(struct device *dev)
+{
+ apple_z2_shutdown(to_spi_device(dev));
+
+ return 0;
+}
+
+static int apple_z2_resume(struct device *dev)
+{
+ struct apple_z2 *z2 = spi_get_drvdata(to_spi_device(dev));
+
+ return apple_z2_boot(z2);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(apple_z2_pm, apple_z2_suspend, apple_z2_resume);
+
+static const struct of_device_id apple_z2_of_match[] = {
+ { .compatible = "apple,j293-touchbar" },
+ { .compatible = "apple,j493-touchbar" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, apple_z2_of_match);
+
+static struct spi_device_id apple_z2_of_id[] = {
+ { .name = "j293-touchbar", .driver_data = (kernel_ulong_t)"MacBookPro17,1 Touch Bar" },
+ { .name = "j493-touchbar", .driver_data = (kernel_ulong_t)"Mac14,7 Touch Bar" },
+ {}
+};
+MODULE_DEVICE_TABLE(spi, apple_z2_of_id);
+
+static struct spi_driver apple_z2_driver = {
+ .driver = {
+ .name = "apple-z2",
+ .pm = pm_sleep_ptr(&apple_z2_pm),
+ .of_match_table = apple_z2_of_match,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ },
+ .id_table = apple_z2_of_id,
+ .probe = apple_z2_probe,
+ .remove = apple_z2_shutdown,
+};
+
+module_spi_driver(apple_z2_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("apple/dfrmtfw-*.bin");
+MODULE_DESCRIPTION("Apple Z2 touchscreens driver");
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 8a606bd441ae..dd0544cc1bc1 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -19,6 +19,7 @@
#include <linux/firmware.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
+#include <linux/input/touchscreen.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/of.h>
@@ -26,7 +27,7 @@
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-v4l2.h>
@@ -355,6 +356,8 @@ struct mxt_data {
enum mxt_suspend_mode suspend_mode;
u32 wakeup_method;
+
+ struct touchscreen_properties prop;
};
struct mxt_vb2_buffer {
@@ -888,8 +891,7 @@ static void mxt_proc_t9_message(struct mxt_data *data, u8 *message)
/* Touch active */
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_PRESSURE, amplitude);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, area);
} else {
@@ -1010,8 +1012,7 @@ static void mxt_proc_t100_message(struct mxt_data *data, u8 *message)
id, type, x, y, major, pressure, orientation);
input_mt_report_slot_state(input_dev, tool, 1);
- input_report_abs(input_dev, ABS_MT_POSITION_X, x);
- input_report_abs(input_dev, ABS_MT_POSITION_Y, y);
+ touchscreen_report_pos(input_dev, &data->prop, x, y, true);
input_report_abs(input_dev, ABS_MT_TOUCH_MAJOR, major);
input_report_abs(input_dev, ABS_MT_PRESSURE, pressure);
input_report_abs(input_dev, ABS_MT_DISTANCE, distance);
@@ -2212,6 +2213,8 @@ static int mxt_initialize_input_device(struct mxt_data *data)
0, 255, 0, 0);
}
+ touchscreen_parse_properties(input_dev, true, &data->prop);
+
/* For T15 and T97 Key Array */
if (data->T15_reportid_min || data->T97_reportid_min) {
for (i = 0; i < data->t15_num_keys; i++)
@@ -2535,8 +2538,6 @@ fault:
static const struct vb2_ops mxt_queue_ops = {
.queue_setup = mxt_queue_setup,
.buf_queue = mxt_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue mxt_queue = {
@@ -3069,9 +3070,7 @@ static struct attribute *mxt_attrs[] = {
NULL
};
-static const struct attribute_group mxt_attr_group = {
- .attrs = mxt_attrs,
-};
+ATTRIBUTE_GROUPS(mxt);
static void mxt_start(struct mxt_data *data)
{
@@ -3321,7 +3320,7 @@ static int mxt_probe(struct i2c_client *client)
if (data->reset_gpio) {
/* Wait a while and then de-assert the RESET GPIO line */
msleep(MXT_RESET_GPIO_TIME);
- gpiod_set_value(data->reset_gpio, 0);
+ gpiod_set_value_cansleep(data->reset_gpio, 0);
msleep(MXT_RESET_INVALID_CHG);
}
@@ -3348,18 +3347,8 @@ static int mxt_probe(struct i2c_client *client)
if (error)
goto err_disable_regulators;
- error = sysfs_create_group(&client->dev.kobj, &mxt_attr_group);
- if (error) {
- dev_err(&client->dev, "Failure %d creating sysfs group\n",
- error);
- goto err_free_object;
- }
-
return 0;
-err_free_object:
- mxt_free_input_device(data);
- mxt_free_object_table(data);
err_disable_regulators:
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
data->regulators);
@@ -3371,7 +3360,6 @@ static void mxt_remove(struct i2c_client *client)
struct mxt_data *data = i2c_get_clientdata(client);
disable_irq(data->irq);
- sysfs_remove_group(&client->dev.kobj, &mxt_attr_group);
mxt_free_input_device(data);
mxt_free_object_table(data);
regulator_bulk_disable(ARRAY_SIZE(data->regulators),
@@ -3455,6 +3443,7 @@ MODULE_DEVICE_TABLE(i2c, mxt_id);
static struct i2c_driver mxt_driver = {
.driver = {
.name = "atmel_mxt_ts",
+ .dev_groups = mxt_groups,
.of_match_table = mxt_of_match,
.acpi_match_table = ACPI_PTR(mxt_acpi_id),
.pm = pm_sleep_ptr(&mxt_pm_ops),
diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c
index 8db2a112a476..363a4a1f1560 100644
--- a/drivers/input/touchscreen/auo-pixcir-ts.c
+++ b/drivers/input/touchscreen/auo-pixcir-ts.c
@@ -72,7 +72,7 @@
/*
* Interrupt modes:
- * periodical: interrupt is asserted periodicaly
+ * periodical: interrupt is asserted periodically
* compare coordinates: interrupt is asserted when coordinates change
* indicate touch: interrupt is asserted during touch
*/
diff --git a/drivers/input/touchscreen/bcm_iproc_tsc.c b/drivers/input/touchscreen/bcm_iproc_tsc.c
index 9c84235327bf..e49bde50d77a 100644
--- a/drivers/input/touchscreen/bcm_iproc_tsc.c
+++ b/drivers/input/touchscreen/bcm_iproc_tsc.c
@@ -217,7 +217,7 @@ static irqreturn_t iproc_touchscreen_interrupt(int irq, void *data)
"pen up-down (%d)\n", priv->pen_status);
}
- /* coordinates in FIFO exceed the theshold */
+ /* coordinates in FIFO exceed the threshold */
if (intr_status & TS_FIFO_INTR_MASK) {
for (i = 0; i < priv->cfg_params.fifo_threshold; i++) {
regmap_read(priv->regmap, FIFO_DATA, &raw_coordinate);
diff --git a/drivers/input/touchscreen/bu21029_ts.c b/drivers/input/touchscreen/bu21029_ts.c
index 686d0a6b1570..64f474e67312 100644
--- a/drivers/input/touchscreen/bu21029_ts.c
+++ b/drivers/input/touchscreen/bu21029_ts.c
@@ -209,7 +209,8 @@ static void bu21029_touch_report(struct bu21029_ts_data *bu21029, const u8 *buf)
static void bu21029_touch_release(struct timer_list *t)
{
- struct bu21029_ts_data *bu21029 = from_timer(bu21029, t, timer);
+ struct bu21029_ts_data *bu21029 = timer_container_of(bu21029, t,
+ timer);
input_report_abs(bu21029->in_dev, ABS_PRESSURE, 0);
input_report_key(bu21029->in_dev, BTN_TOUCH, 0);
@@ -325,7 +326,7 @@ static void bu21029_stop_chip(struct input_dev *dev)
struct bu21029_ts_data *bu21029 = input_get_drvdata(dev);
disable_irq(bu21029->client->irq);
- del_timer_sync(&bu21029->timer);
+ timer_delete_sync(&bu21029->timer);
bu21029_put_chip_in_reset(bu21029);
regulator_disable(bu21029->vdd);
diff --git a/drivers/input/touchscreen/chipone_icn8505.c b/drivers/input/touchscreen/chipone_icn8505.c
index c1b4fc28fa8d..cde0e4789503 100644
--- a/drivers/input/touchscreen/chipone_icn8505.c
+++ b/drivers/input/touchscreen/chipone_icn8505.c
@@ -8,7 +8,7 @@
* Hans de Goede <hdegoede@redhat.com>
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/acpi.h>
#include <linux/crc32.h>
#include <linux/delay.h>
diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c
index aa829725ded7..98d5b2ba63fb 100644
--- a/drivers/input/touchscreen/colibri-vf50-ts.c
+++ b/drivers/input/touchscreen/colibri-vf50-ts.c
@@ -239,14 +239,10 @@ static void vf50_ts_close(struct input_dev *dev_input)
static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d,
const char *con_id, enum gpiod_flags flags)
{
- int error;
-
*gpio_d = devm_gpiod_get(dev, con_id, flags);
- if (IS_ERR(*gpio_d)) {
- error = PTR_ERR(*gpio_d);
- dev_err(dev, "Could not get gpio_%s %d\n", con_id, error);
- return error;
- }
+ if (IS_ERR(*gpio_d))
+ return dev_err_probe(dev, PTR_ERR(*gpio_d),
+ "Could not get gpio_%s\n", con_id);
return 0;
}
diff --git a/drivers/input/touchscreen/cy8ctma140.c b/drivers/input/touchscreen/cy8ctma140.c
index 567c9dcaac91..2d4b6e343203 100644
--- a/drivers/input/touchscreen/cy8ctma140.c
+++ b/drivers/input/touchscreen/cy8ctma140.c
@@ -16,7 +16,7 @@
* same.
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/input.h>
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
deleted file mode 100644
index 7cb26929dc73..000000000000
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ /dev/null
@@ -1,2174 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cyttsp4_core.c
- * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2012 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include "cyttsp4_core.h"
-#include <linux/delay.h>
-#include <linux/gpio.h>
-#include <linux/input/mt.h>
-#include <linux/interrupt.h>
-#include <linux/pm_runtime.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-/* Timeout in ms. */
-#define CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT 500
-#define CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT 5000
-#define CY_CORE_MODE_CHANGE_TIMEOUT 1000
-#define CY_CORE_RESET_AND_WAIT_TIMEOUT 500
-#define CY_CORE_WAKEUP_TIMEOUT 500
-
-#define CY_CORE_STARTUP_RETRY_COUNT 3
-
-static const char * const cyttsp4_tch_abs_string[] = {
- [CY_TCH_X] = "X",
- [CY_TCH_Y] = "Y",
- [CY_TCH_P] = "P",
- [CY_TCH_T] = "T",
- [CY_TCH_E] = "E",
- [CY_TCH_O] = "O",
- [CY_TCH_W] = "W",
- [CY_TCH_MAJ] = "MAJ",
- [CY_TCH_MIN] = "MIN",
- [CY_TCH_OR] = "OR",
- [CY_TCH_NUM_ABS] = "INVALID"
-};
-
-static const u8 ldr_exit[] = {
- 0xFF, 0x01, 0x3B, 0x00, 0x00, 0x4F, 0x6D, 0x17
-};
-
-static const u8 ldr_err_app[] = {
- 0x01, 0x02, 0x00, 0x00, 0x55, 0xDD, 0x17
-};
-
-static inline size_t merge_bytes(u8 high, u8 low)
-{
- return (high << 8) + low;
-}
-
-#ifdef VERBOSE_DEBUG
-static void cyttsp4_pr_buf(struct device *dev, u8 *pr_buf, u8 *dptr, int size,
- const char *data_name)
-{
- int i, k;
- const char fmt[] = "%02X ";
- int max;
-
- if (!size)
- return;
-
- max = (CY_MAX_PRBUF_SIZE - 1) - sizeof(CY_PR_TRUNCATED);
-
- pr_buf[0] = 0;
- for (i = k = 0; i < size && k < max; i++, k += 3)
- scnprintf(pr_buf + k, CY_MAX_PRBUF_SIZE, fmt, dptr[i]);
-
- dev_vdbg(dev, "%s: %s[0..%d]=%s%s\n", __func__, data_name, size - 1,
- pr_buf, size <= max ? "" : CY_PR_TRUNCATED);
-}
-#else
-#define cyttsp4_pr_buf(dev, pr_buf, dptr, size, data_name) do { } while (0)
-#endif
-
-static int cyttsp4_load_status_regs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- struct device *dev = cd->dev;
- int rc;
-
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, si->si_ofs.mode_size,
- si->xy_mode);
- if (rc < 0)
- dev_err(dev, "%s: fail read mode regs r=%d\n",
- __func__, rc);
- else
- cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_mode,
- si->si_ofs.mode_size, "xy_mode");
-
- return rc;
-}
-
-static int cyttsp4_handshake(struct cyttsp4 *cd, u8 mode)
-{
- u8 cmd = mode ^ CY_HST_TOGGLE;
- int rc;
-
- /*
- * Mode change issued, handshaking now will cause endless mode change
- * requests, for sync mode modechange will do same with handshake
- * */
- if (mode & CY_HST_MODE_CHANGE)
- return 0;
-
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
- if (rc < 0)
- dev_err(cd->dev, "%s: bus write fail on handshake (ret=%d)\n",
- __func__, rc);
-
- return rc;
-}
-
-static int cyttsp4_hw_soft_reset(struct cyttsp4 *cd)
-{
- u8 cmd = CY_HST_RESET;
- int rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(cmd), &cmd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: FAILED to execute SOFT reset\n",
- __func__);
- return rc;
- }
- return 0;
-}
-
-static int cyttsp4_hw_hard_reset(struct cyttsp4 *cd)
-{
- if (cd->cpdata->xres) {
- cd->cpdata->xres(cd->cpdata, cd->dev);
- dev_dbg(cd->dev, "%s: execute HARD reset\n", __func__);
- return 0;
- }
- dev_err(cd->dev, "%s: FAILED to execute HARD reset\n", __func__);
- return -ENOSYS;
-}
-
-static int cyttsp4_hw_reset(struct cyttsp4 *cd)
-{
- int rc = cyttsp4_hw_hard_reset(cd);
- if (rc == -ENOSYS)
- rc = cyttsp4_hw_soft_reset(cd);
- return rc;
-}
-
-/*
- * Gets number of bits for a touch filed as parameter,
- * sets maximum value for field which is used as bit mask
- * and returns number of bytes required for that field
- */
-static int cyttsp4_bits_2_bytes(unsigned int nbits, size_t *max)
-{
- *max = 1UL << nbits;
- return (nbits + 7) / 8;
-}
-
-static int cyttsp4_si_data_offsets(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(si->si_data),
- &si->si_data);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read sysinfo data offsets r=%d\n",
- __func__, rc);
- return rc;
- }
-
- /* Print sysinfo data offsets */
- cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)&si->si_data,
- sizeof(si->si_data), "sysinfo_data_offsets");
-
- /* convert sysinfo data offset bytes into integers */
-
- si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
- si->si_data.map_szl);
- si->si_ofs.map_sz = merge_bytes(si->si_data.map_szh,
- si->si_data.map_szl);
- si->si_ofs.cydata_ofs = merge_bytes(si->si_data.cydata_ofsh,
- si->si_data.cydata_ofsl);
- si->si_ofs.test_ofs = merge_bytes(si->si_data.test_ofsh,
- si->si_data.test_ofsl);
- si->si_ofs.pcfg_ofs = merge_bytes(si->si_data.pcfg_ofsh,
- si->si_data.pcfg_ofsl);
- si->si_ofs.opcfg_ofs = merge_bytes(si->si_data.opcfg_ofsh,
- si->si_data.opcfg_ofsl);
- si->si_ofs.ddata_ofs = merge_bytes(si->si_data.ddata_ofsh,
- si->si_data.ddata_ofsl);
- si->si_ofs.mdata_ofs = merge_bytes(si->si_data.mdata_ofsh,
- si->si_data.mdata_ofsl);
- return rc;
-}
-
-static int cyttsp4_si_get_cydata(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int read_offset;
- int mfgid_sz, calc_mfgid_sz;
- void *p;
- int rc;
-
- if (si->si_ofs.test_ofs <= si->si_ofs.cydata_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset test_ofs: %zu, cydata_ofs: %zu\n",
- __func__, si->si_ofs.test_ofs, si->si_ofs.cydata_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.cydata_size = si->si_ofs.test_ofs - si->si_ofs.cydata_ofs;
- dev_dbg(cd->dev, "%s: cydata size: %zd\n", __func__,
- si->si_ofs.cydata_size);
-
- p = krealloc(si->si_ptrs.cydata, si->si_ofs.cydata_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate cydata memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.cydata = p;
-
- read_offset = si->si_ofs.cydata_ofs;
-
- /* Read the CYDA registers up to MFGID field */
- rc = cyttsp4_adap_read(cd, read_offset,
- offsetof(struct cyttsp4_cydata, mfgid_sz)
- + sizeof(si->si_ptrs.cydata->mfgid_sz),
- si->si_ptrs.cydata);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read cydata r=%d\n",
- __func__, rc);
- return rc;
- }
-
- /* Check MFGID size */
- mfgid_sz = si->si_ptrs.cydata->mfgid_sz;
- calc_mfgid_sz = si->si_ofs.cydata_size - sizeof(struct cyttsp4_cydata);
- if (mfgid_sz != calc_mfgid_sz) {
- dev_err(cd->dev, "%s: mismatch in MFGID size, reported:%d calculated:%d\n",
- __func__, mfgid_sz, calc_mfgid_sz);
- return -EINVAL;
- }
-
- read_offset += offsetof(struct cyttsp4_cydata, mfgid_sz)
- + sizeof(si->si_ptrs.cydata->mfgid_sz);
-
- /* Read the CYDA registers for MFGID field */
- rc = cyttsp4_adap_read(cd, read_offset, si->si_ptrs.cydata->mfgid_sz,
- si->si_ptrs.cydata->mfg_id);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read cydata r=%d\n",
- __func__, rc);
- return rc;
- }
-
- read_offset += si->si_ptrs.cydata->mfgid_sz;
-
- /* Read the rest of the CYDA registers */
- rc = cyttsp4_adap_read(cd, read_offset,
- sizeof(struct cyttsp4_cydata)
- - offsetof(struct cyttsp4_cydata, cyito_idh),
- &si->si_ptrs.cydata->cyito_idh);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read cydata r=%d\n",
- __func__, rc);
- return rc;
- }
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.cydata,
- si->si_ofs.cydata_size, "sysinfo_cydata");
- return rc;
-}
-
-static int cyttsp4_si_get_test_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- if (si->si_ofs.pcfg_ofs <= si->si_ofs.test_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset pcfg_ofs: %zu, test_ofs: %zu\n",
- __func__, si->si_ofs.pcfg_ofs, si->si_ofs.test_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.test_size = si->si_ofs.pcfg_ofs - si->si_ofs.test_ofs;
-
- p = krealloc(si->si_ptrs.test, si->si_ofs.test_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate test memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.test = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.test_ofs, si->si_ofs.test_size,
- si->si_ptrs.test);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read test data r=%d\n",
- __func__, rc);
- return rc;
- }
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.test, si->si_ofs.test_size,
- "sysinfo_test_data");
- if (si->si_ptrs.test->post_codel &
- CY_POST_CODEL_WDG_RST)
- dev_info(cd->dev, "%s: %s codel=%02X\n",
- __func__, "Reset was a WATCHDOG RESET",
- si->si_ptrs.test->post_codel);
-
- if (!(si->si_ptrs.test->post_codel &
- CY_POST_CODEL_CFG_DATA_CRC_FAIL))
- dev_info(cd->dev, "%s: %s codel=%02X\n", __func__,
- "Config Data CRC FAIL",
- si->si_ptrs.test->post_codel);
-
- if (!(si->si_ptrs.test->post_codel &
- CY_POST_CODEL_PANEL_TEST_FAIL))
- dev_info(cd->dev, "%s: %s codel=%02X\n",
- __func__, "PANEL TEST FAIL",
- si->si_ptrs.test->post_codel);
-
- dev_info(cd->dev, "%s: SCANNING is %s codel=%02X\n",
- __func__, si->si_ptrs.test->post_codel & 0x08 ?
- "ENABLED" : "DISABLED",
- si->si_ptrs.test->post_codel);
- return rc;
-}
-
-static int cyttsp4_si_get_pcfg_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- if (si->si_ofs.opcfg_ofs <= si->si_ofs.pcfg_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset opcfg_ofs: %zu, pcfg_ofs: %zu\n",
- __func__, si->si_ofs.opcfg_ofs, si->si_ofs.pcfg_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.pcfg_size = si->si_ofs.opcfg_ofs - si->si_ofs.pcfg_ofs;
-
- p = krealloc(si->si_ptrs.pcfg, si->si_ofs.pcfg_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate pcfg memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.pcfg = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size,
- si->si_ptrs.pcfg);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read pcfg data r=%d\n",
- __func__, rc);
- return rc;
- }
-
- si->si_ofs.max_x = merge_bytes((si->si_ptrs.pcfg->res_xh
- & CY_PCFG_RESOLUTION_X_MASK), si->si_ptrs.pcfg->res_xl);
- si->si_ofs.x_origin = !!(si->si_ptrs.pcfg->res_xh
- & CY_PCFG_ORIGIN_X_MASK);
- si->si_ofs.max_y = merge_bytes((si->si_ptrs.pcfg->res_yh
- & CY_PCFG_RESOLUTION_Y_MASK), si->si_ptrs.pcfg->res_yl);
- si->si_ofs.y_origin = !!(si->si_ptrs.pcfg->res_yh
- & CY_PCFG_ORIGIN_Y_MASK);
- si->si_ofs.max_p = merge_bytes(si->si_ptrs.pcfg->max_zh,
- si->si_ptrs.pcfg->max_zl);
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.pcfg,
- si->si_ofs.pcfg_size, "sysinfo_pcfg_data");
- return rc;
-}
-
-static int cyttsp4_si_get_opcfg_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- struct cyttsp4_tch_abs_params *tch;
- struct cyttsp4_tch_rec_params *tch_old, *tch_new;
- enum cyttsp4_tch_abs abs;
- int i;
- void *p;
- int rc;
-
- if (si->si_ofs.ddata_ofs <= si->si_ofs.opcfg_ofs) {
- dev_err(cd->dev,
- "%s: invalid offset ddata_ofs: %zu, opcfg_ofs: %zu\n",
- __func__, si->si_ofs.ddata_ofs, si->si_ofs.opcfg_ofs);
- return -EINVAL;
- }
-
- si->si_ofs.opcfg_size = si->si_ofs.ddata_ofs - si->si_ofs.opcfg_ofs;
-
- p = krealloc(si->si_ptrs.opcfg, si->si_ofs.opcfg_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: failed to allocate opcfg memory\n",
- __func__);
- return -ENOMEM;
- }
- si->si_ptrs.opcfg = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size,
- si->si_ptrs.opcfg);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail read opcfg data r=%d\n",
- __func__, rc);
- return rc;
- }
- si->si_ofs.cmd_ofs = si->si_ptrs.opcfg->cmd_ofs;
- si->si_ofs.rep_ofs = si->si_ptrs.opcfg->rep_ofs;
- si->si_ofs.rep_sz = (si->si_ptrs.opcfg->rep_szh * 256) +
- si->si_ptrs.opcfg->rep_szl;
- si->si_ofs.num_btns = si->si_ptrs.opcfg->num_btns;
- si->si_ofs.num_btn_regs = (si->si_ofs.num_btns +
- CY_NUM_BTN_PER_REG - 1) / CY_NUM_BTN_PER_REG;
- si->si_ofs.tt_stat_ofs = si->si_ptrs.opcfg->tt_stat_ofs;
- si->si_ofs.obj_cfg0 = si->si_ptrs.opcfg->obj_cfg0;
- si->si_ofs.max_tchs = si->si_ptrs.opcfg->max_tchs &
- CY_BYTE_OFS_MASK;
- si->si_ofs.tch_rec_size = si->si_ptrs.opcfg->tch_rec_size &
- CY_BYTE_OFS_MASK;
-
- /* Get the old touch fields */
- for (abs = CY_TCH_X; abs < CY_NUM_TCH_FIELDS; abs++) {
- tch = &si->si_ofs.tch_abs[abs];
- tch_old = &si->si_ptrs.opcfg->tch_rec_old[abs];
-
- tch->ofs = tch_old->loc & CY_BYTE_OFS_MASK;
- tch->size = cyttsp4_bits_2_bytes(tch_old->size,
- &tch->max);
- tch->bofs = (tch_old->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
- }
-
- /* button fields */
- si->si_ofs.btn_rec_size = si->si_ptrs.opcfg->btn_rec_size;
- si->si_ofs.btn_diff_ofs = si->si_ptrs.opcfg->btn_diff_ofs;
- si->si_ofs.btn_diff_size = si->si_ptrs.opcfg->btn_diff_size;
-
- if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
- /* Get the extended touch fields */
- for (i = 0; i < CY_NUM_EXT_TCH_FIELDS; abs++, i++) {
- tch = &si->si_ofs.tch_abs[abs];
- tch_new = &si->si_ptrs.opcfg->tch_rec_new[i];
-
- tch->ofs = tch_new->loc & CY_BYTE_OFS_MASK;
- tch->size = cyttsp4_bits_2_bytes(tch_new->size,
- &tch->max);
- tch->bofs = (tch_new->loc & CY_BOFS_MASK) >> CY_BOFS_SHIFT;
- }
- }
-
- for (abs = 0; abs < CY_TCH_NUM_ABS; abs++) {
- dev_dbg(cd->dev, "%s: tch_rec_%s\n", __func__,
- cyttsp4_tch_abs_string[abs]);
- dev_dbg(cd->dev, "%s: ofs =%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].ofs);
- dev_dbg(cd->dev, "%s: siz =%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].size);
- dev_dbg(cd->dev, "%s: max =%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].max);
- dev_dbg(cd->dev, "%s: bofs=%2zd\n", __func__,
- si->si_ofs.tch_abs[abs].bofs);
- }
-
- si->si_ofs.mode_size = si->si_ofs.tt_stat_ofs + 1;
- si->si_ofs.data_size = si->si_ofs.max_tchs *
- si->si_ptrs.opcfg->tch_rec_size;
-
- cyttsp4_pr_buf(cd->dev, cd->pr_buf, (u8 *)si->si_ptrs.opcfg,
- si->si_ofs.opcfg_size, "sysinfo_opcfg_data");
-
- return 0;
-}
-
-static int cyttsp4_si_get_ddata(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- si->si_ofs.ddata_size = si->si_ofs.mdata_ofs - si->si_ofs.ddata_ofs;
-
- p = krealloc(si->si_ptrs.ddata, si->si_ofs.ddata_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: fail alloc ddata memory\n", __func__);
- return -ENOMEM;
- }
- si->si_ptrs.ddata = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.ddata_ofs, si->si_ofs.ddata_size,
- si->si_ptrs.ddata);
- if (rc < 0)
- dev_err(cd->dev, "%s: fail read ddata data r=%d\n",
- __func__, rc);
- else
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.ddata,
- si->si_ofs.ddata_size, "sysinfo_ddata");
- return rc;
-}
-
-static int cyttsp4_si_get_mdata(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
- int rc;
-
- si->si_ofs.mdata_size = si->si_ofs.map_sz - si->si_ofs.mdata_ofs;
-
- p = krealloc(si->si_ptrs.mdata, si->si_ofs.mdata_size, GFP_KERNEL);
- if (p == NULL) {
- dev_err(cd->dev, "%s: fail alloc mdata memory\n", __func__);
- return -ENOMEM;
- }
- si->si_ptrs.mdata = p;
-
- rc = cyttsp4_adap_read(cd, si->si_ofs.mdata_ofs, si->si_ofs.mdata_size,
- si->si_ptrs.mdata);
- if (rc < 0)
- dev_err(cd->dev, "%s: fail read mdata data r=%d\n",
- __func__, rc);
- else
- cyttsp4_pr_buf(cd->dev, cd->pr_buf,
- (u8 *)si->si_ptrs.mdata,
- si->si_ofs.mdata_size, "sysinfo_mdata");
- return rc;
-}
-
-static int cyttsp4_si_get_btn_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int btn;
- int num_defined_keys;
- u16 *key_table;
- void *p;
- int rc = 0;
-
- if (si->si_ofs.num_btns) {
- si->si_ofs.btn_keys_size = si->si_ofs.num_btns *
- sizeof(struct cyttsp4_btn);
-
- p = krealloc(si->btn, si->si_ofs.btn_keys_size,
- GFP_KERNEL|__GFP_ZERO);
- if (p == NULL) {
- dev_err(cd->dev, "%s: %s\n", __func__,
- "fail alloc btn_keys memory");
- return -ENOMEM;
- }
- si->btn = p;
-
- if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS] == NULL)
- num_defined_keys = 0;
- else if (cd->cpdata->sett[CY_IC_GRPNUM_BTN_KEYS]->data == NULL)
- num_defined_keys = 0;
- else
- num_defined_keys = cd->cpdata->sett
- [CY_IC_GRPNUM_BTN_KEYS]->size;
-
- for (btn = 0; btn < si->si_ofs.num_btns &&
- btn < num_defined_keys; btn++) {
- key_table = (u16 *)cd->cpdata->sett
- [CY_IC_GRPNUM_BTN_KEYS]->data;
- si->btn[btn].key_code = key_table[btn];
- si->btn[btn].state = CY_BTN_RELEASED;
- si->btn[btn].enabled = true;
- }
- for (; btn < si->si_ofs.num_btns; btn++) {
- si->btn[btn].key_code = KEY_RESERVED;
- si->btn[btn].state = CY_BTN_RELEASED;
- si->btn[btn].enabled = true;
- }
-
- return rc;
- }
-
- si->si_ofs.btn_keys_size = 0;
- kfree(si->btn);
- si->btn = NULL;
- return rc;
-}
-
-static int cyttsp4_si_get_op_data_ptrs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- void *p;
-
- p = krealloc(si->xy_mode, si->si_ofs.mode_size, GFP_KERNEL|__GFP_ZERO);
- if (p == NULL)
- return -ENOMEM;
- si->xy_mode = p;
-
- p = krealloc(si->xy_data, si->si_ofs.data_size, GFP_KERNEL|__GFP_ZERO);
- if (p == NULL)
- return -ENOMEM;
- si->xy_data = p;
-
- p = krealloc(si->btn_rec_data,
- si->si_ofs.btn_rec_size * si->si_ofs.num_btns,
- GFP_KERNEL|__GFP_ZERO);
- if (p == NULL)
- return -ENOMEM;
- si->btn_rec_data = p;
-
- return 0;
-}
-
-static void cyttsp4_si_put_log_data(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- dev_dbg(cd->dev, "%s: cydata_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.cydata_ofs, si->si_ofs.cydata_size);
- dev_dbg(cd->dev, "%s: test_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.test_ofs, si->si_ofs.test_size);
- dev_dbg(cd->dev, "%s: pcfg_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.pcfg_ofs, si->si_ofs.pcfg_size);
- dev_dbg(cd->dev, "%s: opcfg_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.opcfg_ofs, si->si_ofs.opcfg_size);
- dev_dbg(cd->dev, "%s: ddata_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.ddata_ofs, si->si_ofs.ddata_size);
- dev_dbg(cd->dev, "%s: mdata_ofs =%4zd siz=%4zd\n", __func__,
- si->si_ofs.mdata_ofs, si->si_ofs.mdata_size);
-
- dev_dbg(cd->dev, "%s: cmd_ofs =%4zd\n", __func__,
- si->si_ofs.cmd_ofs);
- dev_dbg(cd->dev, "%s: rep_ofs =%4zd\n", __func__,
- si->si_ofs.rep_ofs);
- dev_dbg(cd->dev, "%s: rep_sz =%4zd\n", __func__,
- si->si_ofs.rep_sz);
- dev_dbg(cd->dev, "%s: num_btns =%4zd\n", __func__,
- si->si_ofs.num_btns);
- dev_dbg(cd->dev, "%s: num_btn_regs =%4zd\n", __func__,
- si->si_ofs.num_btn_regs);
- dev_dbg(cd->dev, "%s: tt_stat_ofs =%4zd\n", __func__,
- si->si_ofs.tt_stat_ofs);
- dev_dbg(cd->dev, "%s: tch_rec_size =%4zd\n", __func__,
- si->si_ofs.tch_rec_size);
- dev_dbg(cd->dev, "%s: max_tchs =%4zd\n", __func__,
- si->si_ofs.max_tchs);
- dev_dbg(cd->dev, "%s: mode_size =%4zd\n", __func__,
- si->si_ofs.mode_size);
- dev_dbg(cd->dev, "%s: data_size =%4zd\n", __func__,
- si->si_ofs.data_size);
- dev_dbg(cd->dev, "%s: map_sz =%4zd\n", __func__,
- si->si_ofs.map_sz);
-
- dev_dbg(cd->dev, "%s: btn_rec_size =%2zd\n", __func__,
- si->si_ofs.btn_rec_size);
- dev_dbg(cd->dev, "%s: btn_diff_ofs =%2zd\n", __func__,
- si->si_ofs.btn_diff_ofs);
- dev_dbg(cd->dev, "%s: btn_diff_size =%2zd\n", __func__,
- si->si_ofs.btn_diff_size);
-
- dev_dbg(cd->dev, "%s: max_x = 0x%04zX (%zd)\n", __func__,
- si->si_ofs.max_x, si->si_ofs.max_x);
- dev_dbg(cd->dev, "%s: x_origin = %zd (%s)\n", __func__,
- si->si_ofs.x_origin,
- si->si_ofs.x_origin == CY_NORMAL_ORIGIN ?
- "left corner" : "right corner");
- dev_dbg(cd->dev, "%s: max_y = 0x%04zX (%zd)\n", __func__,
- si->si_ofs.max_y, si->si_ofs.max_y);
- dev_dbg(cd->dev, "%s: y_origin = %zd (%s)\n", __func__,
- si->si_ofs.y_origin,
- si->si_ofs.y_origin == CY_NORMAL_ORIGIN ?
- "upper corner" : "lower corner");
- dev_dbg(cd->dev, "%s: max_p = 0x%04zX (%zd)\n", __func__,
- si->si_ofs.max_p, si->si_ofs.max_p);
-
- dev_dbg(cd->dev, "%s: xy_mode=%p xy_data=%p\n", __func__,
- si->xy_mode, si->xy_data);
-}
-
-static int cyttsp4_get_sysinfo_regs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
- int rc;
-
- rc = cyttsp4_si_data_offsets(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_cydata(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_test_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_pcfg_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_opcfg_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_ddata(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_mdata(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_btn_data(cd);
- if (rc < 0)
- return rc;
-
- rc = cyttsp4_si_get_op_data_ptrs(cd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: failed to get_op_data\n",
- __func__);
- return rc;
- }
-
- cyttsp4_si_put_log_data(cd);
-
- /* provide flow control handshake */
- rc = cyttsp4_handshake(cd, si->si_data.hst_mode);
- if (rc < 0)
- dev_err(cd->dev, "%s: handshake fail on sysinfo reg\n",
- __func__);
-
- si->ready = true;
- return rc;
-}
-
-static void cyttsp4_queue_startup_(struct cyttsp4 *cd)
-{
- if (cd->startup_state == STARTUP_NONE) {
- cd->startup_state = STARTUP_QUEUED;
- schedule_work(&cd->startup_work);
- dev_dbg(cd->dev, "%s: cyttsp4_startup queued\n", __func__);
- } else {
- dev_dbg(cd->dev, "%s: startup_state = %d\n", __func__,
- cd->startup_state);
- }
-}
-
-static void cyttsp4_report_slot_liftoff(struct cyttsp4_mt_data *md,
- int max_slots)
-{
- int t;
-
- if (md->num_prv_tch == 0)
- return;
-
- for (t = 0; t < max_slots; t++) {
- input_mt_slot(md->input, t);
- input_mt_report_slot_inactive(md->input);
- }
-}
-
-static void cyttsp4_lift_all(struct cyttsp4_mt_data *md)
-{
- if (!md->si)
- return;
-
- if (md->num_prv_tch != 0) {
- cyttsp4_report_slot_liftoff(md,
- md->si->si_ofs.tch_abs[CY_TCH_T].max);
- input_sync(md->input);
- md->num_prv_tch = 0;
- }
-}
-
-static void cyttsp4_get_touch_axis(struct cyttsp4_mt_data *md,
- int *axis, int size, int max, u8 *xy_data, int bofs)
-{
- int nbyte;
- int next;
-
- for (nbyte = 0, *axis = 0, next = 0; nbyte < size; nbyte++) {
- dev_vdbg(&md->input->dev,
- "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
- " xy_data[%d]=%02X(%d) bofs=%d\n",
- __func__, *axis, *axis, size, max, xy_data, next,
- xy_data[next], xy_data[next], bofs);
- *axis = (*axis * 256) + (xy_data[next] >> bofs);
- next++;
- }
-
- *axis &= max - 1;
-
- dev_vdbg(&md->input->dev,
- "%s: *axis=%02X(%d) size=%d max=%08X xy_data=%p"
- " xy_data[%d]=%02X(%d)\n",
- __func__, *axis, *axis, size, max, xy_data, next,
- xy_data[next], xy_data[next]);
-}
-
-static void cyttsp4_get_touch(struct cyttsp4_mt_data *md,
- struct cyttsp4_touch *touch, u8 *xy_data)
-{
- struct device *dev = &md->input->dev;
- struct cyttsp4_sysinfo *si = md->si;
- enum cyttsp4_tch_abs abs;
- bool flipped;
-
- for (abs = CY_TCH_X; abs < CY_TCH_NUM_ABS; abs++) {
- cyttsp4_get_touch_axis(md, &touch->abs[abs],
- si->si_ofs.tch_abs[abs].size,
- si->si_ofs.tch_abs[abs].max,
- xy_data + si->si_ofs.tch_abs[abs].ofs,
- si->si_ofs.tch_abs[abs].bofs);
- dev_vdbg(dev, "%s: get %s=%04X(%d)\n", __func__,
- cyttsp4_tch_abs_string[abs],
- touch->abs[abs], touch->abs[abs]);
- }
-
- if (md->pdata->flags & CY_FLAG_FLIP) {
- swap(touch->abs[CY_TCH_X], touch->abs[CY_TCH_Y]);
- flipped = true;
- } else
- flipped = false;
-
- if (md->pdata->flags & CY_FLAG_INV_X) {
- if (flipped)
- touch->abs[CY_TCH_X] = md->si->si_ofs.max_y -
- touch->abs[CY_TCH_X];
- else
- touch->abs[CY_TCH_X] = md->si->si_ofs.max_x -
- touch->abs[CY_TCH_X];
- }
- if (md->pdata->flags & CY_FLAG_INV_Y) {
- if (flipped)
- touch->abs[CY_TCH_Y] = md->si->si_ofs.max_x -
- touch->abs[CY_TCH_Y];
- else
- touch->abs[CY_TCH_Y] = md->si->si_ofs.max_y -
- touch->abs[CY_TCH_Y];
- }
-
- dev_vdbg(dev, "%s: flip=%s inv-x=%s inv-y=%s x=%04X(%d) y=%04X(%d)\n",
- __func__, flipped ? "true" : "false",
- md->pdata->flags & CY_FLAG_INV_X ? "true" : "false",
- md->pdata->flags & CY_FLAG_INV_Y ? "true" : "false",
- touch->abs[CY_TCH_X], touch->abs[CY_TCH_X],
- touch->abs[CY_TCH_Y], touch->abs[CY_TCH_Y]);
-}
-
-static void cyttsp4_final_sync(struct input_dev *input, int max_slots, int *ids)
-{
- int t;
-
- for (t = 0; t < max_slots; t++) {
- if (ids[t])
- continue;
- input_mt_slot(input, t);
- input_mt_report_slot_inactive(input);
- }
-
- input_sync(input);
-}
-
-static void cyttsp4_get_mt_touches(struct cyttsp4_mt_data *md, int num_cur_tch)
-{
- struct device *dev = &md->input->dev;
- struct cyttsp4_sysinfo *si = md->si;
- struct cyttsp4_touch tch;
- int sig;
- int i, j, t = 0;
- int ids[max(CY_TMA1036_MAX_TCH, CY_TMA4XX_MAX_TCH)];
-
- memset(ids, 0, si->si_ofs.tch_abs[CY_TCH_T].max * sizeof(int));
- for (i = 0; i < num_cur_tch; i++) {
- cyttsp4_get_touch(md, &tch, si->xy_data +
- (i * si->si_ofs.tch_rec_size));
- if ((tch.abs[CY_TCH_T] < md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST]) ||
- (tch.abs[CY_TCH_T] > md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MAX_OST])) {
- dev_err(dev, "%s: tch=%d -> bad trk_id=%d max_id=%d\n",
- __func__, i, tch.abs[CY_TCH_T],
- md->pdata->frmwrk->abs[(CY_ABS_ID_OST *
- CY_NUM_ABS_SET) + CY_MAX_OST]);
- continue;
- }
-
- /* use 0 based track id's */
- sig = md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + 0];
- if (sig != CY_IGNORE_VALUE) {
- t = tch.abs[CY_TCH_T] - md->pdata->frmwrk->abs
- [(CY_ABS_ID_OST * CY_NUM_ABS_SET) + CY_MIN_OST];
- if (tch.abs[CY_TCH_E] == CY_EV_LIFTOFF) {
- dev_dbg(dev, "%s: t=%d e=%d lift-off\n",
- __func__, t, tch.abs[CY_TCH_E]);
- goto cyttsp4_get_mt_touches_pr_tch;
- }
- input_mt_slot(md->input, t);
- input_mt_report_slot_state(md->input, MT_TOOL_FINGER,
- true);
- ids[t] = true;
- }
-
- /* all devices: position and pressure fields */
- for (j = 0; j <= CY_ABS_W_OST; j++) {
- sig = md->pdata->frmwrk->abs[((CY_ABS_X_OST + j) *
- CY_NUM_ABS_SET) + 0];
- if (sig != CY_IGNORE_VALUE)
- input_report_abs(md->input, sig,
- tch.abs[CY_TCH_X + j]);
- }
- if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE) {
- /*
- * TMA400 size and orientation fields:
- * if pressure is non-zero and major touch
- * signal is zero, then set major and minor touch
- * signals to minimum non-zero value
- */
- if (tch.abs[CY_TCH_P] > 0 && tch.abs[CY_TCH_MAJ] == 0)
- tch.abs[CY_TCH_MAJ] = tch.abs[CY_TCH_MIN] = 1;
-
- /* Get the extended touch fields */
- for (j = 0; j < CY_NUM_EXT_TCH_FIELDS; j++) {
- sig = md->pdata->frmwrk->abs
- [((CY_ABS_MAJ_OST + j) *
- CY_NUM_ABS_SET) + 0];
- if (sig != CY_IGNORE_VALUE)
- input_report_abs(md->input, sig,
- tch.abs[CY_TCH_MAJ + j]);
- }
- }
-
-cyttsp4_get_mt_touches_pr_tch:
- if (si->si_ofs.tch_rec_size > CY_TMA1036_TCH_REC_SIZE)
- dev_dbg(dev,
- "%s: t=%d x=%d y=%d z=%d M=%d m=%d o=%d e=%d\n",
- __func__, t,
- tch.abs[CY_TCH_X],
- tch.abs[CY_TCH_Y],
- tch.abs[CY_TCH_P],
- tch.abs[CY_TCH_MAJ],
- tch.abs[CY_TCH_MIN],
- tch.abs[CY_TCH_OR],
- tch.abs[CY_TCH_E]);
- else
- dev_dbg(dev,
- "%s: t=%d x=%d y=%d z=%d e=%d\n", __func__,
- t,
- tch.abs[CY_TCH_X],
- tch.abs[CY_TCH_Y],
- tch.abs[CY_TCH_P],
- tch.abs[CY_TCH_E]);
- }
-
- cyttsp4_final_sync(md->input, si->si_ofs.tch_abs[CY_TCH_T].max, ids);
-
- md->num_prv_tch = num_cur_tch;
-
- return;
-}
-
-/* read xy_data for all current touches */
-static int cyttsp4_xy_worker(struct cyttsp4 *cd)
-{
- struct cyttsp4_mt_data *md = &cd->md;
- struct device *dev = &md->input->dev;
- struct cyttsp4_sysinfo *si = md->si;
- u8 num_cur_tch;
- u8 hst_mode;
- u8 rep_len;
- u8 rep_stat;
- u8 tt_stat;
- int rc = 0;
-
- /*
- * Get event data from cyttsp4 device.
- * The event data includes all data
- * for all active touches.
- * Event data also includes button data
- */
- /*
- * Use 2 reads:
- * 1st read to get mode + button bytes + touch count (core)
- * 2nd read (optional) to get touch 1 - touch n data
- */
- hst_mode = si->xy_mode[CY_REG_BASE];
- rep_len = si->xy_mode[si->si_ofs.rep_ofs];
- rep_stat = si->xy_mode[si->si_ofs.rep_ofs + 1];
- tt_stat = si->xy_mode[si->si_ofs.tt_stat_ofs];
- dev_vdbg(dev, "%s: %s%02X %s%d %s%02X %s%02X\n", __func__,
- "hst_mode=", hst_mode, "rep_len=", rep_len,
- "rep_stat=", rep_stat, "tt_stat=", tt_stat);
-
- num_cur_tch = GET_NUM_TOUCHES(tt_stat);
- dev_vdbg(dev, "%s: num_cur_tch=%d\n", __func__, num_cur_tch);
-
- if (rep_len == 0 && num_cur_tch > 0) {
- dev_err(dev, "%s: report length error rep_len=%d num_tch=%d\n",
- __func__, rep_len, num_cur_tch);
- goto cyttsp4_xy_worker_exit;
- }
-
- /* read touches */
- if (num_cur_tch > 0) {
- rc = cyttsp4_adap_read(cd, si->si_ofs.tt_stat_ofs + 1,
- num_cur_tch * si->si_ofs.tch_rec_size,
- si->xy_data);
- if (rc < 0) {
- dev_err(dev, "%s: read fail on touch regs r=%d\n",
- __func__, rc);
- goto cyttsp4_xy_worker_exit;
- }
- }
-
- /* print xy data */
- cyttsp4_pr_buf(dev, cd->pr_buf, si->xy_data, num_cur_tch *
- si->si_ofs.tch_rec_size, "xy_data");
-
- /* check any error conditions */
- if (IS_BAD_PKT(rep_stat)) {
- dev_dbg(dev, "%s: Invalid buffer detected\n", __func__);
- rc = 0;
- goto cyttsp4_xy_worker_exit;
- }
-
- if (IS_LARGE_AREA(tt_stat))
- dev_dbg(dev, "%s: Large area detected\n", __func__);
-
- if (num_cur_tch > si->si_ofs.max_tchs) {
- dev_err(dev, "%s: too many tch; set to max tch (n=%d c=%zd)\n",
- __func__, num_cur_tch, si->si_ofs.max_tchs);
- num_cur_tch = si->si_ofs.max_tchs;
- }
-
- /* extract xy_data for all currently reported touches */
- dev_vdbg(dev, "%s: extract data num_cur_tch=%d\n", __func__,
- num_cur_tch);
- if (num_cur_tch)
- cyttsp4_get_mt_touches(md, num_cur_tch);
- else
- cyttsp4_lift_all(md);
-
- rc = 0;
-
-cyttsp4_xy_worker_exit:
- return rc;
-}
-
-static int cyttsp4_mt_attention(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- struct cyttsp4_mt_data *md = &cd->md;
- int rc = 0;
-
- if (!md->si)
- return 0;
-
- mutex_lock(&md->report_lock);
- if (!md->is_suspended) {
- /* core handles handshake */
- rc = cyttsp4_xy_worker(cd);
- } else {
- dev_vdbg(dev, "%s: Ignoring report while suspended\n",
- __func__);
- }
- mutex_unlock(&md->report_lock);
- if (rc < 0)
- dev_err(dev, "%s: xy_worker error r=%d\n", __func__, rc);
-
- return rc;
-}
-
-static irqreturn_t cyttsp4_irq(int irq, void *handle)
-{
- struct cyttsp4 *cd = handle;
- struct device *dev = cd->dev;
- enum cyttsp4_mode cur_mode;
- u8 cmd_ofs = cd->sysinfo.si_ofs.cmd_ofs;
- u8 mode[3];
- int rc;
-
- /*
- * Check whether this IRQ should be ignored (external)
- * This should be the very first thing to check since
- * ignore_irq may be set for a very short period of time
- */
- if (atomic_read(&cd->ignore_irq)) {
- dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
- return IRQ_HANDLED;
- }
-
- dev_dbg(dev, "%s int:0x%x\n", __func__, cd->int_status);
-
- mutex_lock(&cd->system_lock);
-
- /* Just to debug */
- if (cd->sleep_state == SS_SLEEP_ON || cd->sleep_state == SS_SLEEPING)
- dev_vdbg(dev, "%s: Received IRQ while in sleep\n", __func__);
-
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), mode);
- if (rc) {
- dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
- goto cyttsp4_irq_exit;
- }
- dev_vdbg(dev, "%s mode[0-2]:0x%X 0x%X 0x%X\n", __func__,
- mode[0], mode[1], mode[2]);
-
- if (IS_BOOTLOADER(mode[0], mode[1])) {
- cur_mode = CY_MODE_BOOTLOADER;
- dev_vdbg(dev, "%s: bl running\n", __func__);
- if (cd->mode == CY_MODE_BOOTLOADER) {
- /* Signal bootloader heartbeat heard */
- wake_up(&cd->wait_q);
- goto cyttsp4_irq_exit;
- }
-
- /* switch to bootloader */
- dev_dbg(dev, "%s: restart switch to bl m=%d -> m=%d\n",
- __func__, cd->mode, cur_mode);
-
- /* catch operation->bl glitch */
- if (cd->mode != CY_MODE_UNKNOWN) {
- /* Incase startup_state do not let startup_() */
- cd->mode = CY_MODE_UNKNOWN;
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_irq_exit;
- }
-
- /*
- * do not wake thread on this switch since
- * it is possible to get an early heartbeat
- * prior to performing the reset
- */
- cd->mode = cur_mode;
-
- goto cyttsp4_irq_exit;
- }
-
- switch (mode[0] & CY_HST_MODE) {
- case CY_HST_OPERATE:
- cur_mode = CY_MODE_OPERATIONAL;
- dev_vdbg(dev, "%s: operational\n", __func__);
- break;
- case CY_HST_CAT:
- cur_mode = CY_MODE_CAT;
- dev_vdbg(dev, "%s: CaT\n", __func__);
- break;
- case CY_HST_SYSINFO:
- cur_mode = CY_MODE_SYSINFO;
- dev_vdbg(dev, "%s: sysinfo\n", __func__);
- break;
- default:
- cur_mode = CY_MODE_UNKNOWN;
- dev_err(dev, "%s: unknown HST mode 0x%02X\n", __func__,
- mode[0]);
- break;
- }
-
- /* Check whether this IRQ should be ignored (internal) */
- if (cd->int_status & CY_INT_IGNORE) {
- dev_vdbg(dev, "%s: Ignoring IRQ\n", __func__);
- goto cyttsp4_irq_exit;
- }
-
- /* Check for wake up interrupt */
- if (cd->int_status & CY_INT_AWAKE) {
- cd->int_status &= ~CY_INT_AWAKE;
- wake_up(&cd->wait_q);
- dev_vdbg(dev, "%s: Received wake up interrupt\n", __func__);
- goto cyttsp4_irq_handshake;
- }
-
- /* Expecting mode change interrupt */
- if ((cd->int_status & CY_INT_MODE_CHANGE)
- && (mode[0] & CY_HST_MODE_CHANGE) == 0) {
- cd->int_status &= ~CY_INT_MODE_CHANGE;
- dev_dbg(dev, "%s: finish mode switch m=%d -> m=%d\n",
- __func__, cd->mode, cur_mode);
- cd->mode = cur_mode;
- wake_up(&cd->wait_q);
- goto cyttsp4_irq_handshake;
- }
-
- /* compare current core mode to current device mode */
- dev_vdbg(dev, "%s: cd->mode=%d cur_mode=%d\n",
- __func__, cd->mode, cur_mode);
- if ((mode[0] & CY_HST_MODE_CHANGE) == 0 && cd->mode != cur_mode) {
- /* Unexpected mode change occurred */
- dev_err(dev, "%s %d->%d 0x%x\n", __func__, cd->mode,
- cur_mode, cd->int_status);
- dev_dbg(dev, "%s: Unexpected mode change, startup\n",
- __func__);
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_irq_exit;
- }
-
- /* Expecting command complete interrupt */
- dev_vdbg(dev, "%s: command byte:0x%x\n", __func__, mode[cmd_ofs]);
- if ((cd->int_status & CY_INT_EXEC_CMD)
- && mode[cmd_ofs] & CY_CMD_COMPLETE) {
- cd->int_status &= ~CY_INT_EXEC_CMD;
- dev_vdbg(dev, "%s: Received command complete interrupt\n",
- __func__);
- wake_up(&cd->wait_q);
- /*
- * It is possible to receive a single interrupt for
- * command complete and touch/button status report.
- * Continue processing for a possible status report.
- */
- }
-
- /* This should be status report, read status regs */
- if (cd->mode == CY_MODE_OPERATIONAL) {
- dev_vdbg(dev, "%s: Read status registers\n", __func__);
- rc = cyttsp4_load_status_regs(cd);
- if (rc < 0)
- dev_err(dev, "%s: fail read mode regs r=%d\n",
- __func__, rc);
- }
-
- cyttsp4_mt_attention(cd);
-
-cyttsp4_irq_handshake:
- /* handshake the event */
- dev_vdbg(dev, "%s: Handshake mode=0x%02X r=%d\n",
- __func__, mode[0], rc);
- rc = cyttsp4_handshake(cd, mode[0]);
- if (rc < 0)
- dev_err(dev, "%s: Fail handshake mode=0x%02X r=%d\n",
- __func__, mode[0], rc);
-
- /*
- * a non-zero udelay period is required for using
- * IRQF_TRIGGER_LOW in order to delay until the
- * device completes isr deassert
- */
- udelay(cd->cpdata->level_irq_udelay);
-
-cyttsp4_irq_exit:
- mutex_unlock(&cd->system_lock);
- return IRQ_HANDLED;
-}
-
-static void cyttsp4_start_wd_timer(struct cyttsp4 *cd)
-{
- if (!CY_WATCHDOG_TIMEOUT)
- return;
-
- mod_timer(&cd->watchdog_timer, jiffies +
- msecs_to_jiffies(CY_WATCHDOG_TIMEOUT));
-}
-
-static void cyttsp4_stop_wd_timer(struct cyttsp4 *cd)
-{
- if (!CY_WATCHDOG_TIMEOUT)
- return;
-
- /*
- * Ensure we wait until the watchdog timer
- * running on a different CPU finishes
- */
- timer_shutdown_sync(&cd->watchdog_timer);
- cancel_work_sync(&cd->watchdog_work);
-}
-
-static void cyttsp4_watchdog_timer(struct timer_list *t)
-{
- struct cyttsp4 *cd = from_timer(cd, t, watchdog_timer);
-
- dev_vdbg(cd->dev, "%s: Watchdog timer triggered\n", __func__);
-
- schedule_work(&cd->watchdog_work);
-
- return;
-}
-
-static int cyttsp4_request_exclusive(struct cyttsp4 *cd, void *ownptr,
- int timeout_ms)
-{
- int t = msecs_to_jiffies(timeout_ms);
- bool with_timeout = (timeout_ms != 0);
-
- mutex_lock(&cd->system_lock);
- if (!cd->exclusive_dev && cd->exclusive_waits == 0) {
- cd->exclusive_dev = ownptr;
- goto exit;
- }
-
- cd->exclusive_waits++;
-wait:
- mutex_unlock(&cd->system_lock);
- if (with_timeout) {
- t = wait_event_timeout(cd->wait_q, !cd->exclusive_dev, t);
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: tmo waiting exclusive access\n",
- __func__);
- mutex_lock(&cd->system_lock);
- cd->exclusive_waits--;
- mutex_unlock(&cd->system_lock);
- return -ETIME;
- }
- } else {
- wait_event(cd->wait_q, !cd->exclusive_dev);
- }
- mutex_lock(&cd->system_lock);
- if (cd->exclusive_dev)
- goto wait;
- cd->exclusive_dev = ownptr;
- cd->exclusive_waits--;
-exit:
- mutex_unlock(&cd->system_lock);
-
- return 0;
-}
-
-/*
- * returns error if was not owned
- */
-static int cyttsp4_release_exclusive(struct cyttsp4 *cd, void *ownptr)
-{
- mutex_lock(&cd->system_lock);
- if (cd->exclusive_dev != ownptr) {
- mutex_unlock(&cd->system_lock);
- return -EINVAL;
- }
-
- dev_vdbg(cd->dev, "%s: exclusive_dev %p freed\n",
- __func__, cd->exclusive_dev);
- cd->exclusive_dev = NULL;
- wake_up(&cd->wait_q);
- mutex_unlock(&cd->system_lock);
- return 0;
-}
-
-static int cyttsp4_wait_bl_heartbeat(struct cyttsp4 *cd)
-{
- long t;
- int rc = 0;
-
- /* wait heartbeat */
- dev_vdbg(cd->dev, "%s: wait heartbeat...\n", __func__);
- t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_BOOTLOADER,
- msecs_to_jiffies(CY_CORE_RESET_AND_WAIT_TIMEOUT));
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: tmo waiting bl heartbeat cd->mode=%d\n",
- __func__, cd->mode);
- rc = -ETIME;
- }
-
- return rc;
-}
-
-static int cyttsp4_wait_sysinfo_mode(struct cyttsp4 *cd)
-{
- long t;
-
- dev_vdbg(cd->dev, "%s: wait sysinfo...\n", __func__);
-
- t = wait_event_timeout(cd->wait_q, cd->mode == CY_MODE_SYSINFO,
- msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: tmo waiting exit bl cd->mode=%d\n",
- __func__, cd->mode);
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_MODE_CHANGE;
- mutex_unlock(&cd->system_lock);
- return -ETIME;
- }
-
- return 0;
-}
-
-static int cyttsp4_reset_and_wait(struct cyttsp4 *cd)
-{
- int rc;
-
- /* reset hardware */
- mutex_lock(&cd->system_lock);
- dev_dbg(cd->dev, "%s: reset hw...\n", __func__);
- rc = cyttsp4_hw_reset(cd);
- cd->mode = CY_MODE_UNKNOWN;
- mutex_unlock(&cd->system_lock);
- if (rc < 0) {
- dev_err(cd->dev, "%s:Fail hw reset r=%d\n", __func__, rc);
- return rc;
- }
-
- return cyttsp4_wait_bl_heartbeat(cd);
-}
-
-/*
- * returns err if refused or timeout; block until mode change complete
- * bit is set (mode change interrupt)
- */
-static int cyttsp4_set_mode(struct cyttsp4 *cd, int new_mode)
-{
- u8 new_dev_mode;
- u8 mode;
- long t;
- int rc;
-
- switch (new_mode) {
- case CY_MODE_OPERATIONAL:
- new_dev_mode = CY_HST_OPERATE;
- break;
- case CY_MODE_SYSINFO:
- new_dev_mode = CY_HST_SYSINFO;
- break;
- case CY_MODE_CAT:
- new_dev_mode = CY_HST_CAT;
- break;
- default:
- dev_err(cd->dev, "%s: invalid mode: %02X(%d)\n",
- __func__, new_mode, new_mode);
- return -EINVAL;
- }
-
- /* change mode */
- dev_dbg(cd->dev, "%s: %s=%p new_dev_mode=%02X new_mode=%d\n",
- __func__, "have exclusive", cd->exclusive_dev,
- new_dev_mode, new_mode);
-
- mutex_lock(&cd->system_lock);
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
- if (rc < 0) {
- mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Fail read mode r=%d\n",
- __func__, rc);
- goto exit;
- }
-
- /* Clear device mode bits and set to new mode */
- mode &= ~CY_HST_MODE;
- mode |= new_dev_mode | CY_HST_MODE_CHANGE;
-
- cd->int_status |= CY_INT_MODE_CHANGE;
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode), &mode);
- mutex_unlock(&cd->system_lock);
- if (rc < 0) {
- dev_err(cd->dev, "%s: Fail write mode change r=%d\n",
- __func__, rc);
- goto exit;
- }
-
- /* wait for mode change done interrupt */
- t = wait_event_timeout(cd->wait_q,
- (cd->int_status & CY_INT_MODE_CHANGE) == 0,
- msecs_to_jiffies(CY_CORE_MODE_CHANGE_TIMEOUT));
- dev_dbg(cd->dev, "%s: back from wait t=%ld cd->mode=%d\n",
- __func__, t, cd->mode);
-
- if (IS_TMO(t)) {
- dev_err(cd->dev, "%s: %s\n", __func__,
- "tmo waiting mode change");
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_MODE_CHANGE;
- mutex_unlock(&cd->system_lock);
- rc = -EINVAL;
- }
-
-exit:
- return rc;
-}
-
-static void cyttsp4_watchdog_work(struct work_struct *work)
-{
- struct cyttsp4 *cd =
- container_of(work, struct cyttsp4, watchdog_work);
- u8 *mode;
- int retval;
-
- mutex_lock(&cd->system_lock);
- retval = cyttsp4_load_status_regs(cd);
- if (retval < 0) {
- dev_err(cd->dev,
- "%s: failed to access device in watchdog timer r=%d\n",
- __func__, retval);
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_timer_watchdog_exit_error;
- }
- mode = &cd->sysinfo.xy_mode[CY_REG_BASE];
- if (IS_BOOTLOADER(mode[0], mode[1])) {
- dev_err(cd->dev,
- "%s: device found in bootloader mode when operational mode\n",
- __func__);
- cyttsp4_queue_startup_(cd);
- goto cyttsp4_timer_watchdog_exit_error;
- }
-
- cyttsp4_start_wd_timer(cd);
-cyttsp4_timer_watchdog_exit_error:
- mutex_unlock(&cd->system_lock);
- return;
-}
-
-static int cyttsp4_core_sleep_(struct cyttsp4 *cd)
-{
- enum cyttsp4_sleep_state ss = SS_SLEEP_ON;
- enum cyttsp4_int_state int_status = CY_INT_IGNORE;
- int rc = 0;
- u8 mode[2];
-
- /* Already in sleep mode? */
- mutex_lock(&cd->system_lock);
- if (cd->sleep_state == SS_SLEEP_ON) {
- mutex_unlock(&cd->system_lock);
- return 0;
- }
- cd->sleep_state = SS_SLEEPING;
- mutex_unlock(&cd->system_lock);
-
- cyttsp4_stop_wd_timer(cd);
-
- /* Wait until currently running IRQ handler exits and disable IRQ */
- disable_irq(cd->irq);
-
- dev_vdbg(cd->dev, "%s: write DEEP SLEEP...\n", __func__);
- mutex_lock(&cd->system_lock);
- rc = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
- if (rc) {
- mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Fail read adapter r=%d\n", __func__, rc);
- goto error;
- }
-
- if (IS_BOOTLOADER(mode[0], mode[1])) {
- mutex_unlock(&cd->system_lock);
- dev_err(cd->dev, "%s: Device in BOOTLOADER mode.\n", __func__);
- rc = -EINVAL;
- goto error;
- }
-
- mode[0] |= CY_HST_SLEEP;
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(mode[0]), &mode[0]);
- mutex_unlock(&cd->system_lock);
- if (rc) {
- dev_err(cd->dev, "%s: Fail write adapter r=%d\n", __func__, rc);
- goto error;
- }
- dev_vdbg(cd->dev, "%s: write DEEP SLEEP succeeded\n", __func__);
-
- if (cd->cpdata->power) {
- dev_dbg(cd->dev, "%s: Power down HW\n", __func__);
- rc = cd->cpdata->power(cd->cpdata, 0, cd->dev, &cd->ignore_irq);
- } else {
- dev_dbg(cd->dev, "%s: No power function\n", __func__);
- rc = 0;
- }
- if (rc < 0) {
- dev_err(cd->dev, "%s: HW Power down fails r=%d\n",
- __func__, rc);
- goto error;
- }
-
- /* Give time to FW to sleep */
- msleep(50);
-
- goto exit;
-
-error:
- ss = SS_SLEEP_OFF;
- int_status = CY_INT_NONE;
- cyttsp4_start_wd_timer(cd);
-
-exit:
- mutex_lock(&cd->system_lock);
- cd->sleep_state = ss;
- cd->int_status |= int_status;
- mutex_unlock(&cd->system_lock);
- enable_irq(cd->irq);
- return rc;
-}
-
-static int cyttsp4_startup_(struct cyttsp4 *cd)
-{
- int retry = CY_CORE_STARTUP_RETRY_COUNT;
- int rc;
-
- cyttsp4_stop_wd_timer(cd);
-
-reset:
- if (retry != CY_CORE_STARTUP_RETRY_COUNT)
- dev_dbg(cd->dev, "%s: Retry %d\n", __func__,
- CY_CORE_STARTUP_RETRY_COUNT - retry);
-
- /* reset hardware and wait for heartbeat */
- rc = cyttsp4_reset_and_wait(cd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: Error on h/w reset r=%d\n", __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- /* exit bl into sysinfo mode */
- dev_vdbg(cd->dev, "%s: write exit ldr...\n", __func__);
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_IGNORE;
- cd->int_status |= CY_INT_MODE_CHANGE;
-
- rc = cyttsp4_adap_write(cd, CY_REG_BASE, sizeof(ldr_exit),
- (u8 *)ldr_exit);
- mutex_unlock(&cd->system_lock);
- if (rc < 0) {
- dev_err(cd->dev, "%s: Fail write r=%d\n", __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- rc = cyttsp4_wait_sysinfo_mode(cd);
- if (rc < 0) {
- u8 buf[sizeof(ldr_err_app)];
- int rc1;
-
- /* Check for invalid/corrupted touch application */
- rc1 = cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(ldr_err_app),
- buf);
- if (rc1) {
- dev_err(cd->dev, "%s: Fail read r=%d\n", __func__, rc1);
- } else if (!memcmp(buf, ldr_err_app, sizeof(ldr_err_app))) {
- dev_err(cd->dev, "%s: Error launching touch application\n",
- __func__);
- mutex_lock(&cd->system_lock);
- cd->invalid_touch_app = true;
- mutex_unlock(&cd->system_lock);
- goto exit_no_wd;
- }
-
- if (retry--)
- goto reset;
- goto exit;
- }
-
- mutex_lock(&cd->system_lock);
- cd->invalid_touch_app = false;
- mutex_unlock(&cd->system_lock);
-
- /* read sysinfo data */
- dev_vdbg(cd->dev, "%s: get sysinfo regs..\n", __func__);
- rc = cyttsp4_get_sysinfo_regs(cd);
- if (rc < 0) {
- dev_err(cd->dev, "%s: failed to get sysinfo regs rc=%d\n",
- __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- rc = cyttsp4_set_mode(cd, CY_MODE_OPERATIONAL);
- if (rc < 0) {
- dev_err(cd->dev, "%s: failed to set mode to operational rc=%d\n",
- __func__, rc);
- if (retry--)
- goto reset;
- goto exit;
- }
-
- cyttsp4_lift_all(&cd->md);
-
- /* restore to sleep if was suspended */
- mutex_lock(&cd->system_lock);
- if (cd->sleep_state == SS_SLEEP_ON) {
- cd->sleep_state = SS_SLEEP_OFF;
- mutex_unlock(&cd->system_lock);
- cyttsp4_core_sleep_(cd);
- goto exit_no_wd;
- }
- mutex_unlock(&cd->system_lock);
-
-exit:
- cyttsp4_start_wd_timer(cd);
-exit_no_wd:
- return rc;
-}
-
-static int cyttsp4_startup(struct cyttsp4 *cd)
-{
- int rc;
-
- mutex_lock(&cd->system_lock);
- cd->startup_state = STARTUP_RUNNING;
- mutex_unlock(&cd->system_lock);
-
- rc = cyttsp4_request_exclusive(cd, cd->dev,
- CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
- __func__, cd->exclusive_dev, cd->dev);
- goto exit;
- }
-
- rc = cyttsp4_startup_(cd);
-
- if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
- /* Don't return fail code, mode is already changed. */
- dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
- else
- dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
-exit:
- mutex_lock(&cd->system_lock);
- cd->startup_state = STARTUP_NONE;
- mutex_unlock(&cd->system_lock);
-
- /* Wake the waiters for end of startup */
- wake_up(&cd->wait_q);
-
- return rc;
-}
-
-static void cyttsp4_startup_work_function(struct work_struct *work)
-{
- struct cyttsp4 *cd = container_of(work, struct cyttsp4, startup_work);
- int rc;
-
- rc = cyttsp4_startup(cd);
- if (rc < 0)
- dev_err(cd->dev, "%s: Fail queued startup r=%d\n",
- __func__, rc);
-}
-
-static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
-{
- struct cyttsp4_sysinfo *si = &cd->sysinfo;
-
- if (!si)
- return;
-
- kfree(si->si_ptrs.cydata);
- kfree(si->si_ptrs.test);
- kfree(si->si_ptrs.pcfg);
- kfree(si->si_ptrs.opcfg);
- kfree(si->si_ptrs.ddata);
- kfree(si->si_ptrs.mdata);
- kfree(si->btn);
- kfree(si->xy_mode);
- kfree(si->xy_data);
- kfree(si->btn_rec_data);
-}
-
-static int cyttsp4_core_sleep(struct cyttsp4 *cd)
-{
- int rc;
-
- rc = cyttsp4_request_exclusive(cd, cd->dev,
- CY_CORE_SLEEP_REQUEST_EXCLUSIVE_TIMEOUT);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
- __func__, cd->exclusive_dev, cd->dev);
- return 0;
- }
-
- rc = cyttsp4_core_sleep_(cd);
-
- if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
- dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
- else
- dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
- return rc;
-}
-
-static int cyttsp4_core_wake_(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- int rc;
- u8 mode;
- int t;
-
- /* Already woken? */
- mutex_lock(&cd->system_lock);
- if (cd->sleep_state == SS_SLEEP_OFF) {
- mutex_unlock(&cd->system_lock);
- return 0;
- }
- cd->int_status &= ~CY_INT_IGNORE;
- cd->int_status |= CY_INT_AWAKE;
- cd->sleep_state = SS_WAKING;
-
- if (cd->cpdata->power) {
- dev_dbg(dev, "%s: Power up HW\n", __func__);
- rc = cd->cpdata->power(cd->cpdata, 1, dev, &cd->ignore_irq);
- } else {
- dev_dbg(dev, "%s: No power function\n", __func__);
- rc = -ENOSYS;
- }
- if (rc < 0) {
- dev_err(dev, "%s: HW Power up fails r=%d\n",
- __func__, rc);
-
- /* Initiate a read transaction to wake up */
- cyttsp4_adap_read(cd, CY_REG_BASE, sizeof(mode), &mode);
- } else
- dev_vdbg(cd->dev, "%s: HW power up succeeds\n",
- __func__);
- mutex_unlock(&cd->system_lock);
-
- t = wait_event_timeout(cd->wait_q,
- (cd->int_status & CY_INT_AWAKE) == 0,
- msecs_to_jiffies(CY_CORE_WAKEUP_TIMEOUT));
- if (IS_TMO(t)) {
- dev_err(dev, "%s: TMO waiting for wakeup\n", __func__);
- mutex_lock(&cd->system_lock);
- cd->int_status &= ~CY_INT_AWAKE;
- /* Try starting up */
- cyttsp4_queue_startup_(cd);
- mutex_unlock(&cd->system_lock);
- }
-
- mutex_lock(&cd->system_lock);
- cd->sleep_state = SS_SLEEP_OFF;
- mutex_unlock(&cd->system_lock);
-
- cyttsp4_start_wd_timer(cd);
-
- return 0;
-}
-
-static int cyttsp4_core_wake(struct cyttsp4 *cd)
-{
- int rc;
-
- rc = cyttsp4_request_exclusive(cd, cd->dev,
- CY_CORE_REQUEST_EXCLUSIVE_TIMEOUT);
- if (rc < 0) {
- dev_err(cd->dev, "%s: fail get exclusive ex=%p own=%p\n",
- __func__, cd->exclusive_dev, cd->dev);
- return 0;
- }
-
- rc = cyttsp4_core_wake_(cd);
-
- if (cyttsp4_release_exclusive(cd, cd->dev) < 0)
- dev_err(cd->dev, "%s: fail to release exclusive\n", __func__);
- else
- dev_vdbg(cd->dev, "%s: pass release exclusive\n", __func__);
-
- return rc;
-}
-
-static int cyttsp4_core_suspend(struct device *dev)
-{
- struct cyttsp4 *cd = dev_get_drvdata(dev);
- struct cyttsp4_mt_data *md = &cd->md;
- int rc;
-
- md->is_suspended = true;
-
- rc = cyttsp4_core_sleep(cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error on sleep\n", __func__);
- return -EAGAIN;
- }
- return 0;
-}
-
-static int cyttsp4_core_resume(struct device *dev)
-{
- struct cyttsp4 *cd = dev_get_drvdata(dev);
- struct cyttsp4_mt_data *md = &cd->md;
- int rc;
-
- md->is_suspended = false;
-
- rc = cyttsp4_core_wake(cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error on wake\n", __func__);
- return -EAGAIN;
- }
-
- return 0;
-}
-
-EXPORT_GPL_RUNTIME_DEV_PM_OPS(cyttsp4_pm_ops,
- cyttsp4_core_suspend, cyttsp4_core_resume, NULL);
-
-static int cyttsp4_mt_open(struct input_dev *input)
-{
- pm_runtime_get(input->dev.parent);
- return 0;
-}
-
-static void cyttsp4_mt_close(struct input_dev *input)
-{
- struct cyttsp4_mt_data *md = input_get_drvdata(input);
- mutex_lock(&md->report_lock);
- if (!md->is_suspended)
- pm_runtime_put(input->dev.parent);
- mutex_unlock(&md->report_lock);
-}
-
-
-static int cyttsp4_setup_input_device(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- struct cyttsp4_mt_data *md = &cd->md;
- int signal = CY_IGNORE_VALUE;
- int max_x, max_y, max_p, min, max;
- int max_x_tmp, max_y_tmp;
- int i;
- int rc;
-
- dev_vdbg(dev, "%s: Initialize event signals\n", __func__);
- __set_bit(EV_ABS, md->input->evbit);
- __set_bit(EV_REL, md->input->evbit);
- __set_bit(EV_KEY, md->input->evbit);
-
- max_x_tmp = md->si->si_ofs.max_x;
- max_y_tmp = md->si->si_ofs.max_y;
-
- /* get maximum values from the sysinfo data */
- if (md->pdata->flags & CY_FLAG_FLIP) {
- max_x = max_y_tmp - 1;
- max_y = max_x_tmp - 1;
- } else {
- max_x = max_x_tmp - 1;
- max_y = max_y_tmp - 1;
- }
- max_p = md->si->si_ofs.max_p;
-
- /* set event signal capabilities */
- for (i = 0; i < (md->pdata->frmwrk->size / CY_NUM_ABS_SET); i++) {
- signal = md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_SIGNAL_OST];
- if (signal != CY_IGNORE_VALUE) {
- __set_bit(signal, md->input->absbit);
- min = md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_MIN_OST];
- max = md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_MAX_OST];
- if (i == CY_ABS_ID_OST) {
- /* shift track ids down to start at 0 */
- max = max - min;
- min = min - min;
- } else if (i == CY_ABS_X_OST)
- max = max_x;
- else if (i == CY_ABS_Y_OST)
- max = max_y;
- else if (i == CY_ABS_P_OST)
- max = max_p;
- input_set_abs_params(md->input, signal, min, max,
- md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_FUZZ_OST],
- md->pdata->frmwrk->abs
- [(i * CY_NUM_ABS_SET) + CY_FLAT_OST]);
- dev_dbg(dev, "%s: register signal=%02X min=%d max=%d\n",
- __func__, signal, min, max);
- if ((i == CY_ABS_ID_OST) &&
- (md->si->si_ofs.tch_rec_size <
- CY_TMA4XX_TCH_REC_SIZE))
- break;
- }
- }
-
- input_mt_init_slots(md->input, md->si->si_ofs.tch_abs[CY_TCH_T].max,
- INPUT_MT_DIRECT);
- rc = input_register_device(md->input);
- if (rc < 0)
- dev_err(dev, "%s: Error, failed register input device r=%d\n",
- __func__, rc);
- return rc;
-}
-
-static int cyttsp4_mt_probe(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
- struct cyttsp4_mt_data *md = &cd->md;
- struct cyttsp4_mt_platform_data *pdata = cd->pdata->mt_pdata;
- int rc = 0;
-
- mutex_init(&md->report_lock);
- md->pdata = pdata;
- /* Create the input device and register it. */
- dev_vdbg(dev, "%s: Create the input device and register it\n",
- __func__);
- md->input = input_allocate_device();
- if (md->input == NULL) {
- dev_err(dev, "%s: Error, failed to allocate input device\n",
- __func__);
- rc = -ENOSYS;
- goto error_alloc_failed;
- }
-
- md->input->name = pdata->inp_dev_name;
- scnprintf(md->phys, sizeof(md->phys)-1, "%s", dev_name(dev));
- md->input->phys = md->phys;
- md->input->id.bustype = cd->bus_ops->bustype;
- md->input->dev.parent = dev;
- md->input->open = cyttsp4_mt_open;
- md->input->close = cyttsp4_mt_close;
- input_set_drvdata(md->input, md);
-
- /* get sysinfo */
- md->si = &cd->sysinfo;
-
- rc = cyttsp4_setup_input_device(cd);
- if (rc)
- goto error_init_input;
-
- return 0;
-
-error_init_input:
- input_free_device(md->input);
-error_alloc_failed:
- dev_err(dev, "%s failed.\n", __func__);
- return rc;
-}
-
-struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
- struct device *dev, u16 irq, size_t xfer_buf_size)
-{
- struct cyttsp4 *cd;
- struct cyttsp4_platform_data *pdata = dev_get_platdata(dev);
- unsigned long irq_flags;
- int rc = 0;
-
- if (!pdata || !pdata->core_pdata || !pdata->mt_pdata) {
- dev_err(dev, "%s: Missing platform data\n", __func__);
- rc = -ENODEV;
- goto error_no_pdata;
- }
-
- cd = kzalloc(sizeof(*cd), GFP_KERNEL);
- if (!cd) {
- dev_err(dev, "%s: Error, kzalloc\n", __func__);
- rc = -ENOMEM;
- goto error_alloc_data;
- }
-
- cd->xfer_buf = kzalloc(xfer_buf_size, GFP_KERNEL);
- if (!cd->xfer_buf) {
- dev_err(dev, "%s: Error, kzalloc\n", __func__);
- rc = -ENOMEM;
- goto error_free_cd;
- }
-
- /* Initialize device info */
- cd->dev = dev;
- cd->pdata = pdata;
- cd->cpdata = pdata->core_pdata;
- cd->bus_ops = ops;
-
- /* Initialize mutexes and spinlocks */
- mutex_init(&cd->system_lock);
- mutex_init(&cd->adap_lock);
-
- /* Initialize wait queue */
- init_waitqueue_head(&cd->wait_q);
-
- /* Initialize works */
- INIT_WORK(&cd->startup_work, cyttsp4_startup_work_function);
- INIT_WORK(&cd->watchdog_work, cyttsp4_watchdog_work);
-
- /* Initialize IRQ */
- cd->irq = gpio_to_irq(cd->cpdata->irq_gpio);
- if (cd->irq < 0) {
- rc = -EINVAL;
- goto error_free_xfer;
- }
-
- dev_set_drvdata(dev, cd);
-
- /* Call platform init function */
- if (cd->cpdata->init) {
- dev_dbg(cd->dev, "%s: Init HW\n", __func__);
- rc = cd->cpdata->init(cd->cpdata, 1, cd->dev);
- } else {
- dev_dbg(cd->dev, "%s: No HW INIT function\n", __func__);
- rc = 0;
- }
- if (rc < 0)
- dev_err(cd->dev, "%s: HW Init fail r=%d\n", __func__, rc);
-
- dev_dbg(dev, "%s: initialize threaded irq=%d\n", __func__, cd->irq);
- if (cd->cpdata->level_irq_udelay > 0)
- /* use level triggered interrupts */
- irq_flags = IRQF_TRIGGER_LOW | IRQF_ONESHOT;
- else
- /* use edge triggered interrupts */
- irq_flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
-
- rc = request_threaded_irq(cd->irq, NULL, cyttsp4_irq, irq_flags,
- dev_name(dev), cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error, could not request irq\n", __func__);
- goto error_request_irq;
- }
-
- /* Setup watchdog timer */
- timer_setup(&cd->watchdog_timer, cyttsp4_watchdog_timer, 0);
-
- /*
- * call startup directly to ensure that the device
- * is tested before leaving the probe
- */
- rc = cyttsp4_startup(cd);
-
- /* Do not fail probe if startup fails but the device is detected */
- if (rc < 0 && cd->mode == CY_MODE_UNKNOWN) {
- dev_err(cd->dev, "%s: Fail initial startup r=%d\n",
- __func__, rc);
- goto error_startup;
- }
-
- rc = cyttsp4_mt_probe(cd);
- if (rc < 0) {
- dev_err(dev, "%s: Error, fail mt probe\n", __func__);
- goto error_startup;
- }
-
- pm_runtime_enable(dev);
-
- return cd;
-
-error_startup:
- cancel_work_sync(&cd->startup_work);
- cyttsp4_stop_wd_timer(cd);
- pm_runtime_disable(dev);
- cyttsp4_free_si_ptrs(cd);
- free_irq(cd->irq, cd);
-error_request_irq:
- if (cd->cpdata->init)
- cd->cpdata->init(cd->cpdata, 0, dev);
-error_free_xfer:
- kfree(cd->xfer_buf);
-error_free_cd:
- kfree(cd);
-error_alloc_data:
-error_no_pdata:
- dev_err(dev, "%s failed.\n", __func__);
- return ERR_PTR(rc);
-}
-EXPORT_SYMBOL_GPL(cyttsp4_probe);
-
-static void cyttsp4_mt_release(struct cyttsp4_mt_data *md)
-{
- input_unregister_device(md->input);
- input_set_drvdata(md->input, NULL);
-}
-
-int cyttsp4_remove(struct cyttsp4 *cd)
-{
- struct device *dev = cd->dev;
-
- cyttsp4_mt_release(&cd->md);
-
- /*
- * Suspend the device before freeing the startup_work and stopping
- * the watchdog since sleep function restarts watchdog on failure
- */
- pm_runtime_suspend(dev);
- pm_runtime_disable(dev);
-
- cancel_work_sync(&cd->startup_work);
-
- cyttsp4_stop_wd_timer(cd);
-
- free_irq(cd->irq, cd);
- if (cd->cpdata->init)
- cd->cpdata->init(cd->cpdata, 0, dev);
- cyttsp4_free_si_ptrs(cd);
- kfree(cd);
- return 0;
-}
-EXPORT_SYMBOL_GPL(cyttsp4_remove);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard touchscreen core driver");
-MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp4_core.h b/drivers/input/touchscreen/cyttsp4_core.h
deleted file mode 100644
index 6262f6e45075..000000000000
--- a/drivers/input/touchscreen/cyttsp4_core.h
+++ /dev/null
@@ -1,448 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * cyttsp4_core.h
- * Cypress TrueTouch(TM) Standard Product V4 Core driver module.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2012 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#ifndef _LINUX_CYTTSP4_CORE_H
-#define _LINUX_CYTTSP4_CORE_H
-
-#include <linux/device.h>
-#include <linux/err.h>
-#include <linux/input.h>
-#include <linux/kernel.h>
-#include <linux/limits.h>
-#include <linux/module.h>
-#include <linux/stringify.h>
-#include <linux/types.h>
-#include <linux/platform_data/cyttsp4.h>
-
-#define CY_REG_BASE 0x00
-
-#define CY_POST_CODEL_WDG_RST 0x01
-#define CY_POST_CODEL_CFG_DATA_CRC_FAIL 0x02
-#define CY_POST_CODEL_PANEL_TEST_FAIL 0x04
-
-#define CY_NUM_BTN_PER_REG 4
-
-/* touch record system information offset masks and shifts */
-#define CY_BYTE_OFS_MASK 0x1F
-#define CY_BOFS_MASK 0xE0
-#define CY_BOFS_SHIFT 5
-
-#define CY_TMA1036_TCH_REC_SIZE 6
-#define CY_TMA4XX_TCH_REC_SIZE 9
-#define CY_TMA1036_MAX_TCH 0x0E
-#define CY_TMA4XX_MAX_TCH 0x1E
-
-#define CY_NORMAL_ORIGIN 0 /* upper, left corner */
-#define CY_INVERT_ORIGIN 1 /* lower, right corner */
-
-/* helpers */
-#define GET_NUM_TOUCHES(x) ((x) & 0x1F)
-#define IS_LARGE_AREA(x) ((x) & 0x20)
-#define IS_BAD_PKT(x) ((x) & 0x20)
-#define IS_BOOTLOADER(hst_mode, reset_detect) \
- ((hst_mode) & 0x01 || (reset_detect) != 0)
-#define IS_TMO(t) ((t) == 0)
-
-
-enum cyttsp_cmd_bits {
- CY_CMD_COMPLETE = (1 << 6),
-};
-
-/* Timeout in ms. */
-#define CY_WATCHDOG_TIMEOUT 1000
-
-#define CY_MAX_PRINT_SIZE 512
-#ifdef VERBOSE_DEBUG
-#define CY_MAX_PRBUF_SIZE PIPE_BUF
-#define CY_PR_TRUNCATED " truncated..."
-#endif
-
-enum cyttsp4_ic_grpnum {
- CY_IC_GRPNUM_RESERVED,
- CY_IC_GRPNUM_CMD_REGS,
- CY_IC_GRPNUM_TCH_REP,
- CY_IC_GRPNUM_DATA_REC,
- CY_IC_GRPNUM_TEST_REC,
- CY_IC_GRPNUM_PCFG_REC,
- CY_IC_GRPNUM_TCH_PARM_VAL,
- CY_IC_GRPNUM_TCH_PARM_SIZE,
- CY_IC_GRPNUM_RESERVED1,
- CY_IC_GRPNUM_RESERVED2,
- CY_IC_GRPNUM_OPCFG_REC,
- CY_IC_GRPNUM_DDATA_REC,
- CY_IC_GRPNUM_MDATA_REC,
- CY_IC_GRPNUM_TEST_REGS,
- CY_IC_GRPNUM_BTN_KEYS,
- CY_IC_GRPNUM_TTHE_REGS,
- CY_IC_GRPNUM_NUM
-};
-
-enum cyttsp4_int_state {
- CY_INT_NONE,
- CY_INT_IGNORE = (1 << 0),
- CY_INT_MODE_CHANGE = (1 << 1),
- CY_INT_EXEC_CMD = (1 << 2),
- CY_INT_AWAKE = (1 << 3),
-};
-
-enum cyttsp4_mode {
- CY_MODE_UNKNOWN,
- CY_MODE_BOOTLOADER = (1 << 1),
- CY_MODE_OPERATIONAL = (1 << 2),
- CY_MODE_SYSINFO = (1 << 3),
- CY_MODE_CAT = (1 << 4),
- CY_MODE_STARTUP = (1 << 5),
- CY_MODE_LOADER = (1 << 6),
- CY_MODE_CHANGE_MODE = (1 << 7),
- CY_MODE_CHANGED = (1 << 8),
- CY_MODE_CMD_COMPLETE = (1 << 9),
-};
-
-enum cyttsp4_sleep_state {
- SS_SLEEP_OFF,
- SS_SLEEP_ON,
- SS_SLEEPING,
- SS_WAKING,
-};
-
-enum cyttsp4_startup_state {
- STARTUP_NONE,
- STARTUP_QUEUED,
- STARTUP_RUNNING,
-};
-
-#define CY_NUM_REVCTRL 8
-struct cyttsp4_cydata {
- u8 ttpidh;
- u8 ttpidl;
- u8 fw_ver_major;
- u8 fw_ver_minor;
- u8 revctrl[CY_NUM_REVCTRL];
- u8 blver_major;
- u8 blver_minor;
- u8 jtag_si_id3;
- u8 jtag_si_id2;
- u8 jtag_si_id1;
- u8 jtag_si_id0;
- u8 mfgid_sz;
- u8 cyito_idh;
- u8 cyito_idl;
- u8 cyito_verh;
- u8 cyito_verl;
- u8 ttsp_ver_major;
- u8 ttsp_ver_minor;
- u8 device_info;
- u8 mfg_id[];
-} __packed;
-
-struct cyttsp4_test {
- u8 post_codeh;
- u8 post_codel;
-} __packed;
-
-struct cyttsp4_pcfg {
- u8 electrodes_x;
- u8 electrodes_y;
- u8 len_xh;
- u8 len_xl;
- u8 len_yh;
- u8 len_yl;
- u8 res_xh;
- u8 res_xl;
- u8 res_yh;
- u8 res_yl;
- u8 max_zh;
- u8 max_zl;
- u8 panel_info0;
-} __packed;
-
-struct cyttsp4_tch_rec_params {
- u8 loc;
- u8 size;
-} __packed;
-
-#define CY_NUM_TCH_FIELDS 7
-#define CY_NUM_EXT_TCH_FIELDS 3
-struct cyttsp4_opcfg {
- u8 cmd_ofs;
- u8 rep_ofs;
- u8 rep_szh;
- u8 rep_szl;
- u8 num_btns;
- u8 tt_stat_ofs;
- u8 obj_cfg0;
- u8 max_tchs;
- u8 tch_rec_size;
- struct cyttsp4_tch_rec_params tch_rec_old[CY_NUM_TCH_FIELDS];
- u8 btn_rec_size; /* btn record size (in bytes) */
- u8 btn_diff_ofs; /* btn data loc, diff counts */
- u8 btn_diff_size; /* btn size of diff counts (in bits) */
- struct cyttsp4_tch_rec_params tch_rec_new[CY_NUM_EXT_TCH_FIELDS];
-} __packed;
-
-struct cyttsp4_sysinfo_ptr {
- struct cyttsp4_cydata *cydata;
- struct cyttsp4_test *test;
- struct cyttsp4_pcfg *pcfg;
- struct cyttsp4_opcfg *opcfg;
- struct cyttsp4_ddata *ddata;
- struct cyttsp4_mdata *mdata;
-} __packed;
-
-struct cyttsp4_sysinfo_data {
- u8 hst_mode;
- u8 reserved;
- u8 map_szh;
- u8 map_szl;
- u8 cydata_ofsh;
- u8 cydata_ofsl;
- u8 test_ofsh;
- u8 test_ofsl;
- u8 pcfg_ofsh;
- u8 pcfg_ofsl;
- u8 opcfg_ofsh;
- u8 opcfg_ofsl;
- u8 ddata_ofsh;
- u8 ddata_ofsl;
- u8 mdata_ofsh;
- u8 mdata_ofsl;
-} __packed;
-
-enum cyttsp4_tch_abs { /* for ordering within the extracted touch data array */
- CY_TCH_X, /* X */
- CY_TCH_Y, /* Y */
- CY_TCH_P, /* P (Z) */
- CY_TCH_T, /* TOUCH ID */
- CY_TCH_E, /* EVENT ID */
- CY_TCH_O, /* OBJECT ID */
- CY_TCH_W, /* SIZE */
- CY_TCH_MAJ, /* TOUCH_MAJOR */
- CY_TCH_MIN, /* TOUCH_MINOR */
- CY_TCH_OR, /* ORIENTATION */
- CY_TCH_NUM_ABS
-};
-
-struct cyttsp4_touch {
- int abs[CY_TCH_NUM_ABS];
-};
-
-struct cyttsp4_tch_abs_params {
- size_t ofs; /* abs byte offset */
- size_t size; /* size in bits */
- size_t max; /* max value */
- size_t bofs; /* bit offset */
-};
-
-struct cyttsp4_sysinfo_ofs {
- size_t chip_type;
- size_t cmd_ofs;
- size_t rep_ofs;
- size_t rep_sz;
- size_t num_btns;
- size_t num_btn_regs; /* ceil(num_btns/4) */
- size_t tt_stat_ofs;
- size_t tch_rec_size;
- size_t obj_cfg0;
- size_t max_tchs;
- size_t mode_size;
- size_t data_size;
- size_t map_sz;
- size_t max_x;
- size_t x_origin; /* left or right corner */
- size_t max_y;
- size_t y_origin; /* upper or lower corner */
- size_t max_p;
- size_t cydata_ofs;
- size_t test_ofs;
- size_t pcfg_ofs;
- size_t opcfg_ofs;
- size_t ddata_ofs;
- size_t mdata_ofs;
- size_t cydata_size;
- size_t test_size;
- size_t pcfg_size;
- size_t opcfg_size;
- size_t ddata_size;
- size_t mdata_size;
- size_t btn_keys_size;
- struct cyttsp4_tch_abs_params tch_abs[CY_TCH_NUM_ABS];
- size_t btn_rec_size; /* btn record size (in bytes) */
- size_t btn_diff_ofs;/* btn data loc ,diff counts, (Op-Mode byte ofs) */
- size_t btn_diff_size;/* btn size of diff counts (in bits) */
-};
-
-enum cyttsp4_btn_state {
- CY_BTN_RELEASED,
- CY_BTN_PRESSED,
- CY_BTN_NUM_STATE
-};
-
-struct cyttsp4_btn {
- bool enabled;
- int state; /* CY_BTN_PRESSED, CY_BTN_RELEASED */
- int key_code;
-};
-
-struct cyttsp4_sysinfo {
- bool ready;
- struct cyttsp4_sysinfo_data si_data;
- struct cyttsp4_sysinfo_ptr si_ptrs;
- struct cyttsp4_sysinfo_ofs si_ofs;
- struct cyttsp4_btn *btn; /* button states */
- u8 *btn_rec_data; /* button diff count data */
- u8 *xy_mode; /* operational mode and status regs */
- u8 *xy_data; /* operational touch regs */
-};
-
-struct cyttsp4_mt_data {
- struct cyttsp4_mt_platform_data *pdata;
- struct cyttsp4_sysinfo *si;
- struct input_dev *input;
- struct mutex report_lock;
- bool is_suspended;
- char phys[NAME_MAX];
- int num_prv_tch;
-};
-
-struct cyttsp4 {
- struct device *dev;
- struct mutex system_lock;
- struct mutex adap_lock;
- enum cyttsp4_mode mode;
- enum cyttsp4_sleep_state sleep_state;
- enum cyttsp4_startup_state startup_state;
- int int_status;
- wait_queue_head_t wait_q;
- int irq;
- struct work_struct startup_work;
- struct work_struct watchdog_work;
- struct timer_list watchdog_timer;
- struct cyttsp4_sysinfo sysinfo;
- void *exclusive_dev;
- int exclusive_waits;
- atomic_t ignore_irq;
- bool invalid_touch_app;
- struct cyttsp4_mt_data md;
- struct cyttsp4_platform_data *pdata;
- struct cyttsp4_core_platform_data *cpdata;
- const struct cyttsp4_bus_ops *bus_ops;
- u8 *xfer_buf;
-#ifdef VERBOSE_DEBUG
- u8 pr_buf[CY_MAX_PRBUF_SIZE];
-#endif
-};
-
-struct cyttsp4_bus_ops {
- u16 bustype;
- int (*write)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
- const void *values);
- int (*read)(struct device *dev, u8 *xfer_buf, u16 addr, u8 length,
- void *values);
-};
-
-enum cyttsp4_hst_mode_bits {
- CY_HST_TOGGLE = (1 << 7),
- CY_HST_MODE_CHANGE = (1 << 3),
- CY_HST_MODE = (7 << 4),
- CY_HST_OPERATE = (0 << 4),
- CY_HST_SYSINFO = (1 << 4),
- CY_HST_CAT = (2 << 4),
- CY_HST_LOWPOW = (1 << 2),
- CY_HST_SLEEP = (1 << 1),
- CY_HST_RESET = (1 << 0),
-};
-
-/* abs settings */
-#define CY_IGNORE_VALUE 0xFFFF
-
-/* abs signal capabilities offsets in the frameworks array */
-enum cyttsp4_sig_caps {
- CY_SIGNAL_OST,
- CY_MIN_OST,
- CY_MAX_OST,
- CY_FUZZ_OST,
- CY_FLAT_OST,
- CY_NUM_ABS_SET /* number of signal capability fields */
-};
-
-/* abs axis signal offsets in the framworks array */
-enum cyttsp4_sig_ost {
- CY_ABS_X_OST,
- CY_ABS_Y_OST,
- CY_ABS_P_OST,
- CY_ABS_W_OST,
- CY_ABS_ID_OST,
- CY_ABS_MAJ_OST,
- CY_ABS_MIN_OST,
- CY_ABS_OR_OST,
- CY_NUM_ABS_OST /* number of abs signals */
-};
-
-enum cyttsp4_flags {
- CY_FLAG_NONE = 0x00,
- CY_FLAG_HOVER = 0x04,
- CY_FLAG_FLIP = 0x08,
- CY_FLAG_INV_X = 0x10,
- CY_FLAG_INV_Y = 0x20,
- CY_FLAG_VKEYS = 0x40,
-};
-
-enum cyttsp4_object_id {
- CY_OBJ_STANDARD_FINGER,
- CY_OBJ_LARGE_OBJECT,
- CY_OBJ_STYLUS,
- CY_OBJ_HOVER,
-};
-
-enum cyttsp4_event_id {
- CY_EV_NO_EVENT,
- CY_EV_TOUCHDOWN,
- CY_EV_MOVE, /* significant displacement (> act dist) */
- CY_EV_LIFTOFF, /* record reports last position */
-};
-
-/* x-axis resolution of panel in pixels */
-#define CY_PCFG_RESOLUTION_X_MASK 0x7F
-
-/* y-axis resolution of panel in pixels */
-#define CY_PCFG_RESOLUTION_Y_MASK 0x7F
-
-/* x-axis, 0:origin is on left side of panel, 1: right */
-#define CY_PCFG_ORIGIN_X_MASK 0x80
-
-/* y-axis, 0:origin is on top side of panel, 1: bottom */
-#define CY_PCFG_ORIGIN_Y_MASK 0x80
-
-static inline int cyttsp4_adap_read(struct cyttsp4 *ts, u16 addr, int size,
- void *buf)
-{
- return ts->bus_ops->read(ts->dev, ts->xfer_buf, addr, size, buf);
-}
-
-static inline int cyttsp4_adap_write(struct cyttsp4 *ts, u16 addr, int size,
- const void *buf)
-{
- return ts->bus_ops->write(ts->dev, ts->xfer_buf, addr, size, buf);
-}
-
-extern struct cyttsp4 *cyttsp4_probe(const struct cyttsp4_bus_ops *ops,
- struct device *dev, u16 irq, size_t xfer_buf_size);
-extern int cyttsp4_remove(struct cyttsp4 *ts);
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, const void *values);
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, void *values);
-extern const struct dev_pm_ops cyttsp4_pm_ops;
-
-#endif /* _LINUX_CYTTSP4_CORE_H */
diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c
deleted file mode 100644
index da32c151def5..000000000000
--- a/drivers/input/touchscreen/cyttsp4_i2c.c
+++ /dev/null
@@ -1,72 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cyttsp_i2c.c
- * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
- * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
- * Copyright (C) 2013 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include "cyttsp4_core.h"
-
-#include <linux/i2c.h>
-#include <linux/input.h>
-
-#define CYTTSP4_I2C_DATA_SIZE (3 * 256)
-
-static const struct cyttsp4_bus_ops cyttsp4_i2c_bus_ops = {
- .bustype = BUS_I2C,
- .write = cyttsp_i2c_write_block_data,
- .read = cyttsp_i2c_read_block_data,
-};
-
-static int cyttsp4_i2c_probe(struct i2c_client *client)
-{
- struct cyttsp4 *ts;
-
- if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
- dev_err(&client->dev, "I2C functionality not Supported\n");
- return -EIO;
- }
-
- ts = cyttsp4_probe(&cyttsp4_i2c_bus_ops, &client->dev, client->irq,
- CYTTSP4_I2C_DATA_SIZE);
-
- return PTR_ERR_OR_ZERO(ts);
-}
-
-static void cyttsp4_i2c_remove(struct i2c_client *client)
-{
- struct cyttsp4 *ts = i2c_get_clientdata(client);
-
- cyttsp4_remove(ts);
-}
-
-static const struct i2c_device_id cyttsp4_i2c_id[] = {
- { CYTTSP4_I2C_NAME },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id);
-
-static struct i2c_driver cyttsp4_i2c_driver = {
- .driver = {
- .name = CYTTSP4_I2C_NAME,
- .pm = pm_ptr(&cyttsp4_pm_ops),
- },
- .probe = cyttsp4_i2c_probe,
- .remove = cyttsp4_i2c_remove,
- .id_table = cyttsp4_i2c_id,
-};
-
-module_i2c_driver(cyttsp4_i2c_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver");
-MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/cyttsp4_spi.c b/drivers/input/touchscreen/cyttsp4_spi.c
deleted file mode 100644
index 944fbbe9113e..000000000000
--- a/drivers/input/touchscreen/cyttsp4_spi.c
+++ /dev/null
@@ -1,187 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Source for:
- * Cypress TrueTouch(TM) Standard Product (TTSP) SPI touchscreen driver.
- * For use with Cypress Txx4xx parts.
- * Supported parts include:
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
- * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
- * Copyright (C) 2013 Cypress Semiconductor
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include "cyttsp4_core.h"
-
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/spi/spi.h>
-
-#define CY_SPI_WR_OP 0x00 /* r/~w */
-#define CY_SPI_RD_OP 0x01
-#define CY_SPI_BITS_PER_WORD 8
-#define CY_SPI_A8_BIT 0x02
-#define CY_SPI_WR_HEADER_BYTES 2
-#define CY_SPI_RD_HEADER_BYTES 1
-#define CY_SPI_CMD_BYTES 2
-#define CY_SPI_SYNC_BYTE 0
-#define CY_SPI_SYNC_ACK 0x62 /* from TRM *A protocol */
-#define CY_SPI_DATA_SIZE (2 * 256)
-
-#define CY_SPI_DATA_BUF_SIZE (CY_SPI_CMD_BYTES + CY_SPI_DATA_SIZE)
-
-static int cyttsp_spi_xfer(struct device *dev, u8 *xfer_buf,
- u8 op, u16 reg, u8 *buf, int length)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct spi_message msg;
- struct spi_transfer xfer[2];
- u8 *wr_buf = &xfer_buf[0];
- u8 rd_buf[CY_SPI_CMD_BYTES];
- int retval;
- int i;
-
- if (length > CY_SPI_DATA_SIZE) {
- dev_err(dev, "%s: length %d is too big.\n",
- __func__, length);
- return -EINVAL;
- }
-
- memset(wr_buf, 0, CY_SPI_DATA_BUF_SIZE);
- memset(rd_buf, 0, CY_SPI_CMD_BYTES);
-
- wr_buf[0] = op + (((reg >> 8) & 0x1) ? CY_SPI_A8_BIT : 0);
- if (op == CY_SPI_WR_OP) {
- wr_buf[1] = reg & 0xFF;
- if (length > 0)
- memcpy(wr_buf + CY_SPI_CMD_BYTES, buf, length);
- }
-
- memset(xfer, 0, sizeof(xfer));
- spi_message_init(&msg);
-
- /*
- We set both TX and RX buffers because Cypress TTSP
- requires full duplex operation.
- */
- xfer[0].tx_buf = wr_buf;
- xfer[0].rx_buf = rd_buf;
- switch (op) {
- case CY_SPI_WR_OP:
- xfer[0].len = length + CY_SPI_CMD_BYTES;
- spi_message_add_tail(&xfer[0], &msg);
- break;
-
- case CY_SPI_RD_OP:
- xfer[0].len = CY_SPI_RD_HEADER_BYTES;
- spi_message_add_tail(&xfer[0], &msg);
-
- xfer[1].rx_buf = buf;
- xfer[1].len = length;
- spi_message_add_tail(&xfer[1], &msg);
- break;
-
- default:
- dev_err(dev, "%s: bad operation code=%d\n", __func__, op);
- return -EINVAL;
- }
-
- retval = spi_sync(spi, &msg);
- if (retval < 0) {
- dev_dbg(dev, "%s: spi_sync() error %d, len=%d, op=%d\n",
- __func__, retval, xfer[1].len, op);
-
- /*
- * do not return here since was a bad ACK sequence
- * let the following ACK check handle any errors and
- * allow silent retries
- */
- }
-
- if (rd_buf[CY_SPI_SYNC_BYTE] != CY_SPI_SYNC_ACK) {
- dev_dbg(dev, "%s: operation %d failed\n", __func__, op);
-
- for (i = 0; i < CY_SPI_CMD_BYTES; i++)
- dev_dbg(dev, "%s: test rd_buf[%d]:0x%02x\n",
- __func__, i, rd_buf[i]);
- for (i = 0; i < length; i++)
- dev_dbg(dev, "%s: test buf[%d]:0x%02x\n",
- __func__, i, buf[i]);
-
- return -EIO;
- }
-
- return 0;
-}
-
-static int cyttsp_spi_read_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, void *data)
-{
- int rc;
-
- rc = cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, NULL, 0);
- if (rc)
- return rc;
- else
- return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_RD_OP, addr, data,
- length);
-}
-
-static int cyttsp_spi_write_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, const void *data)
-{
- return cyttsp_spi_xfer(dev, xfer_buf, CY_SPI_WR_OP, addr, (void *)data,
- length);
-}
-
-static const struct cyttsp4_bus_ops cyttsp_spi_bus_ops = {
- .bustype = BUS_SPI,
- .write = cyttsp_spi_write_block_data,
- .read = cyttsp_spi_read_block_data,
-};
-
-static int cyttsp4_spi_probe(struct spi_device *spi)
-{
- struct cyttsp4 *ts;
- int error;
-
- /* Set up SPI*/
- spi->bits_per_word = CY_SPI_BITS_PER_WORD;
- spi->mode = SPI_MODE_0;
- error = spi_setup(spi);
- if (error < 0) {
- dev_err(&spi->dev, "%s: SPI setup error %d\n",
- __func__, error);
- return error;
- }
-
- ts = cyttsp4_probe(&cyttsp_spi_bus_ops, &spi->dev, spi->irq,
- CY_SPI_DATA_BUF_SIZE);
-
- return PTR_ERR_OR_ZERO(ts);
-}
-
-static void cyttsp4_spi_remove(struct spi_device *spi)
-{
- struct cyttsp4 *ts = spi_get_drvdata(spi);
- cyttsp4_remove(ts);
-}
-
-static struct spi_driver cyttsp4_spi_driver = {
- .driver = {
- .name = CYTTSP4_SPI_NAME,
- .pm = pm_ptr(&cyttsp4_pm_ops),
- },
- .probe = cyttsp4_spi_probe,
- .remove = cyttsp4_spi_remove,
-};
-
-module_spi_driver(cyttsp4_spi_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) SPI driver");
-MODULE_AUTHOR("Cypress");
-MODULE_ALIAS("spi:cyttsp4");
diff --git a/drivers/input/touchscreen/cyttsp5.c b/drivers/input/touchscreen/cyttsp5.c
index 3ca246ab192e..071b7c9bf566 100644
--- a/drivers/input/touchscreen/cyttsp5.c
+++ b/drivers/input/touchscreen/cyttsp5.c
@@ -21,7 +21,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/regmap.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define CYTTSP5_NAME "cyttsp5"
#define CY_I2C_DATA_SIZE (2 * 256)
@@ -580,7 +580,7 @@ static int cyttsp5_power_control(struct cyttsp5 *ts, bool on)
int rc;
SET_CMD_REPORT_TYPE(cmd[0], 0);
- SET_CMD_REPORT_ID(cmd[0], HID_POWER_SLEEP);
+ SET_CMD_REPORT_ID(cmd[0], state);
SET_CMD_OPCODE(cmd[1], HID_CMD_SET_POWER);
rc = cyttsp5_write(ts, HID_COMMAND_REG, cmd, sizeof(cmd));
@@ -870,13 +870,16 @@ static int cyttsp5_probe(struct device *dev, struct regmap *regmap, int irq,
ts->input->phys = ts->phys;
input_set_drvdata(ts->input, ts);
- /* Reset the gpio to be in a reset state */
+ /* Assert gpio to be in a reset state */
ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ts->reset_gpio)) {
error = PTR_ERR(ts->reset_gpio);
dev_err(dev, "Failed to request reset gpio, error %d\n", error);
return error;
}
+
+ fsleep(10); /* Ensure long-enough reset pulse (minimum 10us). */
+
gpiod_set_value_cansleep(ts->reset_gpio, 0);
/* Need a delay to have device up */
diff --git a/drivers/input/touchscreen/cyttsp_core.c b/drivers/input/touchscreen/cyttsp_core.c
index 132ed5786e84..9e729910fbc8 100644
--- a/drivers/input/touchscreen/cyttsp_core.c
+++ b/drivers/input/touchscreen/cyttsp_core.c
@@ -14,10 +14,10 @@
*/
#include <linux/delay.h>
+#include <linux/export.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
-#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/property.h>
@@ -615,17 +615,14 @@ static int cyttsp_parse_properties(struct cyttsp *ts)
return 0;
}
-static void cyttsp_disable_regulators(void *_ts)
-{
- struct cyttsp *ts = _ts;
-
- regulator_bulk_disable(ARRAY_SIZE(ts->regulators),
- ts->regulators);
-}
-
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size)
{
+ /*
+ * VCPIN is the analog voltage supply
+ * VDD is the digital voltage supply
+ */
+ static const char * const supplies[] = { "vcpin", "vdd" };
struct cyttsp *ts;
struct input_dev *input_dev;
int error;
@@ -643,29 +640,10 @@ struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
ts->bus_ops = bus_ops;
ts->irq = irq;
- /*
- * VCPIN is the analog voltage supply
- * VDD is the digital voltage supply
- */
- ts->regulators[0].supply = "vcpin";
- ts->regulators[1].supply = "vdd";
- error = devm_regulator_bulk_get(dev, ARRAY_SIZE(ts->regulators),
- ts->regulators);
- if (error) {
- dev_err(dev, "Failed to get regulators: %d\n", error);
- return ERR_PTR(error);
- }
-
- error = regulator_bulk_enable(ARRAY_SIZE(ts->regulators),
- ts->regulators);
- if (error) {
- dev_err(dev, "Cannot enable regulators: %d\n", error);
- return ERR_PTR(error);
- }
-
- error = devm_add_action_or_reset(dev, cyttsp_disable_regulators, ts);
+ error = devm_regulator_bulk_get_enable(dev, ARRAY_SIZE(supplies),
+ supplies);
if (error) {
- dev_err(dev, "failed to install chip disable handler\n");
+ dev_err(dev, "Failed to enable regulators: %d\n", error);
return ERR_PTR(error);
}
diff --git a/drivers/input/touchscreen/cyttsp_core.h b/drivers/input/touchscreen/cyttsp_core.h
index 075509e695a2..40a605d20285 100644
--- a/drivers/input/touchscreen/cyttsp_core.h
+++ b/drivers/input/touchscreen/cyttsp_core.h
@@ -122,7 +122,6 @@ struct cyttsp {
enum cyttsp_state state;
bool suspended;
- struct regulator_bulk_data regulators[2];
struct gpio_desc *reset_gpio;
bool use_hndshk;
u8 act_dist;
@@ -137,10 +136,6 @@ struct cyttsp {
struct cyttsp *cyttsp_probe(const struct cyttsp_bus_ops *bus_ops,
struct device *dev, int irq, size_t xfer_buf_size);
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, const void *values);
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf, u16 addr,
- u8 length, void *values);
extern const struct dev_pm_ops cyttsp_pm_ops;
#endif /* __CYTTSP_CORE_H__ */
diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c
index bf13b3448a6b..cb15600549cd 100644
--- a/drivers/input/touchscreen/cyttsp_i2c.c
+++ b/drivers/input/touchscreen/cyttsp_i2c.c
@@ -22,6 +22,61 @@
#define CY_I2C_DATA_SIZE 128
+static int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
+ u16 addr, u8 length, void *values)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 client_addr = client->addr | ((addr >> 8) & 0x1);
+ u8 addr_lo = addr & 0xFF;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client_addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &addr_lo,
+ },
+ {
+ .addr = client_addr,
+ .flags = I2C_M_RD,
+ .len = length,
+ .buf = values,
+ },
+ };
+ int retval;
+
+ retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (retval < 0)
+ return retval;
+
+ return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
+static int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
+ u16 addr, u8 length, const void *values)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 client_addr = client->addr | ((addr >> 8) & 0x1);
+ u8 addr_lo = addr & 0xFF;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client_addr,
+ .flags = 0,
+ .len = length + 1,
+ .buf = xfer_buf,
+ },
+ };
+ int retval;
+
+ xfer_buf[0] = addr_lo;
+ memcpy(&xfer_buf[1], values, length);
+
+ retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (retval < 0)
+ return retval;
+
+ return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
+}
+
static const struct cyttsp_bus_ops cyttsp_i2c_bus_ops = {
.bustype = BUS_I2C,
.write = cyttsp_i2c_write_block_data,
diff --git a/drivers/input/touchscreen/cyttsp_i2c_common.c b/drivers/input/touchscreen/cyttsp_i2c_common.c
deleted file mode 100644
index 1f0b6d6f48e2..000000000000
--- a/drivers/input/touchscreen/cyttsp_i2c_common.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * cyttsp_i2c_common.c
- * Cypress TrueTouch(TM) Standard Product (TTSP) I2C touchscreen driver.
- * For use with Cypress Txx3xx and Txx4xx parts.
- * Supported parts include:
- * CY8CTST341
- * CY8CTMA340
- * TMA4XX
- * TMA1036
- *
- * Copyright (C) 2009, 2010, 2011 Cypress Semiconductor, Inc.
- * Copyright (C) 2012 Javier Martinez Canillas <javier@dowhile0.org>
- *
- * Contact Cypress Semiconductor at www.cypress.com <ttdrivers@cypress.com>
- */
-
-#include <linux/device.h>
-#include <linux/export.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/types.h>
-
-#include "cyttsp4_core.h"
-
-int cyttsp_i2c_read_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, void *values)
-{
- struct i2c_client *client = to_i2c_client(dev);
- u8 client_addr = client->addr | ((addr >> 8) & 0x1);
- u8 addr_lo = addr & 0xFF;
- struct i2c_msg msgs[] = {
- {
- .addr = client_addr,
- .flags = 0,
- .len = 1,
- .buf = &addr_lo,
- },
- {
- .addr = client_addr,
- .flags = I2C_M_RD,
- .len = length,
- .buf = values,
- },
- };
- int retval;
-
- retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (retval < 0)
- return retval;
-
- return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
-}
-EXPORT_SYMBOL_GPL(cyttsp_i2c_read_block_data);
-
-int cyttsp_i2c_write_block_data(struct device *dev, u8 *xfer_buf,
- u16 addr, u8 length, const void *values)
-{
- struct i2c_client *client = to_i2c_client(dev);
- u8 client_addr = client->addr | ((addr >> 8) & 0x1);
- u8 addr_lo = addr & 0xFF;
- struct i2c_msg msgs[] = {
- {
- .addr = client_addr,
- .flags = 0,
- .len = length + 1,
- .buf = xfer_buf,
- },
- };
- int retval;
-
- xfer_buf[0] = addr_lo;
- memcpy(&xfer_buf[1], values, length);
-
- retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (retval < 0)
- return retval;
-
- return retval != ARRAY_SIZE(msgs) ? -EIO : 0;
-}
-EXPORT_SYMBOL_GPL(cyttsp_i2c_write_block_data);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Cypress");
diff --git a/drivers/input/touchscreen/da9052_tsi.c b/drivers/input/touchscreen/da9052_tsi.c
index d71690ce6463..c2d3252f8466 100644
--- a/drivers/input/touchscreen/da9052_tsi.c
+++ b/drivers/input/touchscreen/da9052_tsi.c
@@ -232,7 +232,7 @@ static int da9052_ts_probe(struct platform_device *pdev)
if (!da9052)
return -EINVAL;
- tsi = kzalloc(sizeof(struct da9052_tsi), GFP_KERNEL);
+ tsi = kzalloc(sizeof(*tsi), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tsi || !input_dev) {
error = -ENOMEM;
@@ -326,7 +326,7 @@ static void da9052_ts_remove(struct platform_device *pdev)
static struct platform_driver da9052_tsi_driver = {
.probe = da9052_ts_probe,
- .remove_new = da9052_ts_remove,
+ .remove = da9052_ts_remove,
.driver = {
.name = "da9052-tsi",
},
diff --git a/drivers/input/touchscreen/dynapro.c b/drivers/input/touchscreen/dynapro.c
index dc07fca7c5ed..fe626a226b85 100644
--- a/drivers/input/touchscreen/dynapro.c
+++ b/drivers/input/touchscreen/dynapro.c
@@ -110,7 +110,7 @@ static int dynapro_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- pdynapro = kzalloc(sizeof(struct dynapro), GFP_KERNEL);
+ pdynapro = kzalloc(sizeof(*pdynapro), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pdynapro || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index 06ec0f2e18ae..bf498bd4dea9 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -32,7 +32,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define WORK_REGISTER_THRESHOLD 0x00
#define WORK_REGISTER_REPORT_RATE 0x08
@@ -120,7 +120,6 @@ struct edt_ft5x06_ts_data {
struct regmap *regmap;
#if defined(CONFIG_DEBUG_FS)
- struct dentry *debug_dir;
u8 *raw_buffer;
size_t raw_bufsize;
#endif
@@ -815,23 +814,21 @@ static const struct file_operations debugfs_raw_data_fops = {
.read = edt_ft5x06_debugfs_raw_data_read,
};
-static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
- const char *debugfs_name)
+static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
- tsdata->debug_dir = debugfs_create_dir(debugfs_name, NULL);
+ struct dentry *debug_dir = tsdata->client->debugfs;
- debugfs_create_u16("num_x", S_IRUSR, tsdata->debug_dir, &tsdata->num_x);
- debugfs_create_u16("num_y", S_IRUSR, tsdata->debug_dir, &tsdata->num_y);
+ debugfs_create_u16("num_x", S_IRUSR, debug_dir, &tsdata->num_x);
+ debugfs_create_u16("num_y", S_IRUSR, debug_dir, &tsdata->num_y);
debugfs_create_file("mode", S_IRUSR | S_IWUSR,
- tsdata->debug_dir, tsdata, &debugfs_mode_fops);
+ debug_dir, tsdata, &debugfs_mode_fops);
debugfs_create_file("raw_data", S_IRUSR,
- tsdata->debug_dir, tsdata, &debugfs_raw_data_fops);
+ debug_dir, tsdata, &debugfs_raw_data_fops);
}
static void edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
- debugfs_remove_recursive(tsdata->debug_dir);
kfree(tsdata->raw_buffer);
}
@@ -842,8 +839,7 @@ static int edt_ft5x06_factory_mode(struct edt_ft5x06_ts_data *tsdata)
return -ENOSYS;
}
-static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata,
- const char *debugfs_name)
+static void edt_ft5x06_ts_prepare_debugfs(struct edt_ft5x06_ts_data *tsdata)
{
}
@@ -1121,6 +1117,14 @@ static void edt_ft5x06_ts_set_regs(struct edt_ft5x06_ts_data *tsdata)
}
}
+static void edt_ft5x06_exit_regmap(void *arg)
+{
+ struct edt_ft5x06_ts_data *data = arg;
+
+ if (!IS_ERR_OR_NULL(data->regmap))
+ regmap_exit(data->regmap);
+}
+
static void edt_ft5x06_disable_regulators(void *arg)
{
struct edt_ft5x06_ts_data *data = arg;
@@ -1154,6 +1158,16 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
return PTR_ERR(tsdata->regmap);
}
+ /*
+ * We are not using devm_regmap_init_i2c() and instead install a
+ * custom action because we may replace regmap with M06-specific one
+ * and we need to make sure that it will not be released too early.
+ */
+ error = devm_add_action_or_reset(&client->dev, edt_ft5x06_exit_regmap,
+ tsdata);
+ if (error)
+ return error;
+
chip_data = device_get_match_data(&client->dev);
if (!chip_data)
chip_data = (const struct edt_i2c_chip_data *)id->driver_data;
@@ -1219,7 +1233,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
}
/*
- * Check which sleep modes we can support. Power-off requieres the
+ * Check which sleep modes we can support. Power-off requires the
* reset-pin to ensure correct power-down/power-up behaviour. Start with
* the EDT_PMODE_POWEROFF test since this is the deepest possible sleep
* mode.
@@ -1331,7 +1345,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client)
if (error)
return error;
- edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
+ edt_ft5x06_ts_prepare_debugfs(tsdata);
dev_dbg(&client->dev,
"EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
@@ -1347,7 +1361,6 @@ static void edt_ft5x06_ts_remove(struct i2c_client *client)
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
edt_ft5x06_ts_teardown_debugfs(tsdata);
- regmap_exit(tsdata->regmap);
}
static int edt_ft5x06_ts_suspend(struct device *dev)
@@ -1474,6 +1487,14 @@ static const struct edt_i2c_chip_data edt_ft6236_data = {
.max_support_points = 2,
};
+static const struct edt_i2c_chip_data edt_ft8201_data = {
+ .max_support_points = 10,
+};
+
+static const struct edt_i2c_chip_data edt_ft8716_data = {
+ .max_support_points = 10,
+};
+
static const struct edt_i2c_chip_data edt_ft8719_data = {
.max_support_points = 10,
};
@@ -1485,6 +1506,8 @@ static const struct i2c_device_id edt_ft5x06_ts_id[] = {
{ .name = "ft5452", .driver_data = (long)&edt_ft5452_data },
/* Note no edt- prefix for compatibility with the ft6236.c driver */
{ .name = "ft6236", .driver_data = (long)&edt_ft6236_data },
+ { .name = "ft8201", .driver_data = (long)&edt_ft8201_data },
+ { .name = "ft8716", .driver_data = (long)&edt_ft8716_data },
{ .name = "ft8719", .driver_data = (long)&edt_ft8719_data },
{ /* sentinel */ }
};
@@ -1496,9 +1519,12 @@ static const struct of_device_id edt_ft5x06_of_match[] = {
{ .compatible = "edt,edt-ft5406", .data = &edt_ft5x06_data },
{ .compatible = "edt,edt-ft5506", .data = &edt_ft5506_data },
{ .compatible = "evervision,ev-ft5726", .data = &edt_ft5506_data },
+ { .compatible = "focaltech,ft5426", .data = &edt_ft5506_data },
{ .compatible = "focaltech,ft5452", .data = &edt_ft5452_data },
/* Note focaltech vendor prefix for compatibility with ft6236.c */
{ .compatible = "focaltech,ft6236", .data = &edt_ft6236_data },
+ { .compatible = "focaltech,ft8201", .data = &edt_ft8201_data },
+ { .compatible = "focaltech,ft8716", .data = &edt_ft8716_data },
{ .compatible = "focaltech,ft8719", .data = &edt_ft8719_data },
{ /* sentinel */ }
};
diff --git a/drivers/input/touchscreen/eeti_ts.c b/drivers/input/touchscreen/eeti_ts.c
index 48c69788b84a..87eb18977b71 100644
--- a/drivers/input/touchscreen/eeti_ts.c
+++ b/drivers/input/touchscreen/eeti_ts.c
@@ -21,7 +21,7 @@
#include <linux/gpio/consumer.h>
#include <linux/of.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
struct eeti_ts {
struct i2c_client *client;
diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c
index f4e950920e84..eb3cc2befcdf 100644
--- a/drivers/input/touchscreen/egalax_ts.c
+++ b/drivers/input/touchscreen/egalax_ts.c
@@ -23,6 +23,7 @@
#include <linux/gpio/consumer.h>
#include <linux/delay.h>
#include <linux/slab.h>
+#include <linux/string_choices.h>
#include <linux/bitops.h>
#include <linux/input/mt.h>
@@ -102,7 +103,7 @@ static irqreturn_t egalax_ts_interrupt(int irq, void *dev_id)
input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, down);
dev_dbg(&client->dev, "%s id:%d x:%d y:%d z:%d",
- down ? "down" : "up", id, x, y, z);
+ str_down_up(down), id, x, y, z);
if (down) {
input_report_abs(input_dev, ABS_MT_POSITION_X, x);
diff --git a/drivers/input/touchscreen/egalax_ts_serial.c b/drivers/input/touchscreen/egalax_ts_serial.c
index 375922d3a6d1..07a4aa1c19bb 100644
--- a/drivers/input/touchscreen/egalax_ts_serial.c
+++ b/drivers/input/touchscreen/egalax_ts_serial.c
@@ -99,7 +99,7 @@ static int egalax_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int error;
- egalax = kzalloc(sizeof(struct egalax), GFP_KERNEL);
+ egalax = kzalloc(sizeof(*egalax), GFP_KERNEL);
input_dev = input_allocate_device();
if (!egalax || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/touchscreen/ektf2127.c b/drivers/input/touchscreen/ektf2127.c
index ab8159e1c99d..46a0611fac82 100644
--- a/drivers/input/touchscreen/ektf2127.c
+++ b/drivers/input/touchscreen/ektf2127.c
@@ -13,6 +13,7 @@
* Hans de Goede <hdegoede@redhat.com>
*/
+#include <linux/bits.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
@@ -46,6 +47,11 @@ struct ektf2127_ts {
struct input_dev *input;
struct gpio_desc *power_gpios;
struct touchscreen_properties prop;
+ int status_shift;
+};
+
+struct ektf2127_i2c_chip_data {
+ int status_shift;
};
static void ektf2127_parse_coordinates(const u8 *buf, unsigned int touch_count,
@@ -112,8 +118,8 @@ static void ektf2127_report2_contact(struct ektf2127_ts *ts, int slot,
static void ektf2127_report2_event(struct ektf2127_ts *ts, const u8 *buf)
{
- ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & 2));
- ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & 4));
+ ektf2127_report2_contact(ts, 0, &buf[1], !!(buf[7] & BIT(ts->status_shift)));
+ ektf2127_report2_contact(ts, 1, &buf[4], !!(buf[7] & BIT(ts->status_shift + 1)));
input_mt_sync_frame(ts->input);
input_sync(ts->input);
@@ -247,6 +253,7 @@ static int ektf2127_query_dimension(struct i2c_client *client, bool width)
static int ektf2127_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
+ const struct ektf2127_i2c_chip_data *chip_data;
struct ektf2127_ts *ts;
struct input_dev *input;
u8 buf[4];
@@ -303,6 +310,13 @@ static int ektf2127_probe(struct i2c_client *client)
return error;
ts->input = input;
+
+ chip_data = i2c_get_match_data(client);
+ if (!chip_data)
+ return dev_err_probe(&client->dev, -EINVAL, "missing chip data\n");
+
+ ts->status_shift = chip_data->status_shift;
+
input_set_drvdata(input, ts);
error = devm_request_threaded_irq(dev, client->irq,
@@ -325,18 +339,28 @@ static int ektf2127_probe(struct i2c_client *client)
return 0;
}
+static const struct ektf2127_i2c_chip_data ektf2127_data = {
+ .status_shift = 1,
+};
+
+static const struct ektf2127_i2c_chip_data ektf2232_data = {
+ .status_shift = 0,
+};
+
#ifdef CONFIG_OF
static const struct of_device_id ektf2127_of_match[] = {
- { .compatible = "elan,ektf2127" },
- { .compatible = "elan,ektf2132" },
+ { .compatible = "elan,ektf2127", .data = &ektf2127_data},
+ { .compatible = "elan,ektf2132", .data = &ektf2127_data},
+ { .compatible = "elan,ektf2232", .data = &ektf2232_data},
{}
};
MODULE_DEVICE_TABLE(of, ektf2127_of_match);
#endif
static const struct i2c_device_id ektf2127_i2c_id[] = {
- { "ektf2127" },
- { "ektf2132" },
+ { .name = "ektf2127", .driver_data = (long)&ektf2127_data },
+ { .name = "ektf2132", .driver_data = (long)&ektf2127_data },
+ { .name = "ektf2232", .driver_data = (long)&ektf2232_data },
{}
};
MODULE_DEVICE_TABLE(i2c, ektf2127_i2c_id);
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index 365765d40e62..3fd170f75b4a 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -40,7 +40,7 @@
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/uuid.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Device, Driver information */
#define DEVICE_NAME "elants_i2c"
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 96173232e53f..ad209e6e82a6 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -225,10 +225,10 @@ static int elo_command_10(struct elo *elo, unsigned char *packet)
mutex_lock(&elo->cmd_mutex);
- serio_pause_rx(elo->serio);
- elo->expected_packet = toupper(packet[0]);
- init_completion(&elo->cmd_done);
- serio_continue_rx(elo->serio);
+ scoped_guard(serio_pause_rx, elo->serio) {
+ elo->expected_packet = toupper(packet[0]);
+ init_completion(&elo->cmd_done);
+ }
if (serio_write(elo->serio, ELO10_LEAD_BYTE))
goto out;
@@ -307,7 +307,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- elo = kzalloc(sizeof(struct elo), GFP_KERNEL);
+ elo = kzalloc(sizeof(*elo), GFP_KERNEL);
input_dev = input_allocate_device();
if (!elo || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/exc3000.c b/drivers/input/touchscreen/exc3000.c
index a4030cc9ff60..28da7ba55a4b 100644
--- a/drivers/input/touchscreen/exc3000.c
+++ b/drivers/input/touchscreen/exc3000.c
@@ -22,7 +22,7 @@
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
#include <linux/timer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define EXC3000_NUM_SLOTS 10
#define EXC3000_SLOTS_PER_FRAME 5
@@ -53,6 +53,7 @@ enum eeti_dev_id {
EETI_EXC3000,
EETI_EXC80H60,
EETI_EXC80H84,
+ EETI_EXC81W32,
};
static struct eeti_dev_info exc3000_info[] = {
@@ -68,6 +69,10 @@ static struct eeti_dev_info exc3000_info[] = {
.name = "EETI EXC80H84 Touch Screen",
.max_xy = SZ_16K - 1,
},
+ [EETI_EXC81W32] = {
+ .name = "EETI EXC81W32 Touch Screen",
+ .max_xy = SZ_16K - 1,
+ },
};
struct exc3000_data {
@@ -100,7 +105,7 @@ static void exc3000_report_slots(struct input_dev *input,
static void exc3000_timer(struct timer_list *t)
{
- struct exc3000_data *data = from_timer(data, t, timer);
+ struct exc3000_data *data = timer_container_of(data, t, timer);
input_mt_sync_frame(data->input);
input_sync(data->input);
@@ -169,7 +174,7 @@ static int exc3000_handle_mt_event(struct exc3000_data *data)
/*
* We read full state successfully, no contacts will be "stuck".
*/
- del_timer_sync(&data->timer);
+ timer_delete_sync(&data->timer);
while (total_slots > 0) {
int slots = min(total_slots, EXC3000_SLOTS_PER_FRAME);
@@ -441,6 +446,7 @@ static const struct i2c_device_id exc3000_id[] = {
{ "exc3000", EETI_EXC3000 },
{ "exc80h60", EETI_EXC80H60 },
{ "exc80h84", EETI_EXC80H84 },
+ { "exc81w32", EETI_EXC81W32 },
{ }
};
MODULE_DEVICE_TABLE(i2c, exc3000_id);
@@ -450,6 +456,7 @@ static const struct of_device_id exc3000_of_match[] = {
{ .compatible = "eeti,exc3000", .data = &exc3000_info[EETI_EXC3000] },
{ .compatible = "eeti,exc80h60", .data = &exc3000_info[EETI_EXC80H60] },
{ .compatible = "eeti,exc80h84", .data = &exc3000_info[EETI_EXC80H84] },
+ { .compatible = "eeti,exc81w32", .data = &exc3000_info[EETI_EXC81W32] },
{ }
};
MODULE_DEVICE_TABLE(of, exc3000_of_match);
diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c
index 60a7246c5157..ff270b3b8572 100644
--- a/drivers/input/touchscreen/fsl-imx25-tcq.c
+++ b/drivers/input/touchscreen/fsl-imx25-tcq.c
@@ -38,8 +38,7 @@ struct mx25_tcq_priv {
struct device *dev;
};
-static struct regmap_config mx25_tcq_regconfig = {
- .fast_io = true,
+static const struct regmap_config mx25_tcq_regconfig = {
.max_register = 0x5c,
.reg_bits = 32,
.val_bits = 32,
diff --git a/drivers/input/touchscreen/fujitsu_ts.c b/drivers/input/touchscreen/fujitsu_ts.c
index 3b0b8fccc3f0..1a3e14ea2e08 100644
--- a/drivers/input/touchscreen/fujitsu_ts.c
+++ b/drivers/input/touchscreen/fujitsu_ts.c
@@ -99,7 +99,7 @@ static int fujitsu_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- fujitsu = kzalloc(sizeof(struct fujitsu), GFP_KERNEL);
+ fujitsu = kzalloc(sizeof(*fujitsu), GFP_KERNEL);
input_dev = input_allocate_device();
if (!fujitsu || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index 435714f18c23..f8798d11ec03 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -22,7 +22,7 @@
#include <linux/slab.h>
#include <linux/acpi.h>
#include <linux/of.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "goodix.h"
#define GOODIX_GPIO_INT_NAME "irq"
@@ -44,9 +44,11 @@
#define GOODIX_HAVE_KEY BIT(4)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20
-#define RESOLUTION_LOC 1
-#define MAX_CONTACTS_LOC 5
-#define TRIGGER_LOC 6
+#define RESOLUTION_LOC 1
+#define MAX_CONTACTS_LOC 5
+#define TRIGGER_LOC 6
+
+#define GOODIX_POLL_INTERVAL_MS 17 /* 17ms = 60fps */
/* Our special handling for GPIO accesses through ACPI is x86 specific */
#if defined CONFIG_X86 && defined CONFIG_ACPI
@@ -497,6 +499,14 @@ sync:
input_sync(ts->input_dev);
}
+static void goodix_ts_work_i2c_poll(struct input_dev *input)
+{
+ struct goodix_ts_data *ts = input_get_drvdata(input);
+
+ goodix_process_events(ts);
+ goodix_i2c_write_u8(ts->client, GOODIX_READ_COOR_ADDR, 0);
+}
+
/**
* goodix_ts_irq_handler - The IRQ handler
*
@@ -513,13 +523,29 @@ static irqreturn_t goodix_ts_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static void goodix_enable_irq(struct goodix_ts_data *ts)
+{
+ if (ts->client->irq)
+ enable_irq(ts->client->irq);
+}
+
+static void goodix_disable_irq(struct goodix_ts_data *ts)
+{
+ if (ts->client->irq)
+ disable_irq(ts->client->irq);
+}
+
static void goodix_free_irq(struct goodix_ts_data *ts)
{
- devm_free_irq(&ts->client->dev, ts->client->irq, ts);
+ if (ts->client->irq)
+ devm_free_irq(&ts->client->dev, ts->client->irq, ts);
}
static int goodix_request_irq(struct goodix_ts_data *ts)
{
+ if (!ts->client->irq)
+ return 0;
+
return devm_request_threaded_irq(&ts->client->dev, ts->client->irq,
NULL, goodix_ts_irq_handler,
ts->irq_flags, ts->client->name, ts);
@@ -770,17 +796,6 @@ int goodix_reset_no_int_sync(struct goodix_ts_data *ts)
usleep_range(6000, 10000); /* T4: > 5ms */
- /*
- * Put the reset pin back in to input / high-impedance mode to save
- * power. Only do this in the non ACPI case since some ACPI boards
- * don't have a pull-up, so there the reset pin must stay active-high.
- */
- if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_GPIO) {
- error = gpiod_direction_input(ts->gpiod_rst);
- if (error)
- goto error;
- }
-
return 0;
error:
@@ -931,14 +946,6 @@ static int goodix_add_acpi_gpio_mappings(struct goodix_ts_data *ts)
return -EINVAL;
}
- /*
- * Normally we put the reset pin in input / high-impedance mode to save
- * power. But some x86/ACPI boards don't have a pull-up, so for the ACPI
- * case, leave the pin as is. This results in the pin not being touched
- * at all on x86/ACPI boards, except when needed for error-recover.
- */
- ts->gpiod_rst_flags = GPIOD_ASIS;
-
return devm_acpi_dev_add_driver_gpios(dev, gpio_mapping);
}
#else
@@ -963,12 +970,6 @@ static int goodix_get_gpio_config(struct goodix_ts_data *ts)
return -EINVAL;
dev = &ts->client->dev;
- /*
- * By default we request the reset pin as input, leaving it in
- * high-impedance when not resetting the controller to save power.
- */
- ts->gpiod_rst_flags = GPIOD_IN;
-
ts->avdd28 = devm_regulator_get(dev, "AVDD28");
if (IS_ERR(ts->avdd28))
return dev_err_probe(dev, PTR_ERR(ts->avdd28), "Failed to get AVDD28 regulator\n");
@@ -993,7 +994,7 @@ retry_get_irq_gpio:
ts->gpiod_int = gpiod;
/* Get the reset line GPIO pin number */
- gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, ts->gpiod_rst_flags);
+ gpiod = devm_gpiod_get_optional(dev, GOODIX_GPIO_RST_NAME, GPIOD_ASIS);
if (IS_ERR(gpiod))
return dev_err_probe(dev, PTR_ERR(gpiod), "Failed to get %s GPIO\n",
GOODIX_GPIO_RST_NAME);
@@ -1219,6 +1220,18 @@ retry_read_config:
return error;
}
+ input_set_drvdata(ts->input_dev, ts);
+
+ if (!ts->client->irq) {
+ error = input_setup_polling(ts->input_dev, goodix_ts_work_i2c_poll);
+ if (error) {
+ dev_err(&ts->client->dev,
+ "could not set up polling mode, %d\n", error);
+ return error;
+ }
+ input_set_poll_interval(ts->input_dev, GOODIX_POLL_INTERVAL_MS);
+ }
+
error = input_register_device(ts->input_dev);
if (error) {
dev_err(&ts->client->dev,
@@ -1422,7 +1435,7 @@ static int goodix_suspend(struct device *dev)
/* We need gpio pins to suspend/resume */
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
- disable_irq(client->irq);
+ goodix_disable_irq(ts);
return 0;
}
@@ -1466,7 +1479,7 @@ static int goodix_resume(struct device *dev)
int error;
if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
- enable_irq(client->irq);
+ goodix_enable_irq(ts);
return 0;
}
@@ -1519,6 +1532,7 @@ MODULE_DEVICE_TABLE(i2c, goodix_ts_id);
static const struct acpi_device_id goodix_acpi_match[] = {
{ "GDIX1001", 0 },
{ "GDIX1002", 0 },
+ { "GDIX1003", 0 },
{ "GDX9110", 0 },
{ }
};
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 87797cc88b32..0d1e8a8d2cba 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -88,7 +88,6 @@ struct goodix_ts_data {
struct gpio_desc *gpiod_rst;
int gpio_count;
int gpio_int_idx;
- enum gpiod_flags gpiod_rst_flags;
char id[GOODIX_ID_MAX_LEN + 1];
char cfg_name[64];
u16 version;
diff --git a/drivers/input/touchscreen/goodix_berlin.h b/drivers/input/touchscreen/goodix_berlin.h
index 1fd77eb69c9a..d8bbd4853206 100644
--- a/drivers/input/touchscreen/goodix_berlin.h
+++ b/drivers/input/touchscreen/goodix_berlin.h
@@ -12,13 +12,28 @@
#include <linux/pm.h>
+#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A 0x1000C
+#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D 0x10014
+
+#define GOODIX_BERLIN_IC_INFO_ADDR_A 0x10068
+#define GOODIX_BERLIN_IC_INFO_ADDR_D 0x10070
+
+struct goodix_berlin_ic_data {
+ int fw_version_info_addr;
+ int ic_info_addr;
+ ssize_t read_dummy_len;
+ ssize_t read_prefix_len;
+};
+
struct device;
struct input_id;
struct regmap;
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
- struct regmap *regmap);
+ struct regmap *regmap,
+ const struct goodix_berlin_ic_data *ic_data);
extern const struct dev_pm_ops goodix_berlin_pm_ops;
+extern const struct attribute_group *goodix_berlin_groups[];
#endif
diff --git a/drivers/input/touchscreen/goodix_berlin_core.c b/drivers/input/touchscreen/goodix_berlin_core.c
index e7b41a926ef8..83f28b870531 100644
--- a/drivers/input/touchscreen/goodix_berlin_core.c
+++ b/drivers/input/touchscreen/goodix_berlin_core.c
@@ -12,7 +12,7 @@
* to the previous generations.
*
* Currently the driver only handles Multitouch events with already
- * programmed firmware and "config" for "Revision D" Berlin IC.
+ * programmed firmware and "config" for "Revision A/D" Berlin IC.
*
* Support is missing for:
* - ESD Management
@@ -20,18 +20,20 @@
* - "Config" update/flashing
* - Stylus Events
* - Gesture Events
- * - Support for older revisions (A & B)
+ * - Support for revision B
*/
#include <linux/bitfield.h>
+#include <linux/export.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
+#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include "goodix_berlin.h"
@@ -53,10 +55,8 @@
#define GOODIX_BERLIN_DEV_CONFIRM_VAL 0xAA
#define GOODIX_BERLIN_BOOTOPTION_ADDR 0x10000
-#define GOODIX_BERLIN_FW_VERSION_INFO_ADDR 0x10014
#define GOODIX_BERLIN_IC_INFO_MAX_LEN SZ_1K
-#define GOODIX_BERLIN_IC_INFO_ADDR 0x10070
#define GOODIX_BERLIN_CHECKSUM_SIZE sizeof(u16)
@@ -165,7 +165,7 @@ struct goodix_berlin_core {
struct device *dev;
struct regmap *regmap;
struct regulator *avdd;
- struct regulator *iovdd;
+ struct regulator *vddio;
struct gpio_desc *reset_gpio;
struct touchscreen_properties props;
struct goodix_berlin_fw_version fw_version;
@@ -175,6 +175,8 @@ struct goodix_berlin_core {
/* Runtime parameters extracted from IC_INFO buffer */
u32 touch_data_addr;
+ const struct goodix_berlin_ic_data *ic_data;
+
struct goodix_berlin_event event;
};
@@ -248,22 +250,22 @@ static int goodix_berlin_power_on(struct goodix_berlin_core *cd)
{
int error;
- error = regulator_enable(cd->iovdd);
+ error = regulator_enable(cd->vddio);
if (error) {
- dev_err(cd->dev, "Failed to enable iovdd: %d\n", error);
+ dev_err(cd->dev, "Failed to enable vddio: %d\n", error);
return error;
}
- /* Vendor waits 3ms for IOVDD to settle */
+ /* Vendor waits 3ms for VDDIO to settle */
usleep_range(3000, 3100);
error = regulator_enable(cd->avdd);
if (error) {
dev_err(cd->dev, "Failed to enable avdd: %d\n", error);
- goto err_iovdd_disable;
+ goto err_vddio_disable;
}
- /* Vendor waits 15ms for IOVDD to settle */
+ /* Vendor waits 15ms for AVDD to settle */
usleep_range(15000, 15100);
gpiod_set_value_cansleep(cd->reset_gpio, 0);
@@ -283,8 +285,8 @@ static int goodix_berlin_power_on(struct goodix_berlin_core *cd)
err_dev_reset:
gpiod_set_value_cansleep(cd->reset_gpio, 1);
regulator_disable(cd->avdd);
-err_iovdd_disable:
- regulator_disable(cd->iovdd);
+err_vddio_disable:
+ regulator_disable(cd->vddio);
return error;
}
@@ -292,14 +294,14 @@ static void goodix_berlin_power_off(struct goodix_berlin_core *cd)
{
gpiod_set_value_cansleep(cd->reset_gpio, 1);
regulator_disable(cd->avdd);
- regulator_disable(cd->iovdd);
+ regulator_disable(cd->vddio);
}
static int goodix_berlin_read_version(struct goodix_berlin_core *cd)
{
int error;
- error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_FW_VERSION_INFO_ADDR,
+ error = regmap_raw_read(cd->regmap, cd->ic_data->fw_version_info_addr,
&cd->fw_version, sizeof(cd->fw_version));
if (error) {
dev_err(cd->dev, "error reading fw version, %d\n", error);
@@ -367,7 +369,7 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
if (!afe_data)
return -ENOMEM;
- error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
+ error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr,
&length_raw, sizeof(length_raw));
if (error) {
dev_err(cd->dev, "failed get ic info length, %d\n", error);
@@ -380,8 +382,8 @@ static int goodix_berlin_get_ic_info(struct goodix_berlin_core *cd)
return -EINVAL;
}
- error = regmap_raw_read(cd->regmap, GOODIX_BERLIN_IC_INFO_ADDR,
- afe_data, length);
+ error = regmap_raw_read(cd->regmap, cd->ic_data->ic_info_addr, afe_data,
+ length);
if (error) {
dev_err(cd->dev, "failed get ic info data, %d\n", error);
return error;
@@ -672,8 +674,52 @@ static void goodix_berlin_power_off_act(void *data)
goodix_berlin_power_off(cd);
}
+static ssize_t registers_read(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct goodix_berlin_core *cd = dev_get_drvdata(dev);
+ int error;
+
+ error = regmap_raw_read(cd->regmap, off, buf, count);
+
+ return error ? error : count;
+}
+
+static ssize_t registers_write(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct goodix_berlin_core *cd = dev_get_drvdata(dev);
+ int error;
+
+ error = regmap_raw_write(cd->regmap, off, buf, count);
+
+ return error ? error : count;
+}
+
+static const BIN_ATTR_ADMIN_RW(registers, 0);
+
+static const struct bin_attribute *const goodix_berlin_bin_attrs[] = {
+ &bin_attr_registers,
+ NULL,
+};
+
+static const struct attribute_group goodix_berlin_attr_group = {
+ .bin_attrs = goodix_berlin_bin_attrs,
+};
+
+const struct attribute_group *goodix_berlin_groups[] = {
+ &goodix_berlin_attr_group,
+ NULL,
+};
+EXPORT_SYMBOL_GPL(goodix_berlin_groups);
+
int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
- struct regmap *regmap)
+ struct regmap *regmap,
+ const struct goodix_berlin_ic_data *ic_data)
{
struct goodix_berlin_core *cd;
int error;
@@ -690,6 +736,7 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
cd->dev = dev;
cd->regmap = regmap;
cd->irq = irq;
+ cd->ic_data = ic_data;
cd->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(cd->reset_gpio))
@@ -701,10 +748,10 @@ int goodix_berlin_probe(struct device *dev, int irq, const struct input_id *id,
return dev_err_probe(dev, PTR_ERR(cd->avdd),
"Failed to request avdd regulator\n");
- cd->iovdd = devm_regulator_get(dev, "iovdd");
- if (IS_ERR(cd->iovdd))
- return dev_err_probe(dev, PTR_ERR(cd->iovdd),
- "Failed to request iovdd regulator\n");
+ cd->vddio = devm_regulator_get(dev, "vddio");
+ if (IS_ERR(cd->vddio))
+ return dev_err_probe(dev, PTR_ERR(cd->vddio),
+ "Failed to request vddio regulator\n");
error = goodix_berlin_power_on(cd);
if (error) {
diff --git a/drivers/input/touchscreen/goodix_berlin_i2c.c b/drivers/input/touchscreen/goodix_berlin_i2c.c
index 2e7098078838..929090a094bf 100644
--- a/drivers/input/touchscreen/goodix_berlin_i2c.c
+++ b/drivers/input/touchscreen/goodix_berlin_i2c.c
@@ -31,6 +31,8 @@ static const struct input_id goodix_berlin_i2c_input_id = {
static int goodix_berlin_i2c_probe(struct i2c_client *client)
{
+ const struct goodix_berlin_ic_data *ic_data =
+ i2c_get_match_data(client);
struct regmap *regmap;
int error;
@@ -39,22 +41,28 @@ static int goodix_berlin_i2c_probe(struct i2c_client *client)
return PTR_ERR(regmap);
error = goodix_berlin_probe(&client->dev, client->irq,
- &goodix_berlin_i2c_input_id, regmap);
+ &goodix_berlin_i2c_input_id, regmap,
+ ic_data);
if (error)
return error;
return 0;
}
+static const struct goodix_berlin_ic_data gt9916_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
+};
+
static const struct i2c_device_id goodix_berlin_i2c_id[] = {
- { "gt9916" },
+ { .name = "gt9916", .driver_data = (long)&gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, goodix_berlin_i2c_id);
static const struct of_device_id goodix_berlin_i2c_of_match[] = {
- { .compatible = "goodix,gt9916", },
+ { .compatible = "goodix,gt9916", .data = &gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_i2c_of_match);
@@ -64,6 +72,7 @@ static struct i2c_driver goodix_berlin_i2c_driver = {
.name = "goodix-berlin-i2c",
.of_match_table = goodix_berlin_i2c_of_match,
.pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
+ .dev_groups = goodix_berlin_groups,
},
.probe = goodix_berlin_i2c_probe,
.id_table = goodix_berlin_i2c_id,
diff --git a/drivers/input/touchscreen/goodix_berlin_spi.c b/drivers/input/touchscreen/goodix_berlin_spi.c
index 4cc557da048a..01f850f484c2 100644
--- a/drivers/input/touchscreen/goodix_berlin_spi.c
+++ b/drivers/input/touchscreen/goodix_berlin_spi.c
@@ -7,7 +7,7 @@
*
* Based on goodix_ts_berlin driver.
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/regmap.h>
@@ -18,10 +18,14 @@
#define GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN 1
#define GOODIX_BERLIN_REGISTER_WIDTH 4
-#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN 3
-#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A 4
+#define GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D 3
+#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
GOODIX_BERLIN_REGISTER_WIDTH + \
- GOODIX_BERLIN_SPI_READ_DUMMY_LEN)
+ GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A)
+#define GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
+ GOODIX_BERLIN_REGISTER_WIDTH + \
+ GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D)
#define GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN (GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + \
GOODIX_BERLIN_REGISTER_WIDTH)
@@ -33,41 +37,42 @@ static int goodix_berlin_spi_read(void *context, const void *reg_buf,
size_t val_size)
{
struct spi_device *spi = context;
+ const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
struct spi_transfer xfers;
struct spi_message spi_msg;
const u32 *reg = reg_buf; /* reg is stored as native u32 at start of buffer */
- u8 *buf;
int error;
if (reg_size != GOODIX_BERLIN_REGISTER_WIDTH)
return -EINVAL;
- buf = kzalloc(GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size, GFP_KERNEL);
+ u8 *buf __free(kfree) =
+ kzalloc(ic_data->read_prefix_len + val_size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
spi_message_init(&spi_msg);
memset(&xfers, 0, sizeof(xfers));
- /* buffer format: 0xF1 + addr(4bytes) + dummy(3bytes) + data */
+ /* buffer format: 0xF1 + addr(4bytes) + dummy(3/4bytes) + data */
buf[0] = GOODIX_BERLIN_SPI_READ_FLAG;
put_unaligned_be32(*reg, buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN);
memset(buf + GOODIX_BERLIN_SPI_TRANS_PREFIX_LEN + GOODIX_BERLIN_REGISTER_WIDTH,
- 0xff, GOODIX_BERLIN_SPI_READ_DUMMY_LEN);
+ 0xff, ic_data->read_dummy_len);
xfers.tx_buf = buf;
xfers.rx_buf = buf;
- xfers.len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN + val_size;
+ xfers.len = ic_data->read_prefix_len + val_size;
xfers.cs_change = 0;
spi_message_add_tail(&xfers, &spi_msg);
error = spi_sync(spi, &spi_msg);
- if (error < 0)
+ if (error < 0) {
dev_err(&spi->dev, "spi transfer error, %d", error);
- else
- memcpy(val_buf, buf + GOODIX_BERLIN_SPI_READ_PREFIX_LEN, val_size);
+ return error;
+ }
- kfree(buf);
+ memcpy(val_buf, buf + ic_data->read_prefix_len, val_size);
return error;
}
@@ -79,10 +84,10 @@ static int goodix_berlin_spi_write(void *context, const void *data,
struct spi_transfer xfers;
struct spi_message spi_msg;
const u32 *reg = data; /* reg is stored as native u32 at start of buffer */
- u8 *buf;
int error;
- buf = kzalloc(GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL);
+ u8 *buf __free(kfree) =
+ kzalloc(GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN + len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -100,11 +105,12 @@ static int goodix_berlin_spi_write(void *context, const void *data,
spi_message_add_tail(&xfers, &spi_msg);
error = spi_sync(spi, &spi_msg);
- if (error < 0)
+ if (error < 0) {
dev_err(&spi->dev, "spi transfer error, %d", error);
+ return error;
+ }
- kfree(buf);
- return error;
+ return 0;
}
static const struct regmap_config goodix_berlin_spi_regmap_conf = {
@@ -121,6 +127,7 @@ static const struct input_id goodix_berlin_spi_input_id = {
static int goodix_berlin_spi_probe(struct spi_device *spi)
{
+ const struct goodix_berlin_ic_data *ic_data = spi_get_device_match_data(spi);
struct regmap_config regmap_config;
struct regmap *regmap;
size_t max_size;
@@ -135,7 +142,7 @@ static int goodix_berlin_spi_probe(struct spi_device *spi)
max_size = spi_max_transfer_size(spi);
regmap_config = goodix_berlin_spi_regmap_conf;
- regmap_config.max_raw_read = max_size - GOODIX_BERLIN_SPI_READ_PREFIX_LEN;
+ regmap_config.max_raw_read = max_size - ic_data->read_prefix_len;
regmap_config.max_raw_write = max_size - GOODIX_BERLIN_SPI_WRITE_PREFIX_LEN;
regmap = devm_regmap_init(&spi->dev, NULL, spi, &regmap_config);
@@ -143,21 +150,38 @@ static int goodix_berlin_spi_probe(struct spi_device *spi)
return PTR_ERR(regmap);
error = goodix_berlin_probe(&spi->dev, spi->irq,
- &goodix_berlin_spi_input_id, regmap);
+ &goodix_berlin_spi_input_id, regmap,
+ ic_data);
if (error)
return error;
return 0;
}
+static const struct goodix_berlin_ic_data gt9897_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_A,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_A,
+ .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_A,
+ .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_A,
+};
+
+static const struct goodix_berlin_ic_data gt9916_data = {
+ .fw_version_info_addr = GOODIX_BERLIN_FW_VERSION_INFO_ADDR_D,
+ .ic_info_addr = GOODIX_BERLIN_IC_INFO_ADDR_D,
+ .read_dummy_len = GOODIX_BERLIN_SPI_READ_DUMMY_LEN_D,
+ .read_prefix_len = GOODIX_BERLIN_SPI_READ_PREFIX_LEN_D,
+};
+
static const struct spi_device_id goodix_berlin_spi_ids[] = {
- { "gt9916" },
+ { .name = "gt9897", .driver_data = (long)&gt9897_data },
+ { .name = "gt9916", .driver_data = (long)&gt9916_data },
{ },
};
MODULE_DEVICE_TABLE(spi, goodix_berlin_spi_ids);
static const struct of_device_id goodix_berlin_spi_of_match[] = {
- { .compatible = "goodix,gt9916", },
+ { .compatible = "goodix,gt9897", .data = &gt9897_data },
+ { .compatible = "goodix,gt9916", .data = &gt9916_data },
{ }
};
MODULE_DEVICE_TABLE(of, goodix_berlin_spi_of_match);
@@ -167,6 +191,7 @@ static struct spi_driver goodix_berlin_spi_driver = {
.name = "goodix-berlin-spi",
.of_match_table = goodix_berlin_spi_of_match,
.pm = pm_sleep_ptr(&goodix_berlin_pm_ops),
+ .dev_groups = goodix_berlin_groups,
},
.probe = goodix_berlin_spi_probe,
.id_table = goodix_berlin_spi_ids,
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index 5a5f9da73fa1..dbf92fb02f80 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -97,7 +97,7 @@ static int gunze_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- gunze = kzalloc(sizeof(struct gunze), GFP_KERNEL);
+ gunze = kzalloc(sizeof(*gunze), GFP_KERNEL);
input_dev = input_allocate_device();
if (!gunze || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/hampshire.c b/drivers/input/touchscreen/hampshire.c
index 5c4d877564ee..dc0a2482ddd6 100644
--- a/drivers/input/touchscreen/hampshire.c
+++ b/drivers/input/touchscreen/hampshire.c
@@ -109,7 +109,7 @@ static int hampshire_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- phampshire = kzalloc(sizeof(struct hampshire), GFP_KERNEL);
+ phampshire = kzalloc(sizeof(*phampshire), GFP_KERNEL);
input_dev = input_allocate_device();
if (!phampshire || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/hideep.c b/drivers/input/touchscreen/hideep.c
index 682abbbe5bd6..a73369e15dda 100644
--- a/drivers/input/touchscreen/hideep.c
+++ b/drivers/input/touchscreen/hideep.c
@@ -17,7 +17,7 @@
#include <linux/input/mt.h>
#include <linux/input/touchscreen.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define HIDEEP_TS_NAME "HiDeep Touchscreen"
#define HIDEEP_I2C_NAME "hideep_ts"
diff --git a/drivers/input/touchscreen/himax_hx83112b.c b/drivers/input/touchscreen/himax_hx83112b.c
index bafabd06dabc..896a145ddb2b 100644
--- a/drivers/input/touchscreen/himax_hx83112b.c
+++ b/drivers/input/touchscreen/himax_hx83112b.c
@@ -4,6 +4,9 @@
*
* Copyright (C) 2022 Job Noorman <job@noorman.info>
*
+ * HX83100A support
+ * Copyright (C) 2024 Felix Kaechele <felix@kaechele.ca>
+ *
* This code is based on "Himax Android Driver Sample Code for QCT platform":
*
* Copyright (C) 2017 Himax Corporation.
@@ -20,16 +23,22 @@
#include <linux/kernel.h>
#include <linux/regmap.h>
-#define HIMAX_ID_83112B 0x83112b
-
#define HIMAX_MAX_POINTS 10
-#define HIMAX_REG_CFG_SET_ADDR 0x00
-#define HIMAX_REG_CFG_INIT_READ 0x0c
-#define HIMAX_REG_CFG_READ_VALUE 0x08
-#define HIMAX_REG_READ_EVENT 0x30
+#define HIMAX_AHB_ADDR_BYTE_0 0x00
+#define HIMAX_AHB_ADDR_RDATA_BYTE_0 0x08
+#define HIMAX_AHB_ADDR_ACCESS_DIRECTION 0x0c
+#define HIMAX_AHB_ADDR_INCR4 0x0d
+#define HIMAX_AHB_ADDR_CONTI 0x13
+#define HIMAX_AHB_ADDR_EVENT_STACK 0x30
+
+#define HIMAX_AHB_CMD_ACCESS_DIRECTION_READ 0x00
+#define HIMAX_AHB_CMD_INCR4 0x10
+#define HIMAX_AHB_CMD_CONTI 0x31
-#define HIMAX_CFG_PRODUCT_ID 0x900000d0
+#define HIMAX_REG_ADDR_ICID 0x900000d0
+
+#define HX83100A_REG_FW_EVENT_STACK 0x90060000
#define HIMAX_INVALID_COORD 0xffff
@@ -49,7 +58,16 @@ struct himax_event {
static_assert(sizeof(struct himax_event) == 56);
+struct himax_ts_data;
+struct himax_chip {
+ u32 id;
+ int (*check_id)(struct himax_ts_data *ts);
+ int (*read_events)(struct himax_ts_data *ts, struct himax_event *event,
+ size_t length);
+};
+
struct himax_ts_data {
+ const struct himax_chip *chip;
struct gpio_desc *gpiod_rst;
struct input_dev *input_dev;
struct i2c_client *client;
@@ -63,19 +81,49 @@ static const struct regmap_config himax_regmap_config = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
};
-static int himax_read_config(struct himax_ts_data *ts, u32 address, u32 *dst)
+static int himax_bus_enable_burst(struct himax_ts_data *ts)
+{
+ int error;
+
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_CONTI,
+ HIMAX_AHB_CMD_CONTI);
+ if (error)
+ return error;
+
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_INCR4,
+ HIMAX_AHB_CMD_INCR4);
+ if (error)
+ return error;
+
+ return 0;
+}
+
+static int himax_bus_read(struct himax_ts_data *ts, u32 address, void *dst,
+ size_t length)
{
int error;
- error = regmap_write(ts->regmap, HIMAX_REG_CFG_SET_ADDR, address);
+ if (length > 4) {
+ error = himax_bus_enable_burst(ts);
+ if (error)
+ return error;
+ }
+
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_BYTE_0, address);
if (error)
return error;
- error = regmap_write(ts->regmap, HIMAX_REG_CFG_INIT_READ, 0x0);
+ error = regmap_write(ts->regmap, HIMAX_AHB_ADDR_ACCESS_DIRECTION,
+ HIMAX_AHB_CMD_ACCESS_DIRECTION_READ);
if (error)
return error;
- error = regmap_read(ts->regmap, HIMAX_REG_CFG_READ_VALUE, dst);
+ if (length > 4)
+ error = regmap_noinc_read(ts->regmap, HIMAX_AHB_ADDR_RDATA_BYTE_0,
+ dst, length);
+ else
+ error = regmap_read(ts->regmap, HIMAX_AHB_ADDR_RDATA_BYTE_0,
+ dst);
if (error)
return error;
@@ -101,7 +149,8 @@ static int himax_read_product_id(struct himax_ts_data *ts, u32 *product_id)
{
int error;
- error = himax_read_config(ts, HIMAX_CFG_PRODUCT_ID, product_id);
+ error = himax_bus_read(ts, HIMAX_REG_ADDR_ICID, product_id,
+ sizeof(*product_id));
if (error)
return error;
@@ -120,15 +169,12 @@ static int himax_check_product_id(struct himax_ts_data *ts)
dev_dbg(&ts->client->dev, "Product id: %x\n", product_id);
- switch (product_id) {
- case HIMAX_ID_83112B:
+ if (product_id == ts->chip->id)
return 0;
- default:
- dev_err(&ts->client->dev,
- "Unknown product id: %x\n", product_id);
- return -EINVAL;
- }
+ dev_err(&ts->client->dev, "Unknown product id: %x\n",
+ product_id);
+ return -EINVAL;
}
static int himax_input_register(struct himax_ts_data *ts)
@@ -230,13 +276,25 @@ static bool himax_verify_checksum(struct himax_ts_data *ts,
return true;
}
+static int himax_read_events(struct himax_ts_data *ts,
+ struct himax_event *event, size_t length)
+{
+ return regmap_raw_read(ts->regmap, HIMAX_AHB_ADDR_EVENT_STACK, event,
+ length);
+}
+
+static int hx83100a_read_events(struct himax_ts_data *ts,
+ struct himax_event *event, size_t length)
+{
+ return himax_bus_read(ts, HX83100A_REG_FW_EVENT_STACK, event, length);
+};
+
static int himax_handle_input(struct himax_ts_data *ts)
{
int error;
struct himax_event event;
- error = regmap_raw_read(ts->regmap, HIMAX_REG_READ_EVENT, &event,
- sizeof(event));
+ error = ts->chip->read_events(ts, &event, sizeof(event));
if (error) {
dev_err(&ts->client->dev, "Failed to read input event: %d\n",
error);
@@ -282,6 +340,7 @@ static int himax_probe(struct i2c_client *client)
i2c_set_clientdata(client, ts);
ts->client = client;
+ ts->chip = i2c_get_match_data(client);
ts->regmap = devm_regmap_init_i2c(client, &himax_regmap_config);
error = PTR_ERR_OR_ZERO(ts->regmap);
@@ -299,9 +358,11 @@ static int himax_probe(struct i2c_client *client)
himax_reset(ts);
- error = himax_check_product_id(ts);
- if (error)
- return error;
+ if (ts->chip->check_id) {
+ error = himax_check_product_id(ts);
+ if (error)
+ return error;
+ }
error = himax_input_register(ts);
if (error)
@@ -334,15 +395,27 @@ static int himax_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(himax_pm_ops, himax_suspend, himax_resume);
+static const struct himax_chip hx83100a_chip = {
+ .read_events = hx83100a_read_events,
+};
+
+static const struct himax_chip hx83112b_chip = {
+ .id = 0x83112b,
+ .check_id = himax_check_product_id,
+ .read_events = himax_read_events,
+};
+
static const struct i2c_device_id himax_ts_id[] = {
- { "hx83112b" },
+ { "hx83100a", (kernel_ulong_t)&hx83100a_chip },
+ { "hx83112b", (kernel_ulong_t)&hx83112b_chip },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(i2c, himax_ts_id);
#ifdef CONFIG_OF
static const struct of_device_id himax_of_match[] = {
- { .compatible = "himax,hx83112b" },
+ { .compatible = "himax,hx83100a", .data = &hx83100a_chip },
+ { .compatible = "himax,hx83112b", .data = &hx83112b_chip },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, himax_of_match);
diff --git a/drivers/input/touchscreen/himax_hx852x.c b/drivers/input/touchscreen/himax_hx852x.c
new file mode 100644
index 000000000000..83c60e137a55
--- /dev/null
+++ b/drivers/input/touchscreen/himax_hx852x.c
@@ -0,0 +1,503 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Himax HX852x(ES) Touchscreen Driver
+ * Copyright (c) 2020-2024 Stephan Gerhold <stephan@gerhold.net>
+ * Copyright (c) 2020 Jonathan Albrieux <jonathan.albrieux@gmail.com>
+ *
+ * Based on the Himax Android Driver Sample Code Ver 0.3 for HMX852xES chipset:
+ * Copyright (c) 2014 Himax Corporation.
+ */
+
+#include <linux/delay.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/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/regulator/consumer.h>
+#include <linux/unaligned.h>
+
+#define HX852X_COORD_SIZE(fingers) ((fingers) * sizeof(struct hx852x_coord))
+#define HX852X_WIDTH_SIZE(fingers) ALIGN(fingers, 4)
+#define HX852X_BUF_SIZE(fingers) (HX852X_COORD_SIZE(fingers) + \
+ HX852X_WIDTH_SIZE(fingers) + \
+ sizeof(struct hx852x_touch_info))
+
+#define HX852X_MAX_FINGERS 12
+#define HX852X_MAX_KEY_COUNT 4
+#define HX852X_MAX_BUF_SIZE HX852X_BUF_SIZE(HX852X_MAX_FINGERS)
+
+#define HX852X_TS_SLEEP_IN 0x80
+#define HX852X_TS_SLEEP_OUT 0x81
+#define HX852X_TS_SENSE_OFF 0x82
+#define HX852X_TS_SENSE_ON 0x83
+#define HX852X_READ_ONE_EVENT 0x85
+#define HX852X_READ_ALL_EVENTS 0x86
+#define HX852X_READ_LATEST_EVENT 0x87
+#define HX852X_CLEAR_EVENT_STACK 0x88
+
+#define HX852X_REG_SRAM_SWITCH 0x8c
+#define HX852X_REG_SRAM_ADDR 0x8b
+#define HX852X_REG_FLASH_RPLACE 0x5a
+
+#define HX852X_SRAM_SWITCH_TEST_MODE 0x14
+#define HX852X_SRAM_ADDR_CONFIG 0x7000
+
+struct hx852x {
+ struct i2c_client *client;
+ struct input_dev *input_dev;
+ struct touchscreen_properties props;
+ struct gpio_desc *reset_gpiod;
+ struct regulator_bulk_data supplies[2];
+ unsigned int max_fingers;
+ unsigned int keycount;
+ unsigned int keycodes[HX852X_MAX_KEY_COUNT];
+};
+
+struct hx852x_config {
+ u8 rx_num;
+ u8 tx_num;
+ u8 max_pt;
+ u8 padding1[3];
+ __be16 x_res;
+ __be16 y_res;
+ u8 padding2[2];
+} __packed __aligned(4);
+
+struct hx852x_coord {
+ __be16 x;
+ __be16 y;
+} __packed __aligned(4);
+
+struct hx852x_touch_info {
+ u8 finger_num;
+ __le16 finger_pressed;
+ u8 padding;
+} __packed __aligned(4);
+
+static int hx852x_i2c_read(struct hx852x *hx, u8 cmd, void *data, u16 len)
+{
+ struct i2c_client *client = hx->client;
+ int error;
+ int ret;
+
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &cmd,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = data,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret != ARRAY_SIZE(msg)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(&client->dev, "failed to read %#x: %d\n", cmd, error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_power_on(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = regulator_bulk_enable(ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error) {
+ dev_err(dev, "failed to enable regulators: %d\n", error);
+ return error;
+ }
+
+ gpiod_set_value_cansleep(hx->reset_gpiod, 1);
+ msleep(20);
+ gpiod_set_value_cansleep(hx->reset_gpiod, 0);
+ msleep(50);
+
+ return 0;
+}
+
+static int hx852x_start(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_OUT);
+ if (error) {
+ dev_err(dev, "failed to send TS_SLEEP_OUT: %d\n", error);
+ return error;
+ }
+ msleep(30);
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_ON);
+ if (error) {
+ dev_err(dev, "failed to send TS_SENSE_ON: %d\n", error);
+ return error;
+ }
+ msleep(20);
+
+ return 0;
+}
+
+static int hx852x_stop(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SENSE_OFF);
+ if (error) {
+ dev_err(dev, "failed to send TS_SENSE_OFF: %d\n", error);
+ return error;
+ }
+ msleep(20);
+
+ error = i2c_smbus_write_byte(hx->client, HX852X_TS_SLEEP_IN);
+ if (error) {
+ dev_err(dev, "failed to send TS_SLEEP_IN: %d\n", error);
+ return error;
+ }
+ msleep(30);
+
+ return 0;
+}
+
+static int hx852x_power_off(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error;
+
+ error = regulator_bulk_disable(ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error) {
+ dev_err(dev, "failed to disable regulators: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_read_config(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ struct hx852x_config conf;
+ int x_res, y_res;
+ int error, error2;
+
+ error = hx852x_power_on(hx);
+ if (error)
+ return error;
+
+ /* Sensing must be turned on briefly to load the config */
+ error = hx852x_start(hx);
+ if (error)
+ goto err_power_off;
+
+ error = hx852x_stop(hx);
+ if (error)
+ goto err_power_off;
+
+ error = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH,
+ HX852X_SRAM_SWITCH_TEST_MODE);
+ if (error)
+ goto err_power_off;
+
+ error = i2c_smbus_write_word_data(hx->client, HX852X_REG_SRAM_ADDR,
+ HX852X_SRAM_ADDR_CONFIG);
+ if (error)
+ goto err_test_mode;
+
+ error = hx852x_i2c_read(hx, HX852X_REG_FLASH_RPLACE, &conf, sizeof(conf));
+ if (error)
+ goto err_test_mode;
+
+ x_res = be16_to_cpu(conf.x_res);
+ y_res = be16_to_cpu(conf.y_res);
+ hx->max_fingers = (conf.max_pt & 0xf0) >> 4;
+ dev_dbg(dev, "x res: %u, y res: %u, max fingers: %u\n",
+ x_res, y_res, hx->max_fingers);
+
+ if (hx->max_fingers > HX852X_MAX_FINGERS) {
+ dev_err(dev, "max supported fingers: %u, found: %u\n",
+ HX852X_MAX_FINGERS, hx->max_fingers);
+ error = -EINVAL;
+ goto err_test_mode;
+ }
+
+ if (x_res && y_res) {
+ input_set_abs_params(hx->input_dev, ABS_MT_POSITION_X, 0, x_res - 1, 0, 0);
+ input_set_abs_params(hx->input_dev, ABS_MT_POSITION_Y, 0, y_res - 1, 0, 0);
+ }
+
+err_test_mode:
+ error2 = i2c_smbus_write_byte_data(hx->client, HX852X_REG_SRAM_SWITCH, 0);
+ error = error ?: error2;
+err_power_off:
+ error2 = hx852x_power_off(hx);
+ return error ?: error2;
+}
+
+static int hx852x_handle_events(struct hx852x *hx)
+{
+ /*
+ * The event packets have variable size, depending on the amount of
+ * supported fingers (hx->max_fingers). They are laid out as follows:
+ * - struct hx852x_coord[hx->max_fingers]: Coordinates for each finger
+ * - u8[ALIGN(hx->max_fingers, 4)]: Touch width for each finger
+ * with padding for 32-bit alignment
+ * - struct hx852x_touch_info
+ *
+ * Load everything into a 32-bit aligned buffer so the coordinates
+ * can be assigned directly, without using get_unaligned_*().
+ */
+ u8 buf[HX852X_MAX_BUF_SIZE] __aligned(4);
+ struct hx852x_coord *coord = (struct hx852x_coord *)buf;
+ u8 *width = &buf[HX852X_COORD_SIZE(hx->max_fingers)];
+ struct hx852x_touch_info *info = (struct hx852x_touch_info *)
+ &width[HX852X_WIDTH_SIZE(hx->max_fingers)];
+ unsigned long finger_pressed, key_pressed;
+ unsigned int i, x, y, w;
+ int error;
+
+ error = hx852x_i2c_read(hx, HX852X_READ_ALL_EVENTS, buf,
+ HX852X_BUF_SIZE(hx->max_fingers));
+ if (error)
+ return error;
+
+ finger_pressed = get_unaligned_le16(&info->finger_pressed);
+ key_pressed = finger_pressed >> HX852X_MAX_FINGERS;
+
+ /* All bits are set when no touch is detected */
+ if (info->finger_num == 0xff || !(info->finger_num & 0x0f))
+ finger_pressed = 0;
+ if (key_pressed == 0xf)
+ key_pressed = 0;
+
+ for_each_set_bit(i, &finger_pressed, hx->max_fingers) {
+ x = be16_to_cpu(coord[i].x);
+ y = be16_to_cpu(coord[i].y);
+ w = width[i];
+
+ input_mt_slot(hx->input_dev, i);
+ input_mt_report_slot_state(hx->input_dev, MT_TOOL_FINGER, 1);
+ touchscreen_report_pos(hx->input_dev, &hx->props, x, y, true);
+ input_report_abs(hx->input_dev, ABS_MT_TOUCH_MAJOR, w);
+ }
+ input_mt_sync_frame(hx->input_dev);
+
+ for (i = 0; i < hx->keycount; i++)
+ input_report_key(hx->input_dev, hx->keycodes[i], key_pressed & BIT(i));
+
+ input_sync(hx->input_dev);
+ return 0;
+}
+
+static irqreturn_t hx852x_interrupt(int irq, void *ptr)
+{
+ struct hx852x *hx = ptr;
+ int error;
+
+ error = hx852x_handle_events(hx);
+ if (error) {
+ dev_err_ratelimited(&hx->client->dev,
+ "failed to handle events: %d\n", error);
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hx852x_input_open(struct input_dev *dev)
+{
+ struct hx852x *hx = input_get_drvdata(dev);
+ int error;
+
+ error = hx852x_power_on(hx);
+ if (error)
+ return error;
+
+ error = hx852x_start(hx);
+ if (error) {
+ hx852x_power_off(hx);
+ return error;
+ }
+
+ enable_irq(hx->client->irq);
+ return 0;
+}
+
+static void hx852x_input_close(struct input_dev *dev)
+{
+ struct hx852x *hx = input_get_drvdata(dev);
+
+ hx852x_stop(hx);
+ disable_irq(hx->client->irq);
+ hx852x_power_off(hx);
+}
+
+static int hx852x_parse_properties(struct hx852x *hx)
+{
+ struct device *dev = &hx->client->dev;
+ int error, count;
+
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count == -EINVAL) {
+ /* Property does not exist, keycodes are optional */
+ return 0;
+ } else if (count < 0) {
+ dev_err(dev, "Failed to read linux,keycodes: %d\n", count);
+ return count;
+ } else if (count > HX852X_MAX_KEY_COUNT) {
+ dev_err(dev, "max supported keys: %u, found: %u\n",
+ HX852X_MAX_KEY_COUNT, hx->keycount);
+ return -EINVAL;
+ }
+ hx->keycount = count;
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ hx->keycodes, hx->keycount);
+ if (error) {
+ dev_err(dev, "failed to read linux,keycodes: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static int hx852x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct hx852x *hx;
+ int error, i;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_WRITE_BYTE |
+ I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
+ I2C_FUNC_SMBUS_WRITE_WORD_DATA)) {
+ dev_err(dev, "not all required i2c functionality supported\n");
+ return -ENXIO;
+ }
+
+ hx = devm_kzalloc(dev, sizeof(*hx), GFP_KERNEL);
+ if (!hx)
+ return -ENOMEM;
+
+ hx->client = client;
+ hx->input_dev = devm_input_allocate_device(dev);
+ if (!hx->input_dev)
+ return -ENOMEM;
+
+ hx->input_dev->name = "Himax HX852x";
+ hx->input_dev->id.bustype = BUS_I2C;
+ hx->input_dev->open = hx852x_input_open;
+ hx->input_dev->close = hx852x_input_close;
+
+ i2c_set_clientdata(client, hx);
+ input_set_drvdata(hx->input_dev, hx);
+
+ hx->supplies[0].supply = "vcca";
+ hx->supplies[1].supply = "vccd";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(hx->supplies), hx->supplies);
+ if (error)
+ return dev_err_probe(dev, error, "failed to get regulators\n");
+
+ hx->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(hx->reset_gpiod))
+ return dev_err_probe(dev, PTR_ERR(hx->reset_gpiod),
+ "failed to get reset gpio\n");
+
+ error = devm_request_threaded_irq(dev, client->irq, NULL, hx852x_interrupt,
+ IRQF_ONESHOT | IRQF_NO_AUTOEN, NULL, hx);
+ if (error)
+ return dev_err_probe(dev, error, "failed to request irq %d", client->irq);
+
+ error = hx852x_read_config(hx);
+ if (error)
+ return error;
+
+ input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_X);
+ input_set_capability(hx->input_dev, EV_ABS, ABS_MT_POSITION_Y);
+ input_set_abs_params(hx->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+
+ touchscreen_parse_properties(hx->input_dev, true, &hx->props);
+ error = hx852x_parse_properties(hx);
+ if (error)
+ return error;
+
+ hx->input_dev->keycode = hx->keycodes;
+ hx->input_dev->keycodemax = hx->keycount;
+ hx->input_dev->keycodesize = sizeof(hx->keycodes[0]);
+ for (i = 0; i < hx->keycount; i++)
+ input_set_capability(hx->input_dev, EV_KEY, hx->keycodes[i]);
+
+ error = input_mt_init_slots(hx->input_dev, hx->max_fingers,
+ INPUT_MT_DIRECT | INPUT_MT_DROP_UNUSED);
+ if (error)
+ return dev_err_probe(dev, error, "failed to init MT slots\n");
+
+ error = input_register_device(hx->input_dev);
+ if (error)
+ return dev_err_probe(dev, error, "failed to register input device\n");
+
+ return 0;
+}
+
+static int hx852x_suspend(struct device *dev)
+{
+ struct hx852x *hx = dev_get_drvdata(dev);
+
+ guard(mutex)(&hx->input_dev->mutex);
+
+ if (input_device_enabled(hx->input_dev))
+ return hx852x_stop(hx);
+
+ return 0;
+}
+
+static int hx852x_resume(struct device *dev)
+{
+ struct hx852x *hx = dev_get_drvdata(dev);
+
+ guard(mutex)(&hx->input_dev->mutex);
+
+ if (input_device_enabled(hx->input_dev))
+ return hx852x_start(hx);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(hx852x_pm_ops, hx852x_suspend, hx852x_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id hx852x_of_match[] = {
+ { .compatible = "himax,hx852es" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hx852x_of_match);
+#endif
+
+static struct i2c_driver hx852x_driver = {
+ .probe = hx852x_probe,
+ .driver = {
+ .name = "himax_hx852x",
+ .pm = pm_sleep_ptr(&hx852x_pm_ops),
+ .of_match_table = of_match_ptr(hx852x_of_match),
+ },
+};
+module_i2c_driver(hx852x_driver);
+
+MODULE_DESCRIPTION("Himax HX852x(ES) Touchscreen Driver");
+MODULE_AUTHOR("Jonathan Albrieux <jonathan.albrieux@gmail.com>");
+MODULE_AUTHOR("Stephan Gerhold <stephan@gerhold.net>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/hycon-hy46xx.c b/drivers/input/touchscreen/hycon-hy46xx.c
index 2e01d87977c1..b2ff7a45b908 100644
--- a/drivers/input/touchscreen/hycon-hy46xx.c
+++ b/drivers/input/touchscreen/hycon-hy46xx.c
@@ -15,7 +15,7 @@
#include <linux/regulator/consumer.h>
#include <linux/regmap.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define HY46XX_CHKSUM_CODE 0x1
#define HY46XX_FINGER_NUM 0x2
diff --git a/drivers/input/touchscreen/hynitron-cst816x.c b/drivers/input/touchscreen/hynitron-cst816x.c
new file mode 100644
index 000000000000..b64d7928e18f
--- /dev/null
+++ b/drivers/input/touchscreen/hynitron-cst816x.c
@@ -0,0 +1,253 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Driver for I2C connected Hynitron CST816x Series Touchscreen
+ *
+ * Copyright (C) 2025 Oleh Kuzhylnyi <kuzhylol@gmail.com>
+ */
+
+#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/unaligned.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#define CST816X_RD_REG 0x01
+#define CST816X_NUM_KEYS 5
+
+struct cst816x_touch {
+ u8 gest;
+ u8 active;
+ u16 abs_x;
+ u16 abs_y;
+} __packed;
+
+struct cst816x_priv {
+ struct i2c_client *client;
+ struct gpio_desc *reset;
+ struct input_dev *input;
+ unsigned int keycode[CST816X_NUM_KEYS];
+ unsigned int keycodemax;
+};
+
+static int cst816x_parse_keycodes(struct device *dev, struct cst816x_priv *priv)
+{
+ int count;
+ int error;
+
+ if (device_property_present(dev, "linux,keycodes")) {
+ count = device_property_count_u32(dev, "linux,keycodes");
+ if (count < 0) {
+ error = count;
+ dev_err(dev, "failed to count keys: %d\n", error);
+ return error;
+ } else if (count > ARRAY_SIZE(priv->keycode)) {
+ dev_err(dev, "too many keys defined: %d\n", count);
+ return -EINVAL;
+ }
+ priv->keycodemax = count;
+
+ error = device_property_read_u32_array(dev, "linux,keycodes",
+ priv->keycode,
+ priv->keycodemax);
+ if (error) {
+ dev_err(dev, "failed to read keycodes: %d\n", error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static int cst816x_i2c_read_register(struct cst816x_priv *priv, u8 reg,
+ void *buf, size_t len)
+{
+ struct i2c_msg xfer[] = {
+ {
+ .addr = priv->client->addr,
+ .flags = 0,
+ .buf = &reg,
+ .len = sizeof(reg),
+ },
+ {
+ .addr = priv->client->addr,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ .len = len,
+ },
+ };
+ int error;
+ int ret;
+
+ ret = i2c_transfer(priv->client->adapter, xfer, ARRAY_SIZE(xfer));
+ if (ret != ARRAY_SIZE(xfer)) {
+ error = ret < 0 ? ret : -EIO;
+ dev_err(&priv->client->dev, "i2c rx err: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static u8 cst816x_gest_idx(u8 gest)
+{
+ u8 index;
+
+ switch (gest) {
+ case 0x01: /* Slide up gesture */
+ case 0x02: /* Slide down gesture */
+ case 0x03: /* Slide left gesture */
+ case 0x04: /* Slide right gesture */
+ index = gest;
+ break;
+ case 0x0c: /* Long press gesture */
+ default:
+ index = CST816X_NUM_KEYS;
+ break;
+ }
+
+ return index - 1;
+}
+
+static bool cst816x_process_touch(struct cst816x_priv *priv,
+ struct cst816x_touch *tch)
+{
+ if (cst816x_i2c_read_register(priv, CST816X_RD_REG, tch, sizeof(*tch)))
+ return false;
+
+ tch->abs_x = get_unaligned_be16(&tch->abs_x) & GENMASK(11, 0);
+ tch->abs_y = get_unaligned_be16(&tch->abs_y) & GENMASK(11, 0);
+
+ dev_dbg(&priv->client->dev, "x: %u, y: %u, t: %u, g: 0x%x\n",
+ tch->abs_x, tch->abs_y, tch->active, tch->gest);
+
+ return true;
+}
+
+static int cst816x_register_input(struct cst816x_priv *priv)
+{
+ priv->input = devm_input_allocate_device(&priv->client->dev);
+ if (!priv->input)
+ return -ENOMEM;
+
+ priv->input->name = "Hynitron CST816x Series Touchscreen";
+ priv->input->phys = "input/ts";
+ priv->input->id.bustype = BUS_I2C;
+
+ input_set_drvdata(priv->input, priv);
+
+ input_set_abs_params(priv->input, ABS_X, 0, 240, 0, 0);
+ input_set_abs_params(priv->input, ABS_Y, 0, 240, 0, 0);
+ input_set_capability(priv->input, EV_KEY, BTN_TOUCH);
+
+ priv->input->keycode = priv->keycode;
+ priv->input->keycodesize = sizeof(priv->keycode[0]);
+ priv->input->keycodemax = priv->keycodemax;
+
+ for (int i = 0; i < priv->keycodemax; i++) {
+ if (priv->keycode[i] == KEY_RESERVED)
+ continue;
+
+ input_set_capability(priv->input, EV_KEY, priv->keycode[i]);
+ }
+
+ return input_register_device(priv->input);
+}
+
+static void cst816x_reset(struct cst816x_priv *priv)
+{
+ gpiod_set_value_cansleep(priv->reset, 1);
+ msleep(50);
+ gpiod_set_value_cansleep(priv->reset, 0);
+ msleep(100);
+}
+
+static irqreturn_t cst816x_irq_cb(int irq, void *cookie)
+{
+ struct cst816x_priv *priv = cookie;
+ struct cst816x_touch tch;
+
+ if (!cst816x_process_touch(priv, &tch))
+ return IRQ_HANDLED;
+
+ input_report_abs(priv->input, ABS_X, tch.abs_x);
+ input_report_abs(priv->input, ABS_Y, tch.abs_y);
+
+ if (tch.gest)
+ input_report_key(priv->input,
+ priv->keycode[cst816x_gest_idx(tch.gest)],
+ tch.active);
+
+ input_report_key(priv->input, BTN_TOUCH, tch.active);
+
+ input_sync(priv->input);
+
+ return IRQ_HANDLED;
+}
+
+static int cst816x_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct cst816x_priv *priv;
+ int error;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ priv->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset))
+ return dev_err_probe(dev, PTR_ERR(priv->reset),
+ "gpio reset request failed\n");
+
+ if (priv->reset)
+ cst816x_reset(priv);
+
+ error = cst816x_parse_keycodes(dev, priv);
+ if (error)
+ dev_warn(dev, "no gestures found in dt\n");
+
+ error = cst816x_register_input(priv);
+ if (error)
+ return dev_err_probe(dev, error, "input register failed\n");
+
+ error = devm_request_threaded_irq(dev, client->irq,
+ NULL, cst816x_irq_cb, IRQF_ONESHOT,
+ dev_driver_string(dev), priv);
+ if (error)
+ return dev_err_probe(dev, error, "irq request failed\n");
+
+ return 0;
+}
+
+static const struct i2c_device_id cst816x_id[] = {
+ { .name = "cst816s", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cst816x_id);
+
+static const struct of_device_id cst816x_of_match[] = {
+ { .compatible = "hynitron,cst816s", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cst816x_of_match);
+
+static struct i2c_driver cst816x_driver = {
+ .driver = {
+ .name = "cst816x",
+ .of_match_table = cst816x_of_match,
+ },
+ .id_table = cst816x_id,
+ .probe = cst816x_probe,
+};
+
+module_i2c_driver(cst816x_driver);
+
+MODULE_AUTHOR("Oleh Kuzhylnyi <kuzhylol@gmail.com>");
+MODULE_DESCRIPTION("Hynitron CST816x Series Touchscreen Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/hynitron_cstxxx.c b/drivers/input/touchscreen/hynitron_cstxxx.c
index 05946fee4fd4..1d8ca90dcda6 100644
--- a/drivers/input/touchscreen/hynitron_cstxxx.c
+++ b/drivers/input/touchscreen/hynitron_cstxxx.c
@@ -22,7 +22,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/property.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Per chip data */
struct hynitron_ts_chip_data {
@@ -470,7 +470,7 @@ static const struct hynitron_ts_chip_data cst3xx_data = {
};
static const struct i2c_device_id hyn_tpd_id[] = {
- { .name = "hynitron_ts", 0 },
+ { .name = "hynitron_ts" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(i2c, hyn_tpd_id);
diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c
index 79bdb2b10949..fa38d70aded7 100644
--- a/drivers/input/touchscreen/ili210x.c
+++ b/drivers/input/touchscreen/ili210x.c
@@ -12,7 +12,7 @@
#include <linux/module.h>
#include <linux/sizes.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define ILI2XXX_POLL_PERIOD 15
@@ -582,14 +582,12 @@ static ssize_t ili210x_calibrate(struct device *dev,
}
static DEVICE_ATTR(calibrate, S_IWUSR, NULL, ili210x_calibrate);
-static int ili251x_firmware_to_buffer(const struct firmware *fw,
- u8 **buf, u16 *ac_end, u16 *df_end)
+static const u8 *ili251x_firmware_to_buffer(const struct firmware *fw,
+ u16 *ac_end, u16 *df_end)
{
const struct ihex_binrec *rec;
u32 fw_addr, fw_last_addr = 0;
u16 fw_len;
- u8 *fw_buf;
- int error;
/*
* The firmware ihex blob can never be bigger than 64 kiB, so make this
@@ -597,9 +595,9 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
* once, copy them all into this buffer at the right locations, and then
* do all operations on this linear buffer.
*/
- fw_buf = kzalloc(SZ_64K, GFP_KERNEL);
+ u8* fw_buf __free(kvfree) = kvmalloc(SZ_64K, GFP_KERNEL);
if (!fw_buf)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
rec = (const struct ihex_binrec *)fw->data;
while (rec) {
@@ -607,10 +605,8 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
fw_len = be16_to_cpu(rec->len);
/* The last 32 Byte firmware block can be 0xffe0 */
- if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32) {
- error = -EFBIG;
- goto err_big;
- }
+ if (fw_addr + fw_len > SZ_64K || fw_addr > SZ_64K - 32)
+ return ERR_PTR(-EFBIG);
/* Find the last address before DF start address, that is AC end */
if (fw_addr == 0xf000)
@@ -623,12 +619,8 @@ static int ili251x_firmware_to_buffer(const struct firmware *fw,
/* DF end address is the last address in the firmware blob */
*df_end = fw_addr + fw_len;
- *buf = fw_buf;
- return 0;
-err_big:
- kfree(fw_buf);
- return error;
+ return_ptr(fw_buf);
}
/* Switch mode between Application and BootLoader */
@@ -691,7 +683,7 @@ static int ili251x_firmware_busy(struct i2c_client *client)
return 0;
}
-static int ili251x_firmware_write_to_ic(struct device *dev, u8 *fwbuf,
+static int ili251x_firmware_write_to_ic(struct device *dev, const u8 *fwbuf,
u16 start, u16 end, u8 dataflash)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -776,47 +768,17 @@ static void ili210x_hardware_reset(struct gpio_desc *reset_gpio)
msleep(300);
}
-static ssize_t ili210x_firmware_update_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static int ili210x_do_firmware_update(struct ili210x *priv,
+ const u8 *fwbuf, u16 ac_end, u16 df_end)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct ili210x *priv = i2c_get_clientdata(client);
- const char *fwname = ILI251X_FW_FILENAME;
- const struct firmware *fw;
- u16 ac_end, df_end;
- u8 *fwbuf;
+ struct i2c_client *client = priv->client;
+ struct device *dev = &client->dev;
int error;
int i;
- error = request_ihex_firmware(&fw, fwname, dev);
- if (error) {
- dev_err(dev, "Failed to request firmware %s, error=%d\n",
- fwname, error);
- return error;
- }
-
- error = ili251x_firmware_to_buffer(fw, &fwbuf, &ac_end, &df_end);
- release_firmware(fw);
- if (error)
- return error;
-
- /*
- * Disable touchscreen IRQ, so that we would not get spurious touch
- * interrupt during firmware update, and so that the IRQ handler won't
- * trigger and interfere with the firmware update. There is no bit in
- * the touch controller to disable the IRQs during update, so we have
- * to do it this way here.
- */
- disable_irq(client->irq);
-
- dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
-
- ili210x_hardware_reset(priv->reset_gpio);
-
error = ili251x_firmware_reset(client);
if (error)
- goto exit;
+ return error;
/* This may not succeed on first try, so re-try a few times. */
for (i = 0; i < 5; i++) {
@@ -826,7 +788,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
}
if (error)
- goto exit;
+ return error;
dev_dbg(dev, "IC is now in BootLoader mode\n");
@@ -835,7 +797,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0xf000, df_end, 1);
if (error) {
dev_err(dev, "DF firmware update failed, error=%d\n", error);
- goto exit;
+ return error;
}
dev_dbg(dev, "DataFlash firmware written\n");
@@ -843,7 +805,7 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
error = ili251x_firmware_write_to_ic(dev, fwbuf, 0x2000, ac_end, 0);
if (error) {
dev_err(dev, "AC firmware update failed, error=%d\n", error);
- goto exit;
+ return error;
}
dev_dbg(dev, "Application firmware written\n");
@@ -856,22 +818,61 @@ static ssize_t ili210x_firmware_update_store(struct device *dev,
}
if (error)
- goto exit;
+ return error;
dev_dbg(dev, "IC is now in Application mode\n");
error = ili251x_firmware_update_cached_state(dev);
if (error)
- goto exit;
+ return error;
- error = count;
+ return 0;
+}
-exit:
- ili210x_hardware_reset(priv->reset_gpio);
- dev_dbg(dev, "Firmware update ended, error=%i\n", error);
- enable_irq(client->irq);
- kfree(fwbuf);
- return error;
+static ssize_t ili210x_firmware_update_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ili210x *priv = i2c_get_clientdata(client);
+ const char *fwname = ILI251X_FW_FILENAME;
+ u16 ac_end, df_end;
+ int error;
+
+ const struct firmware *fw __free(firmware) = NULL;
+ error = request_ihex_firmware(&fw, fwname, dev);
+ if (error) {
+ dev_err(dev, "Failed to request firmware %s, error=%d\n",
+ fwname, error);
+ return error;
+ }
+
+ const u8* fwbuf __free(kvfree) =
+ ili251x_firmware_to_buffer(fw, &ac_end, &df_end);
+ error = PTR_ERR_OR_ZERO(fwbuf);
+ if (error)
+ return error;
+
+ /*
+ * Disable touchscreen IRQ, so that we would not get spurious touch
+ * interrupt during firmware update, and so that the IRQ handler won't
+ * trigger and interfere with the firmware update. There is no bit in
+ * the touch controller to disable the IRQs during update, so we have
+ * to do it this way here.
+ */
+ scoped_guard(disable_irq, &client->irq) {
+ dev_dbg(dev, "Firmware update started, firmware=%s\n", fwname);
+
+ ili210x_hardware_reset(priv->reset_gpio);
+
+ error = ili210x_do_firmware_update(priv, fwbuf, ac_end, df_end);
+
+ ili210x_hardware_reset(priv->reset_gpio);
+
+ dev_dbg(dev, "Firmware update ended, error=%i\n", error);
+ }
+
+ return error ?: count;
}
static DEVICE_ATTR(firmware_update, 0200, NULL, ili210x_firmware_update_store);
@@ -897,7 +898,7 @@ static umode_t ili210x_attributes_visible(struct kobject *kobj,
if (attr == &dev_attr_calibrate.attr)
return priv->chip->has_calibrate_reg ? attr->mode : 0;
- /* Firmware/Kernel/Protocol/BootMode is implememted only for ILI251x */
+ /* Firmware/Kernel/Protocol/BootMode is implemented only for ILI251x */
if (!priv->chip->has_firmware_proto)
return 0;
diff --git a/drivers/input/touchscreen/ilitek_ts_i2c.c b/drivers/input/touchscreen/ilitek_ts_i2c.c
index 3eb762896345..0dd632724a00 100644
--- a/drivers/input/touchscreen/ilitek_ts_i2c.c
+++ b/drivers/input/touchscreen/ilitek_ts_i2c.c
@@ -15,12 +15,11 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/input/touchscreen.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define ILITEK_TS_NAME "ilitek_ts"
@@ -37,6 +36,8 @@
#define ILITEK_TP_CMD_GET_MCU_VER 0x61
#define ILITEK_TP_CMD_GET_IC_MODE 0xC0
+#define ILITEK_TP_I2C_REPORT_ID 0x48
+
#define REPORT_COUNT_ADDRESS 61
#define ILITEK_SUPPORT_MAX_POINT 40
@@ -160,15 +161,19 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
error = ilitek_i2c_write_and_read(ts, NULL, 0, 0, buf, 64);
if (error) {
dev_err(dev, "get touch info failed, err:%d\n", error);
- goto err_sync_frame;
+ return error;
+ }
+
+ if (buf[0] != ILITEK_TP_I2C_REPORT_ID) {
+ dev_err(dev, "get touch info failed. Wrong id: 0x%02X\n", buf[0]);
+ return -EINVAL;
}
report_max_point = buf[REPORT_COUNT_ADDRESS];
if (report_max_point > ts->max_tp) {
dev_err(dev, "FW report max point:%d > panel info. max:%d\n",
report_max_point, ts->max_tp);
- error = -EINVAL;
- goto err_sync_frame;
+ return -EINVAL;
}
count = DIV_ROUND_UP(report_max_point, packet_max_point);
@@ -178,7 +183,7 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
if (error) {
dev_err(dev, "get touch info. failed, cnt:%d, err:%d\n",
count, error);
- goto err_sync_frame;
+ return error;
}
}
@@ -203,10 +208,10 @@ static int ilitek_process_and_report_v6(struct ilitek_ts_data *ts)
ilitek_touch_down(ts, id, x, y);
}
-err_sync_frame:
input_mt_sync_frame(input);
input_sync(input);
- return error;
+
+ return 0;
}
/* APIs of cmds for ILITEK Touch IC */
diff --git a/drivers/input/touchscreen/imagis.c b/drivers/input/touchscreen/imagis.c
index 074dd6c342ec..3c8bbe284b73 100644
--- a/drivers/input/touchscreen/imagis.c
+++ b/drivers/input/touchscreen/imagis.c
@@ -12,9 +12,18 @@
#include <linux/property.h>
#include <linux/regulator/consumer.h>
+#define IST30XX_REG_STATUS 0x20
+#define IST30XX_REG_CHIPID (0x40000000 | IST3038C_DIRECT_ACCESS)
+
+#define IST30XX_WHOAMI 0x30003000
+#define IST30XXA_WHOAMI 0x300a300a
+#define IST30XXB_WHOAMI 0x300b300b
+#define IST3038_WHOAMI 0x30383038
+
#define IST3032C_WHOAMI 0x32c
+#define IST3038C_WHOAMI 0x38c
+#define IST3038H_WHOAMI 0x38d
-#define IST3038B_REG_STATUS 0x20
#define IST3038B_REG_CHIPID 0x30
#define IST3038B_WHOAMI 0x30380b
@@ -25,7 +34,6 @@
#define IST3038C_REG_TOUCH_STATUS (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS)
#define IST3038C_REG_TOUCH_COORD (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x8)
#define IST3038C_REG_INTR_MESSAGE (IST3038C_REG_HIB_BASE | IST3038C_HIB_ACCESS | 0x4)
-#define IST3038C_WHOAMI 0x38c
#define IST3038C_CHIP_ON_DELAY_MS 60
#define IST3038C_I2C_RETRY_COUNT 3
#define IST3038C_MAX_FINGER_NUM 10
@@ -121,11 +129,11 @@ static irqreturn_t imagis_interrupt(int irq, void *dev_id)
for (i = 0; i < finger_count; i++) {
if (ts->tdata->protocol_b)
error = imagis_i2c_read_reg(ts,
- ts->tdata->touch_coord_cmd, &finger_status);
- else
- error = imagis_i2c_read_reg(ts,
ts->tdata->touch_coord_cmd + (i * 4),
&finger_status);
+ else
+ error = imagis_i2c_read_reg(ts,
+ ts->tdata->touch_coord_cmd, &finger_status);
if (error) {
dev_err(&ts->client->dev,
"failed to read coordinates for finger %d: %d\n",
@@ -388,20 +396,29 @@ static int imagis_resume(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(imagis_pm_ops, imagis_suspend, imagis_resume);
+#ifdef CONFIG_OF
static const struct imagis_properties imagis_3032c_data = {
.interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
.touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
.whoami_cmd = IST3038C_REG_CHIPID,
.whoami_val = IST3032C_WHOAMI,
.touch_keys_supported = true,
+ .protocol_b = true,
+};
+
+static const struct imagis_properties imagis_3038_data = {
+ .interrupt_msg_cmd = IST30XX_REG_STATUS,
+ .touch_coord_cmd = IST30XX_REG_STATUS,
+ .whoami_cmd = IST30XX_REG_CHIPID,
+ .whoami_val = IST3038_WHOAMI,
+ .touch_keys_supported = true,
};
static const struct imagis_properties imagis_3038b_data = {
- .interrupt_msg_cmd = IST3038B_REG_STATUS,
- .touch_coord_cmd = IST3038B_REG_STATUS,
+ .interrupt_msg_cmd = IST30XX_REG_STATUS,
+ .touch_coord_cmd = IST30XX_REG_STATUS,
.whoami_cmd = IST3038B_REG_CHIPID,
.whoami_val = IST3038B_WHOAMI,
- .protocol_b = true,
};
static const struct imagis_properties imagis_3038c_data = {
@@ -409,13 +426,22 @@ static const struct imagis_properties imagis_3038c_data = {
.touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
.whoami_cmd = IST3038C_REG_CHIPID,
.whoami_val = IST3038C_WHOAMI,
+ .protocol_b = true,
+};
+
+static const struct imagis_properties imagis_3038h_data = {
+ .interrupt_msg_cmd = IST3038C_REG_INTR_MESSAGE,
+ .touch_coord_cmd = IST3038C_REG_TOUCH_COORD,
+ .whoami_cmd = IST3038C_REG_CHIPID,
+ .whoami_val = IST3038H_WHOAMI,
};
-#ifdef CONFIG_OF
static const struct of_device_id imagis_of_match[] = {
{ .compatible = "imagis,ist3032c", .data = &imagis_3032c_data },
+ { .compatible = "imagis,ist3038", .data = &imagis_3038_data },
{ .compatible = "imagis,ist3038b", .data = &imagis_3038b_data },
{ .compatible = "imagis,ist3038c", .data = &imagis_3038c_data },
+ { .compatible = "imagis,ist3038h", .data = &imagis_3038h_data },
{ },
};
MODULE_DEVICE_TABLE(of, imagis_of_match);
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index 6ac8fa84ed9f..85f697de2b7e 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -7,6 +7,7 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/bitfield.h>
#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/slab.h>
@@ -20,25 +21,23 @@
#include <linux/log2.h>
/* ADC configuration registers field define */
-#define ADC_AIEN (0x1 << 7)
+#define ADC_AIEN BIT(7)
+#define ADC_ADCH_MASK GENMASK(4, 0)
#define ADC_CONV_DISABLE 0x1F
-#define ADC_AVGE (0x1 << 5)
-#define ADC_CAL (0x1 << 7)
-#define ADC_CALF 0x2
-#define ADC_12BIT_MODE (0x2 << 2)
-#define ADC_CONV_MODE_MASK (0x3 << 2)
+#define ADC_AVGE BIT(5)
+#define ADC_CAL BIT(7)
+#define ADC_CALF BIT(1)
+#define ADC_CONV_MODE_MASK GENMASK(3, 2)
+#define ADC_12BIT_MODE 0x2
#define ADC_IPG_CLK 0x00
-#define ADC_INPUT_CLK_MASK 0x3
-#define ADC_CLK_DIV_8 (0x03 << 5)
-#define ADC_CLK_DIV_MASK (0x3 << 5)
-#define ADC_SHORT_SAMPLE_MODE (0x0 << 4)
-#define ADC_SAMPLE_MODE_MASK (0x1 << 4)
-#define ADC_HARDWARE_TRIGGER (0x1 << 13)
-#define ADC_AVGS_SHIFT 14
-#define ADC_AVGS_MASK (0x3 << 14)
+#define ADC_INPUT_CLK_MASK GENMASK(1, 0)
+#define ADC_CLK_DIV_8 0x03
+#define ADC_CLK_DIV_MASK GENMASK(6, 5)
+#define ADC_SAMPLE_MODE BIT(4)
+#define ADC_HARDWARE_TRIGGER BIT(13)
+#define ADC_AVGS_MASK GENMASK(15, 14)
#define SELECT_CHANNEL_4 0x04
#define SELECT_CHANNEL_1 0x01
-#define DISABLE_CONVERSION_INT (0x0 << 7)
/* ADC registers */
#define REG_ADC_HC0 0x00
@@ -55,7 +54,7 @@
#define ADC_TIMEOUT msecs_to_jiffies(100)
/* TSC registers */
-#define REG_TSC_BASIC_SETING 0x00
+#define REG_TSC_BASIC_SETTING 0x00
#define REG_TSC_PRE_CHARGE_TIME 0x10
#define REG_TSC_FLOW_CONTROL 0x20
#define REG_TSC_MEASURE_VALUE 0x30
@@ -65,19 +64,26 @@
#define REG_TSC_DEBUG_MODE 0x70
#define REG_TSC_DEBUG_MODE2 0x80
+/* TSC_MEASURE_VALUE register field define */
+#define X_VALUE_MASK GENMASK(27, 16)
+#define Y_VALUE_MASK GENMASK(11, 0)
+
/* TSC configuration registers field define */
-#define DETECT_4_WIRE_MODE (0x0 << 4)
-#define AUTO_MEASURE 0x1
-#define MEASURE_SIGNAL 0x1
-#define DETECT_SIGNAL (0x1 << 4)
-#define VALID_SIGNAL (0x1 << 8)
-#define MEASURE_INT_EN 0x1
-#define MEASURE_SIG_EN 0x1
-#define VALID_SIG_EN (0x1 << 8)
-#define DE_GLITCH_2 (0x2 << 29)
-#define START_SENSE (0x1 << 12)
-#define TSC_DISABLE (0x1 << 16)
+#define MEASURE_DELAY_TIME_MASK GENMASK(31, 8)
+#define DETECT_5_WIRE_MODE BIT(4)
+#define AUTO_MEASURE BIT(0)
+#define MEASURE_SIGNAL BIT(0)
+#define DETECT_SIGNAL BIT(4)
+#define VALID_SIGNAL BIT(8)
+#define MEASURE_INT_EN BIT(0)
+#define MEASURE_SIG_EN BIT(0)
+#define VALID_SIG_EN BIT(8)
+#define DE_GLITCH_MASK GENMASK(30, 29)
+#define DE_GLITCH_DEF 0x02
+#define START_SENSE BIT(12)
+#define TSC_DISABLE BIT(16)
#define DETECT_MODE 0x2
+#define STATE_MACHINE_MASK GENMASK(22, 20)
struct imx6ul_tsc {
struct device *dev;
@@ -92,6 +98,7 @@ struct imx6ul_tsc {
u32 pre_charge_time;
bool average_enable;
u32 average_select;
+ u32 de_glitch;
struct completion completion;
};
@@ -112,19 +119,20 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG);
adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK);
- adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
- adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
- adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
+ adc_cfg |= FIELD_PREP(ADC_CONV_MODE_MASK, ADC_12BIT_MODE) |
+ FIELD_PREP(ADC_INPUT_CLK_MASK, ADC_IPG_CLK);
+ adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE);
+ adc_cfg |= FIELD_PREP(ADC_CLK_DIV_MASK, ADC_CLK_DIV_8);
if (tsc->average_enable) {
adc_cfg &= ~ADC_AVGS_MASK;
- adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
+ adc_cfg |= FIELD_PREP(ADC_AVGS_MASK, tsc->average_select);
}
adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
/* enable calibration interrupt */
adc_hc |= ADC_AIEN;
- adc_hc |= ADC_CONV_DISABLE;
+ adc_hc |= FIELD_PREP(ADC_ADCH_MASK, ADC_CONV_DISABLE);
writel(adc_hc, tsc->adc_regs + REG_ADC_HC0);
/* start ADC calibration */
@@ -164,19 +172,21 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
{
u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4;
- adc_hc0 = DISABLE_CONVERSION_INT;
+ adc_hc0 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0);
- adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4;
+ adc_hc1 = FIELD_PREP(ADC_AIEN, 0) |
+ FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_4);
writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1);
- adc_hc2 = DISABLE_CONVERSION_INT;
+ adc_hc2 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2);
- adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1;
+ adc_hc3 = FIELD_PREP(ADC_AIEN, 0) |
+ FIELD_PREP(ADC_ADCH_MASK, SELECT_CHANNEL_1);
writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3);
- adc_hc4 = DISABLE_CONVERSION_INT;
+ adc_hc4 = FIELD_PREP(ADC_AIEN, 0);
writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4);
}
@@ -188,13 +198,16 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc)
static void imx6ul_tsc_set(struct imx6ul_tsc *tsc)
{
u32 basic_setting = 0;
+ u32 debug_mode2;
u32 start;
- basic_setting |= tsc->measure_delay_time << 8;
- basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE;
- writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING);
+ basic_setting |= FIELD_PREP(MEASURE_DELAY_TIME_MASK,
+ tsc->measure_delay_time);
+ basic_setting |= AUTO_MEASURE;
+ writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETTING);
- writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
+ debug_mode2 = FIELD_PREP(DE_GLITCH_MASK, tsc->de_glitch);
+ writel(debug_mode2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME);
writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN);
@@ -250,7 +263,7 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc)
usleep_range(200, 400);
debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2);
- state_machine = (debug_mode2 >> 20) & 0x7;
+ state_machine = FIELD_GET(STATE_MACHINE_MASK, debug_mode2);
} while (state_machine != DETECT_MODE);
usleep_range(200, 400);
@@ -278,8 +291,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id)
if (status & MEASURE_SIGNAL) {
value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE);
- x = (value >> 16) & 0x0fff;
- y = value & 0x0fff;
+ x = FIELD_GET(X_VALUE_MASK, value);
+ y = FIELD_GET(Y_VALUE_MASK, value);
/*
* In detect mode, we can get the xnur gpio value,
@@ -379,6 +392,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int tsc_irq;
int adc_irq;
u32 average_samples;
+ u32 de_glitch;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc)
@@ -501,6 +515,25 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
return -EINVAL;
}
+ err = of_property_read_u32(np, "debounce-delay-us", &de_glitch);
+ if (err) {
+ tsc->de_glitch = DE_GLITCH_DEF;
+ } else {
+ u64 cycles;
+ unsigned long rate = clk_get_rate(tsc->tsc_clk);
+
+ cycles = DIV64_U64_ROUND_UP((u64)de_glitch * rate, USEC_PER_SEC);
+
+ if (cycles <= 0x3ff)
+ tsc->de_glitch = 3;
+ else if (cycles <= 0x7ff)
+ tsc->de_glitch = 2;
+ else if (cycles <= 0xfff)
+ tsc->de_glitch = 1;
+ else
+ tsc->de_glitch = 0;
+ }
+
err = input_register_device(tsc->input);
if (err) {
dev_err(&pdev->dev,
diff --git a/drivers/input/touchscreen/inexio.c b/drivers/input/touchscreen/inexio.c
index 1d7e4c3966ce..82f7ac62a4f2 100644
--- a/drivers/input/touchscreen/inexio.c
+++ b/drivers/input/touchscreen/inexio.c
@@ -114,7 +114,7 @@ static int inexio_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- pinexio = kzalloc(sizeof(struct inexio), GFP_KERNEL);
+ pinexio = kzalloc(sizeof(*pinexio), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pinexio || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/iqs5xx.c b/drivers/input/touchscreen/iqs5xx.c
index 4d226118f3cc..4ebd7565ae6e 100644
--- a/drivers/input/touchscreen/iqs5xx.c
+++ b/drivers/input/touchscreen/iqs5xx.c
@@ -26,7 +26,7 @@
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define IQS5XX_FW_FILE_LEN 64
#define IQS5XX_NUM_RETRIES 10
diff --git a/drivers/input/touchscreen/iqs7211.c b/drivers/input/touchscreen/iqs7211.c
index f0a56cde899e..c5d447ee6f53 100644
--- a/drivers/input/touchscreen/iqs7211.c
+++ b/drivers/input/touchscreen/iqs7211.c
@@ -22,7 +22,7 @@
#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define IQS7211_PROD_NUM 0x00
diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
index bfbebe245040..5abf164ae14c 100644
--- a/drivers/input/touchscreen/mainstone-wm97xx.c
+++ b/drivers/input/touchscreen/mainstone-wm97xx.c
@@ -261,7 +261,7 @@ static void mainstone_wm97xx_remove(struct platform_device *pdev)
static struct platform_driver mainstone_wm97xx_driver = {
.probe = mainstone_wm97xx_probe,
- .remove_new = mainstone_wm97xx_remove,
+ .remove = mainstone_wm97xx_remove,
.driver = {
.name = "wm97xx-touch",
},
diff --git a/drivers/input/touchscreen/mc13783_ts.c b/drivers/input/touchscreen/mc13783_ts.c
index cbcd6e34efb7..47b8da00027f 100644
--- a/drivers/input/touchscreen/mc13783_ts.c
+++ b/drivers/input/touchscreen/mc13783_ts.c
@@ -42,8 +42,6 @@ static irqreturn_t mc13783_ts_handler(int irq, void *data)
{
struct mc13783_ts_priv *priv = data;
- mc13xxx_irq_ack(priv->mc13xxx, irq);
-
/*
* Kick off reading coordinates. Note that if work happens already
* be queued for future execution (it rearms itself) it will not
@@ -137,8 +135,6 @@ static int mc13783_ts_open(struct input_dev *dev)
mc13xxx_lock(priv->mc13xxx);
- mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TS);
-
ret = mc13xxx_irq_request(priv->mc13xxx, MC13XXX_IRQ_TS,
mc13783_ts_handler, MC13783_TS_NAME, priv);
if (ret)
@@ -226,7 +222,7 @@ static void mc13783_ts_remove(struct platform_device *pdev)
}
static struct platform_driver mc13783_ts_driver = {
- .remove_new = mc13783_ts_remove,
+ .remove = mc13783_ts_remove,
.driver = {
.name = MC13783_TS_NAME,
},
diff --git a/drivers/input/touchscreen/mcs5000_ts.c b/drivers/input/touchscreen/mcs5000_ts.c
deleted file mode 100644
index 5aff8dcda0dc..000000000000
--- a/drivers/input/touchscreen/mcs5000_ts.c
+++ /dev/null
@@ -1,288 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * mcs5000_ts.c - Touchscreen driver for MELFAS MCS-5000 controller
- *
- * Copyright (C) 2009 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * Based on wm97xx-core.c
- */
-
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
-#include <linux/irq.h>
-#include <linux/platform_data/mcs.h>
-#include <linux/slab.h>
-
-/* Registers */
-#define MCS5000_TS_STATUS 0x00
-#define STATUS_OFFSET 0
-#define STATUS_NO (0 << STATUS_OFFSET)
-#define STATUS_INIT (1 << STATUS_OFFSET)
-#define STATUS_SENSING (2 << STATUS_OFFSET)
-#define STATUS_COORD (3 << STATUS_OFFSET)
-#define STATUS_GESTURE (4 << STATUS_OFFSET)
-#define ERROR_OFFSET 4
-#define ERROR_NO (0 << ERROR_OFFSET)
-#define ERROR_POWER_ON_RESET (1 << ERROR_OFFSET)
-#define ERROR_INT_RESET (2 << ERROR_OFFSET)
-#define ERROR_EXT_RESET (3 << ERROR_OFFSET)
-#define ERROR_INVALID_REG_ADDRESS (8 << ERROR_OFFSET)
-#define ERROR_INVALID_REG_VALUE (9 << ERROR_OFFSET)
-
-#define MCS5000_TS_OP_MODE 0x01
-#define RESET_OFFSET 0
-#define RESET_NO (0 << RESET_OFFSET)
-#define RESET_EXT_SOFT (1 << RESET_OFFSET)
-#define OP_MODE_OFFSET 1
-#define OP_MODE_SLEEP (0 << OP_MODE_OFFSET)
-#define OP_MODE_ACTIVE (1 << OP_MODE_OFFSET)
-#define GESTURE_OFFSET 4
-#define GESTURE_DISABLE (0 << GESTURE_OFFSET)
-#define GESTURE_ENABLE (1 << GESTURE_OFFSET)
-#define PROXIMITY_OFFSET 5
-#define PROXIMITY_DISABLE (0 << PROXIMITY_OFFSET)
-#define PROXIMITY_ENABLE (1 << PROXIMITY_OFFSET)
-#define SCAN_MODE_OFFSET 6
-#define SCAN_MODE_INTERRUPT (0 << SCAN_MODE_OFFSET)
-#define SCAN_MODE_POLLING (1 << SCAN_MODE_OFFSET)
-#define REPORT_RATE_OFFSET 7
-#define REPORT_RATE_40 (0 << REPORT_RATE_OFFSET)
-#define REPORT_RATE_80 (1 << REPORT_RATE_OFFSET)
-
-#define MCS5000_TS_SENS_CTL 0x02
-#define MCS5000_TS_FILTER_CTL 0x03
-#define PRI_FILTER_OFFSET 0
-#define SEC_FILTER_OFFSET 4
-
-#define MCS5000_TS_X_SIZE_UPPER 0x08
-#define MCS5000_TS_X_SIZE_LOWER 0x09
-#define MCS5000_TS_Y_SIZE_UPPER 0x0A
-#define MCS5000_TS_Y_SIZE_LOWER 0x0B
-
-#define MCS5000_TS_INPUT_INFO 0x10
-#define INPUT_TYPE_OFFSET 0
-#define INPUT_TYPE_NONTOUCH (0 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_SINGLE (1 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_DUAL (2 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_PALM (3 << INPUT_TYPE_OFFSET)
-#define INPUT_TYPE_PROXIMITY (7 << INPUT_TYPE_OFFSET)
-#define GESTURE_CODE_OFFSET 3
-#define GESTURE_CODE_NO (0 << GESTURE_CODE_OFFSET)
-
-#define MCS5000_TS_X_POS_UPPER 0x11
-#define MCS5000_TS_X_POS_LOWER 0x12
-#define MCS5000_TS_Y_POS_UPPER 0x13
-#define MCS5000_TS_Y_POS_LOWER 0x14
-#define MCS5000_TS_Z_POS 0x15
-#define MCS5000_TS_WIDTH 0x16
-#define MCS5000_TS_GESTURE_VAL 0x17
-#define MCS5000_TS_MODULE_REV 0x20
-#define MCS5000_TS_FIRMWARE_VER 0x21
-
-/* Touchscreen absolute values */
-#define MCS5000_MAX_XC 0x3ff
-#define MCS5000_MAX_YC 0x3ff
-
-enum mcs5000_ts_read_offset {
- READ_INPUT_INFO,
- READ_X_POS_UPPER,
- READ_X_POS_LOWER,
- READ_Y_POS_UPPER,
- READ_Y_POS_LOWER,
- READ_BLOCK_SIZE,
-};
-
-/* Each client has this additional data */
-struct mcs5000_ts_data {
- struct i2c_client *client;
- struct input_dev *input_dev;
- const struct mcs_platform_data *platform_data;
-};
-
-static irqreturn_t mcs5000_ts_interrupt(int irq, void *dev_id)
-{
- struct mcs5000_ts_data *data = dev_id;
- struct i2c_client *client = data->client;
- u8 buffer[READ_BLOCK_SIZE];
- int err;
- int x;
- int y;
-
- err = i2c_smbus_read_i2c_block_data(client, MCS5000_TS_INPUT_INFO,
- READ_BLOCK_SIZE, buffer);
- if (err < 0) {
- dev_err(&client->dev, "%s, err[%d]\n", __func__, err);
- goto out;
- }
-
- switch (buffer[READ_INPUT_INFO]) {
- case INPUT_TYPE_NONTOUCH:
- input_report_key(data->input_dev, BTN_TOUCH, 0);
- input_sync(data->input_dev);
- break;
-
- case INPUT_TYPE_SINGLE:
- x = (buffer[READ_X_POS_UPPER] << 8) | buffer[READ_X_POS_LOWER];
- y = (buffer[READ_Y_POS_UPPER] << 8) | buffer[READ_Y_POS_LOWER];
-
- input_report_key(data->input_dev, BTN_TOUCH, 1);
- input_report_abs(data->input_dev, ABS_X, x);
- input_report_abs(data->input_dev, ABS_Y, y);
- input_sync(data->input_dev);
- break;
-
- case INPUT_TYPE_DUAL:
- /* TODO */
- break;
-
- case INPUT_TYPE_PALM:
- /* TODO */
- break;
-
- case INPUT_TYPE_PROXIMITY:
- /* TODO */
- break;
-
- default:
- dev_err(&client->dev, "Unknown ts input type %d\n",
- buffer[READ_INPUT_INFO]);
- break;
- }
-
- out:
- return IRQ_HANDLED;
-}
-
-static void mcs5000_ts_phys_init(struct mcs5000_ts_data *data,
- const struct mcs_platform_data *platform_data)
-{
- struct i2c_client *client = data->client;
-
- /* Touch reset & sleep mode */
- i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE,
- RESET_EXT_SOFT | OP_MODE_SLEEP);
-
- /* Touch size */
- i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_UPPER,
- platform_data->x_size >> 8);
- i2c_smbus_write_byte_data(client, MCS5000_TS_X_SIZE_LOWER,
- platform_data->x_size & 0xff);
- i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_UPPER,
- platform_data->y_size >> 8);
- i2c_smbus_write_byte_data(client, MCS5000_TS_Y_SIZE_LOWER,
- platform_data->y_size & 0xff);
-
- /* Touch active mode & 80 report rate */
- i2c_smbus_write_byte_data(data->client, MCS5000_TS_OP_MODE,
- OP_MODE_ACTIVE | REPORT_RATE_80);
-}
-
-static int mcs5000_ts_probe(struct i2c_client *client)
-{
- const struct mcs_platform_data *pdata;
- struct mcs5000_ts_data *data;
- struct input_dev *input_dev;
- int error;
-
- pdata = dev_get_platdata(&client->dev);
- if (!pdata)
- return -EINVAL;
-
- data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
- if (!data) {
- dev_err(&client->dev, "Failed to allocate memory\n");
- return -ENOMEM;
- }
-
- data->client = client;
-
- input_dev = devm_input_allocate_device(&client->dev);
- if (!input_dev) {
- dev_err(&client->dev, "Failed to allocate input device\n");
- return -ENOMEM;
- }
-
- input_dev->name = "MELFAS MCS-5000 Touchscreen";
- input_dev->id.bustype = BUS_I2C;
- input_dev->dev.parent = &client->dev;
-
- __set_bit(EV_ABS, input_dev->evbit);
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(BTN_TOUCH, input_dev->keybit);
- input_set_abs_params(input_dev, ABS_X, 0, MCS5000_MAX_XC, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, MCS5000_MAX_YC, 0, 0);
-
- data->input_dev = input_dev;
-
- if (pdata->cfg_pin)
- pdata->cfg_pin();
-
- error = devm_request_threaded_irq(&client->dev, client->irq,
- NULL, mcs5000_ts_interrupt,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "mcs5000_ts", data);
- if (error) {
- dev_err(&client->dev, "Failed to register interrupt\n");
- return error;
- }
-
- error = input_register_device(data->input_dev);
- if (error) {
- dev_err(&client->dev, "Failed to register input device\n");
- return error;
- }
-
- mcs5000_ts_phys_init(data, pdata);
- i2c_set_clientdata(client, data);
-
- return 0;
-}
-
-static int mcs5000_ts_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
-
- /* Touch sleep mode */
- i2c_smbus_write_byte_data(client, MCS5000_TS_OP_MODE, OP_MODE_SLEEP);
-
- return 0;
-}
-
-static int mcs5000_ts_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct mcs5000_ts_data *data = i2c_get_clientdata(client);
- const struct mcs_platform_data *pdata = dev_get_platdata(dev);
-
- mcs5000_ts_phys_init(data, pdata);
-
- return 0;
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(mcs5000_ts_pm,
- mcs5000_ts_suspend, mcs5000_ts_resume);
-
-static const struct i2c_device_id mcs5000_ts_id[] = {
- { "mcs5000_ts" },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, mcs5000_ts_id);
-
-static struct i2c_driver mcs5000_ts_driver = {
- .probe = mcs5000_ts_probe,
- .driver = {
- .name = "mcs5000_ts",
- .pm = pm_sleep_ptr(&mcs5000_ts_pm),
- },
- .id_table = mcs5000_ts_id,
-};
-
-module_i2c_driver(mcs5000_ts_driver);
-
-/* Module information */
-MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
-MODULE_DESCRIPTION("Touchscreen driver for MELFAS MCS-5000 controller");
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c
index b99a0e3c4084..869884219908 100644
--- a/drivers/input/touchscreen/melfas_mip4.c
+++ b/drivers/input/touchscreen/melfas_mip4.c
@@ -18,7 +18,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define MIP4_DEVICE_NAME "mip4_ts"
@@ -1554,7 +1554,7 @@ static DEFINE_SIMPLE_DEV_PM_OPS(mip4_pm_ops, mip4_suspend, mip4_resume);
#ifdef CONFIG_OF
static const struct of_device_id mip4_of_match[] = {
- { .compatible = "melfas,"MIP4_DEVICE_NAME, },
+ { .compatible = "melfas,mip4_ts", },
{ },
};
MODULE_DEVICE_TABLE(of, mip4_of_match);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 28e449eea318..eefae96a2d40 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -128,7 +128,7 @@ static int mtouch_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- mtouch = kzalloc(sizeof(struct mtouch), GFP_KERNEL);
+ mtouch = kzalloc(sizeof(*mtouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!mtouch || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/novatek-nvt-ts.c b/drivers/input/touchscreen/novatek-nvt-ts.c
index 1a797e410a3f..44b58e0dc1ad 100644
--- a/drivers/input/touchscreen/novatek-nvt-ts.c
+++ b/drivers/input/touchscreen/novatek-nvt-ts.c
@@ -15,7 +15,7 @@
#include <linux/input/touchscreen.h>
#include <linux/module.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define NVT_TS_TOUCH_START 0x00
#define NVT_TS_TOUCH_SIZE 6
@@ -31,9 +31,6 @@
#define NVT_TS_PARAMS_CHIP_ID 0x0e
#define NVT_TS_PARAMS_SIZE 0x0f
-#define NVT_TS_SUPPORTED_WAKE_TYPE 0x05
-#define NVT_TS_SUPPORTED_CHIP_ID 0x05
-
#define NVT_TS_MAX_TOUCHES 10
#define NVT_TS_MAX_SIZE 4096
@@ -51,10 +48,16 @@ static const int nvt_ts_irq_type[4] = {
IRQF_TRIGGER_HIGH
};
+struct nvt_ts_i2c_chip_data {
+ u8 wake_type;
+ u8 chip_id;
+};
+
struct nvt_ts_data {
struct i2c_client *client;
struct input_dev *input;
struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data regulators[2];
struct touchscreen_properties prop;
int max_touches;
u8 buf[NVT_TS_TOUCH_SIZE * NVT_TS_MAX_TOUCHES];
@@ -142,6 +145,13 @@ static irqreturn_t nvt_ts_irq(int irq, void *dev_id)
static int nvt_ts_start(struct input_dev *dev)
{
struct nvt_ts_data *data = input_get_drvdata(dev);
+ int error;
+
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), data->regulators);
+ if (error) {
+ dev_err(&data->client->dev, "failed to enable regulators\n");
+ return error;
+ }
enable_irq(data->client->irq);
gpiod_set_value_cansleep(data->reset_gpio, 0);
@@ -155,6 +165,7 @@ static void nvt_ts_stop(struct input_dev *dev)
disable_irq(data->client->irq);
gpiod_set_value_cansleep(data->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
}
static int nvt_ts_suspend(struct device *dev)
@@ -188,6 +199,7 @@ static int nvt_ts_probe(struct i2c_client *client)
struct device *dev = &client->dev;
int error, width, height, irq_type;
struct nvt_ts_data *data;
+ const struct nvt_ts_i2c_chip_data *chip;
struct input_dev *input;
if (!client->irq) {
@@ -199,12 +211,35 @@ static int nvt_ts_probe(struct i2c_client *client)
if (!data)
return -ENOMEM;
+ chip = device_get_match_data(&client->dev);
+ if (!chip)
+ return -EINVAL;
+
data->client = client;
i2c_set_clientdata(client, data);
+ /*
+ * VCC is the analog voltage supply
+ * IOVCC is the digital voltage supply
+ */
+ data->regulators[0].supply = "vcc";
+ data->regulators[1].supply = "iovcc";
+ error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators), data->regulators);
+ if (error) {
+ dev_err(dev, "cannot get regulators: %d\n", error);
+ return error;
+ }
+
+ error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), data->regulators);
+ if (error) {
+ dev_err(dev, "failed to enable regulators: %d\n", error);
+ return error;
+ }
+
data->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
error = PTR_ERR_OR_ZERO(data->reset_gpio);
if (error) {
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
dev_err(dev, "failed to request reset GPIO: %d\n", error);
return error;
}
@@ -214,6 +249,7 @@ static int nvt_ts_probe(struct i2c_client *client)
error = nvt_ts_read_data(data->client, NVT_TS_PARAMETERS_START,
data->buf, NVT_TS_PARAMS_SIZE);
gpiod_set_value_cansleep(data->reset_gpio, 1); /* Put back in reset */
+ regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators);
if (error)
return error;
@@ -225,8 +261,8 @@ static int nvt_ts_probe(struct i2c_client *client)
if (width > NVT_TS_MAX_SIZE || height >= NVT_TS_MAX_SIZE ||
data->max_touches > NVT_TS_MAX_TOUCHES ||
irq_type >= ARRAY_SIZE(nvt_ts_irq_type) ||
- data->buf[NVT_TS_PARAMS_WAKE_TYPE] != NVT_TS_SUPPORTED_WAKE_TYPE ||
- data->buf[NVT_TS_PARAMS_CHIP_ID] != NVT_TS_SUPPORTED_CHIP_ID) {
+ data->buf[NVT_TS_PARAMS_WAKE_TYPE] != chip->wake_type ||
+ data->buf[NVT_TS_PARAMS_CHIP_ID] != chip->chip_id) {
dev_err(dev, "Unsupported touchscreen parameters: %*ph\n",
NVT_TS_PARAMS_SIZE, data->buf);
return -EIO;
@@ -277,8 +313,26 @@ static int nvt_ts_probe(struct i2c_client *client)
return 0;
}
+static const struct nvt_ts_i2c_chip_data nvt_nt11205_ts_data = {
+ .wake_type = 0x05,
+ .chip_id = 0x05,
+};
+
+static const struct nvt_ts_i2c_chip_data nvt_nt36672a_ts_data = {
+ .wake_type = 0x01,
+ .chip_id = 0x08,
+};
+
+static const struct of_device_id nvt_ts_of_match[] = {
+ { .compatible = "novatek,nt11205-ts", .data = &nvt_nt11205_ts_data },
+ { .compatible = "novatek,nt36672a-ts", .data = &nvt_nt36672a_ts_data },
+ { }
+};
+MODULE_DEVICE_TABLE(of, nvt_ts_of_match);
+
static const struct i2c_device_id nvt_ts_i2c_id[] = {
- { "NVT-ts" },
+ { "nt11205-ts", (unsigned long) &nvt_nt11205_ts_data },
+ { "nt36672a-ts", (unsigned long) &nvt_nt36672a_ts_data },
{ }
};
MODULE_DEVICE_TABLE(i2c, nvt_ts_i2c_id);
@@ -287,6 +341,7 @@ static struct i2c_driver nvt_ts_driver = {
.driver = {
.name = "novatek-nvt-ts",
.pm = pm_sleep_ptr(&nvt_ts_pm_ops),
+ .of_match_table = nvt_ts_of_match,
},
.probe = nvt_ts_probe,
.id_table = nvt_ts_i2c_id,
diff --git a/drivers/input/touchscreen/pcap_ts.c b/drivers/input/touchscreen/pcap_ts.c
index 821245019fea..083206a3457b 100644
--- a/drivers/input/touchscreen/pcap_ts.c
+++ b/drivers/input/touchscreen/pcap_ts.c
@@ -238,7 +238,7 @@ static const struct dev_pm_ops pcap_ts_pm_ops = {
static struct platform_driver pcap_ts_driver = {
.probe = pcap_ts_probe,
- .remove_new = pcap_ts_remove,
+ .remove = pcap_ts_remove,
.driver = {
.name = "pcap-ts",
.pm = PCAP_TS_PM_OPS,
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
index 12abb3b36128..95adede26703 100644
--- a/drivers/input/touchscreen/penmount.c
+++ b/drivers/input/touchscreen/penmount.c
@@ -199,7 +199,7 @@ static int pm_connect(struct serio *serio, struct serio_driver *drv)
int max_x, max_y;
int err;
- pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
+ pm = kzalloc(sizeof(*pm), GFP_KERNEL);
input_dev = input_allocate_device();
if (!pm || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 4ede0687beb0..dad5786e82a4 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -5,7 +5,7 @@
* Copyright (C) 2010-2011 Pixcir, Inc.
*/
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
@@ -44,7 +44,7 @@ enum pixcir_power_mode {
/*
* Interrupt modes:
- * periodical: interrupt is asserted periodicaly
+ * periodical: interrupt is asserted periodically
* diff coordinates: interrupt is asserted when coordinates change
* level on touch: interrupt level asserted during touch
* pulse on touch: interrupt pulse asserted during touch
diff --git a/drivers/input/touchscreen/raspberrypi-ts.c b/drivers/input/touchscreen/raspberrypi-ts.c
index 45c575df994e..841d39a449b3 100644
--- a/drivers/input/touchscreen/raspberrypi-ts.c
+++ b/drivers/input/touchscreen/raspberrypi-ts.c
@@ -122,20 +122,18 @@ static int rpi_ts_probe(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct input_dev *input;
- struct device_node *fw_node;
struct rpi_firmware *fw;
struct rpi_ts *ts;
u32 touchbuf;
int error;
- fw_node = of_get_parent(np);
+ struct device_node *fw_node __free(device_node) = of_get_parent(np);
if (!fw_node) {
dev_err(dev, "Missing firmware node\n");
return -ENOENT;
}
fw = devm_rpi_firmware_get(&pdev->dev, fw_node);
- of_node_put(fw_node);
if (!fw)
return -EPROBE_DEFER;
diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c
index 92d75057de2d..f975b53e8825 100644
--- a/drivers/input/touchscreen/raydium_i2c_ts.c
+++ b/drivers/input/touchscreen/raydium_i2c_ts.c
@@ -24,7 +24,7 @@
#include <linux/pm_wakeirq.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Slave I2C mode */
#define RM_BOOT_BLDR 0x02
diff --git a/drivers/input/touchscreen/rohm_bu21023.c b/drivers/input/touchscreen/rohm_bu21023.c
index 06fa3a19d266..295d8d75ba32 100644
--- a/drivers/input/touchscreen/rohm_bu21023.c
+++ b/drivers/input/touchscreen/rohm_bu21023.c
@@ -388,13 +388,13 @@ static int rohm_ts_manual_calibration(struct rohm_ts_data *ts)
err_y = (int)READ_CALIB_BUF(PRM1_Y_H) << 2 |
READ_CALIB_BUF(PRM1_Y_L);
- /* X axis ajust */
+ /* X axis adjust */
if (err_x <= 4)
calib_x -= AXIS_ADJUST;
else if (err_x >= 60)
calib_x += AXIS_ADJUST;
- /* Y axis ajust */
+ /* Y axis adjust */
if (err_y <= 4)
calib_y -= AXIS_ADJUST;
else if (err_y >= 60)
@@ -643,12 +643,12 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
const char *firmware_name)
{
struct device *dev = &client->dev;
- const struct firmware *fw;
s32 status;
unsigned int offset, len, xfer_len;
unsigned int retry = 0;
int error, error2;
+ const struct firmware *fw __free(firmware) = NULL;
error = request_firmware(&fw, firmware_name, dev);
if (error) {
dev_err(dev, "unable to retrieve firmware %s: %d\n",
@@ -722,18 +722,39 @@ static int rohm_ts_load_firmware(struct i2c_client *client,
out:
error2 = i2c_smbus_write_byte_data(client, INT_MASK, INT_ALL);
- release_firmware(fw);
-
return error ? error : error2;
}
+static int rohm_ts_update_setting(struct rohm_ts_data *ts,
+ unsigned int setting_bit, bool on)
+{
+ int error;
+
+ scoped_cond_guard(mutex_intr, return -EINTR, &ts->input->mutex) {
+ if (on)
+ ts->setup2 |= setting_bit;
+ else
+ ts->setup2 &= ~setting_bit;
+
+ if (ts->initialized) {
+ error = i2c_smbus_write_byte_data(ts->client,
+ COMMON_SETUP2,
+ ts->setup2);
+ if (error)
+ return error;
+ }
+ }
+
+ return 0;
+}
+
static ssize_t swap_xy_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct rohm_ts_data *ts = i2c_get_clientdata(client);
- return sprintf(buf, "%d\n", !!(ts->setup2 & SWAP_XY));
+ return sysfs_emit(buf, "%d\n", !!(ts->setup2 & SWAP_XY));
}
static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr,
@@ -748,22 +769,8 @@ static ssize_t swap_xy_store(struct device *dev, struct device_attribute *attr,
if (error)
return error;
- error = mutex_lock_interruptible(&ts->input->mutex);
- if (error)
- return error;
-
- if (val)
- ts->setup2 |= SWAP_XY;
- else
- ts->setup2 &= ~SWAP_XY;
-
- if (ts->initialized)
- error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
- ts->setup2);
-
- mutex_unlock(&ts->input->mutex);
-
- return error ? error : count;
+ error = rohm_ts_update_setting(ts, SWAP_XY, val);
+ return error ?: count;
}
static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr,
@@ -772,7 +779,7 @@ static ssize_t inv_x_show(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct rohm_ts_data *ts = i2c_get_clientdata(client);
- return sprintf(buf, "%d\n", !!(ts->setup2 & INV_X));
+ return sysfs_emit(buf, "%d\n", !!(ts->setup2 & INV_X));
}
static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr,
@@ -787,22 +794,8 @@ static ssize_t inv_x_store(struct device *dev, struct device_attribute *attr,
if (error)
return error;
- error = mutex_lock_interruptible(&ts->input->mutex);
- if (error)
- return error;
-
- if (val)
- ts->setup2 |= INV_X;
- else
- ts->setup2 &= ~INV_X;
-
- if (ts->initialized)
- error = i2c_smbus_write_byte_data(ts->client, COMMON_SETUP2,
- ts->setup2);
-
- mutex_unlock(&ts->input->mutex);
-
- return error ? error : count;
+ error = rohm_ts_update_setting(ts, INV_X, val);
+ return error ?: count;
}
static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr,
@@ -811,7 +804,7 @@ static ssize_t inv_y_show(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct rohm_ts_data *ts = i2c_get_clientdata(client);
- return sprintf(buf, "%d\n", !!(ts->setup2 & INV_Y));
+ return sysfs_emit(buf, "%d\n", !!(ts->setup2 & INV_Y));
}
static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr,
@@ -826,22 +819,8 @@ static ssize_t inv_y_store(struct device *dev, struct device_attribute *attr,
if (error)
return error;
- error = mutex_lock_interruptible(&ts->input->mutex);
- if (error)
- return error;
-
- if (val)
- ts->setup2 |= INV_Y;
- else
- ts->setup2 &= ~INV_Y;
-
- if (ts->initialized)
- error = i2c_smbus_write_byte_data(client, COMMON_SETUP2,
- ts->setup2);
-
- mutex_unlock(&ts->input->mutex);
-
- return error ? error : count;
+ error = rohm_ts_update_setting(ts, INV_Y, val);
+ return error ?: count;
}
static DEVICE_ATTR_RW(swap_xy);
@@ -861,7 +840,7 @@ static int rohm_ts_device_init(struct i2c_client *client, u8 setup2)
struct device *dev = &client->dev;
int error;
- disable_irq(client->irq);
+ guard(disable_irq)(&client->irq);
/*
* Wait 200usec for reset
@@ -1036,10 +1015,10 @@ static int rohm_ts_device_init(struct i2c_client *client, u8 setup2)
/* controller CPU power on */
error = i2c_smbus_write_byte_data(client, SYSTEM,
ANALOG_POWER_ON | CPU_POWER_ON);
+ if (error)
+ return error;
- enable_irq(client->irq);
-
- return error;
+ return 0;
}
static int rohm_ts_power_off(struct i2c_client *client)
diff --git a/drivers/input/touchscreen/s6sy761.c b/drivers/input/touchscreen/s6sy761.c
index a529217e748f..e1518a75a51b 100644
--- a/drivers/input/touchscreen/s6sy761.c
+++ b/drivers/input/touchscreen/s6sy761.c
@@ -4,7 +4,7 @@
// Copyright (c) 2017 Samsung Electronics Co., Ltd.
// Copyright (c) 2017 Andi Shyti <andi@etezian.org>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input/mt.h>
diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c
index 6a42b27c4599..5ccc96764742 100644
--- a/drivers/input/touchscreen/silead.c
+++ b/drivers/input/touchscreen/silead.c
@@ -24,7 +24,7 @@
#include <linux/irq.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SILEAD_TS_NAME "silead_ts"
diff --git a/drivers/input/touchscreen/sis_i2c.c b/drivers/input/touchscreen/sis_i2c.c
index 2023c6df416f..a625f2ad809d 100644
--- a/drivers/input/touchscreen/sis_i2c.c
+++ b/drivers/input/touchscreen/sis_i2c.c
@@ -15,7 +15,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SIS_I2C_NAME "sis_i2c_ts"
diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c
index 6475084aee1b..9b3901eec0a5 100644
--- a/drivers/input/touchscreen/st1232.c
+++ b/drivers/input/touchscreen/st1232.c
@@ -22,6 +22,7 @@
#include <linux/pm_qos.h>
#include <linux/slab.h>
#include <linux/types.h>
+#include <linux/input/touch-overlay.h>
#define ST1232_TS_NAME "st1232-ts"
#define ST1633_TS_NAME "st1633-ts"
@@ -57,6 +58,7 @@ struct st1232_ts_data {
struct dev_pm_qos_request low_latency_req;
struct gpio_desc *reset_gpio;
const struct st_chip_info *chip_info;
+ struct list_head touch_overlay_list;
int read_buf_len;
u8 *read_buf;
};
@@ -156,6 +158,10 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
input_mt_assign_slots(input, slots, pos, n_contacts, 0);
for (i = 0; i < n_contacts; i++) {
+ if (touch_overlay_process_contact(&ts->touch_overlay_list,
+ input, &pos[i], slots[i]))
+ continue;
+
input_mt_slot(input, slots[i]);
input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
input_report_abs(input, ABS_MT_POSITION_X, pos[i].x);
@@ -164,6 +170,7 @@ static int st1232_ts_parse_and_report(struct st1232_ts_data *ts)
input_report_abs(input, ABS_MT_TOUCH_MAJOR, z[i]);
}
+ touch_overlay_sync_frame(&ts->touch_overlay_list, input);
input_mt_sync_frame(input);
input_sync(input);
@@ -292,18 +299,30 @@ static int st1232_ts_probe(struct i2c_client *client)
if (error)
return error;
- /* Read resolution from the chip */
- error = st1232_ts_read_resolution(ts, &max_x, &max_y);
- if (error) {
- dev_err(&client->dev,
- "Failed to read resolution: %d\n", error);
- return error;
- }
-
if (ts->chip_info->have_z)
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ts->chip_info->max_area, 0, 0);
+ /* map overlay objects if defined in the device tree */
+ INIT_LIST_HEAD(&ts->touch_overlay_list);
+ error = touch_overlay_map(&ts->touch_overlay_list, input_dev);
+ if (error)
+ return error;
+
+ if (touch_overlay_mapped_touchscreen(&ts->touch_overlay_list)) {
+ /* Read resolution from the overlay touchscreen if defined */
+ touch_overlay_get_touchscreen_abs(&ts->touch_overlay_list,
+ &max_x, &max_y);
+ } else {
+ /* Read resolution from the chip */
+ error = st1232_ts_read_resolution(ts, &max_x, &max_y);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read resolution: %d\n", error);
+ return error;
+ }
+ }
+
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, max_x, 0, 0);
input_set_abs_params(input_dev, ABS_MT_POSITION_Y,
diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c
index b204fdb2d22c..af0fb38bcfdc 100644
--- a/drivers/input/touchscreen/stmpe-ts.c
+++ b/drivers/input/touchscreen/stmpe-ts.c
@@ -107,7 +107,7 @@ static void stmpe_work(struct work_struct *work)
/*
* touch_det sometimes get desasserted or just get stuck. This appears
- * to be a silicon bug, We still have to clearify this with the
+ * to be a silicon bug, We still have to clarify this with the
* manufacture. As a workaround We release the key anyway if the
* touch_det keeps coming in after 4ms, while the FIFO contains no value
* during the whole time.
@@ -140,7 +140,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data)
/*
* The FIFO sometimes just crashes and stops generating interrupts. This
- * appears to be a silicon bug. We still have to clearify this with
+ * appears to be a silicon bug. We still have to clarify this with
* the manufacture. As a workaround we disable the TSC while we are
* collecting data and flush the FIFO after reading
*/
@@ -362,16 +362,11 @@ static struct platform_driver stmpe_ts_driver = {
.name = STMPE_TS_NAME,
},
.probe = stmpe_input_probe,
- .remove_new = stmpe_ts_remove,
+ .remove = stmpe_ts_remove,
};
module_platform_driver(stmpe_ts_driver);
-static const struct of_device_id stmpe_ts_ids[] = {
- { .compatible = "st,stmpe-ts", },
- { },
-};
-MODULE_DEVICE_TABLE(of, stmpe_ts_ids);
-
+MODULE_ALIAS("platform:stmpe-ts");
MODULE_AUTHOR("Luotao Fu <l.fu@pengutronix.de>");
MODULE_DESCRIPTION("STMPEXXX touchscreen driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 92b2b840b4b7..e8286060043a 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -396,12 +396,12 @@ static const struct of_device_id sun4i_ts_of_match[] = {
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
static struct platform_driver sun4i_ts_driver = {
- .driver = {
+ .driver = {
.name = "sun4i-ts",
.of_match_table = sun4i_ts_of_match,
},
.probe = sun4i_ts_probe,
- .remove_new = sun4i_ts_remove,
+ .remove = sun4i_ts_remove,
};
module_platform_driver(sun4i_ts_driver);
diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 5f2cf8881e72..7b3b10cbfcfc 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -672,7 +672,7 @@ static int sur40_probe(struct usb_interface *interface,
return -ENODEV;
/* Allocate memory for our device state and initialize it. */
- sur40 = kzalloc(sizeof(struct sur40_state), GFP_KERNEL);
+ sur40 = kzalloc(sizeof(*sur40), GFP_KERNEL);
if (!sur40)
return -ENOMEM;
@@ -1108,8 +1108,6 @@ static const struct vb2_ops sur40_queue_ops = {
.buf_queue = sur40_buffer_queue,
.start_streaming = sur40_start_streaming,
.stop_streaming = sur40_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct vb2_queue sur40_queue = {
diff --git a/drivers/input/touchscreen/surface3_spi.c b/drivers/input/touchscreen/surface3_spi.c
index 7efbcd0fde4f..6074b7730e86 100644
--- a/drivers/input/touchscreen/surface3_spi.c
+++ b/drivers/input/touchscreen/surface3_spi.c
@@ -18,7 +18,7 @@
#include <linux/spi/spi.h>
#include <linux/acpi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define SURFACE3_PACKET_SIZE 264
diff --git a/drivers/input/touchscreen/sx8654.c b/drivers/input/touchscreen/sx8654.c
index f5c5881cef6b..5fa47a1a6fdc 100644
--- a/drivers/input/touchscreen/sx8654.c
+++ b/drivers/input/touchscreen/sx8654.c
@@ -116,7 +116,7 @@ static inline void sx865x_penrelease(struct sx8654 *ts)
static void sx865x_penrelease_timer_handler(struct timer_list *t)
{
- struct sx8654 *ts = from_timer(ts, t, timer);
+ struct sx8654 *ts = timer_container_of(ts, t, timer);
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
@@ -290,7 +290,7 @@ static void sx8654_close(struct input_dev *dev)
disable_irq(client->irq);
if (!sx8654->data->has_irq_penrelease)
- del_timer_sync(&sx8654->timer);
+ timer_delete_sync(&sx8654->timer);
/* enable manual mode mode */
error = i2c_smbus_write_byte(client, sx8654->data->cmd_manual);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 294b7ceded27..93d659ff90aa 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -550,9 +550,9 @@ MODULE_DEVICE_TABLE(of, ti_tsc_dt_ids);
static struct platform_driver ti_tsc_driver = {
.probe = titsc_probe,
- .remove_new = titsc_remove,
+ .remove = titsc_remove,
.driver = {
- .name = "TI-am335x-tsc",
+ .name = "TI-am335x-tsc",
.pm = pm_sleep_ptr(&titsc_pm_ops),
.of_match_table = ti_tsc_dt_ids,
},
diff --git a/drivers/input/touchscreen/touchit213.c b/drivers/input/touchscreen/touchit213.c
index fb49687da405..c2718350815c 100644
--- a/drivers/input/touchscreen/touchit213.c
+++ b/drivers/input/touchscreen/touchit213.c
@@ -139,7 +139,7 @@ static int touchit213_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- touchit213 = kzalloc(sizeof(struct touchit213), GFP_KERNEL);
+ touchit213 = kzalloc(sizeof(*touchit213), GFP_KERNEL);
input_dev = input_allocate_device();
if (!touchit213 || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
index 3cd58a13e44f..30ba97bd00a1 100644
--- a/drivers/input/touchscreen/touchright.c
+++ b/drivers/input/touchscreen/touchright.c
@@ -102,7 +102,7 @@ static int tr_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- tr = kzalloc(sizeof(struct tr), GFP_KERNEL);
+ tr = kzalloc(sizeof(*tr), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tr || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
index bde3c6ee3c60..fbd72789ea80 100644
--- a/drivers/input/touchscreen/touchwin.c
+++ b/drivers/input/touchscreen/touchwin.c
@@ -109,7 +109,7 @@ static int tw_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int err;
- tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
+ tw = kzalloc(sizeof(*tw), GFP_KERNEL);
input_dev = input_allocate_device();
if (!tw || !input_dev) {
err = -ENOMEM;
diff --git a/drivers/input/touchscreen/ts4800-ts.c b/drivers/input/touchscreen/ts4800-ts.c
index 6cf66aadc10e..98422d1e80d6 100644
--- a/drivers/input/touchscreen/ts4800-ts.c
+++ b/drivers/input/touchscreen/ts4800-ts.c
@@ -110,18 +110,17 @@ static int ts4800_parse_dt(struct platform_device *pdev,
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
- struct device_node *syscon_np;
u32 reg, bit;
int error;
- syscon_np = of_parse_phandle(np, "syscon", 0);
+ struct device_node *syscon_np __free(device_node) =
+ of_parse_phandle(np, "syscon", 0);
if (!syscon_np) {
dev_err(dev, "no syscon property\n");
return -ENODEV;
}
ts->regmap = syscon_node_to_regmap(syscon_np);
- of_node_put(syscon_np);
if (IS_ERR(ts->regmap)) {
dev_err(dev, "cannot get parent's regmap\n");
return PTR_ERR(ts->regmap);
diff --git a/drivers/input/touchscreen/tsc2004.c b/drivers/input/touchscreen/tsc2004.c
index b673098535ad..787f2caf4f73 100644
--- a/drivers/input/touchscreen/tsc2004.c
+++ b/drivers/input/touchscreen/tsc2004.c
@@ -42,11 +42,6 @@ static int tsc2004_probe(struct i2c_client *i2c)
tsc2004_cmd);
}
-static void tsc2004_remove(struct i2c_client *i2c)
-{
- tsc200x_remove(&i2c->dev);
-}
-
static const struct i2c_device_id tsc2004_idtable[] = {
{ "tsc2004" },
{ }
@@ -70,7 +65,6 @@ static struct i2c_driver tsc2004_driver = {
},
.id_table = tsc2004_idtable,
.probe = tsc2004_probe,
- .remove = tsc2004_remove,
};
module_i2c_driver(tsc2004_driver);
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 1b40ce0ca1b9..6fe8b41b3ecc 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -64,11 +64,6 @@ static int tsc2005_probe(struct spi_device *spi)
tsc2005_cmd);
}
-static void tsc2005_remove(struct spi_device *spi)
-{
- tsc200x_remove(&spi->dev);
-}
-
#ifdef CONFIG_OF
static const struct of_device_id tsc2005_of_match[] = {
{ .compatible = "ti,tsc2005" },
@@ -85,7 +80,6 @@ static struct spi_driver tsc2005_driver = {
.pm = pm_sleep_ptr(&tsc200x_pm_ops),
},
.probe = tsc2005_probe,
- .remove = tsc2005_remove,
};
module_spi_driver(tsc2005_driver);
diff --git a/drivers/input/touchscreen/tsc2007.h b/drivers/input/touchscreen/tsc2007.h
index 69b08dd6c8df..e346fb4f7552 100644
--- a/drivers/input/touchscreen/tsc2007.h
+++ b/drivers/input/touchscreen/tsc2007.h
@@ -19,6 +19,7 @@
#ifndef _TSC2007_H
#define _TSC2007_H
+#include <linux/input/touchscreen.h>
struct gpio_desc;
#define TSC2007_MEASURE_TEMP0 (0x0 << 4)
@@ -63,6 +64,7 @@ struct tsc2007 {
struct i2c_client *client;
+ struct touchscreen_properties prop;
u16 model;
u16 x_plate_ohms;
u16 max_rt;
diff --git a/drivers/input/touchscreen/tsc2007_core.c b/drivers/input/touchscreen/tsc2007_core.c
index 8d832a372b89..948935de894b 100644
--- a/drivers/input/touchscreen/tsc2007_core.c
+++ b/drivers/input/touchscreen/tsc2007_core.c
@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
+#include <linux/math64.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/platform_data/tsc2007.h>
@@ -68,7 +69,7 @@ static void tsc2007_read_values(struct tsc2007 *tsc, struct ts_event *tc)
u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
{
- u32 rt = 0;
+ u64 rt = 0;
/* range filtering */
if (tc->x == MAX_12BIT)
@@ -79,11 +80,13 @@ u32 tsc2007_calculate_resistance(struct tsc2007 *tsc, struct ts_event *tc)
rt = tc->z2 - tc->z1;
rt *= tc->x;
rt *= tsc->x_plate_ohms;
- rt /= tc->z1;
+ rt = div_u64(rt, tc->z1);
rt = (rt + 2047) >> 12;
}
- return rt;
+ if (rt > U32_MAX)
+ return U32_MAX;
+ return (u32) rt;
}
bool tsc2007_is_pen_down(struct tsc2007 *ts)
@@ -142,8 +145,7 @@ static irqreturn_t tsc2007_soft_irq(int irq, void *handle)
rt = ts->max_rt - rt;
input_report_key(input, BTN_TOUCH, 1);
- input_report_abs(input, ABS_X, tc.x);
- input_report_abs(input, ABS_Y, tc.y);
+ touchscreen_report_pos(input, &ts->prop, tc.x, tc.y, false);
input_report_abs(input, ABS_PRESSURE, rt);
input_sync(input);
@@ -178,7 +180,8 @@ static void tsc2007_stop(struct tsc2007 *ts)
mb();
wake_up(&ts->wait);
- disable_irq(ts->irq);
+ if (ts->irq)
+ disable_irq(ts->irq);
}
static int tsc2007_open(struct input_dev *input_dev)
@@ -189,7 +192,8 @@ static int tsc2007_open(struct input_dev *input_dev)
ts->stopped = false;
mb();
- enable_irq(ts->irq);
+ if (ts->irq)
+ enable_irq(ts->irq);
/* Prepare for touch readings - power down ADC and enable PENIRQ */
err = tsc2007_xfer(ts, PWRDOWN);
@@ -254,7 +258,7 @@ static int tsc2007_probe_properties(struct device *dev, struct tsc2007 *ts)
if (ts->gpiod)
ts->get_pendown_state = tsc2007_get_pendown_state_gpio;
else
- dev_warn(dev, "Pen down GPIO is not specified in properties\n");
+ dev_dbg(dev, "Pen down GPIO is not specified in properties\n");
return 0;
}
@@ -339,9 +343,9 @@ static int tsc2007_probe(struct i2c_client *client)
input_set_drvdata(input_dev, ts);
input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
-
input_set_abs_params(input_dev, ABS_X, 0, MAX_12BIT, ts->fuzzx, 0);
input_set_abs_params(input_dev, ABS_Y, 0, MAX_12BIT, ts->fuzzy, 0);
+ touchscreen_parse_properties(input_dev, false, &ts->prop);
input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_12BIT,
ts->fuzzz, 0);
@@ -362,17 +366,19 @@ static int tsc2007_probe(struct i2c_client *client)
pdata->init_platform_hw();
}
- err = devm_request_threaded_irq(&client->dev, ts->irq,
- NULL, tsc2007_soft_irq,
- IRQF_ONESHOT,
- client->dev.driver->name, ts);
- if (err) {
- dev_err(&client->dev, "Failed to request irq %d: %d\n",
- ts->irq, err);
- return err;
- }
+ if (ts->irq) {
+ err = devm_request_threaded_irq(&client->dev, ts->irq,
+ NULL, tsc2007_soft_irq,
+ IRQF_ONESHOT,
+ client->dev.driver->name, ts);
+ if (err) {
+ dev_err(&client->dev, "Failed to request irq %d: %d\n",
+ ts->irq, err);
+ return err;
+ }
- tsc2007_stop(ts);
+ tsc2007_stop(ts);
+ }
/* power down the chip (TSC2007_SETUP does not ACK on I2C) */
err = tsc2007_xfer(ts, PWRDOWN);
diff --git a/drivers/input/touchscreen/tsc200x-core.c b/drivers/input/touchscreen/tsc200x-core.c
index a4c0e9db9bb9..eba53613b005 100644
--- a/drivers/input/touchscreen/tsc200x-core.c
+++ b/drivers/input/touchscreen/tsc200x-core.c
@@ -10,6 +10,7 @@
* based on TSC2301 driver by Klaus K. Pedersen <klaus.k.pedersen@nokia.com>
*/
+#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
@@ -104,11 +105,11 @@ struct tsc200x {
bool pen_down;
- struct regulator *vio;
-
struct gpio_desc *reset_gpio;
int (*tsc200x_cmd)(struct device *dev, u8 cmd);
+
int irq;
+ bool wake_irq_enabled;
};
static void tsc200x_update_pen_state(struct tsc200x *ts,
@@ -136,7 +137,6 @@ static void tsc200x_update_pen_state(struct tsc200x *ts,
static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
{
struct tsc200x *ts = _ts;
- unsigned long flags;
unsigned int pressure;
struct tsc200x_data tsdata;
int error;
@@ -182,13 +182,11 @@ static irqreturn_t tsc200x_irq_thread(int irq, void *_ts)
if (unlikely(pressure > MAX_12BIT))
goto out;
- spin_lock_irqsave(&ts->lock, flags);
-
- tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
- mod_timer(&ts->penup_timer,
- jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS));
-
- spin_unlock_irqrestore(&ts->lock, flags);
+ scoped_guard(spinlock_irqsave, &ts->lock) {
+ tsc200x_update_pen_state(ts, tsdata.x, tsdata.y, pressure);
+ mod_timer(&ts->penup_timer,
+ jiffies + msecs_to_jiffies(TSC200X_PENUP_TIME_MS));
+ }
ts->last_valid_interrupt = jiffies;
out:
@@ -197,12 +195,10 @@ out:
static void tsc200x_penup_timer(struct timer_list *t)
{
- struct tsc200x *ts = from_timer(ts, t, penup_timer);
- unsigned long flags;
+ struct tsc200x *ts = timer_container_of(ts, t, penup_timer);
- spin_lock_irqsave(&ts->lock, flags);
+ guard(spinlock_irqsave)(&ts->lock);
tsc200x_update_pen_state(ts, 0, 0, 0);
- spin_unlock_irqrestore(&ts->lock, flags);
}
static void tsc200x_start_scan(struct tsc200x *ts)
@@ -232,12 +228,10 @@ static void __tsc200x_disable(struct tsc200x *ts)
{
tsc200x_stop_scan(ts);
- disable_irq(ts->irq);
- del_timer_sync(&ts->penup_timer);
+ guard(disable_irq)(&ts->irq);
+ timer_delete_sync(&ts->penup_timer);
cancel_delayed_work_sync(&ts->esd_work);
-
- enable_irq(ts->irq);
}
/* must be called with ts->mutex held */
@@ -253,80 +247,79 @@ static void __tsc200x_enable(struct tsc200x *ts)
}
}
-static ssize_t tsc200x_selftest_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+/*
+ * Test TSC200X communications via temp high register.
+ */
+static int tsc200x_do_selftest(struct tsc200x *ts)
{
- struct tsc200x *ts = dev_get_drvdata(dev);
- unsigned int temp_high;
unsigned int temp_high_orig;
unsigned int temp_high_test;
- bool success = true;
+ unsigned int temp_high;
int error;
- mutex_lock(&ts->mutex);
-
- /*
- * Test TSC200X communications via temp high register.
- */
- __tsc200x_disable(ts);
-
error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high_orig);
if (error) {
- dev_warn(dev, "selftest failed: read error %d\n", error);
- success = false;
- goto out;
+ dev_warn(ts->dev, "selftest failed: read error %d\n", error);
+ return error;
}
temp_high_test = (temp_high_orig - 1) & MAX_12BIT;
error = regmap_write(ts->regmap, TSC200X_REG_TEMP_HIGH, temp_high_test);
if (error) {
- dev_warn(dev, "selftest failed: write error %d\n", error);
- success = false;
- goto out;
+ dev_warn(ts->dev, "selftest failed: write error %d\n", error);
+ return error;
}
error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
if (error) {
- dev_warn(dev, "selftest failed: read error %d after write\n",
- error);
- success = false;
- goto out;
- }
-
- if (temp_high != temp_high_test) {
- dev_warn(dev, "selftest failed: %d != %d\n",
- temp_high, temp_high_test);
- success = false;
+ dev_warn(ts->dev,
+ "selftest failed: read error %d after write\n", error);
+ return error;
}
/* hardware reset */
tsc200x_reset(ts);
- if (!success)
- goto out;
+ if (temp_high != temp_high_test) {
+ dev_warn(ts->dev, "selftest failed: %d != %d\n",
+ temp_high, temp_high_test);
+ return -EINVAL;
+ }
/* test that the reset really happened */
error = regmap_read(ts->regmap, TSC200X_REG_TEMP_HIGH, &temp_high);
if (error) {
- dev_warn(dev, "selftest failed: read error %d after reset\n",
- error);
- success = false;
- goto out;
+ dev_warn(ts->dev,
+ "selftest failed: read error %d after reset\n", error);
+ return error;
}
if (temp_high != temp_high_orig) {
- dev_warn(dev, "selftest failed after reset: %d != %d\n",
+ dev_warn(ts->dev, "selftest failed after reset: %d != %d\n",
temp_high, temp_high_orig);
- success = false;
+ return -EINVAL;
}
-out:
- __tsc200x_enable(ts);
- mutex_unlock(&ts->mutex);
+ return 0;
+}
+
+static ssize_t tsc200x_selftest_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct tsc200x *ts = dev_get_drvdata(dev);
+ int error;
+
+ scoped_guard(mutex, &ts->mutex) {
+ __tsc200x_disable(ts);
+
+ error = tsc200x_do_selftest(ts);
- return sprintf(buf, "%d\n", success);
+ __tsc200x_enable(ts);
+ }
+
+ return sprintf(buf, "%d\n", !error);
}
static DEVICE_ATTR(selftest, S_IRUGO, tsc200x_selftest_show, NULL);
@@ -368,46 +361,42 @@ static void tsc200x_esd_work(struct work_struct *work)
int error;
unsigned int r;
- if (!mutex_trylock(&ts->mutex)) {
- /*
- * If the mutex is taken, it means that disable or enable is in
- * progress. In that case just reschedule the work. If the work
- * is not needed, it will be canceled by disable.
- */
- goto reschedule;
- }
-
- if (time_is_after_jiffies(ts->last_valid_interrupt +
- msecs_to_jiffies(ts->esd_timeout)))
- goto out;
-
- /* We should be able to read register without disabling interrupts. */
- error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r);
- if (!error &&
- !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) {
- goto out;
- }
-
/*
- * If we could not read our known value from configuration register 0
- * then we should reset the controller as if from power-up and start
- * scanning again.
+ * If the mutex is taken, it means that disable or enable is in
+ * progress. In that case just reschedule the work. If the work
+ * is not needed, it will be canceled by disable.
*/
- dev_info(ts->dev, "TSC200X not responding - resetting\n");
+ scoped_guard(mutex_try, &ts->mutex) {
+ if (time_is_after_jiffies(ts->last_valid_interrupt +
+ msecs_to_jiffies(ts->esd_timeout)))
+ break;
- disable_irq(ts->irq);
- del_timer_sync(&ts->penup_timer);
+ /*
+ * We should be able to read register without disabling
+ * interrupts.
+ */
+ error = regmap_read(ts->regmap, TSC200X_REG_CFR0, &r);
+ if (!error &&
+ !((r ^ TSC200X_CFR0_INITVALUE) & TSC200X_CFR0_RW_MASK)) {
+ break;
+ }
- tsc200x_update_pen_state(ts, 0, 0, 0);
+ /*
+ * If we could not read our known value from configuration
+ * register 0 then we should reset the controller as if from
+ * power-up and start scanning again.
+ */
+ dev_info(ts->dev, "TSC200X not responding - resetting\n");
- tsc200x_reset(ts);
+ scoped_guard(disable_irq, &ts->irq) {
+ timer_delete_sync(&ts->penup_timer);
+ tsc200x_update_pen_state(ts, 0, 0, 0);
+ tsc200x_reset(ts);
+ }
- enable_irq(ts->irq);
- tsc200x_start_scan(ts);
+ tsc200x_start_scan(ts);
+ }
-out:
- mutex_unlock(&ts->mutex);
-reschedule:
/* re-arm the watchdog */
schedule_delayed_work(&ts->esd_work,
round_jiffies_relative(
@@ -418,15 +407,13 @@ static int tsc200x_open(struct input_dev *input)
{
struct tsc200x *ts = input_get_drvdata(input);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
if (!ts->suspended)
__tsc200x_enable(ts);
ts->opened = true;
- mutex_unlock(&ts->mutex);
-
return 0;
}
@@ -434,14 +421,12 @@ static void tsc200x_close(struct input_dev *input)
{
struct tsc200x *ts = input_get_drvdata(input);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
if (!ts->suspended)
__tsc200x_disable(ts);
ts->opened = false;
-
- mutex_unlock(&ts->mutex);
}
int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
@@ -488,20 +473,6 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
&esd_timeout);
ts->esd_timeout = error ? 0 : esd_timeout;
- ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(ts->reset_gpio)) {
- error = PTR_ERR(ts->reset_gpio);
- dev_err(dev, "error acquiring reset gpio: %d\n", error);
- return error;
- }
-
- ts->vio = devm_regulator_get(dev, "vio");
- if (IS_ERR(ts->vio)) {
- error = PTR_ERR(ts->vio);
- dev_err(dev, "error acquiring vio regulator: %d", error);
- return error;
- }
-
mutex_init(&ts->mutex);
spin_lock_init(&ts->lock);
@@ -542,60 +513,60 @@ int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
touchscreen_parse_properties(input_dev, false, &ts->prop);
+ ts->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ error = PTR_ERR_OR_ZERO(ts->reset_gpio);
+ if (error) {
+ dev_err(dev, "error acquiring reset gpio: %d\n", error);
+ return error;
+ }
+
+ error = devm_regulator_get_enable(dev, "vio");
+ if (error) {
+ dev_err(dev, "error acquiring vio regulator: %d\n", error);
+ return error;
+ }
+
+ tsc200x_reset(ts);
+
/* Ensure the touchscreen is off */
tsc200x_stop_scan(ts);
- error = devm_request_threaded_irq(dev, irq, NULL,
- tsc200x_irq_thread,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "tsc200x", ts);
+ error = devm_request_threaded_irq(dev, irq, NULL, tsc200x_irq_thread,
+ IRQF_ONESHOT, "tsc200x", ts);
if (error) {
dev_err(dev, "Failed to request irq, err: %d\n", error);
return error;
}
- error = regulator_enable(ts->vio);
- if (error)
- return error;
-
dev_set_drvdata(dev, ts);
error = input_register_device(ts->idev);
if (error) {
dev_err(dev,
"Failed to register input device, err: %d\n", error);
- goto disable_regulator;
+ return error;
}
- irq_set_irq_wake(irq, 1);
- return 0;
+ device_init_wakeup(dev,
+ device_property_read_bool(dev, "wakeup-source"));
-disable_regulator:
- regulator_disable(ts->vio);
- return error;
+ return 0;
}
EXPORT_SYMBOL_GPL(tsc200x_probe);
-void tsc200x_remove(struct device *dev)
-{
- struct tsc200x *ts = dev_get_drvdata(dev);
-
- regulator_disable(ts->vio);
-}
-EXPORT_SYMBOL_GPL(tsc200x_remove);
-
static int tsc200x_suspend(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
if (!ts->suspended && ts->opened)
__tsc200x_disable(ts);
ts->suspended = true;
- mutex_unlock(&ts->mutex);
+ if (device_may_wakeup(dev))
+ ts->wake_irq_enabled = enable_irq_wake(ts->irq) == 0;
return 0;
}
@@ -604,15 +575,18 @@ static int tsc200x_resume(struct device *dev)
{
struct tsc200x *ts = dev_get_drvdata(dev);
- mutex_lock(&ts->mutex);
+ guard(mutex)(&ts->mutex);
+
+ if (ts->wake_irq_enabled) {
+ disable_irq_wake(ts->irq);
+ ts->wake_irq_enabled = false;
+ }
if (ts->suspended && ts->opened)
__tsc200x_enable(ts);
ts->suspended = false;
- mutex_unlock(&ts->mutex);
-
return 0;
}
diff --git a/drivers/input/touchscreen/tsc200x-core.h b/drivers/input/touchscreen/tsc200x-core.h
index 37de91efd78e..e76ba7a889dd 100644
--- a/drivers/input/touchscreen/tsc200x-core.h
+++ b/drivers/input/touchscreen/tsc200x-core.h
@@ -75,6 +75,5 @@ extern const struct attribute_group *tsc200x_groups[];
int tsc200x_probe(struct device *dev, int irq, const struct input_id *tsc_id,
struct regmap *regmap,
int (*tsc200x_cmd)(struct device *dev, u8 cmd));
-void tsc200x_remove(struct device *dev);
#endif
diff --git a/drivers/input/touchscreen/tsc40.c b/drivers/input/touchscreen/tsc40.c
index 139577021413..9f485cf57a72 100644
--- a/drivers/input/touchscreen/tsc40.c
+++ b/drivers/input/touchscreen/tsc40.c
@@ -83,7 +83,7 @@ static int tsc_connect(struct serio *serio, struct serio_driver *drv)
struct input_dev *input_dev;
int error;
- ptsc = kzalloc(sizeof(struct tsc_ser), GFP_KERNEL);
+ ptsc = kzalloc(sizeof(*ptsc), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ptsc || !input_dev) {
error = -ENOMEM;
diff --git a/drivers/input/touchscreen/usbtouchscreen.c b/drivers/input/touchscreen/usbtouchscreen.c
index 60354ebc7242..7567efabe014 100644
--- a/drivers/input/touchscreen/usbtouchscreen.c
+++ b/drivers/input/touchscreen/usbtouchscreen.c
@@ -68,8 +68,6 @@ struct usbtouch_device_info {
*/
bool irq_always;
- void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
-
/*
* used to get the packet len. possible return values:
* > 0: packet len
@@ -94,7 +92,7 @@ struct usbtouch_usb {
struct urb *irq;
struct usb_interface *interface;
struct input_dev *input;
- struct usbtouch_device_info *type;
+ const struct usbtouch_device_info *type;
struct mutex pm_mutex; /* serialize access to open/suspend */
bool is_open;
char name[128];
@@ -103,141 +101,8 @@ struct usbtouch_usb {
int x, y;
int touch, press;
-};
-
-
-/* device types */
-enum {
- DEVTYPE_IGNORE = -1,
- DEVTYPE_EGALAX,
- DEVTYPE_PANJIT,
- DEVTYPE_3M,
- DEVTYPE_ITM,
- DEVTYPE_ETURBO,
- DEVTYPE_GUNZE,
- DEVTYPE_DMC_TSC10,
- DEVTYPE_IRTOUCH,
- DEVTYPE_IRTOUCH_HIRES,
- DEVTYPE_IDEALTEK,
- DEVTYPE_GENERAL_TOUCH,
- DEVTYPE_GOTOP,
- DEVTYPE_JASTEC,
- DEVTYPE_E2I,
- DEVTYPE_ZYTRONIC,
- DEVTYPE_TC45USB,
- DEVTYPE_NEXIO,
- DEVTYPE_ELO,
- DEVTYPE_ETOUCH,
-};
-
-#define USB_DEVICE_HID_CLASS(vend, prod) \
- .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
- | USB_DEVICE_ID_MATCH_DEVICE, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = USB_INTERFACE_CLASS_HID
-
-static const struct usb_device_id usbtouch_devices[] = {
-#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
- /* ignore the HID capable devices, handled by usbhid */
- {USB_DEVICE_HID_CLASS(0x0eef, 0x0001), .driver_info = DEVTYPE_IGNORE},
- {USB_DEVICE_HID_CLASS(0x0eef, 0x0002), .driver_info = DEVTYPE_IGNORE},
-
- /* normal device IDs */
- {USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
- {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
- {USB_DEVICE(0x134c, 0x0001), .driver_info = DEVTYPE_PANJIT},
- {USB_DEVICE(0x134c, 0x0002), .driver_info = DEVTYPE_PANJIT},
- {USB_DEVICE(0x134c, 0x0003), .driver_info = DEVTYPE_PANJIT},
- {USB_DEVICE(0x134c, 0x0004), .driver_info = DEVTYPE_PANJIT},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_3M
- {USB_DEVICE(0x0596, 0x0001), .driver_info = DEVTYPE_3M},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ITM
- {USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
- {USB_DEVICE(0x16e3, 0xf9e9), .driver_info = DEVTYPE_ITM},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
- {USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
- {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
- {USB_DEVICE(0x0afa, 0x03e8), .driver_info = DEVTYPE_DMC_TSC10},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
- {USB_DEVICE(0x255e, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
- {USB_DEVICE(0x595a, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
- {USB_DEVICE(0x6615, 0x0001), .driver_info = DEVTYPE_IRTOUCH},
- {USB_DEVICE(0x6615, 0x0012), .driver_info = DEVTYPE_IRTOUCH_HIRES},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
- {USB_DEVICE(0x1391, 0x1000), .driver_info = DEVTYPE_IDEALTEK},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
- {USB_DEVICE(0x0dfc, 0x0001), .driver_info = DEVTYPE_GENERAL_TOUCH},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
- {USB_DEVICE(0x08f2, 0x007f), .driver_info = DEVTYPE_GOTOP},
- {USB_DEVICE(0x08f2, 0x00ce), .driver_info = DEVTYPE_GOTOP},
- {USB_DEVICE(0x08f2, 0x00f4), .driver_info = DEVTYPE_GOTOP},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
- {USB_DEVICE(0x0f92, 0x0001), .driver_info = DEVTYPE_JASTEC},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_E2I
- {USB_DEVICE(0x1ac7, 0x0001), .driver_info = DEVTYPE_E2I},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
- {USB_DEVICE(0x14c8, 0x0003), .driver_info = DEVTYPE_ZYTRONIC},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
- /* TC5UH */
- {USB_DEVICE(0x0664, 0x0309), .driver_info = DEVTYPE_TC45USB},
- /* TC4UM */
- {USB_DEVICE(0x0664, 0x0306), .driver_info = DEVTYPE_TC45USB},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
- /* data interface only */
- {USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
- .driver_info = DEVTYPE_NEXIO},
- {USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
- .driver_info = DEVTYPE_NEXIO},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ELO
- {USB_DEVICE(0x04e7, 0x0020), .driver_info = DEVTYPE_ELO},
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
- {USB_DEVICE(0x7374, 0x0001), .driver_info = DEVTYPE_ETOUCH},
-#endif
- {}
+ void (*process_pkt)(struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
};
@@ -273,6 +138,16 @@ static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info e2i_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 6,
+ .init = e2i_init,
+ .read_data = e2i_read_data,
+};
#endif
@@ -292,9 +167,8 @@ static int e2i_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int egalax_init(struct usbtouch_usb *usbtouch)
{
- int ret, i;
- unsigned char *buf;
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
+ int ret, i;
/*
* An eGalax diagnostic packet kicks the device into using the right
@@ -302,7 +176,7 @@ static int egalax_init(struct usbtouch_usb *usbtouch)
* read later and ignored.
*/
- buf = kmalloc(3, GFP_KERNEL);
+ u8 *buf __free(kfree) = kmalloc(3, GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -316,17 +190,11 @@ static int egalax_init(struct usbtouch_usb *usbtouch)
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0, buf, 3,
USB_CTRL_SET_TIMEOUT);
- if (ret >= 0) {
- ret = 0;
- break;
- }
if (ret != -EPIPE)
break;
}
- kfree(buf);
-
- return ret;
+ return ret < 0 ? ret : 0;
}
static int egalax_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
@@ -356,6 +224,17 @@ static int egalax_get_pkt_len(unsigned char *buf, int len)
return 0;
}
+
+static const struct usbtouch_device_info egalax_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 16,
+ .get_pkt_len = egalax_get_pkt_len,
+ .read_data = egalax_read_data,
+ .init = egalax_init,
+};
#endif
/*****************************************************************************
@@ -402,6 +281,16 @@ static int etouch_get_pkt_len(unsigned char *buf, int len)
return 0;
}
+
+static const struct usbtouch_device_info etouch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 16,
+ .get_pkt_len = etouch_get_pkt_len,
+ .read_data = etouch_read_data,
+};
#endif
/*****************************************************************************
@@ -416,6 +305,15 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info panjit_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .read_data = panjit_read_data,
+};
#endif
@@ -449,35 +347,13 @@ struct mtouch_priv {
u8 fw_rev_minor;
};
-static ssize_t mtouch_firmware_rev_show(struct device *dev,
- struct device_attribute *attr, char *output)
-{
- struct usb_interface *intf = to_usb_interface(dev);
- struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- struct mtouch_priv *priv = usbtouch->priv;
-
- return sysfs_emit(output, "%1x.%1x\n",
- priv->fw_rev_major, priv->fw_rev_minor);
-}
-static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
-
-static struct attribute *mtouch_attrs[] = {
- &dev_attr_firmware_rev.attr,
- NULL
-};
-
-static const struct attribute_group mtouch_attr_group = {
- .attrs = mtouch_attrs,
-};
-
static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
{
struct usb_device *udev = interface_to_usbdev(usbtouch->interface);
struct mtouch_priv *priv = usbtouch->priv;
- u8 *buf;
int ret;
- buf = kzalloc(MTOUCHUSB_REQ_CTRLLR_ID_LEN, GFP_NOIO);
+ u8 *buf __free(kfree) = kzalloc(MTOUCHUSB_REQ_CTRLLR_ID_LEN, GFP_NOIO);
if (!buf)
return -ENOMEM;
@@ -489,36 +365,24 @@ static int mtouch_get_fw_revision(struct usbtouch_usb *usbtouch)
if (ret != MTOUCHUSB_REQ_CTRLLR_ID_LEN) {
dev_warn(&usbtouch->interface->dev,
"Failed to read FW rev: %d\n", ret);
- ret = ret < 0 ? ret : -EIO;
- goto free;
+ return ret < 0 ? ret : -EIO;
}
priv->fw_rev_major = buf[3];
priv->fw_rev_minor = buf[4];
- ret = 0;
-
-free:
- kfree(buf);
- return ret;
+ return 0;
}
static int mtouch_alloc(struct usbtouch_usb *usbtouch)
{
- int ret;
+ struct mtouch_priv *priv;
- usbtouch->priv = kmalloc(sizeof(struct mtouch_priv), GFP_KERNEL);
- if (!usbtouch->priv)
+ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
return -ENOMEM;
- ret = sysfs_create_group(&usbtouch->interface->dev.kobj,
- &mtouch_attr_group);
- if (ret) {
- kfree(usbtouch->priv);
- usbtouch->priv = NULL;
- return ret;
- }
-
+ usbtouch->priv = priv;
return 0;
}
@@ -569,9 +433,53 @@ static void mtouch_exit(struct usbtouch_usb *usbtouch)
{
struct mtouch_priv *priv = usbtouch->priv;
- sysfs_remove_group(&usbtouch->interface->dev.kobj, &mtouch_attr_group);
kfree(priv);
}
+
+static struct usbtouch_device_info mtouch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x4000,
+ .min_yc = 0x0,
+ .max_yc = 0x4000,
+ .rept_size = 11,
+ .read_data = mtouch_read_data,
+ .alloc = mtouch_alloc,
+ .init = mtouch_init,
+ .exit = mtouch_exit,
+};
+
+static ssize_t mtouch_firmware_rev_show(struct device *dev,
+ struct device_attribute *attr, char *output)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+ struct mtouch_priv *priv = usbtouch->priv;
+
+ return sysfs_emit(output, "%1x.%1x\n",
+ priv->fw_rev_major, priv->fw_rev_minor);
+}
+static DEVICE_ATTR(firmware_rev, 0444, mtouch_firmware_rev_show, NULL);
+
+static struct attribute *mtouch_attrs[] = {
+ &dev_attr_firmware_rev.attr,
+ NULL
+};
+
+static bool mtouch_group_visible(struct kobject *kobj)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
+
+ return usbtouch->type == &mtouch_dev_info;
+}
+
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(mtouch);
+
+static const struct attribute_group mtouch_attr_group = {
+ .is_visible = SYSFS_GROUP_VISIBLE(mtouch),
+ .attrs = mtouch_attrs,
+};
#endif
@@ -606,6 +514,16 @@ static int itm_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info itm_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .max_press = 0xff,
+ .rept_size = 8,
+ .read_data = itm_read_data,
+};
#endif
@@ -640,6 +558,16 @@ static int eturbo_get_pkt_len(unsigned char *buf, int len)
return 3;
return 0;
}
+
+static const struct usbtouch_device_info eturbo_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 8,
+ .get_pkt_len = eturbo_get_pkt_len,
+ .read_data = eturbo_read_data,
+};
#endif
@@ -658,6 +586,15 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info gunze_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = gunze_read_data,
+};
#endif
/*****************************************************************************
@@ -686,24 +623,23 @@ static int gunze_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
{
struct usb_device *dev = interface_to_usbdev(usbtouch->interface);
- int ret = -ENOMEM;
- unsigned char *buf;
+ int ret;
- buf = kmalloc(2, GFP_NOIO);
+ u8 *buf __free(kfree) = kmalloc(2, GFP_NOIO);
if (!buf)
- goto err_nobuf;
+ return -ENOMEM;
+
/* reset */
buf[0] = buf[1] = 0xFF;
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
- TSC10_CMD_RESET,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+ TSC10_CMD_RESET,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
- goto err_out;
- if (buf[0] != 0x06) {
- ret = -ENODEV;
- goto err_out;
- }
+ return ret;
+
+ if (buf[0] != 0x06)
+ return -ENODEV;
/* TSC-25 data sheet specifies a delay after the RESET command */
msleep(150);
@@ -711,28 +647,22 @@ static int dmc_tsc10_init(struct usbtouch_usb *usbtouch)
/* set coordinate output rate */
buf[0] = buf[1] = 0xFF;
ret = usb_control_msg(dev, usb_rcvctrlpipe (dev, 0),
- TSC10_CMD_RATE,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
+ TSC10_CMD_RATE,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ TSC10_RATE_150, 0, buf, 2, USB_CTRL_SET_TIMEOUT);
if (ret < 0)
- goto err_out;
- if ((buf[0] != 0x06) && (buf[0] != 0x15 || buf[1] != 0x01)) {
- ret = -ENODEV;
- goto err_out;
- }
+ return ret;
+
+ if (buf[0] != 0x06 && (buf[0] != 0x15 || buf[1] != 0x01))
+ return -ENODEV;
/* start sending data */
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- TSC10_CMD_DATA1,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
-err_out:
- kfree(buf);
-err_nobuf:
- return ret;
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ TSC10_CMD_DATA1,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
-
static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
{
dev->x = ((pkt[2] & 0x03) << 8) | pkt[1];
@@ -741,6 +671,16 @@ static int dmc_tsc10_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info dmc_tsc10_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 5,
+ .init = dmc_tsc10_init,
+ .read_data = dmc_tsc10_read_data,
+};
#endif
@@ -756,6 +696,24 @@ static int irtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info irtouch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .read_data = irtouch_read_data,
+};
+
+static const struct usbtouch_device_info irtouch_hires_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 8,
+ .read_data = irtouch_read_data,
+};
#endif
/*****************************************************************************
@@ -770,6 +728,15 @@ static int tc45usb_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info tc45usb_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 5,
+ .read_data = tc45usb_read_data,
+};
#endif
/*****************************************************************************
@@ -809,6 +776,16 @@ static int idealtek_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 0;
}
}
+
+static const struct usbtouch_device_info idealtek_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 8,
+ .get_pkt_len = idealtek_get_pkt_len,
+ .read_data = idealtek_read_data,
+};
#endif
/*****************************************************************************
@@ -824,6 +801,15 @@ static int general_touch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info general_touch_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x7fff,
+ .min_yc = 0x0,
+ .max_yc = 0x7fff,
+ .rept_size = 7,
+ .read_data = general_touch_read_data,
+};
#endif
/*****************************************************************************
@@ -838,6 +824,15 @@ static int gotop_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info gotop_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 4,
+ .read_data = gotop_read_data,
+};
#endif
/*****************************************************************************
@@ -852,6 +847,15 @@ static int jastec_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
+
+static const struct usbtouch_device_info jastec_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = jastec_read_data,
+};
#endif
/*****************************************************************************
@@ -888,6 +892,16 @@ static int zytronic_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 0;
}
+
+static const struct usbtouch_device_info zytronic_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x03ff,
+ .min_yc = 0x0,
+ .max_yc = 0x03ff,
+ .rept_size = 5,
+ .read_data = zytronic_read_data,
+ .irq_always = true,
+};
#endif
/*****************************************************************************
@@ -924,12 +938,11 @@ static int nexio_alloc(struct usbtouch_usb *usbtouch)
struct nexio_priv *priv;
int ret = -ENOMEM;
- usbtouch->priv = kmalloc(sizeof(struct nexio_priv), GFP_KERNEL);
- if (!usbtouch->priv)
+ priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
goto out_buf;
- priv = usbtouch->priv;
-
+ usbtouch->priv = priv;
priv->ack_buf = kmemdup(nexio_ack_pkt, sizeof(nexio_ack_pkt),
GFP_KERNEL);
if (!priv->ack_buf)
@@ -959,7 +972,6 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
struct nexio_priv *priv = usbtouch->priv;
int ret = -ENOMEM;
int actual_len, i;
- unsigned char *buf;
char *firmware_ver = NULL, *device_name = NULL;
int input_ep = 0, output_ep = 0;
@@ -975,9 +987,9 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
if (!input_ep || !output_ep)
return -ENXIO;
- buf = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
+ u8 *buf __free(kfree) = kmalloc(NEXIO_BUFSIZE, GFP_NOIO);
if (!buf)
- goto out_buf;
+ return -ENOMEM;
/* two empty reads */
for (i = 0; i < 2; i++) {
@@ -985,7 +997,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
buf, NEXIO_BUFSIZE, &actual_len,
NEXIO_TIMEOUT);
if (ret < 0)
- goto out_buf;
+ return ret;
}
/* send init command */
@@ -994,7 +1006,7 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
buf, sizeof(nexio_init_pkt), &actual_len,
NEXIO_TIMEOUT);
if (ret < 0)
- goto out_buf;
+ return ret;
/* read replies */
for (i = 0; i < 3; i++) {
@@ -1025,11 +1037,8 @@ static int nexio_init(struct usbtouch_usb *usbtouch)
usb_fill_bulk_urb(priv->ack, dev, usb_sndbulkpipe(dev, output_ep),
priv->ack_buf, sizeof(nexio_ack_pkt),
nexio_ack_complete, usbtouch);
- ret = 0;
-out_buf:
- kfree(buf);
- return ret;
+ return 0;
}
static void nexio_exit(struct usbtouch_usb *usbtouch)
@@ -1066,13 +1075,11 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
if (ret)
dev_warn(dev, "Failed to submit ACK URB: %d\n", ret);
- if (!usbtouch->type->max_xc) {
- usbtouch->type->max_xc = 2 * x_len;
+ if (!input_abs_get_max(usbtouch->input, ABS_X)) {
input_set_abs_params(usbtouch->input, ABS_X,
- 0, usbtouch->type->max_xc, 0, 0);
- usbtouch->type->max_yc = 2 * y_len;
+ 0, 2 * x_len, 0, 0);
input_set_abs_params(usbtouch->input, ABS_Y,
- 0, usbtouch->type->max_yc, 0, 0);
+ 0, 2 * y_len, 0, 0);
}
/*
* The device reports state of IR sensors on X and Y axes.
@@ -1127,6 +1134,15 @@ static int nexio_read_data(struct usbtouch_usb *usbtouch, unsigned char *pkt)
}
return 0;
}
+
+static const struct usbtouch_device_info nexio_dev_info = {
+ .rept_size = 1024,
+ .irq_always = true,
+ .read_data = nexio_read_data,
+ .alloc = nexio_alloc,
+ .init = nexio_init,
+ .exit = nexio_exit,
+};
#endif
@@ -1145,241 +1161,17 @@ static int elo_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
return 1;
}
-#endif
-
-
-/*****************************************************************************
- * the different device descriptors
- */
-#ifdef MULTI_PACKET
-static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
- unsigned char *pkt, int len);
-#endif
-
-static struct usbtouch_device_info usbtouch_dev_info[] = {
-#ifdef CONFIG_TOUCHSCREEN_USB_ELO
- [DEVTYPE_ELO] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .max_press = 0xff,
- .rept_size = 8,
- .read_data = elo_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
- [DEVTYPE_EGALAX] = {
- .min_xc = 0x0,
- .max_xc = 0x07ff,
- .min_yc = 0x0,
- .max_yc = 0x07ff,
- .rept_size = 16,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = egalax_get_pkt_len,
- .read_data = egalax_read_data,
- .init = egalax_init,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
- [DEVTYPE_PANJIT] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 8,
- .read_data = panjit_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_3M
- [DEVTYPE_3M] = {
- .min_xc = 0x0,
- .max_xc = 0x4000,
- .min_yc = 0x0,
- .max_yc = 0x4000,
- .rept_size = 11,
- .read_data = mtouch_read_data,
- .alloc = mtouch_alloc,
- .init = mtouch_init,
- .exit = mtouch_exit,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ITM
- [DEVTYPE_ITM] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .max_press = 0xff,
- .rept_size = 8,
- .read_data = itm_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
- [DEVTYPE_ETURBO] = {
- .min_xc = 0x0,
- .max_xc = 0x07ff,
- .min_yc = 0x0,
- .max_yc = 0x07ff,
- .rept_size = 8,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = eturbo_get_pkt_len,
- .read_data = eturbo_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
- [DEVTYPE_GUNZE] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 4,
- .read_data = gunze_read_data,
- },
-#endif
-#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
- [DEVTYPE_DMC_TSC10] = {
- .min_xc = 0x0,
- .max_xc = 0x03ff,
- .min_yc = 0x0,
- .max_yc = 0x03ff,
- .rept_size = 5,
- .init = dmc_tsc10_init,
- .read_data = dmc_tsc10_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
- [DEVTYPE_IRTOUCH] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 8,
- .read_data = irtouch_read_data,
- },
-
- [DEVTYPE_IRTOUCH_HIRES] = {
- .min_xc = 0x0,
- .max_xc = 0x7fff,
- .min_yc = 0x0,
- .max_yc = 0x7fff,
- .rept_size = 8,
- .read_data = irtouch_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
- [DEVTYPE_IDEALTEK] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 8,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = idealtek_get_pkt_len,
- .read_data = idealtek_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
- [DEVTYPE_GENERAL_TOUCH] = {
- .min_xc = 0x0,
- .max_xc = 0x7fff,
- .min_yc = 0x0,
- .max_yc = 0x7fff,
- .rept_size = 7,
- .read_data = general_touch_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
- [DEVTYPE_GOTOP] = {
- .min_xc = 0x0,
- .max_xc = 0x03ff,
- .min_yc = 0x0,
- .max_yc = 0x03ff,
- .rept_size = 4,
- .read_data = gotop_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
- [DEVTYPE_JASTEC] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 4,
- .read_data = jastec_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_E2I
- [DEVTYPE_E2I] = {
- .min_xc = 0x0,
- .max_xc = 0x7fff,
- .min_yc = 0x0,
- .max_yc = 0x7fff,
- .rept_size = 6,
- .init = e2i_init,
- .read_data = e2i_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
- [DEVTYPE_ZYTRONIC] = {
- .min_xc = 0x0,
- .max_xc = 0x03ff,
- .min_yc = 0x0,
- .max_yc = 0x03ff,
- .rept_size = 5,
- .read_data = zytronic_read_data,
- .irq_always = true,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
- [DEVTYPE_TC45USB] = {
- .min_xc = 0x0,
- .max_xc = 0x0fff,
- .min_yc = 0x0,
- .max_yc = 0x0fff,
- .rept_size = 5,
- .read_data = tc45usb_read_data,
- },
-#endif
-
-#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
- [DEVTYPE_NEXIO] = {
- .rept_size = 1024,
- .irq_always = true,
- .read_data = nexio_read_data,
- .alloc = nexio_alloc,
- .init = nexio_init,
- .exit = nexio_exit,
- },
-#endif
-#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
- [DEVTYPE_ETOUCH] = {
- .min_xc = 0x0,
- .max_xc = 0x07ff,
- .min_yc = 0x0,
- .max_yc = 0x07ff,
- .rept_size = 16,
- .process_pkt = usbtouch_process_multi,
- .get_pkt_len = etouch_get_pkt_len,
- .read_data = etouch_read_data,
- },
-#endif
+static const struct usbtouch_device_info elo_dev_info = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .max_press = 0xff,
+ .rept_size = 8,
+ .read_data = elo_read_data,
};
+#endif
/*****************************************************************************
@@ -1388,10 +1180,10 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
unsigned char *pkt, int len)
{
- struct usbtouch_device_info *type = usbtouch->type;
+ const struct usbtouch_device_info *type = usbtouch->type;
if (!type->read_data(usbtouch, pkt))
- return;
+ return;
input_report_key(usbtouch->input, BTN_TOUCH, usbtouch->touch);
@@ -1484,9 +1276,15 @@ out_flush_buf:
usbtouch->buf_len = 0;
return;
}
+#else
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+ unsigned char *pkt, int len)
+{
+ dev_WARN_ONCE(&usbtouch->interface->dev, 1,
+ "Protocol has ->get_pkt_len() without #define MULTI_PACKET");
+}
#endif
-
static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
@@ -1517,7 +1315,7 @@ static void usbtouch_irq(struct urb *urb)
goto exit;
}
- usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
+ usbtouch->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
exit:
usb_mark_last_busy(interface_to_usbdev(usbtouch->interface));
@@ -1527,6 +1325,20 @@ exit:
__func__, retval);
}
+static int usbtouch_start_io(struct usbtouch_usb *usbtouch)
+{
+ guard(mutex)(&usbtouch->pm_mutex);
+
+ if (!usbtouch->type->irq_always)
+ if (usb_submit_urb(usbtouch->irq, GFP_KERNEL))
+ return -EIO;
+
+ usbtouch->interface->needs_remote_wakeup = 1;
+ usbtouch->is_open = true;
+
+ return 0;
+}
+
static int usbtouch_open(struct input_dev *input)
{
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
@@ -1535,23 +1347,12 @@ static int usbtouch_open(struct input_dev *input)
usbtouch->irq->dev = interface_to_usbdev(usbtouch->interface);
r = usb_autopm_get_interface(usbtouch->interface) ? -EIO : 0;
- if (r < 0)
- goto out;
-
- mutex_lock(&usbtouch->pm_mutex);
- if (!usbtouch->type->irq_always) {
- if (usb_submit_urb(usbtouch->irq, GFP_KERNEL)) {
- r = -EIO;
- goto out_put;
- }
- }
+ if (r)
+ return r;
+
+ r = usbtouch_start_io(usbtouch);
- usbtouch->interface->needs_remote_wakeup = 1;
- usbtouch->is_open = true;
-out_put:
- mutex_unlock(&usbtouch->pm_mutex);
usb_autopm_put_interface(usbtouch->interface);
-out:
return r;
}
@@ -1560,11 +1361,11 @@ static void usbtouch_close(struct input_dev *input)
struct usbtouch_usb *usbtouch = input_get_drvdata(input);
int r;
- mutex_lock(&usbtouch->pm_mutex);
- if (!usbtouch->type->irq_always)
- usb_kill_urb(usbtouch->irq);
- usbtouch->is_open = false;
- mutex_unlock(&usbtouch->pm_mutex);
+ scoped_guard(mutex, &usbtouch->pm_mutex) {
+ if (!usbtouch->type->irq_always)
+ usb_kill_urb(usbtouch->irq);
+ usbtouch->is_open = false;
+ }
r = usb_autopm_get_interface(usbtouch->interface);
usbtouch->interface->needs_remote_wakeup = 0;
@@ -1572,8 +1373,7 @@ static void usbtouch_close(struct input_dev *input)
usb_autopm_put_interface(usbtouch->interface);
}
-static int usbtouch_suspend
-(struct usb_interface *intf, pm_message_t message)
+static int usbtouch_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
@@ -1585,20 +1385,19 @@ static int usbtouch_suspend
static int usbtouch_resume(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- int result = 0;
- mutex_lock(&usbtouch->pm_mutex);
+ guard(mutex)(&usbtouch->pm_mutex);
+
if (usbtouch->is_open || usbtouch->type->irq_always)
- result = usb_submit_urb(usbtouch->irq, GFP_NOIO);
- mutex_unlock(&usbtouch->pm_mutex);
+ return usb_submit_urb(usbtouch->irq, GFP_NOIO);
- return result;
+ return 0;
}
static int usbtouch_reset_resume(struct usb_interface *intf)
{
struct usbtouch_usb *usbtouch = usb_get_intfdata(intf);
- int err = 0;
+ int err;
/* reinit the device */
if (usbtouch->type->init) {
@@ -1612,12 +1411,12 @@ static int usbtouch_reset_resume(struct usb_interface *intf)
}
/* restart IO if needed */
- mutex_lock(&usbtouch->pm_mutex);
+ guard(mutex)(&usbtouch->pm_mutex);
+
if (usbtouch->is_open)
- err = usb_submit_urb(usbtouch->irq, GFP_NOIO);
- mutex_unlock(&usbtouch->pm_mutex);
+ return usb_submit_urb(usbtouch->irq, GFP_NOIO);
- return err;
+ return 0;
}
static void usbtouch_free_buffers(struct usb_device *udev,
@@ -1647,31 +1446,25 @@ static int usbtouch_probe(struct usb_interface *intf,
struct input_dev *input_dev;
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
- struct usbtouch_device_info *type;
+ const struct usbtouch_device_info *type;
int err = -ENOMEM;
/* some devices are ignored */
- if (id->driver_info == DEVTYPE_IGNORE)
- return -ENODEV;
-
- if (id->driver_info >= ARRAY_SIZE(usbtouch_dev_info))
+ type = (const struct usbtouch_device_info *)id->driver_info;
+ if (!type)
return -ENODEV;
endpoint = usbtouch_get_input_endpoint(intf->cur_altsetting);
if (!endpoint)
return -ENXIO;
- usbtouch = kzalloc(sizeof(struct usbtouch_usb), GFP_KERNEL);
+ usbtouch = kzalloc(sizeof(*usbtouch), GFP_KERNEL);
input_dev = input_allocate_device();
if (!usbtouch || !input_dev)
goto out_free;
mutex_init(&usbtouch->pm_mutex);
-
- type = &usbtouch_dev_info[id->driver_info];
usbtouch->type = type;
- if (!type->process_pkt)
- type->process_pkt = usbtouch_process_pkt;
usbtouch->data_size = type->rept_size;
if (type->get_pkt_len) {
@@ -1695,6 +1488,9 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->buffer = kmalloc(type->rept_size, GFP_KERNEL);
if (!usbtouch->buffer)
goto out_free_buffers;
+ usbtouch->process_pkt = usbtouch_process_multi;
+ } else {
+ usbtouch->process_pkt = usbtouch_process_pkt;
}
usbtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
@@ -1841,6 +1637,150 @@ static void usbtouch_disconnect(struct usb_interface *intf)
kfree(usbtouch);
}
+static const struct attribute_group *usbtouch_groups[] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+ &mtouch_attr_group,
+#endif
+ NULL
+};
+
+static const struct usb_device_id usbtouch_devices[] = {
+#ifdef CONFIG_TOUCHSCREEN_USB_EGALAX
+ /* ignore the HID capable devices, handled by usbhid */
+ { USB_DEVICE_INTERFACE_CLASS(0x0eef, 0x0001, USB_INTERFACE_CLASS_HID),
+ .driver_info = 0 },
+ { USB_DEVICE_INTERFACE_CLASS(0x0eef, 0x0002, USB_INTERFACE_CLASS_HID),
+ .driver_info = 0 },
+
+ /* normal device IDs */
+ { USB_DEVICE(0x3823, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x3823, 0x0002),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x0123, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x0eef, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x0eef, 0x0002),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x1234, 0x0001),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+ { USB_DEVICE(0x1234, 0x0002),
+ .driver_info = (kernel_ulong_t)&egalax_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_PANJIT
+ { USB_DEVICE(0x134c, 0x0001),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+ { USB_DEVICE(0x134c, 0x0002),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+ { USB_DEVICE(0x134c, 0x0003),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+ { USB_DEVICE(0x134c, 0x0004),
+ .driver_info = (kernel_ulong_t)&panjit_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_3M
+ { USB_DEVICE(0x0596, 0x0001),
+ .driver_info = (kernel_ulong_t)&mtouch_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ITM
+ { USB_DEVICE(0x0403, 0xf9e9),
+ .driver_info = (kernel_ulong_t)&itm_dev_info },
+ { USB_DEVICE(0x16e3, 0xf9e9),
+ .driver_info = (kernel_ulong_t)&itm_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETURBO
+ { USB_DEVICE(0x1234, 0x5678),
+ .driver_info = (kernel_ulong_t)&eturbo_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GUNZE
+ { USB_DEVICE(0x0637, 0x0001),
+ .driver_info = (kernel_ulong_t)&gunze_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_DMC_TSC10
+ { USB_DEVICE(0x0afa, 0x03e8),
+ .driver_info = (kernel_ulong_t)&dmc_tsc10_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IRTOUCH
+ { USB_DEVICE(0x255e, 0x0001),
+ .driver_info = (kernel_ulong_t)&irtouch_dev_info },
+ { USB_DEVICE(0x595a, 0x0001),
+ .driver_info = (kernel_ulong_t)&irtouch_dev_info },
+ { USB_DEVICE(0x6615, 0x0001),
+ .driver_info = (kernel_ulong_t)&irtouch_dev_info },
+ { USB_DEVICE(0x6615, 0x0012),
+ .driver_info = (kernel_ulong_t)&irtouch_hires_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_IDEALTEK
+ { USB_DEVICE(0x1391, 0x1000),
+ .driver_info = (kernel_ulong_t)&idealtek_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH
+ { USB_DEVICE(0x0dfc, 0x0001),
+ .driver_info = (kernel_ulong_t)&general_touch_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_GOTOP
+ { USB_DEVICE(0x08f2, 0x007f),
+ .driver_info = (kernel_ulong_t)&gotop_dev_info },
+ { USB_DEVICE(0x08f2, 0x00ce),
+ .driver_info = (kernel_ulong_t)&gotop_dev_info },
+ { USB_DEVICE(0x08f2, 0x00f4),
+ .driver_info = (kernel_ulong_t)&gotop_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_JASTEC
+ { USB_DEVICE(0x0f92, 0x0001),
+ .driver_info = (kernel_ulong_t)&jastec_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_E2I
+ { USB_DEVICE(0x1ac7, 0x0001),
+ .driver_info = (kernel_ulong_t)&e2i_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ZYTRONIC
+ { USB_DEVICE(0x14c8, 0x0003),
+ .driver_info = (kernel_ulong_t)&zytronic_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ETT_TC45USB
+ /* TC5UH */
+ { USB_DEVICE(0x0664, 0x0309),
+ .driver_info = (kernel_ulong_t)&tc45usb_dev_info },
+ /* TC4UM */
+ { USB_DEVICE(0x0664, 0x0306),
+ .driver_info = (kernel_ulong_t)&tc45usb_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_NEXIO
+ /* data interface only */
+ { USB_DEVICE_AND_INTERFACE_INFO(0x10f0, 0x2002, 0x0a, 0x00, 0x00),
+ .driver_info = (kernel_ulong_t)&nexio_dev_info },
+ { USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00),
+ .driver_info = (kernel_ulong_t)&nexio_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_ELO
+ { USB_DEVICE(0x04e7, 0x0020),
+ .driver_info = (kernel_ulong_t)&elo_dev_info },
+#endif
+
+#ifdef CONFIG_TOUCHSCREEN_USB_EASYTOUCH
+ { USB_DEVICE(0x7374, 0x0001),
+ .driver_info = (kernel_ulong_t)&etouch_dev_info },
+#endif
+
+ { }
+};
MODULE_DEVICE_TABLE(usb, usbtouch_devices);
static struct usb_driver usbtouch_driver = {
@@ -1851,6 +1791,7 @@ static struct usb_driver usbtouch_driver = {
.resume = usbtouch_resume,
.reset_resume = usbtouch_reset_resume,
.id_table = usbtouch_devices,
+ .dev_groups = usbtouch_groups,
.supports_autosuspend = 1,
};
diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c
index 486230985bf0..fd97a83f5664 100644
--- a/drivers/input/touchscreen/wacom_i2c.c
+++ b/drivers/input/touchscreen/wacom_i2c.c
@@ -13,7 +13,7 @@
#include <linux/slab.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
/* Bitmasks (for data[3]) */
#define WACOM_TIP_SWITCH BIT(0)
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 928c5ee3ac36..ed2ca8a689d5 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -380,30 +380,28 @@ static int w8001_open(struct input_dev *dev)
struct w8001 *w8001 = input_get_drvdata(dev);
int err;
- err = mutex_lock_interruptible(&w8001->mutex);
- if (err)
- return err;
+ scoped_guard(mutex_intr, &w8001->mutex) {
+ if (w8001->open_count == 0) {
+ err = w8001_command(w8001, W8001_CMD_START, false);
+ if (err)
+ return err;
+ }
- if (w8001->open_count++ == 0) {
- err = w8001_command(w8001, W8001_CMD_START, false);
- if (err)
- w8001->open_count--;
+ w8001->open_count++;
+ return 0;
}
- mutex_unlock(&w8001->mutex);
- return err;
+ return -EINTR;
}
static void w8001_close(struct input_dev *dev)
{
struct w8001 *w8001 = input_get_drvdata(dev);
- mutex_lock(&w8001->mutex);
+ guard(mutex)(&w8001->mutex);
if (--w8001->open_count == 0)
w8001_command(w8001, W8001_CMD_STOP, false);
-
- mutex_unlock(&w8001->mutex);
}
static int w8001_detect(struct w8001 *w8001)
@@ -595,10 +593,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
struct w8001 *w8001;
struct input_dev *input_dev_pen;
struct input_dev *input_dev_touch;
- char basename[64];
+ char basename[64] = "Wacom Serial";
int err, err_pen, err_touch;
- w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL);
+ w8001 = kzalloc(sizeof(*w8001), GFP_KERNEL);
input_dev_pen = input_allocate_device();
input_dev_touch = input_allocate_device();
if (!w8001 || !input_dev_pen || !input_dev_touch) {
@@ -625,8 +623,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
/* For backwards-compatibility we compose the basename based on
* capabilities and then just append the tool type
*/
- strscpy(basename, "Wacom Serial", sizeof(basename));
-
err_pen = w8001_setup_pen(w8001, basename, sizeof(basename));
err_touch = w8001_setup_touch(w8001, basename, sizeof(basename));
if (err_pen && err_touch) {
@@ -635,8 +631,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
if (!err_pen) {
- strscpy(w8001->pen_name, basename, sizeof(w8001->pen_name));
- strlcat(w8001->pen_name, " Pen", sizeof(w8001->pen_name));
+ snprintf(w8001->pen_name, sizeof(w8001->pen_name),
+ "%s Pen", basename);
input_dev_pen->name = w8001->pen_name;
w8001_set_devdata(input_dev_pen, w8001, serio);
@@ -651,9 +647,8 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
}
if (!err_touch) {
- strscpy(w8001->touch_name, basename, sizeof(w8001->touch_name));
- strlcat(w8001->touch_name, " Finger",
- sizeof(w8001->touch_name));
+ snprintf(w8001->touch_name, sizeof(w8001->touch_name),
+ "%s Finger", basename);
input_dev_touch->name = w8001->touch_name;
w8001_set_devdata(input_dev_touch, w8001, serio);
diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c
index 698fc7e0ee7f..88d376090e6e 100644
--- a/drivers/input/touchscreen/wdt87xx_i2c.c
+++ b/drivers/input/touchscreen/wdt87xx_i2c.c
@@ -20,7 +20,7 @@
#include <linux/firmware.h>
#include <linux/input/mt.h>
#include <linux/acpi.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define WDT87XX_NAME "wdt87xx_i2c"
#define WDT87XX_FW_NAME "wdt87xx_fw.bin"
@@ -1153,11 +1153,13 @@ static const struct i2c_device_id wdt87xx_dev_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wdt87xx_dev_id);
+#ifdef CONFIG_ACPI
static const struct acpi_device_id wdt87xx_acpi_id[] = {
{ "WDHT0001", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, wdt87xx_acpi_id);
+#endif
static struct i2c_driver wdt87xx_driver = {
.probe = wdt87xx_ts_probe,
diff --git a/drivers/input/touchscreen/wm831x-ts.c b/drivers/input/touchscreen/wm831x-ts.c
index 9cee26b63341..98f8ec408cad 100644
--- a/drivers/input/touchscreen/wm831x-ts.c
+++ b/drivers/input/touchscreen/wm831x-ts.c
@@ -387,7 +387,7 @@ static struct platform_driver wm831x_ts_driver = {
.name = "wm831x-touch",
},
.probe = wm831x_ts_probe,
- .remove_new = wm831x_ts_remove,
+ .remove = wm831x_ts_remove,
};
module_platform_driver(wm831x_ts_driver);
diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
index 4b55d5e1ea0f..96484aae030c 100644
--- a/drivers/input/touchscreen/wm9705.c
+++ b/drivers/input/touchscreen/wm9705.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
index 6947714dfefa..087ece57741a 100644
--- a/drivers/input/touchscreen/wm9712.c
+++ b/drivers/input/touchscreen/wm9712.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
index a67fbe304f92..6f13f46ce6e6 100644
--- a/drivers/input/touchscreen/wm9713.c
+++ b/drivers/input/touchscreen/wm9713.c
@@ -9,6 +9,7 @@
* Russell King <rmk@arm.linux.org.uk>
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index f01f6cc9b59f..96354c44af87 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -29,6 +29,7 @@
* - Support for async sampling control for noisy LCDs.
*/
+#include <linux/export.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
@@ -222,7 +223,7 @@ EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
/*
* Codec GPIO pin configuration, this sets pin direction, polarity,
- * stickyness and wake up.
+ * stickiness and wake up.
*/
void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky,
@@ -403,7 +404,7 @@ static int wm97xx_read_samples(struct wm97xx *wm)
* is actively working with the touchscreen we
* don't want to lose the quick response. So we
* will slowly increase sleep time after the
- * pen is up and quicky restore it to ~one task
+ * pen is up and quickly restore it to ~one task
* switch when pen is down again.
*/
if (wm->ts_reader_interval < HZ / 10)
@@ -876,7 +877,7 @@ static struct platform_driver wm97xx_mfd_driver = {
.pm = pm_sleep_ptr(&wm97xx_pm_ops),
},
.probe = wm97xx_mfd_probe,
- .remove_new = wm97xx_mfd_remove,
+ .remove = wm97xx_mfd_remove,
};
static int __init wm97xx_init(void)
diff --git a/drivers/input/touchscreen/zet6223.c b/drivers/input/touchscreen/zet6223.c
index 27333fded9a9..943634ba9cd9 100644
--- a/drivers/input/touchscreen/zet6223.c
+++ b/drivers/input/touchscreen/zet6223.c
@@ -11,7 +11,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
-#include <asm/unaligned.h>
+#include <linux/unaligned.h>
#define ZET6223_MAX_FINGERS 16
#define ZET6223_MAX_PKT_SIZE (3 + 4 * ZET6223_MAX_FINGERS)
diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c
index fdf2d1e770c8..df42fdf36ae3 100644
--- a/drivers/input/touchscreen/zforce_ts.c
+++ b/drivers/input/touchscreen/zforce_ts.c
@@ -9,21 +9,20 @@
* Author: Pieter Truter<ptruter@intrinsyc.com>
*/
-#include <linux/module.h>
-#include <linux/hrtimer.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/i2c.h>
#include <linux/delay.h>
-#include <linux/gpio/consumer.h>
#include <linux/device.h>
-#include <linux/sysfs.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/platform_data/zforce_ts.h>
-#include <linux/regulator/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/of.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
#define WAIT_TIMEOUT msecs_to_jiffies(1000)
@@ -97,9 +96,7 @@ struct zforce_point {
* @suspending in the process of going to suspend (don't emit wakeup
* events for commands executed to suspend the device)
* @suspended device suspended
- * @access_mutex serialize i2c-access, to keep multipart reads together
* @command_done completion to wait for the command result
- * @command_mutex serialize commands sent to the ic
* @command_waiting the id of the command that is currently waiting
* for a result
* @command_result returned result of the command
@@ -108,11 +105,8 @@ struct zforce_ts {
struct i2c_client *client;
struct input_dev *input;
struct touchscreen_properties prop;
- const struct zforce_ts_platdata *pdata;
char phys[32];
- struct regulator *reg_vdd;
-
struct gpio_desc *gpio_int;
struct gpio_desc *gpio_rst;
@@ -126,10 +120,7 @@ struct zforce_ts {
u16 version_build;
u16 version_rev;
- struct mutex access_mutex;
-
struct completion command_done;
- struct mutex command_mutex;
int command_waiting;
int command_result;
};
@@ -146,9 +137,7 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd)
buf[1] = 1; /* data size, command only */
buf[2] = cmd;
- mutex_lock(&ts->access_mutex);
ret = i2c_master_send(client, &buf[0], ARRAY_SIZE(buf));
- mutex_unlock(&ts->access_mutex);
if (ret < 0) {
dev_err(&client->dev, "i2c send data request error: %d\n", ret);
return ret;
@@ -157,59 +146,36 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd)
return 0;
}
-static void zforce_reset_assert(struct zforce_ts *ts)
-{
- gpiod_set_value_cansleep(ts->gpio_rst, 1);
-}
-
-static void zforce_reset_deassert(struct zforce_ts *ts)
-{
- gpiod_set_value_cansleep(ts->gpio_rst, 0);
-}
-
static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len)
{
struct i2c_client *client = ts->client;
int ret;
- ret = mutex_trylock(&ts->command_mutex);
- if (!ret) {
- dev_err(&client->dev, "already waiting for a command\n");
- return -EBUSY;
- }
-
dev_dbg(&client->dev, "sending %d bytes for command 0x%x\n",
buf[1], buf[2]);
ts->command_waiting = buf[2];
- mutex_lock(&ts->access_mutex);
ret = i2c_master_send(client, buf, len);
- mutex_unlock(&ts->access_mutex);
if (ret < 0) {
dev_err(&client->dev, "i2c send data request error: %d\n", ret);
- goto unlock;
+ return ret;
}
dev_dbg(&client->dev, "waiting for result for command 0x%x\n", buf[2]);
- if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) {
- ret = -ETIME;
- goto unlock;
- }
+ if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)
+ return -ETIME;
ret = ts->command_result;
-
-unlock:
- mutex_unlock(&ts->command_mutex);
- return ret;
+ return 0;
}
static int zforce_command_wait(struct zforce_ts *ts, u8 cmd)
{
struct i2c_client *client = ts->client;
char buf[3];
- int ret;
+ int error;
dev_dbg(&client->dev, "%s: 0x%x\n", __func__, cmd);
@@ -217,10 +183,11 @@ static int zforce_command_wait(struct zforce_ts *ts, u8 cmd)
buf[1] = 1; /* data size, command only */
buf[2] = cmd;
- ret = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
- if (ret < 0) {
- dev_err(&client->dev, "i2c send data request error: %d\n", ret);
- return ret;
+ error = zforce_send_wait(ts, &buf[0], ARRAY_SIZE(buf));
+ if (error) {
+ dev_err(&client->dev, "i2c send data request error: %d\n",
+ error);
+ return error;
}
return 0;
@@ -268,40 +235,40 @@ static int zforce_setconfig(struct zforce_ts *ts, char b1)
static int zforce_start(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
- int ret;
+ int error;
dev_dbg(&client->dev, "starting device\n");
- ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
- if (ret) {
- dev_err(&client->dev, "Unable to initialize, %d\n", ret);
- return ret;
+ error = zforce_command_wait(ts, COMMAND_INITIALIZE);
+ if (error) {
+ dev_err(&client->dev, "Unable to initialize, %d\n", error);
+ return error;
}
- ret = zforce_resolution(ts, ts->prop.max_x, ts->prop.max_y);
- if (ret) {
- dev_err(&client->dev, "Unable to set resolution, %d\n", ret);
- goto error;
+ error = zforce_resolution(ts, ts->prop.max_x, ts->prop.max_y);
+ if (error) {
+ dev_err(&client->dev, "Unable to set resolution, %d\n", error);
+ goto err_deactivate;
}
- ret = zforce_scan_frequency(ts, 10, 50, 50);
- if (ret) {
+ error = zforce_scan_frequency(ts, 10, 50, 50);
+ if (error) {
dev_err(&client->dev, "Unable to set scan frequency, %d\n",
- ret);
- goto error;
+ error);
+ goto err_deactivate;
}
- ret = zforce_setconfig(ts, SETCONFIG_DUALTOUCH);
- if (ret) {
+ error = zforce_setconfig(ts, SETCONFIG_DUALTOUCH);
+ if (error) {
dev_err(&client->dev, "Unable to set config\n");
- goto error;
+ goto err_deactivate;
}
/* start sending touch events */
- ret = zforce_command(ts, COMMAND_DATAREQUEST);
- if (ret) {
+ error = zforce_command(ts, COMMAND_DATAREQUEST);
+ if (error) {
dev_err(&client->dev, "Unable to request data\n");
- goto error;
+ goto err_deactivate;
}
/*
@@ -312,24 +279,24 @@ static int zforce_start(struct zforce_ts *ts)
return 0;
-error:
+err_deactivate:
zforce_command_wait(ts, COMMAND_DEACTIVATE);
- return ret;
+ return error;
}
static int zforce_stop(struct zforce_ts *ts)
{
struct i2c_client *client = ts->client;
- int ret;
+ int error;
dev_dbg(&client->dev, "stopping device\n");
/* Deactivates touch sensing and puts the device into sleep. */
- ret = zforce_command_wait(ts, COMMAND_DEACTIVATE);
- if (ret != 0) {
+ error = zforce_command_wait(ts, COMMAND_DEACTIVATE);
+ if (error) {
dev_err(&client->dev, "could not deactivate device, %d\n",
- ret);
- return ret;
+ error);
+ return error;
}
return 0;
@@ -340,6 +307,7 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
struct i2c_client *client = ts->client;
struct zforce_point point;
int count, i, num = 0;
+ u8 *p;
count = payload[0];
if (count > ZFORCE_REPORT_POINTS) {
@@ -350,10 +318,10 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
}
for (i = 0; i < count; i++) {
- point.coord_x =
- payload[9 * i + 2] << 8 | payload[9 * i + 1];
- point.coord_y =
- payload[9 * i + 4] << 8 | payload[9 * i + 3];
+ p = &payload[i * 9 + 1];
+
+ point.coord_x = get_unaligned_le16(&p[0]);
+ point.coord_y = get_unaligned_le16(&p[2]);
if (point.coord_x > ts->prop.max_x ||
point.coord_y > ts->prop.max_y) {
@@ -362,18 +330,16 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
point.coord_x = point.coord_y = 0;
}
- point.state = payload[9 * i + 5] & 0x0f;
- point.id = (payload[9 * i + 5] & 0xf0) >> 4;
+ point.state = p[4] & 0x0f;
+ point.id = (p[4] & 0xf0) >> 4;
/* determine touch major, minor and orientation */
- point.area_major = max(payload[9 * i + 6],
- payload[9 * i + 7]);
- point.area_minor = min(payload[9 * i + 6],
- payload[9 * i + 7]);
- point.orientation = payload[9 * i + 6] > payload[9 * i + 7];
+ point.area_major = max(p[5], p[6]);
+ point.area_minor = min(p[5], p[6]);
+ point.orientation = p[5] > p[6];
- point.pressure = payload[9 * i + 8];
- point.prblty = payload[9 * i + 9];
+ point.pressure = p[7];
+ point.prblty = p[8];
dev_dbg(&client->dev,
"point %d/%d: state %d, id %d, pressure %d, prblty %d, x %d, y %d, amajor %d, aminor %d, ori %d\n",
@@ -386,10 +352,8 @@ static int zforce_touch_event(struct zforce_ts *ts, u8 *payload)
/* the zforce id starts with "1", so needs to be decreased */
input_mt_slot(ts->input, point.id - 1);
- input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,
- point.state != STATE_UP);
-
- if (point.state != STATE_UP) {
+ if (input_mt_report_slot_state(ts->input, MT_TOOL_FINGER,
+ point.state != STATE_UP)) {
touchscreen_report_pos(ts->input, &ts->prop,
point.coord_x, point.coord_y,
true);
@@ -417,41 +381,35 @@ static int zforce_read_packet(struct zforce_ts *ts, u8 *buf)
struct i2c_client *client = ts->client;
int ret;
- mutex_lock(&ts->access_mutex);
-
/* read 2 byte message header */
ret = i2c_master_recv(client, buf, 2);
if (ret < 0) {
dev_err(&client->dev, "error reading header: %d\n", ret);
- goto unlock;
+ return ret;
}
if (buf[PAYLOAD_HEADER] != FRAME_START) {
dev_err(&client->dev, "invalid frame start: %d\n", buf[0]);
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
if (buf[PAYLOAD_LENGTH] == 0) {
dev_err(&client->dev, "invalid payload length: %d\n",
buf[PAYLOAD_LENGTH]);
- ret = -EIO;
- goto unlock;
+ return -EIO;
}
/* read the message */
ret = i2c_master_recv(client, &buf[PAYLOAD_BODY], buf[PAYLOAD_LENGTH]);
if (ret < 0) {
dev_err(&client->dev, "error reading payload: %d\n", ret);
- goto unlock;
+ return ret;
}
dev_dbg(&client->dev, "read %d bytes for response command 0x%x\n",
buf[PAYLOAD_LENGTH], buf[PAYLOAD_BODY]);
-unlock:
- mutex_unlock(&ts->access_mutex);
- return ret;
+ return 0;
}
static void zforce_complete(struct zforce_ts *ts, int cmd, int result)
@@ -482,9 +440,10 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
{
struct zforce_ts *ts = dev_id;
struct i2c_client *client = ts->client;
- int ret;
+ int error;
u8 payload_buffer[FRAME_MAXSIZE];
u8 *payload;
+ bool suspending;
/*
* When still suspended, return.
@@ -498,7 +457,8 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
dev_dbg(&client->dev, "handling interrupt\n");
/* Don't emit wakeup events from commands run by zforce_suspend */
- if (!ts->suspending && device_may_wakeup(&client->dev))
+ suspending = READ_ONCE(ts->suspending);
+ if (!suspending && device_may_wakeup(&client->dev))
pm_stay_awake(&client->dev);
/*
@@ -511,10 +471,10 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
* no IRQ any more)
*/
do {
- ret = zforce_read_packet(ts, payload_buffer);
- if (ret < 0) {
+ error = zforce_read_packet(ts, payload_buffer);
+ if (error) {
dev_err(&client->dev,
- "could not read packet, ret: %d\n", ret);
+ "could not read packet, ret: %d\n", error);
break;
}
@@ -526,7 +486,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
* Always report touch-events received while
* suspending, when being a wakeup source
*/
- if (ts->suspending && device_may_wakeup(&client->dev))
+ if (suspending && device_may_wakeup(&client->dev))
pm_wakeup_event(&client->dev, 500);
zforce_touch_event(ts, &payload[RESPONSE_DATA]);
break;
@@ -550,14 +510,15 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
* Version Payload Results
* [2:major] [2:minor] [2:build] [2:rev]
*/
- ts->version_major = (payload[RESPONSE_DATA + 1] << 8) |
- payload[RESPONSE_DATA];
- ts->version_minor = (payload[RESPONSE_DATA + 3] << 8) |
- payload[RESPONSE_DATA + 2];
- ts->version_build = (payload[RESPONSE_DATA + 5] << 8) |
- payload[RESPONSE_DATA + 4];
- ts->version_rev = (payload[RESPONSE_DATA + 7] << 8) |
- payload[RESPONSE_DATA + 6];
+ ts->version_major =
+ get_unaligned_le16(&payload[RESPONSE_DATA]);
+ ts->version_minor =
+ get_unaligned_le16(&payload[RESPONSE_DATA + 2]);
+ ts->version_build =
+ get_unaligned_le16(&payload[RESPONSE_DATA + 4]);
+ ts->version_rev =
+ get_unaligned_le16(&payload[RESPONSE_DATA + 6]);
+
dev_dbg(&ts->client->dev,
"Firmware Version %04x:%04x %04x:%04x\n",
ts->version_major, ts->version_minor,
@@ -579,7 +540,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id)
}
} while (gpiod_get_value_cansleep(ts->gpio_int));
- if (!ts->suspending && device_may_wakeup(&client->dev))
+ if (!suspending && device_may_wakeup(&client->dev))
pm_relax(&client->dev);
dev_dbg(&client->dev, "finished interrupt\n");
@@ -598,24 +559,20 @@ static void zforce_input_close(struct input_dev *dev)
{
struct zforce_ts *ts = input_get_drvdata(dev);
struct i2c_client *client = ts->client;
- int ret;
+ int error;
- ret = zforce_stop(ts);
- if (ret)
+ error = zforce_stop(ts);
+ if (error)
dev_warn(&client->dev, "stopping zforce failed\n");
-
- return;
}
-static int zforce_suspend(struct device *dev)
+static int __zforce_suspend(struct zforce_ts *ts)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct zforce_ts *ts = i2c_get_clientdata(client);
+ struct i2c_client *client = ts->client;
struct input_dev *input = ts->input;
- int ret = 0;
+ int error;
- mutex_lock(&input->mutex);
- ts->suspending = true;
+ guard(mutex)(&input->mutex);
/*
* When configured as a wakeup source device should always wake
@@ -626,9 +583,9 @@ static int zforce_suspend(struct device *dev)
/* Need to start device, if not open, to be a wakeup source. */
if (!input_device_enabled(input)) {
- ret = zforce_start(ts);
- if (ret)
- goto unlock;
+ error = zforce_start(ts);
+ if (error)
+ return error;
}
enable_irq_wake(client->irq);
@@ -636,18 +593,30 @@ static int zforce_suspend(struct device *dev)
dev_dbg(&client->dev,
"suspend without being a wakeup source\n");
- ret = zforce_stop(ts);
- if (ret)
- goto unlock;
+ error = zforce_stop(ts);
+ if (error)
+ return error;
disable_irq(client->irq);
}
ts->suspended = true;
+ return 0;
+}
+
+static int zforce_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct zforce_ts *ts = i2c_get_clientdata(client);
+ int ret;
+
+ WRITE_ONCE(ts->suspending, true);
+ smp_mb();
-unlock:
- ts->suspending = false;
- mutex_unlock(&input->mutex);
+ ret = __zforce_suspend(ts);
+
+ smp_mb();
+ WRITE_ONCE(ts->suspending, false);
return ret;
}
@@ -657,9 +626,9 @@ static int zforce_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct zforce_ts *ts = i2c_get_clientdata(client);
struct input_dev *input = ts->input;
- int ret = 0;
+ int error;
- mutex_lock(&input->mutex);
+ guard(mutex)(&input->mutex);
ts->suspended = false;
@@ -670,24 +639,21 @@ static int zforce_resume(struct device *dev)
/* need to stop device if it was not open on suspend */
if (!input_device_enabled(input)) {
- ret = zforce_stop(ts);
- if (ret)
- goto unlock;
+ error = zforce_stop(ts);
+ if (error)
+ return error;
}
} else if (input_device_enabled(input)) {
dev_dbg(&client->dev, "resume without being a wakeup source\n");
enable_irq(client->irq);
- ret = zforce_start(ts);
- if (ret < 0)
- goto unlock;
+ error = zforce_start(ts);
+ if (error)
+ return error;
}
-unlock:
- mutex_unlock(&input->mutex);
-
- return ret;
+ return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(zforce_pm_ops, zforce_suspend, zforce_resume);
@@ -696,46 +662,27 @@ static void zforce_reset(void *data)
{
struct zforce_ts *ts = data;
- zforce_reset_assert(ts);
-
+ gpiod_set_value_cansleep(ts->gpio_rst, 1);
udelay(10);
-
- if (!IS_ERR(ts->reg_vdd))
- regulator_disable(ts->reg_vdd);
}
-static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev)
+static void zforce_ts_parse_legacy_properties(struct zforce_ts *ts)
{
- struct zforce_ts_platdata *pdata;
- struct device_node *np = dev->of_node;
+ u32 x_max = 0;
+ u32 y_max = 0;
- if (!np)
- return ERR_PTR(-ENOENT);
+ device_property_read_u32(&ts->client->dev, "x-size", &x_max);
+ input_set_abs_params(ts->input, ABS_MT_POSITION_X, 0, x_max, 0, 0);
- pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "failed to allocate platform data\n");
- return ERR_PTR(-ENOMEM);
- }
-
- of_property_read_u32(np, "x-size", &pdata->x_max);
- of_property_read_u32(np, "y-size", &pdata->y_max);
-
- return pdata;
+ device_property_read_u32(&ts->client->dev, "y-size", &y_max);
+ input_set_abs_params(ts->input, ABS_MT_POSITION_Y, 0, y_max, 0, 0);
}
static int zforce_probe(struct i2c_client *client)
{
- const struct zforce_ts_platdata *pdata = dev_get_platdata(&client->dev);
struct zforce_ts *ts;
struct input_dev *input_dev;
- int ret;
-
- if (!pdata) {
- pdata = zforce_parse_dt(&client->dev);
- if (IS_ERR(pdata))
- return PTR_ERR(pdata);
- }
+ int error;
ts = devm_kzalloc(&client->dev, sizeof(struct zforce_ts), GFP_KERNEL);
if (!ts)
@@ -743,22 +690,18 @@ static int zforce_probe(struct i2c_client *client)
ts->gpio_rst = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_HIGH);
- if (IS_ERR(ts->gpio_rst)) {
- ret = PTR_ERR(ts->gpio_rst);
- dev_err(&client->dev,
- "failed to request reset GPIO: %d\n", ret);
- return ret;
- }
+ error = PTR_ERR_OR_ZERO(ts->gpio_rst);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request reset GPIO\n");
if (ts->gpio_rst) {
ts->gpio_int = devm_gpiod_get_optional(&client->dev, "irq",
GPIOD_IN);
- if (IS_ERR(ts->gpio_int)) {
- ret = PTR_ERR(ts->gpio_int);
- dev_err(&client->dev,
- "failed to request interrupt GPIO: %d\n", ret);
- return ret;
- }
+ error = PTR_ERR_OR_ZERO(ts->gpio_int);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request interrupt GPIO\n");
} else {
/*
* Deprecated GPIO handling for compatibility
@@ -768,66 +711,45 @@ static int zforce_probe(struct i2c_client *client)
/* INT GPIO */
ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0,
GPIOD_IN);
- if (IS_ERR(ts->gpio_int)) {
- ret = PTR_ERR(ts->gpio_int);
- dev_err(&client->dev,
- "failed to request interrupt GPIO: %d\n", ret);
- return ret;
- }
+
+ error = PTR_ERR_OR_ZERO(ts->gpio_int);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request interrupt GPIO\n");
/* RST GPIO */
ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1,
GPIOD_OUT_HIGH);
- if (IS_ERR(ts->gpio_rst)) {
- ret = PTR_ERR(ts->gpio_rst);
- dev_err(&client->dev,
- "failed to request reset GPIO: %d\n", ret);
- return ret;
- }
- }
-
- ts->reg_vdd = devm_regulator_get_optional(&client->dev, "vdd");
- if (IS_ERR(ts->reg_vdd)) {
- ret = PTR_ERR(ts->reg_vdd);
- if (ret == -EPROBE_DEFER)
- return ret;
- } else {
- ret = regulator_enable(ts->reg_vdd);
- if (ret)
- return ret;
-
- /*
- * according to datasheet add 100us grace time after regular
- * regulator enable delay.
- */
- udelay(100);
+ error = PTR_ERR_OR_ZERO(ts->gpio_rst);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request reset GPIO\n");
}
- ret = devm_add_action(&client->dev, zforce_reset, ts);
- if (ret) {
- dev_err(&client->dev, "failed to register reset action, %d\n",
- ret);
+ error = devm_regulator_get_enable(&client->dev, "vdd");
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to request vdd supply\n");
- /* hereafter the regulator will be disabled by the action */
- if (!IS_ERR(ts->reg_vdd))
- regulator_disable(ts->reg_vdd);
+ /*
+ * According to datasheet add 100us grace time after regular
+ * regulator enable delay.
+ */
+ usleep_range(100, 200);
- return ret;
- }
+ error = devm_add_action_or_reset(&client->dev, zforce_reset, ts);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "failed to register reset action\n");
snprintf(ts->phys, sizeof(ts->phys),
"%s/input0", dev_name(&client->dev));
input_dev = devm_input_allocate_device(&client->dev);
- if (!input_dev) {
- dev_err(&client->dev, "could not allocate input device\n");
- return -ENOMEM;
- }
-
- mutex_init(&ts->access_mutex);
- mutex_init(&ts->command_mutex);
+ if (!input_dev)
+ return dev_err_probe(&client->dev, -ENOMEM,
+ "could not allocate input device\n");
- ts->pdata = pdata;
ts->client = client;
ts->input = input_dev;
@@ -838,28 +760,21 @@ static int zforce_probe(struct i2c_client *client)
input_dev->open = zforce_input_open;
input_dev->close = zforce_input_close;
- __set_bit(EV_KEY, input_dev->evbit);
- __set_bit(EV_SYN, input_dev->evbit);
- __set_bit(EV_ABS, input_dev->evbit);
-
- /* For multi touch */
- input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0,
- pdata->x_max, 0, 0);
- input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0,
- pdata->y_max, 0, 0);
-
+ zforce_ts_parse_legacy_properties(ts);
touchscreen_parse_properties(input_dev, true, &ts->prop);
- if (ts->prop.max_x == 0 || ts->prop.max_y == 0) {
- dev_err(&client->dev, "no size specified\n");
- return -EINVAL;
- }
+ if (ts->prop.max_x == 0 || ts->prop.max_y == 0)
+ return dev_err_probe(&client->dev, -EINVAL, "no size specified");
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0,
ZFORCE_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0,
ZFORCE_MAX_AREA, 0, 0);
input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0);
- input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS, INPUT_MT_DIRECT);
+
+ error = input_mt_init_slots(input_dev, ZFORCE_REPORT_POINTS,
+ INPUT_MT_DIRECT);
+ if (error)
+ return error;
input_set_drvdata(ts->input, ts);
@@ -872,57 +787,51 @@ static int zforce_probe(struct i2c_client *client)
* Therefore we can trigger the interrupt anytime it is low and do
* not need to limit it to the interrupt edge.
*/
- ret = devm_request_threaded_irq(&client->dev, client->irq,
- zforce_irq, zforce_irq_thread,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- input_dev->name, ts);
- if (ret) {
- dev_err(&client->dev, "irq %d request failed\n", client->irq);
- return ret;
- }
+ error = devm_request_threaded_irq(&client->dev, client->irq,
+ zforce_irq, zforce_irq_thread,
+ IRQF_ONESHOT, input_dev->name, ts);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "irq %d request failed\n", client->irq);
i2c_set_clientdata(client, ts);
/* let the controller boot */
- zforce_reset_deassert(ts);
+ gpiod_set_value_cansleep(ts->gpio_rst, 0);
ts->command_waiting = NOTIFICATION_BOOTCOMPLETE;
if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0)
dev_warn(&client->dev, "bootcomplete timed out\n");
/* need to start device to get version information */
- ret = zforce_command_wait(ts, COMMAND_INITIALIZE);
- if (ret) {
- dev_err(&client->dev, "unable to initialize, %d\n", ret);
- return ret;
- }
+ error = zforce_command_wait(ts, COMMAND_INITIALIZE);
+ if (error)
+ return dev_err_probe(&client->dev, error, "unable to initialize\n");
/* this gets the firmware version among other information */
- ret = zforce_command_wait(ts, COMMAND_STATUS);
- if (ret < 0) {
- dev_err(&client->dev, "couldn't get status, %d\n", ret);
+ error = zforce_command_wait(ts, COMMAND_STATUS);
+ if (error) {
+ dev_err_probe(&client->dev, error, "couldn't get status\n");
zforce_stop(ts);
- return ret;
+ return error;
}
/* stop device and put it into sleep until it is opened */
- ret = zforce_stop(ts);
- if (ret < 0)
- return ret;
+ error = zforce_stop(ts);
+ if (error)
+ return error;
device_set_wakeup_capable(&client->dev, true);
- ret = input_register_device(input_dev);
- if (ret) {
- dev_err(&client->dev, "could not register input device, %d\n",
- ret);
- return ret;
- }
+ error = input_register_device(input_dev);
+ if (error)
+ return dev_err_probe(&client->dev, error,
+ "could not register input device\n");
return 0;
}
-static struct i2c_device_id zforce_idtable[] = {
+static const struct i2c_device_id zforce_idtable[] = {
{ "zforce-ts" },
{ }
};
@@ -941,6 +850,7 @@ static struct i2c_driver zforce_driver = {
.name = "zforce-ts",
.pm = pm_sleep_ptr(&zforce_pm_ops),
.of_match_table = of_match_ptr(zforce_dt_idtable),
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
.probe = zforce_probe,
.id_table = zforce_idtable,
diff --git a/drivers/input/touchscreen/zinitix.c b/drivers/input/touchscreen/zinitix.c
index 1b4807ba4624..716d6fa60f86 100644
--- a/drivers/input/touchscreen/zinitix.c
+++ b/drivers/input/touchscreen/zinitix.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -34,7 +35,13 @@
#define ZINITIX_DEBUG_REG 0x0115 /* 0~7 */
#define ZINITIX_TOUCH_MODE 0x0010
+
#define ZINITIX_CHIP_REVISION 0x0011
+#define ZINITIX_CHIP_BTX0X_MASK 0xF0F0
+#define ZINITIX_CHIP_BT4X2 0x4020
+#define ZINITIX_CHIP_BT4X3 0x4030
+#define ZINITIX_CHIP_BT4X4 0x4040
+
#define ZINITIX_FIRMWARE_VERSION 0x0012
#define ZINITIX_USB_DETECT 0x116
@@ -62,7 +69,11 @@
#define ZINITIX_Y_RESOLUTION 0x00C1
#define ZINITIX_POINT_STATUS_REG 0x0080
-#define ZINITIX_ICON_STATUS_REG 0x00AA
+
+#define ZINITIX_BT4X2_ICON_STATUS_REG 0x009A
+#define ZINITIX_BT4X3_ICON_STATUS_REG 0x00A0
+#define ZINITIX_BT4X4_ICON_STATUS_REG 0x00A0
+#define ZINITIX_BT5XX_ICON_STATUS_REG 0x00AA
#define ZINITIX_POINT_COORD_REG (ZINITIX_POINT_STATUS_REG + 2)
@@ -119,6 +130,7 @@
#define DEFAULT_TOUCH_POINT_MODE 2
#define MAX_SUPPORTED_FINGER_NUM 5
+#define MAX_SUPPORTED_BUTTON_NUM 8
#define CHIP_ON_DELAY 15 // ms
#define FIRMWARE_ON_DELAY 40 // ms
@@ -146,6 +158,13 @@ struct bt541_ts_data {
struct touchscreen_properties prop;
struct regulator_bulk_data supplies[2];
u32 zinitix_mode;
+ u32 keycodes[MAX_SUPPORTED_BUTTON_NUM];
+ int num_keycodes;
+ bool have_versioninfo;
+ u16 chip_revision;
+ u16 firmware_version;
+ u16 regdata_version;
+ u16 icon_status_reg;
};
static int zinitix_read_data(struct i2c_client *client,
@@ -190,11 +209,25 @@ static int zinitix_write_cmd(struct i2c_client *client, u16 reg)
return 0;
}
+static u16 zinitix_get_u16_reg(struct bt541_ts_data *bt541, u16 vreg)
+{
+ struct i2c_client *client = bt541->client;
+ int error;
+ __le16 val;
+
+ error = zinitix_read_data(client, vreg, (void *)&val, 2);
+ if (error)
+ return U8_MAX;
+
+ return le16_to_cpu(val);
+}
+
static int zinitix_init_touch(struct bt541_ts_data *bt541)
{
struct i2c_client *client = bt541->client;
int i;
int error;
+ u16 int_flags;
error = zinitix_write_cmd(client, ZINITIX_SWRESET_CMD);
if (error) {
@@ -202,6 +235,47 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
return error;
}
+ /*
+ * Read and cache the chip revision and firmware version the first time
+ * we get here.
+ */
+ if (!bt541->have_versioninfo) {
+ bt541->chip_revision = zinitix_get_u16_reg(bt541,
+ ZINITIX_CHIP_REVISION);
+ bt541->firmware_version = zinitix_get_u16_reg(bt541,
+ ZINITIX_FIRMWARE_VERSION);
+ bt541->regdata_version = zinitix_get_u16_reg(bt541,
+ ZINITIX_DATA_VERSION_REG);
+ bt541->have_versioninfo = true;
+
+ dev_dbg(&client->dev,
+ "chip revision %04x firmware version %04x regdata version %04x\n",
+ bt541->chip_revision, bt541->firmware_version,
+ bt541->regdata_version);
+
+ /*
+ * Determine the "icon" status register which varies by the
+ * chip.
+ */
+ switch (bt541->chip_revision & ZINITIX_CHIP_BTX0X_MASK) {
+ case ZINITIX_CHIP_BT4X2:
+ bt541->icon_status_reg = ZINITIX_BT4X2_ICON_STATUS_REG;
+ break;
+
+ case ZINITIX_CHIP_BT4X3:
+ bt541->icon_status_reg = ZINITIX_BT4X3_ICON_STATUS_REG;
+ break;
+
+ case ZINITIX_CHIP_BT4X4:
+ bt541->icon_status_reg = ZINITIX_BT4X4_ICON_STATUS_REG;
+ break;
+
+ default:
+ bt541->icon_status_reg = ZINITIX_BT5XX_ICON_STATUS_REG;
+ break;
+ }
+ }
+
error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, 0x0);
if (error) {
dev_err(&client->dev,
@@ -225,6 +299,11 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
if (error)
return error;
+ error = zinitix_write_u16(client, ZINITIX_BUTTON_SUPPORTED_NUM,
+ bt541->num_keycodes);
+ if (error)
+ return error;
+
error = zinitix_write_u16(client, ZINITIX_INITIAL_TOUCH_MODE,
bt541->zinitix_mode);
if (error)
@@ -235,9 +314,11 @@ static int zinitix_init_touch(struct bt541_ts_data *bt541)
if (error)
return error;
- error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG,
- BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE |
- BIT_UP);
+ int_flags = BIT_PT_CNT_CHANGE | BIT_DOWN | BIT_MOVE | BIT_UP;
+ if (bt541->num_keycodes)
+ int_flags |= BIT_ICON_EVENT;
+
+ error = zinitix_write_u16(client, ZINITIX_INT_ENABLE_FLAG, int_flags);
if (error)
return error;
@@ -350,12 +431,22 @@ static void zinitix_report_finger(struct bt541_ts_data *bt541, int slot,
}
}
+static void zinitix_report_keys(struct bt541_ts_data *bt541, u16 icon_events)
+{
+ int i;
+
+ for (i = 0; i < bt541->num_keycodes; i++)
+ input_report_key(bt541->input_dev,
+ bt541->keycodes[i], icon_events & BIT(i));
+}
+
static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
{
struct bt541_ts_data *bt541 = bt541_handler;
struct i2c_client *client = bt541->client;
struct touch_event touch_event;
unsigned long finger_mask;
+ __le16 icon_events;
int error;
int i;
@@ -368,6 +459,17 @@ static irqreturn_t zinitix_ts_irq_handler(int irq, void *bt541_handler)
goto out;
}
+ if (le16_to_cpu(touch_event.status) & BIT_ICON_EVENT) {
+ error = zinitix_read_data(bt541->client, bt541->icon_status_reg,
+ &icon_events, sizeof(icon_events));
+ if (error) {
+ dev_err(&client->dev, "Failed to read icon events\n");
+ goto out;
+ }
+
+ zinitix_report_keys(bt541, le16_to_cpu(icon_events));
+ }
+
finger_mask = touch_event.finger_mask;
for_each_set_bit(i, &finger_mask, MAX_SUPPORTED_FINGER_NUM) {
const struct point_coord *p = &touch_event.point_coord[i];
@@ -453,6 +555,7 @@ static int zinitix_init_input_dev(struct bt541_ts_data *bt541)
{
struct input_dev *input_dev;
int error;
+ int i;
input_dev = devm_input_allocate_device(&bt541->client->dev);
if (!input_dev) {
@@ -470,6 +573,14 @@ static int zinitix_init_input_dev(struct bt541_ts_data *bt541)
input_dev->open = zinitix_input_open;
input_dev->close = zinitix_input_close;
+ if (bt541->num_keycodes) {
+ input_dev->keycode = bt541->keycodes;
+ input_dev->keycodemax = bt541->num_keycodes;
+ input_dev->keycodesize = sizeof(bt541->keycodes[0]);
+ for (i = 0; i < bt541->num_keycodes; i++)
+ input_set_capability(input_dev, EV_KEY, bt541->keycodes[i]);
+ }
+
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(input_dev, EV_ABS, ABS_MT_POSITION_Y);
input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
@@ -534,6 +645,31 @@ static int zinitix_ts_probe(struct i2c_client *client)
return error;
}
+ if (device_property_present(&client->dev, "linux,keycodes")) {
+ bt541->num_keycodes = device_property_count_u32(&client->dev,
+ "linux,keycodes");
+ if (bt541->num_keycodes < 0) {
+ dev_err(&client->dev, "Failed to count keys (%d)\n",
+ bt541->num_keycodes);
+ return bt541->num_keycodes;
+ } else if (bt541->num_keycodes > ARRAY_SIZE(bt541->keycodes)) {
+ dev_err(&client->dev, "Too many keys defined (%d)\n",
+ bt541->num_keycodes);
+ return -EINVAL;
+ }
+
+ error = device_property_read_u32_array(&client->dev,
+ "linux,keycodes",
+ bt541->keycodes,
+ bt541->num_keycodes);
+ if (error) {
+ dev_err(&client->dev,
+ "Unable to parse \"linux,keycodes\" property: %d\n",
+ error);
+ return error;
+ }
+ }
+
error = zinitix_init_input_dev(bt541);
if (error) {
dev_err(&client->dev,
diff --git a/drivers/input/vivaldi-fmap.c b/drivers/input/vivaldi-fmap.c
index 0d29ec014e2f..978949eba9eb 100644
--- a/drivers/input/vivaldi-fmap.c
+++ b/drivers/input/vivaldi-fmap.c
@@ -36,4 +36,5 @@ ssize_t vivaldi_function_row_physmap_show(const struct vivaldi_data *data,
}
EXPORT_SYMBOL_GPL(vivaldi_function_row_physmap_show);
+MODULE_DESCRIPTION("Helpers for ChromeOS Vivaldi keyboard function row mapping");
MODULE_LICENSE("GPL");