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