diff --git a/arch/cpu/cc2538/cc2538-def.h b/arch/cpu/cc2538/cc2538-def.h
index 07947a21550ed73fdd97869dfadfb5317bdfc446..7189d63ee8a533e313879a2d8bd62b62437282bf 100644
--- a/arch/cpu/cc2538/cc2538-def.h
+++ b/arch/cpu/cc2538/cc2538-def.h
@@ -69,8 +69,10 @@
 #define MUTEX_CONF_ARCH_HEADER_PATH          "mutex-cortex.h"
 #define ATOMIC_CONF_ARCH_HEADER_PATH         "atomic-cortex.h"
 #define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h"
-
+/*---------------------------------------------------------------------------*/
 #define GPIO_HAL_CONF_ARCH_HDR_PATH          "dev/gpio-hal-arch.h"
+#define GPIO_HAL_CONF_ARCH_SW_TOGGLE         1
+#define GPIO_HAL_CONF_PORT_PIN_NUMBERING     0
 /*---------------------------------------------------------------------------*/
 #endif /* CC2538_DEF_H_ */
 /*---------------------------------------------------------------------------*/
diff --git a/arch/cpu/cc2538/dev/gpio-hal-arch.c b/arch/cpu/cc2538/dev/gpio-hal-arch.c
index bd2dfb92d8d57e58c2f9f84fd85a0b2c7beed6b5..8654945d4b09b5487fdf9089e96a183488739a02 100644
--- a/arch/cpu/cc2538/dev/gpio-hal-arch.c
+++ b/arch/cpu/cc2538/dev/gpio-hal-arch.c
@@ -45,7 +45,7 @@
 #include <stdint.h>
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
+gpio_hal_arch_no_port_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 {
   uint8_t port, pin_num, pin_mask;
   uint32_t port_base;
@@ -94,7 +94,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_cfg_t
-gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_pin_cfg_get(gpio_hal_pin_t pin)
 {
   uint8_t port, pin_num, pin_mask;
   uint32_t port_base;
@@ -145,17 +145,17 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value)
+gpio_hal_arch_no_port_write_pin(gpio_hal_pin_t pin, uint8_t value)
 {
   if(value == 1) {
-    gpio_hal_arch_set_pin(pin);
+    gpio_hal_arch_set_pin(GPIO_HAL_NULL_PORT, pin);
     return;
   }
-  gpio_hal_arch_clear_pin(pin);
+  gpio_hal_arch_clear_pin(GPIO_HAL_NULL_PORT, pin);
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_set_pins(gpio_hal_pin_mask_t pins)
 {
   GPIO_SET_PIN(GPIO_A_BASE, pins & 0xFF);
   GPIO_SET_PIN(GPIO_B_BASE, (pins >> 8) & 0xFF);
@@ -164,7 +164,7 @@ gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_clear_pins(gpio_hal_pin_mask_t pins)
 {
   GPIO_CLR_PIN(GPIO_A_BASE, pins & 0xFF);
   GPIO_CLR_PIN(GPIO_B_BASE, (pins >> 8) & 0xFF);
@@ -173,7 +173,7 @@ gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_mask_t
-gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_read_pins(gpio_hal_pin_mask_t pins)
 {
   gpio_hal_pin_mask_t rv = 0;
 
@@ -186,7 +186,8 @@ gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_write_pins(gpio_hal_pin_mask_t pins, gpio_hal_pin_mask_t value)
+gpio_hal_arch_no_port_write_pins(gpio_hal_pin_mask_t pins,
+                                 gpio_hal_pin_mask_t value)
 {
   GPIO_WRITE_PIN(GPIO_A_BASE, pins & 0xFF, value & 0xFF);
   GPIO_WRITE_PIN(GPIO_B_BASE, (pins >> 8) & 0xFF, (value >> 8) & 0xFF);
diff --git a/arch/cpu/cc2538/dev/gpio-hal-arch.h b/arch/cpu/cc2538/dev/gpio-hal-arch.h
index ad2f24219e5704c281e430a084ed14e0675df1ca..5d8db3ce8534433e8ff6b713b87d0537c9e8e3d1 100644
--- a/arch/cpu/cc2538/dev/gpio-hal-arch.h
+++ b/arch/cpu/cc2538/dev/gpio-hal-arch.h
@@ -58,31 +58,31 @@
 /*---------------------------------------------------------------------------*/
 #define gpio_hal_arch_init() do { /* Do nothing */ } while(0)
 
-#define gpio_hal_arch_interrupt_enable(p) do { \
+#define gpio_hal_arch_interrupt_enable(port, p) do { \
   GPIO_ENABLE_INTERRUPT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
   NVIC_EnableIRQ(PIN_TO_PORT(p)); \
 } while(0);
 
-#define gpio_hal_arch_interrupt_disable(p) \
+#define gpio_hal_arch_interrupt_disable(port, p) \
   GPIO_DISABLE_INTERRUPT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8))
 
-#define gpio_hal_arch_pin_set_input(p) do { \
+#define gpio_hal_arch_pin_set_input(port, p) do { \
   GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
   GPIO_SET_INPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
 } while(0);
 
-#define gpio_hal_arch_pin_set_output(p) do { \
+#define gpio_hal_arch_pin_set_output(port, p) do { \
   GPIO_SOFTWARE_CONTROL(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
   GPIO_SET_OUTPUT(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)); \
 } while(0);
 
-#define gpio_hal_arch_set_pin(p) \
+#define gpio_hal_arch_set_pin(port, p) \
   GPIO_SET_PIN(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8))
 
-#define gpio_hal_arch_clear_pin(p) \
+#define gpio_hal_arch_clear_pin(port, p) \
   GPIO_CLR_PIN(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8))
 
-#define gpio_hal_arch_read_pin(p) \
+#define gpio_hal_arch_read_pin(port, p) \
   (GPIO_READ_PIN(PIN_TO_PORT_BASE(p), GPIO_PIN_MASK((p) % 8)) == 0 ? 0 : 1)
 /*---------------------------------------------------------------------------*/
 #endif /* GPIO_HAL_ARCH_H_ */
diff --git a/arch/cpu/cc26x0-cc13x0/cc13xx-cc26xx-def.h b/arch/cpu/cc26x0-cc13x0/cc13xx-cc26xx-def.h
index c563ca86e338aa195a81361122f5d0d7ff6bc214..302becc3ff3cc43398e6488aa958656cc90fc876 100644
--- a/arch/cpu/cc26x0-cc13x0/cc13xx-cc26xx-def.h
+++ b/arch/cpu/cc26x0-cc13x0/cc13xx-cc26xx-def.h
@@ -137,10 +137,10 @@
 #define MUTEX_CONF_ARCH_HEADER_PATH          "mutex-cortex.h"
 #define ATOMIC_CONF_ARCH_HEADER_PATH         "atomic-cortex.h"
 #define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h"
-
-#define GPIO_HAL_CONF_ARCH_HDR_PATH          "dev/gpio-hal-arch.h"
 /*---------------------------------------------------------------------------*/
-#define GPIO_HAL_CONF_ARCH_SW_TOGGLE 0
+#define GPIO_HAL_CONF_ARCH_HDR_PATH          "dev/gpio-hal-arch.h"
+#define GPIO_HAL_CONF_ARCH_SW_TOGGLE         0
+#define GPIO_HAL_CONF_PORT_PIN_NUMBERING     0
 /*---------------------------------------------------------------------------*/
 #define SPI_CONF_CONTROLLER_COUNT    2
 /*---------------------------------------------------------------------------*/
