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

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

commit da6a682abca3231d5ccd51703fba2860edb3641e
Author: dongjiuzhu1 <[email protected]>
AuthorDate: Mon Oct 20 15:48:22 2025 +0800

    drivers/i2c: add ioexpander-based lower-half implementation for I2C bit-bang
    
    This commit adds a new lower-half driver implementation for I2C bit-bang
    that uses IO expander pins as the GPIO backend, enabling I2C bit-bang
    functionality on systems where direct GPIO access is not available or
    when I2C needs to be implemented using IO expander pins.
    
    Background:
    The existing I2C bit-bang driver (i2c_bitbang.c) provides a generic
    upper-half implementation that requires a platform-specific lower-half
    to control the SDA and SCL GPIO lines. Previously, each platform had to
    implement its own lower-half using direct GPIO access.
    
    Usage Example:
    FAR struct ioexpander_dev_s *ioe = /* get IO expander */;
    FAR struct i2c_master_s *i2c;
    
    /* Initialize I2C bit-bang using IO expander pins 10 (SCL) and 11 (SDA) */
    i2c = i2c_bitbang_ioexpander_initialize(ioe, 10, 11, 0);
    if (i2c)
      {
        /* Use i2c master device normally */
      }
    
    Signed-off-by: dongjiuzhu1 <[email protected]>
---
 drivers/i2c/CMakeLists.txt                 |   5 +
 drivers/i2c/Kconfig                        |   7 +
 drivers/i2c/Make.defs                      |   5 +
 drivers/i2c/i2c_bitbang_ioexpander.c       | 276 +++++++++++++++++++++++++++++
 include/nuttx/i2c/i2c_bitbang_ioexpander.h |  60 +++++++
 5 files changed, 353 insertions(+)

diff --git a/drivers/i2c/CMakeLists.txt b/drivers/i2c/CMakeLists.txt
index 3b97aa78744..e882fae1ab8 100644
--- a/drivers/i2c/CMakeLists.txt
+++ b/drivers/i2c/CMakeLists.txt
@@ -29,6 +29,11 @@ if(CONFIG_I2C)
 
   if(CONFIG_I2C_BITBANG)
     list(APPEND SRCS i2c_bitbang.c)
+
+    if(CONFIG_I2C_BITBANG_IOEXPANDER)
+      list(APPEND SRCS i2c_bitbang_ioexpander.c)
+    endif()
+
   endif()
 
   if(CONFIG_I2C_SLAVE_DRIVER)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index dfa74af883c..a68f64c1584 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -112,6 +112,13 @@ config I2C_BITBANG_CLOCK_STRETCHING
                the pin into open-collector mode (master sets SCL high and 
waits until
                slave stops holding it low).
 
+config I2C_BITBANG_IOEXPANDER
+       bool "Support the ioexpander lower half of i2c bitbang"
+       default n
+       depends on IOEXPANDER
+       ---help---
+               Using ioexpander to control gpio to implement i2c bitbang 
function.
+
 endif # I2C_BITBANG
 
 config I2C_DRIVER
diff --git a/drivers/i2c/Make.defs b/drivers/i2c/Make.defs
index 059dbd3cd2e..5d7e276493b 100644
--- a/drivers/i2c/Make.defs
+++ b/drivers/i2c/Make.defs
@@ -32,6 +32,11 @@ endif
 
 ifeq ($(CONFIG_I2C_BITBANG),y)
 CSRCS += i2c_bitbang.c
+
+ifeq ($(CONFIG_I2C_BITBANG_IOEXPANDER),y)
+CSRCS += i2c_bitbang_ioexpander.c
+endif
+
 endif
 
 ifeq ($(CONFIG_I2C_SLAVE_DRIVER),y)
