1.)menuconfig 添加led支持,這裏我編譯成模塊,後面手工加載該內核模塊
>make
>make modules ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi-
> make modules_install ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- INSTALL_MOD_PATH=/tftpboot/nfs
安裝到開發板上/lib/modules/2.6.35.7+/kernel/drivers/leds
開發板上>cd /lib/modules/2.6.35.7+/kernel/drivers/leds
/lib/modules/2.6.35.7+/kernel/drivers/leds # ls
led-class.ko leds-gpio.ko(安裝模塊得來)
#代碼中用到gpio_request(GPIO_LED1, "led1_gpj0.3"),即通過gpio資源統一管理,驅動中用gpio_request調用,所以要加載leds-gpio.ko 模塊
>insmod leds-gpio.ko
>insmod led-class.ko
2.)去/sys/class/查看安裝的模塊類
/sys/class/leds # ls
led1 led2 led3
3)編譯安裝led設備驅動leds-s5pv210
代碼路徑~/news5pv210/study/zhulaoshi/code/linux_driver/4.LEDDriver/5.4.16
> make
>sudo cp leds-s5pv210.ko /tftpboot/nfs/driver_test
開發板上driver_test>insmod leds-s5pv210.ko
>lsmod
leds_s5pv210 1221 0 - Live 0xbf01e000
led_class 2494 1 leds_s5pv210, Live 0xbf000000
4) 測試
/sys/class/leds # cd led1
/sys/devices/virtual/leds/led1 # ls
brightness max_brightness power subsystem uevent
/sys/devices/virtual/leds/led1 # echo 1 > brightness
[ 2800.294451] s5pv210_led1_set
i
注意:如果不添加led內核框架模塊支持,直接運行朱老師的insmod leds-s5pv210.ko,會報沒找到led_class_*相關注冊類
附錄:leds-s5pv210.c
#include <linux/module.h> // module_init module_exit
#include <linux/init.h> // __init __exit
#include <linux/fs.h>
#include <linux/leds.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank.h>
#include <linux/io.h>
#include <linux/ioport.h>
#include <mach/gpio.h>
#define GPIO_LED1 S5PV210_GPJ0(3)
#define GPIO_LED2 S5PV210_GPJ0(4)
#define GPIO_LED3 S5PV210_GPJ0(5)
#define X210_LED_OFF 1 // X210中LED是正極接電源,負極節GPIO
#define X210_LED_ON 0 // 所以1是滅,0是亮
static struct led_classdev mydev1; // 定義結構體變量
static struct led_classdev mydev2; // 定義結構體變量
static struct led_classdev mydev3; // 定義結構體變量
// 這個函數就是要去完成具體的硬件讀寫任務的
static void s5pv210_led1_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
printk(KERN_INFO "s5pv210_led1_set\n");
//writel(0x11111111, GPJ0CON);
// 在這裏根據用戶設置的值來操作硬件
// 用戶設置的值就是value
if (value == LED_OFF)
{
// 用戶給了個0,希望LED滅
//writel(0x11111111, GPJ0CON);
// 讀改寫三部曲
//writel((readl(GPJ0DAT) | (1<<3)), GPJ0DAT);
gpio_set_value(GPIO_LED1, X210_LED_OFF); //通過gpio庫統一訪問
}
else
{
// 用戶給的是非0,希望LED亮
//writel(0x11111111, GPJ0CON);
//writel((readl(GPJ0DAT) & ~(1<<3)), GPJ0DAT);
gpio_set_value(GPIO_LED1, X210_LED_ON);
}
}
static void s5pv210_led2_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
printk(KERN_INFO "s5pv2102_led_set\n");
//writel(0x11111111, GPJ0CON);
// 在這裏根據用戶設置的值來操作硬件
// 用戶設置的值就是value
if (value == LED_OFF)
{
// 用戶給了個0,希望LED滅
//writel(0x11111111, GPJ0CON);
// 讀改寫三部曲
//writel((readl(GPJ0DAT) | (1<<4)), GPJ0DAT);
}
else
{
// 用戶給的是非0,希望LED亮
//writel(0x11111111, GPJ0CON);
//writel((readl(GPJ0DAT) & ~(1<<4)), GPJ0DAT);
}
}
static void s5pv210_led3_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
printk(KERN_INFO "s5pv210_led3_set\n");
//writel(0x11111111, GPJ0CON);
// 在這裏根據用戶設置的值來操作硬件
// 用戶設置的值就是value
if (value == LED_OFF)
{
// 用戶給了個0,希望LED滅
//writel(0x11111111, GPJ0CON);
// 讀改寫三部曲
//writel((readl(GPJ0DAT) | (1<<5)), GPJ0DAT);
}
else
{
// 用戶給的是非0,希望LED亮
//writel(0x11111111, GPJ0CON);
//writel((readl(GPJ0DAT) & ~(1<<5)), GPJ0DAT);
}
}
static int __init s5pv210_led_init(void)
{
// 用戶insmod安裝驅動模塊時會調用該函數
// 該函數的主要任務就是去使用led驅動框架提供的設備註冊函數來註冊一個設備
int ret = -1;
// 在這裏去申請驅動用到的各種資源,當前驅動中就是GPIO資源
if (gpio_request(GPIO_LED1, "led1_gpj0.3"))
{
printk(KERN_ERR "gpio_request failed\n");
}
else
{
// 設置爲輸出模式,並且默認輸出1讓LED燈滅
gpio_direction_output(GPIO_LED1, 1); //通過gpio庫統一訪問
}
// led1
mydev1.name = "led1";
mydev1.brightness = 0;
mydev1.brightness_set = s5pv210_led1_set;
ret = led_classdev_register(NULL, &mydev1);
if (ret < 0) {
printk(KERN_ERR "led_classdev_register failed\n");
return ret;
}
// led2
mydev2.name = "led2";
mydev2.brightness = 0;
mydev2.brightness_set = s5pv210_led2_set;
ret = led_classdev_register(NULL, &mydev2);
if (ret < 0) {
printk(KERN_ERR "led_classdev_register failed\n");
return ret;
}
// led3
mydev3.name = "led3";
mydev3.brightness = 0;
mydev3.brightness_set = s5pv210_led3_set;
ret = led_classdev_register(NULL, &mydev3);
if (ret < 0) {
printk(KERN_ERR "led_classdev_register failed\n");
return ret;
}
return 0;
}
static void __exit s5pv210_led_exit(void)
{
led_classdev_unregister(&mydev1);
led_classdev_unregister(&mydev2);
led_classdev_unregister(&mydev3);
gpio_free(GPIO_LED1);
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
// MODULE_xxx這種宏作用是用來添加模塊描述信息
MODULE_LICENSE("GPL"); // 描述模塊的許可證
MODULE_AUTHOR("aston <[email protected]>"); // 描述模塊的作者
MODULE_DESCRIPTION("s5pv210 led driver"); // 描述模塊的介紹信息
MODULE_ALIAS("s5pv210_led"); // 描述模塊的別名信息