mt 7628/7688 PWM駆動

10905 ワード

MT 7628/MT 7688のpwm、datasheetはとても悪くて、サムスンのようではありませんて、あなたにプログラミングのフローチャートを返して、どのレジスタを配置してもあなたに教えて、1つのレジスタはあなたになくします..
そのPWMは2つのモードに分けられて、OLDとnew、ここで私达は简単なOLDモードを使って、NEWモードは研究したことがなくて、マニュアルは详しくなくて、NEWモードが分かりません...
      
PWMのメインレジスタは以下の通り、
     
OLDモードで使用するレジスタはPWM_ENABLE, PWMX_CON, PWMX_GDURATION,PWMX_WAVE_NUM,PWMX_DATA_WIDTH,PWMX_THRESH.
そのうちPWM_ENABLEは各PWM,PWM_CONは以下のように預けます.
                
OLDモードを選択し、STOP_BITSレジスタ無視、GUARD_VALUEとIDEL_VALは0または1を配置する必要があり、残りはクロック配置である.
他のいくつかのレジスタ、GUARD_DURATIONという配置はOLDモードに対応するようでは有効にならない.したがって、PWM波形全体がPWM_DATA_WIDTH,PWM_THRESHとPWM_WAVE_NUMで設定する.そのうちDATA_WIDTHは1周期の時間値である、もちろんこの値はPWMクロック単位である.PWM_THRESHはいわゆるデューティ比であり、DATA_WIDTHは1000、PWM_THRESHが500に設定と、出力方波は、高低レベル比が同じになる.PWM_WAVE_NUMは、このようなPWM信号をいくつ送信するかである.
次のように駆動します.
         
         
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  		
#include 
#include   
#include 
#include 
#include    
#include 
#include 

#include "sooall_pwm.h"

MODULE_LICENSE("GPL");

#define RALINK_CLK_CFG    0xB0000030 
#define RALINK_AGPIO_CFG  0xB000003C
#define RALINK_GPIOMODE   0xB0000060 

#define RALINK_PWM_BASE   0xB0005000 
#define RALINK_PWM_ENABLE    RALINK_PWM_BASE 

#define PWM_MODE_BIT      15 
#define PWM_GVAL_BIT      8 
#define PWM_IVAL_BIT      7  

enum {
	PWM_REG_CON,
	PWM_REG_GDUR = 0x0C,
	PWM_REG_WNUM = 0x28,
	PWM_REG_DWID = 0x2C,
	PWM_REG_THRE = 0x30,
	PWM_REG_SNDNUM = 0x34,
}PWM_REG_OFF;

#define PWM_NUM  4 
u32 PWM_REG[PWM_NUM] = {
	(RALINK_PWM_BASE + 0x10),    /* pwm0 base */
	(RALINK_PWM_BASE + 0x50),    /* pwm1 base */
	(RALINK_PWM_BASE + 0x90),    /* pwm2 base */
	(RALINK_PWM_BASE + 0xD0)     /* pwm3 base */
};

#define NAME  "sooall_pwm"

int pwm_major;
int pwm_minor  = 0;
int pwm_device_cnt = 1;
struct cdev pwm_cdev;

static struct class  *pwm_class;
static struct device *pwm_device;

spinlock_t pwm_lock;

static void sooall_pwm_cfg(struct pwm_cfg *cfg)
{
	u32 value;
	unsigned long  flags;
	u32 basereg;

	basereg = PWM_REG[cfg->no];

	spin_lock_irqsave(&pwm_lock, flags);
	
	/* 1. set the pwm control register */
	value  = le32_to_cpu(*(volatile u32 *)(basereg + PWM_REG_CON));
	/* old mode */
	value |= (1 << PWM_MODE_BIT);
	/* set the idel val and guard val */
	value &= ~((1 << PWM_IVAL_BIT) | (1 << PWM_GVAL_BIT));
	value |= ((cfg->idelval & 0x1) << PWM_IVAL_BIT);
	value |= ((cfg->guardval & 0x1) << PWM_GVAL_BIT);
	/* set the source clk */
	if (cfg->clksrc == PWM_CLK_100HZ) {
		value &= ~(1<<3);		
	} else {
		value |= (1<<3);	
	}
    /* set the clk div */
	value &= ~0x7;
	value |= (0x7 & cfg->clkdiv);	
	*(volatile u32 *)(basereg + PWM_REG_CON) = cpu_to_le32(value);	

	/* 2. set the guard duration val */
	value  = le32_to_cpu(*(volatile u32 *)(basereg + PWM_REG_GDUR));
	value &= ~(0xffff);
	value |= (cfg->guarddur & 0xffff);
	*(volatile u32 *)(basereg + PWM_REG_GDUR) = cpu_to_le32(value);	
	
	
	/* 3. set the wave num val */
	value  = le32_to_cpu(*(volatile u32 *)(basereg + PWM_REG_WNUM));
	value &= ~(0xffff);
	value |= (cfg->wavenum & 0xffff);
	*(volatile u32 *)(basereg + PWM_REG_WNUM) = cpu_to_le32(value);	
	
	
	/* 4. set the data width val */
	value  = le32_to_cpu(*(volatile u32 *)(basereg + PWM_REG_DWID));
	value &= ~(0x1fff);
	value |= (cfg->datawidth & 0x1fff);
	*(volatile u32 *)(basereg + PWM_REG_DWID) = cpu_to_le32(value);	
	
	
	/* 5. set the thresh  val */
	value  = le32_to_cpu(*(volatile u32 *)(basereg + PWM_REG_THRE));
	value &= ~(0x1fff);
	value |= (cfg->threshold & 0x1fff);
	*(volatile u32 *)(basereg + PWM_REG_THRE) = cpu_to_le32(value);	

	spin_unlock_irqrestore(&pwm_lock, flags);
}

