⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 s3c2410_pwm.c

📁 SMDK2410内部的PWM驱动程序和测试程序!
💻 C
字号:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/miscdevice.h> 
#include <linux/sched.h> 
#include <linux/delay.h> 
#include <linux/poll.h> 
#include <linux/spinlock.h> 
#include <linux/delay.h> 
#include <linux/wait.h>

#include <linux/device.h> 
#include <linux/devfs_fs_kernel.h> 
#include <linux/types.h> 
#include <linux/cdev.h> 
#include <linux/errno.h> 
#include <asm/uaccess.h> 
#include <asm/hardware.h>
#include <asm/io.h>
#include <asm/arch/regs-mem.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch-s3c2410/regs-timer.h>
#include "s3c2410_pwm.h"

#define DEVICE_NAME			"pwm" 

static int pwm_major = 0;

static int pwm_set_prescaler(struct PWM_CHANNEL *pwm)
{
	writel( (readl(S3C2410_TCFG0)&0xffffff00) + (pwm->prescaler0&0xFF) ,S3C2410_TCFG0 );	
	return 0;
}

static int pwm_set_channel(unsigned char channel,struct PWM_CHANNEL *pwm)
{	
	unsigned long tmp;
	unsigned long tmp1;

	switch(channel)
	{
		case 0:
			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;
	
		case 1:
			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;
		case 2:
			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;		
		case 3:
			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;
	}
	return 0;
}

static int pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct PWM_CHANNEL pwm;

	switch(cmd)
	{
		case PWM_CHANNEL_0:
		case PWM_CHANNEL_1:
		case PWM_CHANNEL_2:
		case PWM_CHANNEL_3:
			if(copy_from_user(&pwm,(struct PWM_CHANNEL *)arg,sizeof(struct PWM_CHANNEL))) 
	    		return -EFAULT;	
			pwm_set_channel(cmd,&pwm);
			break;
		default:
			return -EFAULT;	
	}
	return 0;
}

static int pwm_open(struct inode * inode, struct file * filp)
{
	return 0;
}

static int pwm_release(struct inode * inode, struct file * filp)
{
	return 0;
}

static struct file_operations pwm_fops = { 
	.owner = THIS_MODULE, 
	.ioctl = pwm_ioctl, 
	.open  = pwm_open,
	.release=pwm_release,
}; 

static int __init pwm_init(void)
{
	int ret;
	
	ret = register_chrdev(0,DEVICE_NAME,&pwm_fops);
  	if(ret < 0) 
	{
		printk("pwm: can't get major number\n");
       	return ret;
	}
	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");
		return ret;
	}
#endif

	s3c2410_gpio_cfgpin(S3C2410_GPB0,S3C2410_GPB0_TOUT0); 
	s3c2410_gpio_cfgpin(S3C2410_GPB1,S3C2410_GPB1_TOUT1); 
    printk("s3c2410_pwm driver initial\n");
    
	return 0;
}

static void __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("FENG");
MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -