mt7628/7688 PWM驱动

news/2024/11/14 13:04:47/

     MT7628/MT7688中的pwm,datasheet写的很糟糕,不像三星,还给你来个编程的流程图,配置哪个寄存器都会告诉你,一坨寄存器丢给你..

     它的PWM分为两种模式,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为一个周期的时间值,当然这个值是以PWM时钟为单位的.PWM_THRESH为所谓的占空比,若DATA_WIDTH为1000,PWM_THRESH设置为500,则输出方波,高低电平比相同. PWM_WAVE_NUM为发送多少个这种PWM信号。

         驱动如下:

         

         

#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/module.h>
#include <linux/device.h> 		
#include <linux/cdev.h>
#include <linux/interrupt.h>  
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/poll.h>   
#include <linux/fcntl.h>
#include <linux/spinlock.h>#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\n", 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\n", 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,
#elseioctl: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\n");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\n");	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\n");	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\n");	goto class_clean;}setup_gpio();	printk(KERN_INFO "sooall pwm init success\n"); 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\n");
}module_init(sooall_pwm_init);  
module_exit(sooall_pwm_exit);  	
</pre><pre name="code" class="cpp">
头文件如下:
<pre name="code" class="cpp">#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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>#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\n");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\n", cfg.wavenum);cnt++;if (cnt == 10) {ioctl(pwm_fd, PWM_DISABLE, &cfg);break;}}return 0;
}


http://www.ppmy.cn/news/293676.html

相关文章

Servlet运行原理及常见API

文章目录 一. Servlet运行原理二. Servlet常用API1. HttpServlet1.1. Servlet的生命周期1.2. Post请求的构造 2. HttpServletRequest2.1. 获取请求信息2.2. 前端给后端传输数据的三种方式2.2.1. 发送Get请求通过query string传输数据2.2.2. 发送Post请求通过form提交数据2.2.3.…

无线网卡芯片rtl8821CU-linux驱动解决方案

最近想在笔记本上kali上使用无线网络&#xff0c;但是vmware的kali虚拟机是无法使用笔记本自带的无线网卡的&#xff0c;于是在淘宝上买了个usb外置无线网卡。但是&#xff0c;网卡买回来了&#xff0c;才发现官网给的linux驱动尼玛竟然无法编译&#xff0c;打电话给官方客服。…

酷派7269_评测:酷派7269的整体性能简介及性价比如何

简单的说一下关于酷派7269的整体性能简介及性价比如何这方面的讯息&#xff0c;不少朋友对于酷派7269的整体性能简介及性价比如何这方面的信息颇感兴趣的。小编今天就为此整理一些相关的讯息&#xff0c;希望对有需要的朋友有所帮助。 酷派7269配备了一块4.5英寸屏幕&#xff0…

酷派大神9976A刷机

酷派大神9976A刷机 元旦回家&#xff0c;听嫂子讲自己的手机变得越来越卡。当然听到这个抱怨的时候&#xff0c;作为一个程序猿&#xff0c;下意识会嗤之以鼻。虽然Android系统会越用越卡&#xff0c;不如iOS&#xff0c;但是真正的程序猿对这样的论断还是觉得嗤之以鼻&#x…

【USB-WIFI模块:rtl8723bu (无线网卡的基于 x6818的移植)

这里写自定义目录标题 wpa_supplicant运行于后台&#xff0c;它需要借助控制台工具wpa_cli来进行手动操作&#xff0c;使用wpa_cli来搜索、设置、和连接网络。 【USB-WIFI模块&#xff1a;rtl8723bu &#xff08;无线网卡的基于 x6818的移植&#xff09; 需要在 X6818 开发板上…

LAN8742替换LAN8720

LAN8742可以替换LAN8720吗&#xff1f; 肯定可以的&#xff0c;LAN8742就是8720的升级版 两者引脚是pin to pin兼容的 8742比8720多了一个wol网络唤醒功能&#xff0c;8742和电脑直连时可以使用直连网线&#xff0c;芯片自己交叉tx和rx信号线。 那么用8742的驱动可以驱动87…

rollup打包ts报错:Original error: Cannot use import statement outside a module

在 package.json 的 scripts 对应的命令行后面&#xff0c;加上 --bundleConfigAsCjs&#xff0c;如&#xff1a; "scripts": {"test": "echo \"Error: no test specified\" && exit 1","dev": "rollup -c -w…

spring-mvc 工作流程

一、概述 spring-mvc 主要是DispatcherServlet工作流程流程可以分为两块&#xff0c;第一块为DispatcherServlet的加载&#xff0c;第二块为请求处理 二、DispatcherServlet的加载 主要依靠三个对象 DispatcherServletRegistrationBean&#xff1a;实现了ServletContextInit…