Implement the gpio-mailbox api for brcm w/ NEXUS.

This change adds an implementation of the low-level
BRCM API for gpio-mailbox that uses the BRCM provided
nexus API (via nxclient). In order to facilitate this
change, the original broadcom.c file is split into
the public pin API and a new private HAL API (defined
in brcm-platform.h).

The old mmap implementation is moved to brcm-direct.c
while the nexus implementation lives in brcm-nexus.c.
The backing implementation for a given system can be
swapped as necessary, although the nexus API only supports
the GFHD254 as of now.

Change-Id: I7488c7856179d3082b8cb15721d4d06c786c42ae
diff --git a/gpio-mailbox/brcm-direct.c b/gpio-mailbox/brcm-direct.c
new file mode 100644
index 0000000..6de0934
--- /dev/null
+++ b/gpio-mailbox/brcm-direct.c
@@ -0,0 +1,648 @@
+#ifdef BROADCOM
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "brcm-platform.h"
+
+#define UNUSED        __attribute__((unused))
+#define DEVMEM       "/dev/mem"
+
+const int PWM_CYCLE_PERIOD = 0x63;
+
+static volatile void* mmap_addr = MAP_FAILED;
+static size_t mmap_size = 0;
+static int mmap_fd = -1;
+
+static void init_gfhd200(UNUSED struct platform_info* p);
+static void init_gfhd254(UNUSED struct platform_info* p);
+static double get_avs_voltage_7252(struct Voltage* v);
+static double get_avs_voltage_74xx(struct Voltage* v);
+static double get_avs_temperature_7252(struct Temp* t);
+static double get_avs_temperature_74xx(struct Temp* t);
+
+struct platform_info platforms[] = {
+  {
+    .name = "GFHD100",
+    .mmap_base = 0x10400000,            // base of many brcm registers
+    .mmap_size = 0x40000,
+    .leds = {
+      .led_red = {
+        .is_present = 1,                  // GPIO 17
+        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+        .mask = 0x00020000,               // 1<<17
+        .shift = 17,
+        .off_value = 0,
+        .on_value = 1,
+        .direction_value = 0,
+        .old_val = -1,
+      },
+      .led_blue = {
+        .is_present = 1,                  // GPIO 12
+        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+        .mask = 0x00001000,               // 1<<12
+        .shift = 12,
+        .off_value = 0,
+        .on_value = 1,
+        .direction_value = 0,
+        .old_val = -1,
+      },
+      .led_activity = {
+        .is_present = 1,                  // GPIO 13
+        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+        .mask = 0x00002000,               // 1<<13
+        .shift = 13,
+        .off_value = 0,
+        .on_value = 1,
+        .direction_value = 0,
+        .old_val = -1,
+      },
+      .led_standby = {
+        .is_present = 1,                  // GPIO 10
+        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+        .mask = 0x00000400,               // 1<<10
+        .shift = 10,
+        .off_value = 0,
+        .on_value = 1,
+        .direction_value = 0,
+        .old_val = -1,
+      },
+    },
+    .reset_button = {
+      .is_present = 1,                  // GPIO 4
+      .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+      .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+      .mask = 0x00000010,               // 1<<4
+      .shift = 4,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_tick = {
+      .is_present = 1,                  // GPIO 98
+      .offset_direction = 0x6768,       // GIO_IODIR_EXT_HI
+      .offset_data = 0x6764,            // GIO_DATA_EXT_HI
+      .mask = 0x00000100,               // 1<<8
+      .shift = 8,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_control = {
+      .is_present = 1,                  // PWM 1
+      .offset_data = 0x6580,            // PWM_CTRL ...
+      .channel = 0,
+      .open_drain = 1,
+    },
+    .temp_monitor = {
+      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
+      .offset_data = 0x32b00,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
+      .get_temp = get_avs_temperature_74xx,
+    },
+    .voltage_monitor = {
+      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
+      .offset_data = 0x32b0c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1P10V_0_MNTR_STATUS
+      .get_voltage = get_avs_voltage_74xx,
+    },
+  },
+  {
+    .name = "GFMS100",
+    .mmap_base = 0x10400000,            // base of many brcm registers
+    .mmap_size = 0x40000,
+    .leds = {
+      .led_red = {
+        .is_present = 1,                  // GPIO 17
+        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+        .offset_data = 0x94c4,            // GIO_AON_DATA_LO 0..17
+        .mask = 0x00020000,               // 1<<17
+        .shift = 17,
+        .off_value = 0,
+        .on_value = 1,
+        .direction_value = 0,
+        .old_val = -1,
+      },
+      .led_blue = {
+        .is_present = 0,
+      },
+      .led_activity = {
+        .is_present = 1,                  // GPIO 13
+        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+        .mask = 0x00002000,               // 1<<13
+        .shift = 13,
+        .off_value = 0,
+        .on_value = 1,
+        .direction_value = 0,
+        .old_val = -1,
+      },
+      .led_standby = {
+        .is_present = 0,
+      },
+    },
+    .reset_button = {
+      .is_present = 1,                  // GPIO 4
+      .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
+      .offset_data = 0x94c4,            // GIO_AON_DATA_LO
+      .mask = 0x00000010,               // 1<<4
+      .shift = 4,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_tick = {
+      .is_present = 1,                  // GPIO 98
+      .offset_direction = 0x6768,       // GIO_IODIR_EXT_HI
+      .offset_data = 0x6764,            // GIO_DATA_EXT_HI
+      .mask = 0x00000100,               // 1<<8
+      .shift = 8,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_control = {
+      .is_present = 1,                  // PWM 1
+      .offset_data = 0x6580,            // PWM_CTRL ...
+      .channel = 0,
+      .open_drain = 1,
+    },
+    .temp_monitor = {
+      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
+      .offset_data = 0x32b00,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
+      .get_temp = get_avs_temperature_74xx,
+    },
+    .voltage_monitor = {
+      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
+      .offset_data = 0x32b0c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1P10V_0_MNTR_STATUS
+      .get_voltage = get_avs_voltage_74xx,
+    },
+  },
+  {
+    .name = "GFHD200",
+    .init = init_gfhd200,
+    .mmap_base = 0x10400000,            // AON_PIN_CTRL ...
+    .mmap_size = 0x30000,
+    .leds = {
+      .led_red = {
+        .is_present = 1,                  // GPIO 5
+        .pinmux_offset = 0x8500,          // PIN_MUX_CTRL_0
+        .pinmux_mask = 0xf0000000,
+        .pinmux_value = 0x10000000,       // LED_LD1 (segment 1 on led digit1)
+        .offset_data = 0x9018,            // GIO_AON_DATA_LO
+        .mask = 0x00000002,               // 1<<1
+        .shift = 1,
+        .off_value =1,
+        .on_value = 0,
+        .old_val = -1,
+      },
+      .led_blue = {
+        .is_present = 0,
+      },
+      .led_activity = {
+        .is_present = 1,                  // GPIO 4
+        .pinmux_offset = 0x8500,          // PIN_MUX_CTRL_0
+        .pinmux_mask = 0x0f000000,
+        .pinmux_value = 0x01000000,       // LED_LD0 (segment 0 on led digit1)
+        .offset_data = 0x9018,            // GIO_AON_DATA_LO
+        .mask = 0x00000001,               // 1<<0
+        .shift = 0,
+        .off_value = 1,
+        .on_value = 0,
+        .old_val = -1,
+      },
+      .led_standby = {
+        .is_present = 0,
+      },
+    },
+    .reset_button = {
+      .is_present = 1,                  // GPIO 3
+      .offset_direction = 0x9808,       // GIO_AON_IODIR_LO
+      .offset_data = 0x9804,            // GIO_AON_DATA_LO
+      .mask = 0x00000008,               // 1<<3
+      .shift = 3,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_control = {
+      .is_present = 0,
+    },
+    .temp_monitor = {
+      .is_present = 1,                  // 7429 AVS_RO_REGISTERS_0
+      .offset_data = 0x23300,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
+      .get_temp = get_avs_temperature_74xx,
+    },
+    .voltage_monitor = {
+      .is_present = 1,                  // 7429 AVS_RO_REGISTERS_0
+      .offset_data = 0x2330c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1P10V_0_MNTR_STATUS
+      .get_voltage = get_avs_voltage_74xx,
+    },
+  },
+  {
+    .name = "GFHD254",
+    .init = init_gfhd254,
+    .mmap_base = 0xf0400000,            // AON_PIN_CTRL ...
+    .mmap_size =    0xe0000,
+    .leds = {
+      .led_red = {
+        .is_present = 1,                  // AON_GPIO_05
+        .pinmux_offset = 0x10700,         // PIN_MUX_CTRL_0
+        .pinmux_mask =  0x00f00000,
+        .pinmux_value = 0x00200000,       // LED_LD_13
+        .offset_data = 0x1701c,           // LDK_DIGIT1
+        .mask = 1<<13,                    // 1<<13
+        .shift = 13,
+        .off_value =1,
+        .on_value = 0,
+        .old_val = -1,
+      },
+      .led_blue = {
+        .is_present = 0,
+      },
+      .led_activity = {
+        .is_present = 1,                  // AON_GPIO_04
+        .pinmux_offset = 0x10700,         // PIN_MUX_CTRL_0
+        .pinmux_mask = 0x000f0000,
+        .pinmux_value = 0x00020000,       // LED_LD_12
+        .offset_data = 0x1701c,           // LDK_DIGIT1
+        .mask = 1<<12,                    // 1<<12
+        .shift = 12,
+        .off_value = 1,
+        .on_value = 0,
+        .old_val = -1,
+      },
+      .led_standby = {
+        .is_present = 0,
+      },
+      .led_brightness = {
+        .is_present = 1,                // GPIO_098
+        .open_drain = 0,
+        .offset_data = 0x9000,          // PWM_2
+        .channel = 0,
+        .old_percent = -1,
+      },
+    },
+    .reset_button = {
+      .is_present = 1,                  // GPIO_009
+      .pinmux_offset = 0x4120,          // SUN_TOP_CTRL_PIN_MUX_CTRL_8
+      .pinmux_mask = 0xf0000000,
+      .pinmux_value = 0x00000000,       // GPIO_009
+      .offset_direction = 0xa608,       // GIO_IODIR_LO
+      .offset_data = 0xa604,            // GIO_DATA_LO
+      .mask = 0x00000200,               // 1<<9
+      .shift = 9,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_tick = {
+      .is_present = 1,                  // GPIO 78
+      .offset_direction = 0xa648,       // GIO_IODIR_EXT_HI
+      .offset_data = 0xa644,            // GIO_DATA_EXT_HI
+      .mask = 1<<14,
+      .shift = 14,
+      .off_value = 0,
+      .on_value = 1,
+      .direction_value = 1,
+      .old_val = -1,
+    },
+    .fan_control = {
+      .is_present = 1,                  // PWM 3
+      .offset_data = 0x9000,            // PWM_CTRL ...
+      .channel = 1,
+      .open_drain = 0,
+    },
+    .temp_monitor = {
+      .is_present = 1,                  // 7252 AVS_RO_REGISTERS_0
+      .offset_data = 0xd2200,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
+      .get_temp = get_avs_temperature_7252,
+    },
+    .voltage_monitor = {
+      .is_present = 1,                  // 7252 AVS_RO_REGISTERS_0
+      .offset_data = 0xd220c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1V_0_MNTR_STATUS
+      .get_voltage = get_avs_voltage_7252,
+    },
+  }
+};
+
+
+struct platform_info *get_platform_info(const char *platform_name) {
+  int lim = sizeof(platforms) / sizeof(platforms[0]);
+  for (int i = 0; i < lim; ++i) {
+    struct platform_info *p = &platforms[i];
+    if (0 == strncmp(platform_name, p->name, strlen(p->name))) {
+      return p;
+    }
+  }
+  fprintf(stderr, "No support for platform %s", platform_name);
+  return NULL;
+}
+
+/* set LED/Keypad timings to control LED brightness */
+static void init_gfhd200(UNUSED struct platform_info* p) {
+  volatile uint32_t* reg;
+
+  reg = mmap_addr + 0x9034;     // LDK_CONTROL
+  *reg = 0x01;                  // reset
+  *reg = 0x18;                  // ver=1 inv_led=1
+
+  reg = mmap_addr + 0x9008;     // LDK_PRESCHI, LO (clock divisor)
+  reg[0] = 0x00;
+  reg[1] = 0x10;                // tick = clock / 0x0010, not sure what clock is
+
+  reg = mmap_addr + 0x9010;     // LDK_DUTYOFF, ON
+  reg[0] = 0x40;
+  reg[1] = 0xc0;                // 0x40 off ticks then 0xc0 on ticks == 75% brightness
+}
+
+/* set LED/Keypad timings to control LED brightness */
+static void init_gfhd254(struct platform_info* p) {
+  volatile uint32_t* reg;
+
+  // The following comment explains how the LED controller works on <= EVT3.
+  //  For EVT4+, the LED controller was changed to control via PWM. We currently
+  //  configure both. The EVT3 specific code can be removed at a later date.
+  //
+  // The led display controller works like this:
+  //  - there are 16 gpios (we connect our leds to 2 of these)
+  //  - the controller steps through digit1-4 and then status
+  //  - bit0 in a register maps to a particular gpio
+  //     when digit1 is being displayed the controller uses digit1_bit[15:0] to
+  //     drive the gpios.  When digit 2 is displayed digit2[15:0] and so forth.
+  //  - duty_on controls how many clocks a digit is displayed
+  //  - duty_off controls number of clocks of all off time when switching
+  //    between digits
+  //
+  //  To get 100% brightness you set all of digit1-4 and status to 1 for the led
+  //  you are drivng, and set duty_off to 0.
+  //
+  //  Here we also invert the values, so a 1 means off, and 0 means on, this is
+  //  done because for unknown reasons the time between status and digit1 is on,
+  //  so we can't get the brightness to 0 unless we invert.
+  //
+  //  For simplicity we enable only one of the digits because the leds are
+  //  already insanely bright, and then to disable an led we simply toggle the
+  //  bit in that one digit register.
+  //
+  //  The red led is attached to bit 13 and blue led is attached to bit 12.
+  reg = mmap_addr + 0x17034;     // LDK_CONTROL
+  *reg = 0x01;                   // reset
+  *reg = 0x18;                   // ver=1
+
+  reg = mmap_addr + 0x17018;
+  reg[0] = 0xffff;               // LDK_DIGIT2
+  reg[1] = 0xcfff;               // LDK_DIGIT1
+  reg[2] = 0xffff;               // LDK_DIGIT4
+  reg[3] = 0xffff;               // LDK_DIGIT3
+  reg[5] = 0xffff;               // LDK_STATUS
+
+  reg = mmap_addr + 0x17008;     // LDK_PRESCHI, LO (clock divisor)
+  reg[0] = 0x00;
+  reg[1] = 0x10;                 // tick = clock / 0x0010, not sure what clock is
+
+  reg = mmap_addr + 0x17010;     // LDK_DUTYOFF, ON
+  reg[0] = 0x40;
+  reg[1] = 0xc0;                 // 0x40 off ticks then 0xc0 on ticks to dim a bit more.
+
+  // The fan is connected to PWM3, the register PWM3_CWORD_LSB is set to 1,
+  // this is the frequency of the PWM, the other pwm register control
+  // the duty cycle.
+  reg = mmap_addr + 0x9014;       // PWM3_CWORD_LSB
+  reg[0] = 1;
+
+  // LEDs are connected to PWM2. Setting CWORD_LSB to 0xf to control
+  // the output freq of the var rate clock.
+  reg = mmap_addr + 0x900c;
+  reg[0] = 0xf;
+
+  // Default the LED brightness to 50.
+  set_pwm(&p->leds.led_brightness, 50);
+}
+
+static double get_avs_voltage_7252(struct Voltage* v) {
+  volatile uint32_t* reg;
+  uint32_t value, valid, raw_data;
+
+  reg = mmap_addr + v->offset_data;
+  value = *reg;
+  valid = (value & 0x00000400) >> 10;
+  raw_data = value & 0x000003ff;
+  if (!valid) return -1.0;
+  return ((880.0/1024.0)/(0.7)*raw_data) / 1000;
+}
+
+static double get_avs_voltage_74xx(struct Voltage* v) {
+  volatile uint32_t* reg;
+  uint32_t value, valid, raw_data;
+
+  reg = mmap_addr + v->offset_data;
+  value = *reg;
+  // see 7425-PR500-RDS.pdf
+  valid = (value & 0x00000400) >> 10;
+  raw_data = value & 0x000003ff;
+  if (!valid) return -1.0;
+  return ((990 * raw_data * 8) / (7*1024)) / 1000.0;
+}
+
+static double get_avs_temperature_74xx(struct Temp* t) {
+  volatile uint32_t* reg;
+  uint32_t value, valid, raw_data;
+
+  reg = mmap_addr + t->offset_data;
+  value = *reg;
+  // see 7425-PR500-RDS.pdf
+  valid = (value & 0x00000400) >> 10;
+  raw_data = value & 0x000003ff;
+  if (!valid) return -1.0;
+  return (418000 - (556 * raw_data)) / 1000.0;
+}
+
+static double get_avs_temperature_7252(struct Temp* t) {
+  volatile uint32_t* reg;
+  uint32_t value, valid, raw_data;
+
+  reg = mmap_addr + t->offset_data;
+  value = *reg;
+  valid = (value & 0x00000400) >> 10;
+  raw_data = value & 0x000003ff;
+  if (!valid) return -1.0;
+  return 410.04 - (0.48705 * raw_data);
+}
+
+/*
+   platform_init has three steps:
+   1) Generic platform init. This sets up the mmap.
+   2) Platform-specific init. Calls the gf* function
+   corresponding to the passed in platform.
+   3) GPIO init. Sets up the gpios properly.
+*/
+int platform_init(struct platform_info* p) {
+  platform_cleanup();
+
+  mmap_fd = open(DEVMEM, O_RDWR);
+  if (mmap_fd < 0) {
+    perror(DEVMEM);
+    return -1;
+  }
+  mmap_size = p->mmap_size;
+  mmap_addr = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, p->mmap_base);
+  if (mmap_addr == MAP_FAILED) {
+    perror("mmap");
+    platform_cleanup();
+    return -1;
+  }
+
+  if (p->init) {
+    (*p->init)(p);
+  }
+
+  set_pinmux(&p->leds.led_red);
+  set_pinmux(&p->leds.led_blue);
+  set_pinmux(&p->leds.led_activity);
+  set_pinmux(&p->leds.led_standby);
+
+  set_direction(&p->leds.led_red);
+  set_direction(&p->leds.led_blue);
+  set_direction(&p->leds.led_activity);
+  set_direction(&p->leds.led_standby);
+  set_direction(&p->reset_button);
+  set_direction(&p->fan_tick);
+
+  return 0;
+}
+
+void platform_cleanup() {
+  if (mmap_addr != MAP_FAILED) {
+    if (munmap((void*) mmap_addr, mmap_size) < 0) {
+      perror("munmap");
+    }
+    mmap_addr = MAP_FAILED;
+    mmap_size = 0;
+  }
+  if (mmap_fd >= 0) {
+    close(mmap_fd);
+    mmap_fd = -1;
+  }
+
+}
+
+void set_gpio(struct Gpio *g, int level) {
+  volatile uint32_t* reg;
+  uint32_t value;
+
+  if (g->old_val == level) {
+    // If this is the same value as last time, don't do anything, for two
+    // reasons:
+    //   1) If you set the gpio too often, it seems to stay low (the led
+    //      stays off).
+    //   2) If some process other than us is twiddling a led, this way we
+    //      won't interfere with it.
+    return;
+  }
+  g->old_val = level;
+
+  reg = mmap_addr + g->offset_data;
+  value = *reg;
+  value &= ~g->mask;
+  value |= (level ? g->on_value : g->off_value) << g->shift;
+  *reg = value;
+}
+
+int get_gpio(struct Gpio *g) {
+  volatile uint32_t* reg;
+  uint32_t value;
+
+  reg = mmap_addr + g->offset_data;
+  value = (*reg & g->mask) >> g->shift;
+  return (value == g->on_value);
+}
+
+void set_pwm(struct PwmControl *f, int percent) {
+  volatile uint32_t* reg;
+  uint32_t mask0, val0, mask1, val1, on;
+
+  if (percent < 0) percent = 0;
+  if (percent > 100) percent = 100;
+  if (f->old_percent == percent) return;
+  f->old_percent = percent;
+
+  reg = mmap_addr + f->offset_data;
+  if (f->channel == 0) {
+    mask0 = 0xf0;       // preserve other channel
+    val0 = 0x01;        // open-drain|start
+    if (f->open_drain)
+      val0 |= 0x08;
+    mask1 = 0x10;       // preserve
+    val1 = 0x01;        // constant-freq
+    on = 6;
+  } else {
+    mask0 = 0x0f;       // see above
+    val0 = 0x10;
+    if (f->open_drain)
+      val0 |= 0x80;
+    mask1 = 0x01;
+    val1 = 0x10;
+    on = 8;
+  }
+  reg[0] = (reg[0] & mask0) | val0;
+  reg[1] = (reg[1] & mask1) | val1;
+  reg[on] = (PWM_CYCLE_PERIOD * percent)/100;         // 0x63 is what old code used
+  reg[on+1] = PWM_CYCLE_PERIOD;
+}
+
+/* PWM operates on either channel 0 or 1. We want to get the duty cycle value
+   by calculating it from the "ON" register, located offset 6 for channel 0
+   and 8 for channel 1.
+
+   Duty cycle is calculated by ON / Period.
+*/
+int get_pwm(struct PwmControl *f) {
+  volatile uint32_t* reg = mmap_addr + f->offset_data;
+  uint8_t offset = f->channel ? 8 : 6;
+  uint32_t val = reg[offset];
+  return ((uint64_t)val * 100) / PWM_CYCLE_PERIOD;
+}
+
+void set_direction(struct Gpio *g) {
+  volatile uint32_t* reg;
+  uint32_t value;
+
+  if (!g->is_present || g->offset_direction == 0)
+    return;
+
+  reg = mmap_addr + g->offset_direction;
+  value = *reg;
+  value &= ~g->mask;
+  value |= g->direction_value << g->shift;
+  *reg = value;
+}
+
+void set_pinmux(struct Gpio *g) {
+  volatile uint32_t* reg;
+  uint32_t value;
+
+  if (!g->is_present || g->pinmux_offset == 0)
+    return;
+
+  reg = mmap_addr + g->pinmux_offset;
+  value = *reg;
+  value &= ~g->pinmux_mask;
+  value |= g->pinmux_value;
+  *reg = value;
+}
+
+#endif // BROADCOM
diff --git a/gpio-mailbox/brcm-nexus.c b/gpio-mailbox/brcm-nexus.c
new file mode 100644
index 0000000..d52e5f1
--- /dev/null
+++ b/gpio-mailbox/brcm-nexus.c
@@ -0,0 +1,326 @@
+#ifdef ANDROID    /* Should work fine on non Android platforms, but is only necessary on Android */
+#ifdef BROADCOM
+
+/* Broadcom platform implementation using the NEXUS API.
+   Only the GFHD254 is supported via this API as of now. */
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "brcm-platform.h"
+
+#include "nexus_avs.h"
+#include "nexus_pwm.h"
+#include "nexus_gpio.h"
+#include "nxclient.h"
+
+#define UNUSED        __attribute__((unused))
+#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
+
+static void init_gfhd254(struct platform_info* p);
+static double get_avs_voltage_7252(struct Voltage* v);
+static double get_avs_temperature_7252(struct Temp* t);
+
+const int PWM_CYCLE_PERIOD = 0x63;
+
+/* This is an array. Of structs! It contains structs of
+   the type platform_info. The platform_info struct provides
+   much useful information for use in all sorts of fun
+   operations. Structs are considered "aggregate types",
+   which you can of course read all about by pointing your
+   browser at Google and searching for your favorite version
+   of our beloved C standard, such as ISO/IEC 9899:TC3! */
+struct platform_info platforms[] = {
+  {
+    .name = "GFHD254",
+    .init = init_gfhd254,
+    .leds = {
+      .led_red = {
+        .is_present = 1,                  // AON_GPIO_05
+        .type = AON,
+        .pin = 5,
+        .old_val = -1,
+      },
+      .led_blue = {
+        .is_present = 0,
+      },
+      .led_activity = {
+        .is_present = 1,                  // AON_GPIO_04
+        .pin = 4,
+        .type = AON,
+        .old_val = -1,
+      },
+      .led_standby = {
+        .is_present = 0,
+      },
+      .led_brightness = {
+        .is_present = 1,                // GPIO_098
+        .open_drain = 0,
+        .pwm_index = 2,
+        .old_percent = -1,
+      },
+    },
+    .reset_button = {
+      .is_present = 1,                  // GPIO_009
+      .pin = 9,
+      .type = STANDARD,
+      .old_val = -1,
+    },
+    .fan_tick = {
+      .is_present = 1,                  // GPIO 78
+      .pin = 78,
+      .type = STANDARD,
+      .old_val = -1,
+    },
+    .fan_control = {
+      .is_present = 1,                // GPIO_098
+      .open_drain = 0,
+      .pwm_index = 3,
+      .old_percent = -1,
+    },
+    .temp_monitor = {
+      .is_present = 1,                  // 7252 AVS_RO_REGISTERS_0
+      .get_temp = get_avs_temperature_7252,
+    },
+    .voltage_monitor = {
+      .is_present = 1,
+      .get_voltage = get_avs_voltage_7252,
+    },
+  }
+};
+
+struct platform_info *get_platform_info(const char *platform_name) {
+  for (unsigned int i = 0; i < ARRAYSIZE(platforms); ++i) {
+    struct platform_info *p = &platforms[i];
+    if (0 == strncmp(platform_name, p->name, strlen(p->name))) {
+      return p;
+    }
+  }
+  fprintf(stderr, "No support for platform %s", platform_name);
+  return NULL;
+}
+
+static NEXUS_GpioType get_nexus_type(enum GpioType type) {
+  switch (type) {
+    case STANDARD:
+      return NEXUS_GpioType_eStandard;
+    case AON:
+      return NEXUS_GpioType_eAonStandard;
+  }
+
+  /* If we added a GpioType and are using it and never updated this, we
+     are going to have a bad time somewhere. Return an invalid val and let
+     nxclient handle it, while logging the problem. */
+  fprintf(stderr, "No matching NEXUS type for GPIO: %d\n", type);
+  return -1;
+}
+
+// Don't need to set direction for GFHD254
+static void initialize_gpio(struct Gpio* gpio) {
+  if (!gpio || !gpio->is_present)
+    return;
+
+  /* TODO(doughorn): Cannot set pinmux from NEXUS? Can retrieve
+     pinmux information but can't set it because it is 'dangerous'.
+     So we can use the raw Read/WriteRegister functions. These, however,
+     are also dangerous and their "indiscriminate use will result in
+     system failure." Seems to work properly without us setting... */
+  NEXUS_GpioSettings gpioSettings;
+  NEXUS_GpioHandle handle;
+  NEXUS_GpioType type = get_nexus_type(gpio->type);
+
+  NEXUS_Gpio_GetDefaultSettings(type, &gpioSettings);
+  gpioSettings.mode = NEXUS_GpioMode_eOutputPushPull;
+  gpioSettings.interruptMode = NEXUS_GpioInterrupt_eDisabled;
+
+  handle = NEXUS_Gpio_Open(type, gpio->pin, &gpioSettings);
+  if (!handle) {
+    fprintf(stderr, "Failed opening GPIO pin %d. gpio-mailbox cannot continue.\n", gpio->pin);
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Gpio_Close(handle);
+}
+
+/* TODO(doughorn): We can probably avoid calling GetAvsStatus twice for
+   the voltage and temp individually, but the poll rate is low enough
+   that it most likely doesn't matter...*/
+static double get_avs_voltage_7252(UNUSED struct Voltage* v) {
+  NEXUS_AvsStatus status;
+  if (NEXUS_GetAvsStatus(&status)) {
+    fprintf(stderr, "Could not get AVS status. Aborting...\n");
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  /* NEXUS_AvsStatus.voltage measured in millivolts */
+  return (double)status.voltage / 1000;
+}
+
+static double get_avs_temperature_7252(UNUSED struct Temp* t) {
+  NEXUS_AvsStatus status;
+
+  if (NEXUS_GetAvsStatus(&status)) {
+    fprintf(stderr, "Could not get AVS status. Aborting...\n");
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  /* Temp is in thousands of a degree. */
+  return (double)status.temperature / 1000;
+}
+
+static void init_gfhd254(struct platform_info* p) {
+  NEXUS_PwmChannelSettings pwmSettings;
+  NEXUS_PwmChannelHandle pwm;
+  NEXUS_PwmFreqModeType frequencyMode;
+
+  /* Set the control word for the led brightness PWM to 0xf.
+   This is used to control the output frequency from the
+   variable rate clock. */
+  NEXUS_Pwm_GetDefaultChannelSettings(&pwmSettings);
+  pwm = NEXUS_Pwm_OpenChannel(2, &pwmSettings);
+  if (NEXUS_Pwm_SetControlWord(pwm, 0xf)) {
+    fprintf(stderr, "Failed setting control word for PWM.\n");
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Pwm_CloseChannel(pwm);
+
+  /* Set the control word for the fan to 0x1. */
+  NEXUS_Pwm_GetDefaultChannelSettings(&pwmSettings);
+  pwm = NEXUS_Pwm_OpenChannel(3, &pwmSettings);
+  if (NEXUS_Pwm_SetControlWord(pwm, 0x1)) {
+    fprintf(stderr, "Failed setting control word for PWM.\n");
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Pwm_CloseChannel(pwm);
+
+  // Default the LED brightness to 50.
+  set_pwm(&p->leds.led_brightness, 50);
+}
+
+void platform_cleanup() {
+  NxClient_Uninit();
+}
+
+int platform_init(struct platform_info* p) {
+  if (NxClient_Join(NULL)) {
+    fprintf(stderr, "gpio-mailbox failed to connect to nxserver. Aborting...\n");
+    return -1;
+  }
+
+  if (p->init) {
+    (*p->init)(p);
+  }
+
+  initialize_gpio(&p->leds.led_red);
+  initialize_gpio(&p->leds.led_blue);
+  initialize_gpio(&p->leds.led_activity);
+  initialize_gpio(&p->leds.led_standby);
+  return 0;
+}
+
+void set_gpio(struct Gpio *gpio, int level) {
+  if (!gpio || !gpio->is_present || gpio->old_val == level) {
+    // If this is the same value as last time, don't do anything, for two
+    // reasons:
+    //   1) If you set the gpio too often, it seems to stay low (the led
+    //      stays off).
+    //   2) If some process other than us is twiddling a led, this way we
+    //      won't interfere with it.
+    return;
+  }
+
+  gpio->old_val = level;
+
+  NEXUS_GpioSettings gpioSettings;
+  NEXUS_GpioHandle handle;
+  uint32_t error;
+  NEXUS_GpioType type = get_nexus_type(gpio->type);
+
+  handle = NEXUS_Gpio_Open(type, gpio->pin, NULL);
+  if (!handle) {
+    fprintf(stderr, "Failed opening GPIO pin %d. Cannot continue.\n", gpio->pin);
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Gpio_GetSettings(handle, &gpioSettings);
+  gpioSettings.value = level ? NEXUS_GpioValue_eHigh : NEXUS_GpioValue_eLow;
+  if ((error = NEXUS_Gpio_SetSettings(handle, &gpioSettings))) {
+    fprintf(stderr, "Failed setting GPIO pin %d. Cannot continue.\n", gpio->pin);
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Gpio_Close(handle);
+}
+
+int get_gpio(struct Gpio *gpio) {
+  if (!gpio || !gpio->is_present)
+    return 0;
+
+  NEXUS_GpioStatus status;
+  NEXUS_GpioHandle handle;
+  uint32_t error;
+  NEXUS_GpioType type = get_nexus_type(gpio->type);
+
+  handle = NEXUS_Gpio_Open(type, gpio->pin, NULL);
+
+  if (!handle) {
+    fprintf(stderr, "Failed opening GPIO pin %d. Cannot continue.\n", gpio->pin);
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  if ((error = NEXUS_Gpio_GetStatus(handle, &status))) {
+    fprintf(stderr, "Failed getting status of GPIO pin %d. Cannot continue.\n", gpio->pin);
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Gpio_Close(handle);
+
+  return status.value != NEXUS_GpioValue_eLow;
+}
+
+void set_pwm(struct PwmControl *f, int percent) {
+  if (percent < 0) percent = 0;
+  if (percent > 100) percent = 100;
+  if (percent == f->old_percent) return;
+  f->old_percent = percent;
+
+  NEXUS_PwmChannelSettings pwmSettings;
+  NEXUS_PwmChannelHandle pwm;
+  uint16_t onInterval = (PWM_CYCLE_PERIOD * percent)/100;
+
+  NEXUS_Pwm_GetDefaultChannelSettings(&pwmSettings);
+  pwmSettings.openDrain = f->open_drain;
+  pwmSettings.eFreqMode = NEXUS_PwmFreqModeType_eConstant;
+  pwm = NEXUS_Pwm_OpenChannel(f->pwm_index, &pwmSettings);
+
+  if (NEXUS_Pwm_SetOnAndPeriodInterval(pwm, onInterval, PWM_CYCLE_PERIOD)) {
+    fprintf(stderr, "Could not set ON and PERIOD for PWM. Aborting...\n");
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  if (NEXUS_Pwm_Start(pwm)) {
+    fprintf(stderr, "Could not start PWM %d!\n", f->pwm_index);
+    platform_cleanup();
+    exit(EXIT_FAILURE);
+  }
+
+  NEXUS_Pwm_CloseChannel(pwm);
+}
+
+#endif // BROADCOM
+#endif // ANDROID
diff --git a/gpio-mailbox/brcm-platform.h b/gpio-mailbox/brcm-platform.h
new file mode 100644
index 0000000..1322c60
--- /dev/null
+++ b/gpio-mailbox/brcm-platform.h
@@ -0,0 +1,113 @@
+/*
+ * Hardware abstraction layer for GPIO's and PWMs.
+ */
+
+#ifndef BRCM_PLATFORM_
+#define BRCM_PLATFORM_
+
+/*
+ * Defines the category that a given GPIO falls under.
+ */
+enum GpioType {
+  STANDARD,
+  AON,
+};
+
+struct Gpio {
+  int is_present;
+
+  unsigned int pinmux_offset;
+  unsigned int pinmux_mask;
+  unsigned int pinmux_value;
+
+  unsigned int offset_direction;
+  unsigned int offset_data;
+
+  /* for offset_direction and offset_data */
+  unsigned int mask;                    // eg, (*reg & mask) >> shift == on_value
+  unsigned int shift;
+  unsigned int off_value;
+  unsigned int on_value;
+  unsigned int direction_value;         // 0 is output
+  unsigned int pin;                     // gpio #
+  enum GpioType type;                   // 'type' of gpio (aon/standard)
+  int old_val;
+};
+
+struct PwmControl {
+  int is_present;
+  int open_drain;
+  unsigned int offset_data;
+  unsigned int pwm_index;               // index of this pwm.
+  unsigned int channel;
+  int old_percent;
+};
+
+struct Temp {
+  int is_present;
+  unsigned int offset_data;
+  double (*get_temp)(struct Temp* t);
+};
+
+struct Voltage {
+  int is_present;
+  unsigned int offset_data;
+  double (*get_voltage)(struct Voltage* v);
+};
+
+struct Leds {
+  struct Gpio led_red;
+  struct Gpio led_blue;
+  struct Gpio led_activity;
+  struct Gpio led_standby;
+  struct PwmControl led_brightness;
+};
+
+struct platform_info {
+  const char *name;
+  off_t mmap_base;
+  size_t mmap_size;
+  void (*init)(struct platform_info* p);
+  struct Leds leds;
+  struct Gpio reset_button;
+  struct Gpio fan_tick;
+  struct PwmControl fan_control;
+  struct Temp temp_monitor;
+  struct Voltage voltage_monitor;
+};
+
+/* This value, from old code, controls the pwm period. The duty cycle
+  is defined as on/(period + 1) and on is defined as (on/Fv). Fv is
+  the frequency of the variable rate PWM.*/
+extern const int PWM_CYCLE_PERIOD;
+
+/* Return the master platform_info struct for the provided platforn_name.
+   If no platform matches, returns NULL */
+extern struct platform_info *get_platform_info(const char *);
+
+/* Initialize the platform! */
+extern int platform_init(struct platform_info *);
+
+/* Cleanup the platform! */
+extern void platform_cleanup();
+
+/* Set the gpio represented by to the provided level.
+   Level is restricted to [0, 1] */
+extern void set_gpio(struct Gpio *, int);
+
+/* Get the value of the gpio provided. */
+extern int get_gpio(struct Gpio *);
+
+/* Set the provided PWM to the given duty cycle percent */
+extern void set_pwm(struct PwmControl *, int);
+
+/* Return the duty cycle for the given PWM */
+extern int get_pwm(struct PwmControl *);
+
+/* Init GPIO to input or output. */
+extern void set_direction(struct Gpio *);
+
+/* Set the pinmux (init pin to LED, GPIO, etc) */
+extern void set_pinmux(struct Gpio *);
+
+#endif
diff --git a/gpio-mailbox/broadcom.c b/gpio-mailbox/broadcom.c
index a53e51e..7540571 100644
--- a/gpio-mailbox/broadcom.c
+++ b/gpio-mailbox/broadcom.c
@@ -2,35 +2,19 @@
 
 #define _POSIX_C_SOURCE 199309L /* for clock_gettime */
 #define _BSD_SOURCE             /* for usleep */
-#include <features.h>
 
-#include <assert.h>
 #include <fcntl.h>
-#include <signal.h>
+#include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/select.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include <sys/wait.h>
-#include <sys/mman.h>
+#include <stacktrace.h>
+#include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
-#include <stacktrace.h>
 
+#include "brcm-platform.h"
 #include "pin.h"
 
-#define UNUSED        __attribute__((unused))
-
-#define DEVMEM          "/dev/mem"
-
-/* This value, from old code, controls the pwm period. The duty cycle
-  is defined as on/(period + 1) and on is defined as (on/Fv). Fv is
-  the frequency of the variable rate PWM.*/
-static const int PWM_CYCLE_PERIOD = 0x63;
-
 struct PinHandle_s {
   int   unused;
 };
@@ -43,556 +27,8 @@
     } \
   } while (0)
 
-static volatile void* mmap_addr = MAP_FAILED;
-static size_t mmap_size = 0;
-static int mmap_fd = -1;
-
-struct Gpio {
-  int is_present;
-
-  unsigned int pinmux_offset;
-  unsigned int pinmux_mask;
-  unsigned int pinmux_value;
-
-  unsigned int offset_direction;
-  unsigned int offset_data;
-
-  /* for offset_direction and offset_data */
-  unsigned int mask;                    // eg, (*reg & mask) >> shift == on_value
-  unsigned int shift;
-  unsigned int off_value;
-  unsigned int on_value;
-  unsigned int direction_value;         // 0 is output
-  int old_val;
-};
-
-struct PwmControl {
-  int is_present;
-  int open_drain;
-  unsigned int offset_data;
-  unsigned int channel;
-  int old_percent;
-};
-
-struct Temp {
-  int is_present;
-  unsigned int offset_data;
-  double (*get_temp)(struct Temp* t);
-};
-
-struct Voltage {
-  int is_present;
-  unsigned int offset_data;
-  double (*get_voltage)(struct Voltage* v);
-};
-
-struct Leds {
-  struct Gpio led_red;
-  struct Gpio led_blue;
-  struct Gpio led_activity;
-  struct Gpio led_standby;
-  struct PwmControl led_brightness;
-};
-
-struct platform_info {
-  const char *name;
-  off_t mmap_base;
-  size_t mmap_size;
-  void (*init)(struct platform_info* p);
-  struct Leds leds;
-  struct Gpio reset_button;
-  struct Gpio fan_tick;
-  struct PwmControl fan_control;
-  struct Temp temp_monitor;
-  struct Voltage voltage_monitor;
-};
-
-static void init_gfhd200(struct platform_info* p);
-static void init_gfhd254(struct platform_info* p);
-static double get_avs_temperature_74xx(struct Temp* t);
-static double get_avs_temperature_7252(struct Temp* t);
-static double get_avs_voltage_74xx(struct Voltage* v);
-static double get_avs_voltage_7252(struct Voltage* v);
-
-struct platform_info platforms[] = {
-  {
-    .name = "GFHD100",
-    .mmap_base = 0x10400000,            // base of many brcm registers
-    .mmap_size = 0x40000,
-    .leds = {
-      .led_red = {
-        .is_present = 1,                  // GPIO 17
-        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-        .mask = 0x00020000,               // 1<<17
-        .shift = 17,
-        .off_value = 0,
-        .on_value = 1,
-        .direction_value = 0,
-        .old_val = -1,
-      },
-      .led_blue = {
-        .is_present = 1,                  // GPIO 12
-        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-        .mask = 0x00001000,               // 1<<12
-        .shift = 12,
-        .off_value = 0,
-        .on_value = 1,
-        .direction_value = 0,
-        .old_val = -1,
-      },
-      .led_activity = {
-        .is_present = 1,                  // GPIO 13
-        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-        .mask = 0x00002000,               // 1<<13
-        .shift = 13,
-        .off_value = 0,
-        .on_value = 1,
-        .direction_value = 0,
-        .old_val = -1,
-      },
-      .led_standby = {
-        .is_present = 1,                  // GPIO 10
-        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-        .mask = 0x00000400,               // 1<<10
-        .shift = 10,
-        .off_value = 0,
-        .on_value = 1,
-        .direction_value = 0,
-        .old_val = -1,
-      },
-    },
-    .reset_button = {
-      .is_present = 1,                  // GPIO 4
-      .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-      .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-      .mask = 0x00000010,               // 1<<4
-      .shift = 4,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_tick = {
-      .is_present = 1,                  // GPIO 98
-      .offset_direction = 0x6768,       // GIO_IODIR_EXT_HI
-      .offset_data = 0x6764,            // GIO_DATA_EXT_HI
-      .mask = 0x00000100,               // 1<<8
-      .shift = 8,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_control = {
-      .is_present = 1,                  // PWM 1
-      .offset_data = 0x6580,            // PWM_CTRL ...
-      .channel = 0,
-      .open_drain = 1,
-    },
-    .temp_monitor = {
-      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
-      .offset_data = 0x32b00,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
-      .get_temp = get_avs_temperature_74xx,
-    },
-    .voltage_monitor = {
-      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
-      .offset_data = 0x32b0c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1P10V_0_MNTR_STATUS
-      .get_voltage = get_avs_voltage_74xx,
-    },
-  },
-  {
-    .name = "GFMS100",
-    .mmap_base = 0x10400000,            // base of many brcm registers
-    .mmap_size = 0x40000,
-    .leds = {
-      .led_red = {
-        .is_present = 1,                  // GPIO 17
-        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-        .offset_data = 0x94c4,            // GIO_AON_DATA_LO 0..17
-        .mask = 0x00020000,               // 1<<17
-        .shift = 17,
-        .off_value = 0,
-        .on_value = 1,
-        .direction_value = 0,
-        .old_val = -1,
-      },
-      .led_blue = {
-        .is_present = 0,
-      },
-      .led_activity = {
-        .is_present = 1,                  // GPIO 13
-        .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-        .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-        .mask = 0x00002000,               // 1<<13
-        .shift = 13,
-        .off_value = 0,
-        .on_value = 1,
-        .direction_value = 0,
-        .old_val = -1,
-      },
-      .led_standby = {
-        .is_present = 0,
-      },
-    },
-    .reset_button = {
-      .is_present = 1,                  // GPIO 4
-      .offset_direction = 0x94c8,       // GIO_AON_IODIR_LO
-      .offset_data = 0x94c4,            // GIO_AON_DATA_LO
-      .mask = 0x00000010,               // 1<<4
-      .shift = 4,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_tick = {
-      .is_present = 1,                  // GPIO 98
-      .offset_direction = 0x6768,       // GIO_IODIR_EXT_HI
-      .offset_data = 0x6764,            // GIO_DATA_EXT_HI
-      .mask = 0x00000100,               // 1<<8
-      .shift = 8,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_control = {
-      .is_present = 1,                  // PWM 1
-      .offset_data = 0x6580,            // PWM_CTRL ...
-      .channel = 0,
-      .open_drain = 1,
-    },
-    .temp_monitor = {
-      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
-      .offset_data = 0x32b00,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
-      .get_temp = get_avs_temperature_74xx,
-    },
-    .voltage_monitor = {
-      .is_present = 1,                  // 7425 AVS_RO_REGISTERS_0
-      .offset_data = 0x32b0c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1P10V_0_MNTR_STATUS
-      .get_voltage = get_avs_voltage_74xx,
-    },
-  },
-  {
-    .name = "GFHD200",
-    .init = init_gfhd200,
-    .mmap_base = 0x10400000,            // AON_PIN_CTRL ...
-    .mmap_size = 0x30000,
-    .leds = {
-      .led_red = {
-        .is_present = 1,                  // GPIO 5
-        .pinmux_offset = 0x8500,          // PIN_MUX_CTRL_0
-        .pinmux_mask = 0xf0000000,
-        .pinmux_value = 0x10000000,       // LED_LD1 (segment 1 on led digit1)
-        .offset_data = 0x9018,            // GIO_AON_DATA_LO
-        .mask = 0x00000002,               // 1<<1
-        .shift = 1,
-        .off_value =1,
-        .on_value = 0,
-        .old_val = -1,
-      },
-      .led_blue = {
-        .is_present = 0,
-      },
-      .led_activity = {
-        .is_present = 1,                  // GPIO 4
-        .pinmux_offset = 0x8500,          // PIN_MUX_CTRL_0
-        .pinmux_mask = 0x0f000000,
-        .pinmux_value = 0x01000000,       // LED_LD0 (segment 0 on led digit1)
-        .offset_data = 0x9018,            // GIO_AON_DATA_LO
-        .mask = 0x00000001,               // 1<<0
-        .shift = 0,
-        .off_value = 1,
-        .on_value = 0,
-        .old_val = -1,
-      },
-      .led_standby = {
-        .is_present = 0,
-      },
-    },
-    .reset_button = {
-      .is_present = 1,                  // GPIO 3
-      .offset_direction = 0x9808,       // GIO_AON_IODIR_LO
-      .offset_data = 0x9804,            // GIO_AON_DATA_LO
-      .mask = 0x00000008,               // 1<<3
-      .shift = 3,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_control = {
-      .is_present = 0,
-    },
-    .temp_monitor = {
-      .is_present = 1,                  // 7429 AVS_RO_REGISTERS_0
-      .offset_data = 0x23300,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
-      .get_temp = get_avs_temperature_74xx,
-    },
-    .voltage_monitor = {
-      .is_present = 1,                  // 7429 AVS_RO_REGISTERS_0
-      .offset_data = 0x2330c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1P10V_0_MNTR_STATUS
-      .get_voltage = get_avs_voltage_74xx,
-    },
-  },
-  {
-    .name = "GFHD254",
-    .init = init_gfhd254,
-    .mmap_base = 0xf0400000,            // AON_PIN_CTRL ...
-    .mmap_size =    0xe0000,
-    .leds = {
-      .led_red = {
-        .is_present = 1,                  // AON_GPIO_05
-        .pinmux_offset = 0x10700,         // PIN_MUX_CTRL_0
-        .pinmux_mask =  0x00f00000,
-        .pinmux_value = 0x00200000,       // LED_LD_13
-        .offset_data = 0x1701c,           // LDK_DIGIT1
-        .mask = 1<<13,                    // 1<<13
-        .shift = 13,
-        .off_value =1,
-        .on_value = 0,
-        .old_val = -1,
-      },
-      .led_blue = {
-        .is_present = 0,
-      },
-      .led_activity = {
-        .is_present = 1,                  // AON_GPIO_04
-        .pinmux_offset = 0x10700,         // PIN_MUX_CTRL_0
-        .pinmux_mask = 0x000f0000,
-        .pinmux_value = 0x00020000,       // LED_LD_12
-        .offset_data = 0x1701c,           // LDK_DIGIT1
-        .mask = 1<<12,                    // 1<<12
-        .shift = 12,
-        .off_value = 1,
-        .on_value = 0,
-        .old_val = -1,
-      },
-      .led_standby = {
-        .is_present = 0,
-      },
-      .led_brightness = {
-        .is_present = 1,                // GPIO_098
-        .open_drain = 0,
-        .offset_data = 0x9000,          // PWM_2
-        .channel = 0,
-        .old_percent = -1,
-      },
-    },
-    .reset_button = {
-      .is_present = 1,                  // GPIO_009
-      .pinmux_offset = 0x4120,          // SUN_TOP_CTRL_PIN_MUX_CTRL_8
-      .pinmux_mask = 0xf0000000,
-      .pinmux_value = 0x00000000,       // GPIO_009
-      .offset_direction = 0xa608,       // GIO_IODIR_LO
-      .offset_data = 0xa604,            // GIO_DATA_LO
-      .mask = 0x00000200,               // 1<<9
-      .shift = 9,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_tick = {
-      .is_present = 1,                  // GPIO 78
-      .offset_direction = 0xa648,       // GIO_IODIR_EXT_HI
-      .offset_data = 0xa644,            // GIO_DATA_EXT_HI
-      .mask = 1<<14,
-      .shift = 14,
-      .off_value = 0,
-      .on_value = 1,
-      .direction_value = 1,
-      .old_val = -1,
-    },
-    .fan_control = {
-      .is_present = 1,                  // PWM 3
-      .offset_data = 0x9000,            // PWM_CTRL ...
-      .channel = 1,
-      .open_drain = 0,
-    },
-    .temp_monitor = {
-      .is_present = 1,                  // 7252 AVS_RO_REGISTERS_0
-      .offset_data = 0xd2200,           // BCHP_AVS_RO_REGISTERS_0_PVT_TEMPERATURE_MNTR_STATUS
-      .get_temp = get_avs_temperature_7252,
-    },
-    .voltage_monitor = {
-      .is_present = 1,                  // 7252 AVS_RO_REGISTERS_0
-      .offset_data = 0xd220c,           // BCHP_AVS_RO_REGISTERS_0_PVT_1V_0_MNTR_STATUS
-      .get_voltage = get_avs_voltage_7252,
-    },
-  }
-};
-
 struct platform_info *platform = NULL;
 
-/* PWM operates on either channel 0 or 1. We want to get the duty cycle value
-   by calculating it from the "ON" register, located offset 6 for channel 0
-   and 8 for channel 1.
-
-   Duty cycle is calculated by ON / Period.
-*/
-static UNUSED int get_pwm(struct PwmControl *f) {
-  volatile uint32_t* reg = mmap_addr + f->offset_data;
-  uint8_t offset = f->channel ? 8 : 6;
-  uint32_t val = reg[offset];
-  return ((uint64_t)val * 100) / PWM_CYCLE_PERIOD;
-}
-
-// Set the given PWM (pulse width modulator) to the given percent duty cycle.
-static void set_pwm(struct PwmControl *f, int percent) {
-  volatile uint32_t* reg;
-  uint32_t mask0, val0, mask1, val1, on;
-
-  if (percent < 0) percent = 0;
-  if (percent > 100) percent = 100;
-  if (f->old_percent == percent) return;
-  f->old_percent = percent;
-
-  reg = mmap_addr + f->offset_data;
-  if (f->channel == 0) {
-    mask0 = 0xf0;       // preserve other channel
-    val0 = 0x01;        // open-drain|start
-    if (f->open_drain)
-      val0 |= 0x08;
-    mask1 = 0x10;       // preserve
-    val1 = 0x01;        // constant-freq
-    on = 6;
-  } else {
-    mask0 = 0x0f;       // see above
-    val0 = 0x10;
-    if (f->open_drain)
-      val0 |= 0x80;
-    mask1 = 0x01;
-    val1 = 0x10;
-    on = 8;
-  }
-  reg[0] = (reg[0] & mask0) | val0;
-  reg[1] = (reg[1] & mask1) | val1;
-  reg[on] = (PWM_CYCLE_PERIOD * percent)/100;         // 0x63 is what old code used
-  reg[on+1] = PWM_CYCLE_PERIOD;
-}
-
-// Get the CPU temperature.  I think it's in Celsius.
-static double get_avs_temperature_74xx(struct Temp* t) {
-  volatile uint32_t* reg;
-  uint32_t value, valid, raw_data;
-
-  reg = mmap_addr + t->offset_data;
-  value = *reg;
-  // see 7425-PR500-RDS.pdf
-  valid = (value & 0x00000400) >> 10;
-  raw_data = value & 0x000003ff;
-  if (!valid) return -1.0;
-  return (418000 - (556 * raw_data)) / 1000.0;
-}
-
-static double get_avs_temperature_7252(struct Temp* t) {
-  volatile uint32_t* reg;
-  uint32_t value, valid, raw_data;
-
-  reg = mmap_addr + t->offset_data;
-  value = *reg;
-  valid = (value & 0x00000400) >> 10;
-  raw_data = value & 0x000003ff;
-  if (!valid) return -1.0;
-  return 410.04 - (0.48705 * raw_data);
-}
-
-static double get_avs_voltage_74xx(struct Voltage* v) {
-  volatile uint32_t* reg;
-  uint32_t value, valid, raw_data;
-
-  reg = mmap_addr + v->offset_data;
-  value = *reg;
-  // see 7425-PR500-RDS.pdf
-  valid = (value & 0x00000400) >> 10;
-  raw_data = value & 0x000003ff;
-  if (!valid) return -1.0;
-  return ((990 * raw_data * 8) / (7*1024)) / 1000.0;
-}
-
-static double get_avs_voltage_7252(struct Voltage* v) {
-  volatile uint32_t* reg;
-  uint32_t value, valid, raw_data;
-
-  reg = mmap_addr + v->offset_data;
-  value = *reg;
-  valid = (value & 0x00000400) >> 10;
-  raw_data = value & 0x000003ff;
-  if (!valid) return -1.0;
-  return ((880.0/1024.0)/(0.7)*raw_data) / 1000;
-}
-
-// Write the given GPIO pin.
-static void set_gpio(struct Gpio *g, int level) {
-  volatile uint32_t* reg;
-  uint32_t value;
-
-  if (g->old_val == level) {
-    // If this is the same value as last time, don't do anything, for two
-    // reasons:
-    //   1) If you set the gpio too often, it seems to stay low (the led
-    //      stays off).
-    //   2) If some process other than us is twiddling a led, this way we
-    //      won't interfere with it.
-    return;
-  }
-  g->old_val = level;
-
-  reg = mmap_addr + g->offset_data;
-  value = *reg;
-  value &= ~g->mask;
-  value |= (level ? g->on_value : g->off_value) << g->shift;
-  *reg = value;
-}
-
-
-// Read the given GPIO pin
-static int get_gpio(struct Gpio *g) {
-  volatile uint32_t* reg;
-  uint32_t value;
-
-  reg = mmap_addr + g->offset_data;
-  value = (*reg & g->mask) >> g->shift;
-  return (value == g->on_value);
-}
-
-
-// initialize GPIO to input or output
-static void set_direction(struct Gpio *g)
-{
-  volatile uint32_t* reg;
-  uint32_t value;
-
-  if (!g->is_present || g->offset_direction == 0)
-    return;
-
-  reg = mmap_addr + g->offset_direction;
-  value = *reg;
-  value &= ~g->mask;
-  value |= g->direction_value << g->shift;
-  *reg = value;
-}
-
-// initialize pin to LED or GPIO etc
-static void set_pinmux(struct Gpio *g) {
-  volatile uint32_t* reg;
-  uint32_t value;
-
-  if (!g->is_present || g->pinmux_offset == 0)
-    return;
-
-  reg = mmap_addr + g->pinmux_offset;
-  value = *reg;
-  value &= ~g->pinmux_mask;
-  value |= g->pinmux_value;
-  *reg = value;
-}
-
 // Same as time(), but in monotonic clock milliseconds instead.
 static long long msec_now(void) {
   struct timespec ts;
@@ -600,61 +36,6 @@
   return ((long long)ts.tv_sec) * 1000 + (ts.tv_nsec / 1000000);
 }
 
-static void platform_cleanup(void) {
-  if (mmap_addr != MAP_FAILED) {
-    if (munmap((void*) mmap_addr, mmap_size) < 0) {
-      perror("munmap");
-    }
-    mmap_addr = MAP_FAILED;
-    mmap_size = 0;
-  }
-  if (mmap_fd >= 0) {
-    close(mmap_fd);
-    mmap_fd = -1;
-  }
-}
-
-static void *mmap_(void* addr, size_t size, int prot, int flags, int fd,
-                   off_t offset) {
-#ifdef __ANDROID__
-  return mmap64(addr, size, prot, flags, fd, (off64_t)(uint64_t)(uint32_t)offset);
-#else
-  return mmap(addr, size, prot, flags, fd, offset);
-#endif
-}
-
-static int platform_init(struct platform_info* p) {
-  platform_cleanup();
-
-  mmap_fd = open(DEVMEM, O_RDWR);
-  if (mmap_fd < 0) {
-    perror(DEVMEM);
-    return -1;
-  }
-  mmap_size = p->mmap_size;
-  mmap_addr = mmap_(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED,
-                    mmap_fd, p->mmap_base);
-  if (mmap_addr == MAP_FAILED) {
-    perror("mmap");
-    platform_cleanup();
-    return -1;
-  }
-  return 0;
-}
-
-static struct platform_info *get_platform_info(const char *platform_name) {
-  int lim = sizeof(platforms) / sizeof(platforms[0]);
-  for (int i = 0; i < lim; ++i) {
-    struct platform_info *p = &platforms[i];
-    if (0 == strncmp(platform_name, p->name, strlen(p->name))) {
-      return p;
-    }
-  }
-  fprintf(stderr, "No support for platform %s", platform_name);
-  exit(1);
-}
-
-
 // read a file containing a single short string.
 // Returns a static buffer.  Be careful!
 static char *read_file(const char *filename) {
@@ -677,7 +58,6 @@
   return (platform->fan_control.is_present);
 }
 
-
 /*
  * We're polling at a very high frequency, which is a pain.  This would be
  * slightly less gross inside the kernel (for less context switching and
@@ -796,109 +176,6 @@
   set_pwm(&platform->leds.led_brightness, level);
 }
 
-/* set LED/Keypad timings to control LED brightness */
-static void init_gfhd200(UNUSED struct platform_info* p) {
-  volatile uint32_t* reg;
-
-  reg = mmap_addr + 0x9034;     // LDK_CONTROL
-  *reg = 0x01;                  // reset
-  *reg = 0x18;                  // ver=1 inv_led=1
-
-  reg = mmap_addr + 0x9008;     // LDK_PRESCHI, LO (clock divisor)
-  reg[0] = 0x00;
-  reg[1] = 0x10;                // tick = clock / 0x0010, not sure what clock is
-
-  reg = mmap_addr + 0x9010;     // LDK_DUTYOFF, ON
-  reg[0] = 0x40;
-  reg[1] = 0xc0;                // 0x40 off ticks then 0xc0 on ticks == 75% brightness
-}
-
-/* set LED/Keypad timings to control LED brightness */
-static void init_gfhd254(UNUSED struct platform_info* p) {
-  volatile uint32_t* reg;
-
-  // The following comment explains how the LED controller works on <= EVT3.
-  //  For EVT4+, the LED controller was changed to control via PWM. We currently
-  //  configure both. The EVT3 specific code can be removed at a later date.
-  //
-  // The led display controller works like this:
-  //  - there are 16 gpios (we connect our leds to 2 of these)
-  //  - the controller steps through digit1-4 and then status
-  //  - bit0 in a register maps to a particular gpio
-  //     when digit1 is being displayed the controller uses digit1_bit[15:0] to
-  //     drive the gpios.  When digit 2 is displayed digit2[15:0] and so forth.
-  //  - duty_on controls how many clocks a digit is displayed
-  //  - duty_off controls number of clocks of all off time when switching
-  //    between digits
-  //
-  //  To get 100% brightness you set all of digit1-4 and status to 1 for the led
-  //  you are drivng, and set duty_off to 0.
-  //
-  //  Here we also invert the values, so a 1 means off, and 0 means on, this is
-  //  done because for unknown reasons the time between status and digit1 is on,
-  //  so we can't get the brightness to 0 unless we invert.
-  //
-  //  For simplicity we enable only one of the digits because the leds are
-  //  already insanely bright, and then to disable an led we simply toggle the
-  //  bit in that one digit register.
-  //
-  //  The red led is attached to bit 13 and blue led is attached to bit 12.
-  reg = mmap_addr + 0x17034;     // LDK_CONTROL
-  *reg = 0x01;                   // reset
-  *reg = 0x18;                   // ver=1
-
-  reg = mmap_addr + 0x17018;
-  reg[0] = 0xffff;               // LDK_DIGIT2
-  reg[1] = 0xcfff;               // LDK_DIGIT1
-  reg[2] = 0xffff;               // LDK_DIGIT4
-  reg[3] = 0xffff;               // LDK_DIGIT3
-  reg[5] = 0xffff;               // LDK_STATUS
-
-  reg = mmap_addr + 0x17008;     // LDK_PRESCHI, LO (clock divisor)
-  reg[0] = 0x00;
-  reg[1] = 0x10;                 // tick = clock / 0x0010, not sure what clock is
-
-  reg = mmap_addr + 0x17010;     // LDK_DUTYOFF, ON
-  reg[0] = 0x40;
-  reg[1] = 0xc0;                 // 0x40 off ticks then 0xc0 on ticks to dim a bit more.
-
-  // The fan is connected to PWM3, the register PWM3_CWORD_LSB is set to 1,
-  // this is the frequency of the PWM, the other pwm register control
-  // the duty cycle.
-  reg = mmap_addr + 0x9014;       // PWM3_CWORD_LSB
-  reg[0] = 1;
-
-  // LEDs are connected to PWM2. Setting CWORD_LSB to 0xf to control
-  // the output freq of the var rate clock.
-  reg = mmap_addr + 0x900c;
-  reg[0] = 0xf;
-
-  // Default the LED brightness to 50.
-  set_led_brightness(50);
-}
-
-static void init_platform(struct platform_info* p) {
-  if (p->init) {
-    (*p->init)(p);
-  }
-}
-
-static void initialize_gpios(void) {
-  init_platform(platform);
-
-  set_pinmux(&platform->leds.led_red);
-  set_pinmux(&platform->leds.led_blue);
-  set_pinmux(&platform->leds.led_activity);
-  set_pinmux(&platform->leds.led_standby);
-
-  set_direction(&platform->leds.led_red);
-  set_direction(&platform->leds.led_blue);
-  set_direction(&platform->leds.led_activity);
-  set_direction(&platform->leds.led_standby);
-  set_direction(&platform->reset_button);
-  set_direction(&platform->fan_tick);
-}
-
 /* standard API follows */
 
 PinHandle PinCreate(void) {
@@ -907,13 +184,14 @@
     perror("calloc(PinHandle)");
     return NULL;
   }
+
   platform = get_platform_info(read_file("/etc/platform"));
   if (platform_init(platform) < 0) {
     fprintf(stderr, "platform_init failed\n");
     PinDestroy(handle);
     return NULL;
   }
-  initialize_gpios();
+
   return handle;
 }