summaryrefslogblamecommitdiffstats
path: root/bsps/arm/altera-cyclone-v/rtc/rtc.c
blob: 2ff9791871427b1ce42a59c48ec0eb5e23e70230 (plain) (tree)
1
2
3
4
5
6





                            














                                                                 

                                                           











                                                      
                                  

                      
                   


                       
                                      
 
 
                                                                               
 
 

                                                                   
 
                                
 

























                                        


                                                


                   
                                 



                

                                                                          

                                                          

                                         




                                                            


                          





                                                            


                          
 






                                                          

                


                                                        
                  
        
                  




               






                                                                 


                          






                                                          


                          





                                                         

                                 
                                         
                
                           
                
 


              












                                                 





















                                                                                
                                      
                                   




                                           
 

 


                                                   
 


                                           

                                            
                
                        
 

                             
                                                                   
                 
                          




            
 
                                                               
                                                                           
 



                                           


                             

                             
                                        
                           
                          

   

                             
                             
                   
                          


                 
              
                        



            
 
                                                                
                                                                            
 



                                           


                                                                               

                                                      







                                              

                             
                                          
                         
                          


                 
              
                        



                          

                                                         
 


                                           



                                                                


                                 


                                              
                                         






                                                                 
                                                         


                                                             
 

 

                                                                              
 
 


                                           
 
                                                          
 









                                                     
                                                              
                               
                                               




             

                                                                                     
 
 










                                           





                                                           

















                                                                          















































































































































































































































































































































                                                                                

                                
                                             































                                                                                      
 














                                                                       
              
 

 








                                                                                         

  
 








                                                          
 












                                                 


                              

                                                  






                          
/**
 * @file
 *
 * @ingroup RTEMSBSPsARMCycV
 */

/*
 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
 *
 *  embedded brains GmbH
 *  Dornierstr. 4
 *  82178 Puchheim
 *  Germany
 *  <info@embedded-brains.de>
 *
 * The license and distribution terms for this file may be
 * found in the file LICENSE in this distribution or at
 * http://www.rtems.org/license/LICENSE.
 */

/*
 * Driver for the DS1339 RTC (Maxim Semiconductors) -> RTC1
 *        and the M41ST87 RTC (ST Microelectronics) -> RTC2
 *
 * Please note the following points:
 * - The day of week is ignored.
 * - The century bit is interpreted the following way:
 *   - century not set: TOD_BASE_YEAR .. 1999
 *   - century set: 2000 .. 2099
 *   - century not set: 2100 .. (TOD_BASE_YEAR + 200)
 */

#include <libchip/rtc.h>
#include <assert.h>
#include <rtems/score/todimpl.h>
#include <rtems/rtems/clockimpl.h>
#include <sys/filio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <bsp/i2cdrv.h>

#define ALTERA_CYCLONE_V_RTC_NUMBER  2


/* ******************************* DS1339 ********************************** */


#define DS1339_I2C_ADDRESS     (0xD0 >> 1)  /* 7-bit addressing! */
#define DS1339_I2C_BUS_DEVICE  "/dev/i2c0"

#define DS1339_ADDR_TIME    0x00

#define DS1339_ADDR_CTRL   0x0E
#define   DS1339_CTRL_EOSC   0x80
#define   DS1339_CTRL_BBSQI  0x20
#define   DS1339_CTRL_RS2    0x10
#define   DS1339_CTRL_RS1    0x08
#define   DS1339_CTRL_INTCN  0x04
#define   DS1339_CTRL_A2IE   0x02
#define   DS1339_CTRL_A1IE   0x01

#define DS1339_CTRL_DEFAULT  (0x00)

#define DS1339_ADDR_STATUS  0x0F
#define   DS1339_STATUS_OSF   0x80
#define   DS1339_STATUS_A2F   0x02
#define   DS1339_STATUS_A1F   0x01

#define DS1339_STATUS_CLEAR  (0x00)

#define DS1339_ADDR_TRICKLE_CHARGE  0x10


