1 /*
2 * Copyright (C) 2021 Alibaba Group Holding Limited
3 */
4
5 #include <stdint.h>
6 #include <errno.h>
7 #include <stdbool.h>
8 #include <aos/kernel.h>
9 #include <aos/list.h>
10 #include <aos/pwm.h>
11 #include <aos/pwm_core.h>
12 #include <drivers/ddkc_log.h>
13
14 #define AOS_MAX_PERIOD (1000000000U)
15 #define AOS_PWM_CHECK_NULL(x) \
16 do { \
17 if ((x) == NULL) { \
18 return -EINVAL; \
19 } \
20 } while (0)
21
aos_pwm_get(aos_pwm_ref_t * ref,uint32_t id)22 aos_status_t aos_pwm_get(aos_pwm_ref_t *ref, uint32_t id)
23 {
24 AOS_PWM_CHECK_NULL(ref);
25
26 return aos_dev_get(ref, AOS_DEV_TYPE_PWM, id);
27 }
28
aos_pwm_put(aos_pwm_ref_t * ref)29 void aos_pwm_put(aos_pwm_ref_t *ref)
30 {
31 if (ref == NULL)
32 return;
33
34 aos_dev_put(ref);
35 }
36
aos_pwm_set_attr(aos_pwm_ref_t * ref,aos_pwm_attr_t const * attr)37 aos_status_t aos_pwm_set_attr(aos_pwm_ref_t *ref, aos_pwm_attr_t const *attr)
38 {
39 aos_status_t ret;
40 aos_pwm_t *pwm;
41 aos_pwm_attr_t l_attr;
42
43 AOS_PWM_CHECK_NULL(ref);
44 AOS_PWM_CHECK_NULL(attr);
45 pwm = aos_container_of(ref->dev, aos_pwm_t, dev);
46 memcpy(&l_attr, attr, sizeof(aos_pwm_attr_t));
47 if (l_attr.period > AOS_MAX_PERIOD) {
48 ddkc_warn("warning:period exceeds 1s\r\n");
49 l_attr.period = AOS_MAX_PERIOD;
50 }
51 if (l_attr.duty_cycle > l_attr.period) {
52 ddkc_warn("warning: duty exceeds period\r\n");
53 l_attr.duty_cycle = l_attr.period;
54 }
55 if (l_attr.period == pwm->period &&
56 l_attr.duty_cycle == pwm->duty_cycle &&
57 l_attr.enabled == pwm->enabled &&
58 l_attr.polarity == pwm->polarity)
59 return 0;
60 if (pwm->ops->apply == NULL)
61 return -ENOTSUP;
62
63 aos_dev_lock(ref->dev);
64 ret = pwm->ops->apply(pwm, &l_attr);
65 if (!ret) {
66 pwm->period = l_attr.period;
67 pwm->duty_cycle = l_attr.duty_cycle;
68 pwm->enabled = l_attr.enabled;
69 pwm->polarity = (uint32_t)l_attr.polarity;
70 }
71 aos_dev_unlock(ref->dev);
72 return ret;
73 }
74
aos_pwm_get_attr(aos_pwm_ref_t * ref,aos_pwm_attr_t * attr)75 aos_status_t aos_pwm_get_attr(aos_pwm_ref_t *ref, aos_pwm_attr_t *attr)
76 {
77 aos_status_t ret;
78 aos_pwm_t *pwm;
79
80 AOS_PWM_CHECK_NULL(ref);
81 AOS_PWM_CHECK_NULL(attr);
82 pwm = aos_container_of(ref->dev, aos_pwm_t, dev);
83 aos_dev_lock(ref->dev);
84 attr->period = pwm->period;
85 attr->duty_cycle = pwm->duty_cycle;
86 attr->enabled = pwm->enabled;
87 attr->polarity = pwm->polarity;
88 aos_dev_unlock(ref->dev);
89 return 0;
90 }
dev_pwm_unregister(aos_dev_t * dev)91 static void dev_pwm_unregister(aos_dev_t *dev)
92 {
93 aos_pwm_t *pwm = aos_container_of(dev, aos_pwm_t, dev);
94
95 if (pwm->ops->unregister)
96 pwm->ops->unregister(pwm);
97 }
98
dev_pwm_get(aos_dev_ref_t * ref)99 static aos_status_t dev_pwm_get(aos_dev_ref_t *ref)
100 {
101 aos_pwm_t *pwm = aos_container_of(ref->dev, aos_pwm_t, dev);
102
103 if (!aos_dev_ref_is_first(ref))
104 return 0;
105 return pwm->ops->startup(pwm);
106 }
107
dev_pwm_put(aos_dev_ref_t * ref)108 static void dev_pwm_put(aos_dev_ref_t *ref)
109 {
110 aos_pwm_t *pwm = aos_container_of(ref->dev, aos_pwm_t, dev);
111
112 if (!aos_dev_ref_is_last(ref))
113 return;
114 pwm->ops->shutdown(pwm);
115 pwm->period = 0;
116 pwm->duty_cycle = 0;
117 pwm->enabled = 0;
118 return;
119 }
120
121 static const aos_dev_ops_t dev_pwm_ops = {
122 .unregister = dev_pwm_unregister,
123 .get = dev_pwm_get,
124 .put = dev_pwm_put,
125 };
126
aos_pwm_register(aos_pwm_t * pwm)127 aos_status_t aos_pwm_register(aos_pwm_t *pwm)
128 {
129 aos_status_t ret;
130
131 AOS_PWM_CHECK_NULL(pwm);
132
133 /* startup/shutdown/unregister/apply/startup must be set. */
134 if ((pwm->ops == NULL) || (pwm->ops->unregister == NULL) ||
135 (pwm->ops->apply == NULL) || (pwm->ops->shutdown == NULL) ||
136 (pwm->ops->startup == NULL))
137 return -EINVAL;
138
139 pwm->dev.type = AOS_DEV_TYPE_PWM;
140 pwm->dev.ops = &dev_pwm_ops;
141 pwm->enabled = 0;
142 pwm->duty_cycle = 0;
143 pwm->period = 0;
144 pwm->polarity = 0;
145 #ifdef AOS_COMP_VFS
146 /* TODO: support vfs ops. */
147 pwm->dev.vfs_helper.name[0] = '\0';
148 pwm->dev.vfs_helper.ops = NULL;
149 #endif
150
151 return aos_dev_register(&(pwm->dev));
152 }
153
aos_pwm_unregister(uint32_t id)154 aos_status_t aos_pwm_unregister(uint32_t id)
155 {
156 return aos_dev_unregister(AOS_DEV_TYPE_PWM, id);
157 }
158