#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "s3c2410_pwm.h"
#define DEVICE_NAME "pwm"
staticintpwm_major = 0;
staticintpwm_set_prescaler(structPWM_CHANNEL *pwm)
{
writel( (readl(S3C2410_TCFG0)&0xffffff00) + (pwm->prescaler0&0xFF) ,S3C2410_TCFG0 );
return0;
}
staticintpwm_set_channel(unsignedcharchannel,structPWM_CHANNEL *pwm)
{
unsigned longtmp;
unsigned longtmp1;
switch(channel)
{
case0:
pwm_set_prescaler(pwm);
tmp = readl(S3C2410_TCFG1);
tmp = (tmp & (~(0x0F<<0))) | ((pwm->div_clock&0x000F)<<0);
writel(tmp, S3C2410_TCFG1);
writel((pwm->tcntb_reg&0xFFFF), S3C2410_TCNTB(channel));
writel((pwm->tcmpb_reg&0xFFFF), S3C2410_TCMPB(channel));
tmp = readl(S3C2410_TCON) | S3C2410_TCON_T0RELOAD | S3C2410_TCON_T0MANUALUPD;
tmp1 = (readl(S3C2410_TCON) | S3C2410_TCON_T0RELOAD) & (~S3C2410_TCON_T0MANUALUPD);
writel(tmp, S3C2410_TCON);
if(pwm->off)
writel(tmp1&(~S3C2410_TCON_T0START), S3C2410_TCON);
else
writel(tmp1 | S3C2410_TCON_T0START, S3C2410_TCON);
break;
case1:
pwm_set_prescaler(pwm);
tmp = readl(S3C2410_TCFG1);
tmp = (tmp & (~(0x0F<<4))) | ((pwm->div_clock&0x000F)<<4);
writel(tmp, S3C2410_TCFG1);
writel((pwm->tcntb_reg&0xFFFF), S3C2410_TCNTB(channel));
writel((pwm->tcmpb_reg&0xFFFF), S3C2410_TCMPB(channel));
tmp = readl(S3C2410_TCON) | S3C2410_TCON_T1RELOAD | S3C2410_TCON_T1MANUALUPD;
tmp1 = (readl(S3C2410_TCON) | S3C2410_TCON_T1RELOAD) & (~S3C2410_TCON_T1MANUALUPD);
writel(tmp, S3C2410_TCON);
if(pwm->off)
writel(tmp1 & (~S3C2410_TCON_T1START), S3C2410_TCON);
else
writel(tmp1 | S3C2410_TCON_T1START, S3C2410_TCON);
break;
case2:
tmp = readl(S3C2410_TCFG1);
tmp = (tmp & (~(0x0F<<8))) | ((pwm->div_clock&0x000F)<<8);
writel(tmp, S3C2410_TCFG1);
writel(pwm->tcntb_reg&0xFFFF, S3C2410_TCNTB(channel));
writel(pwm->tcmpb_reg&0xFFFF, S3C2410_TCMPB(channel));
tmp = readl(S3C2410_TCON) | S3C2410_TCON_T2RELOAD | S3C2410_TCON_T2MANUALUPD;
tmp1 = (readl(S3C2410_TCON) | S3C2410_TCON_T2RELOAD) & (~S3C2410_TCON_T2MANUALUPD);
writel(tmp, S3C2410_TCON);
if(pwm->off)
writel(tmp1 & (~S3C2410_TCON_T2START), S3C2410_TCON);
else
writel(tmp1 | S3C2410_TCON_T2START, S3C2410_TCON);
break;
case3:
tmp = readl(S3C2410_TCFG1);
tmp = (tmp & (~(0x0F<<12))) | ((pwm->div_clock&0x000F)<<12);
writel(tmp, S3C2410_TCFG1);
writel(pwm->tcntb_reg&0xFFFF, S3C2410_TCNTB(channel));
writel(pwm->tcmpb_reg&0xFFFF, S3C2410_TCMPB(channel));
tmp = readl(S3C2410_TCON) | S3C2410_TCON_T3RELOAD | S3C2410_TCON_T3MANUALUPD;
tmp1 = (readl(S3C2410_TCON) | S3C2410_TCON_T3RELOAD) & (~S3C2410_TCON_T3MANUALUPD);
writel(tmp, S3C2410_TCON);
if(pwm->off)
writel(tmp1 & (~S3C2410_TCON_T3START), S3C2410_TCON);
else
writel(tmp1 | S3C2410_TCON_T3START, S3C2410_TCON);
break;
default:
break;
}
return0;
}
staticintpwm_ioctl(structinode *inode,structfile *file, unsignedintcmd, unsignedlongarg)
{
structPWM_CHANNEL pwm;
switch(cmd)
{
casePWM_CHANNEL_0:
casePWM_CHANNEL_1:
casePWM_CHANNEL_2:
casePWM_CHANNEL_3:
if(copy_from_user(&pwm,(structPWM_CHANNEL *)arg,sizeof(structPWM_CHANNEL)))
return-EFAULT;
pwm_set_channel(cmd,&pwm);
break;
default:
return-EFAULT;
}
return0;
}
staticintpwm_open(structinode * inode,structfile * filp)
{
return0;
}
staticintpwm_release(structinode * inode,structfile * filp)
{
return0;
}
staticstructfile_operations pwm_fops = {
.owner = THIS_MODULE,
.ioctl = pwm_ioctl,
.open = pwm_open,
.release=pwm_release,
};
staticint__init pwm_init(void)
{
intret;
ret = register_chrdev(0,DEVICE_NAME,&pwm_fops);
if(ret
{
printk("pwm: can't get major number\n");
returnret;
}
pwm_major = ret;
#ifdef CONFIG_DEVFS_FS
ret = devfs_mk_cdev(MKDEV(pwm_major,0), S_IFCHR | S_IRUGO | S_IWUSR,DEVICE_NAME);
if(ret)
{
unregister_chrdev(pwm_major,DEVICE_NAME);
printk("pwm: can't make char device fo devfs\n");
returnret;
}
#endif
s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_TOUT0);
s3c2410_gpio_cfgpin(S3C2410_GPB1,S3C2410_GPB1_TOUT1);
s3c2410_gpio_cfgpin(S3C2410_GPB2,S3C2410_GPB2_TOUT2);
s3c2410_gpio_cfgpin(S3C2410_GPB3,S3C2410_GPB3_TOUT3);
printk("s3c2410_pwm driver initial\n");
return0;
}
staticvoid__exit pwm_exit(void)
{
#ifdef CONFIG_DEVFS_FS
devfs_remove(DEVICE_NAME);
#endif
unregister_chrdev(pwm_major,DEVICE_NAME);
printk("s3c2410_pwm driver removed\n");
}
module_init(pwm_init);
module_exit(pwm_exit);
MODULE_ALIAS("pwm");
MODULE_DESCRIPTION("PWM IO Driver For EM104-MINI2410");
MODULE_AUTHOR("LIANXJ");
MODULE_LICENSE("GPL");