1 // SPDX-License-Identifier: GPL-2.0+
3 * Qualcomm MSM vibrator driver
5 * Copyright (c) 2018 Brian Masney <masneyb@onstation.org>
7 * Based on qcom,pwm-vibrator.c from:
8 * Copyright (c) 2018 Jonathan Marek <jonathan@marek.ca>
10 * Based on msm_pwm_vibrator.c from downstream Android sources:
11 * Copyright (C) 2009-2014 LGE, Inc.
14 #include <linux/clk.h>
15 #include <linux/err.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/input.h>
19 #include <linux/module.h>
21 #include <linux/platform_device.h>
22 #include <linux/regulator/consumer.h>
24 #define REG_CMD_RCGR 0x00
25 #define REG_CFG_RCGR 0x04
30 #define MMSS_CC_M_DEFAULT 1
33 struct input_dev
*input
;
35 struct work_struct worker
;
37 struct regulator
*vcc
;
39 struct gpio_desc
*enable_gpio
;
44 static void msm_vibrator_write(struct msm_vibrator
*vibrator
, int offset
,
47 writel(value
, vibrator
->base
+ offset
);
50 static int msm_vibrator_start(struct msm_vibrator
*vibrator
)
52 int d_reg_val
, ret
= 0;
54 mutex_lock(&vibrator
->mutex
);
56 if (!vibrator
->enabled
) {
57 ret
= clk_set_rate(vibrator
->clk
, 24000);
59 dev_err(&vibrator
->input
->dev
,
60 "Failed to set clock rate: %d\n", ret
);
64 ret
= clk_prepare_enable(vibrator
->clk
);
66 dev_err(&vibrator
->input
->dev
,
67 "Failed to enable clock: %d\n", ret
);
71 ret
= regulator_enable(vibrator
->vcc
);
73 dev_err(&vibrator
->input
->dev
,
74 "Failed to enable regulator: %d\n", ret
);
75 clk_disable(vibrator
->clk
);
79 gpiod_set_value_cansleep(vibrator
->enable_gpio
, 1);
81 vibrator
->enabled
= true;
84 d_reg_val
= 127 - ((126 * vibrator
->magnitude
) / 0xffff);
85 msm_vibrator_write(vibrator
, REG_CFG_RCGR
,
86 (2 << 12) | /* dual edge mode */
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);
96 mutex_unlock(&vibrator
->mutex
);
101 static void msm_vibrator_stop(struct msm_vibrator
*vibrator
)
103 mutex_lock(&vibrator
->mutex
);
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;
112 mutex_unlock(&vibrator
->mutex
);
115 static void msm_vibrator_worker(struct work_struct
*work
)
117 struct msm_vibrator
*vibrator
= container_of(work
,
121 if (vibrator
->magnitude
)
122 msm_vibrator_start(vibrator
);
124 msm_vibrator_stop(vibrator
);
127 static int msm_vibrator_play_effect(struct input_dev
*dev
, void *data
,
128 struct ff_effect
*effect
)
130 struct msm_vibrator
*vibrator
= input_get_drvdata(dev
);
132 mutex_lock(&vibrator
->mutex
);
134 if (effect
->u
.rumble
.strong_magnitude
> 0)
135 vibrator
->magnitude
= effect
->u
.rumble
.strong_magnitude
;
137 vibrator
->magnitude
= effect
->u
.rumble
.weak_magnitude
;
139 mutex_unlock(&vibrator
->mutex
);
141 schedule_work(&vibrator
->worker
);
146 static void msm_vibrator_close(struct input_dev
*input
)
148 struct msm_vibrator
*vibrator
= input_get_drvdata(input
);
150 cancel_work_sync(&vibrator
->worker
);
151 msm_vibrator_stop(vibrator
);
154 static int msm_vibrator_probe(struct platform_device
*pdev
)
156 struct msm_vibrator
*vibrator
;
157 struct resource
*res
;
160 vibrator
= devm_kzalloc(&pdev
->dev
, sizeof(*vibrator
), GFP_KERNEL
);
164 vibrator
->input
= devm_input_allocate_device(&pdev
->dev
);
165 if (!vibrator
->input
)
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
);
176 vibrator
->enable_gpio
= devm_gpiod_get(&pdev
->dev
, "enable",
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
);
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
);
193 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
195 dev_err(&pdev
->dev
, "Failed to get platform resource\n");
199 vibrator
->base
= devm_ioremap(&pdev
->dev
, res
->start
,
201 if (!vibrator
->base
) {
202 dev_err(&pdev
->dev
, "Failed to iomap resource.\n");
206 vibrator
->enabled
= false;
207 mutex_init(&vibrator
->mutex
);
208 INIT_WORK(&vibrator
->worker
, msm_vibrator_worker
);
210 vibrator
->input
->name
= "msm-vibrator";
211 vibrator
->input
->id
.bustype
= BUS_HOST
;
212 vibrator
->input
->close
= msm_vibrator_close
;
214 input_set_drvdata(vibrator
->input
, vibrator
);
215 input_set_capability(vibrator
->input
, EV_FF
, FF_RUMBLE
);
217 ret
= input_ff_create_memless(vibrator
->input
, NULL
,
218 msm_vibrator_play_effect
);
220 dev_err(&pdev
->dev
, "Failed to create ff memless: %d", ret
);
224 ret
= input_register_device(vibrator
->input
);
226 dev_err(&pdev
->dev
, "Failed to register input device: %d", ret
);
230 platform_set_drvdata(pdev
, vibrator
);
235 static int __maybe_unused
msm_vibrator_suspend(struct device
*dev
)
237 struct platform_device
*pdev
= to_platform_device(dev
);
238 struct msm_vibrator
*vibrator
= platform_get_drvdata(pdev
);
240 cancel_work_sync(&vibrator
->worker
);
242 if (vibrator
->enabled
)
243 msm_vibrator_stop(vibrator
);
248 static int __maybe_unused
msm_vibrator_resume(struct device
*dev
)
250 struct platform_device
*pdev
= to_platform_device(dev
);
251 struct msm_vibrator
*vibrator
= platform_get_drvdata(pdev
);
253 if (vibrator
->enabled
)
254 msm_vibrator_start(vibrator
);
259 static SIMPLE_DEV_PM_OPS(msm_vibrator_pm_ops
, msm_vibrator_suspend
,
260 msm_vibrator_resume
);
262 static const struct of_device_id msm_vibrator_of_match
[] = {
263 { .compatible
= "qcom,msm8226-vibrator" },
264 { .compatible
= "qcom,msm8974-vibrator" },
267 MODULE_DEVICE_TABLE(of
, msm_vibrator_of_match
);
269 static struct platform_driver msm_vibrator_driver
= {
270 .probe
= msm_vibrator_probe
,
272 .name
= "msm-vibrator",
273 .pm
= &msm_vibrator_pm_ops
,
274 .of_match_table
= of_match_ptr(msm_vibrator_of_match
),
277 module_platform_driver(msm_vibrator_driver
);
279 MODULE_AUTHOR("Brian Masney <masneyb@onstation.org>");
280 MODULE_DESCRIPTION("Qualcomm MSM vibrator driver");
281 MODULE_LICENSE("GPL");