TIMER DEVICE DRIVER 
(SYSTEM TIMER, RTC, WATCHDOG) 
1
系統宣告(arch/arm/mach-ixp4xx) 
MACHINE_START(IXDP425, "Intel IXDP425 Development Platform") 
/* Maintainer: MontaVista Software, Inc. */ 
.phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, 
.io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 
0xfffc, 
.map_io = ixp4xx_map_io, 
.init_irq = ixp4xx_init_irq, 
.timer = &ixp4xx_timer, 
.boot_params = 0x0100, 
.init_machine = ixdp425_init, 
MACHINE_END 
2
struct sys_timer armcpu_timer __initdata = 
{ 
.init = armcpu_timer_init, 
.offset = armcpu_gettimeoffset, 
.resume = armcpu_timer_setup, 
}; 
3 
Timer 資料結構宣告
static void armcpu_timer_setup(void) 
{ 
armcpu_timer_set_reload(USED_TIMER, APB_CLK/HZ); 
armcpu_timer_set_counter(USED_TIMER, APB_CLK/HZ); 
……………… 
} 
void __init armcpu_timer_init(void) 
{ 
armcpu_timer_setup(); 
setup_irq(IRQ_TIMER1, &armcpu_timer_irq); 
} 
4 
Timer Initiailzation
static irqreturn_t 
armcpu_timer_interrupt(int irq, void *dev_id) 
{ 
write_seqlock(&xtime_lock); 
timer_tick(); 
write_sequnlock(&xtime_lock); 
return IRQ_HANDLED; 
} 
5 
Timer interrupt
unsigned long armcpu_gettimeoffset (void) 
{ 
unsigned long volatile offsetticks; 
offsetticks = SET_COUNTER-armcpu_timer_get_counter(USED_TIMER); 
if ( *(volatile unsigned int *)(CPE_TIMER1_VA_BASE+TIMER_INTR_STATE) ) { 
offsetticks = SET_COUNTER-armcpu_timer_get_counter(USED_TIMER); 
offsetticks += SET_COUNTER; 
} 
offsetticks = offsetticks / (APB_CLK / 1000000); // tansfer ticks to usec 
return offsetticks; 
} 
6 
gettimeoffset callback 
#include <sys/time.h> 
int gettimeofday(struct timeval *tv, struct timezone *tz); 
struct timeval { 
time_t tv_sec; /* seconds */ 
suseconds_t tv_usec; /* microseconds */ 
};
RTC DRIVER 
7
簡單來看它就是一個時鐘,通常它只能計 
時至秒。 
大都規格是在一年內誤差為10幾秒。 
它需要電池供電,上電一輩子需要有一次 
啓動的動作,斷電後則時間停止。 
以PC為例系統時間(用date指令,或者任何 
API取得的時間)在開機時會讀入RTC時間並 
設定時間,關機時會將系統時間設回RTC。 
其應用層設定的程式為hwclock,使用的 
device node 為/dev/rtc (10, 135)。 
8 
RTC (Real Time Clock)
Usage: hwclock [-r|--show] [-s|--hctosys] [-w|--systohc] [-l|-- 
localtime] [-u|--utc] [-f FILE] 
Query and set hardware clock (RTC) 
Options: 
-r Show hardware clock time 
-s Set system time from hardware clock 
-w Set hardware clock to system time 
-u Hardware clock is in UTC 
-l Hardware clock is in local time 
-f FILE Use specified device (e.g. /dev/rtc2) 
9 
hwclock usage
RTC Device Driver Example 
可架構在misc之下 
主要是支援兩個ioctl command 
1) RTC_RD_TIME 讀取時間 
2) RTC_SET_TIME 設定時間 
struct rtc_time { 
int tm_sec; 
int tm_min; 
int tm_hour; 
int tm_mday; 
int tm_mon; 
int tm_year; 
int tm_wday; 
int tm_yday; 
int tm_isdst; 
}; 
10
Module Initialize Example 
static struct file_operations rtc_fops = { 
owner:THIS_MODULE, 
ioctl:rtc_ioctl, 
open:rtc_open, 
release:rtc_release, 
}; 
static struct miscdevice rtc_dev = { 
RTC_MINOR, 
"rtc", 
&rtc_fops 
}; 
static int __init rtc_init(void) 
{ 
misc_register(&rtc_dev); 
return 0; 
}
Ioctl Example 
static int 
rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) 
{ 
struct rtc_time rtc_tm; 
switch (cmd) { 
case RTC_RD_TIME: /* Read the time/date from RTC */ 
get_rtc_time(&rtc_tm); 
return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ? -EFAULT : 0; 
case RTC_SET_TIME: /* Set the RTC */ 
if (copy_from_user(&rtc_tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) 
return -EFAULT; 
// set to hardware RTC with the time 
return 0; 
default: 
return -EINVAL; 
} 
}
新RTC Driver 
Device node is put on /dev/misc directory. 
Up to 16 RTC node, from rtc0 
The major number is 254. 
The minor number is from 0. 
These are the same IOCTL command with the 
old type RTC driver. 
More features.
RTC Class Structure 
struct rtc_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); 
int (*alarm_irq_enable)(struct device *, unsigned int enabled); 
int (*update_irq_enable)(struct device *, unsigned int enabled); 
};
RTC Time structure 
struct rtc_time { 
int tm_sec; 
int tm_min; 
int tm_hour; 
int tm_mday; 
int tm_mon; 
int tm_year; 
int tm_wday; 
int tm_yday; 
int tm_isdst; 
};
New RTC Driver Example 
static int rtc_read_time(struct device *dev, struct rtc_time *tm) 
{ 
……………. 
} 
static int rtc_set_time(struct device *dev, struct rtc_time *tm) 
{ 
………….. 
} 
static struct rtc_class_ops rtc_ops = { 
.read_time = rtc_read_time, 
.set_time = rtc_set_time, 
}; 
static struct rtc_device *rtc; 
static int rtc_module_init(void) 
{ 
………….. 
rtc = rtc_device_register(“name”, NULL, &rtc_ops, THIS_MODULE); 
if ( IS_ERR(rtc) { 
…….. 
} 
return 0; 
} 
static void rtc_module_exit(void) 
{ 
rtc_device_unregister(rtc); 
….. 
}
WATCHDOG DRIVER 
17
什麼是Watchdog 
1) 它是一種可以reset CPU的機制, 在一定的時間 
內需要觸發, 若沒有將會引起CPU reset 
它有什麼注意事項 
1) 小心檔案系統crashed, 因為它是直接CPU reset, 
並沒有做很好的shutdown動作 
2) 可能因為Flash在write state,使得reset之後無 
法boot from flash 
3) 硬體需配合reset CPU週邊元件, 否則系統還是 
無法reset 
View source code newwdt 
18 
Watchdog面面觀

