使用gpiolib的GPIO应用例子

/*
*  Status LEDs driver 
*  Copyright (c) 2012 
*/
#include <linux/module.h>  
#include <linux/types.h>  
#include <linux/fs.h>  
#include <linux/errno.h>  
#include <linux/mm.h>  
#include <linux/cdev.h>  
#include <linux/sched.h> 
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h> 
#include <asm/uaccess.h>

#define DEVICE_NAME "Statusled"    //定义设备名  
#define LED_MAJOR 261             //定义主设备号  
#define LED_MINOR 0     
#define LED_MAGIC 0xBB            //定义幻数  
//定义操作    
#define LED_ON  _IOW(LED_MAGIC,1,int)
#define LED_OFF _IOW(LED_MAGIC,2,int)


static int led_major = LED_MAJOR; //设置主设备号
struct statusled_dev{  //define dev struct
	unsigned char value;
	struct semaphore sem;   //定义信号量
	struct cdev cdev;
};
struct led_gpio {
	unsigned base;
	unsigned gpio;
	#define GPIOF_DIR_OUT       0x00000001
	#define GPIOF_DIR_IN 	 0x00000002
	#define GPIOF_INIT_LOW 	 0x00000004
	#define GPIOF_INIT_HIGH	 0x00000008
unsigned long flags;
	const char *label;
};
static struct led_gpio leds_gpio[]={
	{224,6,GPIOF_DIR_OUT | GPIOF_INIT_LOW,"RUN LED"},
	{224,8,GPIOF_DIR_OUT | GPIOF_INIT_LOW,"ERRO LED"},
	//{},
};
struct statusled_dev *statusled_devp = NULL;
static int leds_open(struct inode *inode, struct file *filp)
{
	struct statusled_dev *dev;  
	int i,j;
    dev = container_of(inode->i_cdev, struct statusled_dev, cdev); //通过结构体成员指针找到对应结构体的指针  
    filp->private_data = dev;    //将设备结构体指针赋给文件私有数据指针   
    //TODO: Status tips
	printk("statusled device opened\n"); 
    return 0;  
}
static int leds_release(struct inode *inode, struct file *filp)
{
	int i,j; 
    //TODO 
	printk("statusled device closing\n");
    return 0;  
}
/*
*	leds_write
*	I want to modify all the leds status,so,there ervery one ....bits
*	note: don't use size.so,the max led number is 8;
*/
static ssize_t leds_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
	int i;	
	struct statusled_dev *dev = filp->private_data; 
	int num =  ARRAY_SIZE(leds_gpio);
    down(&dev->sem);    
	copy_from_user(&(dev->value),buf,1);

	for(i=0; i < num; i++){
		gpio_set_value(leds_gpio[i].base + leds_gpio[i].gpio,((dev->value >> i) & 0x01)%2);
	}
    up(&dev->sem);  
	printk(KERN_ALERT "status LED device write ,dev->value: %d\n",dev->value);
    return size;  
}
static int leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	if(arg > 4){
		return -EINVAL;
	}
	switch (cmd)  
    {  
        case LED_ON:   
			gpio_set_value(leds_gpio[arg].base + leds_gpio[arg].gpio,0);
            return 0;  
		case LED_OFF:  
			gpio_set_value(leds_gpio[arg].base + leds_gpio[arg].gpio,1);
            return 0;  
        default:  
            return -EINVAL;  
    }  
}
//file_operations  
static struct file_operations leds_fops = {  
    .owner = THIS_MODULE,  
    .open = leds_open,  
    .release = leds_release,   
    .write = leds_write,  
    .ioctl = leds_ioctl,  
};  
	 
static int leds_request(struct led_gpio *leds,size_t num){
	int i,ret = 0;
	for(i=0;i<num;i++){
		ret = gpio_request(leds[i].gpio + leds[i].base,leds[i].label);
		if(ret){
			printk("%s:request gpio %d faild\n",leds[i].label,leds[i].gpio);
			return ret;
		}
		if((leds[i].flags) & GPIOF_DIR_OUT) {// output
			if((leds[i].flags) & GPIOF_INIT_LOW){
				gpio_direction_output(leds_gpio[i].base + leds[i].gpio,0);
			}
			else{
				gpio_direction_output(leds_gpio[i].base + leds[i].gpio,1);
			}
		}
		else if((leds[i].flags) & GPIOF_DIR_IN){ //input
			gpio_direction_input(leds_gpio[i].base + leds[i].gpio);
		}
		else{
			return -EINVAL;
		}
	}
	return ret;
}
static int leds_free(struct led_gpio *leds,size_t num){
	int  i,ret = 0;
	for(i=0; i<num;i++){
		gpio_free(leds[i].base + leds[i].gpio);}
	return ret;
}
// inint cdev struct and register a char dev
static void statusled_setup_cdev(struct statusled_dev *dev,int index)
{
	int err,devno=MKDEV(led_major, LED_MINOR+index);
	cdev_init(&dev->cdev,&leds_fops);
    dev->cdev.owner = THIS_MODULE;  
    dev->cdev.ops = &leds_fops;
	err = leds_request(&leds_gpio,ARRAY_SIZE(leds_gpio));
	if(err){
		printk(KERN_NOTICE "Error:request gpio faild \n");}
	err = cdev_add(&dev->cdev,devno,1);
	if(err)
		printk(KERN_NOTICE "Error %d adding statusled%d\n",err,index);
}
static  int __init statusleds_init(void)
{
    int result,i,j;  
    dev_t devno = MKDEV(led_major, LED_MINOR); //创建设备号   
     //注册设备号  
     if (led_major)  {  
        result = register_chrdev_region(devno, 1, DEVICE_NAME);  
    }  
    else {  
        result = alloc_chrdev_region(&devno, LED_MINOR, 1, DEVICE_NAME);  
        led_major = MAJOR(devno);  
    }  
    if (result < 0) {  
        printk("Can't register\n");  
        return result;  
    }  
	statusled_devp = kmalloc(sizeof(struct statusled_dev), GFP_KERNEL);  
    if (!statusled_devp)  {  
        result = -ENOMEM;  
        unregister_chrdev_region(devno, 1);  
        return result;  
    }  
    memset(statusled_devp, 0, sizeof(struct statusled_dev));  
	statusled_setup_cdev(statusled_devp,0);
	init_MUTEX(&statusled_devp->sem);
	printk("Status LEDs Function is enable\n");
	return 0;
}
static  void __exit statusleds_exit(void){
	int i,j;
	leds_free(&leds_gpio,ARRAY_SIZE(leds_gpio));
	cdev_del(&statusled_devp->cdev);  
    kfree(statusled_devp);  
    unregister_chrdev_region(MKDEV(led_major, LED_MINOR), 1); 
	printk("Status LEDs Function is disable\n");
}
module_init(statusleds_init);  
module_exit(statusleds_exit);  

MODULE_AUTHOR("Caijun");  
MODULE_DESCRIPTION("Status LEDs Driver"); // 一些描述信息  
MODULE_LICENSE("GPL");


 

你可能感兴趣的:(Module,led,GPIO,GPIO,GPIOLIB)