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)
1611205bb6SAmy Maloche #define VIB_MAX_LEVELS		(VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV)
1711205bb6SAmy Maloche 
1811205bb6SAmy Maloche #define MAX_FF_SPEED		0xff
1911205bb6SAmy Maloche 
202de3b704SDamien Riegel struct pm8xxx_regs {
21d4c7c5c9SDamien Riegel 	unsigned int enable_addr;
22d4c7c5c9SDamien Riegel 	unsigned int enable_mask;
23d4c7c5c9SDamien Riegel 
242de3b704SDamien Riegel 	unsigned int drv_addr;
252de3b704SDamien Riegel 	unsigned int drv_mask;
262de3b704SDamien Riegel 	unsigned int drv_shift;
272de3b704SDamien Riegel 	unsigned int drv_en_manual_mask;
282de3b704SDamien Riegel };
292de3b704SDamien Riegel 
302de3b704SDamien Riegel static const struct pm8xxx_regs pm8058_regs = {
312de3b704SDamien Riegel 	.drv_addr = 0x4A,
322de3b704SDamien Riegel 	.drv_mask = 0xf8,
332de3b704SDamien Riegel 	.drv_shift = 3,
342de3b704SDamien Riegel 	.drv_en_manual_mask = 0xfc,
352de3b704SDamien Riegel };
362de3b704SDamien Riegel 
37792ad668SDamien Riegel static struct pm8xxx_regs pm8916_regs = {
38792ad668SDamien Riegel 	.enable_addr = 0xc046,
39792ad668SDamien Riegel 	.enable_mask = BIT(7),
40792ad668SDamien Riegel 	.drv_addr = 0xc041,
41792ad668SDamien Riegel 	.drv_mask = 0x1F,
42792ad668SDamien Riegel 	.drv_shift = 0,
43792ad668SDamien Riegel 	.drv_en_manual_mask = 0,
44792ad668SDamien Riegel };
45792ad668SDamien Riegel 
4611205bb6SAmy Maloche /**
4711205bb6SAmy Maloche  * struct pm8xxx_vib - structure to hold vibrator data
4811205bb6SAmy Maloche  * @vib_input_dev: input device supporting force feedback
4911205bb6SAmy Maloche  * @work: work structure to set the vibration parameters
5021014b80SStephen Boyd  * @regmap: regmap for register read/write
512de3b704SDamien Riegel  * @regs: registers' info
5211205bb6SAmy Maloche  * @speed: speed of vibration set from userland
5311205bb6SAmy Maloche  * @active: state of vibrator
5411205bb6SAmy Maloche  * @level: level of vibration to set in the chip
552de3b704SDamien Riegel  * @reg_vib_drv: regs->drv_addr register value
5611205bb6SAmy Maloche  */
5711205bb6SAmy Maloche struct pm8xxx_vib {
5811205bb6SAmy Maloche 	struct input_dev *vib_input_dev;
5911205bb6SAmy Maloche 	struct work_struct work;
6021014b80SStephen Boyd 	struct regmap *regmap;
612de3b704SDamien Riegel 	const struct pm8xxx_regs *regs;
6211205bb6SAmy Maloche 	int speed;
6311205bb6SAmy Maloche 	int level;
6411205bb6SAmy Maloche 	bool active;
6511205bb6SAmy Maloche 	u8  reg_vib_drv;
6611205bb6SAmy Maloche };
6711205bb6SAmy Maloche 
6811205bb6SAmy Maloche /**
6911205bb6SAmy Maloche  * pm8xxx_vib_set - handler to start/stop vibration
7011205bb6SAmy Maloche  * @vib: pointer to vibrator structure
7111205bb6SAmy Maloche  * @on: state to set
7211205bb6SAmy Maloche  */
pm8xxx_vib_set(struct pm8xxx_vib * vib,bool on)7311205bb6SAmy Maloche static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on)
7411205bb6SAmy Maloche {
7511205bb6SAmy Maloche 	int rc;
7621014b80SStephen Boyd 	unsigned int val = vib->reg_vib_drv;
772de3b704SDamien Riegel 	const struct pm8xxx_regs *regs = vib->regs;
7811205bb6SAmy Maloche 
7911205bb6SAmy Maloche 	if (on)
802de3b704SDamien Riegel 		val |= (vib->level << regs->drv_shift) & regs->drv_mask;
8111205bb6SAmy Maloche 	else
822de3b704SDamien Riegel 		val &= ~regs->drv_mask;
8311205bb6SAmy Maloche 
842de3b704SDamien Riegel 	rc = regmap_write(vib->regmap, regs->drv_addr, val);
8511205bb6SAmy Maloche 	if (rc < 0)
8611205bb6SAmy Maloche 		return rc;
8711205bb6SAmy Maloche 
8811205bb6SAmy Maloche 	vib->reg_vib_drv = val;
89d4c7c5c9SDamien Riegel 
90d4c7c5c9SDamien Riegel 	if (regs->enable_mask)
91d4c7c5c9SDamien Riegel 		rc = regmap_update_bits(vib->regmap, regs->enable_addr,
92996d5d5fSStephan Gerhold 					regs->enable_mask, on ? ~0 : 0);
93d4c7c5c9SDamien Riegel 
94d4c7c5c9SDamien Riegel 	return rc;
9511205bb6SAmy Maloche }
9611205bb6SAmy Maloche 
9711205bb6SAmy Maloche /**
9811205bb6SAmy Maloche  * pm8xxx_work_handler - worker to set vibration level
9911205bb6SAmy Maloche  * @work: pointer to work_struct
10011205bb6SAmy Maloche  */
pm8xxx_work_handler(struct work_struct * work)10111205bb6SAmy Maloche static void pm8xxx_work_handler(struct work_struct *work)
10211205bb6SAmy Maloche {
10311205bb6SAmy Maloche 	struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work);
1042de3b704SDamien Riegel 	const struct pm8xxx_regs *regs = vib->regs;
10511205bb6SAmy Maloche 	int rc;
10621014b80SStephen Boyd 	unsigned int val;
10711205bb6SAmy Maloche 
1082de3b704SDamien Riegel 	rc = regmap_read(vib->regmap, regs->drv_addr, &val);
10911205bb6SAmy Maloche 	if (rc < 0)
11011205bb6SAmy Maloche 		return;
11111205bb6SAmy Maloche 
11211205bb6SAmy Maloche 	/*
11311205bb6SAmy Maloche 	 * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so
11411205bb6SAmy Maloche 	 * scale the level to fit into these ranges.
11511205bb6SAmy Maloche 	 */
11611205bb6SAmy Maloche 	if (vib->speed) {
11711205bb6SAmy Maloche 		vib->active = true;
11811205bb6SAmy Maloche 		vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) +
11911205bb6SAmy Maloche 						VIB_MIN_LEVEL_mV;
12011205bb6SAmy Maloche 		vib->level /= 100;
12111205bb6SAmy Maloche 	} else {
12211205bb6SAmy Maloche 		vib->active = false;
12311205bb6SAmy Maloche 		vib->level = VIB_MIN_LEVEL_mV / 100;
12411205bb6SAmy Maloche 	}
12511205bb6SAmy Maloche 
12611205bb6SAmy Maloche 	pm8xxx_vib_set(vib, vib->active);
12711205bb6SAmy Maloche }
12811205bb6SAmy Maloche 
12911205bb6SAmy Maloche /**
13011205bb6SAmy Maloche  * pm8xxx_vib_close - callback of input close callback
13111205bb6SAmy Maloche  * @dev: input device pointer
13211205bb6SAmy Maloche  *
13311205bb6SAmy Maloche  * Turns off the vibrator.
13411205bb6SAmy Maloche  */
pm8xxx_vib_close(struct input_dev * dev)13511205bb6SAmy Maloche static void pm8xxx_vib_close(struct input_dev *dev)
13611205bb6SAmy Maloche {
13711205bb6SAmy Maloche 	struct pm8xxx_vib *vib = input_get_drvdata(dev);
13811205bb6SAmy Maloche 
13911205bb6SAmy Maloche 	cancel_work_sync(&vib->work);
14011205bb6SAmy Maloche 	if (vib->active)
14111205bb6SAmy Maloche 		pm8xxx_vib_set(vib, false);
14211205bb6SAmy Maloche }
14311205bb6SAmy Maloche 
14411205bb6SAmy Maloche /**
14511205bb6SAmy Maloche  * pm8xxx_vib_play_effect - function to handle vib effects.
14611205bb6SAmy Maloche  * @dev: input device pointer
14711205bb6SAmy Maloche  * @data: data of effect
14811205bb6SAmy Maloche  * @effect: effect to play
14911205bb6SAmy Maloche  *
15011205bb6SAmy Maloche  * Currently this driver supports only rumble effects.
15111205bb6SAmy Maloche  */
pm8xxx_vib_play_effect(struct input_dev * dev,void * data,struct ff_effect * effect)15211205bb6SAmy Maloche static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data,
15311205bb6SAmy Maloche 				  struct ff_effect *effect)
15411205bb6SAmy Maloche {
15511205bb6SAmy Maloche 	struct pm8xxx_vib *vib = input_get_drvdata(dev);
15611205bb6SAmy Maloche 
15711205bb6SAmy Maloche 	vib->speed = effect->u.rumble.strong_magnitude >> 8;
15811205bb6SAmy Maloche 	if (!vib->speed)
15911205bb6SAmy Maloche 		vib->speed = effect->u.rumble.weak_magnitude >> 9;
16011205bb6SAmy Maloche 
16111205bb6SAmy Maloche 	schedule_work(&vib->work);
16211205bb6SAmy Maloche 
16311205bb6SAmy Maloche 	return 0;
16411205bb6SAmy Maloche }
16511205bb6SAmy Maloche 
pm8xxx_vib_probe(struct platform_device * pdev)1665298cc4cSBill Pemberton static int pm8xxx_vib_probe(struct platform_device *pdev)
16711205bb6SAmy Maloche {
16811205bb6SAmy Maloche 	struct pm8xxx_vib *vib;
16911205bb6SAmy Maloche 	struct input_dev *input_dev;
17011205bb6SAmy Maloche 	int error;
17121014b80SStephen Boyd 	unsigned int val;
1722de3b704SDamien Riegel 	const struct pm8xxx_regs *regs;
17311205bb6SAmy Maloche 
17412a5a8fdSStephen Boyd 	vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL);
17512a5a8fdSStephen Boyd 	if (!vib)
17612a5a8fdSStephen Boyd 		return -ENOMEM;
17712a5a8fdSStephen Boyd 
17821014b80SStephen Boyd 	vib->regmap = dev_get_regmap(pdev->dev.parent, NULL);
17921014b80SStephen Boyd 	if (!vib->regmap)
18021014b80SStephen Boyd 		return -ENODEV;
18121014b80SStephen Boyd 
18212a5a8fdSStephen Boyd 	input_dev = devm_input_allocate_device(&pdev->dev);
18312a5a8fdSStephen Boyd 	if (!input_dev)
18412a5a8fdSStephen Boyd 		return -ENOMEM;
18511205bb6SAmy Maloche 
18611205bb6SAmy Maloche 	INIT_WORK(&vib->work, pm8xxx_work_handler);
18711205bb6SAmy Maloche 	vib->vib_input_dev = input_dev;
18811205bb6SAmy Maloche 
1892de3b704SDamien Riegel 	regs = of_device_get_match_data(&pdev->dev);
1902de3b704SDamien Riegel 
19111205bb6SAmy Maloche 	/* operate in manual mode */
1922de3b704SDamien Riegel 	error = regmap_read(vib->regmap, regs->drv_addr, &val);
19311205bb6SAmy Maloche 	if (error < 0)
19412a5a8fdSStephen Boyd 		return error;
19512a5a8fdSStephen Boyd 
1962de3b704SDamien Riegel 	val &= regs->drv_en_manual_mask;
1972de3b704SDamien Riegel 	error = regmap_write(vib->regmap, regs->drv_addr, val);
19811205bb6SAmy Maloche 	if (error < 0)
19912a5a8fdSStephen Boyd 		return error;
20011205bb6SAmy Maloche 
2012de3b704SDamien Riegel 	vib->regs = regs;
20211205bb6SAmy Maloche 	vib->reg_vib_drv = val;
20311205bb6SAmy Maloche 
20411205bb6SAmy Maloche 	input_dev->name = "pm8xxx_vib_ffmemless";
20511205bb6SAmy Maloche 	input_dev->id.version = 1;
20611205bb6SAmy Maloche 	input_dev->close = pm8xxx_vib_close;
20711205bb6SAmy Maloche 	input_set_drvdata(input_dev, vib);
20811205bb6SAmy Maloche 	input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE);
20911205bb6SAmy Maloche 
21011205bb6SAmy Maloche 	error = input_ff_create_memless(input_dev, NULL,
21111205bb6SAmy Maloche 					pm8xxx_vib_play_effect);
21211205bb6SAmy Maloche 	if (error) {
21311205bb6SAmy Maloche 		dev_err(&pdev->dev,
21411205bb6SAmy Maloche 			"couldn't register vibrator as FF device\n");
21512a5a8fdSStephen Boyd 		return error;
21611205bb6SAmy Maloche 	}
21711205bb6SAmy Maloche 
21811205bb6SAmy Maloche 	error = input_register_device(input_dev);
21911205bb6SAmy Maloche 	if (error) {
22011205bb6SAmy Maloche 		dev_err(&pdev->dev, "couldn't register input device\n");
22111205bb6SAmy Maloche 		return error;
22211205bb6SAmy Maloche 	}
22311205bb6SAmy Maloche 
22412a5a8fdSStephen Boyd 	platform_set_drvdata(pdev, vib);
22511205bb6SAmy Maloche 	return 0;
22611205bb6SAmy Maloche }
22711205bb6SAmy Maloche 
pm8xxx_vib_suspend(struct device * dev)228*37aee595SJonathan Cameron static int pm8xxx_vib_suspend(struct device *dev)
22911205bb6SAmy Maloche {
23011205bb6SAmy Maloche 	struct pm8xxx_vib *vib = dev_get_drvdata(dev);
23111205bb6SAmy Maloche 
23211205bb6SAmy Maloche 	/* Turn off the vibrator */
23311205bb6SAmy Maloche 	pm8xxx_vib_set(vib, false);
23411205bb6SAmy Maloche 
23511205bb6SAmy Maloche 	return 0;
23611205bb6SAmy Maloche }
23711205bb6SAmy Maloche 
238*37aee595SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL);
23911205bb6SAmy Maloche 
240877e1f15SStephen Boyd static const struct of_device_id pm8xxx_vib_id_table[] = {
2412de3b704SDamien Riegel 	{ .compatible = "qcom,pm8058-vib", .data = &pm8058_regs },
2422de3b704SDamien Riegel 	{ .compatible = "qcom,pm8921-vib", .data = &pm8058_regs },
243792ad668SDamien Riegel 	{ .compatible = "qcom,pm8916-vib", .data = &pm8916_regs },
244877e1f15SStephen Boyd 	{ }
245877e1f15SStephen Boyd };
246877e1f15SStephen Boyd MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table);
247877e1f15SStephen Boyd 
24811205bb6SAmy Maloche static struct platform_driver pm8xxx_vib_driver = {
24911205bb6SAmy Maloche 	.probe		= pm8xxx_vib_probe,
25011205bb6SAmy Maloche 	.driver		= {
25111205bb6SAmy Maloche 		.name	= "pm8xxx-vib",
252*37aee595SJonathan Cameron 		.pm	= pm_sleep_ptr(&pm8xxx_vib_pm_ops),
253877e1f15SStephen Boyd 		.of_match_table = pm8xxx_vib_id_table,
25411205bb6SAmy Maloche 	},
25511205bb6SAmy Maloche };
256840a746bSJJ Ding module_platform_driver(pm8xxx_vib_driver);
25711205bb6SAmy Maloche 
25811205bb6SAmy Maloche MODULE_ALIAS("platform:pm8xxx_vib");
25911205bb6SAmy Maloche MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework");
26011205bb6SAmy Maloche MODULE_LICENSE("GPL v2");
26111205bb6SAmy Maloche MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>");
262