From 02778b28757acda547959ff0507fc780133a2154 Mon Sep 17 00:00:00 2001 From: Chekhov Ma Date: Wed, 11 Sep 2024 18:02:28 +0800 Subject: [PATCH] drivers: gpio: retire pca95xx driver pca95xx driver can be replaced by pca_series driver, which covers a larger number of devices. Signed-off-by: Chekhov Ma --- .../mec15xxevb_assy6853.dts | 3 +- .../mec172xevb_assy6906.dts | 3 +- drivers/gpio/CMakeLists.txt | 1 - drivers/gpio/Kconfig | 1 - drivers/gpio/Kconfig.pca95xx | 27 - drivers/gpio/gpio_pca95xx.c | 877 ------------------ dts/bindings/gpio/nxp,pca95xx.yaml | 28 - .../mec15xxevb_assy6853/i2c_api/src/main.c | 2 +- .../mec15xxevb_assy6853/i2c_api/testcase.yaml | 2 +- .../mec172xevb_assy6906/i2c_api/src/main.c | 2 +- .../mec172xevb_assy6906/i2c_api/testcase.yaml | 2 +- tests/drivers/build_all/gpio/app.overlay | 4 +- tests/drivers/build_all/gpio/prj.conf | 1 - 13 files changed, 10 insertions(+), 943 deletions(-) delete mode 100644 drivers/gpio/Kconfig.pca95xx delete mode 100644 drivers/gpio/gpio_pca95xx.c delete mode 100644 dts/bindings/gpio/nxp,pca95xx.yaml diff --git a/boards/microchip/mec15xxevb_assy6853/mec15xxevb_assy6853.dts b/boards/microchip/mec15xxevb_assy6853/mec15xxevb_assy6853.dts index 11daa0efbe3736c..2ba2c9e1d94fbd4 100644 --- a/boards/microchip/mec15xxevb_assy6853/mec15xxevb_assy6853.dts +++ b/boards/microchip/mec15xxevb_assy6853/mec15xxevb_assy6853.dts @@ -96,7 +96,7 @@ pinctrl-names = "default"; pca9555@26 { - compatible = "nxp,pca95xx"; + compatible = "nxp,pca9555"; /* Depends on JP53 for device address. * Pin 1-2 = A0, pin 3-4 = A1, pin 5-6 = A2. @@ -106,6 +106,7 @@ * resulting in device address 0x26. */ reg = <0x26>; + ngpios = <16>; gpio-controller; #gpio-cells = <2>; diff --git a/boards/microchip/mec172xevb_assy6906/mec172xevb_assy6906.dts b/boards/microchip/mec172xevb_assy6906/mec172xevb_assy6906.dts index c0427d03d3deda2..43584ff9a30b872 100644 --- a/boards/microchip/mec172xevb_assy6906/mec172xevb_assy6906.dts +++ b/boards/microchip/mec172xevb_assy6906/mec172xevb_assy6906.dts @@ -150,7 +150,7 @@ pinctrl-names = "default"; pca9555@26 { - compatible = "nxp,pca95xx"; + compatible = "nxp,pca9555"; /* Depends on JP53 for device address. * Pin 1-2 = A0, pin 3-4 = A1, pin 5-6 = A2. @@ -160,6 +160,7 @@ * resulting in device address 0x26. */ reg = <0x26>; + ngpios = <16>; gpio-controller; #gpio-cells = <2>; diff --git a/drivers/gpio/CMakeLists.txt b/drivers/gpio/CMakeLists.txt index cd441db164e5fed..07cf568dc88583e 100644 --- a/drivers/gpio/CMakeLists.txt +++ b/drivers/gpio/CMakeLists.txt @@ -62,7 +62,6 @@ zephyr_library_sources_ifdef(CONFIG_GPIO_NUMAKER gpio_numaker.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NUMICRO gpio_numicro.c) zephyr_library_sources_ifdef(CONFIG_GPIO_NXP_S32 gpio_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCA953X gpio_pca953x.c) -zephyr_library_sources_ifdef(CONFIG_GPIO_PCA95XX gpio_pca95xx.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCAL64XXA gpio_pcal64xxa.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCA_SERIES gpio_pca_series.c) zephyr_library_sources_ifdef(CONFIG_GPIO_PCF857X gpio_pcf857x.c) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 90cad25cebe96a3..31e3bc9520a5559 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -149,7 +149,6 @@ source "drivers/gpio/Kconfig.numaker" source "drivers/gpio/Kconfig.numicro" source "drivers/gpio/Kconfig.nxp_s32" source "drivers/gpio/Kconfig.pca953x" -source "drivers/gpio/Kconfig.pca95xx" source "drivers/gpio/Kconfig.pca_series" source "drivers/gpio/Kconfig.pcal64xxa" source "drivers/gpio/Kconfig.pcf857x" diff --git a/drivers/gpio/Kconfig.pca95xx b/drivers/gpio/Kconfig.pca95xx deleted file mode 100644 index 91383a1a400cace..000000000000000 --- a/drivers/gpio/Kconfig.pca95xx +++ /dev/null @@ -1,27 +0,0 @@ -# PCA95XX GPIO configuration options - -# Copyright (c) 2016 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -menuconfig GPIO_PCA95XX - bool "PCA95XX I2C-based GPIO chip" - default y - depends on DT_HAS_NXP_PCA95XX_ENABLED - depends on I2C - help - Enable driver for PCA95XX I2C-based GPIO chip. - -config GPIO_PCA95XX_INIT_PRIORITY - int "Init priority" - default 70 - depends on GPIO_PCA95XX - help - Device driver initialization priority. - -config GPIO_PCA95XX_INTERRUPT - bool "Interrupt enable" - depends on GPIO_PCA95XX - help - Enable interrupt support in PCA95XX driver. - Note that the PCA95XX cannot reliably detect - short-pulse interrupts due to its design. diff --git a/drivers/gpio/gpio_pca95xx.c b/drivers/gpio/gpio_pca95xx.c deleted file mode 100644 index 2cfffe7e198f26a..000000000000000 --- a/drivers/gpio/gpio_pca95xx.c +++ /dev/null @@ -1,877 +0,0 @@ -/* - * Copyright (c) 2015 Intel Corporation. - * Copyright (c) 2020 Norbit ODM AS - * Copyright 2022 NXP - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#define DT_DRV_COMPAT nxp_pca95xx - -/** - * @file Driver for PCA95XX and PCAL95XX I2C-based GPIO driver. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define LOG_LEVEL CONFIG_GPIO_LOG_LEVEL -#include -LOG_MODULE_REGISTER(gpio_pca95xx); - -#if CONFIG_LITTLE_ENDIAN -#define LOW_BYTE_LE16_IDX 0 -#define HIGH_BYTE_LE16_IDX 1 -#else -#define LOW_BYTE_LE16_IDX 1 -#define HIGH_BYTE_LE16_IDX 0 -#endif - -/* Register definitions */ -#define REG_INPUT_PORT0 0x00 -#define REG_INPUT_PORT1 0x01 -#define REG_OUTPUT_PORT0 0x02 -#define REG_OUTPUT_PORT1 0x03 -#define REG_POL_INV_PORT0 0x04 -#define REG_POL_INV_PORT1 0x05 -#define REG_CONF_PORT0 0x06 -#define REG_CONF_PORT1 0x07 -#define REG_OUT_DRV_STRENGTH_PORT0_L 0x40 -#define REG_OUT_DRV_STRENGTH_PORT0_H 0x41 -#define REG_OUT_DRV_STRENGTH_PORT1_L 0x42 -#define REG_OUT_DRV_STRENGTH_PORT1_H 0x43 -#define REG_INPUT_LATCH_PORT0 0x44 -#define REG_INPUT_LATCH_PORT1 0x45 -#define REG_PUD_EN_PORT0 0x46 -#define REG_PUD_EN_PORT1 0x47 -#define REG_PUD_SEL_PORT0 0x48 -#define REG_PUD_SEL_PORT1 0x49 -#define REG_INT_MASK_PORT0 0x4A -#define REG_INT_MASK_PORT1 0x4B -#define REG_INT_STATUS_PORT0 0x4C -#define REG_INT_STATUS_PORT1 0x4D -#define REG_OUTPUT_PORT_CONF 0x4F - -/* Driver flags */ -#define PCA_HAS_PUD BIT(0) -#define PCA_HAS_INTERRUPT BIT(1) -#define PCA_HAS_INTERRUPT_MASK_REG BIT(2) - -/** Configuration data */ -struct gpio_pca95xx_config { - /* gpio_driver_config needs to be first */ - struct gpio_driver_config common; - struct i2c_dt_spec bus; - uint8_t capabilities; -#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT - struct gpio_dt_spec int_gpio; -#endif -}; - -/** Runtime driver data */ -struct gpio_pca95xx_drv_data { - /* gpio_driver_data needs to be first */ - struct gpio_driver_data common; - - struct { - uint16_t input; - uint16_t output; - uint16_t dir; - uint16_t pud_en; - uint16_t pud_sel; - uint16_t int_mask; - uint16_t input_latch; - } reg_cache; - - struct k_sem lock; - -#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT - /* Self-reference to the driver instance */ - const struct device *instance; - - /* port ISR callback routine address */ - sys_slist_t callbacks; - - /* interrupt triggering pin masks */ - struct { - uint16_t edge_rising; - uint16_t edge_falling; - uint16_t level_high; - uint16_t level_low; - } interrupts; - - struct gpio_callback gpio_callback; - - struct k_work interrupt_worker; - - bool interrupt_active; -#endif -}; - -static int read_port_reg(const struct device *dev, uint8_t reg, uint8_t pin, - uint16_t *cache, uint16_t *buf) -{ - const struct gpio_pca95xx_config * const config = dev->config; - uint8_t b_buf; - int ret; - - if (pin >= 8) { - reg++; - } - - ret = i2c_reg_read_byte_dt(&config->bus, reg, &b_buf); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: error reading register 0x%X (%d)", - config->bus.addr, reg, ret); - return ret; - } - - if (pin < 8) { - ((uint8_t *)cache)[LOW_BYTE_LE16_IDX] = b_buf; - } else { - ((uint8_t *)cache)[HIGH_BYTE_LE16_IDX] = b_buf; - } - - *buf = *cache; - - LOG_DBG("PCA95XX[0x%X]: Read: REG[0x%X] = 0x%X", - config->bus.addr, reg, b_buf); - - return 0; -} - -/** - * @brief Read both port 0 and port 1 registers of certain register function. - * - * Given the register in reg, read the pair of port 0 and port 1. - * - * @param dev Device struct of the PCA95XX. - * @param reg Register to read (the PORT0 of the pair of registers). - * @param cache Pointer to the cache to be updated after successful read. - * @param buf Buffer to read data into. - * - * @return 0 if successful, failed otherwise. - */ -static int read_port_regs(const struct device *dev, uint8_t reg, - uint16_t *cache, uint16_t *buf) -{ - const struct gpio_pca95xx_config * const config = dev->config; - uint16_t port_data, value; - int ret; - - ret = i2c_burst_read_dt(&config->bus, reg, (uint8_t *)&port_data, - sizeof(port_data)); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: error reading register 0x%X (%d)", - config->bus.addr, reg, ret); - return ret; - } - - value = sys_le16_to_cpu(port_data); - *cache = value; - *buf = value; - - LOG_DBG("PCA95XX[0x%X]: Read: REG[0x%X] = 0x%X, REG[0x%X] = 0x%X", - config->bus.addr, reg, (*buf & 0xFF), (reg + 1), (*buf >> 8)); - - return 0; -} - - -static int write_port_reg(const struct device *dev, uint8_t reg, uint8_t pin, - uint16_t *cache, uint16_t value) -{ - const struct gpio_pca95xx_config * const config = dev->config; - uint8_t buf[2]; - int ret; - - if (pin < 8) { - buf[1] = value; - } else { - buf[1] = value >> 8; - reg++; - } - buf[0] = reg; - - LOG_DBG("PCA95XX[0x%X]: Write: REG[0x%X] = 0x%X", config->bus.addr, - reg, buf[1]); - - ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); - if (ret == 0) { - *cache = value; - } else { - LOG_ERR("PCA95XX[0x%X]: error writing to register 0x%X " - "(%d)", config->bus.addr, reg, ret); - } - - return ret; -} - -/** - * @brief Write both port 0 and port 1 registers of certain register function. - * - * Given the register in reg, write the pair of port 0 and port 1. - * - * @param dev Device struct of the PCA95XX. - * @param reg Register to write into (the PORT0 of the pair of registers). - * @param cache Pointer to the cache to be updated after successful write. - * @param value New value to set. - * - * @return 0 if successful, failed otherwise. - */ -static int write_port_regs(const struct device *dev, uint8_t reg, - uint16_t *cache, uint16_t value) -{ - const struct gpio_pca95xx_config * const config = dev->config; - uint8_t buf[3]; - int ret; - - LOG_DBG("PCA95XX[0x%X]: Write: REG[0x%X] = 0x%X, REG[0x%X] = " - "0x%X", config->bus.addr, reg, (value & 0xFF), - (reg + 1), (value >> 8)); - - buf[0] = reg; - sys_put_le16(value, &buf[1]); - - ret = i2c_write_dt(&config->bus, buf, sizeof(buf)); - if (ret == 0) { - *cache = value; - } else { - LOG_ERR("PCA95XX[0x%X]: error writing to register 0x%X " - "(%d)", config->bus.addr, reg, ret); - } - - return ret; -} - -static inline int update_input_reg(const struct device *dev, uint8_t pin, - uint16_t *buf) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return read_port_reg(dev, REG_INPUT_PORT0, pin, - &drv_data->reg_cache.input, buf); -} - -static inline int update_input_regs(const struct device *dev, uint16_t *buf) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return read_port_regs(dev, REG_INPUT_PORT0, - &drv_data->reg_cache.input, buf); -} - -static inline int update_output_reg(const struct device *dev, uint8_t pin, - uint16_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return write_port_reg(dev, REG_OUTPUT_PORT0, pin, - &drv_data->reg_cache.output, value); -} - -static inline int update_output_regs(const struct device *dev, uint16_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return write_port_regs(dev, REG_OUTPUT_PORT0, - &drv_data->reg_cache.output, value); -} - -static inline int update_direction_reg(const struct device *dev, uint8_t pin, - uint16_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return write_port_reg(dev, REG_CONF_PORT0, pin, - &drv_data->reg_cache.dir, value); -} - -static inline int update_pul_sel_reg(const struct device *dev, uint8_t pin, - uint16_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return write_port_reg(dev, REG_PUD_SEL_PORT0, pin, - &drv_data->reg_cache.pud_sel, value); -} - -static inline int update_pul_en_reg(const struct device *dev, uint8_t pin, - uint8_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - return write_port_reg(dev, REG_PUD_EN_PORT0, pin, - &drv_data->reg_cache.pud_en, value); -} - -#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT -static inline int update_int_mask_reg(const struct device *dev, uint8_t pin, - uint16_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - /* If the interrupt mask is present, so is the input latch */ - write_port_reg(dev, REG_INPUT_LATCH_PORT0, pin, &drv_data->reg_cache.input_latch, ~value); - - return write_port_reg(dev, REG_INT_MASK_PORT0, pin, - &drv_data->reg_cache.int_mask, value); -} -#endif /* CONFIG_GPIO_PCA95XX_INTERRUPT */ - -/** - * @brief Setup the pin direction (input or output) - * - * @param dev Device struct of the PCA95XX - * @param pin The pin number - * @param flags Flags of pin or port - * - * @return 0 if successful, failed otherwise - */ -static int setup_pin_dir(const struct device *dev, uint32_t pin, int flags) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - uint16_t reg_dir = drv_data->reg_cache.dir; - uint16_t reg_out = drv_data->reg_cache.output; - int ret; - - /* For each pin, 0 == output, 1 == input */ - if ((flags & GPIO_OUTPUT) != 0U) { - if ((flags & GPIO_OUTPUT_INIT_HIGH) != 0U) { - reg_out |= BIT(pin); - } else if ((flags & GPIO_OUTPUT_INIT_LOW) != 0U) { - reg_out &= ~BIT(pin); - } - ret = update_output_reg(dev, pin, reg_out); - if (ret != 0) { - return ret; - } - reg_dir &= ~BIT(pin); - } else { - reg_dir |= BIT(pin); - } - - ret = update_direction_reg(dev, pin, reg_dir); - - return ret; -} - -/** - * @brief Setup the pin pull up/pull down status - * - * @param dev Device struct of the PCA95XX - * @param pin The pin number - * @param flags Flags of pin or port - * - * @return 0 if successful, failed otherwise - */ -static int setup_pin_pullupdown(const struct device *dev, uint32_t pin, - int flags) -{ - const struct gpio_pca95xx_config * const config = dev->config; - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - uint16_t reg_pud; - int ret; - - if ((config->capabilities & PCA_HAS_PUD) == 0) { - /* Chip does not support pull up/pull down */ - if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0U) { - return -ENOTSUP; - } - - /* If both GPIO_PULL_UP and GPIO_PULL_DOWN are not set, - * we should disable them in hardware. But need to skip - * if the chip does not support pull up/pull down. - */ - return 0; - } - - /* If disabling pull up/down, there is no need to set the selection - * register. Just go straight to disabling. - */ - if ((flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0U) { - /* Setup pin pull up or pull down */ - reg_pud = drv_data->reg_cache.pud_sel; - - /* pull down == 0, pull up == 1 */ - WRITE_BIT(reg_pud, pin, (flags & GPIO_PULL_UP) != 0U); - - ret = update_pul_sel_reg(dev, pin, reg_pud); - if (ret) { - return ret; - } - } - - /* enable/disable pull up/down */ - reg_pud = drv_data->reg_cache.pud_en; - - WRITE_BIT(reg_pud, pin, - (flags & (GPIO_PULL_UP | GPIO_PULL_DOWN)) != 0U); - - ret = update_pul_en_reg(dev, pin, reg_pud); - - return ret; -} - -/** - * @brief Configure pin or port - * - * @param dev Device struct of the PCA95XX - * @param pin The pin number - * @param flags Flags of pin or port - * - * @return 0 if successful, failed otherwise - */ -static int gpio_pca95xx_config(const struct device *dev, - gpio_pin_t pin, gpio_flags_t flags) -{ - int ret; - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - -#if (CONFIG_GPIO_LOG_LEVEL >= LOG_LEVEL_DEBUG) - const struct gpio_pca95xx_config * const config = dev->config; -#endif - - /* Does not support disconnected pin */ - if ((flags & (GPIO_INPUT | GPIO_OUTPUT)) == GPIO_DISCONNECTED) { - return -ENOTSUP; - } - - /* Open-drain support is per port, not per pin. - * So can't really support the API as-is. - */ - if ((flags & GPIO_SINGLE_ENDED) != 0U) { - return -ENOTSUP; - } - - /* Can't do I2C bus operations from an ISR */ - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - ret = setup_pin_dir(dev, pin, flags); - if (ret) { - LOG_ERR("PCA95XX[0x%X]: error setting pin direction (%d)", - config->bus.addr, ret); - goto done; - } - - ret = setup_pin_pullupdown(dev, pin, flags); - if (ret) { - LOG_ERR("PCA95XX[0x%X]: error setting pin pull up/down " - "(%d)", config->bus.addr, ret); - goto done; - } - -done: - k_sem_give(&drv_data->lock); - return ret; -} - -static int gpio_pca95xx_port_get_raw(const struct device *dev, uint32_t *value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - uint16_t buf; - int ret; - - /* Can't do I2C bus operations from an ISR */ - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - ret = update_input_regs(dev, &buf); - if (ret != 0) { - goto done; - } - - *value = buf; - -done: - k_sem_give(&drv_data->lock); - return ret; -} - -static int gpio_pca95xx_port_set_masked_raw(const struct device *dev, - uint32_t mask, uint32_t value) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - uint16_t reg_out; - int ret; - - /* Can't do I2C bus operations from an ISR */ - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - reg_out = drv_data->reg_cache.output; - reg_out = (reg_out & ~mask) | (mask & value); - - ret = update_output_regs(dev, reg_out); - - k_sem_give(&drv_data->lock); - - return ret; -} - -static int gpio_pca95xx_port_set_bits_raw(const struct device *dev, - uint32_t mask) -{ - return gpio_pca95xx_port_set_masked_raw(dev, mask, mask); -} - -static int gpio_pca95xx_port_clear_bits_raw(const struct device *dev, - uint32_t mask) -{ - return gpio_pca95xx_port_set_masked_raw(dev, mask, 0); -} - -static int gpio_pca95xx_port_toggle_bits(const struct device *dev, - uint32_t mask) -{ - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - uint16_t reg_out; - int ret; - - /* Can't do I2C bus operations from an ISR */ - if (k_is_in_isr()) { - return -EWOULDBLOCK; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - reg_out = drv_data->reg_cache.output; - reg_out ^= mask; - - ret = update_output_regs(dev, reg_out); - - k_sem_give(&drv_data->lock); - - return ret; -} - -#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT -static void get_triggered_it(struct gpio_pca95xx_drv_data *drv_data, - uint16_t *trig_edge, uint16_t *trig_level) -{ - uint16_t input_cache, changed_pins, input_new; - int ret; - - input_cache = drv_data->reg_cache.input; - ret = update_input_regs(drv_data->instance, &input_new); - if (ret == 0) { - changed_pins = (input_cache ^ input_new); - - *trig_edge |= (changed_pins & input_new & - drv_data->interrupts.edge_rising); - *trig_edge |= (changed_pins & input_cache & - drv_data->interrupts.edge_falling); - *trig_level |= (input_new & drv_data->interrupts.level_high); - *trig_level |= (~input_new & drv_data->interrupts.level_low); - } -} - -static void gpio_pca95xx_interrupt_worker(struct k_work *work) -{ - struct gpio_pca95xx_drv_data * const drv_data = CONTAINER_OF( - work, struct gpio_pca95xx_drv_data, interrupt_worker); - const struct gpio_pca95xx_config * const config = drv_data->instance->config; - uint16_t trig_edge = 0, trig_level = 0; - uint32_t triggered_int = 0; - - k_sem_take(&drv_data->lock, K_FOREVER); - - /* Note: PCA Interrupt status is cleared by reading inputs */ - if (config->capabilities & PCA_HAS_INTERRUPT_MASK_REG) { - /* gpio latched read values, to be compared to cached ones */ - get_triggered_it(drv_data, &trig_edge, &trig_level); - } - /* gpio unlatched read values, in case signal has flipped again */ - get_triggered_it(drv_data, &trig_edge, &trig_level); - - triggered_int = (trig_edge | trig_level); - - k_sem_give(&drv_data->lock); - - if (triggered_int != 0) { - gpio_fire_callbacks(&drv_data->callbacks, drv_data->instance, - triggered_int); - } - - /* Emulate level triggering */ - if (trig_level != 0) { - /* Reschedule worker */ - k_work_submit(&drv_data->interrupt_worker); - } -} - -static void gpio_pca95xx_interrupt_callback(const struct device *dev, - struct gpio_callback *cb, - gpio_port_pins_t pins) -{ - struct gpio_pca95xx_drv_data * const drv_data = - CONTAINER_OF(cb, struct gpio_pca95xx_drv_data, gpio_callback); - - ARG_UNUSED(pins); - - /* Cannot read PCA95xx registers from ISR context, queue worker */ - k_work_submit(&drv_data->interrupt_worker); -} - -static int gpio_pca95xx_pin_interrupt_configure(const struct device *dev, - gpio_pin_t pin, - enum gpio_int_mode mode, - enum gpio_int_trig trig) -{ - int ret = 0; - const struct gpio_pca95xx_config * const config = dev->config; - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - uint16_t reg; - bool enabled, edge, level, active; - - /* Check if GPIO port supports interrupts */ - if ((config->capabilities & PCA_HAS_INTERRUPT) == 0U) { - return -ENOTSUP; - } - - /* Check for an invalid pin number */ - if (BIT(pin) > config->common.port_pin_mask) { - return -EINVAL; - } - - /* Check configured pin direction */ - if ((mode != GPIO_INT_MODE_DISABLED) && - (BIT(pin) & drv_data->reg_cache.dir) != BIT(pin)) { - LOG_ERR("PCA95XX[0x%X]: output pin cannot trigger interrupt", - config->bus.addr); - return -ENOTSUP; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - /* Check if GPIO port has an interrupt mask register */ - if (config->capabilities & PCA_HAS_INTERRUPT_MASK_REG) { - uint16_t reg_out; - - reg_out = drv_data->reg_cache.int_mask; - WRITE_BIT(reg_out, pin, (mode == GPIO_INT_MODE_DISABLED)); - - ret = update_int_mask_reg(dev, pin, reg_out); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: failed to update int mask (%d)", - config->bus.addr, ret); - goto err; - } - } - - /* Update interrupt masks */ - enabled = ((mode & GPIO_INT_MODE_DISABLED) == 0U); - edge = (mode == GPIO_INT_MODE_EDGE); - level = (mode == GPIO_INT_MODE_LEVEL); - WRITE_BIT(drv_data->interrupts.edge_rising, pin, (enabled && - edge && ((trig & GPIO_INT_TRIG_HIGH) == GPIO_INT_TRIG_HIGH))); - WRITE_BIT(drv_data->interrupts.edge_falling, pin, (enabled && - edge && ((trig & GPIO_INT_TRIG_LOW) == GPIO_INT_TRIG_LOW))); - WRITE_BIT(drv_data->interrupts.level_high, pin, (enabled && - level && ((trig & GPIO_INT_TRIG_HIGH) == GPIO_INT_TRIG_HIGH))); - WRITE_BIT(drv_data->interrupts.level_low, pin, (enabled && - level && ((trig & GPIO_INT_TRIG_LOW) == GPIO_INT_TRIG_LOW))); - - active = ((drv_data->interrupts.edge_rising || - drv_data->interrupts.edge_falling || - drv_data->interrupts.level_high || - drv_data->interrupts.level_low) > 0); - - /* Enable / disable interrupt as needed */ - if (active != drv_data->interrupt_active) { - ret = gpio_pin_interrupt_configure_dt( - &config->int_gpio, active ? - GPIO_INT_EDGE_TO_ACTIVE : - GPIO_INT_MODE_DISABLED); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: failed to configure interrupt " - "on pin %d (%d)", config->bus.addr, - config->int_gpio.pin, ret); - goto err; - } - drv_data->interrupt_active = active; - - if (active) { - /* Read current status to reset any - * active signal on INT line - */ - update_input_regs(dev, ®); - } - } - -err: - k_sem_give(&drv_data->lock); - return ret; -} - -static int gpio_pca95xx_manage_callback(const struct device *dev, - struct gpio_callback *callback, - bool set) -{ - const struct gpio_pca95xx_config * const config = dev->config; - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - if ((config->capabilities & PCA_HAS_INTERRUPT) == 0U) { - return -ENOTSUP; - } - - k_sem_take(&drv_data->lock, K_FOREVER); - - gpio_manage_callback(&drv_data->callbacks, callback, set); - - k_sem_give(&drv_data->lock); - return 0; -} -#endif /* CONFIG_GPIO_PCA95XX_INTERRUPT */ - -static const struct gpio_driver_api gpio_pca95xx_drv_api_funcs = { - .pin_configure = gpio_pca95xx_config, - .port_get_raw = gpio_pca95xx_port_get_raw, - .port_set_masked_raw = gpio_pca95xx_port_set_masked_raw, - .port_set_bits_raw = gpio_pca95xx_port_set_bits_raw, - .port_clear_bits_raw = gpio_pca95xx_port_clear_bits_raw, - .port_toggle_bits = gpio_pca95xx_port_toggle_bits, -#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT - .pin_interrupt_configure = gpio_pca95xx_pin_interrupt_configure, - .manage_callback = gpio_pca95xx_manage_callback, -#endif -}; - -/** - * @brief Initialization function of PCA95XX - * - * @param dev Device struct - * @return 0 if successful, failed otherwise. - */ -static int gpio_pca95xx_init(const struct device *dev) -{ - const struct gpio_pca95xx_config * const config = dev->config; - struct gpio_pca95xx_drv_data * const drv_data = - (struct gpio_pca95xx_drv_data * const)dev->data; - - if (!device_is_ready(config->bus.bus)) { - return -ENODEV; - } - - k_sem_init(&drv_data->lock, 1, 1); - -#ifdef CONFIG_GPIO_PCA95XX_INTERRUPT - /* Check if GPIO port supports interrupts */ - if ((config->capabilities & PCA_HAS_INTERRUPT) != 0) { - int ret; - - /* Store self-reference for interrupt handling */ - drv_data->instance = dev; - - /* Prepare interrupt worker */ - k_work_init(&drv_data->interrupt_worker, - gpio_pca95xx_interrupt_worker); - - /* Configure GPIO interrupt pin */ - if (!gpio_is_ready_dt(&config->int_gpio)) { - LOG_ERR("PCA95XX[0x%X]: interrupt GPIO not ready", - config->bus.addr); - return -ENODEV; - } - - ret = gpio_pin_configure_dt(&config->int_gpio, GPIO_INPUT); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: failed to configure interrupt" - " pin %d (%d)", config->bus.addr, - config->int_gpio.pin, ret); - return ret; - } - - /* Prepare GPIO callback for interrupt pin */ - gpio_init_callback(&drv_data->gpio_callback, - gpio_pca95xx_interrupt_callback, - BIT(config->int_gpio.pin)); - ret = gpio_add_callback(config->int_gpio.port, &drv_data->gpio_callback); - if (ret != 0) { - LOG_ERR("PCA95XX[0x%X]: failed to add interrupt callback for" - " pin %d (%d)", config->bus.addr, - config->int_gpio.pin, ret); - return ret; - } - } -#endif - - return 0; -} - -#define GPIO_PCA95XX_DEVICE_INSTANCE(inst) \ -static const struct gpio_pca95xx_config gpio_pca95xx_##inst##_cfg = { \ - .common = { \ - .port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(inst), \ - }, \ - .bus = I2C_DT_SPEC_INST_GET(inst), \ - .capabilities = \ - (DT_INST_PROP(inst, has_pud) ? PCA_HAS_PUD : 0) | \ - IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, ( \ - (DT_INST_NODE_HAS_PROP(inst, interrupt_gpios) ? \ - PCA_HAS_INTERRUPT : 0) | \ - (DT_INST_PROP(inst, has_interrupt_mask_reg) ? \ - PCA_HAS_INTERRUPT_MASK_REG : 0) | \ - )) \ - 0, \ - IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, \ - (.int_gpio = GPIO_DT_SPEC_INST_GET_OR(inst, interrupt_gpios, {}),)) \ -}; \ - \ -static struct gpio_pca95xx_drv_data gpio_pca95xx_##inst##_drvdata = { \ - .reg_cache.input = 0x0, \ - .reg_cache.output = 0xFFFF, \ - .reg_cache.dir = 0xFFFF, \ - .reg_cache.pud_en = 0x0, \ - .reg_cache.pud_sel = 0xFFFF, \ - .reg_cache.int_mask = 0xFFFF, \ - .reg_cache.input_latch = 0x0, \ - IF_ENABLED(CONFIG_GPIO_PCA95XX_INTERRUPT, ( \ - .interrupt_active = false, \ - )) \ -}; \ - \ -DEVICE_DT_INST_DEFINE(inst, \ - gpio_pca95xx_init, \ - NULL, \ - &gpio_pca95xx_##inst##_drvdata, \ - &gpio_pca95xx_##inst##_cfg, \ - POST_KERNEL, CONFIG_GPIO_PCA95XX_INIT_PRIORITY, \ - &gpio_pca95xx_drv_api_funcs); - -DT_INST_FOREACH_STATUS_OKAY(GPIO_PCA95XX_DEVICE_INSTANCE) diff --git a/dts/bindings/gpio/nxp,pca95xx.yaml b/dts/bindings/gpio/nxp,pca95xx.yaml deleted file mode 100644 index 449d52ac47b07c5..000000000000000 --- a/dts/bindings/gpio/nxp,pca95xx.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright (c) 2019 Intel Corporation -# SPDX-License-Identifier: Apache-2.0 - -description: PCA95xx series I2C-based GPIO expander - -compatible: "nxp,pca95xx" - -include: [gpio-controller.yaml, i2c-device.yaml] - -properties: - has-pud: - type: boolean - description: Supports pull-up/pull-down - - has-interrupt-mask-reg: - type: boolean - description: Has Interrupt mask register (PCAL95xx) - - interrupt-gpios: - type: phandle-array - description: Interrupt GPIO pin (active-low open-drain) - - "#gpio-cells": - const: 2 - -gpio-cells: - - pin - - flags diff --git a/tests/boards/mec15xxevb_assy6853/i2c_api/src/main.c b/tests/boards/mec15xxevb_assy6853/i2c_api/src/main.c index 7143f98c889cb7d..774086f8103b039 100644 --- a/tests/boards/mec15xxevb_assy6853/i2c_api/src/main.c +++ b/tests/boards/mec15xxevb_assy6853/i2c_api/src/main.c @@ -29,7 +29,7 @@ ZTEST(i2c, test_i2c_pca95xx) uint32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_CONTROLLER; /* get i2c device */ - const struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_pca95xx)); + const struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_pca9555)); zassert_true(device_is_ready(i2c.bus), "I2C controller device is not ready"); diff --git a/tests/boards/mec15xxevb_assy6853/i2c_api/testcase.yaml b/tests/boards/mec15xxevb_assy6853/i2c_api/testcase.yaml index 038e4dded3bb3e3..c594717882faa40 100644 --- a/tests/boards/mec15xxevb_assy6853/i2c_api/testcase.yaml +++ b/tests/boards/mec15xxevb_assy6853/i2c_api/testcase.yaml @@ -4,5 +4,5 @@ tests: tags: - drivers - i2c - filter: dt_compat_enabled("nxp,pca95xx") + filter: dt_compat_enabled("nxp,pca9555") platform_allow: mec15xxevb_assy6853 diff --git a/tests/boards/mec172xevb_assy6906/i2c_api/src/main.c b/tests/boards/mec172xevb_assy6906/i2c_api/src/main.c index 5bc99d40cbe4857..7caf33481b963bf 100644 --- a/tests/boards/mec172xevb_assy6906/i2c_api/src/main.c +++ b/tests/boards/mec172xevb_assy6906/i2c_api/src/main.c @@ -29,7 +29,7 @@ ZTEST(boards_mec172x_pca95xx, test_i2c_pca95xx) uint32_t i2c_cfg = I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_CONTROLLER; /* get i2c device */ - const struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_pca95xx)); + const struct i2c_dt_spec i2c = I2C_DT_SPEC_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(nxp_pca9555)); zassert_true(device_is_ready(i2c.bus), "I2C controller device is not ready"); diff --git a/tests/boards/mec172xevb_assy6906/i2c_api/testcase.yaml b/tests/boards/mec172xevb_assy6906/i2c_api/testcase.yaml index 8deaed213edec0e..d772f66f4ff673d 100644 --- a/tests/boards/mec172xevb_assy6906/i2c_api/testcase.yaml +++ b/tests/boards/mec172xevb_assy6906/i2c_api/testcase.yaml @@ -4,5 +4,5 @@ tests: tags: - drivers - i2c - filter: dt_compat_enabled("nxp,pca95xx") + filter: dt_compat_enabled("nxp,pca9555") platform_allow: mec172xevb_assy6906 diff --git a/tests/drivers/build_all/gpio/app.overlay b/tests/drivers/build_all/gpio/app.overlay index 0a2d3133c0a1058..39bb3f349005e51 100644 --- a/tests/drivers/build_all/gpio/app.overlay +++ b/tests/drivers/build_all/gpio/app.overlay @@ -105,8 +105,8 @@ int-gpios = <&test_gpio 0 0>; }; - test_i2c_pca95xx: pca95xx@3 { - compatible = "nxp,pca95xx"; + test_i2c_pca95xx: pca9555@3 { + compatible = "nxp,pca9555"; reg = <0x03>; gpio-controller; #gpio-cells = <2>; diff --git a/tests/drivers/build_all/gpio/prj.conf b/tests/drivers/build_all/gpio/prj.conf index cd3185f68456f23..a7ade43d4c1cf2d 100644 --- a/tests/drivers/build_all/gpio/prj.conf +++ b/tests/drivers/build_all/gpio/prj.conf @@ -2,7 +2,6 @@ CONFIG_TEST=y CONFIG_GPIO=y CONFIG_TEST_USERSPACE=y CONFIG_I2C=y -CONFIG_GPIO_PCA95XX_INTERRUPT=y CONFIG_SPI=y CONFIG_MFD=y CONFIG_MFD_INIT_PRIORITY=80