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
原创粉丝点击