1 /* SPDX-License-Identifier: BSD-3-Clause */
2 /*
3 * Copyright (c) 2020-2021 Rockchip Electronics Co., Ltd.
4 */
5
6 #include "hal_base.h"
7
8 #ifdef HAL_PWM_MODULE_ENABLED
9
10 /** @addtogroup RK_HAL_Driver
11 * @{
12 */
13
14 /** @addtogroup PWM
15 * @{
16 */
17
18 /** @defgroup PWM_How_To_Use How To Use
19 * @{
20
21 The PWM HAL driver can be used as follows:
22
23 - Declare a PWM_Handle handle structure, for example:
24 ```
25 PWM_Handle instance;
26 ```
27 - Invoke HAL_PWM_Init() API to initialize base address and clock frequency:
28 - Base register address;
29 - Input clock frequency.
30
31 - Invoke HAL_PWM_SetConfig() API and HAL_PWM_SetEnable() to start/stop:
32 - Use HAL_PWM_SetConfig() to configurate the request mode;
33 - Use HAL_PWM_Enable() to start PWM;
34 - Use HAL_PWM_Disable() to stop PWM.
35
36 - Invoke HAL_PWM_DeInit() if necessary.
37
38 @} */
39
40 /** @defgroup PWM_Private_Definition Private Definition
41 * @{
42 */
43 /********************* Private MACRO Definition ******************************/
44
45 #define PWM_CNT_REG(pPWM, ch) (pPWM->pReg->CHANNELS[ch].CNT)
46 #define PWM_PERIOD_REG(pPWM, ch) (pPWM->pReg->CHANNELS[ch].PERIOD_HPR)
47 #define PWM_DUTY_REG(pPWM, ch) (pPWM->pReg->CHANNELS[ch].DUTY_LPR)
48 #define PWM_CTRL_REG(pPWM, ch) (pPWM->pReg->CHANNELS[ch].CTRL)
49
50 #define PWM_INT_EN(ch) (1 << (ch))
51 #define PWM_PWR_INT_EN(ch) (1 << ((ch) + 4 ))
52
53 #define PWM_DISABLE (0 << PWM_PWM0_CTRL_PWM_EN_SHIFT)
54 #define PWM_ENABLE (1 << PWM_PWM0_CTRL_PWM_EN_SHIFT)
55
56 #define PWM_MODE_SHIFT (1)
57 #define PWM_MODE_MASK (0x3U << PWM_MODE_SHIFT)
58
59 #define PWM_DUTY_POSTIVE (1 << PWM_PWM0_CTRL_DUTY_POL_SHIFT)
60 #define PWM_DUTY_NEGATIVE (0 << PWM_PWM0_CTRL_DUTY_POL_SHIFT)
61 #define PWM_DUTY_MASK (1 << 3)
62
63 #define PWM_INACTIVE_POSTIVE (1 << PWM_PWM0_CTRL_INACTIVE_POL_SHIFT)
64 #define PWM_INACTIVE_NEGATIVE (0 << PWM_PWM0_CTRL_INACTIVE_POL_SHIFT)
65 #define PWM_INACTIVE_MASK (1 << 4)
66
67 #define PWM_OUTPUT_LEFT (0 << PWM_PWM0_CTRL_OUTPUT_MODE_SHIFT)
68 #define PWM_OUTPUT_CENTER (1 << PWM_PWM0_CTRL_OUTPUT_MODE_SHIFT)
69
70 #define PWM_UNLOCK (0 << PWM_PWM0_CTRL_CONLOCK_SHIFT)
71 #define PWM_LOCK (1 << PWM_PWM0_CTRL_CONLOCK_SHIFT)
72
73 #define PWM_LP_DISABLE (0 << PWM_PWM0_CTRL_FORCE_CLK_EN_SHIFT)
74 #define PWM_LP_ENABLE (1 << PWM_PWM0_CTRL_FORCE_CLK_EN_SHIFT)
75
76 #define PWM_SEL_SRC_CLK (0 << PWM_PWM0_CTRL_CLK_SEL_SHIFT)
77 #define PWM_SEL_SCALE_CLK (1 << PWM_PWM0_CTRL_CLK_SEL_SHIFT)
78
79 #define PWM_CTRL_SCALE_SHIFT (PWM_PWM0_CTRL_SCALE_SHIFT)
80 #define PWM_CTRL_SCALE_MASK (PWM_PWM0_CTRL_SCALE_MASK)
81
82 #define PWM_PWRMATCH_MAX_SHIFT (PWM_PWRMATCH_LPRE_CNT_MIN_SHIFT)
83
84 /********************* Private Structure Definition **************************/
85
86 /********************* Private Variable Definition ***************************/
87
88 /********************* Private Function Definition ***************************/
89
90 /** @} */
91 /********************* Public Function Definition ****************************/
92
93 /** @defgroup PWM_Exported_Functions_Group3 IO Functions
94
95 This section provides functions allowing to IO controlling:
96
97 * @{
98 */
99
100 /**
101 * @brief Handle PWM interrupt for capture/oneshot mode.
102 * @param pPWM: pointer to a PWM_HANDLE structure that contains
103 * the information for PWM module.
104 * @retval HAL status
105 */
HAL_PWM_IRQHandler(struct PWM_HANDLE * pPWM)106 HAL_Status HAL_PWM_IRQHandler(struct PWM_HANDLE *pPWM)
107 {
108 uint32_t status = READ_REG(pPWM->pReg->INTSTS);
109 uint32_t i;
110
111 /* clean ipd */
112 WRITE_REG(pPWM->pReg->INTSTS, status & 0xf);
113
114 if (status & 0xf) {
115 for (i = 0; i < HAL_PWM_NUM_CHANNELS; i++) {
116 if ((status & (1 << i)) &&
117 (pPWM->mode[i] == HAL_PWM_CAPTURE)) {
118 pPWM->result[i].active = true;
119 pPWM->result[i].pol = status & (1 << (i + 8));
120 if (pPWM->result[i].pol) {
121 pPWM->result[i].period = READ_REG(PWM_PERIOD_REG(pPWM, i));
122 } else {
123 pPWM->result[i].period = READ_REG(PWM_DUTY_REG(pPWM, i));
124 }
125 }
126 }
127 }
128
129 return HAL_OK;
130 }
131
132 /**
133 * @brief Configurate PWM mode.
134 * @param pPWM: pointer to a PWM_HANDLE structure that contains
135 * the information for PWM module.
136 * @param channel: PWM channle(0~3).
137 * @param config: Configuration for PWM.
138 * @retval HAL status
139 */
HAL_PWM_SetConfig(struct PWM_HANDLE * pPWM,uint8_t channel,const struct HAL_PWM_CONFIG * config)140 HAL_Status HAL_PWM_SetConfig(struct PWM_HANDLE *pPWM, uint8_t channel,
141 const struct HAL_PWM_CONFIG *config)
142 {
143 unsigned long period, duty;
144 uint32_t ctrl;
145
146 HAL_ASSERT(pPWM != NULL);
147 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
148 HAL_ASSERT(config != NULL);
149 HAL_DBG("channel=%d, period_ns=%ld, duty_ns=%ld\n",
150 channel, config->periodNS, config->dutyNS);
151
152 period = HAL_DivU64((uint64_t)pPWM->freq * config->periodNS, 1000000000);
153 duty = HAL_DivU64((uint64_t)pPWM->freq * config->dutyNS, 1000000000);
154
155 ctrl = READ_REG(PWM_CTRL_REG(pPWM, channel));
156 ctrl |= PWM_LOCK;
157 WRITE_REG(PWM_CTRL_REG(pPWM, channel), ctrl);
158
159 WRITE_REG(PWM_PERIOD_REG(pPWM, channel), period);
160 WRITE_REG(PWM_DUTY_REG(pPWM, channel), duty);
161
162 ctrl &= ~(PWM_DUTY_MASK | PWM_INACTIVE_MASK);
163 if (config->polarity) {
164 ctrl |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSTIVE;
165 } else {
166 ctrl |= PWM_DUTY_POSTIVE | PWM_INACTIVE_NEGATIVE;
167 }
168
169 ctrl &= ~PWM_LOCK;
170 WRITE_REG(PWM_CTRL_REG(pPWM, channel), ctrl);
171
172 HAL_DBG("channel=%d, period=%lu, duty=%lu, polarity=%d\n",
173 channel, period, duty, config->polarity);
174
175 return HAL_OK;
176 }
177
178 /**
179 * @brief Configurate PWM oneshot count.
180 * @param pPWM: pointer to a PWM_HANDLE structure that contains
181 * the information for PWM module.
182 * @param channel: PWM channle(0~3).
183 * @param count: (count + 1)repeated effective periods of output waveform
184 * @retval HAL status
185 */
HAL_PWM_SetOneshot(struct PWM_HANDLE * pPWM,uint8_t channel,uint32_t count)186 HAL_Status HAL_PWM_SetOneshot(struct PWM_HANDLE *pPWM, uint8_t channel, uint32_t count)
187 {
188 uint32_t ctrl;
189
190 HAL_ASSERT(pPWM != NULL);
191 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
192 HAL_DBG("Oneshot count=%ld\n", count);
193
194 ctrl = READ_REG(PWM_CTRL_REG(pPWM, channel));
195 ctrl |= (count << PWM_PWM0_CTRL_RPT_SHIFT) & PWM_PWM0_CTRL_RPT_MASK;
196 WRITE_REG(PWM_CTRL_REG(pPWM, channel), ctrl);
197
198 return HAL_OK;
199 }
200
201 /**
202 * @brief Configurate PWM captured frequency.
203 * @param pPWM: pointer to a PWM_HANDLE structure that contains
204 * the information for PWM module.
205 * @param channel: PWM channle(0~3).
206 * @param freq: PWM use the frequency to capture data
207 * @retval HAL status
208 */
HAL_PWM_SetCapturedFreq(struct PWM_HANDLE * pPWM,uint8_t channel,uint32_t freq)209 HAL_Status HAL_PWM_SetCapturedFreq(struct PWM_HANDLE *pPWM, uint8_t channel, uint32_t freq)
210 {
211 uint32_t ctrl;
212
213 HAL_ASSERT(pPWM != NULL);
214 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
215 HAL_ASSERT(freq != 0);
216 HAL_DBG("Captured freq=%ld\n", freq);
217
218 ctrl = READ_REG(PWM_CTRL_REG(pPWM, channel));
219 ctrl &= ~PWM_CTRL_SCALE_MASK;
220 ctrl |= PWM_LP_ENABLE | PWM_SEL_SCALE_CLK;
221 ctrl |= ((pPWM->freq / (2 * freq)) << PWM_CTRL_SCALE_SHIFT) & PWM_CTRL_SCALE_MASK;
222 WRITE_REG(PWM_CTRL_REG(pPWM, channel), ctrl);
223
224 return HAL_OK;
225 }
226
227 /**
228 * @brief Configurate PWM matched setting.
229 * @param pPWM: pointer to a PWM_HANDLE structure that contains
230 * the information for PWM module.
231 * @param channel: PWM channle(0~3).
232 * @param data: matching configuration.
233 * @retval HAL status
234 */
HAL_PWM_SetMatch(struct PWM_HANDLE * pPWM,uint8_t channel,const struct PWM_MATCH * data)235 HAL_Status HAL_PWM_SetMatch(struct PWM_HANDLE *pPWM, uint8_t channel, const struct PWM_MATCH *data)
236 {
237 uint8_t i;
238
239 HAL_ASSERT(pPWM != NULL);
240 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
241 HAL_ASSERT(data != NULL);
242 HAL_ASSERT(data->matchCount <= PWM_PWRMATCH_MAX_COUNT);
243
244 /* preloader low */
245 WRITE_REG(pPWM->pReg->PWRMATCH_LPRE, data->lpreMin | (data->lpreMax << PWM_PWRMATCH_MAX_SHIFT));
246 /* preloader high */
247 WRITE_REG(pPWM->pReg->PWRMATCH_HPRE, data->hpreMin | (data->hpreMax << PWM_PWRMATCH_MAX_SHIFT));
248 /* logic 0/1 low */
249 WRITE_REG(pPWM->pReg->PWRMATCH_LD, data->ldMin | (data->ldMax << PWM_PWRMATCH_MAX_SHIFT));
250 /* logic 0 high */
251 WRITE_REG(pPWM->pReg->PWRMATCH_HD_ZERO, data->hdZeroMin | (data->hdZeroMax << PWM_PWRMATCH_MAX_SHIFT));
252 /* logic 1 high */
253 WRITE_REG(pPWM->pReg->PWRMATCH_HD_ONE, data->hdOneMin | (data->hdOneMax << PWM_PWRMATCH_MAX_SHIFT));
254
255 for (i = 0; i < data->matchCount; i++) {
256 WRITE_REG(pPWM->pReg->PWRMATCH_VALUE[i], data->match[i]);
257 }
258
259 /* Enable pwr irq */
260 SET_BIT(pPWM->pReg->INT_EN, PWM_PWR_INT_EN(channel));
261 /* Enable pwr */
262 SET_BIT(pPWM->pReg->PWRMATCH_CTRL, channel);
263
264 return HAL_OK;
265 }
266
267 /**
268 * @brief Get PWM mode.
269 * @param pPWM: pointer to a PWM_HANDLE structure that contains
270 * the information for PWM module.
271 * @param channel: PWM channle(0~3).
272 * @retval ePWM_Mode
273 */
HAL_PWM_GetMode(struct PWM_HANDLE * pPWM,uint8_t channel)274 ePWM_Mode HAL_PWM_GetMode(struct PWM_HANDLE *pPWM, uint8_t channel)
275 {
276 uint32_t ctrl;
277
278 HAL_ASSERT(pPWM != NULL);
279 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
280 HAL_DBG("channel=%d\n", channel);
281
282 ctrl = READ_REG(PWM_CTRL_REG(pPWM, channel));
283
284 return (ePWM_Mode)((ctrl >> PWM_MODE_SHIFT) & PWM_MODE_MASK);
285 }
286
287 /**
288 * @brief Enable PWM.
289 * @param pPWM: pointer to a PWM_HANDLE structure that contains
290 * the information for PWM module.
291 * @param channel: PWM channle(0~3).
292 * @param mode: Current mode on for PWM.
293 * @retval HAL status
294 */
HAL_PWM_Enable(struct PWM_HANDLE * pPWM,uint8_t channel,ePWM_Mode mode)295 HAL_Status HAL_PWM_Enable(struct PWM_HANDLE *pPWM, uint8_t channel, ePWM_Mode mode)
296 {
297 uint32_t enableConf, intEnable;
298
299 HAL_ASSERT(pPWM != NULL);
300 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
301 HAL_DBG("Enable channel=%d\n", channel);
302
303 pPWM->mode[channel] = mode;
304 if (pPWM->mode[channel] != HAL_PWM_CONTINUOUS) {
305 intEnable = READ_REG(pPWM->pReg->INT_EN);
306 /* Enable irq */
307 intEnable |= PWM_INT_EN(channel);
308 WRITE_REG(pPWM->pReg->INT_EN, intEnable);
309 }
310
311 enableConf = READ_REG(PWM_CTRL_REG(pPWM, channel));
312 /* clean mode */
313 enableConf &= ~PWM_MODE_MASK;
314 enableConf |= (mode << PWM_MODE_SHIFT) | PWM_OUTPUT_LEFT | PWM_LP_DISABLE | PWM_ENABLE;
315 WRITE_REG(PWM_CTRL_REG(pPWM, channel), enableConf);
316
317 return HAL_OK;
318 }
319
320 /**
321 * @brief Disable PWM.
322 * @param pPWM: pointer to a PWM_HANDLE structure that contains
323 * the information for PWM module.
324 * @param channel: PWM channle(0~3).
325 * @retval HAL status
326 */
HAL_PWM_Disable(struct PWM_HANDLE * pPWM,uint8_t channel)327 HAL_Status HAL_PWM_Disable(struct PWM_HANDLE *pPWM, uint8_t channel)
328 {
329 uint32_t ctrl, intEnable;
330
331 HAL_ASSERT(pPWM != NULL);
332 HAL_ASSERT(channel < HAL_PWM_NUM_CHANNELS);
333 HAL_DBG("Disable channel=%d\n", channel);
334
335 if (pPWM->mode[channel] != HAL_PWM_CONTINUOUS) {
336 intEnable = READ_REG(pPWM->pReg->INT_EN);
337 /* Disable irq */
338 intEnable &= ~PWM_INT_EN(channel);
339 WRITE_REG(pPWM->pReg->INT_EN, intEnable);
340 }
341
342 ctrl = READ_REG(PWM_CTRL_REG(pPWM, channel));
343 ctrl &= ~PWM_ENABLE;
344 WRITE_REG(PWM_CTRL_REG(pPWM, channel), ctrl);
345
346 return HAL_OK;
347 }
348
349 /** @} */
350
351 /** @defgroup PWM_Exported_Functions_Group4 Init and DeInit Functions
352
353 This section provides functions allowing to init and deinit the module:
354
355 * @{
356 */
357
358 /**
359 * @brief Initialize the PWM according to the specified parameters.
360 * @param pPWM: pointer to a PWM_HANDLE structure that contains
361 * the information for PWM module.
362 * @param pReg: PWM controller register base address.
363 * @param freq: PWM bus input clock frequency.
364 * @return HAL_Status
365 */
HAL_PWM_Init(struct PWM_HANDLE * pPWM,struct PWM_REG * pReg,uint32_t freq)366 HAL_Status HAL_PWM_Init(struct PWM_HANDLE *pPWM, struct PWM_REG *pReg, uint32_t freq)
367 {
368 HAL_ASSERT(pPWM != NULL);
369
370 pPWM->pReg = pReg;
371 HAL_ASSERT(IS_PWM_INSTANCE(pPWM->pReg));
372
373 pPWM->freq = freq;
374
375 return HAL_OK;
376 }
377
378 /**
379 * @brief De Initialize the PWM peripheral.
380 * @param pPWM: pointer to a PWM_HANDLE structure that contains
381 * the information for PWM module.
382 * @return HAL status
383 */
HAL_PWM_DeInit(struct PWM_HANDLE * pPWM)384 HAL_Status HAL_PWM_DeInit(struct PWM_HANDLE *pPWM)
385 {
386 /* ...to do */
387 return HAL_OK;
388 }
389
390 /** @} */
391
392 /** @} */
393
394 /** @} */
395
396 #endif /* HAL_PWM_MODULE_ENABLED */
397