在前面我们已经介绍了pinctrl subsystem相关的基础知识,这一节我们尝试修改设备树,在pin controller node下添加两个子节点分别用来控制LED1~LED4的全亮/全灭。然后我们编写LED驱动程序,配置LED的两种状态:
- default:默认状态,LED1~LED4全亮;
- myled-off:LED1~LED4全灭;
一、修改设备树
1.1 修改s3c2440-pinctrl.dtsi
修改内核arch/arm/boot/dts/s3c2440-pinctrl.dtsi文件,在pinctrl节点下添加两个引脚配置节点:
myled_on: myled-on { samsung,pins = "gpb-5","gpb-6","gpb-7","gpb-8"; /* GPB5~8 */ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>; /* 设置为输出模式 */ samsung,pin-val = <0x0>; /* 初始值输出低电平 */ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>; }; myled_off: myled-off { samsung,pins = "gpb-5","gpb-6","gpb-7","gpb-8"; /* 引用GPB5~8*/ samsung,pin-function = <EXYNOS_PIN_FUNC_OUTPUT>; /* 设置为输出模式 */ samsung,pin-val = <0x1>; /* 初始值输出高电平 */ samsung,pin-pud = <EXYNOS_PIN_PULL_UP>; };
其中:
- myled_on节点配置GPB5~GPB8默认为输出模式,并且输出低电平,从而达到LED1~LED4点亮的效果;
- myled_off节点配置GPB5~GPB8默认为输出模式,并且输出高电平,从而达到LED1~LED4熄灭的效果。
1.2 修改s3c2440-smdk2440.dts
在内核arch/arm/boot/dts/s3c2440-smdk2440.dts文件中添加myled设备节点:
myled: myled { compatible = "myled"; status = "okay"; pinctrl-names = "default", "myled_off"; /* 定义两种状态 */ pinctrl-0 = <&myled_on>; /* 当使用default状态时,就会使用所引用节点的配置*/ pinctrl-1 = <&myled_off>; /* 当使用myled_off状态时,就会使用所引用节点的配置*/ };
这里定义了myled设备的两种状态:
- default:默认状态,引脚配置设置为&myled_on;
- myled_off:引脚配置设置为&myled_off;
二、LED驱动程序
这里我们仍然以led驱动程序为例,进行讲解。在/work/sambashare/drivers下创建24.led_dev_pinctr文件夹。用来保存LED驱动程序以及测试应用程序。
2.1 编写led_open、led_write函数
#define DTSLED_CNT 1 #define DTSLED_NAME "myled" /* 下面这个几个类型由于内核没有提供给client device driver使用,因此我们只能自己定义 */ struct pinctrl_setting_mux { unsigned group; unsigned func; }; struct pinctrl_setting_configs { unsigned group_or_pin; unsigned long *configs; unsigned num_configs; }; struct pinctrl_setting { struct list_head node; enum pinctrl_map_type type; struct pinctrl_dev *pctldev; const char *dev_name; union { struct pinctrl_setting_mux mux; // mux配置数据 struct pinctrl_setting_configs configs; // config配置数据 } data; }; struct pinctrl_state { struct list_head node; const char *name; struct list_head settings; }; /* 定义一个led设备 */ struct led_dev myled; /* 定义led结构体 */ struct led_dev { dev_t devid; /* 字符设备编号 */ struct cdev cdev; /* 保存操作结构体的字符设备 */ struct class *class; /* class */ struct device *device; /* 设备类 */ struct device_node *nd; /* 设备节点 */ struct pinctrl *pinctrl; /* pin control state holder */ struct pinctrl_state *state; /* 当前pin control state */ }; static int led_open(struct inode *inode, struct file *file) { return 0; } /* 点亮/熄灭 LED01 */ static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int val,ret; copy_from_user(&val, buf, count); // 用户空间到内核空间传递数据 printk("value %d",val); if(val == 1){ /* 点亮 */ myled.state = pinctrl_lookup_state(myled.pinctrl, "default"); //获取pinctrl-0的配置状态 if (myled.state == NULL){ printk("pinctrl lookup state failed\n"); return -1; }else{ printk("pinctrl lookup state success\n"); } /*3、设置引脚状态*/ ret = pinctrl_select_state(myled.pinctrl, myled.state); if (ret < 0){ printk("pinctrl select state failed\n"); return -1; }else{ printk("pinctrl select state success\n"); } } else{ /* 熄灭 */ myled.state = pinctrl_lookup_state(myled.pinctrl, "myled_off"); //获取pinctrl-1的配置状态 if (myled.state == NULL){ printk("pinctrl lookup state failed\n"); return -1; }else{ printk("pinctrl lookup state success\n"); } /*3、设置引脚状态*/ ret = pinctrl_select_state(myled.pinctrl, myled.state); if (ret < 0){ printk("pinctrl select state failed\n"); return -1; }else{ printk("pinctrl select state success\n"); } } return 0; }
2.2 platform driver定义
这里我们采用platform设备驱动模型,因此需要定义platform_driver:
/* * 用于设备树匹配 */ static const struct of_device_id led_dt_match[] = { { .compatible = "myled", }, {}, }; /* * platform驱动 */ static struct platform_driver led_driver = { .probe = led_probe, .remove = led_remove, .driver = { .name = "myled", .of_match_table = led_dt_match, // 匹配列表 } };
2.3 led_probe
/* * 当驱动和硬件信息匹配成功之后,就会调用probe函数,驱动所有的资源的注册和初始化全部放在probe函数中 */ static int led_probe(struct platform_device *pdev) { int ret = 0,i = 0; struct pinctrl_setting *setting; struct device_node *np; const char *statename; struct dev_pin_info *pins; if(pdev->name != NULL){ printk("platform device name %s",pdev->name); // myled } /* 获取设备引脚状态信息 */ np = pdev->dev.of_node; ret = of_property_read_string_index(np, "pinctrl-names", 0, &statename); // 读取pinctrl-names属性第0个值 if (ret == 0) { printk("pinctrl-names index 0 value %s",statename); } /* 1.获取与设备相关联的pinctrl句柄 */ pins = pdev->dev.pins; myled.pinctrl = pins->p; if(myled.pinctrl == NULL){ printk("retrieves the pinctrl handle for a device failed\n"); return -1; }else{ printk("retrieves the pinctrl handle for a device success\n"); } /* 2. 获取指定的name的state */ myled.state = pinctrl_lookup_state(myled.pinctrl, "default"); //获取pinctrl-0的配置状态 if (myled.state == NULL){ printk("pinctrl lookup state failed\n"); return -1; }else{ printk("pinctrl lookup state success\n"); } /*3、设置引脚状态 */ ret = pinctrl_select_state(myled.pinctrl, myled.state); if (ret < 0){ printk("pinctrl select state failed\n"); return -1; }else{ printk("pinctrl select state success\n"); } /* 输出状态state以及状态setting信息 */ if(myled.state->name != NULL){ printk("state name %s", myled.state->name); // 状态名称为default } /* 遍历当前状态下的所有setting */ list_for_each_entry(setting, &(myled.state->settings), node) { printk("setting type %d", setting->type); printk("setting dev_name %s", setting->dev_name); // 设备名称为myled if(setting->type == PIN_MAP_TYPE_MUX_GROUP ){ // 引脚复用 枚举值为2 printk("setting mux group %d", setting->data.mux.group); printk("setting mux func %d", setting->data.mux.func); }else{ // 配置引脚电气特性 printk("--------------configs start--------"); printk("setting configs group_or_pin %d", setting->data.configs.group_or_pin); for(i=0; i<setting->data.configs.num_configs; i++){ printk("setting configs configs %d", setting->data.configs.configs[i]); } printk("--------------configs end--------"); } } /* 4. 动态分配字符设备号 */ ret = alloc_chrdev_region(&myled.devid, 0, 1,DTSLED_NAME); // ls /proc/devices看到的名字 /* 返回值为负数,表示操作失败 */ if (ret < 0) { printk("alloc char device region failed\n"); goto faile_devid; }else{ printk("alloc char device region success\n"); } /* 5.初始化字符设备,添加字符设备 */ cdev_init(&myled.cdev, &led_fops); ret = cdev_add(&myled.cdev, myled.devid, DTSLED_CNT); /* 返回值为负数,表示操作失败 */ if (ret < 0) { printk("char device add failed\n"); goto fail_cdev; }else{ printk("char device add success\n"); } /* 6.创建类,它会在sys目录下创建/sys/class/dtsled这个类 */ myled.class = class_create(THIS_MODULE, DTSLED_NAME); if(IS_ERR(myled.class)){ printk("create class failed\n"); goto fail_class; }else{ printk("create class success\n"); } /* 7. 在/sys/class/led下创建dtsled设备,然后mdev通过这个自动创建/dev/dtsled这个设备节点 */ myled.device = device_create(myled.class, NULL, myled.devid, NULL, DTSLED_NAME); if(IS_ERR(myled.device)){ printk("create device failed\n"); goto fail_device; }else{ printk("create device success\n"); } return 0; fail_findnd: device_destroy(myled.class, myled.devid); fail_device: class_destroy(myled.class); fail_class: cdev_del(&myled.cdev); fail_cdev: unregister_chrdev_region(myled.devid, DTSLED_CNT); faile_devid: return ret; }
在这个函数中我输出了当前设备的状态,以及状态下的配置信息。
2.4 led_remove
/* * 硬件信息被移除了,或者驱动被卸载了,全部要释放,释放资源的操作就放在该函数中 */ static int led_remove(struct platform_device * pdev) { printk("led driver exit\n"); /* 注销类、以及类设备 */ device_destroy(myled.class, myled.devid); class_destroy(myled.class); /* 删除设备,卸载注册的设备编号 */ cdev_del(&myled.cdev); unregister_chrdev_region(myled.devid, DTSLED_CNT); return 0; }
2.5 led_drv.c完整代码
#include <linux/module.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/io.h> #include <linux/errno.h> #include <linux/uaccess.h> #include <linux/platform_device.h> #include <linux/device.h> #include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/pinctrl/machine.h> #include <linux/pinctrl/devinfo.h> #include <linux/pinctrl/pinctrl.h> #include <linux/list.h> #define DTSLED_CNT 1 #define DTSLED_NAME "myled" /* 下面这个几个类型由于内核没有提供给client device driver使用,因此我们只能自己定义 */ struct pinctrl_setting_mux { unsigned group; unsigned func; }; struct pinctrl_setting_configs { unsigned group_or_pin; unsigned long *configs; unsigned num_configs; }; struct pinctrl_setting { struct list_head node; enum pinctrl_map_type type; struct pinctrl_dev *pctldev; const char *dev_name; union { struct pinctrl_setting_mux mux; // mux配置数据 struct pinctrl_setting_configs configs; // config配置数据 } data; }; struct pinctrl_state { struct list_head node; const char *name; struct list_head settings; }; /* 定义一个led设备 */ struct led_dev myled; /* 定义led结构体 */ struct led_dev { dev_t devid; /* 字符设备编号 */ struct cdev cdev; /* 保存操作结构体的字符设备 */ struct class *class; /* class */ struct device *device; /* 设备类 */ struct device_node *nd; /* 设备节点 */ struct pinctrl *pinctrl; /* pin control state holder */ struct pinctrl_state *state; /* 当前pin control state */ }; static int led_open(struct inode *inode, struct file *file) { return 0; } /* 点亮/熄灭 LED01 */ static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int val,ret; copy_from_user(&val, buf, count); // 用户空间到内核空间传递数据 printk("value %d",val); if(val == 1){ /* 点亮 */ myled.state = pinctrl_lookup_state(myled.pinctrl, "default"); //获取pinctrl-0的配置状态 if (myled.state == NULL){ printk("pinctrl lookup state failed\n"); return -1; }else{ printk("pinctrl lookup state success\n"); } /*3、设置引脚状态*/ ret = pinctrl_select_state(myled.pinctrl, myled.state); if (ret < 0){ printk("pinctrl select state failed\n"); return -1; }else{ printk("pinctrl select state success\n"); } } else{ /* 熄灭 */ myled.state = pinctrl_lookup_state(myled.pinctrl, "myled_off"); //获取pinctrl-1的配置状态 if (myled.state == NULL){ printk("pinctrl lookup state failed\n"); return -1; }else{ printk("pinctrl lookup state success\n"); } /*3、设置引脚状态*/ ret = pinctrl_select_state(myled.pinctrl, myled.state); if (ret < 0){ printk("pinctrl select state failed\n"); return -1; }else{ printk("pinctrl select state success\n"); } } return 0; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write, }; /* * 当驱动和硬件信息匹配成功之后,就会调用probe函数,驱动所有的资源的注册和初始化全部放在probe函数中 */ static int led_probe(struct platform_device *pdev) { int ret = 0,i = 0; struct pinctrl_setting *setting; struct device_node *np; const char *statename; struct dev_pin_info *pins; if(pdev->name != NULL){ printk("platform device name %s",pdev->name); // myled } /* 获取设备引脚状态信息 */ np = pdev->dev.of_node; ret = of_property_read_string_index(np, "pinctrl-names", 0, &statename); // 读取pinctrl-names属性第0个值 if (ret == 0) { printk("pinctrl-names index 0 value %s",statename); } /* 1.获取与设备相关联的pinctrl句柄 */ pins = pdev->dev.pins; myled.pinctrl = pins->p; if(myled.pinctrl == NULL){ printk("retrieves the pinctrl handle for a device failed\n"); return -1; }else{ printk("retrieves the pinctrl handle for a device success\n"); } /* 2. 获取指定的name的state */ myled.state = pinctrl_lookup_state(myled.pinctrl, "default"); //获取pinctrl-0的配置状态 if (myled.state == NULL){ printk("pinctrl lookup state failed\n"); return -1; }else{ printk("pinctrl lookup state success\n"); } /*3、设置引脚状态 */ ret = pinctrl_select_state(myled.pinctrl, myled.state); if (ret < 0){ printk("pinctrl select state failed\n"); return -1; }else{ printk("pinctrl select state success\n"); } /* 输出状态state以及状态setting信息 */ if(myled.state->name != NULL){ printk("state name %s", myled.state->name); // 状态名称为default } /* 遍历当前状态下的所有setting */ list_for_each_entry(setting, &(myled.state->settings), node) { printk("setting type %d", setting->type); printk("setting dev_name %s", setting->dev_name); // 设备名称为myled if(setting->type == PIN_MAP_TYPE_MUX_GROUP ){ // 引脚复用 枚举值为2 printk("setting mux group %d", setting->data.mux.group); printk("setting mux func %d", setting->data.mux.func); }else{ // 配置引脚电气特性 printk("--------------configs start--------"); printk("setting configs group_or_pin %d", setting->data.configs.group_or_pin); for(i=0; i<setting->data.configs.num_configs; i++){ printk("setting configs configs %d", setting->data.configs.configs[i]); } printk("--------------configs end--------"); } } /* 4. 动态分配字符设备号 */ ret = alloc_chrdev_region(&myled.devid, 0, 1,DTSLED_NAME); // ls /proc/devices看到的名字 /* 返回值为负数,表示操作失败 */ if (ret < 0) { printk("alloc char device region failed\n"); goto faile_devid; }else{ printk("alloc char device region success\n"); } /* 5.初始化字符设备,添加字符设备 */ cdev_init(&myled.cdev, &led_fops); ret = cdev_add(&myled.cdev, myled.devid, DTSLED_CNT); /* 返回值为负数,表示操作失败 */ if (ret < 0) { printk("char device add failed\n"); goto fail_cdev; }else{ printk("char device add success\n"); } /* 6.创建类,它会在sys目录下创建/sys/class/dtsled这个类 */ myled.class = class_create(THIS_MODULE, DTSLED_NAME); if(IS_ERR(myled.class)){ printk("create class failed\n"); goto fail_class; }else{ printk("create class success\n"); } /* 7. 在/sys/class/led下创建dtsled设备,然后mdev通过这个自动创建/dev/dtsled这个设备节点 */ myled.device = device_create(myled.class, NULL, myled.devid, NULL, DTSLED_NAME); if(IS_ERR(myled.device)){ printk("create device failed\n"); goto fail_device; }else{ printk("create device success\n"); } return 0; fail_findnd: device_destroy(myled.class, myled.devid); fail_device: class_destroy(myled.class); fail_class: cdev_del(&myled.cdev); fail_cdev: unregister_chrdev_region(myled.devid, DTSLED_CNT); faile_devid: return ret; } /* * 硬件信息被移除了,或者驱动被卸载了,全部要释放,释放资源的操作就放在该函数中 */ static int led_remove(struct platform_device * pdev) { printk("led driver exit\n"); /* 注销类、以及类设备 */ device_destroy(myled.class, myled.devid); class_destroy(myled.class); /* 删除设备,卸载注册的设备编号 */ cdev_del(&myled.cdev); unregister_chrdev_region(myled.devid, DTSLED_CNT); return 0; } /* * 用于设备树匹配 */ static const struct of_device_id led_dt_match[] = { { .compatible = "myled", }, {}, }; /* * platform驱动 */ static struct platform_driver led_driver = { .probe = led_probe, .remove = led_remove, .driver = { .name = "myled", .of_match_table = led_dt_match, // 匹配列表 } }; /* * platform驱动模块入口 */ static int led_drv_init(void) { // platform驱动注册 int err = platform_driver_register(&led_driver); if (err) { printk("platform driver registered failed\n"); } else { printk("platform driver registered successfully\n"); } return err; } /* * platform驱动模块出口 */ static void __exit led_drv_exit(void) { printk("platform driver unregistered\n"); // platform驱动卸载 platform_driver_unregister(&led_driver); } module_init(led_drv_init); module_exit(led_drv_exit); MODULE_LICENSE("GPL");View Code
2.6 Makefile
KERN_DIR :=/work/sambashare/linux-5.2.8-dt all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.order obj-m += led_drv.o
三、LED驱动测试应用程序
在24.led_dev_pinctr下创建test文件夹,保存测试应用程序。
3.1 main.c
#include <sys/stat.h> #include <fcntl.h> #include <stdio.h> void print_usage(char *file) { printf("Usage:\n"); printf("%s <dev> <on|off>\n",file); printf("eg. \n"); printf("%s /dev/myled on\n", file); printf("%s /dev/myled off\n", file); } int main(int argc,char **argv) { int fd; int val; char *filename; if (argc != 3){ print_usage(argv[0]); return 0; } filename = argv[1]; fd = open(filename,O_RDWR); if(fd == -1){ printf("can't open %s!\n",filename); return 0; } if (!strcmp("on", argv[2])){ // 亮灯 val = 1; printf("%s on!\n",filename); write(fd, &val, 4); }else if (!strcmp("off", argv[2])){ // 灭灯 val = 0; printf("%s off!\n",filename); write(fd, &val, 4); }else{ print_usage(argv[0]); } return 0; }
3.2 Makefile
all: arm-linux-gcc -march=armv4t -o main main.c clean: rm -rf *.o main
四、烧录开发板测试
4.1 编译设备树
root@zhengyang:/work/sambashare/linux-5.2.8-dt# make dtbs DTC arch/arm/boot/dts/s3c2416-smdk2416.dtb DTC arch/arm/boot/dts/s3c2440-smdk2440.dtb
编译设备树文件,把前面配置过的arch/arm/boot/dts里的dts文件编译成dtb文件。
将s3c2440-smdk2440.dtb复制到tftp服务器路径下:
root@zhengyang:/work/sambashare/linux-5.2.8-dt# cp /work/sambashare/linux-5.2.8-dt/arch/arm/boot/dts/s3c2440-smdk2440.dtb /work/tftpboot/
4.2 编译驱动
执行make命令编译驱动,并将驱动程序拷贝到nfs文件系统:
root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr# cd /work/sambashare/drivers/24.led_dev_pinctr/ root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr# make root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr# cp /work/sambashare/drivers/24.led_dev_pinctr/led_drv.ko /work/nfs_root/rootfs/
4.3 启动内核
uboot启动后,将dtb下载到内存地址0x30001000中:
SMDK2440 # tftp 0x30001000 s3c2440-smdk2440.dtb
然后将内核镜像加载到内存0x30008000地址:
nand read 0x30008000 kernel;
然后可以使用如下命令启动内核:
SMDK2440 # bootm 0x30008000 - 0x30001000 // 无设备树时,直接bootm 0x30008000 //bootm uImage地址 ramdisk地址 设备树镜像地址
安装驱动:
[root@zy:/]# insmod led_drv.ko samsung-pinctrl 56000000.pinctrl: found group selector 30 for gpb-5 samsung-pinctrl 56000000.pinctrl: found group selector 30 for gpb-5 samsung-pinctrl 56000000.pinctrl: found group selector 31 for gpb-6 samsung-pinctrl 56000000.pinctrl: found group selector 31 for gpb-6 samsung-pinctrl 56000000.pinctrl: found group selector 32 for gpb-7 samsung-pinctrl 56000000.pinctrl: found group selector 32 for gpb-7 samsung-pinctrl 56000000.pinctrl: found group selector 33 for gpb-8 samsung-pinctrl 56000000.pinctrl: found group selector 33 for gpb-8 samsung-pinctrl 56000000.pinctrl: found group selector 30 for gpb-5 samsung-pinctrl 56000000.pinctrl: found group selector 30 for gpb-5 samsung-pinctrl 56000000.pinctrl: found group selector 31 for gpb-6 samsung-pinctrl 56000000.pinctrl: found group selector 31 for gpb-6 samsung-pinctrl 56000000.pinctrl: found group selector 32 for gpb-7 samsung-pinctrl 56000000.pinctrl: found group selector 32 for gpb-7 samsung-pinctrl 56000000.pinctrl: found group selector 33 for gpb-8 samsung-pinctrl 56000000.pinctrl: found group selector 33 for gpb-8 myled myled: no init pinctrl state samsung-pinctrl 56000000.pinctrl: request pin 30 (gpb-5) for myled samsung-pinctrl 56000000.pinctrl: request pin 31 (gpb-6) for myled samsung-pinctrl 56000000.pinctrl: request pin 32 (gpb-7) for myled samsung-pinctrl 56000000.pinctrl: request pin 33 (gpb-8) for myled myled myled: no sleep pinctrl state myled myled: no idle pinctrl state OF: no dma-ranges found for node(/myled) myled myled: device is not dma coherent myled myled: device is not behind an iommu platform device name myled pinctrl-names index 0 value default retrieves the pinctrl handle for a device success pinctrl lookup state success pinctrl select state success state name default // 输出状态名称 setting type 2 // ① pinctl_map类型为2 引脚复用 setting dev_name myled setting mux group 30 // 对应引脚gpb-5 setting mux func 11 setting type 4 // ② pinctrl_map类型为4 配置电气特性 setting dev_name myled --------------configs start-------- setting configs group_or_pin 30 setting configs configs 770 setting configs configs 1 --------------configs end-------- setting type 2 // ① setting dev_name myled setting mux group 31 // 对应引脚gpb-6 setting mux func 11 setting type 4 // ② setting dev_name myled --------------configs start-------- setting configs group_or_pin 31 setting configs configs 770 setting configs configs 1 --------------configs end-------- setting type 2 setting dev_name myled setting mux group 32 setting mux func 11 setting type 4 setting dev_name myled --------------configs start-------- setting configs group_or_pin 32 setting configs configs 770 setting configs configs 1 --------------configs end-------- setting type 2 setting dev_name myled setting mux group 33 setting mux func 11 setting type 4 setting dev_name myled --------------configs start-------- setting configs group_or_pin 33 setting configs configs 770 setting configs configs 1 --------------configs end-------- alloc char device region success char device add success device class 'myled': registering create class success PM: Adding info for No Bus:myled create device success platform driver registered successfully
这里输出了大量的调试信息,主要是因为我开启了调试日志。
查看设备节点文件:
[root@zy:/]# ls /dev/myled -l crw-rw---- 1 0 0 249, 0 Jan 1 00:56 /dev/myled
查看类:
[root@zy:/]# ls /sys/class/myled -l total 0 lrwxrwxrwx 1 0 0 0 Jan 1 02:52 myled -> ../../devices/virtual/myled/myled [root@zy:/]# ls /sys/class/myled/myled/ -l total 0 -r--r--r-- 1 0 0 4096 Jan 1 00:56 dev drwxr-xr-x 2 0 0 0 Jan 1 02:52 power lrwxrwxrwx 1 0 0 0 Jan 1 02:52 subsystem -> ../../../../class/myled -rw-r--r-- 1 0 0 4096 Jan 1 02:52 uevent
在linux的/sys/firmware/devicetree/base目录下可以查看到 myled节点,如下图所示:
[root@zy:/]# ls /sys/firmware/devicetree/base/ #address-cells model #size-cells myled aliases name chosen nand@4e000000 clock-controller@4c000000 pinctrl@56000000 clocks rtc@57000000 compatible serial@50000000 cpus serial@50004000 i2c@54000000 serial@50008000 interrupt-controller@4a000000 srom-cs4@20000000 interrupt-parent timer@51000000 memory@30000000 watchdog@53000000
进入myled节点的目录下可以查看到led节点的属性,如下图所示:
[root@zy:/]# ls /sys/firmware/devicetree/base/myled/ -l total 0 -r--r--r-- 1 0 0 6 Jan 1 02:53 compatible -r--r--r-- 1 0 0 6 Jan 1 02:53 name -r--r--r-- 1 0 0 4 Jan 1 02:53 pinctrl-0 -r--r--r-- 1 0 0 4 Jan 1 02:53 pinctrl-1 -r--r--r-- 1 0 0 18 Jan 1 02:53 pinctrl-names -r--r--r-- 1 0 0 5 Jan 1 02:53 status
4.4 编译测试应用程序
执行make命令编译测试应用程序,并将测试应用程序拷贝到nfs文件系统:
root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr# cd test/ root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr/test# make clean rm -rf *.o main root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr/test# make arm-linux-gcc -march=armv4t -o main main.c root@zhengyang:/work/sambashare/drivers/24.led_dev_pinctr/test# cp ./main /work/nfs_root/rootfs
运行应用程序:
[root@zy:/]# ./main /dev/myled on /dev/myled on! value 1 pinctrl lookup state success pinctrl select state success [root@zy:/]# ./main /dev/myled off /dev/myled off! value 0 pinctrl lookup state success samsung-pinctrl 56000000.pinctrl: request pin 30 (gpb-5) for myled samsung-pinctrl 56000000.pinctrl: request pin 31 (gpb-6) for myled samsung-pinctrl 56000000.pinctrl: request pin 32 (gpb-7) for myled samsung-pinctrl 56000000.pinctrl: request pin 33 (gpb-8) for myled pinctrl select state success
可以看到LED1~LED4同时点亮和同时熄灭。
4.5 卸载LED驱动
通过用lsmod可以查看当前安装了哪些驱动:
[root@zy:/]# lsmod led_drv 2476 0 - Live 0xbf000000 (O)
卸载时直接运行:
[root@zy:/]# rmmod led_drv.ko platform driver unregistered led driver exit PM: Removing info for No Bus:myled device class 'myled': unregistering class 'myled': release. class_create_release called for myled
五、代码下载
Young / s3c2440_project[drivers]
标签:LED,pinctrl,state,setting,myled,linux,led,printk From: https://www.cnblogs.com/zyly/p/17369432.html