linux/arch/m68k/kernel/time.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *  linux/arch/m68k/kernel/time.c
   4 *
   5 *  Copyright (C) 1991, 1992, 1995  Linus Torvalds
   6 *
   7 * This file contains the m68k-specific time handling details.
   8 * Most of the stuff is located in the machine specific files.
   9 *
  10 * 1997-09-10   Updated NTP code according to technical memorandum Jan '96
  11 *              "A Kernel Model for Precision Timekeeping" by Dave Mills
  12 */
  13
  14#include <linux/errno.h>
  15#include <linux/export.h>
  16#include <linux/module.h>
  17#include <linux/sched.h>
  18#include <linux/sched/loadavg.h>
  19#include <linux/kernel.h>
  20#include <linux/param.h>
  21#include <linux/string.h>
  22#include <linux/mm.h>
  23#include <linux/rtc.h>
  24#include <linux/platform_device.h>
  25
  26#include <asm/machdep.h>
  27#include <asm/io.h>
  28#include <asm/irq_regs.h>
  29
  30#include <linux/time.h>
  31#include <linux/timex.h>
  32#include <linux/profile.h>
  33
  34
  35unsigned long (*mach_random_get_entropy)(void);
  36EXPORT_SYMBOL_GPL(mach_random_get_entropy);
  37
  38#ifdef CONFIG_HEARTBEAT
  39void timer_heartbeat(void)
  40{
  41        /* use power LED as a heartbeat instead -- much more useful
  42           for debugging -- based on the version for PReP by Cort */
  43        /* acts like an actual heart beat -- ie thump-thump-pause... */
  44        if (mach_heartbeat) {
  45            static unsigned cnt = 0, period = 0, dist = 0;
  46
  47            if (cnt == 0 || cnt == dist)
  48                mach_heartbeat( 1 );
  49            else if (cnt == 7 || cnt == dist+7)
  50                mach_heartbeat( 0 );
  51
  52            if (++cnt > period) {
  53                cnt = 0;
  54                /* The hyperbolic function below modifies the heartbeat period
  55                 * length in dependency of the current (5min) load. It goes
  56                 * through the points f(0)=126, f(1)=86, f(5)=51,
  57                 * f(inf)->30. */
  58                period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
  59                dist = period / 4;
  60            }
  61        }
  62}
  63#endif /* CONFIG_HEARTBEAT */
  64
  65#ifdef CONFIG_M68KCLASSIC
  66#if !IS_BUILTIN(CONFIG_RTC_DRV_GENERIC)
  67void read_persistent_clock64(struct timespec64 *ts)
  68{
  69        struct rtc_time time;
  70
  71        ts->tv_sec = 0;
  72        ts->tv_nsec = 0;
  73
  74        if (!mach_hwclk)
  75                return;
  76
  77        mach_hwclk(0, &time);
  78
  79        ts->tv_sec = mktime64(time.tm_year + 1900, time.tm_mon + 1, time.tm_mday,
  80                              time.tm_hour, time.tm_min, time.tm_sec);
  81}
  82#endif
  83
  84#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
  85static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
  86{
  87        mach_hwclk(0, tm);
  88        return 0;
  89}
  90
  91static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
  92{
  93        if (mach_hwclk(1, tm) < 0)
  94                return -EOPNOTSUPP;
  95        return 0;
  96}
  97
  98static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
  99{
 100        struct rtc_pll_info pll;
 101        struct rtc_pll_info __user *argp = (void __user *)arg;
 102
 103        switch (cmd) {
 104        case RTC_PLL_GET:
 105                if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll))
 106                        return -EINVAL;
 107                return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
 108
 109        case RTC_PLL_SET:
 110                if (!mach_set_rtc_pll)
 111                        return -EINVAL;
 112                if (!capable(CAP_SYS_TIME))
 113                        return -EACCES;
 114                if (copy_from_user(&pll, argp, sizeof(pll)))
 115                        return -EFAULT;
 116                return mach_set_rtc_pll(&pll);
 117        }
 118
 119        return -ENOIOCTLCMD;
 120}
 121
 122static const struct rtc_class_ops generic_rtc_ops = {
 123        .ioctl = rtc_ioctl,
 124        .read_time = rtc_generic_get_time,
 125        .set_time = rtc_generic_set_time,
 126};
 127
 128static int __init rtc_init(void)
 129{
 130        struct platform_device *pdev;
 131
 132        if (!mach_hwclk)
 133                return -ENODEV;
 134
 135        pdev = platform_device_register_data(NULL, "rtc-generic", -1,
 136                                             &generic_rtc_ops,
 137                                             sizeof(generic_rtc_ops));
 138        return PTR_ERR_OR_ZERO(pdev);
 139}
 140
 141module_init(rtc_init);
 142#endif /* CONFIG_RTC_DRV_GENERIC */
 143#endif /* CONFIG M68KCLASSIC */
 144
 145void __init time_init(void)
 146{
 147        mach_sched_init();
 148}
 149