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 9b8c8bdd7b015ae34337e0b3b44620136dca1db6
Author: Jouni Ukkonen <jouni.ukko...@unikie.com>
AuthorDate: Wed Nov 6 10:33:20 2024 +0200

    drivers/tca64xx: Add support for PCAL6416
    
    - Added new part support for PCAL6416
    - Added pullup/pulldown configuration support
    
    Signed-off-by: Jouni Ukkonen <jouni.ukko...@unikie.com>
    Signed-off-by: Jukka Laitinen <jukka.laiti...@tii.ae>
---
 drivers/ioexpander/tca64xx.c       | 148 +++++++++++++++++++++++++++++++++++--
 drivers/ioexpander/tca64xx.h       |  18 +++++
 include/nuttx/ioexpander/tca64xx.h |   1 +
 3 files changed, 160 insertions(+), 7 deletions(-)

diff --git a/drivers/ioexpander/tca64xx.c b/drivers/ioexpander/tca64xx.c
index a830322e6e..11fe4fec4d 100644
--- a/drivers/ioexpander/tca64xx.c
+++ b/drivers/ioexpander/tca64xx.c
@@ -53,6 +53,9 @@ static uint8_t tca64_input_reg(FAR struct tca64_dev_s *priv, 
uint8_t pin);
 static uint8_t tca64_output_reg(FAR struct tca64_dev_s *priv, uint8_t pin);
 static uint8_t tca64_polarity_reg(FAR struct tca64_dev_s *priv, uint8_t pin);
 static uint8_t tca64_config_reg(FAR struct tca64_dev_s *priv, uint8_t pin);
+static uint8_t tca64_pdenable_reg(FAR struct tca64_dev_s *priv, uint8_t pin);
+static uint8_t tca64_pdselect_reg(FAR struct tca64_dev_s *priv, uint8_t pin);
+
 static int tca64_getreg(FAR struct tca64_dev_s *priv, uint8_t regaddr,
              FAR uint8_t *regval, unsigned int count);
 static int tca64_putreg(struct tca64_dev_s *priv, uint8_t regaddr,
@@ -134,6 +137,8 @@ static const struct tca64_part_s 
g_tca64_parts[TCA64_NPARTS] =
     TCA6408_OUTPUT_REG,
     TCA6408_POLARITY_REG,
     TCA6408_CONFIG_REG,
+    TCA64XX_INVALID_REG,
+    TCA64XX_INVALID_REG,
   },
   {
     TCA6416_PART,
@@ -142,6 +147,8 @@ static const struct tca64_part_s 
g_tca64_parts[TCA64_NPARTS] =
     TCA6416_OUTPUT0_REG,
     TCA6416_POLARITY0_REG,
     TCA6416_CONFIG0_REG,
+    TCA64XX_INVALID_REG,
+    TCA64XX_INVALID_REG,
   },
   {
     TCA6424_PART,
@@ -150,6 +157,18 @@ static const struct tca64_part_s 
g_tca64_parts[TCA64_NPARTS] =
     TCA6424_OUTPUT0_REG,
     TCA6424_POLARITY0_REG,
     TCA6424_CONFIG0_REG,
+    TCA64XX_INVALID_REG,
+    TCA64XX_INVALID_REG,
+  },
+  {
+    PCAL6416A_PART,
+    MIN(PCAL6416A_NR_GPIOS, CONFIG_IOEXPANDER_NPINS),
+    PCAL6416A_INPUT0_REG,
+    PCAL6416A_OUTPUT0_REG,
+    PCAL6416A_POLARITY0_REG,
+    PCAL6416A_CONFIG0_REG,
+    PCAL6416A_PU_ENABLE0_REG,
+    PCAL6416A_PUPD_SELECT0_REG,
   },
 };
 
@@ -256,6 +275,50 @@ static uint8_t tca64_config_reg(FAR struct tca64_dev_s 
*priv, uint8_t pin)
   return reg + (pin >> 3);
 }
 
