#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <plat/regs-timer.h>
#include <mach/regs-irq.h>
#include <asm/mach/time.h>
#include <linux/clk.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/gpio.h>
#include <mach/gpio-bank-f.h>
#define device_name "misc_pwm"
#define command_set_freq 0
#define command_stop 1
static struct semaphore flag;
static void PWM_set_freq(unsigned long freq)
{
unsigned long tcon;
unsigned long tcnt;
unsigned long tcfg0;
unsigned long tcfg1;
struct clk *clk_pointer;
unsigned long pclk;
s3c_gpio_cfgpin(S3C64XX_GPF(14),S3C64XX_GPF14_PWM_TOUT0);
tcon = __raw_readl(S3C_TCON);
tcfg0 = __raw_readl(S3C_TCFG0);
tcfg1 = __raw_readl(S3C_TCFG1);
tcfg0 &= ~(S3C_TCFG_PRESCALER0_MASK);
tcfg0 |= 1;
__raw_writel(tcfg0,S3C_TCFG0);
tcfg1 &= ~(S3C_TCFG1_MUX0_MASK);
tcfg1 |= S3C_TCFG1_MUX0_DIV1;
__raw_writel(tcfg1,S3C_TCFG1);
clk_pointer = clk_get(NULL,"pclk");
pclk = clk_get_rate(clk_pointer);
tcnt = (pclk/1/1)/freq;
__raw_writel(tcnt, S3C_TCNTB(0));
__raw_writel(tcnt/2, S3C_TCMPB(0));
tcon &= ~0x1f;
tcon |= 0xb; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 0
__raw_writel(tcon, S3C_TCON);
tcon &= ~2; //clear manual update bit
__raw_writel(tcon, S3C_TCON);
}
void PWM_Stop(void)
{
s3c_gpio_cfgpin(S3C64XX_GPF(14),S3C_GPIO_INPUT);
__raw_writel(0x00,S3C_TCON);
}
static int PWM_open(struct inode *inode, struct file *filp)
{
if(!down_trylock(&flag))
{
return 0;
}
else
{
return -EBUSY;
}
}
static int PWM_release(struct inode *inode,struct file *filp)
{
up(&flag);
return 0;
}
static long PWM_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch(cmd)
{
case command_set_freq:
PWM_set_freq(arg);
break;
case command_stop:
PWM_Stop();
break;
default:
PWM_Stop();
break;
}
return 0;
}
static struct file_operations PWM_fops = {
.owner = THIS_MODULE,
.open = PWM_open,
.release = PWM_release,
.unlocked_ioctl = PWM_unlocked_ioctl,
};
static struct miscdevice miscpwm = {
.minor = MISC_DYNAMIC_MINOR,
.name = device_name,
.fops = &PWM_fops,
};
int pwm_up_init(void)
{
int ret;
sema_init(&flag,1);
ret = misc_register(&miscpwm);
if(ret < 0)
{
printk("the pwm has unmodule \n");
}
printk("the pwm has registered \n");
return 0;
}
void pwm_exit(void)
{
misc_deregister(&miscpwm);
printk("the pwm has exit\n");
}
module_init(pwm_up_init);
module_exit(pwm_exit);
MODULE_LICENSE("GPL");