1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * (C) Copyright 2018 4 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de. 5 * 6 * (C) Copyright 2008 7 * Stefan Roese, DENX Software Engineering, sr@denx.de. 8 * 9 * based on a the Linux rtc-m41t80.c driver which is: 10 * Alexander Bigga <ab@mycable.de>, 2006 (c) mycable GmbH 11 */ 12 13/* 14 * Date & Time support for STMicroelectronics M41T62 15 */ 16 17/* #define DEBUG */ 18 19#include <common.h> 20#include <command.h> 21#include <dm.h> 22#include <log.h> 23#include <rtc.h> 24#include <i2c.h> 25#include <linux/log2.h> 26#include <linux/delay.h> 27 28#define M41T62_REG_SSEC 0 29#define M41T62_REG_SEC 1 30#define M41T62_REG_MIN 2 31#define M41T62_REG_HOUR 3 32#define M41T62_REG_WDAY 4 33#define M41T62_REG_DAY 5 34#define M41T62_REG_MON 6 35#define M41T62_REG_YEAR 7 36#define M41T62_REG_ALARM_MON 0xa 37#define M41T62_REG_ALARM_DAY 0xb 38#define M41T62_REG_ALARM_HOUR 0xc 39#define M41T62_REG_ALARM_MIN 0xd 40#define M41T62_REG_ALARM_SEC 0xe 41#define M41T62_REG_FLAGS 0xf 42 43#define M41T62_DATETIME_REG_SIZE (M41T62_REG_YEAR + 1) 44#define M41T62_ALARM_REG_SIZE \ 45 (M41T62_REG_ALARM_SEC + 1 - M41T62_REG_ALARM_MON) 46 47#define M41T62_SEC_ST (1 << 7) /* ST: Stop Bit */ 48#define M41T62_ALMON_AFE (1 << 7) /* AFE: AF Enable Bit */ 49#define M41T62_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */ 50#define M41T62_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */ 51#define M41T62_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */ 52#define M41T62_FLAGS_OF (1 << 2) /* OF: Oscillator Flag Bit */ 53#define M41T62_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */ 54 55#define M41T62_WDAY_SQW_FREQ_MASK 0xf0 56#define M41T62_WDAY_SQW_FREQ_SHIFT 4 57 58#define M41T62_SQW_MAX_FREQ 32768 59 60#define M41T62_FEATURE_HT (1 << 0) 61#define M41T62_FEATURE_BL (1 << 1) 62 63#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */ 64 65static void m41t62_update_rtc_time(struct rtc_time *tm, u8 *buf) 66{ 67 debug("%s: raw read data - sec=%02x, min=%02x, hr=%02x, " 68 "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n", 69 __FUNCTION__, 70 buf[0], buf[1], buf[2], buf[3], 71 buf[4], buf[5], buf[6], buf[7]); 72 73 tm->tm_sec = bcd2bin(buf[M41T62_REG_SEC] & 0x7f); 74 tm->tm_min = bcd2bin(buf[M41T62_REG_MIN] & 0x7f); 75 tm->tm_hour = bcd2bin(buf[M41T62_REG_HOUR] & 0x3f); 76 tm->tm_mday = bcd2bin(buf[M41T62_REG_DAY] & 0x3f); 77 tm->tm_wday = buf[M41T62_REG_WDAY] & 0x07; 78 tm->tm_mon = bcd2bin(buf[M41T62_REG_MON] & 0x1f); 79 80 /* assume 20YY not 19YY, and ignore the Century Bit */ 81 /* U-Boot needs to add 1900 here */ 82 tm->tm_year = bcd2bin(buf[M41T62_REG_YEAR]) + 100 + 1900; 83 84 debug("%s: tm is secs=%d, mins=%d, hours=%d, " 85 "mday=%d, mon=%d, year=%d, wday=%d\n", 86 __FUNCTION__, 87 tm->tm_sec, tm->tm_min, tm->tm_hour, 88 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 89} 90 91static void m41t62_set_rtc_buf(const struct rtc_time *tm, u8 *buf) 92{ 93 debug("Set DATE: %4d-%02d-%02d (wday=%d) TIME: %2d:%02d:%02d\n", 94 tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday, 95 tm->tm_hour, tm->tm_min, tm->tm_sec); 96 97 /* Merge time-data and register flags into buf[0..7] */ 98 buf[M41T62_REG_SSEC] = 0; 99 buf[M41T62_REG_SEC] = 100 bin2bcd(tm->tm_sec) | (buf[M41T62_REG_SEC] & ~0x7f); 101 buf[M41T62_REG_MIN] = 102 bin2bcd(tm->tm_min) | (buf[M41T62_REG_MIN] & ~0x7f); 103 buf[M41T62_REG_HOUR] = 104 bin2bcd(tm->tm_hour) | (buf[M41T62_REG_HOUR] & ~0x3f) ; 105 buf[M41T62_REG_WDAY] = 106 (tm->tm_wday & 0x07) | (buf[M41T62_REG_WDAY] & ~0x07); 107 buf[M41T62_REG_DAY] = 108 bin2bcd(tm->tm_mday) | (buf[M41T62_REG_DAY] & ~0x3f); 109 buf[M41T62_REG_MON] = 110 bin2bcd(tm->tm_mon) | (buf[M41T62_REG_MON] & ~0x1f); 111 /* assume 20YY not 19YY */ 112 buf[M41T62_REG_YEAR] = bin2bcd(tm->tm_year % 100); 113} 114 115#ifdef CONFIG_DM_RTC 116static int m41t62_rtc_get(struct udevice *dev, struct rtc_time *tm) 117{ 118 u8 buf[M41T62_DATETIME_REG_SIZE]; 119 int ret; 120 121 ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); 122 if (ret) 123 return ret; 124 125 m41t62_update_rtc_time(tm, buf); 126 127 return 0; 128} 129 130static int m41t62_rtc_set(struct udevice *dev, const struct rtc_time *tm) 131{ 132 u8 buf[M41T62_DATETIME_REG_SIZE]; 133 int ret; 134 135 ret = dm_i2c_read(dev, 0, buf, sizeof(buf)); 136 if (ret) 137 return ret; 138 139 m41t62_set_rtc_buf(tm, buf); 140 141 ret = dm_i2c_write(dev, 0, buf, sizeof(buf)); 142 if (ret) { 143 printf("I2C write failed in %s()\n", __func__); 144 return ret; 145 } 146 147 return 0; 148} 149 150static int m41t62_sqw_enable(struct udevice *dev, bool enable) 151{ 152 u8 val; 153 int ret; 154 155 ret = dm_i2c_read(dev, M41T62_REG_ALARM_MON, &val, sizeof(val)); 156 if (ret) 157 return ret; 158 159 if (enable) 160 val |= M41T62_ALMON_SQWE; 161 else 162 val &= ~M41T62_ALMON_SQWE; 163 164 return dm_i2c_write(dev, M41T62_REG_ALARM_MON, &val, sizeof(val)); 165} 166 167static int m41t62_sqw_set_rate(struct udevice *dev, unsigned int rate) 168{ 169 u8 val, newval, sqwrateval; 170 int ret; 171 172 if (rate >= M41T62_SQW_MAX_FREQ) 173 sqwrateval = 1; 174 else if (rate >= M41T62_SQW_MAX_FREQ / 4) 175 sqwrateval = 2; 176 else if (rate) 177 sqwrateval = 15 - ilog2(rate); 178 179 ret = dm_i2c_read(dev, M41T62_REG_WDAY, &val, sizeof(val)); 180 if (ret) 181 return ret; 182 183 newval = val; 184 newval &= ~M41T62_WDAY_SQW_FREQ_MASK; 185 newval |= (sqwrateval << M41T62_WDAY_SQW_FREQ_SHIFT); 186 187 /* 188 * Try to avoid writing unchanged values. Writing to this register 189 * will reset the internal counter pipeline and thus affect system 190 * time. 191 */ 192 if (newval == val) 193 return 0; 194 195 return dm_i2c_write(dev, M41T62_REG_WDAY, &newval, sizeof(newval)); 196} 197 198static int m41t62_rtc_restart_osc(struct udevice *dev) 199{ 200 u8 val; 201 int ret; 202 203 /* 0. check if oscillator failure happened */ 204 ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val)); 205 if (ret) 206 return ret; 207 if (!(val & M41T62_FLAGS_OF)) 208 return 0; 209 210 ret = dm_i2c_read(dev, M41T62_REG_SEC, &val, sizeof(val)); 211 if (ret) 212 return ret; 213 214 /* 1. Set stop bit */ 215 val |= M41T62_SEC_ST; 216 ret = dm_i2c_write(dev, M41T62_REG_SEC, &val, sizeof(val)); 217 if (ret) 218 return ret; 219 220 /* 2. Clear stop bit */ 221 val &= ~M41T62_SEC_ST; 222 ret = dm_i2c_write(dev, M41T62_REG_SEC, &val, sizeof(val)); 223 if (ret) 224 return ret; 225 226 /* 3. wait 4 seconds */ 227 mdelay(4000); 228 229 ret = dm_i2c_read(dev, M41T62_REG_FLAGS, &val, sizeof(val)); 230 if (ret) 231 return ret; 232 233 /* 4. clear M41T62_FLAGS_OF bit */ 234 val &= ~M41T62_FLAGS_OF; 235 ret = dm_i2c_write(dev, M41T62_REG_FLAGS, &val, sizeof(val)); 236 if (ret) 237 return ret; 238 239 return 0; 240} 241 242static int m41t62_rtc_clear_ht(struct udevice *dev) 243{ 244 u8 val; 245 int ret; 246 247 /* 248 * M41T82: Make sure HT (Halt Update) bit is cleared. 249 * This bit is 0 in M41T62 so its save to clear it always. 250 */ 251 252 ret = dm_i2c_read(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val)); 253 if (ret) 254 return ret; 255 val &= ~M41T80_ALHOUR_HT; 256 ret = dm_i2c_write(dev, M41T62_REG_ALARM_HOUR, &val, sizeof(val)); 257 if (ret) 258 return ret; 259 260 return 0; 261} 262 263static int m41t62_rtc_reset(struct udevice *dev) 264{ 265 int ret; 266 267 ret = m41t62_rtc_restart_osc(dev); 268 if (ret) 269 return ret; 270 271 ret = m41t62_rtc_clear_ht(dev); 272 if (ret) 273 return ret; 274 275 /* 276 * Some boards feed the square wave as clock input into 277 * the SoC. This enables a 32.768kHz square wave, which is 278 * also the hardware default after power-loss. 279 */ 280 ret = m41t62_sqw_set_rate(dev, 32768); 281 if (ret) 282 return ret; 283 return m41t62_sqw_enable(dev, true); 284} 285 286static int m41t62_rtc_read8(struct udevice *dev, unsigned int reg) 287{ 288 return dm_i2c_reg_read(dev, reg); 289} 290 291static int m41t62_rtc_write8(struct udevice *dev, unsigned int reg, int val) 292{ 293 return dm_i2c_reg_write(dev, reg, val); 294} 295 296/* 297 * Make sure HT bit is cleared. This bit is set on entering battery backup 298 * mode, so do this before the first read access. 299 */ 300static int m41t62_rtc_probe(struct udevice *dev) 301{ 302 return m41t62_rtc_clear_ht(dev); 303} 304 305static const struct rtc_ops m41t62_rtc_ops = { 306 .get = m41t62_rtc_get, 307 .set = m41t62_rtc_set, 308 .reset = m41t62_rtc_reset, 309 .read8 = m41t62_rtc_read8, 310 .write8 = m41t62_rtc_write8, 311}; 312 313static const struct udevice_id m41t62_rtc_ids[] = { 314 { .compatible = "st,m41t62" }, 315 { .compatible = "st,m41t82" }, 316 { .compatible = "st,m41st87" }, 317 { .compatible = "microcrystal,rv4162" }, 318 { } 319}; 320 321U_BOOT_DRIVER(rtc_m41t62) = { 322 .name = "rtc-m41t62", 323 .id = UCLASS_RTC, 324 .of_match = m41t62_rtc_ids, 325 .ops = &m41t62_rtc_ops, 326 .probe = &m41t62_rtc_probe, 327}; 328 329#else /* NON DM RTC code - will be removed */ 330int rtc_get(struct rtc_time *tm) 331{ 332 u8 buf[M41T62_DATETIME_REG_SIZE]; 333 334 i2c_read(CFG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE); 335 m41t62_update_rtc_time(tm, buf); 336 337 return 0; 338} 339 340int rtc_set(struct rtc_time *tm) 341{ 342 u8 buf[M41T62_DATETIME_REG_SIZE]; 343 344 i2c_read(CFG_SYS_I2C_RTC_ADDR, 0, 1, buf, M41T62_DATETIME_REG_SIZE); 345 m41t62_set_rtc_buf(tm, buf); 346 347 if (i2c_write(CFG_SYS_I2C_RTC_ADDR, 0, 1, buf, 348 M41T62_DATETIME_REG_SIZE)) { 349 printf("I2C write failed in %s()\n", __func__); 350 return -1; 351 } 352 353 return 0; 354} 355 356void rtc_reset(void) 357{ 358 u8 val; 359 360 /* 361 * M41T82: Make sure HT (Halt Update) bit is cleared. 362 * This bit is 0 in M41T62 so its save to clear it always. 363 */ 364 i2c_read(CFG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1); 365 val &= ~M41T80_ALHOUR_HT; 366 i2c_write(CFG_SYS_I2C_RTC_ADDR, M41T62_REG_ALARM_HOUR, 1, &val, 1); 367} 368#endif /* CONFIG_DM_RTC */ 369