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 regulator_haptic_toggle(haptic, !!magnitude); 80 81 return 0; 82 } 83 84 static void regulator_haptic_work(struct work_struct *work) 85 { 86 struct regulator_haptic *haptic = container_of(work, 87 struct regulator_haptic, work); 88 89 mutex_lock(&haptic->mutex); 90 91 if (!haptic->suspended) 92 regulator_haptic_set_voltage(haptic, haptic->magnitude); 93 94 mutex_unlock(&haptic->mutex); 95 } 96 97 static int regulator_haptic_play_effect(struct input_dev *input, void *data, 98 struct ff_effect *effect) 99 { 100 struct regulator_haptic *haptic = input_get_drvdata(input); 101 102 haptic->magnitude = effect->u.rumble.strong_magnitude; 103 if (!haptic->magnitude) 104 haptic->magnitude = effect->u.rumble.weak_magnitude; 105 106 schedule_work(&haptic->work); 107 108 return 0; 109 } 110 111 static void regulator_haptic_close(struct input_dev *input) 112 { 113 struct regulator_haptic *haptic = input_get_drvdata(input); 114 115 cancel_work_sync(&haptic->work); 116 regulator_haptic_set_voltage(haptic, 0); 117 } 118 119 static int __maybe_unused 120 regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) 121 { 122 struct device_node *node; 123 int error; 124 125 node = dev->of_node; 126 if(!node) { 127 dev_err(dev, "Missing dveice tree data\n"); 128 return -EINVAL; 129 } 130 131 error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt); 132 if (error) { 133 dev_err(dev, "cannot parse max-microvolt\n"); 134 return error; 135 } 136 137 error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt); 138 if (error) { 139 dev_err(dev, "cannot parse min-microvolt\n"); 140 return error; 141 } 142 143 return 0; 144 } 145 146 static int regulator_haptic_probe(struct platform_device *pdev) 147 { 148 const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev); 149 struct regulator_haptic *haptic; 150 struct input_dev *input_dev; 151 int error; 152 153 haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); 154 if (!haptic) 155 return -ENOMEM; 156 157 platform_set_drvdata(pdev, haptic); 158 haptic->dev = &pdev->dev; 159 mutex_init(&haptic->mutex); 160 INIT_WORK(&haptic->work, regulator_haptic_work); 161 162 if (pdata) { 163 haptic->max_volt = pdata->max_volt; 164 haptic->min_volt = pdata->min_volt; 165 } else if (IS_ENABLED(CONFIG_OF)) { 166 error = regulator_haptic_parse_dt(&pdev->dev, haptic); 167 if (error) 168 return error; 169 } else { 170 dev_err(&pdev->dev, "Missing platform data\n"); 171 return -EINVAL; 172 } 173 174 haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic"); 175 if (IS_ERR(haptic->regulator)) { 176 dev_err(&pdev->dev, "failed to get regulator\n"); 177 return PTR_ERR(haptic->regulator); 178 } 179 180 input_dev = devm_input_allocate_device(&pdev->dev); 181 if (!input_dev) 182 return -ENOMEM; 183 184 haptic->input_dev = input_dev; 185 haptic->input_dev->name = "regulator-haptic"; 186 haptic->input_dev->dev.parent = &pdev->dev; 187 haptic->input_dev->close = regulator_haptic_close; 188 input_set_drvdata(haptic->input_dev, haptic); 189 input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); 190 191 error = input_ff_create_memless(input_dev, NULL, 192 regulator_haptic_play_effect); 193 if (error) { 194 dev_err(&pdev->dev, "failed to create force-feedback\n"); 195 return error; 196 } 197 198 error = input_register_device(haptic->input_dev); 199 if (error) { 200 dev_err(&pdev->dev, "failed to register input device\n"); 201 return error; 202 } 203 204 return 0; 205 } 206 207 static int __maybe_unused regulator_haptic_suspend(struct device *dev) 208 { 209 struct platform_device *pdev = to_platform_device(dev); 210 struct regulator_haptic *haptic = platform_get_drvdata(pdev); 211 int error; 212 213 error = mutex_lock_interruptible(&haptic->mutex); 214 if (error) 215 return error; 216 217 regulator_haptic_set_voltage(haptic, 0); 218 219 haptic->suspended = true; 220 221 mutex_unlock(&haptic->mutex); 222 223 return 0; 224 } 225 226 static int __maybe_unused regulator_haptic_resume(struct device *dev) 227 { 228 struct platform_device *pdev = to_platform_device(dev); 229 struct regulator_haptic *haptic = platform_get_drvdata(pdev); 230 unsigned int magnitude; 231 232 mutex_lock(&haptic->mutex); 233 234 haptic->suspended = false; 235 236 magnitude = ACCESS_ONCE(haptic->magnitude); 237 if (magnitude) 238 regulator_haptic_set_voltage(haptic, magnitude); 239 240 mutex_unlock(&haptic->mutex); 241 242 return 0; 243 } 244 245 static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, 246 regulator_haptic_suspend, regulator_haptic_resume); 247 248 static const struct of_device_id regulator_haptic_dt_match[] = { 249 { .compatible = "regulator-haptic" }, 250 { /* sentinel */ }, 251 }; 252 253 static struct platform_driver regulator_haptic_driver = { 254 .probe = regulator_haptic_probe, 255 .driver = { 256 .name = "regulator-haptic", 257 .of_match_table = regulator_haptic_dt_match, 258 .pm = ®ulator_haptic_pm_ops, 259 }, 260 }; 261 module_platform_driver(regulator_haptic_driver); 262 263 MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); 264 MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>"); 265 MODULE_DESCRIPTION("Regulator haptic driver"); 266 MODULE_LICENSE("GPL"); 267