rtc驱动框架分析
来源:互联网 发布:java密码加密算法 编辑:程序博客网 时间:2024/05/16 06:05
本驱动框架的代码以linux 3.1.0为主
1. rtc的启动代码分析
subsys_initcall(rtc_init),说明rtc框架的初始化是在initcall4来调用的。
static int __init rtc_init(void){rtc_class = class_create(THIS_MODULE, "rtc");//创建rtc类if (IS_ERR(rtc_class)) {printk(KERN_ERR "%s: couldn't create class\n", __FILE__);return PTR_ERR(rtc_class);}rtc_class->suspend = rtc_suspend;rtc_class->resume = rtc_resume;rtc_dev_init();<span style="white-space:pre"></span>//创建rtc字符设备rtc_sysfs_init(rtc_class);<span style="white-space:pre"></span>//创建sysfs相关的文件。return 0;}
module_init(s3c_rtc_init),说明s3c-rtc平台设备驱动的初始化是在initcall6来调用的,大部分驱动都是在initcall6调用的。
static struct platform_driver s3c_rtc_driver = {.probe= s3c_rtc_probe,.remove= __devexit_p(s3c_rtc_remove),.suspend= s3c_rtc_suspend,.resume= s3c_rtc_resume,.id_table= s3c_rtc_driver_ids,.driver= {.name= "s3c-rtc",.owner= THIS_MODULE,},};static int __init s3c_rtc_init(void){printk(banner);return platform_driver_register(&s3c_rtc_driver); //注册s3c_rtc_driver}
platform_driver_register,向platform这个虚拟总线上注册s3c-rtc驱动,在setup_arch这个函数里面会调用platform_add_device,所以在platform总线上有s3c-rtc设备,它们之间在”bus,device,device_driver“这个框架的设计下相遇,然后进行probe,分配相应的数据结构(struct rtc_device),向内核注册此数据结构。
static int __devinit s3c_rtc_probe(struct platform_device *pdev){struct rtc_device *rtc;struct rtc_time rtc_tm;struct resource *res;int ret;pr_debug("%s: probe=%p\n", __func__, pdev);/* find the IRQs */s3c_rtc_tickno = platform_get_irq(pdev, 1); //获取滴答中断号if (s3c_rtc_tickno < 0) {dev_err(&pdev->dev, "no irq for rtc tick\n");return -ENOENT;}s3c_rtc_alarmno = platform_get_irq(pdev, 0); //获取报警中断号if (s3c_rtc_alarmno < 0) {dev_err(&pdev->dev, "no irq for alarm\n");return -ENOENT;}pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n", s3c_rtc_tickno, s3c_rtc_alarmno);/* get the memory region */res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //得到IO内存资源信息if (res == NULL) {dev_err(&pdev->dev, "failed to get memory region resource\n");return -ENOENT;}s3c_rtc_mem = request_mem_region(res->start, resource_size(res), //申请IO内存资源 pdev->name);if (s3c_rtc_mem == NULL) {dev_err(&pdev->dev, "failed to reserve memory region\n");ret = -ENOENT;goto err_nores;}s3c_rtc_base = ioremap(res->start, resource_size(res)); //完成IO内存资源的映射if (s3c_rtc_base == NULL) {dev_err(&pdev->dev, "failed ioremap()\n");ret = -EINVAL;goto err_nomap;}rtc_clk = clk_get(&pdev->dev, "rtc");if (IS_ERR(rtc_clk)) {dev_err(&pdev->dev, "failed to find rtc clock source\n");ret = PTR_ERR(rtc_clk);rtc_clk = NULL;goto err_clk;}clk_enable(rtc_clk);/* check to see if everything is setup correctly */s3c_rtc_enable(pdev, 1); //打开RTC实时时钟pr_debug("s3c2410_rtc: RTCCON=%02x\n", readw(s3c_rtc_base + S3C2410_RTCCON));device_init_wakeup(&pdev->dev, 1);/* register RTC and exit */rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops, //分配struct rtc_device结构并且初始化 THIS_MODULE);if (IS_ERR(rtc)) {dev_err(&pdev->dev, "cannot attach rtc\n");ret = PTR_ERR(rtc);goto err_nortc;}s3c_rtc_cpu_type = platform_get_device_id(pdev)->driver_data;/* Check RTC Time */s3c_rtc_gettime(NULL, &rtc_tm);if (rtc_valid_tm(&rtc_tm)) {rtc_tm.tm_year= 100;rtc_tm.tm_mon= 0;rtc_tm.tm_mday= 1;rtc_tm.tm_hour= 0;rtc_tm.tm_min= 0;rtc_tm.tm_sec= 0;s3c_rtc_settime(NULL, &rtc_tm);dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");}if (s3c_rtc_cpu_type == TYPE_S3C64XX)rtc->max_user_freq = 32768;elsertc->max_user_freq = 128;platform_set_drvdata(pdev, rtc); //设置平台设备的驱动数据是struct rtc_device指针s3c_rtc_setfreq(&pdev->dev, 1);ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, IRQF_DISABLED, "s3c2410-rtc alarm", rtc);if (ret) {dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);goto err_alarm_irq;}ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, IRQF_DISABLED, "s3c2410-rtc tick", rtc);if (ret) {dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);free_irq(s3c_rtc_alarmno, rtc);goto err_tick_irq;}clk_disable(rtc_clk);return 0; err_tick_irq:free_irq(s3c_rtc_alarmno, rtc); err_alarm_irq:platform_set_drvdata(pdev, NULL);rtc_device_unregister(rtc); err_nortc:s3c_rtc_enable(pdev, 0);clk_disable(rtc_clk);clk_put(rtc_clk); err_clk:iounmap(s3c_rtc_base); err_nomap:release_resource(s3c_rtc_mem); err_nores:return ret;}
struct rtc_device{struct device dev; //内嵌的设备结构体struct module *owner;int id; //设备的ID号char name[RTC_DEVICE_NAME_SIZE];const struct rtc_class_ops *ops; //类操作函数集struct mutex ops_lock;struct cdev char_dev; //内嵌的字符设备unsigned long flags;unsigned long irq_data;spinlock_t irq_lock;wait_queue_head_t irq_queue; //中断等待队列struct fasync_struct *async_queue; //异步队列struct rtc_task *irq_task; //rtc的任务结构体spinlock_t irq_task_lock;int irq_freq; //中断频率int max_user_freq;struct timerqueue_head timerqueue;struct rtc_timer aie_timer;struct rtc_timer uie_rtctimer;struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */int pie_enabled;struct work_struct irqwork;#ifdef CONFIG_RTC_INTF_DEV_UIE_EMULstruct work_struct uie_task;struct timer_list uie_timer;/* Those fields are protected by rtc->irq_lock */unsigned int oldsecs;unsigned int uie_irq_active:1;unsigned int stop_uie_polling:1;unsigned int uie_task_active:1;unsigned int uie_timer_active:1;#endif};
struct rtc_device *rtc_device_register(const char *name, struct device *dev,const struct rtc_class_ops *ops,struct module *owner){struct rtc_device *rtc;struct rtc_wkalrm alrm;int id, err;if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {err = -ENOMEM;goto exit;}mutex_lock(&idr_lock);err = idr_get_new(&rtc_idr, NULL, &id);mutex_unlock(&idr_lock);if (err < 0)goto exit;id = id & MAX_ID_MASK;rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);if (rtc == NULL) {err = -ENOMEM;goto exit_idr;}rtc->id = id;rtc->ops = ops;rtc->owner = owner;rtc->irq_freq = 1;rtc->max_user_freq = 64;rtc->dev.parent = dev;rtc->dev.class = rtc_class;rtc->dev.release = rtc_device_release;mutex_init(&rtc->ops_lock);spin_lock_init(&rtc->irq_lock);spin_lock_init(&rtc->irq_task_lock);init_waitqueue_head(&rtc->irq_queue);/* Init timerqueue */timerqueue_init_head(&rtc->timerqueue);INIT_WORK(&rtc->irqwork, rtc_timer_do_work);/* Init aie timer */rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc);/* Init uie timer */rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc);/* Init pie timer */hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);rtc->pie_timer.function = rtc_pie_update_irq;rtc->pie_enabled = 0;/* Check to see if there is an ALARM already set in hw */err = __rtc_read_alarm(rtc, &alrm);if (!err && !rtc_valid_tm(&alrm.time))rtc_initialize_alarm(rtc, &alrm);strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);dev_set_name(&rtc->dev, "rtc%d", id);rtc_dev_prepare(rtc);err = device_register(&rtc->dev); //向内核注册此设备if (err) {put_device(&rtc->dev);goto exit_kfree;}rtc_dev_add_device(rtc); //向dev文件系统注册设备rtc_sysfs_add_device(rtc); //向sys文件系统注册设备rtc_proc_add_device(rtc); //向proc文件系统注册设备dev_info(dev, "rtc core: registered %s as %s\n",rtc->name, dev_name(&rtc->dev));return rtc;exit_kfree:kfree(rtc);exit_idr:mutex_lock(&idr_lock);idr_remove(&rtc_idr, id);mutex_unlock(&idr_lock);exit:dev_err(dev, "rtc core: unable to register %s, err = %d\n",name, err);return ERR_PTR(err);}
所以初始化主要是分配了一个struct rtc_device结构,并且设置了类操作函数集指针struct rtc_class_ops
2. rtc设备的接口函数
RTC实时时钟获得时间函数s3c_rtc_gettime
RTC实时时钟设置时间函数s3c_rtc_settime
在正常模式和掉电模式下,RTC在指定的时刻会产生一个报警信号。在掉电模式还会产生一个唤醒信号
RTC报警获取函数s3c_rtc_getalarm
RTC设置报警时间函数s3c_rtc_setalarm
0 0
- rtc驱动框架分析
- platfrom RTC驱动分析
- RTC驱动源码分析
- 时钟RTC驱动分析
- RTC驱动模型分析
- s3c2410 RTC驱动框架linux内核源码分析
- s3c2410 RTC驱动框架linux内核源码分析
- s3c2410 RTC驱动框架linux内核源码分析
- 2410下rtc驱动分析
- S3C2410的RTC驱动分析
- 2410下rtc驱动分析
- 2410下rtc驱动分析
- linux RTC 驱动模型分析
- Linux RTC 驱动模型分析
- linux RTC 驱动模型分析
- linux RTC 驱动模型分析
- linux RTC 驱动模型分析
- linux RTC 驱动模型分析
- DM8168 IPNC Boa移植
- 写给自己
- MVC
- Activity四种启动模式
- C++|C++学习笔记|数据、变量和计算
- rtc驱动框架分析
- 【转载】 经典SQL练习题
- 以互联网思维做好客户端软件
- org.apache.hadoop.hdfs.server.datanode.DataNode: Exception in receiveBlock for block
- 2015060902 - 成就强大的自己,必须坚持做10件事情
- 如何让Java类不可变
- bat 压缩备份文件 xcopy mysqldump备份文件和数据库
- php中字符串的拼接
- cocoapod 64位报错