1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2024 Carl Zeiss Meditec AG
3 * SPDX-FileCopyrightText: Copyright (c) 2025 Jilay Sandeep Pandya
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT adi_tmc50xx
8
9 #include <stdlib.h>
10
11 #include <zephyr/drivers/stepper.h>
12 #include <zephyr/drivers/stepper/stepper_trinamic.h>
13
14 #include "adi_tmc_spi.h"
15 #include "adi_tmc5xxx_common.h"
16
17 #include <zephyr/logging/log.h>
18
19 LOG_MODULE_REGISTER(tmc50xx, CONFIG_STEPPER_LOG_LEVEL);
20
21 struct tmc50xx_data {
22 struct k_sem sem;
23 };
24
25 struct tmc50xx_config {
26 const uint32_t gconf;
27 struct spi_dt_spec spi;
28 const uint32_t clock_frequency;
29 };
30
31 struct tmc50xx_stepper_data {
32 struct k_work_delayable stallguard_dwork;
33 /* Work item to run the callback in a thread context. */
34 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL
35 struct k_work_delayable rampstat_callback_dwork;
36 #endif
37 /* device pointer required to access config in k_work */
38 const struct device *stepper;
39 stepper_event_callback_t callback;
40 void *event_cb_user_data;
41 };
42
43 struct tmc50xx_stepper_config {
44 const uint8_t index;
45 const uint16_t default_micro_step_res;
46 const int8_t sg_threshold;
47 const bool is_sg_enabled;
48 const uint32_t sg_velocity_check_interval_ms;
49 const uint32_t sg_threshold_velocity;
50 /* parent controller required for bus communication */
51 const struct device *controller;
52 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN
53 const struct tmc_ramp_generator_data default_ramp_config;
54 #endif
55 };
56
tmc50xx_write(const struct device * dev,const uint8_t reg_addr,const uint32_t reg_val)57 static int tmc50xx_write(const struct device *dev, const uint8_t reg_addr, const uint32_t reg_val)
58 {
59 const struct tmc50xx_config *config = dev->config;
60 struct tmc50xx_data *data = dev->data;
61 const struct spi_dt_spec bus = config->spi;
62 int err;
63
64 k_sem_take(&data->sem, K_FOREVER);
65
66 err = tmc_spi_write_register(&bus, TMC5XXX_WRITE_BIT, reg_addr, reg_val);
67
68 k_sem_give(&data->sem);
69
70 if (err) {
71 LOG_ERR("Failed to write register 0x%x with value 0x%x", reg_addr, reg_val);
72 return err;
73 }
74 return 0;
75 }
76
tmc50xx_read(const struct device * dev,const uint8_t reg_addr,uint32_t * reg_val)77 static int tmc50xx_read(const struct device *dev, const uint8_t reg_addr, uint32_t *reg_val)
78 {
79 const struct tmc50xx_config *config = dev->config;
80 struct tmc50xx_data *data = dev->data;
81 const struct spi_dt_spec bus = config->spi;
82 int err;
83
84 k_sem_take(&data->sem, K_FOREVER);
85
86 err = tmc_spi_read_register(&bus, TMC5XXX_ADDRESS_MASK, reg_addr, reg_val);
87
88 k_sem_give(&data->sem);
89
90 if (err) {
91 LOG_ERR("Failed to read register 0x%x", reg_addr);
92 return err;
93 }
94 return 0;
95 }
96
tmc50xx_stepper_set_event_callback(const struct device * dev,stepper_event_callback_t callback,void * user_data)97 static int tmc50xx_stepper_set_event_callback(const struct device *dev,
98 stepper_event_callback_t callback, void *user_data)
99 {
100 struct tmc50xx_stepper_data *data = dev->data;
101
102 data->callback = callback;
103 data->event_cb_user_data = user_data;
104 return 0;
105 }
106
stallguard_enable(const struct device * dev,const bool enable)107 static int stallguard_enable(const struct device *dev, const bool enable)
108 {
109 const struct tmc50xx_stepper_config *config = dev->config;
110 uint32_t reg_value;
111 int err;
112
113 err = tmc50xx_read(config->controller, TMC50XX_SWMODE(config->index), ®_value);
114 if (err) {
115 LOG_ERR("Failed to read SWMODE register");
116 return -EIO;
117 }
118
119 if (enable) {
120 reg_value |= TMC5XXX_SW_MODE_SG_STOP_ENABLE;
121
122 int32_t actual_velocity;
123
124 err = tmc50xx_read(config->controller, TMC50XX_VACTUAL(config->index),
125 &actual_velocity);
126 if (err) {
127 LOG_ERR("Failed to read VACTUAL register");
128 return -EIO;
129 }
130
131 actual_velocity = (actual_velocity << (31 - TMC_RAMP_VACTUAL_SHIFT)) >>
132 (31 - TMC_RAMP_VACTUAL_SHIFT);
133 LOG_DBG("actual velocity: %d", actual_velocity);
134
135 if (abs(actual_velocity) < config->sg_threshold_velocity) {
136 return -EAGAIN;
137 }
138 } else {
139 reg_value &= ~TMC5XXX_SW_MODE_SG_STOP_ENABLE;
140 }
141 err = tmc50xx_write(config->controller, TMC50XX_SWMODE(config->index), reg_value);
142 if (err) {
143 LOG_ERR("Failed to write SWMODE register");
144 return -EIO;
145 }
146 return 0;
147 }
148
stallguard_work_handler(struct k_work * work)149 static void stallguard_work_handler(struct k_work *work)
150 {
151 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
152 struct tmc50xx_stepper_data *stepper_data =
153 CONTAINER_OF(dwork, struct tmc50xx_stepper_data, stallguard_dwork);
154 int err;
155 const struct tmc50xx_stepper_config *stepper_config = stepper_data->stepper->config;
156
157 err = stallguard_enable(stepper_data->stepper, true);
158 if (err == -EAGAIN) {
159 LOG_ERR("retrying stallguard activation");
160 k_work_reschedule(dwork, K_MSEC(stepper_config->sg_velocity_check_interval_ms));
161 }
162 if (err == -EIO) {
163 LOG_ERR("Failed to enable stallguard because of I/O error");
164 return;
165 }
166 }
167
168 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL
169
execute_callback(const struct device * dev,const enum stepper_event event)170 static void execute_callback(const struct device *dev, const enum stepper_event event)
171 {
172 struct tmc50xx_stepper_data *data = dev->data;
173
174 if (!data->callback) {
175 LOG_WRN_ONCE("No callback registered");
176 return;
177 }
178 data->callback(dev, event, data->event_cb_user_data);
179 }
180
rampstat_work_handler(struct k_work * work)181 static void rampstat_work_handler(struct k_work *work)
182 {
183 struct k_work_delayable *dwork = k_work_delayable_from_work(work);
184
185 struct tmc50xx_stepper_data *stepper_data =
186 CONTAINER_OF(dwork, struct tmc50xx_stepper_data, rampstat_callback_dwork);
187 const struct tmc50xx_stepper_config *stepper_config = stepper_data->stepper->config;
188
189 __ASSERT_NO_MSG(stepper_config->controller != NULL);
190
191 uint32_t drv_status;
192 int err;
193
194 err = tmc50xx_read(stepper_config->controller, TMC50XX_DRVSTATUS(stepper_config->index),
195 &drv_status);
196 if (err != 0) {
197 LOG_ERR("%s: Failed to read DRVSTATUS register", stepper_data->stepper->name);
198 return;
199 }
200
201 if (FIELD_GET(TMC5XXX_DRV_STATUS_SG_STATUS_MASK, drv_status) == 1U) {
202 LOG_INF("%s: Stall detected", stepper_data->stepper->name);
203 err = tmc50xx_write(stepper_config->controller,
204 TMC50XX_RAMPMODE(stepper_config->index),
205 TMC5XXX_RAMPMODE_HOLD_MODE);
206 if (err != 0) {
207 LOG_ERR("%s: Failed to stop motor", stepper_data->stepper->name);
208 return;
209 }
210 }
211
212 uint32_t rampstat_value;
213
214 err = tmc50xx_read(stepper_config->controller, TMC50XX_RAMPSTAT(stepper_config->index),
215 &rampstat_value);
216 if (err != 0) {
217 LOG_ERR("%s: Failed to read RAMPSTAT register", stepper_data->stepper->name);
218 return;
219 }
220
221 const uint8_t ramp_stat_values = FIELD_GET(TMC5XXX_RAMPSTAT_INT_MASK, rampstat_value);
222
223 if (ramp_stat_values > 0) {
224 switch (ramp_stat_values) {
225
226 case TMC5XXX_STOP_LEFT_EVENT:
227 LOG_DBG("RAMPSTAT %s:Left end-stop detected", stepper_data->stepper->name);
228 execute_callback(stepper_data->stepper,
229 STEPPER_EVENT_LEFT_END_STOP_DETECTED);
230 break;
231
232 case TMC5XXX_STOP_RIGHT_EVENT:
233 LOG_DBG("RAMPSTAT %s:Right end-stop detected", stepper_data->stepper->name);
234 execute_callback(stepper_data->stepper,
235 STEPPER_EVENT_RIGHT_END_STOP_DETECTED);
236 break;
237
238 case TMC5XXX_POS_REACHED_EVENT:
239 LOG_DBG("RAMPSTAT %s:Position reached", stepper_data->stepper->name);
240 execute_callback(stepper_data->stepper, STEPPER_EVENT_STEPS_COMPLETED);
241 break;
242
243 case TMC5XXX_STOP_SG_EVENT:
244 LOG_DBG("RAMPSTAT %s:Stall detected", stepper_data->stepper->name);
245 stallguard_enable(stepper_data->stepper, false);
246 execute_callback(stepper_data->stepper, STEPPER_EVENT_STALL_DETECTED);
247 break;
248 default:
249 LOG_ERR("Illegal ramp stat bit field");
250 break;
251 }
252 } else {
253 k_work_reschedule(
254 &stepper_data->rampstat_callback_dwork,
255 K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC));
256 }
257 }
258
259 #endif
260
tmc50xx_stepper_enable(const struct device * dev,const bool enable)261 static int tmc50xx_stepper_enable(const struct device *dev, const bool enable)
262 {
263 LOG_DBG("Stepper motor controller %s %s", dev->name, enable ? "enabled" : "disabled");
264 const struct tmc50xx_stepper_config *config = dev->config;
265 uint32_t reg_value;
266 int err;
267
268 err = tmc50xx_read(config->controller, TMC50XX_CHOPCONF(config->index), ®_value);
269 if (err != 0) {
270 return -EIO;
271 }
272
273 if (enable) {
274 reg_value |= TMC5XXX_CHOPCONF_DRV_ENABLE_MASK;
275 } else {
276 reg_value &= ~TMC5XXX_CHOPCONF_DRV_ENABLE_MASK;
277 }
278
279 err = tmc50xx_write(config->controller, TMC50XX_CHOPCONF(config->index), reg_value);
280 if (err != 0) {
281 return -EIO;
282 }
283 return 0;
284 }
285
tmc50xx_stepper_is_moving(const struct device * dev,bool * is_moving)286 static int tmc50xx_stepper_is_moving(const struct device *dev, bool *is_moving)
287 {
288 const struct tmc50xx_stepper_config *config = dev->config;
289 uint32_t reg_value;
290 int err;
291
292 err = tmc50xx_read(config->controller, TMC50XX_DRVSTATUS(config->index), ®_value);
293
294 if (err != 0) {
295 LOG_ERR("%s: Failed to read DRVSTATUS register", dev->name);
296 return -EIO;
297 }
298
299 *is_moving = (FIELD_GET(TMC5XXX_DRV_STATUS_STST_BIT, reg_value) != 1U);
300 LOG_DBG("Stepper motor controller %s is moving: %d", dev->name, *is_moving);
301 return 0;
302 }
303
tmc50xx_stepper_move_by(const struct device * dev,const int32_t micro_steps)304 static int tmc50xx_stepper_move_by(const struct device *dev, const int32_t micro_steps)
305 {
306 const struct tmc50xx_stepper_config *config = dev->config;
307 struct tmc50xx_stepper_data *data = dev->data;
308 int err;
309
310 if (config->is_sg_enabled) {
311 err = stallguard_enable(dev, false);
312 if (err != 0) {
313 return -EIO;
314 }
315 }
316
317 int32_t position;
318
319 err = stepper_get_actual_position(dev, &position);
320 if (err != 0) {
321 return -EIO;
322 }
323 int32_t target_position = position + micro_steps;
324
325 err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index),
326 TMC5XXX_RAMPMODE_POSITIONING_MODE);
327 if (err != 0) {
328 return -EIO;
329 }
330 LOG_DBG("Stepper motor controller %s moved to %d by steps: %d", dev->name, target_position,
331 micro_steps);
332 err = tmc50xx_write(config->controller, TMC50XX_XTARGET(config->index), target_position);
333 if (err != 0) {
334 return -EIO;
335 }
336
337 if (config->is_sg_enabled) {
338 k_work_reschedule(&data->stallguard_dwork,
339 K_MSEC(config->sg_velocity_check_interval_ms));
340 }
341 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL
342 if (data->callback) {
343 k_work_reschedule(
344 &data->rampstat_callback_dwork,
345 K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC));
346 }
347 #endif
348 return 0;
349 }
350
tmc50xx_stepper_set_max_velocity(const struct device * dev,uint32_t velocity)351 int tmc50xx_stepper_set_max_velocity(const struct device *dev, uint32_t velocity)
352 {
353 const struct tmc50xx_stepper_config *config = dev->config;
354 const struct tmc50xx_config *tmc50xx_config = config->controller->config;
355 const uint32_t clock_frequency = tmc50xx_config->clock_frequency;
356 uint32_t velocity_fclk;
357 int err;
358
359 velocity_fclk = tmc5xxx_calculate_velocity_from_hz_to_fclk(velocity, clock_frequency);
360
361 err = tmc50xx_write(config->controller, TMC50XX_VMAX(config->index), velocity_fclk);
362 if (err != 0) {
363 LOG_ERR("%s: Failed to set max velocity", dev->name);
364 return -EIO;
365 }
366 return 0;
367 }
368
tmc50xx_stepper_set_micro_step_res(const struct device * dev,enum stepper_micro_step_resolution res)369 static int tmc50xx_stepper_set_micro_step_res(const struct device *dev,
370 enum stepper_micro_step_resolution res)
371 {
372 const struct tmc50xx_stepper_config *config = dev->config;
373 uint32_t reg_value;
374 int err;
375
376 err = tmc50xx_read(config->controller, TMC50XX_CHOPCONF(config->index), ®_value);
377 if (err != 0) {
378 return -EIO;
379 }
380
381 reg_value &= ~TMC5XXX_CHOPCONF_MRES_MASK;
382 reg_value |= ((MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - LOG2(res))
383 << TMC5XXX_CHOPCONF_MRES_SHIFT);
384
385 err = tmc50xx_write(config->controller, TMC50XX_CHOPCONF(config->index), reg_value);
386 if (err != 0) {
387 return -EIO;
388 }
389
390 LOG_DBG("Stepper motor controller %s set micro step resolution to 0x%x", dev->name,
391 reg_value);
392 return 0;
393 }
394
tmc50xx_stepper_get_micro_step_res(const struct device * dev,enum stepper_micro_step_resolution * res)395 static int tmc50xx_stepper_get_micro_step_res(const struct device *dev,
396 enum stepper_micro_step_resolution *res)
397 {
398 const struct tmc50xx_stepper_config *config = dev->config;
399 uint32_t reg_value;
400 int err;
401
402 err = tmc50xx_read(config->controller, TMC50XX_CHOPCONF(config->index), ®_value);
403 if (err != 0) {
404 return -EIO;
405 }
406 reg_value &= TMC5XXX_CHOPCONF_MRES_MASK;
407 reg_value >>= TMC5XXX_CHOPCONF_MRES_SHIFT;
408 *res = (1 << (MICRO_STEP_RES_INDEX(STEPPER_MICRO_STEP_256) - reg_value));
409 LOG_DBG("Stepper motor controller %s get micro step resolution: %d", dev->name, *res);
410 return 0;
411 }
412
tmc50xx_stepper_set_reference_position(const struct device * dev,const int32_t position)413 static int tmc50xx_stepper_set_reference_position(const struct device *dev, const int32_t position)
414 {
415 const struct tmc50xx_stepper_config *config = dev->config;
416 int err;
417
418 err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index),
419 TMC5XXX_RAMPMODE_HOLD_MODE);
420 if (err != 0) {
421 return -EIO;
422 }
423
424 err = tmc50xx_write(config->controller, TMC50XX_XACTUAL(config->index), position);
425 if (err != 0) {
426 return -EIO;
427 }
428 LOG_DBG("Stepper motor controller %s set actual position to %d", dev->name, position);
429 return 0;
430 }
431
tmc50xx_stepper_get_actual_position(const struct device * dev,int32_t * position)432 static int tmc50xx_stepper_get_actual_position(const struct device *dev, int32_t *position)
433 {
434 const struct tmc50xx_stepper_config *config = dev->config;
435 int err;
436
437 err = tmc50xx_read(config->controller, TMC50XX_XACTUAL(config->index), position);
438 if (err != 0) {
439 return -EIO;
440 }
441 LOG_DBG("%s actual position: %d", dev->name, *position);
442 return 0;
443 }
444
tmc50xx_stepper_move_to(const struct device * dev,const int32_t micro_steps)445 static int tmc50xx_stepper_move_to(const struct device *dev, const int32_t micro_steps)
446 {
447 LOG_DBG("Stepper motor controller %s set target position to %d", dev->name, micro_steps);
448 const struct tmc50xx_stepper_config *config = dev->config;
449 struct tmc50xx_stepper_data *data = dev->data;
450 int err;
451
452 if (config->is_sg_enabled) {
453 stallguard_enable(dev, false);
454 }
455
456 err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index),
457 TMC5XXX_RAMPMODE_POSITIONING_MODE);
458 if (err != 0) {
459 return -EIO;
460 }
461 err = tmc50xx_write(config->controller, TMC50XX_XTARGET(config->index), micro_steps);
462 if (err != 0) {
463 return -EIO;
464 }
465
466 if (config->is_sg_enabled) {
467 k_work_reschedule(&data->stallguard_dwork,
468 K_MSEC(config->sg_velocity_check_interval_ms));
469 }
470 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL
471 if (data->callback) {
472 k_work_reschedule(
473 &data->rampstat_callback_dwork,
474 K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC));
475 }
476 #endif
477 return 0;
478 }
479
tmc50xx_stepper_run(const struct device * dev,const enum stepper_direction direction)480 static int tmc50xx_stepper_run(const struct device *dev, const enum stepper_direction direction)
481 {
482 LOG_DBG("Stepper motor controller %s run", dev->name);
483 const struct tmc50xx_stepper_config *config = dev->config;
484 struct tmc50xx_stepper_data *data = dev->data;
485 int err;
486
487 if (config->is_sg_enabled) {
488 err = stallguard_enable(dev, false);
489 if (err != 0) {
490 return -EIO;
491 }
492 }
493
494 switch (direction) {
495 case STEPPER_DIRECTION_POSITIVE:
496 err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index),
497 TMC5XXX_RAMPMODE_POSITIVE_VELOCITY_MODE);
498 if (err != 0) {
499 return -EIO;
500 }
501 break;
502
503 case STEPPER_DIRECTION_NEGATIVE:
504 err = tmc50xx_write(config->controller, TMC50XX_RAMPMODE(config->index),
505 TMC5XXX_RAMPMODE_NEGATIVE_VELOCITY_MODE);
506 if (err != 0) {
507 return -EIO;
508 }
509 break;
510 }
511
512 if (config->is_sg_enabled) {
513 k_work_reschedule(&data->stallguard_dwork,
514 K_MSEC(config->sg_velocity_check_interval_ms));
515 }
516 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL
517 if (data->callback) {
518 k_work_reschedule(
519 &data->rampstat_callback_dwork,
520 K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC));
521 }
522 #endif
523 return 0;
524 }
525
526 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN
527
tmc50xx_stepper_set_ramp(const struct device * dev,const struct tmc_ramp_generator_data * ramp_data)528 int tmc50xx_stepper_set_ramp(const struct device *dev,
529 const struct tmc_ramp_generator_data *ramp_data)
530 {
531 LOG_DBG("Stepper motor controller %s set ramp", dev->name);
532 const struct tmc50xx_stepper_config *config = dev->config;
533 int err;
534
535 err = tmc50xx_write(config->controller, TMC50XX_VSTART(config->index), ramp_data->vstart);
536 if (err != 0) {
537 return -EIO;
538 }
539 err = tmc50xx_write(config->controller, TMC50XX_A1(config->index), ramp_data->a1);
540 if (err != 0) {
541 return -EIO;
542 }
543 err = tmc50xx_write(config->controller, TMC50XX_AMAX(config->index), ramp_data->amax);
544 if (err != 0) {
545 return -EIO;
546 }
547 err = tmc50xx_write(config->controller, TMC50XX_D1(config->index), ramp_data->d1);
548 if (err != 0) {
549 return -EIO;
550 }
551 err = tmc50xx_write(config->controller, TMC50XX_DMAX(config->index), ramp_data->dmax);
552 if (err != 0) {
553 return -EIO;
554 }
555 err = tmc50xx_write(config->controller, TMC50XX_V1(config->index), ramp_data->v1);
556 if (err != 0) {
557 return -EIO;
558 }
559 err = tmc50xx_write(config->controller, TMC50XX_VMAX(config->index), ramp_data->vmax);
560 if (err != 0) {
561 return -EIO;
562 }
563 err = tmc50xx_write(config->controller, TMC50XX_VSTOP(config->index), ramp_data->vstop);
564 if (err != 0) {
565 return -EIO;
566 }
567 err = tmc50xx_write(config->controller, TMC50XX_TZEROWAIT(config->index),
568 ramp_data->tzerowait);
569 if (err != 0) {
570 return -EIO;
571 }
572 err = tmc50xx_write(config->controller, TMC50XX_VHIGH(config->index), ramp_data->vhigh);
573 if (err != 0) {
574 return -EIO;
575 }
576 err = tmc50xx_write(config->controller, TMC50XX_VCOOLTHRS(config->index),
577 ramp_data->vcoolthrs);
578 if (err != 0) {
579 return -EIO;
580 }
581 err = tmc50xx_write(config->controller, TMC50XX_IHOLD_IRUN(config->index),
582 ramp_data->iholdrun);
583 if (err != 0) {
584 return -EIO;
585 }
586 return 0;
587 }
588
589 #endif
590
tmc50xx_init(const struct device * dev)591 static int tmc50xx_init(const struct device *dev)
592 {
593 LOG_DBG("TMC50XX stepper motor controller %s initialized", dev->name);
594 struct tmc50xx_data *data = dev->data;
595 const struct tmc50xx_config *config = dev->config;
596 int err;
597
598 k_sem_init(&data->sem, 1, 1);
599
600 if (!spi_is_ready_dt(&config->spi)) {
601 LOG_ERR("SPI bus is not ready");
602 return -ENODEV;
603 }
604
605 /* Init non motor-index specific registers here. */
606 LOG_DBG("GCONF: %d", config->gconf);
607 err = tmc50xx_write(dev, TMC5XXX_GCONF, config->gconf);
608 if (err != 0) {
609 return -EIO;
610 }
611
612 /* Read GSTAT register values to clear any errors SPI Datagram. */
613 uint32_t gstat_value;
614
615 err = tmc50xx_read(dev, TMC5XXX_GSTAT, &gstat_value);
616 if (err != 0) {
617 return -EIO;
618 }
619
620 LOG_DBG("Device %s initialized", dev->name);
621 return 0;
622 }
623
tmc50xx_stepper_init(const struct device * dev)624 static int tmc50xx_stepper_init(const struct device *dev)
625 {
626 const struct tmc50xx_stepper_config *stepper_config = dev->config;
627 struct tmc50xx_stepper_data *data = dev->data;
628 int err;
629
630 LOG_DBG("Controller: %s, Stepper: %s", stepper_config->controller->name, dev->name);
631
632 if (stepper_config->is_sg_enabled) {
633 k_work_init_delayable(&data->stallguard_dwork, stallguard_work_handler);
634
635 err = tmc50xx_write(stepper_config->controller,
636 TMC50XX_SWMODE(stepper_config->index), BIT(10));
637 if (err != 0) {
638 return -EIO;
639 }
640
641 LOG_DBG("Setting stall guard to %d with delay %d ms", stepper_config->sg_threshold,
642 stepper_config->sg_velocity_check_interval_ms);
643 if (!IN_RANGE(stepper_config->sg_threshold, TMC5XXX_SG_MIN_VALUE,
644 TMC5XXX_SG_MAX_VALUE)) {
645 LOG_ERR("Stallguard threshold out of range");
646 return -EINVAL;
647 }
648
649 int32_t stall_guard_threshold = (int32_t)stepper_config->sg_threshold;
650
651 err = tmc50xx_write(
652 stepper_config->controller, TMC50XX_COOLCONF(stepper_config->index),
653 stall_guard_threshold << TMC5XXX_COOLCONF_SG2_THRESHOLD_VALUE_SHIFT);
654 if (err != 0) {
655 return -EIO;
656 }
657 err = stallguard_enable(dev, true);
658 if (err == -EAGAIN) {
659 LOG_ERR("retrying stallguard activation");
660 k_work_reschedule(&data->stallguard_dwork,
661 K_MSEC(stepper_config->sg_velocity_check_interval_ms));
662 }
663 }
664
665 #ifdef CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN
666 err = tmc50xx_stepper_set_ramp(dev, &stepper_config->default_ramp_config);
667 if (err != 0) {
668 return -EIO;
669 }
670 #endif
671
672 #if CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL
673 k_work_init_delayable(&data->rampstat_callback_dwork, rampstat_work_handler);
674 k_work_reschedule(&data->rampstat_callback_dwork,
675 K_MSEC(CONFIG_STEPPER_ADI_TMC50XX_RAMPSTAT_POLL_INTERVAL_IN_MSEC));
676 #endif
677 err = tmc50xx_stepper_set_micro_step_res(dev, stepper_config->default_micro_step_res);
678 if (err != 0) {
679 return -EIO;
680 }
681 return 0;
682 }
683
684 #define TMC50XX_SHAFT_CONFIG(child) \
685 (DT_PROP(child, invert_direction) << TMC50XX_GCONF_SHAFT_SHIFT(DT_REG_ADDR(child))) |
686
687 #define TMC50XX_STEPPER_CONFIG_DEFINE(child) \
688 COND_CODE_1(DT_PROP_EXISTS(child, stallguard_threshold_velocity), \
689 BUILD_ASSERT(DT_PROP(child, stallguard_threshold_velocity), \
690 "stallguard threshold velocity must be a positive value"), ()); \
691 IF_ENABLED(CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN, (CHECK_RAMP_DT_DATA(child))); \
692 static const struct tmc50xx_stepper_config tmc50xx_stepper_config_##child = { \
693 .controller = DEVICE_DT_GET(DT_PARENT(child)), \
694 .default_micro_step_res = DT_PROP(child, micro_step_res), \
695 .index = DT_REG_ADDR(child), \
696 .sg_threshold = DT_PROP(child, stallguard2_threshold), \
697 .sg_threshold_velocity = DT_PROP(child, stallguard_threshold_velocity), \
698 .sg_velocity_check_interval_ms = DT_PROP(child, \
699 stallguard_velocity_check_interval_ms), \
700 .is_sg_enabled = DT_PROP(child, activate_stallguard2), \
701 IF_ENABLED(CONFIG_STEPPER_ADI_TMC50XX_RAMP_GEN, \
702 (.default_ramp_config = TMC_RAMP_DT_SPEC_GET(child))) };
703
704 #define TMC50XX_STEPPER_DATA_DEFINE(child) \
705 static struct tmc50xx_stepper_data tmc50xx_stepper_data_##child = { \
706 .stepper = DEVICE_DT_GET(child),};
707
708 #define TMC50XX_STEPPER_API_DEFINE(child) \
709 static DEVICE_API(stepper, tmc50xx_stepper_api_##child) = { \
710 .enable = tmc50xx_stepper_enable, \
711 .is_moving = tmc50xx_stepper_is_moving, \
712 .move_by = tmc50xx_stepper_move_by, \
713 .set_micro_step_res = tmc50xx_stepper_set_micro_step_res, \
714 .get_micro_step_res = tmc50xx_stepper_get_micro_step_res, \
715 .set_reference_position = tmc50xx_stepper_set_reference_position, \
716 .get_actual_position = tmc50xx_stepper_get_actual_position, \
717 .move_to = tmc50xx_stepper_move_to, \
718 .run = tmc50xx_stepper_run, \
719 .set_event_callback = tmc50xx_stepper_set_event_callback, };
720
721 #define TMC50XX_STEPPER_DEFINE(child) \
722 DEVICE_DT_DEFINE(child, tmc50xx_stepper_init, NULL, &tmc50xx_stepper_data_##child, \
723 &tmc50xx_stepper_config_##child, POST_KERNEL, \
724 CONFIG_STEPPER_INIT_PRIORITY, &tmc50xx_stepper_api_##child);
725
726 #define TMC50XX_DEFINE(inst) \
727 BUILD_ASSERT(DT_INST_CHILD_NUM(inst) <= 2, "tmc50xx can drive two steppers at max"); \
728 BUILD_ASSERT((DT_INST_PROP(inst, clock_frequency) > 0), \
729 "clock frequency must be non-zero positive value"); \
730 static struct tmc50xx_data tmc50xx_data_##inst; \
731 static const struct tmc50xx_config tmc50xx_config_##inst = { \
732 .gconf = ( \
733 (DT_INST_PROP(inst, poscmp_enable) << TMC50XX_GCONF_POSCMP_ENABLE_SHIFT) | \
734 (DT_INST_PROP(inst, test_mode) << TMC50XX_GCONF_TEST_MODE_SHIFT) | \
735 DT_INST_FOREACH_CHILD(inst, TMC50XX_SHAFT_CONFIG) \
736 (DT_INST_PROP(inst, lock_gconf) << TMC50XX_LOCK_GCONF_SHIFT)), \
737 .spi = SPI_DT_SPEC_INST_GET(inst, (SPI_OP_MODE_MASTER | SPI_TRANSFER_MSB | \
738 SPI_MODE_CPOL | SPI_MODE_CPHA | SPI_WORD_SET(8)), 0), \
739 .clock_frequency = DT_INST_PROP(inst, clock_frequency),}; \
740 DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_CONFIG_DEFINE); \
741 DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_DATA_DEFINE); \
742 DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_API_DEFINE); \
743 DT_INST_FOREACH_CHILD(inst, TMC50XX_STEPPER_DEFINE); \
744 DEVICE_DT_INST_DEFINE(inst, tmc50xx_init, NULL, &tmc50xx_data_##inst, \
745 &tmc50xx_config_##inst, POST_KERNEL, CONFIG_STEPPER_INIT_PRIORITY,\
746 NULL);
747
748 DT_INST_FOREACH_STATUS_OKAY(TMC50XX_DEFINE)
749