leds {
#address-cells = <1>;
#size-cells = <1>;
compatible = "atkalpha-gpioled";
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_gpio_leds> //设置led 所使用 PIN 对应的pinctrl节点
led-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; //设置LED所使用的GPIO
status = "okay";
}
描述led 信息而已。
重点
compatible = "atkalpha-gpioled";
platform驱动需要通过 compatible 属性值来匹配驱动
驱动程序#include代码片段1 分析#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LEDDEV_CNT 1 #define LEDDEV_NAME "dtsplatled" #define LEDOFF 0 #define LEDON 1 struct leddev_dev{ dev_t devid; struct cdev cdev; struct class *class; struct device *device; int major; struct device_node *node; int led0; }; struct leddev_dev leddev; void led0_switch(u8 sta) { if (sta == LEDON ) gpio_set_value(leddev.led0, 0); else if (sta == LEDOFF) gpio_set_value(leddev.led0, 1); } static int led_open(struct inode *inode, struct file *filp) { filp->private_data = &leddev; return 0; } static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue; unsigned char databuf[2]; unsigned char ledstat; retvalue = copy_from_user(databuf, buf, cnt); if(retvalue < 0) { printk("kernel write failed!rn"); return -EFAULT; } ledstat = databuf[0]; if (ledstat == LEDON) { led0_switch(LEDON); } else if (ledstat == LEDOFF) { led0_switch(LEDOFF); } return 0; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .write = led_write, }; static int led_probe(struct platform_device *dev) { printk("led driver and device was matched!rn"); if (leddev.major) { leddev.devid = MKDEV(leddev.major, 0); register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME); } else { alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME); leddev.major = MAJOR(leddev.devid); } cdev_init(&leddev.cdev, &led_fops); cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT); leddev.class = class_create(THIS_MODULE, LEDDEV_NAME); if (IS_ERR(leddev.class)) { return PTR_ERR(leddev.class); } leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME); if (IS_ERR(leddev.device)) { return PTR_ERR(leddev.device); } leddev.node = of_find_node_by_path("/gpioled"); if (leddev.node == NULL){ printk("gpioled node nost find!rn"); return -EINVAL; } leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0); if (leddev.led0 < 0) { printk("can't get led-gpiorn"); return -EINVAL; } gpio_request(leddev.led0, "led0"); gpio_direction_output(leddev.led0, 1); return 0; } static int led_remove(struct platform_device *dev) { gpio_set_value(leddev.led0, 1); cdev_del(&leddev.cdev); unregister_chrdev_region(leddev.devid, LEDDEV_CNT); device_destroy(leddev.class, leddev.devid); class_destroy(leddev.class); return 0; } static const struct of_device_id led_of_match[] = { { .compatible = "atkalpha-gpioled" }, { } }; static struct platform_driver led_driver = { .driver = { .name = "imx6ul-led", .of_match_table = led_of_match, }, .probe = led_probe, .remove = led_remove, }; static int __init leddriver_init(void) { return platform_driver_register(&led_driver); } static void __exit leddriver_exit(void) { platform_driver_unregister(&led_driver); } module_init(leddriver_init); module_exit(leddriver_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("zuozhongkai");
static int led_probe(struct platform_device *dev)
{
printk("led driver and device was matched!rn");
if (leddev.major) {
leddev.devid = MKDEV(leddev.major, 0);
register_chrdev_region(leddev.devid, LEDDEV_CNT, LEDDEV_NAME);
} else {
alloc_chrdev_region(&leddev.devid, 0, LEDDEV_CNT, LEDDEV_NAME);
leddev.major = MAJOR(leddev.devid);
}
cdev_init(&leddev.cdev, &led_fops);
cdev_add(&leddev.cdev, leddev.devid, LEDDEV_CNT);
leddev.class = class_create(THIS_MODULE, LEDDEV_NAME);
if (IS_ERR(leddev.class)) {
return PTR_ERR(leddev.class);
}
leddev.device = device_create(leddev.class, NULL, leddev.devid, NULL, LEDDEV_NAME);
if (IS_ERR(leddev.device)) {
return PTR_ERR(leddev.device);
}
leddev.node = of_find_node_by_path("/gpioled");
if (leddev.node == NULL){
printk("gpioled node nost find!rn");
return -EINVAL;
}
leddev.led0 = of_get_named_gpio(leddev.node, "led-gpio", 0);
if (leddev.led0 < 0) {
printk("can't get led-gpiorn");
return -EINVAL;
}
gpio_request(leddev.led0, "led0");
gpio_direction_output(leddev.led0, 1);
return 0;
}
重点
led_probe 实现 platform_driver中的probe 的函数 当驱动匹配 设备 此函数就会执行。
完成驱动加载的一些任务
(1)获取设备号
(2) 初始化 字符设备
cdev_init(&leddev.cdev, &led_fops); 就是字符设备的文件操作集合
不需要 gpioled.cdev.owner = THIS_MODULE;
(3) 添加一个cdev
(4) 创建类
(5) 创建设备
(6) 初始化IO
代码片段2分析
static int led_remove(struct platform_device *dev)
{
gpio_set_value(leddev.led0, 1);
cdev_del(&leddev.cdev);
unregister_chrdev_region(leddev.devid, LEDDEV_CNT);
device_destroy(leddev.class, leddev.devid);
class_destroy(leddev.class);
return 0;
}
完成驱动卸载的一些任务
代码片段3分析static int __init leddriver_init(void)
{
return platform_driver_register(&led_driver);
}
原来的驱动加载 任务 注册一个platform_driver 即可
代码片段4分析static void __exit leddriver_exit(void)
{
platform_driver_unregister(&led_driver);
}
原来的驱动卸载 任务 卸载一个platform_driver 即可
代码片段5分析
static const struct of_device_id led_of_match[] = {
{ .compatible = "atkalpha-gpioled" },
{ }
};
platform_driver 匹配驱动 和设备的钥匙 匹配方式是 设备树
应用程序#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#define LEDOFF 0
#define LEDON 1
int main(int argc, char *argv[])
{
int fd, retvalue;
char *filename;
unsigned char databuf[2];
if(argc != 3){
printf("Error Usage!rn");
return -1;
}
filename = argv[1];
fd = open(filename, O_RDWR);
if(fd < 0){
printf("file %s open failed!rn", argv[1]);
return -1;
}
databuf[0] = atoi(argv[2]);
retvalue = write(fd, databuf, sizeof(databuf));
if(retvalue < 0){
printf("LED Control Failed!rn");
close(fd);
return -1;
}
retvalue = close(fd);
if(retvalue < 0){
printf("file %s close failed!rn", argv[1]);
return -1;
}
return 0;
}



