diff options
author | Bitan Biswas <bbiswas@nvidia.com> | 2010-01-14 13:56:12 +0530 |
---|---|---|
committer | Bitan Biswas <bbiswas@nvidia.com> | 2010-01-27 21:59:45 +0530 |
commit | 6f22dfd98979b723b6021a3b882e6944cfac79b6 (patch) | |
tree | 713f7c0b8110c967b010e306e07c948ba2db3a83 /arch | |
parent | 98b49ac44d0ce8be847f6272d97dedfd166b6a6d (diff) |
tegra2 rtc: date/time non-persistent on boards
Multi-stage Changes are as follows:
Change1:
1) TPS6586x PMU RTC(harmony) cannot store more than 34 years duration.
Hence, RTC driver has been modified to use year 2009 as reference
instead of the year 1970(used in linux by default). Change in
tps6586x rtc implementation.
Issue was Fixed in Bug 621031 earlier and checked into p4 by modifying
tegra rtc driver. We are using a different approach now by only
modifying tps6586x rtc driver. This way rtc drivers for other PMU
like max8907b which can store as much 9999 years in RTC do not need
to change.
2) MAX8907B PMU RTC(whistler) driver was not storing day/month/year data
earlier. Further, on every boot the RTC was being cleared. Fixed this
in file max8907b_rtc.c
Implementation specific to linux as uses library functions: mktime and
rtc_time_to_tm
3) MAX8907B PMU I2C read API implementation was not reading 4th byte.
Changed this as DD, MM, YY1, YY2 information is being read now.
Changed max8907b_i2c.c Further, changes are as follows:
Change2:
1) TPS6586x PMU RTC(harmony) driver modified to select crystal oscillator
as source for RTC. After this change find that RTC counts even when
harmony is powered off.
2) MAX8907B PMU RTC(whistler) driver modified to incorporate review
comments
a) renamed macro SHIFT_TO_2009 as OFFSET_BASE_YEAR
b) used a macro for BCD to decimal conversion for better readability.
Change set 1 was committed but was reverted because of bugs 645312
and 645286. Further tests showed that if the date is set before
testing gallery app the issue is not seen. Trying to re-submit
reverted checkin for change1 along with change2 as a new change.
Change3:
a) decimal to bcd expresssion converted to macro
b) corrected spelling
Bug 625990 : [Firefly2/Harmony] Date & Time is not persisting after reboot
Tested on : Harmony + whistler. Date/time persists.
Note: Whistler rechargable battery needs to be charged to 2.4V for
RTC data to persist. Harmony has non-rechargable battery.
Change-Id: Icc543261096ee4c89cc1e394e2b3868ac370f8e9
Diffstat (limited to 'arch')
3 files changed, 297 insertions, 162 deletions
diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c index 6e61ddd95135..0f7a09446876 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_i2c.c @@ -37,6 +37,9 @@ #define MAX8907B_I2C_SPEED_KHZ 400 #define MAX8907B_I2C_RETRY_CNT 2 +// Maximum i2c transaction count +#define MAX_TRANSACTION_COUNT 5 + NvBool Max8907bI2cWrite8( NvOdmPmuDeviceHandle hDevice, NvU8 Addr, @@ -45,14 +48,14 @@ NvBool Max8907bI2cWrite8( NvU32 i; NvU8 WriteBuffer[2]; NvOdmI2cTransactionInfo TransactionInfo; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { WriteBuffer[0] = Addr & 0xFF; // PMU offset WriteBuffer[1] = Data & 0xFF; // written data - + TransactionInfo.Address = hPmu->DeviceAddr; TransactionInfo.Buf = &WriteBuffer[0]; TransactionInfo.Flags = NVODM_I2C_IS_WRITE; @@ -69,12 +72,12 @@ NvBool Max8907bI2cWrite8( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cWrite8 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -86,28 +89,30 @@ NvBool Max8907bI2cRead8( { NvU32 i; NvU8 ReadBuffer = 0; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo[2]; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { + NvU32 TransactionCount = 0; // Write the PMU offset ReadBuffer = Addr & 0xFF; - TransactionInfo[0].Address = hPmu->DeviceAddr; - TransactionInfo[0].Buf = &ReadBuffer; - TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; - TransactionInfo[0].NumBytes = 1; + TransactionInfo[TransactionCount].Address = hPmu->DeviceAddr; + TransactionInfo[TransactionCount].Buf = &ReadBuffer; + TransactionInfo[TransactionCount].Flags = + NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; + TransactionInfo[TransactionCount++].NumBytes = 1; - TransactionInfo[1].Address = (hPmu->DeviceAddr | 0x1); - TransactionInfo[1].Buf = &ReadBuffer; - TransactionInfo[1].Flags = 0; - TransactionInfo[1].NumBytes = 1; + TransactionInfo[TransactionCount].Address = (hPmu->DeviceAddr | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; // Read data from PMU at the specified offset - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 2, - MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], + TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) { @@ -120,12 +125,12 @@ NvBool Max8907bI2cRead8( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cRead8 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -137,13 +142,13 @@ NvBool Max8907bI2cWrite32( { NvU32 i; NvU8 WriteBuffer[5]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { - WriteBuffer[0] = (NvU8)(Addr & 0xFF); + WriteBuffer[0] = (NvU8)(Addr & 0xFF); WriteBuffer[1] = (NvU8)((Data >> 24) & 0xFF); WriteBuffer[2] = (NvU8)((Data >> 16) & 0xFF); WriteBuffer[3] = (NvU8)((Data >> 8) & 0xFF); @@ -154,7 +159,7 @@ NvBool Max8907bI2cWrite32( TransactionInfo.Flags = NVODM_I2C_IS_WRITE; TransactionInfo.NumBytes = 5; - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) @@ -165,12 +170,12 @@ NvBool Max8907bI2cWrite32( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cWrite32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -182,30 +187,32 @@ NvBool Max8907bI2cRead32( { NvU32 i; NvU8 ReadBuffer[5]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo[2]; for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { + NvU32 TransactionCount = 0; ReadBuffer[0] = Addr & 0xFF; - TransactionInfo[0].Address = hPmu->DeviceAddr; - TransactionInfo[0].Buf = &ReadBuffer[0]; - TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; - TransactionInfo[0].NumBytes = 1; + TransactionInfo[TransactionCount].Address = hPmu->DeviceAddr; + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = + NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; + TransactionInfo[TransactionCount++].NumBytes = 1; - TransactionInfo[1].Address = (hPmu->DeviceAddr | 0x1); - TransactionInfo[1].Buf = &ReadBuffer[0]; - TransactionInfo[1].Flags = 0; - TransactionInfo[1].NumBytes = 4; + TransactionInfo[TransactionCount].Address = (hPmu->DeviceAddr | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 4; - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 2, - MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], + TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) { - *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | + *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | (ReadBuffer[2] << 8) | ReadBuffer[3]; return NV_TRUE; @@ -216,12 +223,12 @@ NvBool Max8907bI2cRead32( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("NvOdmPmuI2cRead32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -233,13 +240,14 @@ NvBool Max8907bRtcI2cWriteTime( { NvU32 i; NvU8 WriteBuffer[5]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; NvOdmI2cTransactionInfo TransactionInfo; + NVODMPMU_PRINTF(("\n RTC I2C write: Addr=0x%x, Data=0x%x ", Addr, Data)); for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { - WriteBuffer[0] = (NvU8)(Addr & 0xFF); + WriteBuffer[0] = (NvU8)(Addr & 0xFF); WriteBuffer[1] = (NvU8)((Data >> 24) & 0xFF); WriteBuffer[2] = (NvU8)((Data >> 16) & 0xFF); WriteBuffer[3] = (NvU8)((Data >> 8) & 0xFF); @@ -250,7 +258,7 @@ NvBool Max8907bRtcI2cWriteTime( TransactionInfo.Flags = NVODM_I2C_IS_WRITE; TransactionInfo.NumBytes = 5; - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo, 1, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) @@ -261,12 +269,12 @@ NvBool Max8907bRtcI2cWriteTime( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("Max8907bRtcI2cWrite32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } @@ -278,46 +286,63 @@ NvBool Max8907bRtcI2cReadTime( { NvU32 i; NvU8 ReadBuffer[4]; - NvOdmI2cStatus status = NvOdmI2cStatus_Success; + NvOdmI2cStatus status = NvOdmI2cStatus_Success; Max8907bPrivData *hPmu = (Max8907bPrivData*)hDevice->pPrivate; - NvOdmI2cTransactionInfo TransactionInfo[4]; + NvOdmI2cTransactionInfo TransactionInfo[MAX_TRANSACTION_COUNT]; + NVODMPMU_PRINTF(("\n RTC I2C read: Addr=0x%x ", Addr)); for (i = 0; i < MAX8907B_I2C_RETRY_CNT; i++) { - ReadBuffer[0] = Addr++ & 0xFF; - ReadBuffer[1] = Addr++ & 0xFF; - ReadBuffer[2] = Addr++ & 0xFF; - ReadBuffer[3] = 0; - - TransactionInfo[0].Address = MAX8907B_RTC_SLAVE_ADDR; - TransactionInfo[0].Buf = &ReadBuffer[0]; - TransactionInfo[0].Flags = NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; - TransactionInfo[0].NumBytes = 1; - - // Seconds - TransactionInfo[1].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1); - TransactionInfo[1].Buf = &ReadBuffer[0]; - TransactionInfo[1].Flags = 0; - TransactionInfo[1].NumBytes = 1; - - // Minutes - TransactionInfo[2].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1); - TransactionInfo[2].Buf = &ReadBuffer[1]; - TransactionInfo[2].Flags = 0; - TransactionInfo[2].NumBytes = 1; - - // Hours - TransactionInfo[3].Address = (MAX8907B_RTC_SLAVE_ADDR | 0x1); - TransactionInfo[3].Buf = &ReadBuffer[2]; - TransactionInfo[3].Flags = 0; - TransactionInfo[3].NumBytes = 1; - - status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], 4, - MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); + NvU32 TransactionCount = 0; + ReadBuffer[0] = Addr & 0xFF; + TransactionInfo[TransactionCount].Address = MAX8907B_RTC_SLAVE_ADDR; + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = + NVODM_I2C_IS_WRITE | NVODM_I2C_USE_REPEATED_START; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Seconds / day + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[0]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Minutes / month + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[1]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Hours / YY1 + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[2]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + // Weekday / YY2 + if (TransactionCount >= MAX_TRANSACTION_COUNT) + return NV_FALSE; + TransactionInfo[TransactionCount].Address = + (MAX8907B_RTC_SLAVE_ADDR | 0x1); + TransactionInfo[TransactionCount].Buf = &ReadBuffer[3]; + TransactionInfo[TransactionCount].Flags = 0; + TransactionInfo[TransactionCount++].NumBytes = 1; + + status = NvOdmI2cTransaction(hPmu->hOdmI2C, &TransactionInfo[0], + TransactionCount, MAX8907B_I2C_SPEED_KHZ, NV_WAIT_INFINITE); if (status == NvOdmI2cStatus_Success) { - *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | + *Data = (ReadBuffer[0] << 24) | (ReadBuffer[1] << 16) | (ReadBuffer[2] << 8) | ReadBuffer[3]; return NV_TRUE; @@ -328,12 +353,12 @@ NvBool Max8907bRtcI2cReadTime( switch (status) { case NvOdmI2cStatus_Timeout: - NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: Timeout\n")); + NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: Timeout\n")); break; case NvOdmI2cStatus_SlaveNotFound: default: NVODMPMU_PRINTF(("Max8907bRtcI2cRead32 Failed: SlaveNotFound\n")); - break; + break; } return NV_FALSE; } diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c index 0c179efdf21c..88bfa06fa940 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/max8907b/max8907b_rtc.c @@ -30,151 +30,224 @@ * */ +#include <linux/time.h> +#include <linux/rtc.h> #include "max8907b.h" #include "max8907b_rtc.h" #include "max8907b_i2c.h" #include "max8907b_reg.h" -/** +/** * The Maxim 8907B does not have an RTC that simply counts * seconds from some time t0 (as defined by the OS API). * Instead, this RTC contains several BCD (Binary Coded Decimal) * registers, including: seconds, minutes, hours, days, day of * week, date, etc... These registers account for leap year and * the various days of the month as well. -* +* * Since the OS interpretation of seconds to a particular * date/time from some OS-defined t0 is unknown at this level of * the implementation, it is not possible to translate the given * seconds into these registers (at least, not without a * dependency on some OS-specific information). -* -* Therefore, this implementation contains a static variable -* (RtcDays) which is derived from the number of seconds given -* when Max8907bRtcCountWrite() is called. The seconds, minutes -* and hours are then programmed to the RTC and used to keep -* track of the current time within the day. -* -* TO DO: Increment the day whenever it rolls over (requires -* handling an interrupt at midnight each day). +* */ #define MAX8907B_SECONDS_PER_DAY (60*60*24) #define MAX8907B_SECONDS_PER_HOUR (60*60) #define MAX8907B_SECONDS_PER_MINUTE (60) +#define LINUX_RTC_BASE_YEAR 1900 + +/* Macro for conversion of BCD number to decimal format */ +#define BCD_TO_DECIMAL(BCD) \ + ((((BCD) & 0xF0) >> 4) * 10 + ((BCD) & 0xF)) +/* Macro for conversion of decimal number to BCD format */ +#define DECIMAL_TO_BCD(DEC) \ + ((((DEC) / 10) << 4) | ((DEC) % 10)) + static NvBool bRtcNotInitialized = NV_TRUE; -static NvU32 RtcDays = 0; -NvBool +NvBool Max8907bRtcCountRead( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32* Count) { NvU32 data = 0; NvU32 BcdHours, BcdMinutes, BcdSeconds; NvU32 Hours, Minutes, Seconds; + NvU32 BcdDD, BcdMM, BcdYY1, BcdYY2; + NvU32 DD, MM, YY1, YY2, YYYY; +#if NV_DEBUG + struct rtc_time tm; +#endif - if (Max8907bRtcWasStartUpFromNoPower(hDevice) && bRtcNotInitialized) - { - Max8907bRtcCountWrite(hDevice, 0); - *Count = 0; - } - else + *Count = 0; + // Read seconds, minute, hour and weekday data from RTC registers + if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_SEC, &data)) { - if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_SEC, &data)) - { - - BcdHours = (data >> 8) & 0xFF; - BcdMinutes = (data >> 16) & 0xFF; - BcdSeconds = (data >> 24) & 0xFF; + NVODMPMU_PRINTF(("\n Read time data-sec=0x%x ", data)); + // Extract seconds, minute and hour data from RTC registers read + BcdHours = (data >> 8) & 0xFF; + BcdMinutes = (data >> 16) & 0xFF; + BcdSeconds = (data >> 24) & 0xFF; - Hours = ((BcdHours & 0xF0)>>4)*10 + (BcdHours & 0xF); - Minutes = ((BcdMinutes & 0xF0)>>4)*10 + (BcdMinutes & 0xF); - Seconds = ((BcdSeconds & 0xF0)>>4)*10 + (BcdSeconds & 0xF); + // Convert BCD time into decimal values + Hours = BCD_TO_DECIMAL(BcdHours); + Minutes = BCD_TO_DECIMAL(BcdMinutes); + Seconds = BCD_TO_DECIMAL(BcdSeconds); - *Count = (Hours * MAX8907B_SECONDS_PER_HOUR) + - (Minutes * MAX8907B_SECONDS_PER_MINUTE) + Seconds; + // Read day, month, yy1 and yy2 data from RTC registers + if (Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_DATE, &data)) + { + NVODMPMU_PRINTF(("\n Read time data-year=0x%x ", data)); + // Extract day, month, yy1 and yy2 data from RTC registers read + BcdYY2 = (data & 0xFF); + BcdYY1 = (data >> 8) & 0xFF; + BcdMM = (data >> 16) & 0xFF; + BcdDD = (data >> 24) & 0xFF; + // convert bcd day/month/year data to decimal values + YY2 = BCD_TO_DECIMAL(BcdYY2); + YY1 = BCD_TO_DECIMAL(BcdYY1); + YYYY = (YY2 * 100 + YY1) & 0xFFFF; + MM = BCD_TO_DECIMAL(BcdMM); + DD = BCD_TO_DECIMAL(BcdDD); + // get seconds since reference time value given + // year, month, day, hour, minutes and seconds + // NOTE: Using linux specific API mktime for conversion + *Count = mktime(YYYY, (MM + 1), DD, Hours, Minutes, Seconds); + NVODMPMU_PRINTF(("\n Rtc read count=0x%x ", *Count)); + NVODMPMU_PRINTF(("\n mktime: YYYY=%d MM=%d DD=%d Hr=%d Min=%d " + "Sec=%d, *Count=0x%x ", YYYY, (MM + 1), DD, Hours, Minutes, + Seconds, *Count)); +#if NV_DEBUG + // Call to verify that reverse conversion of seconds matches date + rtc_time_to_tm(*Count, &tm); + // Check if Local_rtc_time_to_tm can return values sent to mktime + NVODMPMU_PRINTF(("\n rtc_time_to_tm: YYYY=%d MM=%d DD=%d Hr=%d " + "Min=%d Sec=%d, *Count=0x%x ", (tm.tm_year + + LINUX_RTC_BASE_YEAR), tm.tm_mon, tm.tm_mday, tm.tm_hour, + tm.tm_min, tm.tm_sec, *Count)); +#endif } else { - NvOdmOsDebugPrintf("Max8907bRtcCountRead() error. "); + NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. ")); return NV_FALSE; } } + else + { + NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. ")); + return NV_FALSE; + } + NVODMPMU_PRINTF(("\n *Count=0x%x ", *Count)); return NV_TRUE; } -NvBool +NvBool Max8907bRtcAlarmCountRead( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32* Count) { return NV_FALSE; } -NvBool +NvBool Max8907bRtcCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { - NvU32 Hours, Minutes, Seconds; NvU32 BcdHours, BcdMinutes, BcdSeconds; NvU32 data = 0; + NvU8 BcdDD, BcdMM, BcdYY1, BcdYY2; + NvU16 YYYY; + struct rtc_time tm; + NvU32 data1; - BcdHours = BcdMinutes = BcdSeconds = 0; - - RtcDays = Count / MAX8907B_SECONDS_PER_DAY; + NVODMPMU_PRINTF(("\n Rtc write count=0x%x ", Count)); + // convert seconds since reference time into date + // NOTE: using linux specific convert function rtc_time_to_tm + rtc_time_to_tm(Count, &tm); + NVODMPMU_PRINTF(("\n rtc_time_to_tm: YYYY=%d MM=%d DD=%d Hr=%d Min=%d " + "Sec=%d, *Count=0x%x ", (tm.tm_year + LINUX_RTC_BASE_YEAR), + (tm.tm_mon + 1), tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, Count)); - Hours = (Count % MAX8907B_SECONDS_PER_DAY) / MAX8907B_SECONDS_PER_HOUR; - Minutes = ((Count % MAX8907B_SECONDS_PER_DAY) % MAX8907B_SECONDS_PER_HOUR) / MAX8907B_SECONDS_PER_MINUTE; - Seconds = Count % MAX8907B_SECONDS_PER_MINUTE; - - BcdHours = (( Hours/10) << 4) | ( Hours%10); - BcdMinutes = ((Minutes/10) << 4) | (Minutes%10); - BcdSeconds = ((Seconds/10) << 4) | (Seconds%10); + // Convert time to bcd format + BcdHours = DECIMAL_TO_BCD(tm.tm_hour); + BcdMinutes = DECIMAL_TO_BCD(tm.tm_min); + BcdSeconds = DECIMAL_TO_BCD(tm.tm_sec); data = (BcdSeconds << 24) | (BcdMinutes << 16) | (BcdHours << 8); + // write time - seconds, minutes and hours in a day to RTC registers if (Max8907bRtcI2cWriteTime(hDevice, MAX8907B_RTC_SEC, data)) { - bRtcNotInitialized = NV_FALSE; - return NV_TRUE; + // set the day, month, year + // Assuming we get the days since 1 Jan 1970 + + // convert date to bcd format + BcdDD = DECIMAL_TO_BCD((NvU8)tm.tm_mday); + BcdMM = DECIMAL_TO_BCD((NvU8)tm.tm_mon); + YYYY = (NvU16)tm.tm_year + LINUX_RTC_BASE_YEAR; + BcdYY1 = DECIMAL_TO_BCD((NvU8)(YYYY % 100)); + BcdYY2 = DECIMAL_TO_BCD((NvU8)(YYYY / 100)); + data = (NvU32)((BcdDD << 24) | (BcdMM << 16) | (BcdYY1 << 8) | BcdYY2); + // write date - day, month, and year to RTC registers + if (!(Max8907bRtcI2cWriteTime(hDevice, MAX8907B_RTC_DATE, data))) + { + NVODMPMU_PRINTF(("\n Max8907bRtcCountWrite() error. ")); + return NV_FALSE; + } +#if NV_DEBUG + // verify that read back values from RTC matches written values + if (!(Max8907bRtcI2cReadTime(hDevice, MAX8907B_RTC_DATE, &data1))) + { + NVODMPMU_PRINTF(("\n Max8907bRtcCountRead() error. ")); + return NV_FALSE; + } + if (data1 == data) + { + NVODMPMU_PRINTF(("\n Write read Success. ")); + return NV_TRUE; + } + else + { + // return error when read data does not match written data + NVODMPMU_PRINTF(("\n Error: write data=0x%x, rd data=0x%x. ", data, data1)); + return NV_FALSE; + } +#endif } else { - NvOdmOsDebugPrintf("Max8907bRtcCountWrite() error. "); + NVODMPMU_PRINTF(("\n Max8907bRtcCountWrite() error. ")); return NV_FALSE; } } -NvBool +NvBool Max8907bRtcAlarmCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { return NV_FALSE; } -NvBool +NvBool Max8907bRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice) { return NV_FALSE; } -NvBool +NvBool Max8907bRtcAlarmIntEnable( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvBool Enable) { return NV_FALSE; } -NvBool -Max8907bRtcWasStartUpFromNoPower(NvOdmPmuDeviceHandle hDevice) -{ - return NV_TRUE; -} - NvBool Max8907bIsRtcInitialized(NvOdmPmuDeviceHandle hDevice) { diff --git a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c index d897eb9f4ee3..889cf2bbc6ff 100644 --- a/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c +++ b/arch/arm/mach-tegra/odm_kit/adaptations/pmu/tps6586x/nvodm_pmu_tps6586x_rtc.c @@ -30,10 +30,20 @@ * */ +#include <linux/time.h> #include "nvodm_pmu_tps6586x_rtc.h" #include "nvodm_pmu_tps6586x_i2c.h" #include "tps6586x_reg.h" +// macro OFFSET_BASE_YEAR if 1, uses epoch as reference year instead of 1970 +// This is because RTC in PMU TPS6586x can store duration of 34 years, +// else we cannot retain date beyond 2004 +#define OFFSET_BASE_YEAR 1 +#if OFFSET_BASE_YEAR +static unsigned long epoch = 2009; +static unsigned long epoch_sec = 0; +#endif + static NvBool bRtcNotInitialized = NV_TRUE; /* Read RTC count register */ @@ -43,12 +53,12 @@ Tps6586xRtcCountRead( NvU32* Count) { NvU32 ReadBuffer[2]; - + // 1) The I2C address pointer must not be left pointing in the range 0xC6 to 0xCA // 2) The maximum time for the address pointer to be in this range is 1ms // 3) Always read RTC_ALARM2 in the following order to prevent the address pointer - // from stopping at 0xC6: RTC_ALARM2_LO, then RTC_ALARM2_HI - + // from stopping at 0xC6: RTC_ALARM2_LO, then RTC_ALARM2_HI + if (Tps6586xRtcWasStartUpFromNoPower(hDevice) && bRtcNotInitialized) { Tps6586xRtcCountWrite(hDevice, 0); @@ -59,55 +69,82 @@ Tps6586xRtcCountRead( // The unit of the RTC count is second!!! 1024 tick = 1s. // Read all 40 bit and right move 10 = Read the hightest 32bit and right move 2 Tps6586xI2cRead32(hDevice, TPS6586x_RC6_RTC_COUNT4, &ReadBuffer[0]); - + Tps6586xI2cRead8(hDevice, TPS6586x_RCA_RTC_COUNT0, &ReadBuffer[1]); - + Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer[1]); - + // return second *Count = ReadBuffer[0]>>2; } - +#if OFFSET_BASE_YEAR + // calculate epoch_sec once + if (!epoch_sec) + epoch_sec = mktime(epoch,1,1,0,0,0); + *Count += epoch_sec; +#endif + return NV_TRUE; } /* Write RTC count register */ -NvBool +NvBool Tps6586xRtcCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { NvU32 ReadBuffer = 0; - +#if OFFSET_BASE_YEAR + // calculate epoch_sec once + if (!epoch_sec) + epoch_sec = mktime(epoch,1,1,0,0,0); + if (Count < (NvU32)epoch_sec) + { + // prevent setting date earlier than 'epoch' + pr_warning("\n Date being set cannot be earlier than least " + "year=%d. Setting as least year. ", (int)epoch); + // base year seconds count is 0 + Count = 0; + } + else + Count -= (NvU32)epoch_sec; +#endif + + // Switch to 32KHz crystal oscillator + // POR_SRC_SEL=1 and OSC_SRC_SEL=1 + Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer); + ReadBuffer = ReadBuffer | 0xC0; + Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer); + // To enable incrementing of the RTC_COUNT[39:0] from an initial value set by the host, - // the RTC_ENABLE bit should be written to 1 only after the RTC_OUT voltage reaches + // the RTC_ENABLE bit should be written to 1 only after the RTC_OUT voltage reaches // the operating range - + // Clear RTC_ENABLE before writing RTC_COUNT Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer); ReadBuffer = ReadBuffer & 0xDF; Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer); - + Tps6586xI2cWrite32(hDevice, TPS6586x_RC6_RTC_COUNT4, (Count<<2)); - Tps6586xI2cWrite8(hDevice, TPS6586x_RCA_RTC_COUNT0, 0); - + Tps6586xI2cWrite8(hDevice, TPS6586x_RCA_RTC_COUNT0, 0); + // Set RTC_ENABLE after writing RTC_COUNT Tps6586xI2cRead8(hDevice, TPS6586x_RC0_RTC_CTRL, &ReadBuffer); ReadBuffer = ReadBuffer | 0x20; Tps6586xI2cWrite8(hDevice, TPS6586x_RC0_RTC_CTRL, ReadBuffer); - + if (bRtcNotInitialized) bRtcNotInitialized = NV_FALSE; - + return NV_TRUE; } /* Read RTC alarm count register */ -NvBool +NvBool Tps6586xRtcAlarmCountRead( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32* Count) { return NV_FALSE; @@ -115,9 +152,9 @@ Tps6586xRtcAlarmCountRead( /* Write RTC alarm count register */ -NvBool +NvBool Tps6586xRtcAlarmCountWrite( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvU32 Count) { return NV_FALSE; @@ -125,7 +162,7 @@ Tps6586xRtcAlarmCountWrite( /* Reads RTC alarm interrupt mask status */ -NvBool +NvBool Tps6586xRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice) { return NV_FALSE; @@ -133,9 +170,9 @@ Tps6586xRtcIsAlarmIntEnabled(NvOdmPmuDeviceHandle hDevice) /* Enables / Disables the RTC alarm interrupt */ -NvBool +NvBool Tps6586xRtcAlarmIntEnable( - NvOdmPmuDeviceHandle hDevice, + NvOdmPmuDeviceHandle hDevice, NvBool Enable) { return NV_FALSE; @@ -143,7 +180,7 @@ Tps6586xRtcAlarmIntEnable( /* Checks if boot was from nopower / powered state */ -NvBool +NvBool Tps6586xRtcWasStartUpFromNoPower(NvOdmPmuDeviceHandle hDevice) { NvU32 Data = 0; |