typedef struct
{
  uint8_t  seconds;
  uint8_t  minutes;
  uint8_t  hours;
#define DS1339_HOURS_12_24_FLAG 0x40
#define DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS 0x20
#define DS1339_HOURS_10_HOURS 0x10
  uint8_t  weekday;
  uint8_t  date;
  uint8_t  month;
#define DS1339_MONTH_CENTURY 0x80
  uint8_t  year;
}
ds1339_time_t;


/* The longest write transmission is writing the time + one address bit */
#define DS1339_MAX_WRITE_SIZE  (sizeof(ds1339_time_t) + 1)


/* Functions for converting the fields */
static unsigned int  ds1339_get_seconds(ds1339_time_t* time)
{
  uint8_t  tens = time->seconds >> 4;
  uint8_t  ones = time->seconds & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  ds1339_get_minutes(ds1339_time_t* time)
{
  uint8_t  tens = time->minutes >> 4;
  uint8_t  ones = time->minutes & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  ds1339_get_hours(ds1339_time_t* time)
{

  uint8_t  value = time->hours & 0x0F;

  if (time->hours & DS1339_HOURS_10_HOURS)
  {
    value += 10;
  }
  if (time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS)
  {
    if (time->hours & DS1339_HOURS_12_24_FLAG)
      value += 12;
    else
      value += 20;
  }

  return value;
}


static unsigned int  ds1339_get_day_of_month(ds1339_time_t* time)
{

  uint8_t  tens = time->date >> 4;
  uint8_t  ones = time->date & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  ds1339_get_month(ds1339_time_t* time)
{

  uint8_t  tens = (time->month >> 4) & 0x07;
  uint8_t  ones = time->month & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  ds1339_get_year(ds1339_time_t* time)
{

  unsigned int  year = 1900;

  year += (time->year >> 4) * 10;
  year += time->year & 0x0F;
  if (time->month & DS1339_MONTH_CENTURY)
    year += 100;
  if (year < TOD_BASE_YEAR)
    year += 200;

  return year;
}


static void  ds1339_set_time(ds1339_time_t* time,
                             unsigned int second,
                             unsigned int minute,
                             unsigned int hour,
                             unsigned int day,
                             unsigned int month,
                             unsigned int year)
{

  unsigned int  tens;
  unsigned int  ones;
  uint8_t       century = 0;

  tens = second / 10;
  ones = second % 10;
  time->seconds = tens << 4 | ones;

  tens = minute / 10;
  ones = minute % 10;
  time->minutes = tens << 4 | ones;

  tens = hour / 10;
  ones = hour % 10;
  time->hours = tens << 4 | ones;

  /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
  time->weekday = 1;

  tens = day / 10;
  ones = day % 10;
  time->date = tens << 4 | ones;

  tens = month / 10;
  ones = month % 10;
  if ((year >= 2000) && (year < 2100))
    century = DS1339_MONTH_CENTURY;
  time->month = century | tens << 4 | ones;

  tens = (year % 100) / 10;
  ones = year % 10;
  time->year = tens << 4 | ones;

}



static rtems_status_code  ds1339_open_file(int* fd)
{

  int                rv = 0;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;

  *fd = open(DS1339_I2C_BUS_DEVICE, O_RDWR);
  if (*fd == -1)
    sc = RTEMS_IO_ERROR;

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, DS1339_I2C_ADDRESS);
    if (rv == -1)
      sc = RTEMS_IO_ERROR;
  }

  return sc;
}


/* Read size bytes from ds1339 register address addr to buf. */
static rtems_status_code  ds1339_read(uint8_t addr, void* buf, size_t size)
{

  int                fd = -1;
  int                rv = 0;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;

  sc = ds1339_open_file(&fd);

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = write(fd, &addr, sizeof(addr));
    if (rv != sizeof(addr))
      sc = RTEMS_IO_ERROR;
  }

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = read(fd, buf, size);
    if (rv != size)
      sc = RTEMS_IO_ERROR;
  }

  rv = close(fd);
  if (rv != 0)
    sc = RTEMS_IO_ERROR;

  return sc;
}


