blob: aaf8f95c4aedeb970518c7742c1f23fcea79f56c [file] [log] [blame]
Kelvin Zhangc4c3dd12021-12-24 20:59:18 +08001/*
2 * Copyright (C) 2014-2018 Amlogic, Inc. All rights reserved.
3 *
4 * All information contained herein is Amlogic confidential.
5 *
6 * This software is provided to you pursuant to Software License Agreement
7 * (SLA) with Amlogic Inc ("Amlogic"). This software may be used
8 * only in accordance with the terms of this agreement.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification is strictly prohibited without prior written permission from
12 * Amlogic.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27/*
28 * gpio driver
29 */
30#include "FreeRTOS.h"
31#include <register.h>
32#include <common.h>
33#include <task.h>
34#include <gpio.h>
35#include "projdefs.h"
36#include "gpio_drv.h"
37#include "portmacro.h"
38
39#define DRIVER_NAME "gpio"
40
41extern unsigned int xPortIsIsrContext(void);
42static void prvEnterCritical(UBaseType_t *uxIsr)
43{
44 if (xPortIsIsrContext())
45 *uxIsr = taskENTER_CRITICAL_FROM_ISR();
46 else {
47 taskENTER_CRITICAL();
48 *uxIsr = 0;
49 }
50};
51
52static void prvExitCritical(UBaseType_t uxSaveIsr)
53{
54 if (xPortIsIsrContext())
55 taskEXIT_CRITICAL_FROM_ISR(uxSaveIsr);
56 else {
57 taskEXIT_CRITICAL();
58 (void)uxSaveIsr;
59 }
60};
61
62static inline void prvGpioRegWrite(uint32_t addr,
63 uint32_t mask, uint32_t val)
64{
65 UBaseType_t uxSavedIsr;
66
67 prvEnterCritical(&uxSavedIsr);
68 REG32_UPDATE_BITS(addr, mask, val);
69 prvExitCritical(uxSavedIsr);
70}
71
72static inline void prvGpioCalcRegAndBit(const GpioBank_t *bk,
73 uint8_t offset,
74 enum GpioRegType regType,
75 uint16_t *reg, uint8_t *bit)
76{
77 *reg = bk->regs[regType].reg << 2;
78 *bit = bk->regs[regType].bit + offset;
79}
80
81static inline void prvGpioGetBankAndOffset(uint16_t gpio,
82 const GpioBank_t **bk,
83 uint8_t *off)
84{
85 const GpioBank_t *gpk;
86
87 gpk = pGetGpioBank();
88 *bk = &gpk[gpio >> 5];
89 *off = gpio % 32;
90}
91
92int xGpioSetDir(uint16_t gpio, enum GpioDirType dir)
93{
94 uint16_t reg;
95 uint8_t bit;
96 uint8_t offset;
97 const GpioBank_t *bk;
98
99 if (dir >= GPIO_DIR_INVALID) {
100 printf("%s: invalid DIR [OUT=0, IN=1]: %d\n", DRIVER_NAME,
101 dir);
102 return -pdFREERTOS_ERRNO_EINVAL;
103 }
104
105 prvGpioGetBankAndOffset(gpio, &bk, &offset);
106
107 prvGpioCalcRegAndBit(bk, offset, REG_DIR, &reg, &bit);
108
109 prvGpioRegWrite(bk->domain->rGpio + reg, BIT(bit), dir ? BIT(bit) : 0);
110
111 return 0;
112}
113
114int xGpioSetValue(uint16_t gpio, enum GpioOutLevelType level)
115{
116 uint16_t reg;
117 uint8_t bit;
118 uint8_t offset;
119 const GpioBank_t *bk;
120
121 if (level >= GPIO_LEVEL_INVALID) {
122 printf("%s: invalid output level [LOW=1, HIGH=0]: %d\n",
123 DRIVER_NAME, level);
124 return -pdFREERTOS_ERRNO_EINVAL;
125 }
126
127 prvGpioGetBankAndOffset(gpio, &bk, &offset);
128
129 prvGpioCalcRegAndBit(bk, offset, REG_OUT, &reg, &bit);
130
131 prvGpioRegWrite(bk->domain->rGpio + reg, BIT(bit),
132 level ? BIT(bit) : 0);
133
134 return 0;
135}
136
137int xGpioGetValue(uint16_t gpio)
138{
139 uint16_t reg;
140 uint8_t bit;
141 uint8_t offset;
142 const GpioBank_t *bk;
143
144 prvGpioGetBankAndOffset(gpio, &bk, &offset);
145
146 prvGpioCalcRegAndBit(bk, offset, REG_IN, &reg, &bit);
147
148 return !!(REG32((unsigned long)bk->domain->rGpio + reg) & BIT(bit));
149}
150
151int xPinconfSet(uint16_t gpio, uint32_t flags)
152{
153 uint16_t reg;
154 uint8_t bit;
155 uint8_t offset;
156 uint8_t ds_value = 0;
157 const GpioBank_t *bk;
158 const GpioRegDesc_t *desc;
159
160 prvGpioGetBankAndOffset(gpio, &bk, &offset);
161
162 prvGpioCalcRegAndBit(bk, offset, REG_PULLEN, &reg, &bit);
163
164 if (flags & PINF_CONFIG_BIAS_DISABLE) {
165 prvGpioRegWrite(bk->domain->rPullen + reg, BIT(bit), 0);
166 } else if (flags &
167 (PINF_CONFIG_BIAS_PULL_UP | PINF_CONFIG_BIAS_PULL_DOWN)) {
168 prvGpioRegWrite(bk->domain->rPullen + reg, BIT(bit), BIT(bit));
169
170 prvGpioCalcRegAndBit(bk, offset, REG_PULL, &reg, &bit);
171 if (flags & PINF_CONFIG_BIAS_PULL_UP)
172 prvGpioRegWrite(bk->domain->rPull + reg, BIT(bit),
173 BIT(bit));
174 else
175 prvGpioRegWrite(bk->domain->rPull + reg, BIT(bit), 0);
176 }
177
178 if ((flags & PINF_CONFIG_DRV_MASK) && &bk->regs[REG_DRV] != 0) {
179
180 prvGpioCalcRegAndBit(bk, offset, REG_DRV, &reg, &bit);
181 desc = &bk->regs[REG_DRV];
182
183 reg = desc->reg + ((desc->bit + (offset << 1)) >> 5);
184 bit = (desc->bit + (offset << 1)) % 32;
185
186 if (flags & PINF_CONFIG_DRV_STRENGTH_0)
187 ds_value = 0;
188 else if (flags & PINF_CONFIG_DRV_STRENGTH_1)
189 ds_value = 1;
190 else if (flags & PINF_CONFIG_DRV_STRENGTH_2)
191 ds_value = 2;
192 else if (flags & PINF_CONFIG_DRV_STRENGTH_3)
193 ds_value = 3;
194
195 prvGpioRegWrite(bk->domain->rDrv + (reg << 2), 0x3 << bit,
196 ds_value << bit);
197 }
198
199 return 0;
200}
201
202int xPinmuxSet(uint16_t gpio, enum PinMuxType func)
203{
204 uint16_t reg;
205 uint8_t bit;
206 uint8_t offset;
207 const GpioBank_t *bk;
208 const GpioRegDesc_t *desc;
209
210 if (func >= PIN_FUNC_INVALID) {
211 printf("%s: invalid pin Function [0 - %d]: %d\n",
212 DRIVER_NAME, PIN_FUNC_INVALID - 1, func);
213 return -pdFREERTOS_ERRNO_EINVAL;
214 }
215
216 prvGpioGetBankAndOffset(gpio, &bk, &offset);
217 desc = &bk->regs[REG_MUX];
218
219 reg = desc->reg + ((desc->bit + (offset << 2)) >> 5);
220 bit = (desc->bit + (offset << 2)) % 32;
221
222 prvGpioRegWrite(bk->domain->rMux + (reg << 2), 0xf << bit, func << bit);
223
224 return 0;
225}