Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:47

0001 /*
0002  * This file interfaces with the real-time clock found in a
0003  * Dallas Semiconductor DS1307/DS1308 serial real-time clock chip.
0004  * This RTC have I2C bus interface. BSP have to provide I2C bus primitives
0005  * to make this driver working. getRegister and setRegister primitives is
0006  * not used here to avoid multiple transactions over I2C bus (each transaction
0007  * require significant time and error when date/time information red may
0008  * occurs). ulControlPort contains I2C bus number; ulDataPort contains
0009  * RTC I2C device address.
0010  *
0011  * Year 2000 Note:
0012  *
0013  * This chip only uses a two digit field to store the year. This code
0014  * uses the RTEMS Epoch as a pivot year. This lets us map the two digit
0015  * year field as follows:
0016  *
0017  *    + two digit years 00-87 are mapped to 2000-2087
0018  *    + two digit years 88-99 are mapped to 1988-1999
0019  */
0020 
0021 /*
0022  * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
0023  * Author: Victor V. Vengerov <vvv@oktet.ru>
0024  *
0025  * The license and distribution terms for this file may be
0026  * found in the file LICENSE in this distribution or at
0027  * http://www.rtems.org/license/LICENSE.
0028  */
0029 
0030 #include <rtems.h>
0031 #include <libchip/rtc.h>
0032 #include <string.h>
0033 #include "ds1307.h"
0034 #include "i2c.h"
0035 
0036 /* Convert from/to Binary-Coded Decimal representation */
0037 #define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
0038 #define To_BCD( _x )   ((((_x) / 10) << 4) + ((_x) % 10))
0039 
0040 /* ds1307_initialize --
0041  *     Initialize DS1307 real-time clock chip. If RTC is halted, this
0042  *     function resume counting.
0043  *
0044  * PARAMETERS:
0045  *     minor -- minor RTC device number
0046  */
0047 static void ds1307_initialize(int minor)
0048 {
0049   i2c_message_status status;
0050   int try;
0051   uint8_t         sec;
0052   i2c_bus_number bus;
0053   i2c_address addr;
0054 
0055   bus = RTC_Table[minor].ulCtrlPort1;
0056   addr = RTC_Table[minor].ulDataPort;
0057 
0058   /* Read SECONDS register */
0059   try = 0;
0060   do {
0061     status = i2c_wbrd(bus, addr, 0, &sec, sizeof(sec));
0062     try++;
0063   } while ((status != I2C_SUCCESSFUL) && (try < 15));
0064 
0065   /* If clock is halted, reset and start the clock */
0066   if ((sec & DS1307_SECOND_HALT) != 0) {
0067       uint8_t         start[8];
0068       memset(start, 0, sizeof(start));
0069       start[0] = DS1307_SECOND;
0070       try = 0;
0071       do {
0072       status = i2c_write(bus, addr, start, 2);
0073       } while ((status != I2C_SUCCESSFUL) && (try < 15));
0074   }
0075 }
0076 
0077 /* ds1307_get_time --
0078  *     read current time from DS1307 real-time clock chip and convert it
0079  *     to the rtems_time_of_day structure.
0080  *
0081  * PARAMETERS:
0082  *     minor -- minor RTC device number
0083  *     time -- place to put return value (date and time)
0084  *
0085  * RETURNS:
0086  *     0, if time obtained successfully
0087  *     -1, if error occured
0088  */
0089 static int ds1307_get_time(int minor, rtems_time_of_day *time)
0090 {
0091   i2c_bus_number bus;
0092   i2c_address addr;
0093   uint8_t         info[8];
0094   uint32_t         v1, v2;
0095   i2c_message_status status;
0096   int try;
0097 
0098   if (time == NULL)
0099     return -1;
0100 
0101   bus = RTC_Table[minor].ulCtrlPort1;
0102   addr = RTC_Table[minor].ulDataPort;
0103 
0104   memset(time, 0, sizeof(rtems_time_of_day));
0105   try = 0;
0106   do {
0107     status = i2c_wbrd(bus, addr, 0, info, sizeof(info));
0108     try++;
0109   } while ((status != I2C_SUCCESSFUL) && (try < 10));
0110 
0111   if (status != I2C_SUCCESSFUL) {
0112     return -1;
0113   }
0114 
0115   v1 = info[DS1307_YEAR];
0116   v2 = From_BCD(v1);
0117   if (v2 < 88)
0118     time->year = 2000 + v2;
0119   else
0120     time->year = 1900 + v2;
0121 
0122   v1 = info[DS1307_MONTH] & ~0xE0;
0123   time->month = From_BCD(v1);
0124 
0125   v1 = info[DS1307_DAY] & ~0xC0;
0126   time->day = From_BCD(v1);
0127 
0128   v1 = info[DS1307_HOUR];
0129   if (v1 & DS1307_HOUR_12) {
0130     v2 = v1 & ~0xE0;
0131     if (v1 & DS1307_HOUR_PM) {
0132       time->hour = From_BCD(v2) + 12;
0133     } else {
0134       time->hour = From_BCD(v2);
0135     }
0136   } else {
0137     v2 = v1 & ~0xC0;
0138     time->hour = From_BCD(v2);
0139   }
0140 
0141   v1 = info[DS1307_MINUTE] & ~0x80;
0142   time->minute = From_BCD(v1);
0143 
0144   v1 = info[DS1307_SECOND];
0145   v2 = v1 & ~0x80;
0146   time->second = From_BCD(v2);
0147 
0148   return 0;
0149 }
0150 
0151 /* ds1307_set_time --
0152  *     set time to the DS1307 real-time clock chip
0153  *
0154  * PARAMETERS:
0155  *     minor -- minor RTC device number
0156  *     time -- new date and time to be written to DS1307
0157  *
0158  * RETURNS:
0159  *     0, if time obtained successfully
0160  *     -1, if error occured
0161  */
0162 static int ds1307_set_time(int minor, const rtems_time_of_day *time)
0163 {
0164   i2c_bus_number bus;
0165   i2c_address addr;
0166   uint8_t         info[8];
0167   i2c_message_status status;
0168   int try;
0169 
0170   if (time == NULL)
0171     return -1;
0172 
0173   bus = RTC_Table[minor].ulCtrlPort1;
0174   addr = RTC_Table[minor].ulDataPort;
0175 
0176   if (time->year >= 2088)
0177       rtems_fatal_error_occurred(RTEMS_INVALID_NUMBER);
0178 
0179   info[0] = DS1307_SECOND;
0180   info[1 + DS1307_YEAR] = To_BCD(time->year % 100);
0181   info[1 + DS1307_MONTH] = To_BCD(time->month);
0182   info[1 + DS1307_DAY] = To_BCD(time->day);
0183   info[1 + DS1307_HOUR] = To_BCD(time->hour);
0184   info[1 + DS1307_MINUTE] = To_BCD(time->minute);
0185   info[1 + DS1307_SECOND] = To_BCD(time->second);
0186   info[1 + DS1307_DAY_OF_WEEK] = 1; /* Do not set day of week */
0187 
0188   try = 0;
0189   do {
0190     status = i2c_write(bus, addr, info, 8);
0191     try++;
0192   } while ((status != I2C_SUCCESSFUL) && (try < 10));
0193 
0194   if (status != I2C_SUCCESSFUL)
0195     return -1;
0196   else
0197     return 0;
0198 }
0199 
0200 /* Driver function table */
0201 
0202 rtc_fns ds1307_fns = {
0203   ds1307_initialize,
0204   ds1307_get_time,
0205   ds1307_set_time
0206 };