linux-rtc

迷霧綠洲發表於2019-02-18

RTC(Real-time clock)本身是一個時鐘,用來記錄真實時間,當軟體系統關機後保留系統時間並繼續進行計時,系統重新開啟後在將時間同步進軟體系統。
硬體結構
可以看到,主要電池供電和系統供電雙供電電路和晶振電路。
1.雙供電系統主要作用是系統供電是整體由系統供電,如果是可供電電池,電池還可以充電。系統關機後使用電池僅僅對rtc 部分進行供電,維持記錄的時間不丟失,系統時間還能夠繼續進行計時,防止系統重啟後記錄的確實上次異常關機的時間省去了系統重啟後設定系統時間的步驟。
2.晶振一般採用32.768kHz,至於為什麼是這個古怪的頻率,主要是由於32768是2的15次方。計時頻率越高時間誤差越小,但是由於舊系統一般也只有16位,不像現在都是64位機,所以計數歸零定義為秒進位,也就是秒增加1就是32768,其實這是一個效能個功耗成本的中和。
rtc 內部計時的結構:
rtc 內部暫存器結構
以上就是一般的rtc 的內部暫存器的結構圖,一般有天、時、分、秒暫存器。但是有些晶片內部做了年月日自動計算,閏年閏月識別的功能,這樣就不需要軟體將天暫存器計算成年月日,但由於這樣做會增加些許複雜度一般的小公司產品不敢幹,畢竟硬體錯了不好補救了,做好沒獎勵做錯反而給自己找麻煩的心態
在這裡插入圖片描述
以上是三星的6410的rtc 暫存器設計,他就做了內部年月日分開。
驅動設計:
1.驅動需要呼叫一個註冊函式,系統就知道你使用了硬體rtc了。

	rtc = rtc_device_register(rtc_platform_info->dev_name,\
			&pdev->dev, &fh_rtcops,
				  THIS_MODULE);

2.實現rtc 操作需要的幾個函式

static const struct rtc_class_ops fh_rtcops = {
	.open		= fh_rtc_open,
	.release	= fh_rtc_release,
	.read_time	= fh_rtc_gettime_nosync,
	.set_time	= fh_rtc_settime,
	.read_alarm	= fh_rtc_getalarm,
	.set_alarm	= fh_rtc_setalarm,
	.alarm_irq_enable = fh_rtc_irq_enable,
};

最重要的函式是

	.read_time	= fh_rtc_gettime_nosync,
	.set_time	= fh_rtc_settime,

像alarm 這樣的功能也是可以不支援的,或者使用軟體進行模擬。
讀取時間的介面函式型別:
rtc_tm 中存放的時分秒 年月日資訊,驅動需要把這些時間資訊給這個指標結構體,然後返回給呼叫這個地址。

static int fh_rtc_gettime_nosync(struct device *dev, struct rtc_time *rtc_tm)
{
	unsigned int temp;

	temp = fh_rtc_get_hw_sec_data(TIME_FUNC);
	rtc_time_to_tm(temp, rtc_tm);
	RTC_PRINT_DBG("rtc read date:0x%x\n", temp);
	return 0;
}

設定時間的介面函式型別:
同樣tm 結構體中存放的時分秒 年月日,驅動需要把這些時間資訊存放到硬體,硬體IP從這個時間點繼續計時。

static int fh_rtc_settime(struct device *dev, struct rtc_time *tm)
{
	struct rtc_time rtc_tm_read0;
	unsigned int status;
	unsigned int loop_count;
	struct platform_device *pdev = to_platform_device(dev);
	struct fh_rtc_controller *fh_rtc = platform_get_drvdata(pdev);
	int cnt, ret, read_count = 0;

	RTC_PRINT_DBG("rtc write %d-%d-%d %d:%d:%d\n",
		 tm->tm_year + 1900,
		 tm->tm_mon + 1,
		 tm->tm_mday,
		 tm->tm_hour,
		 tm->tm_min,
		 tm->tm_sec);

這個驅動就正式完成了。