QQ登录

只需一步,快速开始

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 1260|回复: 0

求救S3c2410的RealTimeClock时钟驱动问题

[复制链接]
发表于 2005-8-11 14:33:52 | 显示全部楼层 |阅读模式
我使用的是Linux 2.6.12.3 Kernel,driver/char/s3c2410-rtc.c好象没有问题,但是在make menuconfig选择了Devices Driver-Character-devices-Enhanced Real Time Clock Support 和Devices Driver-Character-devices-S3C2410 RTC Driver选项;并且在linux/arch/arm/mach-s3c2410/mach-smdk2410.c中static struct platform_device *smdk2410_devices[] __initdata函数中增加了&s3c_device_rtc;编译后发现开机时间,一直从1970年1月1日00:00:00开始记时,关闭后,重新启动依然是从1970年1月1日00:00:00开始记时,说明实时时钟没有正常工作;请高手指教.(我的扳子有电池,并且在2.4.18下完好)

系统启动的状况:

VIVI version 0.1.4 ([email protected]) (gcc version 2.95.3 20010315 (release)) #0.1.4 ÀÏ 6¿ù 29 14:21:19 KST 2003
MMU table base address = 0x33DFC000
Succeed memory mapping.
NAND device: Manufacture ID: 0xec, Chip ID: 0x76 (Samsung K9D1208V0M)
Found saved vivi parameters.
Press Return to start the LINUX now, any other key for vivi
Copy linux kernel from 0x00030000 to 0x30008000, size = 0x001d0000 ... done
zImage magic = 0x016f2818
Setup linux parameters at 0x30000100
linux command line is: "noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200"
MACH_TYPE = 193
NOW, Booting Linux......
Uncompressing Linux....................................................... done, booting the kernel.
Linux version 2.6.12.3 (root@ORBClient) (gcc version 3.4.1) #139 Thu Aug 11 13:18:48 CST 2005
CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
CPU0: D VIVT write-back cache
CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
Machine: SMDK2410
ATAG_INITRD is deprecated; please update your bootloader.
Memory policy: ECC disabled, Data cache writeback
CPU S3C2410 (id 0x32410000)
S3C2410: core 200.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz
S3C2410 Clocks, (c) 2004 Simtec Electronics
Built 1 zonelists
Kernel command line: noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200
irq: clearing subpending status 00000002
PID hash table entries: 512 (order: 9, 8192 bytes)
timer tcon=00000000, tcnt a2c1, tcfg 00000200,00000000, usec 00001eb8
Console: colour dummy device 80x30
Dentry cache hash table entries: 16384 (order: 4, 65536 bytes)
Inode-cache hash table entries: 8192 (order: 3, 32768 bytes)
Memory: 64MB = 64MB total
Memory: 63104KB available (1346K code, 303K data, 76K init)
Mount-cache hash table entries: 512
CPU: Testing write buffer coherency: ok
NET: Registered protocol family 16
S3C2410: Initialising architecture
NetWinder Floating Point Emulator V0.97 (double precision)
devfs: 2004-01-31 Richard Gooch ([email protected])
devfs: boot_options: 0x1
Real Time Clock Driver v1.12
S3C2410 RTC, (c) 2004 Simtec Electronics
s3c2410_serial0 at MMIO 0x50000000 (irq = 70) is a S3C2410
s3c2410_serial1 at MMIO 0x50004000 (irq = 73) is a S3C2410
s3c2410_serial2 at MMIO 0x50008000 (irq = 76) is a S3C2410
io scheduler noop registered
Ethernet Channel Bonding Driver: v2.6.1 (October 29, 2004)
bonding: Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details.
Cirrus Logic CS8900A driver for Linux (Modified for SMDK2410)
eth0: CS8900A rev E at 0xe0000300 irq=53, no eeprom , addr: 08: 0:3E:26:0A:5B
S3C2410 NAND Driver, (c) 2004 Simtec Electronics
s3c2410-nand: mapped registers at c4880000
s3c2410-nand: timing: Tacls 10ns, Twrph0 40ns, Twrph1 10ns
NAND device: Manufacturer ID: 0xec, Chip ID: 0x76 (Samsung NAND 64MiB 3,3V 8-bit)
NAND_ECC_NONE selected by board driver. This is not recommended !!
Scanning device for bad blocks
Creating 5 MTD partitions on "NAND 64MiB 3,3V 8-bit":
0x00000000-0x00020000 : "vivi"
0x00020000-0x00030000 : "param"
0x00030000-0x00200000 : "kernel"
0x00200000-0x01000000 : "root"
0x01000000-0x03fe8000 : "usr"
mice: PS/2 mouse device common for all mice
NET: Registered protocol family 2
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP established hash table entries: 4096 (order: 3, 32768 bytes)
TCP bind hash table entries: 4096 (order: 2, 16384 bytes)
TCP: Hash tables configured (established 4096 bind 4096)
NET: Registered protocol family 1
NET: Registered protocol family 17
VFS: Mounted root (cramfs filesystem) readonly.
Mounted devfs on /dev
Freeing init memory: 76K
mount /etc as ramfs
re-create the /etc/mtab entries
yaffs: dev is 32505860 name is "YAFFS file system"

