linux/drivers/input/misc/msm-vibrator.c
<<
>>
Prefs
   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
  32struct 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
  44static void msm_vibrator_write(struct msm_vibrator *vibrator, int offset,
  45                               u32 value)
  46{
  47        writel(value, vibrator->base + offset);
  48}
  49
  50static 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
  95unlock:
  96        mutex_unlock(&vibrator->mutex);
  97
  98        return ret;
  99}
 100
 101static 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
 115static 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
 127static 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
 146static 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
 154static 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
 235static 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
 248static 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
 259static SIMPLE_DEV_PM_OPS(msm_vibrator_pm_ops, msm_vibrator_suspend,
 260                         msm_vibrator_resume);
 261
 262static const struct of_device_id msm_vibrator_of_match[] = {
 263        { .compatible = "qcom,msm8226-vibrator" },
 264        { .compatible = "qcom,msm8974-vibrator" },
 265        {},
 266};
 267MODULE_DEVICE_TABLE(of, msm_vibrator_of_match);
 268
 269static 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};
 277module_platform_driver(msm_vibrator_driver);
 278
 279MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>");
 280MODULE_DESCRIPTION("Qualcomm MSM vibrator driver");
 281MODULE_LICENSE("GPL");
 282