source: rtems/bsps/arm/altera-cyclone-v/rtc/rtc.c @ 9e0244e

Last change on this file since 9e0244e was 9e0244e, checked in by Joel Sherrill <joel@…>, on 06/27/22 at 13:45:43

bsps/arm/altera-cyclone-v: Change license to BSD-2

Updates #3053.

  • Property mode set to 100644
File size: 19.9 KB
Line 
1/* SPDX-License-Identifier: BSD-2-Clause */
2
3/**
4 * @file
5 *
6 * @ingroup RTEMSBSPsARMCycV
7 */
8
9/*
10 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34/*
35 * Driver for the DS1339 RTC (Maxim Semiconductors) -> RTC1
36 *        and the M41ST87 RTC (ST Microelectronics) -> RTC2
37 *
38 * Please note the following points:
39 * - The day of week is ignored.
40 * - The century bit is interpreted the following way:
41 *   - century not set: TOD_BASE_YEAR .. 1999
42 *   - century set: 2000 .. 2099
43 *   - century not set: 2100 .. (TOD_BASE_YEAR + 200)
44 */
45
46#include <libchip/rtc.h>
47#include <assert.h>
48#include <rtems/score/todimpl.h>
49#include <rtems/rtems/clockimpl.h>
50#include <sys/filio.h>
51#include <fcntl.h>
52#include <string.h>
53#include <unistd.h>
54#include <bsp/i2cdrv.h>
55
56#define ALTERA_CYCLONE_V_RTC_NUMBER  2
57
58
59/* ******************************* DS1339 ********************************** */
60
61
62#define DS1339_I2C_ADDRESS     (0xD0 >> 1)  /* 7-bit addressing! */
63#define DS1339_I2C_BUS_DEVICE  "/dev/i2c0"
64
65#define DS1339_ADDR_TIME    0x00
66
67#define DS1339_ADDR_CTRL   0x0E
68#define   DS1339_CTRL_EOSC   0x80
69#define   DS1339_CTRL_BBSQI  0x20
70#define   DS1339_CTRL_RS2    0x10
71#define   DS1339_CTRL_RS1    0x08
72#define   DS1339_CTRL_INTCN  0x04
73#define   DS1339_CTRL_A2IE   0x02
74#define   DS1339_CTRL_A1IE   0x01
75
76#define DS1339_CTRL_DEFAULT  (0x00)
77
78#define DS1339_ADDR_STATUS  0x0F
79#define   DS1339_STATUS_OSF   0x80
80#define   DS1339_STATUS_A2F   0x02
81#define   DS1339_STATUS_A1F   0x01
82
83#define DS1339_STATUS_CLEAR  (0x00)
84
85#define DS1339_ADDR_TRICKLE_CHARGE  0x10
86
87
88typedef struct
89{
90  uint8_t  seconds;
91  uint8_t  minutes;
92  uint8_t  hours;
93#define DS1339_HOURS_12_24_FLAG 0x40
94#define DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS 0x20
95#define DS1339_HOURS_10_HOURS 0x10
96  uint8_t  weekday;
97  uint8_t  date;
98  uint8_t  month;
99#define DS1339_MONTH_CENTURY 0x80
100  uint8_t  year;
101}
102ds1339_time_t;
103
104
105/* The longest write transmission is writing the time + one address bit */
106#define DS1339_MAX_WRITE_SIZE  (sizeof(ds1339_time_t) + 1)
107
108
109/* Functions for converting the fields */
110static unsigned int  ds1339_get_seconds(ds1339_time_t* time)
111{
112  uint8_t  tens = time->seconds >> 4;
113  uint8_t  ones = time->seconds & 0x0F;
114
115  return tens * 10 + ones;
116}
117
118
119static unsigned int  ds1339_get_minutes(ds1339_time_t* time)
120{
121  uint8_t  tens = time->minutes >> 4;
122  uint8_t  ones = time->minutes & 0x0F;
123
124  return tens * 10 + ones;
125}
126
127
128static unsigned int  ds1339_get_hours(ds1339_time_t* time)
129{
130
131  uint8_t  value = time->hours & 0x0F;
132
133  if (time->hours & DS1339_HOURS_10_HOURS)
134  {
135    value += 10;
136  }
137  if (time->hours & DS1339_HOURS_AM_PM_FLAG_OR_20_HOURS)
138  {
139    if (time->hours & DS1339_HOURS_12_24_FLAG)
140      value += 12;
141    else
142      value += 20;
143  }
144
145  return value;
146}
147
148
149static unsigned int  ds1339_get_day_of_month(ds1339_time_t* time)
150{
151
152  uint8_t  tens = time->date >> 4;
153  uint8_t  ones = time->date & 0x0F;
154
155  return tens * 10 + ones;
156}
157
158
159static unsigned int  ds1339_get_month(ds1339_time_t* time)
160{
161
162  uint8_t  tens = (time->month >> 4) & 0x07;
163  uint8_t  ones = time->month & 0x0F;
164
165  return tens * 10 + ones;
166}
167
168
169static unsigned int  ds1339_get_year(ds1339_time_t* time)
170{
171
172  unsigned int  year = 1900;
173
174  year += (time->year >> 4) * 10;
175  year += time->year & 0x0F;
176  if (time->month & DS1339_MONTH_CENTURY)
177    year += 100;
178  if (year < TOD_BASE_YEAR)
179    year += 200;
180
181  return year;
182}
183
184
185static void  ds1339_set_time(ds1339_time_t* time,
186                             unsigned int second,
187                             unsigned int minute,
188                             unsigned int hour,
189                             unsigned int day,
190                             unsigned int month,
191                             unsigned int year)
192{
193
194  unsigned int  tens;
195  unsigned int  ones;
196  uint8_t       century = 0;
197
198  tens = second / 10;
199  ones = second % 10;
200  time->seconds = tens << 4 | ones;
201
202  tens = minute / 10;
203  ones = minute % 10;
204  time->minutes = tens << 4 | ones;
205
206  tens = hour / 10;
207  ones = hour % 10;
208  time->hours = tens << 4 | ones;
209
210  /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
211  time->weekday = 1;
212
213  tens = day / 10;
214  ones = day % 10;
215  time->date = tens << 4 | ones;
216
217  tens = month / 10;
218  ones = month % 10;
219  if ((year >= 2000) && (year < 2100))
220    century = DS1339_MONTH_CENTURY;
221  time->month = century | tens << 4 | ones;
222
223  tens = (year % 100) / 10;
224  ones = year % 10;
225  time->year = tens << 4 | ones;
226
227}
228
229
230
231static rtems_status_code  ds1339_open_file(int* fd)
232{
233
234  int                rv = 0;
235  rtems_status_code  sc = RTEMS_SUCCESSFUL;
236
237  *fd = open(DS1339_I2C_BUS_DEVICE, O_RDWR);
238  if (*fd == -1)
239    sc = RTEMS_IO_ERROR;
240
241  if (sc == RTEMS_SUCCESSFUL)
242  {
243    rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, DS1339_I2C_ADDRESS);
244    if (rv == -1)
245      sc = RTEMS_IO_ERROR;
246  }
247
248  return sc;
249}
250
251
252/* Read size bytes from ds1339 register address addr to buf. */
253static rtems_status_code  ds1339_read(uint8_t addr, void* buf, size_t size)
254{
255
256  int                fd = -1;
257  int                rv = 0;
258  rtems_status_code  sc = RTEMS_SUCCESSFUL;
259
260  sc = ds1339_open_file(&fd);
261
262  if (sc == RTEMS_SUCCESSFUL)
263  {
264    rv = write(fd, &addr, sizeof(addr));
265    if (rv != sizeof(addr))
266      sc = RTEMS_IO_ERROR;
267  }
268
269  if (sc == RTEMS_SUCCESSFUL)
270  {
271    rv = read(fd, buf, size);
272    if (rv != size)
273      sc = RTEMS_IO_ERROR;
274  }
275
276  rv = close(fd);
277  if (rv != 0)
278    sc = RTEMS_IO_ERROR;
279
280  return sc;
281}
282
283
284/* Write size bytes from buf to ds1339 register address addr. */
285static rtems_status_code  ds1339_write(uint8_t addr, void* buf, size_t size)
286{
287
288  int                fd = -1;
289  int                rv = 0;
290  rtems_status_code  sc = RTEMS_SUCCESSFUL;
291  /* The driver never writes many bytes. Therefore it should be less expensive
292   * to reserve the maximum number of bytes that will be written in one go than
293   * use a malloc. */
294  uint8_t            local_buf[DS1339_MAX_WRITE_SIZE];
295  int                write_size = size + 1;
296
297  assert(write_size <= DS1339_MAX_WRITE_SIZE);
298
299  local_buf[0] = addr;
300  memcpy(&local_buf[1], buf, size);
301
302  sc = ds1339_open_file(&fd);
303
304  if (sc == RTEMS_SUCCESSFUL)
305  {
306    rv = write(fd, local_buf, write_size);
307    if (rv != write_size)
308      sc = RTEMS_IO_ERROR;
309  }
310
311  rv = close(fd);
312  if (rv != 0)
313    sc = RTEMS_IO_ERROR;
314
315  return RTEMS_SUCCESSFUL;
316}
317
318
319static void altera_cyclone_v_ds1339_initialize(int minor)
320{
321
322  rtems_status_code  sc = RTEMS_SUCCESSFUL;
323  uint8_t            status = 0;
324
325  /* Check RTC valid */
326  sc = ds1339_read(DS1339_ADDR_STATUS, &status, sizeof(status));
327  assert(sc == RTEMS_SUCCESSFUL);
328
329  if (status & DS1339_STATUS_OSF)
330  {
331    /* RTC has been stopped. Initialise it. */
332    ds1339_time_t time;
333
334    uint8_t  write = DS1339_CTRL_DEFAULT;
335    sc = ds1339_write(DS1339_ADDR_CTRL, &write, sizeof(write));
336    assert(sc == RTEMS_SUCCESSFUL);
337
338    write = DS1339_STATUS_CLEAR;
339    sc = ds1339_write(DS1339_ADDR_STATUS, &write, sizeof(write));
340    assert(sc == RTEMS_SUCCESSFUL);
341
342    ds1339_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
343    sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
344    assert(sc == RTEMS_SUCCESSFUL);
345  }
346
347}
348
349
350static int altera_cyclone_v_ds1339_get_time(int minor, rtems_time_of_day* tod)
351{
352
353  ds1339_time_t      time;
354  rtems_status_code  sc = RTEMS_SUCCESSFUL;
355  rtems_time_of_day  temp_tod;
356
357  sc = ds1339_read(DS1339_ADDR_TIME, &time, sizeof(time));
358
359  if (sc == RTEMS_SUCCESSFUL)
360  {
361    temp_tod.ticks  = 0;
362    temp_tod.second = ds1339_get_seconds(&time);
363    temp_tod.minute = ds1339_get_minutes(&time);
364    temp_tod.hour   = ds1339_get_hours(&time);
365    temp_tod.day    = ds1339_get_day_of_month(&time);
366    temp_tod.month  = ds1339_get_month(&time);
367    temp_tod.year   = ds1339_get_year(&time);
368
369    sc = _TOD_Validate(&temp_tod, TOD_ENABLE_TICKS_VALIDATION);
370    if (sc == RTEMS_SUCCESSFUL)
371      memcpy(tod, &temp_tod, sizeof(temp_tod));
372  }
373
374  return -sc;
375}
376
377
378static int  altera_cyclone_v_ds1339_set_time(int minor, const rtems_time_of_day* tod)
379{
380
381  ds1339_time_t      time;
382  rtems_status_code  sc = RTEMS_SUCCESSFUL;
383
384  ds1339_set_time(&time,
385                  tod->second,
386                  tod->minute,
387                  tod->hour,
388                  tod->day,
389                  tod->month,
390                  tod->year
391                 );
392
393  sc = ds1339_write(DS1339_ADDR_TIME, &time, sizeof(time));
394
395  return -sc;
396}
397
398
399static bool  altera_cyclone_v_ds1339_probe(int minor)
400{
401
402  rtems_status_code  sc = RTEMS_SUCCESSFUL;
403  uint8_t            buf;
404
405  /* try to read from register address 0x00 */
406  sc = ds1339_read(0x00, &buf, 1);
407  if (sc != RTEMS_SUCCESSFUL)
408    /* no RTC implemented */
409    return false;
410  /* try to read from register address 0x20 (not implemented in DS1339) */
411  sc = ds1339_read(0x20, &buf, 1);
412  if (sc == RTEMS_SUCCESSFUL)
413    /* RTC is not DS1339 */
414    return false;
415
416  return true;
417
418}
419
420
421/* ******************************* M41ST87 ********************************** */
422
423
424#define M41ST87_I2C_ADDRESS       (0xD0 >> 1)  /* 7-bit addressing! */
425#define M41ST87_I2C_BUS_DEVICE    "/dev/i2c0"
426
427#define M41ST87_ADDR_TIME         0x00
428
429#define M41ST87_ADDR_CTRL         0x08
430#define   M41ST87_CTRL_OUT          0x80
431#define   M41ST87_CTRL_FT           0x40
432#define   M41ST87_CTRL_S            0x20
433#define   M41ST87_CTRL_CAL          0x1F
434
435#define M41ST87_ADDR_ALARM_HOUR   0x0C
436#define   M41ST87_BIT_HT            0x40
437
438#define M41ST87_ADDR_FLAGS        0x0F
439#define   M41ST87_FLAG_WDF          0x80
440#define   M41ST87_FLAG_AF           0x40
441#define   M41ST87_FLAG_BL           0x10
442#define   M41ST87_FLAG_OF           0x04
443#define   M41ST87_FLAG_TB1          0x02
444#define   M41ST87_FLAG_TB2          0x01
445
446#define M41ST87_ADDR_USER_RAM     0x20
447
448
449typedef struct
450{
451  uint8_t  sec100;
452  uint8_t  seconds;
453#define M41ST87_BIT_ST          0x80
454  uint8_t  minutes;
455#define M41ST87_BIT_OFIE        0x80
456  uint8_t  hours;
457#define M41ST87_BIT_CB1         0x80
458#define M41ST87_BIT_CB0         0x40
459  uint8_t  weekday;
460#define M41ST87_BIT_TR          0x80
461#define M41ST87_BIT_THS         0x40
462#define M41ST87_BIT_CLRPW1      0x20
463#define M41ST87_BIT_CLRPW0      0x10
464#define M41ST87_BIT_32KE        0x08
465  uint8_t  day;
466#define M41ST87_BIT_PFOD        0x80
467  uint8_t  month;
468  uint8_t  year;
469}
470m41st87_time_t;
471
472
473/* The longest write transmission is writing the time + one address bit */
474#define M41ST87_MAX_WRITE_SIZE  (sizeof(m41st87_time_t) + 1)
475
476
477/* Functions for converting the fields */
478
479/*
480static unsigned int  m41st87_get_sec100(m41st87_time_t* time)
481{
482
483  uint8_t  tens = time->sec100 >> 4;
484  uint8_t  ones = time->sec100 & 0x0F;
485
486  return tens * 10 + ones;
487}
488*/
489
490
491static unsigned int  m41st87_get_seconds(m41st87_time_t* time)
492{
493
494  uint8_t  tens = (time->seconds >> 4) & 0x07;
495  uint8_t  ones = time->seconds & 0x0F;
496
497  return tens * 10 + ones;
498}
499
500
501static unsigned int  m41st87_get_minutes(m41st87_time_t* time)
502{
503
504  uint8_t  tens = (time->minutes >> 4) & 0x07;
505  uint8_t  ones = time->minutes & 0x0F;
506
507  return tens * 10 + ones;
508}
509
510
511static unsigned int  m41st87_get_hours(m41st87_time_t* time)
512{
513
514  uint8_t  tens = (time->hours >> 4) & 0x03;
515  uint8_t  ones = time->hours & 0x0F;
516
517  return tens * 10 + ones;
518}
519
520
521/*
522static unsigned int  m41st87_get_day_of_week(m41st87_time_t* time)
523{
524
525  return time->weekday & 0x07;
526}
527*/
528
529
530static unsigned int  m41st87_get_day_of_month(m41st87_time_t* time)
531{
532
533  uint8_t  tens = (time->day >> 4) & 0x03;
534  uint8_t  ones = time->day & 0x0F;
535
536  return tens * 10 + ones;
537}
538
539
540static unsigned int  m41st87_get_month(m41st87_time_t* time)
541{
542
543  uint8_t  tens = (time->month >> 4) & 0x01;
544  uint8_t  ones = time->month & 0x0F;
545
546  return tens * 10 + ones;
547}
548
549
550static unsigned int  m41st87_get_year(m41st87_time_t* time)
551{
552
553  uint8_t  century = time->hours >> 6;
554  uint8_t  tens    = time->year >> 4;
555  uint8_t  ones    = time->year & 0x0F;
556
557  return 1900 + century * 100 + tens * 10 + ones;
558}
559
560
561static void  m41st87_set_time(m41st87_time_t* time,
562                              unsigned int second,
563                              unsigned int minute,
564                              unsigned int hour,
565                              unsigned int day,
566                              unsigned int month,
567                              unsigned int year)
568{
569
570  unsigned int  century;
571  unsigned int  tens;
572  unsigned int  ones;
573
574  if (year < 1900)
575    year = 1900;
576  if (year > 2399)
577    year = 2399;
578  century = (year - 1900) / 100;
579
580  /* Hundreds of seconds is not used, set to 0 */
581  time->sec100 = 0;
582
583  tens = second / 10;
584  ones = second % 10;
585  time->seconds = (time->seconds & 0x80) | (tens << 4) | ones;
586
587  tens = minute / 10;
588  ones = minute % 10;
589  time->minutes = (time->minutes & 0x80) | (tens << 4) | ones;
590
591  tens = hour / 10;
592  ones = hour % 10;
593  time->hours = (century << 6) | (tens << 4) | ones;
594
595  /* Weekday is not used. Therefore it can be set to an arbitrary valid value */
596  time->weekday = (time->weekday & 0xF8) | 1;
597
598  tens = day / 10;
599  ones = day % 10;
600  time->day = (time->day & 0x80) | (tens << 4) | ones;
601
602  tens = month / 10;
603  ones = month % 10;
604  time->month = (tens << 4) | ones;
605
606  tens = (year % 100) / 10;
607  ones = year % 10;
608  time->year = (tens << 4) | ones;
609
610}
611
612
613
614static rtems_status_code  m41st87_open_file(int* fd)
615{
616
617  int                rv = 0;
618  rtems_status_code  sc = RTEMS_SUCCESSFUL;
619
620  *fd = open(M41ST87_I2C_BUS_DEVICE, O_RDWR);
621  if (*fd == -1)
622    sc = RTEMS_IO_ERROR;
623
624  if (sc == RTEMS_SUCCESSFUL)
625  {
626    rv = ioctl(*fd, I2C_IOC_SET_SLAVE_ADDRESS, M41ST87_I2C_ADDRESS);
627    if (rv == -1)
628      sc = RTEMS_IO_ERROR;
629  }
630
631  return sc;
632}
633
634
635/* Read size bytes from m41st87 register address addr to buf. */
636static rtems_status_code  m41st87_read(uint8_t addr, void* buf, size_t size)
637{
638
639  int                fd = -1;
640  int                rv = 0;
641  rtems_status_code  sc = RTEMS_SUCCESSFUL;
642
643  sc = m41st87_open_file(&fd);
644
645  if (sc == RTEMS_SUCCESSFUL)
646  {
647    rv = write(fd, &addr, sizeof(addr));
648    if (rv != sizeof(addr))
649      sc = RTEMS_IO_ERROR;
650  }
651
652  if (sc == RTEMS_SUCCESSFUL)
653  {
654    rv = read(fd, buf, size);
655    if (rv != size)
656      sc = RTEMS_IO_ERROR;
657  }
658
659  rv = close(fd);
660  if (rv != 0)
661    sc = RTEMS_IO_ERROR;
662
663  return sc;
664}
665
666
667/* Write size bytes from buf to m41st87 register address addr. */
668static rtems_status_code  m41st87_write(uint8_t addr, void* buf, size_t size)
669{
670
671  int                fd = -1;
672  int                rv = 0;
673  rtems_status_code  sc = RTEMS_SUCCESSFUL;
674  /* The driver never writes many bytes. Therefore it should be less expensive
675   * to reserve the maximum number of bytes that will be written in one go than
676   * use a malloc. */
677  uint8_t            local_buf[M41ST87_MAX_WRITE_SIZE];
678  int                write_size = size + 1;
679
680  assert(write_size <= M41ST87_MAX_WRITE_SIZE);
681
682  local_buf[0] = addr;
683  memcpy(&local_buf[1], buf, size);
684
685  sc = m41st87_open_file(&fd);
686
687  if (sc == RTEMS_SUCCESSFUL)
688  {
689    rv = write(fd, local_buf, write_size);
690    if (rv != write_size)
691      sc = RTEMS_IO_ERROR;
692  }
693
694  rv = close(fd);
695  if (rv != 0)
696    sc = RTEMS_IO_ERROR;
697
698  return RTEMS_SUCCESSFUL;
699}
700
701
702static void  altera_cyclone_v_m41st87_initialize(int minor)
703{
704
705  m41st87_time_t     time;
706  rtems_status_code  sc = RTEMS_SUCCESSFUL;
707  uint8_t            value;
708
709  /* Check RTC valid */
710  sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
711  assert(sc == RTEMS_SUCCESSFUL);
712
713  if (time.seconds & M41ST87_BIT_ST)
714  {
715    /* RTC has been stopped. Reset stop flag. */
716    time.seconds = 0;
717    /* Initialise RTC. */
718    m41st87_set_time(&time, 0, 0, 0, 1, 1, TOD_BASE_YEAR);
719    sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
720    assert(sc == RTEMS_SUCCESSFUL);
721  }
722
723  /* Reset HT bit */
724  sc = m41st87_read(M41ST87_ADDR_ALARM_HOUR, &value, 1);
725  assert(sc == RTEMS_SUCCESSFUL);
726  value &= ~M41ST87_BIT_HT;
727  sc = m41st87_write(M41ST87_ADDR_ALARM_HOUR, &value, 1);
728  assert(sc == RTEMS_SUCCESSFUL);
729
730}
731
732
733static int  altera_cyclone_v_m41st87_get_time(int minor, rtems_time_of_day* tod)
734{
735
736  m41st87_time_t     time;
737  rtems_status_code  sc = RTEMS_SUCCESSFUL;
738  rtems_time_of_day  temp_tod;
739
740  sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
741  if (sc != RTEMS_SUCCESSFUL)
742    return -sc;
743
744  temp_tod.ticks  = 0;
745  temp_tod.second = m41st87_get_seconds(&time);
746  temp_tod.minute = m41st87_get_minutes(&time);
747  temp_tod.hour   = m41st87_get_hours(&time);
748  temp_tod.day    = m41st87_get_day_of_month(&time);
749  temp_tod.month  = m41st87_get_month(&time);
750  temp_tod.year   = m41st87_get_year(&time);
751
752  sc = _TOD_Validate(&temp_tod, TOD_ENABLE_TICKS_VALIDATION);
753  if (sc == RTEMS_SUCCESSFUL)
754    memcpy(tod, &temp_tod, sizeof(temp_tod));
755
756  return -sc;
757}
758
759
760static int  altera_cyclone_v_m41st87_set_time(int minor, const rtems_time_of_day* tod)
761{
762
763  m41st87_time_t     time;
764  rtems_status_code  sc = RTEMS_SUCCESSFUL;
765
766  /* first read to preserve the additional flags */
767  sc = m41st87_read(M41ST87_ADDR_TIME, &time, sizeof(time));
768  if (sc != RTEMS_SUCCESSFUL)
769    return -sc;
770
771  m41st87_set_time(&time,
772                   tod->second,
773                   tod->minute,
774                   tod->hour,
775                   tod->day,
776                   tod->month,
777                   tod->year
778                  );
779
780  sc = m41st87_write(M41ST87_ADDR_TIME, &time, sizeof(time));
781
782  return -sc;
783}
784
785
786static bool  altera_cyclone_v_m41st87_probe(int minor)
787{
788
789  rtems_status_code  sc = RTEMS_SUCCESSFUL;
790  uint8_t            buf;
791
792  /* try to read from register address 0x00 */
793  sc = m41st87_read(0x00, &buf, 1);
794  if (sc != RTEMS_SUCCESSFUL)
795    /* no RTC implemented */
796    return false;
797  /* try to read from register address 0x20 (implemented in M41ST87) */
798  sc = m41st87_read(0x20, &buf, 1);
799  if (sc != RTEMS_SUCCESSFUL)
800    /* RTC is not M41ST87 */
801    return false;
802
803  return true;
804
805}
806
807
808/* **************************************** General ********************************** */
809
810
811const rtc_fns  altera_cyclone_v_ds1339_ops =
812{
813  .deviceInitialize = altera_cyclone_v_ds1339_initialize,
814  .deviceGetTime = altera_cyclone_v_ds1339_get_time,
815  .deviceSetTime = altera_cyclone_v_ds1339_set_time
816};
817
818
819const rtc_fns  altera_cyclone_v_m41st87_ops =
820{
821  .deviceInitialize = altera_cyclone_v_m41st87_initialize,
822  .deviceGetTime = altera_cyclone_v_m41st87_get_time,
823  .deviceSetTime = altera_cyclone_v_m41st87_set_time
824};
825
826
827size_t  RTC_Count = ALTERA_CYCLONE_V_RTC_NUMBER;
828
829rtc_tbl  RTC_Table[ALTERA_CYCLONE_V_RTC_NUMBER] =
830{
831  {
832    .sDeviceName = "/dev/rtc",
833    .deviceType = RTC_CUSTOM,
834    .pDeviceFns = &altera_cyclone_v_ds1339_ops,
835    .deviceProbe = altera_cyclone_v_ds1339_probe,
836    .pDeviceParams = NULL,
837    .ulCtrlPort1 = 0,
838    .ulDataPort = 0,
839    .getRegister = NULL,
840    .setRegister = NULL
841  },
842  {
843    .sDeviceName = "/dev/rtc",
844    .deviceType = RTC_CUSTOM,
845    .pDeviceFns = &altera_cyclone_v_m41st87_ops,
846    .deviceProbe = altera_cyclone_v_m41st87_probe,
847    .pDeviceParams = NULL,
848    .ulCtrlPort1 = 0,
849    .ulDataPort = 0,
850    .getRegister = NULL,
851    .setRegister = NULL
852  }
853};
Note: See TracBrowser for help on using the repository browser.