Please press Enter to activate this console.

驱动代码:
/* drivers/char/s3c2410_rtc.c
*
* Copyright (c) 2004 Simtec Electronics <[email protected]>
*                      http://www.simtec.co.uk/products/SWLINUX/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* S3C2410 Internal RTC Driver
*
*  Changelog:
*        08-Nov-2004        BJD        Initial creation
*        12-Nov-2004        BJD        Added periodic IRQ and PM code
*        22-Nov-2004        BJD        Sign-test on alarm code to check for <0
*        10-Mar-2005        LCVR        Changed S3C2410_VA_RTC to S3C24XX_VA_RTC
*/

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/rtc.h>
#include <linux/bcd.h>

#include <asm/hardware.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/rtc.h>

#include <asm/mach/time.h>

#include <asm/hardware/clock.h>
#include <asm/arch/regs-rtc.h>

/* need this for the RTC_AF definitions */
#include <linux/mc146818rtc.h>

#undef S3C24XX_VA_RTC
#define S3C24XX_VA_RTC s3c2410_rtc_base

static struct resource *s3c2410_rtc_mem;

static void __iomem *s3c2410_rtc_base;
static int s3c2410_rtc_alarmno = NO_IRQ;
static int s3c2410_rtc_tickno  = NO_IRQ;
static int s3c2410_rtc_freq    = 1;

static DEFINE_SPINLOCK(s3c2410_rtc_pie_lock);

/* IRQ Handlers */

static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
{
        rtc_update(1, RTC_AF | RTC_IRQF);
        return IRQ_HANDLED;
}

static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r)
{
        rtc_update(1, RTC_PF | RTC_IRQF);
        return IRQ_HANDLED;
}

/* Update control registers */
static void s3c2410_rtc_setaie(int to)
{
        unsigned int tmp;

        pr_debug("%s: aie=%d\n", __FUNCTION__, to);

        tmp = readb(S3C2410_RTCALM);

        if (to)
                tmp |= S3C2410_RTCALM_ALMEN;
        else
                tmp &= ~S3C2410_RTCALM_ALMEN;


        writeb(tmp, S3C2410_RTCALM);
}

static void s3c2410_rtc_setpie(int to)
{
        unsigned int tmp;

        pr_debug("%s: pie=%d\n", __FUNCTION__, to);

        spin_lock_irq(&s3c2410_rtc_pie_lock);
        tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;

        if (to)
                tmp |= S3C2410_TICNT_ENABLE;

        writeb(tmp, S3C2410_TICNT);
        spin_unlock_irq(&s3c2410_rtc_pie_lock);
}

static void s3c2410_rtc_setfreq(int freq)
{
        unsigned int tmp;

        spin_lock_irq(&s3c2410_rtc_pie_lock);
        tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;

        s3c2410_rtc_freq = freq;

        tmp |= (128 / freq)-1;

        writeb(tmp, S3C2410_TICNT);
        spin_unlock_irq(&s3c2410_rtc_pie_lock);
}

/* Time read/write */

