raspberrypi / firmware

This repository contains pre-compiled binaries of the current Raspberry Pi kernel and modules, userspace libraries, and bootloader/GPU firmware.
5.15k stars 1.68k forks source link

Feature Request: A dtoverlay for the PCF8574? Even the PCF8575? #1790

Closed Jibun-no-Kage closed 1 year ago

Jibun-no-Kage commented 1 year ago

Feature Request: A dtoverlay for the PCF8574? Maybe even include the PCF8575 as well? Looks like the Linux kernel has a native driver for the PCF8574 and PFC8575 as well. Thanks for considering this request.

pelwell commented 1 year ago

I'm open to the idea. You could help out by gathering useful information such as the I2C addresses supported by the devices and what sensible defaults would be.

kripton commented 1 year ago

PCF8574 datasheet: https://www.ti.com/lit/ds/symlink/pcf8574.pdf (8-bit I2C IO expander) I2C-addresses: 0x40-0x4E (WRITE) = 0x41-0x4F (READ)

PCF8575 datasheet: https://www.ti.com/lit/ds/symlink/pcf8575.pdf (16-bit I2C IO expander) I2C-addresses: 0x40-0x4E (WRITE) = 0x41-0x4F (READ)

pelwell commented 1 year ago

Thanks - Linux will call that an address range of 0x20-0x27.

kripton commented 1 year ago

Thanks, I always forget how those I2C-addresses are being calculated

6by9 commented 1 year ago

Curious as https://github.com/raspberrypi/linux/blob/rpi-6.1.y/arch/arm/boot/dts/overlays/crystalfontz-cfa050_pi_m-overlay.dts#L18 is claiming to use pcf8574a on 0x38.

Ah, PCF8574 is 0x20-0x27, PCF8574A is 0x38-0x3f https://www.nxp.com/docs/en/data-sheet/PCF8574_PCF8574A.pdf

kripton commented 1 year ago

Yes, I think I read back then that they introduced the "A" variant only for the reason to change the I2C addresses. So that one could attached 16 of those ICs to the same bus (by mixing non-A-variants with A-variants) instead of only 8 chips when sticking to the same variant. So, you are right, the DT-overlay might want to support those addresses as well, they should behave identical to the non-A-variants.

kripton commented 1 year ago

It's even explained in chapter 1 of the datasheet you linked:

The PCF8574 and PCF8574A are identical, except for the different fixed portion of the
slave address. The three hardware address pins allow eight of each device to be on the
same I 2C-bus, so there can be up to 16 of these I/O expanders PCF8574/74A together on
the same I 2 C-bus, supporting up to 128 I/Os (for example, 128 LEDs).
Jibun-no-Kage commented 1 year ago

I just looked at the PCF8574s I have.... they must be 'A's since they show up as 0x38 on the i2c bus.

Jibun-no-Kage commented 1 year ago

So, is the dtoverlay available for testing yet?

pelwell commented 1 year ago

No. Why don't you have a go?

Jibun-no-Kage commented 1 year ago

Oh, I thought you were working on it? "I'm open to the idea" I took as affirmation?

soren121 commented 1 year ago

@Jibun-no-Kage In open-source dev, "I'm open to it" usually means "I'll accept a patch and/or help you, but I'm not planning to do it myself."

Jibun-no-Kage commented 1 year ago

LOL... That explains it... I am NOT YET an open source developer. So how would I know? :)

xrh0905 commented 1 year ago

Can you reopen this as it isn't complete? @Jibun-no-Kage

xrh0905 commented 1 year ago

I tried to write a dts file. Dmesg shows

[ 4170.250665] pcf857x 1-0020: probed

And when ls -al /sys/class/gpio/

drwxrwxr-x  2 root gpio    0  4月  1 12:02 .
drwxr-xr-x 63 root root    0  8月  7  2022 ..
--w--w----  1 root gpio 4096  4月  1 10:53 export
lrwxrwxrwx  1 root gpio    0  4月  1 10:53 gpiochip0 -> ../../devices/platform/soc/fe200000.gpio/gpio/gpiochip0
lrwxrwxrwx  1 root gpio    0  4月  1 12:02 gpiochip496 -> ../../devices/platform/soc/fe804000.i2c/i2c-1/1-0020/gpio/gpiochip496
lrwxrwxrwx  1 root gpio    0  4月  1 10:53 gpiochip504 -> ../../devices/platform/soc/soc:firmware/soc:firmware:gpio/gpio/gpiochip504
--w--w----  1 root gpio 4096  4月  1 10:53 unexport

