1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2024 Fabian Blatz <fabianblatz@gmail.com>
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #include <zephyr/drivers/counter.h>
7 #include "step_dir_stepper_common.h"
8 
9 #include <zephyr/logging/log.h>
10 LOG_MODULE_DECLARE(step_dir_stepper);
11 
step_counter_top_interrupt(const struct device * dev,void * user_data)12 static void step_counter_top_interrupt(const struct device *dev, void *user_data)
13 {
14 	ARG_UNUSED(dev);
15 	struct step_dir_stepper_common_data *data = user_data;
16 
17 	stepper_handle_timing_signal(data->dev);
18 }
19 
step_counter_timing_source_update(const struct device * dev,const uint32_t velocity)20 int step_counter_timing_source_update(const struct device *dev, const uint32_t velocity)
21 {
22 	const struct step_dir_stepper_common_config *config = dev->config;
23 	struct step_dir_stepper_common_data *data = dev->data;
24 	int ret;
25 
26 	if (velocity == 0) {
27 		return -EINVAL;
28 	}
29 
30 	data->counter_top_cfg.ticks =
31 		DIV_ROUND_UP(counter_us_to_ticks(config->counter, USEC_PER_SEC), velocity);
32 
33 	/* Lock interrupts while modifying counter settings */
34 	int key = irq_lock();
35 
36 	ret = counter_set_top_value(config->counter, &data->counter_top_cfg);
37 
38 	irq_unlock(key);
39 
40 	if (ret != 0) {
41 		LOG_ERR("%s: Failed to set counter top value (error: %d)", dev->name, ret);
42 		return ret;
43 	}
44 
45 	return 0;
46 }
47 
step_counter_timing_source_start(const struct device * dev)48 int step_counter_timing_source_start(const struct device *dev)
49 {
50 	const struct step_dir_stepper_common_config *config = dev->config;
51 	struct step_dir_stepper_common_data *data = dev->data;
52 	int ret;
53 
54 	ret = counter_start(config->counter);
55 	if (ret < 0 && ret != -EALREADY) {
56 		LOG_ERR("Failed to start counter: %d", ret);
57 		return ret;
58 	}
59 
60 	data->counter_running = true;
61 
62 	return 0;
63 }
64 
step_counter_timing_source_stop(const struct device * dev)65 int step_counter_timing_source_stop(const struct device *dev)
66 {
67 	const struct step_dir_stepper_common_config *config = dev->config;
68 	struct step_dir_stepper_common_data *data = dev->data;
69 	int ret;
70 
71 	ret = counter_stop(config->counter);
72 	if (ret < 0 && ret != -EALREADY) {
73 		LOG_ERR("Failed to stop counter: %d", ret);
74 		return ret;
75 	}
76 
77 	data->counter_running = false;
78 
79 	return 0;
80 }
81 
step_counter_timing_source_needs_reschedule(const struct device * dev)82 bool step_counter_timing_source_needs_reschedule(const struct device *dev)
83 {
84 	ARG_UNUSED(dev);
85 	return false;
86 }
87 
step_counter_timing_source_is_running(const struct device * dev)88 bool step_counter_timing_source_is_running(const struct device *dev)
89 {
90 	struct step_dir_stepper_common_data *data = dev->data;
91 
92 	return data->counter_running;
93 }
94 
step_counter_timing_source_init(const struct device * dev)95 int step_counter_timing_source_init(const struct device *dev)
96 {
97 	const struct step_dir_stepper_common_config *config = dev->config;
98 	struct step_dir_stepper_common_data *data = dev->data;
99 
100 	if (!device_is_ready(config->counter)) {
101 		LOG_ERR("Counter device is not ready");
102 		return -ENODEV;
103 	}
104 
105 	data->counter_top_cfg.callback = step_counter_top_interrupt;
106 	data->counter_top_cfg.user_data = data;
107 	data->counter_top_cfg.flags = 0;
108 	data->counter_top_cfg.ticks = counter_us_to_ticks(config->counter, 1000000);
109 
110 	return 0;
111 }
112 
113 const struct stepper_timing_source_api step_counter_timing_source_api = {
114 	.init = step_counter_timing_source_init,
115 	.update = step_counter_timing_source_update,
116 	.start = step_counter_timing_source_start,
117 	.needs_reschedule = step_counter_timing_source_needs_reschedule,
118 	.stop = step_counter_timing_source_stop,
119 	.is_running = step_counter_timing_source_is_running,
120 };
121