-
Notifications
You must be signed in to change notification settings - Fork 8k
Description
Describe the bug
I am having trouble with the nxp,pcf857x gpio driver. When I set pins as outputs everything works exactly as expected.
The pcf857x chip only has one bit of storage for each pin. if the bit is set high then the pin is weakly pulled up (about 100uA), and if the bit is set low the output sinks current (about 25mA), an engineer would consider this an open drain output.
An I2C write operation sends 8 (or 16) bits of data, the data sets the 8 (or 16) outputs to high or low.
An I2C read operation reads the state of the 8 (or 16) voltages at the pins (independent of how the outputs are programmed).
In order to use a pin an an input, the Output register MUST be set to HIGH, otherwise the open drain is active and the signal is driven low.
When i configure a pin as an input the driver always sets the corresponding output data to LOW, which pulls the pin low and it can't be used as an input.
The driver should set the data for the pins that are configured as inputs to HIGH, unfortunately it does the opposite and makes the pins useless.
Regression
- This is a regression.
Steps to reproduce
- connect a pcf9575 board to power and I2C. I am using an adafruit_feather_nrf52840, but any processor with I2C should work.
- define the i2c connections of the nxp,pcf857x in the devicetree (see app.overlay below).
- build and run test program (see main.c below).
- correct output is pin state=1, if pin_state=0 then the issue exists.
- With a voltmeter measure the voltage at the io pin, it should be above 3V, if it is ~0V then the pin is being driven low.
Here is my 'hack' that makes it work, but I don't think this is the right way to do this:
diff --git a/drivers/gpio/gpio_pcf857x.c b/drivers/gpio/gpio_pcf857x.c
index b14e54cbd9a..c5a1baf9799 100644
--- a/drivers/gpio/gpio_pcf857x.c
+++ b/drivers/gpio/gpio_pcf857x.c
@@ -185,7 +185,7 @@ static int pcf857x_port_set_raw(const struct device *dev, uint16_t mask, uint16_
tx_buf = (drv_data->pins_cfg.outputs_state & ~mask);
tx_buf |= (value & mask);
tx_buf ^= toggle;
- sys_put_le16(tx_buf, tx_buf_p);
+ sys_put_le16(tx_buf|(~drv_data->pins_cfg.configured_as_outputs), tx_buf_p); /* LJK all inputs must be driven high */
rc = i2c_write_dt(&drv_cfg->i2c, tx_buf_p, drv_data->num_bytes);
if (rc != 0) {
app.overlay
&i2c0 {
gpio_bank: pcf8575@20 {
compatible = "nxp,pcf857x";
reg = <0x20>;
gpio-controller;
ngpios = <16>;
#gpio-cells = <2>;
};
};
/{
inputs {
compatible = "gpio-keys";
input_d0: d0 {
gpios = <&gpio_bank 0 GPIO_ACTIVE_HIGH>;
label = "Input 1";
};
};
aliases {
input1 = &input_d0;
};
};
main.c
#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
struct gpio_dt_spec input = GPIO_DT_SPEC_GET(DT_ALIAS(input1), gpios);
int main(void)
{
int state, ret;
printf("Test pcf857x input\n");
ret = gpio_is_ready_dt(&input);
if (ret<0) {
printf("Error: input device %s is not ready\n", input.port->name);
return ret;
}
ret = gpio_pin_configure_dt(&input, GPIO_INPUT);
if (ret<0) {
printf("Error: can not configure device %s as GPIO_INPUT\n", input.port->name);
return ret;
}
state = gpio_pin_get(input.port, input.pin);
printf("pin state = %d, should be \"1\"\n", state);
return 0;
}
Relevant log output
*** Booting Zephyr OS build v4.1.0 ***
Test pcf857x input
pin state = 1, should be "1"
Impact
Functional Limitation – Some features not working as expected, but system usable.
Environment
- OS: Linux 22.04
- Toolchain: zephyr-sdk-0.17.0
- Commit: Zephyr v4.1.0
Additional Context
No response