/* Write size bytes from buf to ds1339 register address addr. */
static rtems_status_code  ds1339_write(uint8_t addr, void* buf, size_t size)
{

  int                fd = -1;
  int                rv = 0;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  /* The driver never writes many bytes. Therefore it should be less expensive
   * to reserve the maximum number of bytes that will be written in one go than
   * use a malloc. */
  uint8_t            local_buf[DS1339_MAX_WRITE_SIZE];
  int                write_size = size + 1;

  assert(write_size <= DS1339_MAX_WRITE_SIZE);

  local_buf[0] = addr;
  memcpy(&local_buf[1], buf, size);

  sc = ds1339_open_file(&fd);

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = write(fd, local_buf, write_size);
    if (rv != write_size)
      sc = RTEMS_IO_ERROR;
  }

  rv = close(fd);
  if (rv != 0)
    sc = RTEMS_IO_ERROR;

  return RTEMS_SUCCESSFUL;
}


static void altera_cyclone_v_ds1339_initialize(int minor)
{

  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  uint8_t            status = 0;

  /* Check RTC valid */
  sc = ds1339_read(DS1339_ADDR_STATUS, &status, sizeof(status));
  assert(sc == RTEMS_SUCCESSFUL);

  if (status & DS1339_STATUS_OSF)
  {
    /* RTC has been stopped. Initialise it. */
    ds1339_time_t time;

    uint8_t  write = DS1339_CTRL_DEFAULT;
    sc = ds1339_write(DS1339_ADDR_CTRL, &write, sizeof(write));
    assert(sc == RTEMS_SUCCESSFUL);

    write = DS1339_STATUS_CLEAR;
    sc = ds1339_write(DS1339_ADDR_STATUS, &write, sizeof(write));
    assert(sc == RTEMS_SUCCESSFUL);

    ds1339_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
    sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
    assert(sc == RTEMS_SUCCESSFUL);
  }

}


static int altera_cyclone_v_ds1339_get_time(int minor, rtems_time_of_day* tod)
{

  ds1339_time_t      time;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  rtems_time_of_day  temp_tod;

  sc = ds1339_read(DS1339_ADDR_TIME, &time, sizeof(time));

  if (sc == RTEMS_SUCCESSFUL)
  {
    temp_tod.ticks  = 0;
    temp_tod.second = ds1339_get_seconds(&time);
    temp_tod.minute = ds1339_get_minutes(&time);
    temp_tod.hour   = ds1339_get_hours(&time);
    temp_tod.day    = ds1339_get_day_of_month(&time);
    temp_tod.month  = ds1339_get_month(&time);
    temp_tod.year   = ds1339_get_year(&time);

    sc = _TOD_Validate(&temp_tod, TOD_ENABLE_TICKS_VALIDATION)
    if (sc == RTEMS_SUCCESSFUL)
      memcpy(tod, &temp_tod, sizeof(temp_tod));
  }

  return -sc;
}


static int  altera_cyclone_v_ds1339_set_time(int minor, const rtems_time_of_day* tod)
{

  ds1339_time_t      time;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;

  ds1339_set_time(&time,
                  tod->second,
                  tod->minute,
                  tod->hour,
                  tod->day,
                  tod->month,
                  tod->year
                 );

  sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));

  return -sc;
}


static bool  altera_cyclone_v_ds1339_probe(int minor)
{

  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  uint8_t            buf;

  /* try to read from register address 0x00 */
  sc = ds1339_read(0x00, &buf, 1);
  if (sc != RTEMS_SUCCESSFUL)
    /* no RTC implemented */
    return false;
  /* try to read from register address 0x20 (not implemented in DS1339) */
  sc = ds1339_read(0x20, &buf, 1);
  if (sc == RTEMS_SUCCESSFUL)
    /* RTC is not DS1339 */
    return false;

  return true;

}


