歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> S3C6410的RTC在Linux中的驅動

S3C6410的RTC在Linux中的驅動

日期:2017/3/1 10:22:37   编辑:Linux編程

如果對RTC硬件不熟悉的話,可以看這篇《S3C6410硬件RTC(實時時鐘)》見 http://www.linuxidc.com/Linux/2012-05/60747.htm,講述了硬件有關的內容。


1、先從整體上做些分析,大致看了下linux2.6.28\drivers\rtc文件中的kconfig和Makefile文件,在Makefile文件中有如下內容:

ifeq ($(CONFIG_RTC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif


obj-$(CONFIG_RTC_LIB) += rtc-lib.o
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
rtc-core-y := class.o interface.o


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_RX8581)+= rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o

應該能從中看出,rtc的驅動大致和那些文件有關,再看對應的kconfig文件,可以看出對應文件的用途,我們就不列出對應的kconfig文件了,因為內容太多了。

2、現在的RTC驅動架構,當然看一下Rtc.txt (linux2.6.28\documentation)文件,對我們理解此架構是很有幫助的,列出部分:

New portable "RTC Class" drivers: /dev/rtcN
--------------------------------------------
Because Linux supports many non-ACPI and non-PC platforms, some of which have more than one RTC style clock, it needed a more portable solution than expecting a single battery-backed MC146818 clone on every system. Accordingly, a new "RTC Class" framework has been defined.講述了新架構建立的原因。

It offers three different userspace interfaces:講述了與用戶空間的三種接口
* /dev/rtcN ... much the same as the older /dev/rtc interface
* /sys/class/rtc/rtcN ... sysfs attributes support readonly access to some RTC attributes.
* /proc/driver/rtc ... the first RTC (rtc0) may expose itself using a procfs interface. More information is (currently) shown here than through sysfs.


The RTC Class framework supports a wide variety of RTCs, ranging from those integrated into embeddable system-on-chip (SOC) processors to discrete chips using I2C, SPI, or some other bus to communicate with the host CPU. There's even support for PC-style RTCs ... including the features exposed on newer PCs through ACPI.

這種分類的架構,支持更廣闊的RTC設備。
The new framework also removes the "one RTC per system" restriction. For example, maybe the low-power battery-backed RTC is a discrete I2C chip, but a high functionality RTC is integrated into the SOC. That system might read the system clock from the discrete RTC, but use the integrated one for all other tasks, because of its greater functionality.
The ioctl() calls supported by /dev/rtc are also supported by the RTC class framework. However, because the chips and systems are not standardized, some PC/AT functionality might not be provided. And in the same way, some newer features -- including those enabled by ACPI -- are exposed by the RTC class framework, but can't be supported by the older driver.


3、有關文件的作用

與RTC核心有關的文件有:


(1)、/drivers/rtc/class.c 這個文件向linux設備驅動模型核心注冊了一個RTC類,然後向具體的驅動程序提供了rtc_device_register用於注冊和rtc_device_unregister用於注銷設備。還實現的rtc類設備的注冊。

列出部分源碼:

static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
if (IS_ERR(rtc_class)) {
printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
return PTR_ERR(rtc_class);
}
rtc_class->suspend = rtc_suspend;
rtc_class->resume = rtc_resume;
rtc_dev_init();
rtc_sysfs_init(rtc_class);
return 0;
}
static void __exit rtc_exit(void)
{
rtc_dev_exit();
class_destroy(rtc_class);
}

subsys_initcall(rtc_init);
module_exit(rtc_exit);
(2)、/drivers/rtc/rtc-dev.c 這個文件定義了頂層基本的字符設備文件操作函數,如:open,read等,有個結構體,如下所示:

static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl= rtc_dev_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
};此結構體用於字符設備注冊是使用。
(3)、/drivers/rtc/interface.c 這個文件主要提供了用戶程序與RTC驅動的接口函數,用戶程序一般通過ioctl與RTC驅動交互,這裡定義了每個ioctl命令需要調用的函數。看函數名,也能猜出大概:

