aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/misc
diff options
context:
space:
mode:
authorJaewon Kim <jaewon02.kim@samsung.com>2014-09-12 02:15:01 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2014-09-12 02:40:28 -0400
commita3b3ca753cdc92c7d5f57404afed3115b3b79cc6 (patch)
treede26e862cd43b9c2cb78eb06749145d3726b8e5c /drivers/input/misc
parentadff5962fdd2f29bac943bc014ebd529444b2153 (diff)
Input: add haptic driver on max77693
This driver to supports the haptic controller on MAX77693 Multifunction device with PMIC, CHARGER, LED, MUIC, HAPTIC. This driver supports external pwm and LRA (Linear Resonant Actuator) motor. User can control the haptic device via force feedback framework. Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com> Acked-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Diffstat (limited to 'drivers/input/misc')
-rw-r--r--drivers/input/misc/Kconfig11
-rw-r--r--drivers/input/misc/Makefile1
-rw-r--r--drivers/input/misc/max77693-haptic.c357
3 files changed, 369 insertions, 0 deletions
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 36382e5b7703..23297ab6163f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -144,6 +144,17 @@ config INPUT_M68K_BEEP
144 tristate "M68k Beeper support" 144 tristate "M68k Beeper support"
145 depends on M68K 145 depends on M68K
146 146
147config INPUT_MAX77693_HAPTIC
148 tristate "MAXIM MAX77693 haptic controller support"
149 depends on MFD_MAX77693 && PWM
150 select INPUT_FF_MEMLESS
151 help
152 This option enables support for the haptic controller on
153 MAXIM MAX77693 chip.
154
155 To compile this driver as module, choose M here: the
156 module will be called max77693-haptic.
157
147config INPUT_MAX8925_ONKEY 158config INPUT_MAX8925_ONKEY
148 tristate "MAX8925 ONKEY support" 159 tristate "MAX8925 ONKEY support"
149 depends on MFD_MAX8925 160 depends on MFD_MAX8925
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index e8b84d2c845f..19c760361f80 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -37,6 +37,7 @@ obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o
37obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o 37obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
38obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o 38obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o
39obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o 39obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o
40obj-$(CONFIG_INPUT_MAX77693_HAPTIC) += max77693-haptic.o
40obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o 41obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o
41obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o 42obj-$(CONFIG_INPUT_MAX8997_HAPTIC) += max8997_haptic.o
42obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o 43obj-$(CONFIG_INPUT_MC13783_PWRBUTTON) += mc13783-pwrbutton.o
diff --git a/drivers/input/misc/max77693-haptic.c b/drivers/input/misc/max77693-haptic.c
new file mode 100644
index 000000000000..d605db4d2f39
--- /dev/null
+++ b/drivers/input/misc/max77693-haptic.c
@@ -0,0 +1,357 @@
1/*
2 * MAXIM MAX77693 Haptic device driver
3 *
4 * Copyright (C) 2014 Samsung Electronics
5 * Jaewon Kim <jaewon02.kim@samsung.com>
6 *
7 * This program is not provided / owned by Maxim Integrated Products.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 */
14
15#include <linux/err.h>
16#include <linux/init.h>
17#include <linux/i2c.h>
18#include <linux/regmap.h>
19#include <linux/input.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/pwm.h>
23#include <linux/slab.h>
24#include <linux/workqueue.h>
25#include <linux/regulator/consumer.h>
26#include <linux/mfd/max77693.h>
27#include <linux/mfd/max77693-private.h>
28
29#define MAX_MAGNITUDE_SHIFT 16
30
31enum max77693_haptic_motor_type {
32 MAX77693_HAPTIC_ERM = 0,
33 MAX77693_HAPTIC_LRA,
34};
35
36enum max77693_haptic_pulse_mode {
37 MAX77693_HAPTIC_EXTERNAL_MODE = 0,
38 MAX77693_HAPTIC_INTERNAL_MODE,
39};
40
41enum max77693_haptic_pwm_divisor {
42 MAX77693_HAPTIC_PWM_DIVISOR_32 = 0,
43 MAX77693_HAPTIC_PWM_DIVISOR_64,
44 MAX77693_HAPTIC_PWM_DIVISOR_128,
45 MAX77693_HAPTIC_PWM_DIVISOR_256,
46};
47
48struct max77693_haptic {
49 struct regmap *regmap_pmic;
50 struct regmap *regmap_haptic;
51 struct device *dev;
52 struct input_dev *input_dev;
53 struct pwm_device *pwm_dev;
54 struct regulator *motor_reg;
55
56 bool enabled;
57 bool suspend_state;
58 unsigned int magnitude;
59 unsigned int pwm_duty;
60 enum max77693_haptic_motor_type type;
61 enum max77693_haptic_pulse_mode mode;
62 enum max77693_haptic_pwm_divisor pwm_divisor;
63
64 struct work_struct work;
65};
66
67static int max77693_haptic_set_duty_cycle(struct max77693_haptic *haptic)
68{
69 int delta = (haptic->pwm_dev->period + haptic->pwm_duty) / 2;
70 int error;
71
72 error = pwm_config(haptic->pwm_dev, delta, haptic->pwm_dev->period);
73 if (error) {
74 dev_err(haptic->dev, "failed to configure pwm: %d\n", error);
75 return error;
76 }
77
78 return 0;
79}
80
81static int max77693_haptic_configure(struct max77693_haptic *haptic,
82 bool enable)
83{
84 unsigned int value;
85 int error;
86
87 value = ((haptic->type << MAX77693_CONFIG2_MODE) |
88 (enable << MAX77693_CONFIG2_MEN) |
89 (haptic->mode << MAX77693_CONFIG2_HTYP) |
90 (haptic->pwm_divisor));
91
92 error = regmap_write(haptic->regmap_haptic,
93 MAX77693_HAPTIC_REG_CONFIG2, value);
94 if (error) {
95 dev_err(haptic->dev,
96 "failed to update haptic config: %d\n", error);
97 return error;
98 }
99
100 return 0;
101}
102
103static int max77693_haptic_lowsys(struct max77693_haptic *haptic, bool enable)
104{
105 int error;
106
107 error = regmap_update_bits(haptic->regmap_pmic,
108 MAX77693_PMIC_REG_LSCNFG,
109 MAX77693_PMIC_LOW_SYS_MASK,
110 enable << MAX77693_PMIC_LOW_SYS_SHIFT);
111 if (error) {
112 dev_err(haptic->dev, "cannot update pmic regmap: %d\n", error);
113 return error;
114 }
115
116 return 0;
117}
118
119static void max77693_haptic_enable(struct max77693_haptic *haptic)
120{
121 int error;
122
123 if (haptic->enabled)
124 return;
125
126 error = pwm_enable(haptic->pwm_dev);
127 if (error) {
128 dev_err(haptic->dev,
129 "failed to enable haptic pwm device: %d\n", error);
130 return;
131 }
132
133 error = max77693_haptic_lowsys(haptic, true);
134 if (error)
135 goto err_enable_lowsys;
136
137 error = max77693_haptic_configure(haptic, true);
138 if (error)
139 goto err_enable_config;
140
141 haptic->enabled = true;
142
143 return;
144
145err_enable_config:
146 max77693_haptic_lowsys(haptic, false);
147err_enable_lowsys:
148 pwm_disable(haptic->pwm_dev);
149}
150
151static void max77693_haptic_disable(struct max77693_haptic *haptic)
152{
153 int error;
154
155 if (haptic->enabled)
156 return;
157
158 error = max77693_haptic_configure(haptic, false);
159 if (error)
160 return;
161
162 error = max77693_haptic_lowsys(haptic, false);
163 if (error)
164 goto err_disable_lowsys;
165
166 pwm_disable(haptic->pwm_dev);
167 haptic->enabled = false;
168
169 return;
170
171err_disable_lowsys:
172 max77693_haptic_configure(haptic, true);
173}
174
175static void max77693_haptic_play_work(struct work_struct *work)
176{
177 struct max77693_haptic *haptic =
178 container_of(work, struct max77693_haptic, work);
179 int error;
180
181 error = max77693_haptic_set_duty_cycle(haptic);
182 if (error) {
183 dev_err(haptic->dev, "failed to set duty cycle: %d\n", error);
184 return;
185 }
186
187 if (haptic->magnitude)
188 max77693_haptic_enable(haptic);
189 else
190 max77693_haptic_disable(haptic);
191}
192
193static int max77693_haptic_play_effect(struct input_dev *dev, void *data,
194 struct ff_effect *effect)
195{
196 struct max77693_haptic *haptic = input_get_drvdata(dev);
197 uint64_t period_mag_multi;
198
199 haptic->magnitude = effect->u.rumble.strong_magnitude;
200 if (!haptic->magnitude)
201 haptic->magnitude = effect->u.rumble.weak_magnitude;
202
203 /*
204 * The magnitude comes from force-feedback interface.
205 * The formula to convert magnitude to pwm_duty as follows:
206 * - pwm_duty = (magnitude * pwm_period) / MAX_MAGNITUDE(0xFFFF)
207 */
208 period_mag_multi = (int64_t)(haptic->pwm_dev->period *
209 haptic->magnitude);
210 haptic->pwm_duty = (unsigned int)(period_mag_multi >>
211 MAX_MAGNITUDE_SHIFT);
212
213 schedule_work(&haptic->work);
214
215 return 0;
216}
217
218static int max77693_haptic_open(struct input_dev *dev)
219{
220 struct max77693_haptic *haptic = input_get_drvdata(dev);
221 int error;
222
223 error = regulator_enable(haptic->motor_reg);
224 if (error) {
225 dev_err(haptic->dev,
226 "failed to enable regulator: %d\n", error);
227 return error;
228 }
229
230 return 0;
231}
232
233static void max77693_haptic_close(struct input_dev *dev)
234{
235 struct max77693_haptic *haptic = input_get_drvdata(dev);
236 int error;
237
238 cancel_work_sync(&haptic->work);
239 max77693_haptic_disable(haptic);
240
241 error = regulator_disable(haptic->motor_reg);
242 if (error)
243 dev_err(haptic->dev,
244 "failed to disable regulator: %d\n", error);
245}
246
247static int max77693_haptic_probe(struct platform_device *pdev)
248{
249 struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
250 struct max77693_haptic *haptic;
251 int error;
252
253 haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
254 if (!haptic)
255 return -ENOMEM;
256
257 haptic->regmap_pmic = max77693->regmap;
258 haptic->regmap_haptic = max77693->regmap_haptic;
259 haptic->dev = &pdev->dev;
260 haptic->type = MAX77693_HAPTIC_LRA;
261 haptic->mode = MAX77693_HAPTIC_EXTERNAL_MODE;
262 haptic->pwm_divisor = MAX77693_HAPTIC_PWM_DIVISOR_128;
263 haptic->suspend_state = false;
264
265 INIT_WORK(&haptic->work, max77693_haptic_play_work);
266
267 /* Get pwm and regulatot for haptic device */
268 haptic->pwm_dev = devm_pwm_get(&pdev->dev, NULL);
269 if (IS_ERR(haptic->pwm_dev)) {
270 dev_err(&pdev->dev, "failed to get pwm device\n");
271 return PTR_ERR(haptic->pwm_dev);
272 }
273
274 haptic->motor_reg = devm_regulator_get(&pdev->dev, "haptic");
275 if (IS_ERR(haptic->motor_reg)) {
276 dev_err(&pdev->dev, "failed to get regulator\n");
277 return PTR_ERR(haptic->motor_reg);
278 }
279
280 /* Initialize input device for haptic device */
281 haptic->input_dev = devm_input_allocate_device(&pdev->dev);
282 if (!haptic->input_dev) {
283 dev_err(&pdev->dev, "failed to allocate input device\n");
284 return -ENOMEM;
285 }
286
287 haptic->input_dev->name = "max77693-haptic";
288 haptic->input_dev->id.version = 1;
289 haptic->input_dev->dev.parent = &pdev->dev;
290 haptic->input_dev->open = max77693_haptic_open;
291 haptic->input_dev->close = max77693_haptic_close;
292 input_set_drvdata(haptic->input_dev, haptic);
293 input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
294
295 error = input_ff_create_memless(haptic->input_dev, NULL,
296 max77693_haptic_play_effect);
297 if (error) {
298 dev_err(&pdev->dev, "failed to create force-feedback\n");
299 return error;
300 }
301
302 error = input_register_device(haptic->input_dev);
303 if (error) {
304 dev_err(&pdev->dev, "failed to register input device\n");
305 return error;
306 }
307
308 platform_set_drvdata(pdev, haptic);
309
310 return 0;
311}
312
313#ifdef CONFIG_PM_SLEEP
314static int max77693_haptic_suspend(struct device *dev)
315{
316 struct platform_device *pdev = to_platform_device(dev);
317 struct max77693_haptic *haptic = platform_get_drvdata(pdev);
318
319 if (haptic->enabled) {
320 max77693_haptic_disable(haptic);
321 haptic->suspend_state = true;
322 }
323
324 return 0;
325}
326
327static int max77693_haptic_resume(struct device *dev)
328{
329 struct platform_device *pdev = to_platform_device(dev);
330 struct max77693_haptic *haptic = platform_get_drvdata(pdev);
331
332 if (haptic->suspend_state) {
333 max77693_haptic_enable(haptic);
334 haptic->suspend_state = false;
335 }
336
337 return 0;
338}
339#endif
340
341static SIMPLE_DEV_PM_OPS(max77693_haptic_pm_ops,
342 max77693_haptic_suspend, max77693_haptic_resume);
343
344static struct platform_driver max77693_haptic_driver = {
345 .driver = {
346 .name = "max77693-haptic",
347 .owner = THIS_MODULE,
348 .pm = &max77693_haptic_pm_ops,
349 },
350 .probe = max77693_haptic_probe,
351};
352module_platform_driver(max77693_haptic_driver);
353
354MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
355MODULE_DESCRIPTION("MAXIM MAX77693 Haptic driver");
356MODULE_ALIAS("platform:max77693-haptic");
357MODULE_LICENSE("GPL");