xref: /minix3/minix/drivers/power/tps65950/rtc.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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