summaryrefslogtreecommitdiff
path: root/drivers/input/misc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/88pm80x_onkey.c19
-rw-r--r--drivers/input/misc/88pm860x_onkey.c9
-rw-r--r--drivers/input/misc/88pm886-onkey.c98
-rw-r--r--drivers/input/misc/Kconfig181
-rw-r--r--drivers/input/misc/Makefile16
-rw-r--r--drivers/input/misc/ad714x-i2c.c29
-rw-r--r--drivers/input/misc/ad714x-spi.c14
-rw-r--r--drivers/input/misc/ad714x.c25
-rw-r--r--drivers/input/misc/ad714x.h4
-rw-r--r--drivers/input/misc/adxl34x-i2c.c39
-rw-r--r--drivers/input/misc/adxl34x-spi.c34
-rw-r--r--drivers/input/misc/adxl34x.c175
-rw-r--r--drivers/input/misc/adxl34x.h6
-rw-r--r--drivers/input/misc/apanel.c5
-rw-r--r--drivers/input/misc/ariel-pwrbutton.c7
-rw-r--r--drivers/input/misc/arizona-haptics.c14
-rw-r--r--drivers/input/misc/ati_remote2.c109
-rw-r--r--drivers/input/misc/atlas_btns.c5
-rw-r--r--drivers/input/misc/atmel_captouch.c9
-rw-r--r--drivers/input/misc/aw86927.c846
-rw-r--r--drivers/input/misc/axp20x-pek.c121
-rw-r--r--drivers/input/misc/bma150.c13
-rw-r--r--drivers/input/misc/cm109.c169
-rw-r--r--drivers/input/misc/cma3000_d0x.c21
-rw-r--r--drivers/input/misc/cma3000_d0x_i2c.c17
-rw-r--r--drivers/input/misc/cpcap-pwrbutton.c19
-rw-r--r--drivers/input/misc/cs40l50-vibra.c558
-rw-r--r--drivers/input/misc/da7280.c42
-rw-r--r--drivers/input/misc/da9052_onkey.c6
-rw-r--r--drivers/input/misc/da9055_onkey.c6
-rw-r--r--drivers/input/misc/da9063_onkey.c91
-rw-r--r--drivers/input/misc/dm355evm_keys.c238
-rw-r--r--drivers/input/misc/drv260x.c119
-rw-r--r--drivers/input/misc/drv2665.c59
-rw-r--r--drivers/input/misc/drv2667.c59
-rw-r--r--drivers/input/misc/e3x0-button.c10
-rw-r--r--drivers/input/misc/gpio-beeper.c2
-rw-r--r--drivers/input/misc/gpio-vibra.c32
-rw-r--r--drivers/input/misc/gpio_decoder.c10
-rw-r--r--drivers/input/misc/hisi_powerkey.c2
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c2
-rw-r--r--drivers/input/misc/ibm-panel.c196
-rw-r--r--drivers/input/misc/ideapad_slidebar.c32
-rw-r--r--drivers/input/misc/ims-pcu.c221
-rw-r--r--drivers/input/misc/iqs269a.c722
-rw-r--r--drivers/input/misc/iqs626a.c175
-rw-r--r--drivers/input/misc/iqs7222.c3162
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c183
-rw-r--r--drivers/input/misc/keyspan_remote.c2
-rw-r--r--drivers/input/misc/kxtj9.c58
-rw-r--r--drivers/input/misc/m68kspkr.c4
-rw-r--r--drivers/input/misc/max7360-rotary.c192
-rw-r--r--drivers/input/misc/max77693-haptic.c83
-rw-r--r--drivers/input/misc/max8925_onkey.c11
-rw-r--r--drivers/input/misc/max8997_haptic.c125
-rw-r--r--drivers/input/misc/mc13783-pwrbutton.c5
-rw-r--r--drivers/input/misc/mma8450.c25
-rw-r--r--drivers/input/misc/nxp-bbnsm-pwrkey.c239
-rw-r--r--drivers/input/misc/palmas-pwrbutton.c38
-rw-r--r--drivers/input/misc/pcap_keys.c6
-rw-r--r--drivers/input/misc/pcf50633-input.c115
-rw-r--r--drivers/input/misc/pcf8574_keypad.c24
-rw-r--r--drivers/input/misc/pcspkr.c4
-rw-r--r--drivers/input/misc/pf1550-onkey.c197
-rw-r--r--drivers/input/misc/pm8941-pwrkey.c181
-rw-r--r--drivers/input/misc/pm8xxx-vibrator.c99
-rw-r--r--drivers/input/misc/pmic8xxx-pwrkey.c9
-rw-r--r--drivers/input/misc/powermate.c16
-rw-r--r--drivers/input/misc/pwm-beeper.c45
-rw-r--r--drivers/input/misc/pwm-vibra.c68
-rw-r--r--drivers/input/misc/qnap-mcu-input.c153
-rw-r--r--drivers/input/misc/regulator-haptic.c35
-rw-r--r--drivers/input/misc/rk805-pwrkey.c1
-rw-r--r--drivers/input/misc/rotary_encoder.c42
-rw-r--r--drivers/input/misc/rt5120-pwrkey.c120
-rw-r--r--drivers/input/misc/sgi_btns.c1
-rw-r--r--drivers/input/misc/sirfsoc-onkey.c207
-rw-r--r--drivers/input/misc/soc_button_array.c82
-rw-r--r--drivers/input/misc/sparcspkr.c87
-rw-r--r--drivers/input/misc/stpmic1_onkey.c12
-rw-r--r--drivers/input/misc/tps65218-pwrbutton.c10
-rw-r--r--drivers/input/misc/tps65219-pwrbutton.c150
-rw-r--r--drivers/input/misc/tps6594-pwrbutton.c126
-rw-r--r--drivers/input/misc/twl4030-pwrbutton.c5
-rw-r--r--drivers/input/misc/twl4030-vibra.c34
-rw-r--r--drivers/input/misc/twl6040-vibra.c15
-rw-r--r--drivers/input/misc/uinput.c52
-rw-r--r--drivers/input/misc/wistron_btns.c18
-rw-r--r--drivers/input/misc/wm831x-on.c4
-rw-r--r--drivers/input/misc/xen-kbdfront.c10
-rw-r--r--drivers/input/misc/yealink.c91
91 files changed, 8036 insertions, 2696 deletions
diff --git a/drivers/input/misc/88pm80x_onkey.c b/drivers/input/misc/88pm80x_onkey.c
index 51c8a326fd06..9159b5fec129 100644
--- a/drivers/input/misc/88pm80x_onkey.c
+++ b/drivers/input/misc/88pm80x_onkey.c
@@ -1,22 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Marvell 88PM80x ONKEY driver
*
* Copyright (C) 2012 Marvell International Ltd.
* Haojian Zhuang <haojian.zhuang@marvell.com>
* Qiao Zhou <zhouqiao@marvell.com>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of this
- * archive for more details.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
@@ -69,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;
@@ -138,14 +126,13 @@ out:
return err;
}
-static int pm80x_onkey_remove(struct platform_device *pdev)
+static void pm80x_onkey_remove(struct platform_device *pdev)
{
struct pm80x_onkey_info *info = platform_get_drvdata(pdev);
pm80x_free_irq(info->pm80x, info->irq, info);
input_unregister_device(info->idev);
kfree(info);
- return 0;
}
static struct platform_driver pm80x_onkey_driver = {
diff --git a/drivers/input/misc/88pm860x_onkey.c b/drivers/input/misc/88pm860x_onkey.c
index 685995cad73f..0f8b7ffb3aff 100644
--- a/drivers/input/misc/88pm860x_onkey.c
+++ b/drivers/input/misc/88pm860x_onkey.c
@@ -110,7 +110,7 @@ static int pm860x_onkey_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pm860x_onkey_suspend(struct device *dev)
+static int pm860x_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -119,7 +119,7 @@ static int __maybe_unused pm860x_onkey_suspend(struct device *dev)
chip->wakeup_flag |= 1 << PM8607_IRQ_ONKEY;
return 0;
}
-static int __maybe_unused pm860x_onkey_resume(struct device *dev)
+static int pm860x_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
@@ -129,12 +129,13 @@ static int __maybe_unused pm860x_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops, pm860x_onkey_suspend, pm860x_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pm860x_onkey_pm_ops,
+ pm860x_onkey_suspend, pm860x_onkey_resume);
static struct platform_driver pm860x_onkey_driver = {
.driver = {
.name = "88pm860x-onkey",
- .pm = &pm860x_onkey_pm_ops,
+ .pm = pm_sleep_ptr(&pm860x_onkey_pm_ops),
},
.probe = pm860x_onkey_probe,
};
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 498cde376981..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
@@ -107,7 +114,7 @@ config INPUT_ATC260X_ONKEY
config INPUT_ATMEL_CAPTOUCH
tristate "Atmel Capacitive Touch Button Driver"
- depends on OF || COMPILE_TEST
+ depends on OF
depends on I2C
help
Say Y here if an Atmel Capacitive Touch Button device which
@@ -119,6 +126,28 @@ 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
+ depends on OF
+ help
+ This is the bbnsm powerkey driver for the NXP i.MX application
+ processors.
+
+ To compile this driver as a module, choose M here; the
+ module will be called bbnsm_pwrkey.
+
config INPUT_BMA150
tristate "BMA150/SMB380 acceleration sensor support"
depends on I2C
@@ -129,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
@@ -151,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
@@ -202,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
@@ -212,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.
@@ -309,18 +369,6 @@ config INPUT_GPIO_VIBRA
To compile this driver as a module, choose M here: the module will be
called gpio-vibra.
-config INPUT_IXP4XX_BEEPER
- tristate "IXP4XX Beeper support"
- depends on ARCH_IXP4XX
- help
- If you say yes here, you can connect a beeper to the
- ixp4xx gpio pins. This is used by the LinkSys NSLU2.
-
- If unsure, say Y.
-
- To compile this driver as a module, choose M here: the
- module will be called ixp4xx-beeper.
-
config INPUT_COBALT_BTNS
tristate "Cobalt button interface"
depends on MIPS_COBALT
@@ -342,7 +390,7 @@ config INPUT_CPCAP_PWRBUTTON
config INPUT_WISTRON_BTNS
tristate "x86 Wistron laptop button interface"
- depends on X86_32
+ depends on X86_32 && !UML
select INPUT_SPARSEKMAP
select NEW_LEDS
select LEDS_CLASS
@@ -480,6 +528,26 @@ config INPUT_TPS65218_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called tps65218-pwrbutton.
+config INPUT_TPS65219_PWRBUTTON
+ tristate "TPS65219 Power button driver"
+ depends on MFD_TPS65219
+ help
+ Say Y here if you want to enable power button reporting for
+ TPS65219 Power Management IC devices.
+
+ 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
@@ -558,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
@@ -600,7 +661,7 @@ config INPUT_PWM_VIBRA
config INPUT_RK805_PWRKEY
tristate "Rockchip RK805 PMIC power key support"
- depends on MFD_RK808
+ depends on MFD_RK8XX
help
Select this option to enable power key driver for RK805.
@@ -674,17 +735,6 @@ config INPUT_DA9063_ONKEY
To compile this driver as a module, choose M here: the module
will be called da9063_onkey.
-config INPUT_DM355EVM
- tristate "TI DaVinci DM355 EVM Keypad and IR Remote"
- depends on MFD_DM355EVM_MSP
- select INPUT_SPARSEKMAP
- help
- Supports the pushbuttons and IR remote used with
- the DM355 EVM board.
-
- To compile this driver as a module, choose M here: the
- module will be called dm355evm_keys.
-
config INPUT_WM831X_ON
tristate "WM831X ON pin"
depends on MFD_WM831X
@@ -742,6 +792,24 @@ config INPUT_ADXL34X_SPI
To compile this driver as a module, choose M here: the
module will be called adxl34x-spi.
+config INPUT_IBM_PANEL
+ tristate "IBM Operation Panel driver"
+ depends on I2C && I2C_SLAVE
+ help
+ Say Y here if you have an IBM Operation Panel connected to your system
+ over I2C. The panel is typically connected only to a system's service
+ processor (BMC).
+
+ If unsure, say N.
+
+ The Operation Panel is a controller with some buttons and an LCD
+ display that allows someone with physical access to the system to
+ perform various administrative tasks. This driver only supports the part
+ of the controller that sends commands to the system.
+
+ To compile this driver as a module, choose M here: the module will be
+ called ibm-panel.
+
config INPUT_IMS_PCU
tristate "IMS Passenger Control Unit driver"
depends on USB
@@ -774,6 +842,16 @@ config INPUT_IQS626A
To compile this driver as a module, choose M here: the
module will be called iqs626a.
+config INPUT_IQS7222
+ tristate "Azoteq IQS7222A/B/C/D capacitive touch controller"
+ depends on I2C
+ help
+ Say Y to enable support for the Azoteq IQS7222A/B/C/D family
+ of capacitive touch controllers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called iqs7222.
+
config INPUT_CMA3000
tristate "VTI CMA3000 Tri-axis accelerometer"
help
@@ -811,16 +889,6 @@ config INPUT_XEN_KBDDEV_FRONTEND
To compile this driver as a module, choose M here: the
module will be called xen-kbdfront.
-config INPUT_SIRFSOC_ONKEY
- tristate "CSR SiRFSoC power on/off/suspend key support"
- depends on ARCH_SIRF && OF
- default y
- help
- Say Y here if you want to support for the SiRFSoC power on/off/suspend key
- in Linux, after you press the onkey, system will suspend.
-
- If unsure, say N.
-
config INPUT_IDEAPAD_SLIDEBAR
tristate "IdeaPad Laptop Slidebar"
depends on INPUT
@@ -884,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
@@ -903,6 +983,15 @@ config INPUT_SC27XX_VIBRA
To compile this driver as a module, choose M here. The module will
be called sc27xx_vibra.
+config INPUT_RT5120_PWRKEY
+ tristate "RT5120 PMIC power key support"
+ depends on MFD_RT5120 || COMPILE_TEST
+ help
+ This enables support for RT5120 PMIC power key driver.
+
+ To compile this driver as a module, choose M here. the module will
+ be called rt5120-pwrkey.
+
config INPUT_STPMIC1_ONKEY
tristate "STPMIC1 PMIC Onkey support"
depends on MFD_STPMIC1
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index f593beed7e05..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,17 +22,19 @@ 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
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
obj-$(CONFIG_INPUT_DA9063_ONKEY) += da9063_onkey.o
-obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
obj-$(CONFIG_INPUT_DRV2665_HAPTICS) += drv2665.o
@@ -41,13 +44,15 @@ obj-$(CONFIG_INPUT_GPIO_DECODER) += gpio_decoder.o
obj-$(CONFIG_INPUT_GPIO_VIBRA) += gpio-vibra.o
obj-$(CONFIG_INPUT_HISI_POWERKEY) += hisi_powerkey.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
+obj-$(CONFIG_INPUT_IBM_PANEL) += ibm-panel.o
obj-$(CONFIG_INPUT_IMS_PCU) += ims-pcu.o
obj-$(CONFIG_INPUT_IQS269A) += iqs269a.o
obj-$(CONFIG_INPUT_IQS626A) += iqs626a.o
-obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
+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
@@ -56,29 +61,32 @@ 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
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
+obj-$(CONFIG_INPUT_RT5120_PWRKEY) += rt5120-pwrkey.o
obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_RK805_PWRKEY) += rk805-pwrkey.o
obj-$(CONFIG_INPUT_SC27XX_VIBRA) += sc27xx-vibra.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
-obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
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-i2c.c b/drivers/input/misc/ad714x-i2c.c
index efeef135007a..2adb7a058362 100644
--- a/drivers/input/misc/ad714x-i2c.c
+++ b/drivers/input/misc/ad714x-i2c.c
@@ -12,18 +12,6 @@
#include <linux/pm.h>
#include "ad714x.h"
-static int __maybe_unused ad714x_i2c_suspend(struct device *dev)
-{
- return ad714x_disable(i2c_get_clientdata(to_i2c_client(dev)));
-}
-
-static int __maybe_unused ad714x_i2c_resume(struct device *dev)
-{
- return ad714x_enable(i2c_get_clientdata(to_i2c_client(dev)));
-}
-
-static SIMPLE_DEV_PM_OPS(ad714x_i2c_pm, ad714x_i2c_suspend, ad714x_i2c_resume);
-
static int ad714x_i2c_write(struct ad714x_chip *chip,
unsigned short reg, unsigned short data)
{
@@ -69,8 +57,7 @@ static int ad714x_i2c_read(struct ad714x_chip *chip,
return 0;
}
-static int ad714x_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ad714x_i2c_probe(struct i2c_client *client)
{
struct ad714x_chip *chip;
@@ -85,11 +72,11 @@ static int ad714x_i2c_probe(struct i2c_client *client,
}
static const struct i2c_device_id ad714x_id[] = {
- { "ad7142_captouch", 0 },
- { "ad7143_captouch", 0 },
- { "ad7147_captouch", 0 },
- { "ad7147a_captouch", 0 },
- { "ad7148_captouch", 0 },
+ { "ad7142_captouch" },
+ { "ad7143_captouch" },
+ { "ad7147_captouch" },
+ { "ad7147a_captouch" },
+ { "ad7148_captouch" },
{ }
};
MODULE_DEVICE_TABLE(i2c, ad714x_id);
@@ -97,9 +84,9 @@ MODULE_DEVICE_TABLE(i2c, ad714x_id);
static struct i2c_driver ad714x_i2c_driver = {
.driver = {
.name = "ad714x_captouch",
- .pm = &ad714x_i2c_pm,
+ .pm = pm_sleep_ptr(&ad714x_pm),
},
- .probe = ad714x_i2c_probe,
+ .probe = ad714x_i2c_probe,
.id_table = ad714x_id,
};
diff --git a/drivers/input/misc/ad714x-spi.c b/drivers/input/misc/ad714x-spi.c
index 7d3bf434620f..eb13b4cd6594 100644
--- a/drivers/input/misc/ad714x-spi.c
+++ b/drivers/input/misc/ad714x-spi.c
@@ -15,18 +15,6 @@
#define AD714x_SPI_CMD_PREFIX 0xE000 /* bits 15:11 */
#define AD714x_SPI_READ BIT(10)
-static int __maybe_unused ad714x_spi_suspend(struct device *dev)
-{
- return ad714x_disable(spi_get_drvdata(to_spi_device(dev)));
-}
-
-static int __maybe_unused ad714x_spi_resume(struct device *dev)
-{
- return ad714x_enable(spi_get_drvdata(to_spi_device(dev)));
-}
-
-static SIMPLE_DEV_PM_OPS(ad714x_spi_pm, ad714x_spi_suspend, ad714x_spi_resume);
-
static int ad714x_spi_read(struct ad714x_chip *chip,
unsigned short reg, unsigned short *data, size_t len)
{
@@ -103,7 +91,7 @@ static int ad714x_spi_probe(struct spi_device *spi)
static struct spi_driver ad714x_spi_driver = {
.driver = {
.name = "ad714x_captouch",
- .pm = &ad714x_spi_pm,
+ .pm = pm_sleep_ptr(&ad714x_pm),
},
.probe = ad714x_spi_probe,
};
diff --git a/drivers/input/misc/ad714x.c b/drivers/input/misc/ad714x.c
index 43132d98feda..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;
}
@@ -1162,29 +1161,27 @@ struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
}
EXPORT_SYMBOL(ad714x_probe);
-#ifdef CONFIG_PM
-int ad714x_disable(struct ad714x_chip *ad714x)
+static int ad714x_suspend(struct device *dev)
{
+ struct ad714x_chip *ad714x = dev_get_drvdata(dev);
unsigned short data;
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;
}
-EXPORT_SYMBOL(ad714x_disable);
-int ad714x_enable(struct ad714x_chip *ad714x)
+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,12 +1194,10 @@ int ad714x_enable(struct ad714x_chip *ad714x)
ad714x->read(ad714x, STG_LOW_INT_STA_REG, &ad714x->l_state, 3);
- mutex_unlock(&ad714x->mutex);
-
return 0;
}
-EXPORT_SYMBOL(ad714x_enable);
-#endif
+
+EXPORT_SIMPLE_DEV_PM_OPS(ad714x_pm, ad714x_suspend, ad714x_resume);
MODULE_DESCRIPTION("Analog Devices AD714X Capacitance Touch Sensor Driver");
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
diff --git a/drivers/input/misc/ad714x.h b/drivers/input/misc/ad714x.h
index af847b5f0d0e..dafa12325f27 100644
--- a/drivers/input/misc/ad714x.h
+++ b/drivers/input/misc/ad714x.h
@@ -8,6 +8,7 @@
#ifndef _AD714X_H_
#define _AD714X_H_
+#include <linux/pm.h>
#include <linux/types.h>
#define STAGE_NUM 12
@@ -45,8 +46,7 @@ struct ad714x_chip {
};
-int ad714x_disable(struct ad714x_chip *ad714x);
-int ad714x_enable(struct ad714x_chip *ad714x);
+extern const struct dev_pm_ops ad714x_pm;
struct ad714x_chip *ad714x_probe(struct device *dev, u16 bus_type, int irq,
ad714x_read_t read, ad714x_write_t write);
diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c
index e64368a63346..c05d898898e8 100644
--- a/drivers/input/misc/adxl34x-i2c.c
+++ b/drivers/input/misc/adxl34x-i2c.c
@@ -74,8 +74,7 @@ static const struct adxl34x_bus_ops adxl34x_i2c_bops = {
.read_block = adxl34x_i2c_read_block,
};
-static int adxl34x_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int adxl34x_i2c_probe(struct i2c_client *client)
{
struct adxl34x *ac;
int error;
@@ -99,38 +98,8 @@ static int adxl34x_i2c_probe(struct i2c_client *client,
return 0;
}
-static int adxl34x_i2c_remove(struct i2c_client *client)
-{
- struct adxl34x *ac = i2c_get_clientdata(client);
-
- return adxl34x_remove(ac);
-}
-
-static int __maybe_unused adxl34x_i2c_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adxl34x *ac = i2c_get_clientdata(client);
-
- adxl34x_suspend(ac);
-
- return 0;
-}
-
-static int __maybe_unused adxl34x_i2c_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct adxl34x *ac = i2c_get_clientdata(client);
-
- adxl34x_resume(ac);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(adxl34x_i2c_pm, adxl34x_i2c_suspend,
- adxl34x_i2c_resume);
-
static const struct i2c_device_id adxl34x_id[] = {
- { "adxl34x", 0 },
+ { "adxl34x" },
{ }
};
@@ -156,11 +125,11 @@ MODULE_DEVICE_TABLE(of, adxl34x_of_id);
static struct i2c_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
- .pm = &adxl34x_i2c_pm,
+ .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 df6afa455e46..fd716d861832 100644
--- a/drivers/input/misc/adxl34x-spi.c
+++ b/drivers/input/misc/adxl34x-spi.c
@@ -87,43 +87,13 @@ static int adxl34x_spi_probe(struct spi_device *spi)
return 0;
}
-static int adxl34x_spi_remove(struct spi_device *spi)
-{
- struct adxl34x *ac = spi_get_drvdata(spi);
-
- return adxl34x_remove(ac);
-}
-
-static int __maybe_unused adxl34x_spi_suspend(struct device *dev)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct adxl34x *ac = spi_get_drvdata(spi);
-
- adxl34x_suspend(ac);
-
- return 0;
-}
-
-static int __maybe_unused adxl34x_spi_resume(struct device *dev)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct adxl34x *ac = spi_get_drvdata(spi);
-
- adxl34x_resume(ac);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(adxl34x_spi_pm, adxl34x_spi_suspend,
- adxl34x_spi_resume);
-
static struct spi_driver adxl34x_driver = {
.driver = {
.name = "adxl34x",
- .pm = &adxl34x_spi_pm,
+ .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 4cc4e8ff42b3..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>
@@ -237,11 +238,12 @@ static const struct adxl34x_platform_data adxl34x_default_init = {
static void adxl34x_get_triple(struct adxl34x *ac, struct axis_triple *axis)
{
- short buf[3];
+ __le16 buf[3];
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)
@@ -412,31 +413,33 @@ static void __adxl34x_enable(struct adxl34x *ac)
AC_WRITE(ac, POWER_CTL, ac->pdata.power_mode | PCTL_MEASURE);
}
-void adxl34x_suspend(struct adxl34x *ac)
+static int adxl34x_suspend(struct device *dev)
{
- mutex_lock(&ac->mutex);
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
+ guard(mutex)(&ac->mutex);
if (!ac->suspended && !ac->disabled && ac->opened)
__adxl34x_disable(ac);
ac->suspended = true;
- mutex_unlock(&ac->mutex);
+ return 0;
}
-EXPORT_SYMBOL_GPL(adxl34x_suspend);
-void adxl34x_resume(struct adxl34x *ac)
+static int adxl34x_resume(struct device *dev)
{
- mutex_lock(&ac->mutex);
+ struct adxl34x *ac = dev_get_drvdata(dev);
+
+ guard(mutex)(&ac->mutex);
if (ac->suspended && !ac->disabled && ac->opened)
__adxl34x_enable(ac);
ac->suspended = false;
- mutex_unlock(&ac->mutex);
+ return 0;
}
-EXPORT_SYMBOL_GPL(adxl34x_resume);
static ssize_t adxl34x_disable_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -458,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) {
@@ -472,8 +475,6 @@ static ssize_t adxl34x_disable_store(struct device *dev,
ac->disabled = !!val;
- mutex_unlock(&ac->mutex);
-
return count;
}
@@ -483,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,
@@ -506,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;
@@ -519,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;
}
@@ -547,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;
}
@@ -582,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);
@@ -592,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;
}
@@ -604,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);
@@ -632,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;
}
@@ -658,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;
}
@@ -678,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,
@@ -695,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;
@@ -742,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;
@@ -757,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
@@ -779,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;
@@ -810,21 +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_TRIGGER_HIGH | 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;
@@ -867,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;
}
@@ -883,30 +862,10 @@ 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);
-int 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);
-
- return 0;
-}
-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>");
MODULE_DESCRIPTION("ADXL345/346 Three-Axis Digital Accelerometer Driver");
diff --git a/drivers/input/misc/adxl34x.h b/drivers/input/misc/adxl34x.h
index 83a0eeccf613..718e90c2046d 100644
--- a/drivers/input/misc/adxl34x.h
+++ b/drivers/input/misc/adxl34x.h
@@ -20,11 +20,11 @@ struct adxl34x_bus_ops {
int (*write)(struct device *, unsigned char, unsigned char);
};
-void adxl34x_suspend(struct adxl34x *ac);
-void adxl34x_resume(struct adxl34x *ac);
struct adxl34x *adxl34x_probe(struct device *dev, int irq,
bool fifo_delay_default,
const struct adxl34x_bus_ops *bops);
-int 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/apanel.c b/drivers/input/misc/apanel.c
index 7276657ad7ca..d43aebd785b7 100644
--- a/drivers/input/misc/apanel.c
+++ b/drivers/input/misc/apanel.c
@@ -120,8 +120,7 @@ static int mail_led_set(struct led_classdev *led,
return i2c_smbus_write_word_data(ap->client, 0x10, led_bits);
}
-static int apanel_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int apanel_probe(struct i2c_client *client)
{
struct apanel *ap;
struct input_dev *idev;
@@ -193,7 +192,7 @@ static void apanel_shutdown(struct i2c_client *client)
}
static const struct i2c_device_id apanel_id[] = {
- { "fujitsu_apanel", 0 },
+ { "fujitsu_apanel" },
{ }
};
MODULE_DEVICE_TABLE(i2c, apanel_id);
diff --git a/drivers/input/misc/ariel-pwrbutton.c b/drivers/input/misc/ariel-pwrbutton.c
index 17bbaac8b80c..cdc80715b5fd 100644
--- a/drivers/input/misc/ariel-pwrbutton.c
+++ b/drivers/input/misc/ariel-pwrbutton.c
@@ -149,12 +149,19 @@ static const struct of_device_id ariel_pwrbutton_of_match[] = {
};
MODULE_DEVICE_TABLE(of, ariel_pwrbutton_of_match);
+static const struct spi_device_id ariel_pwrbutton_spi_ids[] = {
+ { .name = "wyse-ariel-ec-input" },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ariel_pwrbutton_spi_ids);
+
static struct spi_driver ariel_pwrbutton_driver = {
.driver = {
.name = "dell-wyse-ariel-ec-input",
.of_match_table = ariel_pwrbutton_of_match,
},
.probe = ariel_pwrbutton_probe,
+ .id_table = ariel_pwrbutton_spi_ids,
};
module_spi_driver(ariel_pwrbutton_driver);
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 8a36d78fed63..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)
@@ -639,7 +610,7 @@ static int ati_remote2_urb_init(struct ati_remote2 *ar2)
return -ENOMEM;
pipe = usb_rcvintpipe(udev, ar2->ep[i]->bEndpointAddress);
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ maxp = usb_maxpacket(udev, pipe);
maxp = maxp > 4 ? 4 : maxp;
usb_fill_int_urb(ar2->urb[i], udev, pipe, ar2->buf[i], maxp,
@@ -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/atlas_btns.c b/drivers/input/misc/atlas_btns.c
index 0e77c40e1966..5b9be2957746 100644
--- a/drivers/input/misc/atlas_btns.c
+++ b/drivers/input/misc/atlas_btns.c
@@ -106,7 +106,7 @@ static int atlas_acpi_button_add(struct acpi_device *device)
return err;
}
-static int atlas_acpi_button_remove(struct acpi_device *device)
+static void atlas_acpi_button_remove(struct acpi_device *device)
{
acpi_status status;
@@ -116,8 +116,6 @@ static int atlas_acpi_button_remove(struct acpi_device *device)
pr_err("error removing addr spc handler\n");
input_unregister_device(input_dev);
-
- return 0;
}
static const struct acpi_device_id atlas_device_ids[] = {
@@ -129,7 +127,6 @@ MODULE_DEVICE_TABLE(acpi, atlas_device_ids);
static struct acpi_driver atlas_acpi_driver = {
.name = ACPI_ATLAS_NAME,
.class = ACPI_ATLAS_CLASS,
- .owner = THIS_MODULE,
.ids = atlas_device_ids,
.ops = {
.add = atlas_acpi_button_add,
diff --git a/drivers/input/misc/atmel_captouch.c b/drivers/input/misc/atmel_captouch.c
index 051aded6815a..f9744cf0ca80 100644
--- a/drivers/input/misc/atmel_captouch.c
+++ b/drivers/input/misc/atmel_captouch.c
@@ -161,8 +161,7 @@ out:
/*
* Probe function to setup the device, input system and interrupt
*/
-static int atmel_captouch_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int atmel_captouch_probe(struct i2c_client *client)
{
struct atmel_captouch_device *capdev;
struct device *dev = &client->dev;
@@ -249,7 +248,6 @@ static int atmel_captouch_probe(struct i2c_client *client,
return 0;
}
-#ifdef CONFIG_OF
static const struct of_device_id atmel_captouch_of_id[] = {
{
.compatible = "atmel,captouch",
@@ -257,10 +255,9 @@ static const struct of_device_id atmel_captouch_of_id[] = {
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, atmel_captouch_of_id);
-#endif
static const struct i2c_device_id atmel_captouch_id[] = {
- { "atmel_captouch", 0 },
+ { "atmel_captouch" },
{ }
};
MODULE_DEVICE_TABLE(i2c, atmel_captouch_id);
@@ -270,7 +267,7 @@ static struct i2c_driver atmel_captouch_driver = {
.id_table = atmel_captouch_id,
.driver = {
.name = "atmel_captouch",
- .of_match_table = of_match_ptr(atmel_captouch_of_id),
+ .of_match_table = atmel_captouch_of_id,
},
};
module_i2c_driver(atmel_captouch_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/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
index 9c6386b2af33..24f9e9d893de 100644
--- a/drivers/input/misc/axp20x-pek.c
+++ b/drivers/input/misc/axp20x-pek.c
@@ -22,6 +22,7 @@
#include <linux/kernel.h>
#include <linux/mfd/axp20x.h>
#include <linux/module.h>
+#include <linux/platform_data/x86/soc.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -132,20 +133,11 @@ static ssize_t axp20x_store_attr(struct device *dev,
size_t count)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
- char val_str[20];
- size_t len;
int ret, i;
unsigned int val, idx = 0;
unsigned int best_err = UINT_MAX;
- val_str[sizeof(val_str) - 1] = '\0';
- strncpy(val_str, buf, sizeof(val_str) - 1);
- len = strlen(val_str);
-
- if (len && val_str[len - 1] == '\n')
- val_str[len - 1] = '\0';
-
- ret = kstrtouint(val_str, 10, &val);
+ ret = kstrtouint(buf, 10, &val);
if (ret)
return ret;
@@ -205,11 +197,8 @@ ATTRIBUTE_GROUPS(axp20x);
static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
{
- struct axp20x_pek *axp20x_pek = pwr;
- struct input_dev *idev = axp20x_pek->input;
-
- if (!idev)
- return IRQ_HANDLED;
+ struct input_dev *idev = pwr;
+ struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
/*
* The power-button is connected to ground so a falling edge (dbf)
@@ -228,9 +217,22 @@ static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
struct platform_device *pdev)
{
+ struct axp20x_dev *axp20x = axp20x_pek->axp20x;
struct input_dev *idev;
int error;
+ axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
+ if (axp20x_pek->irq_dbr < 0)
+ return axp20x_pek->irq_dbr;
+ axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
+ axp20x_pek->irq_dbr);
+
+ axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
+ if (axp20x_pek->irq_dbf < 0)
+ return axp20x_pek->irq_dbf;
+ axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
+ axp20x_pek->irq_dbf);
+
axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
if (!axp20x_pek->input)
return -ENOMEM;
@@ -245,6 +247,24 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
input_set_drvdata(idev, axp20x_pek);
+ error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr,
+ axp20x_pek_irq, 0,
+ "axp20x-pek-dbr", idev);
+ if (error < 0) {
+ dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n",
+ axp20x_pek->irq_dbr, error);
+ return error;
+ }
+
+ error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf,
+ axp20x_pek_irq, 0,
+ "axp20x-pek-dbf", idev);
+ if (error < 0) {
+ dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n",
+ axp20x_pek->irq_dbf, error);
+ return error;
+ }
+
error = input_register_device(idev);
if (error) {
dev_err(&pdev->dev, "Can't register input device: %d\n",
@@ -252,44 +272,29 @@ static int axp20x_pek_probe_input_device(struct axp20x_pek *axp20x_pek,
return error;
}
+ device_init_wakeup(&pdev->dev, true);
+
return 0;
}
-#ifdef CONFIG_ACPI
-static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek,
- struct platform_device *pdev)
+static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek)
{
- unsigned long long hrv = 0;
- acpi_status status;
-
if (IS_ENABLED(CONFIG_INPUT_SOC_BUTTON_ARRAY) &&
axp20x_pek->axp20x->variant == AXP288_ID) {
- status = acpi_evaluate_integer(ACPI_HANDLE(pdev->dev.parent),
- "_HRV", NULL, &hrv);
- if (ACPI_FAILURE(status))
- dev_err(&pdev->dev, "Failed to get PMIC hardware revision\n");
-
/*
* On Cherry Trail platforms (hrv == 3), do not register the
* input device if there is an "INTCFD9" or "ACPI0011" gpio
* button ACPI device, as that handles the power button too,
* and otherwise we end up reporting all presses twice.
*/
- if (hrv == 3 && (acpi_dev_present("INTCFD9", NULL, -1) ||
+ if (soc_intel_is_cht() &&
+ (acpi_dev_present("INTCFD9", NULL, -1) ||
acpi_dev_present("ACPI0011", NULL, -1)))
return false;
-
}
return true;
}
-#else
-static bool axp20x_pek_should_register_input(struct axp20x_pek *axp20x_pek,
- struct platform_device *pdev)
-{
- return true;
-}
-#endif
static int axp20x_pek_probe(struct platform_device *pdev)
{
@@ -309,19 +314,7 @@ static int axp20x_pek_probe(struct platform_device *pdev)
axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
- axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
- if (axp20x_pek->irq_dbr < 0)
- return axp20x_pek->irq_dbr;
- axp20x_pek->irq_dbr = regmap_irq_get_virq(
- axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbr);
-
- axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
- if (axp20x_pek->irq_dbf < 0)
- return axp20x_pek->irq_dbf;
- axp20x_pek->irq_dbf = regmap_irq_get_virq(
- axp20x_pek->axp20x->regmap_irqc, axp20x_pek->irq_dbf);
-
- if (axp20x_pek_should_register_input(axp20x_pek, pdev)) {
+ if (axp20x_pek_should_register_input(axp20x_pek)) {
error = axp20x_pek_probe_input_device(axp20x_pek, pdev);
if (error)
return error;
@@ -329,32 +322,12 @@ static int axp20x_pek_probe(struct platform_device *pdev)
axp20x_pek->info = (struct axp20x_info *)match->driver_data;
- error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr,
- axp20x_pek_irq, 0,
- "axp20x-pek-dbr", axp20x_pek);
- if (error < 0) {
- dev_err(&pdev->dev, "Failed to request dbr IRQ#%d: %d\n",
- axp20x_pek->irq_dbr, error);
- return error;
- }
-
- error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf,
- axp20x_pek_irq, 0,
- "axp20x-pek-dbf", axp20x_pek);
- if (error < 0) {
- dev_err(&pdev->dev, "Failed to request dbf IRQ#%d: %d\n",
- axp20x_pek->irq_dbf, error);
- return error;
- }
-
- device_init_wakeup(&pdev->dev, true);
-
platform_set_drvdata(pdev, axp20x_pek);
return 0;
}
-static int __maybe_unused axp20x_pek_suspend(struct device *dev)
+static int axp20x_pek_suspend(struct device *dev)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
@@ -373,7 +346,7 @@ static int __maybe_unused axp20x_pek_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused axp20x_pek_resume(struct device *dev)
+static int axp20x_pek_resume(struct device *dev)
{
struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
@@ -407,10 +380,8 @@ static int __maybe_unused axp20x_pek_resume_noirq(struct device *dev)
}
static const struct dev_pm_ops axp20x_pek_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
-#ifdef CONFIG_PM_SLEEP
- .resume_noirq = axp20x_pek_resume_noirq,
-#endif
+ SYSTEM_SLEEP_PM_OPS(axp20x_pek_suspend, axp20x_pek_resume)
+ .resume_noirq = pm_sleep_ptr(axp20x_pek_resume_noirq),
};
static const struct platform_device_id axp_pek_id_match[] = {
@@ -431,7 +402,7 @@ static struct platform_driver axp20x_pek_driver = {
.id_table = axp_pek_id_match,
.driver = {
.name = "axp20x-pek",
- .pm = &axp20x_pek_pm_ops,
+ .pm = pm_sleep_ptr(&axp20x_pek_pm_ops),
.dev_groups = axp20x_groups,
},
};
diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c
index a9d984da95f3..4cc2a0dcaa75 100644
--- a/drivers/input/misc/bma150.c
+++ b/drivers/input/misc/bma150.c
@@ -414,8 +414,7 @@ static int bma150_initialize(struct bma150_data *bma150,
return bma150_set_mode(bma150, BMA150_MODE_SLEEP);
}
-static int bma150_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int bma150_probe(struct i2c_client *client)
{
const struct bma150_platform_data *pdata =
dev_get_platdata(&client->dev);
@@ -513,11 +512,9 @@ static int bma150_probe(struct i2c_client *client,
return 0;
}
-static int bma150_remove(struct i2c_client *client)
+static void bma150_remove(struct i2c_client *client)
{
pm_runtime_disable(&client->dev);
-
- return 0;
}
static int __maybe_unused bma150_suspend(struct device *dev)
@@ -539,9 +536,9 @@ static int __maybe_unused bma150_resume(struct device *dev)
static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL);
static const struct i2c_device_id bma150_id[] = {
- { "bma150", 0 },
- { "smb380", 0 },
- { "bma023", 0 },
+ { "bma150" },
+ { "smb380" },
+ { "bma023" },
{ }
};
diff --git a/drivers/input/misc/cm109.c b/drivers/input/misc/cm109.c
index f515fae465c3..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);
}
@@ -745,7 +736,7 @@ static int cm109_usb_probe(struct usb_interface *intf,
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
- ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ ret = usb_maxpacket(udev, pipe);
if (ret != USB_PKT_LEN)
dev_err(&intf->dev, "invalid payload size %d, expected %d\n",
ret, USB_PKT_LEN);
@@ -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 e6feb73bb52b..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;
@@ -325,8 +318,6 @@ struct cma3000_accl_data *cma3000_init(struct device *dev, int irq,
input_dev->open = cma3000_open;
input_dev->close = cma3000_close;
- __set_bit(EV_ABS, input_dev->evbit);
-
input_set_abs_params(input_dev, ABS_X,
-data->g_range, data->g_range, pdata->fuzz_x, 0);
input_set_abs_params(input_dev, ABS_Y,
diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c
index 03fb49127c3a..f892c5b1e4bd 100644
--- a/drivers/input/misc/cma3000_d0x_i2c.c
+++ b/drivers/input/misc/cma3000_d0x_i2c.c
@@ -44,8 +44,7 @@ static const struct cma3000_bus_ops cma3000_i2c_bops = {
.write = cma3000_i2c_set,
};
-static int cma3000_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int cma3000_i2c_probe(struct i2c_client *client)
{
struct cma3000_accl_data *data;
@@ -58,16 +57,13 @@ static int cma3000_i2c_probe(struct i2c_client *client,
return 0;
}
-static int cma3000_i2c_remove(struct i2c_client *client)
+static void cma3000_i2c_remove(struct i2c_client *client)
{
struct cma3000_accl_data *data = i2c_get_clientdata(client);
cma3000_exit(data);
-
- return 0;
}
-#ifdef CONFIG_PM
static int cma3000_i2c_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -92,11 +88,10 @@ static const struct dev_pm_ops cma3000_i2c_pm_ops = {
.suspend = cma3000_i2c_suspend,
.resume = cma3000_i2c_resume,
};
-#endif
static const struct i2c_device_id cma3000_i2c_id[] = {
- { "cma3000_d01", 0 },
- { },
+ { "cma3000_d01" },
+ { }
};
MODULE_DEVICE_TABLE(i2c, cma3000_i2c_id);
@@ -107,9 +102,7 @@ static struct i2c_driver cma3000_i2c_driver = {
.id_table = cma3000_i2c_id,
.driver = {
.name = "cma3000_i2c_accl",
-#ifdef CONFIG_PM
- .pm = &cma3000_i2c_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&cma3000_i2c_pm_ops),
},
};
diff --git a/drivers/input/misc/cpcap-pwrbutton.c b/drivers/input/misc/cpcap-pwrbutton.c
index 0abef63217e2..85cddb84717a 100644
--- a/drivers/input/misc/cpcap-pwrbutton.c
+++ b/drivers/input/misc/cpcap-pwrbutton.c
@@ -1,16 +1,8 @@
-/**
+// SPDX-License-Identifier: GPL-2.0-only
+/*
* CPCAP Power Button Input Driver
*
* Copyright (C) 2017 Sebastian Reichel <sre@kernel.org>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of this
- * archive for more details.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/module.h>
@@ -54,9 +46,13 @@ static irqreturn_t powerbutton_irq(int irq, void *_button)
static int cpcap_power_button_probe(struct platform_device *pdev)
{
struct cpcap_power_button *button;
- int irq = platform_get_irq(pdev, 0);
+ int irq;
int err;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
button = devm_kmalloc(&pdev->dev, sizeof(*button), GFP_KERNEL);
if (!button)
return -ENOMEM;
@@ -73,7 +69,6 @@ static int cpcap_power_button_probe(struct platform_device *pdev)
button->idev->name = "cpcap-pwrbutton";
button->idev->phys = "cpcap-pwrbutton/input0";
- button->idev->dev.parent = button->dev;
input_set_capability(button->idev, EV_KEY, KEY_POWER);
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
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 b08610d6e575..e4a605c6af15 100644
--- a/drivers/input/misc/da7280.c
+++ b/drivers/input/misc/da7280.c
@@ -230,7 +230,6 @@ struct da7280_haptic {
struct i2c_client *client;
struct pwm_device *pwm_dev;
- bool legacy;
struct work_struct work;
int val;
u16 gain;
@@ -352,7 +351,7 @@ static int da7280_haptic_set_pwm(struct da7280_haptic *haptics, bool enabled)
state.duty_cycle = period_mag_multi;
}
- error = pwm_apply_state(haptics->pwm_dev, &state);
+ error = pwm_apply_might_sleep(haptics->pwm_dev, &state);
if (error)
dev_err(haptics->dev, "Failed to apply pwm state: %d\n", error);
@@ -1140,8 +1139,7 @@ out_err:
return error;
}
-static int da7280_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int da7280_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct da7280_haptic *haptics;
@@ -1176,7 +1174,7 @@ static int da7280_probe(struct i2c_client *client,
/* Sync up PWM state and ensure it is off. */
pwm_init_state(haptics->pwm_dev, &state);
state.enabled = false;
- error = pwm_apply_state(haptics->pwm_dev, &state);
+ error = pwm_apply_might_sleep(haptics->pwm_dev, &state);
if (error) {
dev_err(dev, "Failed to apply PWM state: %d\n", error);
return error;
@@ -1261,43 +1259,41 @@ static int da7280_probe(struct i2c_client *client,
return 0;
}
-static int __maybe_unused da7280_suspend(struct device *dev)
+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 __maybe_unused da7280_resume(struct device *dev)
+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
@@ -1314,13 +1310,13 @@ static const struct i2c_device_id da7280_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, da7280_i2c_id);
-static SIMPLE_DEV_PM_OPS(da7280_pm_ops, da7280_suspend, da7280_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(da7280_pm_ops, da7280_suspend, da7280_resume);
static struct i2c_driver da7280_driver = {
.driver = {
.name = "da7280",
.of_match_table = of_match_ptr(da7280_of_match),
- .pm = &da7280_pm_ops,
+ .pm = pm_sleep_ptr(&da7280_pm_ops),
},
.probe = da7280_probe,
.id_table = da7280_i2c_id,
diff --git a/drivers/input/misc/da9052_onkey.c b/drivers/input/misc/da9052_onkey.c
index 6d1152850a6d..cc23625019e3 100644
--- a/drivers/input/misc/da9052_onkey.c
+++ b/drivers/input/misc/da9052_onkey.c
@@ -127,7 +127,7 @@ err_free_mem:
return error;
}
-static int da9052_onkey_remove(struct platform_device *pdev)
+static void da9052_onkey_remove(struct platform_device *pdev)
{
struct da9052_onkey *onkey = platform_get_drvdata(pdev);
@@ -136,14 +136,12 @@ static int da9052_onkey_remove(struct platform_device *pdev)
input_unregister_device(onkey->input);
kfree(onkey);
-
- return 0;
}
static struct platform_driver da9052_onkey_driver = {
.probe = da9052_onkey_probe,
.remove = da9052_onkey_remove,
- .driver = {
+ .driver = {
.name = "da9052-onkey",
},
};
diff --git a/drivers/input/misc/da9055_onkey.c b/drivers/input/misc/da9055_onkey.c
index 7a0d3a1d503c..3e4fc2f01011 100644
--- a/drivers/input/misc/da9055_onkey.c
+++ b/drivers/input/misc/da9055_onkey.c
@@ -132,7 +132,7 @@ err_free_input:
return err;
}
-static int da9055_onkey_remove(struct platform_device *pdev)
+static void da9055_onkey_remove(struct platform_device *pdev)
{
struct da9055_onkey *onkey = platform_get_drvdata(pdev);
int irq = platform_get_irq_byname(pdev, "ONKEY");
@@ -141,14 +141,12 @@ static int da9055_onkey_remove(struct platform_device *pdev)
free_irq(irq, onkey);
cancel_delayed_work_sync(&onkey->work);
input_unregister_device(onkey->input);
-
- return 0;
}
static struct platform_driver da9055_onkey_driver = {
.probe = da9055_onkey_probe,
.remove = da9055_onkey_remove,
- .driver = {
+ .driver = {
.name = "da9055-onkey",
},
};
diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c
index 79851923ee57..c338765e0ecd 100644
--- a/drivers/input/misc/da9063_onkey.c
+++ b/drivers/input/misc/da9063_onkey.c
@@ -4,14 +4,17 @@
* Copyright (C) 2015 Dialog Semiconductor Ltd.
*/
+#include <linux/devm-helpers.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/property.h>
#include <linux/workqueue.h>
#include <linux/regmap.h>
-#include <linux/of.h>
#include <linux/mfd/da9063/core.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9062/core.h>
@@ -72,13 +75,6 @@ static const struct da906x_chip_config da9062_regs = {
.name = "da9062-onkey",
};
-static const struct of_device_id da9063_compatible_reg_id_table[] = {
- { .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
- { .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
- { },
-};
-MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
-
static void da9063_poll_on(struct work_struct *work)
{
struct da9063_onkey *onkey = container_of(work,
@@ -182,67 +178,46 @@ static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static void da9063_cancel_poll(void *data)
-{
- struct da9063_onkey *onkey = data;
-
- cancel_delayed_work_sync(&onkey->work);
-}
-
static int da9063_onkey_probe(struct platform_device *pdev)
{
struct da9063_onkey *onkey;
- const struct of_device_id *match;
- int irq;
int error;
-
- match = of_match_node(da9063_compatible_reg_id_table,
- pdev->dev.of_node);
- if (!match)
- return -ENXIO;
+ int irq;
onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
GFP_KERNEL);
- if (!onkey) {
- dev_err(&pdev->dev, "Failed to allocate memory.\n");
+ if (!onkey)
return -ENOMEM;
- }
- onkey->config = match->data;
+ onkey->config = device_get_match_data(&pdev->dev);
+ if (!onkey->config)
+ return -ENXIO;
+
onkey->dev = &pdev->dev;
onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!onkey->regmap) {
- dev_err(&pdev->dev, "Parent regmap unavailable.\n");
- return -ENXIO;
- }
+ if (!onkey->regmap)
+ return dev_err_probe(&pdev->dev, -ENXIO,
+ "Parent regmap unavailable.\n");
- onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
- "dlg,disable-key-power");
+ onkey->key_power = !device_property_read_bool(&pdev->dev,
+ "dlg,disable-key-power");
onkey->input = devm_input_allocate_device(&pdev->dev);
- if (!onkey->input) {
- dev_err(&pdev->dev, "Failed to allocated input device.\n");
+ if (!onkey->input)
return -ENOMEM;
- }
onkey->input->name = onkey->config->name;
snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0",
onkey->config->name);
onkey->input->phys = onkey->phys;
- onkey->input->dev.parent = &pdev->dev;
input_set_capability(onkey->input, EV_KEY, KEY_POWER);
- INIT_DELAYED_WORK(&onkey->work, da9063_poll_on);
-
- error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey);
- if (error) {
- dev_err(&pdev->dev,
- "Failed to add cancel poll action: %d\n",
- error);
+ error = devm_delayed_work_autocancel(&pdev->dev, &onkey->work,
+ da9063_poll_on);
+ if (error)
return error;
- }
irq = platform_get_irq_byname(pdev, "ONKEY");
if (irq < 0)
@@ -252,22 +227,32 @@ static int da9063_onkey_probe(struct platform_device *pdev)
NULL, da9063_onkey_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"ONKEY", onkey);
- if (error) {
- dev_err(&pdev->dev,
- "Failed to request IRQ %d: %d\n", irq, error);
- return error;
- }
+ if (error)
+ return dev_err_probe(&pdev->dev, error,
+ "Failed to allocate onkey IRQ\n");
+
+ error = dev_pm_set_wake_irq(&pdev->dev, irq);
+ if (error)
+ dev_warn(&pdev->dev,
+ "Failed to set IRQ %d as a wake IRQ: %d\n",
+ irq, error);
+ else
+ device_init_wakeup(&pdev->dev, true);
error = input_register_device(onkey->input);
- if (error) {
- dev_err(&pdev->dev,
- "Failed to register input device: %d\n", error);
+ if (error)
return error;
- }
return 0;
}
+static const struct of_device_id da9063_compatible_reg_id_table[] = {
+ { .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
+ { .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
+
static struct platform_driver da9063_onkey_driver = {
.probe = da9063_onkey_probe,
.driver = {
diff --git a/drivers/input/misc/dm355evm_keys.c b/drivers/input/misc/dm355evm_keys.c
deleted file mode 100644
index 397ca7c787cc..000000000000
--- a/drivers/input/misc/dm355evm_keys.c
+++ /dev/null
@@ -1,238 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * dm355evm_keys.c - support buttons and IR remote on DM355 EVM board
- *
- * Copyright (c) 2008 by David Brownell
- */
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/input/sparse-keymap.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-
-#include <linux/mfd/dm355evm_msp.h>
-#include <linux/module.h>
-
-
-/*
- * The MSP430 firmware on the DM355 EVM monitors on-board pushbuttons
- * and an IR receptor used for the remote control. When any key is
- * pressed, or its autorepeat kicks in, an event is sent. This driver
- * read those events from the small (32 event) queue and reports them.
- *
- * Note that physically there can only be one of these devices.
- *
- * This driver was tested with firmware revision A4.
- */
-struct dm355evm_keys {
- struct input_dev *input;
- struct device *dev;
-};
-
-/* These initial keycodes can be remapped */
-static const struct key_entry dm355evm_keys[] = {
- /*
- * Pushbuttons on the EVM board ... note that the labels for these
- * are SW10/SW11/etc on the PC board. The left/right orientation
- * comes only from the firmware's documentation, and presumes the
- * power connector is immediately in front of you and the IR sensor
- * is to the right. (That is, rotate the board counter-clockwise
- * by 90 degrees from the SW10/etc and "DM355 EVM" labels.)
- */
- { KE_KEY, 0x00d8, { KEY_OK } }, /* SW12 */
- { KE_KEY, 0x00b8, { KEY_UP } }, /* SW13 */
- { KE_KEY, 0x00e8, { KEY_DOWN } }, /* SW11 */
- { KE_KEY, 0x0078, { KEY_LEFT } }, /* SW14 */
- { KE_KEY, 0x00f0, { KEY_RIGHT } }, /* SW10 */
-
- /*
- * IR buttons ... codes assigned to match the universal remote
- * provided with the EVM (Philips PM4S) using DVD code 0020.
- *
- * These event codes match firmware documentation, but other
- * remote controls could easily send more RC5-encoded events.
- * The PM4S manual was used in several cases to help select
- * a keycode reflecting the intended usage.
- *
- * RC5 codes are 14 bits, with two start bits (0x3 prefix)
- * and a toggle bit (masked out below).
- */
- { KE_KEY, 0x300c, { KEY_POWER } }, /* NOTE: docs omit this */
- { KE_KEY, 0x3000, { KEY_NUMERIC_0 } },
- { KE_KEY, 0x3001, { KEY_NUMERIC_1 } },
- { KE_KEY, 0x3002, { KEY_NUMERIC_2 } },
- { KE_KEY, 0x3003, { KEY_NUMERIC_3 } },
- { KE_KEY, 0x3004, { KEY_NUMERIC_4 } },
- { KE_KEY, 0x3005, { KEY_NUMERIC_5 } },
- { KE_KEY, 0x3006, { KEY_NUMERIC_6 } },
- { KE_KEY, 0x3007, { KEY_NUMERIC_7 } },
- { KE_KEY, 0x3008, { KEY_NUMERIC_8 } },
- { KE_KEY, 0x3009, { KEY_NUMERIC_9 } },
- { KE_KEY, 0x3022, { KEY_ENTER } },
- { KE_KEY, 0x30ec, { KEY_MODE } }, /* "tv/vcr/..." */
- { KE_KEY, 0x300f, { KEY_SELECT } }, /* "info" */
- { KE_KEY, 0x3020, { KEY_CHANNELUP } }, /* "up" */
- { KE_KEY, 0x302e, { KEY_MENU } }, /* "in/out" */
- { KE_KEY, 0x3011, { KEY_VOLUMEDOWN } }, /* "left" */
- { KE_KEY, 0x300d, { KEY_MUTE } }, /* "ok" */
- { KE_KEY, 0x3010, { KEY_VOLUMEUP } }, /* "right" */
- { KE_KEY, 0x301e, { KEY_SUBTITLE } }, /* "cc" */
- { KE_KEY, 0x3021, { KEY_CHANNELDOWN } },/* "down" */
- { KE_KEY, 0x3022, { KEY_PREVIOUS } },
- { KE_KEY, 0x3026, { KEY_SLEEP } },
- { KE_KEY, 0x3172, { KEY_REWIND } }, /* NOTE: docs wrongly say 0x30ca */
- { KE_KEY, 0x3175, { KEY_PLAY } },
- { KE_KEY, 0x3174, { KEY_FASTFORWARD } },
- { KE_KEY, 0x3177, { KEY_RECORD } },
- { KE_KEY, 0x3176, { KEY_STOP } },
- { KE_KEY, 0x3169, { KEY_PAUSE } },
-};
-
-/*
- * Because we communicate with the MSP430 using I2C, and all I2C calls
- * in Linux sleep, we use a threaded IRQ handler. The IRQ itself is
- * active low, but we go through the GPIO controller so we can trigger
- * on falling edges and not worry about enabling/disabling the IRQ in
- * the keypress handling path.
- */
-static irqreturn_t dm355evm_keys_irq(int irq, void *_keys)
-{
- static u16 last_event;
- struct dm355evm_keys *keys = _keys;
- const struct key_entry *ke;
- unsigned int keycode;
- int status;
- u16 event;
-
- /* For simplicity we ignore INPUT_COUNT and just read
- * events until we get the "queue empty" indicator.
- * Reading INPUT_LOW decrements the count.
- */
- for (;;) {
- status = dm355evm_msp_read(DM355EVM_MSP_INPUT_HIGH);
- if (status < 0) {
- dev_dbg(keys->dev, "input high err %d\n",
- status);
- break;
- }
- event = status << 8;
-
- status = dm355evm_msp_read(DM355EVM_MSP_INPUT_LOW);
- if (status < 0) {
- dev_dbg(keys->dev, "input low err %d\n",
- status);
- break;
- }
- event |= status;
- if (event == 0xdead)
- break;
-
- /* Press and release a button: two events, same code.
- * Press and hold (autorepeat), then release: N events
- * (N > 2), same code. For RC5 buttons the toggle bits
- * distinguish (for example) "1-autorepeat" from "1 1";
- * but PCB buttons don't support that bit.
- *
- * So we must synthesize release events. We do that by
- * mapping events to a press/release event pair; then
- * to avoid adding extra events, skip the second event
- * of each pair.
- */
- if (event == last_event) {
- last_event = 0;
- continue;
- }
- last_event = event;
-
- /* ignore the RC5 toggle bit */
- event &= ~0x0800;
-
- /* find the key, or report it as unknown */
- ke = sparse_keymap_entry_from_scancode(keys->input, event);
- keycode = ke ? ke->keycode : KEY_UNKNOWN;
- dev_dbg(keys->dev,
- "input event 0x%04x--> keycode %d\n",
- event, keycode);
-
- /* report press + release */
- input_report_key(keys->input, keycode, 1);
- input_sync(keys->input);
- input_report_key(keys->input, keycode, 0);
- input_sync(keys->input);
- }
-
- return IRQ_HANDLED;
-}
-
-/*----------------------------------------------------------------------*/
-
-static int dm355evm_keys_probe(struct platform_device *pdev)
-{
- struct dm355evm_keys *keys;
- struct input_dev *input;
- int irq;
- int error;
-
- keys = devm_kzalloc(&pdev->dev, sizeof (*keys), GFP_KERNEL);
- if (!keys)
- return -ENOMEM;
-
- input = devm_input_allocate_device(&pdev->dev);
- if (!input)
- return -ENOMEM;
-
- keys->dev = &pdev->dev;
- keys->input = input;
-
- input->name = "DM355 EVM Controls";
- input->phys = "dm355evm/input0";
-
- input->id.bustype = BUS_I2C;
- input->id.product = 0x0355;
- input->id.version = dm355evm_msp_read(DM355EVM_MSP_FIRMREV);
-
- error = sparse_keymap_setup(input, dm355evm_keys, NULL);
- if (error)
- return error;
-
- /* REVISIT: flush the event queue? */
-
- /* set up "threaded IRQ handler" */
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- error = devm_request_threaded_irq(&pdev->dev, irq,
- NULL, dm355evm_keys_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- dev_name(&pdev->dev), keys);
- if (error)
- return error;
-
- /* register */
- error = input_register_device(input);
- if (error)
- return error;
-
- return 0;
-}
-
-/* REVISIT: add suspend/resume when DaVinci supports it. The IRQ should
- * be able to wake up the system. When device_may_wakeup(&pdev->dev), call
- * enable_irq_wake() on suspend, and disable_irq_wake() on resume.
- */
-
-/*
- * I2C is used to talk to the MSP430, but this platform device is
- * exposed by an MFD driver that manages I2C communications.
- */
-static struct platform_driver dm355evm_keys_driver = {
- .probe = dm355evm_keys_probe,
- .driver = {
- .name = "dm355evm_keys",
- },
-};
-module_platform_driver(dm355evm_keys_driver);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index 0efe56f49aa9..96cd6a078c8a 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -149,7 +149,7 @@
/* Control 3 Register */
#define DRV260X_LRA_OPEN_LOOP (1 << 0)
-#define DRV260X_ANANLOG_IN (1 << 1)
+#define DRV260X_ANALOG_IN (1 << 1)
#define DRV260X_LRA_DRV_MODE (1 << 2)
#define DRV260X_RTP_UNSIGNED_DATA (1 << 3)
#define DRV260X_SUPPLY_COMP_DIS (1 << 4)
@@ -186,51 +186,13 @@ struct drv260x_data {
struct work_struct work;
struct gpio_desc *enable_gpio;
struct regulator *regulator;
- u32 magnitude;
+ u8 magnitude;
u32 mode;
u32 library;
int rated_voltage;
int overdrive_voltage;
};
-static const struct reg_default drv260x_reg_defs[] = {
- { DRV260X_STATUS, 0xe0 },
- { DRV260X_MODE, 0x40 },
- { DRV260X_RT_PB_IN, 0x00 },
- { DRV260X_LIB_SEL, 0x00 },
- { DRV260X_WV_SEQ_1, 0x01 },
- { DRV260X_WV_SEQ_2, 0x00 },
- { DRV260X_WV_SEQ_3, 0x00 },
- { DRV260X_WV_SEQ_4, 0x00 },
- { DRV260X_WV_SEQ_5, 0x00 },
- { DRV260X_WV_SEQ_6, 0x00 },
- { DRV260X_WV_SEQ_7, 0x00 },
- { DRV260X_WV_SEQ_8, 0x00 },
- { DRV260X_GO, 0x00 },
- { DRV260X_OVERDRIVE_OFF, 0x00 },
- { DRV260X_SUSTAIN_P_OFF, 0x00 },
- { DRV260X_SUSTAIN_N_OFF, 0x00 },
- { DRV260X_BRAKE_OFF, 0x00 },
- { DRV260X_A_TO_V_CTRL, 0x05 },
- { DRV260X_A_TO_V_MIN_INPUT, 0x19 },
- { DRV260X_A_TO_V_MAX_INPUT, 0xff },
- { DRV260X_A_TO_V_MIN_OUT, 0x19 },
- { DRV260X_A_TO_V_MAX_OUT, 0xff },
- { DRV260X_RATED_VOLT, 0x3e },
- { DRV260X_OD_CLAMP_VOLT, 0x8c },
- { DRV260X_CAL_COMP, 0x0c },
- { DRV260X_CAL_BACK_EMF, 0x6c },
- { DRV260X_FEEDBACK_CTRL, 0x36 },
- { DRV260X_CTRL1, 0x93 },
- { DRV260X_CTRL2, 0xfa },
- { DRV260X_CTRL3, 0xa0 },
- { DRV260X_CTRL4, 0x20 },
- { DRV260X_CTRL5, 0x80 },
- { DRV260X_LRA_LOOP_PERIOD, 0x33 },
- { DRV260X_VBAT_MON, 0x00 },
- { DRV260X_LRA_RES_PERIOD, 0x00 },
-};
-
#define DRV260X_DEF_RATED_VOLT 0x90
#define DRV260X_DEF_OD_CLAMP_VOLT 0x90
@@ -275,10 +237,11 @@ static int drv260x_haptics_play(struct input_dev *input, void *data,
haptics->mode = DRV260X_LRA_NO_CAL_MODE;
+ /* Scale u16 magnitude into u8 register value */
if (effect->u.rumble.strong_magnitude > 0)
- haptics->magnitude = effect->u.rumble.strong_magnitude;
+ haptics->magnitude = effect->u.rumble.strong_magnitude >> 8;
else if (effect->u.rumble.weak_magnitude > 0)
- haptics->magnitude = effect->u.rumble.weak_magnitude;
+ haptics->magnitude = effect->u.rumble.weak_magnitude >> 8;
else
haptics->magnitude = 0;
@@ -304,7 +267,7 @@ static void drv260x_close(struct input_dev *input)
static const struct reg_sequence drv260x_lra_cal_regs[] = {
{ DRV260X_MODE, DRV260X_AUTO_CAL },
- { DRV260X_CTRL3, DRV260X_NG_THRESH_2 },
+ { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA },
{ DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE |
DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH },
};
@@ -322,7 +285,7 @@ static const struct reg_sequence drv260x_lra_init_regs[] = {
DRV260X_BEMF_GAIN_3 },
{ DRV260X_CTRL1, DRV260X_STARTUP_BOOST },
{ DRV260X_CTRL2, DRV260X_SAMP_TIME_250 },
- { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ANANLOG_IN },
+ { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA | DRV260X_ANALOG_IN },
{ DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
};
@@ -337,7 +300,7 @@ static const struct reg_sequence drv260x_erm_cal_regs[] = {
{ DRV260X_CTRL1, DRV260X_STARTUP_BOOST },
{ DRV260X_CTRL2, DRV260X_SAMP_TIME_250 | DRV260X_BLANK_TIME_75 |
DRV260X_IDISS_TIME_75 },
- { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_ERM_OPEN_LOOP },
+ { DRV260X_CTRL3, DRV260X_NG_THRESH_2 | DRV260X_RTP_UNSIGNED_DATA },
{ DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS },
};
@@ -435,6 +398,7 @@ static int drv260x_init(struct drv260x_data *haptics)
}
do {
+ usleep_range(15000, 15500);
error = regmap_read(haptics->regmap, DRV260X_GO, &cal_buf);
if (error) {
dev_err(&haptics->client->dev,
@@ -452,13 +416,10 @@ static const struct regmap_config drv260x_regmap_config = {
.val_bits = 8,
.max_register = DRV260X_MAX_REG,
- .reg_defaults = drv260x_reg_defs,
- .num_reg_defaults = ARRAY_SIZE(drv260x_reg_defs),
.cache_type = REGCACHE_NONE,
};
-static int drv260x_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int drv260x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct drv260x_data *haptics;
@@ -573,73 +534,71 @@ static int drv260x_probe(struct i2c_client *client,
return 0;
}
-static int __maybe_unused drv260x_suspend(struct device *dev)
+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 __maybe_unused drv260x_resume(struct device *dev)
+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 SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(drv260x_pm_ops, drv260x_suspend, drv260x_resume);
static const struct i2c_device_id drv260x_id[] = {
- { "drv2605l", 0 },
+ { "drv2605l" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv260x_id);
@@ -658,7 +617,7 @@ static struct i2c_driver drv260x_driver = {
.driver = {
.name = "drv260x-haptics",
.of_match_table = drv260x_of_match,
- .pm = &drv260x_pm_ops,
+ .pm = pm_sleep_ptr(&drv260x_pm_ops),
},
.id_table = drv260x_id,
};
diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c
index 21913e8085d7..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
@@ -156,8 +156,7 @@ static const struct regmap_config drv2665_regmap_config = {
.cache_type = REGCACHE_NONE,
};
-static int drv2665_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int drv2665_probe(struct i2c_client *client)
{
struct drv2665_data *haptics;
int error;
@@ -223,68 +222,66 @@ static int drv2665_probe(struct i2c_client *client,
return 0;
}
-static int __maybe_unused drv2665_suspend(struct device *dev)
+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 __maybe_unused drv2665_resume(struct device *dev)
+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 SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume);
static const struct i2c_device_id drv2665_id[] = {
- { "drv2665", 0 },
+ { "drv2665" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv2665_id);
@@ -302,7 +299,7 @@ static struct i2c_driver drv2665_driver = {
.driver = {
.name = "drv2665-haptics",
.of_match_table = of_match_ptr(drv2665_of_match),
- .pm = &drv2665_pm_ops,
+ .pm = pm_sleep_ptr(&drv2665_pm_ops),
},
.id_table = drv2665_id,
};
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index 3f67b9b010bf..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
@@ -333,8 +333,7 @@ static const struct regmap_config drv2667_regmap_config = {
.cache_type = REGCACHE_NONE,
};
-static int drv2667_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int drv2667_probe(struct i2c_client *client)
{
struct drv2667_data *haptics;
int error;
@@ -400,68 +399,66 @@ static int drv2667_probe(struct i2c_client *client,
return 0;
}
-static int __maybe_unused drv2667_suspend(struct device *dev)
+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 __maybe_unused drv2667_resume(struct device *dev)
+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 SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(drv2667_pm_ops, drv2667_suspend, drv2667_resume);
static const struct i2c_device_id drv2667_id[] = {
- { "drv2667", 0 },
+ { "drv2667" },
{ }
};
MODULE_DEVICE_TABLE(i2c, drv2667_id);
@@ -479,7 +476,7 @@ static struct i2c_driver drv2667_driver = {
.driver = {
.name = "drv2667-haptics",
.of_match_table = of_match_ptr(drv2667_of_match),
- .pm = &drv2667_pm_ops,
+ .pm = pm_sleep_ptr(&drv2667_pm_ops),
},
.id_table = drv2667_id,
};
diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c
index e2fde6e1553f..5bd527117470 100644
--- a/drivers/input/misc/e3x0-button.c
+++ b/drivers/input/misc/e3x0-button.c
@@ -35,7 +35,7 @@ static irqreturn_t e3x0_button_press_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static int __maybe_unused e3x0_button_suspend(struct device *dev)
+static int e3x0_button_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -45,7 +45,7 @@ static int __maybe_unused e3x0_button_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused e3x0_button_resume(struct device *dev)
+static int e3x0_button_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -55,8 +55,8 @@ static int __maybe_unused e3x0_button_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
- e3x0_button_suspend, e3x0_button_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
+ e3x0_button_suspend, e3x0_button_resume);
static int e3x0_button_probe(struct platform_device *pdev)
{
@@ -122,7 +122,7 @@ static struct platform_driver e3x0_button_driver = {
.driver = {
.name = "e3x0-button",
.of_match_table = of_match_ptr(e3x0_button_match),
- .pm = &e3x0_button_pm_ops,
+ .pm = pm_sleep_ptr(&e3x0_button_pm_ops),
},
.probe = e3x0_button_probe,
};
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/gpio-vibra.c b/drivers/input/misc/gpio-vibra.c
index f79f75595dd7..ad44b4d18a2a 100644
--- a/drivers/input/misc/gpio-vibra.c
+++ b/drivers/input/misc/gpio-vibra.c
@@ -18,7 +18,7 @@
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
@@ -113,22 +113,14 @@ static int gpio_vibrator_probe(struct platform_device *pdev)
return -ENOMEM;
vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
- err = PTR_ERR_OR_ZERO(vibrator->vcc);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to request regulator: %d\n",
- err);
- return err;
- }
+ if (IS_ERR(vibrator->vcc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc),
+ "Failed to request regulator\n");
vibrator->gpio = devm_gpiod_get(&pdev->dev, "enable", GPIOD_OUT_LOW);
- err = PTR_ERR_OR_ZERO(vibrator->gpio);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to request main gpio: %d\n",
- err);
- return err;
- }
+ if (IS_ERR(vibrator->gpio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->gpio),
+ "Failed to request main gpio\n");
INIT_WORK(&vibrator->play_work, gpio_vibrator_play_work);
@@ -157,7 +149,7 @@ static int gpio_vibrator_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
+static int gpio_vibrator_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
@@ -169,7 +161,7 @@ static int __maybe_unused gpio_vibrator_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused gpio_vibrator_resume(struct device *dev)
+static int gpio_vibrator_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct gpio_vibrator *vibrator = platform_get_drvdata(pdev);
@@ -180,8 +172,8 @@ static int __maybe_unused gpio_vibrator_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
- gpio_vibrator_suspend, gpio_vibrator_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(gpio_vibrator_pm_ops,
+ gpio_vibrator_suspend, gpio_vibrator_resume);
#ifdef CONFIG_OF
static const struct of_device_id gpio_vibra_dt_match_table[] = {
@@ -195,7 +187,7 @@ static struct platform_driver gpio_vibrator_driver = {
.probe = gpio_vibrator_probe,
.driver = {
.name = "gpio-vibrator",
- .pm = &gpio_vibrator_pm_ops,
+ .pm = pm_sleep_ptr(&gpio_vibrator_pm_ops),
.of_match_table = of_match_ptr(gpio_vibra_dt_match_table),
},
};
diff --git a/drivers/input/misc/gpio_decoder.c b/drivers/input/misc/gpio_decoder.c
index 145826a1a9a1..ee668eba302f 100644
--- a/drivers/input/misc/gpio_decoder.c
+++ b/drivers/input/misc/gpio_decoder.c
@@ -1,15 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2016 Texas Instruments Incorporated - http://www.ti.com/
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
* A generic driver to read multiple gpio lines and translate the
* encoded numeric value into an input event.
*/
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/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 199bc17ddb1d..afc0d6dc5787 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -265,7 +265,7 @@ static inline int hp_sdc_rtc_read_ct(struct timespec64 *res) {
return 0;
}
-static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v)
+static int __maybe_unused hp_sdc_rtc_proc_show(struct seq_file *m, void *v)
{
#define YN(bit) ("no")
#define NY(bit) ("yes")
diff --git a/drivers/input/misc/ibm-panel.c b/drivers/input/misc/ibm-panel.c
new file mode 100644
index 000000000000..aa48f62d7ea0
--- /dev/null
+++ b/drivers/input/misc/ibm-panel.c
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) IBM Corporation 2020
+ */
+
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/limits.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/spinlock.h>
+
+#define DEVICE_NAME "ibm-panel"
+#define PANEL_KEYCODES_COUNT 3
+
+struct ibm_panel {
+ u8 idx;
+ u8 command[11];
+ u32 keycodes[PANEL_KEYCODES_COUNT];
+ spinlock_t lock; /* protects writes to idx and command */
+ struct input_dev *input;
+};
+
+static u8 ibm_panel_calculate_checksum(struct ibm_panel *panel)
+{
+ u8 chksum;
+ u16 sum = 0;
+ unsigned int i;
+
+ for (i = 0; i < sizeof(panel->command) - 1; ++i) {
+ sum += panel->command[i];
+ if (sum & 0xff00) {
+ sum &= 0xff;
+ sum++;
+ }
+ }
+
+ chksum = sum & 0xff;
+ chksum = ~chksum;
+ chksum++;
+
+ return chksum;
+}
+
+static void ibm_panel_process_command(struct ibm_panel *panel)
+{
+ u8 button;
+ u8 chksum;
+
+ if (panel->command[0] != 0xff && panel->command[1] != 0xf0) {
+ dev_dbg(&panel->input->dev, "command invalid: %02x %02x\n",
+ panel->command[0], panel->command[1]);
+ return;
+ }
+
+ chksum = ibm_panel_calculate_checksum(panel);
+ if (chksum != panel->command[sizeof(panel->command) - 1]) {
+ dev_dbg(&panel->input->dev,
+ "command failed checksum: %u != %u\n", chksum,
+ panel->command[sizeof(panel->command) - 1]);
+ return;
+ }
+
+ button = panel->command[2] & 0xf;
+ if (button < PANEL_KEYCODES_COUNT) {
+ input_report_key(panel->input, panel->keycodes[button],
+ !(panel->command[2] & 0x80));
+ input_sync(panel->input);
+ } else {
+ dev_dbg(&panel->input->dev, "unknown button %u\n",
+ button);
+ }
+}
+
+static int ibm_panel_i2c_slave_cb(struct i2c_client *client,
+ enum i2c_slave_event event, u8 *val)
+{
+ struct ibm_panel *panel = i2c_get_clientdata(client);
+
+ dev_dbg(&panel->input->dev, "event: %u data: %02x\n", event, *val);
+
+ guard(spinlock_irqsave)(&panel->lock);
+
+ switch (event) {
+ case I2C_SLAVE_STOP:
+ if (panel->idx == sizeof(panel->command))
+ ibm_panel_process_command(panel);
+ else
+ dev_dbg(&panel->input->dev,
+ "command incorrect size %u\n", panel->idx);
+ fallthrough;
+ case I2C_SLAVE_WRITE_REQUESTED:
+ panel->idx = 0;
+ break;
+ case I2C_SLAVE_WRITE_RECEIVED:
+ if (panel->idx < sizeof(panel->command))
+ panel->command[panel->idx++] = *val;
+ else
+ /*
+ * The command is too long and therefore invalid, so set the index
+ * to it's largest possible value. When a STOP is finally received,
+ * the command will be rejected upon processing.
+ */
+ panel->idx = U8_MAX;
+ break;
+ case I2C_SLAVE_READ_REQUESTED:
+ case I2C_SLAVE_READ_PROCESSED:
+ *val = 0xff;
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ibm_panel_probe(struct i2c_client *client)
+{
+ struct ibm_panel *panel;
+ int i;
+ int error;
+
+ panel = devm_kzalloc(&client->dev, sizeof(*panel), GFP_KERNEL);
+ if (!panel)
+ return -ENOMEM;
+
+ spin_lock_init(&panel->lock);
+
+ panel->input = devm_input_allocate_device(&client->dev);
+ if (!panel->input)
+ return -ENOMEM;
+
+ panel->input->name = client->name;
+ panel->input->id.bustype = BUS_I2C;
+
+ error = device_property_read_u32_array(&client->dev,
+ "linux,keycodes",
+ panel->keycodes,
+ PANEL_KEYCODES_COUNT);
+ if (error) {
+ /*
+ * Use gamepad buttons as defaults for compatibility with
+ * existing applications.
+ */
+ panel->keycodes[0] = BTN_NORTH;
+ panel->keycodes[1] = BTN_SOUTH;
+ panel->keycodes[2] = BTN_SELECT;
+ }
+
+ for (i = 0; i < PANEL_KEYCODES_COUNT; ++i)
+ input_set_capability(panel->input, EV_KEY, panel->keycodes[i]);
+
+ error = input_register_device(panel->input);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to register input device: %d\n", error);
+ return error;
+ }
+
+ i2c_set_clientdata(client, panel);
+ error = i2c_slave_register(client, ibm_panel_i2c_slave_cb);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to register as i2c slave: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static void ibm_panel_remove(struct i2c_client *client)
+{
+ i2c_slave_unregister(client);
+}
+
+static const struct of_device_id ibm_panel_match[] = {
+ { .compatible = "ibm,op-panel" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ibm_panel_match);
+
+static struct i2c_driver ibm_panel_driver = {
+ .driver = {
+ .name = DEVICE_NAME,
+ .of_match_table = ibm_panel_match,
+ },
+ .probe = ibm_panel_probe,
+ .remove = ibm_panel_remove,
+};
+module_i2c_driver(ibm_panel_driver);
+
+MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");
+MODULE_DESCRIPTION("IBM Operation Panel Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ideapad_slidebar.c b/drivers/input/misc/ideapad_slidebar.c
index 68f1c584da05..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);
@@ -256,13 +244,11 @@ err_release_ports:
return err;
}
-static int ideapad_remove(struct platform_device *pdev)
+static void ideapad_remove(struct platform_device *pdev)
{
i8042_remove_filter(slidebar_i8042_filter);
input_unregister_device(slidebar_input_dev);
release_region(IDEAPAD_BASE, 3);
-
- return 0;
}
static struct platform_driver slidebar_drv = {
diff --git a/drivers/input/misc/ims-pcu.c b/drivers/input/misc/ims-pcu.c
index 6f38aa23a1ff..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
@@ -42,8 +42,8 @@ struct ims_pcu_backlight {
#define IMS_PCU_PART_NUMBER_LEN 15
#define IMS_PCU_SERIAL_NUMBER_LEN 8
#define IMS_PCU_DOM_LEN 8
-#define IMS_PCU_FW_VERSION_LEN (9 + 1)
-#define IMS_PCU_BL_VERSION_LEN (9 + 1)
+#define IMS_PCU_FW_VERSION_LEN 16
+#define IMS_PCU_BL_VERSION_LEN 16
#define IMS_PCU_BL_RESET_REASON_LEN (2 + 1)
#define IMS_PCU_PCU_B_DEVICE_ID 5
@@ -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,11 +739,11 @@ 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,
- "Failure when sending JUMP TO BOOLTLOADER command, error: %d\n",
+ "Failure when sending JUMP TO BOOTLOADER command, error: %d\n",
error);
return error;
}
@@ -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;
}
@@ -1050,7 +1050,7 @@ static ssize_t ims_pcu_attribute_show(struct device *dev,
container_of(dattr, struct ims_pcu_attribute, dattr);
char *field = (char *)pcu + attr->field_offset;
- return scnprintf(buf, PAGE_SIZE, "%.*s\n", attr->field_length, field);
+ return sysfs_emit(buf, "%.*s\n", attr->field_length, field);
}
static ssize_t ims_pcu_attribute_store(struct device *dev,
@@ -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,
@@ -1206,7 +1202,7 @@ ims_pcu_update_firmware_status_show(struct device *dev,
struct usb_interface *intf = to_usb_interface(dev);
struct ims_pcu *pcu = usb_get_intfdata(intf);
- return scnprintf(buf, PAGE_SIZE, "%d\n", pcu->update_firmware_status);
+ return sysfs_emit(buf, "%d\n", pcu->update_firmware_status);
}
static DEVICE_ATTR(update_firmware_status, S_IRUGO,
@@ -1302,14 +1298,13 @@ 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 scnprintf(buf, PAGE_SIZE, "%x\n", data);
+ return sysfs_emit(buf, "%x\n", data);
}
static ssize_t ims_pcu_ofn_reg_data_store(struct device *dev,
@@ -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 = scnprintf(buf, PAGE_SIZE, "%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,14 +1384,13 @@ 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 scnprintf(buf, PAGE_SIZE, "%d\n", !!(data & (1 << attr->nr)));
+ return sysfs_emit(buf, "%d\n", !!(data & (1 << attr->nr)));
}
static ssize_t ims_pcu_ofn_bit_store(struct device *dev,
@@ -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 a348247d3d38..1851848e2cd3 100644
--- a/drivers/input/misc/iqs269a.c
+++ b/drivers/input/misc/iqs269a.c
@@ -9,6 +9,8 @@
* axial sliders presented by the device.
*/
+#include <linux/bits.h>
+#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/err.h>
@@ -16,15 +18,17 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
-#include <linux/of_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#define IQS269_VER_INFO 0x00
#define IQS269_VER_INFO_PROD_NUM 0x4F
+#define IQS269_VER_INFO_FW_NUM_2 0x03
+#define IQS269_VER_INFO_FW_NUM_3 0x10
#define IQS269_SYS_FLAGS 0x02
#define IQS269_SYS_FLAGS_SHOW_RESET BIT(15)
@@ -52,6 +56,7 @@
#define IQS269_SYS_SETTINGS_ULP_UPDATE_MASK GENMASK(10, 8)
#define IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT 8
#define IQS269_SYS_SETTINGS_ULP_UPDATE_MAX 7
+#define IQS269_SYS_SETTINGS_SLIDER_SWIPE BIT(7)
#define IQS269_SYS_SETTINGS_RESEED_OFFSET BIT(6)
#define IQS269_SYS_SETTINGS_EVENT_MODE BIT(5)
#define IQS269_SYS_SETTINGS_EVENT_MODE_LP BIT(4)
@@ -68,6 +73,7 @@
#define IQS269_FILT_STR_MAX 3
#define IQS269_EVENT_MASK_SYS BIT(6)
+#define IQS269_EVENT_MASK_GESTURE BIT(3)
#define IQS269_EVENT_MASK_DEEP BIT(2)
#define IQS269_EVENT_MASK_TOUCH BIT(1)
#define IQS269_EVENT_MASK_PROX BIT(0)
@@ -96,7 +102,14 @@
#define IQS269_MISC_B_TRACKING_UI_ENABLE BIT(4)
#define IQS269_MISC_B_FILT_STR_SLIDER GENMASK(1, 0)
-#define IQS269_CHx_SETTINGS 0x8C
+#define IQS269_TOUCH_HOLD_SLIDER_SEL 0x89
+#define IQS269_TOUCH_HOLD_DEFAULT 0x14
+#define IQS269_TOUCH_HOLD_MS_MIN 256
+#define IQS269_TOUCH_HOLD_MS_MAX 65280
+
+#define IQS269_TIMEOUT_TAP_MS_MAX 4080
+#define IQS269_TIMEOUT_SWIPE_MS_MAX 4080
+#define IQS269_THRESH_SWIPE_MAX 255
#define IQS269_CHx_ENG_A_MEAS_CAP_SIZE BIT(15)
#define IQS269_CHx_ENG_A_RX_GND_INACTIVE BIT(13)
@@ -143,17 +156,14 @@
#define IQS269_MAX_REG 0xFF
+#define IQS269_OTP_OPTION_DEFAULT 0x00
+#define IQS269_OTP_OPTION_TWS 0xD0
+#define IQS269_OTP_OPTION_HOLD BIT(7)
+
#define IQS269_NUM_CH 8
#define IQS269_NUM_SL 2
-#define IQS269_ATI_POLL_SLEEP_US (iqs269->delay_mult * 10000)
-#define IQS269_ATI_POLL_TIMEOUT_US (iqs269->delay_mult * 500000)
-#define IQS269_ATI_STABLE_DELAY_MS (iqs269->delay_mult * 150)
-
-#define IQS269_PWR_MODE_POLL_SLEEP_US IQS269_ATI_POLL_SLEEP_US
-#define IQS269_PWR_MODE_POLL_TIMEOUT_US IQS269_ATI_POLL_TIMEOUT_US
-
-#define iqs269_irq_wait() usleep_range(100, 150)
+#define iqs269_irq_wait() usleep_range(200, 250)
enum iqs269_local_cap_size {
IQS269_LOCAL_CAP_SIZE_0,
@@ -183,6 +193,20 @@ enum iqs269_event_id {
IQS269_EVENT_DEEP_UP,
};
+enum iqs269_slider_id {
+ IQS269_SLIDER_NONE,
+ IQS269_SLIDER_KEY,
+ IQS269_SLIDER_RAW,
+};
+
+enum iqs269_gesture_id {
+ IQS269_GESTURE_TAP,
+ IQS269_GESTURE_HOLD,
+ IQS269_GESTURE_FLICK_POS,
+ IQS269_GESTURE_FLICK_NEG,
+ IQS269_NUM_GESTURES,
+};
+
struct iqs269_switch_desc {
unsigned int code;
bool enabled;
@@ -242,7 +266,19 @@ struct iqs269_ver_info {
u8 prod_num;
u8 sw_num;
u8 hw_num;
- u8 padding;
+ u8 fw_num;
+} __packed;
+
+struct iqs269_ch_reg {
+ u8 rx_enable;
+ u8 tx_enable;
+ __be16 engine_a;
+ __be16 engine_b;
+ __be16 ati_comp;
+ u8 thresh[3];
+ u8 hyst;
+ u8 assoc_select;
+ u8 assoc_weight;
} __packed;
struct iqs269_sys_reg {
@@ -266,18 +302,7 @@ struct iqs269_sys_reg {
u8 timeout_swipe;
u8 thresh_swipe;
u8 redo_ati;
-} __packed;
-
-struct iqs269_ch_reg {
- u8 rx_enable;
- u8 tx_enable;
- __be16 engine_a;
- __be16 engine_b;
- __be16 ati_comp;
- u8 thresh[3];
- u8 hyst;
- u8 assoc_select;
- u8 assoc_weight;
+ struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
} __packed;
struct iqs269_flags {
@@ -292,21 +317,46 @@ struct iqs269_private {
struct regmap *regmap;
struct mutex lock;
struct iqs269_switch_desc switches[ARRAY_SIZE(iqs269_events)];
- struct iqs269_ch_reg ch_reg[IQS269_NUM_CH];
+ struct iqs269_ver_info ver_info;
struct iqs269_sys_reg sys_reg;
+ struct completion ati_done;
struct input_dev *keypad;
struct input_dev *slider[IQS269_NUM_SL];
unsigned int keycode[ARRAY_SIZE(iqs269_events) * IQS269_NUM_CH];
- unsigned int suspend_mode;
- unsigned int delay_mult;
+ unsigned int sl_code[IQS269_NUM_SL][IQS269_NUM_GESTURES];
+ unsigned int otp_option;
unsigned int ch_num;
bool hall_enable;
bool ati_current;
};
+static enum iqs269_slider_id iqs269_slider_type(struct iqs269_private *iqs269,
+ int slider_num)
+{
+ int i;
+
+ /*
+ * Slider 1 is unavailable if the touch-and-hold option is enabled via
+ * OTP. In that case, the channel selection register is repurposed for
+ * the touch-and-hold timer ceiling.
+ */
+ if (slider_num && (iqs269->otp_option & IQS269_OTP_OPTION_HOLD))
+ return IQS269_SLIDER_NONE;
+
+ if (!iqs269->sys_reg.slider_select[slider_num])
+ return IQS269_SLIDER_NONE;
+
+ for (i = 0; i < IQS269_NUM_GESTURES; i++)
+ if (iqs269->sl_code[slider_num][i] != KEY_RESERVED)
+ return IQS269_SLIDER_KEY;
+
+ return IQS269_SLIDER_RAW;
+}
+
static int iqs269_ati_mode_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int mode)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_a;
if (ch_num >= IQS269_NUM_CH)
@@ -315,32 +365,31 @@ 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(iqs269->ch_reg[ch_num].engine_a);
+ engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
engine_a &= ~IQS269_CHx_ENG_A_ATI_MODE_MASK;
engine_a |= (mode << IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
- iqs269->ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
+ ch_reg[ch_num].engine_a = cpu_to_be16(engine_a);
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return 0;
}
static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *mode)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_a;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
- mutex_lock(&iqs269->lock);
- engine_a = be16_to_cpu(iqs269->ch_reg[ch_num].engine_a);
- mutex_unlock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
+
+ engine_a = be16_to_cpu(ch_reg[ch_num].engine_a);
engine_a &= IQS269_CHx_ENG_A_ATI_MODE_MASK;
*mode = (engine_a >> IQS269_CHx_ENG_A_ATI_MODE_SHIFT);
@@ -351,6 +400,7 @@ static int iqs269_ati_mode_get(struct iqs269_private *iqs269,
static int iqs269_ati_base_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int base)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
@@ -377,32 +427,31 @@ 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(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
engine_b &= ~IQS269_CHx_ENG_B_ATI_BASE_MASK;
engine_b |= base;
- iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
+ ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return 0;
}
static int iqs269_ati_base_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *base)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
- mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->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);
switch (engine_b & IQS269_CHx_ENG_B_ATI_BASE_MASK) {
case IQS269_CHx_ENG_B_ATI_BASE_75:
@@ -429,6 +478,7 @@ static int iqs269_ati_base_get(struct iqs269_private *iqs269,
static int iqs269_ati_target_set(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int target)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
@@ -437,33 +487,31 @@ 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(iqs269->ch_reg[ch_num].engine_b);
+ engine_b = be16_to_cpu(ch_reg[ch_num].engine_b);
engine_b &= ~IQS269_CHx_ENG_B_ATI_TARGET_MASK;
engine_b |= target / 32;
- iqs269->ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
+ ch_reg[ch_num].engine_b = cpu_to_be16(engine_b);
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return 0;
}
static int iqs269_ati_target_get(struct iqs269_private *iqs269,
unsigned int ch_num, unsigned int *target)
{
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
u16 engine_b;
if (ch_num >= IQS269_NUM_CH)
return -EINVAL;
- mutex_lock(&iqs269->lock);
- engine_b = be16_to_cpu(iqs269->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;
@@ -502,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;
@@ -528,16 +575,11 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
if (fwnode_property_present(ch_node, "azoteq,slider0-select"))
iqs269->sys_reg.slider_select[0] |= BIT(reg);
- if (fwnode_property_present(ch_node, "azoteq,slider1-select"))
+ if (fwnode_property_present(ch_node, "azoteq,slider1-select") &&
+ !(iqs269->otp_option & IQS269_OTP_OPTION_HOLD))
iqs269->sys_reg.slider_select[1] |= BIT(reg);
- ch_reg = &iqs269->ch_reg[reg];
-
- error = regmap_raw_read(iqs269->regmap,
- IQS269_CHx_SETTINGS + reg * sizeof(*ch_reg) / 2,
- ch_reg, sizeof(*ch_reg));
- if (error)
- return error;
+ ch_reg = &iqs269->sys_reg.ch_reg[reg];
error = iqs269_parse_mask(ch_node, "azoteq,rx-enable",
&ch_reg->rx_enable);
@@ -684,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;
@@ -721,8 +764,15 @@ static int iqs269_parse_chan(struct iqs269_private *iqs269,
}
}
- if (fwnode_property_read_u32(ev_node, "linux,code", &val))
+ error = fwnode_property_read_u32(ev_node, "linux,code", &val);
+ if (error == -EINVAL) {
continue;
+ } else if (error) {
+ dev_err(&client->dev,
+ "Failed to read channel %u code: %d\n", reg,
+ error);
+ return error;
+ }
switch (reg) {
case IQS269_CHx_HALL_ACTIVE:
@@ -751,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;
@@ -759,17 +808,6 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
iqs269->hall_enable = device_property_present(&client->dev,
"azoteq,hall-enable");
- if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
- &val)) {
- if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
- dev_err(&client->dev, "Invalid suspend mode: %u\n",
- val);
- return -EINVAL;
- }
-
- iqs269->suspend_mode = val;
- }
-
error = regmap_raw_read(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
sizeof(*sys_reg));
if (error)
@@ -960,16 +998,50 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
sys_reg->blocking = 0;
sys_reg->slider_select[0] = 0;
- sys_reg->slider_select[1] = 0;
+
+ /*
+ * If configured via OTP to do so, the device asserts a pulse on the
+ * GPIO4 pin for approximately 60 ms once a selected channel is held
+ * in a state of touch for a configurable length of time.
+ *
+ * In that case, the register used for slider 1 channel selection is
+ * repurposed for the touch-and-hold timer ceiling.
+ */
+ if (iqs269->otp_option & IQS269_OTP_OPTION_HOLD) {
+ if (!device_property_read_u32(&client->dev,
+ "azoteq,touch-hold-ms", &val)) {
+ if (val < IQS269_TOUCH_HOLD_MS_MIN ||
+ val > IQS269_TOUCH_HOLD_MS_MAX) {
+ dev_err(&client->dev,
+ "Invalid touch-and-hold ceiling: %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ sys_reg->slider_select[1] = val / 256;
+ } else if (iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3) {
+ /*
+ * The default touch-and-hold timer ceiling initially
+ * read from early revisions of silicon is invalid if
+ * the device experienced a soft reset between power-
+ * on and the read operation.
+ *
+ * To protect against this case, explicitly cache the
+ * default value so that it is restored each time the
+ * device is re-initialized.
+ */
+ sys_reg->slider_select[1] = IQS269_TOUCH_HOLD_DEFAULT;
+ }
+ } else {
+ sys_reg->slider_select[1] = 0;
+ }
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;
- }
}
/*
@@ -980,13 +1052,8 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
general = be16_to_cpu(sys_reg->general);
- if (device_property_present(&client->dev, "azoteq,clk-div")) {
+ if (device_property_present(&client->dev, "azoteq,clk-div"))
general |= IQS269_SYS_SETTINGS_CLK_DIV;
- iqs269->delay_mult = 4;
- } else {
- general &= ~IQS269_SYS_SETTINGS_CLK_DIV;
- iqs269->delay_mult = 1;
- }
/*
* Configure the device to automatically switch between normal and low-
@@ -997,6 +1064,17 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
general &= ~IQS269_SYS_SETTINGS_DIS_AUTO;
general &= ~IQS269_SYS_SETTINGS_PWR_MODE_MASK;
+ if (!device_property_read_u32(&client->dev, "azoteq,suspend-mode",
+ &val)) {
+ if (val > IQS269_SYS_SETTINGS_PWR_MODE_MAX) {
+ dev_err(&client->dev, "Invalid suspend mode: %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ general |= (val << IQS269_SYS_SETTINGS_PWR_MODE_SHIFT);
+ }
+
if (!device_property_read_u32(&client->dev, "azoteq,ulp-update",
&val)) {
if (val > IQS269_SYS_SETTINGS_ULP_UPDATE_MAX) {
@@ -1008,6 +1086,76 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
general |= (val << IQS269_SYS_SETTINGS_ULP_UPDATE_SHIFT);
}
+ if (device_property_present(&client->dev, "linux,keycodes")) {
+ int scale = 1;
+ int count = device_property_count_u32(&client->dev,
+ "linux,keycodes");
+ if (count > IQS269_NUM_GESTURES * IQS269_NUM_SL) {
+ dev_err(&client->dev, "Too many keycodes present\n");
+ return -EINVAL;
+ } else if (count < 0) {
+ dev_err(&client->dev, "Failed to count keycodes: %d\n",
+ count);
+ return count;
+ }
+
+ error = device_property_read_u32_array(&client->dev,
+ "linux,keycodes",
+ *iqs269->sl_code, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read keycodes: %d\n",
+ error);
+ return error;
+ }
+
+ if (device_property_present(&client->dev,
+ "azoteq,gesture-swipe"))
+ general |= IQS269_SYS_SETTINGS_SLIDER_SWIPE;
+
+ /*
+ * Early revisions of silicon use a more granular step size for
+ * tap and swipe gesture timeouts; scale them appropriately.
+ */
+ if (iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3)
+ scale = 4;
+
+ if (!device_property_read_u32(&client->dev,
+ "azoteq,timeout-tap-ms", &val)) {
+ if (val > IQS269_TIMEOUT_TAP_MS_MAX / scale) {
+ dev_err(&client->dev, "Invalid timeout: %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ sys_reg->timeout_tap = val / (16 / scale);
+ }
+
+ if (!device_property_read_u32(&client->dev,
+ "azoteq,timeout-swipe-ms",
+ &val)) {
+ if (val > IQS269_TIMEOUT_SWIPE_MS_MAX / scale) {
+ dev_err(&client->dev, "Invalid timeout: %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ sys_reg->timeout_swipe = val / (16 / scale);
+ }
+
+ if (!device_property_read_u32(&client->dev,
+ "azoteq,thresh-swipe", &val)) {
+ if (val > IQS269_THRESH_SWIPE_MAX) {
+ dev_err(&client->dev, "Invalid threshold: %u\n",
+ val);
+ return -EINVAL;
+ }
+
+ sys_reg->thresh_swipe = val;
+ }
+
+ sys_reg->event_mask &= ~IQS269_EVENT_MASK_GESTURE;
+ }
+
general &= ~IQS269_SYS_SETTINGS_RESEED_OFFSET;
if (device_property_present(&client->dev, "azoteq,reseed-offset"))
general |= IQS269_SYS_SETTINGS_RESEED_OFFSET;
@@ -1016,10 +1164,11 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
/*
* As per the datasheet, enable streaming during normal-power mode if
- * either slider is in use. In that case, the device returns to event
- * mode during low-power mode.
+ * raw coordinates will be read from either slider. In that case, the
+ * device returns to event mode during low-power mode.
*/
- if (sys_reg->slider_select[0] || sys_reg->slider_select[1])
+ if (iqs269_slider_type(iqs269, 0) == IQS269_SLIDER_RAW ||
+ iqs269_slider_type(iqs269, 1) == IQS269_SLIDER_RAW)
general |= IQS269_SYS_SETTINGS_EVENT_MODE_LP;
general |= IQS269_SYS_SETTINGS_REDO_ATI;
@@ -1030,68 +1179,57 @@ static int iqs269_parse_prop(struct iqs269_private *iqs269)
return 0;
}
+static const struct reg_sequence iqs269_tws_init[] = {
+ { IQS269_TOUCH_HOLD_SLIDER_SEL, IQS269_TOUCH_HOLD_DEFAULT },
+ { 0xF0, 0x580F },
+ { 0xF0, 0x59EF },
+};
+
static int iqs269_dev_init(struct iqs269_private *iqs269)
{
- struct iqs269_sys_reg *sys_reg = &iqs269->sys_reg;
- struct iqs269_ch_reg *ch_reg;
- unsigned int val;
- int error, i;
+ int error;
- mutex_lock(&iqs269->lock);
+ guard(mutex)(&iqs269->lock);
+
+ /*
+ * Early revisions of silicon require the following workaround in order
+ * to restore any OTP-enabled functionality after a soft reset.
+ */
+ if (iqs269->otp_option == IQS269_OTP_OPTION_TWS &&
+ iqs269->ver_info.fw_num < IQS269_VER_INFO_FW_NUM_3) {
+ error = regmap_multi_reg_write(iqs269->regmap, iqs269_tws_init,
+ ARRAY_SIZE(iqs269_tws_init));
+ if (error)
+ 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;
-
- for (i = 0; i < IQS269_NUM_CH; i++) {
- if (!(sys_reg->active & BIT(i)))
- continue;
-
- ch_reg = &iqs269->ch_reg[i];
+ return error;
- error = regmap_raw_write(iqs269->regmap,
- IQS269_CHx_SETTINGS + i *
- sizeof(*ch_reg) / 2, ch_reg,
- sizeof(*ch_reg));
- if (error)
- goto err_mutex;
- }
+ error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ &iqs269->sys_reg, sizeof(iqs269->sys_reg));
+ if (error)
+ return error;
/*
- * The REDO-ATI and ATI channel selection fields must be written in the
- * same block write, so every field between registers 0x80 through 0x8B
- * (inclusive) must be written as well.
+ * The following delay gives the device time to deassert its RDY output
+ * so as to prevent an interrupt from being serviced prematurely.
*/
- error = regmap_raw_write(iqs269->regmap, IQS269_SYS_SETTINGS, sys_reg,
- sizeof(*sys_reg));
- if (error)
- goto err_mutex;
-
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- !(val & IQS269_SYS_FLAGS_IN_ATI),
- IQS269_ATI_POLL_SLEEP_US,
- IQS269_ATI_POLL_TIMEOUT_US);
- if (error)
- goto err_mutex;
+ usleep_range(2000, 2100);
- msleep(IQS269_ATI_STABLE_DELAY_MS);
iqs269->ati_current = true;
-err_mutex:
- mutex_unlock(&iqs269->lock);
-
- return error;
+ return 0;
}
static int iqs269_input_init(struct iqs269_private *iqs269)
{
struct i2c_client *client = iqs269->client;
- struct iqs269_flags flags;
unsigned int sw_code, keycode;
int error, i, j;
- u8 dir_mask, state;
iqs269->keypad = devm_input_allocate_device(&client->dev);
if (!iqs269->keypad)
@@ -1104,23 +1242,7 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
iqs269->keypad->name = "iqs269a_keypad";
iqs269->keypad->id.bustype = BUS_I2C;
- if (iqs269->hall_enable) {
- error = regmap_raw_read(iqs269->regmap, IQS269_SYS_FLAGS,
- &flags, sizeof(flags));
- if (error) {
- dev_err(&client->dev,
- "Failed to read initial status: %d\n", error);
- return error;
- }
- }
-
for (i = 0; i < ARRAY_SIZE(iqs269_events); i++) {
- dir_mask = flags.states[IQS269_ST_OFFS_DIR];
- if (!iqs269_events[i].dir_up)
- dir_mask = ~dir_mask;
-
- state = flags.states[iqs269_events[i].st_offs] & dir_mask;
-
sw_code = iqs269->switches[i].code;
for (j = 0; j < IQS269_NUM_CH; j++) {
@@ -1133,13 +1255,9 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
switch (j) {
case IQS269_CHx_HALL_ACTIVE:
if (iqs269->hall_enable &&
- iqs269->switches[i].enabled) {
+ iqs269->switches[i].enabled)
input_set_capability(iqs269->keypad,
EV_SW, sw_code);
- input_report_switch(iqs269->keypad,
- sw_code,
- state & BIT(j));
- }
fallthrough;
case IQS269_CHx_HALL_INACTIVE:
@@ -1155,28 +1273,38 @@ static int iqs269_input_init(struct iqs269_private *iqs269)
}
}
- input_sync(iqs269->keypad);
-
- error = input_register_device(iqs269->keypad);
- if (error) {
- dev_err(&client->dev, "Failed to register keypad: %d\n", error);
- return error;
- }
-
for (i = 0; i < IQS269_NUM_SL; i++) {
- if (!iqs269->sys_reg.slider_select[i])
+ if (iqs269_slider_type(iqs269, i) == IQS269_SLIDER_NONE)
continue;
iqs269->slider[i] = devm_input_allocate_device(&client->dev);
if (!iqs269->slider[i])
return -ENOMEM;
+ iqs269->slider[i]->keycodemax = ARRAY_SIZE(iqs269->sl_code[i]);
+ iqs269->slider[i]->keycode = iqs269->sl_code[i];
+ iqs269->slider[i]->keycodesize = sizeof(**iqs269->sl_code);
+
iqs269->slider[i]->name = i ? "iqs269a_slider_1"
: "iqs269a_slider_0";
iqs269->slider[i]->id.bustype = BUS_I2C;
- input_set_capability(iqs269->slider[i], EV_KEY, BTN_TOUCH);
- input_set_abs_params(iqs269->slider[i], ABS_X, 0, 255, 0, 0);
+ for (j = 0; j < IQS269_NUM_GESTURES; j++)
+ if (iqs269->sl_code[i][j] != KEY_RESERVED)
+ input_set_capability(iqs269->slider[i], EV_KEY,
+ iqs269->sl_code[i][j]);
+
+ /*
+ * Present the slider as a narrow trackpad if one or more chan-
+ * nels have been selected to participate, but no gestures have
+ * been mapped to a keycode.
+ */
+ if (iqs269_slider_type(iqs269, i) == IQS269_SLIDER_RAW) {
+ input_set_capability(iqs269->slider[i],
+ EV_KEY, BTN_TOUCH);
+ input_set_abs_params(iqs269->slider[i],
+ ABS_X, 0, 255, 0, 0);
+ }
error = input_register_device(iqs269->slider[i]);
if (error) {
@@ -1222,28 +1350,65 @@ static int iqs269_report(struct iqs269_private *iqs269)
return error;
}
- error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X, slider_x,
- sizeof(slider_x));
- if (error) {
- dev_err(&client->dev, "Failed to read slider position: %d\n",
- error);
- return error;
+ if (be16_to_cpu(flags.system) & IQS269_SYS_FLAGS_IN_ATI)
+ return 0;
+
+ if (iqs269_slider_type(iqs269, 0) == IQS269_SLIDER_RAW ||
+ iqs269_slider_type(iqs269, 1) == IQS269_SLIDER_RAW) {
+ error = regmap_raw_read(iqs269->regmap, IQS269_SLIDER_X,
+ slider_x, sizeof(slider_x));
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read slider position: %d\n", error);
+ return error;
+ }
}
for (i = 0; i < IQS269_NUM_SL; i++) {
- if (!iqs269->sys_reg.slider_select[i])
+ flags.gesture >>= (i * IQS269_NUM_GESTURES);
+
+ switch (iqs269_slider_type(iqs269, i)) {
+ case IQS269_SLIDER_NONE:
continue;
- /*
- * Report BTN_TOUCH if any channel that participates in the
- * slider is in a state of touch.
- */
- if (flags.states[IQS269_ST_OFFS_TOUCH] &
- iqs269->sys_reg.slider_select[i]) {
- input_report_key(iqs269->slider[i], BTN_TOUCH, 1);
- input_report_abs(iqs269->slider[i], ABS_X, slider_x[i]);
- } else {
- input_report_key(iqs269->slider[i], BTN_TOUCH, 0);
+ case IQS269_SLIDER_KEY:
+ for (j = 0; j < IQS269_NUM_GESTURES; j++)
+ input_report_key(iqs269->slider[i],
+ iqs269->sl_code[i][j],
+ flags.gesture & BIT(j));
+
+ if (!(flags.gesture & (BIT(IQS269_GESTURE_FLICK_NEG) |
+ BIT(IQS269_GESTURE_FLICK_POS) |
+ BIT(IQS269_GESTURE_TAP))))
+ break;
+
+ input_sync(iqs269->slider[i]);
+
+ /*
+ * Momentary gestures are followed by a complementary
+ * release cycle so as to emulate a full keystroke.
+ */
+ for (j = 0; j < IQS269_NUM_GESTURES; j++)
+ if (j != IQS269_GESTURE_HOLD)
+ input_report_key(iqs269->slider[i],
+ iqs269->sl_code[i][j],
+ 0);
+ break;
+
+ case IQS269_SLIDER_RAW:
+ /*
+ * The slider is considered to be in a state of touch
+ * if any selected channels are in a state of touch.
+ */
+ state = flags.states[IQS269_ST_OFFS_TOUCH];
+ state &= iqs269->sys_reg.slider_select[i];
+
+ input_report_key(iqs269->slider[i], BTN_TOUCH, state);
+
+ if (state)
+ input_report_abs(iqs269->slider[i],
+ ABS_X, slider_x[i]);
+ break;
}
input_sync(iqs269->slider[i]);
@@ -1284,6 +1449,12 @@ static int iqs269_report(struct iqs269_private *iqs269)
input_sync(iqs269->keypad);
+ /*
+ * The following completion signals that ATI has finished, any initial
+ * switch states have been reported and the keypad can be registered.
+ */
+ complete_all(&iqs269->ati_done);
+
return 0;
}
@@ -1315,6 +1486,9 @@ static ssize_t counts_show(struct device *dev,
if (!iqs269->ati_current || iqs269->hall_enable)
return -EPERM;
+ if (!completion_done(&iqs269->ati_done))
+ return -EBUSY;
+
/*
* Unsolicited I2C communication prompts the device to assert its RDY
* pin, so disable the interrupt line until the operation is finished
@@ -1332,13 +1506,14 @@ static ssize_t counts_show(struct device *dev,
if (error)
return error;
- return scnprintf(buf, PAGE_SIZE, "%u\n", le16_to_cpu(counts));
+ return sysfs_emit(buf, "%u\n", le16_to_cpu(counts));
}
static ssize_t hall_bin_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
struct i2c_client *client = iqs269->client;
unsigned int val;
int error;
@@ -1353,8 +1528,8 @@ static ssize_t hall_bin_show(struct device *dev,
if (error)
return error;
- switch (iqs269->ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
- iqs269->ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
+ switch (ch_reg[IQS269_CHx_HALL_ACTIVE].rx_enable &
+ ch_reg[IQS269_CHx_HALL_INACTIVE].rx_enable) {
case IQS269_HALL_PAD_R:
val &= IQS269_CAL_DATA_A_HALL_BIN_R_MASK;
val >>= IQS269_CAL_DATA_A_HALL_BIN_R_SHIFT;
@@ -1369,7 +1544,7 @@ static ssize_t hall_bin_show(struct device *dev,
return -EINVAL;
}
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t hall_enable_show(struct device *dev,
@@ -1377,7 +1552,7 @@ static ssize_t hall_enable_show(struct device *dev,
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->hall_enable);
+ return sysfs_emit(buf, "%u\n", iqs269->hall_enable);
}
static ssize_t hall_enable_store(struct device *dev,
@@ -1392,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;
}
@@ -1407,7 +1580,7 @@ static ssize_t ch_number_show(struct device *dev,
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ch_num);
+ return sysfs_emit(buf, "%u\n", iqs269->ch_num);
}
static ssize_t ch_number_store(struct device *dev,
@@ -1434,9 +1607,9 @@ static ssize_t rx_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
- return scnprintf(buf, PAGE_SIZE, "%u\n",
- iqs269->ch_reg[iqs269->ch_num].rx_enable);
+ return sysfs_emit(buf, "%u\n", ch_reg[iqs269->ch_num].rx_enable);
}
static ssize_t rx_enable_store(struct device *dev,
@@ -1444,6 +1617,7 @@ static ssize_t rx_enable_store(struct device *dev,
size_t count)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
+ struct iqs269_ch_reg *ch_reg = iqs269->sys_reg.ch_reg;
unsigned int val;
int error;
@@ -1454,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);
- iqs269->ch_reg[iqs269->ch_num].rx_enable = val;
+ ch_reg[iqs269->ch_num].rx_enable = val;
iqs269->ati_current = false;
- mutex_unlock(&iqs269->lock);
-
return count;
}
@@ -1475,7 +1647,7 @@ static ssize_t ati_mode_show(struct device *dev,
if (error)
return error;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t ati_mode_store(struct device *dev,
@@ -1508,7 +1680,7 @@ static ssize_t ati_base_show(struct device *dev,
if (error)
return error;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t ati_base_store(struct device *dev,
@@ -1541,7 +1713,7 @@ static ssize_t ati_target_show(struct device *dev,
if (error)
return error;
- return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+ return sysfs_emit(buf, "%u\n", val);
}
static ssize_t ati_target_store(struct device *dev,
@@ -1568,7 +1740,9 @@ static ssize_t ati_trigger_show(struct device *dev,
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
- return scnprintf(buf, PAGE_SIZE, "%u\n", iqs269->ati_current);
+ return sysfs_emit(buf, "%u\n",
+ iqs269->ati_current &&
+ completion_done(&iqs269->ati_done));
}
static ssize_t ati_trigger_store(struct device *dev,
@@ -1588,6 +1762,7 @@ static ssize_t ati_trigger_store(struct device *dev,
return count;
disable_irq(client->irq);
+ reinit_completion(&iqs269->ati_done);
error = iqs269_dev_init(iqs269);
@@ -1597,6 +1772,10 @@ static ssize_t ati_trigger_store(struct device *dev,
if (error)
return error;
+ if (!wait_for_completion_timeout(&iqs269->ati_done,
+ msecs_to_jiffies(2000)))
+ return -ETIMEDOUT;
+
return count;
}
@@ -1622,10 +1801,7 @@ static struct attribute *iqs269_attrs[] = {
&dev_attr_ati_trigger.attr,
NULL,
};
-
-static const struct attribute_group iqs269_attr_group = {
- .attrs = iqs269_attrs,
-};
+ATTRIBUTE_GROUPS(iqs269);
static const struct regmap_config iqs269_regmap_config = {
.reg_bits = 8,
@@ -1635,7 +1811,6 @@ static const struct regmap_config iqs269_regmap_config = {
static int iqs269_probe(struct i2c_client *client)
{
- struct iqs269_ver_info ver_info;
struct iqs269_private *iqs269;
int error;
@@ -1655,15 +1830,18 @@ static int iqs269_probe(struct i2c_client *client)
}
mutex_init(&iqs269->lock);
+ init_completion(&iqs269->ati_done);
- error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO, &ver_info,
- sizeof(ver_info));
+ iqs269->otp_option = (uintptr_t)device_get_match_data(&client->dev);
+
+ error = regmap_raw_read(iqs269->regmap, IQS269_VER_INFO,
+ &iqs269->ver_info, sizeof(iqs269->ver_info));
if (error)
return error;
- if (ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) {
+ if (iqs269->ver_info.prod_num != IQS269_VER_INFO_PROD_NUM) {
dev_err(&client->dev, "Unrecognized product number: 0x%02X\n",
- ver_info.prod_num);
+ iqs269->ver_info.prod_num);
return -EINVAL;
}
@@ -1690,123 +1868,94 @@ static int iqs269_probe(struct i2c_client *client)
return error;
}
- error = devm_device_add_group(&client->dev, &iqs269_attr_group);
- if (error)
- dev_err(&client->dev, "Failed to add attributes: %d\n", error);
+ if (!wait_for_completion_timeout(&iqs269->ati_done,
+ msecs_to_jiffies(2000))) {
+ dev_err(&client->dev, "Failed to complete ATI\n");
+ return -ETIMEDOUT;
+ }
+
+ /*
+ * The keypad may include one or more switches and is not registered
+ * until ATI is complete and the initial switch states are read.
+ */
+ error = input_register_device(iqs269->keypad);
+ if (error) {
+ dev_err(&client->dev, "Failed to register keypad: %d\n", error);
+ return error;
+ }
return error;
}
-static int __maybe_unused iqs269_suspend(struct device *dev)
+static u16 iqs269_general_get(struct iqs269_private *iqs269)
+{
+ u16 general = be16_to_cpu(iqs269->sys_reg.general);
+
+ general &= ~IQS269_SYS_SETTINGS_REDO_ATI;
+ general &= ~IQS269_SYS_SETTINGS_ACK_RESET;
+
+ return general | IQS269_SYS_SETTINGS_DIS_AUTO;
+}
+
+static int iqs269_suspend(struct device *dev)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
struct i2c_client *client = iqs269->client;
- unsigned int val;
int error;
+ u16 general = iqs269_general_get(iqs269);
- if (!iqs269->suspend_mode)
+ if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK))
return 0;
disable_irq(client->irq);
- /*
- * Automatic power mode switching must be disabled before the device is
- * forced into any particular power mode. In this case, the device will
- * transition into normal-power mode.
- */
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_DIS_AUTO, ~0);
- if (error)
- goto err_irq;
-
- /*
- * The following check ensures the device has completed its transition
- * into normal-power mode before a manual mode switch is performed.
- */
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- !(val & IQS269_SYS_FLAGS_PWR_MODE_MASK),
- IQS269_PWR_MODE_POLL_SLEEP_US,
- IQS269_PWR_MODE_POLL_TIMEOUT_US);
- if (error)
- goto err_irq;
-
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_PWR_MODE_MASK,
- iqs269->suspend_mode <<
- IQS269_SYS_SETTINGS_PWR_MODE_SHIFT);
- if (error)
- goto err_irq;
+ error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS, general);
- /*
- * This last check ensures the device has completed its transition into
- * the desired power mode to prevent any spurious interrupts from being
- * triggered after iqs269_suspend has already returned.
- */
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- (val & IQS269_SYS_FLAGS_PWR_MODE_MASK)
- == (iqs269->suspend_mode <<
- IQS269_SYS_FLAGS_PWR_MODE_SHIFT),
- IQS269_PWR_MODE_POLL_SLEEP_US,
- IQS269_PWR_MODE_POLL_TIMEOUT_US);
-
-err_irq:
iqs269_irq_wait();
enable_irq(client->irq);
return error;
}
-static int __maybe_unused iqs269_resume(struct device *dev)
+static int iqs269_resume(struct device *dev)
{
struct iqs269_private *iqs269 = dev_get_drvdata(dev);
struct i2c_client *client = iqs269->client;
- unsigned int val;
int error;
+ u16 general = iqs269_general_get(iqs269);
- if (!iqs269->suspend_mode)
+ if (!(general & IQS269_SYS_SETTINGS_PWR_MODE_MASK))
return 0;
disable_irq(client->irq);
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_PWR_MODE_MASK, 0);
- if (error)
- goto err_irq;
-
- /*
- * This check ensures the device has returned to normal-power mode
- * before automatic power mode switching is re-enabled.
- */
- error = regmap_read_poll_timeout(iqs269->regmap, IQS269_SYS_FLAGS, val,
- !(val & IQS269_SYS_FLAGS_PWR_MODE_MASK),
- IQS269_PWR_MODE_POLL_SLEEP_US,
- IQS269_PWR_MODE_POLL_TIMEOUT_US);
- if (error)
- goto err_irq;
-
- error = regmap_update_bits(iqs269->regmap, IQS269_SYS_SETTINGS,
- IQS269_SYS_SETTINGS_DIS_AUTO, 0);
- if (error)
- goto err_irq;
-
- /*
- * This step reports any events that may have been "swallowed" as a
- * result of polling PWR_MODE (which automatically acknowledges any
- * pending interrupts).
- */
- error = iqs269_report(iqs269);
+ error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ general & ~IQS269_SYS_SETTINGS_PWR_MODE_MASK);
+ if (!error)
+ error = regmap_write(iqs269->regmap, IQS269_SYS_SETTINGS,
+ general & ~IQS269_SYS_SETTINGS_DIS_AUTO);
-err_irq:
iqs269_irq_wait();
enable_irq(client->irq);
return error;
}
-static SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs269_pm, iqs269_suspend, iqs269_resume);
static const struct of_device_id iqs269_of_match[] = {
- { .compatible = "azoteq,iqs269a" },
+ {
+ .compatible = "azoteq,iqs269a",
+ .data = (void *)IQS269_OTP_OPTION_DEFAULT,
+ },
+ {
+ .compatible = "azoteq,iqs269a-00",
+ .data = (void *)IQS269_OTP_OPTION_DEFAULT,
+ },
+ {
+ .compatible = "azoteq,iqs269a-d0",
+ .data = (void *)IQS269_OTP_OPTION_TWS,
+ },
{ }
};
MODULE_DEVICE_TABLE(of, iqs269_of_match);
@@ -1814,10 +1963,11 @@ MODULE_DEVICE_TABLE(of, iqs269_of_match);
static struct i2c_driver iqs269_i2c_driver = {
.driver = {
.name = "iqs269a",
+ .dev_groups = iqs269_groups,
.of_match_table = iqs269_of_match,
- .pm = &iqs269_pm,
+ .pm = pm_sleep_ptr(&iqs269_pm),
},
- .probe_new = iqs269_probe,
+ .probe = iqs269_probe,
};
module_i2c_driver(iqs269_i2c_driver);
diff --git a/drivers/input/misc/iqs626a.c b/drivers/input/misc/iqs626a.c
index d57e996732cf..7fba4a8edceb 100644
--- a/drivers/input/misc/iqs626a.c
+++ b/drivers/input/misc/iqs626a.c
@@ -19,8 +19,8 @@
#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_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@@ -456,19 +456,16 @@ struct iqs626_private {
unsigned int suspend_mode;
};
-static int iqs626_parse_events(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
- enum iqs626_ch_id ch_id)
+static noinline_for_stack int
+iqs626_parse_events(struct iqs626_private *iqs626,
+ struct fwnode_handle *ch_node, enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
- const struct fwnode_handle *ev_node;
const char *ev_name;
u8 *thresh, *hyst;
- unsigned int thresh_tp[IQS626_NUM_CH_TP_3];
unsigned int val;
- int num_ch = iqs626_channels[ch_id].num_ch;
- int error, i, j;
+ int i;
switch (ch_id) {
case IQS626_CH_ULP_0:
@@ -503,12 +500,13 @@ static int 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
* trackpad child node.
*/
- ev_node = ch_node;
+ ev_node = fwnode_handle_get(ch_node);
} else {
ev_name = iqs626_events[i].name;
ev_node = fwnode_get_named_child_node(ch_node, ev_name);
@@ -573,48 +571,21 @@ static int iqs626_parse_events(struct iqs626_private *iqs626,
*thresh = val;
else
*(thresh + iqs626_events[i].th_offs) = val;
-
- continue;
- }
-
- if (!fwnode_property_present(ev_node, "azoteq,thresh"))
- continue;
-
- error = fwnode_property_read_u32_array(ev_node, "azoteq,thresh",
- thresh_tp, num_ch);
- if (error) {
- dev_err(&client->dev,
- "Failed to read %s channel thresholds: %d\n",
- fwnode_get_name(ch_node), error);
- return error;
- }
-
- for (j = 0; j < num_ch; j++) {
- if (thresh_tp[j] > IQS626_CHx_THRESH_MAX) {
- dev_err(&client->dev,
- "Invalid %s channel threshold: %u\n",
- fwnode_get_name(ch_node), thresh_tp[j]);
- return -EINVAL;
- }
-
- sys_reg->tp_grp_reg.ch_reg_tp[j].thresh = thresh_tp[j];
}
}
return 0;
}
-static int iqs626_parse_ati_target(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
- enum iqs626_ch_id ch_id)
+static noinline_for_stack int
+iqs626_parse_ati_target(struct iqs626_private *iqs626,
+ struct fwnode_handle *ch_node, enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
- unsigned int ati_base[IQS626_NUM_CH_TP_3];
unsigned int val;
u8 *ati_target;
- int num_ch = iqs626_channels[ch_id].num_ch;
- int error, i;
+ int i;
switch (ch_id) {
case IQS626_CH_ULP_0:
@@ -681,40 +652,13 @@ static int iqs626_parse_ati_target(struct iqs626_private *iqs626,
*ati_target &= ~IQS626_CHx_ATI_BASE_MASK;
*ati_target |= val;
-
- return 0;
- }
-
- if (!fwnode_property_present(ch_node, "azoteq,ati-base"))
- return 0;
-
- error = fwnode_property_read_u32_array(ch_node, "azoteq,ati-base",
- ati_base, num_ch);
- if (error) {
- dev_err(&client->dev,
- "Failed to read %s channel ATI bases: %d\n",
- fwnode_get_name(ch_node), error);
- return error;
- }
-
- for (i = 0; i < num_ch; i++) {
- if (ati_base[i] < IQS626_TPx_ATI_BASE_MIN ||
- ati_base[i] > IQS626_TPx_ATI_BASE_MAX) {
- dev_err(&client->dev,
- "Invalid %s channel ATI base: %u\n",
- fwnode_get_name(ch_node), ati_base[i]);
- return -EINVAL;
- }
-
- ati_base[i] -= IQS626_TPx_ATI_BASE_MIN;
- sys_reg->tp_grp_reg.ch_reg_tp[i].ati_base = ati_base[i];
}
return 0;
}
static int iqs626_parse_pins(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
+ struct fwnode_handle *ch_node,
const char *propname, u8 *enable)
{
struct i2c_client *client = iqs626->client;
@@ -762,13 +706,14 @@ static int iqs626_parse_pins(struct iqs626_private *iqs626,
}
static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node)
+ struct fwnode_handle *ch_node,
+ enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
u8 *hyst = &sys_reg->tp_grp_reg.hyst;
+ int error, count, i;
unsigned int val;
- int error, count;
if (!fwnode_property_read_u32(ch_node, "azoteq,lta-update", &val)) {
if (val > IQS626_MISC_A_TPx_LTA_UPDATE_MAX) {
@@ -821,6 +766,44 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
*hyst |= (val << IQS626_FILT_STR_LP_TPx_SHIFT);
}
+ 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;
+ char tc_name[10];
+
+ scnprintf(tc_name, sizeof(tc_name), "channel-%d", i);
+
+ struct fwnode_handle *tc_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(ch_node, tc_name);
+ if (!tc_node)
+ continue;
+
+ if (!fwnode_property_read_u32(tc_node, "azoteq,ati-base",
+ &val)) {
+ if (val < IQS626_TPx_ATI_BASE_MIN ||
+ val > IQS626_TPx_ATI_BASE_MAX) {
+ dev_err(&client->dev,
+ "Invalid %s %s ATI base: %u\n",
+ fwnode_get_name(ch_node), tc_name, val);
+ return -EINVAL;
+ }
+
+ *ati_base = val - IQS626_TPx_ATI_BASE_MIN;
+ }
+
+ if (!fwnode_property_read_u32(tc_node, "azoteq,thresh",
+ &val)) {
+ if (val > IQS626_CHx_THRESH_MAX) {
+ dev_err(&client->dev,
+ "Invalid %s %s threshold: %u\n",
+ fwnode_get_name(ch_node), tc_name, val);
+ return -EINVAL;
+ }
+
+ *thresh = val;
+ }
+ }
+
if (!fwnode_property_present(ch_node, "linux,keycodes"))
return 0;
@@ -885,9 +868,9 @@ static int iqs626_parse_trackpad(struct iqs626_private *iqs626,
return 0;
}
-static int iqs626_parse_channel(struct iqs626_private *iqs626,
- const struct fwnode_handle *ch_node,
- enum iqs626_ch_id ch_id)
+static noinline_for_stack int
+iqs626_parse_channel(struct iqs626_private *iqs626,
+ struct fwnode_handle *ch_node, enum iqs626_ch_id ch_id)
{
struct iqs626_sys_reg *sys_reg = &iqs626->sys_reg;
struct i2c_client *client = iqs626->client;
@@ -921,6 +904,20 @@ static int iqs626_parse_channel(struct iqs626_private *iqs626,
return -EINVAL;
}
+ error = iqs626_parse_ati_target(iqs626, ch_node, ch_id);
+ if (error)
+ return error;
+
+ error = iqs626_parse_events(iqs626, ch_node, ch_id);
+ if (error)
+ return error;
+
+ if (!fwnode_property_present(ch_node, "azoteq,ati-exclude"))
+ sys_reg->redo_ati |= iqs626_channels[ch_id].active;
+
+ if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
+ sys_reg->reseed |= iqs626_channels[ch_id].active;
+
*engine |= IQS626_CHx_ENG_0_MEAS_CAP_SIZE;
if (fwnode_property_present(ch_node, "azoteq,meas-cap-decrease"))
*engine &= ~IQS626_CHx_ENG_0_MEAS_CAP_SIZE;
@@ -1054,7 +1051,7 @@ static int iqs626_parse_channel(struct iqs626_private *iqs626,
*(engine + 1) |= IQS626_CHx_ENG_1_ATI_BAND_TIGHTEN;
if (ch_id == IQS626_CH_TP_2 || ch_id == IQS626_CH_TP_3)
- return iqs626_parse_trackpad(iqs626, ch_node);
+ return iqs626_parse_trackpad(iqs626, ch_node, ch_id);
if (ch_id == IQS626_CH_ULP_0) {
sys_reg->ch_reg_ulp.hyst &= ~IQS626_ULP_PROJ_ENABLE;
@@ -1227,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;
@@ -1369,8 +1365,9 @@ 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;
@@ -1378,20 +1375,6 @@ static int iqs626_parse_prop(struct iqs626_private *iqs626)
if (error)
return error;
- error = iqs626_parse_ati_target(iqs626, ch_node, i);
- if (error)
- return error;
-
- error = iqs626_parse_events(iqs626, ch_node, i);
- if (error)
- return error;
-
- if (!fwnode_property_present(ch_node, "azoteq,ati-exclude"))
- sys_reg->redo_ati |= iqs626_channels[i].active;
-
- if (!fwnode_property_present(ch_node, "azoteq,reseed-disable"))
- sys_reg->reseed |= iqs626_channels[i].active;
-
sys_reg->active |= iqs626_channels[i].active;
}
@@ -1709,7 +1692,7 @@ static int iqs626_probe(struct i2c_client *client)
return error;
}
-static int __maybe_unused iqs626_suspend(struct device *dev)
+static int iqs626_suspend(struct device *dev)
{
struct iqs626_private *iqs626 = dev_get_drvdata(dev);
struct i2c_client *client = iqs626->client;
@@ -1768,7 +1751,7 @@ err_irq:
return error;
}
-static int __maybe_unused iqs626_resume(struct device *dev)
+static int iqs626_resume(struct device *dev)
{
struct iqs626_private *iqs626 = dev_get_drvdata(dev);
struct i2c_client *client = iqs626->client;
@@ -1815,7 +1798,7 @@ err_irq:
return error;
}
-static SIMPLE_DEV_PM_OPS(iqs626_pm, iqs626_suspend, iqs626_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(iqs626_pm, iqs626_suspend, iqs626_resume);
static const struct of_device_id iqs626_of_match[] = {
{ .compatible = "azoteq,iqs626a" },
@@ -1827,9 +1810,9 @@ static struct i2c_driver iqs626_i2c_driver = {
.driver = {
.name = "iqs626a",
.of_match_table = iqs626_of_match,
- .pm = &iqs626_pm,
+ .pm = pm_sleep_ptr(&iqs626_pm),
},
- .probe_new = iqs626_probe,
+ .probe = iqs626_probe,
};
module_i2c_driver(iqs626_i2c_driver);
diff --git a/drivers/input/misc/iqs7222.c b/drivers/input/misc/iqs7222.c
new file mode 100644
index 000000000000..ff23219a582a
--- /dev/null
+++ b/drivers/input/misc/iqs7222.c
@@ -0,0 +1,3162 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Azoteq IQS7222A/B/C/D Capacitive Touch Controller
+ *
+ * Copyright (C) 2022 Jeff LaBundy <jeff@labundy.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/touchscreen.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/ktime.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/unaligned.h>
+
+#define IQS7222_PROD_NUM 0x00
+#define IQS7222_PROD_NUM_A 840
+#define IQS7222_PROD_NUM_B 698
+#define IQS7222_PROD_NUM_C 863
+#define IQS7222_PROD_NUM_D 1046
+
+#define IQS7222_SYS_STATUS 0x10
+#define IQS7222_SYS_STATUS_RESET BIT(3)
+#define IQS7222_SYS_STATUS_ATI_ERROR BIT(1)
+#define IQS7222_SYS_STATUS_ATI_ACTIVE BIT(0)
+
+#define IQS7222_CHAN_SETUP_0_REF_MODE_MASK GENMASK(15, 14)
+#define IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW BIT(15)
+#define IQS7222_CHAN_SETUP_0_REF_MODE_REF BIT(14)
+#define IQS7222_CHAN_SETUP_0_CHAN_EN BIT(8)
+
+#define IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK GENMASK(2, 0)
+#define IQS7222_SLDR_SETUP_2_RES_MASK GENMASK(15, 8)
+#define IQS7222_SLDR_SETUP_2_RES_SHIFT 8
+#define IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK GENMASK(7, 0)
+
+#define IQS7222_GPIO_SETUP_0_GPIO_EN BIT(0)
+
+#define IQS7222_SYS_SETUP 0xD0
+#define IQS7222_SYS_SETUP_INTF_MODE_MASK GENMASK(7, 6)
+#define IQS7222_SYS_SETUP_INTF_MODE_TOUCH BIT(7)
+#define IQS7222_SYS_SETUP_INTF_MODE_EVENT BIT(6)
+#define IQS7222_SYS_SETUP_PWR_MODE_MASK GENMASK(5, 4)
+#define IQS7222_SYS_SETUP_PWR_MODE_AUTO IQS7222_SYS_SETUP_PWR_MODE_MASK
+#define IQS7222_SYS_SETUP_REDO_ATI BIT(2)
+#define IQS7222_SYS_SETUP_ACK_RESET BIT(0)
+
+#define IQS7222_EVENT_MASK_ATI BIT(12)
+#define IQS7222_EVENT_MASK_SLDR BIT(10)
+#define IQS7222_EVENT_MASK_TPAD IQS7222_EVENT_MASK_SLDR
+#define IQS7222_EVENT_MASK_TOUCH BIT(1)
+#define IQS7222_EVENT_MASK_PROX BIT(0)
+
+#define IQS7222_COMMS_HOLD BIT(0)
+#define IQS7222_COMMS_ERROR 0xEEEE
+#define IQS7222_COMMS_RETRY_MS 50
+#define IQS7222_COMMS_TIMEOUT_MS 100
+#define IQS7222_RESET_TIMEOUT_MS 250
+#define IQS7222_ATI_TIMEOUT_MS 2000
+
+#define IQS7222_MAX_COLS_STAT 8
+#define IQS7222_MAX_COLS_CYCLE 3
+#define IQS7222_MAX_COLS_GLBL 3
+#define IQS7222_MAX_COLS_BTN 3
+#define IQS7222_MAX_COLS_CHAN 6
+#define IQS7222_MAX_COLS_FILT 2
+#define IQS7222_MAX_COLS_SLDR 11
+#define IQS7222_MAX_COLS_TPAD 24
+#define IQS7222_MAX_COLS_GPIO 3
+#define IQS7222_MAX_COLS_SYS 13
+
+#define IQS7222_MAX_CHAN 20
+#define IQS7222_MAX_SLDR 2
+
+#define IQS7222_NUM_RETRIES 5
+#define IQS7222_REG_OFFSET 0x100
+
+enum iqs7222_reg_key_id {
+ IQS7222_REG_KEY_NONE,
+ IQS7222_REG_KEY_PROX,
+ IQS7222_REG_KEY_TOUCH,
+ IQS7222_REG_KEY_DEBOUNCE,
+ IQS7222_REG_KEY_TAP,
+ IQS7222_REG_KEY_TAP_LEGACY,
+ IQS7222_REG_KEY_AXIAL,
+ IQS7222_REG_KEY_AXIAL_LEGACY,
+ IQS7222_REG_KEY_WHEEL,
+ IQS7222_REG_KEY_NO_WHEEL,
+ IQS7222_REG_KEY_RESERVED
+};
+
+enum iqs7222_reg_grp_id {
+ IQS7222_REG_GRP_STAT,
+ 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,
+ IQS7222_REG_GRP_SYS,
+ IQS7222_NUM_REG_GRPS
+};
+
+static const char * const iqs7222_reg_grp_names[IQS7222_NUM_REG_GRPS] = {
+ [IQS7222_REG_GRP_CYCLE] = "cycle-%d",
+ [IQS7222_REG_GRP_CHAN] = "channel-%d",
+ [IQS7222_REG_GRP_SLDR] = "slider-%d",
+ [IQS7222_REG_GRP_TPAD] = "trackpad",
+ [IQS7222_REG_GRP_GPIO] = "gpio-%d",
+};
+
+static const unsigned int iqs7222_max_cols[IQS7222_NUM_REG_GRPS] = {
+ [IQS7222_REG_GRP_STAT] = IQS7222_MAX_COLS_STAT,
+ [IQS7222_REG_GRP_CYCLE] = IQS7222_MAX_COLS_CYCLE,
+ [IQS7222_REG_GRP_GLBL] = IQS7222_MAX_COLS_GLBL,
+ [IQS7222_REG_GRP_BTN] = IQS7222_MAX_COLS_BTN,
+ [IQS7222_REG_GRP_CHAN] = IQS7222_MAX_COLS_CHAN,
+ [IQS7222_REG_GRP_FILT] = IQS7222_MAX_COLS_FILT,
+ [IQS7222_REG_GRP_SLDR] = IQS7222_MAX_COLS_SLDR,
+ [IQS7222_REG_GRP_TPAD] = IQS7222_MAX_COLS_TPAD,
+ [IQS7222_REG_GRP_GPIO] = IQS7222_MAX_COLS_GPIO,
+ [IQS7222_REG_GRP_SYS] = IQS7222_MAX_COLS_SYS,
+};
+
+static const unsigned int iqs7222_gpio_links[] = { 2, 5, 6, };
+
+struct iqs7222_event_desc {
+ const char *name;
+ u16 link;
+ u16 mask;
+ u16 val;
+ u16 strict;
+ u16 enable;
+ enum iqs7222_reg_key_id reg_key;
+};
+
+static const struct iqs7222_event_desc iqs7222_kp_events[] = {
+ {
+ .name = "event-prox",
+ .enable = IQS7222_EVENT_MASK_PROX,
+ .reg_key = IQS7222_REG_KEY_PROX,
+ },
+ {
+ .name = "event-touch",
+ .enable = IQS7222_EVENT_MASK_TOUCH,
+ .reg_key = IQS7222_REG_KEY_TOUCH,
+ },
+};
+
+static const struct iqs7222_event_desc iqs7222_sl_events[] = {
+ { .name = "event-press", },
+ {
+ .name = "event-tap",
+ .mask = BIT(0),
+ .val = BIT(0),
+ .enable = BIT(0),
+ .reg_key = IQS7222_REG_KEY_TAP,
+ },
+ {
+ .name = "event-swipe-pos",
+ .mask = BIT(5) | BIT(1),
+ .val = BIT(1),
+ .enable = BIT(1),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-swipe-neg",
+ .mask = BIT(5) | BIT(1),
+ .val = BIT(5) | BIT(1),
+ .enable = BIT(1),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-flick-pos",
+ .mask = BIT(5) | BIT(2),
+ .val = BIT(2),
+ .enable = BIT(2),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-flick-neg",
+ .mask = BIT(5) | BIT(2),
+ .val = BIT(5) | BIT(2),
+ .enable = BIT(2),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+};
+
+static const struct iqs7222_event_desc iqs7222_tp_events[] = {
+ {
+ .name = "event-press",
+ .link = BIT(7),
+ },
+ {
+ .name = "event-tap",
+ .link = BIT(0),
+ .mask = BIT(0),
+ .val = BIT(0),
+ .enable = BIT(0),
+ .reg_key = IQS7222_REG_KEY_TAP,
+ },
+ {
+ .name = "event-swipe-x-pos",
+ .link = BIT(2),
+ .mask = BIT(2) | BIT(1),
+ .val = BIT(2),
+ .strict = BIT(4),
+ .enable = BIT(1),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-swipe-y-pos",
+ .link = BIT(3),
+ .mask = BIT(3) | BIT(1),
+ .val = BIT(3),
+ .strict = BIT(3),
+ .enable = BIT(1),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-swipe-x-neg",
+ .link = BIT(4),
+ .mask = BIT(4) | BIT(1),
+ .val = BIT(4),
+ .strict = BIT(4),
+ .enable = BIT(1),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-swipe-y-neg",
+ .link = BIT(5),
+ .mask = BIT(5) | BIT(1),
+ .val = BIT(5),
+ .strict = BIT(3),
+ .enable = BIT(1),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-flick-x-pos",
+ .link = BIT(2),
+ .mask = BIT(2) | BIT(1),
+ .val = BIT(2) | BIT(1),
+ .strict = BIT(4),
+ .enable = BIT(2),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-flick-y-pos",
+ .link = BIT(3),
+ .mask = BIT(3) | BIT(1),
+ .val = BIT(3) | BIT(1),
+ .strict = BIT(3),
+ .enable = BIT(2),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-flick-x-neg",
+ .link = BIT(4),
+ .mask = BIT(4) | BIT(1),
+ .val = BIT(4) | BIT(1),
+ .strict = BIT(4),
+ .enable = BIT(2),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+ {
+ .name = "event-flick-y-neg",
+ .link = BIT(5),
+ .mask = BIT(5) | BIT(1),
+ .val = BIT(5) | BIT(1),
+ .strict = BIT(3),
+ .enable = BIT(2),
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ },
+};
+
+struct iqs7222_reg_grp_desc {
+ u16 base;
+ u16 val_len;
+ int num_row;
+ int num_col;
+};
+
+struct iqs7222_dev_desc {
+ u16 prod_num;
+ u16 fw_major;
+ u16 fw_minor;
+ u16 sldr_res;
+ u16 touch_link;
+ u16 wheel_enable;
+ 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];
+};
+
+static const struct iqs7222_dev_desc iqs7222_devs[] = {
+ {
+ .prod_num = IQS7222_PROD_NUM_A,
+ .fw_major = 1,
+ .fw_minor = 13,
+ .sldr_res = U8_MAX * 16,
+ .touch_link = 1768,
+ .allow_offset = 9,
+ .event_offset = 10,
+ .comms_offset = 12,
+ .ext_chan = 10,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 8,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 7,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8700,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 12,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 12,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAC00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_SLDR] = {
+ .base = 0xB000,
+ .num_row = 2,
+ .num_col = 11,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 13,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_A,
+ .fw_major = 1,
+ .fw_minor = 12,
+ .sldr_res = U8_MAX * 16,
+ .touch_link = 1768,
+ .allow_offset = 9,
+ .event_offset = 10,
+ .comms_offset = 12,
+ .ext_chan = 10,
+ .legacy_gesture = true,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 8,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 7,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8700,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 12,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 12,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAC00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_SLDR] = {
+ .base = 0xB000,
+ .num_row = 2,
+ .num_col = 11,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 13,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_B,
+ .fw_major = 1,
+ .fw_minor = 43,
+ .event_offset = 10,
+ .comms_offset = 11,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 10,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8A00,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 20,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xB000,
+ .num_row = 20,
+ .num_col = 4,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xC400,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 13,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_B,
+ .fw_major = 1,
+ .fw_minor = 27,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 10,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8A00,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 20,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xB000,
+ .num_row = 20,
+ .num_col = 4,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xC400,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 10,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_C,
+ .fw_major = 2,
+ .fw_minor = 6,
+ .sldr_res = U16_MAX,
+ .touch_link = 1686,
+ .wheel_enable = BIT(3),
+ .event_offset = 9,
+ .comms_offset = 10,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 5,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8500,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 10,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 10,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAA00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_SLDR] = {
+ .base = 0xB000,
+ .num_row = 2,
+ .num_col = 10,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 3,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 12,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_C,
+ .fw_major = 1,
+ .fw_minor = 13,
+ .sldr_res = U16_MAX,
+ .touch_link = 1674,
+ .wheel_enable = BIT(3),
+ .event_offset = 9,
+ .comms_offset = 10,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 5,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8500,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 10,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 10,
+ .num_col = 6,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAA00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_SLDR] = {
+ .base = 0xB000,
+ .num_row = 2,
+ .num_col = 10,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 11,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_D,
+ .fw_major = 1,
+ .fw_minor = 2,
+ .touch_link = 1770,
+ .allow_offset = 9,
+ .event_offset = 10,
+ .comms_offset = 11,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 7,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 7,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8700,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 14,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 14,
+ .num_col = 4,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAE00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_TPAD] = {
+ .base = 0xB000,
+ .num_row = 1,
+ .num_col = 24,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 3,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 12,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_D,
+ .fw_major = 1,
+ .fw_minor = 1,
+ .touch_link = 1774,
+ .allow_offset = 9,
+ .event_offset = 10,
+ .comms_offset = 11,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 7,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 7,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8700,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 14,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 14,
+ .num_col = 4,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAE00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_TPAD] = {
+ .base = 0xB000,
+ .num_row = 1,
+ .num_col = 24,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 3,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 12,
+ },
+ },
+ },
+ {
+ .prod_num = IQS7222_PROD_NUM_D,
+ .fw_major = 0,
+ .fw_minor = 37,
+ .touch_link = 1770,
+ .allow_offset = 9,
+ .event_offset = 10,
+ .comms_offset = 11,
+ .reg_grps = {
+ [IQS7222_REG_GRP_STAT] = {
+ .base = IQS7222_SYS_STATUS,
+ .num_row = 1,
+ .num_col = 7,
+ },
+ [IQS7222_REG_GRP_CYCLE] = {
+ .base = 0x8000,
+ .num_row = 7,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_GLBL] = {
+ .base = 0x8700,
+ .num_row = 1,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_BTN] = {
+ .base = 0x9000,
+ .num_row = 14,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_CHAN] = {
+ .base = 0xA000,
+ .num_row = 14,
+ .num_col = 4,
+ },
+ [IQS7222_REG_GRP_FILT] = {
+ .base = 0xAE00,
+ .val_len = 3,
+ .num_row = 1,
+ .num_col = 2,
+ },
+ [IQS7222_REG_GRP_TPAD] = {
+ .base = 0xB000,
+ .num_row = 1,
+ .num_col = 24,
+ },
+ [IQS7222_REG_GRP_GPIO] = {
+ .base = 0xC000,
+ .num_row = 3,
+ .num_col = 3,
+ },
+ [IQS7222_REG_GRP_SYS] = {
+ .base = IQS7222_SYS_SETUP,
+ .num_row = 1,
+ .num_col = 12,
+ },
+ },
+ },
+};
+
+struct iqs7222_prop_desc {
+ const char *name;
+ enum iqs7222_reg_grp_id reg_grp;
+ enum iqs7222_reg_key_id reg_key;
+ int reg_offset;
+ int reg_shift;
+ int reg_width;
+ int val_pitch;
+ int val_min;
+ int val_max;
+ bool invert;
+ const char *label;
+};
+
+static const struct iqs7222_prop_desc iqs7222_props[] = {
+ {
+ .name = "azoteq,conv-period",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 0,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "conversion period",
+ },
+ {
+ .name = "azoteq,conv-frac",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 0,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "conversion frequency fractional divider",
+ },
+ {
+ .name = "azoteq,rx-float-inactive",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 1,
+ .reg_shift = 6,
+ .reg_width = 1,
+ .invert = true,
+ },
+ {
+ .name = "azoteq,dead-time-enable",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 1,
+ .reg_shift = 5,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,tx-freq-fosc",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 1,
+ .reg_shift = 4,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,vbias-enable",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 1,
+ .reg_shift = 3,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,sense-mode",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 3,
+ .val_max = 3,
+ .label = "sensing mode",
+ },
+ {
+ .name = "azoteq,iref-enable",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 2,
+ .reg_shift = 10,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,iref-level",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 2,
+ .reg_shift = 4,
+ .reg_width = 4,
+ .label = "current reference level",
+ },
+ {
+ .name = "azoteq,iref-trim",
+ .reg_grp = IQS7222_REG_GRP_CYCLE,
+ .reg_offset = 2,
+ .reg_shift = 0,
+ .reg_width = 4,
+ .label = "current reference trim",
+ },
+ {
+ .name = "azoteq,max-counts",
+ .reg_grp = IQS7222_REG_GRP_GLBL,
+ .reg_offset = 0,
+ .reg_shift = 13,
+ .reg_width = 2,
+ .label = "maximum counts",
+ },
+ {
+ .name = "azoteq,auto-mode",
+ .reg_grp = IQS7222_REG_GRP_GLBL,
+ .reg_offset = 0,
+ .reg_shift = 2,
+ .reg_width = 2,
+ .label = "number of conversions",
+ },
+ {
+ .name = "azoteq,ati-frac-div-fine",
+ .reg_grp = IQS7222_REG_GRP_GLBL,
+ .reg_offset = 1,
+ .reg_shift = 9,
+ .reg_width = 5,
+ .label = "ATI fine fractional divider",
+ },
+ {
+ .name = "azoteq,ati-frac-div-coarse",
+ .reg_grp = IQS7222_REG_GRP_GLBL,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 5,
+ .label = "ATI coarse fractional divider",
+ },
+ {
+ .name = "azoteq,ati-comp-select",
+ .reg_grp = IQS7222_REG_GRP_GLBL,
+ .reg_offset = 2,
+ .reg_shift = 0,
+ .reg_width = 10,
+ .label = "ATI compensation selection",
+ },
+ {
+ .name = "azoteq,ati-band",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 12,
+ .reg_width = 2,
+ .label = "ATI band",
+ },
+ {
+ .name = "azoteq,global-halt",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 11,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,invert-enable",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 10,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,dual-direction",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 9,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,samp-cap-double",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 3,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,vref-half",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 2,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,proj-bias",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 0,
+ .reg_shift = 0,
+ .reg_width = 2,
+ .label = "projected bias current",
+ },
+ {
+ .name = "azoteq,ati-target",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 1,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 8,
+ .label = "ATI target",
+ },
+ {
+ .name = "azoteq,ati-base",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 1,
+ .reg_shift = 3,
+ .reg_width = 5,
+ .val_pitch = 16,
+ .label = "ATI base",
+ },
+ {
+ .name = "azoteq,ati-mode",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 3,
+ .val_max = 5,
+ .label = "ATI mode",
+ },
+ {
+ .name = "azoteq,ati-frac-div-fine",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 2,
+ .reg_shift = 9,
+ .reg_width = 5,
+ .label = "ATI fine fractional divider",
+ },
+ {
+ .name = "azoteq,ati-frac-mult-coarse",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 2,
+ .reg_shift = 5,
+ .reg_width = 4,
+ .label = "ATI coarse fractional multiplier",
+ },
+ {
+ .name = "azoteq,ati-frac-div-coarse",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 2,
+ .reg_shift = 0,
+ .reg_width = 5,
+ .label = "ATI coarse fractional divider",
+ },
+ {
+ .name = "azoteq,ati-comp-div",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 3,
+ .reg_shift = 11,
+ .reg_width = 5,
+ .label = "ATI compensation divider",
+ },
+ {
+ .name = "azoteq,ati-comp-select",
+ .reg_grp = IQS7222_REG_GRP_CHAN,
+ .reg_offset = 3,
+ .reg_shift = 0,
+ .reg_width = 10,
+ .label = "ATI compensation selection",
+ },
+ {
+ .name = "azoteq,debounce-exit",
+ .reg_grp = IQS7222_REG_GRP_BTN,
+ .reg_key = IQS7222_REG_KEY_DEBOUNCE,
+ .reg_offset = 0,
+ .reg_shift = 12,
+ .reg_width = 4,
+ .label = "debounce exit factor",
+ },
+ {
+ .name = "azoteq,debounce-enter",
+ .reg_grp = IQS7222_REG_GRP_BTN,
+ .reg_key = IQS7222_REG_KEY_DEBOUNCE,
+ .reg_offset = 0,
+ .reg_shift = 8,
+ .reg_width = 4,
+ .label = "debounce entrance factor",
+ },
+ {
+ .name = "azoteq,thresh",
+ .reg_grp = IQS7222_REG_GRP_BTN,
+ .reg_key = IQS7222_REG_KEY_PROX,
+ .reg_offset = 0,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .val_max = 127,
+ .label = "threshold",
+ },
+ {
+ .name = "azoteq,thresh",
+ .reg_grp = IQS7222_REG_GRP_BTN,
+ .reg_key = IQS7222_REG_KEY_TOUCH,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "threshold",
+ },
+ {
+ .name = "azoteq,hyst",
+ .reg_grp = IQS7222_REG_GRP_BTN,
+ .reg_key = IQS7222_REG_KEY_TOUCH,
+ .reg_offset = 1,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "hysteresis",
+ },
+ {
+ .name = "azoteq,lta-beta-lp",
+ .reg_grp = IQS7222_REG_GRP_FILT,
+ .reg_offset = 0,
+ .reg_shift = 12,
+ .reg_width = 4,
+ .label = "low-power mode long-term average beta",
+ },
+ {
+ .name = "azoteq,lta-beta-np",
+ .reg_grp = IQS7222_REG_GRP_FILT,
+ .reg_offset = 0,
+ .reg_shift = 8,
+ .reg_width = 4,
+ .label = "normal-power mode long-term average beta",
+ },
+ {
+ .name = "azoteq,counts-beta-lp",
+ .reg_grp = IQS7222_REG_GRP_FILT,
+ .reg_offset = 0,
+ .reg_shift = 4,
+ .reg_width = 4,
+ .label = "low-power mode counts beta",
+ },
+ {
+ .name = "azoteq,counts-beta-np",
+ .reg_grp = IQS7222_REG_GRP_FILT,
+ .reg_offset = 0,
+ .reg_shift = 0,
+ .reg_width = 4,
+ .label = "normal-power mode counts beta",
+ },
+ {
+ .name = "azoteq,lta-fast-beta-lp",
+ .reg_grp = IQS7222_REG_GRP_FILT,
+ .reg_offset = 1,
+ .reg_shift = 4,
+ .reg_width = 4,
+ .label = "low-power mode long-term average fast beta",
+ },
+ {
+ .name = "azoteq,lta-fast-beta-np",
+ .reg_grp = IQS7222_REG_GRP_FILT,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 4,
+ .label = "normal-power mode long-term average fast beta",
+ },
+ {
+ .name = "azoteq,lower-cal",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_offset = 0,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "lower calibration",
+ },
+ {
+ .name = "azoteq,static-beta",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_NO_WHEEL,
+ .reg_offset = 0,
+ .reg_shift = 6,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,bottom-beta",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_NO_WHEEL,
+ .reg_offset = 0,
+ .reg_shift = 3,
+ .reg_width = 3,
+ .label = "bottom beta",
+ },
+ {
+ .name = "azoteq,static-beta",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_WHEEL,
+ .reg_offset = 0,
+ .reg_shift = 7,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,bottom-beta",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_WHEEL,
+ .reg_offset = 0,
+ .reg_shift = 4,
+ .reg_width = 3,
+ .label = "bottom beta",
+ },
+ {
+ .name = "azoteq,bottom-speed",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_offset = 1,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "bottom speed",
+ },
+ {
+ .name = "azoteq,upper-cal",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "upper calibration",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_TAP,
+ .reg_offset = 9,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_TAP_LEGACY,
+ .reg_offset = 9,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 4,
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-min-ms",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_TAP,
+ .reg_offset = 9,
+ .reg_shift = 3,
+ .reg_width = 5,
+ .val_pitch = 16,
+ .label = "minimum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-min-ms",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_TAP_LEGACY,
+ .reg_offset = 9,
+ .reg_shift = 3,
+ .reg_width = 5,
+ .val_pitch = 4,
+ .label = "minimum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ .reg_offset = 10,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
+ .reg_offset = 10,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ .reg_offset = 10,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_grp = IQS7222_REG_GRP_SLDR,
+ .reg_key = IQS7222_REG_KEY_AXIAL_LEGACY,
+ .reg_offset = 10,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .val_pitch = 4,
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,num-rows",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 0,
+ .reg_shift = 4,
+ .reg_width = 4,
+ .val_min = 1,
+ .val_max = 12,
+ .label = "number of rows",
+ },
+ {
+ .name = "azoteq,num-cols",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 0,
+ .reg_shift = 0,
+ .reg_width = 4,
+ .val_min = 1,
+ .val_max = 12,
+ .label = "number of columns",
+ },
+ {
+ .name = "azoteq,lower-cal-y",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 1,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "lower vertical calibration",
+ },
+ {
+ .name = "azoteq,lower-cal-x",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "lower horizontal calibration",
+ },
+ {
+ .name = "azoteq,upper-cal-y",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 2,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .label = "upper vertical calibration",
+ },
+ {
+ .name = "azoteq,upper-cal-x",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 2,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "upper horizontal calibration",
+ },
+ {
+ .name = "azoteq,top-speed",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 3,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 4,
+ .label = "top speed",
+ },
+ {
+ .name = "azoteq,bottom-speed",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_offset = 3,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .label = "bottom speed",
+ },
+ {
+ .name = "azoteq,gesture-min-ms",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_key = IQS7222_REG_KEY_TAP,
+ .reg_offset = 20,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "minimum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ .reg_offset = 21,
+ .reg_shift = 8,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-max-ms",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_key = IQS7222_REG_KEY_TAP,
+ .reg_offset = 21,
+ .reg_shift = 0,
+ .reg_width = 8,
+ .val_pitch = 16,
+ .label = "maximum gesture time",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_key = IQS7222_REG_KEY_TAP,
+ .reg_offset = 22,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .label = "gesture distance",
+ },
+ {
+ .name = "azoteq,gesture-dist",
+ .reg_grp = IQS7222_REG_GRP_TPAD,
+ .reg_key = IQS7222_REG_KEY_AXIAL,
+ .reg_offset = 23,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .label = "gesture distance",
+ },
+ {
+ .name = "drive-open-drain",
+ .reg_grp = IQS7222_REG_GRP_GPIO,
+ .reg_offset = 0,
+ .reg_shift = 1,
+ .reg_width = 1,
+ },
+ {
+ .name = "azoteq,timeout-ati-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 1,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .val_pitch = 500,
+ .label = "ATI error timeout",
+ },
+ {
+ .name = "azoteq,rate-ati-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 2,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .label = "ATI report rate",
+ },
+ {
+ .name = "azoteq,timeout-np-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 3,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .label = "normal-power mode timeout",
+ },
+ {
+ .name = "azoteq,rate-np-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 4,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .val_max = 3000,
+ .label = "normal-power mode report rate",
+ },
+ {
+ .name = "azoteq,timeout-lp-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 5,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .label = "low-power mode timeout",
+ },
+ {
+ .name = "azoteq,rate-lp-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 6,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .val_max = 3000,
+ .label = "low-power mode report rate",
+ },
+ {
+ .name = "azoteq,timeout-ulp-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 7,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .label = "ultra-low-power mode timeout",
+ },
+ {
+ .name = "azoteq,rate-ulp-ms",
+ .reg_grp = IQS7222_REG_GRP_SYS,
+ .reg_offset = 8,
+ .reg_shift = 0,
+ .reg_width = 16,
+ .val_max = 3000,
+ .label = "ultra-low-power mode report rate",
+ },
+};
+
+struct iqs7222_private {
+ const struct iqs7222_dev_desc *dev_desc;
+ struct gpio_desc *reset_gpio;
+ struct gpio_desc *irq_gpio;
+ struct i2c_client *client;
+ struct input_dev *keypad;
+ struct touchscreen_properties prop;
+ unsigned int kp_type[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
+ unsigned int kp_code[IQS7222_MAX_CHAN][ARRAY_SIZE(iqs7222_kp_events)];
+ unsigned int sl_code[IQS7222_MAX_SLDR][ARRAY_SIZE(iqs7222_sl_events)];
+ unsigned int sl_axis[IQS7222_MAX_SLDR];
+ unsigned int tp_code[ARRAY_SIZE(iqs7222_tp_events)];
+ u16 cycle_setup[IQS7222_MAX_CHAN / 2][IQS7222_MAX_COLS_CYCLE];
+ u16 glbl_setup[IQS7222_MAX_COLS_GLBL];
+ u16 btn_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_BTN];
+ u16 chan_setup[IQS7222_MAX_CHAN][IQS7222_MAX_COLS_CHAN];
+ u16 filt_setup[IQS7222_MAX_COLS_FILT];
+ u16 sldr_setup[IQS7222_MAX_SLDR][IQS7222_MAX_COLS_SLDR];
+ u16 tpad_setup[IQS7222_MAX_COLS_TPAD];
+ u16 gpio_setup[ARRAY_SIZE(iqs7222_gpio_links)][IQS7222_MAX_COLS_GPIO];
+ u16 sys_setup[IQS7222_MAX_COLS_SYS];
+};
+
+static u16 *iqs7222_setup(struct iqs7222_private *iqs7222,
+ enum iqs7222_reg_grp_id reg_grp, int row)
+{
+ switch (reg_grp) {
+ case IQS7222_REG_GRP_CYCLE:
+ return iqs7222->cycle_setup[row];
+
+ case IQS7222_REG_GRP_GLBL:
+ return iqs7222->glbl_setup;
+
+ case IQS7222_REG_GRP_BTN:
+ return iqs7222->btn_setup[row];
+
+ case IQS7222_REG_GRP_CHAN:
+ return iqs7222->chan_setup[row];
+
+ case IQS7222_REG_GRP_FILT:
+ return iqs7222->filt_setup;
+
+ case IQS7222_REG_GRP_SLDR:
+ return iqs7222->sldr_setup[row];
+
+ case IQS7222_REG_GRP_TPAD:
+ return iqs7222->tpad_setup;
+
+ case IQS7222_REG_GRP_GPIO:
+ return iqs7222->gpio_setup[row];
+
+ case IQS7222_REG_GRP_SYS:
+ return iqs7222->sys_setup;
+
+ default:
+ return NULL;
+ }
+}
+
+static int iqs7222_irq_poll(struct iqs7222_private *iqs7222, u16 timeout_ms)
+{
+ ktime_t irq_timeout = ktime_add_ms(ktime_get(), timeout_ms);
+ int ret;
+
+ do {
+ usleep_range(1000, 1100);
+
+ ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
+ if (ret < 0)
+ return ret;
+ else if (ret > 0)
+ return 0;
+ } while (ktime_compare(ktime_get(), irq_timeout) < 0);
+
+ return -EBUSY;
+}
+
+static int iqs7222_hard_reset(struct iqs7222_private *iqs7222)
+{
+ struct i2c_client *client = iqs7222->client;
+ int error;
+
+ if (!iqs7222->reset_gpio)
+ return 0;
+
+ gpiod_set_value_cansleep(iqs7222->reset_gpio, 1);
+ usleep_range(1000, 1100);
+
+ gpiod_set_value_cansleep(iqs7222->reset_gpio, 0);
+
+ error = iqs7222_irq_poll(iqs7222, IQS7222_RESET_TIMEOUT_MS);
+ if (error)
+ dev_err(&client->dev, "Failed to reset device: %d\n", error);
+
+ return error;
+}
+
+static int iqs7222_force_comms(struct iqs7222_private *iqs7222)
+{
+ u8 msg_buf[] = { 0xFF, };
+ int ret;
+
+ /*
+ * The device cannot communicate until it asserts its interrupt (RDY)
+ * pin. Attempts to do so while RDY is deasserted return an ACK; how-
+ * ever all write data is ignored, and all read data returns 0xEE.
+ *
+ * Unsolicited communication must be preceded by a special force com-
+ * munication command, after which the device eventually asserts its
+ * RDY pin and agrees to communicate.
+ *
+ * Regardless of whether communication is forced or the result of an
+ * interrupt, the device automatically deasserts its RDY pin once it
+ * detects an I2C stop condition, or a timeout expires.
+ */
+ ret = gpiod_get_value_cansleep(iqs7222->irq_gpio);
+ if (ret < 0)
+ return ret;
+ else if (ret > 0)
+ return 0;
+
+ ret = i2c_master_send(iqs7222->client, msg_buf, sizeof(msg_buf));
+ if (ret < (int)sizeof(msg_buf)) {
+ if (ret >= 0)
+ ret = -EIO;
+
+ /*
+ * The datasheet states that the host must wait to retry any
+ * failed attempt to communicate over I2C.
+ */
+ msleep(IQS7222_COMMS_RETRY_MS);
+ return ret;
+ }
+
+ return iqs7222_irq_poll(iqs7222, IQS7222_COMMS_TIMEOUT_MS);
+}
+
+static int iqs7222_read_burst(struct iqs7222_private *iqs7222,
+ u16 reg, void *val, u16 val_len)
+{
+ u8 reg_buf[sizeof(__be16)];
+ int ret, i;
+ struct i2c_client *client = iqs7222->client;
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = reg > U8_MAX ? sizeof(reg) : sizeof(u8),
+ .buf = reg_buf,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = val_len,
+ .buf = (u8 *)val,
+ },
+ };
+
+ if (reg > U8_MAX)
+ put_unaligned_be16(reg, reg_buf);
+ else
+ *reg_buf = (u8)reg;
+
+ /*
+ * The following loop protects against an edge case in which the RDY
+ * pin is automatically deasserted just as the read is initiated. In
+ * that case, the read must be retried using forced communication.
+ */
+ for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
+ ret = iqs7222_force_comms(iqs7222);
+ if (ret < 0)
+ continue;
+
+ ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (ret < (int)ARRAY_SIZE(msg)) {
+ if (ret >= 0)
+ ret = -EIO;
+
+ msleep(IQS7222_COMMS_RETRY_MS);
+ continue;
+ }
+
+ if (get_unaligned_le16(msg[1].buf) == IQS7222_COMMS_ERROR) {
+ ret = -ENODATA;
+ continue;
+ }
+
+ ret = 0;
+ break;
+ }
+
+ /*
+ * The following delay ensures the device has deasserted the RDY pin
+ * following the I2C stop condition.
+ */
+ usleep_range(50, 100);
+
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Failed to read from address 0x%04X: %d\n", reg, ret);
+
+ return ret;
+}
+
+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, sizeof(val_buf));
+ if (error)
+ return error;
+
+ *val = le16_to_cpu(val_buf);
+
+ return 0;
+}
+
+static int iqs7222_write_burst(struct iqs7222_private *iqs7222,
+ u16 reg, const void *val, u16 val_len)
+{
+ int reg_len = reg > U8_MAX ? sizeof(reg) : sizeof(u8);
+ int msg_len = reg_len + val_len;
+ int ret, i;
+ struct i2c_client *client = iqs7222->client;
+ u8 *msg_buf;
+
+ msg_buf = kzalloc(msg_len, GFP_KERNEL);
+ if (!msg_buf)
+ return -ENOMEM;
+
+ if (reg > U8_MAX)
+ put_unaligned_be16(reg, msg_buf);
+ else
+ *msg_buf = (u8)reg;
+
+ memcpy(msg_buf + reg_len, val, val_len);
+
+ /*
+ * The following loop protects against an edge case in which the RDY
+ * pin is automatically asserted just before the force communication
+ * command is sent.
+ *
+ * In that case, the subsequent I2C stop condition tricks the device
+ * into preemptively deasserting the RDY pin and the command must be
+ * sent again.
+ */
+ for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
+ ret = iqs7222_force_comms(iqs7222);
+ if (ret < 0)
+ continue;
+
+ ret = i2c_master_send(client, msg_buf, msg_len);
+ if (ret < msg_len) {
+ if (ret >= 0)
+ ret = -EIO;
+
+ msleep(IQS7222_COMMS_RETRY_MS);
+ continue;
+ }
+
+ ret = 0;
+ break;
+ }
+
+ kfree(msg_buf);
+
+ usleep_range(50, 100);
+
+ if (ret < 0)
+ dev_err(&client->dev,
+ "Failed to write to address 0x%04X: %d\n", reg, ret);
+
+ return ret;
+}
+
+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, sizeof(val_buf));
+}
+
+static int iqs7222_ati_trigger(struct iqs7222_private *iqs7222)
+{
+ struct i2c_client *client = iqs7222->client;
+ ktime_t ati_timeout;
+ u16 sys_status = 0;
+ u16 sys_setup;
+ int error, i;
+
+ /*
+ * The reserved fields of the system setup register may have changed
+ * as a result of other registers having been written. As such, read
+ * the register's latest value to avoid unexpected behavior when the
+ * register is written in the loop that follows.
+ */
+ error = iqs7222_read_word(iqs7222, IQS7222_SYS_SETUP, &sys_setup);
+ if (error)
+ return error;
+
+ for (i = 0; i < IQS7222_NUM_RETRIES; i++) {
+ /*
+ * Trigger ATI from streaming and normal-power modes so that
+ * the RDY pin continues to be asserted during ATI.
+ */
+ error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
+ sys_setup |
+ IQS7222_SYS_SETUP_REDO_ATI);
+ if (error)
+ return error;
+
+ ati_timeout = ktime_add_ms(ktime_get(), IQS7222_ATI_TIMEOUT_MS);
+
+ do {
+ error = iqs7222_irq_poll(iqs7222,
+ IQS7222_COMMS_TIMEOUT_MS);
+ if (error)
+ continue;
+
+ error = iqs7222_read_word(iqs7222, IQS7222_SYS_STATUS,
+ &sys_status);
+ if (error)
+ return error;
+
+ if (sys_status & IQS7222_SYS_STATUS_RESET)
+ return 0;
+
+ if (sys_status & IQS7222_SYS_STATUS_ATI_ERROR)
+ break;
+
+ if (sys_status & IQS7222_SYS_STATUS_ATI_ACTIVE)
+ continue;
+
+ /*
+ * Use stream-in-touch mode if either slider reports
+ * absolute position.
+ */
+ sys_setup |= test_bit(EV_ABS, iqs7222->keypad->evbit)
+ ? IQS7222_SYS_SETUP_INTF_MODE_TOUCH
+ : IQS7222_SYS_SETUP_INTF_MODE_EVENT;
+ sys_setup |= IQS7222_SYS_SETUP_PWR_MODE_AUTO;
+
+ return iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
+ sys_setup);
+ } while (ktime_compare(ktime_get(), ati_timeout) < 0);
+
+ dev_err(&client->dev,
+ "ATI attempt %d of %d failed with status 0x%02X, %s\n",
+ i + 1, IQS7222_NUM_RETRIES, (u8)sys_status,
+ i + 1 < IQS7222_NUM_RETRIES ? "retrying" : "stopping");
+ }
+
+ return -ETIMEDOUT;
+}
+
+static int iqs7222_dev_init(struct iqs7222_private *iqs7222, int dir)
+{
+ const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
+ int comms_offset = dev_desc->comms_offset;
+ int error, i, j, k;
+
+ /*
+ * Acknowledge reset before writing any registers in case the device
+ * suffers a spurious reset during initialization.
+ */
+ if (dir == WRITE) {
+ error = iqs7222_write_word(iqs7222, IQS7222_SYS_SETUP,
+ iqs7222->sys_setup[0] |
+ IQS7222_SYS_SETUP_ACK_RESET);
+ if (error)
+ return error;
+ }
+
+ /*
+ * Take advantage of the stop-bit disable function, if available, to
+ * save the trouble of having to reopen a communication window after
+ * each burst read or write.
+ */
+ if (comms_offset) {
+ u16 comms_setup;
+
+ error = iqs7222_read_word(iqs7222,
+ IQS7222_SYS_SETUP + comms_offset,
+ &comms_setup);
+ if (error)
+ return error;
+
+ error = iqs7222_write_word(iqs7222,
+ IQS7222_SYS_SETUP + comms_offset,
+ comms_setup | IQS7222_COMMS_HOLD);
+ if (error)
+ return error;
+ }
+
+ for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
+ int num_row = dev_desc->reg_grps[i].num_row;
+ 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)
+ continue;
+
+ val = iqs7222_setup(iqs7222, i, 0);
+ if (!val)
+ continue;
+
+ val_buf = kcalloc(num_col, sizeof(__le16), GFP_KERNEL);
+ if (!val_buf)
+ return -ENOMEM;
+
+ for (j = 0; j < num_row; j++) {
+ switch (dir) {
+ case READ:
+ error = iqs7222_read_burst(iqs7222, reg,
+ val_buf, val_len);
+ for (k = 0; k < num_col; k++)
+ val[k] = le16_to_cpu(val_buf[k]);
+ break;
+
+ case WRITE:
+ for (k = 0; k < num_col; k++)
+ val_buf[k] = cpu_to_le16(val[k]);
+ error = iqs7222_write_burst(iqs7222, reg,
+ val_buf, val_len);
+ break;
+
+ default:
+ error = -EINVAL;
+ }
+
+ if (error)
+ break;
+
+ reg += IQS7222_REG_OFFSET;
+ val += iqs7222_max_cols[i];
+ }
+
+ kfree(val_buf);
+
+ if (error)
+ return error;
+ }
+
+ if (comms_offset) {
+ u16 comms_setup;
+
+ error = iqs7222_read_word(iqs7222,
+ IQS7222_SYS_SETUP + comms_offset,
+ &comms_setup);
+ if (error)
+ return error;
+
+ error = iqs7222_write_word(iqs7222,
+ IQS7222_SYS_SETUP + comms_offset,
+ comms_setup & ~IQS7222_COMMS_HOLD);
+ if (error)
+ return error;
+ }
+
+ if (dir == READ) {
+ iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_INTF_MODE_MASK;
+ iqs7222->sys_setup[0] &= ~IQS7222_SYS_SETUP_PWR_MODE_MASK;
+ return 0;
+ }
+
+ return iqs7222_ati_trigger(iqs7222);
+}
+
+static int iqs7222_dev_info(struct iqs7222_private *iqs7222)
+{
+ struct i2c_client *client = iqs7222->client;
+ bool prod_num_valid = false;
+ __le16 dev_id[3];
+ int error, i;
+
+ error = iqs7222_read_burst(iqs7222, IQS7222_PROD_NUM, dev_id,
+ sizeof(dev_id));
+ if (error)
+ return error;
+
+ for (i = 0; i < ARRAY_SIZE(iqs7222_devs); i++) {
+ if (le16_to_cpu(dev_id[0]) != iqs7222_devs[i].prod_num)
+ continue;
+
+ prod_num_valid = true;
+
+ if (le16_to_cpu(dev_id[1]) < iqs7222_devs[i].fw_major)
+ continue;
+
+ if (le16_to_cpu(dev_id[2]) < iqs7222_devs[i].fw_minor)
+ continue;
+
+ iqs7222->dev_desc = &iqs7222_devs[i];
+ return 0;
+ }
+
+ if (prod_num_valid)
+ dev_err(&client->dev, "Unsupported firmware revision: %u.%u\n",
+ le16_to_cpu(dev_id[1]), le16_to_cpu(dev_id[2]));
+ else
+ dev_err(&client->dev, "Unrecognized product number: %u\n",
+ le16_to_cpu(dev_id[0]));
+
+ return -EINVAL;
+}
+
+static int iqs7222_gpio_select(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *child_node,
+ int child_enable, u16 child_link)
+{
+ const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
+ struct i2c_client *client = iqs7222->client;
+ int num_gpio = dev_desc->reg_grps[IQS7222_REG_GRP_GPIO].num_row;
+ int error, count, i;
+ unsigned int gpio_sel[ARRAY_SIZE(iqs7222_gpio_links)];
+
+ if (!num_gpio)
+ return 0;
+
+ if (!fwnode_property_present(child_node, "azoteq,gpio-select"))
+ return 0;
+
+ count = fwnode_property_count_u32(child_node, "azoteq,gpio-select");
+ if (count > num_gpio) {
+ dev_err(&client->dev, "Invalid number of %s GPIOs\n",
+ fwnode_get_name(child_node));
+ return -EINVAL;
+ } else if (count < 0) {
+ dev_err(&client->dev, "Failed to count %s GPIOs: %d\n",
+ fwnode_get_name(child_node), count);
+ return count;
+ }
+
+ error = fwnode_property_read_u32_array(child_node,
+ "azoteq,gpio-select",
+ gpio_sel, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read %s GPIOs: %d\n",
+ fwnode_get_name(child_node), error);
+ return error;
+ }
+
+ for (i = 0; i < count; i++) {
+ u16 *gpio_setup;
+
+ if (gpio_sel[i] >= num_gpio) {
+ dev_err(&client->dev, "Invalid %s GPIO: %u\n",
+ fwnode_get_name(child_node), gpio_sel[i]);
+ return -EINVAL;
+ }
+
+ gpio_setup = iqs7222->gpio_setup[gpio_sel[i]];
+
+ if (gpio_setup[2] && child_link != gpio_setup[2]) {
+ dev_err(&client->dev,
+ "Conflicting GPIO %u event types\n",
+ gpio_sel[i]);
+ return -EINVAL;
+ }
+
+ gpio_setup[0] |= IQS7222_GPIO_SETUP_0_GPIO_EN;
+ gpio_setup[1] |= child_enable;
+ gpio_setup[2] = child_link;
+ }
+
+ return 0;
+}
+
+static int iqs7222_parse_props(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *reg_grp_node,
+ int reg_grp_index,
+ enum iqs7222_reg_grp_id reg_grp,
+ enum iqs7222_reg_key_id reg_key)
+{
+ u16 *setup = iqs7222_setup(iqs7222, reg_grp, reg_grp_index);
+ struct i2c_client *client = iqs7222->client;
+ int i;
+
+ if (!setup)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(iqs7222_props); i++) {
+ const char *name = iqs7222_props[i].name;
+ int reg_offset = iqs7222_props[i].reg_offset;
+ int reg_shift = iqs7222_props[i].reg_shift;
+ int reg_width = iqs7222_props[i].reg_width;
+ int val_pitch = iqs7222_props[i].val_pitch ? : 1;
+ int val_min = iqs7222_props[i].val_min;
+ int val_max = iqs7222_props[i].val_max;
+ bool invert = iqs7222_props[i].invert;
+ const char *label = iqs7222_props[i].label ? : name;
+ unsigned int val;
+ int error;
+
+ if (iqs7222_props[i].reg_grp != reg_grp ||
+ iqs7222_props[i].reg_key != reg_key)
+ continue;
+
+ /*
+ * Boolean register fields are one bit wide; they are forcibly
+ * reset to provide a means to undo changes by a bootloader if
+ * necessary.
+ *
+ * Scalar fields, on the other hand, are left untouched unless
+ * their corresponding properties are present.
+ */
+ if (reg_width == 1) {
+ if (invert)
+ setup[reg_offset] |= BIT(reg_shift);
+ else
+ setup[reg_offset] &= ~BIT(reg_shift);
+ }
+
+ if (!fwnode_property_present(reg_grp_node, name))
+ continue;
+
+ if (reg_width == 1) {
+ if (invert)
+ setup[reg_offset] &= ~BIT(reg_shift);
+ else
+ setup[reg_offset] |= BIT(reg_shift);
+
+ continue;
+ }
+
+ error = fwnode_property_read_u32(reg_grp_node, name, &val);
+ if (error) {
+ dev_err(&client->dev, "Failed to read %s %s: %d\n",
+ fwnode_get_name(reg_grp_node), label, error);
+ return error;
+ }
+
+ if (!val_max)
+ val_max = GENMASK(reg_width - 1, 0) * val_pitch;
+
+ if (val < val_min || val > val_max) {
+ dev_err(&client->dev, "Invalid %s %s: %u\n",
+ fwnode_get_name(reg_grp_node), label, val);
+ return -EINVAL;
+ }
+
+ setup[reg_offset] &= ~GENMASK(reg_shift + reg_width - 1,
+ reg_shift);
+ setup[reg_offset] |= (val / val_pitch << reg_shift);
+ }
+
+ return 0;
+}
+
+static int iqs7222_parse_event(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *event_node,
+ int reg_grp_index,
+ enum iqs7222_reg_grp_id reg_grp,
+ enum iqs7222_reg_key_id reg_key,
+ u16 event_enable, u16 event_link,
+ unsigned int *event_type,
+ unsigned int *event_code)
+{
+ struct i2c_client *client = iqs7222->client;
+ int error;
+
+ error = iqs7222_parse_props(iqs7222, event_node, reg_grp_index,
+ reg_grp, reg_key);
+ if (error)
+ return error;
+
+ error = iqs7222_gpio_select(iqs7222, event_node, event_enable,
+ event_link);
+ if (error)
+ return error;
+
+ error = fwnode_property_read_u32(event_node, "linux,code", event_code);
+ if (error == -EINVAL) {
+ return 0;
+ } else if (error) {
+ dev_err(&client->dev, "Failed to read %s code: %d\n",
+ fwnode_get_name(event_node), error);
+ return error;
+ }
+
+ if (!event_type) {
+ input_set_capability(iqs7222->keypad, EV_KEY, *event_code);
+ return 0;
+ }
+
+ error = fwnode_property_read_u32(event_node, "linux,input-type",
+ event_type);
+ if (error == -EINVAL) {
+ *event_type = EV_KEY;
+ } else if (error) {
+ dev_err(&client->dev, "Failed to read %s input type: %d\n",
+ fwnode_get_name(event_node), error);
+ return error;
+ } else if (*event_type != EV_KEY && *event_type != EV_SW) {
+ dev_err(&client->dev, "Invalid %s input type: %d\n",
+ fwnode_get_name(event_node), *event_type);
+ return -EINVAL;
+ }
+
+ input_set_capability(iqs7222->keypad, *event_type, *event_code);
+
+ return 0;
+}
+
+static int iqs7222_parse_cycle(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *cycle_node, int cycle_index)
+{
+ u16 *cycle_setup = iqs7222->cycle_setup[cycle_index];
+ struct i2c_client *client = iqs7222->client;
+ unsigned int pins[9];
+ int error, count, i;
+
+ /*
+ * Each channel shares a cycle with one other channel; the mapping of
+ * channels to cycles is fixed. Properties defined for a cycle impact
+ * both channels tied to the cycle.
+ *
+ * Unlike channels which are restricted to a select range of CRx pins
+ * based on channel number, any cycle can claim any of the device's 9
+ * CTx pins (CTx0-8).
+ */
+ if (!fwnode_property_present(cycle_node, "azoteq,tx-enable"))
+ return 0;
+
+ count = fwnode_property_count_u32(cycle_node, "azoteq,tx-enable");
+ if (count < 0) {
+ dev_err(&client->dev, "Failed to count %s CTx pins: %d\n",
+ fwnode_get_name(cycle_node), count);
+ return count;
+ } else if (count > ARRAY_SIZE(pins)) {
+ dev_err(&client->dev, "Invalid number of %s CTx pins\n",
+ fwnode_get_name(cycle_node));
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32_array(cycle_node, "azoteq,tx-enable",
+ pins, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read %s CTx pins: %d\n",
+ fwnode_get_name(cycle_node), error);
+ return error;
+ }
+
+ cycle_setup[1] &= ~GENMASK(7 + ARRAY_SIZE(pins) - 1, 7);
+
+ for (i = 0; i < count; i++) {
+ if (pins[i] > 8) {
+ dev_err(&client->dev, "Invalid %s CTx pin: %u\n",
+ fwnode_get_name(cycle_node), pins[i]);
+ return -EINVAL;
+ }
+
+ cycle_setup[1] |= BIT(pins[i] + 7);
+ }
+
+ return 0;
+}
+
+static int iqs7222_parse_chan(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *chan_node, int chan_index)
+{
+ 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 = dev_desc->ext_chan ? : num_chan;
+ int error, i;
+ u16 *chan_setup = iqs7222->chan_setup[chan_index];
+ u16 *sys_setup = iqs7222->sys_setup;
+ unsigned int val;
+
+ if (dev_desc->allow_offset &&
+ fwnode_property_present(chan_node, "azoteq,ulp-allow"))
+ sys_setup[dev_desc->allow_offset] &= ~BIT(chan_index);
+
+ chan_setup[0] |= IQS7222_CHAN_SETUP_0_CHAN_EN;
+
+ /*
+ * The reference channel function allows for differential measurements
+ * and is only available in the case of IQS7222A or IQS7222C.
+ */
+ if (dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_col > 4 &&
+ fwnode_property_present(chan_node, "azoteq,ref-select")) {
+ u16 *ref_setup;
+
+ error = fwnode_property_read_u32(chan_node, "azoteq,ref-select",
+ &val);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read %s reference channel: %d\n",
+ fwnode_get_name(chan_node), error);
+ return error;
+ }
+
+ if (val >= ext_chan) {
+ dev_err(&client->dev,
+ "Invalid %s reference channel: %u\n",
+ fwnode_get_name(chan_node), val);
+ return -EINVAL;
+ }
+
+ ref_setup = iqs7222->chan_setup[val];
+
+ /*
+ * Configure the current channel as a follower of the selected
+ * reference channel.
+ */
+ chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_FOLLOW;
+ chan_setup[4] = val * 42 + 1048;
+
+ error = fwnode_property_read_u32(chan_node, "azoteq,ref-weight",
+ &val);
+ if (!error) {
+ if (val > U16_MAX) {
+ dev_err(&client->dev,
+ "Invalid %s reference weight: %u\n",
+ fwnode_get_name(chan_node), val);
+ return -EINVAL;
+ }
+
+ chan_setup[5] = val;
+ } else if (error != -EINVAL) {
+ dev_err(&client->dev,
+ "Failed to read %s reference weight: %d\n",
+ fwnode_get_name(chan_node), error);
+ return error;
+ }
+
+ /*
+ * Configure the selected channel as a reference channel which
+ * serves the current channel.
+ */
+ ref_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
+ ref_setup[5] |= BIT(chan_index);
+
+ ref_setup[4] = dev_desc->touch_link;
+ if (fwnode_property_present(chan_node, "azoteq,use-prox"))
+ ref_setup[4] -= 2;
+ } else if (dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row &&
+ fwnode_property_present(chan_node,
+ "azoteq,counts-filt-enable")) {
+ /*
+ * In the case of IQS7222D, however, the reference mode field
+ * is partially repurposed as a counts filter enable control.
+ */
+ chan_setup[0] |= IQS7222_CHAN_SETUP_0_REF_MODE_REF;
+ }
+
+ if (fwnode_property_present(chan_node, "azoteq,rx-enable")) {
+ /*
+ * Each channel can claim up to 4 CRx pins. The first half of
+ * the channels can use CRx0-3, while the second half can use
+ * CRx4-7.
+ */
+ unsigned int pins[4];
+ int count;
+
+ count = fwnode_property_count_u32(chan_node,
+ "azoteq,rx-enable");
+ if (count < 0) {
+ dev_err(&client->dev,
+ "Failed to count %s CRx pins: %d\n",
+ fwnode_get_name(chan_node), count);
+ return count;
+ } else if (count > ARRAY_SIZE(pins)) {
+ dev_err(&client->dev,
+ "Invalid number of %s CRx pins\n",
+ fwnode_get_name(chan_node));
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32_array(chan_node,
+ "azoteq,rx-enable",
+ pins, count);
+ if (error) {
+ dev_err(&client->dev,
+ "Failed to read %s CRx pins: %d\n",
+ fwnode_get_name(chan_node), error);
+ return error;
+ }
+
+ chan_setup[0] &= ~GENMASK(4 + ARRAY_SIZE(pins) - 1, 4);
+
+ for (i = 0; i < count; i++) {
+ int min_crx = chan_index < ext_chan / 2 ? 0 : 4;
+
+ if (pins[i] < min_crx || pins[i] > min_crx + 3) {
+ dev_err(&client->dev,
+ "Invalid %s CRx pin: %u\n",
+ fwnode_get_name(chan_node), pins[i]);
+ return -EINVAL;
+ }
+
+ chan_setup[0] |= BIT(pins[i] + 4 - min_crx);
+ }
+ }
+
+ 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 __free(fwnode_handle) =
+ fwnode_get_named_child_node(chan_node, event_name);
+ if (!event_node)
+ continue;
+
+ error = fwnode_property_read_u32(event_node,
+ "azoteq,timeout-press-ms",
+ &val);
+ if (!error) {
+ /*
+ * The IQS7222B employs a global pair of press timeout
+ * registers as opposed to channel-specific registers.
+ */
+ u16 *setup = dev_desc->reg_grps
+ [IQS7222_REG_GRP_BTN].num_col > 2 ?
+ &iqs7222->btn_setup[chan_index][2] :
+ &sys_setup[9];
+
+ if (val > U8_MAX * 500) {
+ dev_err(&client->dev,
+ "Invalid %s press timeout: %u\n",
+ fwnode_get_name(event_node), val);
+ return -EINVAL;
+ }
+
+ *setup &= ~(U8_MAX << i * 8);
+ *setup |= (val / 500 << i * 8);
+ } else if (error != -EINVAL) {
+ dev_err(&client->dev,
+ "Failed to read %s press timeout: %d\n",
+ fwnode_get_name(event_node), error);
+ return error;
+ }
+
+ error = iqs7222_parse_event(iqs7222, event_node, chan_index,
+ IQS7222_REG_GRP_BTN,
+ iqs7222_kp_events[i].reg_key,
+ BIT(chan_index),
+ dev_desc->touch_link - (i ? 0 : 2),
+ &iqs7222->kp_type[chan_index][i],
+ &iqs7222->kp_code[chan_index][i]);
+ if (error)
+ return error;
+
+ if (!iqs7222->kp_type[chan_index][i])
+ continue;
+
+ if (!dev_desc->event_offset)
+ continue;
+
+ sys_setup[dev_desc->event_offset] |= event_enable;
+ }
+
+ /*
+ * The following call handles a special pair of properties that apply
+ * to a channel node, but reside within the button (event) group.
+ */
+ return iqs7222_parse_props(iqs7222, chan_node, chan_index,
+ IQS7222_REG_GRP_BTN,
+ IQS7222_REG_KEY_DEBOUNCE);
+}
+
+static int iqs7222_parse_sldr(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *sldr_node, int sldr_index)
+{
+ 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 = 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];
+ unsigned int chan_sel[4], val;
+
+ /*
+ * Each slider can be spread across 3 to 4 channels. It is possible to
+ * select only 2 channels, but doing so prevents the slider from using
+ * the specified resolution.
+ */
+ count = fwnode_property_count_u32(sldr_node, "azoteq,channel-select");
+ if (count < 0) {
+ dev_err(&client->dev, "Failed to count %s channels: %d\n",
+ fwnode_get_name(sldr_node), count);
+ return count;
+ } else if (count < 3 || count > ARRAY_SIZE(chan_sel)) {
+ dev_err(&client->dev, "Invalid number of %s channels\n",
+ fwnode_get_name(sldr_node));
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32_array(sldr_node,
+ "azoteq,channel-select",
+ chan_sel, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read %s channels: %d\n",
+ fwnode_get_name(sldr_node), error);
+ return error;
+ }
+
+ /*
+ * Resolution and top speed, if small enough, are packed into a single
+ * register. Otherwise, each occupies its own register and the rest of
+ * the slider-related register addresses are offset by one.
+ */
+ reg_offset = dev_desc->sldr_res < U16_MAX ? 0 : 1;
+
+ sldr_setup[0] |= count;
+ sldr_setup[3 + reg_offset] &= ~GENMASK(ext_chan - 1, 0);
+
+ for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
+ sldr_setup[5 + reg_offset + i] = 0;
+ if (i >= count)
+ continue;
+
+ if (chan_sel[i] >= ext_chan) {
+ dev_err(&client->dev, "Invalid %s channel: %u\n",
+ fwnode_get_name(sldr_node), chan_sel[i]);
+ return -EINVAL;
+ }
+
+ /*
+ * The following fields indicate which channels participate in
+ * the slider, as well as each channel's relative placement.
+ */
+ sldr_setup[3 + reg_offset] |= BIT(chan_sel[i]);
+ sldr_setup[5 + reg_offset + i] = chan_sel[i] * 42 + 1080;
+ }
+
+ sldr_setup[4 + reg_offset] = dev_desc->touch_link;
+ if (fwnode_property_present(sldr_node, "azoteq,use-prox"))
+ sldr_setup[4 + reg_offset] -= 2;
+
+ error = fwnode_property_read_u32(sldr_node, "azoteq,slider-size", &val);
+ if (!error) {
+ if (val > dev_desc->sldr_res) {
+ dev_err(&client->dev, "Invalid %s size: %u\n",
+ fwnode_get_name(sldr_node), val);
+ return -EINVAL;
+ }
+
+ if (reg_offset) {
+ sldr_setup[3] = val;
+ } else {
+ sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_RES_MASK;
+ sldr_setup[2] |= (val / 16 <<
+ IQS7222_SLDR_SETUP_2_RES_SHIFT);
+ }
+ } else if (error != -EINVAL) {
+ dev_err(&client->dev, "Failed to read %s size: %d\n",
+ fwnode_get_name(sldr_node), error);
+ return error;
+ }
+
+ if (!(reg_offset ? sldr_setup[3]
+ : sldr_setup[2] & IQS7222_SLDR_SETUP_2_RES_MASK)) {
+ dev_err(&client->dev, "Undefined %s size\n",
+ fwnode_get_name(sldr_node));
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32(sldr_node, "azoteq,top-speed", &val);
+ if (!error) {
+ if (val > (reg_offset ? U16_MAX : U8_MAX * 4)) {
+ dev_err(&client->dev, "Invalid %s top speed: %u\n",
+ fwnode_get_name(sldr_node), val);
+ return -EINVAL;
+ }
+
+ if (reg_offset) {
+ sldr_setup[2] = val;
+ } else {
+ sldr_setup[2] &= ~IQS7222_SLDR_SETUP_2_TOP_SPEED_MASK;
+ sldr_setup[2] |= (val / 4);
+ }
+ } else if (error != -EINVAL) {
+ dev_err(&client->dev, "Failed to read %s top speed: %d\n",
+ fwnode_get_name(sldr_node), error);
+ return error;
+ }
+
+ error = fwnode_property_read_u32(sldr_node, "linux,axis", &val);
+ if (!error) {
+ u16 sldr_max = sldr_setup[3] - 1;
+
+ if (!reg_offset) {
+ sldr_max = sldr_setup[2];
+
+ sldr_max &= IQS7222_SLDR_SETUP_2_RES_MASK;
+ sldr_max >>= IQS7222_SLDR_SETUP_2_RES_SHIFT;
+
+ sldr_max = sldr_max * 16 - 1;
+ }
+
+ input_set_abs_params(iqs7222->keypad, val, 0, sldr_max, 0, 0);
+ iqs7222->sl_axis[sldr_index] = val;
+ } else if (error != -EINVAL) {
+ dev_err(&client->dev, "Failed to read %s axis: %d\n",
+ fwnode_get_name(sldr_node), error);
+ return error;
+ }
+
+ if (dev_desc->wheel_enable) {
+ sldr_setup[0] &= ~dev_desc->wheel_enable;
+ if (iqs7222->sl_axis[sldr_index] == ABS_WHEEL)
+ sldr_setup[0] |= dev_desc->wheel_enable;
+ }
+
+ /*
+ * The absence of a register offset makes it safe to assume the device
+ * supports gestures, each of which is first disabled until explicitly
+ * enabled.
+ */
+ if (!reg_offset)
+ for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++)
+ sldr_setup[9] &= ~iqs7222_sl_events[i].enable;
+
+ for (i = 0; i < ARRAY_SIZE(iqs7222_sl_events); i++) {
+ const char *event_name = iqs7222_sl_events[i].name;
+ enum iqs7222_reg_key_id reg_key;
+
+ struct fwnode_handle *event_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(sldr_node, event_name);
+ if (!event_node)
+ continue;
+
+ /*
+ * Depending on the device, gestures are either offered using
+ * one of two timing resolutions, or are not supported at all.
+ */
+ if (reg_offset)
+ reg_key = IQS7222_REG_KEY_RESERVED;
+ else if (dev_desc->legacy_gesture &&
+ iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_TAP)
+ reg_key = IQS7222_REG_KEY_TAP_LEGACY;
+ else if (dev_desc->legacy_gesture &&
+ iqs7222_sl_events[i].reg_key == IQS7222_REG_KEY_AXIAL)
+ reg_key = IQS7222_REG_KEY_AXIAL_LEGACY;
+ else
+ reg_key = iqs7222_sl_events[i].reg_key;
+
+ /*
+ * The press/release event does not expose a direct GPIO link,
+ * but one can be emulated by tying each of the participating
+ * channels to the same GPIO.
+ */
+ error = iqs7222_parse_event(iqs7222, event_node, sldr_index,
+ IQS7222_REG_GRP_SLDR, reg_key,
+ i ? iqs7222_sl_events[i].enable
+ : sldr_setup[3 + reg_offset],
+ i ? 1568 + sldr_index * 30
+ : sldr_setup[4 + reg_offset],
+ NULL,
+ &iqs7222->sl_code[sldr_index][i]);
+ if (error)
+ return error;
+
+ if (!reg_offset)
+ sldr_setup[9] |= iqs7222_sl_events[i].enable;
+
+ if (!dev_desc->event_offset)
+ continue;
+
+ /*
+ * The press/release event is determined based on whether the
+ * coordinate field reports 0xFFFF and solely relies on touch
+ * or proximity interrupts to be unmasked.
+ */
+ if (i && !reg_offset)
+ *event_mask |= (IQS7222_EVENT_MASK_SLDR << sldr_index);
+ else if (sldr_setup[4 + reg_offset] == dev_desc->touch_link)
+ *event_mask |= IQS7222_EVENT_MASK_TOUCH;
+ else
+ *event_mask |= IQS7222_EVENT_MASK_PROX;
+ }
+
+ /*
+ * The following call handles a special pair of properties that shift
+ * to make room for a wheel enable control in the case of IQS7222C.
+ */
+ return iqs7222_parse_props(iqs7222, sldr_node, sldr_index,
+ IQS7222_REG_GRP_SLDR,
+ dev_desc->wheel_enable ?
+ IQS7222_REG_KEY_WHEEL :
+ IQS7222_REG_KEY_NO_WHEEL);
+}
+
+static int iqs7222_parse_tpad(struct iqs7222_private *iqs7222,
+ struct fwnode_handle *tpad_node, int tpad_index)
+{
+ const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
+ struct touchscreen_properties *prop = &iqs7222->prop;
+ struct i2c_client *client = iqs7222->client;
+ int num_chan = dev_desc->reg_grps[IQS7222_REG_GRP_CHAN].num_row;
+ int count, error, i;
+ u16 *event_mask = &iqs7222->sys_setup[dev_desc->event_offset];
+ u16 *tpad_setup = iqs7222->tpad_setup;
+ unsigned int chan_sel[12];
+
+ error = iqs7222_parse_props(iqs7222, tpad_node, tpad_index,
+ IQS7222_REG_GRP_TPAD,
+ IQS7222_REG_KEY_NONE);
+ if (error)
+ return error;
+
+ count = fwnode_property_count_u32(tpad_node, "azoteq,channel-select");
+ if (count < 0) {
+ dev_err(&client->dev, "Failed to count %s channels: %d\n",
+ fwnode_get_name(tpad_node), count);
+ return count;
+ } else if (!count || count > ARRAY_SIZE(chan_sel)) {
+ dev_err(&client->dev, "Invalid number of %s channels\n",
+ fwnode_get_name(tpad_node));
+ return -EINVAL;
+ }
+
+ error = fwnode_property_read_u32_array(tpad_node,
+ "azoteq,channel-select",
+ chan_sel, count);
+ if (error) {
+ dev_err(&client->dev, "Failed to read %s channels: %d\n",
+ fwnode_get_name(tpad_node), error);
+ return error;
+ }
+
+ tpad_setup[6] &= ~GENMASK(num_chan - 1, 0);
+
+ for (i = 0; i < ARRAY_SIZE(chan_sel); i++) {
+ tpad_setup[8 + i] = 0;
+ if (i >= count || chan_sel[i] == U8_MAX)
+ continue;
+
+ if (chan_sel[i] >= num_chan) {
+ dev_err(&client->dev, "Invalid %s channel: %u\n",
+ fwnode_get_name(tpad_node), chan_sel[i]);
+ return -EINVAL;
+ }
+
+ /*
+ * The following fields indicate which channels participate in
+ * the trackpad, as well as each channel's relative placement.
+ */
+ tpad_setup[6] |= BIT(chan_sel[i]);
+ tpad_setup[8 + i] = chan_sel[i] * 34 + 1072;
+ }
+
+ tpad_setup[7] = dev_desc->touch_link;
+ if (fwnode_property_present(tpad_node, "azoteq,use-prox"))
+ tpad_setup[7] -= 2;
+
+ for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++)
+ tpad_setup[20] &= ~(iqs7222_tp_events[i].strict |
+ iqs7222_tp_events[i].enable);
+
+ for (i = 0; i < ARRAY_SIZE(iqs7222_tp_events); i++) {
+ const char *event_name = iqs7222_tp_events[i].name;
+
+ struct fwnode_handle *event_node __free(fwnode_handle) =
+ fwnode_get_named_child_node(tpad_node, event_name);
+ if (!event_node)
+ continue;
+
+ if (fwnode_property_present(event_node,
+ "azoteq,gesture-angle-tighten"))
+ tpad_setup[20] |= iqs7222_tp_events[i].strict;
+
+ tpad_setup[20] |= iqs7222_tp_events[i].enable;
+
+ error = iqs7222_parse_event(iqs7222, event_node, tpad_index,
+ IQS7222_REG_GRP_TPAD,
+ iqs7222_tp_events[i].reg_key,
+ iqs7222_tp_events[i].link, 1566,
+ NULL,
+ &iqs7222->tp_code[i]);
+ if (error)
+ return error;
+
+ if (!dev_desc->event_offset)
+ continue;
+
+ /*
+ * The press/release event is determined based on whether the
+ * coordinate fields report 0xFFFF and solely relies on touch
+ * or proximity interrupts to be unmasked.
+ */
+ if (i)
+ *event_mask |= IQS7222_EVENT_MASK_TPAD;
+ else if (tpad_setup[7] == dev_desc->touch_link)
+ *event_mask |= IQS7222_EVENT_MASK_TOUCH;
+ else
+ *event_mask |= IQS7222_EVENT_MASK_PROX;
+ }
+
+ if (!iqs7222->tp_code[0])
+ return 0;
+
+ input_set_abs_params(iqs7222->keypad, ABS_X,
+ 0, (tpad_setup[4] ? : 1) - 1, 0, 0);
+
+ input_set_abs_params(iqs7222->keypad, ABS_Y,
+ 0, (tpad_setup[5] ? : 1) - 1, 0, 0);
+
+ touchscreen_parse_properties(iqs7222->keypad, false, prop);
+
+ if (prop->max_x >= U16_MAX || prop->max_y >= U16_MAX) {
+ dev_err(&client->dev, "Invalid trackpad size: %u*%u\n",
+ prop->max_x, prop->max_y);
+ return -EINVAL;
+ }
+
+ tpad_setup[4] = prop->max_x + 1;
+ tpad_setup[5] = prop->max_y + 1;
+
+ return 0;
+}
+
+static int (*iqs7222_parse_extra[IQS7222_NUM_REG_GRPS])
+ (struct iqs7222_private *iqs7222,
+ struct fwnode_handle *reg_grp_node,
+ int reg_grp_index) = {
+ [IQS7222_REG_GRP_CYCLE] = iqs7222_parse_cycle,
+ [IQS7222_REG_GRP_CHAN] = iqs7222_parse_chan,
+ [IQS7222_REG_GRP_SLDR] = iqs7222_parse_sldr,
+ [IQS7222_REG_GRP_TPAD] = iqs7222_parse_tpad,
+};
+
+static int iqs7222_parse_reg_grp(struct iqs7222_private *iqs7222,
+ enum iqs7222_reg_grp_id reg_grp,
+ int reg_grp_index)
+{
+ struct i2c_client *client = iqs7222->client;
+ int error;
+
+ struct fwnode_handle *reg_grp_node __free(fwnode_handle) = NULL;
+ if (iqs7222_reg_grp_names[reg_grp]) {
+ char reg_grp_name[16];
+
+ snprintf(reg_grp_name, sizeof(reg_grp_name),
+ iqs7222_reg_grp_names[reg_grp], reg_grp_index);
+
+ reg_grp_node = device_get_named_child_node(&client->dev,
+ reg_grp_name);
+ } else {
+ reg_grp_node = fwnode_handle_get(dev_fwnode(&client->dev));
+ }
+
+ if (!reg_grp_node)
+ return 0;
+
+ error = iqs7222_parse_props(iqs7222, reg_grp_node, reg_grp_index,
+ reg_grp, IQS7222_REG_KEY_NONE);
+ if (error)
+ return error;
+
+ if (iqs7222_parse_extra[reg_grp]) {
+ error = iqs7222_parse_extra[reg_grp](iqs7222, reg_grp_node,
+ reg_grp_index);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static int iqs7222_parse_all(struct iqs7222_private *iqs7222)
+{
+ const struct iqs7222_dev_desc *dev_desc = iqs7222->dev_desc;
+ const struct iqs7222_reg_grp_desc *reg_grps = dev_desc->reg_grps;
+ u16 *sys_setup = iqs7222->sys_setup;
+ int error, i, j;
+
+ if (dev_desc->allow_offset)
+ sys_setup[dev_desc->allow_offset] = U16_MAX;
+
+ if (dev_desc->event_offset)
+ sys_setup[dev_desc->event_offset] = IQS7222_EVENT_MASK_ATI;
+
+ for (i = 0; i < reg_grps[IQS7222_REG_GRP_GPIO].num_row; i++) {
+ u16 *gpio_setup = iqs7222->gpio_setup[i];
+
+ gpio_setup[0] &= ~IQS7222_GPIO_SETUP_0_GPIO_EN;
+ gpio_setup[1] = 0;
+ gpio_setup[2] = 0;
+
+ if (reg_grps[IQS7222_REG_GRP_GPIO].num_row == 1)
+ continue;
+
+ /*
+ * The IQS7222C and IQS7222D expose multiple GPIO and must be
+ * informed as to which GPIO this group represents.
+ */
+ for (j = 0; j < ARRAY_SIZE(iqs7222_gpio_links); j++)
+ gpio_setup[0] &= ~BIT(iqs7222_gpio_links[j]);
+
+ gpio_setup[0] |= BIT(iqs7222_gpio_links[i]);
+ }
+
+ for (i = 0; i < reg_grps[IQS7222_REG_GRP_CHAN].num_row; i++) {
+ u16 *chan_setup = iqs7222->chan_setup[i];
+
+ chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_REF_MODE_MASK;
+ chan_setup[0] &= ~IQS7222_CHAN_SETUP_0_CHAN_EN;
+
+ chan_setup[5] = 0;
+ }
+
+ for (i = 0; i < reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
+ u16 *sldr_setup = iqs7222->sldr_setup[i];
+
+ sldr_setup[0] &= ~IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK;
+ }
+
+ for (i = 0; i < IQS7222_NUM_REG_GRPS; i++) {
+ for (j = 0; j < reg_grps[i].num_row; j++) {
+ error = iqs7222_parse_reg_grp(iqs7222, i, j);
+ if (error)
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static int iqs7222_report(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 num_stat = dev_desc->reg_grps[IQS7222_REG_GRP_STAT].num_col;
+ int error, i, j;
+ __le16 status[IQS7222_MAX_COLS_STAT];
+
+ error = iqs7222_read_burst(iqs7222, IQS7222_SYS_STATUS, status,
+ num_stat * sizeof(*status));
+ if (error)
+ return error;
+
+ if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_RESET) {
+ dev_err(&client->dev, "Unexpected device reset\n");
+ return iqs7222_dev_init(iqs7222, WRITE);
+ }
+
+ if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ERROR) {
+ dev_err(&client->dev, "Unexpected ATI error\n");
+ return iqs7222_ati_trigger(iqs7222);
+ }
+
+ if (le16_to_cpu(status[0]) & IQS7222_SYS_STATUS_ATI_ACTIVE)
+ return 0;
+
+ for (i = 0; i < num_chan; i++) {
+ u16 *chan_setup = iqs7222->chan_setup[i];
+
+ if (!(chan_setup[0] & IQS7222_CHAN_SETUP_0_CHAN_EN))
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(iqs7222_kp_events); j++) {
+ /*
+ * Proximity state begins at offset 2 and spills into
+ * offset 3 for devices with more than 16 channels.
+ *
+ * Touch state begins at the first offset immediately
+ * following proximity state.
+ */
+ int k = 2 + j * (num_chan > 16 ? 2 : 1);
+ u16 state = le16_to_cpu(status[k + i / 16]);
+
+ if (!iqs7222->kp_type[i][j])
+ continue;
+
+ input_event(iqs7222->keypad,
+ iqs7222->kp_type[i][j],
+ iqs7222->kp_code[i][j],
+ !!(state & BIT(i % 16)));
+ }
+ }
+
+ for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_SLDR].num_row; i++) {
+ u16 *sldr_setup = iqs7222->sldr_setup[i];
+ u16 sldr_pos = le16_to_cpu(status[4 + i]);
+ u16 state = le16_to_cpu(status[6 + i]);
+
+ if (!(sldr_setup[0] & IQS7222_SLDR_SETUP_0_CHAN_CNT_MASK))
+ continue;
+
+ if (sldr_pos < dev_desc->sldr_res)
+ input_report_abs(iqs7222->keypad, iqs7222->sl_axis[i],
+ sldr_pos);
+
+ input_report_key(iqs7222->keypad, iqs7222->sl_code[i][0],
+ sldr_pos < dev_desc->sldr_res);
+
+ /*
+ * A maximum resolution indicates the device does not support
+ * gestures, in which case the remaining fields are ignored.
+ */
+ if (dev_desc->sldr_res == U16_MAX)
+ continue;
+
+ if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_SLDR << i))
+ continue;
+
+ /*
+ * Skip the press/release event, as it does not have separate
+ * status fields and is handled separately.
+ */
+ for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++) {
+ u16 mask = iqs7222_sl_events[j].mask;
+ u16 val = iqs7222_sl_events[j].val;
+
+ input_report_key(iqs7222->keypad,
+ iqs7222->sl_code[i][j],
+ (state & mask) == val);
+ }
+
+ input_sync(iqs7222->keypad);
+
+ for (j = 1; j < ARRAY_SIZE(iqs7222_sl_events); j++)
+ input_report_key(iqs7222->keypad,
+ iqs7222->sl_code[i][j], 0);
+ }
+
+ for (i = 0; i < dev_desc->reg_grps[IQS7222_REG_GRP_TPAD].num_row; i++) {
+ u16 tpad_pos_x = le16_to_cpu(status[4]);
+ u16 tpad_pos_y = le16_to_cpu(status[5]);
+ u16 state = le16_to_cpu(status[6]);
+
+ input_report_key(iqs7222->keypad, iqs7222->tp_code[0],
+ tpad_pos_x < U16_MAX);
+
+ if (tpad_pos_x < U16_MAX)
+ touchscreen_report_pos(iqs7222->keypad, &iqs7222->prop,
+ tpad_pos_x, tpad_pos_y, false);
+
+ if (!(le16_to_cpu(status[1]) & IQS7222_EVENT_MASK_TPAD))
+ continue;
+
+ /*
+ * Skip the press/release event, as it does not have separate
+ * status fields and is handled separately.
+ */
+ for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++) {
+ u16 mask = iqs7222_tp_events[j].mask;
+ u16 val = iqs7222_tp_events[j].val;
+
+ input_report_key(iqs7222->keypad,
+ iqs7222->tp_code[j],
+ (state & mask) == val);
+ }
+
+ input_sync(iqs7222->keypad);
+
+ for (j = 1; j < ARRAY_SIZE(iqs7222_tp_events); j++)
+ input_report_key(iqs7222->keypad,
+ iqs7222->tp_code[j], 0);
+ }
+
+ input_sync(iqs7222->keypad);
+
+ return 0;
+}
+
+static irqreturn_t iqs7222_irq(int irq, void *context)
+{
+ struct iqs7222_private *iqs7222 = context;
+
+ return iqs7222_report(iqs7222) ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int iqs7222_probe(struct i2c_client *client)
+{
+ struct iqs7222_private *iqs7222;
+ unsigned long irq_flags;
+ int error, irq;
+
+ iqs7222 = devm_kzalloc(&client->dev, sizeof(*iqs7222), GFP_KERNEL);
+ if (!iqs7222)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, iqs7222);
+ iqs7222->client = client;
+
+ iqs7222->keypad = devm_input_allocate_device(&client->dev);
+ if (!iqs7222->keypad)
+ return -ENOMEM;
+
+ iqs7222->keypad->name = client->name;
+ iqs7222->keypad->id.bustype = BUS_I2C;
+
+ /*
+ * The RDY pin behaves as an interrupt, but must also be polled ahead
+ * of unsolicited I2C communication. As such, it is first opened as a
+ * GPIO and then passed to gpiod_to_irq() to register the interrupt.
+ */
+ iqs7222->irq_gpio = devm_gpiod_get(&client->dev, "irq", GPIOD_IN);
+ if (IS_ERR(iqs7222->irq_gpio)) {
+ error = PTR_ERR(iqs7222->irq_gpio);
+ dev_err(&client->dev, "Failed to request IRQ GPIO: %d\n",
+ error);
+ return error;
+ }
+
+ iqs7222->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(iqs7222->reset_gpio)) {
+ error = PTR_ERR(iqs7222->reset_gpio);
+ dev_err(&client->dev, "Failed to request reset GPIO: %d\n",
+ error);
+ return error;
+ }
+
+ error = iqs7222_hard_reset(iqs7222);
+ if (error)
+ return error;
+
+ error = iqs7222_dev_info(iqs7222);
+ if (error)
+ return error;
+
+ error = iqs7222_dev_init(iqs7222, READ);
+ if (error)
+ return error;
+
+ error = iqs7222_parse_all(iqs7222);
+ if (error)
+ return error;
+
+ error = iqs7222_dev_init(iqs7222, WRITE);
+ if (error)
+ return error;
+
+ error = iqs7222_report(iqs7222);
+ if (error)
+ return error;
+
+ error = input_register_device(iqs7222->keypad);
+ if (error) {
+ dev_err(&client->dev, "Failed to register device: %d\n", error);
+ return error;
+ }
+
+ irq = gpiod_to_irq(iqs7222->irq_gpio);
+ if (irq < 0)
+ return irq;
+
+ irq_flags = gpiod_is_active_low(iqs7222->irq_gpio) ? IRQF_TRIGGER_LOW
+ : IRQF_TRIGGER_HIGH;
+ irq_flags |= IRQF_ONESHOT;
+
+ error = devm_request_threaded_irq(&client->dev, irq, NULL, iqs7222_irq,
+ irq_flags, client->name, iqs7222);
+ if (error)
+ dev_err(&client->dev, "Failed to request IRQ: %d\n", error);
+
+ return error;
+}
+
+static const struct of_device_id iqs7222_of_match[] = {
+ { .compatible = "azoteq,iqs7222a" },
+ { .compatible = "azoteq,iqs7222b" },
+ { .compatible = "azoteq,iqs7222c" },
+ { .compatible = "azoteq,iqs7222d" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, iqs7222_of_match);
+
+static struct i2c_driver iqs7222_i2c_driver = {
+ .driver = {
+ .name = "iqs7222",
+ .of_match_table = iqs7222_of_match,
+ },
+ .probe = iqs7222_probe,
+};
+module_i2c_driver(iqs7222_i2c_driver);
+
+MODULE_AUTHOR("Jeff LaBundy <jeff@labundy.com>");
+MODULE_DESCRIPTION("Azoteq IQS7222A/B/C/D Capacitive Touch Controller");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
deleted file mode 100644
index 05018d0c97c7..000000000000
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ /dev/null
@@ -1,183 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Generic IXP4xx beeper driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nslu2-io.c
- * Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- */
-
-#include <linux/module.h>
-#include <linux/input.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <mach/hardware.h>
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("ixp4xx beeper driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ixp4xx-beeper");
-
-static DEFINE_SPINLOCK(beep_lock);
-
-static int ixp4xx_timer2_irq;
-
-static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&beep_lock, flags);
-
- if (count) {
- gpio_direction_output(pin, 0);
- *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
- } else {
- gpio_direction_output(pin, 1);
- gpio_direction_input(pin);
- *IXP4XX_OSRT2 = 0;
- }
-
- spin_unlock_irqrestore(&beep_lock, flags);
-}
-
-static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- unsigned int pin = (unsigned int) input_get_drvdata(dev);
- unsigned int count = 0;
-
- if (type != EV_SND)
- return -1;
-
- switch (code) {
- case SND_BELL:
- if (value)
- value = 1000;
- case SND_TONE:
- break;
- default:
- return -1;
- }
-
- if (value > 20 && value < 32767)
- count = (ixp4xx_timer_freq / (value * 4)) - 1;
-
- ixp4xx_spkr_control(pin, count);
-
- return 0;
-}
-
-static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
-{
- unsigned int pin = (unsigned int) dev_id;
-
- /* clear interrupt */
- *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
-
- /* flip the beeper output */
- gpio_set_value(pin, !gpio_get_value(pin));
-
- return IRQ_HANDLED;
-}
-
-static int ixp4xx_spkr_probe(struct platform_device *dev)
-{
- struct input_dev *input_dev;
- int irq;
- int err;
-
- input_dev = input_allocate_device();
- if (!input_dev)
- return -ENOMEM;
-
- input_set_drvdata(input_dev, (void *) dev->id);
-
- input_dev->name = "ixp4xx beeper";
- input_dev->phys = "ixp4xx/gpio";
- input_dev->id.bustype = BUS_HOST;
- input_dev->id.vendor = 0x001f;
- input_dev->id.product = 0x0001;
- input_dev->id.version = 0x0100;
- input_dev->dev.parent = &dev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_SND);
- input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
- input_dev->event = ixp4xx_spkr_event;
-
- irq = platform_get_irq(dev, 0);
- if (irq < 0) {
- err = irq;
- goto err_free_device;
- }
-
- err = gpio_request(dev->id, "ixp4-beeper");
- if (err)
- goto err_free_device;
-
- err = request_irq(irq, &ixp4xx_spkr_interrupt,
- IRQF_NO_SUSPEND, "ixp4xx-beeper",
- (void *) dev->id);
- if (err)
- goto err_free_gpio;
- ixp4xx_timer2_irq = irq;
-
- err = input_register_device(input_dev);
- if (err)
- goto err_free_irq;
-
- platform_set_drvdata(dev, input_dev);
-
- return 0;
-
- err_free_irq:
- free_irq(irq, (void *)dev->id);
- err_free_gpio:
- gpio_free(dev->id);
- err_free_device:
- input_free_device(input_dev);
-
- return err;
-}
-
-static int ixp4xx_spkr_remove(struct platform_device *dev)
-{
- struct input_dev *input_dev = platform_get_drvdata(dev);
- unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
-
- input_unregister_device(input_dev);
-
- /* turn the speaker off */
- disable_irq(ixp4xx_timer2_irq);
- ixp4xx_spkr_control(pin, 0);
-
- free_irq(ixp4xx_timer2_irq, (void *)dev->id);
- gpio_free(dev->id);
-
- return 0;
-}
-
-static void ixp4xx_spkr_shutdown(struct platform_device *dev)
-{
- struct input_dev *input_dev = platform_get_drvdata(dev);
- unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
-
- /* turn off the speaker */
- disable_irq(ixp4xx_timer2_irq);
- ixp4xx_spkr_control(pin, 0);
-}
-
-static struct platform_driver ixp4xx_spkr_platform_driver = {
- .driver = {
- .name = "ixp4xx-beeper",
- },
- .probe = ixp4xx_spkr_probe,
- .remove = ixp4xx_spkr_remove,
- .shutdown = ixp4xx_spkr_shutdown,
-};
-module_platform_driver(ixp4xx_spkr_platform_driver);
-
diff --git a/drivers/input/misc/keyspan_remote.c b/drivers/input/misc/keyspan_remote.c
index 4650f4a94989..bee4b1376491 100644
--- a/drivers/input/misc/keyspan_remote.c
+++ b/drivers/input/misc/keyspan_remote.c
@@ -485,7 +485,7 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
}
if (udev->manufacturer)
- strlcpy(remote->name, udev->manufacturer, sizeof(remote->name));
+ strscpy(remote->name, udev->manufacturer, sizeof(remote->name));
if (udev->product) {
if (udev->manufacturer)
diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c
index bbb81617c2b2..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,22 +325,30 @@ 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;
}
static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll);
-static struct attribute *kxtj9_attributes[] = {
+static struct attribute *kxtj9_attrs[] = {
&dev_attr_poll.attr,
NULL
};
-static struct attribute_group kxtj9_attribute_group = {
- .attrs = kxtj9_attributes
+static umode_t kxtj9_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int n)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct i2c_client *client = to_i2c_client(dev);
+
+ return client->irq ? attr->mode : 0;
+}
+
+static struct attribute_group kxtj9_group = {
+ .attrs = kxtj9_attrs,
+ .is_visible = kxtj9_attr_is_visible,
};
+__ATTRIBUTE_GROUPS(kxtj9);
static void kxtj9_poll(struct input_dev *input)
{
@@ -385,8 +392,7 @@ out:
return retval;
}
-static int kxtj9_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int kxtj9_probe(struct i2c_client *client)
{
const struct kxtj9_platform_data *pdata =
dev_get_platdata(&client->dev);
@@ -483,61 +489,53 @@ static int kxtj9_probe(struct i2c_client *client,
dev_err(&client->dev, "request irq failed: %d\n", err);
return err;
}
-
- err = devm_device_add_group(&client->dev,
- &kxtj9_attribute_group);
- if (err) {
- dev_err(&client->dev, "sysfs create failed: %d\n", err);
- return err;
- }
}
return 0;
}
-static int __maybe_unused kxtj9_suspend(struct device *dev)
+static int kxtj9_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(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;
}
-static int __maybe_unused kxtj9_resume(struct device *dev)
+static int kxtj9_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(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;
}
-static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume);
static const struct i2c_device_id kxtj9_id[] = {
- { NAME, 0 },
- { },
+ { NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, kxtj9_id);
static struct i2c_driver kxtj9_driver = {
.driver = {
- .name = NAME,
- .pm = &kxtj9_pm_ops,
+ .name = NAME,
+ .dev_groups = kxtj9_groups,
+ .pm = pm_sleep_ptr(&kxtj9_pm_ops),
},
.probe = kxtj9_probe,
.id_table = kxtj9_id,
diff --git a/drivers/input/misc/m68kspkr.c b/drivers/input/misc/m68kspkr.c
index 25fcf1467151..0542334df624 100644
--- a/drivers/input/misc/m68kspkr.c
+++ b/drivers/input/misc/m68kspkr.c
@@ -75,15 +75,13 @@ static int m68kspkr_probe(struct platform_device *dev)
return 0;
}
-static int m68kspkr_remove(struct platform_device *dev)
+static void m68kspkr_remove(struct platform_device *dev)
{
struct input_dev *input_dev = platform_get_drvdata(dev);
input_unregister_device(input_dev);
/* turn off the speaker */
m68kspkr_event(NULL, EV_SND, SND_BELL, 0);
-
- return 0;
}
static void m68kspkr_shutdown(struct platform_device *dev)
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 0d09ffeafeea..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,
@@ -307,11 +317,12 @@ static int max77693_haptic_probe(struct platform_device *pdev)
haptic->suspend_state = false;
/* Variant-specific init */
- haptic->dev_type = platform_get_device_id(pdev)->driver_data;
+ haptic->dev_type = max77693->type;
switch (haptic->dev_type) {
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");
@@ -375,7 +380,7 @@ static int max77693_haptic_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused max77693_haptic_suspend(struct device *dev)
+static int max77693_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max77693_haptic *haptic = platform_get_drvdata(pdev);
@@ -388,7 +393,7 @@ static int __maybe_unused max77693_haptic_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused max77693_haptic_resume(struct device *dev)
+static int max77693_haptic_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max77693_haptic *haptic = platform_get_drvdata(pdev);
@@ -401,20 +406,31 @@ static int __maybe_unused max77693_haptic_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
- max77693_haptic_suspend, max77693_haptic_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
+ max77693_haptic_suspend,
+ max77693_haptic_resume);
static const struct platform_device_id max77693_haptic_id[] = {
- { "max77693-haptic", TYPE_MAX77693 },
- { "max77843-haptic", TYPE_MAX77843 },
+ { "max77693-haptic", },
+ { "max77705-haptic", },
+ { "max77843-haptic", },
{},
};
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 */ },
+};
+MODULE_DEVICE_TABLE(of, of_max77693_haptic_dt_match);
+
static struct platform_driver max77693_haptic_driver = {
.driver = {
.name = "max77693-haptic",
- .pm = &max77693_haptic_pm_ops,
+ .pm = pm_sleep_ptr(&max77693_haptic_pm_ops),
+ .of_match_table = of_max77693_haptic_dt_match,
},
.probe = max77693_haptic_probe,
.id_table = max77693_haptic_id,
@@ -423,6 +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_ALIAS("platform:max77693-haptic");
+MODULE_DESCRIPTION("MAXIM 77693/77705/77843 Haptic driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/max8925_onkey.c b/drivers/input/misc/max8925_onkey.c
index ffab4a490c75..62619e4fed20 100644
--- a/drivers/input/misc/max8925_onkey.c
+++ b/drivers/input/misc/max8925_onkey.c
@@ -1,4 +1,4 @@
-/**
+/*
* MAX8925 ONKEY driver
*
* Copyright (C) 2009 Marvell International Ltd.
@@ -129,7 +129,7 @@ static int max8925_onkey_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused max8925_onkey_suspend(struct device *dev)
+static int max8925_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
@@ -143,7 +143,7 @@ static int __maybe_unused max8925_onkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused max8925_onkey_resume(struct device *dev)
+static int max8925_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8925_onkey_info *info = platform_get_drvdata(pdev);
@@ -157,12 +157,13 @@ static int __maybe_unused max8925_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops, max8925_onkey_suspend, max8925_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(max8925_onkey_pm_ops,
+ max8925_onkey_suspend, max8925_onkey_resume);
static struct platform_driver max8925_onkey_driver = {
.driver = {
.name = "max8925-onkey",
- .pm = &max8925_onkey_pm_ops,
+ .pm = pm_sleep_ptr(&max8925_onkey_pm_ops),
},
.probe = max8925_onkey_probe,
};
diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c
index cd5e99ec1d3c..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");
@@ -278,8 +276,7 @@ static int max8997_haptic_probe(struct platform_device *pdev)
break;
case MAX8997_EXTERNAL_MODE:
- chip->pwm = pwm_request(haptic_pdata->pwm_channel_id,
- "max8997-haptic");
+ chip->pwm = pwm_get(&pdev->dev, NULL);
if (IS_ERR(chip->pwm)) {
error = PTR_ERR(chip->pwm);
dev_err(&pdev->dev,
@@ -288,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:
@@ -344,7 +336,7 @@ err_put_regulator:
regulator_put(chip->regulator);
err_free_pwm:
if (chip->mode == MAX8997_EXTERNAL_MODE)
- pwm_free(chip->pwm);
+ pwm_put(chip->pwm);
err_free_mem:
input_free_device(input_dev);
kfree(chip);
@@ -352,7 +344,7 @@ err_free_mem:
return error;
}
-static int max8997_haptic_remove(struct platform_device *pdev)
+static void max8997_haptic_remove(struct platform_device *pdev)
{
struct max8997_haptic *chip = platform_get_drvdata(pdev);
@@ -360,14 +352,12 @@ static int max8997_haptic_remove(struct platform_device *pdev)
regulator_put(chip->regulator);
if (chip->mode == MAX8997_EXTERNAL_MODE)
- pwm_free(chip->pwm);
+ pwm_put(chip->pwm);
kfree(chip);
-
- return 0;
}
-static int __maybe_unused max8997_haptic_suspend(struct device *dev)
+static int max8997_haptic_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct max8997_haptic *chip = platform_get_drvdata(pdev);
@@ -377,7 +367,8 @@ static int __maybe_unused max8997_haptic_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops, max8997_haptic_suspend, NULL);
+static DEFINE_SIMPLE_DEV_PM_OPS(max8997_haptic_pm_ops,
+ max8997_haptic_suspend, NULL);
static const struct platform_device_id max8997_haptic_id[] = {
{ "max8997-haptic", 0 },
@@ -388,7 +379,7 @@ MODULE_DEVICE_TABLE(platform, max8997_haptic_id);
static struct platform_driver max8997_haptic_driver = {
.driver = {
.name = "max8997-haptic",
- .pm = &max8997_haptic_pm_ops,
+ .pm = pm_sleep_ptr(&max8997_haptic_pm_ops),
},
.probe = max8997_haptic_probe,
.remove = max8997_haptic_remove,
diff --git a/drivers/input/misc/mc13783-pwrbutton.c b/drivers/input/misc/mc13783-pwrbutton.c
index 0636eee4bb6c..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) {
@@ -229,7 +228,7 @@ free_input_dev:
return err;
}
-static int mc13783_pwrbutton_remove(struct platform_device *pdev)
+static void mc13783_pwrbutton_remove(struct platform_device *pdev)
{
struct mc13783_pwrb *priv = platform_get_drvdata(pdev);
const struct mc13xxx_buttons_platform_data *pdata;
@@ -249,8 +248,6 @@ static int mc13783_pwrbutton_remove(struct platform_device *pdev)
input_unregister_device(priv->pwr);
kfree(priv);
-
- return 0;
}
static struct platform_driver mc13783_pwrbutton_driver = {
diff --git a/drivers/input/misc/mma8450.c b/drivers/input/misc/mma8450.c
index 1b5a5e19230a..0c661140fb88 100644
--- a/drivers/input/misc/mma8450.c
+++ b/drivers/input/misc/mma8450.c
@@ -11,7 +11,7 @@
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/input.h>
-#include <linux/of_device.h>
+#include <linux/mod_devicetable.h>
#define MMA8450_DRV_NAME "mma8450"
@@ -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)
{
@@ -146,11 +148,22 @@ static void mma8450_close(struct input_dev *input)
/*
* I2C init/probing/exit functions
*/
-static int mma8450_probe(struct i2c_client *c,
- const struct i2c_device_id *id)
+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)
@@ -187,8 +200,8 @@ static int mma8450_probe(struct i2c_client *c,
}
static const struct i2c_device_id mma8450_id[] = {
- { MMA8450_DRV_NAME, 0 },
- { },
+ { MMA8450_DRV_NAME },
+ { }
};
MODULE_DEVICE_TABLE(i2c, mma8450_id);
diff --git a/drivers/input/misc/nxp-bbnsm-pwrkey.c b/drivers/input/misc/nxp-bbnsm-pwrkey.c
new file mode 100644
index 000000000000..0c7b8f8ef4a5
--- /dev/null
+++ b/drivers/input/misc/nxp-bbnsm-pwrkey.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+//
+// Copyright 2022 NXP.
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+
+#define BBNSM_CTRL 0x8
+#define BBNSM_INT_EN 0x10
+#define BBNSM_EVENTS 0x14
+#define BBNSM_PAD_CTRL 0x24
+
+#define BBNSM_BTN_PRESSED BIT(7)
+#define BBNSM_PWR_ON BIT(6)
+#define BBNSM_BTN_OFF BIT(5)
+#define BBNSM_EMG_OFF BIT(4)
+#define BBNSM_PWRKEY_EVENTS (BBNSM_PWR_ON | BBNSM_BTN_OFF | BBNSM_EMG_OFF)
+#define BBNSM_DP_EN BIT(24)
+
+#define DEBOUNCE_TIME 30
+#define REPEAT_INTERVAL 60
+
+struct bbnsm_pwrkey {
+ struct regmap *regmap;
+ int irq;
+ int keycode;
+ int keystate; /* 1:pressed */
+ 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 = timer_container_of(bbnsm, t, check_timer);
+ struct input_dev *input = bbnsm->input;
+ u32 state;
+
+ regmap_read(bbnsm->regmap, BBNSM_EVENTS, &state);
+
+ state = state & BBNSM_BTN_PRESSED ? 1 : 0;
+
+ /* only report new event if status changed */
+ if (state ^ bbnsm->keystate) {
+ bbnsm->keystate = state;
+ input_event(input, EV_KEY, bbnsm->keycode, state);
+ input_sync(input);
+ pm_relax(bbnsm->input->dev.parent);
+ }
+
+ /* repeat check if pressed long */
+ if (state)
+ mod_timer(&bbnsm->check_timer,
+ jiffies + msecs_to_jiffies(REPEAT_INTERVAL));
+}
+
+static irqreturn_t bbnsm_pwrkey_interrupt(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct bbnsm_pwrkey *bbnsm = platform_get_drvdata(pdev);
+ struct input_dev *input = bbnsm->input;
+ u32 event;
+
+ regmap_read(bbnsm->regmap, BBNSM_EVENTS, &event);
+ if (!(event & BBNSM_BTN_OFF))
+ return IRQ_NONE;
+
+ pm_wakeup_event(bbnsm->input->dev.parent, 0);
+
+ /*
+ * 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));
+
+ /* clear PWR OFF */
+ regmap_write(bbnsm->regmap, BBNSM_EVENTS, BBNSM_BTN_OFF);
+
+ return IRQ_HANDLED;
+}
+
+static void bbnsm_pwrkey_act(void *pdata)
+{
+ struct bbnsm_pwrkey *bbnsm = pdata;
+
+ timer_shutdown_sync(&bbnsm->check_timer);
+}
+
+static int bbnsm_pwrkey_probe(struct platform_device *pdev)
+{
+ struct bbnsm_pwrkey *bbnsm;
+ struct input_dev *input;
+ struct device_node *np = pdev->dev.of_node;
+ int error;
+
+ bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL);
+ if (!bbnsm)
+ return -ENOMEM;
+
+ bbnsm->regmap = syscon_node_to_regmap(np->parent);
+ if (IS_ERR(bbnsm->regmap)) {
+ dev_err(&pdev->dev, "bbnsm pwerkey get regmap failed\n");
+ return PTR_ERR(bbnsm->regmap);
+ }
+
+ if (device_property_read_u32(&pdev->dev, "linux,code",
+ &bbnsm->keycode)) {
+ bbnsm->keycode = KEY_POWER;
+ dev_warn(&pdev->dev, "key code is not specified, using default KEY_POWER\n");
+ }
+
+ bbnsm->irq = platform_get_irq(pdev, 0);
+ if (bbnsm->irq < 0)
+ return -EINVAL;
+
+ /* config the BBNSM power related register */
+ regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, BBNSM_DP_EN, BBNSM_DP_EN);
+
+ /* clear the unexpected interrupt before driver ready */
+ regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, BBNSM_PWRKEY_EVENTS,
+ BBNSM_PWRKEY_EVENTS);
+
+ timer_setup(&bbnsm->check_timer, bbnsm_pwrkey_check_for_events, 0);
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input) {
+ dev_err(&pdev->dev, "failed to allocate the input device\n");
+ return -ENOMEM;
+ }
+
+ input->name = pdev->name;
+ input->phys = "bbnsm-pwrkey/input0";
+ input->id.bustype = BUS_HOST;
+
+ input_set_capability(input, EV_KEY, bbnsm->keycode);
+
+ /* input customer action to cancel release timer */
+ error = devm_add_action(&pdev->dev, bbnsm_pwrkey_act, bbnsm);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register remove action\n");
+ return error;
+ }
+
+ bbnsm->input = input;
+ platform_set_drvdata(pdev, bbnsm);
+
+ error = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_pwrkey_interrupt,
+ IRQF_SHARED, pdev->name, pdev);
+ if (error) {
+ dev_err(&pdev->dev, "interrupt not available.\n");
+ return error;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ return error;
+ }
+
+ device_init_wakeup(&pdev->dev, true);
+ error = dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq);
+ if (error)
+ dev_warn(&pdev->dev, "irq wake enable failed.\n");
+
+ return 0;
+}
+
+static 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 */ }
+};
+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);
+
+MODULE_AUTHOR("Jacky Bai <ping.bai@nxp.com>");
+MODULE_DESCRIPTION("NXP bbnsm power key Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/palmas-pwrbutton.c b/drivers/input/misc/palmas-pwrbutton.c
index 1e1baed63929..39fc451c56e9 100644
--- a/drivers/input/misc/palmas-pwrbutton.c
+++ b/drivers/input/misc/palmas-pwrbutton.c
@@ -1,20 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Texas Instruments' Palmas Power Button Input Driver
*
* Copyright (C) 2012-2014 Texas Instruments Incorporated - http://www.ti.com/
* Girish S Ghongdemath
* Nishanth Menon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
+#include <linux/bitfield.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -115,8 +108,8 @@ static void palmas_pwron_params_ofinit(struct device *dev,
struct device_node *np;
u32 val;
int i, error;
- u8 lpk_times[] = { 6, 8, 10, 12 };
- int pwr_on_deb_ms[] = { 15, 100, 500, 1000 };
+ static const u8 lpk_times[] = { 6, 8, 10, 12 };
+ static const int pwr_on_deb_ms[] = { 15, 100, 500, 1000 };
memset(config, 0, sizeof(*config));
@@ -192,8 +185,8 @@ static int palmas_pwron_probe(struct platform_device *pdev)
* Setup default hardware shutdown option (long key press)
* and debounce.
*/
- val = config.long_press_time_val << __ffs(PALMAS_LPK_TIME_MASK);
- val |= config.pwron_debounce_val << __ffs(PALMAS_PWRON_DEBOUNCE_MASK);
+ val = FIELD_PREP(PALMAS_LPK_TIME_MASK, config.long_press_time_val) |
+ FIELD_PREP(PALMAS_PWRON_DEBOUNCE_MASK, config.pwron_debounce_val);
error = palmas_update_bits(palmas, PALMAS_PMU_CONTROL_BASE,
PALMAS_LONG_PRESS_KEY,
PALMAS_LPK_TIME_MASK |
@@ -210,6 +203,11 @@ static int palmas_pwron_probe(struct platform_device *pdev)
INIT_DELAYED_WORK(&pwron->input_work, palmas_power_button_work);
pwron->irq = platform_get_irq(pdev, 0);
+ if (pwron->irq < 0) {
+ error = pwron->irq;
+ goto err_free_input;
+ }
+
error = request_threaded_irq(pwron->irq, NULL, pwron_irq,
IRQF_TRIGGER_HIGH |
IRQF_TRIGGER_LOW |
@@ -247,7 +245,7 @@ err_free_mem:
*
* Return: 0
*/
-static int palmas_pwron_remove(struct platform_device *pdev)
+static void palmas_pwron_remove(struct platform_device *pdev)
{
struct palmas_pwron *pwron = platform_get_drvdata(pdev);
@@ -256,8 +254,6 @@ static int palmas_pwron_remove(struct platform_device *pdev)
input_unregister_device(pwron->input_dev);
kfree(pwron);
-
- return 0;
}
/**
@@ -268,7 +264,7 @@ static int palmas_pwron_remove(struct platform_device *pdev)
*
* Return: 0
*/
-static int __maybe_unused palmas_pwron_suspend(struct device *dev)
+static int palmas_pwron_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct palmas_pwron *pwron = platform_get_drvdata(pdev);
@@ -289,7 +285,7 @@ static int __maybe_unused palmas_pwron_suspend(struct device *dev)
*
* Return: 0
*/
-static int __maybe_unused palmas_pwron_resume(struct device *dev)
+static int palmas_pwron_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct palmas_pwron *pwron = platform_get_drvdata(pdev);
@@ -300,8 +296,8 @@ static int __maybe_unused palmas_pwron_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
- palmas_pwron_suspend, palmas_pwron_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(palmas_pwron_pm,
+ palmas_pwron_suspend, palmas_pwron_resume);
#ifdef CONFIG_OF
static const struct of_device_id of_palmas_pwr_match[] = {
@@ -318,7 +314,7 @@ static struct platform_driver palmas_pwron_driver = {
.driver = {
.name = "palmas_pwrbutton",
.of_match_table = of_match_ptr(of_palmas_pwr_match),
- .pm = &palmas_pwron_pm,
+ .pm = pm_sleep_ptr(&palmas_pwron_pm),
},
};
module_platform_driver(palmas_pwron_driver);
diff --git a/drivers/input/misc/pcap_keys.c b/drivers/input/misc/pcap_keys.c
index b5a53636d7e2..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;
@@ -99,7 +99,7 @@ fail:
return err;
}
-static int pcap_keys_remove(struct platform_device *pdev)
+static void pcap_keys_remove(struct platform_device *pdev)
{
struct pcap_keys *pcap_keys = platform_get_drvdata(pdev);
@@ -108,8 +108,6 @@ static int pcap_keys_remove(struct platform_device *pdev)
input_unregister_device(pcap_keys->input);
kfree(pcap_keys);
-
- return 0;
}
static struct platform_driver pcap_keys_device_driver = {
diff --git a/drivers/input/misc/pcf50633-input.c b/drivers/input/misc/pcf50633-input.c
deleted file mode 100644
index 4c60c70c4c10..000000000000
--- a/drivers/input/misc/pcf50633-input.c
+++ /dev/null
@@ -1,115 +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 int 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);
-
- return 0;
-}
-
-static struct platform_driver pcf50633_input_driver = {
- .driver = {
- .name = "pcf50633-input",
- },
- .probe = pcf50633_input_probe,
- .remove = 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/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c
index abc423165522..3632cb206e34 100644
--- a/drivers/input/misc/pcf8574_keypad.c
+++ b/drivers/input/misc/pcf8574_keypad.c
@@ -80,7 +80,7 @@ static irqreturn_t pcf8574_kp_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_id *id)
+static int pcf8574_kp_probe(struct i2c_client *client)
{
int i, ret;
struct input_dev *idev;
@@ -157,7 +157,7 @@ static int pcf8574_kp_probe(struct i2c_client *client, const struct i2c_device_i
return ret;
}
-static int pcf8574_kp_remove(struct i2c_client *client)
+static void pcf8574_kp_remove(struct i2c_client *client)
{
struct kp_data *lp = i2c_get_clientdata(client);
@@ -165,11 +165,8 @@ static int pcf8574_kp_remove(struct i2c_client *client)
input_unregister_device(lp->idev);
kfree(lp);
-
- return 0;
}
-#ifdef CONFIG_PM
static int pcf8574_kp_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -188,18 +185,11 @@ static int pcf8574_kp_suspend(struct device *dev)
return 0;
}
-static const struct dev_pm_ops pcf8574_kp_pm_ops = {
- .suspend = pcf8574_kp_suspend,
- .resume = pcf8574_kp_resume,
-};
-
-#else
-# define pcf8574_kp_resume NULL
-# define pcf8574_kp_suspend NULL
-#endif
+static DEFINE_SIMPLE_DEV_PM_OPS(pcf8574_kp_pm_ops,
+ pcf8574_kp_suspend, pcf8574_kp_resume);
static const struct i2c_device_id pcf8574_kp_id[] = {
- { DRV_NAME, 0 },
+ { DRV_NAME },
{ }
};
MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
@@ -207,9 +197,7 @@ MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id);
static struct i2c_driver pcf8574_kp_driver = {
.driver = {
.name = DRV_NAME,
-#ifdef CONFIG_PM
- .pm = &pcf8574_kp_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&pcf8574_kp_pm_ops),
},
.probe = pcf8574_kp_probe,
.remove = pcf8574_kp_remove,
diff --git a/drivers/input/misc/pcspkr.c b/drivers/input/misc/pcspkr.c
index 9c666b2f14fe..0467808402f2 100644
--- a/drivers/input/misc/pcspkr.c
+++ b/drivers/input/misc/pcspkr.c
@@ -95,15 +95,13 @@ static int pcspkr_probe(struct platform_device *dev)
return 0;
}
-static int pcspkr_remove(struct platform_device *dev)
+static void pcspkr_remove(struct platform_device *dev)
{
struct input_dev *pcspkr_dev = platform_get_drvdata(dev);
input_unregister_device(pcspkr_dev);
/* turn off the speaker */
pcspkr_event(NULL, EV_SND, SND_BELL, 0);
-
- return 0;
}
static int pcspkr_suspend(struct device *dev)
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 10e3fc0eac6e..53249d2c081f 100644
--- a/drivers/input/misc/pm8941-pwrkey.c
+++ b/drivers/input/misc/pm8941-pwrkey.c
@@ -9,16 +9,27 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/log2.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
+#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/reboot.h>
#include <linux/regmap.h>
#define PON_REV2 0x01
+#define PON_SUBTYPE 0x05
+
+#define PON_SUBTYPE_PRIMARY 0x01
+#define PON_SUBTYPE_SECONDARY 0x02
+#define PON_SUBTYPE_1REG 0x03
+#define PON_SUBTYPE_GEN2_PRIMARY 0x04
+#define PON_SUBTYPE_GEN2_SECONDARY 0x05
+#define PON_SUBTYPE_GEN3_PBS 0x08
+#define PON_SUBTYPE_GEN3_HLOS 0x09
+
#define PON_RT_STS 0x10
#define PON_KPDPWR_N_SET BIT(0)
#define PON_RESIN_N_SET BIT(1)
@@ -29,6 +40,7 @@
#define PON_PS_HOLD_RST_CTL2 0x5b
#define PON_PS_HOLD_ENABLE BIT(7)
#define PON_PS_HOLD_TYPE_MASK 0x0f
+#define PON_PS_HOLD_TYPE_WARM_RESET 1
#define PON_PS_HOLD_TYPE_SHUTDOWN 4
#define PON_PS_HOLD_TYPE_HARD_RESET 7
@@ -37,13 +49,18 @@
#define PON_RESIN_PULL_UP BIT(0)
#define PON_DBC_CTL 0x71
-#define PON_DBC_DELAY_MASK 0x7
+#define PON_DBC_DELAY_MASK_GEN1 0x7
+#define PON_DBC_DELAY_MASK_GEN2 0xf
+#define PON_DBC_SHIFT_GEN1 6
+#define PON_DBC_SHIFT_GEN2 14
struct pm8941_data {
unsigned int pull_up_bit;
unsigned int status_bit;
bool supports_ps_hold_poff_config;
bool supports_debounce_config;
+ bool has_pon_pbs;
+ bool wakeup_source_default;
const char *name;
const char *phys;
};
@@ -52,13 +69,18 @@ struct pm8941_pwrkey {
struct device *dev;
int irq;
u32 baseaddr;
+ u32 pon_pbs_baseaddr;
struct regmap *regmap;
struct input_dev *input;
unsigned int revision;
+ unsigned int subtype;
struct notifier_block reboot_notifier;
u32 code;
+ u32 sw_debounce_time_us;
+ ktime_t sw_debounce_end_time;
+ bool last_status;
const struct pm8941_data *data;
};
@@ -99,7 +121,10 @@ static int pm8941_reboot_notify(struct notifier_block *nb,
break;
case SYS_RESTART:
default:
- reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
+ if (reboot_mode == REBOOT_WARM)
+ reset_type = PON_PS_HOLD_TYPE_WARM_RESET;
+ else
+ reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
break;
}
@@ -125,21 +150,77 @@ static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
{
struct pm8941_pwrkey *pwrkey = _data;
unsigned int sts;
- int error;
+ int err;
+
+ 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 %lld us\n",
+ ktime_to_us(pwrkey->sw_debounce_end_time));
+ return IRQ_HANDLED;
+ }
+ }
- error = regmap_read(pwrkey->regmap,
- pwrkey->baseaddr + PON_RT_STS, &sts);
- if (error)
+ err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts);
+ if (err)
return IRQ_HANDLED;
- input_report_key(pwrkey->input, pwrkey->code,
- sts & pwrkey->data->status_bit);
+ sts &= pwrkey->data->status_bit;
+
+ if (pwrkey->sw_debounce_time_us && !sts)
+ pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(),
+ pwrkey->sw_debounce_time_us);
+
+ /*
+ * Simulate a press event in case a release event occurred without a
+ * corresponding press event.
+ */
+ if (!pwrkey->last_status && !sts) {
+ input_report_key(pwrkey->input, pwrkey->code, 1);
+ input_sync(pwrkey->input);
+ }
+ pwrkey->last_status = sts;
+
+ input_report_key(pwrkey->input, pwrkey->code, sts);
input_sync(pwrkey->input);
return IRQ_HANDLED;
}
-static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
+static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey)
+{
+ unsigned int val, addr, mask;
+ int error;
+
+ if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) {
+ dev_err(pwrkey->dev,
+ "PON_PBS address missing, can't read HW debounce time\n");
+ return 0;
+ }
+
+ if (pwrkey->pon_pbs_baseaddr)
+ addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL;
+ else
+ addr = pwrkey->baseaddr + PON_DBC_CTL;
+ error = regmap_read(pwrkey->regmap, addr, &val);
+ if (error)
+ return error;
+
+ if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY)
+ mask = 0xf;
+ else
+ mask = 0x7;
+
+ pwrkey->sw_debounce_time_us =
+ 2 * USEC_PER_SEC / (1 << (mask - (val & mask)));
+
+ dev_dbg(pwrkey->dev, "SW debounce time = %u us\n",
+ pwrkey->sw_debounce_time_us);
+
+ return 0;
+}
+
+static int pm8941_pwrkey_suspend(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -149,7 +230,7 @@ static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
+static int pm8941_pwrkey_resume(struct device *dev)
{
struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -159,15 +240,17 @@ static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
- pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
+ pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
static int pm8941_pwrkey_probe(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey;
- bool pull_up;
+ bool pull_up, wakeup;
struct device *parent;
- u32 req_delay;
+ struct device_node *regmap_node;
+ const __be32 *addr;
+ u32 req_delay, mask, delay_shift;
int error;
if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay))
@@ -188,8 +271,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
pwrkey->data = of_device_get_match_data(&pdev->dev);
parent = pdev->dev.parent;
+ regmap_node = pdev->dev.of_node;
pwrkey->regmap = dev_get_regmap(parent, NULL);
if (!pwrkey->regmap) {
+ regmap_node = parent->of_node;
/*
* We failed to get regmap for parent. Let's see if we are
* a child of pon node and read regmap and reg from its
@@ -200,15 +285,21 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "failed to locate regmap\n");
return -ENODEV;
}
+ }
- error = of_property_read_u32(parent->of_node,
- "reg", &pwrkey->baseaddr);
- } else {
- error = of_property_read_u32(pdev->dev.of_node, "reg",
- &pwrkey->baseaddr);
+ addr = of_get_address(regmap_node, 0, NULL, NULL);
+ if (!addr) {
+ dev_err(&pdev->dev, "reg property missing\n");
+ return -EINVAL;
+ }
+ pwrkey->baseaddr = be32_to_cpup(addr);
+
+ if (pwrkey->data->has_pon_pbs) {
+ /* PON_PBS base address is optional */
+ addr = of_get_address(regmap_node, 1, NULL, NULL);
+ if (addr)
+ pwrkey->pon_pbs_baseaddr = be32_to_cpup(addr);
}
- if (error)
- return error;
pwrkey->irq = platform_get_irq(pdev, 0);
if (pwrkey->irq < 0)
@@ -217,7 +308,14 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
&pwrkey->revision);
if (error) {
- dev_err(&pdev->dev, "failed to set debounce: %d\n", error);
+ dev_err(&pdev->dev, "failed to read revision: %d\n", error);
+ return error;
+ }
+
+ error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE,
+ &pwrkey->subtype);
+ if (error) {
+ dev_err(&pdev->dev, "failed to read subtype: %d\n", error);
return error;
}
@@ -241,12 +339,20 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
pwrkey->input->phys = pwrkey->data->phys;
if (pwrkey->data->supports_debounce_config) {
- req_delay = (req_delay << 6) / USEC_PER_SEC;
+ if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY) {
+ mask = PON_DBC_DELAY_MASK_GEN2;
+ delay_shift = PON_DBC_SHIFT_GEN2;
+ } else {
+ mask = PON_DBC_DELAY_MASK_GEN1;
+ delay_shift = PON_DBC_SHIFT_GEN1;
+ }
+
+ req_delay = (req_delay << delay_shift) / USEC_PER_SEC;
req_delay = ilog2(req_delay);
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_DBC_CTL,
- PON_DBC_DELAY_MASK,
+ mask,
req_delay);
if (error) {
dev_err(&pdev->dev, "failed to set debounce: %d\n",
@@ -255,6 +361,10 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
}
}
+ error = pm8941_pwrkey_sw_debounce_init(pwrkey);
+ if (error)
+ return error;
+
if (pwrkey->data->pull_up_bit) {
error = regmap_update_bits(pwrkey->regmap,
pwrkey->baseaddr + PON_PULL_CTL,
@@ -284,7 +394,7 @@ static int pm8941_pwrkey_probe(struct platform_device *pdev)
}
if (pwrkey->data->supports_ps_hold_poff_config) {
- pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify,
+ pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify;
error = register_reboot_notifier(&pwrkey->reboot_notifier);
if (error) {
dev_err(&pdev->dev, "failed to register reboot notifier: %d\n",
@@ -293,20 +403,21 @@ 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;
}
-static int pm8941_pwrkey_remove(struct platform_device *pdev)
+static void pm8941_pwrkey_remove(struct platform_device *pdev)
{
struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev);
if (pwrkey->data->supports_ps_hold_poff_config)
unregister_reboot_notifier(&pwrkey->reboot_notifier);
-
- return 0;
}
static const struct pm8941_data pwrkey_data = {
@@ -316,6 +427,8 @@ static const struct pm8941_data pwrkey_data = {
.phys = "pm8941_pwrkey/input0",
.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 = {
@@ -325,6 +438,8 @@ static const struct pm8941_data resin_data = {
.phys = "pm8941_resin/input0",
.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 = {
@@ -333,6 +448,8 @@ static const struct pm8941_data pon_gen3_pwrkey_data = {
.phys = "pmic_pwrkey/input0",
.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 = {
@@ -341,6 +458,8 @@ static const struct pm8941_data pon_gen3_resin_data = {
.phys = "pmic_resin/input0",
.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[] = {
@@ -357,7 +476,7 @@ static struct platform_driver pm8941_pwrkey_driver = {
.remove = pm8941_pwrkey_remove,
.driver = {
.name = "pm8941-pwrkey",
- .pm = &pm8941_pwr_key_pm_ops,
+ .pm = pm_sleep_ptr(&pm8941_pwr_key_pm_ops),
.of_match_table = of_match_ptr(pm8941_pwr_key_id_table),
},
};
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index 53ad25eaf1a2..381b06473279 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -7,41 +7,61 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
-#define VIB_MAX_LEVEL_mV (3100)
-#define VIB_MIN_LEVEL_mV (1200)
-#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
+#define VIB_MAX_LEVEL_mV(vib) (vib->drv2_addr ? 3544 : 3100)
+#define VIB_MIN_LEVEL_mV(vib) (vib->drv2_addr ? 1504 : 1200)
+#define VIB_PER_STEP_mV(vib) (vib->drv2_addr ? 8 : 100)
+#define VIB_MAX_LEVELS(vib) \
+ (VIB_MAX_LEVEL_mV(vib) - VIB_MIN_LEVEL_mV(vib) + VIB_PER_STEP_mV(vib))
#define MAX_FF_SPEED 0xff
struct pm8xxx_regs {
- unsigned int enable_addr;
+ unsigned int enable_offset;
unsigned int enable_mask;
- unsigned int drv_addr;
+ unsigned int drv_offset;
unsigned int drv_mask;
unsigned int drv_shift;
+ unsigned int drv2_offset;
+ unsigned int drv2_mask;
+ unsigned int drv2_shift;
unsigned int drv_en_manual_mask;
+ bool drv_in_step;
};
static const struct pm8xxx_regs pm8058_regs = {
- .drv_addr = 0x4A,
- .drv_mask = 0xf8,
+ .drv_offset = 0,
+ .drv_mask = GENMASK(7, 3),
.drv_shift = 3,
.drv_en_manual_mask = 0xfc,
+ .drv_in_step = true,
};
static struct pm8xxx_regs pm8916_regs = {
- .enable_addr = 0xc046,
+ .enable_offset = 0x46,
.enable_mask = BIT(7),
- .drv_addr = 0xc041,
- .drv_mask = 0x1F,
+ .drv_offset = 0x41,
+ .drv_mask = GENMASK(4, 0),
.drv_shift = 0,
.drv_en_manual_mask = 0,
+ .drv_in_step = true,
+};
+
+static struct pm8xxx_regs pmi632_regs = {
+ .enable_offset = 0x46,
+ .enable_mask = BIT(7),
+ .drv_offset = 0x40,
+ .drv_mask = GENMASK(7, 0),
+ .drv_shift = 0,
+ .drv2_offset = 0x41,
+ .drv2_mask = GENMASK(3, 0),
+ .drv2_shift = 8,
+ .drv_en_manual_mask = 0,
+ .drv_in_step = false,
};
/**
@@ -50,6 +70,9 @@ static struct pm8xxx_regs pm8916_regs = {
* @work: work structure to set the vibration parameters
* @regmap: regmap for register read/write
* @regs: registers' info
+ * @enable_addr: vibrator enable register
+ * @drv_addr: vibrator drive strength register
+ * @drv2_addr: vibrator drive strength upper byte register
* @speed: speed of vibration set from userland
* @active: state of vibrator
* @level: level of vibration to set in the chip
@@ -60,6 +83,9 @@ struct pm8xxx_vib {
struct work_struct work;
struct regmap *regmap;
const struct pm8xxx_regs *regs;
+ unsigned int enable_addr;
+ unsigned int drv_addr;
+ unsigned int drv2_addr;
int speed;
int level;
bool active;
@@ -77,20 +103,31 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
unsigned int val = vib->reg_vib_drv;
const struct pm8xxx_regs *regs = vib->regs;
+ if (regs->drv_in_step)
+ vib->level /= VIB_PER_STEP_mV(vib);
+
if (on)
val |= (vib->level << regs->drv_shift) & regs->drv_mask;
else
val &= ~regs->drv_mask;
- rc = regmap_write(vib->regmap, regs->drv_addr, val);
+ rc = regmap_write(vib->regmap, vib->drv_addr, val);
if (rc < 0)
return rc;
vib->reg_vib_drv = val;
+ if (regs->drv2_mask) {
+ val = vib->level << regs->drv2_shift;
+ rc = regmap_write_bits(vib->regmap, vib->drv2_addr,
+ regs->drv2_mask, on ? val : 0);
+ if (rc < 0)
+ return rc;
+ }
+
if (regs->enable_mask)
- rc = regmap_update_bits(vib->regmap, regs->enable_addr,
- regs->enable_mask, on ? ~0 : 0);
+ rc = regmap_update_bits(vib->regmap, vib->enable_addr,
+ regs->enable_mask, on ? regs->enable_mask : 0);
return rc;
}
@@ -102,26 +139,24 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
static void pm8xxx_work_handler(struct work_struct *work)
{
struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
- const struct pm8xxx_regs *regs = vib->regs;
- int rc;
unsigned int val;
+ int rc;
- rc = regmap_read(vib->regmap, regs->drv_addr, &val);
+ rc = regmap_read(vib->regmap, vib->drv_addr, &val);
if (rc < 0)
return;
/*
- * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
+ * pmic vibrator supports voltage ranges from MIN_LEVEL to MAX_LEVEL, so
* scale the level to fit into these ranges.
*/
if (vib->speed) {
vib->active = true;
- vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
- VIB_MIN_LEVEL_mV;
- vib->level /= 100;
+ vib->level = VIB_MIN_LEVEL_mV(vib);
+ vib->level += mult_frac(VIB_MAX_LEVELS(vib), vib->speed, MAX_FF_SPEED);
} else {
vib->active = false;
- vib->level = VIB_MIN_LEVEL_mV / 100;
+ vib->level = VIB_MIN_LEVEL_mV(vib);
}
pm8xxx_vib_set(vib, vib->active);
@@ -169,7 +204,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
struct pm8xxx_vib *vib;
struct input_dev *input_dev;
int error;
- unsigned int val;
+ unsigned int val, reg_base = 0;
const struct pm8xxx_regs *regs;
vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL);
@@ -187,15 +222,22 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
INIT_WORK(&vib->work, pm8xxx_work_handler);
vib->vib_input_dev = input_dev;
+ error = fwnode_property_read_u32(pdev->dev.fwnode, "reg", &reg_base);
+ if (error < 0)
+ return dev_err_probe(&pdev->dev, error, "Failed to read reg address\n");
+
regs = of_device_get_match_data(&pdev->dev);
+ vib->enable_addr = reg_base + regs->enable_offset;
+ vib->drv_addr = reg_base + regs->drv_offset;
+ vib->drv2_addr = reg_base + regs->drv2_offset;
/* operate in manual mode */
- error = regmap_read(vib->regmap, regs->drv_addr, &val);
+ error = regmap_read(vib->regmap, vib->drv_addr, &val);
if (error < 0)
return error;
val &= regs->drv_en_manual_mask;
- error = regmap_write(vib->regmap, regs->drv_addr, val);
+ error = regmap_write(vib->regmap, vib->drv_addr, val);
if (error < 0)
return error;
@@ -226,7 +268,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pm8xxx_vib_suspend(struct device *dev)
+static int pm8xxx_vib_suspend(struct device *dev)
{
struct pm8xxx_vib *vib = dev_get_drvdata(dev);
@@ -236,12 +278,13 @@ static int __maybe_unused pm8xxx_vib_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
+static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
static const struct of_device_id pm8xxx_vib_id_table[] = {
{ .compatible = "qcom,pm8058-vib", .data = &pm8058_regs },
{ .compatible = "qcom,pm8921-vib", .data = &pm8058_regs },
{ .compatible = "qcom,pm8916-vib", .data = &pm8916_regs },
+ { .compatible = "qcom,pmi632-vib", .data = &pmi632_regs },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
@@ -250,7 +293,7 @@ static struct platform_driver pm8xxx_vib_driver = {
.probe = pm8xxx_vib_probe,
.driver = {
.name = "pm8xxx-vib",
- .pm = &pm8xxx_vib_pm_ops,
+ .pm = pm_sleep_ptr(&pm8xxx_vib_pm_ops),
.of_match_table = pm8xxx_vib_id_table,
},
};
diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c
index 0e818a3d28c5..c406a1cca5c4 100644
--- a/drivers/input/misc/pmic8xxx-pwrkey.c
+++ b/drivers/input/misc/pmic8xxx-pwrkey.c
@@ -12,7 +12,6 @@
#include <linux/regmap.h>
#include <linux/log2.h>
#include <linux/of.h>
-#include <linux/of_device.h>
#define PON_CNTL_1 0x1C
#define PON_CNTL_PULL_UP BIT(7)
@@ -100,7 +99,7 @@ static irqreturn_t pwrkey_release_irq(int irq, void *_pwr)
return IRQ_HANDLED;
}
-static int __maybe_unused pmic8xxx_pwrkey_suspend(struct device *dev)
+static int pmic8xxx_pwrkey_suspend(struct device *dev)
{
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -110,7 +109,7 @@ static int __maybe_unused pmic8xxx_pwrkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev)
+static int pmic8xxx_pwrkey_resume(struct device *dev)
{
struct pmic8xxx_pwrkey *pwrkey = dev_get_drvdata(dev);
@@ -120,7 +119,7 @@ static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops,
pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume);
static void pmic8xxx_pwrkey_shutdown(struct platform_device *pdev)
@@ -442,7 +441,7 @@ static struct platform_driver pmic8xxx_pwrkey_driver = {
.shutdown = pmic8xxx_pwrkey_shutdown,
.driver = {
.name = "pm8xxx-pwrkey",
- .pm = &pm8xxx_pwr_key_pm_ops,
+ .pm = pm_sleep_ptr(&pm8xxx_pwr_key_pm_ops),
.of_match_table = pm8xxx_pwr_key_id_table,
},
};
diff --git a/drivers/input/misc/powermate.c b/drivers/input/misc/powermate.c
index c4e0e1886061..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;
@@ -374,7 +367,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
- maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ maxp = usb_maxpacket(udev, pipe);
if (maxp < POWERMATE_PAYLOAD_SIZE_MIN || maxp > POWERMATE_PAYLOAD_SIZE_MAX) {
printk(KERN_WARNING "powermate: Expected payload of %d--%d bytes, found %d bytes!\n",
@@ -425,6 +418,7 @@ static void powermate_disconnect(struct usb_interface *intf)
pm->requires_update = 0;
usb_kill_urb(pm->irq);
input_unregister_device(pm->input);
+ usb_kill_urb(pm->config);
usb_free_urb(pm->irq);
usb_free_urb(pm->config);
powermate_free_buffers(interface_to_usbdev(intf), pm);
diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c
index d6b12477748a..0e19e97d98ec 100644
--- a/drivers/input/misc/pwm-beeper.c
+++ b/drivers/input/misc/pwm-beeper.c
@@ -39,7 +39,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period)
state.period = period;
pwm_set_relative_duty_cycle(&state, 50, 100);
- error = pwm_apply_state(beeper->pwm, &state);
+ error = pwm_apply_might_sleep(beeper->pwm, &state);
if (error)
return error;
@@ -132,18 +132,13 @@ static int pwm_beeper_probe(struct platform_device *pdev)
return -ENOMEM;
beeper->pwm = devm_pwm_get(dev, NULL);
- if (IS_ERR(beeper->pwm)) {
- error = PTR_ERR(beeper->pwm);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to request PWM device: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(beeper->pwm))
+ return dev_err_probe(dev, PTR_ERR(beeper->pwm), "Failed to request PWM device\n");
/* Sync up PWM state and ensure it is off. */
pwm_init_state(beeper->pwm, &state);
state.enabled = false;
- error = pwm_apply_state(beeper->pwm, &state);
+ error = pwm_apply_might_sleep(beeper->pwm, &state);
if (error) {
dev_err(dev, "failed to apply initial PWM state: %d\n",
error);
@@ -151,13 +146,9 @@ static int pwm_beeper_probe(struct platform_device *pdev)
}
beeper->amplifier = devm_regulator_get(dev, "amp");
- if (IS_ERR(beeper->amplifier)) {
- error = PTR_ERR(beeper->amplifier);
- if (error != -EPROBE_DEFER)
- dev_err(dev, "Failed to get 'amp' regulator: %d\n",
- error);
- return error;
- }
+ if (IS_ERR(beeper->amplifier))
+ return dev_err_probe(dev, PTR_ERR(beeper->amplifier),
+ "Failed to get 'amp' regulator\n");
INIT_WORK(&beeper->work, pwm_beeper_work);
@@ -203,7 +194,7 @@ static int pwm_beeper_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pwm_beeper_suspend(struct device *dev)
+static int pwm_beeper_suspend(struct device *dev)
{
struct pwm_beeper *beeper = dev_get_drvdata(dev);
@@ -212,22 +203,22 @@ static int __maybe_unused 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);
return 0;
}
-static int __maybe_unused pwm_beeper_resume(struct device *dev)
+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);
@@ -235,8 +226,8 @@ static int __maybe_unused pwm_beeper_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
- pwm_beeper_suspend, pwm_beeper_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pwm_beeper_pm_ops,
+ pwm_beeper_suspend, pwm_beeper_resume);
#ifdef CONFIG_OF
static const struct of_device_id pwm_beeper_match[] = {
@@ -250,7 +241,7 @@ static struct platform_driver pwm_beeper_driver = {
.probe = pwm_beeper_probe,
.driver = {
.name = "pwm-beeper",
- .pm = &pwm_beeper_pm_ops,
+ .pm = pm_sleep_ptr(&pwm_beeper_pm_ops),
.of_match_table = of_match_ptr(pwm_beeper_match),
},
};
diff --git a/drivers/input/misc/pwm-vibra.c b/drivers/input/misc/pwm-vibra.c
index 81e777a04b88..3e5ed685ed8f 100644
--- a/drivers/input/misc/pwm-vibra.c
+++ b/drivers/input/misc/pwm-vibra.c
@@ -11,10 +11,11 @@
* Copyright (C) 2010, Lars-Peter Clausen <lars@metafoo.de>
*/
+#include <linux/gpio/consumer.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pwm.h>
@@ -23,6 +24,7 @@
struct pwm_vibrator {
struct input_dev *input;
+ struct gpio_desc *enable_gpio;
struct pwm_device *pwm;
struct pwm_device *pwm_dir;
struct regulator *vcc;
@@ -42,19 +44,21 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
if (!vibrator->vcc_on) {
err = regulator_enable(vibrator->vcc);
if (err) {
- dev_err(pdev, "failed to enable regulator: %d", err);
+ dev_err(pdev, "failed to enable regulator: %d\n", err);
return err;
}
vibrator->vcc_on = true;
}
+ gpiod_set_value_cansleep(vibrator->enable_gpio, 1);
+
pwm_get_state(vibrator->pwm, &state);
pwm_set_relative_duty_cycle(&state, vibrator->level, 0xffff);
state.enabled = true;
- err = pwm_apply_state(vibrator->pwm, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm, &state);
if (err) {
- dev_err(pdev, "failed to apply pwm state: %d", err);
+ dev_err(pdev, "failed to apply pwm state: %d\n", err);
return err;
}
@@ -63,9 +67,9 @@ static int pwm_vibrator_start(struct pwm_vibrator *vibrator)
state.duty_cycle = vibrator->direction_duty_cycle;
state.enabled = true;
- err = pwm_apply_state(vibrator->pwm_dir, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state);
if (err) {
- dev_err(pdev, "failed to apply dir-pwm state: %d", err);
+ dev_err(pdev, "failed to apply dir-pwm state: %d\n", err);
pwm_disable(vibrator->pwm);
return err;
}
@@ -80,6 +84,8 @@ static void pwm_vibrator_stop(struct pwm_vibrator *vibrator)
pwm_disable(vibrator->pwm_dir);
pwm_disable(vibrator->pwm);
+ gpiod_set_value_cansleep(vibrator->enable_gpio, 0);
+
if (vibrator->vcc_on) {
regulator_disable(vibrator->vcc);
vibrator->vcc_on = false;
@@ -134,31 +140,29 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
return -ENOMEM;
vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
- err = PTR_ERR_OR_ZERO(vibrator->vcc);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to request regulator: %d",
- err);
- return err;
- }
+ if (IS_ERR(vibrator->vcc))
+ return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->vcc),
+ "Failed to request regulator\n");
+
+ vibrator->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(vibrator->enable_gpio))
+ return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->enable_gpio),
+ "Failed to request enable gpio\n");
vibrator->pwm = devm_pwm_get(&pdev->dev, "enable");
- err = PTR_ERR_OR_ZERO(vibrator->pwm);
- if (err) {
- if (err != -EPROBE_DEFER)
- dev_err(&pdev->dev, "Failed to request main pwm: %d",
- err);
- return err;
- }
+ if (IS_ERR(vibrator->pwm))
+ return dev_err_probe(&pdev->dev, PTR_ERR(vibrator->pwm),
+ "Failed to request main pwm\n");
INIT_WORK(&vibrator->play_work, pwm_vibrator_play_work);
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm, &state);
state.enabled = false;
- err = pwm_apply_state(vibrator->pwm, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm, &state);
if (err) {
- dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
+ dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
err);
return err;
}
@@ -170,9 +174,9 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
/* Sync up PWM state and ensure it is off. */
pwm_init_state(vibrator->pwm_dir, &state);
state.enabled = false;
- err = pwm_apply_state(vibrator->pwm_dir, &state);
+ err = pwm_apply_might_sleep(vibrator->pwm_dir, &state);
if (err) {
- dev_err(&pdev->dev, "failed to apply initial PWM state: %d",
+ dev_err(&pdev->dev, "failed to apply initial PWM state: %d\n",
err);
return err;
}
@@ -189,7 +193,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
break;
default:
- dev_err(&pdev->dev, "Failed to request direction pwm: %d", err);
+ dev_err(&pdev->dev, "Failed to request direction pwm: %d\n", err);
fallthrough;
case -EPROBE_DEFER:
@@ -207,13 +211,13 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
err = input_ff_create_memless(vibrator->input, NULL,
pwm_vibrator_play_effect);
if (err) {
- dev_err(&pdev->dev, "Couldn't create FF dev: %d", err);
+ dev_err(&pdev->dev, "Couldn't create FF dev: %d\n", err);
return err;
}
err = input_register_device(vibrator->input);
if (err) {
- dev_err(&pdev->dev, "Couldn't register input dev: %d", err);
+ dev_err(&pdev->dev, "Couldn't register input dev: %d\n", err);
return err;
}
@@ -222,7 +226,7 @@ static int pwm_vibrator_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
+static int pwm_vibrator_suspend(struct device *dev)
{
struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
@@ -233,7 +237,7 @@ static int __maybe_unused pwm_vibrator_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused pwm_vibrator_resume(struct device *dev)
+static int pwm_vibrator_resume(struct device *dev)
{
struct pwm_vibrator *vibrator = dev_get_drvdata(dev);
@@ -243,8 +247,8 @@ static int __maybe_unused pwm_vibrator_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
- pwm_vibrator_suspend, pwm_vibrator_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(pwm_vibrator_pm_ops,
+ pwm_vibrator_suspend, pwm_vibrator_resume);
#ifdef CONFIG_OF
static const struct of_device_id pwm_vibra_dt_match_table[] = {
@@ -258,7 +262,7 @@ static struct platform_driver pwm_vibrator_driver = {
.probe = pwm_vibrator_probe,
.driver = {
.name = "pwm-vibrator",
- .pm = &pwm_vibrator_pm_ops,
+ .pm = pm_sleep_ptr(&pwm_vibrator_pm_ops),
.of_match_table = of_match_ptr(pwm_vibra_dt_match_table),
},
};
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 a661e77545c5..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,
@@ -201,32 +200,28 @@ static int regulator_haptic_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused regulator_haptic_suspend(struct device *dev)
+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 __maybe_unused regulator_haptic_resume(struct device *dev)
+static int regulator_haptic_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_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,12 +229,10 @@ static int __maybe_unused regulator_haptic_resume(struct device *dev)
if (magnitude)
regulator_haptic_set_voltage(haptic, magnitude);
- mutex_unlock(&haptic->mutex);
-
return 0;
}
-static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
+static DEFINE_SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
regulator_haptic_suspend, regulator_haptic_resume);
static const struct of_device_id regulator_haptic_dt_match[] = {
@@ -253,7 +246,7 @@ static struct platform_driver regulator_haptic_driver = {
.driver = {
.name = "regulator-haptic",
.of_match_table = regulator_haptic_dt_match,
- .pm = &regulator_haptic_pm_ops,
+ .pm = pm_sleep_ptr(&regulator_haptic_pm_ops),
},
};
module_platform_driver(regulator_haptic_driver);
diff --git a/drivers/input/misc/rk805-pwrkey.c b/drivers/input/misc/rk805-pwrkey.c
index 3fb64dbda1a2..76873aa005b4 100644
--- a/drivers/input/misc/rk805-pwrkey.c
+++ b/drivers/input/misc/rk805-pwrkey.c
@@ -98,6 +98,7 @@ static struct platform_driver rk805_pwrkey_driver = {
};
module_platform_driver(rk805_pwrkey_driver);
+MODULE_ALIAS("platform:rk805-pwrkey");
MODULE_AUTHOR("Joseph Chen <chenjh@rock-chips.com>");
MODULE_DESCRIPTION("RK805 PMIC Power Key driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c
index 6d613f2a017c..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;
}
@@ -236,12 +229,8 @@ static int rotary_encoder_probe(struct platform_device *pdev)
device_property_read_bool(dev, "rotary-encoder,relative-axis");
encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
- if (IS_ERR(encoder->gpios)) {
- err = PTR_ERR(encoder->gpios);
- if (err != -EPROBE_DEFER)
- dev_err(dev, "unable to get gpios: %d\n", err);
- return err;
- }
+ if (IS_ERR(encoder->gpios))
+ return dev_err_probe(dev, PTR_ERR(encoder->gpios), "unable to get gpios\n");
if (encoder->gpios->ndescs < 2) {
dev_err(dev, "not enough gpios found\n");
return -EINVAL;
@@ -255,7 +244,6 @@ static int rotary_encoder_probe(struct platform_device *pdev)
input->name = pdev->name;
input->id.bustype = BUS_HOST;
- input->dev.parent = dev;
if (encoder->relative_axis)
input_set_capability(input, EV_REL, encoder->axis);
@@ -317,7 +305,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused rotary_encoder_suspend(struct device *dev)
+static int rotary_encoder_suspend(struct device *dev)
{
struct rotary_encoder *encoder = dev_get_drvdata(dev);
unsigned int i;
@@ -330,7 +318,7 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused rotary_encoder_resume(struct device *dev)
+static int rotary_encoder_resume(struct device *dev)
{
struct rotary_encoder *encoder = dev_get_drvdata(dev);
unsigned int i;
@@ -343,8 +331,8 @@ static int __maybe_unused rotary_encoder_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
- rotary_encoder_suspend, rotary_encoder_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(rotary_encoder_pm_ops,
+ rotary_encoder_suspend, rotary_encoder_resume);
#ifdef CONFIG_OF
static const struct of_device_id rotary_encoder_of_match[] = {
@@ -358,7 +346,7 @@ static struct platform_driver rotary_encoder_driver = {
.probe = rotary_encoder_probe,
.driver = {
.name = DRV_NAME,
- .pm = &rotary_encoder_pm_ops,
+ .pm = pm_sleep_ptr(&rotary_encoder_pm_ops),
.of_match_table = of_match_ptr(rotary_encoder_of_match),
}
};
diff --git a/drivers/input/misc/rt5120-pwrkey.c b/drivers/input/misc/rt5120-pwrkey.c
new file mode 100644
index 000000000000..8a8c1aeeed05
--- /dev/null
+++ b/drivers/input/misc/rt5120-pwrkey.c
@@ -0,0 +1,120 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Richtek Technology Corp.
+ * Author: ChiYuan Huang <cy_huang@richtek.com>
+ */
+
+#include <linux/bits.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define RT5120_REG_INTSTAT 0x1E
+#define RT5120_PWRKEYSTAT_MASK BIT(7)
+
+struct rt5120_priv {
+ struct regmap *regmap;
+ struct input_dev *input;
+};
+
+static irqreturn_t rt5120_pwrkey_handler(int irq, void *devid)
+{
+ struct rt5120_priv *priv = devid;
+ unsigned int stat;
+ int error;
+
+ error = regmap_read(priv->regmap, RT5120_REG_INTSTAT, &stat);
+ if (error)
+ return IRQ_NONE;
+
+ input_report_key(priv->input, KEY_POWER,
+ !(stat & RT5120_PWRKEYSTAT_MASK));
+ input_sync(priv->input);
+
+ return IRQ_HANDLED;
+}
+
+static int rt5120_pwrkey_probe(struct platform_device *pdev)
+{
+ struct rt5120_priv *priv;
+ struct device *dev = &pdev->dev;
+ int press_irq, release_irq;
+ int error;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regmap = dev_get_regmap(dev->parent, NULL);
+ if (!priv->regmap) {
+ dev_err(dev, "Failed to init regmap\n");
+ return -ENODEV;
+ }
+
+ press_irq = platform_get_irq_byname(pdev, "pwrkey-press");
+ if (press_irq < 0)
+ return press_irq;
+
+ release_irq = platform_get_irq_byname(pdev, "pwrkey-release");
+ if (release_irq < 0)
+ return release_irq;
+
+ /* Make input device be device resource managed */
+ priv->input = devm_input_allocate_device(dev);
+ if (!priv->input)
+ return -ENOMEM;
+
+ priv->input->name = "rt5120_pwrkey";
+ priv->input->phys = "rt5120_pwrkey/input0";
+ priv->input->id.bustype = BUS_I2C;
+ input_set_capability(priv->input, EV_KEY, KEY_POWER);
+
+ error = input_register_device(priv->input);
+ if (error) {
+ dev_err(dev, "Failed to register input device: %d\n", error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, press_irq,
+ NULL, rt5120_pwrkey_handler,
+ 0, "pwrkey-press", priv);
+ if (error) {
+ dev_err(dev,
+ "Failed to register pwrkey press irq: %d\n", error);
+ return error;
+ }
+
+ error = devm_request_threaded_irq(dev, release_irq,
+ NULL, rt5120_pwrkey_handler,
+ 0, "pwrkey-release", priv);
+ if (error) {
+ dev_err(dev,
+ "Failed to register pwrkey release irq: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static const struct of_device_id r5120_pwrkey_match_table[] = {
+ { .compatible = "richtek,rt5120-pwrkey" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, r5120_pwrkey_match_table);
+
+static struct platform_driver rt5120_pwrkey_driver = {
+ .driver = {
+ .name = "rt5120-pwrkey",
+ .of_match_table = r5120_pwrkey_match_table,
+ },
+ .probe = rt5120_pwrkey_probe,
+};
+module_platform_driver(rt5120_pwrkey_driver);
+
+MODULE_AUTHOR("ChiYuan Huang <cy_huang@richtek.com>");
+MODULE_DESCRIPTION("Richtek RT5120 power key driver");
+MODULE_LICENSE("GPL");
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/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
deleted file mode 100644
index 7982bf8fb839..000000000000
--- a/drivers/input/misc/sirfsoc-onkey.c
+++ /dev/null
@@ -1,207 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Power key driver for SiRF PrimaII
- *
- * Copyright (c) 2013 - 2014 Cambridge Silicon Radio Limited, a CSR plc group
- * company.
- */
-
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/input.h>
-#include <linux/rtc/sirfsoc_rtciobrg.h>
-#include <linux/of.h>
-#include <linux/workqueue.h>
-
-struct sirfsoc_pwrc_drvdata {
- u32 pwrc_base;
- struct input_dev *input;
- struct delayed_work work;
-};
-
-#define PWRC_ON_KEY_BIT (1 << 0)
-
-#define PWRC_INT_STATUS 0xc
-#define PWRC_INT_MASK 0x10
-#define PWRC_PIN_STATUS 0x14
-#define PWRC_KEY_DETECT_UP_TIME 20 /* ms*/
-
-static int sirfsoc_pwrc_is_on_key_down(struct sirfsoc_pwrc_drvdata *pwrcdrv)
-{
- u32 state = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
- PWRC_PIN_STATUS);
- return !(state & PWRC_ON_KEY_BIT); /* ON_KEY is active low */
-}
-
-static void sirfsoc_pwrc_report_event(struct work_struct *work)
-{
- struct sirfsoc_pwrc_drvdata *pwrcdrv =
- container_of(work, struct sirfsoc_pwrc_drvdata, work.work);
-
- if (sirfsoc_pwrc_is_on_key_down(pwrcdrv)) {
- schedule_delayed_work(&pwrcdrv->work,
- msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
- } else {
- input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 0);
- input_sync(pwrcdrv->input);
- }
-}
-
-static irqreturn_t sirfsoc_pwrc_isr(int irq, void *dev_id)
-{
- struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_id;
- u32 int_status;
-
- int_status = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base +
- PWRC_INT_STATUS);
- sirfsoc_rtc_iobrg_writel(int_status & ~PWRC_ON_KEY_BIT,
- pwrcdrv->pwrc_base + PWRC_INT_STATUS);
-
- input_event(pwrcdrv->input, EV_KEY, KEY_POWER, 1);
- input_sync(pwrcdrv->input);
- schedule_delayed_work(&pwrcdrv->work,
- msecs_to_jiffies(PWRC_KEY_DETECT_UP_TIME));
-
- return IRQ_HANDLED;
-}
-
-static void sirfsoc_pwrc_toggle_interrupts(struct sirfsoc_pwrc_drvdata *pwrcdrv,
- bool enable)
-{
- u32 int_mask;
-
- int_mask = sirfsoc_rtc_iobrg_readl(pwrcdrv->pwrc_base + PWRC_INT_MASK);
- if (enable)
- int_mask |= PWRC_ON_KEY_BIT;
- else
- int_mask &= ~PWRC_ON_KEY_BIT;
- sirfsoc_rtc_iobrg_writel(int_mask, pwrcdrv->pwrc_base + PWRC_INT_MASK);
-}
-
-static int sirfsoc_pwrc_open(struct input_dev *input)
-{
- struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
-
- sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
-
- return 0;
-}
-
-static void sirfsoc_pwrc_close(struct input_dev *input)
-{
- struct sirfsoc_pwrc_drvdata *pwrcdrv = input_get_drvdata(input);
-
- sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
- cancel_delayed_work_sync(&pwrcdrv->work);
-}
-
-static const struct of_device_id sirfsoc_pwrc_of_match[] = {
- { .compatible = "sirf,prima2-pwrc" },
- {},
-};
-MODULE_DEVICE_TABLE(of, sirfsoc_pwrc_of_match);
-
-static int sirfsoc_pwrc_probe(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
- struct sirfsoc_pwrc_drvdata *pwrcdrv;
- int irq;
- int error;
-
- pwrcdrv = devm_kzalloc(&pdev->dev, sizeof(struct sirfsoc_pwrc_drvdata),
- GFP_KERNEL);
- if (!pwrcdrv) {
- dev_info(&pdev->dev, "Not enough memory for the device data\n");
- return -ENOMEM;
- }
-
- /*
- * We can't use of_iomap because pwrc is not mapped in memory,
- * the so-called base address is only offset in rtciobrg
- */
- error = of_property_read_u32(np, "reg", &pwrcdrv->pwrc_base);
- if (error) {
- dev_err(&pdev->dev,
- "unable to find base address of pwrc node in dtb\n");
- return error;
- }
-
- pwrcdrv->input = devm_input_allocate_device(&pdev->dev);
- if (!pwrcdrv->input)
- return -ENOMEM;
-
- pwrcdrv->input->name = "sirfsoc pwrckey";
- pwrcdrv->input->phys = "pwrc/input0";
- pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
- input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
-
- INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
-
- pwrcdrv->input->open = sirfsoc_pwrc_open;
- pwrcdrv->input->close = sirfsoc_pwrc_close;
-
- input_set_drvdata(pwrcdrv->input, pwrcdrv);
-
- /* Make sure the device is quiesced */
- sirfsoc_pwrc_toggle_interrupts(pwrcdrv, false);
-
- irq = platform_get_irq(pdev, 0);
- error = devm_request_irq(&pdev->dev, irq,
- sirfsoc_pwrc_isr, 0,
- "sirfsoc_pwrc_int", pwrcdrv);
- if (error) {
- dev_err(&pdev->dev, "unable to claim irq %d, error: %d\n",
- irq, error);
- return error;
- }
-
- error = input_register_device(pwrcdrv->input);
- if (error) {
- dev_err(&pdev->dev,
- "unable to register input device, error: %d\n",
- error);
- return error;
- }
-
- dev_set_drvdata(&pdev->dev, pwrcdrv);
- device_init_wakeup(&pdev->dev, 1);
-
- return 0;
-}
-
-static int __maybe_unused sirfsoc_pwrc_resume(struct device *dev)
-{
- struct sirfsoc_pwrc_drvdata *pwrcdrv = dev_get_drvdata(dev);
- struct input_dev *input = pwrcdrv->input;
-
- /*
- * Do not mask pwrc interrupt as we want pwrc work as a wakeup source
- * if users touch X_ONKEY_B, see arch/arm/mach-prima2/pm.c
- */
- mutex_lock(&input->mutex);
- if (input_device_enabled(input))
- sirfsoc_pwrc_toggle_interrupts(pwrcdrv, true);
- mutex_unlock(&input->mutex);
-
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(sirfsoc_pwrc_pm_ops, NULL, sirfsoc_pwrc_resume);
-
-static struct platform_driver sirfsoc_pwrc_driver = {
- .probe = sirfsoc_pwrc_probe,
- .driver = {
- .name = "sirfsoc-pwrc",
- .pm = &sirfsoc_pwrc_pm_ops,
- .of_match_table = sirfsoc_pwrc_of_match,
- }
-};
-
-module_platform_driver(sirfsoc_pwrc_driver);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Binghua Duan <Binghua.Duan@csr.com>, Xianglong Du <Xianglong.Du@csr.com>");
-MODULE_DESCRIPTION("CSR Prima2 PWRC Driver");
-MODULE_ALIAS("platform:sirfsoc-pwrc");
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index cb6ec59a045d..b8cad415c62c 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -18,6 +18,10 @@
#include <linux/gpio.h>
#include <linux/platform_device.h>
+static bool use_low_level_irq;
+module_param(use_low_level_irq, bool, 0444);
+MODULE_PARM_DESC(use_low_level_irq, "Use low-level triggered IRQ instead of edge triggered");
+
struct soc_button_info {
const char *name;
int acpi_index;
@@ -74,6 +78,13 @@ static const struct dmi_system_id dmi_use_low_level_irq[] = {
},
},
{
+ /* Acer Switch V 10 SW5-017, same issue as Acer Switch 10 SW5-012. */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SW5-017"),
+ },
+ },
+ {
/*
* Acer One S1003. _LID method messes with power-button GPIO
* IRQ settings, leading to a non working power-button.
@@ -85,14 +96,35 @@ static const struct dmi_system_id dmi_use_low_level_irq[] = {
},
{
/*
- * Lenovo Yoga Tab2 1051L, something messes with the home-button
+ * Lenovo Yoga Tab2 1051F/1051L, something messes with the home-button
* IRQ settings, leading to a non working home-button.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
DMI_MATCH(DMI_PRODUCT_NAME, "60073"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "1051L"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1051"),
+ },
+ },
+ {} /* Terminating entry */
+};
+
+/*
+ * Some devices have a wrong entry which points to a GPIO which is
+ * required in another driver, so this driver must not claim it.
+ */
+static const struct dmi_system_id dmi_invalid_acpi_index[] = {
+ {
+ /*
+ * Lenovo Yoga Book X90F / X90L, the PNP0C40 home button entry
+ * points to a GPIO which is not a home button and which is
+ * required by the lenovo-yogabook driver.
+ */
+ .matches = {
+ DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel Corporation"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "CHERRYVIEW D1 PLATFORM"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_VERSION, "YETI-11"),
},
+ .driver_data = (void *)1l,
},
{} /* Terminating entry */
};
@@ -126,6 +158,8 @@ soc_button_device_create(struct platform_device *pdev,
struct platform_device *pd;
struct gpio_keys_button *gpio_keys;
struct gpio_keys_platform_data *gpio_keys_pdata;
+ const struct dmi_system_id *dmi_id;
+ int invalid_acpi_index = -1;
int error, gpio, irq;
int n_buttons = 0;
@@ -143,10 +177,17 @@ soc_button_device_create(struct platform_device *pdev,
gpio_keys = (void *)(gpio_keys_pdata + 1);
n_buttons = 0;
+ dmi_id = dmi_first_match(dmi_invalid_acpi_index);
+ if (dmi_id)
+ invalid_acpi_index = (long)dmi_id->driver_data;
+
for (info = button_info; info->name; info++) {
if (info->autorepeat != autorepeat)
continue;
+ if (info->acpi_index == invalid_acpi_index)
+ continue;
+
error = soc_button_lookup_gpio(&pdev->dev, info->acpi_index, &gpio, &irq);
if (error || irq < 0) {
/*
@@ -164,7 +205,8 @@ soc_button_device_create(struct platform_device *pdev,
}
/* See dmi_use_low_level_irq[] comment */
- if (!autorepeat && dmi_check_system(dmi_use_low_level_irq)) {
+ if (!autorepeat && (use_low_level_irq ||
+ dmi_check_system(dmi_use_low_level_irq))) {
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
gpio_keys[n_buttons].irq = irq;
gpio_keys[n_buttons].gpio = -ENOENT;
@@ -257,6 +299,11 @@ static int soc_button_parse_btn_desc(struct device *dev,
info->name = "power";
info->event_code = KEY_POWER;
info->wakeup = true;
+ } else if (upage == 0x01 && usage == 0xc6) {
+ info->name = "airplane mode switch";
+ info->event_type = EV_SW;
+ info->event_code = SW_RFKILL_ALL;
+ info->active_low = false;
} else if (upage == 0x01 && usage == 0xca) {
info->name = "rotation lock switch";
info->event_type = EV_SW;
@@ -369,7 +416,7 @@ out:
return button_info;
}
-static int soc_button_remove(struct platform_device *pdev)
+static void soc_button_remove(struct platform_device *pdev)
{
struct soc_button_data *priv = platform_get_drvdata(pdev);
@@ -378,8 +425,6 @@ static int soc_button_remove(struct platform_device *pdev)
for (i = 0; i < BUTTON_TYPES; i++)
if (priv->children[i])
platform_device_unregister(priv->children[i]);
-
- return 0;
}
static int soc_button_probe(struct platform_device *pdev)
@@ -470,6 +515,27 @@ static const struct soc_device_data soc_device_INT33D3 = {
};
/*
+ * 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
+ * version of the drivers/platform/x86/intel/hid.c 5 button array ACPI API
+ * instead. A check() callback is not necessary though as the Surface 3 Pro
+ * MSHW0028 ACPI device's resource table does not contain any GPIOs.
+ */
+static const struct soc_button_info soc_button_MSHW0028[] = {
+ { "power", 0, EV_KEY, KEY_POWER, false, true, true },
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false },
+ { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true },
+ { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true },
+ { }
+};
+
+static const struct soc_device_data soc_device_MSHW0028 = {
+ .button_info = soc_button_MSHW0028,
+};
+
+/*
* Special device check for Surface Book 2 and Surface Pro (2017).
* Both, the Surface Pro 4 (surfacepro3_button.c) and the above mentioned
* devices use MSHW0040 for power and volume buttons, however the way they
@@ -535,7 +601,8 @@ static const struct acpi_device_id soc_button_acpi_match[] = {
{ "ID9001", (unsigned long)&soc_device_INT33D3 },
{ "ACPI0011", 0 },
- /* Microsoft Surface Devices (5th and 6th generation) */
+ /* Microsoft Surface Devices (3th, 5th and 6th generation) */
+ { "MSHW0028", (unsigned long)&soc_device_MSHW0028 },
{ "MSHW0040", (unsigned long)&soc_device_MSHW0040 },
{ }
@@ -553,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 fe43e5557ed7..1cfadd73829f 100644
--- a/drivers/input/misc/sparcspkr.c
+++ b/drivers/input/misc/sparcspkr.c
@@ -9,7 +9,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/slab.h>
#include <asm/io.h>
@@ -68,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)
@@ -84,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);
@@ -96,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;
}
@@ -106,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 */
@@ -135,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;
}
@@ -187,49 +192,41 @@ 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);
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 int bbc_remove(struct platform_device *op)
+static void bbc_remove(struct platform_device *op)
{
struct sparcspkr_state *state = platform_get_drvdata(op);
struct input_dev *input_dev = state->input_dev;
@@ -241,10 +238,6 @@ static int bbc_remove(struct platform_device *op)
input_unregister_device(input_dev);
of_iounmap(&op->resource[0], info->regs, 6);
-
- kfree(state);
-
- return 0;
}
static const struct of_device_id bbc_beep_match[] = {
@@ -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,13 +295,11 @@ out_clear_drvdata:
out_unmap_freq_regs:
of_iounmap(&op->resource[2], info->freq_regs, 2);
-out_free:
- kfree(state);
-out_err:
+
return err;
}
-static int grover_remove(struct platform_device *op)
+static void grover_remove(struct platform_device *op)
{
struct sparcspkr_state *state = platform_get_drvdata(op);
struct grover_beep_info *info = &state->u.grover;
@@ -321,10 +312,6 @@ static int 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);
-
- return 0;
}
static const struct of_device_id grover_beep_match[] = {
diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c
index d8dc2f2f8000..d5ebca7b90a5 100644
--- a/drivers/input/misc/stpmic1_onkey.c
+++ b/drivers/input/misc/stpmic1_onkey.c
@@ -142,7 +142,7 @@ static int stpmic1_onkey_probe(struct platform_device *pdev)
return 0;
}
-static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
+static int stpmic1_onkey_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
@@ -154,7 +154,7 @@ static int __maybe_unused stpmic1_onkey_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
+static int stpmic1_onkey_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct stpmic1_onkey *onkey = platform_get_drvdata(pdev);
@@ -166,9 +166,9 @@ static int __maybe_unused stpmic1_onkey_resume(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
- stpmic1_onkey_suspend,
- stpmic1_onkey_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm,
+ stpmic1_onkey_suspend,
+ stpmic1_onkey_resume);
static const struct of_device_id of_stpmic1_onkey_match[] = {
{ .compatible = "st,stpmic1-onkey" },
@@ -182,7 +182,7 @@ static struct platform_driver stpmic1_onkey_driver = {
.driver = {
.name = "stpmic1_onkey",
.of_match_table = of_match_ptr(of_stpmic1_onkey_match),
- .pm = &stpmic1_onkey_pm,
+ .pm = pm_sleep_ptr(&stpmic1_onkey_pm),
},
};
module_platform_driver(stpmic1_onkey_driver);
diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c
index f011447c44fb..fc450fce0932 100644
--- a/drivers/input/misc/tps65218-pwrbutton.c
+++ b/drivers/input/misc/tps65218-pwrbutton.c
@@ -1,18 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
/*
* Texas Instruments' TPS65217 and TPS65218 Power Button Input Driver
*
* Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
* Author: Felipe Balbi <balbi@ti.com>
* Author: Marcin Niestroj <m.niestroj@grinn-global.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
*/
#include <linux/init.h>
diff --git a/drivers/input/misc/tps65219-pwrbutton.c b/drivers/input/misc/tps65219-pwrbutton.c
new file mode 100644
index 000000000000..7a58bae4f1a0
--- /dev/null
+++ b/drivers/input/misc/tps65219-pwrbutton.c
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Driver for TPS65219 Push Button
+//
+// Copyright (C) 2022 BayLibre Incorporated - https://www.baylibre.com/
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps65219.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+struct tps65219_pwrbutton {
+ struct device *dev;
+ struct input_dev *idev;
+ char phys[32];
+};
+
+static irqreturn_t tps65219_pb_push_irq(int irq, void *_pwr)
+{
+ struct tps65219_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 tps65219_pb_release_irq(int irq, void *_pwr)
+{
+ struct tps65219_pwrbutton *pwr = _pwr;
+
+ input_report_key(pwr->idev, KEY_POWER, 0);
+ input_sync(pwr->idev);
+
+ return IRQ_HANDLED;
+}
+
+static int tps65219_pb_probe(struct platform_device *pdev)
+{
+ struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct tps65219_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,
+ tps65219_pb_push_irq,
+ IRQF_ONESHOT,
+ dev->init_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,
+ tps65219_pb_release_irq,
+ IRQF_ONESHOT,
+ dev->init_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;
+ }
+
+ /* Enable interrupts for the pushbutton */
+ regmap_clear_bits(tps->regmap, TPS65219_REG_MASK_CONFIG,
+ TPS65219_REG_MASK_INT_FOR_PB_MASK);
+
+ /* Set PB/EN/VSENSE pin to be a pushbutton */
+ regmap_update_bits(tps->regmap, TPS65219_REG_MFP_2_CONFIG,
+ TPS65219_MFP_2_EN_PB_VSENSE_MASK, TPS65219_MFP_2_PB);
+
+ return 0;
+}
+
+static void tps65219_pb_remove(struct platform_device *pdev)
+{
+ struct tps65219 *tps = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ /* Disable interrupt for the pushbutton */
+ ret = regmap_set_bits(tps->regmap, TPS65219_REG_MASK_CONFIG,
+ TPS65219_REG_MASK_INT_FOR_PB_MASK);
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to disable irq (%pe)\n", ERR_PTR(ret));
+}
+
+static const struct platform_device_id tps65219_pwrbtn_id_table[] = {
+ { "tps65219-pwrbutton", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(platform, tps65219_pwrbtn_id_table);
+
+static struct platform_driver tps65219_pb_driver = {
+ .probe = tps65219_pb_probe,
+ .remove = tps65219_pb_remove,
+ .driver = {
+ .name = "tps65219_pwrbutton",
+ },
+ .id_table = tps65219_pwrbtn_id_table,
+};
+module_platform_driver(tps65219_pb_driver);
+
+MODULE_DESCRIPTION("TPS65219 Power Button");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Markus Schneider-Pargmann <msp@baylibre.com");
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 b307cca17022..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
*
@@ -26,6 +26,7 @@
#include <linux/errno.h>
#include <linux/input.h>
#include <linux/interrupt.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/mfd/twl.h>
diff --git a/drivers/input/misc/twl4030-vibra.c b/drivers/input/misc/twl4030-vibra.c
index e0ff616fb857..5fa7d4a7da36 100644
--- a/drivers/input/misc/twl4030-vibra.c
+++ b/drivers/input/misc/twl4030-vibra.c
@@ -143,7 +143,7 @@ static void twl4030_vibra_close(struct input_dev *input)
}
/*** Module ***/
-static int __maybe_unused twl4030_vibra_suspend(struct device *dev)
+static int twl4030_vibra_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct vibra_info *info = platform_get_drvdata(pdev);
@@ -154,41 +154,31 @@ static int __maybe_unused twl4030_vibra_suspend(struct device *dev)
return 0;
}
-static int __maybe_unused twl4030_vibra_resume(struct device *dev)
+static int twl4030_vibra_resume(struct device *dev)
{
vibra_disable_leds();
return 0;
}
-static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
- twl4030_vibra_suspend, twl4030_vibra_resume);
+static DEFINE_SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
+ twl4030_vibra_suspend, twl4030_vibra_resume);
-static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
- struct device_node *parent)
+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");
- if (pdata && pdata->coexist)
- return true;
-
- 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)
{
- struct twl4030_vibra_data *pdata = dev_get_platdata(&pdev->dev);
struct device_node *twl4030_core_node = pdev->dev.parent->of_node;
struct vibra_info *info;
int ret;
- if (!pdata && !twl4030_core_node) {
- dev_dbg(&pdev->dev, "platform_data not available\n");
+ if (!twl4030_core_node) {
+ dev_dbg(&pdev->dev, "twl4030 OF node is missing\n");
return -EINVAL;
}
@@ -197,7 +187,7 @@ static int twl4030_vibra_probe(struct platform_device *pdev)
return -ENOMEM;
info->dev = &pdev->dev;
- info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
+ info->coexist = twl4030_vibra_check_coexist(twl4030_core_node);
INIT_WORK(&info->play_work, vibra_play_work);
info->input_dev = devm_input_allocate_device(&pdev->dev);
@@ -239,7 +229,7 @@ static struct platform_driver twl4030_vibra_driver = {
.probe = twl4030_vibra_probe,
.driver = {
.name = "twl4030-vibra",
- .pm = &twl4030_vibra_pm_ops,
+ .pm = pm_sleep_ptr(&twl4030_vibra_pm_ops),
},
};
module_platform_driver(twl4030_vibra_driver);
diff --git a/drivers/input/misc/twl6040-vibra.c b/drivers/input/misc/twl6040-vibra.c
index bf6644927630..afed9af65bf9 100644
--- a/drivers/input/misc/twl6040-vibra.c
+++ b/drivers/input/misc/twl6040-vibra.c
@@ -210,7 +210,7 @@ static void twl6040_vibra_close(struct input_dev *input)
twl6040_vibra_disable(info);
}
-static int __maybe_unused twl6040_vibra_suspend(struct device *dev)
+static int twl6040_vibra_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct vibra_info *info = platform_get_drvdata(pdev);
@@ -223,19 +223,19 @@ static int __maybe_unused twl6040_vibra_suspend(struct device *dev)
return 0;
}
-static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
+static DEFINE_SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops,
+ twl6040_vibra_suspend, NULL);
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;
@@ -243,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;
}
@@ -263,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");
@@ -354,7 +351,7 @@ static struct platform_driver twl6040_vibra_driver = {
.probe = twl6040_vibra_probe,
.driver = {
.name = "twl6040-vibra",
- .pm = &twl6040_vibra_pm_ops,
+ .pm = pm_sleep_ptr(&twl6040_vibra_pm_ops),
},
};
module_platform_driver(twl6040_vibra_driver);
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index f2593133e524..13336a2fd49c 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -33,6 +33,7 @@
#define UINPUT_NAME "uinput"
#define UINPUT_BUFFER_SIZE 16
#define UINPUT_NUM_REQUESTS 16
+#define UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS 10
enum uinput_state { UIST_NEW_DEVICE, UIST_SETUP_COMPLETE, UIST_CREATED };
@@ -378,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;
@@ -416,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;
}
@@ -569,11 +584,40 @@ static int uinput_setup_device_legacy(struct uinput_device *udev,
return retval;
}
+/*
+ * Returns true if the given timestamp is valid (i.e., if all the following
+ * conditions are satisfied), false otherwise.
+ * 1) given timestamp is positive
+ * 2) it's within the allowed offset before the current time
+ * 3) it's not in the future
+ */
+static bool is_valid_timestamp(const ktime_t timestamp)
+{
+ ktime_t zero_time;
+ ktime_t current_time;
+ ktime_t min_time;
+ ktime_t offset;
+
+ zero_time = ktime_set(0, 0);
+ if (ktime_compare(zero_time, timestamp) >= 0)
+ return false;
+
+ current_time = ktime_get();
+ offset = ktime_set(UINPUT_TIMESTAMP_ALLOWED_OFFSET_SECS, 0);
+ min_time = ktime_sub(current_time, offset);
+
+ if (ktime_after(min_time, timestamp) || ktime_after(timestamp, current_time))
+ return false;
+
+ return true;
+}
+
static ssize_t uinput_inject_events(struct uinput_device *udev,
const char __user *buffer, size_t count)
{
struct input_event ev;
size_t bytes = 0;
+ ktime_t timestamp;
if (count != 0 && count < input_event_size())
return -EINVAL;
@@ -588,6 +632,10 @@ static ssize_t uinput_inject_events(struct uinput_device *udev,
if (input_event_from_user(buffer + bytes, &ev))
return -EFAULT;
+ timestamp = ktime_set(ev.input_event_sec, ev.input_event_usec * NSEC_PER_USEC);
+ if (is_valid_timestamp(timestamp))
+ input_set_timestamp(udev->dev, timestamp);
+
input_event(udev->dev, ev.type, ev.code, ev.value);
bytes += input_event_size();
cond_resched();
@@ -727,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;
/*
@@ -1084,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 80dfd72a02d3..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;
@@ -1286,16 +1286,13 @@ static int wistron_probe(struct platform_device *dev)
return 0;
}
-static int wistron_remove(struct platform_device *dev)
+static void wistron_remove(struct platform_device *dev)
{
wistron_led_remove();
input_unregister_device(wistron_idev);
bios_detach();
-
- return 0;
}
-#ifdef CONFIG_PM
static int wistron_suspend(struct device *dev)
{
if (have_wifi)
@@ -1330,14 +1327,11 @@ static const struct dev_pm_ops wistron_pm_ops = {
.poweroff = wistron_suspend,
.restore = wistron_resume,
};
-#endif
static struct platform_driver wistron_driver = {
.driver = {
.name = "wistron-bios",
-#ifdef CONFIG_PM
- .pm = &wistron_pm_ops,
-#endif
+ .pm = pm_sleep_ptr(&wistron_pm_ops),
},
.probe = wistron_probe,
.remove = wistron_remove,
diff --git a/drivers/input/misc/wm831x-on.c b/drivers/input/misc/wm831x-on.c
index a42fe041b73c..18eb319bc6f7 100644
--- a/drivers/input/misc/wm831x-on.c
+++ b/drivers/input/misc/wm831x-on.c
@@ -123,15 +123,13 @@ err:
return ret;
}
-static int wm831x_on_remove(struct platform_device *pdev)
+static void wm831x_on_remove(struct platform_device *pdev)
{
struct wm831x_on *wm831x_on = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
free_irq(irq, wm831x_on);
cancel_delayed_work_sync(&wm831x_on->work);
-
- return 0;
}
static struct platform_driver wm831x_on_driver = {
diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c
index 4ff5cd2a6d8d..67f1c7364c95 100644
--- a/drivers/input/misc/xen-kbdfront.c
+++ b/drivers/input/misc/xen-kbdfront.c
@@ -51,7 +51,7 @@ module_param_array(ptr_size, int, NULL, 0444);
MODULE_PARM_DESC(ptr_size,
"Pointing device width, height in pixels (default 800,600)");
-static int xenkbd_remove(struct xenbus_device *);
+static void xenkbd_remove(struct xenbus_device *);
static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
static void xenkbd_disconnect_backend(struct xenkbd_info *);
@@ -404,7 +404,7 @@ static int xenkbd_resume(struct xenbus_device *dev)
return xenkbd_connect_backend(dev, info);
}
-static int xenkbd_remove(struct xenbus_device *dev)
+static void xenkbd_remove(struct xenbus_device *dev)
{
struct xenkbd_info *info = dev_get_drvdata(&dev->dev);
@@ -417,7 +417,6 @@ static int xenkbd_remove(struct xenbus_device *dev)
input_unregister_device(info->mtouch);
free_page((unsigned long)info->page);
kfree(info);
- return 0;
}
static int xenkbd_connect_backend(struct xenbus_device *dev,
@@ -481,7 +480,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev,
error_evtchan:
xenbus_free_evtchn(dev, evtchn);
error_grant:
- gnttab_end_foreign_access(info->gref, 0, 0UL);
+ gnttab_end_foreign_access(info->gref, NULL);
info->gref = -1;
return ret;
}
@@ -492,7 +491,7 @@ static void xenkbd_disconnect_backend(struct xenkbd_info *info)
unbind_from_irqhandler(info->irq, info);
info->irq = -1;
if (info->gref >= 0)
- gnttab_end_foreign_access(info->gref, 0, 0UL);
+ gnttab_end_foreign_access(info->gref, NULL);
info->gref = -1;
}
@@ -542,6 +541,7 @@ static struct xenbus_driver xenkbd_driver = {
.remove = xenkbd_remove,
.resume = xenkbd_resume,
.otherend_changed = xenkbd_backend_changed,
+ .not_essential = true,
};
static int __init xenkbd_init(void)
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c
index 8ab01c7601b1..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)
@@ -905,7 +869,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
- ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+ ret = usb_maxpacket(udev, pipe);
if (ret != USB_PKT_LEN)
dev_err(&intf->dev, "invalid payload size %d, expected %zd\n",
ret, USB_PKT_LEN);
@@ -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);