root/drivers/input/misc/twl6040-vibra.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. twl6040_vib_irq_handler
  2. twl6040_vibra_enable
  3. twl6040_vibra_disable
  4. twl6040_vibra_code
  5. twl6040_vibra_set_effect
  6. vibra_play_work
  7. vibra_play
  8. twl6040_vibra_close
  9. twl6040_vibra_suspend
  10. twl6040_vibra_probe

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * twl6040-vibra.c - TWL6040 Vibrator driver
   4  *
   5  * Author:      Jorge Eduardo Candelaria <jorge.candelaria@ti.com>
   6  * Author:      Misael Lopez Cruz <misael.lopez@ti.com>
   7  *
   8  * Copyright:   (C) 2011 Texas Instruments, Inc.
   9  *
  10  * Based on twl4030-vibra.c by Henrik Saari <henrik.saari@nokia.com>
  11  *                              Felipe Balbi <felipe.balbi@nokia.com>
  12  *                              Jari Vanhala <ext-javi.vanhala@nokia.com>
  13  */
  14 #include <linux/module.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/of.h>
  17 #include <linux/workqueue.h>
  18 #include <linux/input.h>
  19 #include <linux/mfd/twl6040.h>
  20 #include <linux/slab.h>
  21 #include <linux/delay.h>
  22 #include <linux/regulator/consumer.h>
  23 
  24 #define EFFECT_DIR_180_DEG      0x8000
  25 
  26 /* Recommended modulation index 85% */
  27 #define TWL6040_VIBRA_MOD       85
  28 
  29 #define TWL6040_NUM_SUPPLIES 2
  30 
  31 struct vibra_info {
  32         struct device *dev;
  33         struct input_dev *input_dev;
  34         struct work_struct play_work;
  35 
  36         int irq;
  37 
  38         bool enabled;
  39         int weak_speed;
  40         int strong_speed;
  41         int direction;
  42 
  43         unsigned int vibldrv_res;
  44         unsigned int vibrdrv_res;
  45         unsigned int viblmotor_res;
  46         unsigned int vibrmotor_res;
  47 
  48         struct regulator_bulk_data supplies[TWL6040_NUM_SUPPLIES];
  49 
  50         struct twl6040 *twl6040;
  51 };
  52 
  53 static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
  54 {
  55         struct vibra_info *info = data;
  56         struct twl6040 *twl6040 = info->twl6040;
  57         u8 status;
  58 
  59         status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
  60         if (status & TWL6040_VIBLOCDET) {
  61                 dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
  62                 twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
  63                                    TWL6040_VIBENA);
  64         }
  65         if (status & TWL6040_VIBROCDET) {
  66                 dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
  67                 twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
  68                                    TWL6040_VIBENA);
  69         }
  70 
  71         return IRQ_HANDLED;
  72 }
  73 
  74 static void twl6040_vibra_enable(struct vibra_info *info)
  75 {
  76         struct twl6040 *twl6040 = info->twl6040;
  77         int ret;
  78 
  79         ret = regulator_bulk_enable(ARRAY_SIZE(info->supplies), info->supplies);
  80         if (ret) {
  81                 dev_err(info->dev, "failed to enable regulators %d\n", ret);
  82                 return;
  83         }
  84 
  85         twl6040_power(info->twl6040, 1);
  86         if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) {
  87                 /*
  88                  * ERRATA: Disable overcurrent protection for at least
  89                  * 3ms when enabling vibrator drivers to avoid false
  90                  * overcurrent detection
  91                  */
  92                 twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
  93                                   TWL6040_VIBENA | TWL6040_VIBCTRL);
  94                 twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
  95                                   TWL6040_VIBENA | TWL6040_VIBCTRL);
  96                 usleep_range(3000, 3500);
  97         }
  98 
  99         twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
 100                           TWL6040_VIBENA);
 101         twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
 102                           TWL6040_VIBENA);
 103 
 104         info->enabled = true;
 105 }
 106 
 107 static void twl6040_vibra_disable(struct vibra_info *info)
 108 {
 109         struct twl6040 *twl6040 = info->twl6040;
 110 
 111         twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, 0x00);
 112         twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, 0x00);
 113         twl6040_power(info->twl6040, 0);
 114 
 115         regulator_bulk_disable(ARRAY_SIZE(info->supplies), info->supplies);
 116 
 117         info->enabled = false;
 118 }
 119 
 120 static u8 twl6040_vibra_code(int vddvib, int vibdrv_res, int motor_res,
 121                              int speed, int direction)
 122 {
 123         int vpk, max_code;
 124         u8 vibdat;
 125 
 126         /* output swing */
 127         vpk = (vddvib * motor_res * TWL6040_VIBRA_MOD) /
 128                 (100 * (vibdrv_res + motor_res));
 129 
 130         /* 50mV per VIBDAT code step */
 131         max_code = vpk / 50;
 132         if (max_code > TWL6040_VIBDAT_MAX)
 133                 max_code = TWL6040_VIBDAT_MAX;
 134 
 135         /* scale speed to max allowed code */
 136         vibdat = (u8)((speed * max_code) / USHRT_MAX);
 137 
 138         /* 2's complement for direction > 180 degrees */
 139         vibdat *= direction;
 140 
 141         return vibdat;
 142 }
 143 
 144 static void twl6040_vibra_set_effect(struct vibra_info *info)
 145 {
 146         struct twl6040 *twl6040 = info->twl6040;
 147         u8 vibdatl, vibdatr;
 148         int volt;
 149 
 150         /* weak motor */
 151         volt = regulator_get_voltage(info->supplies[0].consumer) / 1000;
 152         vibdatl = twl6040_vibra_code(volt, info->vibldrv_res,
 153                                      info->viblmotor_res,
 154                                      info->weak_speed, info->direction);
 155 
 156         /* strong motor */
 157         volt = regulator_get_voltage(info->supplies[1].consumer) / 1000;
 158         vibdatr = twl6040_vibra_code(volt, info->vibrdrv_res,
 159                                      info->vibrmotor_res,
 160                                      info->strong_speed, info->direction);
 161 
 162         twl6040_reg_write(twl6040, TWL6040_REG_VIBDATL, vibdatl);
 163         twl6040_reg_write(twl6040, TWL6040_REG_VIBDATR, vibdatr);
 164 }
 165 
 166 static void vibra_play_work(struct work_struct *work)
 167 {
 168         struct vibra_info *info = container_of(work,
 169                                 struct vibra_info, play_work);
 170         int ret;
 171 
 172         /* Do not allow effect, while the routing is set to use audio */
 173         ret = twl6040_get_vibralr_status(info->twl6040);
 174         if (ret & TWL6040_VIBSEL) {
 175                 dev_info(info->dev, "Vibra is configured for audio\n");
 176                 return;
 177         }
 178 
 179         if (info->weak_speed || info->strong_speed) {
 180                 if (!info->enabled)
 181                         twl6040_vibra_enable(info);
 182 
 183                 twl6040_vibra_set_effect(info);
 184         } else if (info->enabled)
 185                 twl6040_vibra_disable(info);
 186 
 187 }
 188 
 189 static int vibra_play(struct input_dev *input, void *data,
 190                       struct ff_effect *effect)
 191 {
 192         struct vibra_info *info = input_get_drvdata(input);
 193 
 194         info->weak_speed = effect->u.rumble.weak_magnitude;
 195         info->strong_speed = effect->u.rumble.strong_magnitude;
 196         info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;
 197 
 198         schedule_work(&info->play_work);
 199 
 200         return 0;
 201 }
 202 
 203 static void twl6040_vibra_close(struct input_dev *input)
 204 {
 205         struct vibra_info *info = input_get_drvdata(input);
 206 
 207         cancel_work_sync(&info->play_work);
 208 
 209         if (info->enabled)
 210                 twl6040_vibra_disable(info);
 211 }
 212 
 213 static int __maybe_unused twl6040_vibra_suspend(struct device *dev)
 214 {
 215         struct platform_device *pdev = to_platform_device(dev);
 216         struct vibra_info *info = platform_get_drvdata(pdev);
 217 
 218         cancel_work_sync(&info->play_work);
 219 
 220         if (info->enabled)
 221                 twl6040_vibra_disable(info);
 222 
 223         return 0;
 224 }
 225 
 226 static SIMPLE_DEV_PM_OPS(twl6040_vibra_pm_ops, twl6040_vibra_suspend, NULL);
 227 
 228 static int twl6040_vibra_probe(struct platform_device *pdev)
 229 {
 230         struct device *twl6040_core_dev = pdev->dev.parent;
 231         struct device_node *twl6040_core_node;
 232         struct vibra_info *info;
 233         int vddvibl_uV = 0;
 234         int vddvibr_uV = 0;
 235         int error;
 236 
 237         twl6040_core_node = of_get_child_by_name(twl6040_core_dev->of_node,
 238                                                  "vibra");
 239         if (!twl6040_core_node) {
 240                 dev_err(&pdev->dev, "parent of node is missing?\n");
 241                 return -EINVAL;
 242         }
 243 
 244         info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
 245         if (!info) {
 246                 of_node_put(twl6040_core_node);
 247                 dev_err(&pdev->dev, "couldn't allocate memory\n");
 248                 return -ENOMEM;
 249         }
 250 
 251         info->dev = &pdev->dev;
 252 
 253         info->twl6040 = dev_get_drvdata(pdev->dev.parent);
 254 
 255         of_property_read_u32(twl6040_core_node, "ti,vibldrv-res",
 256                              &info->vibldrv_res);
 257         of_property_read_u32(twl6040_core_node, "ti,vibrdrv-res",
 258                              &info->vibrdrv_res);
 259         of_property_read_u32(twl6040_core_node, "ti,viblmotor-res",
 260                              &info->viblmotor_res);
 261         of_property_read_u32(twl6040_core_node, "ti,vibrmotor-res",
 262                              &info->vibrmotor_res);
 263         of_property_read_u32(twl6040_core_node, "ti,vddvibl-uV", &vddvibl_uV);
 264         of_property_read_u32(twl6040_core_node, "ti,vddvibr-uV", &vddvibr_uV);
 265 
 266         of_node_put(twl6040_core_node);
 267 
 268         if ((!info->vibldrv_res && !info->viblmotor_res) ||
 269             (!info->vibrdrv_res && !info->vibrmotor_res)) {
 270                 dev_err(info->dev, "invalid vibra driver/motor resistance\n");
 271                 return -EINVAL;
 272         }
 273 
 274         info->irq = platform_get_irq(pdev, 0);
 275         if (info->irq < 0)
 276                 return -EINVAL;
 277 
 278         error = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
 279                                           twl6040_vib_irq_handler,
 280                                           IRQF_ONESHOT,
 281                                           "twl6040_irq_vib", info);
 282         if (error) {
 283                 dev_err(info->dev, "VIB IRQ request failed: %d\n", error);
 284                 return error;
 285         }
 286 
 287         info->supplies[0].supply = "vddvibl";
 288         info->supplies[1].supply = "vddvibr";
 289         /*
 290          * When booted with Device tree the regulators are attached to the
 291          * parent device (twl6040 MFD core)
 292          */
 293         error = devm_regulator_bulk_get(twl6040_core_dev,
 294                                         ARRAY_SIZE(info->supplies),
 295                                         info->supplies);
 296         if (error) {
 297                 dev_err(info->dev, "couldn't get regulators %d\n", error);
 298                 return error;
 299         }
 300 
 301         if (vddvibl_uV) {
 302                 error = regulator_set_voltage(info->supplies[0].consumer,
 303                                               vddvibl_uV, vddvibl_uV);
 304                 if (error) {
 305                         dev_err(info->dev, "failed to set VDDVIBL volt %d\n",
 306                                 error);
 307                         return error;
 308                 }
 309         }
 310 
 311         if (vddvibr_uV) {
 312                 error = regulator_set_voltage(info->supplies[1].consumer,
 313                                               vddvibr_uV, vddvibr_uV);
 314                 if (error) {
 315                         dev_err(info->dev, "failed to set VDDVIBR volt %d\n",
 316                                 error);
 317                         return error;
 318                 }
 319         }
 320 
 321         INIT_WORK(&info->play_work, vibra_play_work);
 322 
 323         info->input_dev = devm_input_allocate_device(&pdev->dev);
 324         if (!info->input_dev) {
 325                 dev_err(info->dev, "couldn't allocate input device\n");
 326                 return -ENOMEM;
 327         }
 328 
 329         input_set_drvdata(info->input_dev, info);
 330 
 331         info->input_dev->name = "twl6040:vibrator";
 332         info->input_dev->id.version = 1;
 333         info->input_dev->close = twl6040_vibra_close;
 334         __set_bit(FF_RUMBLE, info->input_dev->ffbit);
 335 
 336         error = input_ff_create_memless(info->input_dev, NULL, vibra_play);
 337         if (error) {
 338                 dev_err(info->dev, "couldn't register vibrator to FF\n");
 339                 return error;
 340         }
 341 
 342         error = input_register_device(info->input_dev);
 343         if (error) {
 344                 dev_err(info->dev, "couldn't register input device\n");
 345                 return error;
 346         }
 347 
 348         platform_set_drvdata(pdev, info);
 349 
 350         return 0;
 351 }
 352 
 353 static struct platform_driver twl6040_vibra_driver = {
 354         .probe          = twl6040_vibra_probe,
 355         .driver         = {
 356                 .name   = "twl6040-vibra",
 357                 .pm     = &twl6040_vibra_pm_ops,
 358         },
 359 };
 360 module_platform_driver(twl6040_vibra_driver);
 361 
 362 MODULE_ALIAS("platform:twl6040-vibra");
 363 MODULE_DESCRIPTION("TWL6040 Vibra driver");
 364 MODULE_LICENSE("GPL");
 365 MODULE_AUTHOR("Jorge Eduardo Candelaria <jorge.candelaria@ti.com>");
 366 MODULE_AUTHOR("Misael Lopez Cruz <misael.lopez@ti.com>");

/* [<][>][^][v][top][bottom][index][help] */