📄 time.c
字号:
/* * linux/arch/arm/mach-integrator/time.c * * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. * * 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. */#include <linux/module.h>#include <linux/kernel.h>#include <linux/time.h>#include <linux/mc146818rtc.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/device.h>#include <asm/hardware/amba.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/rtc.h>#include <asm/mach/time.h>#define RTC_DR (0)#define RTC_MR (4)#define RTC_STAT (8)#define RTC_EOI (8)#define RTC_LR (12)#define RTC_CR (16)#define RTC_CR_MIE (1 << 0)extern int (*set_rtc)(void);static void __iomem *rtc_base;static int integrator_set_rtc(void){ __raw_writel(xtime.tv_sec, rtc_base + RTC_LR); return 1;}static int rtc_read_alarm(struct rtc_wkalrm *alrm){ rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); return 0;}static inline int rtc_set_alarm(struct rtc_wkalrm *alrm){ unsigned long time; int ret; /* * At the moment, we can only deal with non-wildcarded alarm times. */ ret = rtc_valid_tm(&alrm->time); if (ret == 0) ret = rtc_tm_to_time(&alrm->time, &time); if (ret == 0) writel(time, rtc_base + RTC_MR); return ret;}static int rtc_read_time(struct rtc_time *tm){ rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); return 0;}/* * Set the RTC time. Unfortunately, we can't accurately set * the point at which the counter updates. * * Also, since RTC_LR is transferred to RTC_CR on next rising * edge of the 1Hz clock, we must write the time one second * in advance. */static inline int rtc_set_time(struct rtc_time *tm){ unsigned long time; int ret; ret = rtc_tm_to_time(tm, &time); if (ret == 0) writel(time + 1, rtc_base + RTC_LR); return ret;}static struct rtc_ops rtc_ops = { .owner = THIS_MODULE, .read_time = rtc_read_time, .set_time = rtc_set_time, .read_alarm = rtc_read_alarm, .set_alarm = rtc_set_alarm,};static irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs){ writel(0, rtc_base + RTC_EOI); return IRQ_HANDLED;}static int rtc_probe(struct amba_device *dev, void *id){ int ret; if (rtc_base) return -EBUSY; ret = amba_request_regions(dev, NULL); if (ret) goto out; rtc_base = ioremap(dev->res.start, SZ_4K); if (!rtc_base) { ret = -ENOMEM; goto res_out; } __raw_writel(0, rtc_base + RTC_CR); __raw_writel(0, rtc_base + RTC_EOI); xtime.tv_sec = __raw_readl(rtc_base + RTC_DR); ret = request_irq(dev->irq[0], rtc_interrupt, SA_INTERRUPT, "rtc-pl030", dev); if (ret) goto map_out; ret = register_rtc(&rtc_ops); if (ret) goto irq_out; set_rtc = integrator_set_rtc; return 0; irq_out: free_irq(dev->irq[0], dev); map_out: iounmap(rtc_base); rtc_base = NULL; res_out: amba_release_regions(dev); out: return ret;}static int rtc_remove(struct amba_device *dev){ set_rtc = NULL; writel(0, rtc_base + RTC_CR); free_irq(dev->irq[0], dev); unregister_rtc(&rtc_ops); iounmap(rtc_base); rtc_base = NULL; amba_release_regions(dev); return 0;}static struct timespec rtc_delta;static int rtc_suspend(struct amba_device *dev, pm_message_t state){ struct timespec rtc; rtc.tv_sec = readl(rtc_base + RTC_DR); rtc.tv_nsec = 0; save_time_delta(&rtc_delta, &rtc); return 0;}static int rtc_resume(struct amba_device *dev){ struct timespec rtc; rtc.tv_sec = readl(rtc_base + RTC_DR); rtc.tv_nsec = 0; restore_time_delta(&rtc_delta, &rtc); return 0;}static struct amba_id rtc_ids[] = { { .id = 0x00041030, .mask = 0x000fffff, }, { 0, 0 },};static struct amba_driver rtc_driver = { .drv = { .name = "rtc-pl030", }, .probe = rtc_probe, .remove = rtc_remove, .suspend = rtc_suspend, .resume = rtc_resume, .id_table = rtc_ids,};static int __init integrator_rtc_init(void){ return amba_driver_register(&rtc_driver);}static void __exit integrator_rtc_exit(void){ amba_driver_unregister(&rtc_driver);}module_init(integrator_rtc_init);module_exit(integrator_rtc_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -