硬件连接图如下所示:我们要操作的是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");