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