You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/01/04 12:46:33 UTC

[incubator-nuttx] branch master updated: Improvements for NRF52 (#37)

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new 9e091d2  Improvements for NRF52 (#37)
9e091d2 is described below

commit 9e091d2027a42fbec14555ae98c76e7579cd8b8e
Author: Mateusz Szafoni <ra...@railab.me>
AuthorDate: Sat Jan 4 09:44:00 2020 -0300

    Improvements for NRF52 (#37)
    
    Author: Alan Carvalho de Assis <ac...@gmail.com>
            Fix long line comments in the header files
    
    Author: Mateusz Szafoni <ra...@users.noreply.github.com>
    
        * arch/arm/src/nrf52: add GPIOTE and SAADC registers definitions
    
        * arch/arm/src/nrf52: update some registers definitions
    
        * arch/arm/src/nrf52: add basic I2C support
    
        * arch/arm/src/nrf52: add function to unconfigure GPIO
    
        * arch/arm/src/nrf52/nrf52_lowputc: add missing FAR
---
 arch/arm/src/nrf52/hardware/nrf52_gpio.h           |   2 +
 arch/arm/src/nrf52/hardware/nrf52_gpiote.h         |  99 ++++
 arch/arm/src/nrf52/hardware/nrf52_saadc.h          | 221 +++++++
 arch/arm/src/nrf52/hardware/nrf52_spi.h            |  26 +-
 arch/arm/src/nrf52/hardware/nrf52_twi.h            |  22 +-
 arch/arm/src/nrf52/hardware/nrf52_uarte.h          |  22 +-
 arch/arm/src/nrf52/nrf52_gpio.c                    |  30 +
 arch/arm/src/nrf52/nrf52_gpio.h                    |  10 +
 arch/arm/src/nrf52/nrf52_i2c.c                     | 644 +++++++++++++++++++++
 .../arm/src/nrf52/{nrf52_lowputc.h => nrf52_i2c.h} | 107 ++--
 arch/arm/src/nrf52/nrf52_lowputc.c                 |  19 +-
 arch/arm/src/nrf52/nrf52_lowputc.h                 |   6 +-
 arch/arm/src/nrf52/nrf52_serial.c                  |   4 +-
 13 files changed, 1109 insertions(+), 103 deletions(-)

diff --git a/arch/arm/src/nrf52/hardware/nrf52_gpio.h b/arch/arm/src/nrf52/hardware/nrf52_gpio.h
index 3fb29bc..118e2f9 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_gpio.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_gpio.h
@@ -89,6 +89,8 @@
 
 /* Register bit definitions *********************************************************/
 
+#define NRF52_GPIO_CNF_DIR              (1 << 0) /* Bit 0: Pin direction */
+#define NRF52_GPIO_CNF_INPUT            (1 << 1) /* Bit 1: Input buffer disconnect */
 #define NRF52_GPIO_CNF_PULL_SHIFT       (2)
 #define NRF52_GPIO_CNF_PULL_MASK        (0x3 << NRF52_GPIO_CNF_PULL_SHIFT)
 #  define NRF52_GPIO_CNF_PULL_DISABLED  (0 << NRF52_GPIO_CNF_PULL_SHIFT)
diff --git a/arch/arm/src/nrf52/hardware/nrf52_gpiote.h b/arch/arm/src/nrf52/hardware/nrf52_gpiote.h
new file mode 100644
index 0000000..fe7528d
--- /dev/null
+++ b/arch/arm/src/nrf52/hardware/nrf52_gpiote.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/hardware/nrf52_gpiote.h
+ *
+ *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ *   Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_GPIOTE_H
+#define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_GPIOTE_H
+
+/****************************************************************************
+ * Included Files
+ ***************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf52_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ***************************************************************************/
+
+/* Register offsets for GPIOTE *********************************************/
+
+#define NRF52_GPIOTE_TASKS_OUT_OFFSET(x)    (0x0000 + (0x04 * x)) /* TASKS_OUT[x] */
+#define NRF52_GPIOTE_TASKS_SET_OFFSET(x)    (0x0030 + (0x04 * x)) /* TASKS_SET[x] */
+#define NRF52_GPIOTE_TASKS_CLR_OFFSET(x)    (0x0060 + (0x04 * x)) /* TASKS_CLR[x] */
+#define NRF52_GPIOTE_EVENTS_IN_OFFSET(x)    (0x0100 + (0x04 * x)) /* EVENTS_IN[x] */
+#define NRF52_GPIOTE_EVENTS_PORT_OFFSET     0x017c                /* EVENTS_PORT */
+#define NRF52_GPIOTE_INTENSET_OFFSET        0x0304                /* INTENSET */
+#define NRF52_GPIOTE_INTENCLR_OFFSET        0x0308                /* INTENCLR */
+#define NRF52_GPIOTE_CONFIG_OFFSET(x)       (0x0510 + (0x04 * x)) /* CONFIG[x] */
+
+/* Register addresses for GPIOTE *******************************************/
+
+#define NRF52_GPIOTE_TASKS_OUT(x)           (NRF52_GPIOTE_BASE + NRF52_GPIOTE_TASKS_OUT_OFFSET(x))
+#define NRF52_GPIOTE_TASKS_SET(x)           (NRF52_GPIOTE_BASE + NRF52_GPIOTE_TASKS_SET_OFFSET(x))
+#define NRF52_GPIOTE_TASKS_CLR(x)           (NRF52_GPIOTE_BASE + NRF52_GPIOTE_TASKS_CLR_OFFSET(x))
+#define NRF52_GPIOTE_EVENTS_IN(x)           (NRF52_GPIOTE_BASE + NRF52_GPIOTE_EVENTS_IN_OFFSET(x))
+#define NRF52_GPIOTE_EVENTS_PORT            (NRF52_GPIOTE_BASE + NRF52_GPIOTE_EVENTS_PORT_OFFSET)
+#define NRF52_GPIOTE_INTENSET               (NRF52_GPIOTE_BASE + NRF52_GPIOTE_INTENSET_OFFSET)
+#define NRF52_GPIOTE_INTENCLR               (NRF52_GPIOTE_BASE + NRF52_GPIOTE_INTENCLR_OFFSET)
+#define NRF52_GPIOTE_CONFIG(x)              (NRF52_GPIOTE_BASE + NRF52_GPIOTE_CONFIG_OFFSET(x))
+
+/* Register offsets for GPIOTE *********************************************/
+
+/* INTENSET/INTENCLR Register */
+
+#define GPIOTE_INT_IN_SHIFT      0    /* Bits 0-7: Enable interrupt for event IN[i] */
+#define GPIOTE_INT_IN_MASK       (0xff << GPIOTE_INT_IN_SHIFT)
+#  define GPIOTE_INT_IN(i)       ((1 << (i + GPIOTE_INT_IN_SHIFT)) & GPIOTE_INT_IN_MASK)
+#define GPIOTE_INT_PORT          31   /* Bit 31: Enable interrupt for event PORT */
+
+/* CONFIG Register */
+
+#define GPIOTE_CONFIG_MODE_SHIFT 0    /* Bits 0-1: Mode */
+#define GPIOTE_CONFIG_MODE_MASK  (0x3 << GPIOTE_CONFIG_MODE_SHIFT)
+#  define GPIOTE_CONFIG_MODE_DIS (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 0: Disabled */
+#  define GPIOTE_CONFIG_MODE_EV  (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 1: Event */
+#  define GPIOTE_CONFIG_MODE_TS  (0x0 << GPIOTE_CONFIG_MODE_SHIFT) /* 2: Task */
+#define GPIOTE_CONFIG_PSEL_SHIFT (8)  /* Bits 8-12: GPIO number */
+#define GPIOTE_CONFIG_PSEL_MASK  (0x1f << GPIOTE_CONFIG_PSEL_SHIFT)
+#define GPIOTE_CONFIG_PORT_SHIFT (13) /* Bit 13: GPIO port */
+#define GPIOTE_CONFIG_POL_SHIFT  (16) /* Bits 16-17: Polarity */
+#define GPIOTE_CONFIG_POL_MASK   (0x3 << GPIOTE_CONFIG_POL_SHIFT)
+#  define GPIOTE_CONFIG_POL_NONE (0x0 << GPIOTE_CONFIG_POL_SHIFT) /* 0: None */
+#  define GPIOTE_CONFIG_POL_LTH  (0x1 << GPIOTE_CONFIG_POL_SHIFT) /* 1: LoToHi */
+#  define GPIOTE_CONFIG_POL_HTL  (0x2 << GPIOTE_CONFIG_POL_SHIFT) /* 2: HiToLo */
+#  define GPIOTE_CONFIG_POL_TG   (0x3 << GPIOTE_CONFIG_POL_SHIFT) /* 3: Toggle */
+#define GPIOTE_CONFIG_OUTINIT    (20) /* Bit 20: Initial value */
+
+#endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_GPIOTE_H */
diff --git a/arch/arm/src/nrf52/hardware/nrf52_saadc.h b/arch/arm/src/nrf52/hardware/nrf52_saadc.h
new file mode 100644
index 0000000..9b7fdd7
--- /dev/null
+++ b/arch/arm/src/nrf52/hardware/nrf52_saadc.h
@@ -0,0 +1,221 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/hardware/nrf52_saadc.h
+ *
+ *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ *   Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ***************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_SAADC_H
+#define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_SAADC_H
+
+/****************************************************************************
+ * Included Files
+ ***************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf52_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ***************************************************************************/
+
+/* Register offsets for SAADC **********************************************/
+
+#define NRF52_SAADC_TASKS_START        0x0000 /* Start the SAADCM */
+#define NRF52_SAADC_TASKS_SAMPLE       0x0004 /* Takes one SAADC sample */
+#define NRF52_SAADC_TASKS_STOP         0x0008 /* Stop the SAADC */
+#define NRF52_SAADC_TASKS_CALEOFFSET   0x000c /* Starts offset auto-calibration */
+#define NRF52_SAADC_EVENTS_STARTED     0x0100 /* The SAADC has started */
+#define NRF52_SAADC_EVENTS_END         0x0104 /* The SAADC has filled up the result buffer */
+#define NRF52_SAADC_EVENTS_DONE        0x0108 /* A conversio ntask has been completed */
+#define NRF52_SAADC_EVENTS_RESULTDONE  0x010c /* Result ready for transfer to RAM */
+#define NRF52_SAADC_EVENTS_CALDONE     0x0110 /* Calibration is complete */
+#define NRF52_SAADC_EVENTS_STOPPED     0x0110 /* The SAADC has stopped */
+#define NRF52_SAADC_EVENTS_CHLIMH(x)   (0x118 + (x + 0x8)) /* Limit high event for channel x */
+#define NRF52_SAADC_EVENTS_CHLIML(x)   (0x11c + (x + 0x8)) /* Limit low event for channel x */
+#define NRF52_SAADC_INTEN              0x0300 /* Enable or disable interrupt */
+#define NRF52_SAADC_INTENSET           0x0304 /* Enable interrupt */
+#define NRF52_SAADC_INTENCLR           0x0308 /* Disable interrupt */
+#define NRF52_SAADC_STATUS             0x0400 /* Status */
+#define NRF52_SAADC_ENABLE             0x0500 /* Enable or disable SAADC */
+#define NRF52_SAADC_CHPSELP(x)         (0x510 + (x + 0x10)) /* Input positive pin for CH[x] */
+#define NRF52_SAADC_CHPSELN(x)         (0x514 + (x + 0x10)) /* Input negative pin for CH[x] */
+#define NRF52_SAADC_CHCONFIG(x)        (0x518 + (x + 0x10)) /* Input configuration for CH[x] */
+#define NRF52_SAADC_CHLIMIT(x)         (0x51c + (x + 0x10)) /* High/low limits for event monitoring of a CH[x] */
+#define NRF52_SAADC_RESOLUTION         0x05f0 /* Resolution configuration */
+#define NRF52_SAADC_OVERSAMPLE         0x05f4 /* Oversampling configuration */
+#define NRF52_SAADC_SAMPLERATE         0x05f8 /* Controls normal or continous sample rate */
+#define NRF52_SAADC_PTR                0x062c /* Data pointer */
+#define NRF52_SAADC_MAXCNT             0x0630 /* Maximum number of 16-bit samples */
+#define NRF52_SAADC_AMOUNT             0x0634 /* Number of 16-bit samples written to buffer */
+
+/* Register Bitfield Definitions for SAADC *********************************/
+
+/* INTEN/INTENSET/INTENCLR Register */
+
+#define SAADC_INT_STARTED              (1 << 0)  /* Bit 0: Interrupt for event STARTED */
+#define SAADC_INT_END                  (1 << 1)  /* Bit 1: Interrupt for event END */
+#define SAADC_INT_DONE                 (1 << 2)  /* Bit 2: Interrupt for event DONE */
+#define SAADC_INT_RESULTDONE           (1 << 3)  /* Bit 3: Interrupt for event RESULTDONE */
+#define SAADC_INT_CALDONE              (1 << 4)  /* Bit 4: Interrupt for event CALIBRATEDONE */
+#define SAADC_INT_STOPPED              (1 << 5)  /* Bit 5: Interrupt for event STOPPED */
+#define SAADC_INT_CHXLIMH(x)           (1 << (x + 0x6)) /* Bit (x+6): Interrupt for event CHxLIMITH */
+#define SAADC_INT_CHXLIML(x)           (1 << (x + 0x7)) /* Bit (x+7): Interrupt for event CHxLIMITL */
+
+/* STATUS Register */
+
+#define SAADC_STATUS_READY             (0)       /* Bit 0: SAADC is ready */
+#define SAADC_STATUS_BUSY              (1 << 0)  /* Bit 0: SAADC is busy */
+
+/* ENABLE Register */
+
+#define SAADC_ENABLE_DIS               (0)       /* Bit 0: Disable SAADC */
+#define SAADC_ENABLE_EN                (1 << 0)  /* Bit 0: Enable SAADC */
+
+/* CH[n] PSELP Register */
+
+#define SAADC_CHPSELP_SHIFT            (0)       /* Bits 0-4: Intput positive pin selection for CH[x] */
+#define SAADC_CHPSELP_MASK             (0xf << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_NC             (0x0 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN0            (0x1 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN1            (0x2 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN2            (0x3 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN3            (0x4 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN4            (0x5 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN5            (0x6 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN6            (0x7 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_IN7            (0x8 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_VDD            (0x9 << SAADC_CHPSELP_SHIFT)
+#  define SAADC_CHPSELP_VDDHDIV5       (0xd << SAADC_CHPSELP_SHIFT)
+
+/* CH[n] PSELN Register */
+
+#define SAADC_CHPSELN_SHIFT            (0)       /* Bits 0-4: Intput negative pin selection for CH[x] */
+#define SAADC_CHPSELN_MASK             (0xf << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_NC             (0x0 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN0            (0x1 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN1            (0x2 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN2            (0x3 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN3            (0x4 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN4            (0x5 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN5            (0x6 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN6            (0x7 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_IN7            (0x8 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_VDD            (0x9 << SAADC_CHPSELN_SHIFT)
+#  define SAADC_CHPSELN_VDDHDIV5       (0xd << SAADC_CHPSELN_SHIFT)
+
+/* CH[n] CONFIG Register */
+
+#define SAADC_CONFIG_RESP_SHIFT        (0)       /* Bits 0-2: Positive channel resistor control */
+#define SAADC_CONFIG_RESP_MASK         (0x3 << SAADC_CONFIG_RESP_SHIFT)
+#  define SAADC_CONFIG_RESN_NONE       (0x0 << SAADC_CONFIG_RESP_SHIFT)
+#  define SAADC_CONFIG_RESN_PD         (0x1 << SAADC_CONFIG_RESP_SHIFT)
+#  define SAADC_CONFIG_RESN_PU         (0x2 << SAADC_CONFIG_RESP_SHIFT)
+#  define SAADC_CONFIG_RESN_VDD1P2     (0x3 << SAADC_CONFIG_RESP_SHIFT)
+#define SAADC_CONFIG_RESN_SHIFT        (4)       /* Bits 4-5: Negative channel resistor control */
+#define SAADC_CONFIG_RESN_MASK         (0x3 << SAADC_CONFIG_RESN_SHIFT)
+#  define SAADC_CONFIG_RESN_NONE       (0x0 << SAADC_CONFIG_RESN_SHIFT)
+#  define SAADC_CONFIG_RESN_PD         (0x1 << SAADC_CONFIG_RESN_SHIFT)
+#  define SAADC_CONFIG_RESN_PU         (0x2 << SAADC_CONFIG_RESN_SHIFT)
+#  define SAADC_CONFIG_RESN_VDD1D2     (0x3 << SAADC_CONFIG_RESN_SHIFT)
+#define SAADC_CONFIG_GAIN_SHIFT        (8)       /* Bits 8-10: Gain control */
+#define SAADC_CONFIG_GAIN_MASK         (0x7 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_1P6        (0x0 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_1P5        (0x1 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_1P4        (0x2 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_1P3        (0x3 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_1P2        (0x4 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_1          (0x5 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_2          (0x6 << SAADC_CONFIG_GAIN_SHIFT)
+#  define SAADC_CONFIG_GAIN_4          (0x7 << SAADC_CONFIG_GAIN_SHIFT)
+#define SAADC_REFSEL_INTERNAL          (0 << 12) /* Bit 12: Internal reference (0.6V) */
+#define SAADC_REFSEL_VDD1P4            (1 << 12) /* Bit 12: VDD/4 as reference */
+#define SAADC_CONFIG_TACQ_SHIFT        (16)      /* Bits 16-18: Acquisition time */
+#define SAADC_CONFIG_TACQ_MASK         (0x7 << SAADC_CONFIG_TACQ_SHIFT)
+#  define SAADC_CONFIG_TACQ_3US        (0x0 << SAADC_CONFIG_TACQ_SHIFT)
+#  define SAADC_CONFIG_TACQ_5US        (0x1 << SAADC_CONFIG_TACQ_SHIFT)
+#  define SAADC_CONFIG_TACQ_10US       (0x2 << SAADC_CONFIG_TACQ_SHIFT)
+#  define SAADC_CONFIG_TACQ_15US       (0x3 << SAADC_CONFIG_TACQ_SHIFT)
+#  define SAADC_CONFIG_TACQ_20US       (0x4 << SAADC_CONFIG_TACQ_SHIFT)
+#  define SAADC_CONFIG_TACQ_40US       (0x5 << SAADC_CONFIG_TACQ_SHIFT)
+#define SAADC_CONFIG_MODE_SE           (0 << 20) /* Bit 20: Single-ended */
+#define SAADC_CONFIG_MODE_DIFF         (1 << 20) /* Bit 20: Differential */
+#define SAADC_CONFIG_BURS_DIS          (0 << 24) /* Bit 24: Burst mode is disabled */
+#define SAADC_CONFIG_BURS_EN           (1 << 24) /* Bit 24: Burst mode is enabled  */
+
+/* CH[n] LIMIT Register */
+
+#define SAADC_CHLIMIT_LOW_SHIFT        (0)       /* Bits 0-15: Low level limit */
+#define SAADC_CHLIMIT_LOW_MASK         (0xffff << SAADC_CHLIMIT_LOW_SHIFT)
+#define SAADC_CHLIMIT_HIGH_SHIFT       (16)      /* Bits 0-15: High level limit */
+#define SAADC_CHLIMIT_HIGH_MASK        (0xffff << SAADC_CHLIMIT_HIGH_SHIFT)
+
+/* RESOLUTION Register */
+
+#define SAADC_RESOLUTION_SHIFT         (0)       /* Bits 0-2: SAADC resolution */
+#define SAADC_RESOLUTION_MASK          (0xf << SAADC_RESOLUTION_SHIFT)
+#  define SAADC_RESOLUTION_8BIT        (0x0 << SAADC_RESOLUTION_SHIFT)
+#  define SAADC_RESOLUTION_10BIT       (0x1 << SAADC_RESOLUTION_SHIFT)
+#  define SAADC_RESOLUTION_12BIT       (0x2 << SAADC_RESOLUTION_SHIFT)
+#  define SAADC_RESOLUTION_14BIT       (0x3 << SAADC_RESOLUTION_SHIFT)
+
+/* OVERSAMPLE Register */
+
+#define SAADC_OVERSAMPLE_SHIFT         (0)       /* Bit 0-3: Oversample control */
+#define SAADC_OVERSAMPLE_MASK          (0xf << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_NONE        (0x0 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_2X          (0x1 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_4X          (0x2 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_8X          (0x3 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_16X         (0x4 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_32X         (0x5 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_64X         (0x6 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_128X        (0x7 << SAADC_OVERSAMPLE_SHIFT)
+#  define SAADC_OVERSAMPLE_256X        (0x8 << SAADC_OVERSAMPLE_SHIFT)
+
+/* SAMPLERATE Register */
+
+#define SAADC_SAMPLERATE_CC_SHIFT      (0)       /* Bits 0-10: Capture and compare value */
+#define SAADC_SAMPLERATE_CC_MASK       (0x7ff << SAADC_SAMPLERATE_CC_SHIFT)
+#define SAADC_SAMPLERATE_MODE_TASK     (0 << 12) /* Bit 12: Rate is controlled from SAMPLE task */
+#define SAADC_SAMPLERATE_MODE_TIMERS   (1 << 12) /* Bit 12: Rate is controlled from local timer */
+
+/* MAXCNT Register */
+
+#define SAADC_MAXCNT_SHIFT             (0)       /* Bits 0-14: Maximum of 16-bit samples written to output buffer */
+#define SAADC_MAXCNT_MASK              (0x7fff)
+
+/* AMOUNT Register */
+
+#define SAADC_AMOUNT_SHIFT             (0)       /* Bits 0-14: Number of 16-bit samples written to output buffer */
+#define SAADC_AMOUNT_MASK              (0x7fff)
+
+#endif /* __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_SAADC_H */
diff --git a/arch/arm/src/nrf52/hardware/nrf52_spi.h b/arch/arm/src/nrf52/hardware/nrf52_spi.h
index 7f56d98..8b554ab 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_spi.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_spi.h
@@ -1,4 +1,4 @@
-/************************************************************************************************
+/****************************************************************************
  * arch/arm/src/nrf52/hardware/nrf52_spi.h
  *
  *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
@@ -31,23 +31,23 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ************************************************************************************************/
+ ***************************************************************************/
 
 #ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_SPI_H
 #define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_SPI_H
 
-/************************************************************************************************
+/****************************************************************************
  * Included Files
- ************************************************************************************************/
+ ***************************************************************************/
 
 #include <nuttx/config.h>
 #include "hardware/nrf52_memorymap.h"
 
-/************************************************************************************************
+/****************************************************************************
  * Pre-processor Definitions
- ************************************************************************************************/
+ ***************************************************************************/
 
-/* Register offsets for SPI master (SPIM) *******************************************************/
+/* Register offsets for SPI master (SPIM) **********************************/
 
 #define NRF52_SPIM_TASK_START_OFFSET      (0x0010) /* Start SPI transaction */
 #define NRF52_SPIM_TASK_STOP_OFFSET       (0x0014) /* Stop SPI transaction */
@@ -84,7 +84,7 @@
 #define NRF52_SPIM_DCXCNT_OFFSET          (0x0570) /* DCX configuration */
 #define NRF52_SPIM_ORC_OFFSET             (0x05c0) /* ORC */
 
-/* Register offsets for SPI slave (SPIS) *******************************************************/
+/* Register offsets for SPI slave (SPIS) ***********************************/
 
 #define NRF52_SPIS_SHORTS_OFFSET          (0x0200) /* Shortcuts between local events and tasks */
 #define NRF52_SPIS_INTENSET_OFFSET        (0x0304) /* Enable interrupt */
@@ -108,7 +108,7 @@
 #define NRF52_SPIS_DEF_OFFSET             (0x055c) /* Default character */
 #define NRF52_SPIS_ORC_OFFSET             (0x05c0) /* Over-read character */
 
-/* Register Bitfield Definitions for SPIM *******************************************************/
+/* Register Bitfield Definitions for SPIM **********************************/
 
 /* TASKS_START Register */
 
@@ -160,13 +160,13 @@
 
 /* STALLLSTAT Register */
 
-#define SPIM_STALLSTAT_TX           (1 << 0)  /* Bit 0: Stall status for EasyDMA RAM reads */
+#define SPIM_STALLSTAT_RX           (1 << 0)  /* Bit 0: Stall status for EasyDMA RAM reads */
 #define SPIM_STALLSTAT_TX           (1 << 1)  /* Bit 1: Stall status for EasyDMA RAM writes */
 
 /* ENABLE Register */
 
 #define SPIM_ENABLE_DIS             (0)        /* Disable SPIM */
-#define SPIM_ENABLE_EN              (0xf << 0) /* Enable SPIM */
+#define SPIM_ENABLE_EN              (0x7 << 0) /* Enable SPIM */
 
 /* PSELSCK Register */
 
@@ -175,6 +175,7 @@
 #define SPIM_PSELSCK_PORT_SHIFT     (5)       /* Bit 5: SCK port number */
 #define SPIM_PSELSCK_PORT_MASK      (0x1 << SPIM_PSELSCK_PORT_SHIFT)
 #define SPIM_PSELSCK_CONNECTED      (1 << 31) /* Bit 31: Connection */
+#define SPIM_PSELSCK_RESET          (0xffffffff)
 
 /* PSELMOSI Register */
 
@@ -183,6 +184,7 @@
 #define SPIM_PSELMOSI_PORT_SHIFT    (5)       /* Bit 5: MOSI port number */
 #define SPIM_PSELMOSI_PORT_MASK     (0x1 << SPIM_PSELMOSI_PORT_SHIFT)
 #define SPIM_PSELMOSI_CONNECTED     (1 << 31) /* Bit 31: Connection */
+#define SPIM_PSELMOSI_RESET         (0xffffffff)
 
 /* PSELMISO Register */
 
@@ -191,6 +193,7 @@
 #define SPIM_PSELMISO_PORT_SHIFT    (5)       /* Bit 5: MISO port number */
 #define SPIM_PSELMISO_PORT_MASK     (0x1 << SPIM_PSELMISO_PORT_SHIFT)
 #define SPIM_PSELMISO_CONNECTED     (1 << 31) /* Bit 31: Connection */
+#define SPIM_PSELMISO_RESET         (0xffffffff)
 
 /* PSELCSN Register */
 
@@ -199,6 +202,7 @@
 #define SPIM_PSELCSN_PORT_SHIFT     (5)       /* Bit 5: CSN port number */
 #define SPIM_PSELCSN_PORT_MASK      (0x1 << SPIM_PSELCSN_PORT_SHIFT)
 #define SPIM_PSELCSN_CONNECTED      (1 << 31) /* Bit 31: Connection */
+#define SPIM_PSELCSN_RESET          (0xffffffff)
 
 /* FREQUENCY Register */
 
diff --git a/arch/arm/src/nrf52/hardware/nrf52_twi.h b/arch/arm/src/nrf52/hardware/nrf52_twi.h
index c27e9b9..e17d706 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_twi.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_twi.h
@@ -1,4 +1,4 @@
-/************************************************************************************************
+/****************************************************************************
  * arch/arm/src/nrf52/hardware/nrf52_twi.h
  *
  *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
@@ -31,23 +31,23 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ************************************************************************************************/
+ ***************************************************************************/
 
 #ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_TWI_H
 #define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_TWI_H
 
-/************************************************************************************************
+/****************************************************************************
  * Included Files
- ************************************************************************************************/
+ ***************************************************************************/
 
 #include <nuttx/config.h>
 #include "hardware/nrf52_memorymap.h"
 
-/************************************************************************************************
+/****************************************************************************
  * Pre-processor Definitions
- ************************************************************************************************/
+ ***************************************************************************/
 
-/* Register offsets for TWI master (TWIM) *******************************************************/
+/* Register offsets for TWI master (TWIM) **********************************/
 
 #define NRF52_TWIM_TASKS_STARTRX_OFFSET     0x0000 /* Start TWIM receive sequence */
 #define NRF52_TWIM_TASKS_STARTTX_OFFSET     0x0008 /* Start TWIM transmit sequence */
@@ -80,7 +80,7 @@
 #define NRF52_TWIM_TXLIST_OFFSET            0x0550 /* TX EasyDMA list type */
 #define NRF52_TWIM_ADDRESS_OFFSET           0x0588 /* TWIM address */
 
-/* Register offsets for TWI slave (TWIS) ********************************************************/
+/* Register offsets for TWI slave (TWIS) ***********************************/
 
 #define NRF52_TWIS_TASKS_STOP_OFFSET        0x0014 /* Stop TWIS transaction */
 #define NRF52_TWIS_TASKS_SUSPEND_OFFSET     0x001c /* Suspend TWIS transaction */
@@ -115,7 +115,7 @@
 #define NRF52_TWIS_CONFIG_OFFSET            0x0594 /* Configuration register for the address match mechanism */
 #define NRF52_TWIS_ORC_OFFSET               0x05c0 /* Over-read character */
 
-/* Register Bitfield Definitions for TWIM *******************************************************/
+/* Register Bitfield Definitions for TWIM **********************************/
 
 /* SHORTS Register */
 
@@ -145,7 +145,7 @@
 /* ENABLE Register */
 
 #define TWIM_ENABLE_DIS                     (0)        /* Disable TWIM */
-#define TWIM_ENABLE_EN                      (0xf << 0) /* Disable TWIM */
+#define TWIM_ENABLE_EN                      (0x6 << 0) /* Disable TWIM */
 
 /* PSELSCL Register */
 
@@ -154,6 +154,7 @@
 #define TWIM_PSELSCL_PORT_SHIFT             (5)        /* Bit 5: SCL port number */
 #define TWIM_PSELSCL_PORT_MASK              (0x1 << TWIM_PSELSCL_PORT_SHIFT)
 #define TWIM_PSELSCL_CONNECTED              (1 << 31)  /* Bit 31: Connection */
+#define TWIM_PSELSCL_RESET                  (0xffffffff)
 
 /* PSELSDA Register */
 
@@ -162,6 +163,7 @@
 #define TWIM_PSELSDA_PORT_SHIFT             (5)        /* Bit 5: SDA port number */
 #define TWIM_PSELSDA_PORT_MASK              (0x1 << TWIM_PSELSDA_PORT_SHIFT)
 #define TWIM_PSELSDA_CONNECTED              (1 << 31)  /* Bit 31: Connection */
+#define TWIM_PSELSDA_RESET                  (0xffffffff)
 
 /* FREQUENCY Register */
 
diff --git a/arch/arm/src/nrf52/hardware/nrf52_uarte.h b/arch/arm/src/nrf52/hardware/nrf52_uarte.h
index cb9c3c2..3a0e05c 100644
--- a/arch/arm/src/nrf52/hardware/nrf52_uarte.h
+++ b/arch/arm/src/nrf52/hardware/nrf52_uarte.h
@@ -1,4 +1,4 @@
-/*****************************************************************************************************
+/****************************************************************************
  * arch/arm/src/nrf52/hardware/nrf52_uarte.h
  *
  *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
@@ -31,23 +31,23 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- *****************************************************************************************************/
+ ***************************************************************************/
 
 #ifndef __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_UARTE_H
 #define __ARCH_ARM_SRC_NRF52_HARDWARE_NRF52_UARTE_H
 
-/*****************************************************************************************************
+/****************************************************************************
  * Included Files
- *****************************************************************************************************/
+ ***************************************************************************/
 
 #include <nuttx/config.h>
 #include "hardware/nrf52_memorymap.h"
 
-/*****************************************************************************************************
+/****************************************************************************
  * Pre-processor Definitions
- *****************************************************************************************************/
+ ***************************************************************************/
 
-/* UART/UARTE Register Offsets ***********************************************************************/
+/* UART/UARTE Register Offsets *********************************************/
 
 #define NRF52_UARTE_TASKS_STARTRX_OFFSET    0x0000  /* Start UART receiver */
 #define NRF52_UARTE_TASKS_STOPRX_OFFSET     0x0004  /* Stop UART receiver */
@@ -109,7 +109,7 @@
 #define NRF52_UART_BAUDRATE_OFFSET          0x0524 /* Baud rate */
 #define NRF52_UART_CONFIG_OFFSET            0x056c /* Configuration of parity and hardware flow control */
 
-/* UART/UARTE Register Addresses *********************************************************************/
+/* UART/UARTE Register Addresses *******************************************/
 
 #define NRF52_UARTE0_TASKS_STARTRX          (NRF52_UARTE0_BASE + NRF52_UARTE_TASKS_STARTRX_OFFSET)
 #define NRF52_UARTE0_TASKS_STOPRX           (NRF52_UARTE0_BASE + NRF52_UARTE_TASKS_STOPRX_OFFSET)
@@ -233,7 +233,7 @@
 #  define NRF52_UART1_CONFIG                (NRF52_UART1_BASE + NRF52_UART_CONFIG_OFFSET)
 #endif
 
-/* UART Register Bitfield Definitions ****************************************************************/
+/* UART Register Bitfield Definitions **************************************/
 
 /* PSELRTS Register */
 
@@ -242,6 +242,7 @@
 #define UART_PSELRTS_PORT_SHIFT             (5)       /* Bit 5: Port number */
 #define UART_PSELRTS_PORT_MASK              (0x1 << UART_PSELRTS_PORT_SHIFT)
 #define UART_PSELRTS_CONNECT                (1 << 31) /* Bit 31: Connection */
+#define UART_PSELRTS_RESET                  (0xffffffff)
 
 /* PSELTXD Register */
 
@@ -250,6 +251,7 @@
 #define UART_PSELTXD_PORT_SHIFT             (5)       /* Bit 5: Port number */
 #define UART_PSELTXD_PORT_MASK              (0x1 << UART_PSELTXD_PORT_SHIFT)
 #define UART_PSELTXD_CONNECT                (1 << 31) /* Bit 31: Connection */
+#define UART_PSELTXD_RESET                  (0xffffffff)
 
 /* PSELCTS Register */
 
@@ -258,6 +260,7 @@
 #define UART_PSELCTS_PORT_SHIFT             (5)       /* Bit 5: Port number */
 #define UART_PSELCTS_PORT_MASK              (0x1 << UART_PSELCTS_PORT_SHIFT)
 #define UART_PSELCTS_CONNECT                (1 << 31) /* Bit 31: Connection */
+#define UART_PSELCTS_RESET                  (0xffffffff)
 
 /* PSELRXD Register */
 
@@ -266,6 +269,7 @@
 #define UART_PSELRXD_PORT_SHIFT             (5)       /* Bit 5: Port number */
 #define UART_PSELRXD_PORT_MASK              (0x1 << UART_PSELRXD_PORT_SHIFT)
 #define UART_PSELRXD_CONNECT                (1 << 31) /* Bit 31: Connection */
+#define UART_PSELRXD_RESET                  (0xffffffff)
 
 /* ENABLE Register */
 
diff --git a/arch/arm/src/nrf52/nrf52_gpio.c b/arch/arm/src/nrf52/nrf52_gpio.c
index 70c7884..c5f29d0 100644
--- a/arch/arm/src/nrf52/nrf52_gpio.c
+++ b/arch/arm/src/nrf52/nrf52_gpio.c
@@ -229,6 +229,36 @@ int nrf52_gpio_config(nrf52_pinset_t cfgset)
 }
 
 /****************************************************************************
+ * Name: nrf52_gpio_unconfig
+ *
+ * Description:
+ *   Unconfigure a GPIO pin based on bit-encoded description of the pin.
+ *
+ ****************************************************************************/
+
+int nrf52_gpio_unconfig(nrf52_pinset_t cfgset)
+{
+  unsigned int pin;
+  unsigned int port;
+  uint32_t offset;
+
+  /* Get port and pin number */
+
+  port = (cfgset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+  pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+
+  /* Get address offset */
+
+  offset = nrf52_gpio_regget(port, NRF52_GPIO_PIN_CNF_OFFSET(pin));
+
+  /* Configure as input and disconnect input buffer */
+
+  putreg32(NRF52_GPIO_CNF_INPUT, offset);
+
+  return OK;
+}
+
+/****************************************************************************
  * Name: nrf52_gpio_write
  *
  * Description:
diff --git a/arch/arm/src/nrf52/nrf52_gpio.h b/arch/arm/src/nrf52/nrf52_gpio.h
index 55f6580..612d0af 100644
--- a/arch/arm/src/nrf52/nrf52_gpio.h
+++ b/arch/arm/src/nrf52/nrf52_gpio.h
@@ -226,6 +226,16 @@ void nrf52_gpio_irqinitialize(void);
 int nrf52_gpio_config(nrf52_pinset_t cfgset);
 
 /************************************************************************************
+ * Name: nrf52_gpio_unconfig
+ *
+ * Description:
+ *   Unconfigure a GPIO pin based on bit-encoded description of the pin.
+ *
+ ************************************************************************************/
+
+int nrf52_gpio_unconfig(nrf52_pinset_t cfgset);
+
+/************************************************************************************
  * Name: nrf52_gpio_interrupt
  *
  * Description:
diff --git a/arch/arm/src/nrf52/nrf52_i2c.c b/arch/arm/src/nrf52/nrf52_i2c.c
new file mode 100644
index 0000000..258917a
--- /dev/null
+++ b/arch/arm/src/nrf52/nrf52_i2c.c
@@ -0,0 +1,644 @@
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_i2c.c
+ *
+ *   Copyright (C) 2020 Gregory Nutt. All rights reserved.
+ *   Author: Mateusz Szafoni <ra...@railab.me>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ *    used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <debug.h>
+#include <semaphore.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/semaphore.h>
+#include <arch/board/board.h>
+
+#include "up_arch.h"
+
+#include "nrf52_gpio.h"
+#include "nrf52_i2c.h"
+
+#include "hardware/nrf52_twi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+#  error I2C irq not supported yet
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* I2C Device Private Data */
+
+struct nrf52_i2c_priv_s
+{
+  const struct i2c_ops_s *ops;      /* Standard I2C operations */
+  uint32_t                base;     /* TWI base address */
+  uint32_t                scl_pin;  /* SCL pin configuration */
+  uint32_t                sda_pin;  /* SDA pin configuration */
+  int                     refs;     /* Reference count */
+#ifndef CONFIG_I2C_POLLED
+  uint32_t                irq;      /* TWI interrupt */
+#endif
+  uint8_t                 msgc;     /* Message count */
+  struct i2c_msg_s       *msgv;     /* Message list */
+  uint8_t                *ptr;      /* Current message buffer */
+  uint32_t                freq;     /* Current I2C frequency */
+  int                     dcnt;     /* Current message length */
+  uint16_t                flags;    /* Current message flags */
+  uint16_t                addr;     /* Current I2C address*/
+  sem_t                   sem_excl; /* Mutual exclusion semaphore */
+#ifndef CONFIG_I2C_POLLED
+  sem_t sem_isr;                    /* Interrupt wait semaphore */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline void nrf52_i2c_putreg(FAR struct nrf52_i2c_priv_s *priv,
+                                    uint32_t offset,
+                                    uint32_t value);
+static inline uint32_t nrf52_i2c_getreg(FAR struct nrf52_i2c_priv_s *priv,
+                                        uint32_t offset);
+static int nrf52_i2c_transfer(FAR struct i2c_master_s *dev,
+                              FAR struct i2c_msg_s *msgs,
+                              int count);
+#ifdef CONFIG_I2C_RESET
+static int nrf52_i2c_reset(FAR struct i2c_master_s *dev);
+#endif
+#ifndef CONFIG_I2C_POLLED
+static int nrf52_i2c_isr(int irq, void *context, FAR void *arg);
+#endif
+static int nrf52_i2c_deinit(FAR struct nrf52_i2c_priv_s *priv);
+static int nrf52_i2c_init(FAR struct nrf52_i2c_priv_s *priv);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C operations */
+
+static const struct i2c_ops_s g_nrf52_i2c_ops =
+{
+  .transfer = nrf52_i2c_transfer
+#ifdef CONFIG_I2C_RESET
+  , .reset  = nrf52_i2c_reset
+#endif
+};
+
+/* I2C0 (TWI0) device */
+
+#ifdef CONFIG_NRF52_I2C0_MASTER
+
+static struct nrf52_i2c_priv_s g_nrf52_i2c0_priv =
+{
+  .ops     = &g_nrf52_i2c_ops,
+  .base    = NRF52_TWIM0_BASE,
+  .scl_pin = BOARD_I2C0_SCL_PIN,
+  .sda_pin = BOARD_I2C0_SDA_PIN,
+  .refs    = 0,
+#ifndef CONFIG_I2C_POLLED
+  .irq     = NRF52_IRQ_SPI_TWI_0,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/* I2C1 (TWI1) device */
+
+#ifdef CONFIG_NRF52_I2C1_MASTER
+static struct nrf52_i2c_priv_s g_nrf52_i2c1_priv =
+{
+  .ops     = &g_nrf52_i2c_ops,
+  .base    = NRF52_TWIM0_BASE,
+  .scl_pin = BOARD_I2C1_SCL_PIN,
+  .sda_pin = BOARD_I2C1_SDA_PIN,
+  .refs    = 0,
+#ifndef CONFIG_I2C_POLLED
+  .irq     = NRF52_IRQ_SPI_TWI_1,
+#endif
+  .msgc    = 0,
+  .msgv    = NULL,
+  .ptr     = NULL,
+  .freq    = 0,
+  .dcnt    = 0,
+  .flags   = 0,
+  .addr    = 0,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_i2c_putreg
+ *
+ * Description:
+ *   Put a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline void nrf52_i2c_putreg(FAR struct nrf52_i2c_priv_s *priv,
+                                    uint32_t offset,
+                                    uint32_t value)
+{
+  putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_i2c_getreg
+ *
+ * Description:
+ *   Get a 32-bit register value by offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf52_i2c_getreg(FAR struct nrf52_i2c_priv_s *priv,
+                                        uint32_t offset)
+{
+  return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: nrf52_i2c_transfer
+ *
+ * Description:
+ *   Generic I2C transfer function
+ *
+ ****************************************************************************/
+
+static int nrf52_i2c_transfer(FAR struct i2c_master_s *dev,
+                              FAR struct i2c_msg_s *msgs,
+                              int count)
+{
+  FAR struct nrf52_i2c_priv_s *priv = (FAR struct nrf52_i2c_priv_s *)dev;
+  uint32_t regval = 0;
+  int      ret = OK;
+
+  /* Reset ptr and dcnt */
+
+  priv->dcnt = 0;
+  priv->ptr = NULL;
+
+  priv->msgv = msgs;
+  priv->msgc = count;
+
+  /* Do we need change I2C bus freqency ? */
+
+  if (priv->msgv->frequency != priv->freq)
+    {
+      /* Get TWI frequency */
+
+      switch (priv->msgv->frequency)
+        {
+            case 100000:
+            {
+              regval = TWIM_FREQUENCY_100KBPS;
+              break;
+            }
+
+            case 250000:
+            {
+              regval = TWIM_FREQUENCY_250KBPS;
+              break;
+            }
+
+            case 400000:
+            {
+              regval = TWIM_FREQUENCY_400KBPS;
+              break;
+            }
+
+            default:
+            {
+              ret = -EINVAL;
+              goto errout;
+            }
+        }
+
+      /* Write TWI frequency */
+
+      nrf52_i2c_putreg(priv, NRF52_TWIM_FREQUENCY_OFFSET, regval);
+
+      /* Save the new I2C frequency */
+
+      priv->freq = priv->msgv->frequency;
+    }
+
+  /* I2C transfer */
+
+  do
+    {
+      /* Get current message data */
+
+      priv->ptr   = priv->msgv->buffer;
+      priv->dcnt  = priv->msgv->length;
+      priv->flags = priv->msgv->flags;
+      priv->addr  = priv->msgv->addr;
+
+      /* Write TWI address */
+
+      regval = priv->addr;
+      nrf52_i2c_putreg(priv, NRF52_TWIM_ADDRESS_OFFSET, regval);
+
+      if ((priv->flags & I2C_M_READ) == 0)
+        {
+          /* Write TXD data pointer */
+
+          regval = (uint32_t)priv->ptr;
+          nrf52_i2c_putreg(priv, NRF52_TWIM_TXDPTR_OFFSET, regval);
+
+          /* Write number of bytes in TXD buffer */
+
+          regval = priv->dcnt;
+          nrf52_i2c_putreg(priv, NRF52_TWIM_TXMAXCNT_OFFSET, regval);
+
+          /* Start TX sequence */
+
+          nrf52_i2c_putreg(priv, NRF52_TWIM_TASKS_STARTTX_OFFSET, 1);
+
+          /* Wait for last TX event */
+
+#ifdef CONFIG_I2C_POLLED
+          while (nrf52_i2c_getreg(priv,
+                                  NRF52_TWIM_EVENTS_LASTTX_OFFSET) != 1);
+#endif
+
+          /* TWIM stop */
+
+          nrf52_i2c_putreg(priv, NRF52_TWIM_TASKS_STOP_OFFSET, 1);
+
+          /* Wait for stop event */
+
+#ifdef CONFIG_I2C_POLLED
+          while (nrf52_i2c_getreg(priv,
+                                  NRF52_TWIM_EVENTS_STOPPED_OFFSET) != 1);
+#endif
+        }
+      else
+        {
+          /* Write RXD data pointer */
+
+          regval = (uint32_t)priv->ptr;
+          nrf52_i2c_putreg(priv, NRF52_TWIM_RXDPTR_OFFSET, regval);
+
+          /* Write number of bytes in RXD buffer */
+
+          regval = priv->dcnt;
+          nrf52_i2c_putreg(priv, NRF52_TWIM_RXDMAXCNT_OFFSET, regval);
+
+          /* Start RX sequence */
+
+          nrf52_i2c_putreg(priv, NRF52_TWIM_TASKS_STARTRX_OFFSET, 1);
+
+          /* Wait for last RX done */
+
+#ifdef CONFIG_I2C_POLLED
+          while (nrf52_i2c_getreg(priv,
+                                  NRF52_TWIM_EVENTS_LASTRX_OFFSET) != 1);
+#endif
+          /* Stop TWIM */
+
+          nrf52_i2c_putreg(priv, NRF52_TWIM_TASKS_STOP_OFFSET, 1);
+
+          /* Wait for stop event */
+
+#ifdef CONFIG_I2C_POLLED
+          while (nrf52_i2c_getreg(priv,
+                                  NRF52_TWIM_EVENTS_STOPPED_OFFSET) != 1);
+#endif
+        }
+
+      /* Next message */
+
+      priv->msgc -= 1;
+      priv->msgv += 1;
+    }
+  while (priv->msgc > 0);
+
+errout:
+    return ret;
+}
+
+/****************************************************************************
+ * Name: nrf52_i2c_reset
+ *
+ * Description:
+ *   Perform an I2C bus reset in an attempt to break loose stuck I2C devices.
+ *
+ * Input Parameters:
+ *   dev   - Device-specific state data
+ *
+ * Returned Value:
+ *   Zero (OK) on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_I2C_RESET
+static int nrf52_i2c_reset(FAR struct i2c_master_s *dev)
+{
+#error not implemented
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf52_i2c_isr
+ *
+ * Description:
+ *   Common I2C interrupt service routine
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_I2C_POLLED
+static int nrf52_i2c_isr(int irq, void *context, FAR void *arg)
+{
+#error not implemented
+}
+#endif
+
+/****************************************************************************
+ * Name: nrf52_i2c_init
+ *
+ * Description:
+ *   Setup the I2C hardware, ready for operation with defaults
+ *
+ ****************************************************************************/
+
+static int nrf52_i2c_init(FAR struct nrf52_i2c_priv_s *priv)
+{
+  uint32_t regval = 0;
+  int pin         = 0;
+  int port        = 0;
+
+  /* Configure SCL and SDA pins */
+
+  nrf52_gpio_config(priv->scl_pin);
+  nrf52_gpio_config(priv->sda_pin);
+
+  /* Select SCL pin */
+
+  pin = (priv->scl_pin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+  port = (priv->scl_pin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+
+  regval = (pin << TWIM_PSELSCL_PIN_SHIFT);
+  regval |= (port << TWIM_PSELSCL_PORT_SHIFT);
+  nrf52_i2c_putreg(priv, NRF52_TWIM_PSELSCL_OFFSET, regval);
+
+  /* Select SDA pin */
+
+  pin = (priv->sda_pin & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
+  port = (priv->sda_pin & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+
+  regval = (pin << TWIM_PSELSDA_PIN_SHIFT);
+  regval |= (port << TWIM_PSELSDA_PORT_SHIFT);
+  nrf52_i2c_putreg(priv, NRF52_TWIM_PSELSDA_OFFSET, regval);
+
+  /* Enable TWI interface */
+
+  nrf52_i2c_putreg(priv, NRF52_TWIS_ENABLE_OFFSET, TWIM_ENABLE_EN);
+
+#ifndef CONFIG_I2C_POLLED
+  /* Attach error and event interrupts to the ISRs */
+
+  irq_attach(priv->irq, nrf52_i2c_isr, priv);
+  up_enable_irq(priv->irq);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_i2c_sem_init
+ *
+ * Description:
+ *   Initialize semaphores
+ *
+ ****************************************************************************/
+
+static int nrf52_i2c_sem_init(FAR struct nrf52_i2c_priv_s *priv)
+{
+  /* Initialize semaphores */
+
+  nxsem_init(&priv->sem_excl, 0, 1);
+
+#ifndef CONFIG_I2C_POLLED
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&priv->sem_isr, 0, 0);
+  nxsem_setprotocol(&priv->sem_isr, SEM_PRIO_NONE);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_i2c_sem_destroy
+ *
+ * Description:
+ *   Destroy semaphores.
+ *
+ ****************************************************************************/
+
+static int nrf52_i2c_sem_destroy(FAR struct nrf52_i2c_priv_s *priv)
+{
+  /* Release unused resources */
+
+  nxsem_destroy(&priv->sem_excl);
+#ifndef CONFIG_I2C_POLLED
+  nxsem_destroy(&priv->sem_isr);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nrf52_i2c_deinit
+ *
+ * Description:
+ *   Shutdown the I2C hardware
+ *
+ ****************************************************************************/
+
+static int nrf52_i2c_deinit(FAR struct nrf52_i2c_priv_s *priv)
+{
+  /* Enable TWI interface */
+
+  nrf52_i2c_putreg(priv, TWIM_ENABLE_DIS, NRF52_TWIS_ENABLE_OFFSET);
+
+  /* Unconfigure GPIO pins */
+
+  nrf52_gpio_unconfig(priv->scl_pin);
+  nrf52_gpio_unconfig(priv->sda_pin);
+
+  /* Deatach TWI from GPIO */
+
+  nrf52_i2c_putreg(priv, NRF52_TWIM_PSELSCL_OFFSET, TWIM_PSELSCL_RESET);
+  nrf52_i2c_putreg(priv, NRF52_TWIM_PSELSDA_OFFSET, TWIM_PSELSDA_RESET);
+
+  /* Disable and detach interrupts */
+
+#ifndef CONFIG_I2C_POLLED
+  up_disable_irq(priv->irq);
+  irq_detach(priv->irq);
+#endif
+
+  return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf52_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize one I2C bus
+ *
+ ****************************************************************************/
+
+FAR struct i2c_master_s *nrf52_i2cbus_initialize(int port)
+{
+  FAR struct nrf52_i2c_priv_s *priv = NULL;
+  irqstate_t flags;
+
+  /* Get interface */
+
+  switch (port)
+    {
+#ifdef CONFIG_NRF52_I2C0_MASTER
+      case 0:
+        {
+          priv = (FAR struct nrf52_i2c_priv_s *)&g_nrf52_i2c0_priv;
+          break;
+        }
+#endif
+
+#ifdef CONFIG_NRF52_I2C1_MASTER
+      case 1:
+        {
+          priv = (FAR struct nrf52_i2c_priv_s *)&g_nrf52_i2c1_priv;
+          break;
+        }
+#endif
+
+      default:
+        {
+          return NULL;
+        }
+    }
+
+  /* Initialize private data for the first time, increment reference count,
+   * power-up hardware and configure GPIOs.
+   */
+
+  flags = enter_critical_section();
+
+  if (priv->refs++ == 0)
+    {
+      /* Initialize sempaphores */
+
+      nrf52_i2c_sem_init(priv);
+
+      /* Initialize I2C */
+
+      nrf52_i2c_init(priv);
+    }
+
+  leave_critical_section(flags);
+
+  return (struct i2c_master_s *)priv;
+}
+
+/****************************************************************************
+ * Name: nrf52_i2cbus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an I2C bus
+ *
+ ****************************************************************************/
+
+int nrf52_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
+{
+  FAR struct nrf52_i2c_priv_s *priv = (struct nrf52_i2c_priv_s *)dev;
+  irqstate_t flags;
+
+  DEBUGASSERT(dev);
+
+  /* Decrement reference count and check for underflow */
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  flags = enter_critical_section();
+
+  if (--priv->refs)
+    {
+      leave_critical_section(flags);
+      return OK;
+    }
+
+  leave_critical_section(flags);
+
+  /* Disable power and other HW resource (GPIO's) */
+
+  nrf52_i2c_deinit(priv);
+
+  /* Release semaphores */
+
+  nrf52_i2c_sem_destroy(priv);
+
+  return OK;
+}
diff --git a/arch/arm/src/nrf52/nrf52_lowputc.h b/arch/arm/src/nrf52/nrf52_i2c.h
similarity index 51%
copy from arch/arm/src/nrf52/nrf52_lowputc.h
copy to arch/arm/src/nrf52/nrf52_i2c.h
index 7503412..9e39e7b 100644
--- a/arch/arm/src/nrf52/nrf52_lowputc.h
+++ b/arch/arm/src/nrf52/nrf52_i2c.h
@@ -1,8 +1,8 @@
-/************************************************************************************
- * arch/arm/src/nrf52/nrf52_lowputc.h
+/****************************************************************************
+ * arch/arm/src/nrf52/nrf52_i2c.h
  *
- *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
- *   Author: Gregory Nutt <gn...@nuttx.org>
+ *   Copyright (C) 2019 Gregory Nutt. All rights reserved.
+ *   Author: Mateusz Szafoni <ra...@railab.me>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,85 +31,62 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ************************************************************************************/
+ ****************************************************************************/
 
-#ifndef __ARCH_ARM_SRC_NRF52_NRF52_LOWPUTC_H
-#define __ARCH_ARM_SRC_NRF52_NRF52_LOWPUTC_H
+#ifndef __ARCH_ARM_SRC_NRF52_NRF52_I2C_H
+#define __ARCH_ARM_SRC_NRF52_NRF52_I2C_H
 
-/************************************************************************************
+/****************************************************************************
  * Included Files
- ************************************************************************************/
+ ****************************************************************************/
 
 #include <nuttx/config.h>
+#include <nuttx/i2c/i2c_master.h>
 
-#include <stdint.h>
-#include <stdbool.h>
-#include <nrf52_gpio.h>
+#include "chip.h"
 
-/************************************************************************************
- * Public Types
- ************************************************************************************/
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
 
-#ifdef HAVE_UART_DEVICE
-/* This structure describes the configuration of an UART */
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
 
-struct uart_config_s
-{
-  uint32_t baud;          /* Configured baud */
-  uint8_t  parity;        /* 0=none, 1=odd, 2=even */
-  uint8_t  bits;          /* Number of bits (5-9) */
-  bool     stopbits2;     /* true: Configure with 2 stop bits instead of 1 */
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
-  bool     iflow;         /* true: Input flow control supported */
-#endif
-#ifdef CONFIG_SERIAL_OFLOWCONTROL
-  bool     oflow;         /* true: Output flow control supported. */
-#endif
-  nrf52_pinset_t txpin;   /* TX pin */
-  nrf52_pinset_t rxpin;   /* RX pin */
-};
-#endif
-
-/************************************************************************************
- * Public Functions
- ************************************************************************************/
-
-/************************************************************************************
- * Name: nrf52_lowsetup
+/****************************************************************************
+ * Name: nrf52_i2cbus_initialize
  *
  * Description:
- *   Called at the very beginning of _start.  Performs low level initialization
- *   including setup of the console UART.  This UART initialization is done
- *   early so that the serial console is available for debugging very early in
- *   the boot sequence.
+ *   Initialize the selected I2C port. And return a unique instance of struct
+ *   struct i2c_master_s. This function may be called to obtain multiple
+ *   instances of the interface, each of which may be set up with a
+ *   different frequency and slave address.
  *
- ************************************************************************************/
-
-void nrf52_lowsetup(void);
-
-/************************************************************************************
- * Name: nrf52_usart_configure
+ * Input Parameters:
+ *   Port number (for hardware that has multiple TWI interfaces)
  *
- * Description:
- *   Configure a UART for non-interrupt driven operation
+ * Returned Value:
+ *   Valid I2C device structure reference on success; a NULL on failure
  *
- ************************************************************************************/
+ ****************************************************************************/
 
-#ifdef HAVE_UART_DEVICE
-void nrf52_usart_configure(uintptr_t base, FAR const struct uart_config_s *config);
-#endif
+FAR struct i2c_master_s *nrf52_i2cbus_initialize(int port);
 
-/************************************************************************************
- * Name: nrf52_usart_disable
+/****************************************************************************
+ * Name: nrf52_i2cbus_uninitialize
  *
  * Description:
- *   Disable a UART.  it will be necessary to again call
- *   nrf52_usart_configure() in order to use this UART channel again.
+ *   De-initialize the selected I2C port, and power down the device.
+ *
+ * Input Parameters:
+ *   Device structure as returned by the nrf52_i2cbus_initialize()
+ *
+ * Returned Value:
+ *   OK on success, ERROR when internal reference count mismatch or dev
+ *   points to invalid hardware device.
  *
- ************************************************************************************/
+ ****************************************************************************/
 
-#ifdef HAVE_UART_DEVICE
-void nrf52_usart_disable(uintptr_t base);
-#endif
+int nrf52_i2cbus_uninitialize(FAR struct i2c_master_s *dev);
 
-#endif /* __ARCH_ARM_SRC_NRF52_NRF52_LOWPUTC_H */
+#endif /* __ARCH_ARM_SRC_NRF52_NRF52_I2C_H */
diff --git a/arch/arm/src/nrf52/nrf52_lowputc.c b/arch/arm/src/nrf52/nrf52_lowputc.c
index ca44bcb..68f7600 100644
--- a/arch/arm/src/nrf52/nrf52_lowputc.c
+++ b/arch/arm/src/nrf52/nrf52_lowputc.c
@@ -114,7 +114,8 @@ static const struct uart_config_s g_console_config =
  ****************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
-static void nrf52_setbaud(uintptr_t base, const struct uart_config_s *config)
+static void nrf52_setbaud(uintptr_t base,
+                          FAR const struct uart_config_s *config)
 {
   uint32_t br = 0;
 
@@ -163,7 +164,8 @@ void nrf52_lowsetup(void)
  ****************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
-void nrf52_usart_configure(uintptr_t base, const struct uart_config_s *config)
+void nrf52_usart_configure(uintptr_t base,
+                           FAR const struct uart_config_s *config)
 {
   uint32_t pin    = 0;
   uint32_t port   = 0;
@@ -216,7 +218,8 @@ void nrf52_usart_configure(uintptr_t base, const struct uart_config_s *config)
  ****************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
-void nrf52_usart_disable(uintptr_t base)
+void nrf52_usart_disable(uintptr_t base,
+                         FAR const struct uart_config_s *config)
 {
   /* Disable interrupts */
 
@@ -228,6 +231,16 @@ void nrf52_usart_disable(uintptr_t base)
 
   putreg32(0xffffffff, base + NRF52_UART_PSELTXD_OFFSET);
   putreg32(0xffffffff, base + NRF52_UART_PSELRXD_OFFSET);
+
+  /* Unconfigure GPIO */
+
+  nrf52_gpio_unconfig(config->rxpin);
+  nrf52_gpio_unconfig(config->txpin);
+
+  /* Deatach TWI from GPIO */
+
+  putreg32(UART_PSELTXD_RESET, base + NRF52_UART_PSELTXD_OFFSET);
+  putreg32(UART_PSELRXD_RESET, base + NRF52_UART_PSELRXD_OFFSET);
 }
 #endif
 
diff --git a/arch/arm/src/nrf52/nrf52_lowputc.h b/arch/arm/src/nrf52/nrf52_lowputc.h
index 7503412..aac31d9 100644
--- a/arch/arm/src/nrf52/nrf52_lowputc.h
+++ b/arch/arm/src/nrf52/nrf52_lowputc.h
@@ -96,7 +96,8 @@ void nrf52_lowsetup(void);
  ************************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
-void nrf52_usart_configure(uintptr_t base, FAR const struct uart_config_s *config);
+void nrf52_usart_configure(uintptr_t base,
+                           FAR const struct uart_config_s *config);
 #endif
 
 /************************************************************************************
@@ -109,7 +110,8 @@ void nrf52_usart_configure(uintptr_t base, FAR const struct uart_config_s *confi
  ************************************************************************************/
 
 #ifdef HAVE_UART_DEVICE
-void nrf52_usart_disable(uintptr_t base);
+void nrf52_usart_disable(uintptr_t base,
+                         FAR const struct uart_config_s *config);
 #endif
 
 #endif /* __ARCH_ARM_SRC_NRF52_NRF52_LOWPUTC_H */
diff --git a/arch/arm/src/nrf52/nrf52_serial.c b/arch/arm/src/nrf52/nrf52_serial.c
index f4a269b..70c8e76 100644
--- a/arch/arm/src/nrf52/nrf52_serial.c
+++ b/arch/arm/src/nrf52/nrf52_serial.c
@@ -319,13 +319,11 @@ static void nrf52_shutdown(struct uart_dev_s *dev)
 {
   struct nrf52_dev_s *priv = (struct nrf52_dev_s *)dev->priv;
 
-  /* TODO: release uart pins */
-
   /* Disable interrupts */
 
   /* Reset hardware and disable Rx and Tx */
 
-  nrf52_usart_disable(priv->uartbase);
+  nrf52_usart_disable(priv->uartbase, &priv->config);
 }
 
 /****************************************************************************