日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux下的RTC子系统

發(fā)布時間:2024/9/21 linux 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux下的RTC子系统 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

版權所有,轉載必須說明轉自?http://my.csdn.net/weiqing1981127?

?

實時時鐘的作用主要是為操作系統(tǒng)提供一個可靠的時間,并在斷電下,RTC時鐘也可以通過電池供電一直運行下去。實時時鐘驅動也有一個子系統(tǒng),叫做RTC子系統(tǒng),其源代碼目錄是/driver/rtc/,在這個目錄下有一個rtc核心代碼區(qū),主要是Rtc-dev.cRtc-sysfs.cRtc-proc.c三個文件,其中Rtc-dev.c主要是增加一個字符設備的作用,例如用戶層的ioctl命令就是通過訪問該文件;Rtc-sysfs.c主要是創(chuàng)建device_attribute機制;Rtc-proc.c文件主要創(chuàng)建/proc屬性文件。另外對于RTC設備。內核中的說明文檔在/Document/Rtc.txt

我們這里講的是基于mini2440RTC驅動,其對應驅動是/driver/rtc/Rtc-s3c.c

?

RTC驅動源碼路徑在/driver/rtc/Rtc-s3c.c

查看/driver/rtc/Makefile

rtc-core-$(CONFIG_RTC_INTF_DEV)?????? += rtc-dev.o

rtc-core-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o

rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o

obj-$(CONFIG_RTC_DRV_S3C)? += rtc-s3c.o

查看/driver/rtc//Konfig

config RTC_INTF_DEV

?????? boolean "/dev/rtcN (character devices)"

?????? default RTC_CLASS

config RTC_INTF_PROC

?????? boolean "/proc/driver/rtc (procfs for rtc0)"

?????? depends on PROC_FS

config RTC_INTF_SYSFS

?????? boolean "/sys/class/rtc/rtcN (sysfs)"

?????? depends on SYSFS

?????? default RTC_CLASS

config RTC_DRV_S3C

?????? tristate "Samsung S3C series SoC RTC"

?????? depends on ARCH_S3C2410

所以配置內核make menuconfig?時,需要選中這幾項。

?

現(xiàn)在先來看如何移植,下面就看移植代碼了,因為通過查看"s3c2410-rtc"名知道,在內核Devs.c文件中已經定義如下代碼

struct platform_device s3c_device_rtc = {

?????? .name???????????? ? = "s3c2410-rtc",

?????? .id?????????? ? = -1,

?????? .num_resources???? ? = ARRAY_SIZE(s3c_rtc_resource),

?????? .resource ? = s3c_rtc_resource,

};

所以只要在mach-mini2440.c這個mini2440開發(fā)板的BSP中把這個s3c_device_rtc加入到mini2440_devices數(shù)組

static struct platform_device *mini2440_devices[] __initdata = {

?????? ……

?????? & s3c_device_rtc, //添加

};

這樣配置完后,進行make zImage生成zImage內核鏡像。

?

下面大致說說/driver/rtc/Rtc-s3c.c

static struct platform_driver s3c2410_rtc_driver = {

?????? .probe??????????? = s3c_rtc_probe,

?????? .remove????????? = __devexit_p(s3c_rtc_remove),

?????? .suspend? = s3c_rtc_suspend,

?????? .resume????????? = s3c_rtc_resume,

?????? .driver??????????? = {

????????????? .name????? = "s3c2410-rtc",? //驅動名

????????????? .owner??? = THIS_MODULE,

?????? },

};

跟蹤下探測函數(shù)probe

static int __devinit s3c_rtc_probe(struct platform_device *pdev)

{

?????? struct rtc_device *rtc;

?????? struct resource *res;

?????? int ret;

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

?????? s3c_rtc_tickno = platform_get_irq(pdev, 1);? //獲取滴答中斷號

?????? if (s3c_rtc_tickno < 0) {

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

????????????? return -ENOENT;

?????? }

?????? s3c_rtc_alarmno = platform_get_irq(pdev, 0);? //獲取鬧鐘中斷號

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

????????????? ?s3c_rtc_tickno, s3c_rtc_alarmno);

?????? res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //獲取資源

?????? if (res == NULL) {

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

????????????? return -ENOENT;

?????? }

?????? s3c_rtc_mem = request_mem_region(res->start,

?????????????????????????????????? ?res->end-res->start+1,

?????????????????????????????????? ?pdev->name);? //申請資源

?????? if (s3c_rtc_mem == NULL) {

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

????????????? ret = -ENOENT;

????????????? goto err_nores;

?????? }

?????? s3c_rtc_base = ioremap(res->start, res->end - res->start + 1); //物理地址到虛擬地址的映射

?????? if (s3c_rtc_base == NULL) {

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

????????????? ret = -EINVAL;

????????????? goto err_nomap;

?????? }

?????? s3c_rtc_enable(pdev, 1);

????? pr_debug("s3c2410_rtc: RTCCON=%02x\n",

????????????? ?readb(s3c_rtc_base + S3C2410_RTCCON));

?????? s3c_rtc_setfreq(&pdev->dev, 1);???? //設置頻率

?????? device_init_wakeup(&pdev->dev, 1);?

?????? rtc = rtc_device_register("s3c", &pdev->dev, &s3c_rtcops,

??????????????????????????? ? THIS_MODULE);? //注冊rtc設備

?????? if (IS_ERR(rtc)) {

????????????? dev_err(&pdev->dev, "cannot attach rtc\n");

????????????? ret = PTR_ERR(rtc);

????????????? goto err_nortc;

?????? }

?????? rtc->max_user_freq = 128;

