diff options
Diffstat (limited to 'driver/ioexpander/pcal6408.c')
-rw-r--r-- | driver/ioexpander/pcal6408.c | 354 |
1 files changed, 0 insertions, 354 deletions
diff --git a/driver/ioexpander/pcal6408.c b/driver/ioexpander/pcal6408.c deleted file mode 100644 index 287e0506d0..0000000000 --- a/driver/ioexpander/pcal6408.c +++ /dev/null @@ -1,354 +0,0 @@ -/* 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 PCA(L)6408 I/O expander - */ -#include "common.h" -#include "console.h" -#include "math_util.h" -#include "gpio.h" -#include "i2c.h" -#include "ioexpander.h" -#include "pcal6408.h" - -#define CPRINTF(format, args...) cprintf(CC_GPIO, format, ## args) -#define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) - -/* - * Store interrupt mask registers locally. In this way, - * we don't have to read it via i2c transaction every time. - * Default value of interrupt mask register is 0xff. - */ -uint8_t pcal6408_int_mask[] = { - [0 ... (CONFIG_IO_EXPANDER_PORT_COUNT - 1)] = 0xff }; - - -static int pcal6408_read(int ioex, int reg, int *data) -{ - int rv; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); - - return rv; -} - -static int pcal6408_write(int ioex, int reg, int data) -{ - int rv; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); - - return rv; -} - -static int pcal6408_ioex_check_is_valid(int port, int mask) -{ - if (port != 0) - return EC_ERROR_INVAL; - - if (mask & ~PCAL6408_VALID_GPIO_MASK) { - CPRINTF("GPIO%02d is not support in PCAL6408\n", - __fls(mask)); - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} - -static int pcal6408_ioex_init(int ioex) -{ - /* It seems that we have nothing to do here. - * This chip has not a chip id to be identified. - */ - return EC_SUCCESS; -} - -static int pcal6408_ioex_get_level(int ioex, int port, int mask, int *val) -{ - int rv; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_INPUT, val); - if (rv != EC_SUCCESS) - return rv; - - *val = !!(*val & mask); - - return EC_SUCCESS; -} - -static int pcal6408_ioex_set_level(int ioex, int port, int mask, int value) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_OUTPUT, &val); - if (rv != EC_SUCCESS) - return rv; - - if (value) - val |= mask; - else - val &= ~mask; - - return pcal6408_write(ioex, PCAL6408_REG_OUTPUT, val); -} - -static int pcal6408_ioex_get_flags_by_mask(int ioex, int port, int mask, - int *flags) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - *flags = GPIO_FLAG_NONE; - - rv = pcal6408_read(ioex, PCAL6408_REG_CONFIG, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_INPUT; - else - *flags |= GPIO_OUTPUT; - - rv = pcal6408_read(ioex, PCAL6408_REG_INPUT, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_HIGH; - else - *flags |= GPIO_LOW; - - rv = pcal6408_read(ioex, PCAL6408_REG_OUT_CONFIG, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & PCAL6408_OUT_CONFIG_OPEN_DRAIN) - *flags |= GPIO_OPEN_DRAIN; - - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_ENABLE, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) { - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_UP_DOWN, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_PULL_UP; - else - *flags |= GPIO_PULL_DOWN; - } - - rv = pcal6408_read(ioex, PCAL6408_REG_INT_MASK, &val); - if (rv != EC_SUCCESS) - return rv; - - if ((!!(val & mask) == 0) && ((*flags) & GPIO_INPUT)) - *flags |= GPIO_INT_BOTH; - - return rv; -} - -static int pcal6408_ioex_set_flags_by_mask(int ioex, int port, int mask, - int flags) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - if (((flags & GPIO_INT_BOTH) == GPIO_INT_RISING) || - ((flags & GPIO_INT_BOTH) == GPIO_INT_FALLING)) { - CPRINTF("PCAL6408 only support GPIO_INT_BOTH.\n"); - return EC_ERROR_INVAL; - } - - - if ((flags & (GPIO_INT_F_RISING | GPIO_INT_F_FALLING)) && - !(flags & GPIO_INPUT)) { - CPRINTF("Interrupt pin must be GPIO_INPUT.\n"); - return EC_ERROR_INVAL; - } - - /* All output gpios share GPIO_OPEN_DRAIN, should be consistent */ - if (flags & GPIO_OPEN_DRAIN) - val = PCAL6408_OUT_CONFIG_OPEN_DRAIN; - else - val = 0; - - rv = pcal6408_write(ioex, PCAL6408_REG_OUT_CONFIG, val); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_CONFIG, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_INPUT) - val |= mask; - if (flags & GPIO_OUTPUT) - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_CONFIG, val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_OUTPUT) { - rv = pcal6408_read(ioex, PCAL6408_REG_OUTPUT, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_HIGH) - val |= mask; - else if (flags & GPIO_LOW) - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_OUTPUT, val); - if (rv != EC_SUCCESS) - return rv; - } - - if (!(flags & (GPIO_PULL_UP | GPIO_PULL_DOWN))) { - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_ENABLE, &val); - if (rv != EC_SUCCESS) - return rv; - - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_PULL_ENABLE, val); - if (rv != EC_SUCCESS) - return rv; - } else { - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_ENABLE, &val); - if (rv != EC_SUCCESS) - return rv; - - val |= mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_PULL_ENABLE, val); - if (rv != EC_SUCCESS) - return rv; - - rv = pcal6408_read(ioex, PCAL6408_REG_PULL_UP_DOWN, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_PULL_UP) - val |= mask; - else if (flags & GPIO_PULL_DOWN) - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_PULL_UP_DOWN, val); - if (rv != EC_SUCCESS) - return rv; - } - - return rv; -} - -static int pcal6408_ioex_enable_interrupt(int ioex, int port, int mask, - int enable) -{ - int rv, val; - - rv = pcal6408_ioex_check_is_valid(port, mask); - if (rv != EC_SUCCESS) - return rv; - - /* Interrupt should be latched */ - rv = pcal6408_read(ioex, PCAL6408_REG_INPUT_LATCH, &val); - if (rv != EC_SUCCESS) - return rv; - - if (enable) - val |= mask; - else - val &= ~mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_INPUT_LATCH, val); - if (rv != EC_SUCCESS) - return rv; - - /* - * Enable or disable interrupt. - * In PCAL6408_REG_INT_MASK, 0 = enable interrupt, - * 1 = disable interrupt. - */ - if (enable) - pcal6408_int_mask[ioex] &= ~mask; - else - pcal6408_int_mask[ioex] |= mask; - - rv = pcal6408_write(ioex, PCAL6408_REG_INT_MASK, - pcal6408_int_mask[ioex]); - - return rv; -} - -int pcal6408_ioex_event_handler(int ioex) -{ - int int_status, int_mask; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - int i, rv = 0; - const struct ioex_info *g; - - int_mask = pcal6408_int_mask[ioex]; - - /* - * Read input port register will clear the interrupt, - * read status register will not. - */ - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - PCAL6408_REG_INT_STATUS, &int_status); - if (rv != EC_SUCCESS) - return rv; - - /* - * In pcal6408_int_mask[x], 0 = enable interrupt, - * 1 = disable interrupt. - */ - int_status = int_status & ~int_mask; - - if (!int_status) - return EC_SUCCESS; - - for (i = 0, g = ioex_list; i < ioex_ih_count; i++, g++) { - - if (ioex == g->ioex && 0 == g->port && - (int_status & g->mask)) { - ioex_irq_handlers[i](i + IOEX_SIGNAL_START); - int_status &= ~g->mask; - if (!int_status) - break; - } - } - - return EC_SUCCESS; -} - -const struct ioexpander_drv pcal6408_ioexpander_drv = { - .init = &pcal6408_ioex_init, - .get_level = &pcal6408_ioex_get_level, - .set_level = &pcal6408_ioex_set_level, - .get_flags_by_mask = &pcal6408_ioex_get_flags_by_mask, - .set_flags_by_mask = &pcal6408_ioex_set_flags_by_mask, - .enable_interrupt = &pcal6408_ioex_enable_interrupt, -}; |