Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.5 281 lines 7.1 kB view raw
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");