1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * DRV2665 haptics driver family |
4 | * |
5 | * Author: Dan Murphy <dmurphy@ti.com> |
6 | * |
7 | * Copyright: (C) 2015 Texas Instruments, Inc. |
8 | */ |
9 | |
10 | #include <linux/i2c.h> |
11 | #include <linux/input.h> |
12 | #include <linux/module.h> |
13 | #include <linux/regmap.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/delay.h> |
16 | #include <linux/regulator/consumer.h> |
17 | |
18 | /* Contol registers */ |
19 | #define DRV2665_STATUS 0x00 |
20 | #define DRV2665_CTRL_1 0x01 |
21 | #define DRV2665_CTRL_2 0x02 |
22 | #define DRV2665_FIFO 0x0b |
23 | |
24 | /* Status Register */ |
25 | #define DRV2665_FIFO_FULL BIT(0) |
26 | #define DRV2665_FIFO_EMPTY BIT(1) |
27 | |
28 | /* Control 1 Register */ |
29 | #define DRV2665_25_VPP_GAIN 0x00 |
30 | #define DRV2665_50_VPP_GAIN 0x01 |
31 | #define DRV2665_75_VPP_GAIN 0x02 |
32 | #define DRV2665_100_VPP_GAIN 0x03 |
33 | #define DRV2665_DIGITAL_IN 0xfc |
34 | #define DRV2665_ANALOG_IN BIT(2) |
35 | |
36 | /* Control 2 Register */ |
37 | #define DRV2665_BOOST_EN BIT(1) |
38 | #define DRV2665_STANDBY BIT(6) |
39 | #define DRV2665_DEV_RST BIT(7) |
40 | #define DRV2665_5_MS_IDLE_TOUT 0x00 |
41 | #define DRV2665_10_MS_IDLE_TOUT 0x04 |
42 | #define DRV2665_15_MS_IDLE_TOUT 0x08 |
43 | #define DRV2665_20_MS_IDLE_TOUT 0x0c |
44 | |
45 | /** |
46 | * struct drv2665_data - |
47 | * @input_dev: Pointer to the input device |
48 | * @client: Pointer to the I2C client |
49 | * @regmap: Register map of the device |
50 | * @work: Work item used to off load the enable/disable of the vibration |
51 | * @regulator: Pointer to the regulator for the IC |
52 | */ |
53 | struct drv2665_data { |
54 | struct input_dev *input_dev; |
55 | struct i2c_client *client; |
56 | struct regmap *regmap; |
57 | struct work_struct work; |
58 | struct regulator *regulator; |
59 | }; |
60 | |
61 | /* 8kHz Sine wave to stream to the FIFO */ |
62 | static const u8 drv2665_sine_wave_form[] = { |
63 | 0x00, 0x10, 0x20, 0x2e, 0x3c, 0x48, 0x53, 0x5b, 0x61, 0x65, 0x66, |
64 | 0x65, 0x61, 0x5b, 0x53, 0x48, 0x3c, 0x2e, 0x20, 0x10, |
65 | 0x00, 0xf0, 0xe0, 0xd2, 0xc4, 0xb8, 0xad, 0xa5, 0x9f, 0x9b, 0x9a, |
66 | 0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00, |
67 | }; |
68 | |
69 | static const struct reg_default drv2665_reg_defs[] = { |
70 | { DRV2665_STATUS, 0x02 }, |
71 | { DRV2665_CTRL_1, 0x28 }, |
72 | { DRV2665_CTRL_2, 0x40 }, |
73 | { DRV2665_FIFO, 0x00 }, |
74 | }; |
75 | |
76 | static void drv2665_worker(struct work_struct *work) |
77 | { |
78 | struct drv2665_data *haptics = |
79 | container_of(work, struct drv2665_data, work); |
80 | unsigned int read_buf; |
81 | int error; |
82 | |
83 | error = regmap_read(map: haptics->regmap, DRV2665_STATUS, val: &read_buf); |
84 | if (error) { |
85 | dev_err(&haptics->client->dev, |
86 | "Failed to read status: %d\n" , error); |
87 | return; |
88 | } |
89 | |
90 | if (read_buf & DRV2665_FIFO_EMPTY) { |
91 | error = regmap_bulk_write(map: haptics->regmap, |
92 | DRV2665_FIFO, |
93 | val: drv2665_sine_wave_form, |
94 | ARRAY_SIZE(drv2665_sine_wave_form)); |
95 | if (error) { |
96 | dev_err(&haptics->client->dev, |
97 | "Failed to write FIFO: %d\n" , error); |
98 | return; |
99 | } |
100 | } |
101 | } |
102 | |
103 | static int drv2665_haptics_play(struct input_dev *input, void *data, |
104 | struct ff_effect *effect) |
105 | { |
106 | struct drv2665_data *haptics = input_get_drvdata(dev: input); |
107 | |
108 | schedule_work(work: &haptics->work); |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | static void drv2665_close(struct input_dev *input) |
114 | { |
115 | struct drv2665_data *haptics = input_get_drvdata(dev: input); |
116 | int error; |
117 | |
118 | cancel_work_sync(work: &haptics->work); |
119 | |
120 | error = regmap_update_bits(map: haptics->regmap, DRV2665_CTRL_2, |
121 | DRV2665_STANDBY, DRV2665_STANDBY); |
122 | if (error) |
123 | dev_err(&haptics->client->dev, |
124 | "Failed to enter standby mode: %d\n" , error); |
125 | } |
126 | |
127 | static const struct reg_sequence drv2665_init_regs[] = { |
128 | { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT }, |
129 | { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN }, |
130 | }; |
131 | |
132 | static int drv2665_init(struct drv2665_data *haptics) |
133 | { |
134 | int error; |
135 | |
136 | error = regmap_register_patch(map: haptics->regmap, |
137 | regs: drv2665_init_regs, |
138 | ARRAY_SIZE(drv2665_init_regs)); |
139 | if (error) { |
140 | dev_err(&haptics->client->dev, |
141 | "Failed to write init registers: %d\n" , |
142 | error); |
143 | return error; |
144 | } |
145 | |
146 | return 0; |
147 | } |
148 | |
149 | static const struct regmap_config drv2665_regmap_config = { |
150 | .reg_bits = 8, |
151 | .val_bits = 8, |
152 | |
153 | .max_register = DRV2665_FIFO, |
154 | .reg_defaults = drv2665_reg_defs, |
155 | .num_reg_defaults = ARRAY_SIZE(drv2665_reg_defs), |
156 | .cache_type = REGCACHE_NONE, |
157 | }; |
158 | |
159 | static int drv2665_probe(struct i2c_client *client) |
160 | { |
161 | struct drv2665_data *haptics; |
162 | int error; |
163 | |
164 | haptics = devm_kzalloc(dev: &client->dev, size: sizeof(*haptics), GFP_KERNEL); |
165 | if (!haptics) |
166 | return -ENOMEM; |
167 | |
168 | haptics->regulator = devm_regulator_get(dev: &client->dev, id: "vbat" ); |
169 | if (IS_ERR(ptr: haptics->regulator)) { |
170 | error = PTR_ERR(ptr: haptics->regulator); |
171 | dev_err(&client->dev, |
172 | "unable to get regulator, error: %d\n" , error); |
173 | return error; |
174 | } |
175 | |
176 | haptics->input_dev = devm_input_allocate_device(&client->dev); |
177 | if (!haptics->input_dev) { |
178 | dev_err(&client->dev, "Failed to allocate input device\n" ); |
179 | return -ENOMEM; |
180 | } |
181 | |
182 | haptics->input_dev->name = "drv2665:haptics" ; |
183 | haptics->input_dev->dev.parent = client->dev.parent; |
184 | haptics->input_dev->close = drv2665_close; |
185 | input_set_drvdata(dev: haptics->input_dev, data: haptics); |
186 | input_set_capability(dev: haptics->input_dev, EV_FF, FF_RUMBLE); |
187 | |
188 | error = input_ff_create_memless(dev: haptics->input_dev, NULL, |
189 | play_effect: drv2665_haptics_play); |
190 | if (error) { |
191 | dev_err(&client->dev, "input_ff_create() failed: %d\n" , |
192 | error); |
193 | return error; |
194 | } |
195 | |
196 | INIT_WORK(&haptics->work, drv2665_worker); |
197 | |
198 | haptics->client = client; |
199 | i2c_set_clientdata(client, data: haptics); |
200 | |
201 | haptics->regmap = devm_regmap_init_i2c(client, &drv2665_regmap_config); |
202 | if (IS_ERR(ptr: haptics->regmap)) { |
203 | error = PTR_ERR(ptr: haptics->regmap); |
204 | dev_err(&client->dev, "Failed to allocate register map: %d\n" , |
205 | error); |
206 | return error; |
207 | } |
208 | |
209 | error = drv2665_init(haptics); |
210 | if (error) { |
211 | dev_err(&client->dev, "Device init failed: %d\n" , error); |
212 | return error; |
213 | } |
214 | |
215 | error = input_register_device(haptics->input_dev); |
216 | if (error) { |
217 | dev_err(&client->dev, "couldn't register input device: %d\n" , |
218 | error); |
219 | return error; |
220 | } |
221 | |
222 | return 0; |
223 | } |
224 | |
225 | static int drv2665_suspend(struct device *dev) |
226 | { |
227 | struct drv2665_data *haptics = dev_get_drvdata(dev); |
228 | int ret = 0; |
229 | |
230 | mutex_lock(&haptics->input_dev->mutex); |
231 | |
232 | if (input_device_enabled(dev: haptics->input_dev)) { |
233 | ret = regmap_update_bits(map: haptics->regmap, DRV2665_CTRL_2, |
234 | DRV2665_STANDBY, DRV2665_STANDBY); |
235 | if (ret) { |
236 | dev_err(dev, "Failed to set standby mode\n" ); |
237 | regulator_disable(regulator: haptics->regulator); |
238 | goto out; |
239 | } |
240 | |
241 | ret = regulator_disable(regulator: haptics->regulator); |
242 | if (ret) { |
243 | dev_err(dev, "Failed to disable regulator\n" ); |
244 | regmap_update_bits(map: haptics->regmap, |
245 | DRV2665_CTRL_2, |
246 | DRV2665_STANDBY, val: 0); |
247 | } |
248 | } |
249 | out: |
250 | mutex_unlock(lock: &haptics->input_dev->mutex); |
251 | return ret; |
252 | } |
253 | |
254 | static int drv2665_resume(struct device *dev) |
255 | { |
256 | struct drv2665_data *haptics = dev_get_drvdata(dev); |
257 | int ret = 0; |
258 | |
259 | mutex_lock(&haptics->input_dev->mutex); |
260 | |
261 | if (input_device_enabled(dev: haptics->input_dev)) { |
262 | ret = regulator_enable(regulator: haptics->regulator); |
263 | if (ret) { |
264 | dev_err(dev, "Failed to enable regulator\n" ); |
265 | goto out; |
266 | } |
267 | |
268 | ret = regmap_update_bits(map: haptics->regmap, DRV2665_CTRL_2, |
269 | DRV2665_STANDBY, val: 0); |
270 | if (ret) { |
271 | dev_err(dev, "Failed to unset standby mode\n" ); |
272 | regulator_disable(regulator: haptics->regulator); |
273 | goto out; |
274 | } |
275 | |
276 | } |
277 | |
278 | out: |
279 | mutex_unlock(lock: &haptics->input_dev->mutex); |
280 | return ret; |
281 | } |
282 | |
283 | static DEFINE_SIMPLE_DEV_PM_OPS(drv2665_pm_ops, drv2665_suspend, drv2665_resume); |
284 | |
285 | static const struct i2c_device_id drv2665_id[] = { |
286 | { "drv2665" , 0 }, |
287 | { } |
288 | }; |
289 | MODULE_DEVICE_TABLE(i2c, drv2665_id); |
290 | |
291 | #ifdef CONFIG_OF |
292 | static const struct of_device_id drv2665_of_match[] = { |
293 | { .compatible = "ti,drv2665" , }, |
294 | { } |
295 | }; |
296 | MODULE_DEVICE_TABLE(of, drv2665_of_match); |
297 | #endif |
298 | |
299 | static struct i2c_driver drv2665_driver = { |
300 | .probe = drv2665_probe, |
301 | .driver = { |
302 | .name = "drv2665-haptics" , |
303 | .of_match_table = of_match_ptr(drv2665_of_match), |
304 | .pm = pm_sleep_ptr(&drv2665_pm_ops), |
305 | }, |
306 | .id_table = drv2665_id, |
307 | }; |
308 | module_i2c_driver(drv2665_driver); |
309 | |
310 | MODULE_DESCRIPTION("TI DRV2665 haptics driver" ); |
311 | MODULE_LICENSE("GPL" ); |
312 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>" ); |
313 | |