Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1747515
  • 博文数量: 199
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 6186
  • 用 户 组: 普通用户
  • 注册时间: 2012-10-30 11:01
个人简介

Linuxer.

文章存档

2015年(4)

2014年(28)

2013年(167)

分类: LINUX

2013-05-21 15:45:14


  1. 一、概述
  2. 1.在Linux中有硬件时钟与系统时钟等两种时钟。硬件时钟是指主机板上的时钟设备,也就是通常可在BIOS画面设定的时钟。系统时钟则是指kernel中的时钟。当Linux启动时,系统时钟会去读取硬件时钟的设定,之后系统时钟即独立运作。所有Linux相关指令与函数都是读取系统时钟的设定。
  3. 系统时钟的设定就是我们常用的date命令,而我们写的RTC驱动就是为硬件时钟服务的,它有属于自己的命令hwclock,因此使用date命令是不可能调用到我们的驱动的,我们可以通过hwclock的一些指令来实现更新rtc时钟——也就是系统时钟和硬件时钟的交互。
  4. hwclock –r 显示硬件时钟与日期
  5. hwclock –s 将系统时钟调整为与目前的硬件时钟一致。
  6. hwclock –w 将硬件时钟调整为与目前的系统时钟一致。
  7.         
  8. 2.RTC核心文件:
  9. /include/linux/rtc.h 定义了与RTC有关的数据结构
  10. /drivers/rtc/hctosys.c 在启动时初始化系统时间。
  11. /drivers/rtc/rtc-lib.c 提供了一些时间格式相互转化的函数。
  12. /drivers/rtc/class.c 这个文件向linux设备模型核心注册了一个类RTC,然后向驱动程序提供了注册/注销接口
  13. /drivers/rtc/interface.c 这个文件主要提供了用户程序与RTC驱动的接口函数,用户程序一般通过ioctl与RTC驱动交互,这里定义了每个ioctl命令需要调用的函数
  14. /drivers/rtc/rtc-dev.c: 字符设备的注册和用户层文件操作函数接口。
  15. /drivers/rtc/rtc-proc.c     与proc文件系统有关
  16. /drivers/rtc/rtc-sysfs.c 与sysfs有关
  17. /drivers/rtc/rtc-omap.c: davinci RTC的芯片平台驱动。
  18. 3.驱动模型结构


  19. . 基本数据结构
  20. 1. struct rtc_device 结构
  21. //这个结构是RTC驱动程序的基本数据结构,但是他不像其他核心的基本结构一样,驱动程序以他为参数调用注册函数注册到核心。这个结构是由注册函数返回给驱动程序的。
  22. struct rtc_device
  23. {
  24.     struct device dev;
  25.     struct module *owner;
  26.     int id;
  27.     char name[RTC_DEVICE_NAME_SIZE];//RTC名称
  28.     const struct rtc_class_ops *ops;//驱动程序的基本操作函数,操作底层寄存器
  29.     struct mutex ops_lock;
  30.     struct cdev char_dev;//嵌入的字符设备结构
  31.     unsigned long flags;
  32.     unsigned long irq_data;
  33.     spinlock_t irq_lock;
  34.     wait_queue_head_t irq_queue;
  35.     struct fasync_struct *async_queue;
  36.   
  37.     struct rtc_task *irq_task;
  38.     spinlock_t irq_task_lock;
  39.     int irq_freq;
  40.     int max_user_freq;
  41. #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
  42.     struct work_struct uie_task;
  43.     struct timer_list uie_timer;
  44.     /* Those fields are protected by rtc->irq_lock */
  45.     unsigned int oldsecs;
  46.     unsigned int uie_irq_active:1;
  47.     unsigned int stop_uie_polling:1;
  48.     unsigned int uie_task_active:1;
  49.     unsigned int uie_timer_active:1;
  50. #endif
  51. };

  52. 2. struct rtc_class_ops 结构
  53. //这个结构是RTC驱动程序要实现的基本操作函数,注意这里的操作不是文件操作。驱动程序通过初始化这样一个结构,将自己实现的函数与RTC核心联系起来。
  54. //这里面的大部分函数都要驱动程序来实现。而且这些函数都是操作底层硬件的,属于最底层的函数。
  55. struct rtc_class_ops {
  56.     int (*open)(struct device *);
  57.     void (*release)(struct device *);
  58.     int (*ioctl)(struct device *, unsigned int, unsigned long);
  59.     int (*read_time)(struct device *, struct rtc_time *);
  60.     int (*set_time)(struct device *, struct rtc_time *);
  61.     int (*read_alarm)(struct device *, struct rtc_wkalrm *);
  62.     int (*set_alarm)(struct device *, struct rtc_wkalrm *);
  63.     int (*proc)(struct device *, struct seq_file *);
  64.     int (*set_mmss)(struct device *, unsigned long secs);
  65.     int (*irq_set_state)(struct device *, int enabled);
  66.     int (*irq_set_freq)(struct device *, int freq);
  67.     int (*read_callback)(struct device *, int data);
  68.     int (*alarm_irq_enable)(struct device *, unsigned int enabled);
  69.     int (*update_irq_enable)(struct device *, unsigned int enabled);
  70. };

  71. 3. struct rtc_time 结构
  72. //代表了时间与日期,从RTC设备读回的时间和日期就保存在这个结构体中
  73. struct rtc_time {
  74.     int tm_sec;
  75.     int tm_min;
  76.     int tm_hour;
  77.     int tm_mday;
  78.     int tm_mon;
  79.     int tm_year;
  80.     int tm_wday;
  81.     int tm_yday;
  82.     int tm_isdst;
  83. };


  84. 三、RTC驱动过程
  85. 1.platform 设备注册
  86. //在board-da850-evm.c中注册RTC的platform设备。
  87. static __init void da850_evm_init(void)
  88. {
  89.     。。。。。。
  90.     ret = da8xx_register_rtc();
  91.     if (ret)
  92.         pr_warning("da850_evm_init: rtc setup failed: %dn", ret);
  93.     。。。。。。
  94. }

  95. static struct resource da8xx_rtc_resources[] = {
  96.     {
  97.         .start        = DA8XX_RTC_BASE,//#define DA8XX_RTC_BASE            0x01C23000
  98.         .end        = DA8XX_RTC_BASE + SZ_4K - 1,
  99.         .flags        = IORESOURCE_MEM,
  100.     },
  101.     { /* timer irq */
  102.         .start        = IRQ_DA8XX_RTC,//中断号是19
  103.         .end        = IRQ_DA8XX_RTC,
  104.         .flags        = IORESOURCE_IRQ,
  105.     },
  106.     { /* alarm irq */
  107.         .start        = IRQ_DA8XX_RTC,
  108.         .end        = IRQ_DA8XX_RTC,
  109.         .flags        = IORESOURCE_IRQ,
  110.     },
  111. };

  112. static struct platform_device da8xx_rtc_device = {
  113.     .name = "omap_rtc",
  114.     .id = -1,
  115.     .num_resources    = ARRAY_SIZE(da8xx_rtc_resources),
  116.     .resource    = da8xx_rtc_resources,
  117. };

  118. int da8xx_register_rtc(void)
  119. {
  120.     int ret;
  121.     void __iomem *base;

  122.     base = ioremap(DA8XX_RTC_BASE, SZ_4K);//RTC寄存器基地址映射到内存中
  123.     if (WARN_ON(!base))
  124.         return -ENOMEM;

  125.     //写RTC寄存器,解除RTC的写保护
  126.     __raw_writel(0x83e70b13, base + 0x6c);
  127.     __raw_writel(0x95a4f1e0, base + 0x70);

  128.     iounmap(base);//使用虚拟地址访问物理空间,访问结束后,释放本次映射

  129.     ret = platform_device_register(&da8xx_rtc_device);//注册platform设备
  130.     if (!ret)/* Atleast on DA850, RTC is a wakeup source */
  131.         device_init_wakeup(&da8xx_rtc_device.dev, true);

  132.     return ret;
  133. }

  134. 2.调用class_create创建了一个类--rtc。我们知道类是一个设备的高层视图,他抽象出了底层的实现细节。
  135. //driversrtcclass.c
  136. static int __init rtc_init(void)
  137. {
  138.     rtc_class = class_create(THIS_MODULE, "rtc");//为sysfs文件系统创建一个类rtc_class
  139.     if (IS_ERR(rtc_class)) {
  140.         printk(KERN_ERR "%s: couldn't create classn", __FILE__);
  141.         return PTR_ERR(rtc_class);
  142.     }
  143.     rtc_class->suspend = rtc_suspend;
  144.     rtc_class->resume = rtc_resume;
  145.     rtc_dev_init();//为RTC设备动态分配一个设备号
  146.     rtc_sysfs_init(rtc_class);//设置属性
  147.     return 0;
  148. }
  149. //driversrtcrtc-dev.c
  150. void __init rtc_dev_init(void)
  151. {
  152.     int err;

  153.     err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");//动态分配设备号,赋值给rtc_devt
  154.     if (err < 0)
  155.         printk(KERN_ERR "%s: failed to allocate char dev regionn",__FILE__);
  156. }

  157. //driversrtcrtc-sysfs.c
  158. static struct device_attribute rtc_attrs[] = {
  159.     __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),
  160.     __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),
  161.     __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),
  162.     __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),
  163.     __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,rtc_sysfs_set_max_user_freq),
  164.     __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),
  165.     { },
  166. };

  167. void __init rtc_sysfs_init(struct class *rtc_class)
  168. {
  169.     //sysfs文件系统会根据这些属性创建属性文件
  170.     rtc_class->dev_attrs = rtc_attrs;//RTC属性
  171. }

  172. 3.注册RTC设备的platform driver
  173. //在目录driversrtcrtc-omap.c
  174. static struct rtc_class_ops omap_rtc_ops = {
  175.     .ioctl        = omap_rtc_ioctl,
  176.     .read_time    = omap_rtc_read_time,
  177.     .set_time    = omap_rtc_set_time,
  178.     .read_alarm    = omap_rtc_read_alarm,
  179.     .set_alarm    = omap_rtc_set_alarm,
  180. };

  181. static int omap_rtc_alarm;//RTC的alarm中断号
  182. static int omap_rtc_timer;//RTC的timer中断号

  183. static struct platform_driver omap_rtc_driver = {
  184.     .remove        = __exit_p(omap_rtc_remove),
  185.     .suspend    = omap_rtc_suspend,
  186.     .resume        = omap_rtc_resume,
  187.     .shutdown    = omap_rtc_shutdown,
  188.     .driver        = {
  189.         .name    = "omap_rtc",
  190.         .owner    = THIS_MODULE,
  191.     },
  192. };

  193. static int __init rtc_init(void)
  194. {
  195.     //注册RTC的platform driver驱动,platform的设备和驱动配对成功后,会调用omap_rtc_probe()函数
  196.     return platform_driver_probe(&omap_rtc_driver, omap_rtc_probe);
  197. }
  198. module_init(rtc_init);

  199. static int __init omap_rtc_probe(struct platform_device *pdev)
  200. {
  201.     struct resource        *res, *mem;
  202.     struct rtc_device    *rtc;
  203.     u8            reg, new_ctrl;

  204.     omap_rtc_timer = platform_get_irq(pdev, 0);//从platform_device资源中获得RTC的timer中断号
  205.     if (omap_rtc_timer <= 0) {
  206.         pr_debug("%s: no update irq?n", pdev->name);
  207.         return -ENOENT;
  208.     }

  209.     omap_rtc_alarm = platform_get_irq(pdev, 1);//从platform_device资源中获得RTC的alarm中断号
  210.     if (omap_rtc_alarm <= 0) {
  211.         pr_debug("%s: no alarm irq?n", pdev->name);
  212.         return -ENOENT;
  213.     }

  214.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//从platform_device资源中获得RTC的寄存器地址资源
  215.     if (!res) {
  216.         pr_debug("%s: RTC resource data missingn", pdev->name);
  217.         return -ENOENT;
  218.     }

  219.     mem = request_mem_region(res->start, resource_size(res), pdev->name);//申请内存资源
  220.     if (!mem) {
  221.         pr_debug("%s: RTC registers at %08x are not freen",
  222.             pdev->name, res->start);
  223.         return -EBUSY;
  224.     }

  225.     rtc_base = ioremap(res->start, resource_size(res));//将RTC寄存器物理地址映射到内存虚拟地址
  226.     if (!rtc_base) {
  227.         pr_debug("%s: RTC registers can't be mappedn", pdev->name);
  228.         goto fail;
  229.     }

  230.     rtc = rtc_device_register(pdev->name, &pdev->dev,&omap_rtc_ops, THIS_MODULE);//注册RTC设备
  231.     if (IS_ERR(rtc)) {
  232.         pr_debug("%s: can't register RTC device, err %ldn",pdev->name, PTR_ERR(rtc));
  233.         goto fail0;
  234.     }
  235.     platform_set_drvdata(pdev, rtc);//将RTC数据结构rtc_device保存在platform_device结构中的device字段中
  236.     dev_set_drvdata(&rtc->dev, mem);//将资源保存

  237.     //Disable RTC的alarm和timer中断,并且设置秒周期
  238.     rtc_write(0, OMAP_RTC_INTERRUPTS_REG);

  239.     /* clear old status */
  240.     reg = rtc_read(OMAP_RTC_STATUS_REG);//读RTC状态寄存器
  241.     if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {//davinci平台没有第7位的状态
  242.         pr_info("%s: RTC power up reset detectedn",pdev->name);
  243.         rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
  244.     }
  245.     
  246.     if (reg & (u8) OMAP_RTC_STATUS_ALARM)//如果有alarm中断产生
  247.         rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);//此位写1清除alarm中断状态

  248.     //申请中断并设置中断函数
  249.     if (request_irq(omap_rtc_timer, rtc_irq, IRQF_DISABLED,dev_name(&rtc->dev), rtc)) {
  250.         pr_debug("%s: RTC timer interrupt IRQ%d already claimedn",pdev->name, omap_rtc_timer);
  251.         goto fail1;
  252.     }
  253.     if ((omap_rtc_timer != omap_rtc_alarm) &&(request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED,dev_name(&rtc->dev), rtc))) {
  254.         pr_debug("%s: RTC alarm interrupt IRQ%d already claimedn",pdev->name, omap_rtc_alarm);
  255.         goto fail2;
  256.     }

  257.     reg = rtc_read(OMAP_RTC_CTRL_REG);//读RTC控制寄存器
  258.     if (reg & (u8) OMAP_RTC_CTRL_STOP)//查看RTC是否在运行
  259.         pr_info("%s: already runningn", pdev->name);

  260.     //采用24H模式,不自主补偿矫正时间,并且Disable split power.
  261.     new_ctrl = reg & ~(OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP|OMAP_RTC_CTRL_MODE_12_24);
  262.     new_ctrl |= OMAP_RTC_CTRL_STOP;//启动RTC计数

  263.     if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
  264.         pr_info("%s: split power moden", pdev->name);

  265.     if (reg != new_ctrl)
  266.         rtc_write(new_ctrl, OMAP_RTC_CTRL_REG);

  267.     return 0;

  268. fail2:
  269.     free_irq(omap_rtc_timer, NULL);
  270. fail1:
  271.     rtc_device_unregister(rtc);
  272. fail0:
  273.     iounmap(rtc_base);
  274. fail:
  275.     release_resource(mem);
  276.     return -EIO;
  277. }

  278. struct rtc_device *rtc_device_register(const char *name, struct device *dev,const struct rtc_class_ops *ops,struct module *owner)
  279. {
  280.     struct rtc_device *rtc;
  281.     int id, err;
  282.     
  283.     //处理一个idr的结构,idr在linux内核中指的就是整数ID管理机制,从本质上来说,idr是一种将整数ID号和特定指针关联在一起的机制。这里从内核中获取一个idr结构,并与id相关联。
  284.     if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
  285.         err = -ENOMEM;
  286.         goto exit;
  287.     }

  288.     mutex_lock(&idr_lock);
  289.     err = idr_get_new(&rtc_idr, NULL, &id);
  290.     mutex_unlock(&idr_lock);

  291.     if (err < 0)
  292.         goto exit;

  293.     id = id & MAX_ID_MASK;
  294.     
  295.     //分配RTC设备的结构体
  296.     rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
  297.     if (rtc == NULL) {
  298.         err = -ENOMEM;
  299.         goto exit_idr;
  300.     }
  301.     
  302.     //对结构体进行初始化
  303.     rtc->id = id;
  304.     rtc->ops = ops;//rtc的底层驱动操作函数
  305.     rtc->owner = owner;
  306.     rtc->max_user_freq = 64;
  307.     rtc->dev.parent = dev;//rtc_device设备的父设备是platform设备中的device结构
  308.     rtc->dev.class = rtc_class;//指向rtc的类
  309.     rtc->dev.release = rtc_device_release;

  310.     mutex_init(&rtc->ops_lock);
  311.     spin_lock_init(&rtc->irq_lock);
  312.     spin_lock_init(&rtc->irq_task_lock);
  313.     init_waitqueue_head(&rtc->irq_queue);

  314.     strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);//设置名称为omap_rtc
  315.     dev_set_name(&rtc->dev, "rtc%d", id);//设置RTC设备名称,生成设备节点就是这个名称
  316.     
  317.     //因为RTC设备本质来讲还是字符设备,所以这里初始化了字符设备相关的结构:设备号以及文件操作。
  318.     rtc_dev_prepare(rtc);//RTC字符设备注册的准备

  319.     err = device_register(&rtc->dev);//RTC设备注册,生成sysfs文件系统相关的诸多文件和目录,udev会根据生成的dev文件创建设备节点
  320.     if (err) {
  321.         put_device(&rtc->dev);
  322.         goto exit_kfree;
  323.     }

  324.     rtc_dev_add_device(rtc);//添加RTC的字符设备
  325.     rtc_sysfs_add_device(rtc);//为设备添加了一个闹钟属性
  326.     rtc_proc_add_device(rtc);//创建proc文件系统接口

  327.     dev_info(dev, "rtc core: registered %s as %sn",rtc->name, dev_name(&rtc->dev));
  328.     return rtc;

  329. exit_kfree:
  330.     kfree(rtc);

  331. exit_idr:
  332.     mutex_lock(&idr_lock);
  333.     idr_remove(&rtc_idr, id);
  334.     mutex_unlock(&idr_lock);

  335. exit:
  336.     dev_err(dev, "rtc core: unable to register %s, err = %dn",name, err);
  337.     return ERR_PTR(err);
  338. }

  339. //用户层文件操作函数接口
  340. static const struct file_operations rtc_dev_fops = {
  341.     .owner        = THIS_MODULE,
  342.     .llseek        = no_llseek,
  343.     .read        = rtc_dev_read,
  344.     .poll        = rtc_dev_poll,
  345.     .unlocked_ioctl    = rtc_dev_ioctl,
  346.     .open        = rtc_dev_open,
  347.     .release    = rtc_dev_release,
  348.     .fasync        = rtc_dev_fasync,
  349. };

  350. void rtc_dev_prepare(struct rtc_device *rtc)
  351. {
  352.     if (!rtc_devt)
  353.         return;

  354.     if (rtc->id >= RTC_DEV_MAX) {
  355.         pr_debug("%s: too many RTC devicesn", rtc->name);
  356.         return;
  357.     }

  358.     rtc->dev.devt = MKDEV(MAJOR(rtc_devt), rtc->id);//获得设备号

  359. #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
  360.     INIT_WORK(&rtc->uie_task, rtc_uie_task);
  361.     setup_timer(&rtc->uie_timer, rtc_uie_timer, (unsigned long)rtc);
  362. #endif

  363.     cdev_init(&rtc->char_dev, &rtc_dev_fops);
  364.     rtc->char_dev.owner = rtc->owner;
  365. }

  366. void rtc_dev_add_device(struct rtc_device *rtc)
  367. {
  368.     //添加字符设备
  369.     if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
  370.         printk(KERN_WARNING "%s: failed to add char device %d:%dn",rtc->name, MAJOR(rtc_devt), rtc->id);
  371.     else
  372.         pr_debug("%s: dev (%d:%d)n", rtc->name,MAJOR(rtc_devt), rtc->id);
  373. }

  374. void rtc_sysfs_add_device(struct rtc_device *rtc)
  375. {
  376.     int err;

  377.     /* not all RTCs support both alarms and wakeup */
  378.     if (!rtc_does_wakealarm(rtc))
  379.         return;
  380.     
  381.     err = device_create_file(&rtc->dev, &dev_attr_wakealarm);
  382.     if (err)
  383.         dev_err(rtc->dev.parent,"failed to create alarm attribute, %dn", err);
  384. }

  385. 四、用户层应用
  386. 1.读时间
  387. 用户打开设备后,通过ioctl命令发出读时间操作,进而调用interface.c中的rtc_read_time()
  388. int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
  389. {
  390.     int err;

  391.     err = mutex_lock_interruptible(&rtc->ops_lock);
  392.     if (err)
  393.         return err;

  394.     if (!rtc->ops)
  395.         err = -ENODEV;
  396.     else if (!rtc->ops->read_time)
  397.         err = -EINVAL;
  398.     else {
  399.         memset(tm, 0, sizeof(struct rtc_time));
  400.         err = rtc->ops->read_time(rtc->dev.parent, tm);//调用底层驱动函数omap_rtc_read_time()
  401.     }

  402.     mutex_unlock(&rtc->ops_lock);
  403.     return err;
  404. }

  405. static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
  406. {
  407.     /* we don't report wday/yday/isdst ... */
  408.     local_irq_disable();
  409.     rtc_wait_not_busy();
  410.     //读RTC寄存器
  411.     tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG);
  412.     tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG);
  413.     tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG);
  414.     tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG);
  415.     tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG);
  416.     tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG);

  417.     local_irq_enable();

  418.     bcd2tm(tm);
  419.     return 0;
  420. }

  421. 2.写时间
  422. int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
  423. {
  424.     int err;

  425.     err = rtc_valid_tm(tm);
  426.     if (err != 0)
  427.         return err;

  428.     err = mutex_lock_interruptible(&rtc->ops_lock);
  429.     if (err)
  430.         return err;

  431.     if (!rtc->ops)
  432.         err = -ENODEV;
  433.     else if (rtc->ops->set_time)
  434.         err = rtc->ops->set_time(rtc->dev.parent, tm);
  435.     else if (rtc->ops->set_mmss) {
  436.         unsigned long secs;
  437.         err = rtc_tm_to_time(tm, &secs);
  438.         if (err == 0)
  439.             err = rtc->ops->set_mmss(rtc->dev.parent, secs);//调用omap_rtc_set_time
  440.     } else
  441.         err = -EINVAL;

  442.     mutex_unlock(&rtc->ops_lock);
  443.     return err;
  444. }

  445. static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
  446. {
  447.     if (tm2bcd(tm) < 0)
  448.         return -EINVAL;
  449.     local_irq_disable();
  450.     rtc_wait_not_busy();

  451.     rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG);
  452.     rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG);
  453.     rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG);
  454.     rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG);
  455.     rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG);
  456.     rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG);

  457.     local_irq_enable();

  458.     return 0;
  459. }
阅读(3490) | 评论(0) | 转发(1) |
0

上一篇:linux 内核分析之list_head

下一篇:i2C调试

给主人留下些什么吧!~~