So I assume it's working.

And here is the file.

// Definitions for pcf857x Gpio Extender from NXP

/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&i2c1>;
                __overlay__ {
                        status = "okay";
                };
        };

        fragment@1 {
                target = <&i2c1>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        pcf857x: gpio-pcf857x@20 {
                                compatible = "nxp,pcf8574";
                                reg = <0x20>;
                                gpio-controller;
                                #gpio-cells = <2>;

                                status = "okay";
                        };
                };
        };

        __overrides__ {
                addr = <&pcf857x>,"reg:0";
        };
};
xrh0905 commented 1 year ago

It's working. Tested with sysfs

root@ThickPad:/sys/class/gpio# ls -l
总用量 0
--w--w---- 1 root gpio 4096  4月  1 12:09 export
lrwxrwxrwx 1 root gpio    0  4月  1 10:53 gpiochip0 -> ../../devices/platform/soc/fe200000.gpio/gpio/gpiochip0
lrwxrwxrwx 1 root gpio    0  4月  1 12:02 gpiochip496 -> ../../devices/platform/soc/fe804000.i2c/i2c-1/1-0020/gpio/gpiochip496
lrwxrwxrwx 1 root gpio    0  4月  1 10:53 gpiochip504 -> ../../devices/platform/soc/soc:firmware/soc:firmware:gpio/gpio/gpiochip504
--w--w---- 1 root gpio 4096  4月  1 12:11 unexport
root@ThickPad:/sys/class/gpio# echo 496 > export
root@ThickPad:/sys/class/gpio# ls -l
总用量 0
--w--w---- 1 root gpio 4096  4月  1 12:12 export
lrwxrwxrwx 1 root root    0  4月  1 12:12 gpio496 -> ../../devices/platform/soc/fe804000.i2c/i2c-1/1-0020/gpiochip2/gpio/gpio496
lrwxrwxrwx 1 root gpio    0  4月  1 10:53 gpiochip0 -> ../../devices/platform/soc/fe200000.gpio/gpio/gpiochip0
lrwxrwxrwx 1 root gpio    0  4月  1 12:02 gpiochip496 -> ../../devices/platform/soc/fe804000.i2c/i2c-1/1-0020/gpio/gpiochip496
lrwxrwxrwx 1 root gpio    0  4月  1 10:53 gpiochip504 -> ../../devices/platform/soc/soc:firmware/soc:firmware:gpio/gpio/gpiochip504
--w--w---- 1 root gpio 4096  4月  1 12:11 unexport
root@ThickPad:/sys/class/gpio# cd gpio496
root@ThickPad:/sys/class/gpio/gpio496# ls
active_low  device  direction  power  subsystem  uevent  value
root@ThickPad:/sys/class/gpio/gpio496# echo out > direction
root@ThickPad:/sys/class/gpio/gpio496# echo 0 > value
root@ThickPad:/sys/class/gpio/gpio496# echo 1 > value
root@ThickPad:/sys/class/gpio/gpio496# cd ..
root@ThickPad:/sys/class/gpio# echo 496 > unexport

Fan on my third-party HAT worked. GPIO range is 496-503.

Jibun-no-Kage commented 1 year ago

