|
You must first set a valid timer char (for example 2006.xx.xx), in the rtc kernel modul. After this you can call:
date -s "20080605 091400"
hwclock --systohc
example rtc-at91.sam9.c (drivers/rtc direrctory) :
/*
* Initialize and install RTC driver
*/
static int __init at91_rtc_probe(struct platform_device *pdev)
{
struct resource *r;
struct sam9_rtc *rtc;
int ret;
u32 mr;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r)
return -ENODEV;
rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
if (!rtc)
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
rtc->rtt = (void __force __iomem *) (AT91_VA_BASE_SYS - AT91_BASE_SYS);
rtc->rtt += r->start;
mr = rtt_readl(rtc, MR);
/* unless RTT is counting at 1 Hz, re-initialize it */
if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
gpbr_writel(rtc, 0);
}
/* disable all interrupts (same as on shutdown path) */
mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
rtt_writel(rtc, MR, mr);
rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
&at91_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtcdev)) {
ret = PTR_ERR(rtc->rtcdev);
goto fail;
}
/* register irq handler after we know what name we'll use */
ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
IRQF_DISABLED | IRQF_SHARED,
rtc->rtcdev->dev.bus_id, rtc);
if (ret) {
dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
rtc_device_unregister(rtc->rtcdev);
goto fail;
}
/* NOTE: sam9260 rev A silicon has a ROM bug which resets the
* RTT on at least some reboots. If you have that chip, you must
* initialize the time from some external source like a GPS, wall
* clock, discrete RTC, etc
*/
if (gpbr_readl(rtc) == 0) {
dev_warn(&pdev->dev, "%s: SET TIME ! sam9260 Rev A?\n",rtc->rtcdev->dev.bus_id);
unsigned int mr_2;
mr_2 = at91_sys_read(AT91_WDT_MR);
printk(KERN_ERR "crt: Watchdog register . %u\n",mr_2);
struct rtc_time tm2;
tm2.tm_year=118;
tm2.tm_mon=1;
tm2.tm_mday=1;
struct rtc_time *tm=&tm2;
int err;
u32 offset, alarm, mr;
unsigned long secs;
dev_dbg(&pdev->dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime",
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
err = rtc_tm_to_time(tm, &secs);
if (err != 0)
return err;
mr = rtt_readl(rtc, MR);
/* disable interrupts */
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
/* read current time offset */
offset = gpbr_readl(rtc);
/* store the new base time in a battery backup register */
secs += 1;
gpbr_writel(rtc, secs);
/* adjust the alarm time for the new base */
alarm = rtt_readl(rtc, AR);
if (alarm != ALARM_DISABLED) {
if (offset > secs) {
/* time jumped backwards, increase time until alarm */
alarm += (offset - secs);
} else if ((alarm + offset) > secs) {
/* time jumped forwards, decrease time until alarm */
alarm -= (secs - offset);
} else {
/* time jumped past the alarm, disable alarm */
alarm = ALARM_DISABLED;
mr &= ~AT91_RTT_ALMIEN;
}
rtt_writel(rtc, AR, alarm);
}
/* reset the timer, and re-enable interrupts */
rtt_writel(rtc, MR, mr | AT91_RTT_RTTRST);
return 0;
}
return 0;
fail:
platform_set_drvdata(pdev, NULL);
kfree(rtc);
return ret;
}
|