9、LED驱动

编写步骤:

1、确定LED是哪个GPIO,通过看原理图确认

2、配置GPIO的寄存器(复用关系、方向、数据寄存器)

        找到相关寄存器的地址 例如设置复用功能的寄存器设置:       

Linux系统 可以使用 io 命令查看寄存器的值 :

io -r -4 0xfdc2000c

3、驱动代码里使用ioremap 获取寄存器的虚拟地址

例程

#include <linux/module.h>
#include <linux/init.h> 
#include <linux/fs.h>
#include <linux/modulepram.h>
#include <linux/kdev_t.h> 
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
 
 
 #define LED_GPIO_DIR_REG   0xfd000000
 #define LED_GPIO_DATA_REG  0xfd00000C
 
 
struct led_device={
 
    dev_t dev_num; 
    int major;
    int minor;  
 
    struct cdev cdev_test; 
    struct class *class;
    struct device *device;
    char kbuf[32];
	unsigened int  *vir_gpio_dir;
 
 
}
 
 
struct led_device  led1;
 
 
 
 
static  int led_open(struct inode *node, struct file *file)
{
    file->private_data=&led1;
 
     printk("cdev_test_open \n");
     return 0;
}
 
static int cdev_test_release(struct inode *node, struct file *file)
{
 
     printk("cdev_test_release \n");
     return 0;
 
}
 
static ssize_t cdev_test_read (struct file *file, char __user *buf, size_t size, loff_t *off)
{
    struct led_device *test_dev=(struct led_device *) file->private_data;
 
    char kbuf[64]="123456hello";
    
    copy_to_user(buf,test_dev ->kbuf,strlen(test_dev ->kbuf));
 
     printk("cdev_test_read \n");
 
 
}  
 
static ssize_t cdev_test_write (struct file *file, const char __user *buf, size_t size, loff_t *off)
{
     struct led_device *test_dev=(struct led_device *) file->private_data;
     char kbuf[64];
     copy_from_user(test_dev -> kbuf,buf,size);
     printk("write buf[%s]\n",test_dev ->kbuf);
     printk("cdev_test_write\n");  
}
 
 
struct file_operations cdev_test_ops={
 
    .owner=THIS_MODULE,
    .open=cdev_test_open,
    .release=cdev_test_release,
    .read=cdev_test_read,
    .write=cdev_test_write,
    .ioctl=cdev_test_ioctl
};
 
 
static int cdv_init(void)
{
    int ret; 
 
	//动态申请
	ret=alloc_chrdev_region(&led1.dev_num,0,1,"led_num");
	if( ret <0 )
	{
		printk("alloc_chrdev_regionerr %d\n",ret);
		goto err_alloc_chrdev_region;
	}
	printk("dev_num=%d \n",led1.dev_num);
	led1.major = MAJOR(led1.dev_num);
	led1.minor = MINOR(led1.dev_num);
	printk("input major=%d minor=%d \n",led1.major,led1.minor);
   
 
    led1.cdev_test.owner= THIS_MODULE;
    cdev_init(&led1.cdev_test,&cdev_test_ops);  
    ret = cdev_add(&led1.cdev_test,led1.dev_num,1);
 	if( ret <0 )
	{
		printk("alloc_chrdev_regionerr %d\n",ret);
		goto err_cdev_add;
	}
    led1.class = class_create(THIS_MODULE,"led1");	
    if(IS_ERR(led1.class  ))
    {
        ret=PTR_ERR( led1.class );
        goto err_device_create ;
    }

	
    led1.device = device_create(led1.class,NULL,led1.dev_num,NULL,"/dev/led1");
    
    if(IS_ERR(led1.device ))
    {
        ret=PTR_ERR( led1.device );
        goto err_device_create ;
    }
	
	
	
	//内核中不能直接操作虚拟地址,需要将物理地址转换成虚拟地址
	led1.vir_gpio_dir= ioremap(LED_GPIO_DIR_REG,4);  
    
	
	
    printk("cdv init\n");
    return 0;
	
	
err_device_create:
    device_destroy(led1.class,led1.dev_num);
err_class_create:
    classs_destroy(led1.class);
err_cdev_add:
    cdev_del(&led1.cdev_test);	
err_alloc_chrdev_region :
    unregister_chrdev_region(led1.dev_num,1);

	
}
 
static void cdv_exit(void)
{
	iounmap(led1.vir_gpio_dir);
	
    device_destroy(led1.class,led1.dev_num);
    classs_destroy(led1.class);
 
 
    cdev_del(&led1.cdev_test);	
    //释放设备号
    unregister_chrdev_region(led1.dev_num,1);
	
    printk("cdv exit\n");
    return 0;
}
 
 
module_init(cdv_init);
module_exit(cdv_exit);
 
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SONG");
MODULE_VERSION("v1.0");

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值