[PATCH v3 1/3] input: pm8xxx-vib: refactor to easily support new SPMI vibrator

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

Currently, all vibrator control register addresses are hard coded,
including the base address and the offset, it's not flexible to support
new SPMI vibrator module which is usually included in different PMICs
with different base address. Refactor this by introducing the HW type
terminology and contain the register offsets/masks/shifts in reg_filed
data structures corresponding to each vibrator type, and the base address
value defined in 'reg' property will be added for SPMI vibrators.

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

diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c
index 04cb87efd799..77bb0018d4e1 100644
--- a/drivers/input/misc/pm8xxx-vibrator.c
+++ b/drivers/input/misc/pm8xxx-vibrator.c
@@ -12,36 +12,36 @@
#include <linux/regmap.h>
#include <linux/slab.h>

+#define SSBI_VIB_DRV_EN_MANUAL_MASK 0xfc
+#define SSBI_VIB_DRV_LEVEL_MASK 0xf8
+#define SSBI_VIB_DRV_SHIFT 3
+#define SPMI_VIB_DRV_LEVEL_MASK 0xff
+#define SPMI_VIB_DRV_SHIFT 0
+
#define VIB_MAX_LEVEL_mV (3100)
#define VIB_MIN_LEVEL_mV (1200)
#define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)

#define MAX_FF_SPEED 0xff

