From caf2d1430e07613c65de7b11f4ce380acf10e03d Mon Sep 17 00:00:00 2001
From: liang <liangzhang@bouffalolab.com>
Date: Thu, 14 Jan 2021 09:04:49 +0800
Subject: [PATCH] arch/risc-v/bl602: add gpioirq and i2c(master) driver

---
 arch/risc-v/src/bl602/Kconfig                 |    3 +
 arch/risc-v/src/bl602/Make.defs               |    4 +
 arch/risc-v/src/bl602/bl602_glb.c             |   28 +-
 arch/risc-v/src/bl602/bl602_glb.h             |   16 +
 arch/risc-v/src/bl602/bl602_gpio.c            |    2 +-
 arch/risc-v/src/bl602/bl602_gpio.h            |  150 ++-
 arch/risc-v/src/bl602/bl602_i2c.c             | 1042 +++++++++++++++++
 arch/risc-v/src/bl602/bl602_i2c.h             |   92 ++
 arch/risc-v/src/bl602/hardware/bl602_i2c.h    |   91 +-
 .../bl602/bl602evb/configs/gpio/defconfig     |   77 ++
 .../bl602/bl602evb/configs/i2c/defconfig      |   78 ++
 boards/risc-v/bl602/bl602evb/include/board.h  |   45 +-
 boards/risc-v/bl602/bl602evb/src/Makefile     |    6 +-
 .../risc-v/bl602/bl602evb/src/bl602_bringup.c |   19 +
 boards/risc-v/bl602/bl602evb/src/bl602_gpio.c |  607 ++++++++++
 15 files changed, 2158 insertions(+), 102 deletions(-)
 create mode 100644 arch/risc-v/src/bl602/bl602_i2c.c
 create mode 100644 arch/risc-v/src/bl602/bl602_i2c.h
 create mode 100644 boards/risc-v/bl602/bl602evb/configs/gpio/defconfig
 create mode 100644 boards/risc-v/bl602/bl602evb/configs/i2c/defconfig
 create mode 100644 boards/risc-v/bl602/bl602evb/src/bl602_gpio.c

diff --git a/arch/risc-v/src/bl602/Kconfig b/arch/risc-v/src/bl602/Kconfig
index 832d6de978..122e92c563 100644
--- a/arch/risc-v/src/bl602/Kconfig
+++ b/arch/risc-v/src/bl602/Kconfig
@@ -39,6 +39,9 @@ config BL602_TIMER1
 config BL602_PWM0
 	bool "PWM0"
 
+config BL602_I2C0
+	bool "I2C0"
+
 config BL602_SPIFLASH
 	bool "SPI Flash"
 	default n
diff --git a/arch/risc-v/src/bl602/Make.defs b/arch/risc-v/src/bl602/Make.defs
index 2797854c46..f0e3547514 100644
--- a/arch/risc-v/src/bl602/Make.defs
+++ b/arch/risc-v/src/bl602/Make.defs
@@ -48,6 +48,10 @@ CHIP_CSRCS += bl602_idle.c bl602_irq.c bl602_irq_dispatch.c
 CHIP_CSRCS += bl602_serial.c bl602_lowputc.c bl602_tim.c
 CHIP_CSRCS += bl602_start.c bl602_timerisr.c
 
+ifeq ($(CONFIG_I2C),y)                                                                               
+CHIP_CSRCS += bl602_i2c.c
+endif
+
 ifeq ($(CONFIG_TIMER),y)
 CHIP_CSRCS  += bl602_tim_lowerhalf.c
 endif
diff --git a/arch/risc-v/src/bl602/bl602_glb.c b/arch/risc-v/src/bl602/bl602_glb.c
index bf709db76c..1e20060437 100644
--- a/arch/risc-v/src/bl602/bl602_glb.c
+++ b/arch/risc-v/src/bl602/bl602_glb.c
@@ -25,7 +25,6 @@
 #include <nuttx/config.h>
 
 #include <stdint.h>
-
 #include "riscv_arch.h"
 #include "hardware/bl602_glb.h"
 
@@ -33,7 +32,7 @@
  * Pre-Processor Declarations
  ****************************************************************************/
 
-#define nop() asm volatile ("nop")
+#define nop() asm volatile("nop")
 
 /****************************************************************************
  * Public Functions
@@ -71,3 +70,28 @@ void bl602_swrst_ahb_slave1(uint32_t slave1)
   nop();
   modifyreg32(BL602_SWRST_CFG1, slave1, 0);
 }
+
+/****************************************************************************
+ * Name: bl602_glb_get_bclk_div
+ *
+ * Description:
+ *   get bus clock div.
+ *
+ * Input Parameters:
+ *   void
+ *
+ * Returned Value:
+ *   bus clock div
+ *
+ ****************************************************************************/
+
+uint8_t bl602_glb_get_bclk_div(void)
+{
+  uint32_t tmp_val;
+
+  tmp_val = getreg32(BL602_CLK_CFG0);
+  tmp_val =
+    (CLK_CFG0_REG_BCLK_DIV_MASK & tmp_val) >> CLK_CFG0_REG_BCLK_DIV_SHIFT;
+
+  return (uint8_t)tmp_val;
+}
diff --git a/arch/risc-v/src/bl602/bl602_glb.h b/arch/risc-v/src/bl602/bl602_glb.h
index 519035a6e7..e174139125 100644
--- a/arch/risc-v/src/bl602/bl602_glb.h
+++ b/arch/risc-v/src/bl602/bl602_glb.h
@@ -64,6 +64,22 @@ extern "C"
 
 void bl602_swrst_ahb_slave1(uint32_t slave1);
 
