smart210 linux3.0.8内核蜂鸣器pwm驱动分析

2024-06-23 05:58

本文主要是介绍smart210 linux3.0.8内核蜂鸣器pwm驱动分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

刚刚移植这个pwm驱动到linux3.7.4,发现了一些问题,所以把这个3.0.8的pwm驱动看看,友善带的pwm驱动为mini210-pwm.c,这个只是这个驱动的一部分,直接搬到3.7.4内核下不能用,让我们来好好看看这个驱动的实现吧

static int __init mini210_pwm_dev_init(void) {int ret;ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME);申请一个io口资源if (ret) {printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO);return ret;}gpio_set_value(BUZZER_PMW_GPIO, 0);设置io口的值为低电平s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT);配置io口为输出pwm4buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME);这个函数为请求一个pwm资源,需要细看if (IS_ERR(pwm4buzzer)) {printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME);return -ENODEV;}pwm_stop();sema_init(&lock, 1);ret = misc_register(&mini210_misc_dev);printk(DEVICE_NAME "\tinitialized\n");return ret;
}
上面是pwm驱动的init函数,主要做的是注册了一个混杂驱动,配置了io口,申请了pwm资源,其中pwm4buzzer为struct pwm_device *类型的指针,lock为这个驱动定义的一个信号量,pwm_device为定义在arch\arm\plat-samsung\pwm.c中的一个结构体,用来描述一个pwm设备

struct pwm_device {struct list_head	 list;struct platform_device	*pdev;struct clk		*clk_div;
struct clk		*clk;const char		*label;unsigned int		 period_ns;unsigned int		 duty_ns;unsigned char		 tcon_base;unsigned char		 running;unsigned char		 use_count;unsigned char		 pwm_id;
};
驱动是怎样跟系统申请一个pwm资源的呢

struct pwm_device *pwm_request(int pwm_id, const char *label)
{struct pwm_device *pwm;int found = 0;mutex_lock(&pwm_lock);list_for_each_entry(pwm, &pwm_list, list) {遍历链表,寻找注册到系统中的pwm_deviceif (pwm->pwm_id == pwm_id) {如果系统中存在这个pwm_id号的pwm资源,found = 1;break;}}if (found) {如果成功找到系统资源,那么就再给pwm_device结构成员赋值if (pwm->use_count == 0) {pwm->use_count = 1;pwm->label = label;} elsepwm = ERR_PTR(-EBUSY);} elsepwm = ERR_PTR(-ENOENT);mutex_unlock(&pwm_lock);return pwm;成功返回一个,pwm_device结构体
}

关键问题来了,系统在哪把pwm_device添加到链表呢,

同样在上面那个pwm.c文件中,有下面这个函数,吧pwm_device这个结构的链表加入到全局链表pwm_list中

static int pwm_register(struct pwm_device *pwm)
{pwm->duty_ns = -1;pwm->period_ns = -1;mutex_lock(&pwm_lock);list_add_tail(&pwm->list, &pwm_list);mutex_unlock(&pwm_lock);return 0;
}
继续看pwm.c这个文件,这个文件也是一个驱动,是一个platform机制的模块

static int __init pwm_init(void)
{int ret;clk_scaler[0] = clk_get(NULL, "pwm-scaler0");clk_scaler[1] = clk_get(NULL, "pwm-scaler1");if (IS_ERR(clk_scaler[0]) || IS_ERR(clk_scaler[1])) {printk(KERN_ERR "%s: failed to get scaler clocks\n", __func__);return -EINVAL;}ret = platform_driver_register(&s3c_pwm_driver);if (ret)printk(KERN_ERR "%s: failed to add pwm driver\n", __func__);return ret;
}arch_initcall(pwm_init);

查看他的probe函数

static int s3c_pwm_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;struct pwm_device *pwm;unsigned long flags;unsigned long tcon;unsigned int id = pdev->id;int ret;if (id == 4) {dev_err(dev, "TIMER4 is currently not supported\n");return -ENXIO;}pwm = kzalloc(sizeof(struct pwm_device), GFP_KERNEL);if (pwm == NULL) {dev_err(dev, "failed to allocate pwm_device\n");return -ENOMEM;}pwm->pdev = pdev;pwm->pwm_id = id;/* calculate base of control bits in TCON */pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;pwm->clk = clk_get(dev, "pwm-tin");if (IS_ERR(pwm->clk)) {dev_err(dev, "failed to get pwm tin clk\n");ret = PTR_ERR(pwm->clk);goto err_alloc;}pwm->clk_div = clk_get(dev, "pwm-tdiv");if (IS_ERR(pwm->clk_div)) {dev_err(dev, "failed to get pwm tdiv clk\n");ret = PTR_ERR(pwm->clk_div);goto err_clk_tin;}local_irq_save(flags);tcon = __raw_readl(S3C2410_TCON);tcon |= pwm_tcon_invert(pwm);__raw_writel(tcon, S3C2410_TCON);local_irq_restore(flags);ret = pwm_register(pwm);if (ret) {dev_err(dev, "failed to register pwm\n");goto err_clk_tdiv;}pwm_dbg(pwm, "config bits %02x\n",(__raw_readl(S3C2410_TCON) >> pwm->tcon_base) & 0x0f);dev_info(dev, "tin at %lu, tdiv at %lu, tin=%sclk, base %d\n",clk_get_rate(pwm->clk),clk_get_rate(pwm->clk_div),pwm_is_tdiv(pwm) ? "div" : "ext", pwm->tcon_base);platform_set_drvdata(pdev, pwm);return 0;err_clk_tdiv:clk_put(pwm->clk_div);err_clk_tin:clk_put(pwm->clk);err_alloc:kfree(pwm);return ret;
}
这个probe函数主要做的事是

