1 /*
2 * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdint.h>
9
10 #include <device_mec5.h>
11 #include "mec_pcfg.h"
12 #include "mec_defs.h"
13 #include "mec_bbled_api.h"
14 #include "mec_ecia_api.h"
15 #include "mec_pcr_api.h"
16 #include "mec_retval.h"
17
18 #define MEC_BBLED_FAST_ADDR_LOOKUP
19 #define MEC_BBLED_ADDR_SPACING 0x100u
20
21 #define MEC_BBLED_CLK_FREQ 32768u
22 #define MEC_BBLED_SYS_CLK_FREQ 48000000u
23
24 #define MEC_BBLED_GIRQ 17
25
26 #define MEC_BBLED0_GIRQ_POS 13
27 #define MEC_BBLED1_GIRQ_POS 14
28 #define MEC_BBLED2_GIRQ_POS 15
29 #define MEC_BBLED3_GIRQ_POS 16
30
31 #define MEC_BBLED0_ECIA_INFO MEC5_ECIA_INFO(23, 0, 14, 136)
32 #define MEC_BBLED1_ECIA_INFO MEC5_ECIA_INFO(23, 1, 14, 137)
33 #define MEC_BBLED2_ECIA_INFO MEC5_ECIA_INFO(23, 2, 14, 138)
34 #define MEC_BBLED3_ECIA_INFO MEC5_ECIA_INFO(23, 3, 14, 139)
35
36 struct mec_bbled_info {
37 uintptr_t base_addr;
38 uint16_t pcr_id;
39 uint32_t devi;
40 };
41
42 static const struct mec_bbled_info bbled_instances[MEC5_BBLED_INSTANCES] = {
43 { MEC_BBLED0_BASE, MEC_PCR_BBLED0, MEC_BBLED0_ECIA_INFO },
44 { MEC_BBLED1_BASE, MEC_PCR_BBLED1, MEC_BBLED1_ECIA_INFO },
45 { MEC_BBLED2_BASE, MEC_PCR_BBLED2, MEC_BBLED2_ECIA_INFO },
46 { MEC_BBLED3_BASE, MEC_PCR_BBLED3, MEC_BBLED3_ECIA_INFO },
47 };
48
49 #ifdef MEC_BBLED_FAST_ADDR_LOOKUP
bbled_fast_idx(uintptr_t base)50 static inline uint32_t bbled_fast_idx(uintptr_t base)
51 {
52 return (((uint32_t)base >> 8) & 0x3u);
53 }
54
find_bbled_info(uintptr_t base_addr)55 static struct mec_bbled_info const *find_bbled_info(uintptr_t base_addr)
56 {
57 return &bbled_instances[bbled_fast_idx(base_addr)];
58 }
59 #else
find_bbled_info(uintptr_t base_addr)60 static struct mec_bbled_info const *find_bbled_info(uintptr_t base_addr)
61 {
62 for (size_t i = 0; i < MEC5_BBLED_INSTANCES; i++) {
63 if (base_addr == bbled_instances[i].base_addr) {
64 return &bbled_instances[i];
65 }
66 }
67
68 return NULL;
69 }
70 #endif /* MEC_BBLED_FAST_ADDR_LOOKUP */
71
find_bbled_index(uintptr_t base_addr)72 static int find_bbled_index(uintptr_t base_addr)
73 {
74 for (int i = 0; i < (int)MEC5_BBLED_INSTANCES; i++) {
75 if (base_addr == bbled_instances[i].base_addr) {
76 return i;
77 }
78 }
79
80 return -1;
81 }
82
bbled_get_pwm_size(struct mec_bbled_regs * regs)83 static uint8_t bbled_get_pwm_size(struct mec_bbled_regs *regs)
84 {
85 return (uint8_t)((regs->CONFIG & MEC_BBLED_CONFIG_PWM_SZ_Msk) >> MEC_BBLED_CONFIG_PWM_SZ_Pos);
86 }
87
bbled_set_pwm_size(struct mec_bbled_regs * regs,uint8_t pwm_width)88 static void bbled_set_pwm_size(struct mec_bbled_regs *regs, uint8_t pwm_width)
89 {
90 regs->CONFIG = (regs->CONFIG & (uint32_t)~MEC_BBLED_CONFIG_PWM_SZ_Msk) |
91 (((uint32_t)pwm_width << MEC_BBLED_CONFIG_PWM_SZ_Pos) & MEC_BBLED_CONFIG_PWM_SZ_Msk);
92 }
93
bbled_set_clk_src(struct mec_bbled_regs * regs,uint8_t use_sys_clk)94 static void bbled_set_clk_src(struct mec_bbled_regs *regs, uint8_t use_sys_clk)
95 {
96 if (use_sys_clk) {
97 regs->CONFIG |= MEC_BIT(MEC_BBLED_CONFIG_CLKSRC_Pos);
98 } else {
99 regs->CONFIG &= (uint32_t)~MEC_BIT(MEC_BBLED_CONFIG_CLKSRC_Pos);
100 }
101 }
102
bbled_set_wdt_reload(struct mec_bbled_regs * regs,uint32_t bbcfg)103 static void bbled_set_wdt_reload(struct mec_bbled_regs *regs, uint32_t bbcfg)
104 {
105 uint32_t temp = (bbcfg & MEC_BBLED_CFG_WDT_RELOAD_MSK) >> MEC_BBLED_CFG_WDT_RELOAD_POS;
106
107 regs->CONFIG = ((regs->CONFIG & (uint32_t)~MEC_BBLED_CONFIG_WDTRLD_Msk) |
108 ((temp << MEC_BBLED_CONFIG_WDTRLD_Pos) & MEC_BBLED_CONFIG_WDTRLD_Msk));
109 }
110
bbled_set_mode(struct mec_bbled_regs * regs,uint8_t mode)111 static void bbled_set_mode(struct mec_bbled_regs *regs, uint8_t mode)
112 {
113 regs->CONFIG = ((regs->CONFIG & (uint32_t)~MEC_BBLED_CONFIG_CTRL_Msk) |
114 (((uint32_t)mode << MEC_BBLED_CONFIG_CTRL_Pos) & MEC_BBLED_CONFIG_CTRL_Msk));
115 }
116
bbled_get_mode(struct mec_bbled_regs * regs)117 static uint8_t bbled_get_mode(struct mec_bbled_regs *regs)
118 {
119 return (uint8_t)((regs->CONFIG & MEC_BBLED_CONFIG_CTRL_Msk) >> MEC_BBLED_CONFIG_CTRL_Pos);
120 }
121
122 /* ---- Public API ---- */
123
mec_hal_bbled_is_valid(struct mec_bbled_regs * regs)124 bool mec_hal_bbled_is_valid(struct mec_bbled_regs *regs)
125 {
126 if (find_bbled_index((uintptr_t)regs) < 0) {
127 return false;
128 }
129
130 return true;
131 }
132
mec_hal_bbled_synchronize_enable(struct mec_bbled_regs * regs,uint8_t enable)133 void mec_hal_bbled_synchronize_enable(struct mec_bbled_regs *regs, uint8_t enable)
134 {
135 if (enable) {
136 regs->CONFIG |= MEC_BIT(MEC_BBLED_CONFIG_SYNC_Pos);
137 } else {
138 regs->CONFIG &= (uint32_t)~MEC_BIT(MEC_BBLED_CONFIG_SYNC_Pos);
139 }
140 }
141
mec_hal_bbled_is_off(struct mec_bbled_regs * regs)142 bool mec_hal_bbled_is_off(struct mec_bbled_regs *regs)
143 {
144 if (regs->CONFIG & MEC_BBLED_CONFIG_CTRL_Msk) {
145 return false;
146 }
147
148 return true;
149 }
150
mec_hal_bbled_asym_enable(struct mec_bbled_regs * regs,uint8_t enable)151 void mec_hal_bbled_asym_enable(struct mec_bbled_regs *regs, uint8_t enable)
152 {
153 if (enable) {
154 regs->CONFIG |= MEC_BIT(MEC_BBLED_CONFIG_ASYM_Pos);
155 } else {
156 regs->CONFIG &= (uint32_t)~MEC_BIT(MEC_BBLED_CONFIG_ASYM_Pos);
157 }
158 }
159
160 /* Initialize a BBLED instance and leave it in OFF mode */
mec_hal_bbled_init(struct mec_bbled_regs * regs,uint32_t bbled_config)161 int mec_hal_bbled_init(struct mec_bbled_regs *regs, uint32_t bbled_config)
162 {
163 const struct mec_bbled_info *info = find_bbled_info((uintptr_t)regs);
164 uint8_t asym_enable = 0;
165
166 if (!info) {
167 return MEC_RET_ERR_INVAL;
168 }
169
170 mec_hal_girq_ctrl(info->devi, 0);
171 mec_hal_pcr_clr_blk_slp_en(info->pcr_id);
172
173 if (bbled_config & MEC_BIT(MEC_BBLED_CFG_SOFT_RESET_POS)) {
174 regs->CONFIG |= MEC_BIT(MEC_BBLED_CONFIG_SRST_Pos);
175 } else {
176 regs->CONFIG &= (uint32_t)~MEC_BBLED_CONFIG_CTRL_Msk;
177 regs->CONFIG |= (MEC_BBLED_CONFIG_CTRL_OFF << MEC_BBLED_CONFIG_CTRL_Pos);
178 }
179
180 mec_hal_girq_clr_src(info->devi);
181
182 if (bbled_config & MEC_BIT(MEC_BBLED_CFG_SET_WDT_RLD_POS)) {
183 bbled_set_wdt_reload(regs, bbled_config);
184 }
185
186 if (bbled_config & MEC_BIT(MEC_BBLED_CFG_WDT_ASYM_EN_POS)) {
187 asym_enable = 1;
188 }
189
190 mec_hal_bbled_asym_enable(regs, asym_enable);
191
192 return 0;
193 }
194
mec_hal_bbled_girq_ctrl(struct mec_bbled_regs * regs,uint8_t enable)195 int mec_hal_bbled_girq_ctrl(struct mec_bbled_regs *regs, uint8_t enable)
196 {
197 const struct mec_bbled_info *info = find_bbled_info((uintptr_t)regs);
198
199 if (!info) {
200 return MEC_RET_ERR_INVAL;
201 }
202
203 mec_hal_girq_ctrl(info->devi, enable);
204
205 return MEC_RET_OK;
206 }
207
mec_hal_bbled_girq_status_clr(struct mec_bbled_regs * regs)208 int mec_hal_bbled_girq_status_clr(struct mec_bbled_regs *regs)
209 {
210 const struct mec_bbled_info *info = find_bbled_info((uintptr_t)regs);
211
212 if (!info) {
213 return MEC_RET_ERR_INVAL;
214 }
215
216 mec_hal_girq_clr_src(info->devi);
217
218 return MEC_RET_OK;
219 }
220
mec_hal_bbled_enable_update(struct mec_bbled_regs * regs)221 void mec_hal_bbled_enable_update(struct mec_bbled_regs *regs)
222 {
223 regs->CONFIG |= MEC_BIT(MEC_BBLED_CONFIG_UPDATE_Pos);
224 }
225
mec_hal_bbled_enable_is_update(struct mec_bbled_regs * regs)226 bool mec_hal_bbled_enable_is_update(struct mec_bbled_regs *regs)
227 {
228 if (regs->CONFIG & MEC_BIT(MEC_BBLED_CONFIG_UPDATE_Pos)) {
229 return true;
230 }
231
232 return false;
233 }
234
mec_hal_bbled_clk_freq(struct mec_bbled_regs * regs)235 uint32_t mec_hal_bbled_clk_freq(struct mec_bbled_regs *regs)
236 {
237 if (regs->CONFIG & MEC_BIT(MEC_BBLED_CONFIG_CLKSRC_Pos)) {
238 return (uint32_t)MEC_BBLED_SYS_CLK_FREQ;
239 }
240 return (uint32_t)MEC_BBLED_CLK_FREQ;
241 }
242
mec_hal_bbled_breathe_pwm_width(struct mec_bbled_regs * regs,uint8_t pwm_width)243 int mec_hal_bbled_breathe_pwm_width(struct mec_bbled_regs *regs, uint8_t pwm_width)
244 {
245 uint8_t mode = 0;
246
247 if (!regs || (pwm_width > MEC_BBLED_PWM_WIDTH_6)) {
248 return MEC_RET_ERR_INVAL;
249 }
250
251 mode = bbled_get_mode(regs);
252 if ((mode == MEC_BBLED_MODE_BREATHE) || (mode == MEC_BBLED_MODE_BLINK)) {
253 return MEC_RET_ERR_BUSY;
254 }
255
256 bbled_set_pwm_size(regs, pwm_width);
257
258 return MEC_RET_OK;
259 }
260
mec_hal_bbled_breathe_pwm_width_get(struct mec_bbled_regs * regs)261 uint8_t mec_hal_bbled_breathe_pwm_width_get(struct mec_bbled_regs *regs)
262 {
263 return bbled_get_pwm_size(regs);
264 }
265
mec_hal_bbled_blink_clk_sel(struct mec_bbled_regs * regs,uint8_t blink_clk_sel)266 int mec_hal_bbled_blink_clk_sel(struct mec_bbled_regs *regs, uint8_t blink_clk_sel)
267 {
268 uint8_t use_sys_clk = 0;
269
270 if (!regs) {
271 return MEC_RET_ERR_INVAL;
272 }
273
274 if (blink_clk_sel != (uint8_t)MEC_BBLED_BLINK_CLK_SEL_32K) {
275 use_sys_clk = 1;
276 }
277
278 bbled_set_clk_src(regs, use_sys_clk);
279
280 return MEC_RET_OK;
281 }
282
mec_hal_bbled_blink_clk_sel_get(struct mec_bbled_regs * regs)283 uint8_t mec_hal_bbled_blink_clk_sel_get(struct mec_bbled_regs *regs)
284 {
285 uint8_t clksel = (uint8_t)MEC_BBLED_BLINK_CLK_SEL_32K;
286
287 if (regs->CONFIG & MEC_BIT(MEC_BBLED_CONFIG_CLKSRC_Pos)) {
288 clksel = (uint8_t)MEC_BBLED_BLINK_CLK_SEL_SYS;
289 }
290
291 return clksel;
292 }
293
mec_hal_bbled_blink_pwm_freq_get(struct mec_bbled_regs * regs)294 uint32_t mec_hal_bbled_blink_pwm_freq_get(struct mec_bbled_regs *regs)
295 {
296 uint32_t fsrc = mec_hal_bbled_clk_freq(regs);
297 uint32_t prescaler = (regs->DELAY & MEC_BBLED_DELAY_LO_Msk) >> MEC_BBLED_DELAY_LO_Pos;
298 uint32_t fpwm = 0;
299
300 prescaler = (prescaler + 1) << 8;
301 if (!prescaler) {
302 return 0;
303 }
304
305 fpwm = fsrc / prescaler;
306 if ((fsrc % prescaler) > (prescaler >> 1)) {
307 fpwm++;
308 }
309
310 return fpwm;
311 }
312
mec_hal_bbled_mode(struct mec_bbled_regs * regs,uint8_t mode)313 int mec_hal_bbled_mode(struct mec_bbled_regs *regs, uint8_t mode)
314 {
315 if (!regs || (mode > MEC_BBLED_MODE_ON)) {
316 return MEC_RET_ERR_INVAL;
317 }
318
319 bbled_set_mode(regs, mode);
320
321 return MEC_RET_OK;
322 }
323
mec_hal_bbled_mode_get(struct mec_bbled_regs * regs)324 uint8_t mec_hal_bbled_mode_get(struct mec_bbled_regs *regs)
325 {
326 return bbled_get_mode(regs);
327 }
328
mec_hal_bbled_breathe_config(struct mec_bbled_regs * regs,struct mec_bbled_breathe_config * br_cfg)329 int mec_hal_bbled_breathe_config(struct mec_bbled_regs *regs, struct mec_bbled_breathe_config *br_cfg)
330 {
331 uint32_t temp = 0;
332 uint8_t mode = 0;
333
334 if (!regs || !br_cfg) {
335 return MEC_RET_ERR_INVAL;
336 }
337
338 mode = bbled_get_mode(regs);
339 if (mode == MEC_BBLED_MODE_BLINK) {
340 return MEC_RET_ERR_INVAL;
341 }
342
343 temp = (((uint32_t)br_cfg->min_hold << MEC_BBLED_LIMITS_MIN_Pos) & MEC_BBLED_LIMITS_MIN_Msk);
344 temp |= (((uint32_t)br_cfg->max_hold << MEC_BBLED_LIMITS_MAX_Pos) & MEC_BBLED_LIMITS_MAX_Msk);
345 regs->LIMITS = temp;
346
347 temp = ((uint32_t)br_cfg->lo_delay << MEC_BBLED_DELAY_LO_Pos) & MEC_BBLED_DELAY_LO_Msk;
348 temp |= (((uint32_t)br_cfg->hi_delay << MEC_BBLED_DELAY_HI_Pos) & MEC_BBLED_DELAY_HI_Msk);
349 regs->DELAY = temp;
350
351 regs->UPDSS = br_cfg->upd_steps;
352 regs->UPINVL = br_cfg->upd_intervals;
353
354 return MEC_RET_OK;
355 }
356
mec_hal_bbled_breathe_config_get(struct mec_bbled_regs * regs,struct mec_bbled_breathe_config * br_cfg)357 int mec_hal_bbled_breathe_config_get(struct mec_bbled_regs *regs,
358 struct mec_bbled_breathe_config *br_cfg)
359 {
360 uint32_t temp = 0;
361
362 if (!regs || !br_cfg) {
363 return MEC_RET_ERR_INVAL;
364 }
365
366 br_cfg->upd_intervals = regs->UPINVL;
367 br_cfg->upd_steps = regs->UPDSS;
368
369 temp = regs->DELAY;
370 br_cfg->lo_delay = (uint16_t)((temp & MEC_BBLED_DELAY_LO_Msk) >> MEC_BBLED_DELAY_LO_Pos);
371 br_cfg->hi_delay = (uint16_t)((temp & MEC_BBLED_DELAY_HI_Msk) >> MEC_BBLED_DELAY_HI_Pos);
372
373 temp = regs->LIMITS;
374 br_cfg->min_hold = (uint8_t)((temp & MEC_BBLED_LIMITS_MIN_Msk) >> MEC_BBLED_LIMITS_MIN_Pos);
375 br_cfg->max_hold = (uint8_t)((temp & MEC_BBLED_LIMITS_MAX_Msk) >> MEC_BBLED_LIMITS_MAX_Pos);
376
377 br_cfg->pwm_width = bbled_get_pwm_size(regs);
378
379 return MEC_RET_OK;
380 }
381
mec_hal_bbled_blink_config(struct mec_bbled_regs * regs,struct mec_bbled_blink_config * bl_cfg)382 int mec_hal_bbled_blink_config(struct mec_bbled_regs *regs, struct mec_bbled_blink_config *bl_cfg)
383 {
384 uint8_t mode = 0;
385
386 if (!regs || !bl_cfg) {
387 return MEC_RET_ERR_INVAL;
388 }
389
390 mode = bbled_get_mode(regs);
391 if (mode == MEC_BBLED_MODE_BREATHE) {
392 return MEC_RET_ERR_INVAL;
393 }
394
395 regs->LIMITS =
396 ((uint32_t)bl_cfg->duty_cycle << MEC_BBLED_LIMITS_MIN_Pos) & MEC_BBLED_LIMITS_MIN_Msk;
397 regs->DELAY =
398 ((uint32_t)bl_cfg->pwm_clk_prescaler << MEC_BBLED_DELAY_LO_Pos) & MEC_BBLED_DELAY_LO_Msk;
399
400 return MEC_RET_OK;
401 }
402
mec_hal_bbled_blink_config_get(struct mec_bbled_regs * regs,struct mec_bbled_blink_config * bl_cfg)403 int mec_hal_bbled_blink_config_get(struct mec_bbled_regs *regs, struct mec_bbled_blink_config *bl_cfg)
404 {
405 if (!regs || !bl_cfg) {
406 return MEC_RET_ERR_INVAL;
407 }
408
409 bl_cfg->pwm_clk_prescaler =
410 (uint16_t)((regs->DELAY & MEC_BBLED_DELAY_LO_Msk) >> MEC_BBLED_DELAY_LO_Pos);
411 bl_cfg->duty_cycle =
412 (uint8_t)((regs->LIMITS & MEC_BBLED_LIMITS_MIN_Msk) >> MEC_BBLED_LIMITS_MIN_Pos);
413 bl_cfg->flags = MEC_BBLED_BLINK_PWM_FREQ_32K;
414 if (regs->CONFIG & MEC_BIT(MEC_BBLED_CONFIG_CLKSRC_Pos)) {
415 bl_cfg->flags = MEC_BBLED_BLINK_PWM_FREQ_SYS;
416 }
417
418 return MEC_RET_OK;
419 }
420
421 /* end mec_bbled.c */
422