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