1.分配pwm_device结构体内存

2初始化pwm_device,比如

pwm->pdev = pdev;
pwm->pwm_id = id;
pwm->tcon_base = id == 0 ? 0 : (id * 4) + 4;

pwm->clk = clk_get(dev, "pwm-tin");

pwm->clk_div = clk_get(dev, "pwm-tdiv");
3.操作tcon寄存器,是对应的定时器的工作模式为TOUT_x Inverter-On 模式

local_irq_save(flags);tcon = __raw_readl(S3C2410_TCON);
tcon |= pwm_tcon_invert(pwm);
__raw_writel(tcon, S3C2410_TCON);

local_irq_restore(flags);

4.注册pwm_device到系统中,这个就是我们上面说的注册到链表

由上面分析可知,要想使用pwm功能用作蜂鸣器,除了要有蜂鸣器的驱动外,在系统中还需要注册pwm_device,要想注册这个pwm_device就要先注册一个pwm类型的platform平台设备,这个设备的定义在arch\arm\plat-samsung\dev-pwm.c中

#define TIMER_RESOURCE_SIZE (1)
#define TIMER_RESOURCE(_tmr, _irq)			\(struct resource [TIMER_RESOURCE_SIZE]) {	\[0] = {					\.start	= _irq,			\.end	= _irq,			\.flags	= IORESOURCE_IRQ	\}					\}#define DEFINE_S3C_TIMER(_tmr_no, _irq)			\.name		= "s3c24xx-pwm",		\.id		= _tmr_no,			\.num_resources	= TIMER_RESOURCE_SIZE,		\.resource	= TIMER_RESOURCE(_tmr_no, _irq),	\/** since we already have an static mapping for the timer,* we do not bother setting any IO resource for the base.*/
struct platform_device s3c_device_timer[] = {[0] = { DEFINE_S3C_TIMER(0, IRQ_TIMER0) },[1] = { DEFINE_S3C_TIMER(1, IRQ_TIMER1) },[2] = { DEFINE_S3C_TIMER(2, IRQ_TIMER2) },[3] = { DEFINE_S3C_TIMER(3, IRQ_TIMER3) },[4] = { DEFINE_S3C_TIMER(4, IRQ_TIMER4) },
};
EXPORT_SYMBOL(s3c_device_timer);
在开发板的板级配置文件mach-mini210.c中有

static struct platform_device *mini210_devices[] __initdata = {

.............................................

&s3c_device_timer[0],

&s3c_device_timer[MINI210_BL_PWM],
..................................

大体上就这样了,linux3.7.4的结构好像和3.0.8的区别很大,有需要的话把3.7.4的也分析一下

这篇关于smart210 linux3.0.8内核蜂鸣器pwm驱动分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086321

相关文章

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb

Apache 高级配置实战之从连接保持到日志分析的完整指南

《Apache高级配置实战之从连接保持到日志分析的完整指南》本文带你从连接保持优化开始,一路走到访问控制和日志管理,最后用AWStats来分析网站数据,对Apache配置日志分析相关知识感兴趣的朋友... 目录Apache 高级配置实战:从连接保持到日志分析的完整指南前言 一、Apache 连接保持 - 性

Linux中的more 和 less区别对比分析

《Linux中的more和less区别对比分析》在Linux/Unix系统中,more和less都是用于分页查看文本文件的命令,但less是more的增强版,功能更强大,:本文主要介绍Linu... 目录1. 基础功能对比2. 常用操作对比less 的操作3. 实际使用示例4. 为什么推荐 less?5.

spring-gateway filters添加自定义过滤器实现流程分析(可插拔)

《spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔)》:本文主要介绍spring-gatewayfilters添加自定义过滤器实现流程分析(可插拔),本文通过实例图... 目录需求背景需求拆解设计流程及作用域逻辑处理代码逻辑需求背景公司要求,通过公司网络代理访问的请求需要做请

Java集成Onlyoffice的示例代码及场景分析

《Java集成Onlyoffice的示例代码及场景分析》:本文主要介绍Java集成Onlyoffice的示例代码及场景分析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 需求场景:实现文档的在线编辑,团队协作总结:两个接口 + 前端页面 + 配置项接口1:一个接口,将o

IDEA下"File is read-only"可能原因分析及"找不到或无法加载主类"的问题

《IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题》:本文主要介绍IDEA下Fileisread-only可能原因分析及找不到或无法加载主类的问题,具有很好的参... 目录1.File is read-only”可能原因2.“找不到或无法加载主类”问题的解决总结1.File