summary refs log tree commit diff
path: root/tmk_core/common
diff options
context:
space:
mode:
authorChristopher Browne <cbbrowne@ca.afilias.info>2016-07-04 12:32:08 -0400
committerChristopher Browne <cbbrowne@ca.afilias.info>2016-07-04 12:32:08 -0400
commit2e1cfaf73fccdfaba2d7542f00bd7c3d49998d5d (patch)
tree9d8e9c6b71116f01c56c870a9e1071760899ff77 /tmk_core/common
parent44a5f7630f18b40b36270d49449a43cd42b802f0 (diff)
parent9e01b219f32b0086728c10658928b8bffcc26ef7 (diff)
Merge branch 'master' of https://github.com/jackhumbert/qmk_firmware
Diffstat (limited to 'tmk_core/common')
-rw-r--r--tmk_core/common/action_tapping.c2
-rw-r--r--tmk_core/common/avr/sleep_led.c (renamed from tmk_core/common/sleep_led.c)0
-rw-r--r--tmk_core/common/avr/suspend.c6
-rw-r--r--tmk_core/common/bootmagic.c23
-rw-r--r--tmk_core/common/chibios/bootloader.c47
-rw-r--r--tmk_core/common/chibios/eeprom.c588
-rw-r--r--tmk_core/common/chibios/printf.c240
-rw-r--r--tmk_core/common/chibios/printf.h111
-rw-r--r--tmk_core/common/chibios/sleep_led.c226
-rw-r--r--tmk_core/common/chibios/suspend.c65
-rw-r--r--tmk_core/common/chibios/timer.c27
-rw-r--r--tmk_core/common/command.c23
-rw-r--r--tmk_core/common/eeconfig.c (renamed from tmk_core/common/avr/eeconfig.c)2
-rw-r--r--tmk_core/common/eeprom.h22
-rw-r--r--tmk_core/common/keyboard.c107
-rw-r--r--tmk_core/common/magic.c4
-rw-r--r--tmk_core/common/matrix.h57
-rw-r--r--tmk_core/common/print.c8
-rw-r--r--tmk_core/common/print.h10
-rw-r--r--tmk_core/common/progmem.h4
-rw-r--r--tmk_core/common/report.h5
-rw-r--r--tmk_core/common/wait.h8
22 files changed, 1476 insertions, 109 deletions
diff --git a/tmk_core/common/action_tapping.c b/tmk_core/common/action_tapping.c
index ff78d7f2ab..e16e11be7f 100644
--- a/tmk_core/common/action_tapping.c
+++ b/tmk_core/common/action_tapping.c
@@ -257,7 +257,7 @@ bool process_tapping(keyrecord_t *keyp)
                     return true;
                 }
             } else {
-                if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n");
+                if (!IS_NOEVENT(event)) debug("Tapping: other key just after tap.\n") {};
                 process_record(keyp);
                 return true;
             }
diff --git a/tmk_core/common/sleep_led.c b/tmk_core/common/avr/sleep_led.c
index dab3eb0f3c..dab3eb0f3c 100644
--- a/tmk_core/common/sleep_led.c
+++ b/tmk_core/common/avr/sleep_led.c
diff --git a/tmk_core/common/avr/suspend.c b/tmk_core/common/avr/suspend.c
index a6f3c64414..8a7272bbc5 100644
--- a/tmk_core/common/avr/suspend.c
+++ b/tmk_core/common/avr/suspend.c
@@ -114,8 +114,10 @@ bool suspend_wakeup_condition(void)
     matrix_power_up();
     matrix_scan();
     matrix_power_down();
-    if (matrix_key_count()) return true;
-    return false;
+    for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+        if (matrix_get_row(r)) return true;
+    }
+     return false;
 }
 
 // run immediately after wakeup
diff --git a/tmk_core/common/bootmagic.c b/tmk_core/common/bootmagic.c
index 30e8a0f20f..6730a2a4aa 100644
--- a/tmk_core/common/bootmagic.c
+++ b/tmk_core/common/bootmagic.c
@@ -1,6 +1,6 @@
 #include <stdint.h>
 #include <stdbool.h>
-#include <util/delay.h>
+#include "wait.h"
 #include "matrix.h"
 #include "bootloader.h"
 #include "debug.h"
@@ -10,6 +10,7 @@
 #include "eeconfig.h"
 #include "bootmagic.h"
 
+keymap_config_t keymap_config;
 
 void bootmagic(void)
 {
@@ -19,9 +20,9 @@ void bootmagic(void)
     }
 
     /* do scans in case of bounce */
-    print("boogmagic scan: ... ");
+    print("bootmagic scan: ... ");
     uint8_t scan = 100;
-    while (scan--) { matrix_scan(); _delay_ms(10); }
+    while (scan--) { matrix_scan(); wait_ms(10); }
     print("done.\n");
 
     /* bootmagic skip */
@@ -105,13 +106,15 @@ void bootmagic(void)
     }
 }
 
