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