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), &reg_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), &reg_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), &reg_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), &reg_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), &reg_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