Commit | Line | Data |
---|---|---|
97fb5e8d | 1 | // SPDX-License-Identifier: GPL-2.0-only |
11205bb6 | 2 | /* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. |
11205bb6 AM |
3 | */ |
4 | ||
11205bb6 | 5 | #include <linux/errno.h> |
11205bb6 | 6 | #include <linux/input.h> |
f6bcc91b DR |
7 | #include <linux/kernel.h> |
8 | #include <linux/module.h> | |
d4c7c5c9 | 9 | #include <linux/of.h> |
2de3b704 | 10 | #include <linux/of_device.h> |
f6bcc91b | 11 | #include <linux/platform_device.h> |
21014b80 | 12 | #include <linux/regmap.h> |
f6bcc91b | 13 | #include <linux/slab.h> |
11205bb6 | 14 | |
11205bb6 AM |
15 | #define VIB_MAX_LEVEL_mV (3100) |
16 | #define VIB_MIN_LEVEL_mV (1200) | |
17 | #define VIB_MAX_LEVELS (VIB_MAX_LEVEL_mV - VIB_MIN_LEVEL_mV) | |
18 | ||
19 | #define MAX_FF_SPEED 0xff | |
20 | ||
2de3b704 | 21 | struct pm8xxx_regs { |
d4c7c5c9 DR |
22 | unsigned int enable_addr; |
23 | unsigned int enable_mask; | |
24 | ||
2de3b704 DR |
25 | unsigned int drv_addr; |
26 | unsigned int drv_mask; | |
27 | unsigned int drv_shift; | |
28 | unsigned int drv_en_manual_mask; | |
29 | }; | |
30 | ||
31 | static const struct pm8xxx_regs pm8058_regs = { | |
32 | .drv_addr = 0x4A, | |
33 | .drv_mask = 0xf8, | |
34 | .drv_shift = 3, | |
35 | .drv_en_manual_mask = 0xfc, | |
36 | }; | |
37 | ||
792ad668 DR |
38 | static struct pm8xxx_regs pm8916_regs = { |
39 | .enable_addr = 0xc046, | |
40 | .enable_mask = BIT(7), | |
41 | .drv_addr = 0xc041, | |
42 | .drv_mask = 0x1F, | |
43 | .drv_shift = 0, | |
44 | .drv_en_manual_mask = 0, | |
45 | }; | |
46 | ||
11205bb6 AM |
47 | /** |
48 | * struct pm8xxx_vib - structure to hold vibrator data | |
49 | * @vib_input_dev: input device supporting force feedback | |
50 | * @work: work structure to set the vibration parameters | |
21014b80 | 51 | * @regmap: regmap for register read/write |
2de3b704 | 52 | * @regs: registers' info |
11205bb6 AM |
53 | * @speed: speed of vibration set from userland |
54 | * @active: state of vibrator | |
55 | * @level: level of vibration to set in the chip | |
2de3b704 | 56 | * @reg_vib_drv: regs->drv_addr register value |
11205bb6 AM |
57 | */ |
58 | struct pm8xxx_vib { | |
59 | struct input_dev *vib_input_dev; | |
60 | struct work_struct work; | |
21014b80 | 61 | struct regmap *regmap; |
2de3b704 | 62 | const struct pm8xxx_regs *regs; |
11205bb6 AM |
63 | int speed; |
64 | int level; | |
65 | bool active; | |
66 | u8 reg_vib_drv; | |
67 | }; | |
68 | ||
11205bb6 AM |
69 | /** |
70 | * pm8xxx_vib_set - handler to start/stop vibration | |
71 | * @vib: pointer to vibrator structure | |
72 | * @on: state to set | |
73 | */ | |
74 | static int pm8xxx_vib_set(struct pm8xxx_vib *vib, bool on) | |
75 | { | |
76 | int rc; | |
21014b80 | 77 | unsigned int val = vib->reg_vib_drv; |
2de3b704 | 78 | const struct pm8xxx_regs *regs = vib->regs; |
11205bb6 AM |
79 | |
80 | if (on) | |
2de3b704 | 81 | val |= (vib->level << regs->drv_shift) & regs->drv_mask; |
11205bb6 | 82 | else |
2de3b704 | 83 | val &= ~regs->drv_mask; |
11205bb6 | 84 | |
2de3b704 | 85 | rc = regmap_write(vib->regmap, regs->drv_addr, val); |
11205bb6 AM |
86 | if (rc < 0) |
87 | return rc; | |
88 | ||
89 | vib->reg_vib_drv = val; | |
d4c7c5c9 DR |
90 | |
91 | if (regs->enable_mask) | |
92 | rc = regmap_update_bits(vib->regmap, regs->enable_addr, | |
93 | on ? regs->enable_mask : 0, val); | |
94 | ||
95 | return rc; | |
11205bb6 AM |
96 | } |
97 | ||
98 | /** | |
99 | * pm8xxx_work_handler - worker to set vibration level | |
100 | * @work: pointer to work_struct | |
101 | */ | |
102 | static void pm8xxx_work_handler(struct work_struct *work) | |
103 | { | |
104 | struct pm8xxx_vib *vib = container_of(work, struct pm8xxx_vib, work); | |
2de3b704 | 105 | const struct pm8xxx_regs *regs = vib->regs; |
11205bb6 | 106 | int rc; |
21014b80 | 107 | unsigned int val; |
11205bb6 | 108 | |
2de3b704 | 109 | rc = regmap_read(vib->regmap, regs->drv_addr, &val); |
11205bb6 AM |
110 | if (rc < 0) |
111 | return; | |
112 | ||
113 | /* | |
114 | * pmic vibrator supports voltage ranges from 1.2 to 3.1V, so | |
115 | * scale the level to fit into these ranges. | |
116 | */ | |
117 | if (vib->speed) { | |
118 | vib->active = true; | |
119 | vib->level = ((VIB_MAX_LEVELS * vib->speed) / MAX_FF_SPEED) + | |
120 | VIB_MIN_LEVEL_mV; | |
121 | vib->level /= 100; | |
122 | } else { | |
123 | vib->active = false; | |
124 | vib->level = VIB_MIN_LEVEL_mV / 100; | |
125 | } | |
126 | ||
127 | pm8xxx_vib_set(vib, vib->active); | |
128 | } | |
129 | ||
130 | /** | |
131 | * pm8xxx_vib_close - callback of input close callback | |
132 | * @dev: input device pointer | |
133 | * | |
134 | * Turns off the vibrator. | |
135 | */ | |
136 | static void pm8xxx_vib_close(struct input_dev *dev) | |
137 | { | |
138 | struct pm8xxx_vib *vib = input_get_drvdata(dev); | |
139 | ||
140 | cancel_work_sync(&vib->work); | |
141 | if (vib->active) | |
142 | pm8xxx_vib_set(vib, false); | |
143 | } | |
144 | ||
145 | /** | |
146 | * pm8xxx_vib_play_effect - function to handle vib effects. | |
147 | * @dev: input device pointer | |
148 | * @data: data of effect | |
149 | * @effect: effect to play | |
150 | * | |
151 | * Currently this driver supports only rumble effects. | |
152 | */ | |
153 | static int pm8xxx_vib_play_effect(struct input_dev *dev, void *data, | |
154 | struct ff_effect *effect) | |
155 | { | |
156 | struct pm8xxx_vib *vib = input_get_drvdata(dev); | |
157 | ||
158 | vib->speed = effect->u.rumble.strong_magnitude >> 8; | |
159 | if (!vib->speed) | |
160 | vib->speed = effect->u.rumble.weak_magnitude >> 9; | |
161 | ||
162 | schedule_work(&vib->work); | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
5298cc4c | 167 | static int pm8xxx_vib_probe(struct platform_device *pdev) |
11205bb6 AM |
168 | { |
169 | struct pm8xxx_vib *vib; | |
170 | struct input_dev *input_dev; | |
171 | int error; | |
21014b80 | 172 | unsigned int val; |
2de3b704 | 173 | const struct pm8xxx_regs *regs; |
11205bb6 | 174 | |
12a5a8fd SB |
175 | vib = devm_kzalloc(&pdev->dev, sizeof(*vib), GFP_KERNEL); |
176 | if (!vib) | |
177 | return -ENOMEM; | |
178 | ||
21014b80 SB |
179 | vib->regmap = dev_get_regmap(pdev->dev.parent, NULL); |
180 | if (!vib->regmap) | |
181 | return -ENODEV; | |
182 | ||
12a5a8fd SB |
183 | input_dev = devm_input_allocate_device(&pdev->dev); |
184 | if (!input_dev) | |
185 | return -ENOMEM; | |
11205bb6 AM |
186 | |
187 | INIT_WORK(&vib->work, pm8xxx_work_handler); | |
11205bb6 AM |
188 | vib->vib_input_dev = input_dev; |
189 | ||
2de3b704 DR |
190 | regs = of_device_get_match_data(&pdev->dev); |
191 | ||
11205bb6 | 192 | /* operate in manual mode */ |
2de3b704 | 193 | error = regmap_read(vib->regmap, regs->drv_addr, &val); |
11205bb6 | 194 | if (error < 0) |
12a5a8fd SB |
195 | return error; |
196 | ||
2de3b704 DR |
197 | val &= regs->drv_en_manual_mask; |
198 | error = regmap_write(vib->regmap, regs->drv_addr, val); | |
11205bb6 | 199 | if (error < 0) |
12a5a8fd | 200 | return error; |
11205bb6 | 201 | |
2de3b704 | 202 | vib->regs = regs; |
11205bb6 AM |
203 | vib->reg_vib_drv = val; |
204 | ||
205 | input_dev->name = "pm8xxx_vib_ffmemless"; | |
206 | input_dev->id.version = 1; | |
11205bb6 AM |
207 | input_dev->close = pm8xxx_vib_close; |
208 | input_set_drvdata(input_dev, vib); | |
209 | input_set_capability(vib->vib_input_dev, EV_FF, FF_RUMBLE); | |
210 | ||
211 | error = input_ff_create_memless(input_dev, NULL, | |
212 | pm8xxx_vib_play_effect); | |
213 | if (error) { | |
214 | dev_err(&pdev->dev, | |
215 | "couldn't register vibrator as FF device\n"); | |
12a5a8fd | 216 | return error; |
11205bb6 AM |
217 | } |
218 | ||
219 | error = input_register_device(input_dev); | |
220 | if (error) { | |
221 | dev_err(&pdev->dev, "couldn't register input device\n"); | |
12a5a8fd | 222 | return error; |
11205bb6 AM |
223 | } |
224 | ||
225 | platform_set_drvdata(pdev, vib); | |
226 | return 0; | |
11205bb6 AM |
227 | } |
228 | ||
97a652a8 | 229 | static int __maybe_unused pm8xxx_vib_suspend(struct device *dev) |
11205bb6 AM |
230 | { |
231 | struct pm8xxx_vib *vib = dev_get_drvdata(dev); | |
232 | ||
233 | /* Turn off the vibrator */ | |
234 | pm8xxx_vib_set(vib, false); | |
235 | ||
236 | return 0; | |
237 | } | |
11205bb6 AM |
238 | |
239 | static SIMPLE_DEV_PM_OPS(pm8xxx_vib_pm_ops, pm8xxx_vib_suspend, NULL); | |
240 | ||
877e1f15 | 241 | static const struct of_device_id pm8xxx_vib_id_table[] = { |
2de3b704 DR |
242 | { .compatible = "qcom,pm8058-vib", .data = &pm8058_regs }, |
243 | { .compatible = "qcom,pm8921-vib", .data = &pm8058_regs }, | |
792ad668 | 244 | { .compatible = "qcom,pm8916-vib", .data = &pm8916_regs }, |
877e1f15 SB |
245 | { } |
246 | }; | |
247 | MODULE_DEVICE_TABLE(of, pm8xxx_vib_id_table); | |
248 | ||
11205bb6 AM |
249 | static struct platform_driver pm8xxx_vib_driver = { |
250 | .probe = pm8xxx_vib_probe, | |
11205bb6 AM |
251 | .driver = { |
252 | .name = "pm8xxx-vib", | |
11205bb6 | 253 | .pm = &pm8xxx_vib_pm_ops, |
877e1f15 | 254 | .of_match_table = pm8xxx_vib_id_table, |
11205bb6 AM |
255 | }, |
256 | }; | |
840a746b | 257 | module_platform_driver(pm8xxx_vib_driver); |
11205bb6 AM |
258 | |
259 | MODULE_ALIAS("platform:pm8xxx_vib"); | |
260 | MODULE_DESCRIPTION("PMIC8xxx vibrator driver based on ff-memless framework"); | |
261 | MODULE_LICENSE("GPL v2"); | |
262 | MODULE_AUTHOR("Amy Maloche <amaloche@codeaurora.org>"); |