input: misc: qti-haptics: Configure haptics for TWM mode
Configure haptics for TWM entry. Identify TWM entry via
the TWM notifier and configure haptics in the shutdown
callback if TWM entry is requested. Haptics is configured
for external-pin control in TWM mode.
Add a DT property "qcom,haptics-ext-pin-twm" to enable
this feature.
Change-Id: Id1d1335dd03b597e7c05b52f1cb6c0b1e5f6b4e3
Signed-off-by: Umang Chheda <uchheda@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/input/qti-haptics.txt b/Documentation/devicetree/bindings/input/qti-haptics.txt
index b3daa49..0f6cb20 100644
--- a/Documentation/devicetree/bindings/input/qti-haptics.txt
+++ b/Documentation/devicetree/bindings/input/qti-haptics.txt
@@ -86,6 +86,12 @@
haptics module through VDD_HAP pin. This is only needed if VDD_HAP
is supplied from an external boost regulator instead of VPH_PWR.
+- qcom,haptics-ext-pin-twm
+ Usage: optional
+ Value type: <empty>
+ Definition: A boolean property which configures haptics into external-pin
+ control during TWM entry.
+
Following properties are specific only when LRA actuator is used:
- qcom,lra-resonance-sig-shape
diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c
index 459faf9..27ce7cf 100644
--- a/drivers/input/misc/qti-haptics.c
+++ b/drivers/input/misc/qti-haptics.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2018, 2020, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/pwm.h>
+#include <linux/qpnp/qpnp-misc.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -173,6 +174,7 @@
#define HAP_PLAY_BIT BIT(7)
#define REG_HAP_SEC_ACCESS 0xD0
+#define REG_HAP_PERPH_RESET_CTL3 0xDA
struct qti_hap_effect {
int id;
@@ -222,6 +224,7 @@
struct hrtimer stop_timer;
struct hrtimer hap_disable_timer;
struct dentry *hap_debugfs;
+ struct notifier_block twm_nb;
spinlock_t bus_lock;
ktime_t last_sc_time;
int play_irq;
@@ -232,6 +235,20 @@
bool perm_disable;
bool play_irq_en;
bool vdd_enabled;
+ bool twm_state;
+ bool haptics_ext_pin_twm;
+};
+
+struct hap_addr_val {
+ u16 addr;
+ u8 value;
+};
+
+static struct hap_addr_val twm_ext_cfg[] = {
+ {REG_HAP_PLAY, 0x00}, /* Stop playing haptics waveform */
+ {REG_HAP_PERPH_RESET_CTL3, 0x0D}, /* Disable SHUTDOWN1_RB reset */
+ {REG_HAP_SEL, 0x01}, /* Configure for external-pin mode */
+ {REG_HAP_EN_CTL1, 0x80}, /* Enable haptics driver */
};
static int wf_repeat[8] = {1, 2, 4, 8, 16, 32, 64, 128};
@@ -1036,6 +1053,24 @@
qti_haptics_config_vmax(chip, play->vmax_mv);
}
+static int qti_haptics_twm_config(struct qti_hap_chip *chip)
+{
+ int rc, i;
+
+ for (i = 0; i < ARRAY_SIZE(twm_ext_cfg); i++) {
+ rc = qti_haptics_write(chip, twm_ext_cfg[i].addr,
+ &twm_ext_cfg[i].value, 1);
+ if (rc < 0) {
+ dev_err(chip->dev, "Haptics TWM config failed, rc=%d\n",
+ rc);
+ return rc;
+ }
+ }
+ pr_debug("Enabled haptics for TWM mode\n");
+
+ return 0;
+}
+
static int qti_haptics_hw_init(struct qti_hap_chip *chip)
{
struct qti_hap_config *config = &chip->config;
@@ -1183,6 +1218,21 @@
effect->brake_en = (val != 0);
}
+static int twm_notifier_cb(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct qti_hap_chip *chip = container_of(nb,
+ struct qti_hap_chip, twm_nb);
+
+ if (action != PMIC_TWM_CLEAR &&
+ action != PMIC_TWM_ENABLE)
+ pr_debug("Unsupported option %lu\n", action);
+ else
+ chip->twm_state = (u8)action;
+
+ return NOTIFY_OK;
+}
+
static int qti_haptics_parse_dt(struct qti_hap_chip *chip)
{
struct qti_hap_config *config = &chip->config;
@@ -1243,6 +1293,9 @@
config->play_rate_us = (tmp >= HAP_PLAY_RATE_US_MAX) ?
HAP_PLAY_RATE_US_MAX : tmp;
+ chip->haptics_ext_pin_twm = of_property_read_bool(node,
+ "qcom,haptics-ext-pin-twm");
+
if (of_find_property(node, "qcom,external-waveform-source", NULL)) {
if (!of_property_read_string(node,
"qcom,external-waveform-source", &str)) {
@@ -1898,6 +1951,11 @@
return rc;
}
+ chip->twm_nb.notifier_call = twm_notifier_cb;
+ rc = qpnp_misc_twm_notifier_register(&chip->twm_nb);
+ if (rc < 0)
+ pr_err("Failed to register twm_notifier_cb rc=%d\n", rc);
+
hrtimer_init(&chip->stop_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
chip->stop_timer.function = qti_hap_stop_timer;
hrtimer_init(&chip->hap_disable_timer, CLOCK_MONOTONIC,
@@ -1948,6 +2006,7 @@
destroy_ff:
input_ff_destroy(chip->input_dev);
+ qpnp_misc_twm_notifier_unregister(&chip->twm_nb);
return rc;
}
@@ -1959,6 +2018,7 @@
debugfs_remove_recursive(chip->hap_debugfs);
#endif
input_ff_destroy(chip->input_dev);
+ qpnp_misc_twm_notifier_unregister(&chip->twm_nb);
dev_set_drvdata(chip->dev, NULL);
return 0;
@@ -1982,6 +2042,12 @@
}
chip->vdd_enabled = false;
}
+
+ if (chip->twm_state == PMIC_TWM_ENABLE && chip->haptics_ext_pin_twm) {
+ rc = qti_haptics_twm_config(chip);
+ if (rc < 0)
+ pr_err("Haptics TWM config failed rc=%d\n", rc);
+ }
}
static const struct of_device_id haptics_match_table[] = {