[PATCH v3 3/3] input: pm8xxx-vibrator: add new SPMI vibrator support

Fenglin Wu
2023-07-25T05:43:30Z

Add new SPMI vibrator module which is very similar to the SPMI vibrator
module inside PM8916 but just has a finer drive voltage step (1mV vs
100mV) hence its drive level control is expanded to across 2 registers.
Name the module as 'qcom,spmi-vib-gen2', and it can be found in
following Qualcomm PMICs: PMI632, PM7250B, PM7325B, PM7550BA. Also, add
a compatible string 'qcom,spmi-vib-gen1' for SPMI vibrator inside PM8916
to maintain the completeness of the hardware version history.

Signed-off-by: Fenglin Wu <quic_fenglinw@quicinc.com>
---
drivers/input/misc/pm8xxx-vibrator.c | 37 ++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index 77bb0018d4e1..2cbccc5c6cf3 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -17,6 +17,8 @@
#define SSBI_VIB_DRV_SHIFT 3
#define SPMI_VIB_DRV_LEVEL_MASK 0xff
#define SPMI_VIB_DRV_SHIFT 0
+#define SPMI_VIB_DRV2_LEVEL_MASK 0x0f
+#define SPMI_VIB_DRV2_SHIFT 8

#define VIB_MAX_LEVEL_mV (3100)
#define VIB_MIN_LEVEL_mV (1200)
@@ -27,11 +29,13 @@
enum pm8xxx_vib_type {
SSBI_VIB,
SPMI_VIB_GEN1,
+ SPMI_VIB_GEN2,
};

enum {
VIB_DRV_REG,
VIB_EN_REG,
+ VIB_DRV2_REG,
VIB_MAX_REG,
};

@@ -44,6 +48,12 @@ static struct reg_field spmi_vib_gen1_regs[VIB_MAX_REG] = {
REG_FIELD(0x46, 7, 7),
};

+static struct reg_field spmi_vib_gen2_regs[VIB_MAX_REG] = {
+ REG_FIELD(0x40, 0, 7),
+ REG_FIELD(0x46, 7, 7),
+ REG_FIELD(0x41, 0, 3),
+};
+
/**
* struct pm8xxx_vib - structure to hold vibrator data
* @vib_input_dev: input device supporting force feedback
@@ -94,6 +104,22 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)

vib->reg_vib_drv = val;

+ if (vib->hw_type == SPMI_VIB_GEN2) {
+ mask = SPMI_VIB_DRV2_LEVEL_MASK;
+ shift = SPMI_VIB_DRV2_SHIFT;
+
+ if (on)
+ val = (vib->level >> shift) & mask;
+ else
+ val = 0;
+
+ rc = regmap_field_write(vib->r_fields[VIB_DRV2_REG], val);
+ if (rc < 0)
+ return rc;
+
+ vib->reg_vib_drv |= val << shift;
+ }
+
if (vib->hw_type != SSBI_VIB)
rc = regmap_field_write(vib->r_fields[VIB_EN_REG], on);

@@ -116,10 +142,13 @@ static void pm8xxx_work_handler(struct work_struct *work)
vib->active = true;
vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
VIB_MIN_LEVEL_mV;
- vib->level /= 100;
+ if (vib->hw_type != SPMI_VIB_GEN2)
+ vib->level /= 100;
} else {
vib->active = false;
- vib->level = VIB_MIN_LEVEL_mV / 100;
+ vib->level = VIB_MIN_LEVEL_mV;
+ if (vib->hw_type != SPMI_VIB_GEN2)
+ vib->level /= 100;
}

pm8xxx_vib_set(vib, vib->active);
@@ -200,6 +229,8 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)

if (vib->hw_type == SPMI_VIB_GEN1)
regs = spmi_vib_gen1_regs;
+ else
+ regs = spmi_vib_gen2_regs;

for (i = 0; i < VIB_MAX_REG; i++)
if (regs[i].reg != 0)
@@ -266,6 +297,8 @@ static const struct of_device_id pm8xxx_vib_id_table[] = {
{ .compatible = "qcom,pm8058-vib", .data = (void *)SSBI_VIB },
{ .compatible = "qcom,pm8921-vib", .data = (void *)SSBI_VIB },
{ .compatible = "qcom,pm8916-vib", .data = (void *)SPMI_VIB_GEN1 },
+ { .compatible = "qcom,spmi-vib-gen1", .data = (void *)SPMI_VIB_GEN1 },
+ { .compatible = "qcom,spmi-vib-gen2", .data = (void *)SPMI_VIB_GEN2 },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
--
2.25.1