* [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; 10+ 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] 10+ 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; 10+ 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 [flat|nested] 10+ 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-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, 1 reply; 10+ 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 [flat|nested] 10+ 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; 10+ 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 [flat|nested] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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-17 8:43 ` Krzysztof Kozlowski
0 siblings, 0 replies; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ messages in thread
end of thread, other threads:[~2026-09-24 9:01 UTC | newest]
Thread overview: 10+ 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-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
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®