栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

正点原子 linux led 驱动之 设备树 + platform

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

正点原子 linux led 驱动之 设备树 + platform

设备树代码
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 
#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");



代码片段1 分析
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;
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/914676.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号