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