blob: e8a50b2b181192900dc1fab07c8b53acafd13f08 [file] [log] [blame]
Angel Ponse67ab182020-04-04 18:51:11 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Tristan Shieh71d227b2018-07-09 18:59:32 +08002
Kyösti Mälkki13f66502019-03-03 08:01:05 +02003#include <device/mmio.h>
Tristan Shieh71d227b2018-07-09 18:59:32 +08004#include <gpio.h>
5
6enum {
7 GPIO_DIRECTION_IN = 0,
8 GPIO_DIRECTION_OUT = 1,
9};
10
11enum {
12 GPIO_MODE = 0,
13};
14
15static void pos_bit_calc(gpio_t gpio, u32 *pos, u32 *bit)
16{
17 *pos = gpio.id / MAX_GPIO_REG_BITS;
18 *bit = gpio.id % MAX_GPIO_REG_BITS;
19}
20
21static void pos_bit_calc_for_mode(gpio_t gpio, u32 *pos, u32 *bit)
22{
23 *pos = gpio.id / MAX_GPIO_MODE_PER_REG;
24 *bit = (gpio.id % MAX_GPIO_MODE_PER_REG) * GPIO_MODE_BITS;
25}
26
27static s32 gpio_set_dir(gpio_t gpio, u32 dir)
28{
29 u32 pos;
30 u32 bit;
31 u32 *reg;
32
33 pos_bit_calc(gpio, &pos, &bit);
34
35 if (dir == GPIO_DIRECTION_IN)
36 reg = &mtk_gpio->dir[pos].rst;
37 else
38 reg = &mtk_gpio->dir[pos].set;
39
40 write32(reg, 1L << bit);
41
42 return 0;
43}
44
45void gpio_set_mode(gpio_t gpio, int mode)
46{
47 u32 pos;
48 u32 bit;
49 u32 mask = (1L << GPIO_MODE_BITS) - 1;
50
51 pos_bit_calc_for_mode(gpio, &pos, &bit);
52
Julius Werner55009af2019-12-02 22:03:27 -080053 clrsetbits32(&mtk_gpio->mode[pos].val, mask << bit, mode << bit);
Tristan Shieh71d227b2018-07-09 18:59:32 +080054}
55
56int gpio_get(gpio_t gpio)
57{
58 u32 pos;
59 u32 bit;
60 u32 *reg;
61 u32 data;
62
63 pos_bit_calc(gpio, &pos, &bit);
64
65 reg = &mtk_gpio->din[pos].val;
66 data = read32(reg);
67
68 return (data & (1L << bit)) ? 1 : 0;
69}
70
71void gpio_set(gpio_t gpio, int output)
72{
73 u32 pos;
74 u32 bit;
75 u32 *reg;
76
77 pos_bit_calc(gpio, &pos, &bit);
78
79 if (output == 0)
80 reg = &mtk_gpio->dout[pos].rst;
81 else
82 reg = &mtk_gpio->dout[pos].set;
83
84 write32(reg, 1L << bit);
85}
86
87void gpio_input_pulldown(gpio_t gpio)
88{
89 gpio_set_pull(gpio, GPIO_PULL_ENABLE, GPIO_PULL_DOWN);
90 gpio_set_dir(gpio, GPIO_DIRECTION_IN);
91 gpio_set_mode(gpio, GPIO_MODE);
92}
93
94void gpio_input_pullup(gpio_t gpio)
95{
96 gpio_set_pull(gpio, GPIO_PULL_ENABLE, GPIO_PULL_UP);
97 gpio_set_dir(gpio, GPIO_DIRECTION_IN);
98 gpio_set_mode(gpio, GPIO_MODE);
99}
100
101void gpio_input(gpio_t gpio)
102{
103 gpio_set_pull(gpio, GPIO_PULL_DISABLE, GPIO_PULL_DOWN);
104 gpio_set_dir(gpio, GPIO_DIRECTION_IN);
105 gpio_set_mode(gpio, GPIO_MODE);
106}
107
108void gpio_output(gpio_t gpio, int value)
109{
110 gpio_set_pull(gpio, GPIO_PULL_DISABLE, GPIO_PULL_DOWN);
111 gpio_set(gpio, value);
112 gpio_set_dir(gpio, GPIO_DIRECTION_OUT);
113 gpio_set_mode(gpio, GPIO_MODE);
114}
Chuanjia Liu3a065f12018-11-26 14:20:09 +0800115
116enum {
117 MAX_EINT_REG_BITS = 32,
118};
119
120static void pos_bit_calc_for_eint(gpio_t gpio, u32 *pos, u32 *bit)
121{
122 *pos = gpio.id / MAX_EINT_REG_BITS;
123 *bit = gpio.id % MAX_EINT_REG_BITS;
124}
125
126int gpio_eint_poll(gpio_t gpio)
127{
128 u32 pos;
129 u32 bit;
130 u32 status;
131
132 pos_bit_calc_for_eint(gpio, &pos, &bit);
133
134 status = (read32(&mtk_eint->sta.regs[pos]) >> bit) & 0x1;
135
136 if (status)
137 write32(&mtk_eint->ack.regs[pos], 1 << bit);
138
139 return status;
140}
141
142void gpio_eint_configure(gpio_t gpio, enum gpio_irq_type type)
143{
144 u32 pos;
145 u32 bit, mask;
146
147 pos_bit_calc_for_eint(gpio, &pos, &bit);
148 mask = 1 << bit;
149
150 /* Make it an input first. */
151 gpio_input_pullup(gpio);
152
153 write32(&mtk_eint->d0en[pos], mask);
154
155 switch (type) {
156 case IRQ_TYPE_EDGE_FALLING:
157 write32(&mtk_eint->sens_clr.regs[pos], mask);
158 write32(&mtk_eint->pol_clr.regs[pos], mask);
159 break;
160 case IRQ_TYPE_EDGE_RISING:
161 write32(&mtk_eint->sens_clr.regs[pos], mask);
162 write32(&mtk_eint->pol_set.regs[pos], mask);
163 break;
164 case IRQ_TYPE_LEVEL_LOW:
165 write32(&mtk_eint->sens_set.regs[pos], mask);
166 write32(&mtk_eint->pol_clr.regs[pos], mask);
167 break;
168 case IRQ_TYPE_LEVEL_HIGH:
169 write32(&mtk_eint->sens_set.regs[pos], mask);
170 write32(&mtk_eint->pol_set.regs[pos], mask);
171 break;
172 }
173
174 write32(&mtk_eint->mask_clr.regs[pos], mask);
175}
Jason Chen61aac5b72023-03-29 14:55:30 +0800176
177static inline bool is_valid_drv(uint8_t drv)
178{
179 return drv <= GPIO_DRV_16_MA;
180}
181
182static inline bool is_valid_drv_adv(enum gpio_drv_adv drv)
183{
184 return drv <= GPIO_DRV_ADV_1_MA && drv >= GPIO_DRV_ADV_125_UA;
185}
186
187int gpio_set_driving(gpio_t gpio, uint8_t drv)
188{
189 uint32_t mask;
190 const struct gpio_drv_info *info = get_gpio_driving_info(gpio.id);
191 const struct gpio_drv_info *adv_info = get_gpio_driving_adv_info(gpio.id);
192 void *reg, *reg_adv, *reg_addr;
193
194 if (!info)
195 return -1;
196
197 if (!is_valid_drv(drv))
198 return -1;
199
200 if (info->width == 0)
201 return -1;
202
203 mask = BIT(info->width) - 1;
204 /* Check setting value is not beyond width */
205 if ((uint32_t)drv > mask)
206 return -1;
207
208 reg_addr = gpio_find_reg_addr(gpio);
209 reg = reg_addr + info->offset;
210 clrsetbits32(reg, mask << info->shift, drv << info->shift);
211
212 /* Disable EH if supported */
213 if (adv_info && adv_info->width != 0) {
214 reg_adv = reg_addr + adv_info->offset;
215 clrbits32(reg_adv, BIT(adv_info->shift));
216 }
217
218 return 0;
219}
220
221int gpio_get_driving(gpio_t gpio)
222{
223 const struct gpio_drv_info *info = get_gpio_driving_info(gpio.id);
224 void *reg;
225
226 if (!info)
227 return -1;
228
229 if (info->width == 0)
230 return -1;
231
232 reg = gpio_find_reg_addr(gpio) + info->offset;
233 return (read32(reg) >> info->shift) & (BIT(info->width) - 1);
234}
235
236int gpio_set_driving_adv(gpio_t gpio, enum gpio_drv_adv drv)
237{
238 uint32_t mask;
239 const struct gpio_drv_info *adv_info = get_gpio_driving_adv_info(gpio.id);
240 void *reg_adv;
241
242 if (!adv_info)
243 return -1;
244
245 if (!is_valid_drv_adv(drv))
246 return -1;
247
248 if (adv_info->width == 0)
249 return -1;
250
251 /* Not include EH bit (the lowest bit) */
252 if ((uint32_t)drv > (BIT(adv_info->width - 1) - 1))
253 return -1;
254
255 reg_adv = gpio_find_reg_addr(gpio) + adv_info->offset;
256 mask = BIT(adv_info->width) - 1;
257 /* EH enable */
258 drv = (drv << 1) | BIT(0);
259
260 clrsetbits32(reg_adv, mask << adv_info->shift, drv << adv_info->shift);
261
262 return 0;
263}
264
265int gpio_get_driving_adv(gpio_t gpio)
266{
267 const struct gpio_drv_info *adv_info = get_gpio_driving_adv_info(gpio.id);
268 void *reg_adv;
269 uint32_t drv;
270
271 if (!adv_info)
272 return -1;
273
274 if (adv_info->width == 0)
275 return -1;
276
277 reg_adv = gpio_find_reg_addr(gpio) + adv_info->offset;
278 drv = (read32(reg_adv) >> adv_info->shift) & (BIT(adv_info->width) - 1);
279
280 /* Drop EH bit */
281 return drv >> 1;
282}