static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
{
        unsigned int have_retried = 0;

retry_get_time:
        rtc_tm->tm_min  = readb(S3C2410_RTCMIN);
        rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
        rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
        rtc_tm->tm_mon  = readb(S3C2410_RTCMON);
        rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
        rtc_tm->tm_sec  = readb(S3C2410_RTCSEC);

        /* the only way to work out wether the system was mid-update
         * when we read it is to check the second counter, and if it
         * is zero, then we re-try the entire read
         */

        if (rtc_tm->tm_sec == 0 && !have_retried) {
                have_retried = 1;
                goto retry_get_time;
        }

        pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
                 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
                 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);

        BCD_TO_BIN(rtc_tm->tm_sec);
        BCD_TO_BIN(rtc_tm->tm_min);
        BCD_TO_BIN(rtc_tm->tm_hour);
        BCD_TO_BIN(rtc_tm->tm_mday);
        BCD_TO_BIN(rtc_tm->tm_mon);
        BCD_TO_BIN(rtc_tm->tm_year);

        rtc_tm->tm_year += 100;
        rtc_tm->tm_mon -= 1;

        return 0;
}


static int s3c2410_rtc_settime(struct rtc_time *tm)
{
        /* the rtc gets round the y2k problem by just not supporting it */

        if (tm->tm_year < 100)
                return -EINVAL;

        writeb(BIN2BCD(tm->tm_sec),  S3C2410_RTCSEC);
        writeb(BIN2BCD(tm->tm_min),  S3C2410_RTCMIN);
        writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
        writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
        writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
        writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);

        return 0;
}

static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
{
        struct rtc_time *alm_tm = &alrm->time;
        unsigned int alm_en;

        alm_tm->tm_sec  = readb(S3C2410_ALMSEC);
        alm_tm->tm_min  = readb(S3C2410_ALMMIN);
        alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
        alm_tm->tm_mon  = readb(S3C2410_ALMMON);
        alm_tm->tm_mday = readb(S3C2410_ALMDATE);
        alm_tm->tm_year = readb(S3C2410_ALMYEAR);

        alm_en = readb(S3C2410_RTCALM);

        pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
                 alm_en,
                 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
                 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);


        /* decode the alarm enable field */

        if (alm_en & S3C2410_RTCALM_SECEN) {
                BCD_TO_BIN(alm_tm->tm_sec);
        } else {
                alm_tm->tm_sec = 0xff;
        }

        if (alm_en & S3C2410_RTCALM_MINEN) {
                BCD_TO_BIN(alm_tm->tm_min);
        } else {
                alm_tm->tm_min = 0xff;
        }

        if (alm_en & S3C2410_RTCALM_HOUREN) {
                BCD_TO_BIN(alm_tm->tm_hour);
        } else {
                alm_tm->tm_hour = 0xff;
        }

        if (alm_en & S3C2410_RTCALM_DAYEN) {
                BCD_TO_BIN(alm_tm->tm_mday);
        } else {
                alm_tm->tm_mday = 0xff;
        }

        if (alm_en & S3C2410_RTCALM_MONEN) {
                BCD_TO_BIN(alm_tm->tm_mon);
                alm_tm->tm_mon -= 1;
        } else {
                alm_tm->tm_mon = 0xff;
        }

        if (alm_en & S3C2410_RTCALM_YEAREN) {
                BCD_TO_BIN(alm_tm->tm_year);
        } else {
                alm_tm->tm_year = 0xffff;
        }

        /* todo - set alrm->enabled ? */

        return 0;
}

static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
{
        struct rtc_time *tm = &alrm->time;
        unsigned int alrm_en;

        pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
                 alrm->enabled,
                 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
                 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);

        if (alrm->enabled || 1) {
                alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
                writeb(0x00, S3C2410_RTCALM);

                if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
                        alrm_en |= S3C2410_RTCALM_SECEN;
                        writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
                }

                if (tm->tm_min < 60 && tm->tm_min >= 0) {
                        alrm_en |= S3C2410_RTCALM_MINEN;
                        writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
                }

                if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
                        alrm_en |= S3C2410_RTCALM_HOUREN;
                        writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
                }

                pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);

                writeb(alrm_en, S3C2410_RTCALM);
                enable_irq_wake(s3c2410_rtc_alarmno);
        } else {
                alrm_en = readb(S3C2410_RTCALM);
                alrm_en &= ~S3C2410_RTCALM_ALMEN;
                writeb(alrm_en, S3C2410_RTCALM);
                disable_irq_wake(s3c2410_rtc_alarmno);
        }

        return 0;
}