/* ******************************* M41ST87 ********************************** */


#define M41ST87_I2C_ADDRESS       (0xD0 >> 1)  /* 7-bit addressing! */
#define M41ST87_I2C_BUS_DEVICE    "/dev/i2c0"

#define M41ST87_ADDR_TIME         0x00

#define M41ST87_ADDR_CTRL         0x08
#define   M41ST87_CTRL_OUT          0x80
#define   M41ST87_CTRL_FT           0x40
#define   M41ST87_CTRL_S            0x20
#define   M41ST87_CTRL_CAL          0x1F

#define M41ST87_ADDR_ALARM_HOUR   0x0C
#define   M41ST87_BIT_HT            0x40

#define M41ST87_ADDR_FLAGS        0x0F
#define   M41ST87_FLAG_WDF          0x80
#define   M41ST87_FLAG_AF           0x40
#define   M41ST87_FLAG_BL           0x10
#define   M41ST87_FLAG_OF           0x04
#define   M41ST87_FLAG_TB1          0x02
#define   M41ST87_FLAG_TB2          0x01

#define M41ST87_ADDR_USER_RAM     0x20


typedef struct
{
  uint8_t  sec100;
  uint8_t  seconds;
#define M41ST87_BIT_ST          0x80
  uint8_t  minutes;
#define M41ST87_BIT_OFIE        0x80
  uint8_t  hours;
#define M41ST87_BIT_CB1         0x80
#define M41ST87_BIT_CB0         0x40
  uint8_t  weekday;
#define M41ST87_BIT_TR          0x80
#define M41ST87_BIT_THS         0x40
#define M41ST87_BIT_CLRPW1      0x20
#define M41ST87_BIT_CLRPW0      0x10
#define M41ST87_BIT_32KE        0x08
  uint8_t  day;
#define M41ST87_BIT_PFOD        0x80
  uint8_t  month;
  uint8_t  year;
}
m41st87_time_t;


/* The longest write transmission is writing the time + one address bit */
#define M41ST87_MAX_WRITE_SIZE  (sizeof(m41st87_time_t) + 1)


/* Functions for converting the fields */

/*
static unsigned int  m41st87_get_sec100(m41st87_time_t* time)
{

  uint8_t  tens = time->sec100 >> 4;
  uint8_t  ones = time->sec100 & 0x0F;

  return tens * 10 + ones;
}
*/


