summaryrefslogblamecommitdiffstats
path: root/c/src/lib/libbsp/m68k/mcf5206elite/tod/ds1307.c
blob: 6ea40f808ad4e1dff88fab9fbc12d69dbfd93b60 (plain) (tree)
























                                                                              
                                        



                        
                   


















                                                                     
                        

                       
 

                                       
 





                                                           
 


                                                       
                                 

























                                                                        

                            

                              
 

                     
 

                                       
 










                                                            
 





                               
 

                                    
 

                                  
 




















                                           
 


                                
 














                                                        
                                                         


                       
                            

                              
 







                                                         
 







                                                                  
 


















                                                       
/*
 * This file interfaces with the real-time clock found in a
 * Dallas Semiconductor DS1307/DS1308 serial real-time clock chip.
 * This RTC have I2C bus interface. BSP have to provide I2C bus primitives
 * to make this driver working. getRegister and setRegister primitives is
 * not used here to avoid multiple transactions over I2C bus (each transaction
 * require significant time and error when date/time information red may
 * occurs). ulControlPort contains I2C bus number; ulDataPort contains
 * RTC I2C device address.
 *
 * Year 2000 Note:
 *
 * This chip only uses a two digit field to store the year. This code
 * uses the RTEMS Epoch as a pivot year. This lets us map the two digit
 * year field as follows:
 *
 *    + two digit years 00-87 are mapped to 2000-2087
 *    + two digit years 88-99 are mapped to 1988-1999
 *
 * Copyright (C) 2000 OKTET Ltd., St.-Petersburg, Russia
 * Author: Victor V. Vengerov <vvv@oktet.ru>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 *
 * http://www.rtems.com/license/LICENSE.
 */

#include <rtems.h>
#include <libchip/rtc.h>
#include <string.h>
#include "ds1307.h"
#include "i2c.h"

/* Convert from/to Binary-Coded Decimal representation */
#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
#define To_BCD( _x )   ((((_x) / 10) << 4) + ((_x) % 10))

/* ds1307_initialize --
 *     Initialize DS1307 real-time clock chip. If RTC is halted, this
 *     function resume counting.
 *
 * PARAMETERS:
 *     minor -- minor RTC device number
 */
void
ds1307_initialize(int minor)
{
    i2c_message_status status;
    int try;
    uint8_t         sec;
    i2c_bus_number bus;
    i2c_address addr;

    bus = RTC_Table[minor].ulCtrlPort1;
    addr = RTC_Table[minor].ulDataPort;

    /* Read SECONDS register */
    try = 0;
    do {
        status = i2c_wbrd(bus, addr, 0, &sec, sizeof(sec));
        try++;
    } while ((status != I2C_SUCCESSFUL) && (try < 15));

    /* If clock is halted, reset and start the clock */
    if ((sec & DS1307_SECOND_HALT) != 0)
    {
        uint8_t         start[8];
        memset(start, 0, sizeof(start));
        start[0] = DS1307_SECOND;
        try = 0;
        do {
            status = i2c_write(bus, addr, start, 2);
        } while ((status != I2C_SUCCESSFUL) && (try < 15));
    }
}

/* ds1307_get_time --
 *     read current time from DS1307 real-time clock chip and convert it
 *     to the rtems_time_of_day structure.
 *
 * PARAMETERS:
 *     minor -- minor RTC device number
 *     time -- place to put return value (date and time)
 *
 * RETURNS:
 *     0, if time obtained successfully
 *     -1, if error occured
 */
int
ds1307_get_time(int minor, rtems_time_of_day *time)
{
    i2c_bus_number bus;
    i2c_address addr;
    uint8_t         info[8];
    uint32_t         v1, v2;
    i2c_message_status status;
    int try;

    if (time == NULL)
        return -1;

    bus = RTC_Table[minor].ulCtrlPort1;
    addr = RTC_Table[minor].ulDataPort;

    memset(time, 0, sizeof(rtems_time_of_day));
    try = 0;
    do {
        status = i2c_wbrd(bus, addr, 0, info, sizeof(info));
        try++;
    } while ((status != I2C_SUCCESSFUL) && (try < 10));

    if (status != I2C_SUCCESSFUL)
    {
        return -1;
    }

    v1 = info[DS1307_YEAR];
    v2 = From_BCD(v1);
    if (v2 < 88)
        time->year = 2000 + v2;
    else
        time->year = 1900 + v2;

    v1 = info[DS1307_MONTH] & ~0xE0;
    time->month = From_BCD(v1);

    v1 = info[DS1307_DAY] & ~0xC0;
    time->day = From_BCD(v1);

    v1 = info[DS1307_HOUR];
    if (v1 & DS1307_HOUR_12)
    {
        v2 = v1 & ~0xE0;
        if (v1 & DS1307_HOUR_PM)
        {
            time->hour = From_BCD(v2) + 12;
        }
        else
        {
            time->hour = From_BCD(v2);
        }
    }
    else
    {
        v2 = v1 & ~0xC0;
        time->hour = From_BCD(v2);
    }

    v1 = info[DS1307_MINUTE] & ~0x80;
    time->minute = From_BCD(v1);

    v1 = info[DS1307_SECOND];
    v2 = v1 & ~0x80;
    time->second = From_BCD(v2);

    return 0;
}

/* ds1307_set_time --
 *     set time to the DS1307 real-time clock chip
 *
 * PARAMETERS:
 *     minor -- minor RTC device number
 *     time -- new date and time to be written to DS1307
 *
 * RETURNS:
 *     0, if time obtained successfully
 *     -1, if error occured
 */
int
ds1307_set_time(int minor, const rtems_time_of_day *time)
{
    i2c_bus_number bus;
    i2c_address addr;
    uint8_t         info[8];
    i2c_message_status status;
    int try;

    if (time == NULL)
        return -1;

    bus = RTC_Table[minor].ulCtrlPort1;
    addr = RTC_Table[minor].ulDataPort;

    if (time->year >= 2088)
        rtems_fatal_error_occurred(RTEMS_INVALID_NUMBER);

    info[0] = DS1307_SECOND;
    info[1 + DS1307_YEAR] = To_BCD(time->year % 100);
    info[1 + DS1307_MONTH] = To_BCD(time->month);
    info[1 + DS1307_DAY] = To_BCD(time->day);
    info[1 + DS1307_HOUR] = To_BCD(time->hour);
    info[1 + DS1307_MINUTE] = To_BCD(time->minute);
    info[1 + DS1307_SECOND] = To_BCD(time->second);
    info[1 + DS1307_DAY_OF_WEEK] = 1; /* Do not set day of week */

    try = 0;
    do {
        status = i2c_write(bus, addr, info, 8);
        try++;
    } while ((status != I2C_SUCCESSFUL) && (try < 10));

    if (status != I2C_SUCCESSFUL)
        return -1;
    else
        return 0;
}

/* Driver function table */

rtc_fns ds1307_fns = {
    ds1307_initialize,
    ds1307_get_time,
    ds1307_set_time
};