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 | /* * Driver for ST M41T94 SPI RTC * * Taken from the Linux kernel drivier: * Copyright (C) 2008 Kim B. Heino * * Adaptation for U-Boot: * Copyright (C) 2009 * Albin Tonnerre, Free Electrons <albin.tonnerre@free-electrons.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ #include <common.h> #include <rtc.h> #include <spi.h> static struct spi_slave *slave; #define M41T94_REG_SECONDS 0x01 #define M41T94_REG_MINUTES 0x02 #define M41T94_REG_HOURS 0x03 #define M41T94_REG_WDAY 0x04 #define M41T94_REG_DAY 0x05 #define M41T94_REG_MONTH 0x06 #define M41T94_REG_YEAR 0x07 #define M41T94_REG_HT 0x0c #define M41T94_BIT_HALT 0x40 #define M41T94_BIT_STOP 0x80 #define M41T94_BIT_CB 0x40 #define M41T94_BIT_CEB 0x80 int rtc_set(struct rtc_time *tm) { u8 buf[8]; /* write cmd + 7 registers */ int ret; if (!slave) { slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS, CONFIG_M41T94_SPI_CS, 1000000, SPI_MODE_3); if (!slave) return -1; } spi_claim_bus(slave); buf[0] = 0x80 | M41T94_REG_SECONDS; /* write time + date */ buf[M41T94_REG_SECONDS] = bin2bcd(tm->tm_sec); buf[M41T94_REG_MINUTES] = bin2bcd(tm->tm_min); buf[M41T94_REG_HOURS] = bin2bcd(tm->tm_hour); buf[M41T94_REG_WDAY] = bin2bcd(tm->tm_wday + 1); buf[M41T94_REG_DAY] = bin2bcd(tm->tm_mday); buf[M41T94_REG_MONTH] = bin2bcd(tm->tm_mon + 1); buf[M41T94_REG_HOURS] |= M41T94_BIT_CEB; if (tm->tm_year >= 100) buf[M41T94_REG_HOURS] |= M41T94_BIT_CB; buf[M41T94_REG_YEAR] = bin2bcd(tm->tm_year % 100); ret = spi_xfer(slave, 64, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); spi_release_bus(slave); return ret; } int rtc_get(struct rtc_time *tm) { u8 buf[2]; int ret, hour; if (!slave) { slave = spi_setup_slave(CONFIG_M41T94_SPI_BUS, CONFIG_M41T94_SPI_CS, 1000000, SPI_MODE_3); if (!slave) return -1; } spi_claim_bus(slave); /* clear halt update bit */ ret = spi_w8r8(slave, M41T94_REG_HT); if (ret < 0) return ret; if (ret & M41T94_BIT_HALT) { buf[0] = 0x80 | M41T94_REG_HT; buf[1] = ret & ~M41T94_BIT_HALT; spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); } /* clear stop bit */ ret = spi_w8r8(slave, M41T94_REG_SECONDS); if (ret < 0) return ret; if (ret & M41T94_BIT_STOP) { buf[0] = 0x80 | M41T94_REG_SECONDS; buf[1] = ret & ~M41T94_BIT_STOP; spi_xfer(slave, 16, buf, NULL, SPI_XFER_BEGIN | SPI_XFER_END); } tm->tm_sec = bcd2bin(spi_w8r8(slave, M41T94_REG_SECONDS)); tm->tm_min = bcd2bin(spi_w8r8(slave, M41T94_REG_MINUTES)); hour = spi_w8r8(slave, M41T94_REG_HOURS); tm->tm_hour = bcd2bin(hour & 0x3f); tm->tm_wday = bcd2bin(spi_w8r8(slave, M41T94_REG_WDAY)) - 1; tm->tm_mday = bcd2bin(spi_w8r8(slave, M41T94_REG_DAY)); tm->tm_mon = bcd2bin(spi_w8r8(slave, M41T94_REG_MONTH)) - 1; tm->tm_year = bcd2bin(spi_w8r8(slave, M41T94_REG_YEAR)); if ((hour & M41T94_BIT_CB) || !(hour & M41T94_BIT_CEB)) tm->tm_year += 100; spi_release_bus(slave); return 0; } void rtc_reset(void) { /* * Could not be tested as the reset pin is not wired on * the sbc35-ag20 board */ } |