?????? platform_set_drvdata(pdev, rtc);

?????? return 0;

?err_nortc:

?????? s3c_rtc_enable(pdev, 0);

?????? iounmap(s3c_rtc_base);

?err_nomap:

?????? release_resource(s3c_rtc_mem);

?err_nores:

?????? return ret;

}

我們主要關注注冊rtc設備的時傳入參數(shù)s3c_rtcops

static const struct rtc_class_ops s3c_rtcops = {

?????? .open???????????? = s3c_rtc_open, ?//打開

?????? .release??? = s3c_rtc_release,? //關閉

?????? .read_time????? = s3c_rtc_gettime,? //獲取當前時間

?????? .set_time = s3c_rtc_settime,? //設置當前時間

?????? .read_alarm???? = s3c_rtc_getalarm,? //獲取鬧鐘時間

?????? .set_alarm?????? = s3c_rtc_setalarm,? //設置鬧鐘時間

?????? .irq_set_freq?? = s3c_rtc_setfreq,? //設置頻率

?????? .irq_set_state? = s3c_rtc_setpie,

?????? .proc?????? ??????? = s3c_rtc_proc,

};

對于struct rtc_class_ops結構體中的成員,其每個函數(shù)的具體實現(xiàn),都是跟自己使用的設備相關的,比如我們這樣使用的是S3C2410,那么在struct rtc_class_ops里定義的函數(shù)使用的就是三星平臺下的資源。如果要在其他平臺下使用,那么就是修改這里的struct rtc_class_ops操作函數(shù)。

rtc_device_register中,會調用rtc_dev_prepare函數(shù),而rtc_dev_prepare函數(shù)會把rtc_dev_fops注冊進內核,而rtc_dev_fops就是我們在增加字符設備的文件Rtc-dev.c中定義的file_operations操作函數(shù),這樣注冊rtc設備其實就表示用戶可以訪問通過訪問file_operations函數(shù)來達到訪問rtc設備的目的。

?

在我們的/driver/rtc/Class.c中的模塊加載函數(shù)中調用rtc_sysfs_init來完成注冊sys文件系統(tǒng),而rtc_sysfs_init就是我們在Rtc-sysyfs.c中定義的,跟蹤下rtc_sysfs_ini

void __init rtc_sysfs_init(struct class *rtc_class)

{

?????? rtc_class->dev_attrs = rtc_attrs;

}

然后看看rtc_attrs屬性

static struct device_attribute rtc_attrs[] = {

?????? __ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL),

?????? __ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL),

?????? __ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL),

?????? __ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL),

?????? __ATTR(max_user_freq, S_IRUGO | S_IWUSR, rtc_sysfs_show_max_user_freq,

???????????????????? rtc_sysfs_set_max_user_freq),

?????? __ATTR(hctosys, S_IRUGO, rtc_sysfs_show_hctosys, NULL),

?????? { },

};

好了,這就是給用戶的第二個操作接口,我們來看看這些屬性的showstore屬性是不是真的能調用在Rtc-s3c.c中的RTC操作函數(shù)s3c_rtcops。我們把注意力放在timeshow屬性函數(shù)rtc_sysfs_show_time

static ssize_t rtc_sysfs_show_time(struct device *dev, struct device_attribute *attr,

????????????? char *buf)

{

?????? ssize_t retval;

?????? struct rtc_time tm;

?????? retval = rtc_read_time(to_rtc_device(dev), &tm);? //調用封裝的讀時間函數(shù)

?????? if (retval == 0) {

????????????? retval = sprintf(buf, "%02d:%02d:%02d\n",

???????????????????? tm.tm_hour, tm.tm_min, tm.tm_sec);

?????? }

?????? return retval;

}

跟蹤rtc_read_time函數(shù)

int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)

{

?????? int err;

?????? err = mutex_lock_interruptible(&rtc->ops_lock);

?????? if (err)

????????????? return err;

?????? if (!rtc->ops)

????????????? err = -ENODEV;

?????? else if (!rtc->ops->read_time)

????????????? err = -EINVAL;

?????? else {

????????????? memset(tm, 0, sizeof(struct rtc_time));

????????????? err = rtc->ops->read_time(rtc->dev.parent, tm);? //調用s3c_rtcops操作中讀時間函數(shù)

?????? }

?????? mutex_unlock(&rtc->ops_lock);

?????? return err;

}

好了,我已經跟蹤到我們需要找的信息了,這樣我們就能證實在Rtc-sysyfs.c中定義的設備的showstore屬性是真的能調用在Rtc-s3c.c中的RTC操作函數(shù)s3c_rtcops的。

?

RTC驅動測試

Linux?中更改時間的方法一般使用date?命令,為了把S3C2440?內部帶的時鐘與linux?系統(tǒng)時鐘同步,

一般使用hwclock?命令,下面是它們的使用方法:

(1) date -s 042916352007 #設置時間為?2007-04-29 16:34

(2) hwclock -w #把剛剛設置的時間存入S3C2440?內部的RTC

(3).開機時使用hwclock -s?命令可以恢復?linux?系統(tǒng)時鐘為RTC,?一般把該語句放入

/etc/init.d/rcS?文件自動執(zhí)行。

?

另外需要注意的是:有時候你會發(fā)現(xiàn)自己的實時時鐘會在走時一段時間后不準,這注意是設計時鐘電路時匹配電容的取值不對,電容公式是C1*C2/(C1+C2)+C3,其中C1C2是兩個并聯(lián)電容,C3是寄生電容,C3一般取3-5PF

總結

以上是生活随笔為你收集整理的Linux下的RTC子系统的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。