]>
Commit | Line | Data |
---|---|---|
ab693e9c MK |
1 | /* |
2 | * (C) Copyright 2009 Samsung Electronics | |
3 | * Minkyu Kang <mk7.kang@samsung.com> | |
4 | * | |
1a459660 | 5 | * SPDX-License-Identifier: GPL-2.0+ |
ab693e9c MK |
6 | */ |
7 | ||
8 | #include <common.h> | |
9 | #include <asm/io.h> | |
365d6070 | 10 | #include <asm/gpio.h> |
ab693e9c | 11 | |
f6ae1ca0 | 12 | #define S5P_GPIO_GET_PIN(x) (x % GPIO_PER_BANK) |
8475c869 | 13 | |
3a233dbf SG |
14 | #define CON_MASK(val) (0xf << ((val) << 2)) |
15 | #define CON_SFR(gpio, cfg) ((cfg) << ((gpio) << 2)) | |
16 | #define CON_SFR_UNSHIFT(val, gpio) ((val) >> ((gpio) << 2)) | |
ab693e9c | 17 | |
3a233dbf SG |
18 | #define DAT_MASK(gpio) (0x1 << (gpio)) |
19 | #define DAT_SET(gpio) (0x1 << (gpio)) | |
ab693e9c | 20 | |
3a233dbf SG |
21 | #define PULL_MASK(gpio) (0x3 << ((gpio) << 1)) |
22 | #define PULL_MODE(gpio, pull) ((pull) << ((gpio) << 1)) | |
ab693e9c | 23 | |
3a233dbf SG |
24 | #define DRV_MASK(gpio) (0x3 << ((gpio) << 1)) |
25 | #define DRV_SET(gpio, mode) ((mode) << ((gpio) << 1)) | |
26 | #define RATE_MASK(gpio) (0x1 << (gpio + 16)) | |
27 | #define RATE_SET(gpio) (0x1 << (gpio + 16)) | |
ab693e9c | 28 | |
f6ae1ca0 AS |
29 | #define name_to_gpio(n) s5p_name_to_gpio(n) |
30 | static inline int s5p_name_to_gpio(const char *name) | |
31 | { | |
32 | unsigned num, irregular_set_number, irregular_bank_base; | |
33 | const struct gpio_name_num_table *tabp; | |
34 | char this_bank, bank_name, irregular_bank_name; | |
35 | char *endp; | |
36 | ||
37 | /* | |
38 | * The gpio name starts with either 'g' or 'gp' followed by the bank | |
39 | * name character. Skip one or two characters depending on the prefix. | |
40 | */ | |
41 | if (name[0] == 'g' && name[1] == 'p') | |
42 | name += 2; | |
43 | else if (name[0] == 'g') | |
44 | name++; | |
45 | else | |
46 | return -1; /* Name must start with 'g' */ | |
47 | ||
48 | bank_name = *name++; | |
49 | if (!*name) | |
50 | return -1; /* At least one digit is required/expected. */ | |
51 | ||
52 | /* | |
53 | * On both exynos5 and exynos5420 architectures there is a bank of | |
54 | * GPIOs which does not fall into the regular address pattern. Those | |
55 | * banks are c4 on Exynos5 and y7 on Exynos5420. The rest of the below | |
56 | * assignments help to handle these irregularities. | |
57 | */ | |
58 | #if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5) | |
59 | if (cpu_is_exynos5()) { | |
60 | if (proid_is_exynos5420()) { | |
61 | tabp = exynos5420_gpio_table; | |
62 | irregular_bank_name = 'y'; | |
63 | irregular_set_number = '7'; | |
64 | irregular_bank_base = EXYNOS5420_GPIO_Y70; | |
65 | } else { | |
66 | tabp = exynos5_gpio_table; | |
67 | irregular_bank_name = 'c'; | |
68 | irregular_set_number = '4'; | |
69 | irregular_bank_base = EXYNOS5_GPIO_C40; | |
70 | } | |
71 | } else { | |
72 | if (proid_is_exynos4412()) | |
73 | tabp = exynos4x12_gpio_table; | |
74 | else | |
75 | tabp = exynos4_gpio_table; | |
76 | irregular_bank_name = 0; | |
77 | irregular_set_number = 0; | |
78 | irregular_bank_base = 0; | |
79 | } | |
80 | #else | |
81 | if (cpu_is_s5pc110()) | |
82 | tabp = s5pc110_gpio_table; | |
83 | else | |
84 | tabp = s5pc100_gpio_table; | |
85 | irregular_bank_name = 0; | |
86 | irregular_set_number = 0; | |
87 | irregular_bank_base = 0; | |
88 | #endif | |
89 | ||
90 | this_bank = tabp->bank; | |
91 | do { | |
92 | if (bank_name == this_bank) { | |
93 | unsigned pin_index; /* pin number within the bank */ | |
94 | if ((bank_name == irregular_bank_name) && | |
95 | (name[0] == irregular_set_number)) { | |
96 | pin_index = name[1] - '0'; | |
97 | /* Irregular sets have 8 pins. */ | |
98 | if (pin_index >= GPIO_PER_BANK) | |
99 | return -1; | |
100 | num = irregular_bank_base + pin_index; | |
101 | } else { | |
102 | pin_index = simple_strtoul(name, &endp, 8); | |
103 | pin_index -= tabp->bank_offset; | |
104 | /* | |
105 | * Sanity check: bunk 'z' has no set number, | |
106 | * for all other banks there must be exactly | |
107 | * two octal digits, and the resulting number | |
108 | * should not exceed the number of pins in the | |
109 | * bank. | |
110 | */ | |
111 | if (((bank_name != 'z') && !name[1]) || | |
112 | *endp || | |
113 | (pin_index >= tabp->bank_size)) | |
114 | return -1; | |
115 | num = tabp->base + pin_index; | |
116 | } | |
117 | return num; | |
118 | } | |
119 | this_bank = (++tabp)->bank; | |
120 | } while (this_bank); | |
121 | ||
122 | return -1; | |
123 | } | |
124 | ||
125 | static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) | |
ab693e9c MK |
126 | { |
127 | unsigned int value; | |
128 | ||
129 | value = readl(&bank->con); | |
130 | value &= ~CON_MASK(gpio); | |
131 | value |= CON_SFR(gpio, cfg); | |
132 | writel(value, &bank->con); | |
133 | } | |
134 | ||
f6ae1ca0 | 135 | static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) |
ab693e9c MK |
136 | { |
137 | unsigned int value; | |
138 | ||
139 | value = readl(&bank->dat); | |
140 | value &= ~DAT_MASK(gpio); | |
141 | if (en) | |
142 | value |= DAT_SET(gpio); | |
143 | writel(value, &bank->dat); | |
144 | } | |
145 | ||
f6ae1ca0 AS |
146 | static void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, |
147 | int gpio, int en) | |
148 | { | |
149 | s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_OUTPUT); | |
150 | s5p_gpio_set_value(bank, gpio, en); | |
151 | } | |
152 | ||
153 | static void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) | |
154 | { | |
155 | s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_INPUT); | |
156 | } | |
157 | ||
158 | static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) | |
ab693e9c MK |
159 | { |
160 | unsigned int value; | |
161 | ||
162 | value = readl(&bank->dat); | |
163 | return !!(value & DAT_MASK(gpio)); | |
164 | } | |
165 | ||
f6ae1ca0 | 166 | static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) |
ab693e9c MK |
167 | { |
168 | unsigned int value; | |
169 | ||
170 | value = readl(&bank->pull); | |
171 | value &= ~PULL_MASK(gpio); | |
172 | ||
173 | switch (mode) { | |
f6ae1ca0 AS |
174 | case S5P_GPIO_PULL_DOWN: |
175 | case S5P_GPIO_PULL_UP: | |
ab693e9c MK |
176 | value |= PULL_MODE(gpio, mode); |
177 | break; | |
178 | default: | |
ffb4b025 | 179 | break; |
ab693e9c MK |
180 | } |
181 | ||
182 | writel(value, &bank->pull); | |
183 | } | |
184 | ||
f6ae1ca0 | 185 | static void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) |
ab693e9c MK |
186 | { |
187 | unsigned int value; | |
188 | ||
189 | value = readl(&bank->drv); | |
190 | value &= ~DRV_MASK(gpio); | |
191 | ||
192 | switch (mode) { | |
f6ae1ca0 AS |
193 | case S5P_GPIO_DRV_1X: |
194 | case S5P_GPIO_DRV_2X: | |
195 | case S5P_GPIO_DRV_3X: | |
196 | case S5P_GPIO_DRV_4X: | |
ab693e9c MK |
197 | value |= DRV_SET(gpio, mode); |
198 | break; | |
199 | default: | |
200 | return; | |
201 | } | |
202 | ||
203 | writel(value, &bank->drv); | |
204 | } | |
205 | ||
f6ae1ca0 | 206 | static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) |
ab693e9c MK |
207 | { |
208 | unsigned int value; | |
209 | ||
210 | value = readl(&bank->drv); | |
211 | value &= ~RATE_MASK(gpio); | |
212 | ||
213 | switch (mode) { | |
f6ae1ca0 AS |
214 | case S5P_GPIO_DRV_FAST: |
215 | case S5P_GPIO_DRV_SLOW: | |
ab693e9c MK |
216 | value |= RATE_SET(gpio); |
217 | break; | |
218 | default: | |
219 | return; | |
220 | } | |
221 | ||
222 | writel(value, &bank->drv); | |
223 | } | |
9f15bc0c | 224 | |
903fd795 | 225 | static struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio) |
9f15bc0c | 226 | { |
f6ae1ca0 AS |
227 | const struct gpio_info *data; |
228 | unsigned int upto; | |
229 | int i, count; | |
230 | ||
231 | data = get_gpio_data(); | |
232 | count = get_bank_num(); | |
233 | upto = 0; | |
234 | ||
235 | for (i = 0; i < count; i++) { | |
236 | debug("i=%d, upto=%d\n", i, upto); | |
237 | if (gpio < data->max_gpio) { | |
238 | struct s5p_gpio_bank *bank; | |
239 | bank = (struct s5p_gpio_bank *)data->reg_addr; | |
240 | bank += (gpio - upto) / GPIO_PER_BANK; | |
241 | debug("gpio=%d, bank=%p\n", gpio, bank); | |
242 | return bank; | |
243 | } | |
244 | ||
245 | upto = data->max_gpio; | |
246 | data++; | |
247 | } | |
9f15bc0c | 248 | |
f6ae1ca0 | 249 | return NULL; |
9f15bc0c ŁM |
250 | } |
251 | ||
365d6070 | 252 | int s5p_gpio_get_pin(unsigned gpio) |
9f15bc0c | 253 | { |
8475c869 | 254 | return S5P_GPIO_GET_PIN(gpio); |
9f15bc0c ŁM |
255 | } |
256 | ||
365d6070 JH |
257 | /* Common GPIO API */ |
258 | ||
259 | int gpio_request(unsigned gpio, const char *label) | |
9f15bc0c ŁM |
260 | { |
261 | return 0; | |
262 | } | |
263 | ||
365d6070 | 264 | int gpio_free(unsigned gpio) |
9f15bc0c | 265 | { |
9f15bc0c ŁM |
266 | return 0; |
267 | } | |
268 | ||
365d6070 | 269 | int gpio_direction_input(unsigned gpio) |
9f15bc0c | 270 | { |
365d6070 JH |
271 | s5p_gpio_direction_input(s5p_gpio_get_bank(gpio), |
272 | s5p_gpio_get_pin(gpio)); | |
9f15bc0c ŁM |
273 | return 0; |
274 | } | |
275 | ||
365d6070 | 276 | int gpio_direction_output(unsigned gpio, int value) |
9f15bc0c | 277 | { |
365d6070 JH |
278 | s5p_gpio_direction_output(s5p_gpio_get_bank(gpio), |
279 | s5p_gpio_get_pin(gpio), value); | |
280 | return 0; | |
9f15bc0c ŁM |
281 | } |
282 | ||
365d6070 | 283 | int gpio_get_value(unsigned gpio) |
9f15bc0c | 284 | { |
365d6070 JH |
285 | return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio), |
286 | s5p_gpio_get_pin(gpio)); | |
287 | } | |
288 | ||
289 | int gpio_set_value(unsigned gpio, int value) | |
290 | { | |
291 | s5p_gpio_set_value(s5p_gpio_get_bank(gpio), | |
292 | s5p_gpio_get_pin(gpio), value); | |
293 | ||
294 | return 0; | |
9f15bc0c | 295 | } |
f6ae1ca0 AS |
296 | |
297 | void gpio_set_pull(int gpio, int mode) | |
298 | { | |
299 | s5p_gpio_set_pull(s5p_gpio_get_bank(gpio), | |
300 | s5p_gpio_get_pin(gpio), mode); | |
301 | } | |
302 | ||
303 | void gpio_set_drv(int gpio, int mode) | |
304 | { | |
305 | s5p_gpio_set_drv(s5p_gpio_get_bank(gpio), | |
306 | s5p_gpio_get_pin(gpio), mode); | |
307 | } | |
308 | ||
309 | void gpio_cfg_pin(int gpio, int cfg) | |
310 | { | |
311 | s5p_gpio_cfg_pin(s5p_gpio_get_bank(gpio), | |
312 | s5p_gpio_get_pin(gpio), cfg); | |
313 | } | |
314 | ||
315 | void gpio_set_rate(int gpio, int mode) | |
316 | { | |
317 | s5p_gpio_set_rate(s5p_gpio_get_bank(gpio), | |
318 | s5p_gpio_get_pin(gpio), mode); | |
319 | } |