[AM335x] change a leds{} pin from input to output after boot

Hi,
Custom board using Octavo Systems OSD3358-BAS.
Boot loader: Barebox 2021.03.0
Kernel: 5.11.10

I have several gpio pins setup as an output and added to leds{}.
snippet from my custom device tree.

/ {
	leds {
		pinctrl-names = "default";
		pinctrl-0 = <&user_leds_s0>;

		compatible = "gpio-leds";

		led1 {
			label = "zcpu:green:sw-led";
			gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
			linux,default-trigger = "none";
			default-state = "off";
		};

		led2 {
			label = "zcpu:yellow:sw-led";
			gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
			linux,default-trigger = "none";
			default-state = "off";
		};

		led3 {
			label = "zcpu:red:sw-led";
			gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
			linux,default-trigger = "none";
			default-state = "off";
		};

		led4 {
			label = "zcpu:spare1:dout";
			gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
			default-state = "off";
		};
	};
};

&am33xx_pinmux {
	pinctrl-names = "default";
	pinctrl-0 = <&gpio1_pins_default>;
	user_leds_s0: user_leds_s0 {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x85c, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (T15) gpmc_a7.gpio1[23] GREEN LED*/
			AM33XX_IOPAD(0x860, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (V16) gpmc_a8.gpio1[24] YELLOW LED*/
			AM33XX_IOPAD(0x864, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (U16) gpmc_a9.gpio1[25] RED LED*/
			AM33XX_IOPAD(0x88c, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (V12) gpmc_clk.gpio2[1]   SPARE*/
		>;
	};
};

I use leds{} in the DT to the control the pin properties ‘active_low’ and ‘default_state’.
I now need to change SPARE pin from output to input after boot. My first thought is to use /sys/class/gpio/gpioxx/direction to set the pin to output.
I tried “echo 33 > /sys/class/gpio/export”
but receive
“ash: write error: Device or resource busy”
I understand the error is because the pin belongs to leds{}.
I need to remove the pin from leds{}.

Is there a way to change a gpio pin that is a member of leds{} from output to input by the command line?

Thank you,

1 Like

Sadly, there is no good subsystem for this, gpio-led is for output, gpio-key is for input, there is no subsystem for both…

If you need a pin to be an output and then an input… You’ll need to go thru /sys/clas/gpio/

Regards,

RCN,
I removed led4 from the leds{} section and moved the pinmux from ‘user_leds_s0: user_leds_s0’ to ‘gpio1_pins_default: pinmux_gpio1_pins’.

/ {
	leds {
		pinctrl-names = "default";
		pinctrl-0 = <&user_leds_s0>;

		compatible = "gpio-leds";

		led1 {
			label = "zcpu:green:sw-led";
			gpios = <&gpio1 23 GPIO_ACTIVE_LOW>;
			linux,default-trigger = "none";
			default-state = "off";
		};

		led2 {
			label = "zcpu:yellow:sw-led";
			gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
			linux,default-trigger = "none";
			default-state = "off";
		};

		led3 {
			label = "zcpu:red:sw-led";
			gpios = <&gpio1 25 GPIO_ACTIVE_LOW>;
			linux,default-trigger = "none";
			default-state = "off";
		};
};

&am33xx_pinmux {
	pinctrl-names = "default";
	pinctrl-0 = <&gpio1_pins_default>;
	gpio1_pins_default: pinmux_gpio1_pins {
		pinctrl-single,pins = <
			AM33XX_IOPAD(0x88c, PIN_OUTPUT_PULLUP | MUX_MODE7) /* (V12) gpmc_clk.gpio2[1]   SPARE*/
		>;
	};
};

After booting and login,
#I list the /sys/class/gpio directory
ls /sys/class/gpio
export gpiochip0 gpiochip64 gpiochip32 gpiochip96 unexport
#problem! the pin is not exported.

Q. Is there something that can be added to the DT to automatically export then pin and set the direction while the kernel is parsing the DT?

Up to this point I have wanted the pin to be an input instead of an output. In this example I want the pin direction to be an output. I expected that when the pin was exported that direction would be ‘out’ because the pinmux sets the pin PIN_OUTPUT_PULLUP.

#I export the pin and check the direction
echo 33 > /sys/class/gpio/export
#re-list the dirctory
ls /sys/class/gpio
export gpio33 gpiochip0 gpiochip64 gpiochip32 gpiochip96 unexport
#check the direction of the pin
cat /sys/class/gpio/gpio33/direction
in
#problem! the pin direction is ‘in’

Q. Why is the direction ‘in’ when the pinmux set the pin as PIN_OUTPUT_PULLUP?

Thank you,

Pretty sure ‘in’ is the default state of sysfs…

PS, take a look at mvduin’s library here:

Regards,

1 Like

RCN,
Thank you for the link to the example.

When using /sys/class/gpio, is there a gpio or other DT property to automatically export the pin and set the direction while the kernel is parsing the DT?

Thank you,

Nope, not in DT…

Regards,

Hi,
When exporting a gpio, ‘echo 33 > /sys/class/gpio/export’, the default direction is input.
When changing direction to output ‘echo out /sys/class/gpio/gpio33/direction’, the default value is 0 (zero). On my custom board, a value of 0 causes my output to be ON. A value of 1 = OFF.

Is there a way to set the default value to ‘1’ when changing direction to ‘out’.

Another option would be to invert gpio pin so that a value of 0=OFF and 1=ON.

Is there a way to invert the state of the gpio pin in the device tree or by command line before exporting the gpio pin?

Thank you,

Use an external buffer to set these states…

Regards,

RCN,
I was looking thru the kernel code. The linux-5.19.3/drivers/gpio/gpiolib-sysfx.c file has a function

static ssize_t direction_store(struct device *dev,
		struct device_attribute *attr, const char *buf, size_t size)
{
	struct gpiod_data *data = dev_get_drvdata(dev);
	struct gpio_desc *desc = data->desc;
	ssize_t			status;

	mutex_lock(&data->mutex);

	if (sysfs_streq(buf, "high"))
		status = gpiod_direction_output_raw(desc, 1);
	else if (sysfs_streq(buf, "out") || sysfs_streq(buf, "low"))
		status = gpiod_direction_output_raw(desc, 0);
	else if (sysfs_streq(buf, "in"))
		status = gpiod_direction_input(desc);
	else
		status = -EINVAL;

	mutex_unlock(&data->mutex);

	return status ? : size;
}

I don’t know what the gpiolib-sysfs.c file has to do with export but the mention of ‘high’ made me think to try,

echo 23 > /sys/class/gpio/export
#default direction is input
echo high > /sys/class/gpio/gpio23/direction
cat /sys/class/gpio/gpio23/direction
out
cat /sys/class/gpio/gpio23/value
1
#direction was set to output with a value of 1, which on my custom board is OFF

I hope you or others find this useful.
Thank you,