pwm驱动程序及其注释
2013-10-22 21:13
597 查看
//开发环境 s3c2440
//pwm.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#define PWM_MAJOR 0 //主设备号
#define PWM_NAME "my2440_pwm" //设备名称
static int device_major = PWM_MAJOR; //系统动态生成的主设备号
//打开设备
static int pwm_open(struct inode *inode, struct file *file)
{
//对GPB0复用口进行复用功能设置,设置为TOUT0 PWM输出
s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_TOUT0);
return 0;
}
//关闭设备
static int pwm_close(struct inode *inode,struct file *file)
{
return 0;
}
//对设备进行控制
static int pwm_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
if(cmd <= 0)//如果输入的参数小于或等于0的话,就让蜂鸣器停止工作
{
//这里又恢复GPB0口为IO口输出功能,由原理图可知直接给低电平可让蜂鸣器停止工作
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
}
//如果输入的参数大于0,就让蜂鸣器开始工作,不同的参数,蜂鸣器的频率也不一样
else
{
unsigned long tcon;
unsigned long tcnt;
unsigned long tcfg1;
unsigned long tcfg0;
struct clk *clk_p;
unsigned long pclk;
//以下对各寄存器的操作结合上面讲的开始一个PWM定时器的步骤和2440手册PWM寄存器操作部分来看就比较容易理解
tcfg1 = __raw_readl(S3C2410_TCFG1); //读取定时器配置寄存器1的值
tcfg0 = __raw_readl(S3C2410_TCFG0);//读取定时器配置寄存器0的值
tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
tcfg0 |= (50 - 1);//设置tcfg0的值为49
tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; //设置tcfg1的值为0x0011即:1/16
__raw_writel(tcfg1, S3C2410_TCFG1);//将值tcfg1写入定时器配置寄存器1中
__raw_writel(tcfg0, S3C2410_TCFG0);//将值tcfg0写入定时器配置寄存器0中
clk_p = clk_get(NULL, "pclk");
pclk = clk_get_rate(clk_p);//从系统平台时钟队列中获取pclk的时钟频率,在include/linux/clk.h中定义
tcnt = (pclk/50/16)/cmd;//计算定时器0的输出时钟频率(pclk/{prescaler0 + 1}/divider value)
__raw_writel(tcnt, S3C2410_TCNTB(0));//设置定时器0计数缓存寄存器的值
__raw_writel(tcnt/2, S3C2410_TCMPB(0));//设置定时器0比较缓存寄存器的值
tcon = __raw_readl(S3C2410_TCON);//读取定时器控制寄存器的值
tcon &= ~0x1f;
tcon |= 0xb;//关闭死区、自动重载、关反相器、更新TCNTB0&TCMPB0、启动定时器0
__raw_writel(tcon, S3C2410_TCON);//设置定时器控制寄存器的0-4位,即对定时器0进行控
tcon &= ~2;
__raw_writel(tcon, S3C2410_TCON);//清除定时器0的手动更新位
}
return 0;
}
//设备操作结构体
static struct file_operations pwm_fops =
{
.owner = THIS_MODULE,
.open = pwm_open,
.release = pwm_close,
.ioctl = pwm_ioctl,
};
//定义一个设备类
//
static struct class *pwm_class;
static int __init pwm_init(void)
{
//注册为字符设备,主设备号为0让系统自动分配,设备名为my2440_pwm,注册成功返回动态生成的主设备号
device_major = register_chrdev(PWM_MAJOR, PWM_NAME, &pwm_fops);
if(device_major < 0)
{
printk(PWM_NAME " register falid!\n");
return device_major;
}
//注册一个设备类,使mdev可以在/dev/目录下自动建立设备节点
pwm_class = class_create(THIS_MODULE, PWM_NAME);
if(IS_ERR(pwm_class))
{
printk(PWM_NAME " register class falid!\n");
return -1;
}
//创建一个设备节点,设备名为PWM_NAME,即:my2440_pwm
device_create(pwm_class, NULL, MKDEV(device_major, 0), NULL, PWM_NAME);
return 0;
}
static void __exit pwm_exit(void)
{
//注销设备
unregister_chrdev(device_major, PWM_NAME);
//删除设备节点
device_destroy(pwm_class, MKDEV(device_major, 0));
//注销设备类
class_destroy(pwm_class);
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zpc");
MODULE_DESCRIPTION("my2440 pwm driver");
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int tmp;
int fd;
int i;
//打开蜂鸣器设备
fd = open("/dev/my2440_pwm", O_RDWR);
if(fd < 0)
{
printf("Open PWM Device Faild!\n");
exit(1);
}
//提示用户输入一个参数来对蜂鸣器进行调频,0表示停止工作
printf("please enter the times number(0 is stop):\n");
while(1)
{
//输入参数
scanf("%d", &tmp);
printf("times = %d\n", tmp);
//IO控制
ioctl(fd, tmp);
if(tmp <= 0)break;
}
//关闭设备
close(fd);
return 0;
}
//Makefile
ifneq ($(KERNELRELEASE),)
obj-m := 1_pwm.o
else
KERNELDIR := /home/wokerspace/kernel/linux-2.6.30.4
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.order *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module.symvers
endif
//pwm.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <asm/io.h>
#include <mach/hardware.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#define PWM_MAJOR 0 //主设备号
#define PWM_NAME "my2440_pwm" //设备名称
static int device_major = PWM_MAJOR; //系统动态生成的主设备号
//打开设备
static int pwm_open(struct inode *inode, struct file *file)
{
//对GPB0复用口进行复用功能设置,设置为TOUT0 PWM输出
s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_TOUT0);
return 0;
}
//关闭设备
static int pwm_close(struct inode *inode,struct file *file)
{
return 0;
}
//对设备进行控制
static int pwm_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
if(cmd <= 0)//如果输入的参数小于或等于0的话,就让蜂鸣器停止工作
{
//这里又恢复GPB0口为IO口输出功能,由原理图可知直接给低电平可让蜂鸣器停止工作
s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_OUTP);
s3c2410_gpio_setpin(S3C2410_GPB0, 0);
}
//如果输入的参数大于0,就让蜂鸣器开始工作,不同的参数,蜂鸣器的频率也不一样
else
{
unsigned long tcon;
unsigned long tcnt;
unsigned long tcfg1;
unsigned long tcfg0;
struct clk *clk_p;
unsigned long pclk;
//以下对各寄存器的操作结合上面讲的开始一个PWM定时器的步骤和2440手册PWM寄存器操作部分来看就比较容易理解
tcfg1 = __raw_readl(S3C2410_TCFG1); //读取定时器配置寄存器1的值
tcfg0 = __raw_readl(S3C2410_TCFG0);//读取定时器配置寄存器0的值
tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK;
tcfg0 |= (50 - 1);//设置tcfg0的值为49
tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK;
tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; //设置tcfg1的值为0x0011即:1/16
__raw_writel(tcfg1, S3C2410_TCFG1);//将值tcfg1写入定时器配置寄存器1中
__raw_writel(tcfg0, S3C2410_TCFG0);//将值tcfg0写入定时器配置寄存器0中
clk_p = clk_get(NULL, "pclk");
pclk = clk_get_rate(clk_p);//从系统平台时钟队列中获取pclk的时钟频率,在include/linux/clk.h中定义
tcnt = (pclk/50/16)/cmd;//计算定时器0的输出时钟频率(pclk/{prescaler0 + 1}/divider value)
__raw_writel(tcnt, S3C2410_TCNTB(0));//设置定时器0计数缓存寄存器的值
__raw_writel(tcnt/2, S3C2410_TCMPB(0));//设置定时器0比较缓存寄存器的值
tcon = __raw_readl(S3C2410_TCON);//读取定时器控制寄存器的值
tcon &= ~0x1f;
tcon |= 0xb;//关闭死区、自动重载、关反相器、更新TCNTB0&TCMPB0、启动定时器0
__raw_writel(tcon, S3C2410_TCON);//设置定时器控制寄存器的0-4位,即对定时器0进行控
tcon &= ~2;
__raw_writel(tcon, S3C2410_TCON);//清除定时器0的手动更新位
}
return 0;
}
//设备操作结构体
static struct file_operations pwm_fops =
{
.owner = THIS_MODULE,
.open = pwm_open,
.release = pwm_close,
.ioctl = pwm_ioctl,
};
//定义一个设备类
//
static struct class *pwm_class;
static int __init pwm_init(void)
{
//注册为字符设备,主设备号为0让系统自动分配,设备名为my2440_pwm,注册成功返回动态生成的主设备号
device_major = register_chrdev(PWM_MAJOR, PWM_NAME, &pwm_fops);
if(device_major < 0)
{
printk(PWM_NAME " register falid!\n");
return device_major;
}
//注册一个设备类,使mdev可以在/dev/目录下自动建立设备节点
pwm_class = class_create(THIS_MODULE, PWM_NAME);
if(IS_ERR(pwm_class))
{
printk(PWM_NAME " register class falid!\n");
return -1;
}
//创建一个设备节点,设备名为PWM_NAME,即:my2440_pwm
device_create(pwm_class, NULL, MKDEV(device_major, 0), NULL, PWM_NAME);
return 0;
}
static void __exit pwm_exit(void)
{
//注销设备
unregister_chrdev(device_major, PWM_NAME);
//删除设备节点
device_destroy(pwm_class, MKDEV(device_major, 0));
//注销设备类
class_destroy(pwm_class);
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zpc");
MODULE_DESCRIPTION("my2440 pwm driver");
//test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
int main(int argc, char **argv)
{
int tmp;
int fd;
int i;
//打开蜂鸣器设备
fd = open("/dev/my2440_pwm", O_RDWR);
if(fd < 0)
{
printf("Open PWM Device Faild!\n");
exit(1);
}
//提示用户输入一个参数来对蜂鸣器进行调频,0表示停止工作
printf("please enter the times number(0 is stop):\n");
while(1)
{
//输入参数
scanf("%d", &tmp);
printf("times = %d\n", tmp);
//IO控制
ioctl(fd, tmp);
if(tmp <= 0)break;
}
//关闭设备
close(fd);
return 0;
}
//Makefile
ifneq ($(KERNELRELEASE),)
obj-m := 1_pwm.o
else
KERNELDIR := /home/wokerspace/kernel/linux-2.6.30.4
PWD := $(shell pwd)
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf *.order *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions Module.symvers
endif
相关文章推荐
- pwm驱动程序及其注释
- 下图为 TCP/IP 协议驱动程序 (Tcpip.sys) 及其用于在 Windows XP Service Pack 2 和 Windows Server 2003 Service Pack 1
- TQ2440裸板---pwm时钟(详细注释)
- Cocos2D编程Xcode读取文件代码及其注释
- 下图为 TCP/IP 协议驱动程序 (Tcpip.sys) 及其用于在 Windows XP Service Pack 2 和 Windows Server 2003 Service Pack 1
- 一个简单的makefile示例及其注释
- 一个简单的makefile示例及其注释
- MySQL查询数据表中表字段及其注释
- 如何根据驱动程序及其安装文件来访问该设备[转]
- [摘]Visual Studio 2005的SP1的整合制作及其问题注释
- 一个简单的makefile示例及其注释
- 如何根据驱动程序及其安装文件来访问该设备呢(Visual C++ or C++ Builder均可以)
- 初学JS作业三:试阐述js的两种注释方式,及其区别
- 嵌入式linux 内核驱动程序模块编译及其操作流程
- 电阻式触摸屏的驱动程序和详细注释
- PWM的基本原理及其应用实例
- mini2440的pwm驱动程序和测试程序详解
- C#注释含义(XML注释)标签及其含义(一)
- Java学习系列(二)Java注释、标识符、基本数据类型及其转换易错点详解
- mysql查询数据库所有表和字段及其注释