2410下rtc驱动分析

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

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

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

static void __init s3c2410_rtc_init(void)

{

printk(banner);

/*

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

* s3c2410_rtcdrv的probe函数.

*/

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;

}

你可能感兴趣的:(分析)