+/****************************************************************************
+ * Name: tca64_pdenable_reg
+ *
+ * Description:
+ *  Return the address of the pu/pd enable register for the specified pin.
+ *
+ ****************************************************************************/
+
+static uint8_t tca64_pdenable_reg(FAR struct tca64_dev_s *priv, uint8_t pin)
+{
+  FAR const struct tca64_part_s *part = tca64_getpart(priv);
+  uint8_t reg = part->tp_puenable;
+
+  if (reg == TCA64XX_INVALID_REG)
+    {
+      return reg;
+    }
+
+  DEBUGASSERT(pin <= part->tp_ngpios);
+  return reg + (pin >> 3);
+}
+
+/****************************************************************************
+ * Name: tca64_pdselect_reg
+ *
+ * Description:
+ *  Return the address of the pu/pd selection register for the specified pin.
+ *
+ ****************************************************************************/
+
+static uint8_t tca64_pdselect_reg(FAR struct tca64_dev_s *priv, uint8_t pin)
+{
+  FAR const struct tca64_part_s *part = tca64_getpart(priv);
+  uint8_t reg = part->tp_puselect;
+
+  if (reg == TCA64XX_INVALID_REG)
+    {
+      return reg;
+    }
+
+  DEBUGASSERT(pin <= part->tp_ngpios);
+  return reg + (pin >> 3);
+}
+
 /****************************************************************************
  * Name: tca64_getreg
  *
@@ -375,12 +438,6 @@ static int tca64_direction(FAR struct ioexpander_dev_s 
*dev, uint8_t pin,
   uint8_t regval;
   int ret;
 
-  if (direction != IOEXPANDER_DIRECTION_IN &&
-      direction != IOEXPANDER_DIRECTION_OUT)
-    {
-      return -EINVAL;
-    }
-
   DEBUGASSERT(priv != NULL && priv->config != NULL &&
               pin < CONFIG_IOEXPANDER_NPINS);
 
@@ -411,7 +468,9 @@ static int tca64_direction(FAR struct ioexpander_dev_s 
*dev, uint8_t pin,
 
   /* Set the pin direction in the I/O Expander */
 
-  if (direction == IOEXPANDER_DIRECTION_IN)
+  if ((direction == IOEXPANDER_DIRECTION_IN) ||
+      (direction == IOEXPANDER_DIRECTION_IN_PULLDOWN) ||
+      (direction == IOEXPANDER_DIRECTION_IN_PULLUP))
     {
       /* Configure pin as input. If a bit in the configuration register is
        * set to 1, the corresponding port pin is enabled as an input with a
@@ -441,6 +500,81 @@ static int tca64_direction(FAR struct ioexpander_dev_s 
*dev, uint8_t pin,
               regaddr, ret);
     }
 
+  if ((direction == IOEXPANDER_DIRECTION_IN_PULLDOWN) ||
+      (direction == IOEXPANDER_DIRECTION_IN_PULLUP))
+    {
+      regaddr = tca64_pdenable_reg(priv, pin);
+      if (regaddr == TCA64XX_INVALID_REG)
+        {
+          gpioerr("ERROR: This part does not support PU/PD settings\n");
+          ret = -EINVAL;
+          goto errout_with_lock;
+        }
+
+      ret = tca64_getreg(priv, regaddr, &regval, 1);
+      if (ret < 0)
+        {
+          gpioerr("ERROR: Failed to read pu config register at %u: %d\n",
+                  regaddr, ret);
+          goto errout_with_lock;
+        }
+
+      regval |= (1 << (pin & 7));
+
+      ret = tca64_putreg(priv, regaddr, &regval, 1);
+      if (ret < 0)
+        {
+          gpioerr("ERROR: Failed to write pu config register at %u: %d\n",
+              regaddr, ret);
+          goto errout_with_lock;
+        }
+
+      regaddr = tca64_pdselect_reg(priv, pin);
+      ret = tca64_getreg(priv, regaddr, &regval, 1);
+      if (ret < 0)
+        {
+          gpioerr("ERROR: Failed to read pu select register at %u: %d\n",
+                  regaddr, ret);
+          goto errout_with_lock;
+        }
+
+      if (direction == IOEXPANDER_DIRECTION_IN_PULLUP)
+        {
+          regval |= (1 << (pin & 7));
+        }
+      else
+        {
+          regval &= ~(1 << (pin & 7));
+        }
+
+      ret = tca64_putreg(priv, regaddr, &regval, 1);
+      if (ret < 0)
+        {
+          gpioerr("ERROR: Failed to write pu select register at %u: %d\n",
+              regaddr, ret);
+          goto errout_with_lock;
+        }
+    }
+  else if (direction == IOEXPANDER_DIRECTION_IN)
+    {
+      /* Disable pu/pd if that is available */
+
+      regaddr = tca64_pdenable_reg(priv, pin);
+      if (regaddr != TCA64XX_INVALID_REG)
+        {
+          ret = tca64_getreg(priv, regaddr, &regval, 1);
+          if (ret < 0)
+            {
+              gpioerr("ERROR: Failed to read pu config register at %u: %d\n",
+                      regaddr, ret);
+              goto errout_with_lock;
+            }
+
+          regval &= ~(1 << (pin & 7));
+          ret = tca64_putreg(priv, regaddr, &regval, 1);
+        }
+    }
+
 errout_with_lock:
   nxmutex_unlock(&priv->lock);
   return ret;
