这是昨天写的内核定时器驱动,分享一下
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <plat/gpio-cfg.h>
#include <plat/regs-clock.h>
#include <plat/regs-gpio.h>
#include <plat/gpio-bank-e.h>
#include <plat/gpio-bank-f.h>
#include <plat/gpio-bank-k.h>
#include <linux/timer.h>
#define DEVICE_NAME "pwmtimer"
int PWMTIMER_MAJOR=277;
/*定时器生成pwm驱动设备结构体*/
struct pwmtimer_dev{
struct cdev cdev;
atomic_t counter;
struct timer_list pwm_timer;
};
struct pwmtimer_dev *pwmtimerdev;
unsigned int time=0;
unsigned int pwm[2]={10,10};
unsigned int tmp=0;
/*定时器中断处理函数*/
static void pwm_timer_irq(unsigned long data){
mod_timer(&pwmtimerdev->pwm_timer ,jiffies +1);
atomic_inc(&pwmtimerdev->counter);
printk("%ld timer is working! HZ is %d\n",jiffies,HZ);
{
time++;
if(time ==pwm[0])
{
tmp = readl(S3C64XX_GPEDAT);
tmp |= (0x4);
writel(tmp, S3C64XX_GPEDAT);
}
if(time ==pwm[1])
{
tmp = readl(S3C64XX_GPEDAT);
tmp |= (0x8);
writel(tmp, S3C64XX_GPEDAT);
}
if(time ==20)
{
tmp = readl(S3C64XX_GPEDAT);
tmp &= ~(0xc);
writel(tmp, S3C64XX_GPEDAT);
time=0;
}
}
}
/*文件打开函数*/
static int pwmtimer_open(struct inode *inode , struct file *file){
init_timer(&pwmtimerdev->pwm_timer);//初始化定时器
pwmtimerdev->pwm_timer.function = &pwm_timer_irq;//设置中断函数
pwmtimerdev->pwm_timer.expires = jiffies +HZ;//设置定时器的溢出时间
add_timer(&pwmtimerdev->pwm_timer);//注册定时器
atomic_set(&pwmtimerdev->counter , 0);//counter清零
printk("open is working success!\n");
return 0;
}
/*文件释放函数*/
static int pwmtimer_release(struct inode *inode , struct file *file){
printk("release is working!\n");
del_timer(&pwmtimerdev->pwm_timer);
return 0;
}
/*ioctl函数*/
static int pwmtimer_ioctl(struct inode *inode , struct file *file , unsigned int cmd , unsigned long arg){
return 0;
}
static ssize_t pwmtimer_read(struct file *file , char __user *buf ,size_t count , loff_t *ppos){
int counter;
counter = atomic_read(&pwmtimerdev->counter);
if(put_user(counter, (int*)buf))
{
//printk("read is working success!\n");
return - EFAULT;
}
else
{
//printk("read is working fail!\n");
return sizeof(unsigned int);
}
}
/*文件操作结构体*/
static const struct file_operations pwmtimer_fops = {
.owner = THIS_MODULE,
.open = pwmtimer_open,
.release = pwmtimer_release,
.ioctl = pwmtimer_ioctl,
.read = pwmtimer_read,
};
/*初始化并注册cdev*/
static void pwmtimer_init_cdev(struct pwmtimer_dev *dev , int index){
int error , devno =MKDEV(PWMTIMER_MAJOR , index);
cdev_init(&dev->cdev , &pwmtimer_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &pwmtimer_fops;
error = cdev_add(&dev->cdev , devno , 1);
if(error)
printk(KERN_NOTICE "Error %d adding LED %d\n" , error , index);
}
/*设备驱动模块初始化函数*/
static int pwmtimer_init(void){
int ret;
dev_t devno = MKDEV(PWMTIMER_MAJOR , 0);
/*申请设备号*/
if(PWMTIMER_MAJOR)
ret=register_chrdev_region(devno , 1 ,"pwmtimer");
else
{
ret = alloc_chrdev_region(&devno , 0 ,1 ,"pwmtimer");
PWMTIMER_MAJOR = MAJOR(devno);
}
if(ret<0)
return ret;
pwmtimerdev = kmalloc(sizeof(struct pwmtimer_dev) , GFP_KERNEL);
if(!pwmtimerdev)
{
ret = - ENOMEM;
unregister_chrdev_region(devno , 1);
return -1;
}
memset(pwmtimerdev , 0 , sizeof(struct pwmtimer_dev));
pwmtimer_init_cdev(pwmtimerdev , 0);
printk("init pwmtimerdev success!\n");
printk("MAJOR is %d!\n",PWMTIMER_MAJOR);
{
unsigned temp;
temp = readl(S3C64XX_GPECON);
temp = (temp & ~(0xffU<<8))|(0x11U<<8);
writel(temp, S3C64XX_GPECON);
temp = readl(S3C64XX_GPEDAT);
temp |= (0xc);
writel(temp, S3C64XX_GPEDAT);
}
return 0;
}
/*模块卸载函数*/
void pwmtimer_exit(void){
cdev_del(&pwmtimerdev->cdev);//注销cdev
kfree(pwmtimerdev);//释放设备结构体内存
unregister_chrdev_region(MKDEV(PWMTIMER_MAJOR , 0) , 1);//释放设备号
}
MODULE_AUTHOR("GaoFeng's email is
gfpeak@gmail.com");
MODULE_LICENSE("GPL");
module_init(pwmtimer_init);
module_exit(pwmtimer_exit);