-static bool scan_keycode(uint8_t keycode) {
-    for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
+static bool scan_keycode(uint8_t keycode)
+{
+    for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
         matrix_row_t matrix_row = matrix_get_row(r);
-        for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
-            if (matrix_row & (matrix_row_t)1 << c) {
-                keypos_t key = (keypos_t){ .row = r, .col = c };
-                if (keycode == keymap_key_to_keycode(0, key)) return true;
+        for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+            if (matrix_row & ((matrix_row_t)1<<c)) {
+                if (keycode == keymap_key_to_keycode(0, (keypos_t){ .row = r, .col = c })) {
+                    return true;
+                }
             }
         }
     }
@@ -123,4 +126,4 @@ bool bootmagic_scan_keycode(uint8_t keycode)
     if (!scan_keycode(BOOTMAGIC_KEY_SALT)) return false;
 
     return scan_keycode(keycode);
-}
+}
\ No newline at end of file
diff --git a/tmk_core/common/chibios/bootloader.c b/tmk_core/common/chibios/bootloader.c
new file mode 100644
index 0000000000..8a533ab6f6
--- /dev/null
+++ b/tmk_core/common/chibios/bootloader.c
@@ -0,0 +1,47 @@
+#include "bootloader.h"
+
+#include "ch.h"
+#include "hal.h"
+
+#ifdef STM32_BOOTLOADER_ADDRESS
+/* STM32 */
+
+#if defined(STM32F0XX)
+/* This code should be checked whether it runs correctly on platforms */
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+extern uint32_t __ram0_end__;
+
+void bootloader_jump(void) {
+  *((unsigned long *)(SYMVAL(__ram0_end__) - 4)) = 0xDEADBEEF; // set magic flag => reset handler will jump into boot loader
+   NVIC_SystemReset();
+}
+
+#else /* defined(STM32F0XX) */
+#error Check that the bootloader code works on your platform and add it to bootloader.c!
+#endif /* defined(STM32F0XX) */
+
+#elif defined(KL2x) || defined(K20x) /* STM32_BOOTLOADER_ADDRESS */
+/* Kinetis */
+
+#if defined(KIIBOHD_BOOTLOADER)
+/* Kiibohd Bootloader (MCHCK and Infinity KB) */
+#define SCB_AIRCR_VECTKEY_WRITEMAGIC 0x05FA0000
+const uint8_t sys_reset_to_loader_magic[] = "\xff\x00\x7fRESET TO LOADER\x7f\x00\xff";
+void bootloader_jump(void) {
+  __builtin_memcpy((void *)VBAT, (const void *)sys_reset_to_loader_magic, sizeof(sys_reset_to_loader_magic));
+  // request reset
+  SCB->AIRCR = SCB_AIRCR_VECTKEY_WRITEMAGIC | SCB_AIRCR_SYSRESETREQ_Msk;
+}
+
+#else /* defined(KIIBOHD_BOOTLOADER) */
+/* Default for Kinetis - expecting an ARM Teensy */
+void bootloader_jump(void) {
+	chThdSleepMilliseconds(100);
+	__BKPT(0);
+}
+#endif /* defined(KIIBOHD_BOOTLOADER) */
+
+#else /* neither STM32 nor KINETIS */
+__attribute__((weak))
+void bootloader_jump(void) {}
+#endif
\ No newline at end of file
diff --git a/tmk_core/common/chibios/eeprom.c b/tmk_core/common/chibios/eeprom.c
new file mode 100644
index 0000000000..5ff8ee86f4
--- /dev/null
+++ b/tmk_core/common/chibios/eeprom.c
@@ -0,0 +1,588 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "eeconfig.h"
+
+/*************************************/
+/*          Hardware backend         */
+/*                                   */
+/*    Code from PJRC/Teensyduino     */
+/*************************************/
+
+/* Teensyduino Core Library
+ * http://www.pjrc.com/teensy/
+ * Copyright (c) 2013 PJRC.COM, LLC.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * 1. The above copyright notice and this permission notice shall be 
+ * included in all copies or substantial portions of the Software.
+ *
+ * 2. If the Software is incorporated into a build system that allows 
+ * selection among a list of target devices, then similar target
+ * devices manufactured by PJRC.COM must be included in the list of
+ * target devices and selectable in the same manner.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+
+#if defined(K20x) /* chip selection */
+/* Teensy 3.0, 3.1, 3.2; mchck; infinity keyboard */
+
+// The EEPROM is really RAM with a hardware-based backup system to
+// flash memory.  Selecting a smaller size EEPROM allows more wear
+// leveling, for higher write endurance.  If you edit this file,
+// set this to the smallest size your application can use.  Also,
+// due to Freescale's implementation, writing 16 or 32 bit words
+// (aligned to 2 or 4 byte boundaries) has twice the endurance
+// compared to writing 8 bit bytes.
+//
+#define EEPROM_SIZE 32
+
+// Writing unaligned 16 or 32 bit data is handled automatically when
+// this is defined, but at a cost of extra code size.  Without this,
+// any unaligned write will cause a hard fault exception!  If you're
+// absolutely sure all 16 and 32 bit writes will be aligned, you can
+// remove the extra unnecessary code.
+//
+#define HANDLE_UNALIGNED_WRITES
+
+// Minimum EEPROM Endurance
+// ------------------------
+#if (EEPROM_SIZE == 2048)	// 35000 writes/byte or 70000 writes/word
+  #define EEESIZE 0x33
+#elif (EEPROM_SIZE == 1024)	// 75000 writes/byte or 150000 writes/word
+  #define EEESIZE 0x34
+#elif (EEPROM_SIZE == 512)	// 155000 writes/byte or 310000 writes/word
+  #define EEESIZE 0x35
+#elif (EEPROM_SIZE == 256)	// 315000 writes/byte or 630000 writes/word
+  #define EEESIZE 0x36
+#elif (EEPROM_SIZE == 128)	// 635000 writes/byte or 1270000 writes/word
+  #define EEESIZE 0x37
+#elif (EEPROM_SIZE == 64)	// 1275000 writes/byte or 2550000 writes/word
+  #define EEESIZE 0x38
+#elif (EEPROM_SIZE == 32)	// 2555000 writes/byte or 5110000 writes/word
+  #define EEESIZE 0x39
+#endif
+
+void eeprom_initialize(void)
+{
+	uint32_t count=0;
+	uint16_t do_flash_cmd[] = {
+		0xf06f, 0x037f, 0x7003, 0x7803,
+		0xf013, 0x0f80, 0xd0fb, 0x4770};
+	uint8_t status;
+
+	if (FTFL->FCNFG & FTFL_FCNFG_RAMRDY) {
+		// FlexRAM is configured as traditional RAM
+		// We need to reconfigure for EEPROM usage
+		FTFL->FCCOB0 = 0x80; // PGMPART = Program Partition Command
+		FTFL->FCCOB4 = EEESIZE; // EEPROM Size
+		FTFL->FCCOB5 = 0x03; // 0K for Dataflash, 32K for EEPROM backup
+		__disable_irq();
+		// do_flash_cmd() must execute from RAM.  Luckily the C syntax is simple...
+		(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFL->FSTAT));
+		__enable_irq();
+		status = FTFL->FSTAT;
+		if (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL)) {
+			FTFL->FSTAT = (status & (FTFL_FSTAT_RDCOLERR|FTFL_FSTAT_ACCERR|FTFL_FSTAT_FPVIOL));
+			return; // error
+		}
+	}
+	// wait for eeprom to become ready (is this really necessary?)
+	while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+		if (++count > 20000) break;
+	}
+}
+
+#define FlexRAM ((uint8_t *)0x14000000)
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+	uint32_t offset = (uint32_t)addr;
+	if (offset >= EEPROM_SIZE) return 0;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+	return FlexRAM[offset];
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+	uint32_t offset = (uint32_t)addr;
+	if (offset >= EEPROM_SIZE-1) return 0;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+	return *(uint16_t *)(&FlexRAM[offset]);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+	uint32_t offset = (uint32_t)addr;
+	if (offset >= EEPROM_SIZE-3) return 0;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+	return *(uint32_t *)(&FlexRAM[offset]);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+	uint32_t offset = (uint32_t)addr;
+	uint8_t *dest = (uint8_t *)buf;
+	uint32_t end = offset + len;
+	
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+	if (end > EEPROM_SIZE) end = EEPROM_SIZE;
+	while (offset < end) {
+		*dest++ = FlexRAM[offset++];
+	}
+}
+
+int eeprom_is_ready(void)
+{
+	return (FTFL->FCNFG & FTFL_FCNFG_EEERDY) ? 1 : 0;
+}
+
+static void flexram_wait(void)
+{
+	while (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) {
+		// TODO: timeout
+	}
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value)
+{
+	uint32_t offset = (uint32_t)addr;
+
+	if (offset >= EEPROM_SIZE) return;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+	if (FlexRAM[offset] != value) {
+		FlexRAM[offset] = value;
+		flexram_wait();
+	}
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+	uint32_t offset = (uint32_t)addr;
+
+	if (offset >= EEPROM_SIZE-1) return;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+	if ((offset & 1) == 0) {
+#endif
+		if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+			*(uint16_t *)(&FlexRAM[offset]) = value;
+			flexram_wait();
+		}
+#ifdef HANDLE_UNALIGNED_WRITES
+	} else {
+		if (FlexRAM[offset] != value) {
+			FlexRAM[offset] = value;
+			flexram_wait();
+		}
+		if (FlexRAM[offset + 1] != (value >> 8)) {
+			FlexRAM[offset + 1] = value >> 8;
+			flexram_wait();
+		}
+	}
+#endif
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+	uint32_t offset = (uint32_t)addr;
+
+	if (offset >= EEPROM_SIZE-3) return;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+#ifdef HANDLE_UNALIGNED_WRITES
+	switch (offset & 3) {
+	case 0:
+#endif
+		if (*(uint32_t *)(&FlexRAM[offset]) != value) {
+			*(uint32_t *)(&FlexRAM[offset]) = value;
+			flexram_wait();
+		}
+		return;
+#ifdef HANDLE_UNALIGNED_WRITES
+	case 2:
+		if (*(uint16_t *)(&FlexRAM[offset]) != value) {
+			*(uint16_t *)(&FlexRAM[offset]) = value;
+			flexram_wait();
+		}
+		if (*(uint16_t *)(&FlexRAM[offset + 2]) != (value >> 16)) {
+			*(uint16_t *)(&FlexRAM[offset + 2]) = value >> 16;
+			flexram_wait();
+		}
+		return;
+	default:
+		if (FlexRAM[offset] != value) {
+			FlexRAM[offset] = value;
+			flexram_wait();
+		}
+		if (*(uint16_t *)(&FlexRAM[offset + 1]) != (value >> 8)) {
+			*(uint16_t *)(&FlexRAM[offset + 1]) = value >> 8;
+			flexram_wait();
+		}
+		if (FlexRAM[offset + 3] != (value >> 24)) {
+			FlexRAM[offset + 3] = value >> 24;
+			flexram_wait();
+		}
+	}
+#endif
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+	uint32_t offset = (uint32_t)addr;
+	const uint8_t *src = (const uint8_t *)buf;
+
+	if (offset >= EEPROM_SIZE) return;
+	if (!(FTFL->FCNFG & FTFL_FCNFG_EEERDY)) eeprom_initialize();
+	if (len >= EEPROM_SIZE) len = EEPROM_SIZE;
+	if (offset + len >= EEPROM_SIZE) len = EEPROM_SIZE - offset;
+	while (len > 0) {
+		uint32_t lsb = offset & 3;
+		if (lsb == 0 && len >= 4) {
+			// write aligned 32 bits
+			uint32_t val32;
+			val32 = *src++;
+			val32 |= (*src++ << 8);
+			val32 |= (*src++ << 16);
+			val32 |= (*src++ << 24);
+			if (*(uint32_t *)(&FlexRAM[offset]) != val32) {
+				*(uint32_t *)(&FlexRAM[offset]) = val32;
+				flexram_wait();
+			}
+			offset += 4;
+			len -= 4;
+		} else if ((lsb == 0 || lsb == 2) && len >= 2) {
+			// write aligned 16 bits
+			uint16_t val16;
+			val16 = *src++;
+			val16 |= (*src++ << 8);
+			if (*(uint16_t *)(&FlexRAM[offset]) != val16) {
+				*(uint16_t *)(&FlexRAM[offset]) = val16;
+				flexram_wait();
+			}
+			offset += 2;
+			len -= 2;
+		} else {
+			// write 8 bits
+			uint8_t val8 = *src++;
+			if (FlexRAM[offset] != val8) {
+				FlexRAM[offset] = val8;
+				flexram_wait();
+			}
+			offset++;
+			len--;
+		}
+	}
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+	*fstat = 0x80;
+	while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+   0:	f06f 037f 	mvn.w	r3, #127	; 0x7f
+   4:	7003      	strb	r3, [r0, #0]
+   6:	7803      	ldrb	r3, [r0, #0]
+   8:	f013 0f80 	tst.w	r3, #128	; 0x80
+   c:	d0fb      	beq.n	6 <do_flash_cmd+0x6>
+   e:	4770      	bx	lr
+*/
+
+#elif defined(KL2x) /* chip selection */
+/* Teensy LC (emulated) */
+
+#define SYMVAL(sym) (uint32_t)(((uint8_t *)&(sym)) - ((uint8_t *)0))
+
+extern uint32_t __eeprom_workarea_start__;
+extern uint32_t __eeprom_workarea_end__;
+
+#define EEPROM_SIZE 128
+
+static uint32_t flashend = 0;
+
+void eeprom_initialize(void)
+{
+	const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+
+	do {
+		if (*p++ == 0xFFFF) {
+			flashend = (uint32_t)(p - 2);
+			return;
+		}
+	} while (p < (uint16_t *)SYMVAL(__eeprom_workarea_end__));
+	flashend = (uint32_t)((uint16_t *)SYMVAL(__eeprom_workarea_end__) - 1);
+}
+
+uint8_t eeprom_read_byte(const uint8_t *addr)
+{
+	uint32_t offset = (uint32_t)addr;
+	const uint16_t *p = (uint16_t *)SYMVAL(__eeprom_workarea_start__);
+	const uint16_t *end = (const uint16_t *)((uint32_t)flashend);
+	uint16_t val;
+	uint8_t data=0xFF;
+
+	if (!end) {
+		eeprom_initialize();
+		end = (const uint16_t *)((uint32_t)flashend);
+	}
+	if (offset < EEPROM_SIZE) {
+		while (p <= end) {
+			val = *p++;
+			if ((val & 255) == offset) data = val >> 8;
+		}
+	}
+	return data;
+}
+
+static void flash_write(const uint16_t *code, uint32_t addr, uint32_t data)
+{
+	// with great power comes great responsibility....
+	uint32_t stat;
+	*(uint32_t *)&(FTFA->FCCOB3) = 0x06000000 | (addr & 0x00FFFFFC);
+	*(uint32_t *)&(FTFA->FCCOB7) = data;
+	__disable_irq();
+	(*((void (*)(volatile uint8_t *))((uint32_t)code | 1)))(&(FTFA->FSTAT));
+	__enable_irq();
+	stat = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);
+	if (stat) {
+		FTFA->FSTAT = stat;
+	}
+	MCM->PLACR |= MCM_PLACR_CFCC;
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t data)
+{
+	uint32_t offset = (uint32_t)addr;
+	const uint16_t *p, *end = (const uint16_t *)((uint32_t)flashend);
+	uint32_t i, val, flashaddr;
+	uint16_t do_flash_cmd[] = {
+		0x2380, 0x7003, 0x7803, 0xb25b, 0x2b00, 0xdafb, 0x4770};
+	uint8_t buf[EEPROM_SIZE];
+
+	if (offset >= EEPROM_SIZE) return;
+	if (!end) {
+		eeprom_initialize();
+		end = (const uint16_t *)((uint32_t)flashend);
+	}
+	if (++end < (uint16_t *)SYMVAL(__eeprom_workarea_end__)) {
+		val = (data << 8) | offset;
+		flashaddr = (uint32_t)end;
+		flashend = flashaddr;
+		if ((flashaddr & 2) == 0) {
+			val |= 0xFFFF0000;
+		} else {
+			val <<= 16;
+			val |= 0x0000FFFF;
+		}
+		flash_write(do_flash_cmd, flashaddr, val);
+	} else {
+		for (i=0; i < EEPROM_SIZE; i++) {
+			buf[i] = 0xFF;
+		}
+		val = 0;
+		for (p = (uint16_t *)SYMVAL(__eeprom_workarea_start__); p < (uint16_t *)SYMVAL(__eeprom_workarea_end__); p++) {
+			val = *p;
+			if ((val & 255) < EEPROM_SIZE) {
+				buf[val & 255] = val >> 8;
+			}
+		}
+		buf[offset] = data;
+		for (flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__); flashaddr < (uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_end__); flashaddr += 1024) {
+			*(uint32_t *)&(FTFA->FCCOB3) = 0x09000000 | flashaddr;
+			__disable_irq();
+			(*((void (*)(volatile uint8_t *))((uint32_t)do_flash_cmd | 1)))(&(FTFA->FSTAT));
+			__enable_irq();
+			val = FTFA->FSTAT & (FTFA_FSTAT_RDCOLERR|FTFA_FSTAT_ACCERR|FTFA_FSTAT_FPVIOL);;
+			if (val) FTFA->FSTAT = val;
+			MCM->PLACR |= MCM_PLACR_CFCC;
+		}
+		flashaddr=(uint32_t)(uint16_t *)SYMVAL(__eeprom_workarea_start__);
+		for (i=0; i < EEPROM_SIZE; i++) {
+			if (buf[i] == 0xFF) continue;
+			if ((flashaddr & 2) == 0) {
+				val = (buf[i] << 8) | i;
+			} else {
+				val = val | (buf[i] << 24) | (i << 16);
+				flash_write(do_flash_cmd, flashaddr, val);
+			}
+			flashaddr += 2;
+		}
+		flashend = flashaddr;
+		if ((flashaddr & 2)) {
+			val |= 0xFFFF0000;
+			flash_write(do_flash_cmd, flashaddr, val);
+		}
+	}
+}
+
+/*
+void do_flash_cmd(volatile uint8_t *fstat)
+{
+        *fstat = 0x80;
+        while ((*fstat & 0x80) == 0) ; // wait
+}
+00000000 <do_flash_cmd>:
+   0:	2380      	movs	r3, #128	; 0x80
+   2:	7003      	strb	r3, [r0, #0]
+   4:	7803      	ldrb	r3, [r0, #0]
+   6:	b25b      	sxtb	r3, r3
+   8:	2b00      	cmp	r3, #0
+   a:	dafb      	bge.n	4 <do_flash_cmd+0x4>
+   c:	4770      	bx	lr
+*/
+
+
+uint16_t eeprom_read_word(const uint16_t *addr)
+{
+	const uint8_t *p = (const uint8_t *)addr;
+	return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr)
+{
+	const uint8_t *p = (const uint8_t *)addr;
+	return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+		| (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len)
+{
+	const uint8_t *p = (const uint8_t *)addr;
+	uint8_t *dest = (uint8_t *)buf;
+	while (len--) {
+		*dest++ = eeprom_read_byte(p++);
+	}
+}
+
+int eeprom_is_ready(void)
+{
+	return 1;
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value)
+{
+	uint8_t *p = (uint8_t *)addr;
+	eeprom_write_byte(p++, value);
+	eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value)
+{
+	uint8_t *p = (uint8_t *)addr;
+	eeprom_write_byte(p++, value);
+	eeprom_write_byte(p++, value >> 8);
+	eeprom_write_byte(p++, value >> 16);
+	eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len)
+{
+	uint8_t *p = (uint8_t *)addr;
+	const uint8_t *src = (const uint8_t *)buf;
+	while (len--) {
+		eeprom_write_byte(p++, *src++);
+	}
+}
+
+#else
+// No EEPROM supported, so emulate it
+
+#define EEPROM_SIZE 32
+static uint8_t buffer[EEPROM_SIZE];
+
+uint8_t eeprom_read_byte(const uint8_t *addr) {
+	uint32_t offset = (uint32_t)addr;
+	return buffer[offset];
+}
+
+void eeprom_write_byte(uint8_t *addr, uint8_t value) {
+	uint32_t offset = (uint32_t)addr;
+	buffer[offset] = value;
+}
+
+uint16_t eeprom_read_word(const uint16_t *addr) {
+	const uint8_t *p = (const uint8_t *)addr;
+	return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8);
+}
+
+uint32_t eeprom_read_dword(const uint32_t *addr) {
+	const uint8_t *p = (const uint8_t *)addr;
+	return eeprom_read_byte(p) | (eeprom_read_byte(p+1) << 8)
+		| (eeprom_read_byte(p+2) << 16) | (eeprom_read_byte(p+3) << 24);
+}
+
+void eeprom_read_block(void *buf, const void *addr, uint32_t len) {
+	const uint8_t *p = (const uint8_t *)addr;
+	uint8_t *dest = (uint8_t *)buf;
+	while (len--) {
+		*dest++ = eeprom_read_byte(p++);
+	}
+}
+
+void eeprom_write_word(uint16_t *addr, uint16_t value) {
+	uint8_t *p = (uint8_t *)addr;
+	eeprom_write_byte(p++, value);
+	eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_write_dword(uint32_t *addr, uint32_t value) {
+	uint8_t *p = (uint8_t *)addr;
+	eeprom_write_byte(p++, value);
+	eeprom_write_byte(p++, value >> 8);
+	eeprom_write_byte(p++, value >> 16);
+	eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_write_block(const void *buf, void *addr, uint32_t len) {
+	uint8_t *p = (uint8_t *)addr;
+	const uint8_t *src = (const uint8_t *)buf;
+	while (len--) {
+		eeprom_write_byte(p++, *src++);
+	}
+}
+
+#endif /* chip selection */
+// The update functions just calls write for now, but could probably be optimized
+
+void eeprom_update_byte(uint8_t *addr, uint8_t value) {
+	eeprom_write_byte(addr, value);
+}
+
+void eeprom_update_word(uint16_t *addr, uint16_t value) {
+	uint8_t *p = (uint8_t *)addr;
+	eeprom_write_byte(p++, value);
+	eeprom_write_byte(p, value >> 8);
+}
+
+void eeprom_update_dword(uint32_t *addr, uint32_t value) {
+	uint8_t *p = (uint8_t *)addr;
+	eeprom_write_byte(p++, value);
+	eeprom_write_byte(p++, value >> 8);
+	eeprom_write_byte(p++, value >> 16);
+	eeprom_write_byte(p, value >> 24);
+}
+
+void eeprom_update_block(const void *buf, void *addr, uint32_t len) {
+	uint8_t *p = (uint8_t *)addr;
+	const uint8_t *src = (const uint8_t *)buf;
+	while (len--) {
+		eeprom_write_byte(p++, *src++);
+	}
+}
diff --git a/tmk_core/common/chibios/printf.c b/tmk_core/common/chibios/printf.c
new file mode 100644
index 0000000000..72e3d4f8c4
--- /dev/null
+++ b/tmk_core/common/chibios/printf.c
@@ -0,0 +1,240 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and:      http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.c
+
+Copyright (C) 2004  Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+#include "printf.h"
+
+typedef void (*putcf) (void*,char);
+static putcf stdout_putf;
+static void* stdout_putp;
+
+// this adds cca 400 bytes
+#define PRINTF_LONG_SUPPORT
+
+#ifdef PRINTF_LONG_SUPPORT
+
+static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
+    {
+    int n=0;
+    unsigned int d=1;
+    while (num/d >= base)
+        d*=base;         
+    while (d!=0) {
+        int dgt = num / d;
+        num%=d;
+        d/=base;
+        if (n || dgt>0|| d==0) {
+            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+            ++n;
+            }
+        }
+    *bf=0;
+    }
+
+static void li2a (long num, char * bf)
+    {
+    if (num<0) {
+        num=-num;
+        *bf++ = '-';
+        }
+    uli2a(num,10,0,bf);
+    }
+
+#endif
+
+static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
+    {
+    int n=0;
+    unsigned int d=1;
+    while (num/d >= base)
+        d*=base;        
+    while (d!=0) {
+        int dgt = num / d;
+        num%= d;
+        d/=base;
+        if (n || dgt>0 || d==0) {
+            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
+            ++n;
+            }
+        }
+    *bf=0;
+    }
+
+static void i2a (int num, char * bf)
+    {
+    if (num<0) {
+        num=-num;
+        *bf++ = '-';
+        }
+    ui2a(num,10,0,bf);
+    }
+
+static int a2d(char ch)
+    {
+    if (ch>='0' && ch<='9') 
+        return ch-'0';
+    else if (ch>='a' && ch<='f')
+        return ch-'a'+10;
+    else if (ch>='A' && ch<='F')
+        return ch-'A'+10;
+    else return -1;
+    }
+
+static char a2i(char ch, char** src,int base,int* nump)
+    {
+    char* p= *src;
+    int num=0;
+    int digit;
+    while ((digit=a2d(ch))>=0) {
+        if (digit>base) break;
+        num=num*base+digit;
+        ch=*p++;
+        }
+    *src=p;
+    *nump=num;
+    return ch;
+    }
+
+static void putchw(void* putp,putcf putf,int n, char z, char* bf)
+    {
+    char fc=z? '0' : ' ';
+    char ch;
+    char* p=bf;
+    while (*p++ && n > 0)
+        n--;
+    while (n-- > 0) 
+        putf(putp,fc);
+    while ((ch= *bf++))
+        putf(putp,ch);
+    }
+
+void tfp_format(void* putp,putcf putf,char *fmt, va_list va)
+    {
+    char bf[12];
+    
+    char ch;
+
+
+    while ((ch=*(fmt++))) {
+        if (ch!='%') 
+            putf(putp,ch);
+        else {
+            char lz=0;
+#ifdef  PRINTF_LONG_SUPPORT
+            char lng=0;
+#endif
+            int w=0;
+            ch=*(fmt++);
+            if (ch=='0') {
+                ch=*(fmt++);
+                lz=1;
+                }
+            if (ch>='0' && ch<='9') {
+                ch=a2i(ch,&fmt,10,&w);
+                }
+#ifdef  PRINTF_LONG_SUPPORT
+            if (ch=='l') {
+                ch=*(fmt++);
+                lng=1;
+            }
+#endif
+            switch (ch) {
+                case 0: 
+                    goto abort;
+                case 'u' : {
+#ifdef  PRINTF_LONG_SUPPORT
+                    if (lng)
+                        uli2a(va_arg(va, unsigned long int),10,0,bf);
+                    else
+#endif
+                    ui2a(va_arg(va, unsigned int),10,0,bf);
+                    putchw(putp,putf,w,lz,bf);
+                    break;
+                    }
+                case 'd' :  {
+#ifdef  PRINTF_LONG_SUPPORT
+                    if (lng)
+                        li2a(va_arg(va, unsigned long int),bf);
+                    else
+#endif
+                    i2a(va_arg(va, int),bf);
+                    putchw(putp,putf,w,lz,bf);
+                    break;
+                    }
+                case 'x': case 'X' : 
+#ifdef  PRINTF_LONG_SUPPORT
+                    if (lng)
+                        uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
+                    else
+#endif
+                    ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
+                    putchw(putp,putf,w,lz,bf);
+                    break;
+                case 'c' : 
+                    putf(putp,(char)(va_arg(va, int)));
+                    break;
+                case 's' : 
+                    putchw(putp,putf,w,0,va_arg(va, char*));
+                    break;
+                case '%' :
+                    putf(putp,ch);
+                default:
+                    break;
+                }
+            }
+        }
+    abort:;
+    }
+
+
+void init_printf(void* putp,void (*putf) (void*,char))
+    {
+    stdout_putf=putf;
+    stdout_putp=putp;
+    }
+
+void tfp_printf(char *fmt, ...)
+    {
+    va_list va;
+    va_start(va,fmt);
+    tfp_format(stdout_putp,stdout_putf,fmt,va);
+    va_end(va);
+    }
+
+static void putcp(void* p,char c)
+    {
+    *(*((char**)p))++ = c;
+    }
+
+
+
+void tfp_sprintf(char* s,char *fmt, ...)
+    {
+    va_list va;
+    va_start(va,fmt);
+    tfp_format(&s,putcp,fmt,va);
+    putcp(&s,0);
+    va_end(va);
+    }
diff --git a/tmk_core/common/chibios/printf.h b/tmk_core/common/chibios/printf.h
new file mode 100644
index 0000000000..678a100c6e
--- /dev/null
+++ b/tmk_core/common/chibios/printf.h
@@ -0,0 +1,111 @@
+/*
+ * found at: http://www.sparetimelabs.com/tinyprintf/tinyprintf.php
+ * and:      http://www.sparetimelabs.com/printfrevisited/printfrevisited.php
+ */
+
+/*
+File: printf.h
+
+Copyright (C) 2004  Kustaa Nyholm
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+See the GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+This library is realy just two files: 'printf.h' and 'printf.c'.
+
+They provide a simple and small (+200 loc) printf functionality to 
+be used in embedded systems.
+
+I've found them so usefull in debugging that I do not bother with a 
+debugger at all.
+
+They are distributed in source form, so to use them, just compile them 
+into your project. 
+
+Two printf variants are provided: printf and sprintf. 
+
+The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
+
+Zero padding and field width are also supported.
+
+If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the 
+long specifier is also
+supported. Note that this will pull in some long math routines (pun intended!)
+and thus make your executable noticably longer.
+
+The memory foot print of course depends on the target cpu, compiler and 
+compiler options, but a rough guestimate (based on a H8S target) is about 
+1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. 
+Not too bad. Your milage may vary. By hacking the source code you can 
+get rid of some hunred bytes, I'm sure, but personally I feel the balance of 
+functionality and flexibility versus  code size is close to optimal for
+many embedded systems.
+
+To use the printf you need to supply your own character output function, 
+something like :
+
+    void putc ( void* p, char c)
+        {
+        while (!SERIAL_PORT_EMPTY) ;
+        SERIAL_PORT_TX_REGISTER = c;
+        }
+
+Before you can call printf you need to initialize it to use your 
+character output function with something like:
+
+    init_printf(NULL,putc);
+
+Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', 
+the NULL (or any pointer) you pass into the 'init_printf' will eventually be 
+passed to your 'putc' routine. This allows you to pass some storage space (or 
+anything realy) to the character output function, if necessary. 
+This is not often needed but it was implemented like that because it made 
+implementing the sprintf function so neat (look at the source code).
+
+The code is re-entrant, except for the 'init_printf' function, so it 
+is safe to call it from interupts too, although this may result in mixed output. 
+If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
+
+The printf and sprintf functions are actually macros that translate to 
+'tfp_printf' and 'tfp_sprintf'. This makes it possible
+to use them along with 'stdio.h' printf's in a single source file. 
+You just need to undef the names before you include the 'stdio.h'.
+Note that these are not function like macros, so if you have variables
+or struct members with these names, things will explode in your face.
+Without variadic macros this is the best we can do to wrap these
+fucnction. If it is a problem just give up the macros and use the
+functions directly or rename them.
+
+For further details see source code.
+
+regs Kusti, 23.10.2004
+*/
+
+
+#ifndef __TFP_PRINTF__
+#define __TFP_PRINTF__
+
+#include <stdarg.h>
+
+void init_printf(void* putp,void (*putf) (void*,char));
+
+void tfp_printf(char *fmt, ...);
+void tfp_sprintf(char* s,char *fmt, ...);
+
+void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va);
+
+#define printf tfp_printf 
+#define sprintf tfp_sprintf 
+
+#endif
diff --git a/tmk_core/common/chibios/sleep_led.c b/tmk_core/common/chibios/sleep_led.c
new file mode 100644
index 0000000000..4c35cfcbac
--- /dev/null
+++ b/tmk_core/common/chibios/sleep_led.c
@@ -0,0 +1,226 @@
+#include "ch.h"
+#include "hal.h"
+
+#include "led.h"
+#include "sleep_led.h"
+
+/* All right, we go the "software" way: timer, toggle LED in interrupt.
+ * Based on hasu's code for AVRs.
+ * Use LP timer on Kinetises, TIM14 on STM32F0.
+ */
+
+#if defined(KL2x) || defined(K20x)
+
+/* Use Low Power Timer (LPTMR) */
+#define TIMER_INTERRUPT_VECTOR KINETIS_LPTMR0_IRQ_VECTOR
+#define RESET_COUNTER LPTMR0->CSR |= LPTMRx_CSR_TCF
+
+#elif defined(STM32F0XX)
+
+/* Use TIM14 manually */
+#define TIMER_INTERRUPT_VECTOR STM32_TIM14_HANDLER
+#define RESET_COUNTER STM32_TIM14->SR &= ~STM32_TIM_SR_UIF
+
+#endif
+
+#if defined(KL2x) || defined(K20x) || defined(STM32F0XX) /* common parts for timers/interrupts */
+
+/* Breathing Sleep LED brighness(PWM On period) table
+ * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
+ *
+ * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
+ * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
+ */
+static const uint8_t breathing_table[64] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 10,
+15, 23, 32, 44, 58, 74, 93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
+255, 252, 245, 233, 218, 199, 179, 157, 135, 113, 93, 74, 58, 44, 32, 23,
+15, 10, 6, 4, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* interrupt handler */
+OSAL_IRQ_HANDLER(TIMER_INTERRUPT_VECTOR) {
+    OSAL_IRQ_PROLOGUE();
+
+    /* Software PWM
+    * timer:1111 1111 1111 1111
+    *       \_____/\/ \_______/____  count(0-255)
+    *          \    \______________  duration of step(4)
+    *           \__________________  index of step table(0-63)
+    */
+
+    // this works for cca 65536 irqs/sec
+    static union {
+    uint16_t row;
+    struct {
+      uint8_t count:8;
+      uint8_t duration:2;
+      uint8_t index:6;
+    } pwm;
+    } timer = { .row = 0 };
+
+    timer.row++;
+
+    // LED on
+    if (timer.pwm.count == 0) {
+        led_set(1<<USB_LED_CAPS_LOCK);
+    }
+    // LED off
+    if (timer.pwm.count == breathing_table[timer.pwm.index]) {
+        led_set(0);
+    }
+
+    /* Reset the counter */
+    RESET_COUNTER;
+
+    OSAL_IRQ_EPILOGUE();
+}
+
+#endif /* common parts for known platforms */
+
+
+#if defined(KL2x) || defined(K20x) /* platform selection: familiar Kinetis chips */
+
+/* LPTMR clock options */
+#define LPTMR_CLOCK_MCGIRCLK 0 /* 4MHz clock */
+#define LPTMR_CLOCK_LPO      1 /* 1kHz clock */
+#define LPTMR_CLOCK_ERCLK32K 2 /* external 32kHz crystal */
+#define LPTMR_CLOCK_OSCERCLK 3 /* output from OSC */
+
+/* Work around inconsistencies in Freescale naming */
+#if !defined(SIM_SCGC5_LPTMR)
+#define SIM_SCGC5_LPTMR SIM_SCGC5_LPTIMER
+#endif
+
+/* Initialise the timer */
+void sleep_led_init(void) {
+    /* Make sure the clock to the LPTMR is enabled */
+    SIM->SCGC5 |= SIM_SCGC5_LPTMR;
+    /* Reset LPTMR settings */
+    LPTMR0->CSR = 0;
+    /* Set the compare value */
+    LPTMR0->CMR = 0;  // trigger on counter value (i.e. every time)
+
+    /* Set up clock source and prescaler */
+    /* Software PWM
+    *  ______           ______           __
+    * |  ON  |___OFF___|  ON  |___OFF___|   ....
+    * |<-------------->|<-------------->|<- ....
+    *     PWM period       PWM period
+    *
+    * R                interrupts/period[resolution]
+    * F                periods/second[frequency]
+    * R * F            interrupts/second
+    */
+
+    /* === OPTION 1 === */
+    #if 0
+    //  1kHz LPO
+    //  No prescaler => 1024 irqs/sec
+    //  Note: this is too slow for a smooth breathe
+    LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_LPO)|LPTMRx_PSR_PBYP;
+    #endif /* OPTION 1 */
+
+    /* === OPTION 2 === */
+    #if 1
+    //  nMHz IRC (n=4 on KL25Z, KL26Z and K20x; n=2 or 8 on KL27Z)
+    MCG->C2 |= MCG_C2_IRCS; // fast (4MHz) internal ref clock
+    #if defined(KL27) // divide the 8MHz IRC by 2, to have the same MCGIRCLK speed as others
+    MCG->MC |= MCG_MC_LIRC_DIV2_DIV2;
+    #endif /* KL27 */
+    MCG->C1 |= MCG_C1_IRCLKEN; // enable internal ref clock
+    //  to work in stop mode, also MCG_C1_IREFSTEN
+    //  Divide 4MHz by 2^N (N=6) => 62500 irqs/sec =>
+    //  => approx F=61, R=256, duration = 4
+    LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_MCGIRCLK)|LPTMRx_PSR_PRESCALE(6);
+    #endif /* OPTION 2 */
+
+    /* === OPTION 3 === */
+    #if 0
+    //  OSC output (external crystal), usually 8MHz or 16MHz
+    OSC0->CR |= OSC_CR_ERCLKEN; // enable ext ref clock
+    //  to work in stop mode, also OSC_CR_EREFSTEN
+    //  Divide by 2^N
+    LPTMR0->PSR = LPTMRx_PSR_PCS(LPTMR_CLOCK_OSCERCLK)|LPTMRx_PSR_PRESCALE(7);
+    #endif /* OPTION 3 */
+    /* === END OPTIONS === */
+
+    /* Interrupt on TCF set (compare flag) */
+    nvicEnableVector(LPTMR0_IRQn, 2); // vector, priority
+    LPTMR0->CSR |= LPTMRx_CSR_TIE;
+}
+
+void sleep_led_enable(void) {
+    /* Enable the timer */
+    LPTMR0->CSR |= LPTMRx_CSR_TEN;
+}
+
+void sleep_led_disable(void) {
+    /* Disable the timer */
+    LPTMR0->CSR &= ~LPTMRx_CSR_TEN;
+}
+
+void sleep_led_toggle(void) {
+    /* Toggle the timer */
+    LPTMR0->CSR ^= LPTMRx_CSR_TEN;
+}
+
+#elif defined(STM32F0XX) /* platform selection: STM32F0XX */
+
+/* Initialise the timer */
+void sleep_led_init(void) {
+    /* enable clock */
+    rccEnableTIM14(FALSE); /* low power enable = FALSE */
+    rccResetTIM14();
+
+    /* prescale */
+    /* Assuming 48MHz internal clock */
+    /* getting cca 65484 irqs/sec */
+    STM32_TIM14->PSC = 733;
+
+    /* auto-reload */
+    /* 0 => interrupt every time */
+    STM32_TIM14->ARR = 3;
+
+    /* enable counter update event interrupt */
+    STM32_TIM14->DIER |= STM32_TIM_DIER_UIE;
+
+    /* register interrupt vector */
+    nvicEnableVector(STM32_TIM14_NUMBER, 2); /* vector, priority */
+}
+
+void sleep_led_enable(void) {
+    /* Enable the timer */
+    STM32_TIM14->CR1 = STM32_TIM_CR1_CEN | STM32_TIM_CR1_URS;
+    /* URS => update event only on overflow; setting UG bit disabled */
+}
+
+void sleep_led_disable(void) {
+    /* Disable the timer */
+    STM32_TIM14->CR1 = 0;
+}
+
+void sleep_led_toggle(void) {
+    /* Toggle the timer */
+    STM32_TIM14->CR1 ^= STM32_TIM_CR1_CEN;
+}
+
+
+#else /* platform selection: not on familiar chips */
+
+void sleep_led_init(void) {
+}
+ 
+void sleep_led_enable(void) {
+    led_set(1<<USB_LED_CAPS_LOCK);
+}
+ 
+void sleep_led_disable(void) {
+    led_set(0);
+}
+ 
+void sleep_led_toggle(void) {
+    // not implemented
+}
+
+#endif /* platform selection */
\ No newline at end of file
diff --git a/tmk_core/common/chibios/suspend.c b/tmk_core/common/chibios/suspend.c
new file mode 100644
index 0000000000..6ca16034f3
--- /dev/null
+++ b/tmk_core/common/chibios/suspend.c
@@ -0,0 +1,65 @@
+/* TODO */
+
+#include "ch.h"
+#include "hal.h"
+
+#include "matrix.h"
+#include "action.h"
+#include "action_util.h"
+#include "mousekey.h"
+#include "host.h"
+#include "backlight.h"
+#include "suspend.h"
+
+void suspend_idle(uint8_t time) {
+	// TODO: this is not used anywhere - what units is 'time' in?
+	chThdSleepMilliseconds(time);
+}
+
+void suspend_power_down(void) {
+	// TODO: figure out what to power down and how
+	// shouldn't power down TPM/FTM if we want a breathing LED
+	// also shouldn't power down USB
+
+	// on AVR, this enables the watchdog for 15ms (max), and goes to
+	// SLEEP_MODE_PWR_DOWN
+
+	chThdSleepMilliseconds(17);
+}
+
+__attribute__ ((weak)) void matrix_power_up(void) {}
+__attribute__ ((weak)) void matrix_power_down(void) {}
+bool suspend_wakeup_condition(void)
+{
+    matrix_power_up();
+    matrix_scan();
+    matrix_power_down();
+    for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+        if (matrix_get_row(r)) return true;
+    }
+    return false;
+}
+
+// run immediately after wakeup
+void suspend_wakeup_init(void)
+{
+    // clear keyboard state
+    // need to do it manually, because we're running from ISR
+    //  and clear_keyboard() calls print
+    // so only clear the variables in memory
+    // the reports will be sent from main.c afterwards
+    // or if the PC asks for GET_REPORT
+    clear_mods();
+    clear_weak_mods();
+    clear_keys();
+#ifdef MOUSEKEY_ENABLE
+    mousekey_clear();
+#endif /* MOUSEKEY_ENABLE */
+#ifdef EXTRAKEY_ENABLE
+    host_system_send(0);
+    host_consumer_send(0);
+#endif /* EXTRAKEY_ENABLE */
+#ifdef BACKLIGHT_ENABLE
+    backlight_init();
+#endif /* BACKLIGHT_ENABLE */
+}
diff --git a/tmk_core/common/chibios/timer.c b/tmk_core/common/chibios/timer.c
new file mode 100644
index 0000000000..3de4cc368b
--- /dev/null
+++ b/tmk_core/common/chibios/timer.c
@@ -0,0 +1,27 @@
+#include "ch.h"
+
+#include "timer.h"
+
+void timer_init(void) {}
+
+void timer_clear(void) {}
+
+uint16_t timer_read(void)
+{
+    return (uint16_t)ST2MS(chVTGetSystemTime());
+}
+
+uint32_t timer_read32(void)
+{
+    return ST2MS(chVTGetSystemTime());
+}
+
+uint16_t timer_elapsed(uint16_t last)
+{
+    return (uint16_t)(ST2MS(chVTTimeElapsedSinceX(MS2ST(last))));
+}
+
+uint32_t timer_elapsed32(uint32_t last)
+{
+    return ST2MS(chVTTimeElapsedSinceX(MS2ST(last)));
+}
diff --git a/tmk_core/common/command.c b/tmk_core/common/command.c
index 187a2b9496..084c9fe155 100644
--- a/tmk_core/common/command.c
+++ b/tmk_core/common/command.c
@@ -16,7 +16,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
 #include <stdint.h>
 #include <stdbool.h>
