1 /*
2 * Copyright 2024 Cirrus Logic, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * DRV2605 Datasheet: https://www.ti.com/lit/gpn/drv2605
7 */
8
9 #define DT_DRV_COMPAT ti_drv2605
10
11 #include <zephyr/device.h>
12 #include <zephyr/devicetree.h>
13 #include <zephyr/drivers/gpio.h>
14 #include <zephyr/drivers/i2c.h>
15 #include <zephyr/drivers/haptics.h>
16 #include <zephyr/drivers/haptics/drv2605.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/logging/log.h>
19 #include <zephyr/drivers/haptics.h>
20 #include <zephyr/pm/device.h>
21 #include <zephyr/pm/device_runtime.h>
22 #include <zephyr/sys/util.h>
23
24 LOG_MODULE_REGISTER(DRV2605, CONFIG_HAPTICS_LOG_LEVEL);
25
26 #define DRV2605_REG_STATUS 0x0
27 #define DRV2605_DEVICE_ID GENMASK(7, 5)
28 #define DRV2605_DEVICE_ID_DRV2605 0x3
29 #define DRV2605_DEVICE_ID_DRV2605L 0x7
30 #define DRV2605_DIAG_RESULT BIT(3)
31 #define DRV2605_FB_STS BIT(2)
32 #define DRV2605_OVER_TEMP BIT(1)
33 #define DRV2605_OC_DETECT BIT(0)
34
35 #define DRV2605_REG_MODE 0x1
36 #define DRV2605_DEV_RESET BIT(7)
37 #define DRV2605_STANDBY BIT(6)
38 #define DRV2605_MODE GENMASK(2, 0)
39
40 #define DRV2605_REG_RT_PLAYBACK_INPUT 0x2
41
42 #define DRV2605_REG_UNNAMED 0x3
43 #define DRV2605_HI_Z_OUTPUT BIT(4)
44 #define DRV2605_LIBRARY_SEL GENMASK(2, 0)
45
46 #define DRV2605_REG_WAVEFORM_SEQUENCER 0x4
47 #define DRV2605_WAIT BIT(7)
48 #define DRV2605_WAV_FRM_SEQ GENMASK(6, 0)
49
50 #define DRV2605_REG_GO 0xc
51 #define DRV2605_GO BIT(0)
52
53 #define DRV2605_REG_OVERDRIVE_TIME_OFFSET 0xd
54
55 #define DRV2605_REG_SUSTAIN_TIME_OFFSET_POS 0xe
56
57 #define DRV2605_REG_SUSTAIN_TIME_OFFSET_NEG 0xf
58
59 #define DRV2605_REG_BRAKE_TIME_OFFSET 0x10
60
61 #define DRV2605_TIME_STEP_MS 5
62
63 #define DRV2605_REG_AUDIO_TO_VIBE_CONTROL 0x11
64 #define DRV2605_ATH_PEAK_TIME GENMASK(3, 2)
65 #define DRV2605_ATH_FILTER GENMASK(1, 0)
66
67 #define DRV2605_REG_AUDIO_TO_VIBE_MIN_INPUT_LEVEL 0x12
68
69 #define DRV2605_REG_AUDIO_TO_VIBE_MAX_INPUT_LEVEL 0x13
70
71 #define DRV2605_ATH_INPUT_STEP_UV (1800000 / 255)
72
73 #define DRV2605_REG_AUDIO_TO_VIBE_MIN_OUTPUT_DRIVE 0x14
74
75 #define DRV2605_REG_AUDIO_TO_VIBE_MAX_OUTPUT_DRIVE 0x15
76
77 #define DRV2605_ATH_OUTPUT_DRIVE_PCT (100 * 255)
78
79 #define DRV2605_REG_RATED_VOLTAGE 0x16
80
81 #define DRV2605_REG_OVERDRIVE_CLAMP_VOLTAGE 0x17
82
83 #define DRV2605_REG_AUTO_CAL_COMP_RESULT 0x18
84
85 #define DRV2605_REG_AUTO_CAL_BACK_EMF_RESULT 0x19
86
87 #define DRV2605_REG_FEEDBACK_CONTROL 0x1a
88 #define DRV2605_N_ERM_LRA BIT(7)
89 #define DRV2605_FB_BRAKE_FACTOR GENMASK(6, 4)
90 #define DRV2605_LOOP_GAIN GENMASK(3, 2)
91 #define DRV2605_BEMF_GAIN GENMASK(1, 0)
92
93 #define DRV2605_ACTUATOR_MODE_ERM 0
94 #define DRV2605_ACTUATOR_MODE_LRA 1
95
96 #define DRV2605_REG_CONTROL1 0x1b
97 #define DRV2605_STARTUP_BOOST BIT(7)
98 #define DRV2605_AC_COUPLE BIT(5)
99 #define DRV2605_DRIVE_TIME GENMASK(4, 0)
100
101 #define DRV2605_REG_CONTROL2 0x1c
102 #define DRV2605_BIDIR_INPUT BIT(7)
103 #define DRV2605_BRAKE_STABILIZER BIT(6)
104 #define DRV2605_SAMPLE_TIME GENMASK(5, 4)
105 #define DRV2605_BLANKING_TIME GENMASK(3, 2)
106 #define DRV2605_IDISS_TIME GENMASK(1, 0)
107
108 #define DRV2605_REG_CONTROL3 0x1d
109 #define DRV2605_NG_THRESH GENMASK(7, 6)
110 #define DRV2605_ERM_OPEN_LOOP BIT(5)
111 #define DRV2605_SUPPLY_COMP_DIS BIT(4)
112 #define DRV2605_DATA_FORMAT_RTP BIT(3)
113 #define DRV2605_LRA_DRIVE_MODE BIT(2)
114 #define DRV2605_N_PWM_ANALOG BIT(1)
115 #define DRV2605_LRA_OPEN_LOOP BIT(0)
116
117 #define DRV2605_REG_CONTROL4 0x1e
118 #define DRV2605_ZERO_CROSSING_TIME GENMASK(7, 6)
119 #define DRV2605_AUTO_CAL_TIME GENMASK(5, 4)
120 #define DRV2605_OTP_STATUS BIT(2)
121 #define DRV2605_OTP_PROGRAM BIT(0)
122
123 #define DRV2605_REG_BATT_VOLTAGE_MONITOR 0x21
124 #define DRV2605_VBAT_STEP_UV (5600000 / 255)
125
126 #define DRV2605_REG_LRA_RESONANCE_PERIOD 0x22
127
128 #define DRV2605_POWER_UP_DELAY_US 250
129
130 #define DRV2605_VOLTAGE_SCALE_FACTOR_MV 5600
131
132 #define DRV2605_CALCULATE_VOLTAGE(_volt) ((_volt * 255) / DRV2605_VOLTAGE_SCALE_FACTOR_MV)
133
134 struct drv2605_config {
135 struct i2c_dt_spec i2c;
136 struct gpio_dt_spec en_gpio;
137 struct gpio_dt_spec in_trig_gpio;
138 uint8_t feedback_brake_factor;
139 uint8_t loop_gain;
140 uint8_t rated_voltage;
141 uint8_t overdrive_clamp_voltage;
142 uint8_t auto_cal_time;
143 uint8_t drive_time;
144 bool actuator_mode;
145 };
146
147 struct drv2605_data {
148 const struct device *dev;
149 struct k_work rtp_work;
150 const struct drv2605_rtp_data *rtp_data;
151 enum drv2605_mode mode;
152 };
153
drv2605_haptic_config_audio(const struct device * dev)154 static inline int drv2605_haptic_config_audio(const struct device *dev)
155 {
156 const struct drv2605_config *config = dev->config;
157 struct drv2605_data *data = dev->data;
158 int ret;
159
160 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_CONTROL3, DRV2605_N_PWM_ANALOG,
161 DRV2605_N_PWM_ANALOG);
162 if (ret < 0) {
163 return ret;
164 }
165
166 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_CONTROL1, DRV2605_AC_COUPLE,
167 DRV2605_AC_COUPLE);
168 if (ret < 0) {
169 return ret;
170 }
171
172 data->mode = DRV2605_MODE_AUDIO_TO_VIBE;
173
174 return 0;
175 }
176
drv2605_haptic_config_pwm_analog(const struct device * dev,const bool analog)177 static inline int drv2605_haptic_config_pwm_analog(const struct device *dev, const bool analog)
178 {
179 const struct drv2605_config *config = dev->config;
180 struct drv2605_data *data = dev->data;
181 uint8_t value = 0;
182 int ret;
183
184 if (analog) {
185 value = DRV2605_N_PWM_ANALOG;
186 }
187
188 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_CONTROL3, DRV2605_N_PWM_ANALOG,
189 value);
190 if (ret < 0) {
191 return ret;
192 }
193
194 data->mode = DRV2605_MODE_PWM_ANALOG_INPUT;
195
196 return 0;
197 }
198
drv2605_rtp_work_handler(struct k_work * work)199 static void drv2605_rtp_work_handler(struct k_work *work)
200 {
201 struct drv2605_data *data = CONTAINER_OF(work, struct drv2605_data, rtp_work);
202 const struct drv2605_rtp_data *rtp_data = data->rtp_data;
203 const struct drv2605_config *config = data->dev->config;
204 int i;
205
206 for (i = 0; i < rtp_data->size; i++) {
207 i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_RT_PLAYBACK_INPUT,
208 rtp_data->rtp_input[i]);
209 k_usleep(rtp_data->rtp_hold_us[i]);
210 }
211 }
212
drv2605_haptic_config_rtp(const struct device * dev,const struct drv2605_rtp_data * rtp_data)213 static inline int drv2605_haptic_config_rtp(const struct device *dev,
214 const struct drv2605_rtp_data *rtp_data)
215 {
216 const struct drv2605_config *config = dev->config;
217 struct drv2605_data *data = dev->data;
218 int ret;
219
220 data->rtp_data = rtp_data;
221
222 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_RT_PLAYBACK_INPUT, 0);
223 if (ret < 0) {
224 return ret;
225 }
226
227 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_MODE,
228 (uint8_t)DRV2605_MODE_RTP);
229 if (ret < 0) {
230 return ret;
231 }
232
233 data->mode = DRV2605_MODE_RTP;
234
235 return 0;
236 }
237
drv2605_haptic_config_rom(const struct device * dev,const struct drv2605_rom_data * rom_data)238 static inline int drv2605_haptic_config_rom(const struct device *dev,
239 const struct drv2605_rom_data *rom_data)
240 {
241 const struct drv2605_config *config = dev->config;
242 uint8_t reg_addr = DRV2605_REG_WAVEFORM_SEQUENCER;
243 struct drv2605_data *data = dev->data;
244 int i, ret;
245
246 switch (rom_data->trigger) {
247 case DRV2605_MODE_INTERNAL_TRIGGER:
248 case DRV2605_MODE_EXTERNAL_EDGE_TRIGGER:
249 case DRV2605_MODE_EXTERNAL_LEVEL_TRIGGER:
250 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_MODE,
251 (uint8_t)rom_data->trigger);
252 if (ret < 0) {
253 return ret;
254 }
255
256 data->mode = rom_data->trigger;
257 break;
258 default:
259 return -EINVAL;
260 }
261
262 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_UNNAMED, DRV2605_LIBRARY_SEL,
263 (uint8_t)rom_data->library);
264 if (ret < 0) {
265 return ret;
266 }
267
268 for (i = 0; i < DRV2605_WAVEFORM_SEQUENCER_MAX; i++) {
269 ret = i2c_reg_write_byte_dt(&config->i2c, reg_addr, rom_data->seq_regs[i]);
270 if (ret < 0) {
271 return ret;
272 }
273
274 reg_addr++;
275
276 if (rom_data->seq_regs[i] == 0U) {
277 break;
278 }
279 }
280
281 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_OVERDRIVE_TIME_OFFSET,
282 rom_data->overdrive_time);
283 if (ret < 0) {
284 return ret;
285 }
286
287 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_SUSTAIN_TIME_OFFSET_POS,
288 rom_data->sustain_pos_time);
289 if (ret < 0) {
290 return ret;
291 }
292
293 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_SUSTAIN_TIME_OFFSET_NEG,
294 rom_data->sustain_neg_time);
295 if (ret < 0) {
296 return ret;
297 }
298
299 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_BRAKE_TIME_OFFSET,
300 rom_data->brake_time);
301 if (ret < 0) {
302 return ret;
303 }
304
305 return 0;
306 }
307
drv2605_haptic_config(const struct device * dev,enum drv2605_haptics_source source,const union drv2605_config_data * config_data)308 int drv2605_haptic_config(const struct device *dev, enum drv2605_haptics_source source,
309 const union drv2605_config_data *config_data)
310 {
311 switch (source) {
312 case DRV2605_HAPTICS_SOURCE_ROM:
313 return drv2605_haptic_config_rom(dev, config_data->rom_data);
314 case DRV2605_HAPTICS_SOURCE_RTP:
315 return drv2605_haptic_config_rtp(dev, config_data->rtp_data);
316 case DRV2605_HAPTICS_SOURCE_AUDIO:
317 return drv2605_haptic_config_audio(dev);
318 case DRV2605_HAPTICS_SOURCE_PWM:
319 return drv2605_haptic_config_pwm_analog(dev, false);
320 case DRV2605_HAPTICS_SOURCE_ANALOG:
321 return drv2605_haptic_config_pwm_analog(dev, true);
322 default:
323 return -ENOTSUP;
324 }
325
326 return 0;
327 }
328
drv2605_edge_mode_event(const struct device * dev)329 static inline int drv2605_edge_mode_event(const struct device *dev)
330 {
331 const struct drv2605_config *config = dev->config;
332 int ret;
333
334 ret = gpio_pin_set_dt(&config->in_trig_gpio, 1);
335 if (ret < 0) {
336 return ret;
337 }
338
339 return gpio_pin_set_dt(&config->in_trig_gpio, 0);
340 }
341
drv2605_stop_output(const struct device * dev)342 static int drv2605_stop_output(const struct device *dev)
343 {
344 const struct drv2605_config *config = dev->config;
345 struct drv2605_data *data = dev->data;
346 uint8_t value;
347 int ret;
348
349 switch (data->mode) {
350 case DRV2605_MODE_DIAGNOSTICS:
351 case DRV2605_MODE_AUTO_CAL:
352 ret = i2c_reg_read_byte_dt(&config->i2c, DRV2605_REG_GO, &value);
353 if (ret < 0) {
354 return ret;
355 }
356
357 if (FIELD_GET(DRV2605_GO, value)) {
358 LOG_DBG("Playback mode: %d is uninterruptible", data->mode);
359 return -EBUSY;
360 }
361
362 break;
363 case DRV2605_MODE_INTERNAL_TRIGGER:
364 return i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_GO, DRV2605_GO, 0);
365 case DRV2605_MODE_EXTERNAL_EDGE_TRIGGER:
366 return drv2605_edge_mode_event(dev);
367 case DRV2605_MODE_EXTERNAL_LEVEL_TRIGGER:
368 return gpio_pin_set_dt(&config->in_trig_gpio, 0);
369 case DRV2605_MODE_PWM_ANALOG_INPUT:
370 case DRV2605_MODE_AUDIO_TO_VIBE:
371 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_MODE,
372 (uint8_t)DRV2605_MODE_INTERNAL_TRIGGER);
373 if (ret < 0) {
374 return ret;
375 }
376
377 return i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_GO, DRV2605_GO, 0);
378 case DRV2605_MODE_RTP:
379 return k_work_cancel(&data->rtp_work);
380 default:
381 return -ENOTSUP;
382 }
383
384 return 0;
385 }
386
drv2605_start_output(const struct device * dev)387 static int drv2605_start_output(const struct device *dev)
388 {
389 const struct drv2605_config *config = dev->config;
390 struct drv2605_data *data = dev->data;
391
392 switch (data->mode) {
393 case DRV2605_MODE_DIAGNOSTICS:
394 case DRV2605_MODE_AUTO_CAL:
395 case DRV2605_MODE_INTERNAL_TRIGGER:
396 return i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_GO, DRV2605_GO, DRV2605_GO);
397 case DRV2605_MODE_EXTERNAL_EDGE_TRIGGER:
398 return drv2605_edge_mode_event(dev);
399 case DRV2605_MODE_EXTERNAL_LEVEL_TRIGGER:
400 return gpio_pin_set_dt(&config->in_trig_gpio, 1);
401 case DRV2605_MODE_AUDIO_TO_VIBE:
402 case DRV2605_MODE_PWM_ANALOG_INPUT:
403 return i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_MODE,
404 (uint8_t)data->mode);
405 case DRV2605_MODE_RTP:
406 return k_work_submit(&data->rtp_work);
407 default:
408 return -ENOTSUP;
409 }
410
411 return 0;
412 }
413
414 #ifdef CONFIG_PM_DEVICE
drv2605_pm_action(const struct device * dev,enum pm_device_action action)415 static int drv2605_pm_action(const struct device *dev, enum pm_device_action action)
416 {
417 const struct drv2605_config *config = dev->config;
418
419 switch (action) {
420 case PM_DEVICE_ACTION_RESUME:
421 return i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_STANDBY, 0);
422 case PM_DEVICE_ACTION_SUSPEND:
423 return i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_STANDBY,
424 DRV2605_STANDBY);
425 case PM_DEVICE_ACTION_TURN_OFF:
426 if (config->en_gpio.port != NULL) {
427 gpio_pin_set_dt(&config->en_gpio, 0);
428 }
429
430 break;
431 case PM_DEVICE_ACTION_TURN_ON:
432 if (config->en_gpio.port != NULL) {
433 gpio_pin_set_dt(&config->en_gpio, 1);
434 }
435
436 break;
437 default:
438 return -ENOTSUP;
439 }
440
441 return 0;
442 }
443 #endif
444
drv2605_hw_config(const struct device * dev)445 static int drv2605_hw_config(const struct device *dev)
446 {
447 const struct drv2605_config *config = dev->config;
448 uint8_t mask, value;
449 int ret;
450
451 value = FIELD_PREP(DRV2605_N_ERM_LRA, config->actuator_mode) |
452 FIELD_PREP(DRV2605_FB_BRAKE_FACTOR, config->feedback_brake_factor) |
453 FIELD_PREP(DRV2605_LOOP_GAIN, config->loop_gain);
454
455 mask = DRV2605_N_ERM_LRA | DRV2605_FB_BRAKE_FACTOR | DRV2605_LOOP_GAIN;
456
457 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_FEEDBACK_CONTROL, mask, value);
458 if (ret < 0) {
459 return ret;
460 }
461
462 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_RATED_VOLTAGE, config->rated_voltage);
463 if (ret < 0) {
464 return ret;
465 }
466
467 ret = i2c_reg_write_byte_dt(&config->i2c, DRV2605_REG_OVERDRIVE_CLAMP_VOLTAGE,
468 config->overdrive_clamp_voltage);
469 if (ret < 0) {
470 return ret;
471 }
472
473 if (config->actuator_mode == DRV2605_ACTUATOR_MODE_LRA) {
474 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_CONTROL3,
475 DRV2605_LRA_OPEN_LOOP, DRV2605_LRA_OPEN_LOOP);
476 if (ret < 0) {
477 return ret;
478 }
479 }
480
481 return 0;
482 }
483
drv2605_reset(const struct device * dev)484 static int drv2605_reset(const struct device *dev)
485 {
486 const struct drv2605_config *config = dev->config;
487 int retries = 5, ret;
488 uint8_t value;
489
490 i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_STANDBY, 0);
491
492 ret = i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_DEV_RESET,
493 DRV2605_DEV_RESET);
494 if (ret < 0) {
495 return ret;
496 }
497
498 k_msleep(100);
499
500 while (retries > 0) {
501 retries--;
502
503 ret = i2c_reg_read_byte_dt(&config->i2c, DRV2605_REG_MODE, &value);
504 if (ret < 0) {
505 k_usleep(10000);
506 continue;
507 }
508
509 if ((value & DRV2605_DEV_RESET) == 0U) {
510 i2c_reg_update_byte_dt(&config->i2c, DRV2605_REG_MODE, DRV2605_STANDBY, 0);
511 return 0;
512 }
513 }
514
515 return -ETIMEDOUT;
516 }
517
drv2605_check_devid(const struct device * dev)518 static int drv2605_check_devid(const struct device *dev)
519 {
520 const struct drv2605_config *config = dev->config;
521 uint8_t value;
522 int ret;
523
524 ret = i2c_reg_read_byte_dt(&config->i2c, DRV2605_REG_STATUS, &value);
525 if (ret < 0) {
526 return ret;
527 }
528
529 value = FIELD_GET(DRV2605_DEVICE_ID, value);
530
531 switch (value) {
532 case DRV2605_DEVICE_ID_DRV2605:
533 case DRV2605_DEVICE_ID_DRV2605L:
534 break;
535 default:
536 LOG_ERR("Invalid device ID found");
537 return -ENOTSUP;
538 }
539
540 LOG_DBG("Found DRV2605, DEVID: 0x%x", value);
541
542 return 0;
543 }
544
drv2605_gpio_config(const struct device * dev)545 static int drv2605_gpio_config(const struct device *dev)
546 {
547 const struct drv2605_config *config = dev->config;
548 int ret;
549
550 if (config->en_gpio.port != NULL) {
551 if (!gpio_is_ready_dt(&config->en_gpio)) {
552 return -ENODEV;
553 }
554
555 ret = gpio_pin_configure_dt(&config->en_gpio, GPIO_OUTPUT_ACTIVE);
556 if (ret < 0) {
557 return ret;
558 }
559 }
560
561 if (config->in_trig_gpio.port != NULL) {
562 if (!gpio_is_ready_dt(&config->in_trig_gpio)) {
563 return -ENODEV;
564 }
565
566 ret = gpio_pin_configure_dt(&config->in_trig_gpio, GPIO_OUTPUT_INACTIVE);
567 if (ret < 0) {
568 return ret;
569 }
570 }
571
572 return 0;
573 }
574
drv2605_init(const struct device * dev)575 static int drv2605_init(const struct device *dev)
576 {
577 const struct drv2605_config *config = dev->config;
578 struct drv2605_data *data = dev->data;
579 int ret;
580
581 data->dev = dev;
582
583 k_usleep(DRV2605_POWER_UP_DELAY_US);
584
585 if (!i2c_is_ready_dt(&config->i2c)) {
586 return -ENODEV;
587 }
588
589 k_work_init(&data->rtp_work, drv2605_rtp_work_handler);
590
591 ret = drv2605_gpio_config(dev);
592 if (ret < 0) {
593 LOG_DBG("Failed to allocate GPIOs: %d", ret);
594 return ret;
595 }
596
597 ret = drv2605_check_devid(dev);
598 if (ret < 0) {
599 return ret;
600 }
601
602 ret = drv2605_reset(dev);
603 if (ret < 0) {
604 LOG_DBG("Failed to reset device: %d", ret);
605 return ret;
606 }
607
608 ret = drv2605_hw_config(dev);
609 if (ret < 0) {
610 LOG_DBG("Failed to configure device: %d", ret);
611 return ret;
612 }
613
614 return 0;
615 }
616
617 static DEVICE_API(haptics, drv2605_driver_api) = {
618 .start_output = &drv2605_start_output,
619 .stop_output = &drv2605_stop_output,
620 };
621
622 #define HAPTICS_DRV2605_DEFINE(inst) \
623 \
624 static const struct drv2605_config drv2605_config_##inst = { \
625 .i2c = I2C_DT_SPEC_INST_GET(inst), \
626 .en_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, en_gpios, {}), \
627 .in_trig_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, in_trig_gpios, {}), \
628 .feedback_brake_factor = DT_INST_ENUM_IDX(inst, feedback_brake_factor), \
629 .loop_gain = DT_INST_ENUM_IDX(inst, loop_gain), \
630 .actuator_mode = DT_INST_ENUM_IDX(inst, actuator_mode), \
631 .rated_voltage = DRV2605_CALCULATE_VOLTAGE(DT_INST_PROP(inst, vib_rated_mv)), \
632 .overdrive_clamp_voltage = \
633 DRV2605_CALCULATE_VOLTAGE(DT_INST_PROP(inst, vib_overdrive_mv)), \
634 }; \
635 \
636 static struct drv2605_data drv2605_data_##inst = { \
637 .mode = DRV2605_MODE_INTERNAL_TRIGGER, \
638 }; \
639 \
640 PM_DEVICE_DT_INST_DEFINE(inst, drv2605_pm_action); \
641 \
642 DEVICE_DT_INST_DEFINE(inst, drv2605_init, PM_DEVICE_DT_INST_GET(inst), \
643 &drv2605_data_##inst, &drv2605_config_##inst, POST_KERNEL, \
644 CONFIG_HAPTICS_INIT_PRIORITY, &drv2605_driver_api);
645
646 DT_INST_FOREACH_STATUS_OKAY(HAPTICS_DRV2605_DEFINE)
647