Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:44

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsARMCycV
0007  */
0008 
0009 /*
0010  * Copyright (c) 2014 embedded brains GmbH & Co. KG
0011  *
0012  * Redistribution and use in source and binary forms, with or without
0013  * modification, are permitted provided that the following conditions
0014  * are met:
0015  * 1. Redistributions of source code must retain the above copyright
0016  *    notice, this list of conditions and the following disclaimer.
0017  * 2. Redistributions in binary form must reproduce the above copyright
0018  *    notice, this list of conditions and the following disclaimer in the
0019  *    documentation and/or other materials provided with the distribution.
0020  *
0021  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0022  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0023  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0024  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0025  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0026  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0027  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0030  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0031  * POSSIBILITY OF SUCH DAMAGE.
0032  */
0033 
0034 /*
0035  * Driver for the DS1339 RTC (Maxim Semiconductors) -> RTC1
0036  *        and the M41ST87 RTC (ST Microelectronics) -> RTC2
0037  *
0038  * Please note the following points:
0039  * - The day of week is ignored.
0040  * - The century bit is interpreted the following way:
0041  *   - century not set: TOD_BASE_YEAR .. 1999
0042  *   - century set: 2000 .. 2099
0043  *   - century not set: 2100 .. (TOD_BASE_YEAR + 200)
0044  */
0045 
0046 #include <libchip/rtc.h>
0047 #include <assert.h>
0048 #include <rtems/score/todimpl.h>
0049 #include <rtems/rtems/clockimpl.h>
0050 #include <sys/filio.h>
0051 #include <fcntl.h>
0052 #include <string.h>
0053 #include <unistd.h>
0054 #include <bsp/i2cdrv.h>
0055 
0056 #define ALTERA_CYCLONE_V_RTC_NUMBER  2
0057 
0058 
0059 /* ******************************* DS1339 ********************************** */
0060 
0061 
0062 #define DS1339_I2C_ADDRESS     (0xD0 >> 1)  /* 7-bit addressing! */
0063 #define DS1339_I2C_BUS_DEVICE  "/dev/i2c0"
0064 
0065 #define DS1339_ADDR_TIME    0x00
0066 
0067 #define DS1339_ADDR_CTRL   0x0E
0068 #define   DS1339_CTRL_EOSC   0x80
0069 #define   DS1339_CTRL_BBSQI  0x20
0070 #define   DS1339_CTRL_RS2    0x10
0071 #define   DS1339_CTRL_RS1    0x08
0072 #define   DS1339_CTRL_INTCN  0x04
0073 #define   DS1339_CTRL_A2IE   0x02
0074 #define   DS1339_CTRL_A1IE   0x01
0075 
0076 #define DS1339_CTRL_DEFAULT  (0x00)
0077 
0078 #define DS1339_ADDR_STATUS  0x0F
0079 #define   DS1339_STATUS_OSF   0x80
0080 #define   DS1339_STATUS_A2F   0x02
0081 #define   DS1339_STATUS_A1F   0x01
0082 
0083 #define DS1339_STATUS_CLEAR  (0x00)
0084 
0085 #define DS1339_ADDR_TRICKLE_CHARGE  0x10
0086 
0087 
0088 typedef struct
0089 {
0090   uint8_t  seconds;
0091   uint8_t  minutes;
0092   uint8_t  hours;
0093 #define DS1339_HOURS_12_24_FLAG 0x40
0094 #define DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS 0x20
0095 #define DS1339_HOURS_10_HOURS 0x10
0096   uint8_t  weekday;
0097   uint8_t  date;
0098   uint8_t  month;
0099 #define DS1339_MONTH_CENTURY 0x80
0100   uint8_t  year;
0101 }
0102 ds1339_time_t;
0103 
0104 
0105 /* The longest write transmission is writing the time + one address bit */
0106 #define DS1339_MAX_WRITE_SIZE  (sizeof(ds1339_time_t) + 1)
0107 
0108 
0109 /* Functions for converting the fields */
0110 static unsigned int  ds1339_get_seconds(ds1339_time_t* time)
0111 {
0112   uint8_t  tens = time->seconds >> 4;
0113   uint8_t  ones = time->seconds & 0x0F;
0114 
0115   return tens * 10 + ones;
0116 }
0117 
0118 
0119 static unsigned int  ds1339_get_minutes(ds1339_time_t* time)
0120 {
0121   uint8_t  tens = time->minutes >> 4;
0122   uint8_t  ones = time->minutes & 0x0F;
0123 
0124   return tens * 10 + ones;
0125 }
0126 
0127 
0128 static unsigned int  ds1339_get_hours(ds1339_time_t* time)
0129 {
0130 
0131   uint8_t  value = time->hours & 0x0F;
0132 
0133   if (time->hours & DS1339_HOURS_10_HOURS)
0134   {
0135     value += 10;
0136   }
0137   if (time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS)
0138   {
0139     if (time->hours & DS1339_HOURS_12_24_FLAG)
0140       value += 12;
0141     else
0142       value += 20;
0143   }
0144 
0145   return value;
0146 }
0147 
0148 
0149 static unsigned int  ds1339_get_day_of_month(ds1339_time_t* time)
0150 {
0151 
0152   uint8_t  tens = time->date >> 4;
0153   uint8_t  ones = time->date & 0x0F;
0154 
0155   return tens * 10 + ones;
0156 }
0157 
0158 
0159 static unsigned int  ds1339_get_month(ds1339_time_t* time)
0160 {
0161 
0162   uint8_t  tens = (time->month >> 4) & 0x07;
0163   uint8_t  ones = time->month & 0x0F;
0164 
0165   return tens * 10 + ones;
0166 }
0167 
0168 
0169 static unsigned int  ds1339_get_year(ds1339_time_t* time)
0170 {
0171 
0172   unsigned int  year = 1900;
0173 
0174   year += (time->year >> 4) * 10;
0175   year += time->year & 0x0F;
0176   if (time->month & DS1339_MONTH_CENTURY)
0177     year += 100;
0178   if (year < TOD_BASE_YEAR)
0179     year += 200;
0180 
0181   return year;
0182 }
0183 
0184 
0185 static void  ds1339_set_time(ds1339_time_t* time,
0186                              unsigned int second,
0187                              unsigned int minute,
0188                              unsigned int hour,
0189                              unsigned int day,
0190                              unsigned int month,
0191                              unsigned int year)
0192 {
0193 
0194   unsigned int  tens;
0195   unsigned int  ones;
0196   uint8_t       century = 0;
0197 
0198   tens = second / 10;
0199   ones = second % 10;
0200   time->seconds = tens << 4 | ones;
0201 
0202   tens = minute / 10;
0203   ones = minute % 10;
0204   time->minutes = tens << 4 | ones;
0205 
0206   tens = hour / 10;
0207   ones = hour % 10;
0208   time->hours = tens << 4 | ones;
0209 
0210   /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
0211   time->weekday = 1;
0212 
0213   tens = day / 10;
0214   ones = day % 10;
0215   time->date = tens << 4 | ones;
0216 
0217   tens = month / 10;
0218   ones = month % 10;
0219   if ((year >= 2000) && (year < 2100))
0220     century = DS1339_MONTH_CENTURY;
0221   time->month = century | tens << 4 | ones;
0222 
0223   tens = (year % 100) / 10;
0224   ones = year % 10;
0225   time->year = tens << 4 | ones;
0226 
0227 }
0228 
0229 
0230 
0231 static rtems_status_code  ds1339_open_file(int* fd)
0232 {
0233 
0234   int                rv = 0;
0235   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0236 
0237   *fd = open(DS1339_I2C_BUS_DEVICE, O_RDWR);
0238   if (*fd == -1)
0239     sc = RTEMS_IO_ERROR;
0240 
0241   if (sc == RTEMS_SUCCESSFUL)
0242   {
0243     rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, DS1339_I2C_ADDRESS);
0244     if (rv == -1)
0245       sc = RTEMS_IO_ERROR;
0246   }
0247 
0248   return sc;
0249 }
0250 
0251 
0252 /* Read size bytes from ds1339 register address addr to buf. */
0253 static rtems_status_code  ds1339_read(uint8_t addr, void* buf, size_t size)
0254 {
0255 
0256   int                fd = -1;
0257   int                rv = 0;
0258   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0259 
0260   sc = ds1339_open_file(&fd);
0261 
0262   if (sc == RTEMS_SUCCESSFUL)
0263   {
0264     rv = write(fd, &addr, sizeof(addr));
0265     if (rv != sizeof(addr))
0266       sc = RTEMS_IO_ERROR;
0267   }
0268 
0269   if (sc == RTEMS_SUCCESSFUL)
0270   {
0271     rv = read(fd, buf, size);
0272     if (rv != size)
0273       sc = RTEMS_IO_ERROR;
0274   }
0275 
0276   rv = close(fd);
0277   if (rv != 0)
0278     sc = RTEMS_IO_ERROR;
0279 
0280   return sc;
0281 }
0282 
0283 
0284 /* Write size bytes from buf to ds1339 register address addr. */
0285 static rtems_status_code  ds1339_write(uint8_t addr, void* buf, size_t size)
0286 {
0287 
0288   int                fd = -1;
0289   int                rv = 0;
0290   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0291   /* The driver never writes many bytes. Therefore it should be less expensive
0292    * to reserve the maximum number of bytes that will be written in one go than
0293    * use a malloc. */
0294   uint8_t            local_buf[DS1339_MAX_WRITE_SIZE];
0295   int                write_size = size + 1;
0296 
0297   assert(write_size <= DS1339_MAX_WRITE_SIZE);
0298 
0299   local_buf[0] = addr;
0300   memcpy(&local_buf[1], buf, size);
0301 
0302   sc = ds1339_open_file(&fd);
0303 
0304   if (sc == RTEMS_SUCCESSFUL)
0305   {
0306     rv = write(fd, local_buf, write_size);
0307     if (rv != write_size)
0308       sc = RTEMS_IO_ERROR;
0309   }
0310 
0311   rv = close(fd);
0312   if (rv != 0)
0313     sc = RTEMS_IO_ERROR;
0314 
0315   return RTEMS_SUCCESSFUL;
0316 }
0317 
0318 
0319 static void altera_cyclone_v_ds1339_initialize(int minor)
0320 {
0321 
0322   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0323   uint8_t            status = 0;
0324 
0325   /* Check RTC valid */
0326   sc = ds1339_read(DS1339_ADDR_STATUS, &status, sizeof(status));
0327   assert(sc == RTEMS_SUCCESSFUL);
0328 
0329   if (status & DS1339_STATUS_OSF)
0330   {
0331     /* RTC has been stopped. Initialise it. */
0332     ds1339_time_t time;
0333 
0334     uint8_t  write = DS1339_CTRL_DEFAULT;
0335     sc = ds1339_write(DS1339_ADDR_CTRL, &write, sizeof(write));
0336     assert(sc == RTEMS_SUCCESSFUL);
0337 
0338     write = DS1339_STATUS_CLEAR;
0339     sc = ds1339_write(DS1339_ADDR_STATUS, &write, sizeof(write));
0340     assert(sc == RTEMS_SUCCESSFUL);
0341 
0342     ds1339_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
0343     sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
0344     assert(sc == RTEMS_SUCCESSFUL);
0345   }
0346 
0347 }
0348 
0349 
0350 static int altera_cyclone_v_ds1339_get_time(int minor, rtems_time_of_day* tod)
0351 {
0352 
0353   ds1339_time_t      time;
0354   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0355   rtems_time_of_day  temp_tod;
0356 
0357   sc = ds1339_read(DS1339_ADDR_TIME, &time, sizeof(time));
0358 
0359   if (sc == RTEMS_SUCCESSFUL)
0360   {
0361     temp_tod.ticks  = 0;
0362     temp_tod.second = ds1339_get_seconds(&time);
0363     temp_tod.minute = ds1339_get_minutes(&time);
0364     temp_tod.hour   = ds1339_get_hours(&time);
0365     temp_tod.day    = ds1339_get_day_of_month(&time);
0366     temp_tod.month  = ds1339_get_month(&time);
0367     temp_tod.year   = ds1339_get_year(&time);
0368 
0369     sc = _TOD_Validate(&temp_tod, TOD_ENABLE_TICKS_VALIDATION);
0370     if (sc == RTEMS_SUCCESSFUL)
0371       memcpy(tod, &temp_tod, sizeof(temp_tod));
0372   }
0373 
0374   return -sc;
0375 }
0376 
0377 
0378 static int  altera_cyclone_v_ds1339_set_time(int minor, const rtems_time_of_day* tod)
0379 {
0380 
0381   ds1339_time_t      time;
0382   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0383 
0384   ds1339_set_time(&time,
0385                   tod->second,
0386                   tod->minute,
0387                   tod->hour,
0388                   tod->day,
0389                   tod->month,
0390                   tod->year
0391                  );
0392 
0393   sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
0394 
0395   return -sc;
0396 }
0397 
0398 
0399 static bool  altera_cyclone_v_ds1339_probe(int minor)
0400 {
0401 
0402   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0403   uint8_t            buf;
0404 
0405   /* try to read from register address 0x00 */
0406   sc = ds1339_read(0x00, &buf, 1);
0407   if (sc != RTEMS_SUCCESSFUL)
0408     /* no RTC implemented */
0409     return false;
0410   /* try to read from register address 0x20 (not implemented in DS1339) */
0411   sc = ds1339_read(0x20, &buf, 1);
0412   if (sc == RTEMS_SUCCESSFUL)
0413     /* RTC is not DS1339 */
0414     return false;
0415 
0416   return true;
0417 
0418 }
0419 
0420 
0421 /* ******************************* M41ST87 ********************************** */
0422 
0423 
0424 #define M41ST87_I2C_ADDRESS       (0xD0 >> 1)  /* 7-bit addressing! */
0425 #define M41ST87_I2C_BUS_DEVICE    "/dev/i2c0"
0426 
0427 #define M41ST87_ADDR_TIME         0x00
0428 
0429 #define M41ST87_ADDR_CTRL         0x08
0430 #define   M41ST87_CTRL_OUT          0x80
0431 #define   M41ST87_CTRL_FT           0x40
0432 #define   M41ST87_CTRL_S            0x20
0433 #define   M41ST87_CTRL_CAL          0x1F
0434 
0435 #define M41ST87_ADDR_ALARM_HOUR   0x0C
0436 #define   M41ST87_BIT_HT            0x40
0437 
0438 #define M41ST87_ADDR_FLAGS        0x0F
0439 #define   M41ST87_FLAG_WDF          0x80
0440 #define   M41ST87_FLAG_AF           0x40
0441 #define   M41ST87_FLAG_BL           0x10
0442 #define   M41ST87_FLAG_OF           0x04
0443 #define   M41ST87_FLAG_TB1          0x02
0444 #define   M41ST87_FLAG_TB2          0x01
0445 
0446 #define M41ST87_ADDR_USER_RAM     0x20
0447 
0448 
0449 typedef struct
0450 {
0451   uint8_t  sec100;
0452   uint8_t  seconds;
0453 #define M41ST87_BIT_ST          0x80
0454   uint8_t  minutes;
0455 #define M41ST87_BIT_OFIE        0x80
0456   uint8_t  hours;
0457 #define M41ST87_BIT_CB1         0x80
0458 #define M41ST87_BIT_CB0         0x40
0459   uint8_t  weekday;
0460 #define M41ST87_BIT_TR          0x80
0461 #define M41ST87_BIT_THS         0x40
0462 #define M41ST87_BIT_CLRPW1      0x20
0463 #define M41ST87_BIT_CLRPW0      0x10
0464 #define M41ST87_BIT_32KE        0x08
0465   uint8_t  day;
0466 #define M41ST87_BIT_PFOD        0x80
0467   uint8_t  month;
0468   uint8_t  year;
0469 }
0470 m41st87_time_t;
0471 
0472 
0473 /* The longest write transmission is writing the time + one address bit */
0474 #define M41ST87_MAX_WRITE_SIZE  (sizeof(m41st87_time_t) + 1)
0475 
0476 
0477 /* Functions for converting the fields */
0478 
0479 /*
0480 static unsigned int  m41st87_get_sec100(m41st87_time_t* time)
0481 {
0482 
0483   uint8_t  tens = time->sec100 >> 4;
0484   uint8_t  ones = time->sec100 & 0x0F;
0485 
0486   return tens * 10 + ones;
0487 }
0488 */
0489 
0490 
0491 static unsigned int  m41st87_get_seconds(m41st87_time_t* time)
0492 {
0493 
0494   uint8_t  tens = (time->seconds >> 4) & 0x07;
0495   uint8_t  ones = time->seconds & 0x0F;
0496 
0497   return tens * 10 + ones;
0498 }
0499 
0500 
0501 static unsigned int  m41st87_get_minutes(m41st87_time_t* time)
0502 {
0503 
0504   uint8_t  tens = (time->minutes >> 4) & 0x07;
0505   uint8_t  ones = time->minutes & 0x0F;
0506 
0507   return tens * 10 + ones;
0508 }
0509 
0510 
0511 static unsigned int  m41st87_get_hours(m41st87_time_t* time)
0512 {
0513 
0514   uint8_t  tens = (time->hours >> 4) & 0x03;
0515   uint8_t  ones = time->hours & 0x0F;
0516 
0517   return tens * 10 + ones;
0518 }
0519 
0520 
0521 /*
0522 static unsigned int  m41st87_get_day_of_week(m41st87_time_t* time)
0523 {
0524 
0525   return time->weekday & 0x07;
0526 }
0527 */
0528 
0529 
0530 static unsigned int  m41st87_get_day_of_month(m41st87_time_t* time)
0531 {
0532 
0533   uint8_t  tens = (time->day >> 4) & 0x03;
0534   uint8_t  ones = time->day & 0x0F;
0535 
0536   return tens * 10 + ones;
0537 }
0538 
0539 
0540 static unsigned int  m41st87_get_month(m41st87_time_t* time)
0541 {
0542 
0543   uint8_t  tens = (time->month >> 4) & 0x01;
0544   uint8_t  ones = time->month & 0x0F;
0545 
0546   return tens * 10 + ones;
0547 }
0548 
0549 
0550 static unsigned int  m41st87_get_year(m41st87_time_t* time)
0551 {
0552 
0553   uint8_t  century = time->hours >> 6;
0554   uint8_t  tens    = time->year >> 4;
0555   uint8_t  ones    = time->year & 0x0F;
0556 
0557   return 1900 + century * 100 + tens * 10 + ones;
0558 }
0559 
0560 
0561 static void  m41st87_set_time(m41st87_time_t* time,
0562                               unsigned int second,
0563                               unsigned int minute,
0564                               unsigned int hour,
0565                               unsigned int day,
0566                               unsigned int month,
0567                               unsigned int year)
0568 {
0569 
0570   unsigned int  century;
0571   unsigned int  tens;
0572   unsigned int  ones;
0573 
0574   if (year < 1900)
0575     year = 1900;
0576   if (year > 2399)
0577     year = 2399;
0578   century = (year - 1900) / 100;
0579 
0580   /* Hundreds of seconds is not used, set to 0 */
0581   time->sec100 = 0;
0582 
0583   tens = second / 10;
0584   ones = second % 10;
0585   time->seconds = (time->seconds & 0x80) | (tens << 4) | ones;
0586 
0587   tens = minute / 10;
0588   ones = minute % 10;
0589   time->minutes = (time->minutes & 0x80) | (tens << 4) | ones;
0590 
0591   tens = hour / 10;
0592   ones = hour % 10;
0593   time->hours = (century << 6) | (tens << 4) | ones;
0594 
0595   /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
0596   time->weekday = (time->weekday & 0xF8) | 1;
0597 
0598   tens = day / 10;
0599   ones = day % 10;
0600   time->day = (time->day & 0x80) | (tens << 4) | ones;
0601 
0602   tens = month / 10;
0603   ones = month % 10;
0604   time->month = (tens << 4) | ones;
0605 
0606   tens = (year % 100) / 10;
0607   ones = year % 10;
0608   time->year = (tens << 4) | ones;
0609 
0610 }
0611 
0612 
0613 
0614 static rtems_status_code  m41st87_open_file(int* fd)
0615 {
0616 
0617   int                rv = 0;
0618   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0619 
0620   *fd = open(M41ST87_I2C_BUS_DEVICE, O_RDWR);
0621   if (*fd == -1)
0622     sc = RTEMS_IO_ERROR;
0623 
0624   if (sc == RTEMS_SUCCESSFUL)
0625   {
0626     rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, M41ST87_I2C_ADDRESS);
0627     if (rv == -1)
0628       sc = RTEMS_IO_ERROR;
0629   }
0630 
0631   return sc;
0632 }
0633 
0634 
0635 /* Read size bytes from m41st87 register address addr to buf. */
0636 static rtems_status_code  m41st87_read(uint8_t addr, void* buf, size_t size)
0637 {
0638 
0639   int                fd = -1;
0640   int                rv = 0;
0641   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0642 
0643   sc = m41st87_open_file(&fd);
0644 
0645   if (sc == RTEMS_SUCCESSFUL)
0646   {
0647     rv = write(fd, &addr, sizeof(addr));
0648     if (rv != sizeof(addr))
0649       sc = RTEMS_IO_ERROR;
0650   }
0651 
0652   if (sc == RTEMS_SUCCESSFUL)
0653   {
0654     rv = read(fd, buf, size);
0655     if (rv != size)
0656       sc = RTEMS_IO_ERROR;
0657   }
0658 
0659   rv = close(fd);
0660   if (rv != 0)
0661     sc = RTEMS_IO_ERROR;
0662 
0663   return sc;
0664 }
0665 
0666 
0667 /* Write size bytes from buf to m41st87 register address addr. */
0668 static rtems_status_code  m41st87_write(uint8_t addr, void* buf, size_t size)
0669 {
0670 
0671   int                fd = -1;
0672   int                rv = 0;
0673   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0674   /* The driver never writes many bytes. Therefore it should be less expensive
0675    * to reserve the maximum number of bytes that will be written in one go than
0676    * use a malloc. */
0677   uint8_t            local_buf[M41ST87_MAX_WRITE_SIZE];
0678   int                write_size = size + 1;
0679 
0680   assert(write_size <= M41ST87_MAX_WRITE_SIZE);
0681 
0682   local_buf[0] = addr;
0683   memcpy(&local_buf[1], buf, size);
0684 
0685   sc = m41st87_open_file(&fd);
0686 
0687   if (sc == RTEMS_SUCCESSFUL)
0688   {
0689     rv = write(fd, local_buf, write_size);
0690     if (rv != write_size)
0691       sc = RTEMS_IO_ERROR;
0692   }
0693 
0694   rv = close(fd);
0695   if (rv != 0)
0696     sc = RTEMS_IO_ERROR;
0697 
0698   return RTEMS_SUCCESSFUL;
0699 }
0700 
0701 
0702 static void  altera_cyclone_v_m41st87_initialize(int minor)
0703 {
0704 
0705   m41st87_time_t     time;
0706   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0707   uint8_t            value;
0708 
0709   /* Check RTC valid */
0710   sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
0711   assert(sc == RTEMS_SUCCESSFUL);
0712 
0713   if (time.seconds & M41ST87_BIT_ST)
0714   {
0715     /* RTC has been stopped. Reset stop flag. */
0716     time.seconds = 0;
0717     /* Initialise RTC. */
0718     m41st87_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
0719     sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
0720     assert(sc == RTEMS_SUCCESSFUL);
0721   }
0722 
0723   /* Reset HT bit */
0724   sc = m41st87_read(M41ST87_ADDR_ALARM_HOUR, &value, 1);
0725   assert(sc == RTEMS_SUCCESSFUL);
0726   value &= ~M41ST87_BIT_HT;
0727   sc = m41st87_write(M41ST87_ADDR_ALARM_HOUR, &value, 1);
0728   assert(sc == RTEMS_SUCCESSFUL);
0729 
0730 }
0731 
0732 
0733 static int  altera_cyclone_v_m41st87_get_time(int minor, rtems_time_of_day* tod)
0734 {
0735 
0736   m41st87_time_t     time;
0737   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0738   rtems_time_of_day  temp_tod;
0739 
0740   sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
0741   if (sc != RTEMS_SUCCESSFUL)
0742     return -sc;
0743 
0744   temp_tod.ticks  = 0;
0745   temp_tod.second = m41st87_get_seconds(&time);
0746   temp_tod.minute = m41st87_get_minutes(&time);
0747   temp_tod.hour   = m41st87_get_hours(&time);
0748   temp_tod.day    = m41st87_get_day_of_month(&time);
0749   temp_tod.month  = m41st87_get_month(&time);
0750   temp_tod.year   = m41st87_get_year(&time);
0751 
0752   sc = _TOD_Validate(&temp_tod, TOD_ENABLE_TICKS_VALIDATION);
0753   if (sc == RTEMS_SUCCESSFUL)
0754     memcpy(tod, &temp_tod, sizeof(temp_tod));
0755 
0756   return -sc;
0757 }
0758 
0759 
0760 static int  altera_cyclone_v_m41st87_set_time(int minor, const rtems_time_of_day* tod)
0761 {
0762 
0763   m41st87_time_t     time;
0764   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0765 
0766   /* first read to preserve the additional flags */
0767   sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
0768   if (sc != RTEMS_SUCCESSFUL)
0769     return -sc;
0770 
0771   m41st87_set_time(&time,
0772                    tod->second,
0773                    tod->minute,
0774                    tod->hour,
0775                    tod->day,
0776                    tod->month,
0777                    tod->year
0778                   );
0779 
0780   sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
0781 
0782   return -sc;
0783 }
0784 
0785 
0786 static bool  altera_cyclone_v_m41st87_probe(int minor)
0787 {
0788 
0789   rtems_status_code  sc = RTEMS_SUCCESSFUL;
0790   uint8_t            buf;
0791 
0792   /* try to read from register address 0x00 */
0793   sc = m41st87_read(0x00, &buf, 1);
0794   if (sc != RTEMS_SUCCESSFUL)
0795     /* no RTC implemented */
0796     return false;
0797   /* try to read from register address 0x20 (implemented in M41ST87) */
0798   sc = m41st87_read(0x20, &buf, 1);
0799   if (sc != RTEMS_SUCCESSFUL)
0800     /* RTC is not M41ST87 */
0801     return false;
0802 
0803   return true;
0804 
0805 }
0806 
0807 
0808 /* **************************************** General ********************************** */
0809 
0810 
0811 const rtc_fns  altera_cyclone_v_ds1339_ops =
0812 {
0813   .deviceInitialize = altera_cyclone_v_ds1339_initialize,
0814   .deviceGetTime = altera_cyclone_v_ds1339_get_time,
0815   .deviceSetTime = altera_cyclone_v_ds1339_set_time
0816 };
0817 
0818 
0819 const rtc_fns  altera_cyclone_v_m41st87_ops =
0820 {
0821   .deviceInitialize = altera_cyclone_v_m41st87_initialize,
0822   .deviceGetTime = altera_cyclone_v_m41st87_get_time,
0823   .deviceSetTime = altera_cyclone_v_m41st87_set_time
0824 };
0825 
0826 
0827 size_t  RTC_Count = ALTERA_CYCLONE_V_RTC_NUMBER;
0828 
0829 rtc_tbl  RTC_Table[ALTERA_CYCLONE_V_RTC_NUMBER] =
0830 {
0831   {
0832     .sDeviceName = "/dev/rtc",
0833     .deviceType = RTC_CUSTOM,
0834     .pDeviceFns = &altera_cyclone_v_ds1339_ops,
0835     .deviceProbe = altera_cyclone_v_ds1339_probe,
0836     .pDeviceParams = NULL,
0837     .ulCtrlPort1 = 0,
0838     .ulDataPort = 0,
0839     .getRegister = NULL,
0840     .setRegister = NULL
0841   },
0842   {
0843     .sDeviceName = "/dev/rtc",
0844     .deviceType = RTC_CUSTOM,
0845     .pDeviceFns = &altera_cyclone_v_m41st87_ops,
0846     .deviceProbe = altera_cyclone_v_m41st87_probe,
0847     .pDeviceParams = NULL,
0848     .ulCtrlPort1 = 0,
0849     .ulDataPort = 0,
0850     .getRegister = NULL,
0851     .setRegister = NULL
0852   }
0853 };