+/****************************************************************************
+ * Name: bl602_glb_get_bclk_div
+ *
+ * Description:
+ *   get bus clock div.
+ *
+ * Input Parameters:
+ *   void
+ *
+ * Returned Value:
+ *   bus clock div
+ *
+ ****************************************************************************/
+
+uint8_t bl602_glb_get_bclk_div(void);
+
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/arch/risc-v/src/bl602/bl602_gpio.c b/arch/risc-v/src/bl602/bl602_gpio.c
index ac49da0708..9778ee9c1e 100644
--- a/arch/risc-v/src/bl602/bl602_gpio.c
+++ b/arch/risc-v/src/bl602/bl602_gpio.c
@@ -219,5 +219,5 @@ void bl602_gpiowrite(gpio_pinset_t pinset, bool value)
 bool bl602_gpioread(gpio_pinset_t pinset)
 {
   uint8_t pin = (pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT;
-  return (getreg32(BL602_GPIO_CFGCTL30) & (1 << pin)) == 1;
+  return ((getreg32(BL602_GPIO_CFGCTL30) & (1 << pin)) ? 1 : 0);
 }
diff --git a/arch/risc-v/src/bl602/bl602_gpio.h b/arch/risc-v/src/bl602/bl602_gpio.h
index 28bc94b139..b3f43c7948 100644
--- a/arch/risc-v/src/bl602/bl602_gpio.h
+++ b/arch/risc-v/src/bl602/bl602_gpio.h
@@ -28,8 +28,8 @@
 #include <nuttx/config.h>
 
 #ifndef __ASSEMBLY__
-#  include <stdint.h>
-#  include <stdbool.h>
+#include <stdint.h>
+#include <stdbool.h>
 #endif
 
 #include <nuttx/irq.h>
@@ -81,11 +81,11 @@
  * ..UU .... .... ....
  */
 
-#define GPIO_PUPD_SHIFT  (12)                   /* Bits 16-17: Pull-up/down */
-#define GPIO_PUPD_MASK   (3 << GPIO_PUPD_SHIFT)
-#  define GPIO_FLOAT     (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */
-#  define GPIO_PULLUP    (1 << GPIO_PUPD_SHIFT) /* Pull-up */
-#  define GPIO_PULLDOWN  (2 << GPIO_PUPD_SHIFT) /* Pull-down */
+#define GPIO_PUPD_SHIFT (12) /* Bits 16-17: Pull-up/down */
+#define GPIO_PUPD_MASK  (3 << GPIO_PUPD_SHIFT)
+#define GPIO_FLOAT      (0 << GPIO_PUPD_SHIFT) /* No pull-up, pull-down */
+#define GPIO_PULLUP     (1 << GPIO_PUPD_SHIFT) /* Pull-up */
+#define GPIO_PULLDOWN   (2 << GPIO_PUPD_SHIFT) /* Pull-down */
 
 /* Drive:
  *
@@ -95,12 +95,12 @@
  * .... DD.. .... ....
  */
 
-#define GPIO_DRV_SHIFT   (10)                   /* Bits 10-11: Drive */
-#define GPIO_DRV_MASK    (3 << GPIO_DRV_SHIFT)
-#  define GPIO_DRV_0     (0 << GPIO_DRV_SHIFT)
-#  define GPIO_DRV_1     (1 << GPIO_DRV_SHIFT)
-#  define GPIO_DRV_2     (2 << GPIO_DRV_SHIFT)
-#  define GPIO_DRV_3     (3 << GPIO_DRV_SHIFT)
+#define GPIO_DRV_SHIFT (10) /* Bits 10-11: Drive */
+#define GPIO_DRV_MASK  (3 << GPIO_DRV_SHIFT)
+#define GPIO_DRV_0     (0 << GPIO_DRV_SHIFT)
+#define GPIO_DRV_1     (1 << GPIO_DRV_SHIFT)
+#define GPIO_DRV_2     (2 << GPIO_DRV_SHIFT)
+#define GPIO_DRV_3     (3 << GPIO_DRV_SHIFT)
 
 /* Input Schmitt trigger:
  *
@@ -110,10 +110,10 @@
  * .... ..S. .... ....
  */
 
-#define GPIO_SMT_SHIFT   (9)                   /* Bits 9: SMT Enable */
-#define GPIO_SMT_MASK    (3 << GPIO_SMT_SHIFT)
-#  define GPIO_SMT_DIS   (0 << GPIO_SMT_SHIFT)
-#  define GPIO_SMT_EN    (1 << GPIO_SMT_SHIFT)
+#define GPIO_SMT_SHIFT (9) /* Bits 9: SMT Enable */
+#define GPIO_SMT_MASK  (3 << GPIO_SMT_SHIFT)
+#define GPIO_SMT_DIS   (0 << GPIO_SMT_SHIFT)
+#define GPIO_SMT_EN    (1 << GPIO_SMT_SHIFT)
 
 /* GPIO type selection:
  *
@@ -123,18 +123,18 @@
  * .... ...F FFF. ....
  */
 
-#define GPIO_FUNC_SHIFT      (5)                     /* Bits 5-8: GPIO Type */
-#define GPIO_FUNC_MASK       (15 << GPIO_FUNC_SHIFT)
-#  define GPIO_FUNC_SDIO     (1 << GPIO_FUNC_SHIFT)   /* SDIO */
-#  define GPIO_FUNC_FLASH    (2 << GPIO_FUNC_SHIFT)   /* Flash */
-#  define GPIO_FUNC_SPI      (4 << GPIO_FUNC_SHIFT)   /* SPI */
-#  define GPIO_FUNC_I2C      (6 << GPIO_FUNC_SHIFT)   /* I2C */
-#  define GPIO_FUNC_UART     (7 << GPIO_FUNC_SHIFT)   /* UART */
-#  define GPIO_FUNC_PWM      (8 << GPIO_FUNC_SHIFT)   /* PWM */
-#  define GPIO_FUNC_EXT_PA   (9 << GPIO_FUNC_SHIFT)   /* Analog */
-#  define GPIO_FUNC_ANA      (10 << GPIO_FUNC_SHIFT)  /* Analog */
-#  define GPIO_FUNC_SWGPIO   (11 << GPIO_FUNC_SHIFT)  /* Software GPIO */
-#  define GPIO_FUNC_JTAG     (14 << GPIO_FUNC_SHIFT)  /* JTAG */
+#define GPIO_FUNC_SHIFT  (5) /* Bits 5-8: GPIO Type */
+#define GPIO_FUNC_MASK   (15 << GPIO_FUNC_SHIFT)
+#define GPIO_FUNC_SDIO   (1 << GPIO_FUNC_SHIFT)  /* SDIO */
+#define GPIO_FUNC_FLASH  (2 << GPIO_FUNC_SHIFT)  /* Flash */
+#define GPIO_FUNC_SPI    (4 << GPIO_FUNC_SHIFT)  /* SPI */
+#define GPIO_FUNC_I2C    (6 << GPIO_FUNC_SHIFT)  /* I2C */
+#define GPIO_FUNC_UART   (7 << GPIO_FUNC_SHIFT)  /* UART */
+#define GPIO_FUNC_PWM    (8 << GPIO_FUNC_SHIFT)  /* PWM */
+#define GPIO_FUNC_EXT_PA (9 << GPIO_FUNC_SHIFT)  /* Analog */
+#define GPIO_FUNC_ANA    (10 << GPIO_FUNC_SHIFT) /* Analog */
+#define GPIO_FUNC_SWGPIO (11 << GPIO_FUNC_SHIFT) /* Software GPIO */
+#define GPIO_FUNC_JTAG   (14 << GPIO_FUNC_SHIFT) /* JTAG */
 
 /* This identifies the bit in the port:
  *
@@ -146,35 +146,49 @@
 
 #define GPIO_PIN_SHIFT (0) /* Bits 0-4: GPIO number: 0-28 */
 #define GPIO_PIN_MASK  (0x1f << GPIO_PIN_SHIFT)
-#  define GPIO_PIN0    (0 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN1    (1 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN2    (2 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN3    (3 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN4    (4 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN5    (5 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN6    (6 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN7    (7 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN8    (8 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN9    (9 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN10   (10 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN11   (11 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN12   (12 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN13   (13 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN14   (14 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN15   (15 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN16   (16 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN17   (17 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN18   (18 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN19   (19 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN20   (20 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN21   (21 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN22   (22 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN23   (23 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN24   (24 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN25   (25 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN26   (26 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN27   (27 << GPIO_PIN_SHIFT)
-#  define GPIO_PIN28   (28 << GPIO_PIN_SHIFT)
+#define GPIO_PIN0      (0 << GPIO_PIN_SHIFT)
+#define GPIO_PIN1      (1 << GPIO_PIN_SHIFT)
+#define GPIO_PIN2      (2 << GPIO_PIN_SHIFT)
+#define GPIO_PIN3      (3 << GPIO_PIN_SHIFT)
+#define GPIO_PIN4      (4 << GPIO_PIN_SHIFT)
+#define GPIO_PIN5      (5 << GPIO_PIN_SHIFT)
+#define GPIO_PIN6      (6 << GPIO_PIN_SHIFT)
+#define GPIO_PIN7      (7 << GPIO_PIN_SHIFT)
+#define GPIO_PIN8      (8 << GPIO_PIN_SHIFT)
+#define GPIO_PIN9      (9 << GPIO_PIN_SHIFT)
+#define GPIO_PIN10     (10 << GPIO_PIN_SHIFT)
+#define GPIO_PIN11     (11 << GPIO_PIN_SHIFT)
+#define GPIO_PIN12     (12 << GPIO_PIN_SHIFT)
+#define GPIO_PIN13     (13 << GPIO_PIN_SHIFT)
+#define GPIO_PIN14     (14 << GPIO_PIN_SHIFT)
+#define GPIO_PIN15     (15 << GPIO_PIN_SHIFT)
+#define GPIO_PIN16     (16 << GPIO_PIN_SHIFT)
+#define GPIO_PIN17     (17 << GPIO_PIN_SHIFT)
+#define GPIO_PIN18     (18 << GPIO_PIN_SHIFT)
+#define GPIO_PIN19     (19 << GPIO_PIN_SHIFT)
+#define GPIO_PIN20     (20 << GPIO_PIN_SHIFT)
+#define GPIO_PIN21     (21 << GPIO_PIN_SHIFT)
+#define GPIO_PIN22     (22 << GPIO_PIN_SHIFT)
+#define GPIO_PIN23     (23 << GPIO_PIN_SHIFT)
+#define GPIO_PIN24     (24 << GPIO_PIN_SHIFT)
+#define GPIO_PIN25     (25 << GPIO_PIN_SHIFT)
+#define GPIO_PIN26     (26 << GPIO_PIN_SHIFT)
+#define GPIO_PIN27     (27 << GPIO_PIN_SHIFT)
+#define GPIO_PIN28     (28 << GPIO_PIN_SHIFT)
+
+/* GLB GPIO interrupt trigger mode type definition */
+
+#define GLB_GPIO_INT_TRIG_NEG_PULSE \
+  0 /* GPIO negedge pulse trigger interrupt */
+
+#define GLB_GPIO_INT_TRIG_POS_PULSE \
+  1 /* GPIO posedge pulse trigger interrupt */
+
+#define GLB_GPIO_INT_TRIG_NEG_LEVEL \
+  2 /* GPIO negedge level trigger interrupt (32k 3T) */
+
+#define GLB_GPIO_INT_TRIG_POS_LEVEL \
+  3 /* GPIO posedge level trigger interrupt (32k 3T) */
 
 /****************************************************************************
  * Public Types
@@ -286,8 +300,22 @@ bool bl602_gpioread(gpio_pinset_t pinset);
  *
  ****************************************************************************/
 
-int bl602_gpiosetevent(gpio_pinset_t pinset, bool risingedge,
-                       bool fallingedge, bool event, xcpt_t func, void *arg);
+int bl602_gpiosetevent(gpio_pinset_t pinset,
+                       bool          risingedge,
+                       bool          fallingedge,
+                       bool          event,
+                       xcpt_t        func,
+                       void *        arg);
+
+/****************************************************************************
+ * Name: bl602_gpio_initialize
+ *
+ * Description:
+ *   Initialize GPIO drivers for use with /apps/examples/gpio
+ *
+ ****************************************************************************/
+
+int bl602_gpio_initialize(void);
 
 /****************************************************************************
  * Function:  bl602_dumpgpio
@@ -300,7 +328,7 @@ int bl602_gpiosetevent(gpio_pinset_t pinset, bool risingedge,
 #ifdef CONFIG_DEBUG_GPIO_INFO
 int bl602_dumpgpio(gpio_pinset_t pinset, const char *msg);
 #else
-#  define bl602_dumpgpio(p,m)
+#define bl602_dumpgpio(p, m)
 #endif
 
 #undef EXTERN
diff --git a/arch/risc-v/src/bl602/bl602_i2c.c b/arch/risc-v/src/bl602/bl602_i2c.c
new file mode 100644
index 0000000000..8c06a4ca67
--- /dev/null
+++ b/arch/risc-v/src/bl602/bl602_i2c.c
@@ -0,0 +1,1042 @@
+/****************************************************************************
+ * arch/risc-v/src/bl602/bl602_i2c.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <nuttx/irq.h>
+#include <arch/board/board.h>
+
+#include "chip.h"
+#include "riscv_arch.h"
+
+#include "hardware/bl602_glb.h"
+#include "hardware/bl602_hbn.h"
+#include "hardware/bl602_i2c.h"
+#include "bl602_i2c.h"
+#include "bl602_gpio.h"
+#include "bl602_glb.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#define I2C0 0
+
+#define PUT_UINT32_LE(n, b, i) \
+  { \
+    (b)[(i)]     = (uint8_t)((n)); \
+    (b)[(i) + 1] = (uint8_t)((n) >> 8); \
+    (b)[(i) + 2] = (uint8_t)((n) >> 16); \
+    (b)[(i) + 3] = (uint8_t)((n) >> 24); \
+  }
+
+#define I2C_DEFAULT_FREQUENCY 100000
+
+/* I2C state */
+
+#define EV_I2C_END_INT    0
+#define EV_I2C_TXF_INT    1
+#define EV_I2C_RXF_INT    3
+#define EV_I2C_FER_INT    4
+#define EV_I2C_ARB_INT    5
+#define EV_I2C_NAK_INT    6
+#define EV_I2C_UNKNOW_INT 0xff
+
+/* I2C Device hardware configuration */
+
+struct bl602_i2c_config_s
+{
+  uint32_t reg_base; /* I2C register base address */
+  uint8_t  irq;      /* Interrupt ID */
+  uint32_t clk_freq; /* i2c freq */
+};
+
+/* I2C Device Private Data */
+
+struct bl602_i2c_priv_s
+{
+  const struct i2c_ops_s *ops; /* Standard I2C operations */
+
+  /* Port configuration */
+
+  const struct bl602_i2c_config_s *config;
+
+  uint8_t  subflag;  /* Sub address flag */
+  uint32_t subaddr;  /* Sub address */
+  uint8_t  sublen;   /* Sub address length */
+  sem_t    sem_excl; /* Mutual exclusion semaphore */
+  sem_t    sem_isr;  /* Interrupt wait semaphore */
+
+  /* I2C work state */
+
+  uint8_t i2cstate;
+
+  struct i2c_msg_s *msgv; /* Message list */
+
+  uint8_t msgid; /* Current message ID */
+  ssize_t bytes; /* Processed data bytes */
+  int     refs;  /* Reference count */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int bl602_i2c_transfer(FAR struct i2c_master_s *dev,
+                              FAR struct i2c_msg_s *   msgs,
+                              int                      count);
+
+#ifdef CONFIG_I2C_RESET
+static int bl602_i2c_reset(FAR struct i2c_master_s *dev);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* I2C interface */
+
+static const struct i2c_ops_s bl602_i2c_ops =
+{
+  .transfer = bl602_i2c_transfer,
+#ifdef CONFIG_I2C_RESET
+  .reset = bl602_i2c_reset
+#endif
+};
+
+/* I2C device structures */
+
+#ifdef CONFIG_BL602_I2C0
+static const struct bl602_i2c_config_s bl602_i2c0_config =
+{
+  .reg_base = BL602_I2C_BASE,
+  .irq      = BL602_IRQ_I2C,
+  .clk_freq = I2C_DEFAULT_FREQUENCY,
+};
+
+static struct bl602_i2c_priv_s bl602_i2c0_priv =
+{
+  .ops      = &bl602_i2c_ops,
+  .config   = &bl602_i2c0_config,
+  .subaddr  = 0,
+  .sublen   = 0,
+  .i2cstate = EV_I2C_END_INT,
+  .msgv     = NULL,
+  .msgid    = 0,
+  .bytes    = 0,
+};
+#endif /* CONFIG_BL602_I2C0 */
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl602_i2c_send_data
+ *
+ * Description:
+ *   Send I2C data
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_send_data(FAR struct bl602_i2c_priv_s *priv)
+{
+  uint32_t          temp = 0;
+  uint32_t          val  = 0;
+  int               i;
+  int               count;
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  count = msg->length - priv->bytes;
+  if (count >= 4)
+    {
+      count = 4;
+    }
+
+  for (i = 0; i < count; i++)
+    {
+      val = *(msg->buffer + priv->bytes + i);
+      temp += val << i * 8;
+    }
+
+  putreg32(temp, BL602_I2C_FIFO_WDATA);
+  priv->bytes += count;
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_recvdata
+ *
+ * Description:
+ *   Receive I2C data
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_recvdata(struct bl602_i2c_priv_s *priv)
+{
+  uint32_t          temp = 0;
+  int               i    = 0;
+  int               count;
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  count = msg->length - priv->bytes;
+  temp  = getreg32(BL602_I2C_FIFO_RDATA);
+  if (count >= 4)
+    {
+      PUT_UINT32_LE(temp, msg->buffer, priv->bytes);
+      count = 4;
+    }
+  else if (count < 4)
+    {
+      for (i = 0; i < count; i++)
+        {
+          msg->buffer[priv->bytes + i] = (temp & 0xff);
+          temp                         = (temp >> 8);
+        }
+    }
+
+  priv->bytes += count;
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_sem_init
+ *
+ * Description:
+ *   Initialize semaphores
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_sem_init(FAR struct bl602_i2c_priv_s *priv)
+{
+  nxsem_init(&priv->sem_excl, 0, 1);
+
+  /* This semaphore is used for signaling and, hence, should not have
+   * priority inheritance enabled.
+   */
+
+  nxsem_init(&priv->sem_isr, 0, 1);
+  nxsem_set_protocol(&priv->sem_isr, SEM_PRIO_NONE);
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_clear_status
+ *
+ * Description:
+ *   clear i2c status
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_clear_status(int i2cx)
+{
+  if (i2cx == I2C0)
+    {
+      modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_END_CLR
+              | I2C_INT_STS_CR_NAK_CLR | I2C_INT_STS_CR_ARB_CLR);
+    }
+  else
+    {
+      i2cerr("port error\r\n");
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_config_para
+ *
+ * Description:
+ *   config i2c param
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_config_para(struct bl602_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  if (msg->flags & I2C_M_READ)
+    {
+      modifyreg32(BL602_I2C_CONFIG, 0, I2C_CONFIG_CR_I2C_PKT_DIR);
+    }
+  else
+    {
+      modifyreg32(BL602_I2C_CONFIG, I2C_CONFIG_CR_I2C_PKT_DIR, 0);
+    }
+
+  modifyreg32(BL602_I2C_CONFIG,
+              I2C_CONFIG_CR_I2C_SLV_ADDR_MASK,
+              msg->addr << I2C_CONFIG_CR_I2C_SLV_ADDR_SHIFT);
+  if (priv->subflag > 0)
+    {
+      modifyreg32(BL602_I2C_CONFIG, 0, I2C_CONFIG_CR_I2C_SUB_ADDR_EN);
+      modifyreg32(BL602_I2C_CONFIG,
+                  I2C_CONFIG_CR_I2C_SUB_ADDR_BC_MASK,
+                  (priv->sublen - 1) << I2C_CONFIG_CR_I2C_SUB_ADDR_BC_SHIFT);
+    }
+  else
+    {
+      modifyreg32(BL602_I2C_CONFIG, I2C_CONFIG_CR_I2C_SUB_ADDR_EN, 0);
+    }
+
+  modifyreg32(BL602_I2C_CONFIG,
+              I2C_CONFIG_CR_I2C_PKT_LEN_MASK,
+              (msg->length - 1) << I2C_CONFIG_CR_I2C_PKT_LEN_SHIFT);
+
+  if (priv->subflag > 0)
+    {
+      putreg32(priv->subaddr, BL602_I2C_SUB_ADDR);
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_intmask
+ *
+ * Description:
+ *   Mask/Unmask the I2C interrupt
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_intmask(uint8_t int_type, uint8_t int_mask)
+{
+  switch (int_type)
+    {
+    case I2C_TRANS_END_INT:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_END_EN);
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_END_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_END_EN, 0);
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_END_MASK);
+        }
+      break;
+    case I2C_TX_FIFO_READY_INT:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_TXF_EN);
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_TXF_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_TXF_EN, 0);
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_TXF_MASK);
+        }
+      break;
+    case I2C_RX_FIFO_READY_INT:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_RXF_EN);
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_RXF_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_RXF_EN, 0);
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_RXF_MASK);
+        }
+      break;
+    case I2C_NACK_RECV_INT:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_NAK_EN);
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_NAK_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_NAK_EN, 0);
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_NAK_MASK);
+        }
+      break;
+    case I2C_ARB_LOST_INT:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_ARB_EN);
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_ARB_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_ARB_EN, 0);
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_ARB_MASK);
+        }
+      break;
+    case I2C_FIFO_ERR_INT:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_FER_EN);
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_FER_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_FER_EN, 0);
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_FER_MASK);
+        }
+      break;
+    case I2C_INT_ALL:
+      if (int_mask == 0)
+        {
+          /* UNMASK(Enable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_END_EN
+                  | I2C_INT_STS_CR_TXF_EN | I2C_INT_STS_CR_RXF_EN
+                  | I2C_INT_STS_CR_NAK_EN | I2C_INT_STS_CR_ARB_EN
+                  | I2C_INT_STS_CR_FER_EN);
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_END_MASK
+                  | I2C_INT_STS_CR_TXF_MASK | I2C_INT_STS_CR_RXF_MASK
+                  | I2C_INT_STS_CR_NAK_MASK | I2C_INT_STS_CR_ARB_MASK
+                  | I2C_INT_STS_CR_FER_MASK, 0);
+        }
+      else
+        {
+          /* MASK(Disable) this interrupt */
+
+          modifyreg32(BL602_I2C_INT_STS, I2C_INT_STS_CR_END_EN
+                  | I2C_INT_STS_CR_TXF_EN | I2C_INT_STS_CR_RXF_EN
+                  | I2C_INT_STS_CR_NAK_EN | I2C_INT_STS_CR_ARB_EN
+                  | I2C_INT_STS_CR_FER_EN, 0);
+
+          modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_END_MASK
+                  | I2C_INT_STS_CR_TXF_MASK | I2C_INT_STS_CR_RXF_MASK
+                  | I2C_INT_STS_CR_NAK_MASK | I2C_INT_STS_CR_ARB_MASK
+                  | I2C_INT_STS_CR_FER_MASK);
+        }
+      break;
+
+    default:
+      break;
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_enable
+ *
+ * Description:
+ *   i2c enable
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_enable(void)
+{
+  modifyreg32(BL602_I2C_FIFO_CONFIG_0, 0, I2C_FIFO_CONFIG_0_TX_FIFO_CLR);
+  modifyreg32(BL602_I2C_FIFO_CONFIG_0, 0, I2C_FIFO_CONFIG_0_RX_FIFO_CLR);
+  modifyreg32(BL602_I2C_CONFIG, 0, I2C_CONFIG_CR_I2C_M_EN);
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_transfer_enable
+ *
+ * Description:
+ *   i2c transfer enable
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_transfer_enable(struct bl602_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  if (msg->flags & I2C_M_READ)
+    {
+      bl602_i2c_intmask(I2C_RX_FIFO_READY_INT, 0);
+    }
+  else
+    {
+      bl602_i2c_intmask(I2C_TX_FIFO_READY_INT, 0);
+    }
+
+  bl602_i2c_intmask(I2C_TRANS_END_INT, 0);
+  bl602_i2c_intmask(I2C_FIFO_ERR_INT, 0);
+  bl602_i2c_intmask(I2C_ARB_LOST_INT, 0);
+  bl602_i2c_intmask(I2C_NACK_RECV_INT, 0);
+
+  bl602_i2c_enable();
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_start_transfer
+ *
+ * Description:
+ *   Send I2C start signal
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_start_transfer(FAR struct bl602_i2c_priv_s *priv)
+{
+  bl602_i2c_clear_status(I2C0);
+  bl602_i2c_config_para(priv);
+  bl602_i2c_transfer_enable(priv);
+}
+
+/****************************************************************************
+ * Device Driver Operations
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl602_i2c_setsclsync
+ *
+ * Description:
+ *   set i2c scl sync
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_setsclsync(uint8_t enable)
+{
+  if (enable)
+    {
+      modifyreg32(BL602_I2C_CONFIG, 0, I2C_CONFIG_CR_I2C_SCL_SYNC_EN);
+    }
+  else
+    {
+      modifyreg32(BL602_I2C_CONFIG, I2C_CONFIG_CR_I2C_SCL_SYNC_EN, 0);
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_setprd
+ *
+ * Description:
+ *   set i2c prd
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_setprd(uint8_t phase)
+{
+  modifyreg32(BL602_I2C_PRD_START, I2C_PRD_START_CR_PRD_S_PH_0_MASK, phase);
+  modifyreg32(BL602_I2C_PRD_START,
+              I2C_PRD_START_CR_PRD_S_PH_1_MASK,
+              phase << I2C_PRD_START_CR_PRD_S_PH_1_SHIFT);
+  modifyreg32(BL602_I2C_PRD_START,
+              I2C_PRD_START_CR_PRD_S_PH_2_MASK,
+              phase << I2C_PRD_START_CR_PRD_S_PH_2_SHIFT);
+  modifyreg32(BL602_I2C_PRD_START,
+              I2C_PRD_START_CR_PRD_S_PH_3_MASK,
+              phase << I2C_PRD_START_CR_PRD_S_PH_3_SHIFT);
+
+  modifyreg32(BL602_I2C_PRD_STOP, I2C_PRD_STOP_CR_PRD_P_PH_0_MASK, phase);
+  modifyreg32(BL602_I2C_PRD_STOP,
+              I2C_PRD_STOP_CR_PRD_P_PH_1_MASK,
+              phase << I2C_PRD_STOP_CR_PRD_P_PH_1_SHIFT);
+  modifyreg32(BL602_I2C_PRD_STOP,
+              I2C_PRD_STOP_CR_PRD_P_PH_2_MASK,
+              phase << I2C_PRD_STOP_CR_PRD_P_PH_2_SHIFT);
+  modifyreg32(BL602_I2C_PRD_STOP,
+              I2C_PRD_STOP_CR_PRD_P_PH_3_MASK,
+              phase << I2C_PRD_STOP_CR_PRD_P_PH_3_SHIFT);
+
+  modifyreg32(BL602_I2C_PRD_DATA, I2C_PRD_DATA_CR_PRD_D_PH_0_MASK, phase);
+  modifyreg32(BL602_I2C_PRD_DATA,
+              I2C_PRD_DATA_CR_PRD_D_PH_1_MASK,
+              phase << I2C_PRD_DATA_CR_PRD_D_PH_1_SHIFT);
+  modifyreg32(BL602_I2C_PRD_DATA,
+              I2C_PRD_DATA_CR_PRD_D_PH_2_MASK,
+              phase << I2C_PRD_DATA_CR_PRD_D_PH_2_SHIFT);
+  modifyreg32(BL602_I2C_PRD_DATA,
+              I2C_PRD_DATA_CR_PRD_D_PH_3_MASK,
+              phase << I2C_PRD_DATA_CR_PRD_D_PH_3_SHIFT);
+}
+
+/****************************************************************************
+ * Name: bl602_set_i2c_clk
+ *
+ * Description:
+ *   set I2C clock.
+ *
+ ****************************************************************************/
+
+void bl602_set_i2c_clk(uint8_t enable, uint8_t div)
+{
+  modifyreg32(BL602_CLK_CFG3,
+              CLK_CFG3_I2C_CLK_DIV_MASK,
+              div << CLK_CFG3_I2C_CLK_DIV_SHIFT);
+
+  if (enable)
+    {
+      modifyreg32(BL602_CLK_CFG3, 0, CLK_CFG3_I2C_CLK_EN);
+    }
+  else
+    {
+      modifyreg32(BL602_CLK_CFG3, CLK_CFG3_I2C_CLK_EN, 0);
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_clockset
+ *
+ * Description:
+ *   set i2c clock
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_clockset(uint32_t clk)
+{
+  uint8_t bclk_div = 0;
+  uint32_t sys_clock = 0;
+
+  bclk_div = bl602_glb_get_bclk_div();
+  sys_clock = getreg32(BL602_HBN_RSV2);
+
+  if (clk >= 100000)
+    {
+      bl602_set_i2c_clk(1, 0);
+      bl602_i2c_setprd((sys_clock / (bclk_div + 1)) / (clk * 4) -
+                       1);
+    }
+  else if (clk >= 8000)
+    {
+      bl602_set_i2c_clk(1, 9);
+      bl602_i2c_setprd(
+        ((sys_clock / (bclk_div + 1)) / 10) / (clk * 4) - 1);
+    }
+  else if (clk >= 800)
+    {
+      bl602_set_i2c_clk(1, 99);
+      bl602_i2c_setprd(
+        ((sys_clock / (bclk_div + 1)) / 100) / (clk * 4) - 1);
+    }
+  else
+    {
+      bl602_set_i2c_clk(1, 255);
+      bl602_i2c_setprd(
+        ((sys_clock / (bclk_div + 1)) / 256) / (clk * 4) - 1);
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_set_freq
+ *
+ * Description:
+ *   set i2c freq
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_set_freq(int freq)
+{
+  bl602_i2c_setsclsync(0);
+  bl602_i2c_clockset(freq);
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_transfer
+ *
+ * Description:
+ *   Generic I2C transfer function
+ *
+ ****************************************************************************/
+
+static int bl602_i2c_transfer(FAR struct i2c_master_s *dev,
+                              FAR struct i2c_msg_s *   msgs,
+                              int                      count)
+{
+  int                          i;
+  int                          j;
+  int                          ret  = OK;
+  FAR struct bl602_i2c_priv_s *priv = (FAR struct bl602_i2c_priv_s *)dev;
+
+  if (count <= 0)
+    {
+      i2cerr("count is error\r\n");
+      return -1;
+    }
+
+  ret = nxsem_wait_uninterruptible(&priv->sem_excl);
+  if (ret < 0)
+    {
+      i2cerr("take sem_excl error\r\n");
+      return ret;
+    }
+
+  ret = nxsem_wait_uninterruptible(&priv->sem_isr);
+
+  if (ret < 0)
+    {
+      i2cerr("take sem_irq error\r\n");
+      return ret;
+    }
+
+  priv->msgv = msgs;
+
+  for (i = 0; i < count; i++)
+    {
+      priv->bytes    = 0;
+      priv->i2cstate = EV_I2C_END_INT;
+
+      bl602_i2c_set_freq(msgs[i].frequency);
+
+      /* if msgs[i].flag I2C_M_NOSTOP,means start i2c with subddr */
+
+      if (msgs[i].flags & I2C_M_NOSTOP)
+        {
+          priv->subflag = 1;
+          priv->subaddr = 0;
+          for (j = 0; j < msgs[i].length; j++)
+            {
+              priv->subaddr += msgs[i].buffer[j] << (j * 8);
+            }
+
+          priv->sublen = msgs[i].length;
+          i++;
+        }
+      else
+        {
+          priv->subflag = 0;
+          priv->subaddr = 0;
+          priv->sublen  = 0;
+        }
+
+      priv->msgid = i;
+      bl602_i2c_start_transfer(priv);
+
+      /* wait for transter finished */
+
+      ret = nxsem_wait_uninterruptible(&priv->sem_isr);
+
+      if (ret < 0)
+        {
+          i2cerr("transter error\r\n");
+          return ret;
+        }
+
+      if (priv->i2cstate == EV_I2C_END_INT)
+        {
+          i2cinfo("i2c transfer success\r\n");
+        }
+      else
+        {
+          i2cerr("i2c transfer error, event = %d \r\n", priv->i2cstate);
+        }
+
+      nxsem_post(&priv->sem_isr);
+    }
+
+  nxsem_post(&priv->sem_excl);
+
+  return ret;
+}
+
+/****************************************************************************
+ * Name: bl602_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 bl602_i2c_reset(FAR struct i2c_master_s *dev)
+{
+  FAR struct bl602_i2c_priv_s *priv = (FAR struct bl602_i2c_priv_s *)dev;
+
+  bl602_swrst_ahb_slave1(AHB_SLAVE1_I2C);
+  bl602_i2c_set_freq(priv->config->clk_freq);
+  bl602_i2c_disable();
+  up_enable_irq(BL602_IRQ_I2C);
+  bl602_i2c_intmask(I2C_INT_ALL, 1);
+  priv->i2cstate = EV_I2C_END_INT;
+  priv->msgid    = 0;
+  priv->bytes    = 0;
+
+  return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: bl602_i2c_transferbytes
+ *
+ * Description:
+ *   i2c transfer bytes.
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_transferbytes(struct bl602_i2c_priv_s *priv)
+{
+  struct i2c_msg_s *msg = &priv->msgv[priv->msgid];
+
+  if (msg->flags & I2C_M_READ)
+    {
+      if (priv->i2cstate == EV_I2C_RXF_INT)
+        {
+          if (priv->bytes < msg->length)
+            {
+              bl602_i2c_recvdata(priv);
+            }
+          else if (priv->bytes == msg->length)
+            {
+              bl602_i2c_intmask(I2C_RX_FIFO_READY_INT, 1);
+              return;
+            }
+          else
+            {
+            }
+        }
+    }
+  else
+    {
+      if (priv->i2cstate == EV_I2C_TXF_INT)
+        {
+          if (msg->length > priv->bytes)
+            {
+              bl602_i2c_send_data(priv);
+            }
+          else if (priv->bytes == msg->length)
+            {
+              bl602_i2c_intmask(I2C_TX_FIFO_READY_INT, 1);
+              return;
+            }
+          else
+            {
+            }
+        }
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_disable
+ *
+ * Description:
+ *   disable i2c
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_disable(void)
+{
+  modifyreg32(BL602_I2C_CONFIG, I2C_CONFIG_CR_I2C_M_EN, 0);
+
+  /* Clear I2C fifo */
+
+  modifyreg32(BL602_I2C_FIFO_CONFIG_0, 0, I2C_FIFO_CONFIG_0_TX_FIFO_CLR);
+  modifyreg32(BL602_I2C_FIFO_CONFIG_0, 0, I2C_FIFO_CONFIG_0_RX_FIFO_CLR);
+
+  /* Clear I2C interrupt status */
+
+  modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_END_CLR);
+  modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_NAK_CLR);
+  modifyreg32(BL602_I2C_INT_STS, 0, I2C_INT_STS_CR_ARB_CLR);
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_callback
+ *
+ * Description:
+ *   callback function.
+ *
+ ****************************************************************************/
+
+static void bl602_i2c_callback(struct bl602_i2c_priv_s *priv)
+{
+  bl602_i2c_disable();
+  bl602_i2c_intmask(I2C_INT_ALL, 1);
+  bl602_i2c_clear_status(I2C0);
+  nxsem_post(&priv->sem_isr);
+}
+
+/****************************************************************************
+ * Name: bl602_i2c_irq
+ *
+ * Description:
+ *   This is the common I2C interrupt handler.  It will be invoked
+ *   when an interrupt received on the device.
+ *
+ ****************************************************************************/
+
+static int bl602_i2c_irq(int cpuint, void *context, FAR void *arg)
+{
+  uint32_t tmp_val;
+
+  struct bl602_i2c_priv_s *priv = (struct bl602_i2c_priv_s *)arg;
+
+  tmp_val = getreg32(BL602_I2C_INT_STS);
+
+  if (tmp_val & I2C_INT_STS_RXF_INT)
+    {
+      priv->i2cstate = EV_I2C_RXF_INT;
+    }
+  else if (tmp_val & I2C_INT_STS_END_INT)
+    {
+      priv->i2cstate = EV_I2C_END_INT;
+      bl602_i2c_callback(priv);
+      return 0;
+    }
+  else if (tmp_val & I2C_INT_STS_NAK_INT)
+    {
+      priv->i2cstate = EV_I2C_NAK_INT;
+      bl602_i2c_callback(priv);
+      return -1;
+    }
+  else if (tmp_val & I2C_INT_STS_TXF_INT)
+    {
+      priv->i2cstate = EV_I2C_TXF_INT;
+    }
+  else if (tmp_val & I2C_INT_STS_ARB_INT)
+    {
+      priv->i2cstate = EV_I2C_ARB_INT;
+      bl602_i2c_callback(priv);
+      return -1;
+    }
+  else if (tmp_val & I2C_INT_STS_FER_INT)
+    {
+      priv->i2cstate = EV_I2C_FER_INT;
+      bl602_i2c_callback(priv);
+      return -1;
+    }
+  else
+    {
+      i2cerr("other interrupt \r\n");
+      priv->i2cstate = EV_I2C_UNKNOW_INT;
+      bl602_i2c_callback(priv);
+      return -1;
+    }
+
+  bl602_i2c_transferbytes(priv);
+  return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl602_i2cbus_initialize
+ *
+ * Description:
+ *   Initialize one I2C bus
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *bl602_i2cbus_initialize(int port)
+{
+  irqstate_t                       flags;
+  struct bl602_i2c_priv_s *        priv;
+  const struct bl602_i2c_config_s *config;
+
+  switch (port)
+    {
+#ifdef CONFIG_BL602_I2C0
+    case 0:
+      priv = (struct bl602_i2c_priv_s *)&bl602_i2c0_priv;
+      break;
+#endif
+    default:
+      return NULL;
+    }
+
+  config = priv->config;
+
+  flags = enter_critical_section();
+
+  priv->refs++;
+
+  if (priv->refs > 1)
+  {
+    leave_critical_section(flags);
+    return (struct i2c_master_s *)priv;
+  }
+
+  bl602_configgpio(BOARD_I2C_SCL);
+  bl602_configgpio(BOARD_I2C_SDA);
+
+  bl602_i2c_set_freq(config->clk_freq);
+  bl602_i2c_disable();
+  up_enable_irq(BL602_IRQ_I2C);
+  bl602_i2c_intmask(I2C_INT_ALL, 1);
+  irq_attach(BL602_IRQ_I2C, bl602_i2c_irq, priv);
+  bl602_i2c_sem_init(priv);
+
+  leave_critical_section(flags);
+
+  return (struct i2c_master_s *)priv;
+}
+
+/****************************************************************************
+ * Name: bl602_i2cbus_uninitialize
+ *
+ * Description:
+ *   Uninitialize an I2C bus
+ *
+ ****************************************************************************/
+
+int bl602_i2cbus_uninitialize(FAR struct i2c_master_s *dev)
+{
+  irqstate_t flags;
+  FAR struct bl602_i2c_priv_s *priv = (FAR struct bl602_i2c_priv_s *)dev;
+
+  DEBUGASSERT(dev);
+
+  if (priv->refs == 0)
+    {
+      return ERROR;
+    }
+
+  flags = enter_critical_section();
+
+  if (--priv->refs)
+    {
+      leave_critical_section(flags);
+      return OK;
+    }
+
+  leave_critical_section(flags);
+
+  bl602_swrst_ahb_slave1(AHB_SLAVE1_I2C);
+
+  nxsem_destroy(&priv->sem_excl);
+  nxsem_destroy(&priv->sem_isr);
+
+  return OK;
+}
+
diff --git a/arch/risc-v/src/bl602/bl602_i2c.h b/arch/risc-v/src/bl602/bl602_i2c.h
new file mode 100644
index 0000000000..a2ba836bc8
--- /dev/null
+++ b/arch/risc-v/src/bl602/bl602_i2c.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+ * arch/risc-v/src/bl602/bl602_i2c.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_RISCV_SRC_BL602_BL602_I2C_H
+#define __ARCH_RISCV_SRC_BL602_BL602_I2C_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/i2c/i2c_master.h>
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+#ifndef __ASSEMBLY__
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/****************************************************************************
+ * Public Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl602_i2cbus_initialize
+ *
+ * Description:
+ *   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.
+ *
+ * Input Parameters:
+ *   Port number (for hardware that has multiple I2C interfaces)
+ *
+ * Returned Value:
+ *   Valid I2C device structure reference on success; a NULL on failure
+ *
+ ****************************************************************************/
+
+struct i2c_master_s *bl602_i2cbus_initialize(int port);
+
+/****************************************************************************
+ * Name: bl602_i2cbus_uninitialize
+ *
+ * Description:
+ *   De-initialize the selected I2C port, and power down the device.
+ *
+ * Input Parameters:
+ *   Device structure as returned by the bl602_i2cbus_initialize()
+ *
+ * Returned Value:
+ *   OK on success, ERROR when internal reference count mismatch or dev
+ *   points to invalid hardware device.
+ *
+ ****************************************************************************/
+
+int bl602_i2cbus_uninitialize(FAR struct i2c_master_s *dev);
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ARCH_RISCV_SRC_BL602_BL602_HBN_H */
diff --git a/arch/risc-v/src/bl602/hardware/bl602_i2c.h b/arch/risc-v/src/bl602/hardware/bl602_i2c.h
index d2fefcf8d1..4efa7ea02a 100644
--- a/arch/risc-v/src/bl602/hardware/bl602_i2c.h
+++ b/arch/risc-v/src/bl602/hardware/bl602_i2c.h
@@ -48,28 +48,36 @@
 
 /* Register definitions *****************************************************/
 
-#define BL602_I2C_CONFIG         (BL602_I2C_BASE + BL602_I2C_CONFIG_OFFSET)
-#define BL602_I2C_INT_STS        (BL602_I2C_BASE + BL602_I2C_INT_STS_OFFSET)
-#define BL602_I2C_SUB_ADDR       (BL602_I2C_BASE + BL602_I2C_SUB_ADDR_OFFSET)
-#define BL602_I2C_BUS_BUSY       (BL602_I2C_BASE + BL602_I2C_BUS_BUSY_OFFSET)
-#define BL602_I2C_PRD_START      (BL602_I2C_BASE + BL602_I2C_PRD_START_OFFSET)
-#define BL602_I2C_PRD_STOP       (BL602_I2C_BASE + BL602_I2C_PRD_STOP_OFFSET)
-#define BL602_I2C_PRD_DATA       (BL602_I2C_BASE + BL602_I2C_PRD_DATA_OFFSET)
-#define BL602_I2C_FIFO_CONFIG_0  (BL602_I2C_BASE + BL602_I2C_FIFO_CONFIG_0_OFFSET)
-#define BL602_I2C_FIFO_CONFIG_1  (BL602_I2C_BASE + BL602_I2C_FIFO_CONFIG_1_OFFSET)
-#define BL602_I2C_FIFO_WDATA     (BL602_I2C_BASE + BL602_I2C_FIFO_WDATA_OFFSET)
-#define BL602_I2C_FIFO_RDATA     (BL602_I2C_BASE + BL602_I2C_FIFO_RDATA_OFFSET)
+#define BL602_I2C_CONFIG     (BL602_I2C_BASE + BL602_I2C_CONFIG_OFFSET)
+#define BL602_I2C_INT_STS    (BL602_I2C_BASE + BL602_I2C_INT_STS_OFFSET)
+#define BL602_I2C_SUB_ADDR   (BL602_I2C_BASE + BL602_I2C_SUB_ADDR_OFFSET)
+#define BL602_I2C_BUS_BUSY   (BL602_I2C_BASE + BL602_I2C_BUS_BUSY_OFFSET)
+#define BL602_I2C_PRD_START  (BL602_I2C_BASE + BL602_I2C_PRD_START_OFFSET)
+#define BL602_I2C_PRD_STOP   (BL602_I2C_BASE + BL602_I2C_PRD_STOP_OFFSET)
+#define BL602_I2C_PRD_DATA   (BL602_I2C_BASE + BL602_I2C_PRD_DATA_OFFSET)
+#define BL602_I2C_FIFO_CONFIG_0  \
+          (BL602_I2C_BASE + BL602_I2C_FIFO_CONFIG_0_OFFSET)
+#define BL602_I2C_FIFO_CONFIG_1  \
+          (BL602_I2C_BASE + BL602_I2C_FIFO_CONFIG_1_OFFSET)
+#define BL602_I2C_FIFO_WDATA     \
+          (BL602_I2C_BASE + BL602_I2C_FIFO_WDATA_OFFSET)
+#define BL602_I2C_FIFO_RDATA     \
+          (BL602_I2C_BASE + BL602_I2C_FIFO_RDATA_OFFSET)
 
 /* Register bit definitions *************************************************/
 
 #define I2C_CONFIG_CR_I2C_DEG_CNT_SHIFT        (28)
-#define I2C_CONFIG_CR_I2C_DEG_CNT_MASK         (0x0f << I2C_CONFIG_CR_I2C_DEG_CNT_SHIFT)
+#define I2C_CONFIG_CR_I2C_DEG_CNT_MASK         \
+          (0x0f << I2C_CONFIG_CR_I2C_DEG_CNT_SHIFT)
 #define I2C_CONFIG_CR_I2C_PKT_LEN_SHIFT        (16)
-#define I2C_CONFIG_CR_I2C_PKT_LEN_MASK         (0xff << I2C_CONFIG_CR_I2C_PKT_LEN_SHIFT)
+#define I2C_CONFIG_CR_I2C_PKT_LEN_MASK         \
+          (0xff << I2C_CONFIG_CR_I2C_PKT_LEN_SHIFT)
 #define I2C_CONFIG_CR_I2C_SLV_ADDR_SHIFT       (8)
-#define I2C_CONFIG_CR_I2C_SLV_ADDR_MASK        (0x7f << I2C_CONFIG_CR_I2C_SLV_ADDR_SHIFT)
+#define I2C_CONFIG_CR_I2C_SLV_ADDR_MASK        \
+          (0x7f << I2C_CONFIG_CR_I2C_SLV_ADDR_SHIFT)
 #define I2C_CONFIG_CR_I2C_SUB_ADDR_BC_SHIFT    (5)
-#define I2C_CONFIG_CR_I2C_SUB_ADDR_BC_MASK     (0x03 << I2C_CONFIG_CR_I2C_SUB_ADDR_BC_SHIFT)
+#define I2C_CONFIG_CR_I2C_SUB_ADDR_BC_MASK     \
+          (0x03 << I2C_CONFIG_CR_I2C_SUB_ADDR_BC_SHIFT)
 #define I2C_CONFIG_CR_I2C_SUB_ADDR_EN          (1 << 4)
 #define I2C_CONFIG_CR_I2C_SCL_SYNC_EN          (1 << 3)
 #define I2C_CONFIG_CR_I2C_DEG_EN               (1 << 2)
@@ -102,38 +110,50 @@
 #define I2C_INT_STS_END_INT                    (1 << 0)
 
 #define I2C_SUB_ADDR_CR_SUB_ADDR_B3_SHIFT  (24)
-#define I2C_SUB_ADDR_CR_SUB_ADDR_B3_MASK   (0xff << I2C_SUB_ADDR_CR_SUB_ADDR_B3_SHIFT)
+#define I2C_SUB_ADDR_CR_SUB_ADDR_B3_MASK   \
+          (0xff << I2C_SUB_ADDR_CR_SUB_ADDR_B3_SHIFT)
 #define I2C_SUB_ADDR_CR_SUB_ADDR_B2_SHIFT  (16)
-#define I2C_SUB_ADDR_CR_SUB_ADDR_B2_MASK   (0xff << I2C_SUB_ADDR_CR_SUB_ADDR_B2_SHIFT)
+#define I2C_SUB_ADDR_CR_SUB_ADDR_B2_MASK   \
+          (0xff << I2C_SUB_ADDR_CR_SUB_ADDR_B2_SHIFT)
 #define I2C_SUB_ADDR_CR_SUB_ADDR_B1_SHIFT  (8)
-#define I2C_SUB_ADDR_CR_SUB_ADDR_B1_MASK   (0xff << I2C_SUB_ADDR_CR_SUB_ADDR_B1_SHIFT)
+#define I2C_SUB_ADDR_CR_SUB_ADDR_B1_MASK   \
+          (0xff << I2C_SUB_ADDR_CR_SUB_ADDR_B1_SHIFT)
 #define I2C_SUB_ADDR_CR_SUB_ADDR_B0_MASK   (0xff)
 
 #define I2C_BUS_BUSY_CR_BUS_BUSY_CLR       (1 << 1)
 #define I2C_BUS_BUSY_STS_BUS_BUSY          (1 << 0)
 
 #define I2C_PRD_START_CR_PRD_S_PH_3_SHIFT  (24)
-#define I2C_PRD_START_CR_PRD_S_PH_3_MASK   (0xff << I2C_PRD_START_CR_PRD_S_PH_3_SHIFT)
+#define I2C_PRD_START_CR_PRD_S_PH_3_MASK   \
+          (0xff << I2C_PRD_START_CR_PRD_S_PH_3_SHIFT)
 #define I2C_PRD_START_CR_PRD_S_PH_2_SHIFT  (16)
-#define I2C_PRD_START_CR_PRD_S_PH_2_MASK   (0xff << I2C_PRD_START_CR_PRD_S_PH_2_SHIFT)
+#define I2C_PRD_START_CR_PRD_S_PH_2_MASK   \
+          (0xff << I2C_PRD_START_CR_PRD_S_PH_2_SHIFT)
 #define I2C_PRD_START_CR_PRD_S_PH_1_SHIFT  (8)
-#define I2C_PRD_START_CR_PRD_S_PH_1_MASK   (0xff << I2C_PRD_START_CR_PRD_S_PH_1_SHIFT)
+#define I2C_PRD_START_CR_PRD_S_PH_1_MASK   \
+          (0xff << I2C_PRD_START_CR_PRD_S_PH_1_SHIFT)
 #define I2C_PRD_START_CR_PRD_S_PH_0_MASK   (0xff)
 
 #define I2C_PRD_STOP_CR_PRD_P_PH_3_SHIFT   (24)
-#define I2C_PRD_STOP_CR_PRD_P_PH_3_MASK    (0xff << I2C_PRD_STOP_CR_PRD_P_PH_3_SHIFT)
+#define I2C_PRD_STOP_CR_PRD_P_PH_3_MASK    \
+          (0xff << I2C_PRD_STOP_CR_PRD_P_PH_3_SHIFT)
 #define I2C_PRD_STOP_CR_PRD_P_PH_2_SHIFT   (16)
-#define I2C_PRD_STOP_CR_PRD_P_PH_2_MASK    (0xff << I2C_PRD_STOP_CR_PRD_P_PH_2_SHIFT)
+#define I2C_PRD_STOP_CR_PRD_P_PH_2_MASK    \
+          (0xff << I2C_PRD_STOP_CR_PRD_P_PH_2_SHIFT)
 #define I2C_PRD_STOP_CR_PRD_P_PH_1_SHIFT   (8)
-#define I2C_PRD_STOP_CR_PRD_P_PH_1_MASK    (0xff << I2C_PRD_STOP_CR_PRD_P_PH_1_SHIFT)
+#define I2C_PRD_STOP_CR_PRD_P_PH_1_MASK    \
+          (0xff << I2C_PRD_STOP_CR_PRD_P_PH_1_SHIFT)
 #define I2C_PRD_STOP_CR_PRD_P_PH_0_MASK    (0xff)
 
 #define I2C_PRD_DATA_CR_PRD_D_PH_3_SHIFT   (24)
-#define I2C_PRD_DATA_CR_PRD_D_PH_3_MASK    (0xff << I2C_PRD_DATA_CR_PRD_D_PH_3_SHIFT)
+#define I2C_PRD_DATA_CR_PRD_D_PH_3_MASK    \
+          (0xff << I2C_PRD_DATA_CR_PRD_D_PH_3_SHIFT)
 #define I2C_PRD_DATA_CR_PRD_D_PH_2_SHIFT   (16)
-#define I2C_PRD_DATA_CR_PRD_D_PH_2_MASK    (0xff << I2C_PRD_DATA_CR_PRD_D_PH_2_SHIFT)
+#define I2C_PRD_DATA_CR_PRD_D_PH_2_MASK    \
+          (0xff << I2C_PRD_DATA_CR_PRD_D_PH_2_SHIFT)
 #define I2C_PRD_DATA_CR_PRD_D_PH_1_SHIFT   (8)
-#define I2C_PRD_DATA_CR_PRD_D_PH_1_MASK    (0xff << I2C_PRD_DATA_CR_PRD_D_PH_1_SHIFT)
+#define I2C_PRD_DATA_CR_PRD_D_PH_1_MASK    \
+          (0xff << I2C_PRD_DATA_CR_PRD_D_PH_1_SHIFT)
 #define I2C_PRD_DATA_CR_PRD_D_PH_0_MASK    (0xff)
 
 #define I2C_FIFO_CONFIG_0_RX_FIFO_UNDERFLOW    (1 << 7)
@@ -148,7 +168,22 @@
 #define I2C_FIFO_CONFIG_1_RX_FIFO_TH           (1 << 24)
 #define I2C_FIFO_CONFIG_1_TX_FIFO_TH           (1 << 16)
 #define I2C_FIFO_CONFIG_1_RX_FIFO_CNT_SHIFT    (8)
-#define I2C_FIFO_CONFIG_1_RX_FIFO_CNT_MASK     (0x03 << I2C_FIFO_CONFIG_1_RX_FIFO_CNT_SHIFT)
+#define I2C_FIFO_CONFIG_1_RX_FIFO_CNT_MASK    \
+          (0x03 << I2C_FIFO_CONFIG_1_RX_FIFO_CNT_SHIFT)
 #define I2C_FIFO_CONFIG_1_TX_FIFO_CNT_MASK     (0x03)
 
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/* I2C interrupt type definition */
+
+#define I2C_TRANS_END_INT     0 /* I2C transfer end interrupt */
+#define I2C_TX_FIFO_READY_INT 1 /* I2C TX fifo ready interrupt */
+#define I2C_RX_FIFO_READY_INT 2 /* I2C RX fifo ready interrupt */
+#define I2C_NACK_RECV_INT     3 /* I2C nack received interrupt */
+#define I2C_ARB_LOST_INT      4 /* I2C arbitration lost interrupt */
+#define I2C_FIFO_ERR_INT      5 /* I2C TX/RX FIFO error interrupt */
+#define I2C_INT_ALL           6 /* I2C interrupt all type */
+
 #endif /* __ARCH_RISCV_SRC_BL602_HARDWARE_BL602_I2C_H */
diff --git a/boards/risc-v/bl602/bl602evb/configs/gpio/defconfig b/boards/risc-v/bl602/bl602evb/configs/gpio/defconfig
new file mode 100644
index 0000000000..14381d8b17
--- /dev/null
+++ b/boards/risc-v/bl602/bl602evb/configs/gpio/defconfig
@@ -0,0 +1,77 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_NSH_DISABLEBG is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_NSH_DISABLE_UNAME is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="bl602evb"
+CONFIG_ARCH_BOARD_BL602EVB=y
+CONFIG_ARCH_CHIP="bl602"
+CONFIG_ARCH_CHIP_BL602=y
+CONFIG_ARCH_INTERRUPTSTACK=8192
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BINFMT_DISABLE=y
+CONFIG_BL602_HAVE_UART0=y
+CONFIG_BL602_TIMER0=y
+CONFIG_BOARD_LOOPSPERMSEC=10000
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEFAULT_SMALL=y
+CONFIG_DEV_GPIO=y
+CONFIG_DEV_ZERO=y
+CONFIG_DISABLE_MQUEUE=y
+CONFIG_EXAMPLES_GPIO=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_EXAMPLES_HELLO_STACKSIZE=8192
+CONFIG_EXAMPLES_TIMER=y
+CONFIG_FS_PROCFS=y
+CONFIG_IDLETHREAD_STACKSIZE=8192
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MAX_TASKS=8
+CONFIG_NFILE_DESCRIPTORS=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_DISABLE_CD=y
+CONFIG_NSH_DISABLE_CP=y
+CONFIG_NSH_DISABLE_IFUPDOWN=y
+CONFIG_NSH_DISABLE_MKDIR=y
+CONFIG_NSH_DISABLE_RM=y
+CONFIG_NSH_DISABLE_RMDIR=y
+CONFIG_NSH_DISABLE_UMOUNT=y
+CONFIG_NSH_FILEIOSIZE=64
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_PTHREAD_STACK_DEFAULT=8192
+CONFIG_RAM_SIZE=134217728
+CONFIG_RAM_START=0xc0800000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_RV32IM_CUSTOM_IRQ_SUPPORT=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=20
+CONFIG_START_MONTH=3
+CONFIG_START_YEAR=2020
+CONFIG_STDIO_DISABLE_BUFFERING=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=12
+CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=8192
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TIMER=y
+CONFIG_TIMER_ARCH=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_RXBUFSIZE=128
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_UART0_TXBUFSIZE=128
+CONFIG_USERMAIN_STACKSIZE=8192
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/risc-v/bl602/bl602evb/configs/i2c/defconfig b/boards/risc-v/bl602/bl602evb/configs/i2c/defconfig
new file mode 100644
index 0000000000..1542c50414
--- /dev/null
+++ b/boards/risc-v/bl602/bl602evb/configs/i2c/defconfig
@@ -0,0 +1,78 @@
+#
+# This file is autogenerated: PLEASE DO NOT EDIT IT.
+#
+# You can use "make menuconfig" to make any modifications to the installed .config file.
+# You can then do "make savedefconfig" to generate a new defconfig file that includes your
+# modifications.
+#
+# CONFIG_NSH_DISABLEBG is not set
+# CONFIG_NSH_DISABLE_LOSMART is not set
+# CONFIG_NSH_DISABLE_UNAME is not set
+CONFIG_ARCH="risc-v"
+CONFIG_ARCH_BOARD="bl602evb"
+CONFIG_ARCH_BOARD_BL602EVB=y
+CONFIG_ARCH_CHIP="bl602"
+CONFIG_ARCH_CHIP_BL602=y
+CONFIG_ARCH_INTERRUPTSTACK=8192
+CONFIG_ARCH_RISCV=y
+CONFIG_ARCH_STACKDUMP=y
+CONFIG_BINFMT_DISABLE=y
+CONFIG_BL602_HAVE_UART0=y
+CONFIG_BL602_I2C0=y
+CONFIG_BL602_TIMER0=y
+CONFIG_BOARD_LOOPSPERMSEC=10000
+CONFIG_BUILTIN=y
+CONFIG_DEBUG_FEATURES=y
+CONFIG_DEBUG_FULLOPT=y
+CONFIG_DEBUG_SYMBOLS=y
+CONFIG_DEFAULT_SMALL=y
+CONFIG_DEV_ZERO=y
+CONFIG_DISABLE_MQUEUE=y
+CONFIG_EXAMPLES_HELLO=y
+CONFIG_EXAMPLES_HELLO_STACKSIZE=8192
+CONFIG_EXAMPLES_TIMER=y
+CONFIG_FS_PROCFS=y
+CONFIG_I2C=y
+CONFIG_IDLETHREAD_STACKSIZE=8192
+CONFIG_INTELHEX_BINARY=y
+CONFIG_LIBC_PERROR_STDOUT=y
+CONFIG_LIBC_STRERROR=y
+CONFIG_MAX_TASKS=8
+CONFIG_NFILE_DESCRIPTORS=6
+CONFIG_NSH_ARCHINIT=y
+CONFIG_NSH_BUILTIN_APPS=y
+CONFIG_NSH_DISABLE_CD=y
+CONFIG_NSH_DISABLE_CP=y
+CONFIG_NSH_DISABLE_IFUPDOWN=y
+CONFIG_NSH_DISABLE_MKDIR=y
+CONFIG_NSH_DISABLE_RM=y
+CONFIG_NSH_DISABLE_RMDIR=y
+CONFIG_NSH_DISABLE_UMOUNT=y
+CONFIG_NSH_FILEIOSIZE=64
+CONFIG_NSH_STRERROR=y
+CONFIG_PREALLOC_TIMERS=0
+CONFIG_PTHREAD_STACK_DEFAULT=8192
+CONFIG_RAM_SIZE=134217728
+CONFIG_RAM_START=0xc0800000
+CONFIG_RAW_BINARY=y
+CONFIG_RR_INTERVAL=200
+CONFIG_RV32IM_CUSTOM_IRQ_SUPPORT=y
+CONFIG_SCHED_WAITPID=y
+CONFIG_STACK_COLORATION=y
+CONFIG_START_DAY=20
+CONFIG_START_MONTH=3
+CONFIG_START_YEAR=2020
+CONFIG_STDIO_DISABLE_BUFFERING=y
+CONFIG_SYSTEM_I2CTOOL=y
+CONFIG_SYSTEM_NSH=y
+CONFIG_TASK_NAME_SIZE=12
+CONFIG_TASK_SPAWN_DEFAULT_STACKSIZE=8192
+CONFIG_TESTING_GETPRIME=y
+CONFIG_TIMER=y
+CONFIG_TIMER_ARCH=y
+CONFIG_UART0_BAUD=2000000
+CONFIG_UART0_RXBUFSIZE=128
+CONFIG_UART0_SERIAL_CONSOLE=y
+CONFIG_UART0_TXBUFSIZE=128
+CONFIG_USERMAIN_STACKSIZE=8192
+CONFIG_USER_ENTRYPOINT="nsh_main"
diff --git a/boards/risc-v/bl602/bl602evb/include/board.h b/boards/risc-v/bl602/bl602evb/include/board.h
index 3be40822e8..9c7fed6363 100644
--- a/boards/risc-v/bl602/bl602evb/include/board.h
+++ b/boards/risc-v/bl602/bl602evb/include/board.h
@@ -33,20 +33,47 @@
  * Pre-processor Definitions
  ****************************************************************************/
 
+/* GPIO Configuration */
+
+#define BOARD_NGPIOIN     1 /* Amount of GPIO Input pins */
+#define BOARD_NGPIOOUT    1 /* Amount of GPIO Output pins */
+#define BOARD_NGPIOINT    1 /* Amount of GPIO Input w/ Interruption pins */
+
+#define BOARD_GPIO_IN1    (GPIO_INPUT | GPIO_PULLUP | \
+                            GPIO_FUNC_SWGPIO | GPIO_PIN0)
+#define BOARD_GPIO_OUT1   (GPIO_OUTPUT | GPIO_PULLDOWN | \
+                            GPIO_FUNC_SWGPIO | GPIO_PIN1)
+#define BOARD_GPIO_INT1   (GPIO_INPUT | GPIO_PULLUP | \
+                            GPIO_FUNC_SWGPIO | GPIO_PIN2)
+
 /* UART Configuration */
 
-#define BOARD_UART_0_RX_PIN (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_UART | GPIO_PIN7)
-#define BOARD_UART_0_TX_PIN (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_UART | GPIO_PIN16)
-#define BOARD_UART_1_RX_PIN (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_UART | GPIO_PIN3)
-#define BOARD_UART_1_TX_PIN (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_UART | GPIO_PIN4)
+#define BOARD_UART_0_RX_PIN (GPIO_INPUT | GPIO_PULLUP | \
+                              GPIO_FUNC_UART | GPIO_PIN7)
+#define BOARD_UART_0_TX_PIN (GPIO_INPUT | GPIO_PULLUP | \
+                              GPIO_FUNC_UART | GPIO_PIN16)
+#define BOARD_UART_1_RX_PIN (GPIO_INPUT | GPIO_PULLUP | \
+                              GPIO_FUNC_UART | GPIO_PIN3)
+#define BOARD_UART_1_TX_PIN (GPIO_INPUT | GPIO_PULLUP | \
+                              GPIO_FUNC_UART | GPIO_PIN4)
 
 /* PWM Configuration */
 
