分类:
2011-03-22 15:56:27
s3c2440的datasheet中是这样描述的:
The count value reaches '0' when the tick time interrupt occurs. Then the period of interrupt is as follows:
— Period = ( n+1 ) / 128 second
— n: Tick time count value (1~127)
此处n设置为127,所以tick的中断周期是1秒。
用于cpu休眠及唤醒,还没来得及仔细研究。
platform_device->device->device_private->driver_data = rtc_device
把platform_device的一个专用指针指向rtc_device。嵌套了很多层,现在先不管他,以后分析platform框架的时候再考虑。
2.rtc_device_register
Small id to pointer translation service.就是给某个数据结构分配一个id,通过这个id就能找到这个数据结构的地址。先不管他。
cdev_add(&rtc->char_dev, rtc->dev.devt, 1)
这里只涉及了一个属性的添加:dev_attr_wakealarm,没搞明白,稍后还要再看看是怎么回事。@这里涉及到class.c这个文件:
subsys_initcall(rtc_init);
rtc_init负责初试化rtc_class,以及调用rtc_sysfs_init,此处会加载rtc_attrs属性到rtc_class中。
subsys_initcall将rtc_init标记为“初始化段”的一部分,编译器会把他放进该段,而在系统初始化的时候,会调用初始化段里的函数,因此,在rtc的驱动模块之前,rtc_attrs这些通用属性就已经加载完毕了。
在proc文件系统中添加driver/rtc文件。
3.rtc_dev_prepare
INIT_WORK(&rtc->uie_task, rtc_uie_task);
setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);uie部分负责及时更新rtc_device->irq_data,每当经过一秒钟,就在irq_data中记录相应的信息,包括经过的秒数、更新类型(UIE、PIE、AIE)。
这主要通过一个工作队列(uie_task)和一个定时器(uie_timer)完成。最开始,task不断调用自己(schedule_work(&rtc->uie_task))进行轮询,从rtc中读取秒数值,与之前保存的rtc_device->oldsecs对比,如果不一样,就说明经过了至少一秒钟,于是task就停止轮询,并启用定时器,将其延时设为一个不到1秒钟的间隔,而定时器负责启用task轮询。这样,在这个时间间隔内,就不需要再进行轮询了。
static void rtc_uie_task(struct work_struct *work)
{
struct rtc_device *rtc =
container_of(work, struct rtc_device, uie_task);
struct rtc_time tm;
int num = 0;
int err;err = rtc_read_time(rtc, &tm);
spin_lock_irq(&rtc->irq_lock);
if (rtc->stop_uie_polling || err) {
rtc->uie_task_active = 0;
} else if (rtc->oldsecs != tm.tm_sec) { //如果经过了至少1秒,则启用定时器
num = (tm.tm_sec + 60 - rtc->oldsecs) % 60; //究竟经过了多少秒
rtc->oldsecs = tm.tm_sec;
rtc->uie_timer.expires = jiffies + HZ - (HZ/10); //定时器延时设置为将近1秒钟:jiffies+Hz = 1s
rtc->uie_timer_active = 1;
rtc->uie_task_active = 0;
add_timer(&rtc->uie_timer);
} else if (schedule_work(&rtc->uie_task) == 0) { //如果没有到达1秒,就不断轮询
rtc->uie_task_active = 0;
}
spin_unlock_irq(&rtc->irq_lock);
if (num)
rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF);
}
static void rtc_uie_timer(unsigned long data)
{
struct rtc_device *rtc = (struct rtc_device *)data;
unsigned long flags;spin_lock_irqsave(&rtc->irq_lock, flags);
rtc->uie_timer_active = 0;
rtc->uie_task_active = 1;
if ((schedule_work(&rtc->uie_task) == 0)) //重新启用task进行轮询
rtc->uie_task_active = 0;
spin_unlock_irqrestore(&rtc->irq_lock, flags);
}