1 /*
2 * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3 */
4
5 #include <drv/pwm.h>
6 #include <aos/pwm_core.h>
7 #include "device.h"
8 #include "objects.h"
9 #include "pinmap.h"
10
11 #define BIT_PWM_TIM_IDX_FLAG BIT(7)
12 #define BIT_PWM_TIM_IDX_SHIFT 7
13 #define PWM_TIMER 5
14
15 #define DIV_ROUND_CLOSEST(x, divisor)( \
16 { \
17 typeof(x) __x = x; \
18 typeof(divisor) __d = divisor; \
19 (((typeof(x))-1) > 0 || \
20 ((typeof(divisor))-1) > 0 || \
21 (((__x) > 0) == ((__d) > 0))) ? \
22 (((__x) + ((__d) / 2)) / (__d)) : \
23 (((__x) - ((__d) / 2)) / (__d)); \
24 } \
25 )
26
27
28 typedef struct {
29 aos_pwm_t aos_pwm;
30 uint8_t idx;
31 void *priv;
32 } rtl872xd_pwm_t;
33 /* Table elements express the pin to PWM channel number, they are:
34 * {pinName, km0_pin2chan, km4_pin2chan}
35 */
36 static const u32 pin2chan[18][2] = {
37 { PA_12, 0 },
38 { PA_13, 1 },
39 { PA_23, 2 },
40 { PA_24, 3 },
41 { PA_25, 4 },
42 { PA_26, 5 },
43 { PA_28, 6 },
44 { PA_30, 7 },
45 { PB_4, 8 },
46 { PB_5, 9 },
47 { PB_18, 10 },
48 { PB_19, 11 },
49 { PB_20, 12 },
50 { PB_21, 13 },
51 { PB_22, 14 },
52 { PB_23, 15 },
53 { PB_24, 16 },
54 { PB_7, 17 } // this channel also can be PB_7
55 };
56
57 static RTIM_TypeDef *RTL872xD_PWM_TIM[2] = { TIM5, TIMM05 };
58
59 static u8 km4_ch_start[18] = { 0 };
60
rtl872xd_pwm_uninit(rtl872xd_pwm_t * pwm_dev)61 static void rtl872xd_pwm_uninit(rtl872xd_pwm_t *pwm_dev)
62 {
63 uint32_t pwm_chan = pwm_dev->idx & (~BIT_PWM_TIM_IDX_FLAG);
64 uint8_t pwm_tim_idx = pwm_dev->idx >> BIT_PWM_TIM_IDX_SHIFT;
65
66 if (km4_ch_start[pwm_chan]) {
67 km4_ch_start[pwm_chan] = 0;
68 RTIM_CCxCmd(RTL872xD_PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Disable);
69
70 /* stop timer5 if no pwm channels starts */
71 for (pwm_chan = 0; pwm_chan < 18; pwm_chan++) {
72 if (km4_ch_start[pwm_chan]) {
73 return;
74 }
75 }
76 RTIM_Cmd(RTL872xD_PWM_TIM[pwm_tim_idx], DISABLE);
77 }
78
79 if (pwm_dev && pwm_dev->priv) {
80 free(pwm_dev->priv);
81 pwm_dev->priv = NULL;
82 }
83 }
84
rtl872xd_pwm_out_config(rtl872xd_pwm_t * pwm_dev,uint32_t channel,uint32_t period_ns,uint32_t pulse_width_ns,csi_pwm_polarity_t polarity)85 static int rtl872xd_pwm_out_config(rtl872xd_pwm_t *pwm_dev, uint32_t channel, uint32_t period_ns,
86 uint32_t pulse_width_ns, csi_pwm_polarity_t polarity)
87 {
88 uint32_t arr, tmp, ccrx;
89 uint32_t period;
90 float pulse, value, dc;
91 uint8_t pwm_tim_idx = pwm_dev->idx >> BIT_PWM_TIM_IDX_SHIFT;
92 TIM_CCInitTypeDef *TIM_CCInitStruct = (TIM_CCInitTypeDef *)pwm_dev->priv;
93 u32 prescaler = 0;
94
95 if (channel > 18) {
96 return 0;
97 }
98 RTIM_CCStructInit(TIM_CCInitStruct);
99 RTIM_CCxInit(RTL872xD_PWM_TIM[pwm_tim_idx], TIM_CCInitStruct, channel);
100 RTIM_CCxCmd(RTL872xD_PWM_TIM[pwm_tim_idx], channel, TIM_CCx_Enable);
101 PinName pin = pin2chan[channel][0];
102 if (km4_ch_start[channel] == 0) {
103 if (pwm_tim_idx) {
104 Pinmux_Config(pin, PINMUX_FUNCTION_PWM_LP);
105 } else {
106 Pinmux_Config(pin, PINMUX_FUNCTION_PWM_HS);
107 }
108 }
109 km4_ch_start[channel] = 1;
110
111 tmp = DIV_ROUND_CLOSEST(((uint64_t)period_ns * 40), 1000);
112 tmp = tmp / (prescaler + 1);
113 /*
114 * psr is 8bits
115 */
116 if (tmp > 0x10000) {
117 prescaler = DIV_ROUND_CLOSEST(((uint64_t)period_ns * 40), 1000);
118 prescaler = DIV_ROUND_CLOSEST(prescaler, 0x10000);
119 if (prescaler > 0xff) {
120 prescaler = 0xff;
121 }
122 RTIM_PrescalerConfig(RTL872xD_PWM_TIM[pwm_tim_idx], prescaler, TIM_PSCReloadMode_Update);
123 }
124 /*
125 * arr is 16bits
126 */
127
128 /*
129 * 40M oscilator
130 */
131 arr = DIV_ROUND_CLOSEST(((uint64_t)period_ns * 40), 1000);
132 arr = DIV_ROUND_CLOSEST(arr, (prescaler + 1)) - 1;
133 if (arr > 0xffff) {
134 arr = 0xffff;
135 }
136 RTIM_ChangePeriod(RTL872xD_PWM_TIM[pwm_tim_idx], arr);
137 ccrx = DIV_ROUND_CLOSEST(((uint64_t)(period_ns - pulse_width_ns) * 40), 1000);
138 ccrx = (ccrx / (prescaler + 1)) & 0x0000ffff;
139 RTIM_CCRxSet(RTL872xD_PWM_TIM[pwm_tim_idx], ccrx, channel);
140
141 if (0 == polarity)
142 RTIM_CCxPolarityConfig(RTL872xD_PWM_TIM[pwm_tim_idx], TIM_CCPolarity_Low, channel);
143 else
144 RTIM_CCxPolarityConfig(RTL872xD_PWM_TIM[pwm_tim_idx], TIM_CCPolarity_High, channel);
145 return 0;
146 }
147
rtl872xd_pwm_out_start(rtl872xd_pwm_t * pwm_dev,uint32_t channel)148 static int rtl872xd_pwm_out_start(rtl872xd_pwm_t *pwm_dev, uint32_t channel)
149 {
150 uint32_t pwm_chan = channel;
151 uint8_t pwm_tim_idx = pwm_dev->idx >> BIT_PWM_TIM_IDX_SHIFT;
152
153 RTIM_CCxCmd(RTL872xD_PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Enable);
154 return 0;
155 }
156
rtl872xd_pwm_out_stop(rtl872xd_pwm_t * pwm_dev,uint32_t channel)157 static int rtl872xd_pwm_out_stop(rtl872xd_pwm_t *pwm_dev, uint32_t channel)
158 {
159 uint32_t pwm_chan = channel;
160 uint8_t pwm_tim_idx = pwm_dev->idx >> BIT_PWM_TIM_IDX_SHIFT;
161
162 RTIM_CCxCmd(RTL872xD_PWM_TIM[pwm_tim_idx], pwm_chan, TIM_CCx_Disable);
163 return 0;
164 }
165
rtl872xd_pwm_unregister(aos_pwm_t * pwm)166 static void rtl872xd_pwm_unregister(aos_pwm_t *pwm)
167 {
168 rtl872xd_pwm_t *pwm_dev = aos_container_of(pwm, rtl872xd_pwm_t, aos_pwm);
169
170 rtl872xd_pwm_uninit(pwm_dev);
171 }
172
rtl872xd_pwm_startup(aos_pwm_t * pwm)173 static int rtl872xd_pwm_startup(aos_pwm_t *pwm)
174 {
175 return 0;
176 }
177
rtl872xd_pwm_shutdown(aos_pwm_t * pwm)178 static void rtl872xd_pwm_shutdown(aos_pwm_t *pwm)
179 {
180 rtl872xd_pwm_t *pwm_dev = aos_container_of(pwm, rtl872xd_pwm_t, aos_pwm);
181 rtl872xd_pwm_out_stop(pwm_dev, pwm_dev->aos_pwm.dev.id);
182 }
183
rtl872xd_pwm_apply(aos_pwm_t * pwm,aos_pwm_attr_t const * attr)184 static int rtl872xd_pwm_apply(aos_pwm_t *pwm, aos_pwm_attr_t const *attr)
185 {
186 uint32_t period;
187 uint32_t duty_cycle;
188
189 rtl872xd_pwm_t *pwm_dev = aos_container_of(pwm, rtl872xd_pwm_t, aos_pwm);
190 period = attr->period;
191 duty_cycle = attr->duty_cycle;
192 rtl872xd_pwm_out_config(pwm_dev, pwm_dev->aos_pwm.dev.id,
193 period, duty_cycle, attr->polarity);
194 if (attr->enabled)
195 rtl872xd_pwm_out_start(pwm_dev, pwm_dev->aos_pwm.dev.id);
196 else
197 rtl872xd_pwm_out_stop(pwm_dev, pwm_dev->aos_pwm.dev.id);
198 return 0;
199 }
200
201 static const aos_pwm_ops_t rtl872xd_pwm_ops = {
202 .unregister = rtl872xd_pwm_unregister,
203 .apply = rtl872xd_pwm_apply,
204 .shutdown = rtl872xd_pwm_shutdown,
205 .startup = rtl872xd_pwm_startup
206 };
207
rtl872xd_pwm_init(void)208 static int rtl872xd_pwm_init(void)
209 {
210 int ret;
211 static rtl872xd_pwm_t pwm_dev[CONFIG_PWM_NUM];
212 int idx = 0, i;
213 RTIM_TimeBaseInitTypeDef TIM_InitStruct;
214 RTIM_TimeBaseStructInit(&TIM_InitStruct);
215 TIM_InitStruct.TIM_Idx = PWM_TIMER;
216 RTIM_TimeBaseInit(RTL872xD_PWM_TIM[idx], &TIM_InitStruct, TIMER5_IRQ, NULL, (u32)&TIM_InitStruct);
217 RTIM_Cmd(RTL872xD_PWM_TIM[idx], ENABLE);
218 for (i = 0; i < CONFIG_PWM_NUM; i++) {
219 pwm_dev[i].priv = (TIM_CCInitTypeDef *)malloc(sizeof(TIM_CCInitTypeDef));
220 pwm_dev[i].idx = idx << BIT_PWM_TIM_IDX_SHIFT;
221 pwm_dev[i].idx |= (i) & (~BIT_PWM_TIM_IDX_FLAG);
222 if (ret != 0) {
223 return ret;
224 }
225 pwm_dev[i].aos_pwm.dev.id = i;
226 pwm_dev[i].aos_pwm.ops = &rtl872xd_pwm_ops;
227 ret = aos_pwm_register(&(pwm_dev[i].aos_pwm));
228 if (ret != 0) {
229 return ret;
230 }
231 }
232 return 0;
233 }
234
235 LEVEL1_DRIVER_ENTRY(rtl872xd_pwm_init)
236