/* * atrf-gpio/atben.c - ATBEN-specific GPIO driver * * Written 2011 by Werner Almesberger * Copyright 2011 Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include #include #include #include #include "at86rf230.h" #include "atrf.h" #include "atrf-gpio.h" static struct pin { const char *name; int bit; } pins[] = { { "SCLK", 11 }, { "MISO", 10 }, { "SLP_TR", 9 }, { "MOSI", 8 }, { "nSEL", 13 }, { "IRQ", 12 }, { NULL, 0 } }; static uint32_t orig_dat, orig_pe, orig_dir; static uint32_t changed = 0; /* ----- Ben hardware ------------------------------------------------------ */ static volatile uint32_t *pdpin, *pddat, *pddats, *pddatc; static volatile uint32_t *pdpe, *pdpes, *pdpec; static volatile uint32_t *pddir, *pddirs, *pddirc; static void ben_setup(struct atrf_dsc *dsc) { volatile void *base = atrf_ben_regs(dsc); pdpin = base+0x10300; pddat = base+0x10310; pddats = base+0x10314; pddatc = base+0x10318; pdpe = base+0x10330; pdpes = base+0x10334; pdpec = base+0x10338; pddir = base+0x10360; pddirs = base+0x10364; pddirc = base+0x10368; } /* ----- Diagnostic dump --------------------------------------------------- */ static char decode_cfg(uint32_t bit) { if (*pddir & bit) return *pddat & bit ? '1' : '0'; return *pdpe & bit ? 'Z' : 'R'; } static void dump_pd(uint32_t expect, uint32_t got, uint32_t mask) { const struct pin *pin; fprintf(stderr, "name\tcfg exp got\n"); for (pin = pins; pin->name; pin++) { uint32_t bit = 1 << pin->bit; fprintf(stderr, "%s\t%c %c %d", pin->name, decode_cfg(bit), mask & bit ? expect & bit ? '1' : '0' : '-', !!(got & bit)); if ((expect ^ got) & mask & bit) fprintf(stderr, "\t***"); fputc('\n', stderr); } } static void restore_gpios(void) { *pddats = orig_dat & changed; *pddatc = ~orig_dat & changed; *pdpes = orig_pe & changed; *pdpec = ~orig_pe & changed; *pddirs = orig_dir & changed; *pddirc = ~orig_dir & changed; } /* ----- Decode and apply pattern ------------------------------------------ */ void do_atben(struct atrf_dsc *dsc, const char *pattern, const char *next) { static int first = 1; uint32_t read = 0, expect = 0; const struct pin *pin = pins; uint32_t got; const char *p; if (first) { ben_setup(dsc); orig_dat = *pddat; orig_pe = *pdpe; orig_dir = *pddir; atexit(restore_gpios); first = 0; } for (p = pattern; *p; p++) { uint32_t bit; if (!pin->name) { fprintf(stderr, "too many pins in \"%s\"\n", pattern); exit(1); } bit = 1 << pin->bit; switch (*p) { case '0': *pddatc = bit; *pddirs = bit; break; case '1': *pddats = bit; *pddirs = bit; break; case 'H': expect |= bit; /* fall through */ case 'L': read |= bit; /* fall through */ case 'Z': *pdpec = bit; *pddirc = bit; break; case 'h': expect |= bit; /* fall through */ case 'l': case 'o': read |= bit; /* fall through */ case 'z': *pddirc = bit; *pdpes = bit; break; case 'x': pin++; continue; default: continue; } changed |= bit; pin++; } usleep(1000); got = *pdpin; if ((got & read) != expect) { dump_pd(expect, got, read); fprintf(stderr, "at \"%s\", next \"%s\"\n", pattern, next); exit(1); } }