static void sooall_pwm_enable(int no)
{
	u32 value;
	unsigned long  flags;

	printk(KERN_INFO NAME "enable pwm%d
", no); spin_lock_irqsave(&pwm_lock, flags); value = le32_to_cpu(*(volatile u32 *)(RALINK_PWM_ENABLE)); value |= (1 << no); *(volatile u32 *)(RALINK_PWM_ENABLE) = cpu_to_le32(value); spin_unlock_irqrestore(&pwm_lock, flags); } static void sooall_pwm_disable(int no) { u32 value; unsigned long flags; printk(KERN_INFO NAME "disable pwm%d
", no); spin_lock_irqsave(&pwm_lock, flags); value = le32_to_cpu(*(volatile u32 *)(RALINK_PWM_ENABLE)); value &= ~(1 << no); *(volatile u32 *)(RALINK_PWM_ENABLE) = cpu_to_le32(value); spin_unlock_irqrestore(&pwm_lock, flags); } static void sooall_pwm_getsndnum(struct pwm_cfg *cfg) { u32 value; unsigned long flags; u32 regbase = PWM_REG[cfg->no]; spin_lock_irqsave(&pwm_lock, flags); value = le32_to_cpu(*(volatile u32 *)(regbase + PWM_REG_SNDNUM)); cfg->wavenum = value; spin_unlock_irqrestore(&pwm_lock, flags); } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) long sooall_pwm_ioctl(struct file *file, unsigned int req, unsigned long arg) #else int sooall_pwm_ioctl(struct inode *inode, struct file *file, unsigned int req, unsigned long arg) #endif { switch (req) { case PWM_ENABLE: sooall_pwm_enable(((struct pwm_cfg *)arg)->no); break; case PWM_DISABLE: sooall_pwm_disable(((struct pwm_cfg *)arg)->no); break; case PWM_CONFIGURE: sooall_pwm_cfg((struct pwm_cfg *)arg); break; case PWM_GETSNDNUM: sooall_pwm_getsndnum((struct pwm_cfg *)arg); break; default: return -ENOIOCTLCMD; } return 0; } static int sooall_pwm_open(struct inode * inode, struct file * filp) { return 0; } static int sooall_pwm_close(struct inode *inode, struct file *file) { return 0; } static const struct file_operations pwm_fops = { .owner = THIS_MODULE, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35) unlocked_ioctl:sooall_pwm_ioctl, #else ioctl:sooall_pwm_ioctl, #endif .open = sooall_pwm_open, .release = sooall_pwm_close, }; static int setup_chrdev(void) { dev_t dev; int err = 0; if (pwm_major) { dev = MKDEV(pwm_major, 0); err = register_chrdev_region(dev, pwm_device_cnt, NAME); } else { err = alloc_chrdev_region(&dev, 0, pwm_device_cnt, NAME); pwm_major = MAJOR(dev); } if (err < 0) { printk(KERN_ERR NAME "get device number failed
"); return -1; } cdev_init(&pwm_cdev, &pwm_fops); pwm_cdev.owner = THIS_MODULE; pwm_cdev.ops = &pwm_fops; err = cdev_add(&pwm_cdev, dev, pwm_device_cnt); if (err < 0) { printk(KERN_ERR NAME "cdev_add failed
"); unregister_chrdev_region(dev, pwm_device_cnt); return -1; } return 0; } static void clean_chrdev(void) { dev_t dev = MKDEV(pwm_major, 0); cdev_del(&pwm_cdev); unregister_chrdev_region(dev, pwm_device_cnt); } static void setup_gpio(void) { u32 value; int i = 0; /* pwm0 pwm1 */ /* enable the pwm clk */ value = le32_to_cpu(*(volatile u32 *)(RALINK_CLK_CFG)); value |= (1 << 31); *(volatile u32 *)(RALINK_CLK_CFG) = cpu_to_le32(value); /* set the agpio cfg of ephy_gpio_aio_en */ value = le32_to_cpu(*(volatile u32 *)(RALINK_AGPIO_CFG)); value |= (0xF<<17); *(volatile u32 *)(RALINK_AGPIO_CFG) = cpu_to_le32(value); /* set the pwm mode */ value = le32_to_cpu(*(volatile u32 *)(RALINK_GPIOMODE)); value &= ~(3 << 28 | 3 << 30); *(volatile u32 *)(RALINK_GPIOMODE) = cpu_to_le32(value); /* disable all the pwm */ for (i = 0; i < PWM_NUM; i++) { sooall_pwm_disable(i); } } static int sooall_pwm_init(void) { int ret = 0; spin_lock_init(&pwm_lock); ret = setup_chrdev(); if (ret < 0) return -1; pwm_class = class_create(THIS_MODULE, NAME); if (NULL == pwm_class) { printk(KERN_ERR NAME "class_create failed
"); goto dev_clean; } pwm_device = device_create(pwm_class, NULL, MKDEV(pwm_major, pwm_minor), NULL, "sooall_pwm"); if (NULL == pwm_device) { printk(KERN_ERR NAME "device_create failed
"); goto class_clean; } setup_gpio(); printk(KERN_INFO "sooall pwm init success
"); return 0; class_clean: class_destroy(pwm_class); dev_clean: clean_chrdev(); return -1; } static void sooall_pwm_exit(void) { device_destroy(pwm_class, MKDEV(pwm_major, pwm_minor)); class_destroy(pwm_class); clean_chrdev(); printk(KERN_INFO "sooall pwm exit
"); } module_init(sooall_pwm_init); module_exit(sooall_pwm_exit);
 
  
#ifndef _SOOALL_PWM_H_
#define _SOOALL_PWM_H_

/* the source of the clock */
typedef enum {
	PWM_CLK_100KHZ,  
	PWM_CLK_40MHZ
}PWM_CLK_SRC;

/* clock div */
typedef enum {
	PWM_CLI_DIV0 = 0,
	PWM_CLK_DIV2,
	PWM_CLK_DIV4,
	PWM_CLK_DIV8,
	PWM_CLK_DIV16,
	PWM_CLK_DIV32,
	PWM_CLK_DIV64,
	PWM_CLK_DIV128,
}PWM_CLK_DIV;

struct pwm_cfg {
	int no;
	PWM_CLK_SRC    clksrc;
	PWM_CLK_DIV    clkdiv;
	unsigned char  idelval;
	unsigned char  guardval;
	unsigned short guarddur;
	unsigned short wavenum;
	unsigned short datawidth;
	unsigned short threshold;
};

/* ioctl */
#define PWM_ENABLE      0
#define PWM_DISABLE     1  
#define PWM_CONFIGURE   2 
#define PWM_GETSNDNUM   3
#endif 
#include 
#include 
#include 
#include 
#include 
#include 

#include "sooall_pwm.h"

#define PWM_DEV "/dev/sooall_pwm"

int main(int argc, char *argv)
{
	int ret = -1;
	int pwm_fd;
	int pwmno;
	struct pwm_cfg  cfg;

	pwm_fd = open(PWM_DEV, O_RDWR);
	if (pwm_fd < 0) {
		printf("open pwm fd failed
"); return -1; } cfg.no = 0; /* pwm0 */ cfg.clksrc = PWM_CLK_40KHZ; cfg.clkdiv = PWM_CLK_DIV2; cfg.idelval = 0; cfg.guardval = 0; cfg.guarddur = 0; cfg.wavenum = 0; /* forever loop */ cfg.datawidth = 1000; cfg.threshold = 500; ioctl(pwm_fd, PWM_CONFIGURE, &cfg); ioctl(pwm_fd, PWM_ENABLE, &cfg); while (1) { static int cnt = 0; sleep(5); ioctl(pwm_fd, PWM_GETSNDNUM, &cfg); printf("send wave num = %d
", cfg.wavenum); cnt++; if (cnt == 10) { ioctl(pwm_fd, PWM_DISABLE, &cfg); break; } } return 0; }