1 #include <minix/ds.h>
2 #include <minix/drivers.h>
3 #include <minix/i2c.h>
4 #include <minix/i2cdriver.h>
5 #include <minix/log.h>
6
7 #include <time.h>
8
9 #include "tps65950.h"
10 #include "rtc.h"
11
12 /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
13 static struct log log = {
14 .name = "tps65950.rtc",
15 .log_level = LEVEL_INFO,
16 .log_func = default_log
17 };
18
19 static int bcd_to_dec(int n);
20 static int dec_to_bcd(int n);
21
22 int
rtc_init(void)23 rtc_init(void)
24 {
25 int r;
26 uint8_t val;
27 struct tm t;
28
29 r = i2creg_set_bits8(bus_endpoint, addresses[ID4], RTC_CTRL_REG,
30 (1 << STOP_RTC_BIT));
31 if (r != OK) {
32 log_warn(&log, "Failed to start RTC\n");
33 return -1;
34 }
35
36 r = i2creg_read8(bus_endpoint, addresses[ID4], RTC_STATUS_REG, &val);
37 if (r != OK) {
38 log_warn(&log, "Failed to read RTC_STATUS_REG\n");
39 return -1;
40 }
41
42 if ((val & (1 << RUN_BIT)) != (1 << RUN_BIT)) {
43 log_warn(&log, "RTC did not start. Bad MSECURE?\n");
44 return -1;
45 }
46
47 log_debug(&log, "RTC Started\n");
48
49 return OK;
50 }
51
52 int
rtc_get_time(struct tm * t,int flags)53 rtc_get_time(struct tm *t, int flags)
54 {
55 int r;
56 uint8_t val;
57
58 memset(t, '\0', sizeof(struct tm));
59
60 /* Write GET_TIME_BIT to RTC_CTRL_REG to latch the RTC values into
61 * the RTC registers. This is required before each read.
62 */
63 r = i2creg_set_bits8(bus_endpoint, addresses[ID4], RTC_CTRL_REG,
64 (1 << GET_TIME_BIT));
65 if (r != OK) {
66 return -1;
67 }
68
69 /* Read and Convert BCD to binary (default RTC mode). */
70
71 /* Seconds - 0 to 59 */
72 r = i2creg_read8(bus_endpoint, addresses[ID4], SECONDS_REG, &val);
73 if (r != OK) {
74 return -1;
75 }
76 t->tm_sec = bcd_to_dec(val & 0x7f);
77
78 /* Minutes - 0 to 59 */
79 r = i2creg_read8(bus_endpoint, addresses[ID4], MINUTES_REG, &val);
80 if (r != OK) {
81 return -1;
82 }
83 t->tm_min = bcd_to_dec(val & 0x7f);
84
85 /* Hours - 0 to 23 */
86 r = i2creg_read8(bus_endpoint, addresses[ID4], HOURS_REG, &val);
87 if (r != OK) {
88 return -1;
89 }
90 t->tm_hour = bcd_to_dec(val & 0x3f);
91
92 /* Days - 1 to 31 */
93 r = i2creg_read8(bus_endpoint, addresses[ID4], DAYS_REG, &val);
94 if (r != OK) {
95 return -1;
96 }
97 t->tm_mday = bcd_to_dec(val & 0x3f);
98
99 /* Months - Jan=1 to Dec=12 */
100 r = i2creg_read8(bus_endpoint, addresses[ID4], MONTHS_REG, &val);
101 if (r != OK) {
102 return -1;
103 }
104 t->tm_mon = bcd_to_dec(val & 0x1f) - 1;
105
106 /* Years - last 2 digits of year */
107 r = i2creg_read8(bus_endpoint, addresses[ID4], YEARS_REG, &val);
108 if (r != OK) {
109 return -1;
110 }
111 t->tm_year = bcd_to_dec(val & 0x1f) + 100;
112
113 if (t->tm_year == 100) {
114 /* Cold start - no date/time set - default to 2013-01-01 */
115 t->tm_sec = 0;
116 t->tm_min = 0;
117 t->tm_hour = 0;
118 t->tm_mday = 1;
119 t->tm_mon = 0;
120 t->tm_year = 113;
121
122 rtc_set_time(t, RTCDEV_NOFLAGS);
123 }
124
125 return OK;
126 }
127
128 int
rtc_set_time(struct tm * t,int flags)129 rtc_set_time(struct tm *t, int flags)
130 {
131 int r;
132
133 /* Write the date/time to the RTC registers. */
134 r = i2creg_write8(bus_endpoint, addresses[ID4], SECONDS_REG,
135 (dec_to_bcd(t->tm_sec) & 0x7f));
136 if (r != OK) {
137 return -1;
138 }
139
140 r = i2creg_write8(bus_endpoint, addresses[ID4], MINUTES_REG,
141 (dec_to_bcd(t->tm_min) & 0x7f));
142 if (r != OK) {
143 return -1;
144 }
145
146 r = i2creg_write8(bus_endpoint, addresses[ID4], HOURS_REG,
147 (dec_to_bcd(t->tm_hour) & 0x3f));
148 if (r != OK) {
149 return -1;
150 }
151
152 r = i2creg_write8(bus_endpoint, addresses[ID4], DAYS_REG,
153 (dec_to_bcd(t->tm_mday) & 0x3f));
154 if (r != OK) {
155 return -1;
156 }
157
158 r = i2creg_write8(bus_endpoint, addresses[ID4], MONTHS_REG,
159 (dec_to_bcd(t->tm_mon + 1) & 0x1f));
160 if (r != OK) {
161 return -1;
162 }
163
164 r = i2creg_write8(bus_endpoint, addresses[ID4], YEARS_REG,
165 (dec_to_bcd(t->tm_year % 100) & 0xff));
166 if (r != OK) {
167 return -1;
168 }
169
170 return OK;
171 }
172
173 int
rtc_exit(void)174 rtc_exit(void)
175 {
176 return OK;
177 }
178
179 static int
bcd_to_dec(int n)180 bcd_to_dec(int n)
181 {
182 return ((n >> 4) & 0x0F) * 10 + (n & 0x0F);
183 }
184
185 static int
dec_to_bcd(int n)186 dec_to_bcd(int n)
187 {
188 return ((n / 10) << 4) | (n % 10);
189 }
190