diff options
Diffstat (limited to 'driver/ioexpander')
-rw-r--r-- | driver/ioexpander/ccgxxf.c | 145 | ||||
-rw-r--r-- | driver/ioexpander/ioexpander_nct38xx.c | 470 | ||||
-rw-r--r-- | driver/ioexpander/it8300.h | 106 | ||||
-rw-r--r-- | driver/ioexpander/it8801.c | 683 | ||||
-rw-r--r-- | driver/ioexpander/it8801.h | 126 | ||||
-rw-r--r-- | driver/ioexpander/pca9534.c | 52 | ||||
-rw-r--r-- | driver/ioexpander/pca9534.h | 59 | ||||
-rw-r--r-- | driver/ioexpander/pca9555.h | 45 | ||||
-rw-r--r-- | driver/ioexpander/pca9675.c | 127 | ||||
-rw-r--r-- | driver/ioexpander/pca9675.h | 39 | ||||
-rw-r--r-- | driver/ioexpander/pcal6408.c | 354 | ||||
-rw-r--r-- | driver/ioexpander/pcal6408.h | 42 | ||||
-rw-r--r-- | driver/ioexpander/tca64xxa.c | 226 | ||||
-rw-r--r-- | driver/ioexpander/tca64xxa.h | 25 |
14 files changed, 0 insertions, 2499 deletions
diff --git a/driver/ioexpander/ccgxxf.c b/driver/ioexpander/ccgxxf.c deleted file mode 100644 index ac079d7b2f..0000000000 --- a/driver/ioexpander/ccgxxf.c +++ /dev/null @@ -1,145 +0,0 @@ -/* 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 "console.h" -#include "i2c.h" -#include "ioexpander.h" - -/* Add after all include files */ -#include "ccgxxf.h" - -#define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) - -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 - * - 1.8V level GPIOs are supported per port and outputs can only be - * open-drain pins - */ -static int ccgxxf_set_flags_by_mask(int ioex, int port, int mask, int flags) -{ - uint16_t pin_mode; - int rv; - - /* Push-pull output can't be configured for 1.8V level */ - if ((flags & GPIO_OUTPUT) && (flags & GPIO_SEL_1P8V) && - !(flags & GPIO_OPEN_DRAIN)) { - CPRINTS("Invalid flags: ioex=%d, port=%d, mask=%d, flags=0x%x", - ioex, port, mask, flags); - - return EC_ERROR_INVAL; - } - - 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); - - /* Note: once set the 1.8V level affect whole GPIO port */ - if (flags & GPIO_SEL_1P8V) - pin_mode |= CCGXXF_GPIO_1P8V_SEL; - - /* - * 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, -}; diff --git a/driver/ioexpander/ioexpander_nct38xx.c b/driver/ioexpander/ioexpander_nct38xx.c deleted file mode 100644 index 8c87a33d24..0000000000 --- a/driver/ioexpander/ioexpander_nct38xx.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Copyright 2019 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. - */ - -/* GPIO expander for Nuvoton NCT38XX. */ - -#include "console.h" -#include "gpio.h" -#include "i2c.h" -#include "ioexpander.h" -#include "nct38xx.h" -#include "tcpm/tcpci.h" - -#define CPRINTF(format, args...) cprintf(CC_GPIO, format, ## args) -#define CPRINTS(format, args...) cprints(CC_GPIO, format, ## args) - -/* - * Store the GPIO_ALERT_MASK_0/1 and chip ID registers locally. In this way, - * we don't have to read it via I2C transaction everytime. - */ -struct nct38xx_chip_data { - uint8_t int_mask[2]; - int chip_id; -}; - -static struct nct38xx_chip_data chip_data[CONFIG_IO_EXPANDER_PORT_COUNT] = { - [0 ... (CONFIG_IO_EXPANDER_PORT_COUNT - 1)] = { {0, 0}, -1 } -}; - -static int nct38xx_ioex_check_is_valid(int ioex, int port, int mask) -{ - if (chip_data[ioex].chip_id == NCT38XX_VARIANT_3808) { - if (port == 1) { - CPRINTF("Port 1 is not support in NCT3808\n"); - return EC_ERROR_INVAL; - } - if (mask & ~NCT38XXX_3808_VALID_GPIO_MASK) { - - CPRINTF("GPIO%02d is not support in NCT3808\n", - __fls(mask)); - return EC_ERROR_INVAL; - } - } - - return EC_SUCCESS; -} - -static int nct38xx_ioex_init(int ioex) -{ - int rv, val; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - /* - * Check the NCT38xx part number in the register DEVICE_ID[4:2]: - * 000: NCT3807 - * 010: NCT3808 - */ - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - TCPC_REG_BCD_DEV, &val); - - if (rv != EC_SUCCESS) { - CPRINTF("Failed to read NCT38XX DEV ID for IOexpander %d\n", - ioex); - return rv; - } - - chip_data[ioex].chip_id = ((uint8_t)val & NCT38XX_VARIANT_MASK) >> 2; - - /* - * NCT38XX uses the Vendor Define bit in the ALERT event to indicate - * that an IOEX IO's interrupt is triggered. - * Normally, The ALERT MASK for Vendor Define event should be set by - * the NCT38XX TCPCI driver's init function. - * However, it should be also set here if we want to test the interrupt - * function of IOEX when the NCT38XX TCPCI driver is not included. - */ - if (!IS_ENABLED(CONFIG_USB_PD_TCPM_NCT38XX)) { - rv = i2c_write16(ioex_p->i2c_host_port, - ioex_p->i2c_addr_flags, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_VENDOR_DEF); - if (rv != EC_SUCCESS) - return rv; - } - return EC_SUCCESS; -} - -static int nct38xx_ioex_get_level(int ioex, int port, int mask, int *val) -{ - int rv, reg; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DATA_IN(port); - rv = i2c_read8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, val); - if (rv != EC_SUCCESS) - return rv; - - *val = !!(*val & mask); - - return EC_SUCCESS; -} - -static int nct38xx_ioex_set_level(int ioex, int port, int mask, int value) -{ - int rv, reg, val; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DATA_OUT(port); - - rv = i2c_read8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (value) - val |= mask; - else - val &= ~mask; - - return i2c_write8(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, reg, val); -} - -static int nct38xx_ioex_get_flags(int ioex, int port, int mask, int *flags) -{ - int rv, reg, val, i2c_port, i2c_addr; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - i2c_port = ioex_p->i2c_host_port; - i2c_addr = ioex_p->i2c_addr_flags; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DIR(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_OUTPUT; - else - *flags |= GPIO_INPUT; - - reg = NCT38XX_REG_GPIO_DATA_IN(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_HIGH; - else - *flags |= GPIO_LOW; - - reg = NCT38XX_REG_GPIO_OD_SEL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (val & mask) - *flags |= GPIO_OPEN_DRAIN; - - return EC_SUCCESS; -} - -static int nct38xx_ioex_sel_int_type(int i2c_port, int i2c_addr, int port, - int mask, int flags) -{ - int rv; - int reg_rising, reg_falling; - int rising, falling; - - reg_rising = NCT38XX_REG_GPIO_ALERT_RISE(port); - rv = i2c_read8(i2c_port, i2c_addr, reg_rising, &rising); - if (rv != EC_SUCCESS) - return rv; - - reg_falling = NCT38XX_REG_GPIO_ALERT_FALL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg_falling, &falling); - if (rv != EC_SUCCESS) - return rv; - - /* Handle interrupt for level trigger */ - if ((flags & GPIO_INT_F_HIGH) || (flags & GPIO_INT_F_LOW)) { - int reg_level, level; - - reg_level = NCT38XX_REG_GPIO_ALERT_LEVEL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg_level, &level); - if (rv != EC_SUCCESS) - return rv; - /* - * For "level" triggered interrupt, the related bit in - * ALERT_RISE and ALERT_FALL registers must be 0 - */ - rising &= ~mask; - falling &= ~mask; - if (flags & GPIO_INT_F_HIGH) - level |= mask; - else - level &= ~mask; - - rv = i2c_write8(i2c_port, i2c_addr, reg_rising, rising); - if (rv != EC_SUCCESS) - return rv; - rv = i2c_write8(i2c_port, i2c_addr, reg_falling, falling); - if (rv != EC_SUCCESS) - return rv; - rv = i2c_write8(i2c_port, i2c_addr, reg_level, level); - if (rv != EC_SUCCESS) - return rv; - } else if ((flags & GPIO_INT_F_RISING) || - (flags & GPIO_INT_F_FALLING)) { - if (flags & GPIO_INT_F_RISING) - rising |= mask; - else - rising &= ~mask; - if (flags & GPIO_INT_F_FALLING) - falling |= mask; - else - falling &= ~mask; - rv = i2c_write8(i2c_port, i2c_addr, reg_rising, rising); - if (rv != EC_SUCCESS) - return rv; - rv = i2c_write8(i2c_port, i2c_addr, reg_falling, falling); - if (rv != EC_SUCCESS) - return rv; - } - return EC_SUCCESS; -} - -static int nct38xx_ioex_set_flags_by_mask(int ioex, int port, int mask, - int flags) -{ - int rv, reg, val, i2c_port, i2c_addr; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - i2c_port = ioex_p->i2c_host_port; - i2c_addr = ioex_p->i2c_addr_flags; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - /* - * GPIO port 0 muxs with alternative function. Disable the alternative - * function before setting flags. - */ - if (port == 0) { - /* GPIO03 in NCT3807 is not muxed with other function. */ - if (!(chip_data[ioex].chip_id == - NCT38XX_VARIANT_3807 && mask & 0x08)) { - reg = NCT38XX_REG_MUX_CONTROL; - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - val = (val | mask); - rv = i2c_write8(i2c_port, i2c_addr, reg, val); - if (rv != EC_SUCCESS) - return rv; - } - } - - val = flags & ~NCT38XX_SUPPORT_GPIO_FLAGS; - if (val) { - CPRINTF("Flag 0x%08x is not supported\n", val); - return EC_ERROR_INVAL; - } - - /* Select open drain 0:push-pull 1:open-drain */ - reg = NCT38XX_REG_GPIO_OD_SEL(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_OPEN_DRAIN) - val |= mask; - else - val &= ~mask; - rv = i2c_write8(i2c_port, i2c_addr, reg, val); - if (rv != EC_SUCCESS) - return rv; - - nct38xx_ioex_sel_int_type(i2c_port, i2c_addr, port, mask, flags); - - /* Configure the output level */ - reg = NCT38XX_REG_GPIO_DATA_OUT(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_HIGH) - val |= mask; - else if (flags & GPIO_LOW) - val &= ~mask; - rv = i2c_write8(i2c_port, i2c_addr, reg, val); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_DIR(port); - rv = i2c_read8(i2c_port, i2c_addr, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - if (flags & GPIO_OUTPUT) - val |= mask; - else - val &= ~mask; - - return i2c_write8(i2c_port, i2c_addr, reg, val); -} - -/* - * The following functions are used for IO's interrupt support. - * - * please note that if the system needs to use an IO on NCT38XX to support - * the interrupt, the following two consideration should be taken into account. - * 1. Interrupt latency: - * Because it requires to access the registers of NCT38XX via I2C - * transaction to know the interrupt event, there is some added latency - * for the interrupt handling. If the interrupt requires short latency, - * we do not recommend to connect such a signal to the NCT38XX. - * - * 2. Shared ALERT pin: - * Because the ALERT pin is shared also with the TCPC ALERT, we do not - * recommend to connect any signal that may generate a high rate of - * interrupts so it will not interfere with the normal work of the - * TCPC. - */ -static int nct38xx_ioex_enable_interrupt(int ioex, int port, int mask, - int enable) -{ - int rv, reg, val; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = nct38xx_ioex_check_is_valid(ioex, port, mask); - if (rv != EC_SUCCESS) - return rv; - - /* Clear the pending bit */ - reg = NCT38XX_REG_GPIO_ALERT_STAT(port); - rv = i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, &val); - if (rv != EC_SUCCESS) - return rv; - - val |= mask; - rv = i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, val); - if (rv != EC_SUCCESS) - return rv; - - reg = NCT38XX_REG_GPIO_ALERT_MASK(port); - if (enable) { - /* Enable the alert mask */ - chip_data[ioex].int_mask[port] |= mask; - val = chip_data[ioex].int_mask[port]; - } else { - /* Disable the alert mask */ - chip_data[ioex].int_mask[port] &= ~mask; - val = chip_data[ioex].int_mask[port]; - } - - return i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, val); -} - -int nct38xx_ioex_event_handler(int ioex) -{ - int reg, int_status, int_mask; - int i, j, total_port; - const struct ioex_info *g; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - int rv = 0; - - int_mask = chip_data[ioex].int_mask[0] | ( - chip_data[ioex].int_mask[1] << 8); - reg = NCT38XX_REG_GPIO_ALERT_STAT(0); - /* - * Read ALERT_STAT_0 and ALERT_STAT_1 register in a single I2C - * transaction to increase efficiency - */ - rv = i2c_read16(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, &int_status); - if (rv != EC_SUCCESS) - return rv; - - int_status = int_status & int_mask; - /* - * Clear the changed status bits in ALERT_STAT_0 and ALERT_STAT_1 - * register in a single I2C transaction to increase efficiency - */ - rv = i2c_write16(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, int_status); - if (rv != EC_SUCCESS) - return rv; - - /* For NCT3808, only check one port */ - total_port = (chip_data[ioex].chip_id == NCT38XX_VARIANT_3808) ? - NCT38XX_NCT3808_MAX_IO_PORT : - NCT38XX_NCT3807_MAX_IO_PORT; - for (i = 0; i < total_port; i++) { - uint8_t pending; - - pending = int_status >> (i * 8); - - if (!pending) - continue; - - for (j = 0, g = ioex_list; j < ioex_ih_count; j++, g++) { - - if (ioex == g->ioex && i == g->port && - (pending & g->mask)) { - ioex_irq_handlers[j](j + IOEX_SIGNAL_START); - pending &= ~g->mask; - if (!pending) - break; - } - - } - } - - return EC_SUCCESS; -} - -/* - * Normally, the ALERT MASK for Vendor Define event should be checked by - * the NCT38XX TCPCI driver's tcpc_alert function. - * However, it should be checked here if we want to test the interrupt - * function of IOEX when the NCT38XX TCPCI driver is not included. - */ -void nct38xx_ioex_handle_alert(int ioex) -{ - int rv, status; - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - rv = i2c_read16(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - TCPC_REG_ALERT, &status); - if (rv != EC_SUCCESS) - CPRINTF("fail to read ALERT register\n"); - - if (status & TCPC_REG_ALERT_VENDOR_DEF) { - rv = i2c_write16(ioex_p->i2c_host_port, - ioex_p->i2c_addr_flags, TCPC_REG_ALERT, - TCPC_REG_ALERT_VENDOR_DEF); - if (rv != EC_SUCCESS) { - CPRINTF("Fail to clear Vendor Define mask\n"); - return; - } - nct38xx_ioex_event_handler(ioex); - } -} - -const struct ioexpander_drv nct38xx_ioexpander_drv = { - .init = &nct38xx_ioex_init, - .get_level = &nct38xx_ioex_get_level, - .set_level = &nct38xx_ioex_set_level, - .get_flags_by_mask = &nct38xx_ioex_get_flags, - .set_flags_by_mask = &nct38xx_ioex_set_flags_by_mask, - .enable_interrupt = &nct38xx_ioex_enable_interrupt, -}; diff --git a/driver/ioexpander/it8300.h b/driver/ioexpander/it8300.h deleted file mode 100644 index 2b47e7f3e1..0000000000 --- a/driver/ioexpander/it8300.h +++ /dev/null @@ -1,106 +0,0 @@ -/* Copyright 2018 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. - * - * ITE IT8300 I/O Port expander driver header - */ - -#ifndef __CROS_EC_IOEXPANDER_IT8300_H -#define __CROS_EC_IOEXPANDER_IT8300_H - -#include "i2c.h" - -/* Gather Interrupt Status Register */ -#define IT8300_GISR 0x0 - -/* Interrupt Status Registers */ -#define IT8300_ISR_A 0x6 -#define IT8300_ISR_B 0x7 -#define IT8300_ISR_C 0x28 -#define IT8300_ISR_D 0x2E -#define IT8300_ISR_E 0x2F - -/* Port Data Register Groups */ -#define IT8300_PDGR_A 0x1 -#define IT8300_PDGR_B 0x2 -#define IT8300_PDGR_C 0x3 -#define IT8300_PDGR_D 0x4 -#define IT8300_PDGR_E 0x5 - -/* GPIO Port Control n Registers */ -#define IT8300_GPCR_A0 0x10 -#define IT8300_GPCR_A1 0x11 -#define IT8300_GPCR_A2 0x12 -#define IT8300_GPCR_A3 0x13 -#define IT8300_GPCR_A4 0x14 -#define IT8300_GPCR_A5 0x15 -#define IT8300_GPCR_A6 0x16 -#define IT8300_GPCR_A7 0x17 - -#define IT8300_GPCR_B0 0x18 -#define IT8300_GPCR_B1 0x19 -#define IT8300_GPCR_B2 0x1A -#define IT8300_GPCR_B3 0x1B -#define IT8300_GPCR_B4 0x1C -#define IT8300_GPCR_B5 0x1D -#define IT8300_GPCR_B6 0x1E - -#define IT8300_GPCR_C0 0x20 -#define IT8300_GPCR_C1 0x21 -#define IT8300_GPCR_C2 0x22 -#define IT8300_GPCR_C3 0x23 -#define IT8300_GPCR_C4 0x24 -#define IT8300_GPCR_C5 0x25 -#define IT8300_GPCR_C6 0x26 - -#define IT8300_GPCR_D0 0x08 -#define IT8300_GPCR_D1 0x09 -#define IT8300_GPCR_D2 0x0A -#define IT8300_GPCR_D3 0x0B -#define IT8300_GPCR_D4 0x0C -#define IT8300_GPCR_D5 0x0D - -#define IT8300_GPCR_E0 0x32 - -#define IT8300_GPCR_E2 0x34 -#define IT8300_GPCR_E3 0x35 -#define IT8300_GPCR_E4 0x36 -#define IT8300_GPCR_E5 0x37 -#define IT8300_GPCR_E6 0x38 - -#define IT8300_GPCR_GPI_MODE BIT(7) -#define IT8300_GPCR_GP0_MODE BIT(6) -#define IT8300_GPCR_PULL_UP_EN BIT(2) -#define IT8300_GPCR_PULL_DN_EN BIT(1) - -/* EXGPIO Clear Alert */ -#define IT8300_ECA 0x30 - -/* EXGPIO Alert Enable */ -#define IT8300_EAE 0x31 - -/* Port Data Mirror Registers */ -#define IT8300_PDMRA_A 0x29 -#define IT8300_PDMRA_B 0x2A -#define IT8300_PDMRA_C 0x2B -#define IT8300_PDMRA_D 0x2C -#define IT8300_PDMRA_E 0x2D - -/* Output Open-Drain Enable Registers */ -#define IT8300_OODER_A 0x39 -#define IT8300_OODER_B 0x3A -#define IT8300_OODER_C 0x3B -#define IT8300_OODER_D 0x3C -#define IT8300_OODER_E 0x3D - -/* IT83200 Port GPIOs */ -#define IT8300_GPX_0 BIT(0) -#define IT8300_GPX_1 BIT(1) -#define IT8300_GPX_2 BIT(2) -#define IT8300_GPX_3 BIT(3) -#define IT8300_GPX_4 BIT(4) -#define IT8300_GPX_5 BIT(5) -#define IT8300_GPX_6 BIT(6) -#define IT8300_GPX_7 BIT(7) - -#endif /* __CROS_EC_IOEXPANDER_IT8300_H */ diff --git a/driver/ioexpander/it8801.c b/driver/ioexpander/it8801.c deleted file mode 100644 index 96070074fb..0000000000 --- a/driver/ioexpander/it8801.c +++ /dev/null @@ -1,683 +0,0 @@ -/* Copyright 2019 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 "console.h" -#include "gpio.h" -#include "hooks.h" -#include "i2c.h" -#include "ioexpander.h" -#include "it8801.h" -#include "keyboard_raw.h" -#include "keyboard_scan.h" -#include "registers.h" -#include "task.h" -#include "util.h" -#include "keyboard_backlight.h" - -#define CPRINTS(format, args...) cprints(CC_KEYSCAN, format, ## args) - -static int it8801_ioex_set_level(int ioex, int port, int mask, int value); -static void it8801_ioex_event_handler(void); -DECLARE_DEFERRED(it8801_ioex_event_handler); - -static int it8801_read(int reg, int *data) -{ - return i2c_read8(IT8801_KEYBOARD_PWM_I2C_PORT, - IT8801_KEYBOARD_PWM_I2C_ADDR_FLAGS, reg, data); -} - -__maybe_unused static int it8801_write(int reg, int data) -{ - return i2c_write8(IT8801_KEYBOARD_PWM_I2C_PORT, - IT8801_KEYBOARD_PWM_I2C_ADDR_FLAGS, reg, data); -} - -struct it8801_vendor_id_t { - uint8_t chip_id; - uint8_t reg; -}; - -static const struct it8801_vendor_id_t it8801_vendor_id_verify[] = { - { 0x12, IT8801_REG_HBVIDR}, - { 0x83, IT8801_REG_LBVIDR}, -}; - -static int it8801_check_vendor_id(void) -{ - int i, ret, val; - - /* Verify vendor ID registers(16-bits). */ - for (i = 0; i < ARRAY_SIZE(it8801_vendor_id_verify); i++) { - ret = it8801_read(it8801_vendor_id_verify[i].reg, &val); - - if (ret != EC_SUCCESS) - return ret; - - if (val != it8801_vendor_id_verify[i].chip_id) - return EC_ERROR_UNKNOWN; - } - - return EC_SUCCESS; -} - -/* - * Keyboard and GPIO interrupts are muxed inside the IT8801 chip. - * Interrupt enable register controls the individual pins from - * triggering this global interrupt hence it is okay that this - * pin is enabled all the time. - */ -static void it8801_muxed_kbd_gpio_intr_enable(void) -{ - static bool intr_enabled; - - /* - * Allow enabling this pin either by Keyboard enable code or - * IOEX init code whichever gets called first. - */ - if (!intr_enabled) { - gpio_clear_pending_interrupt(GPIO_IT8801_SMB_INT); - gpio_enable_interrupt(GPIO_IT8801_SMB_INT); - intr_enabled = true; - } -} - -#ifdef CONFIG_KEYBOARD_NOT_RAW -void keyboard_raw_init(void) -{ - int ret; - - /* Verify Vendor ID registers. */ - ret = it8801_check_vendor_id(); - if (ret) { - CPRINTS("Failed to read IT8801 vendor id %x", ret); - return; - } - - /* KSO alternate function switching(KSO[21:20, 18]). */ - it8801_write(IT8801_REG_GPIO01_KSO18, IT8801_REG_MASK_GPIOAFS_FUNC2); - it8801_write(IT8801_REG_GPIO22_KSO21, IT8801_REG_MASK_GPIOAFS_FUNC2); - it8801_write(IT8801_REG_GPIO23_KSO20, IT8801_REG_MASK_GPIOAFS_FUNC2); - - /* Start with KEYBOARD_COLUMN_ALL, KSO[22:11, 6:0] output low. */ - it8801_write(IT8801_REG_KSOMCR, IT8801_REG_MASK_AKSOSC); - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* - * Since most of the KSO pins can't drive up, we'll must use - * a pin capable of being a GPIO instead and use the GPIO - * feature to do the required inverted push pull. - */ - it8801_write(IT8801_REG_GPIO23_KSO20, IT8801_REG_MASK_GPIODIR); - - /* Start with KEYBOARD_COLUMN_ALL, output high(so selected). */ - it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 1); - } - - /* Keyboard scan in interrupt enable register */ - it8801_write(IT8801_REG_KSIIER, 0xff); - /* Gather KSI interrupt enable */ - it8801_write(IT8801_REG_GIECR, IT8801_REG_MASK_GKSIIE); - /* Alert response enable */ - it8801_write(IT8801_REG_SMBCR, IT8801_REG_MASK_ARE); - - keyboard_raw_enable_interrupt(0); -} - -void keyboard_raw_task_start(void) -{ - keyboard_raw_enable_interrupt(1); -} - -__overridable const uint8_t it8801_kso_mapping[] = { - 0, 1, 20, 3, 4, 5, 6, 17, 18, 16, 15, 11, 12, -#ifdef CONFIG_KEYBOARD_KEYPAD - 13, 14 -#endif -}; -BUILD_ASSERT(ARRAY_SIZE(it8801_kso_mapping) == KEYBOARD_COLS_MAX); - -test_mockable void keyboard_raw_drive_column(int col) -{ - int kso_val; - - /* Tri-state all outputs */ - if (col == KEYBOARD_COLUMN_NONE) { - /* KSO[22:11, 6:0] output high */ - kso_val = IT8801_REG_MASK_KSOSDIC | IT8801_REG_MASK_AKSOSC; - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* Output low(so not selected). */ - it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 0); - } - } - /* Assert all outputs */ - else if (col == KEYBOARD_COLUMN_ALL) { - /* KSO[22:11, 6:0] output low */ - kso_val = IT8801_REG_MASK_AKSOSC; - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* Output high(so selected). */ - it8801_ioex_set_level(0, 2, IT8801_REG_GPIO23SOV, 1); - } - } else { - /* To check if column is valid or not. */ - if (col >= KEYBOARD_COLS_MAX) - return; - /* - * Selected KSO[20, 18:11, 6:3, 1:0] output low, - * all others KSO output high. - */ - kso_val = it8801_kso_mapping[col]; - - if (IS_ENABLED(CONFIG_KEYBOARD_COL2_INVERTED)) { - /* GPIO23 is inverted. */ - if (col == IT8801_REG_MASK_SELKSO2) { - /* Output high(so selected). */ - it8801_ioex_set_level(0, 2, - IT8801_REG_GPIO23SOV, 1); - } else { - /* Output low(so not selected). */ - it8801_ioex_set_level(0, 2, - IT8801_REG_GPIO23SOV, 0); - } - } - } - - it8801_write(IT8801_REG_KSOMCR, kso_val); -} - -test_mockable int keyboard_raw_read_rows(void) -{ - int data = 0; - int ksieer = 0; - - it8801_read(IT8801_REG_KSIDR, &data); - - /* This register needs to write clear after reading data */ - it8801_read(IT8801_REG_KSIEER, &ksieer); - it8801_write(IT8801_REG_KSIEER, ksieer); - - /* Bits are active-low, so invert returned levels */ - return (~data) & 0xff; -} - -void keyboard_raw_enable_interrupt(int enable) -{ - if (enable) { - /* Clear pending iterrupts */ - it8801_write(IT8801_REG_KSIEER, 0xff); - - /* Enable muxed Keyboard & GPIO interrupt */ - it8801_muxed_kbd_gpio_intr_enable(); - } - - it8801_write(IT8801_REG_KSIIER, enable ? 0xff : 0x00); -} -#endif /* CONFIG_KEYBOARD_NOT_RAW */ - -void io_expander_it8801_interrupt(enum gpio_signal signal) -{ - hook_call_deferred(&it8801_ioex_event_handler_data, 0); -} - -static int it8801_ioex_read(int ioex, int reg, int *data) -{ - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - return i2c_read8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); -} - -static int it8801_ioex_write(int ioex, int reg, int data) -{ - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - return i2c_write8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data); -} - -static int it8801_ioex_update(int ioex, int reg, int data, - enum mask_update_action action) -{ - struct ioexpander_config_t *ioex_p = &ioex_config[ioex]; - - return i2c_update8(ioex_p->i2c_host_port, ioex_p->i2c_addr_flags, - reg, data, action); -} - -static const int it8801_valid_gpio_group[] = { - IT8801_VALID_GPIO_G0_MASK, - IT8801_VALID_GPIO_G1_MASK, - IT8801_VALID_GPIO_G2_MASK, -}; - -/* Mutexes */ -static struct mutex ioex_mutex; - -static uint8_t it8801_gpio_sov[ARRAY_SIZE(it8801_valid_gpio_group)]; - -/* - * Initialize the general purpose I/O port(GPIO) - */ -static int it8801_ioex_init(int ioex) -{ - int ret, port, val = 0; - - /* Verify Vendor ID registers. */ - ret = it8801_check_vendor_id(); - if (ret) { - CPRINTS("Failed to read IT8801 vendor id %x", ret); - return ret; - } - - /* - * We will read the value of SOVR and write it to the - * cache(it8801_gpio_sov[port]) to avoid causing cache - * to reset when EC is reset. - */ - for (port = 0; port < ARRAY_SIZE(it8801_valid_gpio_group); port++) { - it8801_ioex_read(ioex, IT8801_REG_GPIO_SOVR(port), &val); - it8801_gpio_sov[port] = val; - } - - /* Enable muxed Keyboard & GPIO interrupt */ - it8801_muxed_kbd_gpio_intr_enable(); - - return EC_SUCCESS; -} - -static int ioex_check_is_not_valid(int port, int mask) -{ - if (port >= ARRAY_SIZE(it8801_valid_gpio_group)) { - CPRINTS("Port%d is not support in IT8801", port); - return EC_ERROR_INVAL; - } - - if (mask & ~it8801_valid_gpio_group[port]) { - CPRINTS("GPIO%d-%d is not support in IT8801", port, - __fls(mask & ~it8801_valid_gpio_group[port])); - return EC_ERROR_INVAL; - } - - return EC_SUCCESS; -} - -static int it8801_ioex_get_level(int ioex, int port, int mask, int *val) -{ - int rv; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_IPSR(port), val); - - *val = !!(*val & mask); - - return rv; -} - -static int it8801_ioex_set_level(int ioex, int port, int mask, int value) -{ - int rv = EC_SUCCESS; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - mutex_lock(&ioex_mutex); - /* - * The bit of output value in SOV is different than - * the one we were about to set it to. - */ - if (!!(it8801_gpio_sov[port] & mask) ^ value) { - if (value) - it8801_gpio_sov[port] |= mask; - else - it8801_gpio_sov[port] &= ~mask; - - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_SOVR(port), - it8801_gpio_sov[port]); - } - mutex_unlock(&ioex_mutex); - - return rv; -} - -static int it8801_ioex_get_flags_by_mask(int ioex, int port, - int mask, int *flags) -{ - int rv, val; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_CR(port, mask), &val); - if (rv) - return rv; - - *flags = 0; - - /* Get GPIO direction */ - *flags |= (val & IT8801_GPIODIR) ? GPIO_OUTPUT : GPIO_INPUT; - - /* Get GPIO type, 0:push-pull 1:open-drain */ - if (val & IT8801_GPIOIOT) - *flags |= GPIO_OPEN_DRAIN; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_IPSR(port), &val); - if (rv) - return rv; - - /* Get GPIO output level */ - *flags |= (val & mask) ? GPIO_HIGH : GPIO_LOW; - - return EC_SUCCESS; -} - -static int it8801_ioex_set_flags_by_mask(int ioex, int port, - int mask, int flags) -{ - int rv, val; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - if (flags & ~IT8801_SUPPORT_GPIO_FLAGS) { - CPRINTS("Flag 0x%08x is not supported at port %d, mask %d", - flags, port, mask); - return EC_ERROR_INVAL; - } - - /* GPIO alternate function switching(GPIO[00, 12:15, 20:23]). */ - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_CR(port, mask), - IT8801_REG_MASK_GPIOAFS_FUNC1); - if (rv) - return rv; - - mutex_lock(&ioex_mutex); - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_CR(port, mask), &val); - if (rv) - goto unlock_mutex; - - /* Select open drain 0:push-pull 1:open-drain */ - if (flags & GPIO_OPEN_DRAIN) - val |= IT8801_GPIOIOT; - else - val &= ~IT8801_GPIOIOT; - - /* Select GPIO direction */ - if (flags & GPIO_OUTPUT) { - /* Configure the output level */ - if (flags & GPIO_HIGH) - it8801_gpio_sov[port] |= mask; - else - it8801_gpio_sov[port] &= ~mask; - - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_SOVR(port), - it8801_gpio_sov[port]); - if (rv) - goto unlock_mutex; - - val |= IT8801_GPIODIR; - } else { - val &= ~IT8801_GPIODIR; - } - - /* Set Interrupt Type */ - if (flags & GPIO_INT_RISING) - val |= IT8801_GPIOIOT_INT_RISING; - if (flags & GPIO_INT_FALLING) - val |= IT8801_GPIOIOT_INT_FALLING; - - rv = it8801_ioex_write(ioex, IT8801_REG_GPIO_CR(port, mask), val); - -unlock_mutex: - mutex_unlock(&ioex_mutex); - - return rv; -} - -/* Enable the individual GPIO interrupt pins based on the board requirement. */ -static int it8801_ioex_enable_interrupt(int ioex, int port, int mask, - int enable) -{ - int rv; - - if (ioex_check_is_not_valid(port, mask)) - return EC_ERROR_INVAL; - - /* Clear pending interrupt */ - rv = it8801_ioex_update(ioex, IT8801_REG_GPIO_ISR(port), - mask, MASK_SET); - if (rv) - return rv; - - return it8801_ioex_update(ioex, IT8801_REG_GPIO_IER(port), - mask, enable ? MASK_SET : MASK_CLR); -} - -static void it8801_ioex_irq(int ioex, int port) -{ - int rv, data, i; - const struct ioex_info *g; - - rv = it8801_ioex_read(ioex, IT8801_REG_GPIO_ISR(port), &data); - if (rv || !data) - return; - - /* Trigger the intended interrupt from the IOEX IRQ pins */ - for (i = 0, g = ioex_list; i < ioex_ih_count; i++, g++) { - if (ioex == g->ioex && port == g->port && data & g->mask) { - ioex_irq_handlers[i](i + IOEX_SIGNAL_START); - data &= ~g->mask; - - /* Clear pending interrupt */ - it8801_ioex_update(ioex, IT8801_REG_GPIO_ISR(port), - g->mask, MASK_SET); - - if (!data) - break; - } - } -} - -static void it8801_ioex_event_handler(void) -{ - int data, i; - - /* Gather KSI interrupt status register */ - if (it8801_read(IT8801_REG_GISR, &data)) - return; - - /* Wake the keyboard scan task if KSI interrupts are triggered */ - if (IS_ENABLED(CONFIG_KEYBOARD_NOT_RAW) && - data & IT8801_REG_MASK_GISR_GKSIIS) - task_wake(TASK_ID_KEYSCAN); - - /* - * Trigger the GPIO callback functions if the GPIO interrupts are - * triggered. - */ - if (data & (IT8801_REG_MASK_GISR_GGPIOGXIS)) { - for (i = 0; i < CONFIG_IO_EXPANDER_PORT_COUNT; i++) { - if (ioex_config[i].drv == &it8801_ioexpander_drv) { - /* Interrupt from GPIO port 0 is triggered */ - if (data & IT8801_REG_MASK_GISR_GGPIOG0IS) - it8801_ioex_irq(i, 0); - /* Interrupt from GPIO port 1 is triggered */ - if (data & IT8801_REG_MASK_GISR_GGPIOG1IS) - it8801_ioex_irq(i, 1); - /* Interrupt from GPIO port 2 is triggered */ - if (data & IT8801_REG_MASK_GISR_GGPIOG2IS) - it8801_ioex_irq(i, 2); - } - } - } -} - -const struct ioexpander_drv it8801_ioexpander_drv = { - .init = &it8801_ioex_init, - .get_level = &it8801_ioex_get_level, - .set_level = &it8801_ioex_set_level, - .get_flags_by_mask = &it8801_ioex_get_flags_by_mask, - .set_flags_by_mask = &it8801_ioex_set_flags_by_mask, - .enable_interrupt = &it8801_ioex_enable_interrupt, -}; - -static void dump_register(int reg) -{ - int rv; - int data; - - ccprintf("[%Xh] = ", reg); - - rv = it8801_read(reg, &data); - - if (!rv) - ccprintf("0x%02x\n", data); - else - ccprintf("ERR (%d)\n", rv); -} - -static int it8801_dump(int argc, char **argv) -{ - dump_register(IT8801_REG_KSIIER); - dump_register(IT8801_REG_KSIEER); - dump_register(IT8801_REG_KSIDR); - dump_register(IT8801_REG_KSOMCR); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(it8801_dump, it8801_dump, "NULL", - "Dumps IT8801 registers"); - -#ifdef CONFIG_IO_EXPANDER_IT8801_PWM - -struct it8801_pwm_gpio_map { - int port; - int mask; - int pushpull_en; -}; - -const static struct it8801_pwm_gpio_map it8801_pwm_gpio_map[] = { - [1] = {.port = 1, .mask = BIT(2), .pushpull_en = BIT(0)}, - [2] = {.port = 1, .mask = BIT(3), .pushpull_en = BIT(1)}, - [3] = {.port = 1, .mask = BIT(4), .pushpull_en = BIT(2)}, - [4] = {.port = 1, .mask = BIT(5), .pushpull_en = BIT(3)}, - [7] = {.port = 2, .mask = BIT(0), .pushpull_en = BIT(4)}, - [8] = {.port = 2, .mask = BIT(3), .pushpull_en = BIT(5)}, - [9] = {.port = 2, .mask = BIT(2), .pushpull_en = BIT(6)}, -}; - -void it8801_pwm_enable(enum pwm_channel ch, int enabled) -{ - int port, mask, val, index; - - index = it8801_pwm_channels[ch].index; - if (index < 0 || index >= ARRAY_SIZE(it8801_pwm_gpio_map)) - return; - port = it8801_pwm_gpio_map[index].port; - mask = it8801_pwm_gpio_map[index].mask; - if (port == 0 && mask == 0) - return; - - /* - * PWM1~4,7: alt func 1 - * PWM8,9: alt func 2 - */ - if (it8801_pwm_channels[ch].index <= 7) - it8801_write(IT8801_REG_GPIO_CR(port, mask), - 0x1 << IT8801_GPIOAFS_SHIFT); - else - it8801_write(IT8801_REG_GPIO_CR(port, mask), - 0x2 << IT8801_GPIOAFS_SHIFT); - - it8801_read(IT8801_REG_PWMMCR(it8801_pwm_channels[ch].index), &val); - val &= (~IT8801_PWMMCR_MCR_MASK); - if (enabled) - val |= IT8801_PWMMCR_MCR_BLINKING; - it8801_write(IT8801_REG_PWMMCR(it8801_pwm_channels[ch].index), val); - - /* - * 1: enable push pull function - */ - it8801_read(IT8801_REG_PWMODDSR, &val); - val &= ~it8801_pwm_gpio_map[index].pushpull_en; - if (enabled) - val |= it8801_pwm_gpio_map[index].pushpull_en; - it8801_write(IT8801_REG_PWMODDSR, val); - -} - -int it8801_pwm_get_enabled(enum pwm_channel ch) -{ - int val; - - if (it8801_read(IT8801_REG_PWMMCR(it8801_pwm_channels[ch].index), &val)) - return 0; - return (val & IT8801_PWMMCR_MCR_MASK) == IT8801_PWMMCR_MCR_BLINKING; -} - -void it8801_pwm_set_raw_duty(enum pwm_channel ch, uint16_t duty) -{ - duty = MIN(duty, 255); - duty = MAX(duty, 0); - it8801_write(IT8801_REG_PWMDCR(it8801_pwm_channels[ch].index), duty); -} - -uint16_t it8801_pwm_get_raw_duty(enum pwm_channel ch) -{ - int val; - - if (it8801_read(IT8801_REG_PWMDCR(it8801_pwm_channels[ch].index), &val)) - return 0; - return val; -} - -void it8801_pwm_set_duty(enum pwm_channel ch, int percent) -{ - return it8801_pwm_set_raw_duty(ch, percent * 255 / 100); -} - -int it8801_pwm_get_duty(enum pwm_channel ch) -{ - return it8801_pwm_get_raw_duty(ch) * 100 / 255; -} - -#ifdef CONFIG_KEYBOARD_BACKLIGHT -const enum pwm_channel it8801_kblight_pwm_ch = IT8801_PWM_CH_KBLIGHT; - -static int it8801_kblight_enable(int enable) -{ - it8801_pwm_enable(it8801_kblight_pwm_ch, enable); - return EC_SUCCESS; -} - -static int it8801_kblight_set_brightness(int percent) -{ - it8801_pwm_set_duty(it8801_kblight_pwm_ch, percent); - return EC_SUCCESS; -} - -static int it8801_kblight_get_brightness(void) -{ - return it8801_pwm_get_duty(it8801_kblight_pwm_ch); -} - -static int it8801_kblight_init(void) -{ - it8801_pwm_set_duty(it8801_kblight_pwm_ch, 0); - it8801_pwm_enable(it8801_kblight_pwm_ch, 1); - return EC_SUCCESS; -} - -const struct kblight_drv kblight_it8801 = { - .init = it8801_kblight_init, - .set = it8801_kblight_set_brightness, - .get = it8801_kblight_get_brightness, - .enable = it8801_kblight_enable, -}; -#endif -#endif /* CONFIG_IO_EXPANDER_IT8801_PWM */ diff --git a/driver/ioexpander/it8801.h b/driver/ioexpander/it8801.h deleted file mode 100644 index 05a17acf78..0000000000 --- a/driver/ioexpander/it8801.h +++ /dev/null @@ -1,126 +0,0 @@ -/* Copyright 2019 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. - * - * IT8801 is an I/O expander with the keyboard matrix controller. - * - */ - -#ifndef __CROS_EC_IO_EXPANDER_IT8801_H -#define __CROS_EC_IO_EXPANDER_IT8801_H - -/* I2C address flags (7-bit without R/W) */ -#define IT8801_I2C_ADDR1 0x38 -#define IT8801_I2C_ADDR2 0x39 - -/* Keyboard Matrix Scan control (KBS) */ -#define IT8801_REG_KSOMCR 0x40 -#define IT8801_REG_MASK_KSOSDIC BIT(7) -#define IT8801_REG_MASK_KSE BIT(6) -#define IT8801_REG_MASK_AKSOSC BIT(5) -#define IT8801_REG_KSIDR 0x41 -#define IT8801_REG_KSIEER 0x42 -#define IT8801_REG_KSIIER 0x43 -#define IT8801_REG_SMBCR 0xfa -#define IT8801_REG_MASK_ARE BIT(4) -#define IT8801_REG_GIECR 0xfb -#define IT8801_REG_MASK_GKSIIE BIT(3) -#define IT8801_REG_GPIO10 0x12 -#define IT8801_REG_GPIO00_KSO19 0x0a -#define IT8801_REG_GPIO01_KSO18 0x0b -#define IT8801_REG_GPIO22_KSO21 0x1c -#define IT8801_REG_GPIO23_KSO20 0x1d -#define IT8801_REG_MASK_GPIOAFS_PULLUP BIT(7) -#define IT8801_REG_MASK_GPIOAFS_FUNC2 BIT(6) -#define IT8801_REG_MASK_GPIODIR BIT(5) -#define IT8801_REG_MASK_GPIOPUE BIT(0) -#define IT8801_REG_GPIO23SOV BIT(3) -#define IT8801_REG_MASK_SELKSO2 0x02 -#define IT8801_REG_GISR 0xF9 -#define IT8801_REG_MASK_GISR_GKSIIS BIT(6) -#define IT8801_REG_MASK_GISR_GGPIOG2IS BIT(2) -#define IT8801_REG_MASK_GISR_GGPIOG1IS BIT(1) -#define IT8801_REG_MASK_GISR_GGPIOG0IS BIT(0) -#define IT8801_REG_MASK_GISR_GGPIOGXIS (IT8801_REG_MASK_GISR_GGPIOG2IS | \ - IT8801_REG_MASK_GISR_GGPIOG1IS | IT8801_REG_MASK_GISR_GGPIOG0IS) -#define IT8801_REG_LBVIDR 0xFE -#define IT8801_REG_HBVIDR 0xFF -#define IT8801_KSO_COUNT 18 - -/* General Purpose I/O Port (GPIO) */ -#define IT8801_SUPPORT_GPIO_FLAGS (GPIO_OPEN_DRAIN | GPIO_INPUT | \ - GPIO_OUTPUT | GPIO_LOW | GPIO_HIGH | GPIO_INT_ANY) - -#define IT8801_REG_MASK_GPIOAFS_FUNC1 (0x00 << 7) - -/* IT8801 only supports GPIO 0/1/2 */ -#define IT8801_VALID_GPIO_G0_MASK 0xD9 -#define IT8801_VALID_GPIO_G1_MASK 0x3F -#define IT8801_VALID_GPIO_G2_MASK 0x0F - -extern __override_proto const uint8_t it8801_kso_mapping[]; -extern const struct ioexpander_drv it8801_ioexpander_drv; - -/* GPIO Register map */ -/* Input pin status register */ -#define IT8801_REG_GPIO_IPSR(port) (0x00 + (port)) -/* Set output value register */ -#define IT8801_REG_GPIO_SOVR(port) (0x05 + (port)) -/* Control register */ -#define IT8801_REG_GPIO_CR(port, mask) \ - (0x0A + (port) * 8 + GPIO_MASK_TO_NUM(mask)) -/* Interrupt status register */ -#define IT8801_REG_GPIO_ISR(port) (0x32 + (port)) -/* Interrupt enable register */ -#define IT8801_REG_GPIO_IER(port) (0x37 + (port)) - -/* Control register values */ -#define IT8801_GPIOAFS_SHIFT 6 /* bit 6~7 */ - -#define IT8801_GPIODIR BIT(5) /* direction, output=1 */ -/* input pin */ -#define IT8801_GPIOIOT_INT_RISING BIT(3) -#define IT8801_GPIOIOT_INT_FALLING BIT(4) - -#define IT8801_GPIODIR BIT(5) -#define IT8801_GPIOIOT BIT(4) -#define IT8801_GPIOPOL BIT(2) /* polarity */ -#define IT8801_GPIOPDE BIT(1) /* pull-down enable */ -#define IT8801_GPIOPUE BIT(0) /* pull-up enable */ - -/* ISR for IT8801's SMB_INT# */ -void io_expander_it8801_interrupt(enum gpio_signal signal); - -#ifdef CONFIG_IO_EXPANDER_IT8801_PWM - -/* Mapping PWM_CH_LED_* to it8801 channel */ -struct it8801_pwm_t { - int index; -}; - -extern const struct it8801_pwm_t it8801_pwm_channels[]; -extern const struct kblight_drv kblight_it8801; - -/* standard pwm interface as defined in pwm.h */ -void it8801_pwm_enable(enum pwm_channel ch, int enabled); -int it8801_pwm_get_enabled(enum pwm_channel ch); -void it8801_pwm_set_raw_duty(enum pwm_channel ch, uint16_t duty); -uint16_t it8801_pwm_get_raw_duty(enum pwm_channel ch); -void it8801_pwm_set_duty(enum pwm_channel ch, int percent); -int it8801_pwm_get_duty(enum pwm_channel ch); - -#define IT8801_REG_PWMODDSR 0x5F -#define IT8801_REG_PWMMCR(n) (0x60 + ((n) - 1) * 8) -#define IT8801_REG_PWMDCR(n) (0x64 + ((n) - 1) * 8) -#define IT8801_REG_PWMPRSL(n) (0x66 + ((n) - 1) * 8) -#define IT8801_REG_PWMPRSM(n) (0x67 + ((n) - 1) * 8) - -#define IT8801_PWMMCR_MCR_MASK 0x3 -#define IT8801_PWMMCR_MCR_OFF 0 -#define IT8801_PWMMCR_MCR_BLINKING 1 -#define IT8801_PWMMCR_MCR_BREATHING 2 -#define IT8801_PWMMCR_MCR_ON 3 - -#endif /* CONFIG_IO_EXPANDER_IT8801_PWM */ - -#endif /* __CROS_EC_KBEXPANDER_IT8801_H */ diff --git a/driver/ioexpander/pca9534.c b/driver/ioexpander/pca9534.c deleted file mode 100644 index d56eb864cb..0000000000 --- a/driver/ioexpander/pca9534.c +++ /dev/null @@ -1,52 +0,0 @@ -/* Copyright 2014 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 PCA9534 I/O expander - */ - -#include "i2c.h" -#include "pca9534.h" - -static int pca9534_pin_read(const int port, const uint16_t addr_flags, - int reg, int pin, int *val) -{ - int ret; - ret = i2c_read8(port, addr_flags, reg, val); - *val = (*val & BIT(pin)) ? 1 : 0; - return ret; -} - -static int pca9534_pin_write(const int port, const uint16_t addr_flags, - int reg, int pin, int val) -{ - int ret, v; - ret = i2c_read8(port, addr_flags, reg, &v); - if (ret != EC_SUCCESS) - return ret; - v &= ~BIT(pin); - if (val) - v |= 1 << pin; - return i2c_write8(port, addr_flags, reg, v); -} - -int pca9534_get_level(const int port, const uint16_t addr_flags, - int pin, int *level) -{ - return pca9534_pin_read(port, addr_flags, - PCA9534_REG_INPUT, pin, level); -} - -int pca9534_set_level(const int port, const uint16_t addr_flags, - int pin, int level) -{ - return pca9534_pin_write(port, addr_flags, - PCA9534_REG_OUTPUT, pin, level); -} - -int pca9534_config_pin(const int port, const uint16_t addr_flags, - int pin, int is_input) -{ - return pca9534_pin_write(port, addr_flags, - PCA9534_REG_CONFIG, pin, is_input); -} diff --git a/driver/ioexpander/pca9534.h b/driver/ioexpander/pca9534.h deleted file mode 100644 index 0fec577576..0000000000 --- a/driver/ioexpander/pca9534.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Copyright 2014 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 PCA9534 I/O expander - */ - -#ifndef __CROS_EC_IOEXPANDER_PCA9534_H -#define __CROS_EC_IOEXPANDER_PCA9534_H - -#define PCA9534_REG_INPUT 0x0 -#define PCA9534_REG_OUTPUT 0x1 -#define PCA9534_REG_CONFIG 0x3 - -#define PCA9534_OUTPUT 0 -#define PCA9534_INPUT 1 - -/* - * Get input level. Note that this reflects the actual level on the - * pin, even if the pin is configured as output. - * - * @param port The I2C port of PCA9534. - * @param addr The address of PCA9534. - * @param pin The index of the pin to read. - * @param level The pointer to where the read level is stored. - * - * @return EC_SUCCESS, or EC_ERROR_* on error. - */ -int pca9534_get_level(const int port, const uint16_t addr_flags, - int pin, int *level); - -/* - * Set output level. This function has no effect if the pin is - * configured as input. - * - * @param port The I2C port of PCA9534. - * @param addr The address of PCA9534. - * @param pin The index of the pin to set. - * @param level The level to set. - * - * @return EC_SUCCESS, or EC_ERROR_* on error. - */ -int pca9534_set_level(const int port, const uint16_t addr_flags, - int pin, int level); - -/* - * Config a pin as input or output. - * - * @param port The I2C port of PCA9534. - * @param addr The address of PCA9534. - * @param pin The index of the pin to set. - * @param is_input PCA9534_INPUT or PCA9534_OUTPUT. - * - * @return EC_SUCCESS, or EC_ERROR_* on error. - */ -int pca9534_config_pin(const int port, const uint16_t addr_flags, - int pin, int is_input); - -#endif /* __CROS_EC_IOEXPANDER_PCA9534_H */ diff --git a/driver/ioexpander/pca9555.h b/driver/ioexpander/pca9555.h deleted file mode 100644 index 273f898821..0000000000 --- a/driver/ioexpander/pca9555.h +++ /dev/null @@ -1,45 +0,0 @@ -/* Copyright 2017 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 PCA9555 I/O Port expander driver header - */ - -#ifndef __CROS_EC_IOEXPANDER_PCA9555_H -#define __CROS_EC_IOEXPANDER_PCA9555_H - -#include "i2c.h" - -#define PCA9555_CMD_INPUT_PORT_0 0 -#define PCA9555_CMD_INPUT_PORT_1 1 -#define PCA9555_CMD_OUTPUT_PORT_0 2 -#define PCA9555_CMD_OUTPUT_PORT_1 3 -#define PCA9555_CMD_POLARITY_INVERSION_PORT_0 4 -#define PCA9555_CMD_POLARITY_INVERSION_PORT_1 5 -#define PCA9555_CMD_CONFIGURATION_PORT_0 6 -#define PCA9555_CMD_CONFIGURATION_PORT_1 7 - -#define PCA9555_IO_0 BIT(0) -#define PCA9555_IO_1 BIT(1) -#define PCA9555_IO_2 BIT(2) -#define PCA9555_IO_3 BIT(3) -#define PCA9555_IO_4 BIT(4) -#define PCA9555_IO_5 BIT(5) -#define PCA9555_IO_6 BIT(6) -#define PCA9555_IO_7 BIT(7) - -static inline int pca9555_read(const int port, - const uint16_t i2c_addr_flags, - int reg, int *data_ptr) -{ - return i2c_read8(port, i2c_addr_flags, reg, data_ptr); -} - -static inline int pca9555_write(const int port, - const uint16_t i2c_addr_flags, - int reg, int data) -{ - return i2c_write8(port, i2c_addr_flags, reg, data); -} - -#endif /* __CROS_EC_IOEXPANDER_PCA9555_H */ diff --git a/driver/ioexpander/pca9675.c b/driver/ioexpander/pca9675.c deleted file mode 100644 index 3fe3bfa0c4..0000000000 --- a/driver/ioexpander/pca9675.c +++ /dev/null @@ -1,127 +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 PCA9675PW I/O Port expander driver source - */ - -#include "i2c.h" -#include "ioexpander.h" -#include "pca9675.h" - -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_read16(int ioex, uint16_t *data) -{ - return i2c_xfer(ioex_config[ioex].i2c_host_port, - ioex_config[ioex].i2c_addr_flags, - NULL, 0, (uint8_t *)data, 2); -} - -static int pca9675_write16(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(ioex_config[ioex].i2c_host_port, - ioex_config[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(ioex_config[ioex].i2c_host_port, - 0, &reset, 1, NULL, 0); -} - -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 & mask) { - rv = pca9675_read16(ioex, &data_read); - if (!rv) - *val = !!(data_read & mask); - } else { - *val = !!(pca9675_iox[ioex].cache_out_pins & mask); - } - - return rv; -} - -static int pca9675_set_level(int ioex, int port, int mask, int val) -{ - /* Update the output pins */ - 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); -} - -static int pca9675_set_flags_by_mask(int ioex, int port, int mask, int flags) -{ - int rv = EC_SUCCESS; - - /* Initialize the I/O directions */ - if (flags & GPIO_INPUT) { - pca9675_iox[ioex].io_direction |= mask; - } else { - pca9675_iox[ioex].io_direction &= ~mask; - - /* Initialize the pin */ - rv = pca9675_set_level(ioex, port, mask, flags & GPIO_HIGH); - } - - return rv; -} - -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) -{ - pca9675_iox[ioex].io_direction = PCA9675_DEFAULT_IO_DIRECTION; - pca9675_iox[ioex].cache_out_pins = 0; - - /* Set pca9675 to Power-on reset */ - 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 deleted file mode 100644 index 59f36918a4..0000000000 --- a/driver/ioexpander/pca9675.h +++ /dev/null @@ -1,39 +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 PCA9675PW I/O Port expander driver header - */ - -#ifndef __CROS_EC_IOEXPANDER_PCA9675_H -#define __CROS_EC_IOEXPANDER_PCA9675_H - -/* 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, -}; - -/* 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 - -extern const struct ioexpander_drv pca9675_ioexpander_drv; - -#endif /* __CROS_EC_IOEXPANDER_PCA9675_H */ 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, -}; diff --git a/driver/ioexpander/pcal6408.h b/driver/ioexpander/pcal6408.h deleted file mode 100644 index fc9969aab1..0000000000 --- a/driver/ioexpander/pcal6408.h +++ /dev/null @@ -1,42 +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 - */ - -#ifndef __CROS_EC_IOEXPANDER_PCAL6408_H -#define __CROS_EC_IOEXPANDER_PCAL6408_H - -#define PCAL6408_I2C_ADDR0 0x20 -#define PCAL6408_I2C_ADDR1 0x21 - -#define PCAL6408_REG_INPUT 0x00 -#define PCAL6408_REG_OUTPUT 0x01 -#define PCAL6408_REG_POLARITY_INVERSION 0x02 -#define PCAL6408_REG_CONFIG 0x03 -#define PCAL6408_REG_OUT_STRENGTH0 0x40 -#define PCAL6408_REG_OUT_STRENGTH1 0x41 -#define PCAL6408_REG_INPUT_LATCH 0x42 -#define PCAL6408_REG_PULL_ENABLE 0x43 -#define PCAL6408_REG_PULL_UP_DOWN 0x44 -#define PCAL6408_REG_INT_MASK 0x45 -#define PCAL6408_REG_INT_STATUS 0x46 -#define PCAL6408_REG_OUT_CONFIG 0x4f - -#define PCAL6408_VALID_GPIO_MASK 0xff - -#define PCAL6408_OUTPUT 0 -#define PCAL6408_INPUT 1 - -#define PCAL6408_OUT_CONFIG_OPEN_DRAIN 0x01 - -/* - * Check which IO's interrupt event is triggered. If any, call its - * registered interrupt handler. - */ -int pcal6408_ioex_event_handler(int ioex); - -extern const struct ioexpander_drv pcal6408_ioexpander_drv; - -#endif /* __CROS_EC_IOEXPANDER_PCAL6408_H */ diff --git a/driver/ioexpander/tca64xxa.c b/driver/ioexpander/tca64xxa.c deleted file mode 100644 index 9a70ceec11..0000000000 --- a/driver/ioexpander/tca64xxa.c +++ /dev/null @@ -1,226 +0,0 @@ -/* 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_addr_flags, - 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_addr_flags, - 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 deleted file mode 100644 index 8c3448f804..0000000000 --- a/driver/ioexpander/tca64xxa.h +++ /dev/null @@ -1,25 +0,0 @@ -/* 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_ */ |