xref: /OK3568_Linux_fs/kernel/drivers/input/misc/twl4030-vibra.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * twl4030-vibra.c - TWL4030 Vibrator driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2008-2010 Nokia Corporation
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Written by Henrik Saari <henrik.saari@nokia.com>
8*4882a593Smuzhiyun  * Updates by Felipe Balbi <felipe.balbi@nokia.com>
9*4882a593Smuzhiyun  * Input by Jari Vanhala <ext-jari.vanhala@nokia.com>
10*4882a593Smuzhiyun  */
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/jiffies.h>
14*4882a593Smuzhiyun #include <linux/platform_device.h>
15*4882a593Smuzhiyun #include <linux/of.h>
16*4882a593Smuzhiyun #include <linux/workqueue.h>
17*4882a593Smuzhiyun #include <linux/mfd/twl.h>
18*4882a593Smuzhiyun #include <linux/mfd/twl4030-audio.h>
19*4882a593Smuzhiyun #include <linux/input.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /* MODULE ID2 */
23*4882a593Smuzhiyun #define LEDEN		0x00
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* ForceFeedback */
26*4882a593Smuzhiyun #define EFFECT_DIR_180_DEG	0x8000 /* range is 0 - 0xFFFF */
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun struct vibra_info {
29*4882a593Smuzhiyun 	struct device		*dev;
30*4882a593Smuzhiyun 	struct input_dev	*input_dev;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	struct work_struct	play_work;
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	bool			enabled;
35*4882a593Smuzhiyun 	int			speed;
36*4882a593Smuzhiyun 	int			direction;
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun 	bool			coexist;
39*4882a593Smuzhiyun };
40*4882a593Smuzhiyun 
vibra_disable_leds(void)41*4882a593Smuzhiyun static void vibra_disable_leds(void)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun 	u8 reg;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun 	/* Disable LEDA & LEDB, cannot be used with vibra (PWM) */
46*4882a593Smuzhiyun 	twl_i2c_read_u8(TWL4030_MODULE_LED, &reg, LEDEN);
47*4882a593Smuzhiyun 	reg &= ~0x03;
48*4882a593Smuzhiyun 	twl_i2c_write_u8(TWL4030_MODULE_LED, LEDEN, reg);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* Powers H-Bridge and enables audio clk */
vibra_enable(struct vibra_info * info)52*4882a593Smuzhiyun static void vibra_enable(struct vibra_info *info)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	u8 reg;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	twl4030_audio_enable_resource(TWL4030_AUDIO_RES_POWER);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/* turn H-Bridge on */
59*4882a593Smuzhiyun 	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
60*4882a593Smuzhiyun 			&reg, TWL4030_REG_VIBRA_CTL);
61*4882a593Smuzhiyun 	twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
62*4882a593Smuzhiyun 			 (reg | TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	twl4030_audio_enable_resource(TWL4030_AUDIO_RES_APLL);
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 	info->enabled = true;
67*4882a593Smuzhiyun }
68*4882a593Smuzhiyun 
vibra_disable(struct vibra_info * info)69*4882a593Smuzhiyun static void vibra_disable(struct vibra_info *info)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	u8 reg;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	/* Power down H-Bridge */
74*4882a593Smuzhiyun 	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
75*4882a593Smuzhiyun 			&reg, TWL4030_REG_VIBRA_CTL);
76*4882a593Smuzhiyun 	twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
77*4882a593Smuzhiyun 			 (reg & ~TWL4030_VIBRA_EN), TWL4030_REG_VIBRA_CTL);
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	twl4030_audio_disable_resource(TWL4030_AUDIO_RES_APLL);
80*4882a593Smuzhiyun 	twl4030_audio_disable_resource(TWL4030_AUDIO_RES_POWER);
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	info->enabled = false;
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun 
vibra_play_work(struct work_struct * work)85*4882a593Smuzhiyun static void vibra_play_work(struct work_struct *work)
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun 	struct vibra_info *info = container_of(work,
88*4882a593Smuzhiyun 			struct vibra_info, play_work);
89*4882a593Smuzhiyun 	int dir;
90*4882a593Smuzhiyun 	int pwm;
91*4882a593Smuzhiyun 	u8 reg;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	dir = info->direction;
94*4882a593Smuzhiyun 	pwm = info->speed;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
97*4882a593Smuzhiyun 			&reg, TWL4030_REG_VIBRA_CTL);
98*4882a593Smuzhiyun 	if (pwm && (!info->coexist || !(reg & TWL4030_VIBRA_SEL))) {
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 		if (!info->enabled)
101*4882a593Smuzhiyun 			vibra_enable(info);
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 		/* set vibra rotation direction */
104*4882a593Smuzhiyun 		twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE,
105*4882a593Smuzhiyun 				&reg, TWL4030_REG_VIBRA_CTL);
106*4882a593Smuzhiyun 		reg = (dir) ? (reg | TWL4030_VIBRA_DIR) :
107*4882a593Smuzhiyun 			(reg & ~TWL4030_VIBRA_DIR);
108*4882a593Smuzhiyun 		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
109*4882a593Smuzhiyun 				 reg, TWL4030_REG_VIBRA_CTL);
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 		/* set PWM, 1 = max, 255 = min */
112*4882a593Smuzhiyun 		twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
113*4882a593Smuzhiyun 				 256 - pwm, TWL4030_REG_VIBRA_SET);
114*4882a593Smuzhiyun 	} else {
115*4882a593Smuzhiyun 		if (info->enabled)
116*4882a593Smuzhiyun 			vibra_disable(info);
117*4882a593Smuzhiyun 	}
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun /*** Input/ForceFeedback ***/
121*4882a593Smuzhiyun 
vibra_play(struct input_dev * input,void * data,struct ff_effect * effect)122*4882a593Smuzhiyun static int vibra_play(struct input_dev *input, void *data,
123*4882a593Smuzhiyun 		      struct ff_effect *effect)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct vibra_info *info = input_get_drvdata(input);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	info->speed = effect->u.rumble.strong_magnitude >> 8;
128*4882a593Smuzhiyun 	if (!info->speed)
129*4882a593Smuzhiyun 		info->speed = effect->u.rumble.weak_magnitude >> 9;
130*4882a593Smuzhiyun 	info->direction = effect->direction < EFFECT_DIR_180_DEG ? 0 : 1;
131*4882a593Smuzhiyun 	schedule_work(&info->play_work);
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
twl4030_vibra_close(struct input_dev * input)135*4882a593Smuzhiyun static void twl4030_vibra_close(struct input_dev *input)
136*4882a593Smuzhiyun {
137*4882a593Smuzhiyun 	struct vibra_info *info = input_get_drvdata(input);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	cancel_work_sync(&info->play_work);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	if (info->enabled)
142*4882a593Smuzhiyun 		vibra_disable(info);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun /*** Module ***/
twl4030_vibra_suspend(struct device * dev)146*4882a593Smuzhiyun static int __maybe_unused twl4030_vibra_suspend(struct device *dev)
147*4882a593Smuzhiyun {
148*4882a593Smuzhiyun 	struct platform_device *pdev = to_platform_device(dev);
149*4882a593Smuzhiyun 	struct vibra_info *info = platform_get_drvdata(pdev);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	if (info->enabled)
152*4882a593Smuzhiyun 		vibra_disable(info);
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	return 0;
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun 
twl4030_vibra_resume(struct device * dev)157*4882a593Smuzhiyun static int __maybe_unused twl4030_vibra_resume(struct device *dev)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun 	vibra_disable_leds();
160*4882a593Smuzhiyun 	return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(twl4030_vibra_pm_ops,
164*4882a593Smuzhiyun 			 twl4030_vibra_suspend, twl4030_vibra_resume);
165*4882a593Smuzhiyun 
twl4030_vibra_check_coexist(struct twl4030_vibra_data * pdata,struct device_node * parent)166*4882a593Smuzhiyun static bool twl4030_vibra_check_coexist(struct twl4030_vibra_data *pdata,
167*4882a593Smuzhiyun 			      struct device_node *parent)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	struct device_node *node;
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	if (pdata && pdata->coexist)
172*4882a593Smuzhiyun 		return true;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	node = of_get_child_by_name(parent, "codec");
175*4882a593Smuzhiyun 	if (node) {
176*4882a593Smuzhiyun 		of_node_put(node);
177*4882a593Smuzhiyun 		return true;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	return false;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
twl4030_vibra_probe(struct platform_device * pdev)183*4882a593Smuzhiyun static int twl4030_vibra_probe(struct platform_device *pdev)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	struct twl4030_vibra_data *pdata = dev_get_platdata(&pdev->dev);
186*4882a593Smuzhiyun 	struct device_node *twl4030_core_node = pdev->dev.parent->of_node;
187*4882a593Smuzhiyun 	struct vibra_info *info;
188*4882a593Smuzhiyun 	int ret;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	if (!pdata && !twl4030_core_node) {
191*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, "platform_data not available\n");
192*4882a593Smuzhiyun 		return -EINVAL;
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
196*4882a593Smuzhiyun 	if (!info)
197*4882a593Smuzhiyun 		return -ENOMEM;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	info->dev = &pdev->dev;
200*4882a593Smuzhiyun 	info->coexist = twl4030_vibra_check_coexist(pdata, twl4030_core_node);
201*4882a593Smuzhiyun 	INIT_WORK(&info->play_work, vibra_play_work);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	info->input_dev = devm_input_allocate_device(&pdev->dev);
204*4882a593Smuzhiyun 	if (info->input_dev == NULL) {
205*4882a593Smuzhiyun 		dev_err(&pdev->dev, "couldn't allocate input device\n");
206*4882a593Smuzhiyun 		return -ENOMEM;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	input_set_drvdata(info->input_dev, info);
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	info->input_dev->name = "twl4030:vibrator";
212*4882a593Smuzhiyun 	info->input_dev->id.version = 1;
213*4882a593Smuzhiyun 	info->input_dev->close = twl4030_vibra_close;
214*4882a593Smuzhiyun 	__set_bit(FF_RUMBLE, info->input_dev->ffbit);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	ret = input_ff_create_memless(info->input_dev, NULL, vibra_play);
217*4882a593Smuzhiyun 	if (ret < 0) {
218*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, "couldn't register vibrator to FF\n");
219*4882a593Smuzhiyun 		return ret;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	ret = input_register_device(info->input_dev);
223*4882a593Smuzhiyun 	if (ret < 0) {
224*4882a593Smuzhiyun 		dev_dbg(&pdev->dev, "couldn't register input device\n");
225*4882a593Smuzhiyun 		goto err_iff;
226*4882a593Smuzhiyun 	}
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	vibra_disable_leds();
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	platform_set_drvdata(pdev, info);
231*4882a593Smuzhiyun 	return 0;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun err_iff:
234*4882a593Smuzhiyun 	input_ff_destroy(info->input_dev);
235*4882a593Smuzhiyun 	return ret;
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun static struct platform_driver twl4030_vibra_driver = {
239*4882a593Smuzhiyun 	.probe		= twl4030_vibra_probe,
240*4882a593Smuzhiyun 	.driver		= {
241*4882a593Smuzhiyun 		.name	= "twl4030-vibra",
242*4882a593Smuzhiyun 		.pm	= &twl4030_vibra_pm_ops,
243*4882a593Smuzhiyun 	},
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun module_platform_driver(twl4030_vibra_driver);
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun MODULE_ALIAS("platform:twl4030-vibra");
248*4882a593Smuzhiyun MODULE_DESCRIPTION("TWL4030 Vibra driver");
249*4882a593Smuzhiyun MODULE_LICENSE("GPL");
250*4882a593Smuzhiyun MODULE_AUTHOR("Nokia Corporation");
251