[rtems commit] bsp/altera-cyclone-v: Add RTC driver

Sebastian Huber sebh at rtems.org
Fri Apr 10 06:24:14 UTC 2015


Module:    rtems
Branch:    master
Commit:    a1d6f7a405328f8eb5a7d86bdf509db77e74b683
Changeset: http://git.rtems.org/rtems/commit/?id=a1d6f7a405328f8eb5a7d86bdf509db77e74b683

Author:    Thomas Volgmann <Thomas.Volgmann at dsa-volgmann.de>
Date:      Fri Apr 10 08:23:00 2015 +0200

bsp/altera-cyclone-v: Add RTC driver

---

 c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c | 766 +++++++++++++++++++-----
 1 file changed, 622 insertions(+), 144 deletions(-)

diff --git a/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c b/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
index 3c18d1c..aab39b3 100644
--- a/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
+++ b/c/src/lib/libbsp/arm/altera-cyclone-v/rtc/rtc.c
@@ -13,7 +13,8 @@
  */
 
 /*
- * Driver for the DS1339 RTC.
+ * 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.
@@ -31,114 +32,147 @@
 #include <unistd.h>
 #include <bsp/i2cdrv.h>
 
-#define ALTERA_CYCLONE_V_RTC_NUMBER 1
+#define ALTERA_CYCLONE_V_RTC_NUMBER  2
 
-#define DS1339_I2C_ADDRESS 0x68
-#define DS1339_I2C_BUS_DEVICE "/dev/i2c0"
 
-#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
+/* ******************************* DS1339 ********************************** */
 
-#define DS1339_CTRL_DEFAULT (0x00)
 
-#define DS1339_ADDR_TIME 0x00
-#define DS1339_ADDR_STATUS 0x0F
-#define DS1339_STATUS_OSF 0x80
-#define DS1339_STATUS_A2F 0x02
-#define DS1339_STATUS_A1F 0x01
+#define DS1339_I2C_ADDRESS     (0xD0 >> 1)  /* 7-bit addressing! */
+#define DS1339_I2C_BUS_DEVICE  "/dev/i2c0"
 
-#define DS1339_STATUS_CLEAR (0x00)
+#define DS1339_ADDR_TIME    0x00
 
-typedef struct {
-  uint8_t seconds;
-  uint8_t minutes;
-  uint8_t hours;
+#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;
+  uint8_t  weekday;
+  uint8_t  date;
+  uint8_t  month;
 #define DS1339_MONTH_CENTURY 0x80
-  uint8_t year;
-} ds1339_time_t;
+  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)
+#define DS1339_MAX_WRITE_SIZE  (sizeof(ds1339_time_t) + 1)
+
 
 /* Functions for converting the fields */
