+#define DEBUG_MMC5983 0
+
+struct ao_mmc5983_sample ao_mmc5983_current;
+static struct ao_mmc5983_sample ao_mmc5983_offset;
+
+static uint8_t ao_mmc5983_configured;
+
+#ifdef MMC5983_I2C
+#ifdef AO_MMC5983_I2C_INDEX
+
+static void
+ao_mmc5983_start(void) {
+ ao_i2c_get(AO_MMC5983_I2C_INDEX);
+}
+
+static void
+ao_mmc5983_stop(void) {
+ ao_i2c_put(AO_MMC5983_I2C_INDEX);
+}
+
+static void
+ao_mmc5983_reg_write(uint8_t addr, uint8_t data)
+{
+ uint8_t d[2];
+
+ d[0] = addr;
+ d[1] = data;
+
+ ao_mmc5983_start();
+ ao_i2c_start(AO_MMC5983_I2C_INDEX, MMC5983_I2C_ADDR);
+ ao_i2c_send(d, 2, AO_MMC5983_I2C_INDEX, true);
+ ao_mmc5983_stop();
+}
+
+static uint8_t
+ao_mmc5983_reg_read(uint8_t addr)
+{
+ uint8_t d[1];
+
+ ao_mmc5983_start();
+ ao_i2c_start(AO_MMC5983_I2C_INDEX, MMC5983_I2C_ADDR);
+ d[0] = addr;
+ ao_i2c_send(d, 1, AO_MMC5983_I2C_INDEX, false);
+ ao_i2c_start(AO_MMC5983_I2C_INDEX, MMC5983_I2C_ADDR | 1);
+ ao_i2c_recv(d, 1, AO_MMC5983_I2C_INDEX, true);
+ ao_mmc5983_stop();
+ return d[0];
+}
+
+static void
+ao_mmc5983_raw(struct ao_mmc5983_raw *raw)
+{
+ ao_mmc5983_start();
+ ao_i2c_start(AO_MMC5983_I2C_INDEX, MMC5983_I2C_ADDR);
+ raw->addr = MMC5983_X_OUT_0;
+ ao_i2c_send(&(raw->addr), 1, AO_MMC5983_I2C_INDEX, false);
+ ao_i2c_start(AO_MMC5983_I2C_INDEX, MMC5983_I2C_ADDR | 1);
+ ao_i2c_recv(&(raw->x0), sizeof(*raw) - 1, AO_MMC5983_I2C_INDEX, true);
+ ao_mmc5983_stop();
+}
+
+#else
+#include <ao_i2c_bit.h>
+
+static void
+ao_mmc5983_reg_write(uint8_t addr, uint8_t data)
+{
+ uint8_t d[2];
+
+ d[0] = addr;
+ d[1] = data;
+
+ ao_i2c_bit_start(MMC5983_I2C_ADDR);
+ ao_i2c_bit_send(d, 2);
+ ao_i2c_bit_stop();
+}
+
+static uint8_t
+ao_mmc5983_reg_read(uint8_t addr)
+{
+ uint8_t d[1];
+
+ ao_i2c_bit_start(MMC5983_I2C_ADDR);
+ d[0] = addr;
+ ao_i2c_bit_send(d, 1);
+ ao_i2c_bit_restart(MMC5983_I2C_ADDR | 1);
+ ao_i2c_bit_recv(d, 1);
+ ao_i2c_bit_stop();
+ return d[0];
+}
+
+static void
+ao_mmc5983_raw(struct ao_mmc5983_raw *raw)
+{
+ ao_i2c_bit_start(MMC5983_I2C_ADDR);
+ raw->addr = MMC5983_X_OUT_0;
+ ao_i2c_bit_send(&(raw->addr), 1);
+ ao_i2c_bit_restart(MMC5983_I2C_ADDR | 1);
+ ao_i2c_bit_recv(&(raw->x0), sizeof(*raw) - 1);
+ ao_i2c_bit_stop();
+}
+
+#endif
+
+#else
+#define AO_MMC5983_SPI_SPEED ao_spi_speed(AO_MMC5983_SPI_INDEX, 2000000)