197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
211205bb6SAmy Maloche /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
311205bb6SAmy Maloche */
411205bb6SAmy Maloche
511205bb6SAmy Maloche #include <linux/errno.h>
611205bb6SAmy Maloche #include <linux/input.h>
7f6bcc91bSDamien Riegel #include <linux/kernel.h>
8f6bcc91bSDamien Riegel #include <linux/module.h>
9d4c7c5c9SDamien Riegel #include <linux/of.h>
10f6bcc91bSDamien Riegel #include <linux/platform_device.h>
1121014b80SStephen Boyd #include <linux/regmap.h>
12f6bcc91bSDamien Riegel #include <linux/slab.h>
1311205bb6SAmy Maloche
1411205bb6SAmy Maloche #define VIB_MAX_LEVEL_mV (3100)
1511205bb6SAmy Maloche #define VIB_MIN_LEVEL_mV (1200)
16*4031c57fSFenglin Wu #define VIB_PER_STEP_mV (100)
17*4031c57fSFenglin Wu #define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV + VIB_PER_STEP_mV)
1811205bb6SAmy Maloche
1911205bb6SAmy Maloche #define MAX_FF_SPEED 0xff
2011205bb6SAmy Maloche
212de3b704SDamien Riegel struct pm8xxx_regs {
22d4c7c5c9SDamien Riegel unsigned int enable_addr;
23d4c7c5c9SDamien Riegel unsigned int enable_mask;
24d4c7c5c9SDamien Riegel
252de3b704SDamien Riegel unsigned int drv_addr;
262de3b704SDamien Riegel unsigned int drv_mask;
272de3b704SDamien Riegel unsigned int drv_shift;
282de3b704SDamien Riegel unsigned int drv_en_manual_mask;
292de3b704SDamien Riegel };
302de3b704SDamien Riegel
312de3b704SDamien Riegel static const struct pm8xxx_regs pm8058_regs = {
322de3b704SDamien Riegel .drv_addr = 0x4A,
332de3b704SDamien Riegel .drv_mask = 0xf8,
342de3b704SDamien Riegel .drv_shift = 3,
352de3b704SDamien Riegel .drv_en_manual_mask = 0xfc,
362de3b704SDamien Riegel };
372de3b704SDamien Riegel
38792ad668SDamien Riegel static struct pm8xxx_regs pm8916_regs = {
39792ad668SDamien Riegel .enable_addr = 0xc046,
40792ad668SDamien Riegel .enable_mask = BIT(7),
41792ad668SDamien Riegel .drv_addr = 0xc041,
42792ad668SDamien Riegel .drv_mask = 0x1F,
43792ad668SDamien Riegel .drv_shift = 0,
44792ad668SDamien Riegel .drv_en_manual_mask = 0,
45792ad668SDamien Riegel };
46792ad668SDamien Riegel
4711205bb6SAmy Maloche /**
4811205bb6SAmy Maloche * struct pm8xxx_vib - structure to hold vibrator data
4911205bb6SAmy Maloche * @vib_input_dev: input device supporting force feedback
5011205bb6SAmy Maloche * @work: work structure to set the vibration parameters
5121014b80SStephen Boyd * @regmap: regmap for register read/write
522de3b704SDamien Riegel * @regs: registers' info
5311205bb6SAmy Maloche * @speed: speed of vibration set from userland
5411205bb6SAmy Maloche * @active: state of vibrator
5511205bb6SAmy Maloche * @level: level of vibration to set in the chip
562de3b704SDamien Riegel * @reg_vib_drv: regs->drv_addr register value
5711205bb6SAmy Maloche */
5811205bb6SAmy Maloche struct pm8xxx_vib {
5911205bb6SAmy Maloche struct input_dev *vib_input_dev;
6011205bb6SAmy Maloche struct work_struct work;
6121014b80SStephen Boyd struct regmap *regmap;
622de3b704SDamien Riegel const struct pm8xxx_regs *regs;
6311205bb6SAmy Maloche int speed;
6411205bb6SAmy Maloche int level;
6511205bb6SAmy Maloche bool active;
6611205bb6SAmy Maloche u8 reg_vib_drv;
6711205bb6SAmy Maloche };
6811205bb6SAmy Maloche
6911205bb6SAmy Maloche /**
7011205bb6SAmy Maloche * pm8xxx_vib_set - handler to start/stop vibration
7111205bb6SAmy Maloche * @vib: pointer to vibrator structure
7211205bb6SAmy Maloche * @on: state to set
7311205bb6SAmy Maloche */
pm8xxx_vib_set(struct pm8xxx_vib * vib,bool on)7411205bb6SAmy Maloche static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
7511205bb6SAmy Maloche {
7611205bb6SAmy Maloche int rc;
7721014b80SStephen Boyd unsigned int val = vib->reg_vib_drv;
782de3b704SDamien Riegel const struct pm8xxx_regs *regs = vib->regs;
7911205bb6SAmy Maloche
8011205bb6SAmy Maloche if (on)
812de3b704SDamien Riegel val |= (vib->level << regs->drv_shift) & regs->drv_mask;
8211205bb6SAmy Maloche else
832de3b704SDamien Riegel val &= ~regs->drv_mask;
8411205bb6SAmy Maloche
852de3b704SDamien Riegel rc = regmap_write(vib->regmap, regs->drv_addr, val);
8611205bb6SAmy Maloche if (rc < 0)
8711205bb6SAmy Maloche return rc;
8811205bb6SAmy Maloche
8911205bb6SAmy Maloche vib->reg_vib_drv = val;
90d4c7c5c9SDamien Riegel
91d4c7c5c9SDamien Riegel if (regs->enable_mask)
92d4c7c5c9SDamien Riegel rc = regmap_update_bits(vib->regmap, regs->enable_addr,
93996d5d5fSStephan Gerhold regs->enable_mask, on ? ~0 : 0);
94d4c7c5c9SDamien Riegel
95d4c7c5c9SDamien Riegel return rc;
9611205bb6SAmy Maloche }
9711205bb6SAmy Maloche
9811205bb6SAmy Maloche /**
9911205bb6SAmy Maloche * pm8xxx_work_handler - worker to set vibration level
10011205bb6SAmy Maloche * @work: pointer to work_struct
10111205bb6SAmy Maloche */
pm8xxx_work_handler(struct work_struct * work)10211205bb6SAmy Maloche static void pm8xxx_work_handler(struct work_struct *work)
10311205bb6SAmy Maloche {
10411205bb6SAmy Maloche struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
1052de3b704SDamien Riegel const struct pm8xxx_regs *regs = vib->regs;
10611205bb6SAmy Maloche int rc;
10721014b80SStephen Boyd unsigned int val;
10811205bb6SAmy Maloche
1092de3b704SDamien Riegel rc = regmap_read(vib->regmap, regs->drv_addr, &val);
11011205bb6SAmy Maloche if (rc < 0)
11111205bb6SAmy Maloche return;
11211205bb6SAmy Maloche
11311205bb6SAmy Maloche /*
11411205bb6SAmy Maloche * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
11511205bb6SAmy Maloche * scale the level to fit into these ranges.
11611205bb6SAmy Maloche */
11711205bb6SAmy Maloche if (vib->speed) {
11811205bb6SAmy Maloche vib->active = true;
11911205bb6SAmy Maloche vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
12011205bb6SAmy Maloche VIB_MIN_LEVEL_mV;
121*4031c57fSFenglin Wu vib->level /= VIB_PER_STEP_mV;
12211205bb6SAmy Maloche } else {
12311205bb6SAmy Maloche vib->active = false;
124*4031c57fSFenglin Wu vib->level = VIB_MIN_LEVEL_mV / VIB_PER_STEP_mV;
12511205bb6SAmy Maloche }
12611205bb6SAmy Maloche
12711205bb6SAmy Maloche pm8xxx_vib_set(vib, vib->active);
12811205bb6SAmy Maloche }
12911205bb6SAmy Maloche
13011205bb6SAmy Maloche /**
13111205bb6SAmy Maloche * pm8xxx_vib_close - callback of input close callback
13211205bb6SAmy Maloche * @dev: input device pointer
13311205bb6SAmy Maloche *
13411205bb6SAmy Maloche * Turns off the vibrator.
13511205bb6SAmy Maloche */
pm8xxx_vib_close(struct input_dev * dev)13611205bb6SAmy Maloche static void pm8xxx_vib_close(struct input_dev *dev)
13711205bb6SAmy Maloche {
13811205bb6SAmy Maloche struct pm8xxx_vib *vib = input_get_drvdata(dev);
13911205bb6SAmy Maloche
14011205bb6SAmy Maloche cancel_work_sync(&vib->work);
14111205bb6SAmy Maloche if (vib->active)
14211205bb6SAmy Maloche pm8xxx_vib_set(vib, false);
14311205bb6SAmy Maloche }
14411205bb6SAmy Maloche
14511205bb6SAmy Maloche /**
14611205bb6SAmy Maloche * pm8xxx_vib_play_effect - function to handle vib effects.
14711205bb6SAmy Maloche * @dev: input device pointer
14811205bb6SAmy Maloche * @data: data of effect
14911205bb6SAmy Maloche * @effect: effect to play
15011205bb6SAmy Maloche *
15111205bb6SAmy Maloche * Currently this driver supports only rumble effects.
15211205bb6SAmy Maloche */
pm8xxx_vib_play_effect(struct input_dev * dev,void * data,struct ff_effect * effect)15311205bb6SAmy Maloche static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
15411205bb6SAmy Maloche struct ff_effect *effect)
15511205bb6SAmy Maloche {
15611205bb6SAmy Maloche struct pm8xxx_vib *vib = input_get_drvdata(dev);
15711205bb6SAmy Maloche
15811205bb6SAmy Maloche vib->speed = effect->u.rumble.strong_magnitude >> 8;
15911205bb6SAmy Maloche if (!vib->speed)
16011205bb6SAmy Maloche vib->speed = effect->u.rumble.weak_magnitude >> 9;
16111205bb6SAmy Maloche
16211205bb6SAmy Maloche schedule_work(&vib->work);
16311205bb6SAmy Maloche
16411205bb6SAmy Maloche return 0;
16511205bb6SAmy Maloche }
16611205bb6SAmy Maloche
pm8xxx_vib_probe(struct platform_device * pdev)1675298cc4cSBill Pemberton static int pm8xxx_vib_probe(struct platform_device *pdev)
16811205bb6SAmy Maloche {
16911205bb6SAmy Maloche struct pm8xxx_vib *vib;
17011205bb6SAmy Maloche struct input_dev *input_dev;
17111205bb6SAmy Maloche int error;
17221014b80SStephen Boyd unsigned int val;
1732de3b704SDamien Riegel const struct pm8xxx_regs *regs;
17411205bb6SAmy Maloche
17512a5a8fdSStephen Boyd vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL);
17612a5a8fdSStephen Boyd if (!vib)
17712a5a8fdSStephen Boyd return -ENOMEM;
17812a5a8fdSStephen Boyd
17921014b80SStephen Boyd vib->regmap = dev_get_regmap(pdev->dev.parent, NULL);
18021014b80SStephen Boyd if (!vib->regmap)
18121014b80SStephen Boyd return -ENODEV;
18221014b80SStephen Boyd
18312a5a8fdSStephen Boyd input_dev = devm_input_allocate_device(&pdev->dev);
18412a5a8fdSStephen Boyd if (!input_dev)
18512a5a8fdSStephen Boyd return -ENOMEM;
18611205bb6SAmy Maloche
18711205bb6SAmy Maloche INIT_WORK(&vib->work, pm8xxx_work_handler);
18811205bb6SAmy Maloche vib->vib_input_dev = input_dev;
18911205bb6SAmy Maloche
1902de3b704SDamien Riegel regs = of_device_get_match_data(&pdev->dev);
1912de3b704SDamien Riegel
19211205bb6SAmy Maloche /* operate in manual mode */
1932de3b704SDamien Riegel error = regmap_read(vib->regmap, regs->drv_addr, &val);
19411205bb6SAmy Maloche if (error < 0)
19512a5a8fdSStephen Boyd return error;
19612a5a8fdSStephen Boyd
1972de3b704SDamien Riegel val &= regs->drv_en_manual_mask;
1982de3b704SDamien Riegel error = regmap_write(vib->regmap, regs->drv_addr, val);
19911205bb6SAmy Maloche if (error < 0)
20012a5a8fdSStephen Boyd return error;
20111205bb6SAmy Maloche
2022de3b704SDamien Riegel vib->regs = regs;
20311205bb6SAmy Maloche vib->reg_vib_drv = val;
20411205bb6SAmy Maloche
20511205bb6SAmy Maloche input_dev->name = "pm8xxx_vib_ffmemless";
20611205bb6SAmy Maloche input_dev->id.version = 1;
20711205bb6SAmy Maloche input_dev->close = pm8xxx_vib_close;
20811205bb6SAmy Maloche input_set_drvdata(input_dev, vib);
20911205bb6SAmy Maloche input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
21011205bb6SAmy Maloche
21111205bb6SAmy Maloche error = input_ff_create_memless(input_dev, NULL,
21211205bb6SAmy Maloche pm8xxx_vib_play_effect);
21311205bb6SAmy Maloche if (error) {
21411205bb6SAmy Maloche dev_err(&pdev->dev,
21511205bb6SAmy Maloche "couldn't register vibrator as FF device\n");
21612a5a8fdSStephen Boyd return error;
21711205bb6SAmy Maloche }
21811205bb6SAmy Maloche
21911205bb6SAmy Maloche error = input_register_device(input_dev);
22011205bb6SAmy Maloche if (error) {
22111205bb6SAmy Maloche dev_err(&pdev->dev, "couldn't register input device\n");
22211205bb6SAmy Maloche return error;
22311205bb6SAmy Maloche }
22411205bb6SAmy Maloche
22512a5a8fdSStephen Boyd platform_set_drvdata(pdev, vib);
22611205bb6SAmy Maloche return 0;
22711205bb6SAmy Maloche }
22811205bb6SAmy Maloche
pm8xxx_vib_suspend(struct device * dev)22937aee595SJonathan Cameron static int pm8xxx_vib_suspend(struct device *dev)
23011205bb6SAmy Maloche {
23111205bb6SAmy Maloche struct pm8xxx_vib *vib = dev_get_drvdata(dev);
23211205bb6SAmy Maloche
23311205bb6SAmy Maloche /* Turn off the vibrator */
23411205bb6SAmy Maloche pm8xxx_vib_set(vib, false);
23511205bb6SAmy Maloche
23611205bb6SAmy Maloche return 0;
23711205bb6SAmy Maloche }
23811205bb6SAmy Maloche
23937aee595SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
24011205bb6SAmy Maloche
241877e1f15SStephen Boyd static const struct of_device_id pm8xxx_vib_id_table[] = {
2422de3b704SDamien Riegel { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs },
2432de3b704SDamien Riegel { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs },
244792ad668SDamien Riegel { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs },
245877e1f15SStephen Boyd { }
246877e1f15SStephen Boyd };
247877e1f15SStephen Boyd MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
248877e1f15SStephen Boyd
24911205bb6SAmy Maloche static struct platform_driver pm8xxx_vib_driver = {
25011205bb6SAmy Maloche .probe = pm8xxx_vib_probe,
25111205bb6SAmy Maloche .driver = {
25211205bb6SAmy Maloche .name = "pm8xxx-vib",
25337aee595SJonathan Cameron .pm = pm_sleep_ptr(&pm8xxx_vib_pm_ops),
254877e1f15SStephen Boyd .of_match_table = pm8xxx_vib_id_table,
25511205bb6SAmy Maloche },
25611205bb6SAmy Maloche };
257840a746bSJJ Ding module_platform_driver(pm8xxx_vib_driver);
25811205bb6SAmy Maloche
25911205bb6SAmy Maloche MODULE_ALIAS("platform:pm8xxx_vib");
26011205bb6SAmy Maloche MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework");
26111205bb6SAmy Maloche MODULE_LICENSE("GPL v2");
26211205bb6SAmy Maloche MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>");
263