2 * Regulator haptic driver
4 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
5 * Author: Jaewon Kim <jaewon02.kim@samsung.com>
6 * Author: Hyunhee Kim <hyunhee.kim@samsung.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/input.h>
14 #include <linux/module.h>
16 #include <linux/platform_data/regulator-haptic.h>
17 #include <linux/platform_device.h>
18 #include <linux/regulator/consumer.h>
19 #include <linux/slab.h>
21 #define MAX_MAGNITUDE_SHIFT 16
23 struct regulator_haptic
{
25 struct input_dev
*input_dev
;
26 struct regulator
*regulator
;
28 struct work_struct work
;
34 unsigned int max_volt
;
35 unsigned int min_volt
;
36 unsigned int magnitude
;
39 static int regulator_haptic_toggle(struct regulator_haptic
*haptic
, bool on
)
43 if (haptic
->active
!= on
) {
45 error
= on
? regulator_enable(haptic
->regulator
) :
46 regulator_disable(haptic
->regulator
);
49 "failed to switch regulator %s: %d\n",
50 on
? "on" : "off", error
);
60 static int regulator_haptic_set_voltage(struct regulator_haptic
*haptic
,
61 unsigned int magnitude
)
64 unsigned int intensity
;
67 volt_mag_multi
= (u64
)(haptic
->max_volt
- haptic
->min_volt
) * magnitude
;
68 intensity
= (unsigned int)(volt_mag_multi
>> MAX_MAGNITUDE_SHIFT
);
70 error
= regulator_set_voltage(haptic
->regulator
,
71 intensity
+ haptic
->min_volt
,
74 dev_err(haptic
->dev
, "cannot set regulator voltage to %d: %d\n",
75 intensity
+ haptic
->min_volt
, error
);
82 static void regulator_haptic_work(struct work_struct
*work
)
84 struct regulator_haptic
*haptic
= container_of(work
,
85 struct regulator_haptic
, work
);
86 unsigned int magnitude
;
89 mutex_lock(&haptic
->mutex
);
91 if (haptic
->suspended
)
94 magnitude
= ACCESS_ONCE(haptic
->magnitude
);
96 error
= regulator_haptic_set_voltage(haptic
, magnitude
);
100 regulator_haptic_toggle(haptic
, magnitude
!= 0);
103 mutex_unlock(&haptic
->mutex
);
106 static int regulator_haptic_play_effect(struct input_dev
*input
, void *data
,
107 struct ff_effect
*effect
)
109 struct regulator_haptic
*haptic
= input_get_drvdata(input
);
111 haptic
->magnitude
= effect
->u
.rumble
.strong_magnitude
;
112 if (!haptic
->magnitude
)
113 haptic
->magnitude
= effect
->u
.rumble
.weak_magnitude
;
115 schedule_work(&haptic
->work
);
120 static void regulator_haptic_close(struct input_dev
*input
)
122 struct regulator_haptic
*haptic
= input_get_drvdata(input
);
124 cancel_work_sync(&haptic
->work
);
125 regulator_haptic_set_voltage(haptic
, 0);
126 regulator_haptic_toggle(haptic
, false);
129 static int __maybe_unused
130 regulator_haptic_parse_dt(struct device
*dev
, struct regulator_haptic
*haptic
)
132 struct device_node
*node
;
137 dev_err(dev
, "Missing dveice tree data\n");
141 error
= of_property_read_u32(node
, "max-microvolt", &haptic
->max_volt
);
143 dev_err(dev
, "cannot parse max-microvolt\n");
147 error
= of_property_read_u32(node
, "min-microvolt", &haptic
->min_volt
);
149 dev_err(dev
, "cannot parse min-microvolt\n");
156 static int regulator_haptic_probe(struct platform_device
*pdev
)
158 const struct regulator_haptic_data
*pdata
= dev_get_platdata(&pdev
->dev
);
159 struct regulator_haptic
*haptic
;
160 struct input_dev
*input_dev
;
163 haptic
= devm_kzalloc(&pdev
->dev
, sizeof(*haptic
), GFP_KERNEL
);
167 platform_set_drvdata(pdev
, haptic
);
168 haptic
->dev
= &pdev
->dev
;
169 mutex_init(&haptic
->mutex
);
170 INIT_WORK(&haptic
->work
, regulator_haptic_work
);
173 haptic
->max_volt
= pdata
->max_volt
;
174 haptic
->min_volt
= pdata
->min_volt
;
175 } else if (IS_ENABLED(CONFIG_OF
)) {
176 error
= regulator_haptic_parse_dt(&pdev
->dev
, haptic
);
180 dev_err(&pdev
->dev
, "Missing platform data\n");
184 haptic
->regulator
= devm_regulator_get_exclusive(&pdev
->dev
, "haptic");
185 if (IS_ERR(haptic
->regulator
)) {
186 dev_err(&pdev
->dev
, "failed to get regulator\n");
187 return PTR_ERR(haptic
->regulator
);
190 input_dev
= devm_input_allocate_device(&pdev
->dev
);
194 haptic
->input_dev
= input_dev
;
195 haptic
->input_dev
->name
= "regulator-haptic";
196 haptic
->input_dev
->dev
.parent
= &pdev
->dev
;
197 haptic
->input_dev
->close
= regulator_haptic_close
;
198 input_set_drvdata(haptic
->input_dev
, haptic
);
199 input_set_capability(haptic
->input_dev
, EV_FF
, FF_RUMBLE
);
201 error
= input_ff_create_memless(input_dev
, NULL
,
202 regulator_haptic_play_effect
);
204 dev_err(&pdev
->dev
, "failed to create force-feedback\n");
208 error
= input_register_device(haptic
->input_dev
);
210 dev_err(&pdev
->dev
, "failed to register input device\n");
217 static int __maybe_unused
regulator_haptic_suspend(struct device
*dev
)
219 struct platform_device
*pdev
= to_platform_device(dev
);
220 struct regulator_haptic
*haptic
= platform_get_drvdata(pdev
);
223 error
= mutex_lock_interruptible(&haptic
->mutex
);
227 regulator_haptic_set_voltage(haptic
, 0);
228 regulator_haptic_toggle(haptic
, false);
230 haptic
->suspended
= true;
232 mutex_unlock(&haptic
->mutex
);
237 static int __maybe_unused
regulator_haptic_resume(struct device
*dev
)
239 struct platform_device
*pdev
= to_platform_device(dev
);
240 struct regulator_haptic
*haptic
= platform_get_drvdata(pdev
);
241 unsigned int magnitude
;
243 mutex_lock(&haptic
->mutex
);
245 haptic
->suspended
= false;
247 magnitude
= ACCESS_ONCE(haptic
->magnitude
);
249 regulator_haptic_set_voltage(haptic
, magnitude
);
250 regulator_haptic_toggle(haptic
, true);
253 mutex_unlock(&haptic
->mutex
);
258 static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops
,
259 regulator_haptic_suspend
, regulator_haptic_resume
);
261 static struct of_device_id regulator_haptic_dt_match
[] = {
262 { .compatible
= "regulator-haptic" },
266 static struct platform_driver regulator_haptic_driver
= {
267 .probe
= regulator_haptic_probe
,
269 .name
= "regulator-haptic",
270 .of_match_table
= regulator_haptic_dt_match
,
271 .pm
= ®ulator_haptic_pm_ops
,
274 module_platform_driver(regulator_haptic_driver
);
276 MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
277 MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
278 MODULE_DESCRIPTION("Regulator haptic driver");
279 MODULE_LICENSE("GPL");