1 /*
2  * Copyright (c) 2006-2024 RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2024-12-18     hywing       Initial version.
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "fsl_pwm.h"
14 
15 #ifdef RT_USING_PWM
16 
17 #define BOARD_PWM_BASEADDR      (FLEXPWM0)
18 #define PWM_SRC_CLK_FREQ        (CLOCK_GetFreq(kCLOCK_BusClk))
19 #define FLEX_PWM_CLOCK_DEVIDER  (kPWM_Prescale_Divide_2)
20 #define FLEX_PWM_FAULT_LEVEL    true
21 
22 typedef struct
23 {
24     struct rt_device_pwm pwm_device;
25     pwm_submodule_t submodule;
26     pwm_module_control_t control;
27     pwm_channels_t channel;
28     pwm_clock_prescale_t prescale;
29     char *name;
30 } mcx_pwm_obj_t;
31 
32 static mcx_pwm_obj_t mcx_pwm_list[]=
33 {
34 #ifdef BSP_USING_PWM0
35     {
36         .submodule = kPWM_Module_0,
37         .control = kPWM_Control_Module_0,
38         .channel = kPWM_PwmA,
39         .prescale = FLEX_PWM_CLOCK_DEVIDER,
40         .name = "pwm0",
41     },
42 #endif
43 #ifdef BSP_USING_PWM1
44     {
45         .submodule = kPWM_Module_1,
46         .control = kPWM_Control_Module_1,
47         .channel = kPWM_PwmA,
48         .prescale = FLEX_PWM_CLOCK_DEVIDER,
49         .name = "pwm1",
50     },
51 #endif
52 #ifdef BSP_USING_PWM2
53     {
54         .submodule = kPWM_Module_2,
55         .control = kPWM_Control_Module_2,
56         .channel = kPWM_PwmA,
57         .prescale = FLEX_PWM_CLOCK_DEVIDER,
58         .name = "pwm2",
59     },
60 #endif
61 };
62 
mcx_drv_pwm_get(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)63 static rt_err_t mcx_drv_pwm_get(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
64 {
65     return RT_EOK;
66 }
67 
mcx_drv_pwm_set(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)68 static rt_err_t mcx_drv_pwm_set(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
69 {
70     uint8_t dutyCyclePercent = configuration->pulse * 100 / configuration->period;
71     pwm_signal_param_t pwmSignal[1];
72     uint32_t pwmFrequencyInHz = 1000000000 / configuration->period;
73 
74     pwmSignal[0].pwmChannel       = pwm->channel;
75     pwmSignal[0].level            = kPWM_HighTrue;
76     pwmSignal[0].dutyCyclePercent = dutyCyclePercent;
77     pwmSignal[0].deadtimeValue    = 0;
78     pwmSignal[0].faultState       = kPWM_PwmFaultState0;
79     pwmSignal[0].pwmchannelenable = true;
80 
81     PWM_SetupPwm(BOARD_PWM_BASEADDR, pwm->submodule, pwmSignal, 1, kPWM_SignedCenterAligned, pwmFrequencyInHz, PWM_SRC_CLK_FREQ);
82     PWM_UpdatePwmDutycycle(BOARD_PWM_BASEADDR, pwm->submodule, pwm->channel, kPWM_SignedCenterAligned, dutyCyclePercent);
83     PWM_SetPwmLdok(BOARD_PWM_BASEADDR, pwm->control, true);
84 
85     return 0;
86 }
87 
mcx_drv_pwm_enable(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)88 static rt_err_t mcx_drv_pwm_enable(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
89 {
90     PWM_StartTimer(BOARD_PWM_BASEADDR, pwm->control);
91     return 0;
92 }
93 
mcx_drv_pwm_disable(mcx_pwm_obj_t * pwm,struct rt_pwm_configuration * configuration)94 static rt_err_t mcx_drv_pwm_disable(mcx_pwm_obj_t *pwm, struct rt_pwm_configuration *configuration)
95 {
96     PWM_StopTimer(BOARD_PWM_BASEADDR, pwm->control);
97     return 0;
98 }
99 
mcx_drv_pwm_control(struct rt_device_pwm * device,int cmd,void * args)100 static rt_err_t mcx_drv_pwm_control(struct rt_device_pwm *device, int cmd, void *args)
101 {
102     mcx_pwm_obj_t *pwm = device->parent.user_data;
103     struct rt_pwm_configuration *configuration = (struct rt_pwm_configuration *)args;
104 
105     switch (cmd)
106     {
107     case PWM_CMD_ENABLE:
108         return mcx_drv_pwm_enable(pwm, configuration);
109 
110     case PWM_CMD_DISABLE:
111         return mcx_drv_pwm_disable(pwm, configuration);
112 
113     case PWM_CMD_SET:
114         return mcx_drv_pwm_set(pwm, configuration);
115 
116     case PWM_CMD_GET:
117         return mcx_drv_pwm_get(pwm, configuration);
118 
119     default:
120         return -RT_EINVAL;
121     }
122 
123     return RT_EOK;
124 }
125 
126 static struct rt_pwm_ops mcx_pwm_ops =
127 {
128     .control = mcx_drv_pwm_control,
129 };
130 
mcx_pwm_init(void)131 int mcx_pwm_init(void)
132 {
133     rt_err_t ret;
134     pwm_config_t pwmConfig;
135     pwm_fault_param_t faultConfig;
136     PWM_GetDefaultConfig(&pwmConfig);
137     pwmConfig.prescale = FLEX_PWM_CLOCK_DEVIDER;
138     pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
139 
140     int i;
141     for (i = 0; i < sizeof(mcx_pwm_list) / sizeof(mcx_pwm_list[0]); i++)
142     {
143         pwm_config_t pwmConfig;
144         pwm_fault_param_t faultConfig;
145         PWM_GetDefaultConfig(&pwmConfig);
146         pwmConfig.prescale = mcx_pwm_list[i].prescale;
147         pwmConfig.reloadLogic = kPWM_ReloadPwmFullCycle;
148         if (PWM_Init(BOARD_PWM_BASEADDR, mcx_pwm_list[i].submodule, &pwmConfig) == kStatus_Fail)
149         {
150             rt_kprintf("PWM Init Failed\n");
151         }
152         ret = rt_device_pwm_register(&mcx_pwm_list[i].pwm_device, mcx_pwm_list[i].name, &mcx_pwm_ops, &mcx_pwm_list[i]);
153     }
154 
155     /*
156      *   config->faultClearingMode = kPWM_Automatic;
157      *   config->faultLevel = false;
158      *   config->enableCombinationalPath = true;
159      *   config->recoverMode = kPWM_NoRecovery;
160      */
161     PWM_FaultDefaultConfig(&faultConfig);
162     faultConfig.faultLevel = FLEX_PWM_FAULT_LEVEL;
163 
164     /* Sets up the PWM fault protection */
165     PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_0, &faultConfig);
166     PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_1, &faultConfig);
167     PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_2, &faultConfig);
168     PWM_SetupFaults(BOARD_PWM_BASEADDR, kPWM_Fault_3, &faultConfig);
169 
170     /* Set PWM fault disable mapping for submodule 0/1/2 */
171     PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_0, kPWM_PwmA, kPWM_faultchannel_0,
172                              kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
173     PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_1, kPWM_PwmA, kPWM_faultchannel_0,
174                              kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
175     PWM_SetupFaultDisableMap(BOARD_PWM_BASEADDR, kPWM_Module_2, kPWM_PwmA, kPWM_faultchannel_0,
176                              kPWM_FaultDisable_0 | kPWM_FaultDisable_1 | kPWM_FaultDisable_2 | kPWM_FaultDisable_3);
177 
178 
179     /* Set the load okay bit for all submodules to load registers from their buffer */
180     PWM_SetPwmLdok(BOARD_PWM_BASEADDR, kPWM_Control_Module_0 | kPWM_Control_Module_1 | kPWM_Control_Module_2, true);
181 
182     return ret;
183 }
184 
185 INIT_DEVICE_EXPORT(mcx_pwm_init);
186 
187 #endif /* RT_USING_PWM */
188