-#include <util/delay.h>
+#include "wait.h"
 #include "keycode.h"
 #include "host.h"
 #include "keymap.h"
@@ -103,12 +103,14 @@ bool command_proc(uint8_t code)
 bool command_extra(uint8_t code) __attribute__ ((weak));
 bool command_extra(uint8_t code)
 {
+    (void)code;
     return false;
 }
 
 bool command_console_extra(uint8_t code) __attribute__ ((weak));
 bool command_console_extra(uint8_t code)
 {
+    (void)code;
     return false;
 }
 
@@ -217,8 +219,11 @@ static void print_version(void)
 	    " " STR(BOOTLOADER_SIZE) "\n");
 
     print("GCC: " STR(__GNUC__) "." STR(__GNUC_MINOR__) "." STR(__GNUC_PATCHLEVEL__)
+#if defined(__AVR__)
           " AVR-LIBC: " __AVR_LIBC_VERSION_STRING__
-          " AVR_ARCH: avr" STR(__AVR_ARCH__) "\n");
+          " AVR_ARCH: avr" STR(__AVR_ARCH__)
+#endif
+		  "\n");
 
 	return;
 }
@@ -234,7 +239,7 @@ static void print_status(void)
 #ifdef NKRO_ENABLE
     print_val_hex8(keyboard_nkro);
 #endif
