root/drivers/input/misc/msm-vibrator.c

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

DEFINITIONS

This source file includes following definitions.
  1. msm_vibrator_write
  2. msm_vibrator_start
  3. msm_vibrator_stop
  4. msm_vibrator_worker
  5. msm_vibrator_play_effect
  6. msm_vibrator_close
  7. msm_vibrator_probe
  8. msm_vibrator_suspend
  9. msm_vibrator_resume

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Qualcomm MSM vibrator driver
   4  *
   5  * Copyright (c) 2018 Brian Masney <masneyb@onstation.org>
   6  *
   7  * Based on qcom,pwm-vibrator.c from:
   8  * Copyright (c) 2018 Jonathan Marek <jonathan@marek.ca>
   9  *
  10  * Based on msm_pwm_vibrator.c from downstream Android sources:
  11  * Copyright (C) 2009-2014 LGE, Inc.
  12  */
  13 
  14 #include <linux/clk.h>
  15 #include <linux/err.h>
  16 #include <linux/gpio/consumer.h>
  17 #include <linux/input.h>
  18 #include <linux/io.h>
  19 #include <linux/module.h>
  20 #include <linux/of.h>
  21 #include <linux/platform_device.h>
  22 #include <linux/regulator/consumer.h>
  23 
  24 #define REG_CMD_RCGR           0x00
  25 #define REG_CFG_RCGR           0x04
  26 #define REG_M                  0x08
  27 #define REG_N                  0x0C
  28 #define REG_D                  0x10
  29 #define REG_CBCR               0x24
  30 #define MMSS_CC_M_DEFAULT      1
  31 
  32 struct msm_vibrator {
  33         struct input_dev *input;
  34         struct mutex mutex;
  35         struct work_struct worker;
  36         void __iomem *base;
  37         struct regulator *vcc;
  38         struct clk *clk;
  39         struct gpio_desc *enable_gpio;
  40         u16 magnitude;
  41         bool enabled;
  42 };
  43 
  44 static void msm_vibrator_write(struct msm_vibrator *vibrator, int offset,
  45                                u32 value)
  46 {
  47         writel(value, vibrator->base + offset);
  48 }
  49 
  50 static int msm_vibrator_start(struct msm_vibrator *vibrator)
  51 {
  52         int d_reg_val, ret = 0;
  53 
  54         mutex_lock(&vibrator->mutex);
  55 
  56         if (!vibrator->enabled) {
  57                 ret = clk_set_rate(vibrator->clk, 24000);
  58                 if (ret) {
  59                         dev_err(&vibrator->input->dev,
  60                                 "Failed to set clock rate: %d\n", ret);
  61                         goto unlock;
  62                 }
  63 
  64                 ret = clk_prepare_enable(vibrator->clk);
  65                 if (ret) {
  66                         dev_err(&vibrator->input->dev,
  67                                 "Failed to enable clock: %d\n", ret);
  68                         goto unlock;
  69                 }
  70 
  71                 ret = regulator_enable(vibrator->vcc);
  72                 if (ret) {
  73                         dev_err(&vibrator->input->dev,
  74                                 "Failed to enable regulator: %d\n", ret);
  75                         clk_disable(vibrator->clk);
  76                         goto unlock;
  77                 }
  78 
  79                 gpiod_set_value_cansleep(vibrator->enable_gpio, 1);
  80 
  81                 vibrator->enabled = true;
  82         }
  83 
  84         d_reg_val = 127 - ((126 * vibrator->magnitude) / 0xffff);
  85         msm_vibrator_write(vibrator, REG_CFG_RCGR,
  86                            (2 << 12) | /* dual edge mode */
  87                            (0 << 8) |  /* cxo */
  88                            (7 << 0));
  89         msm_vibrator_write(vibrator, REG_M, 1);
  90         msm_vibrator_write(vibrator, REG_N, 128);
  91         msm_vibrator_write(vibrator, REG_D, d_reg_val);
  92         msm_vibrator_write(vibrator, REG_CMD_RCGR, 1);
  93         msm_vibrator_write(vibrator, REG_CBCR, 1);
  94 
  95 unlock:
  96         mutex_unlock(&vibrator->mutex);
  97 
  98         return ret;
  99 }
 100 
 101 static void msm_vibrator_stop(struct msm_vibrator *vibrator)
 102 {
 103         mutex_lock(&vibrator->mutex);
 104 
 105         if (vibrator->enabled) {
 106                 gpiod_set_value_cansleep(vibrator->enable_gpio, 0);
 107                 regulator_disable(vibrator->vcc);
 108                 clk_disable(vibrator->clk);
 109                 vibrator->enabled = false;
 110         }
 111 
 112         mutex_unlock(&vibrator->mutex);
 113 }
 114 
 115 static void msm_vibrator_worker(struct work_struct *work)
 116 {
 117         struct msm_vibrator *vibrator = container_of(work,
 118                                                      struct msm_vibrator,
 119                                                      worker);
 120 
 121         if (vibrator->magnitude)
 122                 msm_vibrator_start(vibrator);
 123         else
 124                 msm_vibrator_stop(vibrator);
 125 }
 126 
 127 static int msm_vibrator_play_effect(struct input_dev *dev, void *data,
 128                                     struct ff_effect *effect)
 129 {
 130         struct msm_vibrator *vibrator = input_get_drvdata(dev);
 131 
 132         mutex_lock(&vibrator->mutex);
 133 
 134         if (effect->u.rumble.strong_magnitude > 0)
 135                 vibrator->magnitude = effect->u.rumble.strong_magnitude;
 136         else
 137                 vibrator->magnitude = effect->u.rumble.weak_magnitude;
 138 
 139         mutex_unlock(&vibrator->mutex);
 140 
 141         schedule_work(&vibrator->worker);
 142 
 143         return 0;
 144 }
 145 
 146 static void msm_vibrator_close(struct input_dev *input)
 147 {
 148         struct msm_vibrator *vibrator = input_get_drvdata(input);
 149 
 150         cancel_work_sync(&vibrator->worker);
 151         msm_vibrator_stop(vibrator);
 152 }
 153 
 154 static int msm_vibrator_probe(struct platform_device *pdev)
 155 {
 156         struct msm_vibrator *vibrator;
 157         struct resource *res;
 158         int ret;
 159 
 160         vibrator = devm_kzalloc(&pdev->dev, sizeof(*vibrator), GFP_KERNEL);
 161         if (!vibrator)
 162                 return -ENOMEM;
 163 
 164         vibrator->input = devm_input_allocate_device(&pdev->dev);
 165         if (!vibrator->input)
 166                 return -ENOMEM;
 167 
 168         vibrator->vcc = devm_regulator_get(&pdev->dev, "vcc");
 169         if (IS_ERR(vibrator->vcc)) {
 170                 if (PTR_ERR(vibrator->vcc) != -EPROBE_DEFER)
 171                         dev_err(&pdev->dev, "Failed to get regulator: %ld\n",
 172                                 PTR_ERR(vibrator->vcc));
 173                 return PTR_ERR(vibrator->vcc);
 174         }
 175 
 176         vibrator->enable_gpio = devm_gpiod_get(&pdev->dev, "enable",
 177                                                GPIOD_OUT_LOW);
 178         if (IS_ERR(vibrator->enable_gpio)) {
 179                 if (PTR_ERR(vibrator->enable_gpio) != -EPROBE_DEFER)
 180                         dev_err(&pdev->dev, "Failed to get enable gpio: %ld\n",
 181                                 PTR_ERR(vibrator->enable_gpio));
 182                 return PTR_ERR(vibrator->enable_gpio);
 183         }
 184 
 185         vibrator->clk = devm_clk_get(&pdev->dev, "pwm");
 186         if (IS_ERR(vibrator->clk)) {
 187                 if (PTR_ERR(vibrator->clk) != -EPROBE_DEFER)
 188                         dev_err(&pdev->dev, "Failed to lookup pwm clock: %ld\n",
 189                                 PTR_ERR(vibrator->clk));
 190                 return PTR_ERR(vibrator->clk);
 191         }
 192 
 193         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 194         if (!res) {
 195                 dev_err(&pdev->dev, "Failed to get platform resource\n");
 196                 return -ENODEV;
 197         }
 198 
 199         vibrator->base = devm_ioremap(&pdev->dev, res->start,
 200                                      resource_size(res));
 201         if (!vibrator->base) {
 202                 dev_err(&pdev->dev, "Failed to iomap resource.\n");
 203                 return -ENOMEM;
 204         }
 205 
 206         vibrator->enabled = false;
 207         mutex_init(&vibrator->mutex);
 208         INIT_WORK(&vibrator->worker, msm_vibrator_worker);
 209 
 210         vibrator->input->name = "msm-vibrator";
 211         vibrator->input->id.bustype = BUS_HOST;
 212         vibrator->input->close = msm_vibrator_close;
 213 
 214         input_set_drvdata(vibrator->input, vibrator);
 215         input_set_capability(vibrator->input, EV_FF, FF_RUMBLE);
 216 
 217         ret = input_ff_create_memless(vibrator->input, NULL,
 218                                       msm_vibrator_play_effect);
 219         if (ret) {
 220                 dev_err(&pdev->dev, "Failed to create ff memless: %d", ret);
 221                 return ret;
 222         }
 223 
 224         ret = input_register_device(vibrator->input);
 225         if (ret) {
 226                 dev_err(&pdev->dev, "Failed to register input device: %d", ret);
 227                 return ret;
 228         }
 229 
 230         platform_set_drvdata(pdev, vibrator);
 231 
 232         return 0;
 233 }
 234 
 235 static int __maybe_unused msm_vibrator_suspend(struct device *dev)
 236 {
 237         struct platform_device *pdev = to_platform_device(dev);
 238         struct msm_vibrator *vibrator = platform_get_drvdata(pdev);
 239 
 240         cancel_work_sync(&vibrator->worker);
 241 
 242         if (vibrator->enabled)
 243                 msm_vibrator_stop(vibrator);
 244 
 245         return 0;
 246 }
 247 
 248 static int __maybe_unused msm_vibrator_resume(struct device *dev)
 249 {
 250         struct platform_device *pdev = to_platform_device(dev);
 251         struct msm_vibrator *vibrator = platform_get_drvdata(pdev);
 252 
 253         if (vibrator->enabled)
 254                 msm_vibrator_start(vibrator);
 255 
 256         return 0;
 257 }
 258 
 259 static SIMPLE_DEV_PM_OPS(msm_vibrator_pm_ops, msm_vibrator_suspend,
 260                          msm_vibrator_resume);
 261 
 262 static const struct of_device_id msm_vibrator_of_match[] = {
 263         { .compatible = "qcom,msm8226-vibrator" },
 264         { .compatible = "qcom,msm8974-vibrator" },
 265         {},
 266 };
 267 MODULE_DEVICE_TABLE(of, msm_vibrator_of_match);
 268 
 269 static struct platform_driver msm_vibrator_driver = {
 270         .probe  = msm_vibrator_probe,
 271         .driver = {
 272                 .name = "msm-vibrator",
 273                 .pm = &msm_vibrator_pm_ops,
 274                 .of_match_table = of_match_ptr(msm_vibrator_of_match),
 275         },
 276 };
 277 module_platform_driver(msm_vibrator_driver);
 278 
 279 MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>");
 280 MODULE_DESCRIPTION("Qualcomm MSM vibrator driver");
 281 MODULE_LICENSE("GPL");

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