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