* [PATCH 0/3] AW8695 haptic driver.
@ 2026-09-14 14:37 Griffin Kroah-Hartman
2026-09-14 14:37 ` [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 Griffin Kroah-Hartman
` (3 more replies)
0 siblings, 4 replies; 13+ messages in thread
From: Griffin Kroah-Hartman @ 2026-09-14 14:37 UTC (permalink / raw)
To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Luca Weiss, Bjorn Andersson, Konrad Dybcio
Cc: linux-input, devicetree, linux-kernel, linux-arm-msm,
Griffin Kroah-Hartman
Clean-up of the aw8695 haptic driver patchset that was sent in 2022.
Variables dependant on devicetree have been hardcoded, and unnecessary
functions have been removed.
Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
Signed-off-by: Luca Weiss <luca.weiss@fairphone.com>
---
Griffin Kroah-Hartman (1):
dt-bindings: input: Add compatibility for Awinic AW8695
Luca Weiss (2):
Input - aw8695: Add driver for AW8695 haptics
arm64: dts: qcom: sm7225-fairphone-fp4: Add AW8695 haptics
.../devicetree/bindings/input/awinic,aw86927.yaml | 1 +
arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 26 +-
drivers/input/misc/Kconfig | 11 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/aw8695.c | 753 +++++++++++++++++++++
5 files changed, 791 insertions(+), 1 deletion(-)
---
base-commit: 5e036ce12de91c6fd674dad33b169c6150be2a7a
change-id: 20260716-aw8695_haptic_fp4_driver-397431e97638
Best regards,
--
Griffin Kroah-Hartman <griffin.kroah@fairphone.com>
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 2026-09-14 14:37 [PATCH 0/3] AW8695 haptic driver Griffin Kroah-Hartman @ 2026-09-14 14:37 ` Griffin Kroah-Hartman 2026-09-17 8:38 ` Krzysztof Kozlowski 2026-09-14 14:37 ` [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics Griffin Kroah-Hartman ` (2 subsequent siblings) 3 siblings, 1 reply; 13+ messages in thread From: Griffin Kroah-Hartman @ 2026-09-14 14:37 UTC (permalink / raw) To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio Cc: linux-input, devicetree, linux-kernel, linux-arm-msm, Griffin Kroah-Hartman Add the AW8695 haptic driver to the binding documentation for the AW86927 and AW86938, as this binding needs the same properties. They are not compatible though, because the chip identification works differently compared to the 86927/86938 Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> --- Documentation/devicetree/bindings/input/awinic,aw86927.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml index bd74b81488f61d72b675b5701b321b30b3430be0..d9da85499cda4d62f14f36f1ce77627e37e348d7 100644 --- a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml +++ b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml @@ -17,6 +17,7 @@ properties: - enum: - awinic,aw86938 - const: awinic,aw86927 + - const: awinic,aw8695 reg: maxItems: 1 -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 2026-09-14 14:37 ` [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 Griffin Kroah-Hartman @ 2026-09-17 8:38 ` Krzysztof Kozlowski 0 siblings, 0 replies; 13+ messages in thread From: Krzysztof Kozlowski @ 2026-09-17 8:38 UTC (permalink / raw) To: Griffin Kroah-Hartman Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio, linux-input, devicetree, linux-kernel, linux-arm-msm On Mon, Sep 14, 2026 at 04:37:47PM +0200, Griffin Kroah-Hartman wrote: > Add the AW8695 haptic driver to the binding documentation for the > AW86927 and AW86938, as this binding needs the same properties. > > They are not compatible though, because the chip identification works > differently compared to the 86927/86938 > > Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > --- > Documentation/devicetree/bindings/input/awinic,aw86927.yaml | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml > index bd74b81488f61d72b675b5701b321b30b3430be0..d9da85499cda4d62f14f36f1ce77627e37e348d7 100644 > --- a/Documentation/devicetree/bindings/input/awinic,aw86927.yaml > +++ b/Documentation/devicetree/bindings/input/awinic,aw86927.yaml > @@ -17,6 +17,7 @@ properties: > - enum: > - awinic,aw86938 > - const: awinic,aw86927 > + - const: awinic,aw8695 This should be combined with the first item (const for aw86927) and turned into enum. Best regards, Krzysztof ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics 2026-09-14 14:37 [PATCH 0/3] AW8695 haptic driver Griffin Kroah-Hartman 2026-09-14 14:37 ` [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 Griffin Kroah-Hartman @ 2026-09-14 14:37 ` Griffin Kroah-Hartman 2026-09-14 14:55 ` sashiko-bot 2026-09-17 8:43 ` Krzysztof Kozlowski 2026-09-14 14:37 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Griffin Kroah-Hartman 2026-09-15 4:14 ` [PATCH 0/3] AW8695 haptic driver Val Packett 3 siblings, 2 replies; 13+ messages in thread From: Griffin Kroah-Hartman @ 2026-09-14 14:37 UTC (permalink / raw) To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio Cc: linux-input, devicetree, linux-kernel, linux-arm-msm, Griffin Kroah-Hartman From: Luca Weiss <luca.weiss@fairphone.com> Add a driver for interfacing with the Awinic AW8695 LRA Haptic Driver. The chip supports multiple modes of which only RAM mode is implemented. RTP mode would enable a user to "stream" waveform data but to my knowledge no such user space API exists in the kernel yet. We upload a basic sine wave to the chip and play this on request. Co-developed-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- drivers/input/misc/Kconfig | 11 + drivers/input/misc/Makefile | 1 + drivers/input/misc/aw8695.c | 753 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 765 insertions(+) diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 1f6c57dba030813c248c068eda26ca1842271cb2..8bc0fdc1a7bc4c1fb1bea69ed08dcd6002a7d5fe 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -137,6 +137,17 @@ config INPUT_AW86927 To compile this driver as a module, choose M here: the module will be called aw86927. +config INPUT_AW8695 + tristate "Awinic AW8695 haptics support" + depends on INPUT && I2C + select INPUT_FF_MEMLESS + select REGMAP_I2C + help + Say Y to enable support for the Awinic AW8695 haptics driver. + + To compile this driver as a module, choose M here: the module will + be called aw8695. + config INPUT_BBNSM_PWRKEY tristate "NXP BBNSM Power Key Driver" depends on ARCH_MXC || COMPILE_TEST diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 2281d6803fce92e54a05c2c4f57ee7f7ea7ef2b8..25fb845125f9bee5b808d3f3b8ee74b9e89af5f5 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -23,6 +23,7 @@ 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_AW8695) += aw8695.o obj-$(CONFIG_INPUT_BBNSM_PWRKEY) += nxp-bbnsm-pwrkey.o obj-$(CONFIG_INPUT_BMA150) += bma150.o obj-$(CONFIG_INPUT_CM109) += cm109.o diff --git a/drivers/input/misc/aw8695.c b/drivers/input/misc/aw8695.c new file mode 100644 index 0000000000000000000000000000000000000000..ea72562a7c2a7c4ab82e535a9cce2224623b5ffa --- /dev/null +++ b/drivers/input/misc/aw8695.c @@ -0,0 +1,753 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2026 Luca Weiss <luca.weiss@fairphone.com> + * Copyright (C) 2026 Griffin Kroah-Hartman <griffin.kroah@fairphone.com> + * + * Partially based on vendor driver: + * Copyright (c) 2018 AWINIC Technology CO., LTD + */ + +#include <linux/bitfield.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> + +#define AW8695_CHIPID 0x95 +#define AW8695_RESET 0xaa +/* Default of BASE_ADDR* registers */ +#define AW8695_RAM_BASE_ADDR 0x800 + +#define AW8695_HIGH_MASK GENMASK(15, 8) +#define AW8695_LOW_MASK GENMASK(7, 0) + +/* Chip ID */ +#define AW8695_ID_REG 0x00 + +/* System Status */ +#define AW8695_SYSST_REG 0x01 + +/* System Interrupt */ +#define AW8695_SYSINT_REG 0x02 +#define AW8695_SYSINT_BSTERRI BIT(7) +#define AW8695_SYSINT_OVI BIT(6) +#define AW8695_SYSINT_UVLI BIT(5) +#define AW8695_SYSINT_FF_AEI BIT(4) +#define AW8695_SYSINT_FF_AFI BIT(3) +#define AW8695_SYSINT_OCDI BIT(2) +#define AW8695_SYSINT_OTI BIT(1) +#define AW8695_SYSINT_DONEI BIT(0) + +/* System Interrupt Mask */ +#define AW8695_SYSINTM_REG 0x03 +#define AW8695_SYSINTM_BSTERR_OFF BIT(7) +#define AW8695_SYSINTM_OV_OFF BIT(6) +#define AW8695_SYSINTM_UVLO_OFF BIT(5) +#define AW8695_SYSINTM_OCD_OFF BIT(2) +#define AW8695_SYSINTM_OT_OFF BIT(1) + +/* System Control */ +#define AW8695_SYSCTRL_REG 0x04 +#define AW8695_SYSCTRL_RAMINIT_EN BIT(5) + +#define AW8695_SYSCTRL_PLAY_MODE_MASK GENMASK(3, 2) +#define AW8695_SYSCTRL_PLAY_MODE_RAM (0) + +#define AW8695_SYSCTRL_BST_MODE_MASK GENMASK(1, 1) +#define AW8695_SYSCTRL_BST_MODE_BYPASS (0) + +#define AW8695_SYSCTRL_WORK_MODE_MASK GENMASK(0, 0) +#define AW8695_SYSCTRL_STANDBY (1) +#define AW8695_SYSCTRL_ACTIVE (0) + +/* Process Control */ +#define AW8695_GO_REG 0x05 +#define AW8695_GO_ENABLE BIT(0) + +/* Waveform #1 */ +#define AW8695_WAVSEQ1_REG 0x07 + +/* Waveform #2 */ +#define AW8695_WAVSEQ2_REG 0x08 + +/* Waveform Loop #1 */ +#define AW8695_WAVLOOP1_REG 0x0f +#define AW8695_WAVLOOP1_SEQ1_MASK GENMASK(7, 4) +#define AW8695_WAVLOOP1_SEQ2_MASK GENMASK(3, 0) + +#define AW8695_WAVLOOP_INFINITE 0xf + +/* Debug Control */ +#define AW8695_DBGCTRL_REG 0x20 +#define AW8695_DBGCTRL_INT_MODE_MASK GENMASK(2, 2) +#define AW8695_DBGCTRL_INT_MODE_EDGE (1) + +/* PWM Output Protect Configuration */ +#define AW8695_PWMPRC_REG 0x2d +#define AW8695_PWMPRC_PRC_ENABLE BIT(7) + +/* PWM Debug */ +#define AW8695_PWMDBG_REG 0x2e +#define AW8695_PWMDBG_PWM_MODE_MASK GENMASK(6, 5) +#define AW8695_PWMDBG_PWM_24K (2) + +/* Debug Status */ +#define AW8695_DBGSTAT_REG 0x30 + +/* Boost Debug #1 */ +#define AW8695_BSTDBG1_REG 0x31 +#define AW8695_BSTDBG1_DEFAULT 0x30 + +/* Boost Debug #2 */ +#define AW8695_BSTDBG2_REG 0x32 +#define AW8695_BSTDBG2_DEFAULT 0xeb + +/* Boost Debug #3 */ +#define AW8695_BSTDBG3_REG 0x33 +#define AW8695_BSTDBG3_DEFAULT 0xd4 + +/* Boost Config */ +#define AW8695_BSTCFG_REG 0x34 +#define AW8695_BSTCFG_PEAKCUR_MASK GENMASK(2, 0) +#define AW8695_BSTCFG_PEAKCUR_2A (1) + +#define AW8695_ANADBG_REG 0x35 +#define AW8695_ANADBG_IOC_MASK GENMASK(3, 2) +#define AW8695_ANADBG_IOC_4P65A (3) + +/* Waveform Protect Level */ +#define AW8695_PRLVL_REG 0x3e +#define AW8695_PRLVL_PR_ENABLE BIT(7) + +/* SRAM Address 0xhigh */ +#define AW8695_RAMADDRH_REG 0x40 + +/* SRAM Address 0xlow */ +#define AW8695_RAMADDRL_REG 0x41 + +/* SRAM Data */ +#define AW8695_RAMDATA_REG 0x42 + +#define AW8695_GLB_STATE_REG 0x46 + +#define AW8695_BST_AUTO_REG 0x47 +#define AW8695_BST_AUTO_BST_AUTOSW_MASK GENMASK(2, 2) +#define AW8695_BST_AUTO_BST_MANUAL_BOOST (0) + +#define AW8695_TSET_REG 0x4d +#define AW8695_TSET_DEFAULT 0x12 + +#define AW8695_R_SPARE_REG 0x5d +#define Aw8695_R_SPARE_DEFAULT 0x68 + +/* Detection Control */ +#define AW8695_DETCTRL_REG 0x5f +#define AW8695_DETCTRL_PROTECT_MASK GENMASK(5, 5) +#define AW8695_DETCTRL_PROTECT_NO_ACTION (1) +#define AW8695_DETCTRL_DIAG_GO_ENABLE BIT(0) + +/* ADC Test */ +#define AW8695_ADCTEST_REG 0x66 +#define AW8695_ADCTEST_VBAT_MODE_MASK GENMASK(6, 6) +#define AW8695_ADCTEST_VBAT_HW_COMP (1) + +#define AW8695_BEMF_VTHH_H_REG 0x74 + +#define AW8695_BEMF_VTHH_L_REG 0x75 + +#define AW8695_BEMF_VTHL_H_REG 0x76 + +#define AW8695_BEMF_VTHL_L_REG 0x77 + +#define AW8695_MAX_REG 0x7f + +#define AW8695_BEMF_UPPER_THRESHOLD 0x1008 +#define AW8695_BEMF_LOWER_THRESHOLD 0x3f8 + +enum aw8695_work_mode { + AW8695_STANDBY_MODE, + AW8695_RAM_MODE, +}; + +struct aw8695_data { + struct input_dev *input_dev; + struct i2c_client *client; + struct regmap *regmap; + struct gpio_desc *reset_gpio; + u16 level; + struct work_struct play_work; +}; + +/* + * 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 aw8695_sine_waveform[] = { + 0x00, 0x05, 0x0a, 0x0f, 0x14, 0x19, 0x1e, 0x23, 0x28, 0x2c, 0x30, 0x35, + 0x39, 0x3c, 0x40, 0x43, 0x46, 0x49, 0x4b, 0x4d, 0x4f, 0x51, 0x52, 0x53, + 0x54, 0x54, 0x54, 0x54, 0x53, 0x52, 0x51, 0x4f, 0x4d, 0x4b, 0x49, 0x46, + 0x43, 0x40, 0x3c, 0x39, 0x35, 0x31, 0x2c, 0x28, 0x23, 0x1f, 0x1a, 0x15, + 0x10, 0x0b, 0x05, 0x00, 0xfb, 0xf6, 0xf1, 0xec, 0xe7, 0xe2, 0xdd, 0xd9, + 0xd4, 0xd0, 0xcc, 0xc8, 0xc4, 0xc0, 0xbd, 0xba, 0xb7, 0xb5, 0xb3, 0xb1, + 0xaf, 0xae, 0xad, 0xac, 0xac, 0xac, 0xac, 0xad, 0xae, 0xaf, 0xb1, 0xb2, + 0xb5, 0xb7, 0xba, 0xbd, 0xc0, 0xc3, 0xc7, 0xcb, 0xcf, 0xd3, 0xd8, 0xdc, + 0xe1, 0xe6, 0xeb, 0xf0, 0xf5, 0xfa +}; + +/* + * Header that gets written to AW8695 SRAM that describes the available + * waveforms being transferred afterwards. + * + * @version: waveform library version + * @start_address: start address of waveform in SRAM + * @end_address: end address of waveform in SRAM + */ +struct aw8695_sram_waveform_header { + u8 version; + __be16 start_address; + __be16 end_address; +} __packed; + +static const struct aw8695_sram_waveform_header sram_waveform_header = { + .version = 0x01, + .start_address = cpu_to_be16(AW8695_RAM_BASE_ADDR + + sizeof(struct aw8695_sram_waveform_header)), + .end_address = cpu_to_be16(AW8695_RAM_BASE_ADDR + + sizeof(struct aw8695_sram_waveform_header) + + ARRAY_SIZE(aw8695_sine_waveform) - 1), +}; + +static int aw8695_interrupt_clear(struct aw8695_data *haptics) +{ + unsigned int read_buf; + + /* Clear UVLI bit by reading register */ + return regmap_read(haptics->regmap, AW8695_SYSINT_REG, &read_buf); +} + +static int aw8695_haptic_set_active(struct aw8695_data *haptics) +{ + int err; + + err = regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_WORK_MODE_MASK, + FIELD_PREP(AW8695_SYSCTRL_WORK_MODE_MASK, + AW8695_SYSCTRL_ACTIVE)); + if (err) + return err; + + err = aw8695_interrupt_clear(haptics); + if (err) + return err; + + return regmap_update_bits(haptics->regmap, AW8695_SYSINTM_REG, + AW8695_SYSINTM_UVLO_OFF, 0); +} + +static int aw8695_play_mode(struct aw8695_data *haptics, + enum aw8695_work_mode mode) +{ + struct device *dev = &haptics->client->dev; + int err; + + switch (mode) { + case AW8695_STANDBY_MODE: + err = regmap_update_bits(haptics->regmap, AW8695_SYSINTM_REG, + AW8695_SYSINTM_UVLO_OFF, AW8695_SYSINTM_UVLO_OFF); + if (err) + return err; + + return regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_WORK_MODE_MASK, + FIELD_PREP(AW8695_SYSCTRL_WORK_MODE_MASK, + AW8695_SYSCTRL_STANDBY)); + case AW8695_RAM_MODE: + err = regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_PLAY_MODE_MASK, + FIELD_PREP(AW8695_SYSCTRL_PLAY_MODE_MASK, + AW8695_SYSCTRL_PLAY_MODE_RAM)); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_BST_MODE_MASK, + FIELD_PREP(AW8695_SYSCTRL_BST_MODE_MASK, + AW8695_SYSCTRL_BST_MODE_BYPASS)); + if (err) + return err; + + return aw8695_haptic_set_active(haptics); + default: + dev_err(dev, "Unhandled mode: %d\n", mode); + return -EINVAL; + } +} + +static int aw8695_haptics_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct aw8695_data *haptics = input_get_drvdata(dev); + int level; + + level = effect->u.rumble.strong_magnitude; + if (!level) + level = effect->u.rumble.weak_magnitude; + + if (haptics->level == level) + return 0; + + haptics->level = level; + schedule_work(&haptics->play_work); + + return 0; +} + +static void aw8695_hw_reset(struct aw8695_data *haptics) +{ + gpiod_set_value_cansleep(haptics->reset_gpio, 1); + + usleep_range(1000, 2000); + + gpiod_set_value_cansleep(haptics->reset_gpio, 0); + + usleep_range(3500, 4000); +} + +static int aw8695_stop(struct aw8695_data *haptics) +{ + int err; + unsigned int read_buf; + struct device *dev = &haptics->client->dev; + + err = regmap_update_bits(haptics->regmap, AW8695_GO_REG, + AW8695_GO_ENABLE, 0); + if (err) + return err; + + err = regmap_read_poll_timeout(haptics->regmap, AW8695_GLB_STATE_REG, read_buf, + (read_buf & 0x0f) == 0, 2000, 2000 * 100); + if (err) { + dev_err(dev, "Did not enter standby: %d\n Trying to force it...\n", err); + err = aw8695_play_mode(haptics, AW8695_STANDBY_MODE); + return err; + } + + return aw8695_play_mode(haptics, AW8695_STANDBY_MODE); +} + +static int aw8695_play_sine(struct aw8695_data *haptics) +{ + int err; + + err = aw8695_stop(haptics); + if (err) + return err; + + /* + * Configure for waveform #1 to be played infinitely, + * and waveform #2 to not be played. + */ + err = regmap_write(haptics->regmap, AW8695_WAVSEQ1_REG, 0x1); + if (err) + return err; + + err = regmap_write(haptics->regmap, AW8695_WAVSEQ2_REG, 0x0); + if (err) + return err; + + err = regmap_write(haptics->regmap, AW8695_WAVLOOP1_REG, + FIELD_PREP(AW8695_WAVLOOP1_SEQ1_MASK, + AW8695_WAVLOOP_INFINITE) | + FIELD_PREP(AW8695_WAVLOOP1_SEQ2_MASK, 0)); + if (err) + return err; + + /* Configure for RAM mode */ + err = aw8695_play_mode(haptics, AW8695_RAM_MODE); + if (err) + return err; + + /* Start vibration */ + return regmap_update_bits(haptics->regmap, AW8695_GO_REG, + AW8695_GO_ENABLE, AW8695_GO_ENABLE); +} + +static void aw8695_close(struct input_dev *input) +{ + struct aw8695_data *haptics = input_get_drvdata(input); + struct device *dev = &haptics->client->dev; + int err; + + cancel_work_sync(&haptics->play_work); + err = aw8695_stop(haptics); + if (err) + dev_err(dev, "Failed to stop haptics: %d\n", err); +} + +static void aw8695_haptics_play_work(struct work_struct *work) +{ + struct aw8695_data *haptics = + container_of(work, struct aw8695_data, play_work); + struct device *dev = &haptics->client->dev; + int err; + + if (haptics->level) + err = aw8695_play_sine(haptics); + else + err = aw8695_stop(haptics); + + if (err) + dev_err(dev, "Failed to execute work command: %d\n", err); +} + +static int aw8695_haptic_offset_calibration(struct aw8695_data *haptics) +{ + unsigned int read_buf; + int err; + + err = regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_RAMINIT_EN, + AW8695_SYSCTRL_RAMINIT_EN); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW8695_DETCTRL_REG, + AW8695_DETCTRL_DIAG_GO_ENABLE, + AW8695_DETCTRL_DIAG_GO_ENABLE); + if (err) + return err; + + err = regmap_read_poll_timeout(haptics->regmap, AW8695_DETCTRL_REG, read_buf, + (read_buf & AW8695_DETCTRL_DIAG_GO_ENABLE) == 0, 10000, 10000 * 50); + if (err) + return err; + + return regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_RAMINIT_EN, 0); +} + +static int aw8695_init(struct aw8695_data *haptics) +{ + int err; + unsigned int read_buf; + struct device *dev = &haptics->client->dev; + + aw8695_hw_reset(haptics); + + err = regmap_read(haptics->regmap, AW8695_ID_REG, &read_buf); + if (err) { + dev_err(dev, "Failed to read ID register: %d\n", err); + return err; + } + + if (read_buf != AW8695_CHIPID) { + dev_err(dev, "Chip ID mismatch: expected %x, got %x\n", + AW8695_CHIPID, read_buf); + return -ENODEV; + } + + err = regmap_write(haptics->regmap, AW8695_ID_REG, AW8695_RESET); + if (err) { + dev_err(dev, "Failed to reset: %d\n", err); + return err; + } + + /* Wait ~1ms after reset */ + usleep_range(1000, 1500); + + /* Clear UVLI bit by reading register */ + err = aw8695_interrupt_clear(haptics); + if (err) { + dev_err(dev, "Failed to clear interrupt: %d\n", err); + return err; + } + + /* Set interrupt mode to edge */ + err = regmap_update_bits(haptics->regmap, AW8695_DBGCTRL_REG, + AW8695_DBGCTRL_INT_MODE_MASK, + FIELD_PREP(AW8695_DBGCTRL_INT_MODE_MASK, + AW8695_DBGCTRL_INT_MODE_EDGE)); + if (err) { + dev_err(dev, "Failed to set interrupt mode: %d\n", err); + return err; + } + + /* Configure interrupts */ + err = regmap_update_bits(haptics->regmap, AW8695_SYSINTM_REG, + AW8695_SYSINTM_BSTERR_OFF | AW8695_SYSINTM_OV_OFF | + AW8695_SYSINTM_UVLO_OFF | AW8695_SYSINTM_OCD_OFF | + AW8695_SYSINTM_OT_OFF, + AW8695_SYSINTM_BSTERR_OFF); + if (err) + return err; + + err = aw8695_play_mode(haptics, AW8695_STANDBY_MODE); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW8695_PWMDBG_REG, + AW8695_PWMDBG_PWM_MODE_MASK, + FIELD_PREP(AW8695_PWMDBG_PWM_MODE_MASK, + AW8695_PWMDBG_PWM_24K)); + if (err) + return err; + + err = regmap_write(haptics->regmap, AW8695_BSTDBG1_REG, AW8695_BSTDBG1_DEFAULT); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_BSTDBG2_REG, AW8695_BSTDBG2_DEFAULT); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_BSTDBG3_REG, AW8695_BSTDBG3_DEFAULT); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_TSET_REG, AW8695_TSET_DEFAULT); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_R_SPARE_REG, Aw8695_R_SPARE_DEFAULT); + if (err) + return err; + + err = regmap_update_bits(haptics->regmap, AW8695_ANADBG_REG, + AW8695_ANADBG_IOC_MASK, + FIELD_PREP(AW8695_ANADBG_IOC_MASK, + AW8695_ANADBG_IOC_4P65A)); + if (err) + return err; + + /* Set boost peak current */ + err = regmap_update_bits(haptics->regmap, AW8695_BSTCFG_REG, + AW8695_BSTCFG_PEAKCUR_MASK, + FIELD_PREP(AW8695_BSTCFG_PEAKCUR_MASK, + AW8695_BSTCFG_PEAKCUR_2A)); + if (err) + return err; + + /* Adjust motorprotect config */ + err = regmap_update_bits(haptics->regmap, AW8695_DETCTRL_REG, + AW8695_DETCTRL_PROTECT_MASK, + FIELD_PREP(AW8695_DETCTRL_PROTECT_MASK, + AW8695_DETCTRL_PROTECT_NO_ACTION)); + if (err) + return err; + err = regmap_update_bits(haptics->regmap, AW8695_PWMPRC_REG, + AW8695_PWMPRC_PRC_ENABLE, 0); + if (err) + return err; + err = regmap_update_bits(haptics->regmap, AW8695_PRLVL_REG, + AW8695_PRLVL_PR_ENABLE, 0); + if (err) + return err; + + /* Adjust auto boost config */ + err = regmap_update_bits(haptics->regmap, AW8695_BST_AUTO_REG, + AW8695_BST_AUTO_BST_AUTOSW_MASK, + FIELD_PREP(AW8695_BST_AUTO_BST_AUTOSW_MASK, + AW8695_BST_AUTO_BST_MANUAL_BOOST)); + if (err) + return err; + + err = aw8695_haptic_offset_calibration(haptics); + if (err) + return err; + + /* Set vbat compensation mode */ + err = regmap_update_bits(haptics->regmap, AW8695_ADCTEST_REG, + AW8695_ADCTEST_VBAT_MODE_MASK, + FIELD_PREP(AW8695_ADCTEST_VBAT_MODE_MASK, + AW8695_ADCTEST_VBAT_HW_COMP)); + if (err) + return err; + + /* bemf config */ + err = regmap_write(haptics->regmap, AW8695_BEMF_VTHH_H_REG, + FIELD_GET(AW8695_HIGH_MASK, AW8695_BEMF_UPPER_THRESHOLD)); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_BEMF_VTHH_L_REG, + FIELD_GET(AW8695_LOW_MASK, AW8695_BEMF_UPPER_THRESHOLD)); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_BEMF_VTHL_H_REG, + FIELD_GET(AW8695_HIGH_MASK, AW8695_BEMF_LOWER_THRESHOLD)); + if (err) + return err; + return regmap_write(haptics->regmap, AW8695_BEMF_VTHL_L_REG, + FIELD_GET(AW8695_LOW_MASK, AW8695_BEMF_LOWER_THRESHOLD)); +} + +static int aw8695_ram_init(struct aw8695_data *haptics) +{ + int err; + + /* Enable SRAM init */ + err = regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_RAMINIT_EN, AW8695_SYSCTRL_RAMINIT_EN); + if (err) + return err; + + /* Set RAMDATA write address */ + err = regmap_write(haptics->regmap, AW8695_RAMADDRH_REG, + FIELD_GET(AW8695_HIGH_MASK, AW8695_RAM_BASE_ADDR)); + if (err) + return err; + err = regmap_write(haptics->regmap, AW8695_RAMADDRL_REG, + FIELD_GET(AW8695_LOW_MASK, AW8695_RAM_BASE_ADDR)); + if (err) + return err; + + err = regmap_noinc_write(haptics->regmap, AW8695_RAMDATA_REG, + &sram_waveform_header, sizeof(sram_waveform_header)); + if (err) + return err; + + err = regmap_noinc_write(haptics->regmap, AW8695_RAMDATA_REG, + aw8695_sine_waveform, ARRAY_SIZE(aw8695_sine_waveform)); + if (err) + return err; + + /* Disable SRAM init */ + return regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, + AW8695_SYSCTRL_RAMINIT_EN, 0); +} + +static irqreturn_t aw8695_irq(int irq, void *data) +{ + struct aw8695_data *haptics = data; + struct device *dev = &haptics->client->dev; + unsigned int read_buf; + int err; + + err = regmap_read(haptics->regmap, AW8695_SYSINT_REG, &read_buf); + if (err) { + dev_err(dev, "Failed to read SYSINT register: %d\n", err); + return IRQ_NONE; + } + dev_dbg(dev, "Interrupt: SYSINT=0x%x\n", read_buf); + + if (read_buf & AW8695_SYSINT_BSTERRI) + dev_err(dev, "Received boost short circuit protection or over-voltage protection interrupt!\n"); + if (read_buf & AW8695_SYSINT_OVI) + dev_err(dev, "Received wave data overflow or DPWM DC error interrupt!\n"); + if (read_buf & AW8695_SYSINT_UVLI) + dev_err(dev, "Received under voltage lock out interrupt!\n"); + if (read_buf & AW8695_SYSINT_OCDI) + dev_err(dev, "Received over current interrupt!\n"); + if (read_buf & AW8695_SYSINT_OTI) + dev_err(dev, "Received over temperature interrupt!\n"); + + if (read_buf & AW8695_SYSINT_DONEI) + dev_dbg(dev, "Received playback done interrupt\n"); + /* FIFO mode is not (yet) implemented in this driver */ + if (read_buf & AW8695_SYSINT_FF_AEI) + dev_dbg(dev, "Received FIFO almost empty interrupt\n"); + if (read_buf & AW8695_SYSINT_FF_AFI) + dev_dbg(dev, "Received FIFO almost full interrupt\n"); + + err = regmap_read(haptics->regmap, AW8695_DBGSTAT_REG, &read_buf); + if (err) { + dev_err(dev, "Failed to read DBGSTAT register: %d\n", err); + return IRQ_NONE; + } + dev_dbg(dev, "Interrupt: DBGSTAT=0x%x\n", read_buf); + + err = regmap_read(haptics->regmap, AW8695_SYSST_REG, &read_buf); + if (err) { + dev_err(dev, "Failed to read SYSST register: %d\n", err); + return IRQ_NONE; + } + dev_dbg(dev, "Interrupt: SYSST=0x%x\n", read_buf); + + return IRQ_HANDLED; +} + +static const struct regmap_config aw8695_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = AW8695_MAX_REG, + .cache_type = REGCACHE_NONE, +}; + +static int aw8695_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct aw8695_data *haptics; + int err; + + haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL); + if (!haptics) + return -ENOMEM; + + haptics->client = client; + i2c_set_clientdata(client, haptics); + + haptics->regmap = devm_regmap_init_i2c(client, &aw8695_regmap_config); + if (IS_ERR(haptics->regmap)) + return dev_err_probe(dev, PTR_ERR(haptics->regmap), + "Failed to allocate register map\n"); + + haptics->input_dev = devm_input_allocate_device(dev); + if (!haptics->input_dev) + return -ENOMEM; + + haptics->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(haptics->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(haptics->reset_gpio), + "Failed to get reset gpio\n"); + + err = devm_request_threaded_irq(dev, client->irq, NULL, aw8695_irq, + IRQF_ONESHOT, NULL, haptics); + if (err) + return dev_err_probe(dev, err, "Failed to request interrupt\n"); + + INIT_WORK(&haptics->play_work, aw8695_haptics_play_work); + + haptics->input_dev->name = "aw8695"; + haptics->input_dev->close = aw8695_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, + aw8695_haptics_play); + if (err) + return dev_err_probe(dev, err, "Failed to create FF dev\n"); + + err = aw8695_init(haptics); + if (err) + return dev_err_probe(dev, err, "Failed to init aw8695\n"); + + err = aw8695_ram_init(haptics); + if (err) + return dev_err_probe(dev, err, "Failed to init aw8695 sram\n"); + + err = input_register_device(haptics->input_dev); + if (err) + return dev_err_probe(dev, err, "Failed to register input device\n"); + + return 0; +} + +static const struct of_device_id aw8695_of_id[] = { + { .compatible = "awinic,aw8695", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, aw8695_of_id); + +static struct i2c_driver aw8695_driver = { + .driver = { + .name = "aw8695", + .of_match_table = aw8695_of_id, + }, + .probe = aw8695_probe, +}; + +module_i2c_driver(aw8695_driver); + +MODULE_AUTHOR("Luca Weiss <luca.weiss@fairphone.com>"); +MODULE_DESCRIPTION("AW8695 LRA Haptic Driver"); +MODULE_LICENSE("GPL"); -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics 2026-09-14 14:37 ` [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics Griffin Kroah-Hartman @ 2026-09-14 14:55 ` sashiko-bot 2026-09-17 8:43 ` Krzysztof Kozlowski 1 sibling, 0 replies; 13+ messages in thread From: sashiko-bot @ 2026-09-14 14:55 UTC (permalink / raw) To: Griffin Kroah-Hartman Cc: conor+dt, devicetree, linux-input, dmitry.torokhov, robh Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] The haptic motor will vibrate indefinitely if the system enters suspend while an effect is playing, due to missing PM callbacks. - [Low] Returning an error-producing action directly instead of using explicit failure paths in functions with multiple failure points. -- commit aaa9fe6e99ccfee800cc251fa21a6409a47045f8 Author: Luca Weiss <luca.weiss@fairphone.com> Input - aw8695: Add driver for AW8695 haptics Add a driver for interfacing with the Awinic AW8695 LRA Haptic Driver. The chip supports multiple modes of which only RAM mode is implemented. > diff --git a/drivers/input/misc/aw8695.c b/drivers/input/misc/aw8695.c > index 0000000000000..ea72562a7c2a7 > --- /dev/null > +++ b/drivers/input/misc/aw8695.c > @@ -0,0 +1,753 @@ [ ... ] > +static int aw8695_stop(struct aw8695_data *haptics) > +{ > + int err; > + unsigned int read_buf; > + struct device *dev = &haptics->client->dev; > + > + err = regmap_update_bits(haptics->regmap, AW8695_GO_REG, > + AW8695_GO_ENABLE, 0); > + if (err) > + return err; > + > + err = regmap_read_poll_timeout(haptics->regmap, AW8695_GLB_STATE_REG, read_buf, > + (read_buf & 0x0f) == 0, 2000, 2000 * 100); > + if (err) { > + dev_err(dev, "Did not enter standby: %d\n Trying to force it...\n", err); > + err = aw8695_play_mode(haptics, AW8695_STANDBY_MODE); > + return err; > + } > + > + return aw8695_play_mode(haptics, AW8695_STANDBY_MODE); [Severity: Low] This isn't a bug, but can we use explicit error handling here instead of directly returning the aw8695_play_mode() error code? The input subsystem prefers checking the error and returning 0 explicitly in functions with multiple failure points. > +} > + > +static int aw8695_play_sine(struct aw8695_data *haptics) > +{ > + int err; > + > + err = aw8695_stop(haptics); > + if (err) > + return err; > + > + /* > + * Configure for waveform #1 to be played infinitely, > + * and waveform #2 to not be played. > + */ > + err = regmap_write(haptics->regmap, AW8695_WAVSEQ1_REG, 0x1); > + if (err) > + return err; > + > + err = regmap_write(haptics->regmap, AW8695_WAVSEQ2_REG, 0x0); > + if (err) > + return err; > + > + err = regmap_write(haptics->regmap, AW8695_WAVLOOP1_REG, > + FIELD_PREP(AW8695_WAVLOOP1_SEQ1_MASK, > + AW8695_WAVLOOP_INFINITE) | > + FIELD_PREP(AW8695_WAVLOOP1_SEQ2_MASK, 0)); [Severity: Medium] Since this configures the hardware to play the waveform infinitely, it relies entirely on the software timer to stop the haptic effect. If the system enters suspend while an effect is playing, will the haptic motor vibrate indefinitely until the system wakes up and the timer resumes? > + if (err) > + return err; > + > + /* Configure for RAM mode */ > + err = aw8695_play_mode(haptics, AW8695_RAM_MODE); > + if (err) > + return err; > + > + /* Start vibration */ > + return regmap_update_bits(haptics->regmap, AW8695_GO_REG, > + AW8695_GO_ENABLE, AW8695_GO_ENABLE); [Severity: Low] This isn't a bug, but could this be converted to an explicit error check and return 0 to match the input subsystem's preferred coding style? [ ... ] > +static int aw8695_init(struct aw8695_data *haptics) > +{ > + int err; > + unsigned int read_buf; > + struct device *dev = &haptics->client->dev; [ ... ] > + /* bemf config */ > + err = regmap_write(haptics->regmap, AW8695_BEMF_VTHH_H_REG, > + FIELD_GET(AW8695_HIGH_MASK, AW8695_BEMF_UPPER_THRESHOLD)); > + if (err) > + return err; > + err = regmap_write(haptics->regmap, AW8695_BEMF_VTHH_L_REG, > + FIELD_GET(AW8695_LOW_MASK, AW8695_BEMF_UPPER_THRESHOLD)); > + if (err) > + return err; > + err = regmap_write(haptics->regmap, AW8695_BEMF_VTHL_H_REG, > + FIELD_GET(AW8695_HIGH_MASK, AW8695_BEMF_LOWER_THRESHOLD)); > + if (err) > + return err; > + return regmap_write(haptics->regmap, AW8695_BEMF_VTHL_L_REG, > + FIELD_GET(AW8695_LOW_MASK, AW8695_BEMF_LOWER_THRESHOLD)); [Severity: Low] This isn't a bug, but should this return be expanded into an explicit error check returning 0? > +} > + > +static int aw8695_ram_init(struct aw8695_data *haptics) > +{ > + int err; [ ... ] > + err = regmap_noinc_write(haptics->regmap, AW8695_RAMDATA_REG, > + aw8695_sine_waveform, ARRAY_SIZE(aw8695_sine_waveform)); > + if (err) > + return err; > + > + /* Disable SRAM init */ > + return regmap_update_bits(haptics->regmap, AW8695_SYSCTRL_REG, > + AW8695_SYSCTRL_RAMINIT_EN, 0); [Severity: Low] This isn't a bug, but should this have an explicit error check instead of directly returning the regmap_update_bits() result? [ ... ] > +static struct i2c_driver aw8695_driver = { > + .driver = { > + .name = "aw8695", > + .of_match_table = aw8695_of_id, > + }, > + .probe = aw8695_probe, > +}; [Severity: Medium] Should this driver populate pm callbacks in the driver struct? If the system enters suspend while playing an infinitely looping waveform, the software timer will freeze, potentially leaving the motor running indefinitely. A suspend handler might be needed to safely stop the hardware. -- Sashiko AI review · https://sashiko.dev/#/patchset/20260914-aw8695_haptic_fp4_driver-v1-0-156f7549149a@fairphone.com?part=2 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics 2026-09-14 14:37 ` [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics Griffin Kroah-Hartman 2026-09-14 14:55 ` sashiko-bot @ 2026-09-17 8:43 ` Krzysztof Kozlowski 1 sibling, 0 replies; 13+ messages in thread From: Krzysztof Kozlowski @ 2026-09-17 8:43 UTC (permalink / raw) To: Griffin Kroah-Hartman Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio, linux-input, devicetree, linux-kernel, linux-arm-msm On Mon, Sep 14, 2026 at 04:37:48PM +0200, Griffin Kroah-Hartman wrote: > From: Luca Weiss <luca.weiss@fairphone.com> > > Add a driver for interfacing with the Awinic AW8695 LRA Haptic Driver. > > The chip supports multiple modes of which only RAM mode is implemented. > RTP mode would enable a user to "stream" waveform data but to my > knowledge no such user space API exists in the kernel yet. > > We upload a basic sine wave to the chip and play this on request. > > Co-developed-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> Your SoB should be the last, after your codev, after author's. > +static irqreturn_t aw8695_irq(int irq, void *data) > +{ > + struct aw8695_data *haptics = data; > + struct device *dev = &haptics->client->dev; > + unsigned int read_buf; > + int err; > + > + err = regmap_read(haptics->regmap, AW8695_SYSINT_REG, &read_buf); > + if (err) { > + dev_err(dev, "Failed to read SYSINT register: %d\n", err); > + return IRQ_NONE; > + } > + dev_dbg(dev, "Interrupt: SYSINT=0x%x\n", read_buf); > + > + if (read_buf & AW8695_SYSINT_BSTERRI) > + dev_err(dev, "Received boost short circuit protection or over-voltage protection interrupt!\n"); > + if (read_buf & AW8695_SYSINT_OVI) > + dev_err(dev, "Received wave data overflow or DPWM DC error interrupt!\n"); > + if (read_buf & AW8695_SYSINT_UVLI) > + dev_err(dev, "Received under voltage lock out interrupt!\n"); > + if (read_buf & AW8695_SYSINT_OCDI) > + dev_err(dev, "Received over current interrupt!\n"); > + if (read_buf & AW8695_SYSINT_OTI) > + dev_err(dev, "Received over temperature interrupt!\n"); > + > + if (read_buf & AW8695_SYSINT_DONEI) > + dev_dbg(dev, "Received playback done interrupt\n"); > + /* FIFO mode is not (yet) implemented in this driver */ > + if (read_buf & AW8695_SYSINT_FF_AEI) > + dev_dbg(dev, "Received FIFO almost empty interrupt\n"); > + if (read_buf & AW8695_SYSINT_FF_AFI) > + dev_dbg(dev, "Received FIFO almost full interrupt\n"); > + > + err = regmap_read(haptics->regmap, AW8695_DBGSTAT_REG, &read_buf); > + if (err) { > + dev_err(dev, "Failed to read DBGSTAT register: %d\n", err); > + return IRQ_NONE; > + } > + dev_dbg(dev, "Interrupt: DBGSTAT=0x%x\n", read_buf); > + > + err = regmap_read(haptics->regmap, AW8695_SYSST_REG, &read_buf); > + if (err) { > + dev_err(dev, "Failed to read SYSST register: %d\n", err); > + return IRQ_NONE; > + } > + dev_dbg(dev, "Interrupt: SYSST=0x%x\n", read_buf); You should not have three debugs (and possibly +3 more in if() conditions) in interrupt handler. In case of irq storm this still will overwhelm the log. This should be only one and most likely dev_dbg_ratelimited(). Errors should also have ratelimit, even if IRQ storm with errors is unlikely or even drop them completely - isn't regmap already going to print some errors in such case? > + > + return IRQ_HANDLED; > +} Best regards, Krzysztof ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add AW8695 haptics 2026-09-14 14:37 [PATCH 0/3] AW8695 haptic driver Griffin Kroah-Hartman 2026-09-14 14:37 ` [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 Griffin Kroah-Hartman 2026-09-14 14:37 ` [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics Griffin Kroah-Hartman @ 2026-09-14 14:37 ` Griffin Kroah-Hartman 2026-09-15 10:04 ` Abel Vesa 2026-09-17 9:25 ` Konrad Dybcio 2026-09-15 4:14 ` [PATCH 0/3] AW8695 haptic driver Val Packett 3 siblings, 2 replies; 13+ messages in thread From: Griffin Kroah-Hartman @ 2026-09-14 14:37 UTC (permalink / raw) To: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio Cc: linux-input, devicetree, linux-kernel, linux-arm-msm, Griffin Kroah-Hartman From: Luca Weiss <luca.weiss@fairphone.com> Add a node for the haptics driver found on the phone. Co-developed-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts | 26 ++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts index 23f950067a08b5ac4f7f9f61cbe060fa00b9f485..8a55a1d3426bce699a076e75b948b3def698fc36 100644 --- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts @@ -707,7 +707,17 @@ vreg_l7p: ldo7 { /* PX8618 @ 26 */ /* SMB1395 PMIC @ 34 */ - /* awinic,aw8695 @ 5a */ + + haptics@5a { + compatible = "awinic,aw8695"; + reg = <0x5a>; + + interrupts-extended = <&tlmm 85 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 90 GPIO_ACTIVE_LOW>; + + pinctrl-0 = <&aw8695_int_default>, <&aw8695_reset_default>; + pinctrl-names = "default"; + }; }; &ipa { @@ -1178,6 +1188,20 @@ reset-n-pins { bias-disable; }; }; + + aw8695_int_default: aw8695-int-default-state { + pins = "gpio85"; + function = "gpio"; + drive-strength = <2>; + bias-pull-up; + }; + + aw8695_reset_default: aw8695-reset-default-state { + pins = "gpio90"; + function = "gpio"; + drive-strength = <2>; + bias-pull-down; + }; }; &uart1 { -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add AW8695 haptics 2026-09-14 14:37 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Griffin Kroah-Hartman @ 2026-09-15 10:04 ` Abel Vesa 2026-09-17 9:25 ` Konrad Dybcio 1 sibling, 0 replies; 13+ messages in thread From: Abel Vesa @ 2026-09-15 10:04 UTC (permalink / raw) To: Griffin Kroah-Hartman Cc: Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio, linux-input, devicetree, linux-kernel, linux-arm-msm On 26-09-14 16:37:49, Griffin Kroah-Hartman wrote: > From: Luca Weiss <luca.weiss@fairphone.com> > > Add a node for the haptics driver found on the phone. > > Co-developed-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> Reviewed-by: Abel Vesa <abel.vesa@oss.qualcomm.com> ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add AW8695 haptics 2026-09-14 14:37 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Griffin Kroah-Hartman 2026-09-15 10:04 ` Abel Vesa @ 2026-09-17 9:25 ` Konrad Dybcio 1 sibling, 0 replies; 13+ messages in thread From: Konrad Dybcio @ 2026-09-17 9:25 UTC (permalink / raw) To: Griffin Kroah-Hartman, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio Cc: linux-input, devicetree, linux-kernel, linux-arm-msm On 9/14/26 4:37 PM, Griffin Kroah-Hartman wrote: > From: Luca Weiss <luca.weiss@fairphone.com> > > Add a node for the haptics driver found on the phone. > > Co-developed-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > Signed-off-by: Griffin Kroah-Hartman <griffin.kroah@fairphone.com> > Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> > --- [...] > + aw8695_int_default: aw8695-int-default-state { > + pins = "gpio85"; > + function = "gpio"; > + drive-strength = <2>; > + bias-pull-up; > + }; > + > + aw8695_reset_default: aw8695-reset-default-state { > + pins = "gpio90"; > + function = "gpio"; > + drive-strength = <2>; > + bias-pull-down; Shouldn't this be a pull-up if the reset is active-low? Konrad ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/3] AW8695 haptic driver. 2026-09-14 14:37 [PATCH 0/3] AW8695 haptic driver Griffin Kroah-Hartman ` (2 preceding siblings ...) 2026-09-14 14:37 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Griffin Kroah-Hartman @ 2026-09-15 4:14 ` Val Packett 2026-09-24 9:01 ` Griffin Kroah-Hartman 3 siblings, 1 reply; 13+ messages in thread From: Val Packett @ 2026-09-15 4:14 UTC (permalink / raw) To: Griffin Kroah-Hartman, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio Cc: linux-input, devicetree, linux-kernel, linux-arm-msm On 9/14/26 11:37 AM, Griffin Kroah-Hartman wrote: > Clean-up of the aw8695 haptic driver patchset that was sent in 2022. > Variables dependant on devicetree have been hardcoded, and unnecessary > functions have been removed. > [..] This looks similar to aw86927.c just with a somewhat different register layout, but there's even the same waveform and so on. Could it be better / worth it to do everything in one driver (aw86927.c) and only have different register accessors per model but shared "logic" overall? Or would that make testing too annoying? FWIW I've been trying to bring up aw86224 which has even fewer (but still *some*) differences to aw86927, so I'm potentially interested in having a unified base to add it to (when I figure out why it's stuck in overvoltage protection or whatever it was..) Thanks, ~val ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 0/3] AW8695 haptic driver. 2026-09-15 4:14 ` [PATCH 0/3] AW8695 haptic driver Val Packett @ 2026-09-24 9:01 ` Griffin Kroah-Hartman 0 siblings, 0 replies; 13+ messages in thread From: Griffin Kroah-Hartman @ 2026-09-24 9:01 UTC (permalink / raw) To: Val Packett, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, Conor Dooley, Luca Weiss, Bjorn Andersson, Konrad Dybcio Cc: linux-input, devicetree, linux-kernel, linux-arm-msm Hi Val, On 9/15/26 06:14, Val Packett wrote: > > On 9/14/26 11:37 AM, Griffin Kroah-Hartman wrote: >> Clean-up of the aw8695 haptic driver patchset that was sent in 2022. >> Variables dependant on devicetree have been hardcoded, and unnecessary >> functions have been removed. >> [..] > > This looks similar to aw86927.c just with a somewhat different register > layout, but there's even the same waveform and so on. > > Could it be better / worth it to do everything in one driver (aw86927.c) > and only have different register accessors per model but shared "logic" > overall? Or would that make testing too annoying? You're totally right with the similarities, and the original idea was to add on to the '27s driver, unfortunately the register layouts are too different for it to be worth it. > FWIW I've been trying to bring up aw86224 which has even fewer (but > still *some*) differences to aw86927, so I'm potentially interested in > having a unified base to add it to (when I figure out why it's stuck in > overvoltage protection or whatever it was..) After a brief glance at the register layout for the aw86224, it totally seems compatible with the aw86927, lots of shared registers, so I definitely think that your approach is the way to go there. > Thanks, > ~val Good luck with the aw869224! Best, Griffin ^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/3] dt-bindings: input: Add bindings for Awinic AW8695 haptics @ 2022-04-08 11:53 Luca Weiss 2022-04-08 11:53 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Luca Weiss 0 siblings, 1 reply; 13+ messages in thread From: Luca Weiss @ 2022-04-08 11:53 UTC (permalink / raw) To: linux-input Cc: ~postmarketos/upstreaming, phone-devel, Luca Weiss, Dmitry Torokhov, Rob Herring, Krzysztof Kozlowski, devicetree, linux-kernel Add a document describing the bindings for the AW8695 LRA Haptic Driver. Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- .../bindings/input/awinic,aw8695-haptics.yaml | 133 ++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/awinic,aw8695-haptics.yaml diff --git a/Documentation/devicetree/bindings/input/awinic,aw8695-haptics.yaml b/Documentation/devicetree/bindings/input/awinic,aw8695-haptics.yaml new file mode 100644 index 000000000000..9f573daaba0e --- /dev/null +++ b/Documentation/devicetree/bindings/input/awinic,aw8695-haptics.yaml @@ -0,0 +1,133 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/awinic,aw8695-haptics.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Awinic AW8695 LRA Haptic Driver + +maintainers: + - Luca Weiss <luca.weiss@fairphone.com> + +properties: + compatible: + const: awinic,aw8695 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + description: GPIO connected to INTN pin (edge falling) + + reset-gpios: + maxItems: 1 + description: GPIO connected to RSTN pin (active high) + + awinic,f0-preset: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Default value for the f0 of LRA + + awinic,f0-coefficient: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Coefficient between actual f0 and the value in the registers + + awinic,f0-calibration-percent: + maxItems: 1 + description: Limit of f0 deviation from awinic,f0-preset + + awinic,drive-level: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Level of drive waveform in normal driving + + awinic,f0-detection-play-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Drive waveform play times in the first period in the f0 detection + + awinic,f0-detection-wait-time: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Waveform wait times in the f0 detection + + awinic,f0-detection-repeat: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Repeat times in the f0 detection + + awinic,f0-detection-trace: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Drive waveform play times in the second period and later in the f0 detection + + awinic,boost-debug: + $ref: /schemas/types.yaml#/definitions/uint8-array + minItems: 3 + maxItems: 3 + description: Values for BSTDBG1-3 registers + + awinic,tset: + $ref: /schemas/types.yaml#/definitions/uint8 + description: Value for TSET register + + awinic,r-spare: + $ref: /schemas/types.yaml#/definitions/uint8 + description: Value for R_SPARE register + + awinic,bemf-upper-threshold: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Back EMF (electromotive force) upper threshold + + awinic,bemf-lower-threshold: + $ref: /schemas/types.yaml#/definitions/uint32 + description: Back EMF (electromotive force) lower threshold + +required: + - compatible + - reg + - interrupts + - reset-gpios + - awinic,f0-preset + - awinic,f0-coefficient + - awinic,f0-calibration-percent + - awinic,drive-level + - awinic,f0-detection-play-time + - awinic,f0-detection-wait-time + - awinic,f0-detection-repeat + - awinic,f0-detection-trace + - awinic,boost-debug + - awinic,tset + - awinic,r-spare + - awinic,bemf-upper-threshold + - awinic,bemf-lower-threshold + +additionalProperties: false + +examples: + - | + #include <dt-bindings/gpio/gpio.h> + #include <dt-bindings/interrupt-controller/irq.h> + i2c { + #address-cells = <1>; + #size-cells = <0>; + + haptics@5a { + compatible = "awinic,aw8695"; + reg = <0x5a>; + interrupts-extended = <&tlmm 85 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 90 GPIO_ACTIVE_HIGH>; + + awinic,f0-preset = <2350>; + awinic,f0-coefficient = <260>; + awinic,f0-calibration-percent = <7>; + awinic,drive-level = <125>; + + awinic,f0-detection-play-time = <5>; + awinic,f0-detection-wait-time = <3>; + awinic,f0-detection-repeat = <2>; + awinic,f0-detection-trace = <15>; + + awinic,boost-debug = /bits/ 8 <0x30 0xeb 0xd4>; + awinic,tset = /bits/ 8 <0x12>; + awinic,r-spare = /bits/ 8 <0x68>; + + awinic,bemf-upper-threshold = <4104>; + awinic,bemf-lower-threshold = <1016>; + }; + }; -- 2.35.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add AW8695 haptics 2022-04-08 11:53 [PATCH 1/3] dt-bindings: input: Add bindings for Awinic AW8695 haptics Luca Weiss @ 2022-04-08 11:53 ` Luca Weiss 2022-04-08 19:49 ` kernel test robot 0 siblings, 1 reply; 13+ messages in thread From: Luca Weiss @ 2022-04-08 11:53 UTC (permalink / raw) To: linux-input Cc: ~postmarketos/upstreaming, phone-devel, Luca Weiss, Andy Gross, Bjorn Andersson, Rob Herring, Krzysztof Kozlowski, linux-arm-msm, devicetree, linux-kernel Add a node for the haptics driver found on the phone. Signed-off-by: Luca Weiss <luca.weiss@fairphone.com> --- This patch depends on the i2c10 node introduced in this patch: https://lore.kernel.org/linux-arm-msm/20220408114205.234635-2-luca.weiss@fairphone.com/ For reference, the dt properties are based on the following properties from the original vendor driver: vib_f0_pre = < 2350 >; => awinic,f0-preset = <2350>; vib_f0_coeff = < 260 >; => awinic,f0-coefficient = <260>; vib_f0_cali_percen = < 7 >; => awinic,f0-calibration-percent = <7>; vib_cont_drv_lev = < 125 >; => awinic,drive-level = <125>; vib_f0_trace_parameter = < 0x05 0x03 0x02 0x0f >; => awinic,f0-detection-play-time = <5>; => awinic,f0-detection-wait-time = <3>; => awinic,f0-detection-repeat = <2>; => awinic,f0-detection-trace = <15>; vib_bstdbg = < 0x30 0xeb 0xd4 0 0 0 >; => awinic,boost-debug = /bits/ 8 <0x30 0xeb 0xd4>; vib_tset = < 0x12 >; => awinic,tset = /bits/ 8 <0x12>; vib_r_spare = < 0x68 >; => awinic,r-spare = /bits/ 8 <0x68>; vib_bemf_config = < 0x10 0x08 0x03 0xf8 >; (0x10 << 8) | 0x08 => awinic,bemf-upper-threshold = <4104>; (0x03 << 8) | 0xf8 => awinic,bemf-lower-threshold = <1016>; .../boot/dts/qcom/sm7225-fairphone-fp4.dts | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts index 67d14bda3797..4691a5e5c8e5 100644 --- a/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts +++ b/arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts @@ -296,6 +296,35 @@ &cdsp { firmware-name = "qcom/sm7225/fairphone4/cdsp.mdt"; }; +&i2c10 { + status = "okay"; + clock-frequency = <400000>; + + haptics@5a { + compatible = "awinic,aw8695"; + reg = <0x5a>; + interrupts-extended = <&tlmm 85 IRQ_TYPE_EDGE_FALLING>; + reset-gpios = <&tlmm 90 GPIO_ACTIVE_HIGH>; + + awinic,f0-preset = <2350>; + awinic,f0-coefficient = <260>; + awinic,f0-calibration-percent = <7>; + awinic,drive-level = <125>; + + awinic,f0-detection-play-time = <5>; + awinic,f0-detection-wait-time = <3>; + awinic,f0-detection-repeat = <2>; + awinic,f0-detection-trace = <15>; + + awinic,boost-debug = /bits/ 8 <0x30 0xeb 0xd4>; + awinic,tset = /bits/ 8 <0x12>; + awinic,r-spare = /bits/ 8 <0x68>; + + awinic,bemf-upper-threshold = <4104>; + awinic,bemf-lower-threshold = <1016>; + }; +}; + &mpss { status = "okay"; firmware-name = "qcom/sm7225/fairphone4/modem.mdt"; -- 2.35.1 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add AW8695 haptics 2022-04-08 11:53 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Luca Weiss @ 2022-04-08 19:49 ` kernel test robot 0 siblings, 0 replies; 13+ messages in thread From: kernel test robot @ 2022-04-08 19:49 UTC (permalink / raw) To: Luca Weiss, linux-input Cc: kbuild-all, ~postmarketos/upstreaming, phone-devel, Luca Weiss, Andy Gross, Bjorn Andersson, Rob Herring, Krzysztof Kozlowski, linux-arm-msm, devicetree, linux-kernel Hi Luca, Thank you for the patch! Yet something to improve: [auto build test ERROR on dtor-input/next] [also build test ERROR on hid/for-next robh/for-next v5.18-rc1 next-20220408] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/intel-lab-lkp/linux/commits/Luca-Weiss/dt-bindings-input-Add-bindings-for-Awinic-AW8695-haptics/20220408-195432 base: https://git.kernel.org/pub/scm/linux/kernel/git/dtor/input.git next config: arm64-randconfig-r015-20220408 (https://download.01.org/0day-ci/archive/20220409/202204090333.QZXMI2tu-lkp@intel.com/config) compiler: aarch64-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/intel-lab-lkp/linux/commit/3f233916afe417b8d4b9100f560892dff2c93f0c git remote add linux-review https://github.com/intel-lab-lkp/linux git fetch --no-tags linux-review Luca-Weiss/dt-bindings-input-Add-bindings-for-Awinic-AW8695-haptics/20220408-195432 git checkout 3f233916afe417b8d4b9100f560892dff2c93f0c # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=arm64 SHELL=/bin/bash If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): >> Error: arch/arm64/boot/dts/qcom/sm7225-fairphone-fp4.dts:298.1-7 Label or path i2c10 not found FATAL ERROR: Syntax error parsing input tree -- 0-DAY CI Kernel Test Service https://01.org/lkp ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-09-24 9:01 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-09-14 14:37 [PATCH 0/3] AW8695 haptic driver Griffin Kroah-Hartman 2026-09-14 14:37 ` [PATCH 1/3] dt-bindings: input: Add compatibility for Awinic AW8695 Griffin Kroah-Hartman 2026-09-17 8:38 ` Krzysztof Kozlowski 2026-09-14 14:37 ` [PATCH 2/3] Input - aw8695: Add driver for AW8695 haptics Griffin Kroah-Hartman 2026-09-14 14:55 ` sashiko-bot 2026-09-17 8:43 ` Krzysztof Kozlowski 2026-09-14 14:37 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Griffin Kroah-Hartman 2026-09-15 10:04 ` Abel Vesa 2026-09-17 9:25 ` Konrad Dybcio 2026-09-15 4:14 ` [PATCH 0/3] AW8695 haptic driver Val Packett 2026-09-24 9:01 ` Griffin Kroah-Hartman -- strict thread matches above, loose matches on Subject: below -- 2022-04-08 11:53 [PATCH 1/3] dt-bindings: input: Add bindings for Awinic AW8695 haptics Luca Weiss 2022-04-08 11:53 ` [PATCH 3/3] arm64: dts: qcom: sm7225-fairphone-fp4: Add " Luca Weiss 2022-04-08 19:49 ` kernel test robot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox