1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-10-25     KevinXu      first version
9  */
10 
11 #include "drv_pwm.h"
12 
13 #ifdef BSP_USING_PWM
14 
15 /* Declare the control function first */
16 static rt_err_t drv_pwm_control(struct rt_device_pwm *, int, void *);
17 static struct rt_pwm_ops drv_ops =
18 {
19     drv_pwm_control
20 };
21 
22 static struct ra_pwm ra6m4_pwm_obj[BSP_PWMS_NUM] =
23 {
24 #ifdef BSP_USING_PWM0
25     [BSP_PWM0_INDEX] = PWM_DRV_INITIALIZER(0),
26 #endif
27 #ifdef BSP_USING_PWM1
28     [BSP_PWM1_INDEX] = PWM_DRV_INITIALIZER(1),
29 #endif
30 #ifdef BSP_USING_PWM2
31     [BSP_PWM2_INDEX] = PWM_DRV_INITIALIZER(2),
32 #endif
33 #ifdef BSP_USING_PWM3
34     [BSP_PWM3_INDEX] = PWM_DRV_INITIALIZER(3),
35 #endif
36 #ifdef BSP_USING_PWM4
37     [BSP_PWM4_INDEX] = PWM_DRV_INITIALIZER(4),
38 #endif
39 #ifdef BSP_USING_PWM5
40     [BSP_PWM5_INDEX] = PWM_DRV_INITIALIZER(5),
41 #endif
42 #ifdef BSP_USING_PWM6
43     [BSP_PWM6_INDEX] = PWM_DRV_INITIALIZER(6),
44 #endif
45 #ifdef BSP_USING_PWM7
46     [BSP_PWM7_INDEX] = PWM_DRV_INITIALIZER(7),
47 #endif
48 #ifdef BSP_USING_PWM8
49     [BSP_PWM8_INDEX] = PWM_DRV_INITIALIZER(8),
50 #endif
51 #ifdef BSP_USING_PWM9
52     [BSP_PWM9_INDEX] = PWM_DRV_INITIALIZER(9),
53 #endif
54 };
55 
56 #ifdef SOC_SERIES_R9A07G0
57     #define FSP_PRIV_CLOCK  FSP_PRIV_CLOCK_PCLKGPTL
58 #else
59     #define FSP_PRIV_CLOCK  FSP_PRIV_CLOCK_PCLKD
60 #endif
61 
62 /* Convert the raw PWM period counts into ns */
_convert_counts_ns(uint32_t source_div,uint32_t raw)63 static rt_uint32_t _convert_counts_ns(uint32_t source_div, uint32_t raw)
64 {
65     uint32_t pclkd_freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK) >> source_div;
66     uint32_t ns = (uint32_t)(((uint64_t)raw * 1000000000ULL) / pclkd_freq_hz);
67     return ns;
68 }
69 
70 /* Convert ns into raw PWM period counts */
_convert_ns_counts(uint32_t source_div,uint32_t raw)71 static rt_uint32_t _convert_ns_counts(uint32_t source_div, uint32_t raw)
72 {
73     uint32_t pclkd_freq_hz = R_FSP_SystemClockHzGet(FSP_PRIV_CLOCK) >> source_div;
74     uint32_t counts = (uint32_t)(((uint64_t)raw * (uint64_t)pclkd_freq_hz) / 1000000000ULL);
75     return counts;
76 }
77 
78 
79 /* PWM_CMD_ENABLE or PWM_CMD_DISABLE */
drv_pwm_enable(struct ra_pwm * device,struct rt_pwm_configuration * configuration,rt_bool_t enable)80 static rt_err_t drv_pwm_enable(struct ra_pwm *device,
81                                struct rt_pwm_configuration *configuration,
82                                rt_bool_t enable)
83 {
84     fsp_err_t err = FSP_SUCCESS;
85 
86     if (enable)
87     {
88         err = R_GPT_Start(device->g_ctrl);
89     }
90     else
91     {
92         err = R_GPT_Stop(device->g_ctrl);
93     }
94 
95     return (err == FSP_SUCCESS) ? RT_EOK : -RT_ERROR;
96 }
97 
98 /* PWM_CMD_GET */
drv_pwm_get(struct ra_pwm * device,struct rt_pwm_configuration * configuration)99 static rt_err_t drv_pwm_get(struct ra_pwm *device,
100                             struct rt_pwm_configuration *configuration)
101 {
102     timer_info_t info;
103     if (R_GPT_InfoGet(device->g_ctrl, &info) != FSP_SUCCESS)
104         return -RT_ERROR;
105 
106     configuration->pulse =
107         _convert_counts_ns(device->g_cfg->source_div, device->g_cfg->duty_cycle_counts);
108     configuration->period =
109         _convert_counts_ns(device->g_cfg->source_div, info.period_counts);
110     configuration->channel = device->g_cfg->channel;
111 
112     return RT_EOK;
113 }
114 
115 /* PWM_CMD_SET */
drv_pwm_set(struct ra_pwm * device,struct rt_pwm_configuration * conf)116 static rt_err_t drv_pwm_set(struct ra_pwm *device,
117                             struct rt_pwm_configuration *conf)
118 {
119     uint32_t counts;
120     fsp_err_t fsp_erra;
121     fsp_err_t fsp_errb;
122     rt_err_t rt_err;
123     uint32_t pulse;
124     uint32_t period;
125     struct rt_pwm_configuration orig_conf;
126 
127     rt_err = drv_pwm_get(device, &orig_conf);
128     if (rt_err != RT_EOK)
129     {
130         return rt_err;
131     }
132 
133     /* Pulse cannot last longer than period. */
134     period = conf->period;
135     pulse = (period >= conf->pulse) ? conf->pulse : period;
136 
137     /* Not to set period again if it's not changed. */
138     if (period != orig_conf.period)
139     {
140         counts = _convert_ns_counts(device->g_cfg->source_div, period);
141         fsp_erra = R_GPT_PeriodSet(device->g_ctrl, counts);
142         if (fsp_erra != FSP_SUCCESS)
143         {
144             return -RT_ERROR;
145         }
146     }
147 
148     /* Two pins of a channel will not be separated. */
149     counts = _convert_ns_counts(device->g_cfg->source_div, pulse);
150     fsp_erra = R_GPT_DutyCycleSet(device->g_ctrl, counts, GPT_IO_PIN_GTIOCA);
151     fsp_errb = R_GPT_DutyCycleSet(device->g_ctrl, counts, GPT_IO_PIN_GTIOCB);
152     if (fsp_erra != FSP_SUCCESS || fsp_errb != FSP_SUCCESS)
153     {
154         return -RT_ERROR;
155     }
156 
157     return RT_EOK;
158 }
159 
160 /**
161  * Implement of control method in struct rt_pwm_ops.
162  */
drv_pwm_control(struct rt_device_pwm * device,int cmd,void * arg)163 static rt_err_t drv_pwm_control(struct rt_device_pwm *device, int cmd, void *arg)
164 {
165     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)arg;
166     struct ra_pwm *pwm_device = (struct ra_pwm *)device->parent.user_data;
167 
168     /**
169      * There's actually only one GPT timer with 10 channels. In this case, the
170      * timer is separated into 10 PWM devices, so each device has only one
171      * channel.
172      */
173     if (configuration->channel != 0)
174     {
175         return -RT_EINVAL;
176     }
177 
178     switch (cmd)
179     {
180     case PWM_CMD_ENABLE:
181         return drv_pwm_enable(pwm_device, configuration, RT_TRUE);
182     case PWM_CMD_DISABLE:
183         return drv_pwm_enable(pwm_device, configuration, RT_FALSE);
184     case PWM_CMD_GET:
185         return drv_pwm_get(pwm_device, configuration);
186     case PWM_CMD_SET:
187         return drv_pwm_set(pwm_device, configuration);
188     default:
189         return -RT_EINVAL;
190     }
191 
192     return RT_EOK;
193 }
194 
195 /**
196  * This is to register the PWM device
197  *
198  * Note that the PWM driver only supports one fixed pin.
199  */
rt_hw_pwm_init(void)200 int rt_hw_pwm_init(void)
201 {
202     rt_err_t ret = RT_EOK;
203     rt_err_t rt_err = RT_EOK;
204     fsp_err_t fsp_err = FSP_SUCCESS;
205 
206     for (int i = 0; i < BSP_PWMS_NUM; i++)
207     {
208         fsp_err = R_GPT_Open(ra6m4_pwm_obj[i].g_ctrl,
209                              ra6m4_pwm_obj[i].g_cfg);
210 
211         rt_err = rt_device_pwm_register(&ra6m4_pwm_obj[i].pwm_device,
212                                         ra6m4_pwm_obj[i].name,
213                                         &drv_ops,
214                                         &ra6m4_pwm_obj[i]);
215 
216         if (fsp_err != FSP_SUCCESS || rt_err != RT_EOK)
217         {
218             ret = -RT_ERROR;
219         }
220     }
221 
222     return ret;
223 }
224 INIT_BOARD_EXPORT(rt_hw_pwm_init);
225 #endif /* BSP_USING_PWM */
226