diff options
author | Vijay Hiremath <vijay.p.hiremath@intel.com> | 2021-04-21 15:45:01 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-04-23 05:42:36 +0000 |
commit | a4e38fe2152b56a178a77c4ff8b89ba5f85e027b (patch) | |
tree | 3e21a939309b351f8afe329d3c437e8c7c0de74f /driver | |
parent | 8d411971acc3a9ebf35918a40e6814a430121b8b (diff) | |
download | chrome-ec-a4e38fe2152b56a178a77c4ff8b89ba5f85e027b.tar.gz |
pca9675: Add code to fit standard I/O expander functionality
Added code so that PCA9675 I/O expander driver fits standard
I/O expander functionality.
BUG=b:169814014
BRANCH=none
TEST=Manually tested on ADLRVP, ioexget & ioexset works
Cq-Depend: chromium:2845014
Change-Id: I07957a3f1de9b70fc396d767e8cc3ac8884b9c2e
Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2829985
Reviewed-by: caveh jalali <caveh@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r-- | driver/ioexpander/pca9675.c | 93 | ||||
-rw-r--r-- | driver/ioexpander/pca9675.h | 90 |
2 files changed, 88 insertions, 95 deletions
diff --git a/driver/ioexpander/pca9675.c b/driver/ioexpander/pca9675.c index df1217bba0..7b08a64175 100644 --- a/driver/ioexpander/pca9675.c +++ b/driver/ioexpander/pca9675.c @@ -5,20 +5,26 @@ * NXP PCA9675PW I/O Port expander driver source */ -/* TODO (b/169814014): Implement code to fit "struct ioexpander_drv" */ - +#include "i2c.h" +#include "ioexpander.h" #include "pca9675.h" -static uint16_t cache_out_pins[CONFIG_IO_EXPANDER_PORT_COUNT]; +struct pca9675_ioexpander { + /* I/O port direction (1 = input, 0 = output) */ + uint16_t io_direction; + uint16_t cache_out_pins; +}; + +static struct pca9675_ioexpander pca9675_iox[CONFIG_IO_EXPANDER_PORT_COUNT]; -static int pca9675_read(int ioex, uint16_t *data) +static int pca9675_read16(int ioex, uint16_t *data) { - return i2c_xfer(pca9675_iox[ioex].i2c_host_port, - pca9675_iox[ioex].i2c_addr_flags, + return i2c_xfer(ioex_config[ioex].i2c_host_port, + ioex_config[ioex].i2c_addr_flags, NULL, 0, (uint8_t *)data, 2); } -static int pca9675_write(int ioex, uint16_t data) +static int pca9675_write16(int ioex, uint16_t data) { /* * PCA9675 is Quasi-bidirectional I/O architecture hence @@ -27,8 +33,8 @@ static int pca9675_write(int ioex, uint16_t data) */ data |= pca9675_iox[ioex].io_direction; - return i2c_xfer(pca9675_iox[ioex].i2c_host_port, - pca9675_iox[ioex].i2c_addr_flags, + return i2c_xfer(ioex_config[ioex].i2c_host_port, + ioex_config[ioex].i2c_addr_flags, (uint8_t *)&data, 2, NULL, 0); } @@ -36,45 +42,80 @@ static int pca9675_reset(int ioex) { uint8_t reset = PCA9675_RESET_SEQ_DATA; - return i2c_xfer(pca9675_iox[ioex].i2c_host_port, + return i2c_xfer(ioex_config[ioex].i2c_host_port, 0, &reset, 1, NULL, 0); } -int pca9675_get_pin(int ioex, uint16_t pin, bool *level) +static int pca9675_set_flags_by_mask(int ioex, int port, int mask, int flags) +{ + /* Initialize the I/O directions */ + if (flags & GPIO_INPUT) + pca9675_iox[ioex].io_direction |= mask; + else + pca9675_iox[ioex].io_direction &= ~mask; + + return EC_SUCCESS; +} + +static int pca9675_get_flags_by_mask(int ioex, int port, int mask, int *flags) +{ + *flags = mask & pca9675_iox[ioex].io_direction ? + GPIO_INPUT : GPIO_OUTPUT; + + return EC_SUCCESS; +} + +static int pca9675_get_level(int ioex, int port, int mask, int *val) { 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 (pca9675_iox[ioex].io_direction & mask) { + rv = pca9675_read16(ioex, &data_read); if (!rv) - *level = !!(data_read & pin); + *val = !!(data_read & mask); } else { - *level = !!(cache_out_pins[ioex] & pin); + *val = !!(pca9675_iox[ioex].cache_out_pins & mask); } return rv; } -int pca9675_update_pins(int ioex, uint16_t setpins, uint16_t clearpins) +static int pca9675_set_level(int ioex, int port, int mask, int val) { /* Update the output pins */ - cache_out_pins[ioex] |= setpins; - cache_out_pins[ioex] &= ~clearpins; + if (val) + pca9675_iox[ioex].cache_out_pins |= mask; + else + pca9675_iox[ioex].cache_out_pins &= ~mask; + + return pca9675_write16(ioex, pca9675_iox[ioex].cache_out_pins); +} - return pca9675_write(ioex, cache_out_pins[ioex]); +static int pca9675_enable_interrupt(int ioex, int port, int mask, int enable) +{ + /* + * Nothing to do as an interrupt is generated by any rising or + * falling edge of the port inputs. + */ + return EC_SUCCESS; } int pca9675_init(int ioex) { - int rv; + pca9675_iox[ioex].io_direction = PCA9675_DEFAULT_IO_DIRECTION; + pca9675_iox[ioex].cache_out_pins = 0; /* Set pca9675 to Power-on reset */ - rv = pca9675_reset(ioex); - if (rv) - return rv; - - /* Initialize the I/O direction */ - return pca9675_write(ioex, 0); + return pca9675_reset(ioex); } + +const struct ioexpander_drv pca9675_ioexpander_drv = { + .init = &pca9675_init, + .get_level = &pca9675_get_level, + .set_level = &pca9675_set_level, + .get_flags_by_mask = &pca9675_get_flags_by_mask, + .set_flags_by_mask = &pca9675_set_flags_by_mask, + .enable_interrupt = &pca9675_enable_interrupt, +}; diff --git a/driver/ioexpander/pca9675.h b/driver/ioexpander/pca9675.h index e01278f7d6..59f36918a4 100644 --- a/driver/ioexpander/pca9675.h +++ b/driver/ioexpander/pca9675.h @@ -8,80 +8,32 @@ #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) +/* PCA9675 IO pins that can be referenced in gpio.inc */ +enum pca9675_io_pins { + PCA9675_IO_P00, + PCA9675_IO_P01, + PCA9675_IO_P02, + PCA9675_IO_P03, + PCA9675_IO_P04, + PCA9675_IO_P05, + PCA9675_IO_P06, + PCA9675_IO_P07, + PCA9675_IO_P10, + PCA9675_IO_P11, + PCA9675_IO_P12, + PCA9675_IO_P13, + PCA9675_IO_P14, + PCA9675_IO_P15, + PCA9675_IO_P16, + PCA9675_IO_P17, +}; -/* Sent 06 to address 00 to reset the PCA9675 to back to power up state */ +/* Write 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); +extern const struct ioexpander_drv pca9675_ioexpander_drv; #endif /* __CROS_EC_IOEXPANDER_PCA9675_H */ |