Author: Xiaolin. Peng
Welcome to discussion 196568501
# 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 <Linux/interrupt. h>
# Include <Linux/gpio. h>
# Include <ASM/IRQ. h>
# Include <ASM/IO. h>
# Include <ASM/uaccess. h>
# Include <Mach/regs-gpio.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>
# Define DEVICE_NAME "pwm"
# Define PWM_IOCTL_SET_FREQ 1
# Define PWM_IOCTL_STOP 0
Static struct semaphore lock;
/* Freq: pclk/50/16/65536 ~ Pclk/50/16
* If pclk = 50 MHz, freq is 1Hz to 62500Hz
* Human ear: 20Hz ~ 20000Hz
*/
Static void PWM_Set_Freq_Duty (unsigned long freq, unsigned long duty)
{
Unsigned long tcon;
Unsigned long tcnt;
Unsigned long tcfg1;
Unsigned long t00000;
// For test added byXiaolin. Peng
Unsigned long TCNTB_saver = 0;
Unsigned long TCMPB_saver = 0;
Struct clk * clk_p;
Unsigned long pclk;
// For test added by Xiaolin. Peng
Printk ("freq: % ld \ n", freq );
// Set GPB0 as tout0, pwm output
S3c2410_gpio_cfgpin (S3C2410_GPB (0), S3C2410_GPB0_TOUT0 );
Tcon = _ raw_readl (S3C2410_TCON );
Tcfg1 = _ raw_readl (S3C2410_TCFG1 );
T1_0 = _ raw_readl (s3c2410_t1_0 );
// Prescaler = 50
T00000 & = ~ S3c2410_t1__prescaler0_mask;
T00000 | = (50-1 );
// Mux = 1/16
Tcfg1 & = ~ S3c2410_t1_mux0_mask;
Tcfg1 | = s3c2410_t00000000mux0_div16;
_ Raw_writel (tcfg1, S3C2410_TCFG1 );
_ Raw_writel (t1_0, s3c2410_t1_0 );
Clk_p = clk_get (NULL, "pclk ");
Pclk = clk_get_rate (clk_p );
Tcnt = (pclk/(t1_0 + 1)/16)/freq;
_ Raw_writel (tcnt, S3C2410_TCNTB (0 ));
_ Raw_writel (tcnt * duty)/100, S3C2410_TCMPB (0 ));
// For test add by Xiaolin. Peng
TCNTB_saver = _ raw_readl (S3C2410_TCNTB (0 ));
TCMPB_saver = _ raw_readl (S3C2410_TCMPB (0 ));
Printk ("TCNTB: % ld \ n", TCNTB_saver );
Printk ("TCMPB: % ld \ n", TCMPB_saver );
Tcon & = ~ 0x1f;
Tcon | = 0xb; // disable deadzone, auto-reload, inv-off, update TCNTB0 & TCMPB0, start timer 0
_ Raw_writel (tcon, S3C2410_TCON );
Tcon & = ~ 2; // clear manual update bit
_ Raw_writel (tcon, S3C2410_TCON );
}
Static void PWM_Stop (void)
{
S3c2410_gpio_cfgpin (S3C2410_GPB (0), S3C2410_GPIO_OUTPUT );
S3c2410_gpio_setpin (S3C2410_GPB (0), 0 );
}
Static int s3c24xx_pwm_open (struct inode * inode, struct file * file)
{
If (! Down_trylock (& lock ))
{
Return 0;
}
Else
Return-ebusy;
}
Static int s3c24xx_pwm_close (struct inode * inode, struct file * file)
{
Pwm_stop ();
Up (& lock );
Return 0;
}
// Cmd = 1, open PWM function. = 0, close PWM function
// PWM frquency = (ARG & 0xff00)> 8,
// PWM duty = (arm & 0x00ff)
//
Static int s3c24xx_pwm_ioctl (struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
Printk ("ioctl pwm: % d % ld \ n", cmd, arg );
Switch (cmd ){
Case PWM_IOCTL_SET_FREQ:
If (arg = 0)
Return-EINVAL;
PWM_Set_Freq_Duty (arg> 8), (arg & 0xff ));
Break;
Case PWM_IOCTL_STOP:
PWM_Stop ();
Break;
}
Return 0;
}
Static struct file_operations dev_fops = {
. Owner = THIS_MODULE,
. Open = s3c24xx_pwm_open,
. Release = s3c24xx_pwm_close,
. Ioctl = s3c24xx_pwm_ioctl,
};
Static struct miscdevice misc = {
. Minor = MISC_DYNAMIC_MINOR,
. Name = DEVICE_NAME,
. Fops = & dev_fops,
};
Static int _ init dev_init (void)
{
Int ret;
Init_MUTEX (& lock); // init semaphore
Ret = misc_register (& misc );
Printk (device_name "\ tinitialized \ n ");
Return ret;
}
Static void _ exit dev_exit (void)
{
Misc_deregister (& MISC );
}
Module_init (dev_init );
Module_exit (dev_exit );
Module_license ("GPL ");
Module_author ("friendlyarm Inc .");
Module_description ("S3C2410/S3C2440 PWM driver ");
The following code is used to test the driver:
# Include <stdio. h>
# Include <stdlib. h>
# Include <unistd. h>
# Include <sys/IOCTL. h>
Int main (INT argc, char ** argv)
{
Int on = 1;
Unsigned long frq_duty = 0 ;;
Int FD;
Fprintf (stderr, "pwm app starting... \ n ");
Fd = open ("/dev/pwm", 0 );
If (fd <0 ){
Fprintf (stderr, "error: open device pwm failed \ n ");
Exit (1 );
}
Else {
Fprintf (stderr, "PWM devie open success \ n ");
}
Frq_duty = (200 <8) | 80 );
Ioctl (fd, on, frq_duty );
While (1 );
Close (fd );
Return 0;
}