Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 | // SPDX-License-Identifier: GPL-2.0-only /* * 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); #ifdef CONFIG_HEARTBEAT void timer_heartbeat(void) { /* 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 */ #ifdef CONFIG_M68KCLASSIC /* machine dependent timer functions */ int (*mach_hwclk) (int, struct rtc_time*); EXPORT_SYMBOL(mach_hwclk); int (*mach_get_rtc_pll)(struct rtc_pll_info *); int (*mach_set_rtc_pll)(struct rtc_pll_info *); EXPORT_SYMBOL(mach_get_rtc_pll); EXPORT_SYMBOL(mach_set_rtc_pll); #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(); } |