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