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
fetch_t(endpoint_t ep,cp_grant_id_t gid,struct tm * t)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
store_t(endpoint_t ep,cp_grant_id_t gid,struct tm * t)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
check_revision(void)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
sef_cb_lu_state_save(int UNUSED (result),int UNUSED (flags))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
lu_state_restore(void)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
sef_cb_init(int type,sef_init_info_t * UNUSED (info))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
sef_local_startup(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
main(int argc,char * argv[])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