-    print_val_hex32(timer_count);
+    print_val_hex32(timer_read32());
 
 #ifdef PROTOCOL_PJRC
     print_val_hex8(UDCON);
@@ -360,7 +365,7 @@ static bool command_common(uint8_t code)
 	            stop_all_notes();
                 shutdown_user();
             #else
-	            _delay_ms(1000);
+	            wait_ms(1000);
             #endif
             bootloader_jump(); // not return
             break;
@@ -430,10 +435,11 @@ static bool command_common(uint8_t code)
         case MAGIC_KC(MAGIC_KEY_NKRO):
             clear_keyboard(); // clear to prevent stuck keys
             keyboard_nkro = !keyboard_nkro;
-            if (keyboard_nkro)
+            if (keyboard_nkro) {
                 print("NKRO: on\n");
-            else
+            } else {
                 print("NKRO: off\n");
+            }
             break;
 #endif
 
@@ -750,10 +756,11 @@ static bool mousekey_console(uint8_t code)
             print("?");
             return false;
     }
-    if (mousekey_param)
+    if (mousekey_param) {
         xprintf("M%d> ", mousekey_param);
-    else
+    } else {
         print("M>" );
+    }
     return true;
 }
 #endif
diff --git a/tmk_core/common/avr/eeconfig.c b/tmk_core/common/eeconfig.c
index 656938fb33..140d2b85bb 100644
--- a/tmk_core/common/avr/eeconfig.c
+++ b/tmk_core/common/eeconfig.c
@@ -1,6 +1,6 @@
 #include <stdint.h>
 #include <stdbool.h>
