Simple Input/Output

The Librem 5 has a number of peripherals that allow applications to interact with users and the outside world in a simple way. This guide covers these I/O peripherals and describes how to use them.

Note: Peripherals that handle input are typically readable by any user but those that allow output, such as LEDs, can only be written by the root user.

Light Emitting Diodes (LEDs)

Only one of the LEDs can be controlled by applications. This red diode is mapped to the /sys/class/leds/LED 1 directory in the file system and its state can be changed by writing to the /sys/class/leds/LED 1/brightness file, as in this shell command:

echo 200 > /sys/class/leds/LED\ 1/brightness

Using the default system configuration, writing a value of 0 to the file will switch the LED off. Writing a value from 1 to 255 will switch it on. Reading from the file returns the value previously used to set the brightness of the LED. The maximum brightness can be read from the /sys/class/leds/LED 1/max_brightness file:

cat /sys/class/leds/LED 1/max_brightness

The LED can also be controlled using the python-periphery library:

#/usr/bin/env python3

import periphery

# Obtain an object for the LED.
led = periphery.LED("LED 1")

# Read the current brightness.
brightness = led.read()

# Switch the LED on.
led.write(1)

# Switch the LED off.
led.write(0)

The lack of control over the brightness of the LED is because it is driven by a Pulse Width Modulator (PWM) that it shares with the haptic motor, and the default kernel device tree configures the motor to use the PWM. If a different device tree is used with the kernel, this behavior can be adjusted.

Haptic Motor

The haptic motor is mapped to the /sys/class/leds/nxp::haptic directory and can be controlled by writing to the /sys/class/leds/nxp::haptic/brightness file:

echo 128 > /sys/class/leds/nxp\:\:haptic/brightness

Values from 0 to the maximum of 255 can be used. Reading from the file returns the value previously set.

The maximum value can be obtained by reading from the /sys/class/leds/nxp::haptic/max_brightness file:

cat /sys/class/leds/nxp\:\:haptic/max_brightness

The motor can also be controlled using the python-periphery library:

#/usr/bin/env python3

import periphery

# Obtain an object for the motor.
motor = periphery.LED("nxp::haptic")

# Turn the motor on at a low level.
motor.write(64)

# Turn the motor on at a higher level.
motor.write(128)

# Turn the motor off.
motor.write(0)

The haptic motor shares a PWM with the red LED. In the device tree used by the default kernel the PWM is used to control the amplitude of the haptic motor, restricting the state of the LED to being either on or off. If a different device tree is used with the kernel, this behavior can be adjusted.

Push Buttons

User input from the volume up and down push buttons can be read. Events from these buttons are delivered to the /dev/input/event0 file. One way to examine these events is to run the evtest command – this will need to be executed using sudo unless the user is in the input group:

sudo evtest /dev/input/event0

This will listen for events from the buttons and write them in human-readable form to the console.

Events can also be read using the python-evdev package:

#/usr/bin/env python3

import evdev
import select

VOLUME_DOWN = 114
VOLUME_UP = 115

# Obtain an object for the input device.
device = evdev.InputDevice('/dev/input/event0')

while True:

    # Wait for an event.
    r, w, x = select.select([device.fd], [], [])

    # Read the events for the device.
    for event in device.read():

        pressed = {0: "released", 1: "pressed"}[event.value]

        if event.code == VOLUME_UP:
            print("volume up", pressed)
        elif event.code == VOLUME_DOWN:
            print("volume down", pressed)

The python-evdev tutorial shows several ways of handling events that can be applied to various situations, using different techniques to read the event queue.

Headphone Connection

Input events are generated when a headphone jack is inserted into or removed from the headphone socket. These events are delivered to the /dev/input/event0 file together with push button events. As with the buttons, the evtest command can be used to examine the events:

sudo evtest /dev/input/event0

This will listen for headphone connection events and write them in human-readable form to the console.

Events can also be read using the python-evdev package:

#/usr/bin/env python3

import evdev
import select

HEADPHONE_CONNECT = 211

# Obtain an object for the input device.
device = evdev.InputDevice('/dev/input/event0')

while True:

    # Wait for an event.
    r, w, x = select.select([device.fd], [], [])

    # Read the events for the device.
    for event in device.read():

        if event.code == HEADPHONE_CONNECT:
            connected = {0: "connected", 1: "disconnected"}[event.value]
            print("headphones", connected)

It may be necessary to combine reading of headphone connection events with those from the push buttons, even if they are handled separately.