I guess my first question is, why 496 to 503? My board (PCF8574 is @0x38 so you hard coded the address? or it is just the default is 0x20?

Jibun-no-Kage commented 1 year ago

@xrh0905, can you itemize the steps you did to install the file, did you just drop it into the /boot/ directory?

xrh0905 commented 1 year ago

@xrh0905, can you itemize the steps you did to install the file, did you just drop it into the /boot/ directory?

Save the file as pcf857x.dts Run

dtc -@ -Hepapr -I dts -O dtb -o pcf857x.dtbo pcf857x.dts
cp pcf857x.dtbo /boot/overlays

And add a line to /boot/config.txt

dtoverlay=pcf857x,addr=0x20

I'm new to dtb, so can't confirm whether it's working for you or not. My chip (PCF8574) use address 0x20 so I take that as default. It should be able to override. About why 496-503 -- I'm not sure. It's based on an article I found about sysfs & GPIO. Under /sys/class/gpio you can find a new gpiochip besides Pi included 0 & 504 In my case it's 496. And the way to calculate the usable GPIO ID is N=Chip ID M=/sys/class/gpio/gpiochip[N]/ngpio Range: N ~ N+M-1

Please let me know if you made it work.

Jibun-no-Kage commented 1 year ago

What you did looks right from what I understand. I have to setup my environment to do the compile. I am still learning how to do that. I am not (as yet) familiar with a lot of this.

Jibun-no-Kage commented 1 year ago

You could just provide the dtb file so i can use the compiled file? That would be faster than me setting up my environment and compiling it myself... which I want to do.... I have other devices/sensors I want to add as overlays.

xrh0905 commented 1 year ago

You could just provide the dtb file so i can use the compiled file? What would be faster than me setting up my environment and compiling it myself... which I want to do.... I have other devices/sensors I want to add as overlays.

Sure. Are you using Raspberry OS? dtc should be included in the defalut packages. If not,

sudo apt install device-tree-compiler

Shoud solve the issue. pcf857x.dtbo.txt Github doesn't allow .dtbo so I rename it. Remember to remove .txt ;)

Jibun-no-Kage commented 1 year ago

LOL! Just found the steps to setup the compiler! When you comment showed. Thanks. however, I can confirm I am on the right track. I am using Pi OS 11, yes. I should have time to test all this in a couple of days. Thanks for the file, I can validate what I create against it.

xrh0905 commented 1 year ago

Waiting for good news. BTW, It seems like the backend kernel module also supprt PCF8574A & PCF8575 I'll try to add them, but I don't have any of those so I won't be able to test them.

6by9 commented 1 year ago

The sysfs interface was deprecated a number of years ago - libgpiod is the preferred GPIO API now, and uses chip and offset numbers rather than a single range.

Under sysfs the GPIO range is 0-511. Allocation is generally from the top down, hence you get 496-503 as 504-511 is already taken by the firmware's GPIO expander. The base SoC GPIOs would be at the top there too if you were running mainline Linux, however we have a downstream patch that requests a base offset of 0 for that GPIO device to make things more predictable.

xrh0905 commented 1 year ago

The sysfs interface was deprecated a number of years ago - libgpiod is the preferred GPIO API now, and uses chip and offset numbers rather than a single range.

Under sysfs the GPIO range is 0-511. Allocation is generally from the top down, hence you get 496-503 as 504-511 is already taken by the firmware's GPIO expander. The base SoC GPIOs would be at the top there too if you were running mainline Linux, however we have a downstream patch that requests a base offset of 0 for that GPIO device to make things more predictable.

Thanks. But which io map is config.txt using? How can I assign an external GPIO to an overlay like gpio-fan?

xrh0905 commented 1 year ago

New dts that support pcf8574a

dtoverlay=pcf857x,pcf8574a

Untested. use with care.

// Definitions for pcf857x Gpio Extender from NXP

/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        pcf8574: pcf8574@20 {
                                compatible = "nxp,pcf8574";
                                reg = <0x20>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                status = "okay";
                        };
                };
        };

        fragment@1 {
                target = <&i2c_arm>;
                __dormant__ {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        pcf8574a: pcf8574a@38 {
                                compatible = "nxp,pcf8574a";
                                reg = <0x38>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                status = "okay";
                        };
                };
        };

        __overrides__ {
                pcf8574 = <0>,"+0";
                pcf8574a = <0>,"+1";
                addr = <&pcf8574>,"reg:0", <&pcf8574a>,"reg:0";
        };
};
pelwell commented 1 year ago

You can shorten it a bit:

// Definitions for pcf857x Gpio Extender from NXP

/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&i2c_arm>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        pcf857x: pcf857x@0 {
                            compatible = "";
                                reg = <0x00>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                status = "okay";
                        };
                };
        };

        __overrides__ {
                pcf8574  = <&pcf857x>,"compatible=nxp,pcf8574",  <&pcf857x>,"reg:0=0x20";
                pcf8574a = <&pcf857x>,"compatible=nxp,pcf8574a", <&pcf857x>,"reg:0=0x38";
                addr = <&pcf857x>,"reg:0";
        };
};
6by9 commented 1 year ago

Thanks. But which io map is config.txt using? How can I assign an external GPIO to an overlay like gpio-fan?

https://github.com/raspberrypi/linux/blob/rpi-6.1.y/arch/arm/boot/dts/overlays/gpio-fan-overlay.dts#L48

gpios = <&gpio 12 0>;

&gpio is the main SoC gpiochip driver. You need to use a label for your new gpiochip device. There's no easy way to do that for a label that is added by another overlay. You can export labels, but the other overlay won't know to look for it.

