Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix I2C GPIO interrupts with ATX-PSU POWER_GOOD input #81

Merged
merged 11 commits into from
Oct 19, 2024
275 changes: 203 additions & 72 deletions components/atx_psu/atx_psu.c

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions components/atx_psu/include/atx_psu.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,15 @@ struct atx_psu_options {
*
* Use <0 to disable.
*/
const struct gpio_options *gpio_options;
struct gpio_options gpio_options;

/*
* Return ATX PSU into standby mode once all bits are inactive, and the timeout has passed.
*/
TickType_t timeout;
};

int atx_psu_new(struct atx_psu **atx_psup, struct atx_psu_options options);
int atx_psu_new(struct atx_psu **atx_psup, const struct atx_psu_options *options);

/* Run as a separate task */
void atx_psu_main(void *arg);
Expand Down
2 changes: 1 addition & 1 deletion components/gpio/esp32/gpio_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ int gpio_host_setup(const struct gpio_options *options)
gpio_host_setup_rtc(gpio, inverted, !inverted);
}
if (interrupt) {
gpio_intr_setup_pin(options, gpio);
gpio_intr_setup_host_pin(gpio, options);
}
}

Expand Down
75 changes: 63 additions & 12 deletions components/gpio/esp32/gpio_intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@

intr_handle_t gpio_intr_handle;

const struct gpio_options *gpio_intr_options[GPIO_HOST_PIN_COUNT] = {};
struct gpio_intr_options {
enum gpio_intr_type {
GPIO_INTR_TYPE_NONE = 0,
GPIO_INTR_TYPE_HOST,
GPIO_INTR_TYPE_I2C,
} type;

union {
const struct gpio_options *host;
const struct gpio_i2c_dev *i2c_dev;
};
} gpio_intr_options[GPIO_HOST_PIN_COUNT] = {};

static IRAM_ATTR void gpio_isr (void *arg)
{
Expand All @@ -21,16 +32,23 @@ static IRAM_ATTR void gpio_isr (void *arg)
LOG_ISR_DEBUG("core=%d pins=" GPIO_PINS_FMT, core, GPIO_PINS_ARGS(pins));

for (gpio_pin_t gpio = 0; gpio < GPIO_HOST_PIN_COUNT; gpio++) {
const struct gpio_options *options;
if ((pins & GPIO_PINS(gpio))) {
const struct gpio_intr_options *options = &gpio_intr_options[gpio];

if ((pins & GPIO_PINS(gpio)) && (options = gpio_intr_options[gpio])) {
switch(options->type) {
case GPIO_TYPE_HOST:
gpio_host_intr_handler(options, pins);
case GPIO_INTR_TYPE_NONE:
break;

case GPIO_TYPE_I2C:
gpio_i2c_intr_handler(options, pins);
case GPIO_INTR_TYPE_HOST:
LOG_ISR_DEBUG("pin=%d host options=%p", gpio, options->host);
gpio_host_intr_handler(options->host, pins);
break;

case GPIO_INTR_TYPE_I2C:
for (const struct gpio_i2c_dev *i2c_dev = options->i2c_dev; i2c_dev; i2c_dev = i2c_dev->intr_link) {
LOG_ISR_DEBUG("pin=%d i2c dev=%p", gpio, i2c_dev);
gpio_i2c_intr_handler(i2c_dev, pins);
}
break;
}
}
Expand All @@ -53,16 +71,49 @@ int gpio_intr_init()
return 0;
}

void gpio_intr_setup_pin(const struct gpio_options *options, gpio_pin_t gpio)
void gpio_intr_setup_host_pin(gpio_pin_t gpio, const struct gpio_options *options)
{
if (gpio >= GPIO_HOST_PIN_COUNT) {
LOG_FATAL("[%d] invalid gpio_pin_t", gpio);
}

if (gpio_intr_options[gpio].type) {
LOG_WARN("[%d] intr pin conflict type=%u", gpio, gpio_intr_options[gpio].type);
}

LOG_DEBUG("[%d] host options=%p", gpio, options);

gpio_intr_options[gpio] = (struct gpio_intr_options) {
.type = GPIO_INTR_TYPE_HOST,
.host = options,
};
}

void gpio_intr_setup_i2c_pin(gpio_pin_t gpio, struct gpio_i2c_dev *i2c_dev)
{
if (gpio >= GPIO_HOST_PIN_COUNT) {
LOG_WARN("[%d] -> %p: invalid gpio_pin_t", gpio, options);
return;
LOG_FATAL("[%d] invalid gpio_pin_t", gpio);
}

LOG_DEBUG("[%d] -> %p", gpio, options);
switch (gpio_intr_options[gpio].type) {
case GPIO_INTR_TYPE_NONE:
LOG_DEBUG("[%d] i2c dev=%p", gpio, i2c_dev);
break;

case GPIO_INTR_TYPE_HOST:
LOG_WARN("[%d] intr pin conflict type=%u", gpio, gpio_intr_options[gpio].type);
break;

case GPIO_INTR_TYPE_I2C:
LOG_DEBUG("[%d] i2c dev=%p link=%p", gpio, i2c_dev, gpio_intr_options[gpio].i2c_dev);
i2c_dev->intr_link = gpio_intr_options[gpio].i2c_dev;
break;
}

gpio_intr_options[gpio] = options;
gpio_intr_options[gpio] = (struct gpio_intr_options) {
.type = GPIO_INTR_TYPE_I2C,
.i2c_dev = i2c_dev,
};
}

int gpio_intr_core()
Expand Down
2 changes: 1 addition & 1 deletion components/gpio/esp8266/gpio_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ int gpio_host_setup(const struct gpio_options *options)
}
if (interrupt) {
if (GPIO_HOST_PINS_HOST & GPIO_PINS(gpio)) {
gpio_intr_setup_pin(options, gpio);
gpio_intr_setup_host_pin(gpio, options);
}
}
}
Expand Down
5 changes: 3 additions & 2 deletions components/gpio/esp8266/gpio_intr.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ static IRAM_ATTR void gpio_isr (void *arg)

