Ubiquity EdgeSwitch 5XP PoE swtich/LED control

Hi all,

recently my 5port EdgeSwitch (previously ToughSwitch) became unmanagable and after some debugging I came to the conclusion the flash chip was corrupt and had to replace it with a blank one. Which in terms caused led to missing eeprom and config partitions, ultimately making the Ubiquity's stock firmware unable to run (saying device is 'counterfeit').

So I switched to OpenWRT and despite device being 8/64, it seems to run okay without LuCI. However, for my use case it is crucial to control the PoE switches and their corresponding LEDs.

Firstly, looking at the hardware, all switches and LEDs are controlled via external shift register IC (74HC595). The devicetree file (at v23.05.5) only describes the PoE switches correctly on "spi-gpio" using the compatible = "fairchild,74hc595";. So I manually added the definitions for the LEDS in a similar fashion (maybe not a good way


	gpio-export {
		compatible = "gpio-export";

        // LED on port 0
		gpio_h595_0 {
			gpio-export,name = "ubnt:24v-poe:gpio_0";
			gpio-export,output = <0>;
			gpios = <&gpio_hc595 0 GPIO_ACTIVE_HIGH>;
		};

This then exposes the the IOs in the /sys/class/gpio/ so I would expect I can do echo to turn the LED on, but this did not work.

echo '1' > /sys/class/gpio/ubnt:24v-poe:gpio_0 

After debugging using gpioclt, gpiod-tools, io utilities, I resorted to trusty oscilloscope probing and concluded that the ~OE pin of the shift registers is actually never driven correctly by GPIO_7 of the AR7240 SoC.

With a bit of luck I found in the SoC's documentation that the GPIO block alternate pin configuration selection register (GPIO_FUNCTION_1). Which conveniently has a bit EJTAG_DISABLE that, when set, enables the "function of GPIO_5, GPIO_6 and GPIO_7 as GPIO".

Using io I could set the bit and voila, the LEDs are now active and I can toggle them via echo.

Now at this point I could probably automate the io bit set in the startup scripts, but I decided to experiment setting this bit from the driver probe function (in linux-ath79_generic/linux-5.15.167/drivers/gpio/gpio-ath79.c)

static int ath79_gpio_probe(struct platform_device *pdev)
{
 .... 
	/* Set the EJTAG_DISABLE bit to enable GPIO5,6 and 7 as GPIOs */ 
	ath79_gpio_update_bits(ctrl, AR71XX_GPIO_REG_FUNCTION_1, 1, 1);
 ....

Example of setting port0 LED by

root@OpenWrt:/# echo '1' > /sys/class/gpio/ubnt:24v-poe:gpio_0/value

So my questions are:

  1. What is the proper way to control LEDs that are connected over gpio-spi device? Can the devicetree just list them as GPIO ?
  2. Was there a proper way to set this EJTAG_DISABLE bit, for example, by using some compile-time macro like CONFIG_xxx?
  3. How should I go about the modifications I did as I wish to contribute to openwrt? I have pretty much no collaboration experience with open source projects like OpenWRT.

Regards,
Dimitar

diff --git a/target/linux/ath79/dts/ar7242_ubnt_edgeswitch-5xp.dts b/target/linux/ath79/dts/ar7242_ubnt_edgeswitch-5xp.dts
index 3d8f56a856..40d5ae244d 100644
--- a/target/linux/ath79/dts/ar7242_ubnt_edgeswitch-5xp.dts
+++ b/target/linux/ath79/dts/ar7242_ubnt_edgeswitch-5xp.dts
@@ -6,6 +6,14 @@
        compatible = "ubnt,edgeswitch-5xp", "qca,ar7242";
        model = "Ubiquiti EdgeSwitch 5XP";

+       leds {
+               port0 {
+                       /* LED color is unknown, <color> needs to be replaced */
+                       label = "<color>:port0";
+                       gpios = <&gpio_hc595 0 GPIO_ACTIVE_HIGH>;
+               };
+       };
+
        gpio-export {
                compatible = "gpio-export";

diff --git a/target/linux/ath79/dts/ar7242_ubnt_sw.dtsi b/target/linux/ath79/dts/ar7242_ubnt_sw.dtsi
index 9834bf70c2..8c87921ca6 100644
--- a/target/linux/ath79/dts/ar7242_ubnt_sw.dtsi
+++ b/target/linux/ath79/dts/ar7242_ubnt_sw.dtsi
@@ -49,6 +49,9 @@
                cs-gpios = <&gpio 14 GPIO_ACTIVE_HIGH>;
                num-chipselects = <1>;

+               pinctrl-0 = <&jtag_disable_pins>;
+               pinctrl-names = "default";
+
                gpio_hc595: gpio_spi@0 {
                        compatible = "fairchild,74hc595";
                        reg = <0>;