mirror of
https://github.com/torvalds/linux.git
synced 2024-11-25 21:51:40 +00:00
065f109f25
We have two ways of getting the current time from a platform at boot
or during suspend: either using read_persistent_clock() or the rtc
class operation. We never need both, so I'm hiding the
read_persistent_clock variant when the generic RTC is enabled.
Since read_persistent_clock() and mktime() are deprecated because of
the y2038 overflow of time_t, we should use the time64_t based
replacements here.
Finally, the dependency on CONFIG_ARCH_USES_GETTIMEOFFSET looks
completely bogus in this case, so let's remove that. It was
added in commit b13b3f51ff
("m68k: fix inclusion of
arch_gettimeoffset for non-MMU 68k classic CPU types") to deal
with arch_gettimeoffset(), which has since been removed from
this file and is unrelated to the RTC functions.
The rtc accessors are only used by classic machines, while
coldfire uses proper RTC drivers, so we can put the old
ifdef back around both functions.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Baolin Wang <baolin.wang@linaro.org>
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
158 lines
3.7 KiB
C
158 lines
3.7 KiB
C
/*
|
|
* linux/arch/m68k/kernel/time.c
|
|
*
|
|
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
|
|
*
|
|
* This file contains the m68k-specific time handling details.
|
|
* Most of the stuff is located in the machine specific files.
|
|
*
|
|
* 1997-09-10 Updated NTP code according to technical memorandum Jan '96
|
|
* "A Kernel Model for Precision Timekeeping" by Dave Mills
|
|
*/
|
|
|
|
#include <linux/errno.h>
|
|
#include <linux/export.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched/loadavg.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/param.h>
|
|
#include <linux/string.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/rtc.h>
|
|
#include <linux/platform_device.h>
|
|
|
|
#include <asm/machdep.h>
|
|
#include <asm/io.h>
|
|
#include <asm/irq_regs.h>
|
|
|
|
#include <linux/time.h>
|
|
#include <linux/timex.h>
|
|
#include <linux/profile.h>
|
|
|
|
|
|
unsigned long (*mach_random_get_entropy)(void);
|
|
EXPORT_SYMBOL_GPL(mach_random_get_entropy);
|
|
|
|
|
|
/*
|
|
* timer_interrupt() needs to keep up the real-time clock,
|
|
* as well as call the "xtime_update()" routine every clocktick
|
|
*/
|
|
static irqreturn_t timer_interrupt(int irq, void *dummy)
|
|
{
|
|
xtime_update(1);
|
|
update_process_times(user_mode(get_irq_regs()));
|
|
profile_tick(CPU_PROFILING);
|
|
|
|
#ifdef CONFIG_HEARTBEAT
|
|
/* use power LED as a heartbeat instead -- much more useful
|
|
for debugging -- based on the version for PReP by Cort */
|
|
/* acts like an actual heart beat -- ie thump-thump-pause... */
|
|
if (mach_heartbeat) {
|
|
static unsigned cnt = 0, period = 0, dist = 0;
|
|
|
|
if (cnt == 0 || cnt == dist)
|
|
mach_heartbeat( 1 );
|
|
else if (cnt == 7 || cnt == dist+7)
|
|
mach_heartbeat( 0 );
|
|
|
|
if (++cnt > period) {
|
|
cnt = 0;
|
|
/* The hyperbolic function below modifies the heartbeat period
|
|
* length in dependency of the current (5min) load. It goes
|
|
* through the points f(0)=126, f(1)=86, f(5)=51,
|
|
* f(inf)->30. */
|
|
period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
|
|
dist = period / 4;
|
|
}
|
|
}
|
|
#endif /* CONFIG_HEARTBEAT */
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
#ifdef CONFIG_M68KCLASSIC
|
|
#if !IS_BUILTIN(CONFIG_RTC_DRV_GENERIC)
|
|
void read_persistent_clock64(struct timespec64 *ts)
|
|
{
|
|
struct rtc_time time;
|
|
|
|
ts->tv_sec = 0;
|
|
ts->tv_nsec = 0;
|
|
|
|
if (!mach_hwclk)
|
|
return;
|
|
|
|
mach_hwclk(0, &time);
|
|
|
|
ts->tv_sec = mktime64(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
|
|
time.tm_hour, time.tm_min, time.tm_sec);
|
|
}
|
|
#endif
|
|
|
|
#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
|
|
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
|
{
|
|
mach_hwclk(0, tm);
|
|
return 0;
|
|
}
|
|
|
|
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
|
{
|
|
if (mach_hwclk(1, tm) < 0)
|
|
return -EOPNOTSUPP;
|
|
return 0;
|
|
}
|
|
|
|
static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
|
{
|
|
struct rtc_pll_info pll;
|
|
struct rtc_pll_info __user *argp = (void __user *)arg;
|
|
|
|
switch (cmd) {
|
|
case RTC_PLL_GET:
|
|
if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll))
|
|
return -EINVAL;
|
|
return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
|
|
|
|
case RTC_PLL_SET:
|
|
if (!mach_set_rtc_pll)
|
|
return -EINVAL;
|
|
if (!capable(CAP_SYS_TIME))
|
|
return -EACCES;
|
|
if (copy_from_user(&pll, argp, sizeof(pll)))
|
|
return -EFAULT;
|
|
return mach_set_rtc_pll(&pll);
|
|
}
|
|
|
|
return -ENOIOCTLCMD;
|
|
}
|
|
|
|
static const struct rtc_class_ops generic_rtc_ops = {
|
|
.ioctl = rtc_ioctl,
|
|
.read_time = rtc_generic_get_time,
|
|
.set_time = rtc_generic_set_time,
|
|
};
|
|
|
|
static int __init rtc_init(void)
|
|
{
|
|
struct platform_device *pdev;
|
|
|
|
if (!mach_hwclk)
|
|
return -ENODEV;
|
|
|
|
pdev = platform_device_register_data(NULL, "rtc-generic", -1,
|
|
&generic_rtc_ops,
|
|
sizeof(generic_rtc_ops));
|
|
return PTR_ERR_OR_ZERO(pdev);
|
|
}
|
|
|
|
module_init(rtc_init);
|
|
#endif /* CONFIG_RTC_DRV_GENERIC */
|
|
#endif /* CONFIG M68KCLASSIC */
|
|
|
|
void __init time_init(void)
|
|
{
|
|
mach_sched_init(timer_interrupt);
|
|
}
|