summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichał Barnaś <mb@semihalf.com>2021-01-19 18:56:55 +0100
committerCommit Bot <commit-bot@chromium.org>2021-02-23 19:12:33 +0000
commit9497502d59d5979d4a60abb58a67eda7a8051fa4 (patch)
treeaa5fe2751ee70c2e9a833eb2a7f14c0ca5b433c6
parent3a8d8b16790ea15bceec6e11d3ed091f5462ce44 (diff)
downloadchrome-ec-9497502d59d5979d4a60abb58a67eda7a8051fa4.tar.gz
tca64xxa: Add new ioexpander driver for TI TCA64xxA modules
Add TI TCA64xxA (TCA6416A, TCA6424A) series driver that conforms to ioexpander_drv interface. Driver supports 16- and 24-bits versions and is configured by flags field in ioex_config (TCA64XXA_FLAG_VER_TCA6416A, TCA64XXA_FLAG_VER_TCA6424A). BUG=b:168385201 BRANCH=main TEST=Add 'CONFIG_IO_EXPANDER_TCA64XXA' to any board.h Execute make to any board, ioexpander/tca64xxa.c should be visible in compiled files list Signed-off-by: Michał Barnaś <mb@semihalf.com> Change-Id: I5ca27df3802d900c9967684403f29c33abd96f18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2700296 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
-rw-r--r--driver/build.mk1
-rw-r--r--driver/ioexpander/tca64xxa.c226
-rw-r--r--driver/ioexpander/tca64xxa.h25
-rw-r--r--include/config.h3
4 files changed, 255 insertions, 0 deletions
diff --git a/driver/build.mk b/driver/build.mk
index 6281247fd8..19b1839635 100644
--- a/driver/build.mk
+++ b/driver/build.mk
@@ -82,6 +82,7 @@ driver-$(CONFIG_IO_EXPANDER_NCT38XX)+=ioexpander/ioexpander_nct38xx.o
driver-$(CONFIG_IO_EXPANDER_PCA9534)+=ioexpander/pca9534.o
driver-$(CONFIG_IO_EXPANDER_PCA9675)+=ioexpander/pca9675.o
driver-$(CONFIG_IO_EXPANDER_PCAL6408)+=ioexpander/pcal6408.o
+driver-$(CONFIG_IO_EXPANDER_TCA64XXA)+=ioexpander/tca64xxa.o
driver-$(CONFIG_CTN730)+=nfc/ctn730.o
diff --git a/driver/ioexpander/tca64xxa.c b/driver/ioexpander/tca64xxa.c
new file mode 100644
index 0000000000..0a65fdc5ca
--- /dev/null
+++ b/driver/ioexpander/tca64xxa.c
@@ -0,0 +1,226 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "i2c.h"
+#include "ioexpander.h"
+#include "system.h"
+#include "tca64xxa.h"
+
+/*
+ * This chip series contain registers in the same order.
+ * Difference between models is only amount of registers and
+ * value of which you must multiply to access specific register.
+ * For 16 bit series, registers are 2 byte away, so to access TCA64XXA_REG_CONF
+ * you must multiply it by 2. For 24 bit, they are away by 4 bytes so you
+ * must multiply them by 4. Flags value contains information which version
+ * of chip is used.
+ */
+#define TCA64XXA_PORT_ID(port, reg, flags) \
+ ((((flags) & TCA64XXA_FLAG_VER_MASK) \
+ >> TCA64XXA_FLAG_VER_OFFSET) * (reg) + (port))
+
+static int tca64xxa_write_byte(int ioex, int port, int reg, uint8_t val)
+{
+ const struct ioexpander_config_t *ioex_p = &ioex_config[ioex];
+ const int reg_addr = TCA64XXA_PORT_ID(port, reg, ioex_p->flags);
+
+ return i2c_write8(ioex_p->i2c_host_port,
+ ioex_p->i2c_slave_addr,
+ reg_addr,
+ val);
+}
+
+static int tca64xxa_read_byte(int ioex, int port, int reg, int *val)
+{
+ const struct ioexpander_config_t *ioex_p = &ioex_config[ioex];
+ const int reg_addr = TCA64XXA_PORT_ID(port, reg, ioex_p->flags);
+
+ return i2c_read8(ioex_p->i2c_host_port,
+ ioex_p->i2c_slave_addr,
+ reg_addr,
+ val);
+}
+
+/* Restore default values in registers */
+static int tca64xxa_reset(int ioex, int portsCount)
+{
+ int port;
+ int ret;
+
+ /*
+ * On servo_v4p1, reset pin is pulled up and it results in values
+ * not being restored to default ones after software reboot.
+ * This loop sets default values (from specification) to all registers.
+ */
+ for (port = 0; port < portsCount; port++) {
+ ret = tca64xxa_write_byte(ioex,
+ port,
+ TCA64XXA_REG_OUTPUT,
+ TCA64XXA_DEFAULT_OUTPUT);
+ if (ret)
+ return ret;
+
+ ret = tca64xxa_write_byte(ioex,
+ port,
+ TCA64XXA_REG_POLARITY_INV,
+ TCA64XXA_DEFAULT_POLARITY_INV);
+ if (ret)
+ return ret;
+
+ ret = tca64xxa_write_byte(ioex,
+ port,
+ TCA64XXA_REG_CONF,
+ TCA64XXA_DEFAULT_CONF);
+ if (ret)
+ return ret;
+ }
+
+ return EC_SUCCESS;
+}
+
+/* Initialize IO expander chip/driver */
+static int tca64xxa_init(int ioex)
+{
+ const struct ioexpander_config_t *ioex_p = &ioex_config[ioex];
+ int portsCount;
+
+ if (ioex_p->flags & TCA64XXA_FLAG_VER_TCA6416A)
+ portsCount = 2;
+ else if (ioex_p->flags & TCA64XXA_FLAG_VER_TCA6424A)
+ portsCount = 3;
+ else
+ return EC_ERROR_UNIMPLEMENTED;
+
+ if (!system_jumped_late())
+ return tca64xxa_reset(ioex, portsCount);
+
+ return EC_SUCCESS;
+}
+
+/* Get the current level of the IOEX pin */
+static int tca64xxa_get_level(int ioex, int port, int mask, int *val)
+{
+ int buf;
+ int ret;
+
+ ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_INPUT, &buf);
+ *val = !!(buf & mask);
+
+ return ret;
+}
+
+/* Set the level of the IOEX pin */
+static int tca64xxa_set_level(int ioex, int port, int mask, int val)
+{
+ int ret;
+ int v;
+
+ ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_OUTPUT, &v);
+ if (ret)
+ return ret;
+
+ if (val)
+ v |= mask;
+ else
+ v &= ~mask;
+
+ return tca64xxa_write_byte(ioex, port, TCA64XXA_REG_OUTPUT, v);
+}
+
+/* Get flags for the IOEX pin */
+static int tca64xxa_get_flags_by_mask(int ioex, int port, int mask, int *flags)
+{
+ int ret;
+ int v;
+
+ ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_CONF, &v);
+ if (ret)
+ return ret;
+
+ *flags = 0;
+ if (v & mask) {
+ *flags |= GPIO_INPUT;
+ } else {
+ *flags |= GPIO_OUTPUT;
+
+ ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_OUTPUT, &v);
+ if(ret)
+ return ret;
+
+ if (v & mask)
+ *flags |= GPIO_HIGH;
+ else
+ *flags |= GPIO_LOW;
+ }
+
+ return EC_SUCCESS;
+}
+
+/* Set flags for the IOEX pin */
+static int tca64xxa_set_flags_by_mask(int ioex, int port, int mask, int flags)
+{
+ int ret;
+ int v;
+
+ /* Output value */
+ if (flags & GPIO_OUTPUT) {
+ ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_OUTPUT, &v);
+ if (ret)
+ return ret;
+
+ if (flags & GPIO_LOW)
+ v &= ~mask;
+ else if (flags & GPIO_HIGH)
+ v |= mask;
+ else
+ return EC_ERROR_INVAL;
+
+ ret = tca64xxa_write_byte(ioex, port, TCA64XXA_REG_OUTPUT, v);
+ if (ret)
+ return ret;
+ }
+
+ /* Configuration */
+ ret = tca64xxa_read_byte(ioex, port, TCA64XXA_REG_CONF, &v);
+ if(ret)
+ return ret;
+
+ if (flags & GPIO_INPUT)
+ v |= mask;
+ else if (flags & GPIO_OUTPUT)
+ v &= ~mask;
+ else
+ return EC_ERROR_INVAL;
+
+ ret = tca64xxa_write_byte(ioex, port, TCA64XXA_REG_CONF, v);
+ if (ret)
+ return ret;
+
+ return EC_SUCCESS;
+}
+
+#ifdef CONFIG_IO_EXPANDER_SUPPORT_GET_PORT
+
+/* Read levels for whole IO expander port */
+static int tca64xxa_get_port(int ioex, int port, int *val)
+{
+ return tca64xxa_read_byte(ioex, port, TCA64XXA_REG_INPUT, val);
+}
+
+#endif
+
+/* Driver structure */
+const struct ioexpander_drv tca64xxa_ioexpander_drv = {
+ .init = tca64xxa_init,
+ .get_level = tca64xxa_get_level,
+ .set_level = tca64xxa_set_level,
+ .get_flags_by_mask = tca64xxa_get_flags_by_mask,
+ .set_flags_by_mask = tca64xxa_set_flags_by_mask,
+ .enable_interrupt = NULL,
+#ifdef CONFIG_IO_EXPANDER_SUPPORT_GET_PORT
+ .get_port = tca64xxa_get_port,
+#endif
+};
diff --git a/driver/ioexpander/tca64xxa.h b/driver/ioexpander/tca64xxa.h
new file mode 100644
index 0000000000..8c3448f804
--- /dev/null
+++ b/driver/ioexpander/tca64xxa.h
@@ -0,0 +1,25 @@
+/* Copyright 2021 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_DRIVER_IOEXPANDER_TCA64XXA_H_
+#define __CROS_EC_DRIVER_IOEXPANDER_TCA64XXA_H_
+
+#define TCA64XXA_FLAG_VER_TCA6416A 2
+#define TCA64XXA_FLAG_VER_TCA6424A 4
+#define TCA64XXA_FLAG_VER_MASK GENMASK(2, 1)
+#define TCA64XXA_FLAG_VER_OFFSET 0
+
+#define TCA64XXA_REG_INPUT 0
+#define TCA64XXA_REG_OUTPUT 1
+#define TCA64XXA_REG_POLARITY_INV 2
+#define TCA64XXA_REG_CONF 3
+
+#define TCA64XXA_DEFAULT_OUTPUT 0xFF
+#define TCA64XXA_DEFAULT_POLARITY_INV 0x00
+#define TCA64XXA_DEFAULT_CONF 0xFF
+
+extern const struct ioexpander_drv tca64xxa_ioexpander_drv;
+
+#endif /* __CROS_EC_DRIVER_IOEXPANDER_TCA64XXA_H_ */
diff --git a/include/config.h b/include/config.h
index e9e3105e5f..3bc1635a84 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2512,6 +2512,9 @@
/* Support NXP PCAL6408 I/O expander. */
#undef CONFIG_IO_EXPANDER_PCAL6408
+/* Support TI TCA64xxA I/O expander. */
+#undef CONFIG_IO_EXPANDER_TCA64XXA
+
/* Number of IO Expander ports */
#undef CONFIG_IO_EXPANDER_PORT_COUNT