#if GPIO_I2C_ENABLED
case GPIO_TYPE_I2C:
gpio_i2c_intr_handler(options, pins);
// TODO:
gpio_i2c_intr_handler(i2c_dev, pins);
break;
#endif
}
Expand All @@ -44,7 +45,7 @@ int gpio_intr_init()
return 0;
}

void gpio_intr_setup_pin(const struct gpio_options *options, gpio_pin_t gpio)
void gpio_intr_setup_host_pin(gpio_pin_t gpio, const struct gpio_options *options)
{
if (gpio >= 16) {
LOG_WARN("[%d] -> %p: invalid gpio_pin_t", gpio, options);
Expand Down
11 changes: 8 additions & 3 deletions components/gpio/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
struct gpio_i2c_options options;
SemaphoreHandle_t mutex;
union gpio_i2c_state state;

const struct gpio_i2c_dev *intr_link; // multiple i2c devs sharing the same host intr pin
const struct gpio_options *intr_pins[GPIO_I2C_PINS_MAX];
};
#endif
Expand All @@ -45,15 +47,18 @@ int gpio_host_set_all(const struct gpio_options *options);

/* gpio_intr.c */
int gpio_intr_init();
void gpio_intr_setup_pin(const struct gpio_options *options, gpio_pin_t gpio);
void gpio_intr_setup_host_pin(gpio_pin_t gpio, const struct gpio_options *options);
#if GPIO_I2C_ENABLED
void gpio_intr_setup_i2c_pin(gpio_pin_t gpio, struct gpio_i2c_dev *i2c_dev);
#endif

#if !CONFIG_IDF_TARGET_ESP8266
int gpio_intr_core();
#endif

#if GPIO_I2C_ENABLED
/* i2c.cc */
void gpio_i2c_intr_handler (const struct gpio_options *options, gpio_pins_t pins);
void gpio_i2c_intr_handler (const struct gpio_i2c_dev *i2c_dev, gpio_pins_t pins);

int gpio_i2c_setup(const struct gpio_options *options);
int gpio_i2c_setup_input(const struct gpio_options *options, gpio_pins_t pins);
Expand All @@ -62,7 +67,7 @@ void gpio_intr_setup_pin(const struct gpio_options *options, gpio_pin_t gpio);
int gpio_i2c_set(const struct gpio_options *options, gpio_pins_t pins);

/* gpio_i2c_pca54xx.c */
int gpio_i2c_pca54xx_init(struct gpio_i2c_pca54xx_state *state);
int gpio_i2c_pca54xx_init(struct gpio_i2c_dev *i2c_dev);
int gpio_i2c_pca54xx_setup(const struct gpio_options *options);
int gpio_i2c_pca54xx_setup_input(const struct gpio_options *options, gpio_pins_t pins);
int gpio_i2c_pca54xx_get(const struct gpio_options *options, gpio_pins_t *pins);
Expand Down
16 changes: 7 additions & 9 deletions components/gpio/i2c.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#if GPIO_I2C_ENABLED
#include <stdlib.h>

IRAM_ATTR void gpio_i2c_intr_handler (const struct gpio_options *options, gpio_pins_t pins)
IRAM_ATTR void gpio_i2c_intr_handler (const struct gpio_i2c_dev *dev, gpio_pins_t pins)
{
struct gpio_i2c_dev *dev = options->i2c_dev;
const struct gpio_options *options;

for (unsigned i = 0; i < GPIO_I2C_PINS_MAX; i++) {
if (!(options = dev->intr_pins[i])) {
Expand Down Expand Up @@ -38,6 +38,8 @@
}

if (options->int_pin > 0) {
gpio_intr_setup_i2c_pin(options->int_pin, dev);

if ((err = gpio_host_setup_intr_pin(options->int_pin, GPIO_INTR_NEGEDGE))) {
LOG_ERROR("gpio_host_setup_intr_pin");
return err;
Expand All @@ -47,7 +49,7 @@
switch(options->type) {
case GPIO_I2C_TYPE_PCA9534:
case GPIO_I2C_TYPE_PCA9554:
return gpio_i2c_pca54xx_init(&dev->state.pca54xx);
return gpio_i2c_pca54xx_init(dev);

default:
LOG_FATAL("unsupported type=%d", options->type);
Expand Down Expand Up @@ -110,12 +112,8 @@
}

if (options->interrupt_pins) {
if (options->i2c_dev->options.int_pin > 0) {
// XXX: multiple gpio_i2c_dev sharing the same int_pin?
gpio_intr_setup_pin(options, options->i2c_dev->options.int_pin);
} else {
LOG_ERROR("interrupt_pins without i2c_dev int_pin");
return -1;
if (!options->i2c_dev->options.int_pin) {
LOG_WARN("interrupt_pins without i2c_dev int_pin");
}

for (gpio_pin_t pin = 0; pin < GPIO_I2C_PINS_MAX; pin++) {
Expand Down
Loading
Loading