diff options
Diffstat (limited to 'drivers/input/misc/pm8xxx-vibrator.c')
-rw-r--r-- | drivers/input/misc/pm8xxx-vibrator.c | 78 |
1 files changed, 57 insertions, 21 deletions
diff --git a/drivers/input/misc/pm8xxx-vibrator.c b/drivers/input/misc/pm8xxx-vibrator.c index 5113877153d7..7dd1c1fbe42a 100644 --- a/drivers/input/misc/pm8xxx-vibrator.c +++ b/drivers/input/misc/pm8xxx-vibrator.c @@ -10,19 +10,15 @@ * GNU General Public License for more details. */ -#include <linux/module.h> -#include <linux/kernel.h> #include <linux/errno.h> -#include <linux/platform_device.h> #include <linux/input.h> -#include <linux/slab.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> #include <linux/regmap.h> - -#define VIB_DRV 0x4A - -#define VIB_DRV_SEL_MASK 0xf8 -#define VIB_DRV_SEL_SHIFT 0x03 -#define VIB_DRV_EN_MANUAL_MASK 0xfc +#include <linux/slab.h> #define VIB_MAX_LEVEL_mV (3100) #define VIB_MIN_LEVEL_mV (1200) @@ -30,20 +26,48 @@ #define MAX_FF_SPEED 0xff +struct pm8xxx_regs { + unsigned int enable_addr; + unsigned int enable_mask; + + unsigned int drv_addr; + unsigned int drv_mask; + unsigned int drv_shift; + unsigned int drv_en_manual_mask; +}; + +static const struct pm8xxx_regs pm8058_regs = { + .drv_addr = 0x4A, + .drv_mask = 0xf8, + .drv_shift = 3, + .drv_en_manual_mask = 0xfc, +}; + +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, +}; + /** * struct pm8xxx_vib - structure to hold vibrator data * @vib_input_dev: input device supporting force feedback * @work: work structure to set the vibration parameters * @regmap: regmap for register read/write + * @regs: registers' info * @speed: speed of vibration set from userland * @active: state of vibrator * @level: level of vibration to set in the chip - * @reg_vib_drv: VIB_DRV register value + * @reg_vib_drv: regs->drv_addr register value */ struct pm8xxx_vib { struct input_dev *vib_input_dev; struct work_struct work; struct regmap *regmap; + const struct pm8xxx_regs *regs; int speed; int level; bool active; @@ -59,18 +83,24 @@ 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; if (on) - val |= ((vib->level << VIB_DRV_SEL_SHIFT) & VIB_DRV_SEL_MASK); + val |= (vib->level << regs->drv_shift) & regs->drv_mask; else - val &= ~VIB_DRV_SEL_MASK; + val &= ~regs->drv_mask; - rc = regmap_write(vib->regmap, VIB_DRV, val); + rc = regmap_write(vib->regmap, regs->drv_addr, val); if (rc < 0) return rc; vib->reg_vib_drv = val; - return 0; + + if (regs->enable_mask) + rc = regmap_update_bits(vib->regmap, regs->enable_addr, + on ? regs->enable_mask : 0, val); + + return rc; } /** @@ -80,10 +110,11 @@ 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, VIB_DRV, &val); + rc = regmap_read(vib->regmap, regs->drv_addr, &val); if (rc < 0) return; @@ -147,6 +178,7 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) struct input_dev *input_dev; int error; unsigned int val; + const struct pm8xxx_regs *regs; vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); if (!vib) @@ -163,16 +195,19 @@ static int pm8xxx_vib_probe(struct platform_device *pdev) INIT_WORK(&vib->work, pm8xxx_work_handler); vib->vib_input_dev = input_dev; + regs = of_device_get_match_data(&pdev->dev); + /* operate in manual mode */ - error = regmap_read(vib->regmap, VIB_DRV, &val); + error = regmap_read(vib->regmap, regs->drv_addr, &val); if (error < 0) return error; - val &= ~VIB_DRV_EN_MANUAL_MASK; - error = regmap_write(vib->regmap, VIB_DRV, val); + val &= regs->drv_en_manual_mask; + error = regmap_write(vib->regmap, regs->drv_addr, val); if (error < 0) return error; + vib->regs = regs; vib->reg_vib_drv = val; input_dev->name = "pm8xxx_vib_ffmemless"; @@ -212,8 +247,9 @@ static int __maybe_unused pm8xxx_vib_suspend(struct device *dev) static 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" }, - { .compatible = "qcom,pm8921-vib" }, + { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs }, + { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs }, + { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); |