设备驱动(十五)
2014-03-06 17:55
337 查看
开启设备的时钟
struct clk *my_clk; //定义时钟结构体
my_clk = clk_get(NULL, "watchdog"); //获取设备的时钟信息
clk_enable(my_clk); //打开时钟
clk_disable(my_clk); //关闭时钟
所有有关时钟的设备,只有打开时钟后设置设备的寄存器才有效。
看门狗驱动
原理图
PCLK = 66MHZ
WTCON
[15:8] 0x80
[5] 0x1
[4:3] 0x2
WTCNT
0x8000
模块许可
加载函数
注册字符设备
映射
获取时钟
卸载函数
操作集合
FEED_DOG
打开时钟
设置计数器WTCNT
使能看门狗WTCON
release关闭时钟
PWM脉冲调制
GPD0_1
TCNTB1 0x1e
TCMPB1 0xf
TCFG0[7:0] 0xff
TCFG1[7:4] 0x4
最后设置
TCON[11:8] 0x2
模块许可
加载函数
申请设备号
注册字符设备
映射寄存器
open函数
设置预分频、设置再分频
设置tcnt、tcmp
设置gpd0_1为TOUT_1输出
使能tcon,手动更新tcnt,tcmp
卸载函数
关闭tcon
操作集合
BEEP_ON
设置自动重装tcon、tcmp
BEEP_OFF
关闭tcon
SET_CNTB1
安装参数更新tcon、tcmp
PWM产考代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
//#include <plat/regs-timer.h>
//#include <mach/regs-gpio.h>
#include "fs210_pwm.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("farsight");
#define GPD0CON 0xE02000A0
struct pwm_timer
{
unsigned int tcfg0;
unsigned int tcfg1;
unsigned int tcon;
unsigned int tcntb0;
unsigned int tcmpb0;
unsigned int tcnto0;
unsigned int tcntb1;
unsigned int tcmpb1;
} *pwm_timer;
static int pwm_major = 250;
static int pwm_minor = 0;
static struct cdev pwm_cdev;
void *gpd0con;
static void beep_init(void)
{
writel((readl(gpd0con) & (~0xf<<4)) | (0x2<<4), gpd0con);
writel(readl(&pwm_timer->tcfg0) | 0xff, &pwm_timer->tcfg0);
writel((readl(&pwm_timer->tcfg1) & ~(0xf<<4)) | (0x4<<4), &pwm_timer->tcfg1);
writel(30, &pwm_timer->tcntb1);
writel(15, &pwm_timer->tcmpb1);
writel((readl(&pwm_timer->tcon) & ~(0xf<<8)) | (0x2<<8), &pwm_timer->tcon);
}
static void beep_on(void)
{
writel((readl(&pwm_timer->tcon) & ~(0xf<<8)) | (0x9<<8), &pwm_timer->tcon);
}
static void beep_off(void)
{
writel((readl(&pwm_timer->tcon) & ~(0xf<<8)), &pwm_timer->tcon);
}
static void set_cnt(unsigned long count)
{
writel(count, &pwm_timer->tcntb1);
writel(count/2, &pwm_timer->tcmpb1);
}
static int fs210_pwm_open(struct inode *inode, struct file *file)
{
printk("pwm: device open\n");
beep_init();
return 0;
}
static int fs210_pwm_close(struct inode *inode, struct file *file)
{
printk("pwm: device close\n");
beep_off();
return 0;
}
static long fs210_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
//printk("pwm: device ioctl\n");
switch(cmd)
{
case BEEP_ON:
printk("pwm: BEEP ON\n");
beep_on();
break;
case BEEP_OFF:
printk("pwm: BEEP OFF\n");
beep_off();
break;
case SET_CNT:
printk("pwm: SET CNT\n");
set_cnt(arg);
break;
default:
printk("pwm: available command\n");
return -EINVAL;
}
return 0;
}
static struct file_operations fs210_pwm_ops = {
.owner = THIS_MODULE,
.open = fs210_pwm_open,
.release = fs210_pwm_close,
.unlocked_ioctl = fs210_pwm_ioctl
};
static int pwm_setup_cdev(struct cdev *cdev,
struct file_operations *fops)
{
int result;
dev_t devno = MKDEV(pwm_major, pwm_minor);
cdev_init(cdev, fops);
cdev->owner = THIS_MODULE;
result = cdev_add(cdev, devno, 1);
if (result)
{
printk("pwm: fail to add cdev\n");
return result;
}
return 0;
}
static int __init fs210_pwm_init(void)
{
int result;
dev_t devno = MKDEV(pwm_major, pwm_minor);
result = register_chrdev_region(devno, 1, "fs210_pwm");
if (result)
{
printk("pwm: unable to get major %d\n", pwm_major);
return result;
}
result = pwm_setup_cdev(&pwm_cdev, &fs210_pwm_ops);
if (result)
return result;
gpd0con = ioremap(GPD0CON, 4);
pwm_timer = ioremap(0xE2500000, sizeof(struct pwm_timer));
printk("pwm: driver installed with major %d!\n", pwm_major);
return 0;
}
static void __exit fs210_pwm_exit(void)
{
dev_t devno = MKDEV(pwm_major, pwm_minor);
cdev_del(&pwm_cdev);
unregister_chrdev_region(devno, 1);
iounmap(gpd0con);
iounmap(pwm_timer);
printk("pwm: driver uninstalled!\n");
}
module_init(fs210_pwm_init);
module_exit(fs210_pwm_exit);
看门狗参考代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
//#include <linux/delay.h>
#include <plat/regs-watchdog.h>
//#include <plat/map-base.h>
#include <linux/clk.h>
#define WATCHDOG_MAGIC 'k'
#define FEED_DOG _IO(WATCHDOG_MAGIC,1)
#define WATCHDOG_MAJOR 250
#define DEVICE_NAME "s5pv210_watchdog"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("farsight");
MODULE_DESCRIPTION("s5pv210 Watchdog");
#define S5PV210_PA_WTCON 0xE2700000
#define S5PV210_PA_WTCNT 0xE2700008
void *s5pv210_wtcon;
void *s5pv210_wtcnt;
struct clk *clk;
static int watchdog_major = WATCHDOG_MAJOR;
static struct cdev watchdog_cdev;
static int watchdog_open(struct inode *inode ,struct file *file)
{
clk_enable(clk);
writel(0x8000, s5pv210_wtcnt);//设置计数寄存器,如果里面内容递减为0时,reset。
writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV64|S3C2410_WTCON_RSTEN |
S3C2410_WTCON_PRESCALE(0x80), s5pv210_wtcon);//设置控制寄存器的属性,具体参看datasheet,主要是得到t_watchdog时钟周期。
printk(KERN_NOTICE"open the watchdog now!\n");
return 0;
}
static int watchdog_release(struct inode *inode,struct file *file)
{
clk_disable(clk);
return 0;
}
//喂狗
static long watchdog_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
switch( cmd )
{
case FEED_DOG:
writel(0x8000, s5pv210_wtcnt);
break;
}
return 0;
}
//将设备注册到系统之中
static void watchdog_setup_dev(struct cdev *dev,int minor,struct file_operations *fops)
{
int err;
dev_t devno = MKDEV(watchdog_major,minor);
cdev_init(dev, fops);
dev->owner = THIS_MODULE;
err = cdev_add(dev, devno, 1);
if (err)
printk(KERN_INFO"Error %d adding watchdog %d\n",err,minor);
}
static struct file_operations watchdog_ops = {
.owner = THIS_MODULE,
.open = watchdog_open,
.release = watchdog_release,
.unlocked_ioctl = watchdog_ioctl,
};
//注册设备驱动程序,主要完成主设备号的注册
static int __init s5pv210_watchdog_init(void)
{
int result;
dev_t dev = MKDEV(watchdog_major,0);
result = register_chrdev_region(dev,1,DEVICE_NAME);
if (result < 0)
{
printk(KERN_WARNING"watchdog:unable to get major %d\n",watchdog_major);
return result;
}
printk(KERN_NOTICE"[DEBUG] watchdog device major is %d\n",watchdog_major);
watchdog_setup_dev(&watchdog_cdev, 0, &watchdog_ops);
s5pv210_wtcon = ioremap(S5PV210_PA_WTCON, 4);
s5pv210_wtcnt = ioremap(S5PV210_PA_WTCNT, 4);
clk = clk_get(NULL, "watchdog");
if (IS_ERR(clk)) {
printk("failed to get watchdog clock\n");
result = PTR_ERR(clk);
return result;
}
return 0;
}
//驱动模块卸载
static void s5pv210_watchdog_exit(void)
{
iounmap(s5pv210_wtcon);
iounmap(s5pv210_wtcnt);
cdev_del(&watchdog_cdev);
unregister_chrdev_region(MKDEV(watchdog_major,0),1);
}
module_init(s5pv210_watchdog_init);
module_exit(s5pv210_watchdog_exit);
struct clk *my_clk; //定义时钟结构体
my_clk = clk_get(NULL, "watchdog"); //获取设备的时钟信息
clk_enable(my_clk); //打开时钟
clk_disable(my_clk); //关闭时钟
所有有关时钟的设备,只有打开时钟后设置设备的寄存器才有效。
看门狗驱动
原理图
PCLK = 66MHZ
WTCON
[15:8] 0x80
[5] 0x1
[4:3] 0x2
WTCNT
0x8000
模块许可
加载函数
注册字符设备
映射
获取时钟
卸载函数
操作集合
FEED_DOG
打开时钟
设置计数器WTCNT
使能看门狗WTCON
release关闭时钟
PWM脉冲调制
GPD0_1
TCNTB1 0x1e
TCMPB1 0xf
TCFG0[7:0] 0xff
TCFG1[7:4] 0x4
最后设置
TCON[11:8] 0x2
模块许可
加载函数
申请设备号
注册字符设备
映射寄存器
open函数
设置预分频、设置再分频
设置tcnt、tcmp
设置gpd0_1为TOUT_1输出
使能tcon,手动更新tcnt,tcmp
卸载函数
关闭tcon
操作集合
BEEP_ON
设置自动重装tcon、tcmp
BEEP_OFF
关闭tcon
SET_CNTB1
安装参数更新tcon、tcmp
PWM产考代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
//#include <plat/regs-timer.h>
//#include <mach/regs-gpio.h>
#include "fs210_pwm.h"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("farsight");
#define GPD0CON 0xE02000A0
struct pwm_timer
{
unsigned int tcfg0;
unsigned int tcfg1;
unsigned int tcon;
unsigned int tcntb0;
unsigned int tcmpb0;
unsigned int tcnto0;
unsigned int tcntb1;
unsigned int tcmpb1;
} *pwm_timer;
static int pwm_major = 250;
static int pwm_minor = 0;
static struct cdev pwm_cdev;
void *gpd0con;
static void beep_init(void)
{
writel((readl(gpd0con) & (~0xf<<4)) | (0x2<<4), gpd0con);
writel(readl(&pwm_timer->tcfg0) | 0xff, &pwm_timer->tcfg0);
writel((readl(&pwm_timer->tcfg1) & ~(0xf<<4)) | (0x4<<4), &pwm_timer->tcfg1);
writel(30, &pwm_timer->tcntb1);
writel(15, &pwm_timer->tcmpb1);
writel((readl(&pwm_timer->tcon) & ~(0xf<<8)) | (0x2<<8), &pwm_timer->tcon);
}
static void beep_on(void)
{
writel((readl(&pwm_timer->tcon) & ~(0xf<<8)) | (0x9<<8), &pwm_timer->tcon);
}
static void beep_off(void)
{
writel((readl(&pwm_timer->tcon) & ~(0xf<<8)), &pwm_timer->tcon);
}
static void set_cnt(unsigned long count)
{
writel(count, &pwm_timer->tcntb1);
writel(count/2, &pwm_timer->tcmpb1);
}
static int fs210_pwm_open(struct inode *inode, struct file *file)
{
printk("pwm: device open\n");
beep_init();
return 0;
}
static int fs210_pwm_close(struct inode *inode, struct file *file)
{
printk("pwm: device close\n");
beep_off();
return 0;
}
static long fs210_pwm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
//printk("pwm: device ioctl\n");
switch(cmd)
{
case BEEP_ON:
printk("pwm: BEEP ON\n");
beep_on();
break;
case BEEP_OFF:
printk("pwm: BEEP OFF\n");
beep_off();
break;
case SET_CNT:
printk("pwm: SET CNT\n");
set_cnt(arg);
break;
default:
printk("pwm: available command\n");
return -EINVAL;
}
return 0;
}
static struct file_operations fs210_pwm_ops = {
.owner = THIS_MODULE,
.open = fs210_pwm_open,
.release = fs210_pwm_close,
.unlocked_ioctl = fs210_pwm_ioctl
};
static int pwm_setup_cdev(struct cdev *cdev,
struct file_operations *fops)
{
int result;
dev_t devno = MKDEV(pwm_major, pwm_minor);
cdev_init(cdev, fops);
cdev->owner = THIS_MODULE;
result = cdev_add(cdev, devno, 1);
if (result)
{
printk("pwm: fail to add cdev\n");
return result;
}
return 0;
}
static int __init fs210_pwm_init(void)
{
int result;
dev_t devno = MKDEV(pwm_major, pwm_minor);
result = register_chrdev_region(devno, 1, "fs210_pwm");
if (result)
{
printk("pwm: unable to get major %d\n", pwm_major);
return result;
}
result = pwm_setup_cdev(&pwm_cdev, &fs210_pwm_ops);
if (result)
return result;
gpd0con = ioremap(GPD0CON, 4);
pwm_timer = ioremap(0xE2500000, sizeof(struct pwm_timer));
printk("pwm: driver installed with major %d!\n", pwm_major);
return 0;
}
static void __exit fs210_pwm_exit(void)
{
dev_t devno = MKDEV(pwm_major, pwm_minor);
cdev_del(&pwm_cdev);
unregister_chrdev_region(devno, 1);
iounmap(gpd0con);
iounmap(pwm_timer);
printk("pwm: driver uninstalled!\n");
}
module_init(fs210_pwm_init);
module_exit(fs210_pwm_exit);
看门狗参考代码
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <asm/io.h>
//#include <linux/delay.h>
#include <plat/regs-watchdog.h>
//#include <plat/map-base.h>
#include <linux/clk.h>
#define WATCHDOG_MAGIC 'k'
#define FEED_DOG _IO(WATCHDOG_MAGIC,1)
#define WATCHDOG_MAJOR 250
#define DEVICE_NAME "s5pv210_watchdog"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("farsight");
MODULE_DESCRIPTION("s5pv210 Watchdog");
#define S5PV210_PA_WTCON 0xE2700000
#define S5PV210_PA_WTCNT 0xE2700008
void *s5pv210_wtcon;
void *s5pv210_wtcnt;
struct clk *clk;
static int watchdog_major = WATCHDOG_MAJOR;
static struct cdev watchdog_cdev;
static int watchdog_open(struct inode *inode ,struct file *file)
{
clk_enable(clk);
writel(0x8000, s5pv210_wtcnt);//设置计数寄存器,如果里面内容递减为0时,reset。
writel(S3C2410_WTCON_ENABLE|S3C2410_WTCON_DIV64|S3C2410_WTCON_RSTEN |
S3C2410_WTCON_PRESCALE(0x80), s5pv210_wtcon);//设置控制寄存器的属性,具体参看datasheet,主要是得到t_watchdog时钟周期。
printk(KERN_NOTICE"open the watchdog now!\n");
return 0;
}
static int watchdog_release(struct inode *inode,struct file *file)
{
clk_disable(clk);
return 0;
}
//喂狗
static long watchdog_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
switch( cmd )
{
case FEED_DOG:
writel(0x8000, s5pv210_wtcnt);
break;
}
return 0;
}
//将设备注册到系统之中
static void watchdog_setup_dev(struct cdev *dev,int minor,struct file_operations *fops)
{
int err;
dev_t devno = MKDEV(watchdog_major,minor);
cdev_init(dev, fops);
dev->owner = THIS_MODULE;
err = cdev_add(dev, devno, 1);
if (err)
printk(KERN_INFO"Error %d adding watchdog %d\n",err,minor);
}
static struct file_operations watchdog_ops = {
.owner = THIS_MODULE,
.open = watchdog_open,
.release = watchdog_release,
.unlocked_ioctl = watchdog_ioctl,
};
//注册设备驱动程序,主要完成主设备号的注册
static int __init s5pv210_watchdog_init(void)
{
int result;
dev_t dev = MKDEV(watchdog_major,0);
result = register_chrdev_region(dev,1,DEVICE_NAME);
if (result < 0)
{
printk(KERN_WARNING"watchdog:unable to get major %d\n",watchdog_major);
return result;
}
printk(KERN_NOTICE"[DEBUG] watchdog device major is %d\n",watchdog_major);
watchdog_setup_dev(&watchdog_cdev, 0, &watchdog_ops);
s5pv210_wtcon = ioremap(S5PV210_PA_WTCON, 4);
s5pv210_wtcnt = ioremap(S5PV210_PA_WTCNT, 4);
clk = clk_get(NULL, "watchdog");
if (IS_ERR(clk)) {
printk("failed to get watchdog clock\n");
result = PTR_ERR(clk);
return result;
}
return 0;
}
//驱动模块卸载
static void s5pv210_watchdog_exit(void)
{
iounmap(s5pv210_wtcon);
iounmap(s5pv210_wtcnt);
cdev_del(&watchdog_cdev);
unregister_chrdev_region(MKDEV(watchdog_major,0),1);
}
module_init(s5pv210_watchdog_init);
module_exit(s5pv210_watchdog_exit);
相关文章推荐
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- c语言实现hashmap(转载)
- Linux 信号signal处理机制
- linux下mysql添加用户
- Scientific Linux 5.5 图形安装教程
- 基于 Linux 集群环境上 GPFS 的问题诊断
- 谁是桌面王者?Win PK Linux三大镇山之宝
- vivi下重新调整分区
- Linux VS Unix:Linux欲一统天下 Unix不死
- linux下设定环境变量
- Linux下修改MySQL编码的方法
- Linux串口通信
- 从Windows系统下访问Linux分区相关软件