Linux Timer device driver

  • 1.
    TIMER DEVICE DRIVER (SYSTEM TIMER, RTC, WATCHDOG) 1
  • 2.
    系統宣告(arch/arm/mach-ixp4xx) MACHINE_START(IXDP425, "IntelIXDP425 Development Platform") /* Maintainer: MontaVista Software, Inc. */ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS, .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc, .map_io = ixp4xx_map_io, .init_irq = ixp4xx_init_irq, .timer = &ixp4xx_timer, .boot_params = 0x0100, .init_machine = ixdp425_init, MACHINE_END 2
  • 3.
    struct sys_timer armcpu_timer__initdata = { .init = armcpu_timer_init, .offset = armcpu_gettimeoffset, .resume = armcpu_timer_setup, }; 3 Timer 資料結構宣告
  • 4.
    static void armcpu_timer_setup(void) { armcpu_timer_set_reload(USED_TIMER, APB_CLK/HZ); armcpu_timer_set_counter(USED_TIMER, APB_CLK/HZ); ……………… } void __init armcpu_timer_init(void) { armcpu_timer_setup(); setup_irq(IRQ_TIMER1, &armcpu_timer_irq); } 4 Timer Initiailzation
  • 5.
    static irqreturn_t armcpu_timer_interrupt(intirq, void *dev_id) { write_seqlock(&xtime_lock); timer_tick(); write_sequnlock(&xtime_lock); return IRQ_HANDLED; } 5 Timer interrupt
  • 6.
    unsigned long armcpu_gettimeoffset(void) { unsigned long volatile offsetticks; offsetticks = SET_COUNTER-armcpu_timer_get_counter(USED_TIMER); if ( *(volatile unsigned int *)(CPE_TIMER1_VA_BASE+TIMER_INTR_STATE) ) { offsetticks = SET_COUNTER-armcpu_timer_get_counter(USED_TIMER); offsetticks += SET_COUNTER; } offsetticks = offsetticks / (APB_CLK / 1000000); // tansfer ticks to usec return offsetticks; } 6 gettimeoffset callback #include <sys/time.h> int gettimeofday(struct timeval *tv, struct timezone *tz); struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };
  • 7.
  • 8.
    簡單來看它就是一個時鐘,通常它只能計 時至秒。 大都規格是在一年內誤差為10幾秒。 它需要電池供電,上電一輩子需要有一次 啓動的動作,斷電後則時間停止。 以PC為例系統時間(用date指令,或者任何 API取得的時間)在開機時會讀入RTC時間並 設定時間,關機時會將系統時間設回RTC。 其應用層設定的程式為hwclock,使用的 device node 為/dev/rtc (10, 135)。 8 RTC (Real Time Clock)
  • 9.
    Usage: hwclock [-r|--show][-s|--hctosys] [-w|--systohc] [-l|-- localtime] [-u|--utc] [-f FILE] Query and set hardware clock (RTC) Options: -r Show hardware clock time -s Set system time from hardware clock -w Set hardware clock to system time -u Hardware clock is in UTC -l Hardware clock is in local time -f FILE Use specified device (e.g. /dev/rtc2) 9 hwclock usage
  • 10.
    RTC Device DriverExample 可架構在misc之下 主要是支援兩個ioctl command 1) RTC_RD_TIME 讀取時間 2) RTC_SET_TIME 設定時間 struct rtc_time { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; }; 10
  • 11.
    Module Initialize Example static struct file_operations rtc_fops = { owner:THIS_MODULE, ioctl:rtc_ioctl, open:rtc_open, release:rtc_release, }; static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; static int __init rtc_init(void) { misc_register(&rtc_dev); return 0; }
  • 12.
    Ioctl Example staticint rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; switch (cmd) { case RTC_RD_TIME: /* Read the time/date from RTC */ get_rtc_time(&rtc_tm); return copy_to_user((void *) arg, &rtc_tm, sizeof(rtc_tm)) ? -EFAULT : 0; case RTC_SET_TIME: /* Set the RTC */ if (copy_from_user(&rtc_tm, (struct rtc_time *) arg, sizeof(struct rtc_time))) return -EFAULT; // set to hardware RTC with the time return 0; default: return -EINVAL; } }
  • 13.
    新RTC Driver Devicenode is put on /dev/misc directory. Up to 16 RTC node, from rtc0 The major number is 254. The minor number is from 0. These are the same IOCTL command with the old type RTC driver. More features.
  • 14.
    RTC Class Structure struct rtc_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); int (*alarm_irq_enable)(struct device *, unsigned int enabled); int (*update_irq_enable)(struct device *, unsigned int enabled); };
  • 15.
    RTC Time structure struct rtc_time { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; };
  • 16.
    New RTC DriverExample static int rtc_read_time(struct device *dev, struct rtc_time *tm) { ……………. } static int rtc_set_time(struct device *dev, struct rtc_time *tm) { ………….. } static struct rtc_class_ops rtc_ops = { .read_time = rtc_read_time, .set_time = rtc_set_time, }; static struct rtc_device *rtc; static int rtc_module_init(void) { ………….. rtc = rtc_device_register(“name”, NULL, &rtc_ops, THIS_MODULE); if ( IS_ERR(rtc) { …….. } return 0; } static void rtc_module_exit(void) { rtc_device_unregister(rtc); ….. }
  • 17.
  • 18.
    什麼是Watchdog 1) 它是一種可以resetCPU的機制, 在一定的時間 內需要觸發, 若沒有將會引起CPU reset 它有什麼注意事項 1) 小心檔案系統crashed, 因為它是直接CPU reset, 並沒有做很好的shutdown動作 2) 可能因為Flash在write state,使得reset之後無 法boot from flash 3) 硬體需配合reset CPU週邊元件, 否則系統還是 無法reset View source code newwdt 18 Watchdog面面觀