1/* 2 * Copyright 2001 MontaVista Software Inc. 3 * Author: jsun@mvista.com or jsun@junsun.net 4 * 5 * arch/mips/ddb5xxx/common/rtc_ds1386.c 6 * low-level RTC hookups for s for Dallas 1396 chip. 7 * 8 * This program is free software; you can redistribute it and/or modify it 9 * under the terms of the GNU General Public License as published by the 10 * Free Software Foundation; either version 2 of the License, or (at your 11 * option) any later version. 12 */ 13 14 15/* 16 * This file exports a function, rtc_ds1386_init(), which expects an 17 * uncached base address as the argument. It will set the two function 18 * pointers expected by the MIPS generic timer code. 19 */ 20 21#include <linux/types.h> 22#include <linux/time.h> 23 24#include <asm/time.h> 25#include <asm/addrspace.h> 26 27#include <asm/mc146818rtc.h> 28#include <asm/debug.h> 29 30#define EPOCH 2000 31 32#undef BCD_TO_BIN 33#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10) 34 35#undef BIN_TO_BCD 36#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10) 37 38#define READ_RTC(x) *(volatile unsigned char*)(rtc_base+x) 39#define WRITE_RTC(x, y) *(volatile unsigned char*)(rtc_base+x) = y 40 41static unsigned long rtc_base; 42 43static unsigned long 44rtc_ds1386_get_time(void) 45{ 46 u8 byte; 47 u8 temp; 48 unsigned int year, month, day, hour, minute, second; 49 50 /* let us freeze external registers */ 51 byte = READ_RTC(0xB); 52 byte &= 0x3f; 53 WRITE_RTC(0xB, byte); 54 55 /* read time data */ 56 year = BCD_TO_BIN(READ_RTC(0xA)) + EPOCH; 57 month = BCD_TO_BIN(READ_RTC(0x9) & 0x1f); 58 day = BCD_TO_BIN(READ_RTC(0x8)); 59 minute = BCD_TO_BIN(READ_RTC(0x2)); 60 second = BCD_TO_BIN(READ_RTC(0x1)); 61 62 /* hour is special - deal with it later */ 63 temp = READ_RTC(0x4); 64 65 /* enable time transfer */ 66 byte |= 0x80; 67 WRITE_RTC(0xB, byte); 68 69 /* calc hour */ 70 if (temp & 0x40) { 71 /* 12 hour format */ 72 hour = BCD_TO_BIN(temp & 0x1f); 73 if (temp & 0x20) hour += 12; /* PM */ 74 } else { 75 /* 24 hour format */ 76 hour = BCD_TO_BIN(temp & 0x3f); 77 } 78 79 return mktime(year, month, day, hour, minute, second); 80} 81 82static int 83rtc_ds1386_set_time(unsigned long t) 84{ 85 struct rtc_time tm; 86 u8 byte; 87 u8 temp; 88 u8 year, month, day, hour, minute, second; 89 90 /* let us freeze external registers */ 91 byte = READ_RTC(0xB); 92 byte &= 0x3f; 93 WRITE_RTC(0xB, byte); 94 95 /* convert */ 96 to_tm(t, &tm); 97 98 99 /* check each field one by one */ 100 year = BIN_TO_BCD(tm.tm_year - EPOCH); 101 if (year != READ_RTC(0xA)) { 102 WRITE_RTC(0xA, year); 103 } 104 105 temp = READ_RTC(0x9); 106 month = BIN_TO_BCD(tm.tm_mon+1); /* tm_mon starts from 0 to 11 */ 107 if (month != (temp & 0x1f)) { 108 WRITE_RTC( 0x9, 109 (month & 0x1f) | (temp & ~0x1f) ); 110 } 111 112 day = BIN_TO_BCD(tm.tm_mday); 113 if (day != READ_RTC(0x8)) { 114 WRITE_RTC(0x8, day); 115 } 116 117 temp = READ_RTC(0x4); 118 if (temp & 0x40) { 119 /* 12 hour format */ 120 hour = 0x40; 121 if (tm.tm_hour > 12) { 122 hour |= 0x20 | (BIN_TO_BCD(hour-12) & 0x1f); 123 } else { 124 hour |= BIN_TO_BCD(tm.tm_hour); 125 } 126 } else { 127 /* 24 hour format */ 128 hour = BIN_TO_BCD(tm.tm_hour) & 0x3f; 129 } 130 if (hour != temp) WRITE_RTC(0x4, hour); 131 132 minute = BIN_TO_BCD(tm.tm_min); 133 if (minute != READ_RTC(0x2)) { 134 WRITE_RTC(0x2, minute); 135 } 136 137 second = BIN_TO_BCD(tm.tm_sec); 138 if (second != READ_RTC(0x1)) { 139 WRITE_RTC(0x1, second); 140 } 141 142 return 0; 143} 144 145void 146rtc_ds1386_init(unsigned long base) 147{ 148 unsigned char byte; 149 150 /* remember the base */ 151 rtc_base = base; 152 db_assert((rtc_base & 0xe0000000) == KSEG1); 153 154 /* turn on RTC if it is not on */ 155 byte = READ_RTC(0x9); 156 if (byte & 0x80) { 157 byte &= 0x7f; 158 WRITE_RTC(0x9, byte); 159 } 160 161 /* enable time transfer */ 162 byte = READ_RTC(0xB); 163 byte |= 0x80; 164 WRITE_RTC(0xB, byte); 165 166 /* set the function pointers */ 167 rtc_get_time = rtc_ds1386_get_time; 168 rtc_set_time = rtc_ds1386_set_time; 169} 170