EXPORT_SYMBOL_GPL(rtc_set_time);

EXPORT_SYMBOL_GPL(rtc_read_alarm);


(4)、/drivers/rtc/rtc-sysfs.c 看名字就很清楚,與sysfs有關,看注釋:

/*
* RTC subsystem, sysfs interface
*/
(5)、/drivers/rtc/rtc-proc.c 與proc文件系統有關,同樣:

/*
* RTC subsystem, proc interface
*/

6)、/drivers/rtc/rtc-lib.c 主要和時間轉化有關,列出一個函數,看函數名就能看出大概,

int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
{
return rtc_ydays[LEAP_YEAR(year)][month] + day-1;
}

(7)、/drivers/rtc/hctosys.c 和系統時鐘有關,就一個函數,

/*
* RTC subsystem, initialize system time on startup
*/

static int __init rtc_hctosys(void)


(8)、/include/linux/rtc.h 定義了與RTC有關的數據結構,如下所示:

structrtc_class_ops { 用於具體設備的驅動接口
int (*open)(struct device *);
void (*release)(struct device *);
int (*ioctl)(struct device *, unsigned int, unsigned long);
int (*read_time)(struct device *, struct rtc_time *);
int (*set_time)(struct device *, struct rtc_time *);
int (*read_alarm)(struct device *, struct rtc_wkalrm *);
int (*set_alarm)(struct device *, struct rtc_wkalrm *);
int (*proc)(struct device *, struct seq_file *);
int (*set_mmss)(struct device *, unsigned long secs);
int (*irq_set_state)(struct device *, int enabled);
int (*irq_set_freq)(struct device *, int freq);
int (*read_callback)(struct device *, int data);
};
struct rtc_device
{
struct device dev;
struct module *owner;


int id;
char name[RTC_DEVICE_NAME_SIZE];


const struct rtc_class_ops *ops;
struct mutex ops_lock;


struct cdev char_dev;
unsigned long flags;


unsigned long irq_data;
spinlock_t irq_lock;
wait_queue_head_t irq_queue;
struct fasync_struct *async_queue;


struct rtc_task *irq_task;
spinlock_t irq_task_lock;
int irq_freq;
int max_user_freq;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
struct work_struct uie_task;
struct timer_list uie_timer;
/* Those fields are protected by rtc->irq_lock */
unsigned int oldsecs;
unsigned int irq_active:1;
unsigned int stop_uie_polling:1;
unsigned int uie_task_active:1;
unsigned int uie_timer_active:1;
#endif
};

4、因為主要關心的是三星架構的s3c6410的RTC,與之有關的文件是Rtc-s3c.c (linux2.6.28\drivers\rtc)。這個文件實現了具體rtc設備的驅動。同樣rtc設備在系統中也作為平台設備存在,所以這個文件中也包含了平台設備相關的內容。如下所示:

提供給上層的驅動函數。

static const struct rtc_class_ops s3c_rtcops = {
.open = s3c_rtc_open,
.release = s3c_rtc_release,
.ioctl = s3c_rtc_ioctl,
.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,
};

平台相關:

static struct platform_driver s3c2410_rtc_driver = {
.probe = s3c_rtc_probe,
.remove = s3c_rtc_remove,
.suspend = s3c_rtc_suspend,
.resume = s3c_rtc_resume,
.driver = {
.name = "s3c2410-rtc",
.owner = THIS_MODULE,
},
};
static char __initdata banner[] = "S3C24XX RTC, (c) 2004,2006 Simtec Electronics\n";
static int __init s3c_rtc_init(void)
{
printk(banner);
return platform_driver_register(&s3c2410_rtc_driver);
}
static void __exit s3c_rtc_exit(void)
{
platform_driver_unregister(&s3c2410_rtc_driver);
}
module_init(s3c_rtc_init);
module_exit(s3c_rtc_exit);

Copyright © Linux教程網 All Rights Reserved