diff --git a/drivers/ioexpander/tca64xx.h b/drivers/ioexpander/tca64xx.h
index 47695874e4..5c2c64a36b 100644
--- a/drivers/ioexpander/tca64xx.h
+++ b/drivers/ioexpander/tca64xx.h
@@ -99,6 +99,8 @@
 
 /* TCA64XX Parts ************************************************************/
 
+#define TCA64XX_INVALID_REG             0xff
+
 #define TCA6408_INPUT_REG               0x00
 #define TCA6408_OUTPUT_REG              0x01
 #define TCA6408_POLARITY_REG            0x02
@@ -134,6 +136,20 @@
 
 #define TCA64XX_NR_GPIO_MAX             TCA6424_NR_GPIOS
 
+#define PCAL6416A_INPUT0_REG            0x00
+#define PCAL6416A_INPUT1_REG            0x01
+#define PCAL6416A_OUTPUT0_REG           0x02
+#define PCAL6416A_OUTPUT1_REG           0x03
+#define PCAL6416A_POLARITY0_REG         0x04
+#define PCAL6416A_POLARITY1_REG         0x05
+#define PCAL6416A_CONFIG0_REG           0x06
+#define PCAL6416A_CONFIG1_REG           0x07
+#define PCAL6416A_PU_ENABLE0_REG        0x46
+#define PCAL6416A_PU_ENABLE1_REG        0x47
+#define PCAL6416A_PUPD_SELECT0_REG      0x48
+#define PCAL6416A_PUPD_SELECT1_REG      0x49
+#define PCAL6416A_NR_GPIOS              16
+
 /* 1us (datasheet: reset pulse duration (Tw) is 4ns */
 
 #define TCA64XX_TW                      1
@@ -183,6 +199,8 @@ struct tca64_part_s
   uint8_t tp_output;   /* Address of first output register */
   uint8_t tp_polarity; /* Address of first polarity register */
   uint8_t tp_config;   /* Address of first configuration register */
+  uint8_t tp_puenable;
+  uint8_t tp_puselect;
 };
 
 #ifdef CONFIG_IOEXPANDER_INT_ENABLE
diff --git a/include/nuttx/ioexpander/tca64xx.h 
b/include/nuttx/ioexpander/tca64xx.h
index 263524628b..189353361a 100644
--- a/include/nuttx/ioexpander/tca64xx.h
+++ b/include/nuttx/ioexpander/tca64xx.h
@@ -43,6 +43,7 @@ enum tca64xx_part_e
   TCA6408_PART = 0,
   TCA6416_PART,
   TCA6424_PART,
+  PCAL6416A_PART,
   TCA64_NPARTS
 };
 

Reply via email to