static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg)
{
        switch (cmd) {
        case RTC_AIE_OFF:
        case RTC_AIE_ON:
                s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
                return 0;

        case RTC_PIE_OFF:
        case RTC_PIE_ON:
                s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
                return 0;

        case RTC_IRQP_READ:
                return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg);

        case RTC_IRQP_SET:
                if (arg < 1 || arg > 64)
                        return -EINVAL;

                if (!capable(CAP_SYS_RESOURCE))
                        return -EACCES;

                /* check for power of 2 */

                if ((arg & (arg-1)) != 0)
                        return -EINVAL;

                pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);

                s3c2410_rtc_setfreq(arg);
                return 0;

        case RTC_UIE_ON:
        case RTC_UIE_OFF:
                return -EINVAL;
        }

        return -EINVAL;
}

static int s3c2410_rtc_proc(char *buf)
{
        unsigned int rtcalm = readb(S3C2410_RTCALM);
        unsigned int ticnt = readb (S3C2410_TICNT);
        char *p = buf;

        p += sprintf(p, "alarm_IRQ\t: %s\n",
                     (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
        p += sprintf(p, "periodic_IRQ\t: %s\n",
                     (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
        p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq);

        return p - buf;
}

static int s3c2410_rtc_open(void)
{
        int ret;

        ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq,
                          SA_INTERRUPT,  "s3c2410-rtc alarm", NULL);

        if (ret)
                printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno);

        ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq,
                          SA_INTERRUPT,  "s3c2410-rtc tick", NULL);

        if (ret) {
                printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno);
                goto tick_err;
        }

        return ret;

tick_err:
        free_irq(s3c2410_rtc_alarmno, NULL);
        return ret;
}

static void s3c2410_rtc_release(void)
{
        /* do not clear AIE here, it may be needed for wake */

        s3c2410_rtc_setpie(0);
        free_irq(s3c2410_rtc_alarmno, NULL);
        free_irq(s3c2410_rtc_tickno, NULL);
}

static struct rtc_ops s3c2410_rtcops = {
        .owner                = THIS_MODULE,
        .open                = s3c2410_rtc_open,
        .release        = s3c2410_rtc_release,
        .ioctl                = s3c2410_rtc_ioctl,
        .read_time        = s3c2410_rtc_gettime,
        .set_time        = s3c2410_rtc_settime,
        .read_alarm        = s3c2410_rtc_getalarm,
        .set_alarm        = s3c2410_rtc_setalarm,
        .proc                = s3c2410_rtc_proc,
};

static void s3c2410_rtc_enable(struct device *dev, int en)
{
        unsigned int tmp;

        if (s3c2410_rtc_base == NULL)
                return;

        if (!en) {
                tmp = readb(S3C2410_RTCCON);
                writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);

                tmp = readb(S3C2410_TICNT);
                writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
        } else {
                /* re-enable the device, and check it is ok */

                if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
                        dev_info(dev, "rtc disabled, re-enabling\n");

                        tmp = readb(S3C2410_RTCCON);
                        writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
                }

                if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
                        dev_info(dev, "removing S3C2410_RTCCON_CNTSEL\n");

                        tmp = readb(S3C2410_RTCCON);
                        writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
                }

                if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
                        dev_info(dev, "removing S3C2410_RTCCON_CLKRST\n");

                        tmp = readb(S3C2410_RTCCON);
                        writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
                }
        }
}

static int s3c2410_rtc_remove(struct device *dev)
{
        unregister_rtc(&s3c2410_rtcops);

        s3c2410_rtc_setpie(0);
        s3c2410_rtc_setaie(0);

        if (s3c2410_rtc_mem != NULL) {
                pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n");
                iounmap(s3c2410_rtc_base);
                release_resource(s3c2410_rtc_mem);
                kfree(s3c2410_rtc_mem);
        }

        return 0;
}

