1 /*
2  * Copyright 2024 Microchip Technology Inc. and its subsidiaries.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include <stddef.h>
7 #include <stdint.h>
8 #include <stdbool.h>
9 
10 #include <device_mec5.h>
11 #include "mec_pcfg.h"
12 #include "mec_defs.h"
13 #include "mec_ecia_api.h"
14 #include "mec_pcr_api.h"
15 #include "mec_tach_api.h"
16 #include "mec_retval.h"
17 
18 #if MEC5_TACH_INSTANCES > 0
19 
20 #define MEC_TACH0_ECIA_INFO MEC5_ECIA_INFO(17, 1, 9, 71)
21 #define MEC_TACH1_ECIA_INFO MEC5_ECIA_INFO(17, 2, 9, 72)
22 #define MEC_TACH2_ECIA_INFO MEC5_ECIA_INFO(17, 3, 9, 73)
23 #define MEC_TACH3_ECIA_INFO MEC5_ECIA_INFO(17, 4, 9, 159)
24 
25 struct mec_tach_info {
26     uintptr_t base_addr;
27     uint32_t devi;
28     uint16_t pcr_id;
29 };
30 
31 static const struct mec_tach_info tach_instances[MEC5_TACH_INSTANCES] = {
32     {MEC_TACH0_BASE, MEC_TACH0_ECIA_INFO, MEC_PCR_TACH0 },
33     {MEC_TACH1_BASE, MEC_TACH1_ECIA_INFO, MEC_PCR_TACH1 },
34     {MEC_TACH2_BASE, MEC_TACH2_ECIA_INFO, MEC_PCR_TACH2 },
35     {MEC_TACH3_BASE, MEC_TACH3_ECIA_INFO, MEC_PCR_TACH3 },
36 };
37 
tach_get_info(struct mec_tach_regs * regs)38 static struct mec_tach_info const *tach_get_info(struct mec_tach_regs *regs)
39 {
40     for (int i = 0; i < MEC5_TACH_INSTANCES; i++) {
41         const struct mec_tach_info *p = &tach_instances[i];
42 
43         if (tach_instances[i].base_addr == (uintptr_t)regs) {
44             return p;
45         }
46     }
47 
48     return NULL;
49 }
50 
mec_hal_tach_init(struct mec_tach_regs * regs,uint32_t limits,uint32_t flags)51 int mec_hal_tach_init(struct mec_tach_regs *regs, uint32_t limits, uint32_t flags)
52 {
53     const struct mec_tach_info *info = tach_get_info(regs);
54     uint32_t ctrl = 0, temp = 0;
55     bool enable_girq = false;
56 
57     if (!info) {
58         return MEC_RET_ERR_INVAL;
59     }
60 
61     mec_hal_pcr_clr_blk_slp_en(info->pcr_id);
62     if (flags & MEC5_TACH_CFG_RESET) {
63         mec_hal_pcr_blk_reset(info->pcr_id);
64     } else {
65         regs->CTRL = 0u;
66         regs->STATUS = UINT32_MAX;
67     }
68 
69     mec_hal_girq_ctrl(info->devi, 0);
70     mec_hal_girq_clr_src(info->devi);
71 
72     /* program high and low 16-bit counter limits */
73     regs->LIMIT_LO = (uint16_t)(limits & 0xffffu);
74     regs->LIMIT_HI = (uint16_t)(limits >> 16);
75 
76     /* program number of tach edges for the count interval */
77     temp = (flags & MEC5_TACH_CFG_INTERVAL_EDGES_MSK) >> MEC5_TACH_CFG_INTERVAL_EDGES_POS;
78     ctrl |= ((temp << MEC_TACH_CTRL_EDGES_Pos) & MEC_TACH_CTRL_EDGES_Msk);
79 
80     if (flags & MEC5_TACH_CFG_FILTER_EN) {
81         ctrl |= MEC_BIT(MEC_TACH_CTRL_FILT_IN_Pos);
82     }
83 
84     /* counter is incremented on rising edge of tach input or rising edge
85      * of Tach input clock. Input clock is the PCR slow clock.
86      */
87     if (flags & MEC5_TACH_CFG_CNT_INCR_CLK) {
88         ctrl |= MEC_BIT(MEC_TACH_CTRL_RDMODE_Pos);
89     }
90 
91     if (flags & MEC5_TACH_CFG_OOL_INTR_EN) { /* out of limit interrupt? */
92         ctrl |= MEC_BIT(MEC_TACH_CTRL_ENOOL_Pos);
93         enable_girq = true;
94     }
95 
96     if (flags & MEC5_TACH_CFG_CNT_RDY_INTR_EN) {
97         ctrl |= MEC_BIT(MEC_TACH_CTRL_CNTRDY_IEN_Pos);
98         enable_girq = true;
99     }
100 
101     if (flags & MEC5_TACH_CFG_INPUT_CHG_INTR_EN) {
102         ctrl |= MEC_BIT(MEC_TACH_CTRL_INTOG_IEN_Pos);
103         enable_girq = true;
104     }
105 
106     if (flags & MEC5_TACH_CFG_ENABLE) {
107         ctrl |= MEC_BIT(MEC_TACH_CTRL_ENABLE_Pos);
108     }
109 
110     if (enable_girq) {
111         mec_hal_girq_ctrl(info->devi, 1);
112     }
113 
114     regs->CTRL = ctrl;
115 
116     return MEC_RET_OK;
117 }
118 
mec_hal_tach_enable(struct mec_tach_regs * regs,uint8_t enable)119 void mec_hal_tach_enable(struct mec_tach_regs *regs, uint8_t enable)
120 {
121     if (enable) {
122         regs->CTRL |= MEC_BIT(MEC_TACH_CTRL_ENABLE_Pos);
123     } else {
124         regs->CTRL &= (uint32_t)~MEC_BIT(MEC_TACH_CTRL_ENABLE_Pos);
125     }
126 }
127 
mec_hal_tach_is_enabled(struct mec_tach_regs * regs)128 bool mec_hal_tach_is_enabled(struct mec_tach_regs *regs)
129 {
130     if (!regs) {
131         return false;
132     }
133 
134     return (regs->CTRL & MEC_BIT(MEC_TACH_CTRL_ENABLE_Pos)) ? true : false;
135 }
136 
mec_hal_tach_clock_freq(void)137 uint32_t mec_hal_tach_clock_freq(void)
138 {
139     return mec_hal_pcr_slow_clock_freq_get();
140 }
141 
mec_hal_tach_counter(struct mec_tach_regs * regs)142 uint32_t mec_hal_tach_counter(struct mec_tach_regs *regs)
143 {
144     const struct mec_tach_info *info = tach_get_info(regs);
145 
146     if (!info) {
147         return 0;
148     }
149 
150     return (regs->CTRL & MEC_TACH_CTRL_COUNT_Msk) >> MEC_TACH_CTRL_COUNT_Pos;
151 }
152 
mec_hal_tach_status(struct mec_tach_regs * regs)153 uint32_t mec_hal_tach_status(struct mec_tach_regs *regs)
154 {
155     return regs->STATUS;
156 }
157 
mec_hal_tach_status_clr(struct mec_tach_regs * regs,uint32_t status)158 void mec_hal_tach_status_clr(struct mec_tach_regs *regs, uint32_t status)
159 {
160     regs->STATUS = status;
161 }
162 
mec_hal_tach_intr_enable(struct mec_tach_regs * regs,uint32_t intr_events,uint8_t enable)163 int mec_hal_tach_intr_enable(struct mec_tach_regs *regs, uint32_t intr_events, uint8_t enable)
164 {
165     uint32_t msk = 0;
166 
167     if (!regs) {
168         return MEC_RET_ERR_INVAL;
169     }
170 
171     if (intr_events & MEC_BIT(MEC5_TACH_IEN_OOL_POS)) {
172         msk |= MEC_BIT(MEC_TACH_CTRL_ENOOL_Pos);
173     }
174 
175     if (intr_events & MEC_BIT(MEC5_TACH_IEN_CNT_RDY_POS)) {
176         msk |= MEC_BIT(MEC_TACH_CTRL_CNTRDY_IEN_Pos);
177     }
178 
179     if (intr_events & MEC_BIT(MEC5_TACH_IEN_INPUT_TOGGLE_POS)) {
180         msk |= MEC_BIT(MEC_TACH_CTRL_INTOG_IEN_Pos);
181     }
182 
183     if (msk) {
184         if (enable) {
185             regs->CTRL |= msk;
186         } else {
187             regs->CTRL &= (uint32_t)~msk;
188         }
189     }
190 
191     return MEC_RET_OK;
192 };
193 
mec_hal_tach_girq_status_clr(struct mec_tach_regs * regs)194 void mec_hal_tach_girq_status_clr(struct mec_tach_regs *regs)
195 {
196     const struct mec_tach_info *info = tach_get_info(regs);
197 
198     if (!info) {
199         return;
200     }
201 
202     mec_hal_girq_clr_src(info->devi);
203 }
204 
mec_hal_tach_girq_enable(struct mec_tach_regs * regs,uint8_t enable)205 void mec_hal_tach_girq_enable(struct mec_tach_regs *regs, uint8_t enable)
206 {
207     const struct mec_tach_info *info = tach_get_info(regs);
208 
209     if (!info) {
210         return;
211     }
212 
213     mec_hal_girq_ctrl(info->devi, enable);
214 }
215 
216 #endif /* MEC5_TACH_INSTANCES */
217 /* end mec_tach.c */
218