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