summaryrefslogtreecommitdiff
path: root/driver/ioexpander
diff options
context:
space:
mode:
authorName <poornima.tom@intel.com>2020-06-19 11:16:23 +0530
committerCommit Bot <commit-bot@chromium.org>2020-10-26 21:09:23 +0000
commit426024dbcc36608744103aaecce815457a9de8a1 (patch)
tree1caf38b89ce6a3d2ad2cea276decd9a1d3e9eb1e /driver/ioexpander
parent8a4a98641799f54ce93ef707288d1fc1a7d35db0 (diff)
downloadchrome-ec-426024dbcc36608744103aaecce815457a9de8a1.tar.gz
IO-expander: Add driver support for PCA9675
BRANCH=None BUG=b:169551130 TEST=make buildall -j Change-Id: If565996850c5c75f3d425e2dc7f705b624ad4cc4 Signed-off-by: pandeyan <anshuman.pandey@intel.com> Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2435172 Reviewed-by: caveh jalali <caveh@chromium.org> Commit-Queue: Poornima Tom <poornima.tom@intel.com>
Diffstat (limited to 'driver/ioexpander')
-rw-r--r--driver/ioexpander/pca9675.c80
-rw-r--r--driver/ioexpander/pca9675.h87
2 files changed, 167 insertions, 0 deletions
diff --git a/driver/ioexpander/pca9675.c b/driver/ioexpander/pca9675.c
new file mode 100644
index 0000000000..df1217bba0
--- /dev/null
+++ b/driver/ioexpander/pca9675.c
@@ -0,0 +1,80 @@
+/* Copyright 2020 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.
+ *
+ * NXP PCA9675PW I/O Port expander driver source
+ */
+
+/* TODO (b/169814014): Implement code to fit "struct ioexpander_drv" */
+
+#include "pca9675.h"
+
+static uint16_t cache_out_pins[CONFIG_IO_EXPANDER_PORT_COUNT];
+
+static int pca9675_read(int ioex, uint16_t *data)
+{
+ return i2c_xfer(pca9675_iox[ioex].i2c_host_port,
+ pca9675_iox[ioex].i2c_addr_flags,
+ NULL, 0, (uint8_t *)data, 2);
+}
+
+static int pca9675_write(int ioex, uint16_t data)
+{
+ /*
+ * PCA9675 is Quasi-bidirectional I/O architecture hence
+ * append the direction (1 = input, 0 = output) to prevent
+ * overwriting I/O pins inadvertently.
+ */
+ data |= pca9675_iox[ioex].io_direction;
+
+ return i2c_xfer(pca9675_iox[ioex].i2c_host_port,
+ pca9675_iox[ioex].i2c_addr_flags,
+ (uint8_t *)&data, 2, NULL, 0);
+}
+
+static int pca9675_reset(int ioex)
+{
+ uint8_t reset = PCA9675_RESET_SEQ_DATA;
+
+ return i2c_xfer(pca9675_iox[ioex].i2c_host_port,
+ 0, &reset, 1, NULL, 0);
+}
+
+int pca9675_get_pin(int ioex, uint16_t pin, bool *level)
+{
+ int rv = EC_SUCCESS;
+ uint16_t data_read;
+
+ /* Read from IO-expander only if the pin is input */
+ if (pca9675_iox[ioex].io_direction & pin) {
+ rv = pca9675_read(ioex, &data_read);
+ if (!rv)
+ *level = !!(data_read & pin);
+ } else {
+ *level = !!(cache_out_pins[ioex] & pin);
+ }
+
+ return rv;
+}
+
+int pca9675_update_pins(int ioex, uint16_t setpins, uint16_t clearpins)
+{
+ /* Update the output pins */
+ cache_out_pins[ioex] |= setpins;
+ cache_out_pins[ioex] &= ~clearpins;
+
+ return pca9675_write(ioex, cache_out_pins[ioex]);
+}
+
+int pca9675_init(int ioex)
+{
+ int rv;
+
+ /* Set pca9675 to Power-on reset */
+ rv = pca9675_reset(ioex);
+ if (rv)
+ return rv;
+
+ /* Initialize the I/O direction */
+ return pca9675_write(ioex, 0);
+}
diff --git a/driver/ioexpander/pca9675.h b/driver/ioexpander/pca9675.h
new file mode 100644
index 0000000000..e01278f7d6
--- /dev/null
+++ b/driver/ioexpander/pca9675.h
@@ -0,0 +1,87 @@
+/* Copyright 2020 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.
+ *
+ * NXP PCA9675PW I/O Port expander driver header
+ */
+
+#ifndef __CROS_EC_IOEXPANDER_PCA9675_H
+#define __CROS_EC_IOEXPANDER_PCA9675_H
+
+#include <stdbool.h>
+
+#include "hooks.h"
+#include "i2c.h"
+
+#define PCA9675_IO_P00 BIT(0)
+#define PCA9675_IO_P01 BIT(1)
+#define PCA9675_IO_P02 BIT(2)
+#define PCA9675_IO_P03 BIT(3)
+#define PCA9675_IO_P04 BIT(4)
+#define PCA9675_IO_P05 BIT(5)
+#define PCA9675_IO_P06 BIT(6)
+#define PCA9675_IO_P07 BIT(7)
+
+#define PCA9675_IO_P10 BIT(8)
+#define PCA9675_IO_P11 BIT(9)
+#define PCA9675_IO_P12 BIT(10)
+#define PCA9675_IO_P13 BIT(11)
+#define PCA9675_IO_P14 BIT(12)
+#define PCA9675_IO_P15 BIT(13)
+#define PCA9675_IO_P16 BIT(14)
+#define PCA9675_IO_P17 BIT(15)
+
+/* Sent 06 to address 00 to reset the PCA9675 to back to power up state */
+#define PCA9675_RESET_SEQ_DATA 0x06
+
+/* Default I/O directons of PCA9675 is input */
+#define PCA9675_DEFAULT_IO_DIRECTION 0xffff
+
+#define HOOK_PRIO_INIT_PCA9675 (HOOK_PRIO_INIT_I2C + 1)
+
+/* PCA9675 IOexpander structure */
+struct pca9675_ioexpander {
+ /* Physical I2C port connects to the IO expander chip. */
+ const int i2c_host_port;
+ /* I2C slave address */
+ const uint16_t i2c_addr_flags;
+ /* I/O port direction (1 = input, 0 = output) */
+ const uint16_t io_direction;
+};
+
+extern const struct pca9675_ioexpander pca9675_iox[];
+
+/*
+ * Get input level. Note that this reflects the actual level on the
+ * pin, even if the pin is configured as output.
+ *
+ * @param ioex I/O expander port number
+ * @param pin Pin number
+ * @param level Pointer to get pin level
+ *
+ * @return EC_SUCCESS, or EC_ERROR_* on error.
+ */
+int pca9675_get_pin(int ioex, uint16_t pin, bool *level);
+
+/*
+ * Update pin levels. This function has no effect if the pin is
+ * configured as input.
+ *
+ * @param ioex I/O expander port number
+ * @param setpins Pins to be set
+ * @param clearpins Pins to be cleared
+ *
+ * @return EC_SUCCESS, or EC_ERROR_* on error.
+ */
+int pca9675_update_pins(int ioex, uint16_t setpins, uint16_t clearpins);
+
+/*
+ * Initialize the PCA9675 to power up state
+ *
+ * @param ioex I/O expander port number
+ *
+ * @return EC_SUCCESS, or EC_ERROR_* on error.
+ */
+int pca9675_init(int ioex);
+
+#endif /* __CROS_EC_IOEXPANDER_PCA9675_H */