-#define BOARD_PWM_CH0_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | GPIO_FUNC_PWM | GPIO_PIN0)
-#define BOARD_PWM_CH1_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | GPIO_FUNC_PWM | GPIO_PIN1)
-#define BOARD_PWM_CH2_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | GPIO_FUNC_PWM | GPIO_PIN2)
-#define BOARD_PWM_CH3_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | GPIO_FUNC_PWM | GPIO_PIN3)
-#define BOARD_PWM_CH4_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | GPIO_FUNC_PWM | GPIO_PIN4)
+#define BOARD_PWM_CH0_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | \
+                            GPIO_FUNC_PWM | GPIO_PIN0)
+#define BOARD_PWM_CH1_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | \
+                            GPIO_FUNC_PWM | GPIO_PIN1)
+#define BOARD_PWM_CH2_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | \
+                            GPIO_FUNC_PWM | GPIO_PIN2)
+#define BOARD_PWM_CH3_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | \
+                            GPIO_FUNC_PWM | GPIO_PIN3)
+#define BOARD_PWM_CH4_PIN (GPIO_OUTPUT | GPIO_PULLDOWN | \
+                            GPIO_FUNC_PWM | GPIO_PIN4)
+
+/* I2C Configuration */
+
+#define BOARD_I2C_SCL (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_I2C | GPIO_PIN4)
+#define BOARD_I2C_SDA (GPIO_INPUT | GPIO_PULLUP | GPIO_FUNC_I2C | GPIO_PIN3)
 
 /****************************************************************************
  * Public Types
diff --git a/boards/risc-v/bl602/bl602evb/src/Makefile b/boards/risc-v/bl602/bl602evb/src/Makefile
index 5b9a2bce22..cc663263ac 100644
--- a/boards/risc-v/bl602/bl602evb/src/Makefile
+++ b/boards/risc-v/bl602/bl602evb/src/Makefile
@@ -25,8 +25,12 @@ CSRCS  = bl602_bringup.c bl602_boot.c
 ifeq ($(CONFIG_LIB_BOARDCTL),y)
 CSRCS += bl602_appinit.c
 ifeq ($(CONFIG_BOARDCTL_RESET),y)
-  CSRCS += bl602_reset.c
+CSRCS += bl602_reset.c
 endif
 endif
 
+ifeq ($(CONFIG_DEV_GPIO),y)
+CSRCS += bl602_gpio.c
+endif
+
 include $(TOPDIR)/boards/Board.mk
diff --git a/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c b/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c
index 5a441dbe63..cbbb3a3b2c 100644
--- a/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c
+++ b/boards/risc-v/bl602/bl602evb/src/bl602_bringup.c
@@ -38,6 +38,8 @@
 #include <bl602_oneshot_lowerhalf.h>
 #include <bl602_pwm_lowerhalf.h>
 #include <bl602_wdt_lowerhalf.h>
+#include <bl602_gpio.h>
+#include <bl602_i2c.h>
 
 #if defined(CONFIG_BL602_SPIFLASH)
 #include <bl602_spiflash.h>
@@ -62,6 +64,9 @@ int bl602_bringup(void)
 #if defined(CONFIG_BL602_SPIFLASH)
   FAR struct mtd_dev_s *mtd_part = NULL;
   const char *path = "/dev/mtdflash";
+#endif
+#ifdef CONFIG_I2C
+  struct i2c_master_s *i2c_bus;
 #endif
   int ret = OK;
 
@@ -149,6 +154,20 @@ int bl602_bringup(void)
     }
 #endif
 
+#ifdef CONFIG_DEV_GPIO
+  ret = bl602_gpio_initialize();
+  if (ret < 0)
+    {
+      syslog(LOG_ERR, "Failed to initialize GPIO Driver: %d\n", ret);
+      return ret;
+    }
+#endif
+
+#ifdef CONFIG_I2C
+  i2c_bus = bl602_i2cbus_initialize(0);
+  i2c_register(i2c_bus, 0);
+#endif
+
 #ifdef CONFIG_BL602_SPIFLASH
   mtd_part = bl602_spiflash_alloc_mtdpart();
 
diff --git a/boards/risc-v/bl602/bl602evb/src/bl602_gpio.c b/boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
new file mode 100644
index 0000000000..66d55a01ee
--- /dev/null
+++ b/boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
@@ -0,0 +1,607 @@
+/****************************************************************************
+ * board/risc-v/bl602/bl602evb/src/bl602_gpio.c
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <debug.h>
+#include <nuttx/arch.h>
+#include <nuttx/ioexpander/gpio.h>
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+#include "bl602_gpio.h"
+
+#if defined(CONFIG_DEV_GPIO) && !defined(CONFIG_GPIO_LOWER_HALF)
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define BOARD_GPIO_PIN(mode, pupd, func, pin) (mode | pupd | func | pin)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct bl602_gpio_dev_s
+{
+  struct gpio_dev_s gpio;
+  uint8_t           id;
+};
+
+struct bl602_gpint_dev_s
+{
+  struct bl602_gpio_dev_s bl602gpio;
+  pin_interrupt_t         callback;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int gpin_read(FAR struct gpio_dev_s *dev, FAR bool *value);
+static int gpout_read(FAR struct gpio_dev_s *dev, FAR bool *value);
+static int gpout_write(FAR struct gpio_dev_s *dev, bool value);
+static int gpint_read(FAR struct gpio_dev_s *dev, FAR bool *value);
+static int gpint_attach(FAR struct gpio_dev_s *dev,
+                        pin_interrupt_t callback);
+static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable);
+static int gpio_setpintype(FAR struct gpio_dev_s *dev,
+                           enum gpio_pintype_e    gp_pintype);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct gpio_operations_s gpin_ops =
+{
+  .go_read       = gpin_read,
+  .go_write      = NULL,
+  .go_attach     = NULL,
+  .go_enable     = NULL,
+  .go_setpintype = gpio_setpintype,
+};
+
+static const struct gpio_operations_s gpout_ops =
+{
+  .go_read       = gpout_read,
+  .go_write      = gpout_write,
+  .go_attach     = NULL,
+  .go_enable     = NULL,
+  .go_setpintype = gpio_setpintype,
+};
+
+static const struct gpio_operations_s gpint_ops =
+{
+  .go_read       = gpint_read,
+  .go_write      = NULL,
+  .go_attach     = gpint_attach,
+  .go_enable     = gpint_enable,
+  .go_setpintype = gpio_setpintype,
+};
+
+#if BOARD_NGPIOIN > 0
+/* This array maps the GPIO pins used as INPUT */
+
+static const uint32_t g_gpioinputs[BOARD_NGPIOIN] =
+{
+  BOARD_GPIO_IN1,
+};
+
+static struct bl602_gpio_dev_s g_gpin[BOARD_NGPIOIN];
+#endif
+
+#if BOARD_NGPIOOUT
+/* This array maps the GPIO pins used as OUTPUT */
+
+static const uint32_t g_gpiooutputs[BOARD_NGPIOOUT] =
+{
+  BOARD_GPIO_OUT1,
+};
+
+static struct bl602_gpio_dev_s g_gpout[BOARD_NGPIOOUT];
+#endif
+
+#if BOARD_NGPIOINT > 0
+/* This array maps the GPIO pins used as INTERRUPT INPUTS */
+
+static const uint32_t g_gpiointinputs[BOARD_NGPIOINT] =
+{
+  BOARD_GPIO_INT1,
+};
+
+static struct bl602_gpint_dev_s g_gpint[BOARD_NGPIOINT];
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: bl602_gpio_intmask
+ *
+ * Description:
+ *   intmask a gpio pin.
+ *
+ ****************************************************************************/
+
+static void bl602_gpio_intmask(int pin, int intmask)
+{
+  uint32_t tmp_val;
+
+  if (pin < 28)
+    {
+      tmp_val = getreg32(BL602_GPIO_INT_MASK1);
+      if (intmask == 1)
+        {
+          tmp_val |= (1 << pin);
+        }
+      else
+        {
+          tmp_val &= ~(1 << pin);
+        }
+
+      putreg32(tmp_val, BL602_GPIO_INT_MASK1);
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_gpio_set_intmod
+ *
+ * Description:
+ *   set gpio intmod.
+ *
+ ****************************************************************************/
+
+static void bl602_gpio_set_intmod(uint8_t gpio_pin,
+              uint8_t int_ctlmod, uint8_t int_trgmod)
+{
+  uint32_t tmp_val;
+
+  if (gpio_pin < GPIO_PIN10)
+    {
+      /* GPIO0 ~ GPIO9 */
+
+      tmp_val = gpio_pin;
+      modifyreg32(BL602_GPIO_INT_MODE_SET1,
+                  0x7 << (3 * tmp_val),
+                  ((int_ctlmod << 2) | int_trgmod) << (3 * tmp_val));
+    }
+  else if (gpio_pin < GPIO_PIN20)
+    {
+      /* GPIO10 ~ GPIO19 */
+
+      tmp_val = gpio_pin - GPIO_PIN10;
+      modifyreg32(BL602_GPIO_INT_MODE_SET2,
+                  0x7 << (3 * tmp_val),
+                  ((int_ctlmod << 2) | int_trgmod) << (3 * tmp_val));
+    }
+  else
+    {
+      /* GPIO20 ~ GPIO29 */
+
+      tmp_val = gpio_pin - GPIO_PIN20;
+      modifyreg32(BL602_GPIO_INT_MODE_SET3,
+                  0x7 << (3 * tmp_val),
+                  ((int_ctlmod << 2) | int_trgmod) << (3 * tmp_val));
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_gpio_get_intstatus
+ *
+ * Description:
+ *   get gpio intstatus.
+ *
+ ****************************************************************************/
+
+static int bl602_gpio_get_intstatus(uint8_t gpio_pin)
+{
+  uint32_t tmp_val = 0;
+
+  if (gpio_pin < 28)
+    {
+      /* GPIO0 ~ GPIO27 */
+
+      tmp_val = getreg32(BL602_GPIO_INT_STAT1);
+    }
+
+  return (tmp_val & (1 << gpio_pin)) ? 1 : 0;
+}
+
+/****************************************************************************
+ * Name: bl602_gpio_intclear
+ *
+ * Description:
+ *   clear gpio int.
+ *
+ ****************************************************************************/
+
+static void bl602_gpio_intclear(uint8_t gpio_pin, uint8_t int_clear)
+{
+  if (gpio_pin < 28)
+    {
+      /* GPIO0 ~ GPIO27 */
+
+      modifyreg32(BL602_GPIO_INT_CLR1,
+                  int_clear ? 0 : (1 << gpio_pin),
+                  int_clear ? (1 << gpio_pin) : 0);
+    }
+}
+
+/****************************************************************************
+ * Name: bl602_gpio_interrupt
+ *
+ * Description:
+ *   gpio interrupt.
+ *
+ ****************************************************************************/
+
+static int bl602_gpio_interrupt(int irq, void *context, void *arg)
+{
+  FAR struct bl602_gpint_dev_s *bl602xgpint =
+    (FAR struct bl602_gpint_dev_s *)arg;
+
+  uint32_t time_out = 0;
+  uint8_t gpio_pin;
+
+  DEBUGASSERT(bl602xgpint != NULL && bl602xgpint->callback != NULL);
+  gpioinfo("Interrupt! callback=%p\n", bl602xgpint->callback);
+
+  gpio_pin = (g_gpiointinputs[bl602xgpint->bl602gpio.id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+
+  if (1 == bl602_gpio_get_intstatus(gpio_pin))
+    {
+      bl602_gpio_intclear(gpio_pin, 1);
+
+      /* timeout check */
+
+      time_out = 32;
+      do
+        {
+          time_out--;
+        }
+      while ((1 == bl602_gpio_get_intstatus(gpio_pin)) && time_out);
+      if (!time_out)
+        {
+          printf("WARNING: Clear GPIO interrupt status fail.\r\n");
+        }
+
+      /* if time_out==0, GPIO interrupt status not cleared */
+
+      bl602_gpio_intclear(gpio_pin, 0);
+    }
+
+  bl602xgpint->callback(&bl602xgpint->bl602gpio.gpio,
+                        gpio_pin);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpio_setpintype
+ *
+ * Description:
+ *   set gpio pintype.
+ *
+ ****************************************************************************/
+
+static int gpio_setpintype(FAR struct gpio_dev_s *dev,
+                           enum gpio_pintype_e    gp_pintype)
+{
+  FAR struct bl602_gpint_dev_s *bl602xgpint =
+    (FAR struct bl602_gpint_dev_s *)dev;
+  uint8_t gpio_pin;
+  uint8_t pintype = bl602xgpint->bl602gpio.gpio.gp_pintype;
+
+  DEBUGASSERT(bl602xgpint != NULL);
+  gpioinfo("setpintype...\n");
+
+  if (pintype <= GPIO_INPUT_PIN_PULLDOWN)
+    {
+      gpio_pin =
+        (g_gpioinputs[bl602xgpint->bl602gpio.id] & GPIO_PIN_MASK) >>
+        GPIO_PIN_SHIFT;
+    }
+  else if (pintype <= GPIO_OUTPUT_PIN_OPENDRAIN)
+    {
+      gpio_pin =
+        (g_gpiooutputs[bl602xgpint->bl602gpio.id] & GPIO_PIN_MASK) >>
+        GPIO_PIN_SHIFT;
+    }
+  else if (pintype < GPIO_NPINTYPES)
+    {
+      gpio_pin =
+        (g_gpiointinputs[bl602xgpint->bl602gpio.id] & GPIO_PIN_MASK) >>
+        GPIO_PIN_SHIFT;
+    }
+  else
+    {
+      printf("pintype error\r\n");
+      return -1;
+    }
+
+  switch (gp_pintype)
+    {
+    case GPIO_INPUT_PIN:
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_INPUT, GPIO_FLOAT, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    case GPIO_INPUT_PIN_PULLUP:
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_INPUT, GPIO_PULLUP, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    case GPIO_INPUT_PIN_PULLDOWN:
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_INPUT, GPIO_PULLDOWN, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    case GPIO_OUTPUT_PIN:
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_OUTPUT, GPIO_PULLUP, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    case GPIO_OUTPUT_PIN_OPENDRAIN:
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_OUTPUT, GPIO_FLOAT, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    case GPIO_INTERRUPT_RISING_PIN:
+      bl602_gpio_set_intmod(gpio_pin, 1, GLB_GPIO_INT_TRIG_POS_PULSE);
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_INPUT, GPIO_PULLUP, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    case GPIO_INTERRUPT_FALLING_PIN:
+      bl602_gpio_set_intmod(gpio_pin, 1, GLB_GPIO_INT_TRIG_NEG_PULSE);
+      bl602_configgpio(
+      BOARD_GPIO_PIN(GPIO_INPUT, GPIO_PULLUP, GPIO_FUNC_SWGPIO, gpio_pin));
+      break;
+    default:
+      break;
+    }
+
+  return 0;
+}
+
+/****************************************************************************
+ * Name: gpin_read
+ *
+ * Description:
+ *   read gpio input.
+ *
+ ****************************************************************************/
+
+static int gpin_read(FAR struct gpio_dev_s *dev, FAR bool *value)
+{
+  FAR struct bl602_gpio_dev_s *bl602xgpio =
+    (FAR struct bl602_gpio_dev_s *)dev;
+
+  DEBUGASSERT(bl602xgpio != NULL && value != NULL);
+  gpioinfo("Reading...\n");
+  *value            = bl602_gpioread(g_gpioinputs[bl602xgpio->id]);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpout_read
+ *
+ * Description:
+ *   read gpio output.
+ *
+ ****************************************************************************/
+
+static int gpout_read(FAR struct gpio_dev_s *dev, FAR bool *value)
+{
+  FAR struct bl602_gpio_dev_s *bl602xgpio =
+    (FAR struct bl602_gpio_dev_s *)dev;
+
+  DEBUGASSERT(bl602xgpio != NULL && value != NULL);
+  DEBUGASSERT(bl602xgpio->id < BOARD_NGPIOOUT);
+  gpioinfo("Reading...\n");
+
+  uint8_t gpio_pin = (g_gpiooutputs[bl602xgpio->id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+
+  *value = (getreg32(BL602_GPIO_CFGCTL32) & (1 << gpio_pin) ? 1 : 0);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpout_write
+ *
+ * Description:
+ *   write gpio.
+ *
+ ****************************************************************************/
+
+static int gpout_write(FAR struct gpio_dev_s *dev, bool value)
+{
+  FAR struct bl602_gpio_dev_s *bl602xgpio =
+    (FAR struct bl602_gpio_dev_s *)dev;
+
+  DEBUGASSERT(bl602xgpio != NULL);
+  DEBUGASSERT(bl602xgpio->id < BOARD_NGPIOOUT);
+  gpioinfo("Writing %d\n", (int)value);
+
+  bl602_gpiowrite(g_gpiooutputs[bl602xgpio->id], value);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpint_read
+ *
+ * Description:
+ *   read gpio.
+ *
+ ****************************************************************************/
+
+static int gpint_read(FAR struct gpio_dev_s *dev, FAR bool *value)
+{
+  FAR struct bl602_gpint_dev_s *bl602xgpint =
+    (FAR struct bl602_gpint_dev_s *)dev;
+
+  DEBUGASSERT(bl602xgpint != NULL && value != NULL);
+  DEBUGASSERT(bl602xgpint->bl602xgpio.id < BOARD_NGPIOINT);
+  gpioinfo("Reading int pin...\n");
+
+  *value = bl602_gpioread(g_gpiointinputs[bl602xgpint->bl602gpio.id]);
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpint_attach
+ *
+ * Description:
+ *   gpio attach.
+ *
+ ****************************************************************************/
+
+static int gpint_attach(FAR struct gpio_dev_s *dev, pin_interrupt_t callback)
+{
+  FAR struct bl602_gpint_dev_s *bl602xgpint =
+    (FAR struct bl602_gpint_dev_s *)dev;
+
+  uint8_t gpio_pin =
+    (g_gpiointinputs[bl602xgpint->bl602gpio.id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  gpioinfo("Attaching the callback\n");
+
+  /* Make sure the interrupt is disabled */
+
+  bl602xgpint->callback = callback;
+  bl602_gpio_intmask(gpio_pin, 1);
+
+  irq_attach(BL602_IRQ_GPIO_INT0, bl602_gpio_interrupt, dev);
+  bl602_gpio_intmask(gpio_pin, 0);
+
+  gpioinfo("Attach %p\n", callback);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: gpint_enable
+ *
+ * Description:
+ *   gpint enable.
+ *
+ ****************************************************************************/
+
+static int gpint_enable(FAR struct gpio_dev_s *dev, bool enable)
+{
+  FAR struct bl602_gpint_dev_s *bl602xgpint =
+    (FAR struct bl602_gpint_dev_s *)dev;
+
+  if (enable)
+    {
+      if (bl602xgpint->callback != NULL)
+        {
+          gpioinfo("Enabling the interrupt\n");
+          up_enable_irq(BL602_IRQ_GPIO_INT0);
+        }
+    }
+  else
+    {
+      gpioinfo("Disable the interrupt\n");
+      up_disable_irq(BL602_IRQ_GPIO_INT0);
+    }
+
+  return OK;
+}
+
+/****************************************************************************
+ * Name: bl602_gpio_initialize
+ *
+ * Description:
+ *   Initialize GPIO drivers for use with /apps/examples/gpio
+ *
+ ****************************************************************************/
+
+int bl602_gpio_initialize(void)
+{
+  int i;
+  int pincount = 0;
+
+#if BOARD_NGPIOIN > 0
+  for (i = 0; i < BOARD_NGPIOIN; i++)
+    {
+      /* Setup and register the GPIO pin */
+
+      g_gpin[i].gpio.gp_pintype = GPIO_INPUT_PIN;
+      g_gpin[i].gpio.gp_ops     = &gpin_ops;
+      g_gpin[i].id              = i;
+      gpio_pin_register(&g_gpin[i].gpio, pincount);
+
+      /* Configure the pin that will be used as input */
+
+      bl602_configgpio(g_gpioinputs[i]);
+
+      pincount++;
+    }
+#endif
+
+#if BOARD_NGPIOOUT > 0
+  for (i = 0; i < BOARD_NGPIOOUT; i++)
+    {
+      /* Setup and register the GPIO pin */
+
+      g_gpout[i].gpio.gp_pintype = GPIO_OUTPUT_PIN;
+      g_gpout[i].gpio.gp_ops     = &gpout_ops;
+      g_gpout[i].id              = i;
+      gpio_pin_register(&g_gpout[i].gpio, pincount);
+
+      /* Configure the pin that will be used as output */
+
+      bl602_configgpio(g_gpiooutputs[i]);
+
+      pincount++;
+    }
+#endif
+
+#if BOARD_NGPIOINT > 0
+  for (i = 0; i < BOARD_NGPIOINT; i++)
+    {
+      /* Setup and register the GPIO pin */
+
+      g_gpint[i].bl602gpio.gpio.gp_pintype = GPIO_INTERRUPT_PIN;
+      g_gpint[i].bl602gpio.gpio.gp_ops     = &gpint_ops;
+      g_gpint[i].bl602gpio.id              = i;
+      gpio_pin_register(&g_gpint[i].bl602gpio.gpio, pincount);
+
+      /* Configure the pin that will be used as interrupt input */
+
+      bl602_gpio_set_intmod(
+        g_gpiointinputs[i], 1, GLB_GPIO_INT_TRIG_NEG_PULSE);
+      bl602_configgpio(g_gpiointinputs[i]);
+
+      pincount++;
+    }
+#endif
+
+  return 0;
+}
+#endif /* CONFIG_DEV_GPIO && !CONFIG_GPIO_LOWER_HALF */