source: rtems/bsps/shared/dev/rtc/mc146818a.c @ 762fa62

5
Last change on this file since 762fa62 was 27de4e1f, checked in by Sebastian Huber <sebastian.huber@…>, on 04/03/18 at 05:20:11

bsps: Move libchip to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 4.2 KB
Line 
1/*
2 *  This file interfaces with the real-time clock found in
3 *  a Motorola MC146818A (common on PC hardware)
4 *
5 *  Year 2K Notes:
6 *
7 *  This chip only uses a two digit field to store the year.  This
8 *  code uses the RTEMS Epoch as a pivot year.  This lets us map the
9 *  two digit year field as follows:
10 *
11 *    + two digit years 0-87 are mapped to 2000-2087.
12 *    + two digit years 88-99 are mapped to 1988-1999.
13 *
14 *  This is less than the time span supported by RTEMS.
15 *
16 *  COPYRIGHT (c) 1989-1999.
17 *  On-Line Applications Research Corporation (OAR).
18 *
19 *  The license and distribution terms for this file may be
20 *  found in the file LICENSE in this distribution or at
21 *  http://www.rtems.org/license/LICENSE.
22 */
23#include <rtems.h>
24#include <libchip/rtc.h>
25#include <libchip/mc146818a.h>
26
27#define From_BCD( _x ) ((((_x) >> 4) * 10) + ((_x) & 0x0F))
28#define To_BCD( _x )   ((((_x) / 10) << 4) + ((_x) % 10))
29
30/*
31 * See if chip is present
32 */
33bool mc146818a_probe(
34  int minor
35)
36{
37  uint32_t     mc146818a;
38  getRegister_f  getReg;
39  uint32_t     value;
40
41  /*
42   * Verify that chip is present and that time is valid
43   */
44  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
45  getReg = RTC_Table[ minor ].getRegister;
46  value = (*getReg)( mc146818a, MC146818A_STATUSD );
47  if ((value == 0) || (value == 0xFF))
48    return false;
49  return true;
50}
51
52/*
53 * Initialize chip
54 */
55static void mc146818a_initialize(
56  int minor
57)
58{
59  uintptr_t      mc146818a;
60  setRegister_f  setReg;
61
62  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
63  setReg = RTC_Table[ minor ].setRegister;
64
65  (*setReg)(
66    mc146818a,
67    MC146818A_STATUSA,
68    MC146818ASA_DIVIDER|MC146818ASA_1024
69  );
70  (*setReg)(
71    mc146818a,
72    MC146818A_STATUSB,
73    MC146818ASB_24HR
74  );
75}
76
77/*
78 * Read time from chip
79 */
80static int mc146818a_get_time(
81  int                minor,
82  rtems_time_of_day *time
83)
84{
85  uintptr_t             mc146818a;
86  getRegister_f         getReg;
87  uint32_t              value;
88  rtems_interrupt_level level;
89
90  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
91  getReg = RTC_Table[ minor ].getRegister;
92
93  /*
94   * No time if power failed
95   */
96  if (((*getReg)( mc146818a, MC146818A_STATUSD ) & MC146818ASD_PWR) == 0)
97    return -1;
98
99  /*
100   * Wait for time update to complete
101   */
102  rtems_interrupt_disable( level );
103  while (((*getReg)( mc146818a, MC146818A_STATUSA ) & MC146818ASA_TUP) != 0) {
104      rtems_interrupt_flash( level );
105  }
106
107  /*
108   * Read the time (we have at least 244 usec to do this)
109   */
110  value = (*getReg)( mc146818a, MC146818A_YEAR );
111  value = From_BCD( value );
112  if ( value < 88 )
113    time->year = 2000 + value;
114  else
115    time->year = 1900 + value;
116
117  value = (*getReg)( mc146818a, MC146818A_MONTH );
118  time->month = From_BCD( value );
119
120  value = (*getReg)( mc146818a, MC146818A_DAY );
121  time->day = From_BCD( value );
122
123  value = (*getReg)( mc146818a, MC146818A_HRS );
124  time->hour = From_BCD( value );
125
126  value = (*getReg)( mc146818a, MC146818A_MIN );
127  time->minute = From_BCD( value );
128
129  value = (*getReg)( mc146818a, MC146818A_SEC );
130  rtems_interrupt_enable( level );
131  time->second = From_BCD( value );
132  time->ticks  = 0;
133
134  return 0;
135}
136
137/*
138 * Set time into chip
139 */
140static int mc146818a_set_time(
141  int                      minor,
142  const rtems_time_of_day *time
143)
144{
145  uint32_t     mc146818a;
146  setRegister_f  setReg;
147
148  mc146818a = RTC_Table[ minor ].ulCtrlPort1;
149  setReg = RTC_Table[ minor ].setRegister;
150
151  /*
152   * Stop the RTC
153   */
154  (*setReg)( mc146818a, MC146818A_STATUSB, MC146818ASB_HALT|MC146818ASB_24HR );
155
156  if ( time->year >= 2088 )
157    rtems_fatal_error_occurred( RTEMS_INVALID_NUMBER );
158
159  (*setReg)( mc146818a, MC146818A_YEAR,  To_BCD(time->year % 100) );
160  (*setReg)( mc146818a, MC146818A_MONTH, To_BCD(time->month) );
161  (*setReg)( mc146818a, MC146818A_DAY,   To_BCD(time->day) );
162  (*setReg)( mc146818a, MC146818A_HRS,   To_BCD(time->hour) );
163  (*setReg)( mc146818a, MC146818A_MIN,   To_BCD(time->minute) );
164  (*setReg)( mc146818a, MC146818A_SEC,   To_BCD(time->second) );
165
166  /*
167   * Restart the RTC
168   */
169  (*setReg)( mc146818a, MC146818A_STATUSB, MC146818ASB_24HR );
170  return 0;
171}
172
173/*
174 *  Driver function table
175 */
176rtc_fns mc146818a_fns = {
177  mc146818a_initialize,
178  mc146818a_get_time,
179  mc146818a_set_time
180};
Note: See TracBrowser for help on using the repository browser.