led驱动程序 基于FL2440

硬件连接图如下所示:我们要操作的是GPB5,GPB6,GPB8,GPB10



打开相应s3c2440 datasheet,查看寄存器配置




/*********************************************************************************

 *      Copyright:  (C) 2015 zhanghaijun
 *                  All rights reserved.
 *
 *       Filename:  my_led.c
 *    Description:  This file is used as a led driver
 *                 
 *        Version:  1.0.0(10/25/2015)
 *         Author:  zhanghaijun <[email protected]>
 *      ChangeLog:  1, Release initial version on "10/25/2015 06:22:09 PM"
 *                 
 ********************************************************************************/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <asm/ioctl.h>


#define LED_BASE    0X56000010    /*LED physical address */
#define LED_CON     0X00          /*LED control control  address */
#define LED_DAT     0X04          /*LED data  address */
#define LED_UP      0X08          /*LED pull up configure register */
#define LED_LENGTH         0X10          /*LED register memory length */
#define PULL_UP_ENABLE     0X00
#define PULL_UP_DISABLE    0X01
#define OUTPUT             0X01
#define HIGH_LEVEL         0X01
#define LED_MAJOR   0
#define DEVICE_MAGIC     0X60
#define LED_ON          _IO(DEVICE_MAGIC,0X01)
#define LED_OFF         _IO(DEVICE_MAGIC,0X2)
 
#define s3c_write(val, reg) __raw_writel((val), (reg)+s3c_gpb_base)
#define s3c_read(reg)       __raw_readl((reg)+s3c_gpb_base)

int  Led_table[]={5,6,8,10};
int  led_number = 4;
static void __iomem   *s3c_gpb_base;
int led_major = LED_MAJOR;
int led_minor =  0;
struct cdev *my_cdev;
dev_t led_dev  =0;
static int s3c_hw_init();
static void  turn_led(int which,int cmd);
static int led_open(struct inode *inode , struct file *file);
static int led_release(struct inode *inode,struct file *file);
static int led_ioctl(struct file *file,unsigned int cmd,unsigned long a);

/* 实现具体的设备驱动*/
 struct file_operations led_ops=
 {
         .owner      = THIS_MODULE,
         .open       = led_open,
         .release    = led_release,
         .unlocked_ioctl      = led_ioctl,
 };


static int __init s3c_led_init(void)
{
   led_dev = MKDEV(led_major,led_minor);
   if(s3c_hw_init()!=0)
   {
       printk(KERN_ERR "led inital error");
       return -ENODEV;
   }

   if(led_major)         /*分配设备号失败*/
   {
      if(register_chrdev_region(led_dev,led_number,"my_led")!=0)
            printk(KERN_ERR "分配设备号失败");
   }
   else
   {
        if(alloc_chrdev_region(&led_dev,0,led_number,"my_led")!=0)
            printk(KERN_ERR "动态分配设备号失败");
   }
   /***************************************************/
   /*************字符设备注册**************************/
    my_cdev       =cdev_alloc(); //分配字符设备内存
    my_cdev->ops  =&led_ops;
   my_cdev->owner = THIS_MODULE;
   cdev_init(my_cdev,&led_ops);  //字符设备初始化,与相应驱动程序的ops结构相关联
    cdev_add(my_cdev,led_dev,led_number);//向内核中加入驱动程序
  printk(KERN_DEBUG "加入模块");

}


 static void __exit s3c_led_exit(void)
 {
        //dev_t devno = MKDEV(led_major, led_minor);
           //s3c_hw_term();
         
           cdev_del(my_cdev);
           unregister_chrdev_region(led_dev,led_number);
         
            printk(KERN_ERR "S3C driver removed!\n");
             //DEV_NAME, DRV_MAJOR_VER, DRV_MINOR_VER,DRV_REVER_VER);
         
             //.return 0 ;

    }
static int s3c_hw_init()
{
    unsigned char i;
    volatile unsigned long  s3c_gpb_con,s3c_gpb_data,s3c_gpb_up;
   if(!request_mem_region(LED_BASE,LED_LENGTH,"LED devices"))   
   {
       return EBUSY;
   }
   if(!(s3c_gpb_base=ioremap(LED_BASE,LED_LENGTH)))
   {
       release_mem_region(LED_BASE,LED_LENGTH);
       return ENOMEM;
   }
   for(i=0;i<4;i++)
   {
       s3c_gpb_con = s3c_read(LED_CON);
       s3c_gpb_con &= ~(0x03<<(2*Led_table[i]));  /*reset gpio as input mode */
       s3c_gpb_con |= (OUTPUT<<(2*Led_table[i]));  /* set gpio as output mode */
       s3c_write(s3c_gpb_con, LED_CON);
       s3c_gpb_up = s3c_read(LED_UP);
       s3c_gpb_up &= ~(PULL_UP_DISABLE<<Led_table[i]);/*reset  gpio as pull up */
       s3c_gpb_up |= (PULL_UP_ENABLE<<Led_table[i]);  /*disable gpio pull up */
       s3c_write(s3c_gpb_up,LED_UP);
       
       s3c_gpb_data = s3c_read(LED_DAT);
       s3c_gpb_data &= ~(0X01<<Led_table[i]);  /*reset gpio output low level*/
       s3c_gpb_data |= (HIGH_LEVEL<<Led_table[i]);
       s3c_write(s3c_gpb_data,LED_DAT);/*set as high level */

   }

return 0;
}

static void  turn_led(int which ,int cmd)
{
    volatile unsigned long  s3c_gpb_data ;
   s3c_gpb_data = __raw_readl(s3c_gpb_base+LED_DAT);
   
   if(cmd==LED_ON)
        {
           s3c_gpb_data &= ~(0x01<<Led_table[which]);
           s3c_write(s3c_gpb_data,LED_DAT);
        }
   else
   {
       s3c_gpb_data &=(0x01<<Led_table[which]);
       s3c_write(s3c_gpb_data,LED_DAT);

   }
}
static int led_open(struct inode *inode , struct file *file)
{
      int minor = iminor(inode);
      file->private_data = (void *)minor;
      printk(KERN_DEBUG "dev/led%d open.\n",minor);
      return 0;
}

static int led_release(struct inode *inode ,struct file *file)
{
      printk(KERN_DEBUG "dev/led%d closed ",iminor(inode));
      return 0;
}
static int led_ioctl(struct file *file,unsigned int cmd,unsigned long  a)

   {
       int which = (int)file->private_data ;
      switch(cmd)
   
    {
    case LED_ON:
          turn_led(which,LED_ON);
          break;
   case LED_OFF:
          turn_led(which,LED_OFF);
          break;
    default:
          turn_led(which,LED_OFF);
    }
   return 0;       
}







module_init(s3c_led_init);
module_exit(s3c_led_exit);


MODULE_LICENSE("GPL");

你可能感兴趣的:(led驱动程序 基于FL2440)