/******************************file : driver_pwm.c******************************
Version : 1.0
Function: The driver of the PWM
Auther: BIT
11/2006
*******************************************************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <asm/io.h> //ioremap,iounmap
#include <linux/ioport.h> //check_mem_region,request_mem_region,release_mem_region
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/mpc83xx.h> //IMMRBAR,MPC83xx_IRQ_PIT
#define DRVPWM_VER "1.0"
#define DRVPWM_DATE "2006-11"
#define CHJ_PWM_MAJOR 35
#define PWM_DEVICE_NAME "pwm"
#define PWM_VALUE(n) ((((n)&0xff)<<5)+(((n)&0xf00)<<16)) //convert the data
//user input to the value pwm bus required
#define BR3_OFFSET 0x5018
#define OR3_OFFSET 0x501c
#define PWM_REG 0xf9005000
#define CONFIG_BR3 0xf9001801
MODULE_LICENSE("GPL");
MODULE_AUTHOR("BIT");
static int pwm_has_opened=0;
static volatile unsigned int* pwm_addr;
static int drvpwm_open(struct inode *,struct file *);
static int drvpwm_read(struct file *,char *,size_t,loff_t *);
static int drvpwm_write(struct file *,const char *,size_t,loff_t *);
static int drvpwm_ioctl(struct inode *,struct file *,unsigned int,unsigned long);
static int drvpwm_close(struct inode *,struct file *);
struct file_operations drvpwm_fops ={
open : drvpwm_open,
read : drvpwm_read,
write: drvpwm_write,
ioctl: drvpwm_ioctl,
release: drvpwm_close,
};
//#define DEBUG
/*******************************************************************************************
Open function
********************************************************************************************/
static int drvpwm_open(struct inode *inode,struct file *file)
{
if(pwm_has_opened) return -EBUSY;
pwm_has_opened++; //Ensure that only one process use the device only once
MOD_INC_USE_COUNT; //Ensure that the module isn't removed while the device file is open
return 0;
}
/*******************************************************************************************
Read the digital data from the dac7624 registers!
The parameter "count" must not be even and >0 and <8
********************************************************************************************/
static int drvpwm_read(struct file *file,char *buffer,size_t count,loff_t *offset)
{
return 0;
}
/****************************************************************************************
Write the pwm value to the pwm registers!
The parameter "count" must be 4
*****************************************************************************************/
static int drvpwm_write(struct file *file,const char *buffer,size_t count,loff_t *offset)
{
unsigned int temp;
if(count!=4) return -EINVAL;
copy_from_user((unsigned char *)&temp,buffer,4);
*pwm_addr=PWM_VALUE(temp);
return 0;
}
/*******************************************************************************************
IOCTL function of the DRVPWM.
This function can the pwm output according to the value that user input.
The meaning of the "arg" is the value of the pwm.
The arg is always below the width of 16bit:(arg=arg &0xfff).
The "cmd" carries is no use untile now, can be anything.
********************************************************************************************/
static int drvpwm_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
arg&=0xfff;
*pwm_addr=(unsigned int)PWM_VALUE(arg);
return 0;
}
static int drvpwm_close(struct inode *inode,struct file *file)
{
pwm_has_opened--; //other process can open the device now
MOD_DEC_USE_COUNT;//The module can be removed
return 0;
}
/*********************************************************************************
The module_init and module_cleanup function
*********************************************************************************/
int drvpwm_init(void)
{
int ret_value;
// volatile unsigned int * addr=NULL;
printk(KERN_INFO "PWM Driver!\nVersion:%s (%s)\n",DRVPWM_VER,DRVPWM_DATE);
printk(KERN_INFO "Author: BIT\n");
ret_value=register_chrdev(CHJ_PWM_MAJOR,PWM_DEVICE_NAME,&drvpwm_fops);
if(ret_value<0)
{
printk(KERN_WARNING "DRVPWM: can't get major %d\n",CHJ_PWM_MAJOR);
return ret_value;
}
printk(KERN_INFO "DRVPWM: get major %d\n",CHJ_PWM_MAJOR);
// addr=(unsigned int *)ioremap(IMMRBAR+BR3_OFFSET,4);
#ifdef DEBUG
printk("The BR3 is: %x\n",*addr);
#endif
// *addr=CONFIG_BR3;
// iounmap((void *)addr);
pwm_addr=(unsigned int *)ioremap(PWM_REG,4); //get the pwm's virtual addr
*pwm_addr=PWM_VALUE(0x400);
return 0;
}
void drvpwm_exit(void)
{
unregister_chrdev(CHJ_PWM_MAJOR,PWM_DEVICE_NAME);
iounmap((void *)pwm_addr);
printk(KERN_INFO "The driver of the PWM EXIT!\n");
}
module_init(drvpwm_init);
module_exit(drvpwm_exit);