Hi Folks! Welcome to my Blog.
I
have a sample code to share with you for controlling a LED on your board
running Linux. LED ON/OFF is controlled by the CPU GPIO. In this
example, I am using BeagleBoneBlack for controlling LED.
In
kernel modules it was crude practice to control the LED by controlling
its corresponding GPIO, this requires, proper pin-muxing is done and in
your module you have to do "requesting for GPIO" --> "make sure it is
valid" --> "setting as output" -> "setting gpio value to 0/1" to
turn OFF/ON.
In
latest kernel we have "LED Support" CONFIG_LEDS_GPIO under this section
we see LEDS_TRIGGERS, TRIGGER_CPU, TRIGGER_GPIO for various purposes.
On BBB we have 4 user-leds for status, from the am335x-bone-common.dtsi files we can see that
- user-led0 --> "heartbeat" this is used by drivers/leds/ledtrig-heartbeat.c to show that sytem is alive
- user-led1 --> "mmc0" this is used by drivers/mmc/core/host.c in mmc_add_host function
- user-led2 --> "cpu0" this is use by drivers/leds/ledtrig-cpu.c to show the cpu status
- user-led3 --> "mmc1" we use this led in our module for experimentation
Let us assume our device name as "myled", and its obvious that you have your device structure lets say I have the following structure for myled device. You have to make sure you have a member of structure type led_trigger
** Do changes to am335x-bone-common.dtsi file, rename "mmc1" as "myled" as shown below. Proper pin-muxing is done in the same file for all the four leds.
led3 { label = "beaglebone:green:usr3"; gpios = <&gpio2 24 0>; default-state = "off"; linux,default-trigger = "myled"; };
this is my "myled" device structure with member "led" pointer to led_trigger structure.
struct myled { struct device *dev; unsigned int id; #ifdef CONFIG_LEDS_TRIGGERS struct led_trigger *led; /* activity led */ #endif char name[8]; }
in the module make sure you include "leds.h"header file.
A pointer to my device structure defined globally, and its memory is allocated in the probe of the module. In the probe you need to register with led_trigger as shown below
for controlling the led lets use sysfs interface, like reading a file should turn ON the LED and similarly for OFF
Create sysfs interface in the probe of your module
#include <linux/of_device.h> #include <linux/sysfs.h> #include <linux/leds.h>
A pointer to my device structure defined globally, and its memory is allocated in the probe of the module. In the probe you need to register with led_trigger as shown below
struct myled *mdev; //declared globally led_trigger_register_simple(dev_name(mdev->dev), &mdev->led);
for controlling the led lets use sysfs interface, like reading a file should turn ON the LED and similarly for OFF
static ssize_t my_led_on(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t i = 0; led_trigger_event(mdev->led, LED_FULL); i += sprintf(buf, "LED is ON\n"); return i; } static ssize_t my_led_off(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t i = 0; led_trigger_event(mdev->led, LED_OFF); i += sprintf(buf, "LED is OFF\n"); return i; } static DEVICE_ATTR(myled_on, 0444, my_led_on, NULL); static DEVICE_ATTR(myled_off, 0444, my_led_off, NULL); static const struct attribute_group myled_att_gr = { &dev_attr_myled_on.attr, &dev_attr_myled_off.attr, NULL } static const struct attribute_group myled_att_gr = { .name = "myled", .attrs = myled_att };
Create sysfs interface in the probe of your module
ret = sysfs_create_group(&mdev->dev.kobj, &myled_att_gr); if (ret) { dev_err(&mdev->dev, "device_create_file failed\n"); return ret; }
in the "remove" of your module you have to unregister with led_trigger as shown below
This completes the coding part, assuming you are able to compile the code with out error and have booted to shell on BBB with your module loaded. We shall use the sysfs interface created above for controlling the LED. Reading the file "myled_on" will call the function "my_led_on" and turns the LED ON using the led_trigger_event and similarly for turning OFF the led.
If you have any issue booting to shell, check my post Booting BeagleBoneBlack
led_trigger_unregister_simple(mdev->led);
This completes the coding part, assuming you are able to compile the code with out error and have booted to shell on BBB with your module loaded. We shall use the sysfs interface created above for controlling the LED. Reading the file "myled_on" will call the function "my_led_on" and turns the LED ON using the led_trigger_event and similarly for turning OFF the led.
If you have any issue booting to shell, check my post Booting BeagleBoneBlack
# cat myled_on LED is ON #
use can now see user-led3 is ON
# cat myled_off LED is OFF #
use can now see user-led3 is OFF.
This process has simplified the things for controlling the LEDs on your board and reduces the number of lines of code you have to write for controlling the led.
You can play around with these leds, by tweaking into ledtrig-cpu.c &
ledtrig-heartbeat.c by changing the names in am335x-bone-common.dtsi or by adding extra led on P8 or P9 expander of BBB
To understand more internals look at drivers/leds/leds-gpio.c, drivers/gpio/gpiolib-of.c files
please leave your comments, it will be encouraging :)