diff options
author | Vijay Hiremath <vijay.p.hiremath@intel.com> | 2021-04-26 17:42:39 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-05-05 19:18:09 +0000 |
commit | 45cdc0f7acd939efc686b4e600b32445f1e017f3 (patch) | |
tree | 2e2639586a313b38ad5e9d2a55604861a506bf00 /driver/ioexpander | |
parent | e96d9283e51c1fc105e1cc2b7d6757105699baf3 (diff) | |
download | chrome-ec-45cdc0f7acd939efc686b4e600b32445f1e017f3.tar.gz |
I/O Expander: Add CCG6XX driver
Cypress CCGXXF PD has built-in I/O Expander, added driver to enable
GPIO functionality.
BUG=none
BRANCH=none
TEST=Tested on ADLRVP, ioexget & ioexset works as expected
Change-Id: I8503178703ad166ac77e96d1990133c88169d23a
Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2853143
Tested-by: Svyatoslav Paliy <svpaliy@gmail.com>
Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
Diffstat (limited to 'driver/ioexpander')
-rw-r--r-- | driver/ioexpander/ccgxxf.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/driver/ioexpander/ccgxxf.c b/driver/ioexpander/ccgxxf.c new file mode 100644 index 0000000000..afaa6820d5 --- /dev/null +++ b/driver/ioexpander/ccgxxf.c @@ -0,0 +1,130 @@ +/* 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. + * + * Cypress CCGXXF I/O Port expander (built inside PD chip) driver source + */ + +#include "i2c.h" +#include "ioexpander.h" + +/* Add after all include files */ +#include "ccgxxf.h" + +static inline int ccgxxf_read8(int ioex, int reg, int *data) +{ + return i2c_read8(ioex_config[ioex].i2c_host_port, + ioex_config[ioex].i2c_addr_flags, reg, data); +} + +static inline int ccgxxf_update8(int ioex, int reg, uint8_t mask, + enum mask_update_action action) +{ + return i2c_update8(ioex_config[ioex].i2c_host_port, + ioex_config[ioex].i2c_addr_flags, reg, mask, action); +} + +static inline int ccgxxf_write16(int ioex, uint16_t reg, uint16_t data) +{ + return i2c_write16(ioex_config[ioex].i2c_host_port, + ioex_config[ioex].i2c_addr_flags, reg, data); +} + +static int ccgxxf_get_level(int ioex, int port, int mask, int *val) +{ + int rv; + + rv = ccgxxf_read8(ioex, CCGXXF_REG_GPIO_STATUS(port), val); + if (!rv) + *val = !!(*val & mask); + + return rv; +} + +static int ccgxxf_set_level(int ioex, int port, int mask, int val) +{ + return ccgxxf_update8(ioex, CCGXXF_REG_GPIO_CONTROL(port), mask, val); +} + +/* + * Following type of pins are supported + * - Output pins are supported with open-drain & pull-up + * - Input pins are supported with pull-up & pull-down + * - Analog pins + * + * TODO: Add support for 1.8V level GPIOs, after implementing it in the + * CCGXXF firmware. + */ +static int ccgxxf_set_flags_by_mask(int ioex, int port, int mask, int flags) +{ + uint16_t pin_mode; + int rv; + + if (flags & GPIO_OUTPUT) { + if (flags & GPIO_OPEN_DRAIN) { + if (flags & GPIO_PULL_UP) + pin_mode = CCGXXF_GPIO_MODE_RES_UP; + else + pin_mode = CCGXXF_GPIO_MODE_OD_LOW; + } else { + pin_mode = CCGXXF_GPIO_MODE_STRONG; + } + } else if (flags & GPIO_INPUT) { + if (flags & GPIO_PULL_UP) { + pin_mode = CCGXXF_GPIO_MODE_RES_UP; + flags |= GPIO_HIGH; + } else if (flags & GPIO_PULL_DOWN) { + pin_mode = CCGXXF_GPIO_MODE_RES_DWN; + flags |= GPIO_LOW; + } else { + pin_mode = CCGXXF_GPIO_MODE_HIZ_DIGITAL; + } + } else if (flags & GPIO_ANALOG) { + pin_mode = CCGXXF_GPIO_MODE_HIZ_ANALOG; + } else { + return EC_ERROR_INVAL; + } + + pin_mode = port | (pin_mode << CCGXXF_GPIO_PIN_MODE_SHIFT) | + (mask << CCGXXF_GPIO_PIN_MASK_SHIFT); + + /* + * Before setting the GPIO mode, initilaize the pins to default value + * to avoid spike on pins. + */ + if (flags & (GPIO_HIGH | GPIO_LOW)) { + rv = ccgxxf_set_level(ioex, port, mask, + flags & GPIO_HIGH ? 1 : 0); + if (rv) + return rv; + } + + return ccgxxf_write16(ioex, CCGXXF_REG_GPIO_MODE, pin_mode); +} + +static int ccgxxf_get_flags_by_mask(int ioex, int port, int mask, int *flags) +{ + /* TODO: Add it after implementing in the CCGXXF firmware. */ + return EC_SUCCESS; +} + +static int ccgxxf_enable_interrupt(int ioex, int port, int mask, int enable) +{ + /* CCGXXF doesn't have interrupt capability on I/O expnader pins */ + return EC_ERROR_UNIMPLEMENTED; +} + +int ccgxxf_init(int ioex) +{ + /* TCPC init of CCGXXF should handle initialization */ + return EC_SUCCESS; +} + +const struct ioexpander_drv ccgxxf_ioexpander_drv = { + .init = &ccgxxf_init, + .get_level = &ccgxxf_get_level, + .set_level = &ccgxxf_set_level, + .get_flags_by_mask = &ccgxxf_get_flags_by_mask, + .set_flags_by_mask = &ccgxxf_set_flags_by_mask, + .enable_interrupt = &ccgxxf_enable_interrupt, +}; |