-struct pm8xxx_regs {
- unsigned int enable_addr;
- unsigned int enable_mask;
+enum pm8xxx_vib_type {
+ SSBI_VIB,
+ SPMI_VIB_GEN1,
+};

- unsigned int drv_addr;
- unsigned int drv_mask;
- unsigned int drv_shift;
- unsigned int drv_en_manual_mask;
+enum {
+ VIB_DRV_REG,
+ VIB_EN_REG,
+ VIB_MAX_REG,
};

-static const struct pm8xxx_regs pm8058_regs = {
- .drv_addr = 0x4A,
- .drv_mask = 0xf8,
- .drv_shift = 3,
- .drv_en_manual_mask = 0xfc,
+static struct reg_field ssbi_vib_regs[VIB_MAX_REG] = {
+ REG_FIELD(0xf8, 0, 7),
};

-static struct pm8xxx_regs pm8916_regs = {
- .enable_addr = 0xc046,
- .enable_mask = BIT(7),
- .drv_addr = 0xc041,
- .drv_mask = 0x1F,
- .drv_shift = 0,
- .drv_en_manual_mask = 0,
+static struct reg_field spmi_vib_gen1_regs[VIB_MAX_REG] = {
+ REG_FIELD(0x41, 0, 4),
+ REG_FIELD(0x46, 7, 7),
};

/**
@@ -58,12 +58,12 @@ static struct pm8xxx_regs pm8916_regs = {
struct pm8xxx_vib {
struct input_dev *vib_input_dev;
struct work_struct work;
- struct regmap *regmap;
- const struct pm8xxx_regs *regs;
+ struct regmap_field *r_fields[VIB_MAX_REG];
int speed;
int level;
bool active;
u8 reg_vib_drv;
+ enum pm8xxx_vib_type hw_type;
};

/**
@@ -75,22 +75,27 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
{
int rc;
unsigned int val = vib->reg_vib_drv;
- const struct pm8xxx_regs *regs = vib->regs;
+ u32 mask = SPMI_VIB_DRV_LEVEL_MASK;
+ u32 shift = SPMI_VIB_DRV_SHIFT;
+
+ if (vib->hw_type == SSBI_VIB) {
+ mask = SSBI_VIB_DRV_LEVEL_MASK;
+ shift = SSBI_VIB_DRV_SHIFT;
+ }

if (on)
- val |= (vib->level << regs->drv_shift) & regs->drv_mask;
+ val |= (vib->level << shift) & mask;
else
- val &= ~regs->drv_mask;
+ val &= ~mask;

- rc = regmap_write(vib->regmap, regs->drv_addr, val);
+ rc = regmap_field_write(vib->r_fields[VIB_DRV_REG], val);
if (rc < 0)
return rc;

vib->reg_vib_drv = val;

- if (regs->enable_mask)
- rc = regmap_update_bits(vib->regmap, regs->enable_addr,
- regs->enable_mask, on ? ~0 : 0);
+ if (vib->hw_type != SSBI_VIB)
+ rc = regmap_field_write(vib->r_fields[VIB_EN_REG], on);

return rc;
}
@@ -102,13 +107,6 @@ static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
static void pm8xxx_work_handler(struct work_struct *work)
{
struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
- const struct pm8xxx_regs *regs = vib->regs;
- int rc;
- unsigned int val;
-
- rc = regmap_read(vib->regmap, regs->drv_addr, &val);
- if (rc < 0)
- return;

/*
* pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
@@ -168,38 +166,65 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
{
struct pm8xxx_vib *vib;
struct input_dev *input_dev;
- int error;
+ struct device *dev = &pdev->dev;
+ struct regmap *regmap;
+ struct reg_field *regs;
+ int error, i;
unsigned int val;
- const struct pm8xxx_regs *regs;
+ u32 reg_base;

- vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL);
+ vib = devm_kzalloc(dev, sizeof(*vib), GFP_KERNEL);
if (!vib)
return -ENOMEM;

- vib->regmap = dev_get_regmap(pdev->dev.parent, NULL);
- if (!vib->regmap)
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
return -ENODEV;

- input_dev = devm_input_allocate_device(&pdev->dev);
+ input_dev = devm_input_allocate_device(dev);
if (!input_dev)
return -ENOMEM;

INIT_WORK(&vib->work, pm8xxx_work_handler);
vib->vib_input_dev = input_dev;

- regs = of_device_get_match_data(&pdev->dev);
+ vib->hw_type = (enum pm8xxx_vib_type)of_device_get_match_data(dev);

- /* operate in manual mode */
- error = regmap_read(vib->regmap, regs->drv_addr, &val);
+ regs = ssbi_vib_regs;
+ if (vib->hw_type != SSBI_VIB) {
+ error = fwnode_property_read_u32(dev->fwnode, "reg", &reg_base);
+ if (error < 0) {
+ dev_err(dev, "Failed to read reg address, rc=%d\n", error);
+ return error;
+ }
+
+ if (vib->hw_type == SPMI_VIB_GEN1)
+ regs = spmi_vib_gen1_regs;
+
+ for (i = 0; i < VIB_MAX_REG; i++)
+ if (regs[i].reg != 0)
+ regs[i].reg += reg_base;
+ }
+
+ error = devm_regmap_field_bulk_alloc(dev, regmap, vib->r_fields, regs, VIB_MAX_REG);
if (error < 0)
+ {
+ dev_err(dev, "Failed to allocate regmap failed, rc=%d\n", error);
return error;
+ }

- val &= regs->drv_en_manual_mask;
- error = regmap_write(vib->regmap, regs->drv_addr, val);
+ error = regmap_field_read(vib->r_fields[VIB_DRV_REG], &val);
if (error < 0)
return error;

- vib->regs = regs;
+ /* operate in manual mode */
+ if (vib->hw_type == SSBI_VIB) {
+ val &= SSBI_VIB_DRV_EN_MANUAL_MASK;
+ error = regmap_field_write(vib->r_fields[VIB_DRV_REG], val);
+ if (error < 0)
+ return error;
+ }
+
vib->reg_vib_drv = val;

input_dev->name = "pm8xxx_vib_ffmemless";
@@ -211,14 +236,13 @@ static int pm8xxx_vib_probe(struct platform_device *pdev)
error = input_ff_create_memless(input_dev, NULL,
pm8xxx_vib_play_effect);
if (error) {
- dev_err(&pdev->dev,
- "couldn't register vibrator as FF device\n");
+ dev_err(dev, "couldn't register vibrator as FF device\n");
return error;
}

error = input_register_device(input_dev);
if (error) {
- dev_err(&pdev->dev, "couldn't register input device\n");
+ dev_err(dev, "couldn't register input device\n");
return error;
}

@@ -239,9 +263,9 @@ static int pm8xxx_vib_suspend(struct device *dev)
static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);

static const struct of_device_id pm8xxx_vib_id_table[] = {
- { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs },
- { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs },
- { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs },
+ { .compatible = "qcom,pm8058-vib", .data = (void *)SSBI_VIB },
+ { .compatible = "qcom,pm8921-vib", .data = (void *)SSBI_VIB },
+ { .compatible = "qcom,pm8916-vib", .data = (void *)SPMI_VIB_GEN1 },
{ }
};
MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
--
2.25.1