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 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | /* $Id: rtc.c,v 1.25 2001/02/13 01:17:00 davem Exp $ * * Linux/SPARC Real Time Clock Driver * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) * * This is a little driver that lets a user-level program access * the SPARC Mostek real time clock chip. It is no use unless you * use the modified clock utility. * * Get the modified clock utility from: * ftp://vger.kernel.org/pub/linux/Sparc/userland/clock.c */ #include <linux/module.h> #include <linux/types.h> #include <linux/errno.h> #include <linux/miscdevice.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/poll.h> #include <linux/init.h> #include <linux/smp_lock.h> #include <asm/mostek.h> #include <asm/system.h> #include <asm/uaccess.h> #include <asm/rtc.h> static int rtc_busy = 0; /* Retrieve the current date and time from the real time clock. */ void get_rtc_time(struct rtc_time *t) { unsigned long regs = mstk48t02_regs; u8 tmp; spin_lock_irq(&mostek_lock); tmp = mostek_read(regs + MOSTEK_CREG); tmp |= MSTK_CREG_READ; mostek_write(regs + MOSTEK_CREG, tmp); t->sec = MSTK_REG_SEC(regs); t->min = MSTK_REG_MIN(regs); t->hour = MSTK_REG_HOUR(regs); t->dow = MSTK_REG_DOW(regs); t->dom = MSTK_REG_DOM(regs); t->month = MSTK_REG_MONTH(regs); t->year = MSTK_CVT_YEAR( MSTK_REG_YEAR(regs) ); tmp = mostek_read(regs + MOSTEK_CREG); tmp &= ~MSTK_CREG_READ; mostek_write(regs + MOSTEK_CREG, tmp); spin_unlock_irq(&mostek_lock); } /* Set the current date and time inthe real time clock. */ void set_rtc_time(struct rtc_time *t) { unsigned long regs = mstk48t02_regs; u8 tmp; spin_lock_irq(&mostek_lock); tmp = mostek_read(regs + MOSTEK_CREG); tmp |= MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); MSTK_SET_REG_SEC(regs,t->sec); MSTK_SET_REG_MIN(regs,t->min); MSTK_SET_REG_HOUR(regs,t->hour); MSTK_SET_REG_DOW(regs,t->dow); MSTK_SET_REG_DOM(regs,t->dom); MSTK_SET_REG_MONTH(regs,t->month); MSTK_SET_REG_YEAR(regs,t->year - MSTK_YEAR_ZERO); tmp = mostek_read(regs + MOSTEK_CREG); tmp &= ~MSTK_CREG_WRITE; mostek_write(regs + MOSTEK_CREG, tmp); spin_unlock_irq(&mostek_lock); } static long long rtc_lseek(struct file *file, long long offset, int origin) { return -ESPIPE; } static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { struct rtc_time rtc_tm; switch (cmd) { case RTCGET: get_rtc_time(&rtc_tm); if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time))) return -EFAULT; return 0; case RTCSET: if (!capable(CAP_SYS_TIME)) return -EPERM; if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time))) return -EFAULT; set_rtc_time(&rtc_tm); return 0; default: return -EINVAL; } } static int rtc_open(struct inode *inode, struct file *file) { int ret; spin_lock_irq(&mostek_lock); if (rtc_busy) { ret = -EBUSY; } else { rtc_busy = 1; ret = 0; } spin_unlock_irq(&mostek_lock); return ret; } static int rtc_release(struct inode *inode, struct file *file) { rtc_busy = 0; return 0; } static struct file_operations rtc_fops = { owner: THIS_MODULE, llseek: rtc_lseek, ioctl: rtc_ioctl, open: rtc_open, release: rtc_release, }; static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops }; EXPORT_NO_SYMBOLS; static int __init rtc_sun_init(void) { int error; if (mstk48t02_regs == 0) { /* This diagnostic is a debugging aid... But a useful one. */ printk(KERN_ERR "rtc: no Mostek in this computer\n"); return -ENODEV; } error = misc_register(&rtc_dev); if (error) { printk(KERN_ERR "rtc: unable to get misc minor for Mostek\n"); return error; } return 0; } static void __exit rtc_sun_cleanup(void) { misc_deregister(&rtc_dev); } module_init(rtc_sun_init); module_exit(rtc_sun_cleanup); |