static int s3c2410_rtc_probe(struct device *dev)
{
        struct platform_device *pdev = to_platform_device(dev);
        struct resource *res;
        int ret;

        pr_debug("%s: probe=%p, device=%p\n", __FUNCTION__, pdev, dev);

        /* find the IRQs */

        s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
        if (s3c2410_rtc_tickno <= 0) {
                dev_err(dev, "no irq for rtc tick\n");
                return -ENOENT;
        }

        s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
        if (s3c2410_rtc_alarmno <= 0) {
                dev_err(dev, "no irq for alarm\n");
                return -ENOENT;
        }

        pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
                 s3c2410_rtc_tickno, s3c2410_rtc_alarmno);

        /* get the memory region */

        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res == NULL) {
                dev_err(dev, "failed to get memory region resource\n");
                return -ENOENT;
        }

        s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,
                                     pdev->name);

        if (s3c2410_rtc_mem == NULL) {
                dev_err(dev, "failed to reserve memory region\n");
                ret = -ENOENT;
                goto exit_err;
        }

        s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
        if (s3c2410_rtc_base == NULL) {
                dev_err(dev, "failed ioremap()\n");
                ret = -EINVAL;
                goto exit_err;
        }

        s3c2410_rtc_mem = res;
        pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);

        pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));

        /* check to see if everything is setup correctly */

        s3c2410_rtc_enable(dev, 1);

        pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));

        s3c2410_rtc_setfreq(s3c2410_rtc_freq);

        /* register RTC and exit */

        register_rtc(&s3c2410_rtcops);
        return 0;

exit_err:
        dev_err(dev, "error %d during initialisation\n", ret);

        return ret;
}

#ifdef CONFIG_PM

/* S3C2410 RTC Power management control */

static struct timespec s3c2410_rtc_delta;

static int ticnt_save;

static int s3c2410_rtc_suspend(struct device *dev, pm_message_t state, u32 level)
{
        struct rtc_time tm;
        struct timespec time;

        time.tv_nsec = 0;

        if (level == SUSPEND_POWER_DOWN) {
                /* save TICNT for anyone using periodic interrupts */

                ticnt_save = readb(S3C2410_TICNT);

                /* calculate time delta for suspend */

                s3c2410_rtc_gettime(&tm);
                rtc_tm_to_time(&tm, &time.tv_sec);
                save_time_delta(&s3c2410_rtc_delta, &time);
                s3c2410_rtc_enable(dev, 0);
        }

        return 0;
}

static int s3c2410_rtc_resume(struct device *dev, u32 level)
{
        struct rtc_time tm;
        struct timespec time;

        time.tv_nsec = 0;

        s3c2410_rtc_enable(dev, 1);
        s3c2410_rtc_gettime(&tm);
        rtc_tm_to_time(&tm, &time.tv_sec);
        restore_time_delta(&s3c2410_rtc_delta, &time);

        writeb(ticnt_save, S3C2410_TICNT);
        return 0;
}
#else
#define s3c2410_rtc_suspend NULL
#define s3c2410_rtc_resume  NULL
#endif

static struct device_driver s3c2410_rtcdrv = {
        .name                = "s3c2410-rtc",
        .bus                = &platform_bus_type,
        .probe                = s3c2410_rtc_probe,
        .remove                = s3c2410_rtc_remove,
        .suspend        = s3c2410_rtc_suspend,
        .resume                = s3c2410_rtc_resume,
};

static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";

static int __init s3c2410_rtc_init(void)
{
        printk(banner);
        return driver_register(&s3c2410_rtcdrv);
}

static void __exit s3c2410_rtc_exit(void)
{
        driver_unregister(&s3c2410_rtcdrv);
}

module_init(s3c2410_rtc_init);
module_exit(s3c2410_rtc_exit);

MODULE_DESCRIPTION("S3C24XX RTC Driver");
MODULE_AUTHOR("Ben Dooks, <[email protected]>");
MODULE_LICENSE("GPL");
您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2024-11-27 04:04 , Processed in 0.072408 second(s), 16 queries .

© 2021 Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表