-static unsigned int get_seconds (ds1339_time_t *time) {
-  uint8_t tens = time->seconds >> 4;
-  uint8_t ones = time->seconds & 0x0F;
+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 get_minutes (ds1339_time_t *time) {
-  uint8_t tens = time->minutes >> 4;
-  uint8_t ones = time->minutes & 0x0F;
+
+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 get_hours (ds1339_time_t *time) {
-  uint8_t value = time->hours & 0x0F;
 
-  if(time->hours & DS1339_HOURS_10_HOURS) {
+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) {
+  if (time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS)
+  {
+    if (time->hours & DS1339_HOURS_12_24_FLAG)
       value += 12;
-    } else {
+    else
       value += 20;
-    }
   }
 
   return value;
 }
 
-static unsigned int get_day_of_month (ds1339_time_t *time) {
-  uint8_t tens = time->date >> 4;
-  uint8_t ones = time->date & 0x0F;
+
+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 get_month (ds1339_time_t *time) {
-  uint8_t tens = (time->month >> 4) & 0x07;
-  uint8_t ones = time->month & 0x0F;
+
+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 get_year (ds1339_time_t *time) {
-  unsigned int year = 1900;
+
+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) {
+  if (time->month & DS1339_MONTH_CENTURY)
     year += 100;
-  }
-  if(year < TOD_BASE_YEAR) {
+  if (year < TOD_BASE_YEAR)
     year += 200;
-  }
+
   return year;
 }
 
-static void 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;
+
+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;
@@ -161,78 +195,83 @@ static void set_time (
 
   tens = month / 10;
   ones = month % 10;
-  if(year >= 2000 && year < 2100) {
+  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)
+
+
+static rtems_status_code  ds1339_open_file(int* fd)
 {
-  int rv = 0;
-  rtems_status_code sc = RTEMS_SUCCESSFUL;
+
+  int                rv = 0;
+  rtems_status_code  sc = RTEMS_SUCCESSFUL;
 
   *fd = open(DS1339_I2C_BUS_DEVICE, O_RDWR);
-  if ( *fd == -1 ) {
+  if (*fd == -1)
     sc = RTEMS_IO_ERROR;
-  }
 
-  if ( sc == RTEMS_SUCCESSFUL ) {
+  if (sc == RTEMS_SUCCESSFUL)
+  {
     rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, DS1339_I2C_ADDRESS);
-    if ( rv == -1 ) {
+    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)
+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;
+
+  int                fd = -1;
+  int                rv = 0;
+  rtems_status_code  sc = RTEMS_SUCCESSFUL;
 
   sc = ds1339_open_file(&fd);
 
-  if ( sc == RTEMS_SUCCESSFUL ) {
+  if (sc == RTEMS_SUCCESSFUL)
+  {
     rv = write(fd, &addr, sizeof(addr));
-    if ( rv != sizeof(addr) ) {
+    if (rv != sizeof(addr))
       sc = RTEMS_IO_ERROR;
-    }
   }
 
-  if ( sc == RTEMS_SUCCESSFUL ) {
+  if (sc == RTEMS_SUCCESSFUL)
+  {
     rv = read(fd, buf, size);
-    if ( rv != size ) {
+    if (rv != size)
       sc = RTEMS_IO_ERROR;
-    }
   }
 
   rv = close(fd);
-  if ( rv != 0 ) {
+  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)
+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;
+
+  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;
+  uint8_t            local_buf[DS1339_MAX_WRITE_SIZE];
+  int                write_size = size + 1;
 
   assert(write_size <= DS1339_MAX_WRITE_SIZE);
 
@@ -241,34 +280,37 @@ static rtems_status_code ds1339_write(uint8_t addr, void *buf, size_t size)
 
   sc = ds1339_open_file(&fd);
 
-  if ( sc == RTEMS_SUCCESSFUL ) {
+  if (sc == RTEMS_SUCCESSFUL)
+  {
     rv = write(fd, local_buf, write_size);
-    if ( rv != write_size ) {
+    if (rv != write_size)
       sc = RTEMS_IO_ERROR;
-    }
   }
 
   rv = close(fd);
-  if ( rv != 0 ) {
+  if (rv != 0)
     sc = RTEMS_IO_ERROR;
-  }
 
   return RTEMS_SUCCESSFUL;
 }
 
-static void altera_cyclone_v_rtc_initialize(int minor)
+
+static void altera_cyclone_v_ds1339_initialize(int minor)
 {
-  rtems_status_code sc = RTEMS_SUCCESSFUL;
-  uint8_t status = 0;
+
+  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) {
+
+  if (status & DS1339_STATUS_OSF)
+  {
     /* RTC has been stopped. Initialise it. */
     ds1339_time_t time;
 
-    uint8_t write = DS1339_CTRL_DEFAULT;
+    uint8_t  write = DS1339_CTRL_DEFAULT;
     sc = ds1339_write(DS1339_ADDR_CTRL, &write, sizeof(write));
     assert(sc == RTEMS_SUCCESSFUL);
 
@@ -276,81 +318,517 @@ static void altera_cyclone_v_rtc_initialize(int minor)
     sc = ds1339_write(DS1339_ADDR_STATUS, &write, sizeof(write));
     assert(sc == RTEMS_SUCCESSFUL);
 
-    set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
+    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_rtc_get_time(int minor, rtems_time_of_day *tod)
+
+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));
+  ds1339_time_t      time;
+  rtems_status_code  sc = RTEMS_SUCCESSFUL;
+  rtems_time_of_day  temp_tod;
 
-  if ( sc == RTEMS_SUCCESSFUL ) {
-    temp_tod.ticks = 0;
-    temp_tod.second = get_seconds(&time);
-    temp_tod.minute = get_minutes(&time);
-    temp_tod.hour = get_hours(&time);
-    temp_tod.day = get_day_of_month(&time);
-    temp_tod.month = get_month(&time);
-    temp_tod.year = get_year(&time);
+  sc = ds1339_read(DS1339_ADDR_TIME, &time, sizeof(time));
 
-    if ( _TOD_Validate(&temp_tod) ) {
+  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);
+
+    if (_TOD_Validate(&temp_tod))
       memcpy(tod, &temp_tod, sizeof(temp_tod));
-    } else {
+    else
       sc = RTEMS_INVALID_CLOCK;
-    }
   }
 
   return -sc;
 }
 
-static int altera_cyclone_v_rtc_set_time(int minor, const rtems_time_of_day *tod)
+
+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;
 
-  set_time (
-    &time,
-    tod->second,
-    tod->minute,
-    tod->hour,
-    tod->day,
-    tod->month,
-    tod->year
-  );
+  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_rtc_probe(int minor)
+
+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;
+
+  printk("RTC detected, type = DS1339\n");
+  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);
+
+  if (_TOD_Validate(&temp_tod))
+    memcpy(tod, &temp_tod, sizeof(temp_tod));
+  else
+    sc = RTEMS_INVALID_CLOCK;
+
+  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)
 {
-  /* FIXME: Probe for i2c device */
+
+  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;
+
+  printk("RTC detected, type = M41ST87\n");
   return true;
+
 }
 
-const rtc_fns altera_cyclone_v_rtc_ops = {
-  .deviceInitialize = altera_cyclone_v_rtc_initialize,
-  .deviceGetTime = altera_cyclone_v_rtc_get_time,
-  .deviceSetTime = altera_cyclone_v_rtc_set_time
+
+/* **************************************** 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
 };
 
-size_t RTC_Count = ALTERA_CYCLONE_V_RTC_NUMBER;
 
-rtems_device_minor_number RTC_Minor = 0;
+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;
+rtems_device_minor_number  RTC_Minor = 0;
+
 
-rtc_tbl RTC_Table [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_rtc_ops,
-    .deviceProbe = altera_cyclone_v_rtc_probe,
+    .pDeviceFns = &altera_cyclone_v_m41st87_ops,
+    .deviceProbe = altera_cyclone_v_m41st87_probe,
     .pDeviceParams = NULL,
     .ulCtrlPort1 = 0,
     .ulDataPort = 0,



More information about the vc mailing list