-#include <avr/eeprom.h>
+#include "eeprom.h"
 #include "eeconfig.h"
 
 void eeconfig_init(void)
diff --git a/tmk_core/common/eeprom.h b/tmk_core/common/eeprom.h
new file mode 100644
index 0000000000..2cc2ccee3f
--- /dev/null
+++ b/tmk_core/common/eeprom.h
@@ -0,0 +1,22 @@
+#ifndef TMK_CORE_COMMON_EEPROM_H_
+#define TMK_CORE_COMMON_EEPROM_H_
+
+#if defined(__AVR__)
+#include <avr/eeprom.h>
+#else
+uint8_t 	eeprom_read_byte (const uint8_t *__p);
+uint16_t 	eeprom_read_word (const uint16_t *__p);
+uint32_t 	eeprom_read_dword (const uint32_t *__p);
+void 	eeprom_read_block (void *__dst, const void *__src, uint32_t __n);
+void 	eeprom_write_byte (uint8_t *__p, uint8_t __value);
+void 	eeprom_write_word (uint16_t *__p, uint16_t __value);
+void 	eeprom_write_dword (uint32_t *__p, uint32_t __value);
+void 	eeprom_write_block (const void *__src, void *__dst, uint32_t __n);
+void 	eeprom_update_byte (uint8_t *__p, uint8_t __value);
+void 	eeprom_update_word (uint16_t *__p, uint16_t __value);
+void 	eeprom_update_dword (uint32_t *__p, uint32_t __value);
+void 	eeprom_update_block (const void *__src, void *__dst, uint32_t __n);
+#endif
+
+
+#endif /* TMK_CORE_COMMON_EEPROM_H_ */
diff --git a/tmk_core/common/keyboard.c b/tmk_core/common/keyboard.c
index 34e1ceeca5..81df8eb73b 100644
--- a/tmk_core/common/keyboard.c
+++ b/tmk_core/common/keyboard.c
@@ -51,17 +51,20 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #endif
 
 #ifdef MATRIX_HAS_GHOST
