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.h>
9 #include <drivers/pwm.h>
10 #include <logging/log.h>
11 
12 LOG_MODULE_REGISTER(pwm_capture, CONFIG_PWM_LOG_LEVEL);
13 
14 struct z_pwm_pin_capture_cb_data {
15 	uint32_t period;
16 	uint32_t pulse;
17 	struct k_sem sem;
18 	int status;
19 };
20 
z_pwm_pin_capture_cycles_callback(const struct device * dev,uint32_t pwm,uint32_t period_cycles,uint32_t pulse_cycles,int status,void * user_data)21 static void z_pwm_pin_capture_cycles_callback(const struct device *dev,
22 					      uint32_t pwm,
23 					      uint32_t period_cycles,
24 					      uint32_t pulse_cycles,
25 					      int status,
26 					      void *user_data)
27 {
28 	struct z_pwm_pin_capture_cb_data *data = user_data;
29 
30 	data->period = period_cycles;
31 	data->pulse = pulse_cycles;
32 	data->status = status;
33 
34 	k_sem_give(&data->sem);
35 }
36 
z_impl_pwm_pin_capture_cycles(const struct device * dev,uint32_t pwm,pwm_flags_t flags,uint32_t * period,uint32_t * pulse,k_timeout_t timeout)37 int z_impl_pwm_pin_capture_cycles(const struct device *dev, uint32_t pwm,
38 				  pwm_flags_t flags, uint32_t *period,
39 				  uint32_t *pulse, k_timeout_t timeout)
40 {
41 	struct z_pwm_pin_capture_cb_data data;
42 	int err;
43 
44 	if ((flags & PWM_CAPTURE_MODE_MASK) == PWM_CAPTURE_MODE_CONTINUOUS) {
45 		LOG_ERR("continuous capture mode only supported via callback");
46 		return -ENOTSUP;
47 	}
48 
49 	flags |= PWM_CAPTURE_MODE_SINGLE;
50 	k_sem_init(&data.sem, 0, 1);
51 
52 	err = pwm_pin_configure_capture(dev, pwm, flags,
53 					z_pwm_pin_capture_cycles_callback,
54 					&data);
55 	if (err) {
56 		LOG_ERR("failed to configure pwm capture");
57 		return err;
58 	}
59 
60 	err = pwm_pin_enable_capture(dev, pwm);
61 	if (err) {
62 		LOG_ERR("failed to enable pwm capture");
63 		return err;
64 	}
65 
66 	err = k_sem_take(&data.sem, timeout);
67 	if (err == -EAGAIN) {
68 		(void)pwm_pin_disable_capture(dev, pwm);
69 		(void)pwm_pin_configure_capture(dev, pwm, flags, NULL, NULL);
70 		LOG_WRN("pwm capture timed out");
71 		return err;
72 	}
73 
74 	if (data.status == 0) {
75 		if (period != NULL) {
76 			*period = data.period;
77 		}
78 
79 		if (pulse != NULL) {
80 			*pulse = data.pulse;
81 		}
82 	}
83 
84 	return data.status;
85 }
86