1 /*
2 * Copyright (c) 2006-2023, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Email: opensource_embedded@phytium.com.cn
7 *
8 * Change Logs:
9 * Date Author Notes
10 * 2023-10-18 zhangyan first version
11 *
12 */
13 #include "rtconfig.h"
14 #include <rtdevice.h>
15 #define LOG_TAG "pwm_drv"
16 #include "drv_log.h"
17 #include "drv_pwm.h"
18 #include "fio_mux.h"
19 #include "fpwm.h"
20 #ifdef RT_USING_SMART
21 #include <ioremap.h>
22 #endif
23 struct phytium_pwm
24 {
25 const char *name;
26 FPwmCtrl pwm_handle;
27 struct rt_device_pwm device; /* inherit from can device */
28 };
29
drv_pwm_config(struct phytium_pwm * pwm_dev)30 static rt_err_t drv_pwm_config(struct phytium_pwm *pwm_dev)
31 {
32 RT_ASSERT(pwm_dev);
33 u32 ret;
34 FPwmConfig config;
35 FPwmCtrl *pwm_handle = &pwm_dev->pwm_handle;
36 FIOPadSetPwmMux(pwm_handle->config.instance_id, 0);
37 #if !defined(PD2408_TEST_A_BOARD) || defined(PD2408_TEST_B_BOARD)
38 FIOPadSetPwmMux(pwm_handle->config.instance_id, 1);
39 #endif
40 config = *FPwmLookupConfig(pwm_handle->config.instance_id);
41 #ifdef RT_USING_SMART
42 config.lsd_config_addr = (uintptr)rt_ioremap((void *)config.lsd_config_addr, 0x100);
43 config.pwm_base_addr = (uintptr)rt_ioremap((void *)config.pwm_base_addr, 0x1000);
44 config.db_base_addr = (uintptr)rt_ioremap((void *)config.db_base_addr, 0x100);
45 #endif
46 ret = FPwmCfgInitialize(pwm_handle, &config);
47 if (ret != FPWM_SUCCESS)
48 {
49 LOG_E("Pwm config init failed.\n");
50
51 return -RT_ERROR;
52 }
53
54 return RT_EOK;
55 }
56
drv_pwm_enable(struct phytium_pwm * pwm_dev,struct rt_pwm_configuration * configuration,boolean enable_pwm)57 static rt_err_t drv_pwm_enable(struct phytium_pwm *pwm_dev, struct rt_pwm_configuration *configuration, boolean enable_pwm)
58 {
59 RT_ASSERT(pwm_dev);
60 RT_ASSERT(configuration);
61 u32 channel = configuration->channel;
62
63 if (enable_pwm == RT_TRUE)
64 {
65 FPwmEnable(&pwm_dev->pwm_handle, channel);
66 }
67 else
68 {
69 FPwmDisable(&pwm_dev->pwm_handle, channel);
70 }
71
72 return RT_EOK;
73 }
74
drv_pwm_set(struct phytium_pwm * pwm_dev,int cmd,struct rt_pwm_configuration * configuration)75 static rt_err_t drv_pwm_set(struct phytium_pwm *pwm_dev, int cmd, struct rt_pwm_configuration *configuration)
76 {
77 RT_ASSERT(pwm_dev);
78 RT_ASSERT(configuration);
79 u32 ret;
80 FPwmVariableConfig pwm_cfg;
81 u32 channel = configuration->channel;
82
83 rt_memset(&pwm_cfg, 0, sizeof(pwm_cfg));
84 pwm_cfg.tim_ctrl_mode = FPWM_MODULO;
85 pwm_cfg.tim_ctrl_div = 50 - 1;
86 /* Precision set to microseconds */
87 switch (cmd)
88 {
89 case PWM_CMD_SET:
90 pwm_cfg.pwm_period = configuration->period / 1000;
91 pwm_cfg.pwm_pulse = configuration->pulse / 1000;
92 break;
93 case PWM_CMD_SET_PERIOD:
94 pwm_cfg.pwm_period = configuration->period / 1000;
95 break;
96 case PWM_CMD_SET_PULSE:
97 pwm_cfg.pwm_pulse = configuration->pulse / 1000;
98 break;
99 }
100 /* Can be modified according to function */
101 pwm_cfg.pwm_mode = FPWM_OUTPUT_COMPARE;
102 pwm_cfg.pwm_polarity = FPWM_POLARITY_NORMAL;
103 pwm_cfg.pwm_duty_source_mode = FPWM_DUTY_CCR;
104
105 FPwmDisable(&pwm_dev->pwm_handle, channel);
106
107 ret = FPwmVariableSet(&pwm_dev->pwm_handle, channel, &pwm_cfg);
108 if (ret != FPWM_SUCCESS)
109 {
110 LOG_E("Pwm variable set failed.\n");
111
112 return -RT_ERROR;
113 }
114
115 FPwmEnable(&pwm_dev->pwm_handle, channel);
116
117 return RT_EOK;
118 }
119
drv_pwm_get(struct phytium_pwm * pwm_dev,struct rt_pwm_configuration * configuration)120 static rt_err_t drv_pwm_get(struct phytium_pwm *pwm_dev, struct rt_pwm_configuration *configuration)
121 {
122 RT_ASSERT(pwm_dev);
123 RT_ASSERT(configuration);
124 FPwmVariableConfig pwm_cfg;
125 u32 channel = configuration->channel;
126
127 rt_memset(&pwm_cfg, 0, sizeof(pwm_cfg));
128 FPwmVariableGet(&pwm_dev->pwm_handle, channel, &pwm_cfg);
129
130 configuration->period = pwm_cfg.pwm_period * 1000;
131 configuration->pulse = pwm_cfg.pwm_pulse * 1000;
132
133 LOG_D("period = %d\n, pulse = %d\n", configuration->period, configuration->pulse);
134
135 return RT_EOK;
136 }
137
drv_pwm_set_dead_time(struct phytium_pwm * pwm_dev,struct rt_pwm_configuration * configuration)138 static rt_err_t drv_pwm_set_dead_time(struct phytium_pwm *pwm_dev, struct rt_pwm_configuration *configuration)
139 {
140 RT_ASSERT(pwm_dev);
141 RT_ASSERT(configuration);
142 u32 ret;
143 FPwmDbVariableConfig db_cfg;
144 u32 channel = configuration->channel;
145
146 rt_memset(&db_cfg, 0, sizeof(db_cfg));
147 db_cfg.db_rise_cycle = configuration->dead_time / 1000;
148 db_cfg.db_fall_cycle = configuration->dead_time / 1000;
149 db_cfg.db_polarity_sel = FPWM_DB_AH;
150 db_cfg.db_in_mode = FPWM_DB_IN_MODE_PWM0;
151 db_cfg.db_out_mode = FPWM_DB_OUT_MODE_ENABLE_RISE_FALL;
152
153 FPwmDisable(&pwm_dev->pwm_handle, channel);
154 ret = FPwmDbVariableSet(&pwm_dev->pwm_handle, &db_cfg);
155 if (ret != FPWM_SUCCESS)
156 {
157 LOG_E("FPwmDbVariableSet failed.");
158
159 return -RT_ERROR;
160 }
161 FPwmEnable(&pwm_dev->pwm_handle, channel);
162
163 return RT_EOK;
164 }
165
_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)166 static rt_err_t _pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
167 {
168 struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
169 struct phytium_pwm *pwm_dev;
170 pwm_dev = (struct phytium_pwm *)(device->parent.user_data);
171
172 switch (cmd)
173 {
174 case PWM_CMD_ENABLE:
175 return drv_pwm_enable(pwm_dev, configuration, RT_TRUE);
176 case PWM_CMD_DISABLE:
177 return drv_pwm_enable(pwm_dev, configuration, RT_FALSE);
178 case PWM_CMD_SET:
179 return drv_pwm_set(pwm_dev, PWM_CMD_SET, configuration);
180 case PWM_CMD_GET:
181 return drv_pwm_get(pwm_dev, configuration);
182 case PWM_CMD_SET_DEAD_TIME:
183 return drv_pwm_set_dead_time(pwm_dev, configuration);
184 case PWM_CMD_SET_PERIOD:
185 return drv_pwm_set(pwm_dev, PWM_CMD_SET_PERIOD, configuration);
186 case PWM_CMD_SET_PULSE:
187 return drv_pwm_set(pwm_dev, PWM_CMD_SET_PULSE, configuration);
188 default:
189 return -RT_EINVAL;
190 }
191 }
192
193 static const struct rt_pwm_ops _pwm_ops =
194 {
195 _pwm_control,
196 };
197
pwm_controller_init(struct phytium_pwm * pwm_dev)198 static rt_err_t pwm_controller_init(struct phytium_pwm *pwm_dev)
199 {
200 u32 ret = RT_EOK;
201 ret = drv_pwm_config(pwm_dev);
202 if (ret != FPWM_SUCCESS)
203 {
204 LOG_E("Pwm config failed.\n");
205
206 return -RT_ERROR;
207 }
208 ret = rt_device_pwm_register(&pwm_dev->device,
209 pwm_dev->name,
210 &_pwm_ops,
211 pwm_dev);
212 RT_ASSERT(ret == RT_EOK);
213
214 return ret;
215 }
216
217 #if defined(RT_USING_PWM0)
218 static struct phytium_pwm pwm0_dev;
219 #endif
220 #if defined(RT_USING_PWM1)
221 static struct phytium_pwm pwm1_dev;
222 #endif
223 #if defined(RT_USING_PWM2)
224 static struct phytium_pwm pwm2_dev;
225 #endif
226 #if defined(RT_USING_PWM3)
227 static struct phytium_pwm pwm3_dev;
228 #endif
229 #if defined(RT_USING_PWM4)
230 static struct phytium_pwm pwm4_dev;
231 #endif
232 #if defined(RT_USING_PWM5)
233 static struct phytium_pwm pwm5_dev;
234 #endif
235 #if defined(RT_USING_PWM6)
236 static struct phytium_pwm pwm6_dev;
237 #endif
238 #if defined(RT_USING_PWM7)
239 static struct phytium_pwm pwm7_dev;
240 #endif
241
rt_hw_pwm_init(void)242 int rt_hw_pwm_init(void)
243 {
244 #if defined(RT_USING_PWM0)
245 pwm0_dev.name = "PWM0";
246 pwm0_dev.pwm_handle.config.instance_id = FPWM0_ID;
247 pwm_controller_init(&pwm0_dev);
248 #endif
249 #if defined(RT_USING_PWM1)
250 pwm1_dev.name = "PWM1";
251 pwm1_dev.pwm_handle.config.instance_id = FPWM1_ID;
252 pwm_controller_init(&pwm1_dev);
253 #endif
254 #if defined(RT_USING_PWM2)
255 pwm2_dev.name = "PWM2";
256 pwm2_dev.pwm_handle.config.instance_id = FPWM2_ID;
257 pwm_controller_init(&pwm2_dev);
258 #endif
259 #if defined(RT_USING_PWM3)
260 pwm3_dev.name = "PWM3";
261 pwm3_dev.pwm_handle.config.instance_id = FPWM3_ID;
262 pwm_controller_init(&pwm3_dev);
263 #endif
264 #if defined(RT_USING_PWM4)
265 pwm4_dev.name = "PWM4";
266 pwm4_dev.pwm_handle.config.instance_id = FPWM4_ID;
267 pwm_controller_init(&pwm4_dev);
268 #endif
269 #if defined(RT_USING_PWM5)
270 pwm5_dev.name = "PWM5";
271 pwm5_dev.pwm_handle.config.instance_id = FPWM5_ID;
272 pwm_controller_init(&pwm5_dev);
273 #endif
274 #if defined(RT_USING_PWM6)
275 pwm6_dev.name = "PWM6";
276 pwm6_dev.pwm_handle.config.instance_id = FPWM6_ID;
277 pwm_controller_init(&pwm6_dev);
278 #endif
279 #if defined(RT_USING_PWM7)
280 pwm7_dev.name = "PWM7";
281 pwm7_dev.pwm_handle.config.instance_id = FPWM7_ID;
282 pwm_controller_init(&pwm7_dev);
283 #endif
284
285 return 0;
286 }
287 INIT_DEVICE_EXPORT(rt_hw_pwm_init);
288