1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2002 4 * Andrew May, Viasat Inc, amay@viasat.com 5 */ 6 7 /* 8 * M41T11 Serial Access Timekeeper(R) SRAM 9 * can you believe a trademark on that? 10 */ 11 12 /* #define DEBUG 1 */ 13 14 #include <common.h> 15 #include <command.h> 16 #include <rtc.h> 17 #include <i2c.h> 18 19 /* 20 I Don't have an example config file but this 21 is what should be done. 22 23 #define CONFIG_RTC_M41T11 1 24 #define CONFIG_SYS_I2C_RTC_ADDR 0x68 25 #if 0 26 #define CONFIG_SYS_M41T11_EXT_CENTURY_DATA 27 #else 28 #define CONFIG_SYS_M41T11_BASE_YEAR 2000 29 #endif 30 */ 31 32 #if defined(CONFIG_SYS_I2C_RTC_ADDR) && defined(CONFIG_CMD_DATE) 33 34 /* ------------------------------------------------------------------------- */ 35 /* 36 these are simple defines for the chip local to here so they aren't too 37 verbose 38 DAY/DATE aren't nice but that is how they are on the data sheet 39 */ 40 #define RTC_SEC_ADDR 0x0 41 #define RTC_MIN_ADDR 0x1 42 #define RTC_HOUR_ADDR 0x2 43 #define RTC_DAY_ADDR 0x3 44 #define RTC_DATE_ADDR 0x4 45 #define RTC_MONTH_ADDR 0x5 46 #define RTC_YEARS_ADDR 0x6 47 48 #define RTC_REG_CNT 7 49 50 #define RTC_CONTROL_ADDR 0x7 51 52 53 #ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA 54 55 #define REG_CNT (RTC_REG_CNT+1) 56 57 /* 58 you only get 00-99 for the year we will asume you 59 want from the year 2000 if you don't set the config 60 */ 61 #ifndef CONFIG_SYS_M41T11_BASE_YEAR 62 #define CONFIG_SYS_M41T11_BASE_YEAR 2000 63 #endif 64 65 #else 66 /* we will store extra year info in byte 9*/ 67 #define M41T11_YEAR_DATA 0x8 68 #define M41T11_YEAR_SIZE 1 69 #define REG_CNT (RTC_REG_CNT+1+M41T11_YEAR_SIZE) 70 #endif 71 72 #define M41T11_STORAGE_SZ (64-REG_CNT) 73 74 int rtc_get (struct rtc_time *tmp) 75 { 76 int rel = 0; 77 uchar data[RTC_REG_CNT]; 78 79 i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT); 80 81 if( data[RTC_SEC_ADDR] & 0x80 ){ 82 printf( "m41t11 RTC Clock stopped!!!\n" ); 83 rel = -1; 84 } 85 tmp->tm_sec = bcd2bin (data[RTC_SEC_ADDR] & 0x7F); 86 tmp->tm_min = bcd2bin (data[RTC_MIN_ADDR] & 0x7F); 87 tmp->tm_hour = bcd2bin (data[RTC_HOUR_ADDR] & 0x3F); 88 tmp->tm_mday = bcd2bin (data[RTC_DATE_ADDR] & 0x3F); 89 tmp->tm_mon = bcd2bin (data[RTC_MONTH_ADDR]& 0x1F); 90 #ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA 91 tmp->tm_year = CONFIG_SYS_M41T11_BASE_YEAR 92 + bcd2bin(data[RTC_YEARS_ADDR]) 93 + ((data[RTC_HOUR_ADDR]&0x40) ? 100 : 0); 94 #else 95 { 96 unsigned char cent; 97 i2c_read(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); 98 if( !(data[RTC_HOUR_ADDR] & 0x80) ){ 99 printf( "m41t11 RTC: cann't keep track of years without CEB set\n" ); 100 rel = -1; 101 } 102 if( (cent & 0x1) != ((data[RTC_HOUR_ADDR]&0x40)>>7) ){ 103 /*century flip store off new year*/ 104 cent += 1; 105 i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); 106 } 107 tmp->tm_year =((int)cent*100)+bcd2bin(data[RTC_YEARS_ADDR]); 108 } 109 #endif 110 tmp->tm_wday = bcd2bin (data[RTC_DAY_ADDR] & 0x07); 111 tmp->tm_yday = 0; 112 tmp->tm_isdst= 0; 113 114 debug ( "Get DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 115 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 116 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 117 118 return rel; 119 } 120 121 int rtc_set (struct rtc_time *tmp) 122 { 123 uchar data[RTC_REG_CNT]; 124 125 debug ( "Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 126 tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday, 127 tmp->tm_hour, tmp->tm_min, tmp->tm_sec); 128 129 data[RTC_SEC_ADDR] = bin2bcd(tmp->tm_sec) & 0x7F;/*just in case*/ 130 data[RTC_MIN_ADDR] = bin2bcd(tmp->tm_min); 131 data[RTC_HOUR_ADDR] = bin2bcd(tmp->tm_hour) & 0x3F;/*handle cent stuff later*/ 132 data[RTC_DATE_ADDR] = bin2bcd(tmp->tm_mday) & 0x3F; 133 data[RTC_MONTH_ADDR] = bin2bcd(tmp->tm_mon); 134 data[RTC_DAY_ADDR] = bin2bcd(tmp->tm_wday) & 0x07; 135 136 data[RTC_HOUR_ADDR] |= 0x80;/*we will always use CEB*/ 137 138 data[RTC_YEARS_ADDR] = bin2bcd(tmp->tm_year%100);/*same thing either way*/ 139 #ifndef CONFIG_SYS_M41T11_EXT_CENTURY_DATA 140 if( ((tmp->tm_year - CONFIG_SYS_M41T11_BASE_YEAR) > 200) || 141 (tmp->tm_year < CONFIG_SYS_M41T11_BASE_YEAR) ){ 142 printf( "m41t11 RTC setting year out of range!!need recompile\n" ); 143 } 144 data[RTC_HOUR_ADDR] |= (tmp->tm_year - CONFIG_SYS_M41T11_BASE_YEAR) > 100 ? 0x40 : 0; 145 #else 146 { 147 unsigned char cent; 148 cent = tmp->tm_year ? tmp->tm_year / 100 : 0; 149 data[RTC_HOUR_ADDR] |= (cent & 0x1) ? 0x40 : 0; 150 i2c_write(CONFIG_SYS_I2C_RTC_ADDR, M41T11_YEAR_DATA, 1, ¢, M41T11_YEAR_SIZE); 151 } 152 #endif 153 i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, data, RTC_REG_CNT); 154 155 return 0; 156 } 157 158 void rtc_reset (void) 159 { 160 unsigned char val; 161 /* clear all control & status registers */ 162 i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, 1); 163 val = val & 0x7F;/*make sure we are running*/ 164 i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_SEC_ADDR, 1, &val, RTC_REG_CNT); 165 166 i2c_read(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1); 167 val = val & 0x3F;/*turn off freq test keep calibration*/ 168 i2c_write(CONFIG_SYS_I2C_RTC_ADDR, RTC_CONTROL_ADDR, 1, &val, 1); 169 } 170 #endif 171