1 /*
2  * Copyright (c) 2020-2021 Vestas Wind Systems A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 
8 #include <zephyr/kernel.h>
9 #include <zephyr/drivers/pwm.h>
10 #include <zephyr/logging/log.h>
11 
12 LOG_MODULE_REGISTER(pwm_capture, CONFIG_PWM_LOG_LEVEL);
13 
14 struct z_pwm_capture_cb_data {
15 	uint32_t period;
16 	uint32_t pulse;
17 	struct k_sem sem;
18 	int status;
19 };
20 
z_pwm_capture_cycles_callback(const struct device * dev,uint32_t channel,uint32_t period_cycles,uint32_t pulse_cycles,int status,void * user_data)21 static void z_pwm_capture_cycles_callback(const struct device *dev,
22 					  uint32_t channel,
23 					  uint32_t period_cycles,
24 					  uint32_t pulse_cycles, int status,
25 					  void *user_data)
26 {
27 	struct z_pwm_capture_cb_data *data = user_data;
28 
29 	data->period = period_cycles;
30 	data->pulse = pulse_cycles;
31 	data->status = status;
32 
33 	k_sem_give(&data->sem);
34 }
35 
z_impl_pwm_capture_cycles(const struct device * dev,uint32_t channel,pwm_flags_t flags,uint32_t * period,uint32_t * pulse,k_timeout_t timeout)36 int z_impl_pwm_capture_cycles(const struct device *dev, uint32_t channel,
37 			      pwm_flags_t flags, uint32_t *period,
38 			      uint32_t *pulse, k_timeout_t timeout)
39 {
40 	struct z_pwm_capture_cb_data data;
41 	int err;
42 
43 	if ((flags & PWM_CAPTURE_MODE_MASK) == PWM_CAPTURE_MODE_CONTINUOUS) {
44 		LOG_ERR("continuous capture mode only supported via callback");
45 		return -ENOTSUP;
46 	}
47 
48 	flags |= PWM_CAPTURE_MODE_SINGLE;
49 	k_sem_init(&data.sem, 0, 1);
50 
51 	err = pwm_configure_capture(dev, channel, flags,
52 				    z_pwm_capture_cycles_callback, &data);
53 	if (err) {
54 		LOG_ERR("failed to configure pwm capture");
55 		return err;
56 	}
57 
58 	err = pwm_enable_capture(dev, channel);
59 	if (err) {
60 		LOG_ERR("failed to enable pwm capture");
61 		return err;
62 	}
63 
64 	err = k_sem_take(&data.sem, timeout);
65 	if (err == -EAGAIN) {
66 		(void)pwm_disable_capture(dev, channel);
67 		(void)pwm_configure_capture(dev, channel, flags, NULL, NULL);
68 		LOG_WRN("pwm capture timed out");
69 		return err;
70 	}
71 
72 	if (data.status == 0) {
73 		if (period != NULL) {
74 			*period = data.period;
75 		}
76 
77 		if (pulse != NULL) {
78 			*pulse = data.pulse;
79 		}
80 	}
81 
82 	return data.status;
83 }
84