Annotation of src/sys/arch/arm/samsung/exynos_gpio.c, Revision 1.11.2.3
1.11.2.3! skrll 1: /* $NetBSD: exynos_gpio.c,v 1.11.2.2 2015/12/27 12:09:32 skrll Exp $ */
1.9 skrll 2:
1.1 reinoud 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>
1.11.2.3! skrll 37: __KERNEL_RCSID(1, "$NetBSD: exynos_gpio.c,v 1.11.2.2 2015/12/27 12:09:32 skrll Exp $");
1.1 reinoud 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>
1.11.2.2 skrll 46:
1.1 reinoud 47: #include <dev/gpio/gpiovar.h>
48:
1.11.2.2 skrll 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>
1.1 reinoud 53:
1.11.2.2 skrll 54: #include <dev/fdt/fdtvar.h>
1.1 reinoud 55:
1.11.2.2 skrll 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: uint8_t bank_pin_mask;
67: uint8_t bank_pin_inuse_mask;
68: bus_space_handle_t bank_bsh;
69: struct exynos_gpio_pin_cfg bank_cfg;
70: struct exynos_gpio_bank * bank_next;
1.1 reinoud 71: };
72:
1.11.2.2 skrll 73: struct exynos_gpio_pin {
74: struct exynos_gpio_softc *pin_sc;
75: int pin_no;
76: u_int pin_flags;
77: int pin_actlo;
78: const struct exynos_gpio_bank *pin_bank;
79: };
80:
1.1 reinoud 81:
1.11.2.2 skrll 82: //#define GPIO_REG(v,s,o) (EXYNOS##v##_GPIO_##s##_OFFSET + (o))
83: #define GPIO_REG(v,s,o) ((o))
84: #define GPIO_GRP(v, s, o, n, b) \
85: { \
86: .bank_name = #n, \
87: .bank_core_offset = GPIO_REG(v,s,o), \
88: .bank_bits = b, \
89: }
90:
91: static struct exynos_gpio_bank exynos5_banks[] = {
92: GPIO_GRP(5, MUXA, 0x0000, gpy7, 8),
93: GPIO_GRP(5, MUXA, 0x0C00, gpx0, 8),
94: GPIO_GRP(5, MUXA, 0x0C20, gpx1, 8),
95: GPIO_GRP(5, MUXA, 0x0C40, gpx2, 8),
96: GPIO_GRP(5, MUXA, 0x0C60, gpx3, 8),
97:
98: GPIO_GRP(5, MUXB, 0x0000, gpc0, 8),
99: GPIO_GRP(5, MUXB, 0x0020, gpc1, 8),
100: GPIO_GRP(5, MUXB, 0x0040, gpc2, 7),
101: GPIO_GRP(5, MUXB, 0x0060, gpc3, 4),
102: GPIO_GRP(5, MUXB, 0x0080, gpc4, 2),
103: GPIO_GRP(5, MUXB, 0x00A0, gpd1, 8),
104: GPIO_GRP(5, MUXB, 0x00C0, gpy0, 6),
105: GPIO_GRP(5, MUXB, 0x00E0, gpy1, 4),
106: GPIO_GRP(5, MUXB, 0x0100, gpy2, 6),
107: GPIO_GRP(5, MUXB, 0x0120, gpy3, 8),
108: GPIO_GRP(5, MUXB, 0x0140, gpy4, 8),
109: GPIO_GRP(5, MUXB, 0x0160, gpy5, 8),
110: GPIO_GRP(5, MUXB, 0x0180, gpy6, 8),
111:
112: GPIO_GRP(5, MUXC, 0x0000, gpe0, 8),
113: GPIO_GRP(5, MUXC, 0x0020, gpe1, 2),
114: GPIO_GRP(5, MUXC, 0x0040, gpf0, 6),
115: GPIO_GRP(5, MUXC, 0x0060, gpf1, 8),
116: GPIO_GRP(5, MUXC, 0x0080, gpg0, 8),
117: GPIO_GRP(5, MUXC, 0x00A0, gpg1, 8),
118: GPIO_GRP(5, MUXC, 0x00C0, gpg2, 2),
119: GPIO_GRP(5, MUXC, 0x00E0, gpj4, 4),
120:
121: GPIO_GRP(5, MUXD, 0x0000, gpa0, 8),
122: GPIO_GRP(5, MUXD, 0x0020, gpa1, 6),
123: GPIO_GRP(5, MUXD, 0x0040, gpa2, 8),
124: GPIO_GRP(5, MUXD, 0x0060, gpb0, 5),
125: GPIO_GRP(5, MUXD, 0x0080, gpb1, 5),
126: GPIO_GRP(5, MUXD, 0x00A0, gpb2, 4),
127: GPIO_GRP(5, MUXD, 0x00C0, gpb3, 8),
128: GPIO_GRP(5, MUXD, 0x00E0, gpb4, 2),
129: GPIO_GRP(5, MUXD, 0x0100, gph0, 4),
1.1 reinoud 130:
1.11.2.3! skrll 131: GPIO_GRP(5, MUXE, 0x0000, gpz, 7),
1.1 reinoud 132:
1.11.2.2 skrll 133: };
1.1 reinoud 134:
1.11.2.2 skrll 135: struct exynos_gpio_bank *exynos_gpio_banks = exynos5_banks;
1.1 reinoud 136:
1.11.2.2 skrll 137: static int exynos_gpio_pin_read(void *, int);
138: static void exynos_gpio_pin_write(void *, int, int);
139: static void exynos_gpio_pin_ctl(void *, int, int);
140: static void *exynos_gpio_fdt_acquire(device_t, const void *,
141: size_t, int);
142: static void exynos_gpio_fdt_release(device_t, void *);
143:
144: static int exynos_gpio_fdt_read(device_t, void *, bool);
145: static void exynos_gpio_fdt_write(device_t, void *, int, bool);
146: static int exynos_gpio_cfprint(void *, const char *);
147:
148: struct fdtbus_gpio_controller_func exynos_gpio_funcs = {
149: .acquire = exynos_gpio_fdt_acquire,
150: .release = exynos_gpio_fdt_release,
151: .read = exynos_gpio_fdt_read,
152: .write = exynos_gpio_fdt_write
153: };
154: #define GPIO_WRITE(bank, reg, val) \
155: bus_space_write_4((bank)->bank_sc->sc_bst, \
156: (bank)->bank_sc->sc_bsh, \
157: (bank)->bank_core_offset + (reg), (val))
158: #define GPIO_READ(bank, reg) \
159: bus_space_read_4((bank)->bank_sc->sc_bst, \
160: (bank)->bank_sc->sc_bsh, \
161: (bank)->bank_core_offset + (reg))
1.1 reinoud 162:
163: static int
1.11.2.2 skrll 164: exynos_gpio_cfprint(void *priv, const char *pnp)
1.1 reinoud 165: {
1.11.2.2 skrll 166: struct gpiobus_attach_args *gba = priv;
167: struct exynos_gpio_bank *bank = gba->gba_gc->gp_cookie;
168: const char *bankname = bank->bank_name;
1.1 reinoud 169:
1.11.2.2 skrll 170: if (pnp)
171: aprint_normal("gpiobus at %s", pnp);
1.1 reinoud 172:
1.11.2.2 skrll 173: aprint_normal(" (%s)", bankname);
1.1 reinoud 174:
1.11.2.2 skrll 175: return UNCONF;
1.1 reinoud 176: }
177:
178: static void
1.11.2.2 skrll 179: exynos_gpio_update_cfg_regs(struct exynos_gpio_bank *bank,
180: const struct exynos_gpio_pin_cfg *ncfg)
1.1 reinoud 181: {
1.11.2.2 skrll 182: if (bank->bank_cfg.cfg != ncfg->cfg) {
183: GPIO_WRITE(bank, EXYNOS_GPIO_CON, ncfg->cfg);
184: bank->bank_cfg.cfg = ncfg->cfg;
185: }
186: if (bank->bank_cfg.pud != ncfg->pud) {
187: GPIO_WRITE(bank, EXYNOS_GPIO_PUD, ncfg->pud);
188: bank->bank_cfg.pud = ncfg->pud;
189: }
190:
191: if (bank->bank_cfg.drv != ncfg->drv) {
192: GPIO_WRITE(bank, EXYNOS_GPIO_DRV, ncfg->drv);
193: bank->bank_cfg.drv = ncfg->drv;
194: }
195: if (bank->bank_cfg.conpwd != ncfg->conpwd) {
196: GPIO_WRITE(bank, EXYNOS_GPIO_CONPWD, ncfg->conpwd);
197: bank->bank_cfg.conpwd = ncfg->conpwd;
198: }
199: if (bank->bank_cfg.pudpwd != ncfg->pudpwd) {
200: GPIO_WRITE(bank, EXYNOS_GPIO_PUDPWD, ncfg->pudpwd);
201: bank->bank_cfg.pudpwd = ncfg->pudpwd;
1.4 reinoud 202: }
1.1 reinoud 203: }
204:
205: static int
206: exynos_gpio_pin_read(void *cookie, int pin)
207: {
1.11.2.2 skrll 208: struct exynos_gpio_bank * const bank = cookie;
1.1 reinoud 209:
1.11.2.2 skrll 210: KASSERT(pin < bank->bank_bits);
211: return (bus_space_read_1(bank->bank_sc->sc_bst,
212: bank->bank_sc->sc_bsh,
1.1 reinoud 213: EXYNOS_GPIO_DAT) >> pin) & 1;
214: }
215:
216: static void
217: exynos_gpio_pin_write(void *cookie, int pin, int value)
218: {
1.11.2.2 skrll 219: struct exynos_gpio_bank * const bank = cookie;
1.1 reinoud 220: int val;
221:
1.11.2.2 skrll 222: KASSERT(pin < bank->bank_bits);
223: val = bus_space_read_1(bank->bank_sc->sc_bst,
224: bank->bank_sc->sc_bsh,
225: EXYNOS_GPIO_DAT);
1.1 reinoud 226: val &= ~__BIT(pin);
227: if (value)
228: val |= __BIT(pin);
1.11.2.2 skrll 229: bus_space_write_1(bank->bank_sc->sc_bst,
230: bank->bank_sc->sc_bsh,
1.1 reinoud 231: EXYNOS_GPIO_DAT, val);
232: }
233:
234: static void
235: exynos_gpio_pin_ctl(void *cookie, int pin, int flags)
236: {
1.11.2.2 skrll 237: struct exynos_gpio_bank * const bank = cookie;
238: struct exynos_gpio_pin_cfg ncfg = bank->bank_cfg;
239: u_int shift;
1.1 reinoud 240: int pull;
241:
242: /* honour pullup requests */
243: pull = EXYNOS_GPIO_PIN_FLOAT;
244: if (flags & GPIO_PIN_PULLUP)
245: pull = EXYNOS_GPIO_PIN_PULL_UP;
246: if (flags & GPIO_PIN_PULLDOWN)
247: pull = EXYNOS_GPIO_PIN_PULL_DOWN;
1.11.2.2 skrll 248: shift = (pin & 7) << 1;
249: ncfg.pud &= ~(0x3 << shift);
250: ncfg.pud |= pull << shift;
1.1 reinoud 251:
252: /* honour i/o */
1.11.2.2 skrll 253: if (flags & GPIO_PIN_INPUT) {
254: ncfg.cfg &= ~(0x0f << shift);
255: ncfg.cfg |= EXYNOS_GPIO_FUNC_INPUT << shift;
256: } else if (flags & GPIO_PIN_OUTPUT) {
257: ncfg.cfg &= ~(0x0f << shift);
258: ncfg.cfg |= EXYNOS_GPIO_FUNC_OUTPUT << shift;
1.1 reinoud 259: }
260:
1.11.2.2 skrll 261: /* update any config registers that changed */
262: exynos_gpio_update_cfg_regs(bank, &ncfg);
1.1 reinoud 263: }
264:
1.11.2.3! skrll 265: void exynos_gpio_pin_ctl_read(const struct exynos_gpio_bank *bank,
! 266: struct exynos_gpio_pin_cfg *cfg)
! 267: {
! 268: cfg->cfg = GPIO_READ(bank, EXYNOS_GPIO_CON);
! 269: cfg->pud = GPIO_READ(bank, EXYNOS_GPIO_PUD);
! 270: cfg->drv = GPIO_READ(bank, EXYNOS_GPIO_DRV);
! 271: cfg->conpwd = GPIO_READ(bank, EXYNOS_GPIO_CONPWD);
! 272: cfg->pudpwd = GPIO_READ(bank, EXYNOS_GPIO_PUDPWD);
! 273: }
! 274:
! 275: void exynos_gpio_pin_ctl_write(const struct exynos_gpio_bank *bank,
! 276: const struct exynos_gpio_pin_cfg *cfg)
! 277: {
! 278: GPIO_WRITE(bank, EXYNOS_GPIO_CON, cfg->cfg);
! 279: GPIO_WRITE(bank, EXYNOS_GPIO_PUD, cfg->pud);
! 280: GPIO_WRITE(bank, EXYNOS_GPIO_DRV, cfg->drv);
! 281: GPIO_WRITE(bank, EXYNOS_GPIO_CONPWD, cfg->conpwd);
! 282: GPIO_WRITE(bank, EXYNOS_GPIO_PUDPWD, cfg->pudpwd);
! 283: }
! 284:
! 285: struct exynos_gpio_softc *
1.11.2.2 skrll 286: exynos_gpio_bank_config(struct exynos_pinctrl_softc * parent,
287: const struct fdt_attach_args *faa, int node)
1.1 reinoud 288: {
1.11.2.2 skrll 289: struct exynos_gpio_bank *bank = kmem_zalloc(sizeof(*bank), KM_SLEEP);
290: struct exynos_gpio_softc *sc = kmem_zalloc(sizeof(*sc), KM_SLEEP);
291: struct gpiobus_attach_args gba;
292: struct gpio_chipset_tag *gc_tag;
293: char result[64];
1.1 reinoud 294:
1.11.2.2 skrll 295: OF_getprop(node, "name", result, sizeof(result));
1.11.2.3! skrll 296: bank = exynos_gpio_bank_lookup(result);
! 297: if (bank == NULL) {
! 298: aprint_error_dev(parent->sc_dev, "no bank found for %s\n",
! 299: result);
! 300: return NULL;
! 301: }
1.11.2.2 skrll 302:
303: sc->sc_dev = parent->sc_dev;
304: sc->sc_bst = &armv7_generic_bs_tag;
305: sc->sc_bsh = parent->sc_bsh;
1.11.2.3! skrll 306: sc->sc_bank = bank;
! 307:
1.11.2.2 skrll 308: gc_tag = &bank->bank_gc;
309: gc_tag->gp_cookie = bank;
310: gc_tag->gp_pin_read = exynos_gpio_pin_read;
311: gc_tag->gp_pin_write = exynos_gpio_pin_write;
312: gc_tag->gp_pin_ctl = exynos_gpio_pin_ctl;
313: memset(&gba, 0, sizeof(gba));
314: gba.gba_gc = &bank->bank_gc;
315: gba.gba_pins = bank->bank_pins;
316: gba.gba_npins = bank->bank_bits;
317: bank->bank_sc = sc;
318: bank->bank_dev = config_found_ia(parent->sc_dev, "gpiobus", &gba,
319: exynos_gpio_cfprint);
320:
321: bank->bank_pin_mask = __BIT(bank->bank_bits) - 1;
322: bank->bank_pin_inuse_mask = 0;
323:
324:
325: /* read in our initial settings */
326: bank->bank_cfg.cfg = GPIO_READ(bank, EXYNOS_GPIO_CON);
327: bank->bank_cfg.pud = GPIO_READ(bank, EXYNOS_GPIO_PUD);
328: bank->bank_cfg.drv = GPIO_READ(bank, EXYNOS_GPIO_DRV);
329: bank->bank_cfg.conpwd = GPIO_READ(bank, EXYNOS_GPIO_CONPWD);
330: bank->bank_cfg.pudpwd = GPIO_READ(bank, EXYNOS_GPIO_PUDPWD);
1.1 reinoud 331:
1.11.2.3! skrll 332: fdtbus_register_gpio_controller(bank->bank_dev, node,
1.11.2.2 skrll 333: &exynos_gpio_funcs);
1.11.2.3! skrll 334: return sc;
1.1 reinoud 335: }
336:
1.11.2.2 skrll 337: /*
1.11.2.3! skrll 338: * This function is a bit funky. Given a string that may look like
! 339: * 'gpAN' or 'gpAN-P' it is meant to find a match to the part before
! 340: * the '-', or the four character string if the dash is not present.
1.11.2.2 skrll 341: */
1.11.2.3! skrll 342: struct exynos_gpio_bank *
! 343: exynos_gpio_bank_lookup(const char *name)
1.5 reinoud 344: {
1.11.2.2 skrll 345: struct exynos_gpio_bank *bank;
346:
1.11.2.3! skrll 347: for (u_int n = 0; n < __arraycount(exynos5_banks); n++) {
1.11.2.2 skrll 348: bank = &exynos_gpio_banks[n];
1.11.2.3! skrll 349: if (!strncmp(bank->bank_name, name,
! 350: strlen(bank->bank_name))) {
1.11.2.2 skrll 351: return bank;
352: }
1.5 reinoud 353: }
354:
1.11.2.2 skrll 355: return NULL;
1.5 reinoud 356: }
357:
1.11.2.3! skrll 358: #if notyet
! 359: static int
! 360: exynos_gpio_pin_lookup(const char *name)
! 361: {
! 362: char *p;
! 363:
! 364: p = strchr(name, '-');
! 365: if (p == NULL || p[1] < '0' || p[1] > '9')
! 366: return -1;
! 367:
! 368: return p[1] - '0';
! 369: }
! 370: #endif
! 371:
1.11.2.2 skrll 372: static void *
373: exynos_gpio_fdt_acquire(device_t dev, const void *data, size_t len, int flags)
1.1 reinoud 374: {
1.11.2.3! skrll 375: const u_int *cells = data;
! 376: struct exynos_gpio_bank *bank = NULL;
1.11.2.2 skrll 377: struct exynos_gpio_pin *gpin;
1.11.2.3! skrll 378: int n;
! 379:
! 380: if (len != 12)
! 381: return NULL;
1.1 reinoud 382:
1.11.2.3! skrll 383: const int pin = be32toh(cells[1]) & 0x0f;
! 384: const int actlo = be32toh(cells[2]) & 0x01;
! 385:
! 386: for (n = 0; n < __arraycount(exynos5_banks); n++) {
! 387: if (exynos_gpio_banks[n].bank_dev == dev) {
! 388: bank = &exynos_gpio_banks[n];
! 389: break;
! 390: }
! 391: }
1.11.2.2 skrll 392: if (bank == NULL)
393: return NULL;
1.1 reinoud 394:
1.11.2.2 skrll 395: gpin = kmem_alloc(sizeof(*gpin), KM_SLEEP);
396: gpin->pin_sc = bank->bank_sc;
397: gpin->pin_bank = bank;
398: gpin->pin_no = pin;
399: gpin->pin_flags = flags;
1.11.2.3! skrll 400: gpin->pin_actlo = actlo;
1.1 reinoud 401:
1.11.2.3! skrll 402: exynos_gpio_pin_ctl(bank, gpin->pin_no, gpin->pin_flags);
1.1 reinoud 403:
1.11.2.2 skrll 404: return gpin;
405: }
1.1 reinoud 406:
1.11.2.2 skrll 407: static void
408: exynos_gpio_fdt_release(device_t dev, void *priv)
1.1 reinoud 409: {
1.11.2.2 skrll 410: struct exynos_gpio_pin *gpin = priv;
1.1 reinoud 411:
1.11.2.2 skrll 412: kmem_free(gpin, sizeof(*gpin));
413: }
1.1 reinoud 414:
1.11.2.2 skrll 415: static int
416: exynos_gpio_fdt_read(device_t dev, void *priv, bool raw)
417: {
418: struct exynos_gpio_pin *gpin = priv;
419: int val;
1.1 reinoud 420:
1.11.2.2 skrll 421: val = (bus_space_read_1(gpin->pin_sc->sc_bst,
422: gpin->pin_sc->sc_bsh,
423: EXYNOS_GPIO_DAT) >> gpin->pin_no) & 1;
1.1 reinoud 424:
1.11.2.2 skrll 425: if (!raw && gpin->pin_actlo)
426: val = !val;
1.1 reinoud 427:
1.11.2.2 skrll 428: return val;
1.1 reinoud 429: }
430:
1.11.2.2 skrll 431: static void
432: exynos_gpio_fdt_write(device_t dev, void *priv, int val, bool raw)
1.1 reinoud 433: {
1.11.2.2 skrll 434: struct exynos_gpio_pin *gpin = priv;
1.1 reinoud 435:
1.11.2.2 skrll 436: if (!raw && gpin->pin_actlo)
437: val = !val;
1.1 reinoud 438:
1.11.2.2 skrll 439: val = bus_space_read_1(gpin->pin_sc->sc_bst,
440: gpin->pin_sc->sc_bsh,
441: EXYNOS_GPIO_DAT);
442: val &= ~__BIT(gpin->pin_no);
443: if (val)
444: val |= __BIT(gpin->pin_no);
445: bus_space_write_1(gpin->pin_sc->sc_bst,
446: gpin->pin_sc->sc_bsh,
447: EXYNOS_GPIO_DAT, val);
1.1 reinoud 448:
449: }
CVSweb <webmaster@jp.NetBSD.org>