-static bool is_row_ghosting(uint8_t row){
-    matrix_row_t state = matrix_get_row(row);
-    /* no ghosting happens when only one key in the row is pressed */
-    if (!(state - 1 & state)) return false;
-    /* ghosting occurs when two keys in the same column are pressed */
-    for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
-        if (r != row && matrix_get_row(r) & state) return true;
+static bool has_ghost_in_row(uint8_t row)
+{
+    matrix_row_t matrix_row = matrix_get_row(row);
+    // No ghost exists when less than 2 keys are down on the row
+    if (((matrix_row - 1) & matrix_row) == 0)
+        return false;
+
+    // Ghost occurs when the row shares column line with other row
+    for (uint8_t i=0; i < MATRIX_ROWS; i++) {
+        if (i != row && (matrix_get_row(i) & matrix_row))
+            return true;
     }
     return false;
 }
-
 #endif
 
 __attribute__ ((weak))
@@ -100,72 +103,86 @@ void keyboard_init(void) {
 #endif
 }
 
-/* does routine keyboard jobs */
-void keyboard_task(void) {
-    static uint8_t led_status;
+/*
+ * Do keyboard routine jobs: scan mantrix, light LEDs, ...
+ * This is repeatedly called as fast as possible.
+ */
+void keyboard_task(void)
+{
+    static matrix_row_t matrix_prev[MATRIX_ROWS];
+#ifdef MATRIX_HAS_GHOST
+    static matrix_row_t matrix_ghost[MATRIX_ROWS];
+#endif
+    static uint8_t led_status = 0;
+    matrix_row_t matrix_row = 0;
+    matrix_row_t matrix_change = 0;
+
     matrix_scan();
-    for (int8_t r = MATRIX_ROWS - 1; r >= 0; --r) {
-        static matrix_row_t previous_matrix[MATRIX_ROWS];
-        matrix_row_t state = matrix_get_row(r);
-        matrix_row_t changes = state ^ previous_matrix[r];
-        if (changes) {
+    for (uint8_t r = 0; r < MATRIX_ROWS; r++) {
+        matrix_row = matrix_get_row(r);
+        matrix_change = matrix_row ^ matrix_prev[r];
+        if (matrix_change) {
 #ifdef MATRIX_HAS_GHOST
-            static matrix_row_t deghosting_matrix[MATRIX_ROWS];
-            if (is_row_ghosting(r)) {
-                /* debugs the deghosting mechanism */
-                /* doesn't update previous_matrix until the ghosting has stopped
-                 * in order to prevent the last key from being lost
+            if (has_ghost_in_row(r)) {
+                /* Keep track of whether ghosted status has changed for
+                 * debugging. But don't update matrix_prev until un-ghosted, or
+                 * the last key would be lost.
                  */
-                if (debug_matrix && deghosting_matrix[r] != state) {
+                if (debug_matrix && matrix_ghost[r] != matrix_row) {
                     matrix_print();
                 }
-                deghosting_matrix[r] = state;
+                matrix_ghost[r] = matrix_row;
                 continue;
             }
-            deghosting_matrix[r] = state;
+            matrix_ghost[r] = matrix_row;
 #endif
             if (debug_matrix) matrix_print();
-            for (int8_t c = MATRIX_COLS - 1; c >= 0; --c) {
-                matrix_row_t mask = (matrix_row_t)1 << c;
-                if (changes & mask) {
-                    keyevent_t event;
-                    event.key = (keypos_t){ .row = r, .col = c };
-                    event.pressed = state & mask;
-                    /* the time should not be 0 */
-                    event.time = timer_read() | 1;
-                    action_exec(event);
-                    /* records the processed key event */
-                    previous_matrix[r] ^= mask;
-                    /* processes one key event per call */
-                    goto event_processed;
+            for (uint8_t c = 0; c < MATRIX_COLS; c++) {
+                if (matrix_change & ((matrix_row_t)1<<c)) {
+                    action_exec((keyevent_t){
+                        .key = (keypos_t){ .row = r, .col = c },
+                        .pressed = (matrix_row & ((matrix_row_t)1<<c)),
+                        .time = (timer_read() | 1) /* time should not be 0 */
+                    });
+                    // record a processed key
+                    matrix_prev[r] ^= ((matrix_row_t)1<<c);
+                    // process a key per task call
+                    goto MATRIX_LOOP_END;
                 }
             }
         }
     }
-    /* sends tick events when the keyboard is idle */
+    // call with pseudo tick event when no real key event.
     action_exec(TICK);
-event_processed:
+
+MATRIX_LOOP_END:
+
 #ifdef MOUSEKEY_ENABLE
-    /* repeats and accelerates the mouse keys */
+    // mousekey repeat & acceleration
     mousekey_task();
 #endif
+
 #ifdef PS2_MOUSE_ENABLE
     ps2_mouse_task();
 #endif
+
 #ifdef SERIAL_MOUSE_ENABLE
-    serial_mouse_task();
+        serial_mouse_task();
 #endif
+
 #ifdef ADB_MOUSE_ENABLE
-    adb_mouse_task();
+        adb_mouse_task();
 #endif
-    /* updates the LEDs */
+
+    // update LED
     if (led_status != host_keyboard_leds()) {
         led_status = host_keyboard_leds();
         keyboard_set_leds(led_status);
     }
 }
 
-void keyboard_set_leds(uint8_t leds) {
-    if (debug_keyboard) dprintf("Keyboard LEDs state: %x\n", leds);
+void keyboard_set_leds(uint8_t leds)
+{
+    if (debug_keyboard) { debug("keyboard_set_led: "); debug_hex8(leds); debug("\n"); }
     led_set(leds);
 }
diff --git a/tmk_core/common/magic.c b/tmk_core/common/magic.c
index f21d1346c7..194e4cc026 100644
--- a/tmk_core/common/magic.c
+++ b/tmk_core/common/magic.c
@@ -1,6 +1,8 @@
 #include <stdint.h>
 #include <stdbool.h>
+#if defined(__AVR__)
 #include <util/delay.h>
+#endif
 #include "matrix.h"
 #include "bootloader.h"
 #include "debug.h"
@@ -33,4 +35,4 @@ void magic(void)
     default_layer = eeconfig_read_default_layer();
     default_layer_set((uint32_t)default_layer);
 
-}
\ No newline at end of file
+}
diff --git a/tmk_core/common/matrix.h b/tmk_core/common/matrix.h
index 5f2f831b45..71153a5f58 100644
--- a/tmk_core/common/matrix.h
+++ b/tmk_core/common/matrix.h
@@ -20,59 +20,48 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #include <stdint.h>
 #include <stdbool.h>
 
-#if MATRIX_COLS <= 8
-typedef uint8_t matrix_row_t;
-#elif MATRIX_COLS <= 16
-typedef uint16_t matrix_row_t;
-#elif MATRIX_COLS <= 32
-typedef uint32_t matrix_row_t;
+
+#if (MATRIX_COLS <= 8)
+typedef  uint8_t    matrix_row_t;
+#elif (MATRIX_COLS <= 16)
+typedef  uint16_t   matrix_row_t;
+#elif (MATRIX_COLS <= 32)
+typedef  uint32_t   matrix_row_t;
 #else
-#   error "There are too many columns."
+#error "MATRIX_COLS: invalid value"
 #endif
 
-#if DIODE_DIRECTION == ROW2COL
-#   if MATRIX_ROWS <= 8
-typedef uint8_t matrix_col_t;
-#   elif MATRIX_ROWS <= 16
-typedef uint16_t matrix_col_t;
-#   elif MATRIX_ROWS <= 32
-typedef uint32_t matrix_col_t;
-#   else
-#       error "There are too many rows."
-#   endif
-#endif
+#define MATRIX_IS_ON(row, col)  (matrix_get_row(row) && (1<<col))
 
-typedef struct {
-    uint8_t input_addr:4;
-    uint8_t bit:4;
-} io_pin_t;
 
 #ifdef __cplusplus
 extern "C" {
 #endif
-/* counts the number of rows in the matrix */
+
+/* number of matrix rows */
 uint8_t matrix_rows(void);
-/* counts the number of columns in the matrix */
+/* number of matrix columns */
 uint8_t matrix_cols(void);
-/* sets up the matrix before matrix_init */
+/* should be called at early stage of startup before matrix_init.(optional) */
 void matrix_setup(void);
-/* intializes the matrix */
+/* intialize matrix for scaning. */
 void matrix_init(void);
-/* scans the entire matrix */
+/* scan all key states on matrix */
 uint8_t matrix_scan(void);
-/* checks if the matrix has been modified */
+/* whether modified from previous scan. used after matrix_scan. */
 bool matrix_is_modified(void) __attribute__ ((deprecated));
-/* checks if a key is pressed */
+/* whether a swtich is on */
 bool matrix_is_on(uint8_t row, uint8_t col);
-/* inspects the state of a row in the matrix */
+/* matrix state on row */
 matrix_row_t matrix_get_row(uint8_t row);
-/* prints the matrix for debugging */
+/* print matrix for debug */
 void matrix_print(void);
-/* counts the total number of keys pressed */
-uint8_t matrix_key_count(void);
-/* controls power to the matrix */
+
+
+/* power control */
 void matrix_power_up(void);
 void matrix_power_down(void);
+
 /* executes code for Quantum */
 void matrix_init_quantum(void);
 void matrix_scan_quantum(void);
diff --git a/tmk_core/common/print.c b/tmk_core/common/print.c
index ca94e1e5d6..00489557f2 100644
--- a/tmk_core/common/print.c
+++ b/tmk_core/common/print.c
@@ -38,11 +38,15 @@ void print_set_sendchar(int8_t (*sendchar_func)(uint8_t))
     xdev_out(sendchar_func);
 }
 
-#elif defined(__arm__)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+
+// don't need anything extra
+
+#elif defined(__arm__) /* __AVR__ */
 
 // TODO
 //void print_set_sendchar(int8_t (*sendchar_func)(uint8_t)) { }
 
-#endif
+#endif /* __AVR__ */
 
 #endif
diff --git a/tmk_core/common/print.h b/tmk_core/common/print.h
index 4f3dde65aa..0368bcd4a1 100644
--- a/tmk_core/common/print.h
+++ b/tmk_core/common/print.h
@@ -47,7 +47,15 @@ extern "C"
 /* function pointer of sendchar to be used by print utility */
 void print_set_sendchar(int8_t (*print_sendchar_func)(uint8_t));
 
-#elif defined(__arm__)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+
+#include "chibios/printf.h"
+
+#define print(s)    printf(s)
+#define println(s)  printf(s "\r\n")
+#define xprintf  printf
+
+#elif defined(__arm__) /* __AVR__ */
 
 #include "mbed/xprintf.h"
 
diff --git a/tmk_core/common/progmem.h b/tmk_core/common/progmem.h
index 199b1bedfe..5b27656250 100644
--- a/tmk_core/common/progmem.h
+++ b/tmk_core/common/progmem.h
@@ -5,8 +5,8 @@
 #   include <avr/pgmspace.h>
 #elif defined(__arm__)
 #   define PROGMEM
-#   define pgm_read_byte(p)     *(p)
-#   define pgm_read_word(p)     *(p)
+#   define pgm_read_byte(p)     *((unsigned char*)p)
+#   define pgm_read_word(p)     *((uint16_t*)p)
 #endif
 
 #endif
diff --git a/tmk_core/common/report.h b/tmk_core/common/report.h
index f6c0a315de..0c799eca39 100644
--- a/tmk_core/common/report.h
+++ b/tmk_core/common/report.h
@@ -84,6 +84,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #   define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
 #   define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
 #   define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
+#elif defined(PROTOCOL_CHIBIOS) && defined(NKRO_ENABLE)
+#   include "protocol/chibios/usb_main.h"
+#   define KEYBOARD_REPORT_SIZE NKRO_EPSIZE
+#   define KEYBOARD_REPORT_KEYS (NKRO_EPSIZE - 2)
+#   define KEYBOARD_REPORT_BITS (NKRO_EPSIZE - 1)
 
 #else
 #   define KEYBOARD_REPORT_SIZE 8
diff --git a/tmk_core/common/wait.h b/tmk_core/common/wait.h
index 40d00b0c75..82727be012 100644
--- a/tmk_core/common/wait.h
+++ b/tmk_core/common/wait.h
@@ -9,9 +9,13 @@ extern "C" {
 #   include <util/delay.h>
 #   define wait_ms(ms)  _delay_ms(ms)
 #   define wait_us(us)  _delay_us(us)
-#elif defined(__arm__)
+#elif defined(PROTOCOL_CHIBIOS) /* __AVR__ */
+#   include "ch.h"
+#   define wait_ms(ms) chThdSleepMilliseconds(ms)
+#   define wait_us(us) chThdSleepMicroseconds(us)
+#elif defined(__arm__) /* __AVR__ */
 #   include "wait_api.h"
-#endif
+#endif /* __AVR__ */
 
 #ifdef __cplusplus
 }