您的位置:首页 > 运维架构 > Linux

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驱动 linux驱动