diff --git a/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.c b/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.c
index 4fd4f768849084e81e3e3e4fa81274f5a69b90ce..8e3d0c783ccf739dc7350bc72c4ea6ace9ed8154 100644
--- a/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.c
+++ b/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.c
@@ -46,7 +46,7 @@
 #define CONFIG_MASK (IOC_IOPULL_M | IOC_INT_M | IOC_IOMODE_OPEN_SRC_INV)
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
+gpio_hal_arch_no_port_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 {
   uint32_t config;
   gpio_hal_pin_cfg_t tmp;
@@ -86,7 +86,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_cfg_t
-gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_pin_cfg_get(gpio_hal_pin_t pin)
 {
   gpio_hal_pin_cfg_t cfg;
   uint32_t tmp;
@@ -129,7 +129,7 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_mask_t
-gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_read_pins(gpio_hal_pin_mask_t pins)
 {
   gpio_hal_pin_mask_t oe_pins;
 
@@ -143,7 +143,7 @@ gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 uint8_t
-gpio_hal_arch_read_pin(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_read_pin(gpio_hal_pin_t pin)
 {
   if(ti_lib_gpio_get_output_enable_dio(pin)) {
     return (HWREG(GPIO_BASE + GPIO_O_DOUT31_0) >> pin) & 1;
diff --git a/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.h b/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.h
index 3997c1062a2205599943b8e6e1725bada2dd1b1d..d142eefab5b7bb7e0ded6f335e44b16627afedf1 100644
--- a/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.h
+++ b/arch/cpu/cc26x0-cc13x0/dev/gpio-hal-arch.h
@@ -54,21 +54,21 @@
 /*---------------------------------------------------------------------------*/
 #define gpio_hal_arch_init()               do { /* Do nothing */ } while(0)
 
-#define gpio_hal_arch_interrupt_enable(p)  interrupt_enable(p)
+#define gpio_hal_arch_interrupt_enable(port, pin)  interrupt_enable(pin)
+#define gpio_hal_arch_interrupt_disable(port, pin) ti_lib_ioc_int_disable(pin)
 
-#define gpio_hal_arch_interrupt_disable(p) ti_lib_ioc_int_disable(p)
-#define gpio_hal_arch_pin_set_input(p)     ti_lib_ioc_pin_type_gpio_input(p)
-#define gpio_hal_arch_pin_set_output(p)    ti_lib_ioc_pin_type_gpio_output(p)
+#define gpio_hal_arch_pin_set_input(port, pin)     ti_lib_ioc_pin_type_gpio_input(pin)
+#define gpio_hal_arch_pin_set_output(port, pin)    ti_lib_ioc_pin_type_gpio_output(pin)
 
-#define gpio_hal_arch_set_pin(p)           ti_lib_gpio_set_dio(p)
-#define gpio_hal_arch_clear_pin(p)         ti_lib_gpio_clear_dio(p)
-#define gpio_hal_arch_toggle_pin(p)        ti_lib_gpio_toggle_dio(p)
-#define gpio_hal_arch_write_pin(p, v)      ti_lib_gpio_write_dio(p, v)
+#define gpio_hal_arch_set_pin(port, pin)           ti_lib_gpio_set_dio(pin)
+#define gpio_hal_arch_clear_pin(port, pin)         ti_lib_gpio_clear_dio(pin)
+#define gpio_hal_arch_toggle_pin(port, pin)        ti_lib_gpio_toggle_dio(pin)
+#define gpio_hal_arch_write_pin(port, pin, v)      ti_lib_gpio_write_dio(pin, v)
 
-#define gpio_hal_arch_set_pins(p)          ti_lib_gpio_set_multi_dio(p)
-#define gpio_hal_arch_clear_pins(p)        ti_lib_gpio_clear_multi_dio(p)
-#define gpio_hal_arch_toggle_pins(p)       ti_lib_gpio_toggle_multi_dio(p)
-#define gpio_hal_arch_write_pins(p, v)     ti_lib_gpio_write_multi_dio(p, v)
+#define gpio_hal_arch_set_pins(port, pin)          ti_lib_gpio_set_multi_dio(pin)
+#define gpio_hal_arch_clear_pins(port, pin)        ti_lib_gpio_clear_multi_dio(pin)
+#define gpio_hal_arch_toggle_pins(port, pin)       ti_lib_gpio_toggle_multi_dio(pin)
+#define gpio_hal_arch_write_pins(port, pin, v)     ti_lib_gpio_write_multi_dio(pin, v)
 /*---------------------------------------------------------------------------*/
 static inline void
 interrupt_enable(gpio_hal_pin_t pin)
diff --git a/arch/cpu/native/dev/gpio-hal-arch.c b/arch/cpu/native/dev/gpio-hal-arch.c
index 366141d775bf9d25c7d7adf90ecea5c40ea081bc..1e56850812b867b5d7522427b11026f89f572427 100644
--- a/arch/cpu/native/dev/gpio-hal-arch.c
+++ b/arch/cpu/native/dev/gpio-hal-arch.c
@@ -49,7 +49,7 @@ gpio_hal_arch_init(void)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_interrupt_enable(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -60,7 +60,7 @@ gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_interrupt_disable(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -71,7 +71,7 @@ gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
+gpio_hal_arch_no_port_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -83,7 +83,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_cfg_t
-gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_pin_cfg_get(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -95,7 +95,7 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_pin_set_input(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_pin_set_input(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -106,7 +106,7 @@ gpio_hal_arch_pin_set_input(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_pin_set_output(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_pin_set_output(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -117,7 +117,7 @@ gpio_hal_arch_pin_set_output(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_set_pin(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_set_pin(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -129,7 +129,7 @@ gpio_hal_arch_set_pin(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_clear_pin(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_clear_pin(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -141,7 +141,7 @@ gpio_hal_arch_clear_pin(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 uint8_t
-gpio_hal_arch_read_pin(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_read_pin(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -153,7 +153,7 @@ gpio_hal_arch_read_pin(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value)
+gpio_hal_arch_no_port_write_pin(gpio_hal_pin_t pin, uint8_t value)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
@@ -165,7 +165,7 @@ gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_set_pins(gpio_hal_pin_mask_t pins)
 {
   gpio_hal_pin_t pin;
 
@@ -179,7 +179,7 @@ gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_clear_pins(gpio_hal_pin_mask_t pins)
 {
   gpio_hal_pin_t pin;
 
@@ -193,7 +193,7 @@ gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_mask_t
-gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_read_pins(gpio_hal_pin_mask_t pins)
 {
   gpio_hal_pin_t pin;
   gpio_hal_pin_mask_t state = 0;
@@ -207,7 +207,8 @@ gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_write_pins(gpio_hal_pin_mask_t pins, gpio_hal_pin_mask_t value)
+gpio_hal_arch_no_port_write_pins(gpio_hal_pin_mask_t pins,
+                                 gpio_hal_pin_mask_t value)
 {
   gpio_hal_pin_t pin;
 
diff --git a/arch/cpu/native/native-def.h b/arch/cpu/native/native-def.h
index d85ae7100440cf0ec9451ca1506d1e7db7e2e853..6d6b817552fc29a6d06c68ab23c658e3335a9b30 100644
--- a/arch/cpu/native/native-def.h
+++ b/arch/cpu/native/native-def.h
@@ -32,7 +32,8 @@
 #ifndef NATIVE_DEF_H_
 #define NATIVE_DEF_H_
 /*---------------------------------------------------------------------------*/
-#define GPIO_HAL_CONF_ARCH_SW_TOGGLE 1
+#define GPIO_HAL_CONF_ARCH_SW_TOGGLE     1
+#define GPIO_HAL_CONF_PORT_PIN_NUMBERING 0
 /*---------------------------------------------------------------------------*/
 #endif /* NATIVE_DEF_H_ */
 /*---------------------------------------------------------------------------*/
diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h
index 0a5b32416039adf0317039857cc9d5f55ea5913b..66079c449c14f5e6cdbf56dd66d9f1cba7085a2b 100644
--- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h
+++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-conf.h
@@ -61,15 +61,6 @@
 #define BOARD_CONF_SENSORS_DISABLE          0
 #endif
 /*---------------------------------------------------------------------------*/
-/**
- * \name GPIO HAL configuration.
- *
- * @{
- */
-#define GPIO_HAL_CONF_ARCH_SW_TOGGLE        0
-#define GPIO_HAL_CONF_ARCH_HDR_PATH         "dev/gpio-hal-arch.h"
-/** @} */
-/*---------------------------------------------------------------------------*/
 /**
  * \name Watchdog Configuration.
  *
diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h
index 75b077a9db3e5d1b9dd73f7cf7c2459d5a7cae70..7c79cc611be4b8b8181a1b975c9c8e37cf03ab7a 100644
--- a/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h
+++ b/arch/cpu/simplelink-cc13xx-cc26xx/cc13xx-cc26xx-def.h
@@ -130,6 +130,11 @@
 #define ATOMIC_CONF_ARCH_HEADER_PATH         "atomic-cortex.h"
 #define MEMORY_BARRIER_CONF_ARCH_HEADER_PATH "memory-barrier-cortex.h"
 /*---------------------------------------------------------------------------*/
+/* GPIO HAL configuration */
+#define GPIO_HAL_CONF_ARCH_HDR_PATH         "dev/gpio-hal-arch.h"
+#define GPIO_HAL_CONF_ARCH_SW_TOGGLE        0
+#define GPIO_HAL_CONF_PORT_PIN_NUMBERING    0
+/*---------------------------------------------------------------------------*/
 #endif /* CC13XX_CC26XX_DEF_H_ */
 /*---------------------------------------------------------------------------*/
 /** @} */
diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c
index f07a1f693862961a3faae56dfb664dbc2cd63c82..1cd8c1d919f075a3584f9b737ae921af47540d2a 100644
--- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c
+++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.c
@@ -147,7 +147,7 @@ gpio_hal_arch_init(void)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_interrupt_enable(gpio_hal_pin_t pin)
 {
   PIN_Config pin_cfg;
   PIN_Config irq_cfg;
@@ -160,7 +160,7 @@ gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_interrupt_disable(gpio_hal_pin_t pin)
 {
   PIN_add(pin_handle, PIN_getConfig(pin));
 
@@ -168,7 +168,7 @@ gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
+gpio_hal_arch_no_port_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 {
   PIN_add(pin_handle, PIN_getConfig(pin));
 
@@ -182,7 +182,7 @@ gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_cfg_t
-gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_pin_cfg_get(gpio_hal_pin_t pin)
 {
   PIN_Config pin_cfg = PIN_getConfig(pin);
   gpio_hal_pin_cfg_t cfg = 0;
@@ -193,7 +193,7 @@ gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin)
 }
 /*---------------------------------------------------------------------------*/
 gpio_hal_pin_mask_t
-gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_read_pins(gpio_hal_pin_mask_t pins)
 {
   /* For pins configured as output we need to read DOUT31_0 */
   gpio_hal_pin_mask_t oe_pins = GPIO_getOutputEnableMultiDio(pins);
@@ -205,7 +205,7 @@ gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins)
 }
 /*---------------------------------------------------------------------------*/
 uint8_t
-gpio_hal_arch_read_pin(gpio_hal_pin_t pin)
+gpio_hal_arch_no_port_read_pin(gpio_hal_pin_t pin)
 {
   return (GPIO_getOutputEnableDio(pin))
          ? PINCC26XX_getOutputValue(pin)
diff --git a/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.h b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.h
index 3ca169a82fdfe7ed5721ec5925d3a006f0ca5738..55e67128e059db1d1d2dc2c150ae0eb8baef62fd 100644
--- a/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.h
+++ b/arch/cpu/simplelink-cc13xx-cc26xx/dev/gpio-hal-arch.h
@@ -53,20 +53,20 @@
 
 #include <ti/drivers/pin/PINCC26XX.h>
 /*---------------------------------------------------------------------------*/
-#define gpio_hal_arch_pin_set_input(p)        PINCC26XX_setOutputEnable(p, false)
-#define gpio_hal_arch_pin_set_output(p)       PINCC26XX_setOutputEnable(p, true)
+#define gpio_hal_arch_pin_set_input(port, pin)  PINCC26XX_setOutputEnable(pin, false)
+#define gpio_hal_arch_pin_set_output(port, pin) PINCC26XX_setOutputEnable(pin, true)
 
-#define gpio_hal_arch_set_pin(p)              PINCC26XX_setOutputValue(p, 1)
-#define gpio_hal_arch_clear_pin(p)            PINCC26XX_setOutputValue(p, 0)
-#define gpio_hal_arch_toggle_pin(p)           PINCC26XX_setOutputValue(p, \
-                                                PINCC26XX_getOutputValue(p) \
+#define gpio_hal_arch_set_pin(port, pin)        PINCC26XX_setOutputValue(pin, 1)
+#define gpio_hal_arch_clear_pin(port, pin)      PINCC26XX_setOutputValue(pin, 0)
+#define gpio_hal_arch_toggle_pin(port, pin)     PINCC26XX_setOutputValue(pin, \
+                                                  PINCC26XX_getOutputValue(pin) \
                                                   ? 0 : 1)
-#define gpio_hal_arch_write_pin(p, v)         PINCC26XX_setOutputValue(p, v)
+#define gpio_hal_arch_write_pin(port, pin, v)   PINCC26XX_setOutputValue(pin, v)
 
-#define gpio_hal_arch_set_pins(p)             GPIO_setMultiDio(p)
-#define gpio_hal_arch_clear_pins(p)           GPIO_clearMultiDio(p)
-#define gpio_hal_arch_toggle_pins(p)          GPIO_toggleMultiDio(p)
-#define gpio_hal_arch_write_pins(p, v)        GPIO_writeMultiDio(p, v)
+#define gpio_hal_arch_set_pins(port, pin)       GPIO_setMultiDio(pin)
+#define gpio_hal_arch_clear_pins(port, pin)     GPIO_clearMultiDio(pin)
+#define gpio_hal_arch_toggle_pins(port, pin)    GPIO_toggleMultiDio(pin)
+#define gpio_hal_arch_write_pins(port, pin, v)  GPIO_writeMultiDio(pin, v)
 /*---------------------------------------------------------------------------*/
 #endif /* GPIO_HAL_ARCH_H_ */
 /*---------------------------------------------------------------------------*/
diff --git a/arch/dev/ext-flash/ext-flash.c b/arch/dev/ext-flash/ext-flash.c
index c4b108271e3f3d69270286c29a357f84a99be977..d50198910f67a3a84d33b390402ca6b198f43159 100644
--- a/arch/dev/ext-flash/ext-flash.c
+++ b/arch/dev/ext-flash/ext-flash.c
@@ -100,6 +100,12 @@
 #define VERIFY_PART_OK               1
 /*---------------------------------------------------------------------------*/
 static const spi_device_t flash_spi_configuration_default = {
+#if GPIO_HAL_PORT_PIN_NUMBERING
+  .port_spi_sck = EXT_FLASH_SPI_PORT_SCK,
+  .port_spi_miso = EXT_FLASH_SPI_PORT_MISO,
+  .port_spi_mosi = EXT_FLASH_SPI_PORT_MOSI,
+  .port_spi_cs = EXT_FLASH_SPI_PORT_CS,
+#endif
   .spi_controller = EXT_FLASH_SPI_CONTROLLER,
   .pin_spi_sck = EXT_FLASH_SPI_PIN_SCK,
   .pin_spi_miso = EXT_FLASH_SPI_PIN_MISO,
diff --git a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c
index 4f625943ba438da49b17172c403e2af9c5c16767..c633974e64eae213b9b937fd4fb82ee706881c4f 100644
--- a/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c
+++ b/arch/platform/simplelink/cc13xx-cc26xx/srf06/als-sensor.c
@@ -74,14 +74,14 @@ config(int type, int enable)
     return init();
 
   case SENSORS_ACTIVE:
-    gpio_hal_arch_pin_set_output(Board_ALS_PWR);
-    gpio_hal_arch_pin_set_input(Board_ALS_OUT);
+    PINCC26XX_setOutputEnable(Board_ALS_PWR, true);
+    PINCC26XX_setOutputEnable(Board_ALS_OUT, false);
 
     if(enable) {
-      gpio_hal_arch_set_pin(Board_ALS_PWR);
+      PINCC26XX_setOutputValue(Board_ALS_PWR, 1);
       clock_delay_usec(2000);
     } else {
-      gpio_hal_arch_clear_pin(Board_ALS_PWR);
+      PINCC26XX_setOutputValue(Board_ALS_PWR, 0);
     }
     break;
 
diff --git a/examples/dev/gpio-hal/README.md b/examples/dev/gpio-hal/README.md
index 84ab68f88372352da07eb060feb79519c23b0931..ac756b0bc67a2a77ee143556a7cbf5b4aff17e2c 100644
--- a/examples/dev/gpio-hal/README.md
+++ b/examples/dev/gpio-hal/README.md
@@ -8,7 +8,9 @@ developing a new port.
 
 This example assumes a device with:
 
-* 3 output pins (e.g. LEDs).
+* 3 output pins (e.g. LEDs). If the platform uses the port/pin GPIO numbering
+  scheme then this example assumes that at least 2 of those pins are part of
+  the same port.
 * 1 button.
 
 # Supported devices
@@ -34,3 +36,10 @@ board that you wish to test with the example. For example, if you have a LED
 connected to pin 20, then you will need to
 
     gpio_hal_pin_t out_pin1 = 20;
+
+If the platform uses the port/pin GPIO numbering scheme then you will also
+need to provide definitions for the following variables:
+
+* `out_port1` and `out_port2_3`. `out_port2_3` corresponds to the port that
+  `out_pin2` and `out_pin3` are members of.
+* `btn_port` for the button pin's port.
diff --git a/examples/dev/gpio-hal/gpio-hal-example.c b/examples/dev/gpio-hal/gpio-hal-example.c
index 75137e26ae2578c6727f8c866d505d7ddc3b9c50..dc29b4674ad26286cac8a6e3cb324f042628a548 100644
--- a/examples/dev/gpio-hal/gpio-hal-example.c
+++ b/examples/dev/gpio-hal/gpio-hal-example.c
@@ -40,6 +40,15 @@
 /*---------------------------------------------------------------------------*/
 extern gpio_hal_pin_t out_pin1, out_pin2, out_pin3;
 extern gpio_hal_pin_t btn_pin;
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+extern gpio_hal_port_t out_port1, out_port2_3;
+extern gpio_hal_port_t btn_port;
+#else
+#define out_port1   GPIO_HAL_NULL_PORT
+#define out_port2_3 GPIO_HAL_NULL_PORT
+#define btn_port    GPIO_HAL_NULL_PORT
+#endif
 /*---------------------------------------------------------------------------*/
 static struct etimer et;
 static uint8_t counter;
@@ -69,70 +78,70 @@ PROCESS_THREAD(gpio_hal_example, ev, data)
     if(ev == PROCESS_EVENT_TIMER && data == &et) {
       if((counter & 7) == 0) {
         /* Set output and test write, high */
-        gpio_hal_arch_pin_set_output(out_pin1);
-        gpio_hal_arch_pin_set_output(out_pin2);
-        gpio_hal_arch_pin_set_output(out_pin3);
+        gpio_hal_arch_pin_set_output(out_port1, out_pin1);
+        gpio_hal_arch_pin_set_output(out_port2_3, out_pin2);
+        gpio_hal_arch_pin_set_output(out_port2_3, out_pin3);
 
-        gpio_hal_arch_write_pin(out_pin1, 1);
-        gpio_hal_arch_write_pins(
+        gpio_hal_arch_write_pin(out_port1, out_pin1, 1);
+        gpio_hal_arch_write_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3),
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3));
       } else if((counter & 7) == 1) {
         /* Test write, low */
-        gpio_hal_arch_write_pin(out_pin1, 0);
-        gpio_hal_arch_write_pins(
+        gpio_hal_arch_write_pin(out_port1, out_pin1, 0);
+        gpio_hal_arch_write_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3), 0);
       } else if((counter & 7) == 2) {
         /* Test set */
-        gpio_hal_arch_set_pin(out_pin1);
-        gpio_hal_arch_set_pins(
+        gpio_hal_arch_set_pin(out_port1, out_pin1);
+        gpio_hal_arch_set_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3));
       } else if((counter & 7) == 3) {
         /* Test clear */
-        gpio_hal_arch_clear_pin(out_pin1);
-        gpio_hal_arch_clear_pins(
+        gpio_hal_arch_clear_pin(out_port1, out_pin1);
+        gpio_hal_arch_clear_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3));
       } else if((counter & 7) == 4) {
         /* Test toggle (should go high) */
-        gpio_hal_arch_toggle_pin(out_pin1);
-        gpio_hal_arch_toggle_pins(
+        gpio_hal_arch_toggle_pin(out_port1, out_pin1);
+        gpio_hal_arch_toggle_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3));
       } else if((counter & 7) == 5) {
         /* Test toggle (should go low) */
-        gpio_hal_arch_toggle_pin(out_pin1);
-        gpio_hal_arch_toggle_pins(
+        gpio_hal_arch_toggle_pin(out_port1, out_pin1);
+        gpio_hal_arch_toggle_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3));
       } else if((counter & 7) == 6) {
         /* Set to input and then set. Should stay off */
-        gpio_hal_arch_pin_set_input(out_pin1);
-        gpio_hal_arch_pin_set_input(out_pin2);
-        gpio_hal_arch_pin_set_input(out_pin3);
-        gpio_hal_arch_set_pin(out_pin1);
-        gpio_hal_arch_set_pins(
+        gpio_hal_arch_pin_set_input(out_port1, out_pin1);
+        gpio_hal_arch_pin_set_input(out_port2_3, out_pin2);
+        gpio_hal_arch_pin_set_input(out_port2_3, out_pin3);
+        gpio_hal_arch_set_pin(out_port1, out_pin1);
+        gpio_hal_arch_set_pins(out_port2_3,
           gpio_hal_pin_to_mask(out_pin2) | gpio_hal_pin_to_mask(out_pin3));
       } else if((counter & 7) == 7) {
         /* Toggle button interrupt */
         gpio_hal_pin_cfg_t interrupt;
 
-        interrupt = gpio_hal_arch_pin_cfg_get(btn_pin) &
+        interrupt = gpio_hal_arch_pin_cfg_get(btn_port, btn_pin) &
           GPIO_HAL_PIN_CFG_INT_ENABLE;
 
         if(interrupt == 0) {
           printf("Enabling button interrupt\n");
-          gpio_hal_arch_interrupt_enable(btn_pin);
+          gpio_hal_arch_interrupt_enable(btn_port, btn_pin);
         } else {
           printf("Disabling button interrupt\n");
-          gpio_hal_arch_interrupt_disable(btn_pin);
+          gpio_hal_arch_interrupt_disable(btn_port, btn_pin);
         }
       }
 
       /* Test read */
       printf("%u: Pins are 1-%u, 2=%u, 3=%u, mask=" PIN_MASK_FMT "\n",
              counter & 7,
-             gpio_hal_arch_read_pin(out_pin1),
-             gpio_hal_arch_read_pin(out_pin2),
-             gpio_hal_arch_read_pin(out_pin3),
-             gpio_hal_arch_read_pins(gpio_hal_pin_to_mask(out_pin1) |
+             gpio_hal_arch_read_pin(out_port1, out_pin1),
+             gpio_hal_arch_read_pin(out_port2_3, out_pin2),
+             gpio_hal_arch_read_pin(out_port2_3, out_pin3),
+             gpio_hal_arch_read_pins(out_port2_3,
                                      gpio_hal_pin_to_mask(out_pin2) |
                                      gpio_hal_pin_to_mask(out_pin3)));
 
diff --git a/os/dev/button-hal.c b/os/dev/button-hal.c
index 58cded79023b43c137b40957d468faa7ed2a3485..547407432a8ce9436bf6ef4cf14647fa47dc3a23 100644
--- a/os/dev/button-hal.c
+++ b/os/dev/button-hal.c
@@ -62,6 +62,12 @@ extern button_hal_button_t *button_hal_buttons[];
 /* Common handler for all handler events, and register it with the GPIO HAL */
 static gpio_hal_event_handler_t button_event_handler;
 /*---------------------------------------------------------------------------*/
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define BTN_PORT(b) (b)->port
+#else
+#define BTN_PORT(b) GPIO_HAL_NULL_PORT
+#endif
+/*---------------------------------------------------------------------------*/
 static void
 duration_exceeded_callback(void *btn)
 {
@@ -121,7 +127,11 @@ debounce_handler(void *btn)
 }
 /*---------------------------------------------------------------------------*/
 static void
-press_release_handler(gpio_hal_pin_mask_t pin_mask)
+press_release_handler(
+#if GPIO_HAL_PORT_PIN_NUMBERING
+                      gpio_hal_port_t port,
+#endif
+                      gpio_hal_pin_mask_t pin_mask)
 {
   pmask |= pin_mask;
   process_poll(&button_hal_process);
@@ -154,7 +164,7 @@ button_hal_get_by_index(uint8_t index)
 uint8_t
 button_hal_get_state(button_hal_button_t *button)
 {
-  uint8_t pin_state = gpio_hal_arch_read_pin(button->pin);
+  uint8_t pin_state = gpio_hal_arch_read_pin(BTN_PORT(button), button->pin);
 
   if((pin_state == 0 && button->negative_logic == true) ||
      (pin_state == 1 && button->negative_logic == false)) {
@@ -180,9 +190,9 @@ button_hal_init()
   for(button = button_hal_buttons; *button != NULL; button++) {
     cfg = GPIO_HAL_PIN_CFG_EDGE_BOTH | GPIO_HAL_PIN_CFG_INT_ENABLE |
       (*button)->pull;
-    gpio_hal_arch_pin_set_input((*button)->pin);
-    gpio_hal_arch_pin_cfg_set((*button)->pin, cfg);
-    gpio_hal_arch_interrupt_enable((*button)->pin);
+    gpio_hal_arch_pin_set_input(BTN_PORT(*button), (*button)->pin);
+    gpio_hal_arch_pin_cfg_set(BTN_PORT(*button), (*button)->pin, cfg);
+    gpio_hal_arch_interrupt_enable(BTN_PORT(*button), (*button)->pin);
     button_event_handler.pin_mask |= gpio_hal_pin_to_mask((*button)->pin);
   }
 
diff --git a/os/dev/button-hal.h b/os/dev/button-hal.h
index c1822ff8eb276a1b3c035511d22891dc3a52c343..8b6110ee217d90ce1fab6433bd37026c8b7d55b2 100644
--- a/os/dev/button-hal.h
+++ b/os/dev/button-hal.h
@@ -151,6 +151,11 @@ struct button_hal_button_s {
   /** True if the button uses negative logic (active: low) */
   const bool negative_logic;
 
+#if GPIO_HAL_PORT_PIN_NUMBERING
+  /** The gpio port connected to the button */
+  gpio_hal_port_t port;
+#endif
+
   /** The gpio pin connected to the button */
   const gpio_hal_pin_t pin;
 
@@ -172,23 +177,36 @@ struct button_hal_button_s {
 };
 /*---------------------------------------------------------------------------*/
 #if BUTTON_HAL_WITH_DESCRIPTION
+#if GPIO_HAL_PORT_PIN_NUMBERING
 /**
  * \brief Define a button to be used by the HAL
  * \param name The variable name for the button
  * \param descr A textual description
- * \param p The pin connected to the button
+ * \param po The port connected to the button
+ * \param pi The pin connected to the button
  * \param nl True if the button is connected using negative logic
  * \param u The button's pull configuration
  * \param id A unique numeric identifier
  */
-#define BUTTON_HAL_BUTTON(name, descr, p, u, id, nl) \
+#define BUTTON_HAL_BUTTON(name, descr, po, pi, u, id, nl) \
   static button_hal_button_t name = { \
     .description = descr, \
-    .pin = p, \
+    .port = po, \
+    .pin = pi, \
     .pull = u, \
     .unique_id = id, \
     .negative_logic = nl, \
   }
+#else /* GPIO_HAL_PORT_PIN_NUMBERING */
+#define BUTTON_HAL_BUTTON(name, descr, pi, u, id, nl) \
+  static button_hal_button_t name = { \
+    .description = descr, \
+    .pin = pi, \
+    .pull = u, \
+    .unique_id = id, \
+    .negative_logic = nl, \
+  }
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
 
 /**
  * \brief Retrieve the textual description of a button
@@ -198,17 +216,30 @@ struct button_hal_button_s {
  * BUTTON_HAL_WITH_DESCRIPTION is 0 then this macro will return ""
  */
 #define BUTTON_HAL_GET_DESCRIPTION(b) (b)->description
-#else
-#define BUTTON_HAL_BUTTON(name, descr, p, u, id, nl) \
+
+#else /* BUTTON_HAL_WITH_DESCRIPTION */
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define BUTTON_HAL_BUTTON(name, descr, po, pi, u, id, nl) \
+  static button_hal_button_t name = { \
+    .port = po, \
+    .pin = pi, \
+    .pull = u, \
+    .unique_id = id, \
+    .negative_logic = nl, \
+  }
+#else /* GPIO_HAL_PORT_PIN_NUMBERING */
+#define BUTTON_HAL_BUTTON(name, descr, pi, u, id, nl) \
   static button_hal_button_t name = { \
-    .pin = p, \
+    .pin = pi, \
     .pull = u, \
     .unique_id = id, \
     .negative_logic = nl, \
   }
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
 
 #define BUTTON_HAL_GET_DESCRIPTION(b) ""
-#endif
+#endif /* BUTTON_HAL_WITH_DESCRIPTION */
 /*---------------------------------------------------------------------------*/
 #define BUTTON_HAL_BUTTONS(...) \
   button_hal_button_t *button_hal_buttons[] = {__VA_ARGS__, NULL}; \
diff --git a/os/dev/gpio-hal.c b/os/dev/gpio-hal.c
index 949d829a7282122e37fcec328e272bac44b27878..880985502ad13ed3e6a1176a81f36c731d5be613 100644
--- a/os/dev/gpio-hal.c
+++ b/os/dev/gpio-hal.c
@@ -57,6 +57,24 @@ gpio_hal_register_handler(gpio_hal_event_handler_t *handler)
   list_add(handlers, handler);
 }
 /*---------------------------------------------------------------------------*/
+#if GPIO_HAL_PORT_PIN_NUMBERING
+/*---------------------------------------------------------------------------*/
+void
+gpio_hal_event_handler(gpio_hal_port_t port, gpio_hal_pin_mask_t pins)
+{
+  gpio_hal_event_handler_t *this;
+
+  for(this = list_head(handlers); this != NULL; this = this->next) {
+    if((port == this->port) && (pins & this->pin_mask)) {
+      if(this->handler != NULL) {
+        this->handler(port, pins & this->pin_mask);
+      }
+    }
+  }
+}
+/*---------------------------------------------------------------------------*/
+#else
+/*---------------------------------------------------------------------------*/
 void
 gpio_hal_event_handler(gpio_hal_pin_mask_t pins)
 {
@@ -71,6 +89,8 @@ gpio_hal_event_handler(gpio_hal_pin_mask_t pins)
   }
 }
 /*---------------------------------------------------------------------------*/
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+/*---------------------------------------------------------------------------*/
 void
 gpio_hal_init()
 {
@@ -81,20 +101,35 @@ gpio_hal_init()
 #if GPIO_HAL_ARCH_SW_TOGGLE
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_toggle_pin(gpio_hal_pin_t pin)
+gpio_hal_arch_port_toggle_pin(gpio_hal_port_t port, gpio_hal_pin_t pin)
+{
+  gpio_hal_arch_write_pin(port, pin, gpio_hal_arch_read_pin(port, pin) ^ 1);
+}
+/*---------------------------------------------------------------------------*/
+void
+gpio_hal_arch_port_toggle_pins(gpio_hal_port_t port, gpio_hal_pin_mask_t pins)
+{
+  gpio_hal_arch_write_pins(port, pins, ~gpio_hal_arch_read_pins(port, pins));
+}
+/*---------------------------------------------------------------------------*/
+void
+gpio_hal_arch_no_port_toggle_pin(gpio_hal_pin_t pin)
 {
   if(pin >= GPIO_HAL_PIN_COUNT) {
     LOG_ERR("Pin %u out of bounds\n", pin);
     return;
   }
 
-  gpio_hal_arch_write_pin(pin, gpio_hal_arch_read_pin(pin) ^ 1);
+  gpio_hal_arch_write_pin(GPIO_HAL_NULL_PORT, pin,
+                          gpio_hal_arch_read_pin(GPIO_HAL_NULL_PORT, pin) ^ 1);
 }
 /*---------------------------------------------------------------------------*/
 void
-gpio_hal_arch_toggle_pins(gpio_hal_pin_mask_t pins)
+gpio_hal_arch_no_port_toggle_pins(gpio_hal_pin_mask_t pins)
 {
-  gpio_hal_arch_write_pins(pins, ~gpio_hal_arch_read_pins(pins));
+  gpio_hal_arch_write_pins(GPIO_HAL_NULL_PORT, pins,
+                           ~gpio_hal_arch_read_pins(GPIO_HAL_NULL_PORT,
+                                                    pins));
 }
 /*---------------------------------------------------------------------------*/
 #endif /* GPIO_HAL_ARCH_SW_TOGGLE */
diff --git a/os/dev/gpio-hal.h b/os/dev/gpio-hal.h
index 5ad9f472bc2efea2625d11812edcda8129d1d143..cc7748cc5acc14a26c2637ee7e609690a7c8d123 100644
--- a/os/dev/gpio-hal.h
+++ b/os/dev/gpio-hal.h
@@ -55,6 +55,24 @@
 
 #include <stdint.h>
 /*---------------------------------------------------------------------------*/
+/**
+ * \brief Specifies whether the HAL should support a port/pin convention
+ *
+ * Some MCUs specify GPIOs as a port/pin combination, whereas some others
+ * only use a pin number. Our GPIO HAL supports both conventions in a portable
+ * fashion and this define is used to set the HAL in the desired of the two
+ * modes.
+ *
+ * The port developer should define GPIO_HAL_CONF_PORT_PIN_NUMBERING as a if
+ * the platform uses port/pin numbering, or to 0 if the platform only uses
+ * a simple number.
+ */
+#ifdef GPIO_HAL_CONF_PORT_PIN_NUMBERING
+#define GPIO_HAL_PORT_PIN_NUMBERING GPIO_HAL_CONF_PORT_PIN_NUMBERING
+#else
+#define GPIO_HAL_PORT_PIN_NUMBERING 1
+#endif
+/*---------------------------------------------------------------------------*/
 /**
  * \brief Specifies whether software-based pin toggle is required
  *
@@ -71,11 +89,26 @@
 #define GPIO_HAL_ARCH_SW_TOGGLE 1
 #endif
 /*---------------------------------------------------------------------------*/
+/**
+ * \brief Convenience macro to use this as the port argument of macros
+ *
+ * Use this as the port \e argument of macros when GPIO_HAL_PORT_PIN_NUMBERING
+ * is zero
+ */
+#define GPIO_HAL_NULL_PORT      0
+/*---------------------------------------------------------------------------*/
 /**
  * \brief GPIO pin number representation
  */
 typedef uint8_t gpio_hal_pin_t;
 
+/**
+ * \brief A data structure that represents ports.
+ *
+ * This is only relevant if GPIO_HAL_PORT_PIN_NUMBERING is non-zero
+ */
+typedef uint8_t gpio_hal_port_t;
+
 /**
  * \brief GPIO pin configuration
  *
@@ -84,22 +117,37 @@ typedef uint8_t gpio_hal_pin_t;
  */
 typedef uint32_t gpio_hal_pin_cfg_t;
 
+/**
+ * \brief Specifies the total number of pins on a device
+ *
+ * This macro has no effect if GPIO_HAL_PORT_PIN_NUMBERING is non-zero.
+ */
 #ifdef GPIO_HAL_CONF_PIN_COUNT
 #define GPIO_HAL_PIN_COUNT GPIO_HAL_CONF_PIN_COUNT
 #else
 #define GPIO_HAL_PIN_COUNT 32
 #endif
 
-#if GPIO_HAL_PIN_COUNT > 32
+#if GPIO_HAL_PIN_COUNT > 32 && !GPIO_HAL_PORT_PIN_NUMBERING
 typedef uint64_t gpio_hal_pin_mask_t;
 #else
 /**
  * \brief GPIO pin mask representation
+ *
+ * A mask that can be used to represent multiple pins using a single variable.
+ *
+ * When GPIO_HAL_PORT_PIN_NUMBERING is non-zero, such variables can only be
+ * used to represent pins within the same port.
  */
 typedef uint32_t gpio_hal_pin_mask_t;
 #endif
-
+/*---------------------------------------------------------------------------*/
+#if GPIO_HAL_PORT_PIN_NUMBERING
+typedef void (*gpio_hal_callback_t)(gpio_hal_port_t port,
+                                    gpio_hal_pin_mask_t pin_mask);
+#else
 typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask);
+#endif
 /*---------------------------------------------------------------------------*/
 #define GPIO_HAL_PIN_CFG_PULL_NONE        0x00
 #define GPIO_HAL_PIN_CFG_PULL_UP          0x01
@@ -125,10 +173,16 @@ typedef void (*gpio_hal_callback_t)(gpio_hal_pin_mask_t pin_mask);
  * A GPIO event handler is a function that gets called whenever a pin triggers
  * an event. The same handler can be registered to handle events for more than
  * one pin by setting the respective pin's position but in \e pin_mask.
+ *
+ * If GPIO_HAL_PORT_PIN_NUMBERING is non-zero, a separate handler is required
+ * per port.
  */
 typedef struct gpio_hal_event_handler_s {
   struct gpio_hal_event_handler_s *next;
   gpio_hal_callback_t handler;
+#if GPIO_HAL_PORT_PIN_NUMBERING
+  gpio_hal_port_t port;
+#endif
   gpio_hal_pin_mask_t pin_mask;
 } gpio_hal_event_handler_t;
 /*---------------------------------------------------------------------------*/
@@ -163,8 +217,10 @@ void gpio_hal_init(void);
  */
 void gpio_hal_register_handler(gpio_hal_event_handler_t *handler);
 
+#if GPIO_HAL_PORT_PIN_NUMBERING
 /**
  * \brief The platform-independent GPIO event handler
+ * \param port The GPIO port, if applicable
  * \param pins OR mask of pins that generated an event
  *
  * Whenever a GPIO input interrupt occurs (edge or level detection) and an ISR
@@ -177,12 +233,19 @@ void gpio_hal_register_handler(gpio_hal_event_handler_t *handler);
  * If a pin set in the mask has an event handler registered, this function
  * will call the registered handler.
  *
+ * If GPIO_HAL_PORT_PIN_NUMBERING is non-zero the function will also accept
+ * as its first argument the port associated to the pins that triggered the
+ * edge detection.
+ *
  * This function will not clear any CPU interrupt flags, this should be done
  * by the calling ISR.
  *
  * \sa gpio_hal_register_handler
  */
+void gpio_hal_event_handler(gpio_hal_port_t port, gpio_hal_pin_mask_t pins);
+#else
 void gpio_hal_event_handler(gpio_hal_pin_mask_t pins);
+#endif
 
 /**
  * \brief Convert a pin to a pin mask
@@ -193,29 +256,45 @@ void gpio_hal_event_handler(gpio_hal_pin_mask_t pins);
 /** @} */
 /*---------------------------------------------------------------------------*/
 /**
- * \name Functions to be provided by the platform
+ * \name GPIO pin manipulation functions to be provided by the platform code.
+ *
+ * All functions have two flavours:
+ * - gpio_hal_arch_port_foo are used when GPIO_HAL_PORT_PIN_NUMBERING is
+ *   non-zero and expect a gpio_hal_port_t as one of their arguments
+ * - gpio_hal_arch_no_port_foo are used when GPIO_HAL_PORT_PIN_NUMBERING is 0
+ *   and do _not_ expect a gpio_hal_port_t as one of their arguments
+ *
+ * Macros are provided that automatically expand to the desirable prototype
+ * depending on the value of GPIO_HAL_PORT_PIN_NUMBERING. In order to achieve
+ * code portability, all platform-independent code should use those macros to
+ * manipulate GPIOs instead of using the port_ / no_port_ functions directly.
+ * A convenience macro GPIO_HAL_NULL_PORT is provided to be used as the port
+ * argument of macros when GPIO_HAL_PORT_PIN_NUMBERING is zero.
  *
  * All the functions below must be provided by the platform's developer. The
  * HAL offers the developer a number of options of how to provide the required
  * functionality.
  *
  * - The developer can provide a symbol. For example, the developer can create
- *   a .c file and implement a function called gpio_hal_arch_set_pin()
+ *   a .c file and implement a function called gpio_hal_arch_set_port_pin().
+ *   In this scenario the developer only needs to provide a symbol for the
+ *   gpio_hal_arch_port_foo / gpio_hal_arch_no_port_foo that applies.
+ *
  * - The developer can provide a function-like macro that has the same name as
- *   the function declared here. In this scenario, the declaration here will
- *   be removed by the pre-processor. For example, the developer can do
- *   something like:
+ *   one of the manipulation macros declared here. In this scenario, the
+ *   declaration here will be removed by the pre-processor. For example, the
+ *   developer can do something like:
  *
  *   \code
- *   #define gpio_hal_arch_write_pin(p, v) platform_sdk_function(p, v)
+ *   #define gpio_hal_arch_write_pin(port, pin, v) sdk_function(port, pin, v)
  *   \endcode
  *
  * - The developer can provide a static inline implementation. For this to
  *   work, the developer can do something like:
  *
  *   \code
- *   #define gpio_hal_arch_set_pin(p) set_pin(p)
- *   static inline void set_pin(gpio_hal_pin_t pin) { ... }
+ *   #define gpio_hal_arch_set_pin(port, pin) set_pin(port, pin)
+ *   static inline void set_pin(gpio_hal_port_t port, gpio_hal_pin_t pin) { ... }
  *   \endcode
  *
  * In the latter two cases, the developer will likely provide implementations
@@ -226,7 +305,6 @@ void gpio_hal_event_handler(gpio_hal_pin_mask_t pins);
  * \code
  * #define GPIO_HAL_CONF_ARCH_HDR_PATH          "dev/gpio-hal-arch.h"
  * \endcode
- *
  * @{
  */
 /*---------------------------------------------------------------------------*/
@@ -248,6 +326,22 @@ void gpio_hal_arch_init(void);
 #endif
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_interrupt_enable
+/**
+ * \brief Enable interrupts for a gpio pin
+ * \param port The GPIO port
+ * \param pin The GPIO pin number
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_port_interrupt_enable(gpio_hal_port_t port,
+                                         gpio_hal_pin_t pin);
+
 /**
  * \brief Enable interrupts for a gpio pin
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
@@ -256,26 +350,65 @@ void gpio_hal_arch_init(void);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_interrupt_enable(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_no_port_interrupt_enable(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_interrupt_enable(port, pin) \
+  gpio_hal_arch_port_interrupt_enable(port, pin)
+#else
+#define gpio_hal_arch_interrupt_enable(port, pin) \
+  gpio_hal_arch_no_port_interrupt_enable(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_interrupt_enable */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_interrupt_disable
 /**
  * \brief Disable interrupts for a gpio pin
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  *
  * It is the platform developer's responsibility to provide an implementation.
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_port_interrupt_disable(gpio_hal_port_t port,
+                                          gpio_hal_pin_t pin);
+
+/**
+ * \brief Disable interrupts for a gpio pin
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_interrupt_disable(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_interrupt_disable(port, pin) \
+  gpio_hal_arch_port_interrupt_disable(port, pin)
+#else
+#define gpio_hal_arch_interrupt_disable(port, pin) \
+  gpio_hal_arch_no_port_interrupt_disable(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_interrupt_disable */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_pin_cfg_set
 /**
  * \brief Configure a gpio pin
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  * \param cfg The configuration
  *
@@ -288,13 +421,48 @@ void gpio_hal_arch_interrupt_disable(gpio_hal_pin_t pin);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg);
-#endif
+void gpio_hal_arch_port_pin_cfg_set(gpio_hal_port_t port,
+                                    gpio_hal_pin_t pin,
+                                    gpio_hal_pin_cfg_t cfg);
+
+/**
+ * \brief Configure a gpio pin
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ * \param cfg The configuration
+ *
+ * \e cfg is an OR mask of GPIO_HAL_PIN_CFG_xyz
+ *
+ * The implementation of this function also has to make sure that \e pin is
+ * configured as software-controlled GPIO.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_pin_cfg_set(gpio_hal_pin_t pin,
+                                       gpio_hal_pin_cfg_t cfg);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_pin_cfg_set(port, pin, cfg) \
+  gpio_hal_arch_port_pin_cfg_set(port, pin, cfg)
+#else
+#define gpio_hal_arch_pin_cfg_set(port, pin, cfg) \
+  gpio_hal_arch_no_port_pin_cfg_set(pin, cfg)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_pin_cfg_set */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_pin_cfg_get
 /**
  * \brief Read the configuration of a GPIO pin
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  * \return An OR mask of GPIO_HAL_PIN_CFG_xyz
  *
@@ -302,13 +470,41 @@ void gpio_hal_arch_pin_cfg_set(gpio_hal_pin_t pin, gpio_hal_pin_cfg_t cfg);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-gpio_hal_pin_cfg_t gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin);
-#endif
+gpio_hal_pin_cfg_t gpio_hal_arch_port_pin_cfg_get(gpio_hal_port_t port,
+                                                  gpio_hal_pin_t pin);
+
+/**
+ * \brief Read the configuration of a GPIO pin
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ * \return An OR mask of GPIO_HAL_PIN_CFG_xyz
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+gpio_hal_pin_cfg_t gpio_hal_arch_no_port_pin_cfg_get(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_pin_cfg_get(port, pin) \
+  gpio_hal_arch_port_pin_cfg_get(port, pin)
+#else
+#define gpio_hal_arch_pin_cfg_get(port, pin) \
+  gpio_hal_arch_no_port_pin_cfg_get(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_pin_cfg_get */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_pin_set_input
 /**
  * \brief Configure a pin as GPIO input
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  *
  * The implementation of this function also has to make sure that \e pin is
@@ -318,13 +514,43 @@ gpio_hal_pin_cfg_t gpio_hal_arch_pin_cfg_get(gpio_hal_pin_t pin);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_pin_set_input(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_port_pin_set_input(gpio_hal_port_t port,
+                                      gpio_hal_pin_t pin);
+
+/**
+ * \brief Configure a pin as GPIO input
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ *
+ * The implementation of this function also has to make sure that \e pin is
+ * configured as software-controlled GPIO.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_pin_set_input(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_pin_set_input(port, pin) \
+  gpio_hal_arch_port_pin_set_input(port, pin)
+#else
+#define gpio_hal_arch_pin_set_input(port, pin) \
+  gpio_hal_arch_no_port_pin_set_input(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_pin_set_input */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_pin_set_output
 /**
  * \brief Configure a pin as GPIO output
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  *
  * The implementation of this function also has to make sure that \e pin is
@@ -334,39 +560,121 @@ void gpio_hal_arch_pin_set_input(gpio_hal_pin_t pin);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_pin_set_output(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_port_pin_set_output(gpio_hal_port_t port,
+                                       gpio_hal_pin_t pin);
+
+/**
+ * \brief Configure a pin as GPIO output
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ *
+ * The implementation of this function also has to make sure that \e pin is
+ * configured as software-controlled GPIO.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_pin_set_output(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_pin_set_output(port, pin) \
+  gpio_hal_arch_port_pin_set_output(port, pin)
+#else
+#define gpio_hal_arch_pin_set_output(port, pin) \
+  gpio_hal_arch_no_port_pin_set_output(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_pin_set_output */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_set_pin
 /**
  * \brief Set a GPIO pin to logical high
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  *
  * It is the platform developer's responsibility to provide an implementation.
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_set_pin(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_port_set_pin(gpio_hal_port_t port, gpio_hal_pin_t pin);
+
+/**
+ * \brief Set a GPIO pin to logical high
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_set_pin(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_set_pin(port, pin) \
+  gpio_hal_arch_port_set_pin(port, pin)
+#else
+#define gpio_hal_arch_set_pin(port, pin) \
+  gpio_hal_arch_no_port_set_pin(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_set_pin */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_clear_pin
 /**
  * \brief Clear a GPIO pin (logical low)
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  *
  * It is the platform developer's responsibility to provide an implementation.
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_clear_pin(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_port_clear_pin(gpio_hal_port_t port, gpio_hal_pin_t pin);
+
+/**
+ * \brief Clear a GPIO pin (logical low)
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_clear_pin(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_clear_pin(port, pin) \
+  gpio_hal_arch_port_clear_pin(port, pin)
+#else
+#define gpio_hal_arch_clear_pin(port, pin) \
+  gpio_hal_arch_no_port_clear_pin(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_clear_pin */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_toggle_pin
 /**
  * \brief Toggle a GPIO pin
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  *
  * Some MCUs allow GPIO pin toggling directly via register access. In this
@@ -378,13 +686,44 @@ void gpio_hal_arch_clear_pin(gpio_hal_pin_t pin);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_toggle_pin(gpio_hal_pin_t pin);
-#endif
+void gpio_hal_arch_port_toggle_pin(gpio_hal_port_t port, gpio_hal_pin_t pin);
+
+/**
+ * \brief Toggle a GPIO pin
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ *
+ * Some MCUs allow GPIO pin toggling directly via register access. In this
+ * case, it is a good idea to provide an implementation of this function.
+ * However, a default, software-based implementation is also provided by the
+ * HAL and can be used if the MCU does not have a pin toggle register. To use
+ * the HAL function, define GPIO_HAL_ARCH_SW_TOGGLE as 1. To provide your own
+ * implementation, define GPIO_HAL_ARCH_SW_TOGGLE as 0.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_toggle_pin(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_toggle_pin(port, pin) \
+  gpio_hal_arch_port_toggle_pin(port, pin)
+#else
+#define gpio_hal_arch_toggle_pin(port, pin) \
+  gpio_hal_arch_no_port_toggle_pin(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_toggle_pin */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_read_pin
 /**
  * \brief Read a GPIO pin
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  * \retval 0 The pin is logical low
  * \retval 1 The pin is logical high
@@ -393,13 +732,41 @@ void gpio_hal_arch_toggle_pin(gpio_hal_pin_t pin);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-uint8_t gpio_hal_arch_read_pin(gpio_hal_pin_t pin);
-#endif
+uint8_t gpio_hal_arch_port_read_pin(gpio_hal_port_t port, gpio_hal_pin_t pin);
+
+/**
+ * \brief Read a GPIO pin
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ * \retval 0 The pin is logical low
+ * \retval 1 The pin is logical high
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+uint8_t gpio_hal_arch_no_port_read_pin(gpio_hal_pin_t pin);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_read_pin(port, pin) \
+  gpio_hal_arch_port_read_pin(port, pin)
+#else
+#define gpio_hal_arch_read_pin(port, pin) \
+  gpio_hal_arch_no_port_read_pin(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_read_pin */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_write_pin
 /**
  * \brief Write a GPIO pin
+ * \param port The GPIO port
  * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
  * \param value 0: Logical low; 1: Logical high
  *
@@ -407,13 +774,42 @@ uint8_t gpio_hal_arch_read_pin(gpio_hal_pin_t pin);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value);
-#endif
+void gpio_hal_arch_port_write_pin(gpio_hal_port_t port,
+                                  gpio_hal_pin_t pin,
+                                  uint8_t value);
+
+/**
+ * \brief Write a GPIO pin
+ * \param pin The GPIO pin number (0...GPIO_HAL_PIN_COUNT - 1)
+ * \param value 0: Logical low; 1: Logical high
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_write_pin(gpio_hal_pin_t pin, uint8_t value);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_write_pin(port, pin, value) \
+  gpio_hal_arch_port_write_pin(port, pin, value)
+#else
+#define gpio_hal_arch_write_pin(port, pin, value) \
+  gpio_hal_arch_no_port_write_pin(pin, value)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_write_pin */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_set_pins
 /**
  * \brief Set multiple pins to logical high
+ * \param port The GPIO port
  * \param pins An ORd pin mask of the pins to set
  *
  * A pin will be set to logical high if its position in \e pins is set. For
@@ -423,13 +819,43 @@ void gpio_hal_arch_write_pin(gpio_hal_pin_t pin, uint8_t value);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins);
-#endif
+void gpio_hal_arch_port_set_pins(gpio_hal_port_t port,
+                                 gpio_hal_pin_mask_t pins);
+
+/**
+ * \brief Set multiple pins to logical high
+ * \param pins An ORd pin mask of the pins to set
+ *
+ * A pin will be set to logical high if its position in \e pins is set. For
+ * example you can set pins 0 and 3 by passing 0x09.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_set_pins(gpio_hal_pin_mask_t pins);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_set_pins(port, pin) \
+  gpio_hal_arch_port_set_pins(port, pin)
+#else
+#define gpio_hal_arch_set_pins(port, pin) \
+  gpio_hal_arch_no_port_set_pins(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_set_pins */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_clear_pins
 /**
  * \brief Clear multiple pins to logical low
+ * \param port The GPIO port
  * \param pins An ORd pin mask of the pins to clear
  *
  * A pin will be set to logical low if its position in \e pins is set. For
@@ -439,13 +865,43 @@ void gpio_hal_arch_set_pins(gpio_hal_pin_mask_t pins);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins);
-#endif
+void gpio_hal_arch_port_clear_pins(gpio_hal_port_t port,
+                                   gpio_hal_pin_mask_t pins);
+
+/**
+ * \brief Clear multiple pins to logical low
+ * \param pins An ORd pin mask of the pins to clear
+ *
+ * A pin will be set to logical low if its position in \e pins is set. For
+ * example you can clear pins 0 and 3 by passing 0x09.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_clear_pins(gpio_hal_pin_mask_t pins);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_clear_pins(port, pin) \
+  gpio_hal_arch_port_clear_pins(port, pin)
+#else
+#define gpio_hal_arch_clear_pins(port, pin) \
+  gpio_hal_arch_no_port_clear_pins(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_clear_pins */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_toggle_pins
 /**
  * \brief Toggle multiple pins
+ * \param port The GPIO port
  * \param pins An ORd pin mask of the pins to toggle
  *
  * A pin will be toggled if its position in \e pins is set. For example you
@@ -460,13 +916,48 @@ void gpio_hal_arch_clear_pins(gpio_hal_pin_mask_t pins);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_toggle_pins(gpio_hal_pin_mask_t pins);
-#endif
+void gpio_hal_arch_port_toggle_pins(gpio_hal_port_t port,
+                                    gpio_hal_pin_mask_t pins);
+
+/**
+ * \brief Toggle multiple pins
+ * \param pins An ORd pin mask of the pins to toggle
+ *
+ * A pin will be toggled if its position in \e pins is set. For example you
+ * can toggle pins 0 and 3 by passing 0x09.
+ *
+ * Some MCUs allow GPIO pin toggling directly via register access. In this
+ * case, it is a good idea to provide an implementation of this function.
+ * However, a default, software-based implementation is also provided by the
+ * HAL and can be used if the MCU does not have a pin toggle register. To use
+ * the HAL function, define GPIO_HAL_ARCH_SW_TOGGLE as 1. To provide your own
+ * implementation, define GPIO_HAL_ARCH_SW_TOGGLE as 0.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_toggle_pins(gpio_hal_pin_mask_t pins);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_toggle_pins(port, pin) \
+  gpio_hal_arch_port_toggle_pins(port, pin)
+#else
+#define gpio_hal_arch_toggle_pins(port, pin) \
+  gpio_hal_arch_no_port_toggle_pins(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_toggle_pins */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_read_pins
 /**
  * \brief Read multiple pins
+ * \param port The GPIO port
  * \param pins An ORd pin mask of the pins to read
  * \retval An ORd mask of the pins that are high
  *
@@ -479,13 +970,46 @@ void gpio_hal_arch_toggle_pins(gpio_hal_pin_mask_t pins);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-gpio_hal_pin_mask_t gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins);
-#endif
+gpio_hal_pin_mask_t gpio_hal_arch_port_read_pins(gpio_hal_port_t port,
+                                                 gpio_hal_pin_mask_t pins);
+
+/**
+ * \brief Read multiple pins
+ * \param pins An ORd pin mask of the pins to read
+ * \retval An ORd mask of the pins that are high
+ *
+ * If the position of the pin in \e pins is set and the pin is logical high
+ * then the position of the pin in the return value will be set. For example,
+ * if you pass 0x09 as the value of \e pins and the return value is 0x08 then
+ * pin 3 is logical high and pin 0 is logical low.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+gpio_hal_pin_mask_t gpio_hal_arch_no_port_read_pins(gpio_hal_pin_mask_t pins);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_read_pins(port, pin) \
+  gpio_hal_arch_port_read_pins(port, pin)
+#else
+#define gpio_hal_arch_read_pins(port, pin) \
+  gpio_hal_arch_no_port_read_pins(pin)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_read_pins */
 /*---------------------------------------------------------------------------*/
 #ifndef gpio_hal_arch_write_pins
 /**
  * \brief Write multiple pins
+ * \param port The GPIO port
  * \param pins An ORd pin mask of the pins to write
  * \param value An ORd mask of the value to write
  *
@@ -502,10 +1026,47 @@ gpio_hal_pin_mask_t gpio_hal_arch_read_pins(gpio_hal_pin_mask_t pins);
  *
  * The implementation can be provided as a global symbol, an inline function
  * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
  */
-void gpio_hal_arch_write_pins(gpio_hal_pin_mask_t pins,
-                              gpio_hal_pin_mask_t value);
-#endif
+void gpio_hal_arch_port_write_pins(gpio_hal_port_t port,
+                                   gpio_hal_pin_mask_t pins,
+                                   gpio_hal_pin_mask_t value);
+
+/**
+ * \brief Write multiple pins
+ * \param pins An ORd pin mask of the pins to write
+ * \param value An ORd mask of the value to write
+ *
+ * The function will modify GPIO pins that have their position in the mask set.
+ * pins, the function will write the value specified in the corresponding
+ * position in \e value.
+
+ * For example, you can set pin 3 and clear pin 0 by a single call to this
+ * function. To achieve this, \e pins must be 0x09 and \e value 0x08.
+ *
+ * It is the platform developer's responsibility to provide an implementation.
+ *
+ * There is no guarantee that this function will result in an atomic operation.
+ *
+ * The implementation can be provided as a global symbol, an inline function
+ * or a function-like macro, as described above.
+ *
+ * \note Code should not call this function directly. Use GPIO manipulation
+ * macros instead.
+ */
+void gpio_hal_arch_no_port_write_pins(gpio_hal_pin_mask_t pins,
+                                      gpio_hal_pin_mask_t value);
+
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define gpio_hal_arch_write_pins(port, pin, value) \
+  gpio_hal_arch_port_write_pins(port, pin, value)
+#else
+#define gpio_hal_arch_write_pins(port, pin, value) \
+  gpio_hal_arch_no_port_write_pins(pin, value)
+#endif /* GPIO_HAL_PORT_PIN_NUMBERING */
+#endif /* gpio_hal_arch_write_pins */
 /** @} */
 /*---------------------------------------------------------------------------*/
 #endif /* GPIO_HAL_H_ */
diff --git a/os/dev/leds.c b/os/dev/leds.c
index f2ce82c29229b9eb659d645c5a5d3dfac46d532e..8c7607b030f11c62f65142e022feb91123f1e114 100644
--- a/os/dev/leds.c
+++ b/os/dev/leds.c
@@ -103,13 +103,20 @@ extern const leds_t leds_arch_leds[];
 static const leds_t *leds_arch_leds = NULL;
 #endif
 /*---------------------------------------------------------------------------*/
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define LED_PORT(led) (led).port
+#else
+#define LED_PORT(led) GPIO_HAL_NULL_PORT
+#endif
+/*---------------------------------------------------------------------------*/
 void
 leds_init()
 {
   leds_num_t led;
 
   for(led = 0; led < LEDS_COUNT; led++) {
-    gpio_hal_arch_pin_set_output(leds_arch_leds[led].pin);
+    gpio_hal_arch_pin_set_output(LED_PORT(leds_arch_leds[led]),
+                                 leds_arch_leds[led].pin);
   }
   leds_off(LEDS_ALL);
 }
@@ -122,9 +129,11 @@ leds_single_on(leds_num_t led)
   }
 
   if(leds_arch_leds[led].negative_logic) {
-    gpio_hal_arch_clear_pin(leds_arch_leds[led].pin);
+    gpio_hal_arch_clear_pin(LED_PORT(leds_arch_leds[led]),
+                                     leds_arch_leds[led].pin);
   } else {
-    gpio_hal_arch_set_pin(leds_arch_leds[led].pin);
+    gpio_hal_arch_set_pin(LED_PORT(leds_arch_leds[led]),
+                          leds_arch_leds[led].pin);
   }
 }
 /*---------------------------------------------------------------------------*/
@@ -136,9 +145,11 @@ leds_single_off(leds_num_t led)
   }
 
   if(leds_arch_leds[led].negative_logic) {
-    gpio_hal_arch_set_pin(leds_arch_leds[led].pin);
+    gpio_hal_arch_set_pin(LED_PORT(leds_arch_leds[led]),
+                          leds_arch_leds[led].pin);
   } else {
-    gpio_hal_arch_clear_pin(leds_arch_leds[led].pin);
+    gpio_hal_arch_clear_pin(LED_PORT(leds_arch_leds[led]),
+                            leds_arch_leds[led].pin);
   }
 }
 /*---------------------------------------------------------------------------*/
@@ -149,7 +160,8 @@ leds_single_toggle(leds_num_t led)
     return;
   }
 
-  gpio_hal_arch_toggle_pin(leds_arch_leds[led].pin);
+  gpio_hal_arch_toggle_pin(LED_PORT(leds_arch_leds[led]),
+                           leds_arch_leds[led].pin);
 }
 /*---------------------------------------------------------------------------*/
 void
@@ -160,9 +172,11 @@ leds_on(leds_mask_t leds)
   for(led = 0; led < LEDS_COUNT; led++) {
     if((1 << led) & leds) {
       if(leds_arch_leds[led].negative_logic) {
-        gpio_hal_arch_clear_pin(leds_arch_leds[led].pin);
+        gpio_hal_arch_clear_pin(LED_PORT(leds_arch_leds[led]),
+                                leds_arch_leds[led].pin);
       } else {
-        gpio_hal_arch_set_pin(leds_arch_leds[led].pin);
+        gpio_hal_arch_set_pin(LED_PORT(leds_arch_leds[led]),
+                              leds_arch_leds[led].pin);
       }
     }
   }
@@ -176,9 +190,11 @@ leds_off(leds_mask_t leds)
   for(led = 0; led < LEDS_COUNT; led++) {
     if((1 << led) & leds) {
       if(leds_arch_leds[led].negative_logic) {
-        gpio_hal_arch_set_pin(leds_arch_leds[led].pin);
+        gpio_hal_arch_set_pin(LED_PORT(leds_arch_leds[led]),
+                              leds_arch_leds[led].pin);
       } else {
-        gpio_hal_arch_clear_pin(leds_arch_leds[led].pin);
+        gpio_hal_arch_clear_pin(LED_PORT(leds_arch_leds[led]),
+                                leds_arch_leds[led].pin);
       }
     }
   }
@@ -191,7 +207,8 @@ leds_toggle(leds_mask_t leds)
 
   for(led = 0; led < LEDS_COUNT; led++) {
     if((1 << led) & leds) {
-      gpio_hal_arch_toggle_pin(leds_arch_leds[led].pin);
+      gpio_hal_arch_toggle_pin(LED_PORT(leds_arch_leds[led]),
+                               leds_arch_leds[led].pin);
     }
   }
 }
@@ -211,7 +228,8 @@ leds_get()
   uint8_t pin_state;
 
   for(led = 0; led < LEDS_COUNT; led++) {
-    pin_state = gpio_hal_arch_read_pin(leds_arch_leds[led].pin);
+    pin_state = gpio_hal_arch_read_pin(LED_PORT(leds_arch_leds[led]),
+                                       leds_arch_leds[led].pin);
 
     if((leds_arch_leds[led].negative_logic == false && pin_state == 1) ||
        (leds_arch_leds[led].negative_logic == true && pin_state == 0)) {
diff --git a/os/dev/leds.h b/os/dev/leds.h
index 654ed250eee09af5e8873954a5cb52b3c901556e..21912a8ec8fd4627d90841fac706aed1e2bde712 100644
--- a/os/dev/leds.h
+++ b/os/dev/leds.h
@@ -208,10 +208,19 @@ void leds_arch_set(leds_mask_t leds);
  * \e pin corresponds to the GPIO pin a LED is driven by, using GPIO HAL pin
  * representation.
  *
+ * \e port corresponds to the GPIO port that the pin is connected to. This
+ * only makes sense if GPIO_HAL_CONF_PORT_PIN_NUMBERING is non-zero.
+ *
  * \e negative_logic should be set to false if the LED is active low.
+ *
+ * \note Do not access the \e port member of this struct direct, use the
+ * LED_PORT() macro instead.
  */
 typedef struct leds_s {
   gpio_hal_pin_t pin;
+#if GPIO_HAL_PORT_PIN_NUMBERING
+  gpio_hal_port_t port;
+#endif
   bool negative_logic;
 } leds_t;
 /*---------------------------------------------------------------------------*/
diff --git a/os/dev/spi.c b/os/dev/spi.c
index 091cf8e51c0afe876248f9e7c99399b4f22c7bc8..af2e0cefd865080275a0994a76c134a34b4e4cee 100644
--- a/os/dev/spi.c
+++ b/os/dev/spi.c
@@ -71,7 +71,7 @@ spi_select(const spi_device_t *dev)
     return SPI_DEV_STATUS_BUS_NOT_OWNED;
   }
 
-  gpio_hal_arch_clear_pin(dev->pin_spi_cs);
+  gpio_hal_arch_clear_pin(SPI_DEVICE_PORT(cs, dev), dev->pin_spi_cs);
 
   return SPI_DEV_STATUS_OK;
 }
@@ -79,7 +79,7 @@ spi_select(const spi_device_t *dev)
 spi_status_t
 spi_deselect(const spi_device_t *dev)
 {
-  gpio_hal_arch_set_pin(dev->pin_spi_cs);
+  gpio_hal_arch_set_pin(SPI_DEVICE_PORT(cs, dev), dev->pin_spi_cs);
 
   return SPI_DEV_STATUS_OK;
 }
diff --git a/os/dev/spi.h b/os/dev/spi.h
index 9dda05b8efdd44fb382a2035d098fb0f3c54be9d..8eb2709e4484c1a77b1b9556872dd6a0d5ca4e16 100644
--- a/os/dev/spi.h
+++ b/os/dev/spi.h
@@ -92,10 +92,18 @@ typedef enum {
  *
  * This is a structure to an architecture-independent SPI configuration.
  *
+ * \note Do not access the port_spi_foo members directly. Access them by using
+ * the SPI_DEVICE_PORT() macro instead
  * @{
  */
 
 typedef struct spi_device {
+#if GPIO_HAL_PORT_PIN_NUMBERING
+  gpio_hal_port_t port_spi_sck;       /* SPI SCK port */
+  gpio_hal_port_t port_spi_miso;      /* SPI MISO port */
+  gpio_hal_port_t port_spi_mosi;      /* SPI MOSI port */
+  gpio_hal_port_t port_spi_cs;        /* SPI Chip Select port */
+#endif
   gpio_hal_pin_t pin_spi_sck;       /* SPI SCK pin */
   gpio_hal_pin_t pin_spi_miso;      /* SPI MISO  pin */
   gpio_hal_pin_t pin_spi_mosi;      /* SPI MOSI pin */
@@ -107,6 +115,22 @@ typedef struct spi_device {
 } spi_device_t;
 /** @} */
 /*---------------------------------------------------------------------------*/
+/**
+ * \brief Retrieve the SPI device's port number if applicable
+ * \param member Retrieve struct member port_spi_member (e.g. port_spi_miso)
+ * \param device A pointer the a variable of type spi_device_t
+ *
+ * The same macro is used for all four port_spi_foo members of the struct. So
+ * to retrieve port_spi_cs, use SPI_DEVICE_PORT(cs, device). Replace cs with
+ * mosi to retrieve port_spi_mosi.
+ *
+ */
+#if GPIO_HAL_PORT_PIN_NUMBERING
+#define SPI_DEVICE_PORT(member, device) (device)->port_spi_##member
+#else
+#define SPI_DEVICE_PORT(member, device) GPIO_HAL_NULL_PORT
+#endif
+/*---------------------------------------------------------------------------*/
 /* These are architecture-independent functions to be used by SPI devices.   */
 /*---------------------------------------------------------------------------*/
 /**