You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2021/01/12 12:59:08 UTC

[GitHub] [incubator-nuttx] liangzhanggb opened a new pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

liangzhanggb opened a new pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669


   ## Summary
   arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.
   
   ## Impact
   
   ## Testing
   config:
   boards/risc-v/bl602/bl602evb/configs/gpio/defconfig
   boards/risc-v/bl602/bl602evb/configs/i2c/defconfig
   
   test gpio:
   gpio /dev/gpin0
   gpio -o 0 /dev/gpout1
   gpio -o 1/dev/gpout1
   gpio -w 1 /dev/gpint2
   
   test i2c:(support master, not support slave)
   i2c set -a50 -r09 -f500 33
   i2c get -a50 -r09
   
   ## References:
   https://github.com/apache/incubator-nuttx/pull/2637  @btashton 
   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] btashton commented on pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
btashton commented on pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#issuecomment-759148952


   @liangzhanggb let's go with yours it's more complete. Maybe we can coordinate more on other drivers. 


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] liangzhanggb commented on a change in pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
liangzhanggb commented on a change in pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#discussion_r556390285



##########
File path: boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
##########
@@ -0,0 +1,648 @@
+/****************************************************************************
+ * 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;
+  uint32_t *p   = (uint32_t *)(BL602_GPIO_CFGCTL32 + ((gpio_pin >> 5) << 2));
+  uint32_t  pos = gpio_pin % 32;
+
+  if ((*p) & (1 << pos))
+    {
+      *value = 1;
+    }
+  else
+    {
+      *value = 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);
+
+  uint8_t gpio_pin = (g_gpiooutputs[bl602xgpio->id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  uint32_t *p_out    = (uint32_t *)(BL602_GPIO_CFGCTL32 +
+                        ((gpio_pin >> 5) << 2));
+  uint32_t  pos      = gpio_pin % 32;

Review comment:
       I have fixed it ,Thanks.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] yamt commented on pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
yamt commented on pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#issuecomment-759288719


   please avoid using non-ascii characters in the commit message. ("、")


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] btashton merged pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
btashton merged pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] liangzhanggb commented on pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
liangzhanggb commented on pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#issuecomment-759146262


   > @liangzhanggb I will look but I had already created a WIP PR for i2c and last night was testing the rest of the full implementation. It would be nice to not be duplicating work.
   
   Great, thank you very much, I am going to close my i2c_drv PR, and then create a gpio_drv PR


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] liangzhanggb commented on a change in pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
liangzhanggb commented on a change in pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#discussion_r557015114



##########
File path: arch/risc-v/src/bl602/bl602_i2c.c
##########
@@ -0,0 +1,1049 @@
+/****************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+
+#include "hardware/bl602_i2c.h"
+#include "hardware/bl602_glb.h"
+#include "bl602_gpio.h"
+#include "bl602_i2c.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 SYS_TEMCORE_CLOCK_GET (*((volatile uint32_t *)(0x4000F108)))
+
+/* 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 = 500,
+};
+
+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
+    {
+      printf("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;
+
+  bclk_div = bl602_glb_get_bclk_div();
+  if (clk >= 100000)
+    {
+      bl602_set_i2c_clk(1, 0);
+      bl602_i2c_setprd((SYS_TEMCORE_CLOCK_GET / (bclk_div + 1)) / (clk * 4) -
+                       1);
+    }
+  else if (clk >= 8000)

Review comment:
       BL602 I2c clk Ranges: 305Hz~3MHz
   
   100~400K, test pass( use device)
   
   3MHz, test pass (use oscilloscope )




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] btashton commented on pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
btashton commented on pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#issuecomment-760324290


   @liangzhanggb Let's merge this in, we can make some more improvements later.  


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] liangzhanggb closed pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
liangzhanggb closed pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669


   


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] liangzhanggb commented on a change in pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
liangzhanggb commented on a change in pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#discussion_r556389708



##########
File path: arch/risc-v/src/bl602/bl602_i2c.c
##########
@@ -0,0 +1,1049 @@
+/****************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+
+#include "hardware/bl602_i2c.h"
+#include "hardware/bl602_glb.h"
+#include "bl602_gpio.h"
+#include "bl602_i2c.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 SYS_TEMCORE_CLOCK_GET (*((volatile uint32_t *)(0x4000F108)))
+
+/* 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 = 500,

Review comment:
       I have fixed it ,Thanks.
   
   arch/risc-v/src/bl602/bl602_i2c.c
   #define I2C_DEFAULT_FREQUENCY 100000




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] btashton commented on a change in pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
btashton commented on a change in pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#discussion_r555922429



##########
File path: arch/risc-v/src/bl602/bl602_i2c.c
##########
@@ -0,0 +1,1049 @@
+/****************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+
+#include "hardware/bl602_i2c.h"
+#include "hardware/bl602_glb.h"
+#include "bl602_gpio.h"
+#include "bl602_i2c.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 SYS_TEMCORE_CLOCK_GET (*((volatile uint32_t *)(0x4000F108)))

Review comment:
       This is already defined.  Just update the name in the hardware header file.

##########
File path: arch/risc-v/src/bl602/bl602_glb.c
##########
@@ -25,15 +25,15 @@
 #include <nuttx/config.h>
 
 #include <stdint.h>
-
+#include <stdio.h>

Review comment:
       Should not be needed in here.

##########
File path: boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
##########
@@ -0,0 +1,648 @@
+/****************************************************************************
+ * 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;
+  uint32_t *p   = (uint32_t *)(BL602_GPIO_CFGCTL32 + ((gpio_pin >> 5) << 2));
+  uint32_t  pos = gpio_pin % 32;
+
+  if ((*p) & (1 << pos))
+    {
+      *value = 1;
+    }
+  else
+    {
+      *value = 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);
+
+  uint8_t gpio_pin = (g_gpiooutputs[bl602xgpio->id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  uint32_t *p_out    = (uint32_t *)(BL602_GPIO_CFGCTL32 +
+                        ((gpio_pin >> 5) << 2));
+  uint32_t  pos      = gpio_pin % 32;
+  uint32_t  tmp_out;
+
+  tmp_out = *p_out;

Review comment:
       Looks like you could just drop tmp_out and pos and just call modify on p_out

##########
File path: boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
##########
@@ -0,0 +1,648 @@
+/****************************************************************************
+ * 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;
+  uint32_t *p   = (uint32_t *)(BL602_GPIO_CFGCTL32 + ((gpio_pin >> 5) << 2));
+  uint32_t  pos = gpio_pin % 32;
+
+  if ((*p) & (1 << pos))
+    {
+      *value = 1;
+    }
+  else
+    {
+      *value = 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);
+
+  uint8_t gpio_pin = (g_gpiooutputs[bl602xgpio->id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  uint32_t *p_out    = (uint32_t *)(BL602_GPIO_CFGCTL32 +
+                        ((gpio_pin >> 5) << 2));
+  uint32_t  pos      = gpio_pin % 32;

Review comment:
       Why is this modulo 32?

##########
File path: boards/risc-v/bl602/bl602evb/src/bl602_bringup.c
##########
@@ -149,6 +151,23 @@ 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 
+  ret = bl602_i2cbus_initialize(0);

Review comment:
       Can you also hook in the i2ctool support here (you can see it in my PR).  Makes it easier to do testing.

##########
File path: arch/risc-v/src/bl602/bl602_i2c.c
##########
@@ -0,0 +1,1049 @@
+/****************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+
+#include "hardware/bl602_i2c.h"
+#include "hardware/bl602_glb.h"
+#include "bl602_gpio.h"
+#include "bl602_i2c.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 SYS_TEMCORE_CLOCK_GET (*((volatile uint32_t *)(0x4000F108)))
+
+/* 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 = 500,
+};
+
+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
+    {
+      printf("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;
+
+  bclk_div = bl602_glb_get_bclk_div();
+  if (clk >= 100000)
+    {
+      bl602_set_i2c_clk(1, 0);
+      bl602_i2c_setprd((SYS_TEMCORE_CLOCK_GET / (bclk_div + 1)) / (clk * 4) -
+                       1);
+    }
+  else if (clk >= 8000)
+    {
+      bl602_set_i2c_clk(1, 9);
+      bl602_i2c_setprd(
+        ((SYS_TEMCORE_CLOCK_GET / (bclk_div + 1)) / 10) / (clk * 4) - 1);
+    }
+  else if (clk >= 800)
+    {
+      bl602_set_i2c_clk(1, 99);
+      bl602_i2c_setprd(
+        ((SYS_TEMCORE_CLOCK_GET / (bclk_div + 1)) / 100) / (clk * 4) - 1);
+    }
+  else
+    {
+      bl602_set_i2c_clk(1, 255);
+      bl602_i2c_setprd(
+        ((SYS_TEMCORE_CLOCK_GET / (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)
+    {
+      printf("count is error\r\n");

Review comment:
       Use `i2c(err,warn,info)` functions

##########
File path: arch/risc-v/src/bl602/bl602_i2c.c
##########
@@ -0,0 +1,1049 @@
+/****************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+
+#include "hardware/bl602_i2c.h"
+#include "hardware/bl602_glb.h"
+#include "bl602_gpio.h"
+#include "bl602_i2c.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 SYS_TEMCORE_CLOCK_GET (*((volatile uint32_t *)(0x4000F108)))
+
+/* 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 = 500,

Review comment:
       Why 500Hz?

##########
File path: boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
##########
@@ -0,0 +1,648 @@
+/****************************************************************************
+ * 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;
+  uint32_t *p   = (uint32_t *)(BL602_GPIO_CFGCTL32 + ((gpio_pin >> 5) << 2));
+  uint32_t  pos = gpio_pin % 32;
+
+  if ((*p) & (1 << pos))
+    {
+      *value = 1;
+    }
+  else
+    {
+      *value = 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);
+
+  uint8_t gpio_pin = (g_gpiooutputs[bl602xgpio->id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  uint32_t *p_out    = (uint32_t *)(BL602_GPIO_CFGCTL32 +
+                        ((gpio_pin >> 5) << 2));
+  uint32_t  pos      = gpio_pin % 32;
+  uint32_t  tmp_out;
+
+  tmp_out = *p_out;

Review comment:
       This block should be locked to protect the modify operation.

##########
File path: boards/risc-v/bl602/bl602evb/src/bl602_gpio.c
##########
@@ -0,0 +1,648 @@
+/****************************************************************************
+ * 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;
+  uint32_t *p   = (uint32_t *)(BL602_GPIO_CFGCTL32 + ((gpio_pin >> 5) << 2));
+  uint32_t  pos = gpio_pin % 32;
+
+  if ((*p) & (1 << pos))
+    {
+      *value = 1;
+    }
+  else
+    {
+      *value = 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);
+
+  uint8_t gpio_pin = (g_gpiooutputs[bl602xgpio->id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  uint32_t *p_out    = (uint32_t *)(BL602_GPIO_CFGCTL32 +
+                        ((gpio_pin >> 5) << 2));
+  uint32_t  pos      = gpio_pin % 32;
+  uint32_t  tmp_out;
+
+  tmp_out = *p_out;
+  if (value > 0)
+    {
+      tmp_out |= (1 << pos);
+    }
+  else
+    {
+      tmp_out &= (~(1 << pos));
+    }
+
+  *p_out = tmp_out;
+
+  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;
+  uint8_t   gpio_pin;
+  uint32_t  pos;
+  uint32_t tmp_val;
+
+  DEBUGASSERT(bl602xgpint != NULL && value != NULL);
+  DEBUGASSERT(bl602xgpint->bl602xgpio.id < BOARD_NGPIOINT);
+  gpioinfo("Reading int pin...\n");
+
+  gpio_pin = (g_gpiointinputs[bl602xgpint->bl602gpio.id] & GPIO_PIN_MASK) >>
+    GPIO_PIN_SHIFT;
+  tmp_val = getreg32(BL602_GPIO_CFGCTL30 + ((gpio_pin >> 5) << 2));
+  pos = gpio_pin % 32;

Review comment:
       Why the % 32?

##########
File path: arch/risc-v/src/bl602/bl602_i2c.c
##########
@@ -0,0 +1,1049 @@
+/****************************************************************************
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <time.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/clock.h>
+#include <nuttx/semaphore.h>
+#include <nuttx/i2c/i2c_master.h>
+
+#include <arch/board/board.h>
+#include "riscv_arch.h"
+
+#include "hardware/bl602_i2c.h"
+#include "hardware/bl602_glb.h"
+#include "bl602_gpio.h"
+#include "bl602_i2c.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 SYS_TEMCORE_CLOCK_GET (*((volatile uint32_t *)(0x4000F108)))
+
+/* 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 = 500,
+};
+
+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
+    {
+      printf("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;
+
+  bclk_div = bl602_glb_get_bclk_div();
+  if (clk >= 100000)
+    {
+      bl602_set_i2c_clk(1, 0);
+      bl602_i2c_setprd((SYS_TEMCORE_CLOCK_GET / (bclk_div + 1)) / (clk * 4) -
+                       1);
+    }
+  else if (clk >= 8000)

Review comment:
       Why are we supporting these lower frequencies?  I am not aware of an i2c device that operates so slow.  Usually you just have 100k 400k and some special devices that can go up to 5MHz




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [incubator-nuttx] btashton commented on pull request #2669: arch/risc-v/bl602 : add gpioirq、 i2c(master) driver.

Posted by GitBox <gi...@apache.org>.
btashton commented on pull request #2669:
URL: https://github.com/apache/incubator-nuttx/pull/2669#issuecomment-758741254


   @liangzhanggb I will look but I had already created a WIP PR for i2c and last night was testing the rest of the full implementation. It would be nice to not be duplicating work.


----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org