static unsigned int  m41st87_get_seconds(m41st87_time_t* time)
{

  uint8_t  tens = (time->seconds >> 4) & 0x07;
  uint8_t  ones = time->seconds & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  m41st87_get_minutes(m41st87_time_t* time)
{

  uint8_t  tens = (time->minutes >> 4) & 0x07;
  uint8_t  ones = time->minutes & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  m41st87_get_hours(m41st87_time_t* time)
{

  uint8_t  tens = (time->hours >> 4) & 0x03;
  uint8_t  ones = time->hours & 0x0F;

  return tens * 10 + ones;
}


/*
static unsigned int  m41st87_get_day_of_week(m41st87_time_t* time)
{

  return time->weekday & 0x07;
}
*/


static unsigned int  m41st87_get_day_of_month(m41st87_time_t* time)
{

  uint8_t  tens = (time->day >> 4) & 0x03;
  uint8_t  ones = time->day & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  m41st87_get_month(m41st87_time_t* time)
{

  uint8_t  tens = (time->month >> 4) & 0x01;
  uint8_t  ones = time->month & 0x0F;

  return tens * 10 + ones;
}


static unsigned int  m41st87_get_year(m41st87_time_t* time)
{

  uint8_t  century = time->hours >> 6;
  uint8_t  tens    = time->year >> 4;
  uint8_t  ones    = time->year & 0x0F;

  return 1900 + century * 100 + tens * 10 + ones;
}


static void  m41st87_set_time(m41st87_time_t* time,
                              unsigned int second,
                              unsigned int minute,
                              unsigned int hour,
                              unsigned int day,
                              unsigned int month,
                              unsigned int year)
{

  unsigned int  century;
  unsigned int  tens;
  unsigned int  ones;

  if (year < 1900)
    year = 1900;
  if (year > 2399)
    year = 2399;
  century = (year - 1900) / 100;

  /* Hundreds of seconds is not used, set to 0 */
  time->sec100 = 0;

  tens = second / 10;
  ones = second % 10;
  time->seconds = (time->seconds & 0x80) | (tens << 4) | ones;

  tens = minute / 10;
  ones = minute % 10;
  time->minutes = (time->minutes & 0x80) | (tens << 4) | ones;

  tens = hour / 10;
  ones = hour % 10;
  time->hours = (century << 6) | (tens << 4) | ones;

  /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
  time->weekday = (time->weekday & 0xF8) | 1;

  tens = day / 10;
  ones = day % 10;
  time->day = (time->day & 0x80) | (tens << 4) | ones;

  tens = month / 10;
  ones = month % 10;
  time->month = (tens << 4) | ones;

  tens = (year % 100) / 10;
  ones = year % 10;
  time->year = (tens << 4) | ones;

}



static rtems_status_code  m41st87_open_file(int* fd)
{

  int                rv = 0;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;

  *fd = open(M41ST87_I2C_BUS_DEVICE, O_RDWR);
  if (*fd == -1)
    sc = RTEMS_IO_ERROR;

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, M41ST87_I2C_ADDRESS);
    if (rv == -1)
      sc = RTEMS_IO_ERROR;
  }

  return sc;
}


/* Read size bytes from m41st87 register address addr to buf. */
static rtems_status_code  m41st87_read(uint8_t addr, void* buf, size_t size)
{

  int                fd = -1;
  int                rv = 0;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;

  sc = m41st87_open_file(&fd);

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = write(fd, &addr, sizeof(addr));
    if (rv != sizeof(addr))
      sc = RTEMS_IO_ERROR;
  }

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = read(fd, buf, size);
    if (rv != size)
      sc = RTEMS_IO_ERROR;
  }

  rv = close(fd);
  if (rv != 0)
    sc = RTEMS_IO_ERROR;

  return sc;
}


/* Write size bytes from buf to m41st87 register address addr. */
static rtems_status_code  m41st87_write(uint8_t addr, void* buf, size_t size)
{

  int                fd = -1;
  int                rv = 0;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  /* The driver never writes many bytes. Therefore it should be less expensive
   * to reserve the maximum number of bytes that will be written in one go than
   * use a malloc. */
  uint8_t            local_buf[M41ST87_MAX_WRITE_SIZE];
  int                write_size = size + 1;

  assert(write_size <= M41ST87_MAX_WRITE_SIZE);

  local_buf[0] = addr;
  memcpy(&local_buf[1], buf, size);

  sc = m41st87_open_file(&fd);

  if (sc == RTEMS_SUCCESSFUL)
  {
    rv = write(fd, local_buf, write_size);
    if (rv != write_size)
      sc = RTEMS_IO_ERROR;
  }

  rv = close(fd);
  if (rv != 0)
    sc = RTEMS_IO_ERROR;

  return RTEMS_SUCCESSFUL;
}


static void  altera_cyclone_v_m41st87_initialize(int minor)
{

  m41st87_time_t     time;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  uint8_t            value;

  /* Check RTC valid */
  sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
  assert(sc == RTEMS_SUCCESSFUL);

  if (time.seconds & M41ST87_BIT_ST)
  {
    /* RTC has been stopped. Reset stop flag. */
    time.seconds = 0;
    /* Initialise RTC. */
    m41st87_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
    sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
    assert(sc == RTEMS_SUCCESSFUL);
  }

  /* Reset HT bit */
  sc = m41st87_read(M41ST87_ADDR_ALARM_HOUR, &value, 1);
  assert(sc == RTEMS_SUCCESSFUL);
  value &= ~M41ST87_BIT_HT;
  sc = m41st87_write(M41ST87_ADDR_ALARM_HOUR, &value, 1);
  assert(sc == RTEMS_SUCCESSFUL);

}


