Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1052264
  • 博文数量: 166
  • 博客积分: 10217
  • 博客等级: 上将
  • 技术积分: 2133
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-09 19:45
文章分类

全部博文(166)

文章存档

2012年(3)

2011年(7)

2010年(18)

2009年(59)

2008年(79)

我的朋友

分类: LINUX

2008-04-25 18:00:38

首先RTC设备是一种片上设备, platform_device来表示 该设备(platform_deviceRTC对象)在设备的初始化过程中就已经注册进了系统(可以参考2410soc上的设备的驱动流程(RTC, watchdog)), 因此我们在RTC驱动的初始化里把RTC驱动注册到系统后,系统会probe到这个RTC设备,最后调用我们RTC驱动的probe函数.

下面就重点分析2410RTC驱动.

首先是初始化函数和退出函数:

static void __init s3c2410_rtc_init(void)

{

    printk(banner);

 

     /*

* 这就把这个RTC驱动注册进了系统,同时系统会查找匹配的RTC设备,并调用

* s3c2410_rtcdrvprobe函数.

*/

    return platform_driver_register(&s3c2410_rtcdrv);

}

Static void __exit s3c2410_rtc_exit(void)

{

    /*卸载这个RTC驱动, 之后RTC设备就无法使用了*/

    platform_driver_unregister(&s3c2410_rtcdrv); 

}

static struct platform_driver s3c2410_rtcdrv = {

      .probe    = s3c2410_rtc_probe,

      .remove   = s3c2410_rtc_remove,

      .suspend  = s3c2410_rtc_suspend,

      .resume   = s3c2410_rtc_resume,

      .driver    = {

           .name = “s3c2410-rtc”,  //这个字符串必须和RTC设备的定义一样,系统才会匹配正确.

           .owner = THIS_MODULE,

       },

};

当系统把RTC设备注册到系统后,它就开始查找相应总线上的所有设备, 并与这个驱动比较, 如果系统找到匹配的RTC设备就会调用RTC驱动的s3c2410_rtc_probe函数, 注意RTC设备实在系统初始化时就注册进了系统.

static int s3c2410_rtc_probe(struct platform_device *pdev /*rtc设备*/)

{

    struct resource *res;

       int ret;

 

       pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);

 

       /*

* 获取设备的tick中断资源, 通过查看platform_get_irq可知,实际上通过查找pdev的资源获得的, * pdev的资源是在构建platform_device对象的时候就指定好的, 可到Devs.c中查看

*/

       s3c2410_rtc_tickno = platform_get_irq(pdev, 1);

       if (s3c2410_rtc_tickno < 0) {

              dev_err(&pdev->dev, "no irq for rtc tick\n");

              return -ENOENT;

       }

 

       /*

* 获取设备的rtc中断资源, 通过查看platform_get_irq可知,实际上通过查找pdev的资源获得的, * pdev的资源是在构建platform_device对象的时候就指定好的, 可到Devs.c中查看

*/

       s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);

       if (s3c2410_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",

               s3c2410_rtc_tickno, s3c2410_rtc_alarmno);

 

       /*

* 获取设备的memory资源, 通过查看platform_get_irq可知,实际上通过查找pdev的资源获得的, * pdev的资源是在构建platform_device对象的时候就指定好的, 可到Devs.c中查看

*/

       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);

       if (res == NULL) {

              dev_err(&pdev->dev, "failed to get memory region resource\n");

              return -ENOENT;

       }

   

    /*

     * 查看指定的memory是否可以使用.

     */

       s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,

                                 pdev->name);

 

       if (s3c2410_rtc_mem == NULL) {

              dev_err(&pdev->dev, "failed to reserve memory region\n");

              ret = -ENOENT;

              goto exit_err;

       }

   

    /*

* 重映射指定的内存区域,即把原来的物理地址映射到相应的虚拟地址, 这样以后就可以用这个* 虚拟地址直接访问原来的物理地址了, 这里是映射RTC的寄存器地址区间.

*/

       s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);

       if (s3c2410_rtc_base == NULL) {

              dev_err(&pdev->dev, "failed ioremap()\n");

              ret = -EINVAL;

              goto exit_err;

       }

 

       s3c2410_rtc_mem = res;

       pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);

 

      pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));

 

       /*正确初始化RTC设备 */

       s3c2410_rtc_enable(pdev, 1);

 

      pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));

   

    /*设置好设备的频率*/

       s3c2410_rtc_setfreq(s3c2410_rtc_freq);

 

       /* 注册RTC设备的操作函数, 以后对该设备的访问将调用这些操作函数*/

       register_rtc(&s3c2410_rtcops);

       return 0;

 

 exit_err:

       dev_err(&pdev->dev, "error %d during initialisation\n", ret);

 

       return ret;

}

阅读(1930) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~