1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2d64cb71bSJaewon Kim /* 3d64cb71bSJaewon Kim * Regulator haptic driver 4d64cb71bSJaewon Kim * 5d64cb71bSJaewon Kim * Copyright (c) 2014 Samsung Electronics Co., Ltd. 6d64cb71bSJaewon Kim * Author: Jaewon Kim <jaewon02.kim@samsung.com> 7d64cb71bSJaewon Kim * Author: Hyunhee Kim <hyunhee.kim@samsung.com> 8d64cb71bSJaewon Kim */ 9d64cb71bSJaewon Kim 10d64cb71bSJaewon Kim #include <linux/input.h> 11d64cb71bSJaewon Kim #include <linux/module.h> 12d64cb71bSJaewon Kim #include <linux/of.h> 13d64cb71bSJaewon Kim #include <linux/platform_data/regulator-haptic.h> 14d64cb71bSJaewon Kim #include <linux/platform_device.h> 15d64cb71bSJaewon Kim #include <linux/regulator/consumer.h> 16d64cb71bSJaewon Kim #include <linux/slab.h> 17d64cb71bSJaewon Kim 18d64cb71bSJaewon Kim #define MAX_MAGNITUDE_SHIFT 16 19d64cb71bSJaewon Kim 20d64cb71bSJaewon Kim struct regulator_haptic { 21d64cb71bSJaewon Kim struct device *dev; 22d64cb71bSJaewon Kim struct input_dev *input_dev; 23d64cb71bSJaewon Kim struct regulator *regulator; 24d64cb71bSJaewon Kim 25d64cb71bSJaewon Kim struct work_struct work; 26d64cb71bSJaewon Kim struct mutex mutex; 27d64cb71bSJaewon Kim 28d64cb71bSJaewon Kim bool active; 29d64cb71bSJaewon Kim bool suspended; 30d64cb71bSJaewon Kim 31d64cb71bSJaewon Kim unsigned int max_volt; 32d64cb71bSJaewon Kim unsigned int min_volt; 33d64cb71bSJaewon Kim unsigned int magnitude; 34d64cb71bSJaewon Kim }; 35d64cb71bSJaewon Kim 36d64cb71bSJaewon Kim static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on) 37d64cb71bSJaewon Kim { 38d64cb71bSJaewon Kim int error; 39d64cb71bSJaewon Kim 40d64cb71bSJaewon Kim if (haptic->active != on) { 41d64cb71bSJaewon Kim 42d64cb71bSJaewon Kim error = on ? regulator_enable(haptic->regulator) : 43d64cb71bSJaewon Kim regulator_disable(haptic->regulator); 44d64cb71bSJaewon Kim if (error) { 45d64cb71bSJaewon Kim dev_err(haptic->dev, 46d64cb71bSJaewon Kim "failed to switch regulator %s: %d\n", 47d64cb71bSJaewon Kim on ? "on" : "off", error); 48d64cb71bSJaewon Kim return error; 49d64cb71bSJaewon Kim } 50d64cb71bSJaewon Kim 51d64cb71bSJaewon Kim haptic->active = on; 52d64cb71bSJaewon Kim } 53d64cb71bSJaewon Kim 54d64cb71bSJaewon Kim return 0; 55d64cb71bSJaewon Kim } 56d64cb71bSJaewon Kim 57d64cb71bSJaewon Kim static int regulator_haptic_set_voltage(struct regulator_haptic *haptic, 58d64cb71bSJaewon Kim unsigned int magnitude) 59d64cb71bSJaewon Kim { 60d64cb71bSJaewon Kim u64 volt_mag_multi; 61d64cb71bSJaewon Kim unsigned int intensity; 62d64cb71bSJaewon Kim int error; 63d64cb71bSJaewon Kim 64d64cb71bSJaewon Kim volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude; 65d64cb71bSJaewon Kim intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT); 66d64cb71bSJaewon Kim 67d64cb71bSJaewon Kim error = regulator_set_voltage(haptic->regulator, 68d64cb71bSJaewon Kim intensity + haptic->min_volt, 69d64cb71bSJaewon Kim haptic->max_volt); 70d64cb71bSJaewon Kim if (error) { 71d64cb71bSJaewon Kim dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n", 72d64cb71bSJaewon Kim intensity + haptic->min_volt, error); 73d64cb71bSJaewon Kim return error; 74d64cb71bSJaewon Kim } 75d64cb71bSJaewon Kim 763cb6dcfaSAxel Lin regulator_haptic_toggle(haptic, !!magnitude); 773cb6dcfaSAxel Lin 78d64cb71bSJaewon Kim return 0; 79d64cb71bSJaewon Kim } 80d64cb71bSJaewon Kim 81d64cb71bSJaewon Kim static void regulator_haptic_work(struct work_struct *work) 82d64cb71bSJaewon Kim { 83d64cb71bSJaewon Kim struct regulator_haptic *haptic = container_of(work, 84d64cb71bSJaewon Kim struct regulator_haptic, work); 85d64cb71bSJaewon Kim 86d64cb71bSJaewon Kim mutex_lock(&haptic->mutex); 87d64cb71bSJaewon Kim 883cb6dcfaSAxel Lin if (!haptic->suspended) 893cb6dcfaSAxel Lin regulator_haptic_set_voltage(haptic, haptic->magnitude); 90d64cb71bSJaewon Kim 91d64cb71bSJaewon Kim mutex_unlock(&haptic->mutex); 92d64cb71bSJaewon Kim } 93d64cb71bSJaewon Kim 94d64cb71bSJaewon Kim static int regulator_haptic_play_effect(struct input_dev *input, void *data, 95d64cb71bSJaewon Kim struct ff_effect *effect) 96d64cb71bSJaewon Kim { 97d64cb71bSJaewon Kim struct regulator_haptic *haptic = input_get_drvdata(input); 98d64cb71bSJaewon Kim 99d64cb71bSJaewon Kim haptic->magnitude = effect->u.rumble.strong_magnitude; 100d64cb71bSJaewon Kim if (!haptic->magnitude) 101d64cb71bSJaewon Kim haptic->magnitude = effect->u.rumble.weak_magnitude; 102d64cb71bSJaewon Kim 103d64cb71bSJaewon Kim schedule_work(&haptic->work); 104d64cb71bSJaewon Kim 105d64cb71bSJaewon Kim return 0; 106d64cb71bSJaewon Kim } 107d64cb71bSJaewon Kim 108d64cb71bSJaewon Kim static void regulator_haptic_close(struct input_dev *input) 109d64cb71bSJaewon Kim { 110d64cb71bSJaewon Kim struct regulator_haptic *haptic = input_get_drvdata(input); 111d64cb71bSJaewon Kim 112d64cb71bSJaewon Kim cancel_work_sync(&haptic->work); 113d64cb71bSJaewon Kim regulator_haptic_set_voltage(haptic, 0); 114d64cb71bSJaewon Kim } 115d64cb71bSJaewon Kim 116d64cb71bSJaewon Kim static int __maybe_unused 117d64cb71bSJaewon Kim regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic) 118d64cb71bSJaewon Kim { 119d64cb71bSJaewon Kim struct device_node *node; 120d64cb71bSJaewon Kim int error; 121d64cb71bSJaewon Kim 122d64cb71bSJaewon Kim node = dev->of_node; 123d64cb71bSJaewon Kim if(!node) { 12498f27d96SColin Ian King dev_err(dev, "Missing device tree data\n"); 125d64cb71bSJaewon Kim return -EINVAL; 126d64cb71bSJaewon Kim } 127d64cb71bSJaewon Kim 128d64cb71bSJaewon Kim error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt); 129d64cb71bSJaewon Kim if (error) { 130d64cb71bSJaewon Kim dev_err(dev, "cannot parse max-microvolt\n"); 131d64cb71bSJaewon Kim return error; 132d64cb71bSJaewon Kim } 133d64cb71bSJaewon Kim 134d64cb71bSJaewon Kim error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt); 135d64cb71bSJaewon Kim if (error) { 136d64cb71bSJaewon Kim dev_err(dev, "cannot parse min-microvolt\n"); 137d64cb71bSJaewon Kim return error; 138d64cb71bSJaewon Kim } 139d64cb71bSJaewon Kim 140d64cb71bSJaewon Kim return 0; 141d64cb71bSJaewon Kim } 142d64cb71bSJaewon Kim 143d64cb71bSJaewon Kim static int regulator_haptic_probe(struct platform_device *pdev) 144d64cb71bSJaewon Kim { 145d64cb71bSJaewon Kim const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev); 146d64cb71bSJaewon Kim struct regulator_haptic *haptic; 147d64cb71bSJaewon Kim struct input_dev *input_dev; 148d64cb71bSJaewon Kim int error; 149d64cb71bSJaewon Kim 150d64cb71bSJaewon Kim haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL); 151d64cb71bSJaewon Kim if (!haptic) 152d64cb71bSJaewon Kim return -ENOMEM; 153d64cb71bSJaewon Kim 154d64cb71bSJaewon Kim platform_set_drvdata(pdev, haptic); 155d64cb71bSJaewon Kim haptic->dev = &pdev->dev; 156d64cb71bSJaewon Kim mutex_init(&haptic->mutex); 157d64cb71bSJaewon Kim INIT_WORK(&haptic->work, regulator_haptic_work); 158d64cb71bSJaewon Kim 159d64cb71bSJaewon Kim if (pdata) { 160d64cb71bSJaewon Kim haptic->max_volt = pdata->max_volt; 161d64cb71bSJaewon Kim haptic->min_volt = pdata->min_volt; 162d64cb71bSJaewon Kim } else if (IS_ENABLED(CONFIG_OF)) { 163d64cb71bSJaewon Kim error = regulator_haptic_parse_dt(&pdev->dev, haptic); 164d64cb71bSJaewon Kim if (error) 165d64cb71bSJaewon Kim return error; 166d64cb71bSJaewon Kim } else { 167d64cb71bSJaewon Kim dev_err(&pdev->dev, "Missing platform data\n"); 168d64cb71bSJaewon Kim return -EINVAL; 169d64cb71bSJaewon Kim } 170d64cb71bSJaewon Kim 171d64cb71bSJaewon Kim haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic"); 172d64cb71bSJaewon Kim if (IS_ERR(haptic->regulator)) { 173d64cb71bSJaewon Kim dev_err(&pdev->dev, "failed to get regulator\n"); 174d64cb71bSJaewon Kim return PTR_ERR(haptic->regulator); 175d64cb71bSJaewon Kim } 176d64cb71bSJaewon Kim 177d64cb71bSJaewon Kim input_dev = devm_input_allocate_device(&pdev->dev); 178d64cb71bSJaewon Kim if (!input_dev) 179d64cb71bSJaewon Kim return -ENOMEM; 180d64cb71bSJaewon Kim 181d64cb71bSJaewon Kim haptic->input_dev = input_dev; 182d64cb71bSJaewon Kim haptic->input_dev->name = "regulator-haptic"; 183d64cb71bSJaewon Kim haptic->input_dev->dev.parent = &pdev->dev; 184d64cb71bSJaewon Kim haptic->input_dev->close = regulator_haptic_close; 185d64cb71bSJaewon Kim input_set_drvdata(haptic->input_dev, haptic); 186d64cb71bSJaewon Kim input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE); 187d64cb71bSJaewon Kim 188d64cb71bSJaewon Kim error = input_ff_create_memless(input_dev, NULL, 189d64cb71bSJaewon Kim regulator_haptic_play_effect); 190d64cb71bSJaewon Kim if (error) { 191d64cb71bSJaewon Kim dev_err(&pdev->dev, "failed to create force-feedback\n"); 192d64cb71bSJaewon Kim return error; 193d64cb71bSJaewon Kim } 194d64cb71bSJaewon Kim 195d64cb71bSJaewon Kim error = input_register_device(haptic->input_dev); 196d64cb71bSJaewon Kim if (error) { 197d64cb71bSJaewon Kim dev_err(&pdev->dev, "failed to register input device\n"); 198d64cb71bSJaewon Kim return error; 199d64cb71bSJaewon Kim } 200d64cb71bSJaewon Kim 201d64cb71bSJaewon Kim return 0; 202d64cb71bSJaewon Kim } 203d64cb71bSJaewon Kim 204*1a3e6c1eSJonathan Cameron static int regulator_haptic_suspend(struct device *dev) 205d64cb71bSJaewon Kim { 206d64cb71bSJaewon Kim struct platform_device *pdev = to_platform_device(dev); 207d64cb71bSJaewon Kim struct regulator_haptic *haptic = platform_get_drvdata(pdev); 208d64cb71bSJaewon Kim int error; 209d64cb71bSJaewon Kim 210d64cb71bSJaewon Kim error = mutex_lock_interruptible(&haptic->mutex); 211d64cb71bSJaewon Kim if (error) 212d64cb71bSJaewon Kim return error; 213d64cb71bSJaewon Kim 214d64cb71bSJaewon Kim regulator_haptic_set_voltage(haptic, 0); 215d64cb71bSJaewon Kim 216d64cb71bSJaewon Kim haptic->suspended = true; 217d64cb71bSJaewon Kim 218d64cb71bSJaewon Kim mutex_unlock(&haptic->mutex); 219d64cb71bSJaewon Kim 220d64cb71bSJaewon Kim return 0; 221d64cb71bSJaewon Kim } 222d64cb71bSJaewon Kim 223*1a3e6c1eSJonathan Cameron static int regulator_haptic_resume(struct device *dev) 224d64cb71bSJaewon Kim { 225d64cb71bSJaewon Kim struct platform_device *pdev = to_platform_device(dev); 226d64cb71bSJaewon Kim struct regulator_haptic *haptic = platform_get_drvdata(pdev); 227d64cb71bSJaewon Kim unsigned int magnitude; 228d64cb71bSJaewon Kim 229d64cb71bSJaewon Kim mutex_lock(&haptic->mutex); 230d64cb71bSJaewon Kim 231d64cb71bSJaewon Kim haptic->suspended = false; 232d64cb71bSJaewon Kim 2336aa7de05SMark Rutland magnitude = READ_ONCE(haptic->magnitude); 2343cb6dcfaSAxel Lin if (magnitude) 235d64cb71bSJaewon Kim regulator_haptic_set_voltage(haptic, magnitude); 236d64cb71bSJaewon Kim 237d64cb71bSJaewon Kim mutex_unlock(&haptic->mutex); 238d64cb71bSJaewon Kim 239d64cb71bSJaewon Kim return 0; 240d64cb71bSJaewon Kim } 241d64cb71bSJaewon Kim 242*1a3e6c1eSJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops, 243d64cb71bSJaewon Kim regulator_haptic_suspend, regulator_haptic_resume); 244d64cb71bSJaewon Kim 245245165deSFabian Frederick static const struct of_device_id regulator_haptic_dt_match[] = { 246d64cb71bSJaewon Kim { .compatible = "regulator-haptic" }, 247d64cb71bSJaewon Kim { /* sentinel */ }, 248d64cb71bSJaewon Kim }; 24973185771SLuis de Bethencourt MODULE_DEVICE_TABLE(of, regulator_haptic_dt_match); 250d64cb71bSJaewon Kim 251d64cb71bSJaewon Kim static struct platform_driver regulator_haptic_driver = { 252d64cb71bSJaewon Kim .probe = regulator_haptic_probe, 253d64cb71bSJaewon Kim .driver = { 254d64cb71bSJaewon Kim .name = "regulator-haptic", 255d64cb71bSJaewon Kim .of_match_table = regulator_haptic_dt_match, 256*1a3e6c1eSJonathan Cameron .pm = pm_sleep_ptr(®ulator_haptic_pm_ops), 257d64cb71bSJaewon Kim }, 258d64cb71bSJaewon Kim }; 259d64cb71bSJaewon Kim module_platform_driver(regulator_haptic_driver); 260d64cb71bSJaewon Kim 261d64cb71bSJaewon Kim MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>"); 262d64cb71bSJaewon Kim MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>"); 263d64cb71bSJaewon Kim MODULE_DESCRIPTION("Regulator haptic driver"); 264d64cb71bSJaewon Kim MODULE_LICENSE("GPL"); 265