1 /******************************************************************************
2  *
3  * Copyright (C) 2022-2023 Maxim Integrated Products, Inc. (now owned by
4  * Analog Devices, Inc.),
5  * Copyright (C) 2023-2024 Analog Devices, Inc.
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************************/
20 
21 #include <stddef.h>
22 #include <string.h>
23 #include "mxc_assert.h"
24 #include "mxc_pins.h"
25 #include "mxc_lock.h"
26 #include "mxc_delay.h"
27 #include "mxc_device.h"
28 #include "mxc_errors.h"
29 #include "nvic_table.h"
30 #include "skbd.h"
31 #include "skbd_reva.h"
32 
33 /* ***** SKBD context info ***** */
34 static mxc_skbd_reva_req_t mxc_skbd_req;
35 
36 #ifndef __riscv
SKBD_RevA_IRQHandler(void)37 static void SKBD_RevA_IRQHandler(void)
38 {
39     if (mxc_skbd_req.irq_handler) {
40         mxc_skbd_req.irq_handler();
41     }
42 
43     /* Acknowledge interrupt at platform level */
44     NVIC_ClearPendingIRQ(SKB_IRQn);
45 }
46 #endif
47 
MXC_SKBD_RevA_PreInit(void)48 int MXC_SKBD_RevA_PreInit(void)
49 {
50     mxc_skbd_req.first_init = 0;
51 
52 #ifndef __riscv
53     NVIC_ClearPendingIRQ(SKB_IRQn);
54     /* Attach vector */
55     MXC_NVIC_SetVector(SKB_IRQn, SKBD_RevA_IRQHandler);
56 #endif
57 
58     return E_NO_ERROR;
59 }
60 
MXC_SKBD_RevA_Init(mxc_skbd_reva_regs_t * skbd,mxc_skbd_config_t config)61 int MXC_SKBD_RevA_Init(mxc_skbd_reva_regs_t *skbd, mxc_skbd_config_t config)
62 {
63     int result = E_NO_ERROR;
64 
65     if (!mxc_skbd_req.first_init) {
66         unsigned int temp;
67         /* Number of output pins */
68         unsigned int outputs = 0;
69 
70         /* Check for the I/O pin overlaps */
71         if (config.outputs & config.inputs) {
72             return MXC_SKBD_REVA_ERR_INVALID_PIN_CONFIGURATION;
73         }
74 
75         /* I/O pin direction selection for the SKBD pins */
76         /* Configure SKBD output pins */
77         skbd->ctrl0 |= config.outputs;
78         /* Configure SKBD input pins */
79         skbd->ctrl0 &= ~(config.inputs);
80         /* Memset like procedure */
81         memset((unsigned char *)&mxc_skbd_req, 0x00, sizeof(mxc_skbd_req));
82         /* Count the number of output SKBD lines */
83         temp = config.outputs;
84 
85         while (temp) {
86             temp &= (temp - 1);
87             outputs++;
88         }
89 
90         /* Configure the SKBD  */
91         skbd->ctrl1 = (config.reg_erase << MXC_F_SKBD_REVA_CTRL1_CLEAR_POS) |
92                       MXC_F_SKBD_REVA_CTRL1_AUTOEN // ->ctrl1[0]
93                       | MXC_F_SKBD_REVA_CTRL1_CLEAR // ->ctrl1[1]
94                       | MXC_F_SKBD_REVA_CTRL1_OUTNB //ctrl1[11:8]
95                       | ((config.debounce << MXC_F_SKBD_REVA_CTRL1_DBTM_POS) &
96                          MXC_F_SKBD_REVA_CTRL1_DBTM); //ctrl1[15:13]
97 
98         while (!(skbd->sr & MXC_F_SKBD_REVA_SR_BUSY)) {}
99 
100         /* Setup IRQ */
101         if (config.irq_handler) {
102             mxc_skbd_req.irq_handler = config.irq_handler;
103         }
104 
105         /* To be done once only */
106         mxc_skbd_req.first_init = 1;
107         mxc_skbd_req.state = MXC_SKBD_REVA_STATE_INITIALIZED;
108     } else {
109         result = MXC_SKBD_REVA_ERR_ALREAD_INITIALIZED;
110     }
111 
112     return result;
113 }
114 
MXC_SKBD_RevA_EnableInterruptEvents(mxc_skbd_reva_regs_t * skbd,unsigned int events)115 int MXC_SKBD_RevA_EnableInterruptEvents(mxc_skbd_reva_regs_t *skbd, unsigned int events)
116 {
117     int result = E_NO_ERROR;
118 
119     if (MXC_SKBD_REVA_STATE_INITIALIZED != mxc_skbd_req.state) {
120         result = MXC_SKBD_REVA_ERR_NOT_INITIALIZED;
121     } else {
122         events &=
123             (MXC_SKBD_REVA_EVENT_PUSH | MXC_SKBD_REVA_EVENT_RELEASE | MXC_SKBD_REVA_EVENT_OVERRUN);
124         skbd->ier |= events;
125     }
126 
127     return result;
128 }
129 
MXC_SKBD_RevA_DisableInterruptEvents(mxc_skbd_reva_regs_t * skbd,unsigned int events)130 extern inline int MXC_SKBD_RevA_DisableInterruptEvents(mxc_skbd_reva_regs_t *skbd,
131                                                        unsigned int events)
132 {
133     events &=
134         (MXC_SKBD_REVA_EVENT_PUSH | MXC_SKBD_REVA_EVENT_RELEASE | MXC_SKBD_REVA_EVENT_OVERRUN);
135     skbd->ier &= ~events;
136     return E_NO_ERROR;
137 }
138 
MXC_SKBD_RevA_ClearInterruptStatus(mxc_skbd_reva_regs_t * skbd,unsigned int status)139 extern inline int MXC_SKBD_RevA_ClearInterruptStatus(mxc_skbd_reva_regs_t *skbd,
140                                                      unsigned int status)
141 {
142     status &= (MXC_SKBD_REVA_INTERRUPT_STATUS_PUSHIS | MXC_SKBD_REVA_INTERRUPT_STATUS_RELEASEIS |
143                MXC_SKBD_REVA_INTERRUPT_STATUS_OVERIS);
144     skbd->isr &= ~status;
145     return E_NO_ERROR;
146 }
147 
MXC_SKBD_RevA_InterruptStatus(mxc_skbd_reva_regs_t * skbd,unsigned int * status)148 extern inline int MXC_SKBD_RevA_InterruptStatus(mxc_skbd_reva_regs_t *skbd, unsigned int *status)
149 {
150     if (status == NULL) {
151         return E_NULL_PTR;
152     }
153 
154     *status = skbd->isr;
155     return E_NO_ERROR;
156 }
157 
MXC_SKBD_RevA_ReadKeys(mxc_skbd_reva_regs_t * skbd,mxc_skbd_reva_keys_t * keys)158 int MXC_SKBD_RevA_ReadKeys(mxc_skbd_reva_regs_t *skbd, mxc_skbd_reva_keys_t *keys)
159 {
160     volatile uint16_t *key;
161     volatile unsigned int i = 0;
162     volatile unsigned int temp;
163     volatile unsigned int *key_reg;
164 
165     if (keys == NULL) {
166         return E_NULL_PTR;
167     }
168 
169     key = (uint16_t *)&keys->key0_reva;
170     key_reg = (unsigned int *)&skbd->evt[0];
171 
172     for (i = 0; i < MXC_SKBD_REVA_TOTAL_KEY_REGS; i++) {
173         if (!(skbd->ctrl1 & MXC_F_SKBD_REVA_CTRL1_CLEAR) &&
174             (skbd->ier & MXC_F_SKBD_REVA_IER_PUSHIE)) {
175             if (!(*key_reg & (MXC_F_SKBD_REVA_EVT_PUSH | MXC_F_SKBD_REVA_EVT_READ))) {
176                 *key++ = ((*key_reg & MXC_F_SKBD_REVA_EVT_IOIN) |
177                           ((*key_reg & MXC_F_SKBD_REVA_EVT_IOOUT) >> 1));
178             }
179         } else if (!(skbd->ctrl1 & MXC_F_SKBD_REVA_CTRL1_CLEAR) &&
180                    (skbd->ier & MXC_F_SKBD_REVA_IER_RELEASEIE)) {
181             temp = *key_reg;
182 
183             if ((temp & MXC_F_SKBD_REVA_EVT_PUSH) && !(temp & MXC_F_SKBD_REVA_EVT_READ)) {
184                 *key++ = ((*key_reg & MXC_F_SKBD_REVA_EVT_IOIN) |
185                           ((*key_reg & MXC_F_SKBD_REVA_EVT_IOOUT) >> 1));
186             }
187         } else {
188             temp = *key_reg;
189 
190             if (!(temp & MXC_F_SKBD_REVA_EVT_READ)) {
191                 *key++ =
192                     ((temp & MXC_F_SKBD_REVA_EVT_IOIN) | ((temp & MXC_F_SKBD_REVA_EVT_IOOUT) >> 1));
193             }
194         }
195 
196         key_reg++;
197     }
198 
199     return E_NO_ERROR;
200 }
201 
MXC_SKBD_RevA_Close(void)202 int MXC_SKBD_RevA_Close(void)
203 {
204 #ifndef __riscv
205     NVIC_DisableIRQ(SKB_IRQn);
206 #endif
207 
208     mxc_skbd_req.state = MXC_SKBD_REVA_STATE_CLOSED;
209     mxc_skbd_req.first_init = 0;
210     return E_NO_ERROR;
211 }
212