内核版本:linux-2.6.32
rtc驱动模块在drivers/rtc目录下,首先来看模块的初始化和卸载函数,在class.c中:
211 static int __init rtc_init(void)
212 {
213 rtc_class = class_create(THIS_MODULE, "rtc");
214 if (IS_ERR(rtc_class)) {
215 printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
216 return PTR_ERR(rtc_class);
217 }
218 rtc_class->suspend = rtc_suspend;
219 rtc_class->resume = rtc_resume;
220 rtc_dev_init();
221 rtc_sysfs_init(rtc_class);
222 return 0;
223 }
224
225 static void __exit rtc_exit(void)
226 {
227 rtc_dev_exit();
228 class_destroy(rtc_class);
229 }
230
231 subsys_initcall(rtc_init);
232 module_exit(rtc_exit);
在模块的初始化函数中,完成了三件事情:
在class.c中如果除去同PM相关的suspend和resume操作外,主要有两个函数:rtc_device_register和rtc_device_unregister。从这两个函数的名字来看,应该是rtc设备的注册和注销函数,先来看rtc_device_register函数:
104 /**
105 * rtc_device_register - register w/ RTC class
106 * @dev: the device to register
107 *
108 * rtc_device_unregister() must be called when the class device is no
109 * longer needed.
110 *
111 * Returns the pointer to the new struct class device.
112 */
113 struct rtc_device *rtc_device_register(const char *name, struct device *dev,
114 const struct rtc_class_ops *ops,
115 struct module *owner)
116 {
117 struct rtc_device *rtc;
118 int id, err;
119
120 if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
121 err = -ENOMEM;
122 goto exit;
123 }
124
125
126 mutex_lock(&idr_lock);
127 err = idr_get_new(&rtc_idr, NULL, &id);
128 mutex_unlock(&idr_lock);
129
130 if (err < 0)
131 goto exit;
132
133 id = id & MAX_ID_MASK;
134
135 rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
136 if (rtc == NULL) {
137 err = -ENOMEM;
138 goto exit_idr;
139 }
140
141 rtc->id = id;
142 rtc->ops = ops;
143 rtc->owner = owner;
144 rtc->max_user_freq = 64;
145 rtc->dev.parent = dev;
146 rtc->dev.class = rtc_class;
147 rtc->dev.release = rtc_device_release;
148
149 mutex_init(&rtc->ops_lock);
150 spin_lock_init(&rtc->irq_lock);
151 spin_lock_init(&rtc->irq_task_lock);
152 init_waitqueue_head(&rtc->irq_queue);
153
154 strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
155 dev_set_name(&rtc->dev, "rtc%d", id);
156
157 rtc_dev_prepare(rtc);
158
159 err = device_register(&rtc->dev);
160 if (err)
161 goto exit_kfree;
162
163 rtc_dev_add_device(rtc);
164 rtc_sysfs_add_device(rtc);
165 rtc_proc_add_device(rtc);
166
167 dev_info(dev, "rtc core: registered %s as %s\n",
168 rtc->name, dev_name(&rtc->dev));
169
170 return rtc;
171
172 exit_kfree:
173 kfree(rtc);
174
175 exit_idr:
176 mutex_lock(&idr_lock);
177 idr_remove(&rtc_idr, id);
178 mutex_unlock(&idr_lock);
179
180 exit:
181 dev_err(dev, "rtc core: unable to register %s, err = %d\n",
182 name, err);
183 return ERR_PTR(err);
184 }
185 EXPORT_SYMBOL_GPL(rtc_device_register);
rtc设备使用struct rtc_device结构来描述,那么除去idr部分,从135行开始看起。
484 void rtc_dev_prepare(struct rtc_device *rtc)
485 {
486 if (!rtc_devt)
487 return;
488
489 if (rtc->id >= RTC_DEV_MAX) {
490 pr_debug("%s: too many RTC devices\n", rtc->name);
491 return;
492 }
493
494 rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);
495
496 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
497 INIT_WORK(&rtc->uie_task, rtc_uie_task);
498 setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
499 #endif
500
501 cdev_init(&rtc->char_dev, &rtc_dev_fops);
502 rtc->char_dev.owner = rtc->owner;
503 }
我们看到,最后调用了cdev_init初始化了一个字符设备。
505 void rtc_dev_add_device(struct rtc_device *rtc)
506 {
507 if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
508 printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
509 rtc->name, MAJOR(rtc_devt), rtc->id);
510 else
511 pr_debug("%s: dev (%d:%d)\n", rtc->name,
512 MAJOR(rtc_devt), rtc->id);
513 }
188 /**
189 * rtc_device_unregister - removes the previously registered RTC class device
190 *
191 * @rtc: the RTC class device to destroy
192 */
193 void rtc_device_unregister(struct rtc_device *rtc)
194 {
195 if (get_device(&rtc->dev) != NULL) {
196 mutex_lock(&rtc->ops_lock);
197 /* remove innards of this RTC, then disable it, before
198 * letting any rtc_class_open() users access it again
199 */
200 rtc_sysfs_del_device(rtc);
201 rtc_dev_del_device(rtc);
202 rtc_proc_del_device(rtc);
203 device_unregister(&rtc->dev);
204 rtc->ops = NULL;
205 mutex_unlock(&rtc->ops_lock);
206 put_device(&rtc->dev);
207 }
208 }
209 EXPORT_SYMBOL_GPL(rtc_device_unregister);
没有什么好说的。
从这里我们可以了解到,如果要使用linux提供的rtc模块来写rtc驱动的话,首先应该定义一个rtc_device结构,然后调用rtc_device_register去注册这个rtc设备,那么再看具体驱动之前,还是来先看dev、sysfs和proc相关的东西,看看他们到底提供了什么接口。
1. rtc中的char device
在rtc_init函数中首先调用了rtc_dev_init函数,函数如下:
521 void __init rtc_dev_init(void)
522 {
523 int err;
524
525 err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
526 if (err < 0)
527 printk(KERN_ERR "%s: failed to allocate char dev region\n",
528 __FILE__);
529 }
可见,该函数只是申请了一个字符设备号。而与之对应的rtc_dev_exit肯定是注销申请的设备号,代码如下:
531 void __exit rtc_dev_exit(void)
532 {
533 if (rtc_devt)
534 unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
535 }
471 static const struct file_operations rtc_dev_fops = {
472 .owner = THIS_MODULE,
473 .llseek = no_llseek,
474 .read = rtc_dev_read,
475 .poll = rtc_dev_poll,
476 .unlocked_ioctl = rtc_dev_ioctl,
477 .open = rtc_dev_open,
478 .release = rtc_dev_release,
479 .fasync = rtc_dev_fasync,
480 };
23 static int rtc_dev_open(struct inode *inode, struct file *file)
24 {
25 int err;
26 struct rtc_device *rtc = container_of(inode->i_cdev,
27 struct rtc_device, char_dev);
28 const struct rtc_class_ops *ops = rtc->ops;
29
30 if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
31 return -EBUSY;
32
33 file->private_data = rtc;
34
35 err = ops->open ? ops->open(rtc->dev.parent) : 0;
36 if (err == 0) {
37 spin_lock_irq(&rtc->irq_lock);
38 rtc->irq_data = 0;
39 spin_unlock_irq(&rtc->irq_lock);
40
41 return 0;
42 }
43
44 /* something has gone wrong */
45 clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
46 return err;
47 }
在rtc_dev_open函数中,并无实际操作,如果rtc设备提供了open操作,则调用rtc设备的open函数,否则直接返回0。
而release操作中也并未做太多事情,调用了ioctl函数的RTC_UIE_OFF操作和调用rtc设备的release方法,代码如下:
446 static int rtc_dev_release(struct inode *inode, struct file *file)
447 {
448 struct rtc_device *rtc = file->private_data;
449
450 /* We shut down the repeating IRQs that userspace enabled,
451 * since nothing is listening to them.
452 * - Update (UIE) ... currently only managed through ioctls
453 * - Periodic (PIE) ... also used through rtc_*() interface calls
454 *
455 * Leave the alarm alone; it may be set to trigger a system wakeup
456 * later, or be used by kernel code, and is a one-shot event anyway.
457 */
458
459 /* Keep ioctl until all drivers are converted */
460 rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
461 rtc_update_irq_enable(rtc, 0);
462 rtc_irq_set_state(rtc, NULL, 0);
463
464 if (rtc->ops->release)
465 rtc->ops->release(rtc->dev.parent);
466
467 clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
468 return 0;
469 }
149 static ssize_t
150 rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
151 {
152 struct rtc_device *rtc = file->private_data;
153
154 DECLARE_WAITQUEUE(wait, current);
155 unsigned long data;
156 ssize_t ret;
157
158 if (count != sizeof(unsigned int) && count < sizeof(unsigned long))
159 return -EINVAL;
160
161 add_wait_queue(&rtc->irq_queue, &wait);
162 do {
163 __set_current_state(TASK_INTERRUPTIBLE);
164
165 spin_lock_irq(&rtc->irq_lock);
166 data = rtc->irq_data;
167 rtc->irq_data = 0;
168 spin_unlock_irq(&rtc->irq_lock);
169
170 if (data != 0) {
171 ret = 0;
172 break;
173 }
174 if (file->f_flags & O_NONBLOCK) {
175 ret = -EAGAIN;
176 break;
177 }
178 if (signal_pending(current)) {
179 ret = -ERESTARTSYS;
180 break;
181 }
182 schedule();
183 } while (1);
184 set_current_state(TASK_RUNNING);
185 remove_wait_queue(&rtc->irq_queue, &wait);
186
187 if (ret == 0) {
188 /* Check for any data updates */
189 if (rtc->ops->read_callback)
190 data = rtc->ops->read_callback(rtc->dev.parent,
191 data);
192
193 if (sizeof(int) != sizeof(long) &&
194 count == sizeof(unsigned int))
195 ret = put_user(data, (unsigned int __user *)buf) ?:
196 sizeof(unsigned int);
197 else
198 ret = put_user(data, (unsigned long __user *)buf) ?:
199 sizeof(unsigned long);
200 }
201 return ret;
202 }
调用read函数时,可能会没有数据供应用程序读取,所以提供了等待队列,在没有数据读取时阻塞read操作。最后调用的是rtc设备的read_callback方法,最后将读取到的数据返回给应用程序。
再来看ioctl操作,代码如下:
216 static long rtc_dev_ioctl(struct file *file,
217 unsigned int cmd, unsigned long arg)
218 {
219 int err = 0;
220 struct rtc_device *rtc = file->private_data;
221 const struct rtc_class_ops *ops = rtc->ops;
222 struct rtc_time tm;
223 struct rtc_wkalrm alarm;
224 void __user *uarg = (void __user *) arg;
225
226 err = mutex_lock_interruptible(&rtc->ops_lock);
227 if (err)
228 return err;
229
230 /* check that the calling task has appropriate permissions
231 * for certain ioctls. doing this check here is useful
232 * to avoid duplicate code in each driver.
233 */
234 switch (cmd) {
235 case RTC_EPOCH_SET:
236 case RTC_SET_TIME:
237 if (!capable(CAP_SYS_TIME))
238 err = -EACCES;
239 break;
240
241 case RTC_IRQP_SET:
242 if (arg > rtc->max_user_freq && !capable(CAP_SYS_RESOURCE))
243 err = -EACCES;
244 break;
245
246 case RTC_PIE_ON:
247 if (rtc->irq_freq > rtc->max_user_freq &&
248 !capable(CAP_SYS_RESOURCE))
249 err = -EACCES;
250 break;
251 }
252
253 if (err)
254 goto done;
255
256 /* try the driver's ioctl interface */
257 if (ops->ioctl) {
258 err = ops->ioctl(rtc->dev.parent, cmd, arg);
259 if (err != -ENOIOCTLCMD) {
260 mutex_unlock(&rtc->ops_lock);
261 return err;
262 }
263 }
264
265 /* if the driver does not provide the ioctl interface
266 * or if that particular ioctl was not implemented
267 * (-ENOIOCTLCMD), we will try to emulate here.
268 *
269 * Drivers *SHOULD NOT* provide ioctl implementations
270 * for these requests. Instead, provide methods to
271 * support the following code, so that the RTC's main
272 * features are accessible without using ioctls.
273 *
274 * RTC and alarm times will be in UTC, by preference,
275 * but dual-booting with MS-Windows implies RTCs must
276 * use the local wall clock time.
277 */
278
279 switch (cmd) {
280 case RTC_ALM_READ:
281 mutex_unlock(&rtc->ops_lock);
282
283 err = rtc_read_alarm(rtc, &alarm);
284 if (err < 0)
285 return err;
286
287 if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
288 err = -EFAULT;
289 return err;
290
291 case RTC_ALM_SET:
292 mutex_unlock(&rtc->ops_lock);
293
294 if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
295 return -EFAULT;
296
297 alarm.enabled = 0;
298 alarm.pending = 0;
299 alarm.time.tm_wday = -1;
300 alarm.time.tm_yday = -1;
301 alarm.time.tm_isdst = -1;
302
303 /* RTC_ALM_SET alarms may be up to 24 hours in the future.
304 * Rather than expecting every RTC to implement "don't care"
305 * for day/month/year fields, just force the alarm to have
306 * the right values for those fields.
307 *
308 * RTC_WKALM_SET should be used instead. Not only does it
309 * eliminate the need for a separate RTC_AIE_ON call, it
310 * doesn't have the "alarm 23:59:59 in the future" race.
311 *
312 * NOTE: some legacy code may have used invalid fields as
313 * wildcards, exposing hardware "periodic alarm" capabilities.
314 * Not supported here.
315 */
316 {
317 unsigned long now, then;
318
319 err = rtc_read_time(rtc, &tm);
320 if (err < 0)
321 return err;
322 rtc_tm_to_time(&tm, &now);
323
324 alarm.time.tm_mday = tm.tm_mday;
325 alarm.time.tm_mon = tm.tm_mon;
326 alarm.time.tm_year = tm.tm_year;
327 err = rtc_valid_tm(&alarm.time);
328 if (err < 0)
329 return err;
330 rtc_tm_to_time(&alarm.time, &then);
331
332 /* alarm may need to wrap into tomorrow */
333 if (then < now) {
334 rtc_time_to_tm(now + 24 * 60 * 60, &tm);
335 alarm.time.tm_mday = tm.tm_mday;
336 alarm.time.tm_mon = tm.tm_mon;
337 alarm.time.tm_year = tm.tm_year;
338 }
339 }
340
341 return rtc_set_alarm(rtc, &alarm);
342
343 case RTC_RD_TIME:
344 mutex_unlock(&rtc->ops_lock);
345
346 err = rtc_read_time(rtc, &tm);
347 if (err < 0)
348 return err;
349
350 if (copy_to_user(uarg, &tm, sizeof(tm)))
351 err = -EFAULT;
352 return err;
353
354 case RTC_SET_TIME:
355 mutex_unlock(&rtc->ops_lock);
356
357 if (copy_from_user(&tm, uarg, sizeof(tm)))
358 return -EFAULT;
359
360 return rtc_set_time(rtc, &tm);
361
362 case RTC_PIE_ON:
363 err = rtc_irq_set_state(rtc, NULL, 1);
364 break;
365
366 case RTC_PIE_OFF:
367 err = rtc_irq_set_state(rtc, NULL, 0);
368 break;
369
370 case RTC_AIE_ON:
371 mutex_unlock(&rtc->ops_lock);
372 return rtc_alarm_irq_enable(rtc, 1);
373
374 case RTC_AIE_OFF:
375 mutex_unlock(&rtc->ops_lock);
376 return rtc_alarm_irq_enable(rtc, 0);
377
378 case RTC_UIE_ON:
379 mutex_unlock(&rtc->ops_lock);
380 return rtc_update_irq_enable(rtc, 1);
381
382 case RTC_UIE_OFF:
383 mutex_unlock(&rtc->ops_lock);
384 return rtc_update_irq_enable(rtc, 0);
385
386 case RTC_IRQP_SET:
387 err = rtc_irq_set_freq(rtc, NULL, arg);
388 break;
389
390 case RTC_IRQP_READ:
391 err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
392 break;
393
394 #if 0
395 case RTC_EPOCH_SET:
396 #ifndef rtc_epoch
397 /*
398 * There were no RTC clocks before 1900.
399 */
400 if (arg < 1900) {
401 err = -EINVAL;
402 break;
403 }
404 rtc_epoch = arg;
405 err = 0;
406 #endif
407 break;
408
409 case RTC_EPOCH_READ:
410 err = put_user(rtc_epoch, (unsigned long __user *)uarg);
411 break;
412 #endif
413 case RTC_WKALM_SET:
414 mutex_unlock(&rtc->ops_lock);
415 if (copy_from_user(&alarm, uarg, sizeof(alarm)))
416 return -EFAULT;
417
418 return rtc_set_alarm(rtc, &alarm);
419
420 case RTC_WKALM_RD:
421 mutex_unlock(&rtc->ops_lock);
422 err = rtc_read_alarm(rtc, &alarm);
423 if (err < 0)
424 return err;
425
426 if (copy_to_user(uarg, &alarm, sizeof(alarm)))
427 err = -EFAULT;
428 return err;
429
430 default:
431 err = -ENOTTY;
432 break;
433 }
434
435 done:
436 mutex_unlock(&rtc->ops_lock);
437 return err;
438 }
这部分代码稍微有点长,但最主要的就两个switch,第一个switch主要是检测task是否具有操作的权限,注释也说了,对有些驱动是很有必要的。然后是尝试调用rtc设备驱动的ioctl操作,如果没有提供ioctl操作,则直接跳过。
根据相应的cmd,支持以下主要的操作:
RTC_ALM_READ: 读取闹钟时间 RTC_ALM_SET: 设置闹钟时间 RTC_RD_TIME: 读取rtc时间 RTC_SET_TIME: 设置rtc时间 RTC_WKALM_SET: 设置唤醒闹钟时间 RTC_WKALM_RD: 读取唤醒闹钟时间
为此,我写了给test程序,来读取rtc时间,代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
static const char *rtc_name = "/dev/rtc0";
int main(void)
{
int fd;
struct rtc_time tm;
fd = open(rtc_name, O_RDWR);
if (fd < 0) {
exit(errno);
}
/* 注意:得到的是格林威治时间,北京时间还需要在此基础上加上8小时。 */
ioctl(fd, RTC_RD_TIME, &tm);
printf("time is %04d-%02d-%02d %02d:%02d:%02d\n", tm.tm_year + 1900,
tm.tm_mon + 1,
tm.tm_mday,
tm.tm_hour,
tm.tm_min,
tm.tm_sec);
close(fd);
return 0;
}
2. rtc sysfs接口
在class.c的初始化函数中,首先会调用rtc_sysfs_init函数,而里面只有一个操作,代码如下:
245 void __init rtc_sysfs_init(struct class *rtc_class)
246 {
247 rtc_class->dev_attrs = rtc_attrs;
248 }
而rtc_attrs是定义的一些设备属性文件,定义如下:
118 static struct device_attribute rtc_attrs[] = {
119 __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
120 __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
121 __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
122 __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
123 __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,
124 rtc_sysfs_set_max_user_freq),
125 __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
126 { },
127 };
里面提供了一些操作,例如,rtc_sysfs_show_name、rtc_sysfs_show_date、rtc_sysfs_show_time等等。可以在/sys/class/rtc/rtc0目录下操作一下,例如:
$ cat name rtc_cmos $ cat date 2014-09-02 $ cat time 08:03:57在rtc_sysfs_show_date和rtc_sysfs_show_time函数里面还是调用的interface.c中的rtc_read_time接口函数。
那么这里呢还有个疑问,那就是这些属性文件并没有明显的调用device_create_file去创建它,只是在rtc_sysfs_init函数中赋值给了rtc_class,然后在rtc_device_register函数中将rtc_class赋值给了rtc设备,也就是每个rtc设备的class都是这里的rtc_class,但就是没有调用device_create_file函数去创建。后来也是在网上找到了结果,原来是在device_register函数中完成的,这部分的流程如下:
device_register()->device_add()->device_add_attrs()->device_add_attributes()->device_create_file()
而在rtc_device_register函数中还调用了rtc-sysfs.c中的rtc_sysfs_add_device函数,而该函数也没有做太多事情,也只是在sysfs下创建了dev_attr_wakealarm这个属性文件,代码如下:
224 void rtc_sysfs_add_device(struct rtc_device *rtc)
225 {
226 int err;
227
228 /* not all RTCs support both alarms and wakeup */
229 if (!rtc_does_wakealarm(rtc))
230 return;
231
232 err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
233 if (err)
234 dev_err(rtc->dev.parent,
235 "failed to create alarm attribute, %d\n", err);
236 }
而它呢也提供了两个操作,rtc_sysfs_set_wakealarm和rtc_sysfs_show_wakealarm,这里也就不再去细看了。
3. rtc proc接口
在rtc_device_register函数中最后调用了proc中的rtc_proc_add_device函数,代码如下:
106 void rtc_proc_add_device(struct rtc_device *rtc)
107 {
108 if (rtc->id == 0)
109 proc_create_data("driver/rtc", 0, NULL, &rtc_proc_fops, rtc);
110 }
将创建/proc/driver/rtc这个文件,并且关联了rtc_proc_fops操作。
112 void rtc_proc_del_device(struct rtc_device *rtc)
113 {
114 if (rtc->id == 0)
115 remove_proc_entry("driver/rtc", NULL);
116 }
22 static int rtc_proc_show(struct seq_file *seq, void *offset)
23 {
24 int err;
25 struct rtc_device *rtc = seq->private;
26 const struct rtc_class_ops *ops = rtc->ops;
27 struct rtc_wkalrm alrm;
28 struct rtc_time tm;
29
30 err = rtc_read_time(rtc, &tm);
31 if (err == 0) {
32 seq_printf(seq,
33 "rtc_time\t: %02d:%02d:%02d\n"
34 "rtc_date\t: %04d-%02d-%02d\n",
35 tm.tm_hour, tm.tm_min, tm.tm_sec,
36 tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
37 }
38
39 err = rtc_read_alarm(rtc, &alrm);
40 if (err == 0) {
41 seq_printf(seq, "alrm_time\t: ");
42 if ((unsigned int)alrm.time.tm_hour <= 24)
43 seq_printf(seq, "%02d:", alrm.time.tm_hour);
44 else
45 seq_printf(seq, "**:");
46 if ((unsigned int)alrm.time.tm_min <= 59)
47 seq_printf(seq, "%02d:", alrm.time.tm_min);
48 else
49 seq_printf(seq, "**:");
50 if ((unsigned int)alrm.time.tm_sec <= 59)
51 seq_printf(seq, "%02d\n", alrm.time.tm_sec);
52 else
53 seq_printf(seq, "**\n");
54
55 seq_printf(seq, "alrm_date\t: ");
56 if ((unsigned int)alrm.time.tm_year <= 200)
57 seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
58 else
59 seq_printf(seq, "****-");
60 if ((unsigned int)alrm.time.tm_mon <= 11)
61 seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
62 else
63 seq_printf(seq, "**-");
64 if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
65 seq_printf(seq, "%02d\n", alrm.time.tm_mday);
66 else
67 seq_printf(seq, "**\n");
68 seq_printf(seq, "alarm_IRQ\t: %s\n",
69 alrm.enabled ? "yes" : "no");
70 seq_printf(seq, "alrm_pending\t: %s\n",
71 alrm.pending ? "yes" : "no");
72 }
73
74 seq_printf(seq, "24hr\t\t: yes\n");
75
76 if (ops->proc)
77 ops->proc(rtc->dev.parent, seq);
78
79 return 0;
80 }
主要是调用rtc_read_time和rtc_read_alarm函数,然后信息显示给用户,例如:
$ cat rtc rtc_time : 09:04:40 rtc_date : 2014-09-02 alrm_time : 01:30:08 alrm_date : 2014-09-03 alarm_IRQ : no alrm_pending : no update IRQ enabled : no periodic IRQ enabled : no periodic IRQ frequency : 1024 max user IRQ frequency : 64 24hr : yes periodic_IRQ : no update_IRQ : no HPET_emulated : yes BCD : yes DST_enable : no periodic_freq : 1024 batt_status : okay
至此,rtc驱动核心模块大概也浏览完了,rtc主要为用户提供了三个接口供其操作,char device、sysfs、proc。
那么再以一个具体的例子来看一下rtc驱动,以s3c2440为例。
首先是模块的初始化部分,代码如下:
515 static struct platform_driver s3c2410_rtc_driver = {
516 .probe = s3c_rtc_probe,
517 .remove = __devexit_p(s3c_rtc_remove),
518 .suspend = s3c_rtc_suspend,
519 .resume = s3c_rtc_resume,
520 .driver = {
521 .name = "s3c2410-rtc",
522 .owner = THIS_MODULE,
523 },
524 };
525
526 static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";
527
528 static int __init s3c_rtc_init(void)
529 {
530 printk(banner);
531 return platform_driver_register(&s3c2410_rtc_driver);
532 }
533
534 static void __exit s3c_rtc_exit(void)
535 {
536 platform_driver_unregister(&s3c2410_rtc_driver);
537 }
538
539 module_init(s3c_rtc_init);
540 module_exit(s3c_rtc_exit);
308 /* RTC */
309
310 static struct resource s3c_rtc_resource[] = {
311 [0] = {
312 .start = S3C24XX_PA_RTC,
313 .end = S3C24XX_PA_RTC + 0xff,
314 .flags = IORESOURCE_MEM,
315 },
316 [1] = {
317 .start = IRQ_RTC,
318 .end = IRQ_RTC,
319 .flags = IORESOURCE_IRQ,
320 },
321 [2] = {
322 .start = IRQ_TICK,
323 .end = IRQ_TICK,
324 .flags = IORESOURCE_IRQ
325 }
326 };
327
328 struct platform_device s3c_device_rtc = {
329 .name = "s3c2410-rtc",
330 .id = -1,
331 .num_resources = ARRAY_SIZE(s3c_rtc_resource),
332 .resource = s3c_rtc_resource,
333 };
334
335 EXPORT_SYMBOL(s3c_device_rtc);
402 static int __devinit s3c_rtc_probe(struct platform_device *pdev)
403 {
404 struct rtc_device *rtc;
405 struct resource *res;
406 int ret;
407
408 pr_debug("%s: probe=%p\n", __func__, pdev);
409
410 /* find the IRQs */
411
412 s3c_rtc_tickno = platform_get_irq(pdev, 1);
413 if (s3c_rtc_tickno < 0) {
414 dev_err(&pdev->dev, "no irq for rtc tick\n");
415 return -ENOENT;
416 }
417
418 s3c_rtc_alarmno = platform_get_irq(pdev, 0);
419 if (s3c_rtc_alarmno < 0) {
420 dev_err(&pdev->dev, "no irq for alarm\n");
421 return -ENOENT;
422 }
423
424 pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
425 s3c_rtc_tickno, s3c_rtc_alarmno);
426
427 /* get the memory region */
428
429 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
430 if (res == NULL) {
431 dev_err(&pdev->dev, "failed to get memory region resource\n");
432 return -ENOENT;
433 }
434
435 s3c_rtc_mem = request_mem_region(res->start,
436 res->end-res->start+1,
437 pdev->name);
438
439 if (s3c_rtc_mem == NULL) {
440 dev_err(&pdev->dev, "failed to reserve memory region\n");
441 ret = -ENOENT;
442 goto err_nores;
443 }
444
445 s3c_rtc_base = ioremap(res->start, res->end - res->start + 1);
446 if (s3c_rtc_base == NULL) {
447 dev_err(&pdev->dev, "failed ioremap()\n");
448 ret = -EINVAL;
449 goto err_nomap;
450 }
451
452 /* check to see if everything is setup correctly */
453
454 s3c_rtc_enable(pdev, 1);
455
456 pr_debug("s3c2410_rtc: RTCCON=%02x\n",
457 readb(s3c_rtc_base + S3C2410_RTCCON));
458
459 s3c_rtc_setfreq(&pdev->dev, 1);
460
461 device_init_wakeup(&pdev->dev, 1);
462
463 /* register RTC and exit */
464
465 rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,
466 THIS_MODULE);
467
468 if (IS_ERR(rtc)) {
469 dev_err(&pdev->dev, "cannot attach rtc\n");
470 ret = PTR_ERR(rtc);
471 goto err_nortc;
472 }
473
474 rtc->max_user_freq = 128;
475
476 platform_set_drvdata(pdev, rtc);
477 return 0;
478
479 err_nortc:
480 s3c_rtc_enable(pdev, 0);
481 iounmap(s3c_rtc_base);
482
483 err_nomap:
484 release_resource(s3c_rtc_mem);
485
486 err_nores:
487 return ret;
488 }
在函数开始部分都是同平台设备相关的,例如,获取平台设备资源,进行io内存映射等等。454行,调用s3c_rtc_enable函数,s3c_rtc_enable用于使能rtc模块,代码如下:
345 static void s3c_rtc_enable(struct platform_device *pdev, int en)
346 {
347 void __iomem *base = s3c_rtc_base;
348 unsigned int tmp;
349
350 if (s3c_rtc_base == NULL)
351 return;
352
353 if (!en) {
354 tmp = readb(base + S3C2410_RTCCON);
355 writeb(tmp & ~S3C2410_RTCCON_RTCEN, base + S3C2410_RTCCON);
356
357 tmp = readb(base + S3C2410_TICNT);
358 writeb(tmp & ~S3C2410_TICNT_ENABLE, base + S3C2410_TICNT);
359 } else {
360 /* re-enable the device, and check it is ok */
361
362 if ((readb(base+S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
363 dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
364
365 tmp = readb(base + S3C2410_RTCCON);
366 writeb(tmp|S3C2410_RTCCON_RTCEN, base+S3C2410_RTCCON);
367 }
368
369 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
370 dev_info(&pdev->dev, "removing RTCCON_CNTSEL\n");
371
372 tmp = readb(base + S3C2410_RTCCON);
373 writeb(tmp& ~S3C2410_RTCCON_CNTSEL, base+S3C2410_RTCCON);
374 }
375
376 if ((readb(base + S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
377 dev_info(&pdev->dev, "removing RTCCON_CLKRST\n");
378
379 tmp = readb(base + S3C2410_RTCCON);
380 writeb(tmp & ~S3C2410_RTCCON_CLKRST, base+S3C2410_RTCCON);
381 }
382 }
383 }
代码根据参数en分为两个部分,使能和禁止,如果是禁止rtc模块,则将RTCCON寄存器的RTCEN位置0,同时将TICNT寄存器的ENABLE位置0。如果是使能rtc模块,那么自然是将RTCON寄存器的RTCEN位置1,同时将该寄存器的CNTSEL、CLKRST位置0。所以该函数就是使能和禁止rtc模块的操作的函数。
93 static int s3c_rtc_setfreq(struct device *dev, int freq)
94 {
95 unsigned int tmp;
96
97 if (!is_power_of_2(freq))
98 return -EINVAL;
99
100 spin_lock_irq(&s3c_rtc_pie_lock);
101
102 tmp = readb(s3c_rtc_base + S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
103 tmp |= (128 / freq)-1;
104
105 writeb(tmp, s3c_rtc_base + S3C2410_TICNT);
106 spin_unlock_irq(&s3c_rtc_pie_lock);
107
108 return 0;
109 }
首先检测freq这个值是否合法,然后读取TICNT寄存器,并将低7位清0,然后计算得tick count值,并将该值写入寄存器TICNT中。
在probe函数中,最后调用rtc_device_register去完成rtc设备的注册,注意注册时提供了s3c_rtcops这个参数,它就是rtc的ops操作。
那么接下来就来看看s3c_rtcops:
333 static const struct rtc_class_ops s3c_rtcops = {
334 .open = s3c_rtc_open,
335 .release = s3c_rtc_release,
336 .read_time = s3c_rtc_gettime,
337 .set_time = s3c_rtc_settime,
338 .read_alarm = s3c_rtc_getalarm,
339 .set_alarm = s3c_rtc_setalarm,
340 .irq_set_freq = s3c_rtc_setfreq,
341 .irq_set_state = s3c_rtc_setpie,
342 .proc = s3c_rtc_proc,
343 };
292 static int s3c_rtc_open(struct device *dev)
293 {
294 struct platform_device *pdev = to_platform_device(dev);
295 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
296 int ret;
297
298 ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq,
299 IRQF_DISABLED, "s3c2410-rtc alarm", rtc_dev);
300
301 if (ret) {
302 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);
303 return ret;
304 }
305
306 ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq,
307 IRQF_DISABLED, "s3c2410-rtc tick", rtc_dev);
308
309 if (ret) {
310 dev_err(dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret);
311 goto tick_err;
312 }
313
314 return ret;
315
316 tick_err:
317 free_irq(s3c_rtc_alarmno, rtc_dev);
318 return ret;
319 }
在open函数中,主要申请了两个中断s3c_rtc_alarmirq和s3c_rtc_tickirq。而在release函数中,则是释放这两个申请:
321 static void s3c_rtc_release(struct device *dev)
322 {
323 struct platform_device *pdev = to_platform_device(dev);
324 struct rtc_device *rtc_dev = platform_get_drvdata(pdev);
325
326 /* do not clear AIE here, it may be needed for wake */
327
328 s3c_rtc_setpie(dev, 0);
329 free_irq(s3c_rtc_alarmno, rtc_dev);
330 free_irq(s3c_rtc_tickno, rtc_dev);
331 }
113 static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
114 {
115 unsigned int have_retried = 0;
116 void __iomem *base = s3c_rtc_base;
117
118 retry_get_time:
119 rtc_tm->tm_min = readb(base + S3C2410_RTCMIN);
120 rtc_tm->tm_hour = readb(base + S3C2410_RTCHOUR);
121 rtc_tm->tm_mday = readb(base + S3C2410_RTCDATE);
122 rtc_tm->tm_mon = readb(base + S3C2410_RTCMON);
123 rtc_tm->tm_year = readb(base + S3C2410_RTCYEAR);
124 rtc_tm->tm_sec = readb(base + S3C2410_RTCSEC);
125
126 /* the only way to work out wether the system was mid-update
127 * when we read it is to check the second counter, and if it
128 * is zero, then we re-try the entire read
129 */
130
131 if (rtc_tm->tm_sec == 0 && !have_retried) {
132 have_retried = 1;
133 goto retry_get_time;
134 }
135
136 pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
137 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
138 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
139
140 rtc_tm->tm_sec = bcd2bin(rtc_tm->tm_sec);
141 rtc_tm->tm_min = bcd2bin(rtc_tm->tm_min);
142 rtc_tm->tm_hour = bcd2bin(rtc_tm->tm_hour);
143 rtc_tm->tm_mday = bcd2bin(rtc_tm->tm_mday);
144 rtc_tm->tm_mon = bcd2bin(rtc_tm->tm_mon);
145 rtc_tm->tm_year = bcd2bin(rtc_tm->tm_year);
146
147 rtc_tm->tm_year += 100;
148 rtc_tm->tm_mon -= 1;
149
150 return 0;
151 }
主要是读取2440的rtc模块的寄存器,例如:BCDSEC、BCDMIN、BCDHOUR、BDCDATE、BCDMON、BCDYEAR等。注意读取出来的数据是BCD码,需要调用bcd2bin将BCD码转换成二进制码。
153 static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
154 {
155 void __iomem *base = s3c_rtc_base;
156 int year = tm->tm_year - 100;
157
158 pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n",
159 tm->tm_year, tm->tm_mon, tm->tm_mday,
160 tm->tm_hour, tm->tm_min, tm->tm_sec);
161
162 /* we get around y2k by simply not supporting it */
163
164 if (year < 0 || year >= 100) {
165 dev_err(dev, "rtc only supports 100 years\n");
166 return -EINVAL;
167 }
168
169 writeb(bin2bcd(tm->tm_sec), base + S3C2410_RTCSEC);
170 writeb(bin2bcd(tm->tm_min), base + S3C2410_RTCMIN);
171 writeb(bin2bcd(tm->tm_hour), base + S3C2410_RTCHOUR);
172 writeb(bin2bcd(tm->tm_mday), base + S3C2410_RTCDATE);
173 writeb(bin2bcd(tm->tm_mon + 1), base + S3C2410_RTCMON);
174 writeb(bin2bcd(year), base + S3C2410_RTCYEAR);
175
176 return 0;
177 }
将rtc_time中的tm_year、tm_mon、tm_mday、tm_hour、tm_min和tm_sec写入到相应的寄存器中,同样需要将二进制码转换成BCD码。
再来看getalarm和setalarm,s3c_rtc_getalarm代码如下:
179 static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
180 {
181 struct rtc_time *alm_tm = &alrm->time;
182 void __iomem *base = s3c_rtc_base;
183 unsigned int alm_en;
184
185 alm_tm->tm_sec = readb(base + S3C2410_ALMSEC);
186 alm_tm->tm_min = readb(base + S3C2410_ALMMIN);
187 alm_tm->tm_hour = readb(base + S3C2410_ALMHOUR);
188 alm_tm->tm_mon = readb(base + S3C2410_ALMMON);
189 alm_tm->tm_mday = readb(base + S3C2410_ALMDATE);
190 alm_tm->tm_year = readb(base + S3C2410_ALMYEAR);
191
192 alm_en = readb(base + S3C2410_RTCALM);
193
194 alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
195
196 pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
197 alm_en,
198 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
199 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
200
201
202 /* decode the alarm enable field */
203
204 if (alm_en & S3C2410_RTCALM_SECEN)
205 alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
206 else
207 alm_tm->tm_sec = 0xff;
208
209 if (alm_en & S3C2410_RTCALM_MINEN)
210 alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
211 else
212 alm_tm->tm_min = 0xff;
213
214 if (alm_en & S3C2410_RTCALM_HOUREN)
215 alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
216 else
217 alm_tm->tm_hour = 0xff;
218
219 if (alm_en & S3C2410_RTCALM_DAYEN)
220 alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
221 else
222 alm_tm->tm_mday = 0xff;
223
224 if (alm_en & S3C2410_RTCALM_MONEN) {
225 alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
226 alm_tm->tm_mon -= 1;
227 } else {
228 alm_tm->tm_mon = 0xff;
229 }
230
231 if (alm_en & S3C2410_RTCALM_YEAREN)
232 alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
233 else
234 alm_tm->tm_year = 0xffff;
235
236 return 0;
237 }
首先读取alarm相关寄存器,例如:ALMSEC、ALMMIN、ALMHOUR、ALMDATE、ALMMON、ALMYEAR,然后再读取RTCALM寄存器,它是alarm的使能寄存器,根据RTCALM寄存器相关设置来禁止无效的alarm设置信息。
s3c_rtc_setalarm代码如下:
239 static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
240 {
241 struct rtc_time *tm = &alrm->time;
242 void __iomem *base = s3c_rtc_base;
243 unsigned int alrm_en;
244
245 pr_debug("s3c_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
246 alrm->enabled,
247 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
248 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
249
250
251 alrm_en = readb(base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
252 writeb(0x00, base + S3C2410_RTCALM);
253
254 if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
255 alrm_en |= S3C2410_RTCALM_SECEN;
256 writeb(bin2bcd(tm->tm_sec), base + S3C2410_ALMSEC);
257 }
258
259 if (tm->tm_min < 60 && tm->tm_min >= 0) {
260 alrm_en |= S3C2410_RTCALM_MINEN;
261 writeb(bin2bcd(tm->tm_min), base + S3C2410_ALMMIN);
262 }
263
264 if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
265 alrm_en |= S3C2410_RTCALM_HOUREN;
266 writeb(bin2bcd(tm->tm_hour), base + S3C2410_ALMHOUR);
267 }
268
269 pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
270
271 writeb(alrm_en, base + S3C2410_RTCALM);
272
273 s3c_rtc_setaie(alrm->enabled);
274
275 if (alrm->enabled)
276 enable_irq_wake(s3c_rtc_alarmno);
277 else
278 disable_irq_wake(s3c_rtc_alarmno);
279
280 return 0;
281 }
首先是读取RTCALM寄存器,最高位的使能位保存在变量alrm_en中,然后将RTCALM寄存器全置0,然后判断rtc_time中的tm_sec、tm_min、tm_hour值是否有效,如果是有效的值,设置相应的寄存器,并使能相关的alarm使能位,最后将alrm_en这个变量写入到寄存器RTCALM中。
61 static void s3c_rtc_setaie(int to)
62 {
63 unsigned int tmp;
64
65 pr_debug("%s: aie=%d\n", __func__, to);
66
67 tmp = readb(s3c_rtc_base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
68
69 if (to)
70 tmp |= S3C2410_RTCALM_ALMEN;
71
72 writeb(tmp, s3c_rtc_base + S3C2410_RTCALM);
73 }
如果to是1,表示使能alarm,如果是0,表示禁止alarm。