GPIO驱动框架,这里只针对高低电平

这里就写个驱动代码框架即可

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/io.h>
#include <linux/spinlock.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>

#include "led.h"

MODULE_LICENSE("GPL");

struct led_device
{
	dev_t devno;
	int   gpio;
	int   trigger_level;
	struct cdev cdev;
	struct class *cls;
	struct device *device;
};

int exynos_led_open(struct inode *inode, struct file *file)
{
	struct led_device *pled = container_of(inode->i_cdev,struct led_device,cdev);
	printk("open success");
	file->private_data = pled;

	return 0;
}

int exynos_led_release(struct inode *inode, struct file *file)
{
	struct led_device *pled = container_of(inode->i_cdev,struct led_device,cdev);
	
	//关闭led灯
	gpio_direction_output(pled->gpio,!pled->trigger_level);
	
	return 0;
}

long exynos_led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
	int ret;
	int level;
	struct led_device *pled =file->private_data;
		
	switch(cmd)
	{
		case DEV_LED_ON:
			level = pled->trigger_level;
			break;

		case DEV_LED_OFF:
			level = !(pled->trigger_level);
			break;

		default:
			return -EINVAL;
	}

	printk("gpio : %d,level : %d\n",pled->gpio,level);
	ret = gpio_direction_output(pled->gpio,level);
	if (ret) {
		printk("Setting LED GPIO direction failed!\n");
		return ret;
	}

	return 0;
}

struct file_operations exynos_led_fops = {
	.owner   = THIS_MODULE,
	.open    = exynos_led_open,
	.release = exynos_led_release,
	.unlocked_ioctl = exynos_led_ioctl,
};

int register_led_device(struct platform_device *pdev)
{
	int ret;
	struct led_device *pled = platform_get_drvdata(pdev);

	cdev_init(&pled->cdev,&exynos_led_fops);

	//动态申请设备号
	ret = alloc_chrdev_region(&pled->devno,0, 1,pdev->name);
	if(ret < 0){
		printk("Cannot alloc dev num");
		return ret;
	}

	//添加字符设备
	ret = cdev_add(&pled->cdev,pled->devno, 1);
	if(ret < 0){
		printk("Failed to add cdev");
		goto err_cdev_add;
	}

	//创建led类
	pled->cls = class_create(THIS_MODULE, "fs-led");
	if(IS_ERR(pled->cls)){
		printk("Failed to class_create\n");
		ret = PTR_ERR(pled->cls);
		goto err_class_create;
	}

	
	//导出设备信息到用户空间,由udev来创建设备节点
	pled->device = device_create(pled->cls,NULL,pled->devno,NULL,"led2.2");
	if(IS_ERR(pled->device)){
			printk("Failed to device_create");
			ret = PTR_ERR(pled->device);
			goto err_device_create;
	}

	return 0;

err_device_create:
	class_destroy(pled->cls);

err_class_create:
	cdev_del(&pled->cdev);

err_cdev_add:
	unregister_chrdev_region(pled->devno,1);

	return ret;
}

static int  exynos_led_probe(struct platform_device *pdev)
{
	int ret;
	struct led_device *pled;
	struct device_node *led_node = pdev->dev.of_node;
	
	printk("match\n");

	printk("pdev->name : %s\n",pdev->name);

	//动态分配led_device内存
	pled = devm_kzalloc(&pdev->dev,sizeof(struct led_device),GFP_KERNEL);
	if (!pled){
		printk("Fail to malloc memory for pled\n");
		return -ENOMEM;
	}
	platform_set_drvdata(pdev, pled);

	//获取led灯对应的gpio口
	/*
	 *@led_node   : 设备树的节点对应的结构体(struct device_node)地址
	 *@led-gpio   : gpio的属性名称
	 *@0          : 这个设备的第一个gpio 
	 *@flags      : 获取设备树的gpio描述的标志
	<p align="justify"> *return      : 返回的是gpio的编号
	 */
	pled->gpio = of_get_named_gpio_flags(led_node,"led-gpio",0,(enum of_gpio_flags *)&pled->trigger_level);
	printk("os gpio number:%d\n",pled->gpio);
	//判断是否是有效的gpio口
	if(!gpio_is_valid(pled->gpio)){
		printk("invalid led-gpios:%d\n",pled->gpio);
		return -ENODEV;
	}

	//请求占用gpio
	ret = devm_gpio_request(&pdev->dev,pled->gpio,"led-gpios");
	if (ret){
		printk("Failed GPIO request for GPIO %d: %d\n",pled->gpio, ret);
		return ret;
	}

	//注册led_device到系统
	ret = register_led_device(pdev);
	if(ret < 0){
		printk("Fail to register led device!\n");
		return ret;
	}
		
	return 0;
}


static int exynos_led_remove(struct platform_device *pdev)
{
	struct led_device *pled = platform_get_drvdata(pdev);
	
	printk("led_remove: device remove\n");
		
	device_destroy(pled->cls,pled->devno);
	class_destroy(pled->cls);
	cdev_del(&pled->cdev);
	unregister_chrdev_region(pled->devno,1);

	return 0;
}


#if defined(CONFIG_OF)
static const struct of_device_id exynos_led_dt_ids[] = {
	{ .compatible = "fs4412-led-gpio" },
	{ /* sentinel */ }
};

MODULE_DEVICE_TABLE(of, exynos_led_dt_ids);
#endif

static struct platform_driver exynos_led_driver = {
	.probe		= exynos_led_probe,
	.remove     = exynos_led_remove,
	.driver		= {
		.owner	= THIS_MODULE,
		.name	= "exynos-led",
		.of_match_table = of_match_ptr(exynos_led_dt_ids),
	},
};

int __init led_init(void)
{
	int ret;
	
	printk("Register led driver to platfrom bus!\n");

	ret = platform_driver_register(&exynos_led_driver);
	
	return ret;	
}



void __exit led_exit(void)
{
	printk("Remove led driver to platfrom bus!\n");
	
	platform_driver_unregister(&exynos_led_driver);
	return;
}

module_init(led_init);
module_exit(led_exit);

设备树编写实例

fs4412-led-gpio{
compatible = “fs4412-led-gpio”;
led-gpio = <&gpx2 7 1>;
}; 7代表管脚,1代表低电平使能

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值