diff --git a/drivers/i2c/i2c_bitbang_ioexpander.c 
b/drivers/i2c/i2c_bitbang_ioexpander.c
new file mode 100644
index 00000000000..b5fcf46a2f8
--- /dev/null
+++ b/drivers/i2c/i2c_bitbang_ioexpander.c
@@ -0,0 +1,276 @@
+/****************************************************************************
+ * drivers/i2c/i2c_bitbang_ioexpander.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 <assert.h>
+#include <debug.h>
+#include <stdbool.h>
+
+#include <nuttx/kmalloc.h>
+#include <nuttx/i2c/i2c_bitbang.h>
+#include <nuttx/i2c/i2c_bitbang_ioexpander.h>
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct i2c_bb_ioe_s
+{
+  struct i2c_bitbang_lower_dev_s lower;
+  FAR struct ioexpander_dev_s *ioe;
+  int sda_pin;
+  int scl_pin;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static void i2c_bb_ioe_init(FAR struct i2c_bitbang_lower_dev_s *lower);
+static void i2c_bb_ioe_set_scl(FAR struct i2c_bitbang_lower_dev_s *lower,
+                               bool value);
+static void i2c_bb_ioe_set_sda(FAR struct i2c_bitbang_lower_dev_s *lower,
+                               bool value);
+static bool i2c_bb_ioe_get_scl(FAR struct i2c_bitbang_lower_dev_s *lower);
+static bool i2c_bb_ioe_get_sda(FAR struct i2c_bitbang_lower_dev_s *lower);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Lower-half I2C bitbang data */
+
+const static struct i2c_bitbang_lower_ops_s g_i2c_bitbang_ops =
+{
+  .initialize = i2c_bb_ioe_init,
+  .set_scl    = i2c_bb_ioe_set_scl,
+  .set_sda    = i2c_bb_ioe_set_sda,
+  .get_scl    = i2c_bb_ioe_get_scl,
+  .get_sda    = i2c_bb_ioe_get_sda
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_bb_ioe_init
+ *
+ * Description:
+ *   Initialize the I2C bit-bang driver
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of
+ *           the "lower-half" driver state structure.
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void i2c_bb_ioe_init(FAR struct i2c_bitbang_lower_dev_s *lower)
+{
+  FAR struct i2c_bb_ioe_s *dev = lower->priv;
+
+  IOEXP_WRITEPIN(dev->ioe, dev->scl_pin, 1);
+  IOEXP_WRITEPIN(dev->ioe, dev->sda_pin, 1);
+
+  IOEXP_SETDIRECTION(dev->ioe, dev->scl_pin,
+                     IOEXPANDER_DIRECTION_OUT_OPENDRAIN);
+  IOEXP_SETDIRECTION(dev->ioe, dev->sda_pin,
+                     IOEXPANDER_DIRECTION_OUT_OPENDRAIN);
+}
+
+/****************************************************************************
+ * Name: i2c_bb_ioe_set_scl
+ *
+ * Description:
+ *   Set SCL line value
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of
+ *           the "lower-half" driver state structure.
+ *   value - The value to be written (0 or 1).
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void i2c_bb_ioe_set_scl(FAR struct i2c_bitbang_lower_dev_s *lower,
+                               bool value)
+{
+  FAR struct i2c_bb_ioe_s *dev = lower->priv;
+
+  IOEXP_WRITEPIN(dev->ioe, dev->scl_pin, value);
+}
+
+/****************************************************************************
+ * Name: i2c_bb_ioe_set_sda
+ *
+ * Description:
+ *   Set SDA line value
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of
+ *           the "lower-half" driver state structure.
+ *   value - The value to be written (0 or 1).
+ *
+ * Returned Value:
+ *   None
+ *
+ ****************************************************************************/
+
+static void i2c_bb_ioe_set_sda(FAR struct i2c_bitbang_lower_dev_s *lower,
+                               bool value)
+{
+  FAR struct i2c_bb_ioe_s *dev = lower->priv;
+
+  IOEXP_WRITEPIN(dev->ioe, dev->sda_pin, value);
+}
+
+/****************************************************************************
+ * Name: i2c_bb_ioe_get_scl
+ *
+ * Description:
+ *   Get value from SCL line
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of
+ *           the "lower-half" driver state structure.
+ *
+ * Returned Value:
+ *   The boolean representation of the SCL line value (true/false).
+ *
+ ****************************************************************************/
+
+static bool i2c_bb_ioe_get_scl(FAR struct i2c_bitbang_lower_dev_s *lower)
+{
+  FAR struct i2c_bb_ioe_s *dev = lower->priv;
+  bool value = true;
+  int ret;
+
+  ret = IOEXP_READPIN(dev->ioe, dev->scl_pin, &value);
+  if (ret < 0)
+    {
+      i2cerr("read scl pin:%d, error res:%d\n", dev->scl_pin, ret);
+    }
+
+  return value;
+}
+
+/****************************************************************************
+ * Name: i2c_bb_ioe_get_sda
+ *
+ * Description:
+ *   Get value from SDA line
+ *
+ * Input Parameters:
+ *   lower - A pointer the publicly visible representation of
+ *           the "lower-half" driver state structure.
+ *
+ * Returned Value:
+ *   The boolean representation of the SDA line value (true/false).
+ *
+ ****************************************************************************/
+
+static bool i2c_bb_ioe_get_sda(FAR struct i2c_bitbang_lower_dev_s *lower)
+{
+  FAR struct i2c_bb_ioe_s *dev = lower->priv;
+  bool value = true;
+  int ret;
+
+  ret = IOEXP_READPIN(dev->ioe, dev->sda_pin, &value);
+  if (ret < 0)
+    {
+      i2cerr("read sda pin:%d, error res:%d\n", dev->sda_pin, ret);
+    }
+
+  return value;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_bitbang_ioexpander_initialize
+ *
+ * Description:
+ *   Initialize i2c bitbang ioexapnder lower half driver.
+ *
+ * Input Parameters:
+ *  ioe     - An instance of the ioexpander device to use for bitbanging
+ *  scl_pin - The pin number to use for SCL
+ *  sda_pin - The pin number to use for SDA
+ *  busnum  - The I2C bus number to register
+ *
+ *  Returned Value:
+ *  On success, a pointer to the initialized I2C driver for the specified.
+ *
+ ****************************************************************************/
+
+FAR struct i2c_master_s *
+i2c_bitbang_ioexpander_initialize(FAR struct ioexpander_dev_s *ioe,
+                                  int scl_pin, int sda_pin, int busnum)
+{
+  FAR struct i2c_master_s *master = NULL;
+  FAR struct i2c_bb_ioe_s *priv;
+
+  priv = kmm_zalloc(sizeof(struct i2c_bb_ioe_s));
+  if (priv == NULL)
+    {
+      i2cerr("i2c-bitbang%d kmm_zalloc failed\n", busnum);
+      return master;
+    }
+
+  priv->lower.priv = priv;
+  priv->lower.ops = &g_i2c_bitbang_ops;
+  priv->scl_pin = scl_pin;
+  priv->sda_pin = sda_pin;
+  priv->ioe = ioe;
+
+  master = i2c_bitbang_initialize(&priv->lower);
+  if (master == NULL)
+    {
+      kmm_free(priv);
+      i2cerr("I2c bitbang:%d initialize failed\n", busnum);
+      return master;
+    }
+
+  if (busnum >= 0)
+    {
+      int ret;
+
+      ret = i2c_register(master, busnum);
+      if (ret < 0)
+        {
+          kmm_free(priv);
+          kmm_free(master);
+          master = NULL;
+          i2cerr("I2c bitbang:%d register failed:%d\n", busnum, ret);
+        }
+    }
+
+  return master;
+}
diff --git a/include/nuttx/i2c/i2c_bitbang_ioexpander.h 
b/include/nuttx/i2c/i2c_bitbang_ioexpander.h
new file mode 100644
index 00000000000..07269a62540
--- /dev/null
+++ b/include/nuttx/i2c/i2c_bitbang_ioexpander.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+ * include/nuttx/i2c/i2c_bitbang_ioexpander.h
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_I2C_I2C_BITBANG_IOEXPANDER_H
+#define __INCLUDE_NUTTX_I2C_I2C_BITBANG_IOEXPANDER_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/i2c/i2c_master.h>
+#include <nuttx/ioexpander/ioexpander.h>
+
+/****************************************************************************
+ * Public Type Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: i2c_bitbang_ioexpander_initialize
+ *
+ * Description:
+ *   Initialize i2c bitbang ioexapnder lower half driver.
+ *
+ * Input Parameters:
+ *  ioe     - An instance of the ioexpander device to use for bitbanging
+ *  scl_pin - The pin number to use for SCL
+ *  sda_pin - The pin number to use for SDA
+ *  busnum  - The I2C bus number to register
+ *
+ *  Returned Value:
+ *  On success, a pointer to the initialized I2C driver for the specified.
+ *
+ ****************************************************************************/
+
+FAR struct i2c_master_s *
+i2c_bitbang_ioexpander_initialize(FAR struct ioexpander_dev_s *ioe,
+                                  int scl_pin, int sda_pin, int busnum);
+
+#endif /* __INCLUDE_NUTTX_I2C_I2C_BITBANG_IOEXPANDER_H */

Reply via email to