1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date             Author           Notes
8  * 2023-03-12       wcx1024979076    first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "drv_pwm.h"
14 
15 #ifdef BSP_USING_PWM
16 
17 #define DBG_LEVEL   DBG_LOG
18 #include <rtdbg.h>
19 #define LOG_TAG "DRV.PWM"
20 
_pwm_set(rt_uint8_t channel,struct rt_pwm_configuration * configuration)21 static rt_err_t _pwm_set(rt_uint8_t channel, struct rt_pwm_configuration *configuration)
22 {
23     struct bflb_device_s* pwm = bflb_device_get_by_name("pwm_v2_0");
24 
25     uint32_t period_hz = 1000000000 / configuration->period;
26 
27     struct bflb_pwm_v2_config_s pwm_config;
28 
29     pwm_config.clk_source = BFLB_SYSTEM_XCLK;
30 
31     pwm_config.clk_div = 40;
32 
33     pwm_config.period = 1000000 / period_hz;
34 
35     bflb_pwm_v2_init(pwm, &pwm_config);
36 
37     struct bflb_pwm_v2_channel_config_s pwm_ch_config = {
38         .positive_polarity = PWM_POLARITY_ACTIVE_HIGH,
39         .negative_polarity = PWM_POLARITY_ACTIVE_HIGH,
40         .positive_stop_state = PWM_STATE_INACTIVE,
41         .negative_stop_state = PWM_STATE_ACTIVE,
42         .positive_brake_state = PWM_STATE_INACTIVE,
43         .negative_brake_state = PWM_STATE_INACTIVE,
44         .dead_time = 0,
45     };
46 
47     bflb_pwm_v2_channel_init(pwm, channel, &pwm_ch_config);
48 
49     bflb_pwm_v2_channel_set_threshold(pwm, channel, 0, configuration->pulse);
50 
51     bflb_pwm_v2_channel_positive_stop(pwm, channel);
52     bflb_pwm_v2_channel_negative_stop(pwm, channel);
53     bflb_pwm_v2_stop(pwm);
54 
55     bflb_pwm_v2_channel_positive_start(pwm, channel);
56     bflb_pwm_v2_channel_negative_start(pwm, channel);
57     bflb_pwm_v2_start(pwm);
58 
59     return RT_EOK;
60 }
61 
_pwm_get(rt_uint8_t channel,struct rt_pwm_configuration * configuration)62 static rt_err_t _pwm_get(rt_uint8_t channel, struct rt_pwm_configuration *configuration)
63 {
64     uint32_t reg_base, regval, tmp;
65     float period;
66 
67     reg_base = bflb_device_get_by_name("pwm_v2_0")->reg_base;
68     regval = getreg32(reg_base + PWM_MC0_PERIOD_OFFSET);
69     tmp = (regval & PWM_PERIOD_MASK) >> PWM_PERIOD_SHIFT;
70     period = (float)tmp;
71 
72     uint32_t period_hz = 1000000 / period;
73 
74     regval = getreg32(reg_base + PWM_MC0_CH0_THRE_OFFSET + channel * 4);
75     uint16_t high_threhold = regval >> 16;
76     uint16_t low_threhold = regval;
77 
78     configuration->period = 1000000000 / period_hz;
79 
80     configuration->pulse = high_threhold;
81 
82     return RT_EOK;
83 }
84 
_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)85 static rt_err_t _pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
86 {
87     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
88 
89     rt_uint32_t channel = 0;
90 
91     channel = configuration->channel;
92 
93     if (channel >= 4)
94         return -RT_EINVAL;
95 
96     struct bflb_device_s* pwm = bflb_device_get_by_name("pwm_v2_0");
97     switch (cmd)
98     {
99     case PWM_CMD_ENABLE:
100         bflb_pwm_v2_channel_positive_start(pwm, channel);
101         bflb_pwm_v2_channel_negative_start(pwm, channel);
102         return RT_EOK;
103     case PWM_CMD_DISABLE:
104         bflb_pwm_v2_channel_positive_stop(pwm, channel);
105         bflb_pwm_v2_channel_negative_stop(pwm, channel);
106         return RT_EOK;
107     case PWM_CMD_SET:
108         return _pwm_set(channel, configuration);
109     case PWM_CMD_GET:
110         return _pwm_get(channel, configuration);
111     default:
112         return -RT_EINVAL;
113     }
114 }
115 
116 static struct rt_pwm_ops _pwm_ops =
117 {
118     _pwm_control
119 };
120 static struct rt_device_pwm pwm_device;
121 
rt_hw_pwm_init(void)122 int rt_hw_pwm_init(void)
123 {
124     int result = RT_EOK;
125 
126     struct bflb_device_s* gpio = bflb_device_get_by_name("gpio");
127     bflb_gpio_init(gpio, GPIO_PIN_8, GPIO_FUNC_PWM0 | GPIO_ALTERNATE | GPIO_PULLDOWN | GPIO_SMT_EN | GPIO_DRV_1);
128     struct bflb_device_s* pwm = bflb_device_get_by_name("pwm_v2_0");
129     bflb_pwm_v2_start(pwm);
130 
131     result = rt_device_pwm_register(&pwm_device, "pwm", &_pwm_ops, 0);
132     if(result != RT_EOK)
133     {
134         LOG_E("pwm device register fail.");
135     }
136     return result;
137 }
138 INIT_DEVICE_EXPORT(rt_hw_pwm_init);
139 
140 #endif /* BSP_USING_PWM */
141