xrh0905 commented 1 year ago

You can shorten it a bit:

// Definitions for PCF857X GPIO Extender from NXP

/dts-v1/;
/plugin/;

/ {
        compatible = "brcm,bcm2835";

        fragment@0 {
                target = <&i2c_arm>;
                __overlay__ {
                        #address-cells = <1>;
                        #size-cells = <0>;

                        pcf857x: pcf857x@0 {
                          compatible = "";
                                reg = <0x00>;
                                gpio-controller;
                                #gpio-cells = <2>;
                                status = "okay";
                        };
                };
        };

        __overrides__ {
                pcf8574  = <&pcf857x>,"compatible=nxp,pcf8574",  <&pcf857x>,"reg:0=0x20";
                pcf8574a = <&pcf857x>,"compatible=nxp,pcf8574a", <&pcf857x>,"reg:0=0x38";
                addr = <&pcf857x>,"reg:0";
        };
};

Thanks! Tested for the pcf8574 and it's working. PCF8575 seems need an interrupt pin. It might be harder to implented.

Jibun-no-Kage commented 1 year ago

FYI... original dtbo floods the i2c bus, every address shows in use on my Pi when I attempt to use it. Is the above the final version for now, that I can test? Nice touch adding the PCF8574A variant.

Jibun-no-Kage commented 1 year ago

Where can I find out why the following warning occurred?

# dtc -@ -Hepapr -I dts -O dtb -o pcf857x.dtbo pcf857x.dts pcf857x.dts:14.5-18: Warning (reg_format): /fragment@0/overlay/pcf857x@0:reg: property has invalid length (4 bytes) (#address-cells == 2, #size-cells == 1) pcf857x.dtbo: Warning (pci_device_reg): Failed prerequisite 'reg_format' pcf857x.dtbo: Warning (pci_device_bus_num): Failed prerequisite 'reg_format' pcf857x.dtbo: Warning (simple_bus_reg): Failed prerequisite 'reg_format' pcf857x.dtbo: Warning (i2c_bus_reg): Failed prerequisite 'reg_format' pcf857x.dtbo: Warning (spi_bus_reg): Failed prerequisite 'reg_format' pcf857x.dts:12.23-17.6: Warning (avoid_default_addr_size): /fragment@0/overlay/pcf857x@0: Relying on default #address-cells value pcf857x.dts:12.23-17.6: Warning (avoid_default_addr_size): /fragment@0/overlay/pcf857x@0: Relying on default #size-cells value pcf857x.dtbo: Warning (avoid_unnecessary_addr_size): Failed prerequisite 'avoid_default_addr_size' pcf857x.dtbo: Warning (unique_unit_address): Failed prerequisite 'avoid_default_addr_size'

Jibun-no-Kage commented 1 year ago

Oh, I am testing PCF8574A.

Jibun-no-Kage commented 1 year ago

I can't seem to get the overlay to load...

No UU for the i2c address 0x38

# i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- 38 -- -- -- -- -- -- -- 40: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- UU --

I tried both of the following in turn...

dtoverlay=pcf8574x,addr=0x38 dtoverlay=pcf8574a,addr=0x38

The overlay I compiled is in the /boot/overlays directory of course

# ls -l /boot/overlays/pcf* -rwxr-xr-x 1 root root 739 Apr 2 14:35 /boot/overlays/pcf857x.dtbo

Am I making some type of boneheaded mistake here?

pelwell commented 1 year ago

Am I making some type of boneheaded mistake here?

Yes. Try:

dtoverlay=pcf857x,pcf8574a
Jibun-no-Kage commented 1 year ago

Geez,, you could have let me down easy.... LOL! I just realized I had '4' in the configuration of device class, line when I tried it before as well.

Jibun-no-Kage commented 1 year ago

OK, after fixing my bone headed typo... it is working, I just turned on and off pin 1, in my case GPIO 504 on my PCF8574A. Test all 8 pins, out and in functional.

Jibun-no-Kage commented 1 year ago

So the last question is how does @xrh0905 submit this for official inclusion?

xrh0905 commented 1 year ago

https://github.com/raspberrypi/linux/pull/5422

Jibun-no-Kage commented 1 year ago

Yahhhoooo!

xrh0905 commented 1 year ago

Done! This can be close as complete now. @Jibun-no-Kage

Jibun-no-Kage commented 1 year ago

Cool! Nice work guys.