exynos_gpio.c revision 1.28 1 /* $NetBSD: exynos_gpio.c,v 1.28 2020/03/20 06:35:59 skrll Exp $ */
2
3 /*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Reinoud Zandijk
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "opt_exynos.h"
33 #include "opt_arm_debug.h"
34 #include "gpio.h"
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(1, "$NetBSD: exynos_gpio.c,v 1.28 2020/03/20 06:35:59 skrll Exp $");
38
39 #include <sys/param.h>
40 #include <sys/bus.h>
41 #include <sys/device.h>
42 #include <sys/intr.h>
43 #include <sys/systm.h>
44 #include <sys/kmem.h>
45 #include <sys/gpio.h>
46
47 #include <dev/gpio/gpiovar.h>
48
49 #include <arm/samsung/exynos_reg.h>
50 #include <arm/samsung/exynos_var.h>
51 #include <arm/samsung/exynos_intr.h>
52 #include <arm/samsung/exynos_pinctrl.h>
53
54 #include <dev/fdt/fdtvar.h>
55
56 struct exynos_gpio_bank {
57 const char bank_name[6];
58 device_t bank_dev;
59 struct gpio_chipset_tag bank_gc;
60 struct exynos_gpio_softc *bank_sc;
61 gpio_pin_t bank_pins[8];
62
63 const bus_addr_t bank_core_offset;
64 const uint8_t bank_bits;
65
66 struct exynos_gpio_pin_cfg bank_cfg;
67 };
68
69 struct exynos_gpio_pin {
70 struct exynos_gpio_softc *pin_sc;
71 int pin_no;
72 u_int pin_flags;
73 int pin_actlo;
74 const struct exynos_gpio_bank *pin_bank;
75 };
76
77
78 //#define GPIO_REG(v,s,o) (EXYNOS##v##_GPIO_##s##_OFFSET + (o))
79 #define GPIO_REG(v,s,o) ((o))
80 #define GPIO_GRP(v, s, o, n, b) \
81 { \
82 .bank_name = #n, \
83 .bank_core_offset = GPIO_REG(v,s,o), \
84 .bank_bits = b, \
85 }
86
87 static struct exynos_gpio_bank exynos5_banks[] = {
88 GPIO_GRP(5, MUXA, 0x0000, gpy7, 8),
89 GPIO_GRP(5, MUXA, 0x0C00, gpx0, 8),
90 GPIO_GRP(5, MUXA, 0x0C20, gpx1, 8),
91 GPIO_GRP(5, MUXA, 0x0C40, gpx2, 8),
92 GPIO_GRP(5, MUXA, 0x0C60, gpx3, 8),
93
94 GPIO_GRP(5, MUXB, 0x0000, gpc0, 8),
95 GPIO_GRP(5, MUXB, 0x0020, gpc1, 8),
96 GPIO_GRP(5, MUXB, 0x0040, gpc2, 7),
97 GPIO_GRP(5, MUXB, 0x0060, gpc3, 4),
98 GPIO_GRP(5, MUXB, 0x0080, gpc4, 2),
99 GPIO_GRP(5, MUXB, 0x00A0, gpd1, 8),
100 GPIO_GRP(5, MUXB, 0x00C0, gpy0, 6),
101 GPIO_GRP(5, MUXB, 0x00E0, gpy1, 4),
102 GPIO_GRP(5, MUXB, 0x0100, gpy2, 6),
103 GPIO_GRP(5, MUXB, 0x0120, gpy3, 8),
104 GPIO_GRP(5, MUXB, 0x0140, gpy4, 8),
105 GPIO_GRP(5, MUXB, 0x0160, gpy5, 8),
106 GPIO_GRP(5, MUXB, 0x0180, gpy6, 8),
107
108 GPIO_GRP(5, MUXC, 0x0000, gpe0, 8),
109 GPIO_GRP(5, MUXC, 0x0020, gpe1, 2),
110 GPIO_GRP(5, MUXC, 0x0040, gpf0, 6),
111 GPIO_GRP(5, MUXC, 0x0060, gpf1, 8),
112 GPIO_GRP(5, MUXC, 0x0080, gpg0, 8),
113 GPIO_GRP(5, MUXC, 0x00A0, gpg1, 8),
114 GPIO_GRP(5, MUXC, 0x00C0, gpg2, 2),
115 GPIO_GRP(5, MUXC, 0x00E0, gpj4, 4),
116
117 GPIO_GRP(5, MUXD, 0x0000, gpa0, 8),
118 GPIO_GRP(5, MUXD, 0x0020, gpa1, 6),
119 GPIO_GRP(5, MUXD, 0x0040, gpa2, 8),
120 GPIO_GRP(5, MUXD, 0x0060, gpb0, 5),
121 GPIO_GRP(5, MUXD, 0x0080, gpb1, 5),
122 GPIO_GRP(5, MUXD, 0x00A0, gpb2, 4),
123 GPIO_GRP(5, MUXD, 0x00C0, gpb3, 8),
124 GPIO_GRP(5, MUXD, 0x00E0, gpb4, 2),
125 GPIO_GRP(5, MUXD, 0x0100, gph0, 4),
126
127 GPIO_GRP(5, MUXE, 0x0000, gpz, 7),
128
129 };
130
131 struct exynos_gpio_bank *exynos_gpio_banks = exynos5_banks;
132
133 static int exynos_gpio_pin_read(void *, int);
134 static void exynos_gpio_pin_write(void *, int, int);
135 static void exynos_gpio_pin_ctl(void *, int, int);
136 static void *exynos_gpio_fdt_acquire(device_t, const void *,
137 size_t, int);
138 static void exynos_gpio_fdt_release(device_t, void *);
139
140 static int exynos_gpio_fdt_read(device_t, void *, bool);
141 static void exynos_gpio_fdt_write(device_t, void *, int, bool);
142 static int exynos_gpio_cfprint(void *, const char *);
143
144 struct fdtbus_gpio_controller_func exynos_gpio_funcs = {
145 .acquire = exynos_gpio_fdt_acquire,
146 .release = exynos_gpio_fdt_release,
147 .read = exynos_gpio_fdt_read,
148 .write = exynos_gpio_fdt_write
149 };
150 #define GPIO_WRITE(bank, reg, val) \
151 bus_space_write_4((bank)->bank_sc->sc_bst, \
152 (bank)->bank_sc->sc_bsh, \
153 (bank)->bank_core_offset + (reg), (val))
154 #define GPIO_READ(bank, reg) \
155 bus_space_read_4((bank)->bank_sc->sc_bst, \
156 (bank)->bank_sc->sc_bsh, \
157 (bank)->bank_core_offset + (reg))
158
159 static int
160 exynos_gpio_cfprint(void *priv, const char *pnp)
161 {
162 struct gpiobus_attach_args *gba = priv;
163 struct exynos_gpio_bank *bank = gba->gba_gc->gp_cookie;
164 const char *bankname = bank->bank_name;
165
166 if (pnp)
167 aprint_normal("gpiobus at %s", pnp);
168
169 aprint_normal(" (%s)", bankname);
170
171 return UNCONF;
172 }
173
174 static int
175 exynos_gpio_pin_read(void *cookie, int pin)
176 {
177 struct exynos_gpio_bank * const bank = cookie;
178 uint8_t val;
179
180 KASSERT(pin < bank->bank_bits);
181 val = bus_space_read_1(bank->bank_sc->sc_bst, bank->bank_sc->sc_bsh,
182 EXYNOS_GPIO_DAT);
183
184 return __SHIFTOUT(val, __BIT(pin));
185 }
186
187 static void
188 exynos_gpio_pin_write(void *cookie, int pin, int value)
189 {
190 struct exynos_gpio_bank * const bank = cookie;
191 int val;
192
193 KASSERT(pin < bank->bank_bits);
194 val = bus_space_read_1(bank->bank_sc->sc_bst, bank->bank_sc->sc_bsh,
195 EXYNOS_GPIO_DAT);
196 val &= ~__BIT(pin);
197 if (value)
198 val |= __BIT(pin);
199 bus_space_write_1(bank->bank_sc->sc_bst, bank->bank_sc->sc_bsh,
200 EXYNOS_GPIO_DAT, val);
201 }
202
203 static void
204 exynos_gpio_pin_ctl(void *cookie, int pin, int flags)
205 {
206 struct exynos_gpio_bank * const bank = cookie;
207 struct exynos_gpio_pin_cfg ncfg = { 0 };
208
209 /* honour pullup requests */
210 if (flags & GPIO_PIN_PULLUP) {
211 ncfg.pud = EXYNOS_GPIO_PIN_PULL_UP;
212 ncfg.pud_valid = true;
213 }
214 if (flags & GPIO_PIN_PULLDOWN) {
215 ncfg.pud = EXYNOS_GPIO_PIN_PULL_DOWN;
216 ncfg.pud_valid = true;
217 }
218
219 /* honour i/o */
220 if (flags & GPIO_PIN_INPUT) {
221 ncfg.cfg = EXYNOS_GPIO_FUNC_INPUT;
222 ncfg.cfg_valid = true;
223 } else if (flags & GPIO_PIN_OUTPUT) {
224 ncfg.cfg = EXYNOS_GPIO_FUNC_OUTPUT;
225 ncfg.cfg_valid = true;
226 }
227
228 /* update any config registers that changed */
229 exynos_gpio_pin_ctl_write(bank, &ncfg, pin);
230 }
231
232 void exynos_gpio_pin_ctl_write(const struct exynos_gpio_bank *bank,
233 const struct exynos_gpio_pin_cfg *cfg,
234 int pin)
235 {
236 uint32_t val;
237
238 if (cfg->cfg_valid) {
239 val = GPIO_READ(bank, EXYNOS_GPIO_CON);
240 val &= ~(0xf << (pin * 4));
241 val |= (cfg->cfg << (pin * 4));
242 GPIO_WRITE(bank, EXYNOS_GPIO_CON, val);
243 }
244
245 if (cfg->pud_valid) {
246 val = GPIO_READ(bank, EXYNOS_GPIO_PUD);
247 val &= ~(0x3 << (pin * 2));
248 val |= (cfg->pud << (pin * 2));
249 GPIO_WRITE(bank, EXYNOS_GPIO_PUD, val);
250 }
251
252 if (cfg->drv_valid) {
253 val = GPIO_READ(bank, EXYNOS_GPIO_DRV);
254 val &= ~(0x3 << (pin * 2));
255 val |= (cfg->drv << (pin * 2));
256 GPIO_WRITE(bank, EXYNOS_GPIO_DRV, val);
257 }
258
259 if (cfg->conpwd_valid) {
260 val = GPIO_READ(bank, EXYNOS_GPIO_CONPWD);
261 val &= ~(0x3 << (pin * 2));
262 val |= (cfg->conpwd << (pin * 2));
263 GPIO_WRITE(bank, EXYNOS_GPIO_CONPWD, val);
264 }
265
266 if (cfg->pudpwd_valid) {
267 val = GPIO_READ(bank, EXYNOS_GPIO_PUDPWD);
268 val &= ~(0x3 << (pin * 2));
269 val |= (cfg->pudpwd << (pin * 2));
270 GPIO_WRITE(bank, EXYNOS_GPIO_PUDPWD, val);
271 }
272 }
273
274 struct exynos_gpio_softc *
275 exynos_gpio_bank_config(struct exynos_pinctrl_softc * parent,
276 const struct fdt_attach_args *faa, int node)
277 {
278 struct exynos_gpio_bank *bank = kmem_zalloc(sizeof(*bank), KM_SLEEP);
279 struct exynos_gpio_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
280 struct gpiobus_attach_args gba;
281 struct gpio_chipset_tag *gc_tag;
282 char result[64];
283
284 OF_getprop(node, "name", result, sizeof(result));
285 bank = exynos_gpio_bank_lookup(result);
286 if (bank == NULL) {
287 aprint_error_dev(parent->sc_dev, "no bank found for %s\n",
288 result);
289 return NULL;
290 }
291
292 sc->sc_dev = parent->sc_dev;
293 sc->sc_bst = &armv7_generic_bs_tag;
294 sc->sc_bsh = parent->sc_bsh;
295 sc->sc_bank = bank;
296
297 gc_tag = &bank->bank_gc;
298 gc_tag->gp_cookie = bank;
299 gc_tag->gp_pin_read = exynos_gpio_pin_read;
300 gc_tag->gp_pin_write = exynos_gpio_pin_write;
301 gc_tag->gp_pin_ctl = exynos_gpio_pin_ctl;
302 memset(&gba, 0, sizeof(gba));
303 gba.gba_gc = &bank->bank_gc;
304 gba.gba_pins = bank->bank_pins;
305 gba.gba_npins = bank->bank_bits;
306 bank->bank_sc = sc;
307 bank->bank_dev = config_found_ia(parent->sc_dev, "gpiobus", &gba,
308 exynos_gpio_cfprint);
309
310 /* read in our initial settings */
311 bank->bank_cfg.cfg = GPIO_READ(bank, EXYNOS_GPIO_CON);
312 bank->bank_cfg.pud = GPIO_READ(bank, EXYNOS_GPIO_PUD);
313 bank->bank_cfg.drv = GPIO_READ(bank, EXYNOS_GPIO_DRV);
314 bank->bank_cfg.conpwd = GPIO_READ(bank, EXYNOS_GPIO_CONPWD);
315 bank->bank_cfg.pudpwd = GPIO_READ(bank, EXYNOS_GPIO_PUDPWD);
316
317 fdtbus_register_gpio_controller(bank->bank_dev, node,
318 &exynos_gpio_funcs);
319 return sc;
320 }
321
322 /*
323 * This function is a bit funky. Given a string that may look like
324 * 'gpAN' or 'gpAN-P' it is meant to find a match to the part before
325 * the '-', or the four character string if the dash is not present.
326 */
327 struct exynos_gpio_bank *
328 exynos_gpio_bank_lookup(const char *name)
329 {
330 struct exynos_gpio_bank *bank;
331
332 for (u_int n = 0; n < __arraycount(exynos5_banks); n++) {
333 bank = &exynos_gpio_banks[n];
334 if (!strncmp(bank->bank_name, name,
335 strlen(bank->bank_name))) {
336 return bank;
337 }
338 }
339
340 return NULL;
341 }
342
343 #if notyet
344 static int
345 exynos_gpio_pin_lookup(const char *name)
346 {
347 char *p;
348
349 p = strchr(name, '-');
350 if (p == NULL || p[1] < '0' || p[1] > '9')
351 return -1;
352
353 return p[1] - '0';
354 }
355 #endif
356
357 static void *
358 exynos_gpio_fdt_acquire(device_t dev, const void *data, size_t len, int flags)
359 {
360 const u_int *cells = data;
361 struct exynos_gpio_bank *bank = NULL;
362 struct exynos_gpio_pin *gpin;
363 int n;
364
365 if (len != 12)
366 return NULL;
367
368 const int pin = be32toh(cells[1]) & 0x0f;
369 const int actlo = be32toh(cells[2]) & 0x01;
370
371 for (n = 0; n < __arraycount(exynos5_banks); n++) {
372 if (exynos_gpio_banks[n].bank_dev == dev) {
373 bank = &exynos_gpio_banks[n];
374 break;
375 }
376 }
377 if (bank == NULL)
378 return NULL;
379
380 gpin = kmem_alloc(sizeof(*gpin), KM_SLEEP);
381 gpin->pin_sc = bank->bank_sc;
382 gpin->pin_bank = bank;
383 gpin->pin_no = pin;
384 gpin->pin_flags = flags;
385 gpin->pin_actlo = actlo;
386
387 exynos_gpio_pin_ctl(bank, gpin->pin_no, gpin->pin_flags);
388
389 return gpin;
390 }
391
392 static void
393 exynos_gpio_fdt_release(device_t dev, void *priv)
394 {
395 struct exynos_gpio_pin *gpin = priv;
396
397 kmem_free(gpin, sizeof(*gpin));
398 }
399
400 static int
401 exynos_gpio_fdt_read(device_t dev, void *priv, bool raw)
402 {
403 struct exynos_gpio_pin *gpin = priv;
404 int val;
405
406 val = (bus_space_read_1(gpin->pin_sc->sc_bst,
407 gpin->pin_sc->sc_bsh,
408 EXYNOS_GPIO_DAT) >> gpin->pin_no) & 1;
409
410 if (!raw && gpin->pin_actlo)
411 val = !val;
412
413 return val;
414 }
415
416 static void
417 exynos_gpio_fdt_write(device_t dev, void *priv, int val, bool raw)
418 {
419 struct exynos_gpio_pin *gpin = priv;
420
421 if (!raw && gpin->pin_actlo)
422 val = !val;
423
424 val = bus_space_read_1(gpin->pin_sc->sc_bst,
425 gpin->pin_sc->sc_bsh,
426 EXYNOS_GPIO_DAT);
427 val &= ~__BIT(gpin->pin_no);
428 if (val)
429 val |= __BIT(gpin->pin_no);
430 bus_space_write_1(gpin->pin_sc->sc_bst,
431 gpin->pin_sc->sc_bsh,
432 EXYNOS_GPIO_DAT, val);
433
434 }
435