static int  altera_cyclone_v_m41st87_get_time(int minor, rtems_time_of_day* tod)
{

  m41st87_time_t     time;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  rtems_time_of_day  temp_tod;

  sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
  if (sc != RTEMS_SUCCESSFUL)
    return -sc;

  temp_tod.ticks  = 0;
  temp_tod.second = m41st87_get_seconds(&time);
  temp_tod.minute = m41st87_get_minutes(&time);
  temp_tod.hour   = m41st87_get_hours(&time);
  temp_tod.day    = m41st87_get_day_of_month(&time);
  temp_tod.month  = m41st87_get_month(&time);
  temp_tod.year   = m41st87_get_year(&time);

  sc = _TOD_Validate(&temp_tod);
  if (sc == RTEMS_SUCCESSFUL)
    memcpy(tod, &temp_tod, sizeof(temp_tod));

  return -sc;
}


static int  altera_cyclone_v_m41st87_set_time(int minor, const rtems_time_of_day* tod)
{

  m41st87_time_t     time;
  rtems_status_code  sc = RTEMS_SUCCESSFUL;

  /* first read to preserve the additional flags */
  sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
  if (sc != RTEMS_SUCCESSFUL)
    return -sc;

  m41st87_set_time(&time,
                   tod->second,
                   tod->minute,
                   tod->hour,
                   tod->day,
                   tod->month,
                   tod->year
                  );

  sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));

  return -sc;
}


static bool  altera_cyclone_v_m41st87_probe(int minor)
{

  rtems_status_code  sc = RTEMS_SUCCESSFUL;
  uint8_t            buf;

  /* try to read from register address 0x00 */
  sc = m41st87_read(0x00, &buf, 1);
  if (sc != RTEMS_SUCCESSFUL)
    /* no RTC implemented */
    return false;
  /* try to read from register address 0x20 (implemented in M41ST87) */
  sc = m41st87_read(0x20, &buf, 1);
  if (sc != RTEMS_SUCCESSFUL)
    /* RTC is not M41ST87 */
    return false;

  return true;

}


/* **************************************** General ********************************** */


const rtc_fns  altera_cyclone_v_ds1339_ops =
{
  .deviceInitialize = altera_cyclone_v_ds1339_initialize,
  .deviceGetTime = altera_cyclone_v_ds1339_get_time,
  .deviceSetTime = altera_cyclone_v_ds1339_set_time
};


const rtc_fns  altera_cyclone_v_m41st87_ops =
{
  .deviceInitialize = altera_cyclone_v_m41st87_initialize,
  .deviceGetTime = altera_cyclone_v_m41st87_get_time,
  .deviceSetTime = altera_cyclone_v_m41st87_set_time
};


size_t  RTC_Count = ALTERA_CYCLONE_V_RTC_NUMBER;

rtc_tbl  RTC_Table[ALTERA_CYCLONE_V_RTC_NUMBER] =
{
  {
    .sDeviceName = "/dev/rtc",
    .deviceType = RTC_CUSTOM,
    .pDeviceFns = &altera_cyclone_v_ds1339_ops,
    .deviceProbe = altera_cyclone_v_ds1339_probe,
    .pDeviceParams = NULL,
    .ulCtrlPort1 = 0,
    .ulDataPort = 0,
    .getRegister = NULL,
    .setRegister = NULL
  },
  {
    .sDeviceName = "/dev/rtc",
    .deviceType = RTC_CUSTOM,
    .pDeviceFns = &altera_cyclone_v_m41st87_ops,
    .deviceProbe = altera_cyclone_v_m41st87_probe,
    .pDeviceParams = NULL,
    .ulCtrlPort1 = 0,
    .ulDataPort = 0,
    .getRegister = NULL,
    .setRegister = NULL
  }
};