Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add regulator haptic driver

This change adds support for haptic driver controlled by voltage of a
regulator. Userspace can control the device via Force Feedback interface
from input framework.

Signed-off-by: Jaewon Kim <jaewon02.kim@samsung.com>
Signed-off-by: Hyunhee Kim <hyunhee.kim@samsung.com>
Acked-by: Kyungmin Park <kyungmin.park@samsung.com>
Tested-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>
Reviewed-by: Pankaj Dubey <pankaj.dubey@samsung.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>

authored by

Jaewon Kim and committed by
Dmitry Torokhov
d64cb71b 27a560ba

+342
+21
Documentation/devicetree/bindings/input/regulator-haptic.txt
··· 1 + * Regulator Haptic Device Tree Bindings 2 + 3 + Required Properties: 4 + - compatible : Should be "regulator-haptic" 5 + - haptic-supply : Power supply to the haptic motor. 6 + [*] refer Documentation/devicetree/bindings/regulator/regulator.txt 7 + 8 + - max-microvolt : The maximum voltage value supplied to the haptic motor. 9 + [The unit of the voltage is a micro] 10 + 11 + - min-microvolt : The minimum voltage value supplied to the haptic motor. 12 + [The unit of the voltage is a micro] 13 + 14 + Example: 15 + 16 + haptics { 17 + compatible = "regulator-haptic"; 18 + haptic-supply = <&motor_regulator>; 19 + max-microvolt = <2700000>; 20 + min-microvolt = <1100000>; 21 + };
+12
drivers/input/misc/Kconfig
··· 394 394 To compile this driver as a module, choose M here: the module will be 395 395 called cm109. 396 396 397 + config INPUT_REGULATOR_HAPTIC 398 + tristate "Regulator haptics support" 399 + depends on REGULATOR 400 + select INPUT_FF_MEMLESS 401 + help 402 + This option enables device driver support for the haptic controlled 403 + by a regulator. This driver supports ff-memless interface 404 + from input framework. 405 + 406 + To compile this driver as a module, choose M here: the 407 + module will be called regulator-haptic. 408 + 397 409 config INPUT_RETU_PWRBUTTON 398 410 tristate "Retu Power button Driver" 399 411 depends on MFD_RETU
+1
drivers/input/misc/Makefile
··· 53 53 obj-$(CONFIG_INPUT_POWERMATE) += powermate.o 54 54 obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o 55 55 obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o 56 + obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o 56 57 obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o 57 58 obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o 58 59 obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
+279
drivers/input/misc/regulator-haptic.c
··· 1 + /* 2 + * Regulator haptic driver 3 + * 4 + * Copyright (c) 2014 Samsung Electronics Co., Ltd. 5 + * Author: Jaewon Kim <jaewon02.kim@samsung.com> 6 + * Author: Hyunhee Kim <hyunhee.kim@samsung.com> 7 + * 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. 11 + */ 12 + 13 + #include <linux/input.h> 14 + #include <linux/module.h> 15 + #include <linux/of.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> 20 + 21 + #define MAX_MAGNITUDE_SHIFT 16 22 + 23 + struct regulator_haptic { 24 + struct device *dev; 25 + struct input_dev *input_dev; 26 + struct regulator *regulator; 27 + 28 + struct work_struct work; 29 + struct mutex mutex; 30 + 31 + bool active; 32 + bool suspended; 33 + 34 + unsigned int max_volt; 35 + unsigned int min_volt; 36 + unsigned int magnitude; 37 + }; 38 + 39 + static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on) 40 + { 41 + int error; 42 + 43 + if (haptic->active != on) { 44 + 45 + error = on ? regulator_enable(haptic->regulator) : 46 + regulator_disable(haptic->regulator); 47 + if (error) { 48 + dev_err(haptic->dev, 49 + "failed to switch regulator %s: %d\n", 50 + on ? "on" : "off", error); 51 + return error; 52 + } 53 + 54 + haptic->active = on; 55 + } 56 + 57 + return 0; 58 + } 59 + 60 + static int regulator_haptic_set_voltage(struct regulator_haptic *haptic, 61 + unsigned int magnitude) 62 + { 63 + u64 volt_mag_multi; 64 + unsigned int intensity; 65 + int error; 66 + 67 + volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude; 68 + intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT); 69 + 70 + error = regulator_set_voltage(haptic->regulator, 71 + intensity + haptic->min_volt, 72 + haptic->max_volt); 73 + if (error) { 74 + dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n", 75 + intensity + haptic->min_volt, error); 76 + return error; 77 + } 78 + 79 + return 0; 80 + } 81 + 82 + static void regulator_haptic_work(struct work_struct *work) 83 + { 84 + struct regulator_haptic *haptic = container_of(work, 85 + struct regulator_haptic, work); 86 + unsigned int magnitude; 87 + int error; 88 + 89 + mutex_lock(&haptic->mutex); 90 + 91 + if (haptic->suspended) 92 + goto out; 93 + 94 + magnitude = ACCESS_ONCE(haptic->magnitude); 95 + 96 + error = regulator_haptic_set_voltage(haptic, magnitude); 97 + if (error) 98 + goto out; 99 + 100 + regulator_haptic_toggle(haptic, magnitude != 0); 101 + 102 + out: 103 + mutex_unlock(&haptic->mutex); 104 + } 105 + 106 + static int regulator_haptic_play_effect(struct input_dev *input, void *data, 107 + struct ff_effect *effect) 108 + { 109 + struct regulator_haptic *haptic = input_get_drvdata(input); 110 + 111 + haptic->magnitude = effect->u.rumble.strong_magnitude; 112 + if (!haptic->magnitude) 113 + haptic->magnitude = effect->u.rumble.weak_magnitude; 114 + 115 + schedule_work(&haptic->work); 116 + 117 + return 0; 118 + } 119 + 120 + static void regulator_haptic_close(struct input_dev *input) 121 + { 122 + struct regulator_haptic *haptic = input_get_drvdata(input); 123 + 124 + cancel_work_sync(&haptic->work); 125 + regulator_haptic_set_voltage(haptic, 0); 126 + regulator_haptic_toggle(haptic, false); 127 + } 128 + 129 + static int __maybe_unused 130 + regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) 131 + { 132 + struct device_node *node; 133 + int error; 134 + 135 + node = dev->of_node; 136 + if(!node) { 137 + dev_err(dev, "Missing dveice tree data\n"); 138 + return -EINVAL; 139 + } 140 + 141 + error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt); 142 + if (error) { 143 + dev_err(dev, "cannot parse max-microvolt\n"); 144 + return error; 145 + } 146 + 147 + error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt); 148 + if (error) { 149 + dev_err(dev, "cannot parse min-microvolt\n"); 150 + return error; 151 + } 152 + 153 + return 0; 154 + } 155 + 156 + static int regulator_haptic_probe(struct platform_device *pdev) 157 + { 158 + const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev); 159 + struct regulator_haptic *haptic; 160 + struct input_dev *input_dev; 161 + int error; 162 + 163 + haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); 164 + if (!haptic) 165 + return -ENOMEM; 166 + 167 + platform_set_drvdata(pdev, haptic); 168 + haptic->dev = &pdev->dev; 169 + mutex_init(&haptic->mutex); 170 + INIT_WORK(&haptic->work, regulator_haptic_work); 171 + 172 + if (pdata) { 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); 177 + if (error) 178 + return error; 179 + } else { 180 + dev_err(&pdev->dev, "Missing platform data\n"); 181 + return -EINVAL; 182 + } 183 + 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); 188 + } 189 + 190 + input_dev = devm_input_allocate_device(&pdev->dev); 191 + if (!input_dev) 192 + return -ENOMEM; 193 + 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); 200 + 201 + error = input_ff_create_memless(input_dev, NULL, 202 + regulator_haptic_play_effect); 203 + if (error) { 204 + dev_err(&pdev->dev, "failed to create force-feedback\n"); 205 + return error; 206 + } 207 + 208 + error = input_register_device(haptic->input_dev); 209 + if (error) { 210 + dev_err(&pdev->dev, "failed to register input device\n"); 211 + return error; 212 + } 213 + 214 + return 0; 215 + } 216 + 217 + static int __maybe_unused regulator_haptic_suspend(struct device *dev) 218 + { 219 + struct platform_device *pdev = to_platform_device(dev); 220 + struct regulator_haptic *haptic = platform_get_drvdata(pdev); 221 + int error; 222 + 223 + error = mutex_lock_interruptible(&haptic->mutex); 224 + if (error) 225 + return error; 226 + 227 + regulator_haptic_set_voltage(haptic, 0); 228 + regulator_haptic_toggle(haptic, false); 229 + 230 + haptic->suspended = true; 231 + 232 + mutex_unlock(&haptic->mutex); 233 + 234 + return 0; 235 + } 236 + 237 + static int __maybe_unused regulator_haptic_resume(struct device *dev) 238 + { 239 + struct platform_device *pdev = to_platform_device(dev); 240 + struct regulator_haptic *haptic = platform_get_drvdata(pdev); 241 + unsigned int magnitude; 242 + 243 + mutex_lock(&haptic->mutex); 244 + 245 + haptic->suspended = false; 246 + 247 + magnitude = ACCESS_ONCE(haptic->magnitude); 248 + if (magnitude) { 249 + regulator_haptic_set_voltage(haptic, magnitude); 250 + regulator_haptic_toggle(haptic, true); 251 + } 252 + 253 + mutex_unlock(&haptic->mutex); 254 + 255 + return 0; 256 + } 257 + 258 + static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, 259 + regulator_haptic_suspend, regulator_haptic_resume); 260 + 261 + static struct of_device_id regulator_haptic_dt_match[] = { 262 + { .compatible = "regulator-haptic" }, 263 + { /* sentinel */ }, 264 + }; 265 + 266 + static struct platform_driver regulator_haptic_driver = { 267 + .probe = regulator_haptic_probe, 268 + .driver = { 269 + .name = "regulator-haptic", 270 + .of_match_table = regulator_haptic_dt_match, 271 + .pm = &regulator_haptic_pm_ops, 272 + }, 273 + }; 274 + module_platform_driver(regulator_haptic_driver); 275 + 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");
+29
include/linux/platform_data/regulator-haptic.h
··· 1 + /* 2 + * Regulator Haptic Platform Data 3 + * 4 + * Copyright (c) 2014 Samsung Electronics Co., Ltd. 5 + * Author: Jaewon Kim <jaewon02.kim@samsung.com> 6 + * Author: Hyunhee Kim <hyunhee.kim@samsung.com> 7 + * 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. 11 + */ 12 + 13 + #ifndef _REGULATOR_HAPTIC_H 14 + #define _REGULATOR_HAPTIC_H 15 + 16 + /* 17 + * struct regulator_haptic_data - Platform device data 18 + * 19 + * @max_volt: maximum voltage value supplied to the haptic motor. 20 + * <The unit of the voltage is a micro> 21 + * @min_volt: minimum voltage value supplied to the haptic motor. 22 + * <The unit of the voltage is a micro> 23 + */ 24 + struct regulator_haptic_data { 25 + unsigned int max_volt; 26 + unsigned int min_volt; 27 + }; 28 + 29 + #endif /* _REGULATOR_HAPTIC_H */