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