xref: /minix/minix/drivers/power/tps65950/tps65950.c (revision 0a6a1f1d)
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 #include <minix/safecopies.h>
7 
8 #include "tps65950.h"
9 #include "rtc.h"
10 
11 /* logging - use with log_warn(), log_info(), log_debug(), log_trace(), etc */
12 static struct log log = {
13 	.name = "tps65950",
14 	.log_level = LEVEL_INFO,
15 	.log_func = default_log
16 };
17 
18 /* TPS65950 doesn't support configuring the addresses, so there is only 1
19  * configuration possible. The chip does have multiple addresses (0x48,
20  * 0x49, 0x4a, 0x4b), but because they're all fixed, we only have the
21  * user pass the base address as a sanity check.
22  */
23 static i2c_addr_t valid_addrs[2] = {
24 	0x48, 0x00
25 };
26 
27 /* the bus that this device is on (counting starting at 1) */
28 static uint32_t bus;
29 
30 /* endpoint for the driver for the bus itself. */
31 endpoint_t bus_endpoint;
32 
33 /* slave addresses of the device */
34 i2c_addr_t addresses[NADDRESSES] = {
35 	0x48, 0x49, 0x4a, 0x4b
36 };
37 
38 /* local functions */
39 static int check_revision(void);
40 
41 /* functions for transfering struct tm to/from this driver and calling proc. */
42 static int fetch_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t);
43 static int store_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t);
44 
45 static int
46 fetch_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t)
47 {
48 	int r;
49 
50 	r = sys_safecopyfrom(ep, gid, (vir_bytes) 0, (vir_bytes) t,
51 	    sizeof(struct tm));
52 	if (r != OK) {
53 		log_warn(&log, "sys_safecopyfrom() failed (r=%d)\n", r);
54 		return r;
55 	}
56 
57 	return OK;
58 }
59 
60 static int
61 store_t(endpoint_t ep, cp_grant_id_t gid, struct tm *t)
62 {
63 	int r;
64 
65 	r = sys_safecopyto(ep, gid, (vir_bytes) 0, (vir_bytes) t,
66 	    sizeof(struct tm));
67 	if (r != OK) {
68 		log_warn(&log, "sys_safecopyto() failed (r=%d)\n", r);
69 		return r;
70 	}
71 
72 	return OK;
73 }
74 
75 static int
76 check_revision(void)
77 {
78 	int r;
79 	uint32_t idcode;
80 	uint8_t idcode_7_0, idcode_15_8, idcode_23_16, idcode_31_24;
81 
82 	/* need to write a special code to unlock read protect on IDCODE */
83 	r = i2creg_write8(bus_endpoint, addresses[ID2], UNLOCK_TEST_REG,
84 	    UNLOCK_TEST_CODE);
85 	if (r != OK) {
86 		log_warn(&log, "Failed to write unlock code to UNLOCK_TEST\n");
87 		return -1;
88 	}
89 
90 	/*
91 	 * read each part of the IDCODE
92 	 */
93 	r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_7_0_REG,
94 	    &idcode_7_0);
95 	if (r != OK) {
96 		log_warn(&log, "Failed to read IDCODE part 1\n");
97 	}
98 
99 	r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_15_8_REG,
100 	    &idcode_15_8);
101 	if (r != OK) {
102 		log_warn(&log, "Failed to read IDCODE part 2\n");
103 	}
104 
105 	r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_23_16_REG,
106 	    &idcode_23_16);
107 	if (r != OK) {
108 		log_warn(&log, "Failed to read IDCODE part 3\n");
109 	}
110 
111 	r = i2creg_read8(bus_endpoint, addresses[ID2], IDCODE_31_24_REG,
112 	    &idcode_31_24);
113 	if (r != OK) {
114 		log_warn(&log, "Failed to read IDCODE part 4\n");
115 	}
116 
117 	/* combine the parts to get the full IDCODE */
118 	idcode =
119 	    ((idcode_31_24 << 24) | (idcode_23_16 << 16) | (idcode_15_8 << 8) |
120 	    (idcode_7_0 << 0));
121 
122 	log_debug(&log, "IDCODE = 0x%x\n", idcode);
123 	switch (idcode) {
124 	case IDCODE_REV_1_0:
125 		log_debug(&log, "TPS65950 rev 1.0\n");
126 		break;
127 	case IDCODE_REV_1_1:
128 		log_debug(&log, "TPS65950 rev 1.1\n");
129 		break;
130 	case IDCODE_REV_1_2:
131 		log_debug(&log, "TPS65950 rev 1.2\n");
132 		break;
133 	case 0:
134 		log_debug(&log, "TPS65950 missing in qemu\n");
135 		break;
136 	default:
137 		log_warn(&log, "Unexpected IDCODE: 0x%x\n", idcode);
138 		return -1;
139 	}
140 
141 	return OK;
142 }
143 
144 static int
145 sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags))
146 {
147 	/* The addresses are fixed/non-configurable so bus is the only state */
148 	ds_publish_u32("bus", bus, DSF_OVERWRITE);
149 	return OK;
150 }
151 
152 static int
153 lu_state_restore(void)
154 {
155 	/* Restore the state. */
156 	u32_t value;
157 
158 	ds_retrieve_u32("bus", &value);
159 	ds_delete_u32("bus");
160 	bus = (int) value;
161 
162 	return OK;
163 }
164 
165 static int
166 sef_cb_init(int type, sef_init_info_t * UNUSED(info))
167 {
168 	int r, i;
169 
170 	if (type == SEF_INIT_LU) {
171 		/* Restore the state. */
172 		lu_state_restore();
173 	}
174 
175 	/* look-up the endpoint for the bus driver */
176 	bus_endpoint = i2cdriver_bus_endpoint(bus);
177 	if (bus_endpoint == 0) {
178 		log_warn(&log, "Couldn't find bus driver.\n");
179 		return EXIT_FAILURE;
180 	}
181 
182 	for (i = 0; i < NADDRESSES; i++) {
183 
184 		/* claim the device */
185 		r = i2cdriver_reserve_device(bus_endpoint, addresses[i]);
186 		if (r != OK) {
187 			log_warn(&log, "Couldn't reserve device 0x%x (r=%d)\n",
188 			    addresses[i], r);
189 			return EXIT_FAILURE;
190 		}
191 	}
192 
193 	/* check that the chip / rev is reasonable */
194 	r = check_revision();
195 	if (r != OK) {
196 		/* prevent user from using the driver with a different chip */
197 		log_warn(&log, "Bad IDCODE\n");
198 		return EXIT_FAILURE;
199 	}
200 
201 	r = rtc_init();
202 	if (r != OK) {
203 		log_warn(&log, "RTC Start-up Failed\n");
204 		return EXIT_FAILURE;
205 	}
206 
207 	if (type != SEF_INIT_LU) {
208 
209 		/* sign up for updates about the i2c bus going down/up */
210 		r = i2cdriver_subscribe_bus_updates(bus);
211 		if (r != OK) {
212 			log_warn(&log, "Couldn't subscribe to bus updates\n");
213 			return EXIT_FAILURE;
214 		}
215 
216 		i2cdriver_announce(bus);
217 		log_debug(&log, "announced\n");
218 	}
219 
220 	return OK;
221 }
222 
223 static void
224 sef_local_startup(void)
225 {
226 	/*
227 	 * Register init callbacks. Use the same function for all event types
228 	 */
229 	sef_setcb_init_fresh(sef_cb_init);
230 	sef_setcb_init_lu(sef_cb_init);
231 	sef_setcb_init_restart(sef_cb_init);
232 
233 	/*
234 	 * Register live update callbacks.
235 	 */
236 	sef_setcb_lu_state_save(sef_cb_lu_state_save);
237 
238 	/* Let SEF perform startup. */
239 	sef_startup();
240 }
241 
242 int
243 main(int argc, char *argv[])
244 {
245 	int r, i;
246 	struct tm t;
247 	endpoint_t user, caller;
248 	message m;
249 	int ipc_status, reply_status;
250 
251 	env_setargs(argc, argv);
252 
253 	r = i2cdriver_env_parse(&bus, &addresses[0], valid_addrs);
254 	if (r < 0) {
255 		log_warn(&log, "Expecting -args 'bus=X address=0xYY'\n");
256 		log_warn(&log, "Example -args 'bus=1 address=0x48'\n");
257 		return EXIT_FAILURE;
258 	} else if (r > 0) {
259 		log_warn(&log,
260 		    "Invalid slave address for device, expecting 0x48\n");
261 		return EXIT_FAILURE;
262 	}
263 
264 	sef_local_startup();
265 
266 	while (TRUE) {
267 
268 		/* Receive Message */
269 		r = sef_receive_status(ANY, &m, &ipc_status);
270 		if (r != OK) {
271 			log_warn(&log, "sef_receive_status() failed\n");
272 			continue;
273 		}
274 
275 		if (is_ipc_notify(ipc_status)) {
276 
277 			if (m.m_source == DS_PROC_NR) {
278 				for (i = 0; i < NADDRESSES; i++) {
279 					/* changed state, update endpoint */
280 					i2cdriver_handle_bus_update
281 					    (&bus_endpoint, bus, addresses[i]);
282 				}
283 			}
284 
285 			/* Do not reply to notifications. */
286 			continue;
287 		}
288 
289 		caller = m.m_source;
290 
291 		log_debug(&log, "Got message 0x%x from 0x%x\n", m.m_type,
292 		    caller);
293 
294 		switch (m.m_type) {
295 		case RTCDEV_GET_TIME_G:
296 			/* Any user can read the time */
297 			reply_status = rtc_get_time(&t, m.m_lc_readclock_rtcdev.flags);
298 			if (reply_status != OK) {
299 				break;
300 			}
301 
302 			/* write results back to calling process */
303 			reply_status =
304 			    store_t(caller, m.m_lc_readclock_rtcdev.grant, &t);
305 			break;
306 
307 		case RTCDEV_SET_TIME_G:
308 			/* Only super user is allowed to set the time */
309 			if (getnuid(caller) == SUPER_USER) {
310 				/* read time from calling process */
311 				reply_status =
312 				    fetch_t(caller,
313 					    m.m_lc_readclock_rtcdev.grant, &t);
314 				if (reply_status != OK) {
315 					break;
316 				}
317 
318 				reply_status =
319 				    rtc_set_time(&t,
320 					    m.m_lc_readclock_rtcdev.flags);
321 			} else {
322 				reply_status = EPERM;
323 			}
324 			break;
325 
326 		case RTCDEV_PWR_OFF:
327 			reply_status = ENOSYS;
328 			break;
329 
330 		default:
331 			/* Unrecognized call */
332 			reply_status = EINVAL;
333 			break;
334 		}
335 
336 		/* Send Reply */
337 		m.m_type = RTCDEV_REPLY;
338 		m.m_readclock_lc_rtcdev.status = reply_status;
339 
340 		log_debug(&log, "Sending Reply");
341 
342 		r = ipc_sendnb(caller, &m);
343 		if (r != OK) {
344 			log_warn(&log, "ipc_sendnb() failed\n");
345 			continue;
346 		}
347 	}
348 
349 	rtc_exit();
350 
351 	return 0;
352 }
353