1*433d6423SLionel Sambuc /* 2*433d6423SLionel Sambuc * i2c - generic driver for Inter-Integrated Circuit bus (I2C). 3*433d6423SLionel Sambuc */ 4*433d6423SLionel Sambuc 5*433d6423SLionel Sambuc /* kernel headers */ 6*433d6423SLionel Sambuc #include <minix/chardriver.h> 7*433d6423SLionel Sambuc #include <minix/drivers.h> 8*433d6423SLionel Sambuc #include <minix/ds.h> 9*433d6423SLionel Sambuc #include <minix/i2c.h> 10*433d6423SLionel Sambuc #include <minix/log.h> 11*433d6423SLionel Sambuc #include <minix/type.h> 12*433d6423SLionel Sambuc #include <minix/board.h> 13*433d6423SLionel Sambuc 14*433d6423SLionel Sambuc /* system headers */ 15*433d6423SLionel Sambuc #include <sys/mman.h> 16*433d6423SLionel Sambuc 17*433d6423SLionel Sambuc /* usr headers */ 18*433d6423SLionel Sambuc #include <string.h> 19*433d6423SLionel Sambuc #include <stdio.h> 20*433d6423SLionel Sambuc #include <stdlib.h> 21*433d6423SLionel Sambuc 22*433d6423SLionel Sambuc /* SoC specific headers - 1 for each SoC */ 23*433d6423SLionel Sambuc #include "omap_i2c.h" 24*433d6423SLionel Sambuc 25*433d6423SLionel Sambuc /* local definitions */ 26*433d6423SLionel Sambuc 27*433d6423SLionel Sambuc /* i2c slave addresses can be up to 10 bits */ 28*433d6423SLionel Sambuc #define NR_I2CDEV (0x3ff) 29*433d6423SLionel Sambuc 30*433d6423SLionel Sambuc /* local function prototypes */ 31*433d6423SLionel Sambuc static int do_reserve(endpoint_t endpt, int slave_addr); 32*433d6423SLionel Sambuc static int check_reservation(endpoint_t endpt, int slave_addr); 33*433d6423SLionel Sambuc static void update_reservation(endpoint_t endpt, char *key); 34*433d6423SLionel Sambuc static void ds_event(void); 35*433d6423SLionel Sambuc 36*433d6423SLionel Sambuc static int validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec); 37*433d6423SLionel Sambuc static int do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr); 38*433d6423SLionel Sambuc 39*433d6423SLionel Sambuc static int env_parse_instance(void); 40*433d6423SLionel Sambuc 41*433d6423SLionel Sambuc /* libchardriver callbacks */ 42*433d6423SLionel Sambuc static int i2c_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, 43*433d6423SLionel Sambuc cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); 44*433d6423SLionel Sambuc static void i2c_other(message * m, int ipc_status); 45*433d6423SLionel Sambuc 46*433d6423SLionel Sambuc /* SEF callbacks and driver state management */ 47*433d6423SLionel Sambuc static int sef_cb_lu_state_save(int); 48*433d6423SLionel Sambuc static int lu_state_restore(void); 49*433d6423SLionel Sambuc static int sef_cb_init(int type, sef_init_info_t * info); 50*433d6423SLionel Sambuc static void sef_local_startup(void); 51*433d6423SLionel Sambuc 52*433d6423SLionel Sambuc /* Globals */ 53*433d6423SLionel Sambuc 54*433d6423SLionel Sambuc /* the bus that this instance of the driver is responsible for */ 55*433d6423SLionel Sambuc uint32_t i2c_bus_id; 56*433d6423SLionel Sambuc 57*433d6423SLionel Sambuc /* Table of i2c device reservations. */ 58*433d6423SLionel Sambuc static struct i2cdev 59*433d6423SLionel Sambuc { 60*433d6423SLionel Sambuc uint8_t inuse; 61*433d6423SLionel Sambuc endpoint_t endpt; 62*433d6423SLionel Sambuc char key[DS_MAX_KEYLEN]; 63*433d6423SLionel Sambuc } i2cdev[NR_I2CDEV]; 64*433d6423SLionel Sambuc 65*433d6423SLionel Sambuc /* Process a request for an i2c operation. 66*433d6423SLionel Sambuc * This is the interface that all hardware specific code must implement. 67*433d6423SLionel Sambuc */ 68*433d6423SLionel Sambuc int (*process) (minix_i2c_ioctl_exec_t * ioctl_exec); 69*433d6423SLionel Sambuc 70*433d6423SLionel Sambuc /* logging - use with log_warn(), log_info(), log_debug(), log_trace() */ 71*433d6423SLionel Sambuc static struct log log = { 72*433d6423SLionel Sambuc .name = "i2c", 73*433d6423SLionel Sambuc .log_level = LEVEL_INFO, 74*433d6423SLionel Sambuc .log_func = default_log 75*433d6423SLionel Sambuc }; 76*433d6423SLionel Sambuc 77*433d6423SLionel Sambuc /* Entry points to the i2c driver from libchardriver. 78*433d6423SLionel Sambuc * Only i2c_ioctl() and i2c_other() are implemented. The rest are no-op. 79*433d6423SLionel Sambuc */ 80*433d6423SLionel Sambuc static struct chardriver i2c_tab = { 81*433d6423SLionel Sambuc .cdr_ioctl = i2c_ioctl, 82*433d6423SLionel Sambuc .cdr_other = i2c_other 83*433d6423SLionel Sambuc }; 84*433d6423SLionel Sambuc 85*433d6423SLionel Sambuc /* 86*433d6423SLionel Sambuc * Claim an unclaimed device for exclusive use by endpt. This function can 87*433d6423SLionel Sambuc * also be used to update the endpt if the endpt's label matches the label 88*433d6423SLionel Sambuc * already associated with the slave address. This is useful if a driver 89*433d6423SLionel Sambuc * shuts down unexpectedly and starts up with a new endpt and wants to reserve 90*433d6423SLionel Sambuc * the same device it reserved before. 91*433d6423SLionel Sambuc */ 92*433d6423SLionel Sambuc static int 93*433d6423SLionel Sambuc do_reserve(endpoint_t endpt, int slave_addr) 94*433d6423SLionel Sambuc { 95*433d6423SLionel Sambuc int r; 96*433d6423SLionel Sambuc char key[DS_MAX_KEYLEN]; 97*433d6423SLionel Sambuc char label[DS_MAX_KEYLEN]; 98*433d6423SLionel Sambuc 99*433d6423SLionel Sambuc /* find the label for the endpoint */ 100*433d6423SLionel Sambuc r = ds_retrieve_label_name(label, endpt); 101*433d6423SLionel Sambuc if (r != OK) { 102*433d6423SLionel Sambuc log_warn(&log, "Couldn't find label for endpt='0x%x'\n", 103*433d6423SLionel Sambuc endpt); 104*433d6423SLionel Sambuc return r; 105*433d6423SLionel Sambuc } 106*433d6423SLionel Sambuc 107*433d6423SLionel Sambuc /* construct the key i2cdriver_announce published (saves an IPC call) */ 108*433d6423SLionel Sambuc snprintf(key, DS_MAX_KEYLEN, "drv.i2c.%d.%s", i2c_bus_id + 1, label); 109*433d6423SLionel Sambuc 110*433d6423SLionel Sambuc if (slave_addr < 0 || slave_addr >= NR_I2CDEV) { 111*433d6423SLionel Sambuc log_debug(&log, 112*433d6423SLionel Sambuc "slave address must be positive & no more than 10 bits\n"); 113*433d6423SLionel Sambuc return EINVAL; 114*433d6423SLionel Sambuc } 115*433d6423SLionel Sambuc 116*433d6423SLionel Sambuc /* check if device is in use by another driver */ 117*433d6423SLionel Sambuc if (i2cdev[slave_addr].inuse != 0 118*433d6423SLionel Sambuc && strncmp(i2cdev[slave_addr].key, key, DS_MAX_KEYLEN) != 0) { 119*433d6423SLionel Sambuc log_debug(&log, "address in use by '%s'/0x%x\n", 120*433d6423SLionel Sambuc i2cdev[slave_addr].key, i2cdev[slave_addr].endpt); 121*433d6423SLionel Sambuc return EBUSY; 122*433d6423SLionel Sambuc } 123*433d6423SLionel Sambuc 124*433d6423SLionel Sambuc /* device is free or already owned by us, claim it */ 125*433d6423SLionel Sambuc i2cdev[slave_addr].inuse = 1; 126*433d6423SLionel Sambuc i2cdev[slave_addr].endpt = endpt; 127*433d6423SLionel Sambuc memcpy(i2cdev[slave_addr].key, key, DS_MAX_KEYLEN); 128*433d6423SLionel Sambuc 129*433d6423SLionel Sambuc sef_cb_lu_state_save(0); /* save reservations */ 130*433d6423SLionel Sambuc 131*433d6423SLionel Sambuc log_debug(&log, "Device 0x%x claimed by 0x%x key='%s'\n", 132*433d6423SLionel Sambuc slave_addr, endpt, key); 133*433d6423SLionel Sambuc 134*433d6423SLionel Sambuc return OK; 135*433d6423SLionel Sambuc } 136*433d6423SLionel Sambuc 137*433d6423SLionel Sambuc /* 138*433d6423SLionel Sambuc * All drivers must reserve their device(s) before doing operations on them 139*433d6423SLionel Sambuc * (read/write, etc). ioctl()'s from VFS (i.e. user programs) can only use 140*433d6423SLionel Sambuc * devices that haven't been reserved. A driver isn't allowed to access a 141*433d6423SLionel Sambuc * device that another driver has reserved (not even other instances of the 142*433d6423SLionel Sambuc * same driver). 143*433d6423SLionel Sambuc */ 144*433d6423SLionel Sambuc static int 145*433d6423SLionel Sambuc check_reservation(endpoint_t endpt, int slave_addr) 146*433d6423SLionel Sambuc { 147*433d6423SLionel Sambuc if (slave_addr < 0 || slave_addr >= NR_I2CDEV) { 148*433d6423SLionel Sambuc log_debug(&log, 149*433d6423SLionel Sambuc "slave address must be positive & no more than 10 bits\n"); 150*433d6423SLionel Sambuc return EINVAL; 151*433d6423SLionel Sambuc } 152*433d6423SLionel Sambuc 153*433d6423SLionel Sambuc if (endpt == VFS_PROC_NR && i2cdev[slave_addr].inuse == 0) { 154*433d6423SLionel Sambuc log_debug(&log, 155*433d6423SLionel Sambuc "allowing ioctl() from VFS to access unclaimed device\n"); 156*433d6423SLionel Sambuc return OK; 157*433d6423SLionel Sambuc } 158*433d6423SLionel Sambuc 159*433d6423SLionel Sambuc if (i2cdev[slave_addr].inuse && i2cdev[slave_addr].endpt != endpt) { 160*433d6423SLionel Sambuc log_debug(&log, "device reserved by another endpoint\n"); 161*433d6423SLionel Sambuc return EBUSY; 162*433d6423SLionel Sambuc } else if (i2cdev[slave_addr].inuse == 0) { 163*433d6423SLionel Sambuc log_debug(&log, 164*433d6423SLionel Sambuc "all drivers sending messages directly to this driver must reserve\n"); 165*433d6423SLionel Sambuc return EPERM; 166*433d6423SLionel Sambuc } else { 167*433d6423SLionel Sambuc log_debug(&log, "allowing access to registered device\n"); 168*433d6423SLionel Sambuc return OK; 169*433d6423SLionel Sambuc } 170*433d6423SLionel Sambuc } 171*433d6423SLionel Sambuc 172*433d6423SLionel Sambuc /* 173*433d6423SLionel Sambuc * i2c listens to updates from ds about i2c device drivers starting up. 174*433d6423SLionel Sambuc * When a driver comes back up with the same label, the endpt associated 175*433d6423SLionel Sambuc * with the reservation needs to be updated. This function does the updating. 176*433d6423SLionel Sambuc */ 177*433d6423SLionel Sambuc static void 178*433d6423SLionel Sambuc update_reservation(endpoint_t endpt, char *key) 179*433d6423SLionel Sambuc { 180*433d6423SLionel Sambuc int i; 181*433d6423SLionel Sambuc 182*433d6423SLionel Sambuc log_debug(&log, "Updating reservation for '%s' endpt=0x%x\n", key, 183*433d6423SLionel Sambuc endpt); 184*433d6423SLionel Sambuc 185*433d6423SLionel Sambuc for (i = 0; i < NR_I2CDEV; i++) { 186*433d6423SLionel Sambuc 187*433d6423SLionel Sambuc /* find devices in use that the driver owns */ 188*433d6423SLionel Sambuc if (i2cdev[i].inuse != 0 189*433d6423SLionel Sambuc && strncmp(i2cdev[i].key, key, DS_MAX_KEYLEN) == 0) { 190*433d6423SLionel Sambuc /* update reservation with new endpoint */ 191*433d6423SLionel Sambuc do_reserve(endpt, i); 192*433d6423SLionel Sambuc log_debug(&log, "Found device to update 0x%x\n", i); 193*433d6423SLionel Sambuc } 194*433d6423SLionel Sambuc } 195*433d6423SLionel Sambuc } 196*433d6423SLionel Sambuc 197*433d6423SLionel Sambuc /* 198*433d6423SLionel Sambuc * Checks a minix_i2c_ioctl_exec_t to see if the fields make sense. 199*433d6423SLionel Sambuc */ 200*433d6423SLionel Sambuc static int 201*433d6423SLionel Sambuc validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec) 202*433d6423SLionel Sambuc { 203*433d6423SLionel Sambuc i2c_op_t op; 204*433d6423SLionel Sambuc i2c_addr_t addr; 205*433d6423SLionel Sambuc size_t len; 206*433d6423SLionel Sambuc 207*433d6423SLionel Sambuc op = ioctl_exec->iie_op; 208*433d6423SLionel Sambuc if (op != I2C_OP_READ && 209*433d6423SLionel Sambuc op != I2C_OP_READ_WITH_STOP && 210*433d6423SLionel Sambuc op != I2C_OP_WRITE && 211*433d6423SLionel Sambuc op != I2C_OP_WRITE_WITH_STOP && 212*433d6423SLionel Sambuc op != I2C_OP_READ_BLOCK && op != I2C_OP_WRITE_BLOCK) { 213*433d6423SLionel Sambuc log_warn(&log, "iie_op value not valid\n"); 214*433d6423SLionel Sambuc return EINVAL; 215*433d6423SLionel Sambuc } 216*433d6423SLionel Sambuc 217*433d6423SLionel Sambuc addr = ioctl_exec->iie_addr; 218*433d6423SLionel Sambuc if (addr < 0 || addr >= NR_I2CDEV) { 219*433d6423SLionel Sambuc log_warn(&log, "iie_addr out of range 0x0-0x%x\n", NR_I2CDEV); 220*433d6423SLionel Sambuc return EINVAL; 221*433d6423SLionel Sambuc } 222*433d6423SLionel Sambuc 223*433d6423SLionel Sambuc len = ioctl_exec->iie_cmdlen; 224*433d6423SLionel Sambuc if (len > I2C_EXEC_MAX_CMDLEN) { 225*433d6423SLionel Sambuc log_warn(&log, 226*433d6423SLionel Sambuc "iie_cmdlen out of range 0-I2C_EXEC_MAX_CMDLEN\n"); 227*433d6423SLionel Sambuc return EINVAL; 228*433d6423SLionel Sambuc } 229*433d6423SLionel Sambuc 230*433d6423SLionel Sambuc len = ioctl_exec->iie_buflen; 231*433d6423SLionel Sambuc if (len > I2C_EXEC_MAX_BUFLEN) { 232*433d6423SLionel Sambuc log_warn(&log, 233*433d6423SLionel Sambuc "iie_buflen out of range 0-I2C_EXEC_MAX_BUFLEN\n"); 234*433d6423SLionel Sambuc return EINVAL; 235*433d6423SLionel Sambuc } 236*433d6423SLionel Sambuc 237*433d6423SLionel Sambuc return OK; 238*433d6423SLionel Sambuc } 239*433d6423SLionel Sambuc 240*433d6423SLionel Sambuc /* 241*433d6423SLionel Sambuc * Performs the action in minix_i2c_ioctl_exec_t. 242*433d6423SLionel Sambuc */ 243*433d6423SLionel Sambuc static int 244*433d6423SLionel Sambuc do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr) 245*433d6423SLionel Sambuc { 246*433d6423SLionel Sambuc int r; 247*433d6423SLionel Sambuc minix_i2c_ioctl_exec_t ioctl_exec; 248*433d6423SLionel Sambuc 249*433d6423SLionel Sambuc /* Copy the requested exection into the driver */ 250*433d6423SLionel Sambuc r = sys_safecopyfrom(caller, grant_nr, (vir_bytes) 0, 251*433d6423SLionel Sambuc (vir_bytes) & ioctl_exec, sizeof(ioctl_exec)); 252*433d6423SLionel Sambuc if (r != OK) { 253*433d6423SLionel Sambuc log_warn(&log, "sys_safecopyfrom() failed\n"); 254*433d6423SLionel Sambuc return r; 255*433d6423SLionel Sambuc } 256*433d6423SLionel Sambuc 257*433d6423SLionel Sambuc /* input validation */ 258*433d6423SLionel Sambuc r = validate_ioctl_exec(&ioctl_exec); 259*433d6423SLionel Sambuc if (r != OK) { 260*433d6423SLionel Sambuc log_debug(&log, "Message validation failed\n"); 261*433d6423SLionel Sambuc return r; 262*433d6423SLionel Sambuc } 263*433d6423SLionel Sambuc 264*433d6423SLionel Sambuc /* permission check */ 265*433d6423SLionel Sambuc r = check_reservation(caller, ioctl_exec.iie_addr); 266*433d6423SLionel Sambuc if (r != OK) { 267*433d6423SLionel Sambuc log_debug(&log, "check_reservation() denied the request\n"); 268*433d6423SLionel Sambuc return r; 269*433d6423SLionel Sambuc } 270*433d6423SLionel Sambuc 271*433d6423SLionel Sambuc /* Call the device specific code to execute the action */ 272*433d6423SLionel Sambuc r = process(&ioctl_exec); 273*433d6423SLionel Sambuc if (r != OK) { 274*433d6423SLionel Sambuc log_debug(&log, "process() failed\n"); 275*433d6423SLionel Sambuc return r; 276*433d6423SLionel Sambuc } 277*433d6423SLionel Sambuc 278*433d6423SLionel Sambuc /* Copy the results of the execution back to the calling process */ 279*433d6423SLionel Sambuc r = sys_safecopyto(caller, grant_nr, (vir_bytes) 0, 280*433d6423SLionel Sambuc (vir_bytes) & ioctl_exec, sizeof(ioctl_exec)); 281*433d6423SLionel Sambuc if (r != OK) { 282*433d6423SLionel Sambuc log_warn(&log, "sys_safecopyto() failed\n"); 283*433d6423SLionel Sambuc return r; 284*433d6423SLionel Sambuc } 285*433d6423SLionel Sambuc 286*433d6423SLionel Sambuc return OK; 287*433d6423SLionel Sambuc } 288*433d6423SLionel Sambuc 289*433d6423SLionel Sambuc static int 290*433d6423SLionel Sambuc i2c_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt, 291*433d6423SLionel Sambuc cp_grant_id_t grant, int UNUSED(flags), endpoint_t UNUSED(user_endpt), 292*433d6423SLionel Sambuc cdev_id_t UNUSED(id)) 293*433d6423SLionel Sambuc { 294*433d6423SLionel Sambuc int r; 295*433d6423SLionel Sambuc 296*433d6423SLionel Sambuc switch (request) { 297*433d6423SLionel Sambuc case MINIX_I2C_IOCTL_EXEC: 298*433d6423SLionel Sambuc r = do_i2c_ioctl_exec(endpt, grant); 299*433d6423SLionel Sambuc break; 300*433d6423SLionel Sambuc default: 301*433d6423SLionel Sambuc log_warn(&log, "Invalid ioctl() 0x%x\n", request); 302*433d6423SLionel Sambuc r = ENOTTY; 303*433d6423SLionel Sambuc break; 304*433d6423SLionel Sambuc } 305*433d6423SLionel Sambuc 306*433d6423SLionel Sambuc return r; 307*433d6423SLionel Sambuc } 308*433d6423SLionel Sambuc 309*433d6423SLionel Sambuc static void 310*433d6423SLionel Sambuc i2c_other(message * m, int ipc_status) 311*433d6423SLionel Sambuc { 312*433d6423SLionel Sambuc message m_reply; 313*433d6423SLionel Sambuc int r; 314*433d6423SLionel Sambuc 315*433d6423SLionel Sambuc if (is_ipc_notify(ipc_status)) { 316*433d6423SLionel Sambuc /* handle notifications about drivers changing state */ 317*433d6423SLionel Sambuc if (m->m_source == DS_PROC_NR) { 318*433d6423SLionel Sambuc ds_event(); 319*433d6423SLionel Sambuc } 320*433d6423SLionel Sambuc return; 321*433d6423SLionel Sambuc } 322*433d6423SLionel Sambuc 323*433d6423SLionel Sambuc switch (m->m_type) { 324*433d6423SLionel Sambuc case BUSC_I2C_RESERVE: 325*433d6423SLionel Sambuc /* reserve a device on the bus for exclusive access */ 326*433d6423SLionel Sambuc r = do_reserve(m->m_source, m->m_li2cdriver_i2c_busc_i2c_reserve.addr); 327*433d6423SLionel Sambuc break; 328*433d6423SLionel Sambuc case BUSC_I2C_EXEC: 329*433d6423SLionel Sambuc /* handle request from another driver */ 330*433d6423SLionel Sambuc r = do_i2c_ioctl_exec(m->m_source, m->m_li2cdriver_i2c_busc_i2c_exec.grant); 331*433d6423SLionel Sambuc break; 332*433d6423SLionel Sambuc default: 333*433d6423SLionel Sambuc log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); 334*433d6423SLionel Sambuc r = EINVAL; 335*433d6423SLionel Sambuc break; 336*433d6423SLionel Sambuc } 337*433d6423SLionel Sambuc 338*433d6423SLionel Sambuc log_trace(&log, "i2c_other() returning r=%d\n", r); 339*433d6423SLionel Sambuc 340*433d6423SLionel Sambuc /* Send a reply. */ 341*433d6423SLionel Sambuc memset(&m_reply, 0, sizeof(m_reply)); 342*433d6423SLionel Sambuc m_reply.m_type = r; 343*433d6423SLionel Sambuc 344*433d6423SLionel Sambuc if ((r = ipc_send(m->m_source, &m_reply)) != OK) 345*433d6423SLionel Sambuc log_warn(&log, "ipc_send() to %d failed: %d\n", m->m_source, r); 346*433d6423SLionel Sambuc } 347*433d6423SLionel Sambuc 348*433d6423SLionel Sambuc /* 349*433d6423SLionel Sambuc * The bus drivers are subscribed to DS events about device drivers on their 350*433d6423SLionel Sambuc * bus. When the device drivers restart, DS sends a notification and this 351*433d6423SLionel Sambuc * function updates the reservation table with the device driver's new 352*433d6423SLionel Sambuc * endpoint. 353*433d6423SLionel Sambuc */ 354*433d6423SLionel Sambuc static void 355*433d6423SLionel Sambuc ds_event(void) 356*433d6423SLionel Sambuc { 357*433d6423SLionel Sambuc char key[DS_MAX_KEYLEN]; 358*433d6423SLionel Sambuc u32_t value; 359*433d6423SLionel Sambuc int type; 360*433d6423SLionel Sambuc endpoint_t owner_endpoint; 361*433d6423SLionel Sambuc int r; 362*433d6423SLionel Sambuc 363*433d6423SLionel Sambuc /* check for pending events */ 364*433d6423SLionel Sambuc while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { 365*433d6423SLionel Sambuc 366*433d6423SLionel Sambuc r = ds_retrieve_u32(key, &value); 367*433d6423SLionel Sambuc if (r != OK) { 368*433d6423SLionel Sambuc log_warn(&log, "ds_retrieve_u32() failed r=%d\n", r); 369*433d6423SLionel Sambuc return; 370*433d6423SLionel Sambuc } 371*433d6423SLionel Sambuc 372*433d6423SLionel Sambuc log_debug(&log, "key='%s' owner_endpoint=0x%x\n", key, 373*433d6423SLionel Sambuc owner_endpoint); 374*433d6423SLionel Sambuc 375*433d6423SLionel Sambuc if (value == DS_DRIVER_UP) { 376*433d6423SLionel Sambuc /* clean up any old reservations the driver had */ 377*433d6423SLionel Sambuc log_debug(&log, "DS_DRIVER_UP\n"); 378*433d6423SLionel Sambuc update_reservation(owner_endpoint, key); 379*433d6423SLionel Sambuc } 380*433d6423SLionel Sambuc } 381*433d6423SLionel Sambuc } 382*433d6423SLionel Sambuc 383*433d6423SLionel Sambuc static int 384*433d6423SLionel Sambuc sef_cb_lu_state_save(int UNUSED(state)) 385*433d6423SLionel Sambuc { 386*433d6423SLionel Sambuc int r; 387*433d6423SLionel Sambuc char key[DS_MAX_KEYLEN]; 388*433d6423SLionel Sambuc 389*433d6423SLionel Sambuc memset(key, '\0', DS_MAX_KEYLEN); 390*433d6423SLionel Sambuc snprintf(key, DS_MAX_KEYLEN, "i2c.%d.i2cdev", i2c_bus_id + 1); 391*433d6423SLionel Sambuc r = ds_publish_mem(key, i2cdev, sizeof(i2cdev), DSF_OVERWRITE); 392*433d6423SLionel Sambuc if (r != OK) { 393*433d6423SLionel Sambuc log_warn(&log, "ds_publish_mem(%s) failed (r=%d)\n", key, r); 394*433d6423SLionel Sambuc return r; 395*433d6423SLionel Sambuc } 396*433d6423SLionel Sambuc 397*433d6423SLionel Sambuc log_debug(&log, "State Saved\n"); 398*433d6423SLionel Sambuc 399*433d6423SLionel Sambuc return OK; 400*433d6423SLionel Sambuc } 401*433d6423SLionel Sambuc 402*433d6423SLionel Sambuc static int 403*433d6423SLionel Sambuc lu_state_restore(void) 404*433d6423SLionel Sambuc { 405*433d6423SLionel Sambuc int r; 406*433d6423SLionel Sambuc char key[DS_MAX_KEYLEN]; 407*433d6423SLionel Sambuc size_t size; 408*433d6423SLionel Sambuc 409*433d6423SLionel Sambuc env_parse_instance(); 410*433d6423SLionel Sambuc 411*433d6423SLionel Sambuc size = sizeof(i2cdev); 412*433d6423SLionel Sambuc 413*433d6423SLionel Sambuc memset(key, '\0', DS_MAX_KEYLEN); 414*433d6423SLionel Sambuc snprintf(key, DS_MAX_KEYLEN, "i2c.%d.i2cdev", i2c_bus_id + 1); 415*433d6423SLionel Sambuc 416*433d6423SLionel Sambuc r = ds_retrieve_mem(key, (char *) i2cdev, &size); 417*433d6423SLionel Sambuc if (r != OK) { 418*433d6423SLionel Sambuc log_warn(&log, "ds_retrieve_mem(%s) failed (r=%d)\n", key, r); 419*433d6423SLionel Sambuc return r; 420*433d6423SLionel Sambuc } 421*433d6423SLionel Sambuc 422*433d6423SLionel Sambuc log_debug(&log, "State Restored\n"); 423*433d6423SLionel Sambuc 424*433d6423SLionel Sambuc return OK; 425*433d6423SLionel Sambuc } 426*433d6423SLionel Sambuc 427*433d6423SLionel Sambuc static int 428*433d6423SLionel Sambuc sef_cb_init(int type, sef_init_info_t * UNUSED(info)) 429*433d6423SLionel Sambuc { 430*433d6423SLionel Sambuc int r; 431*433d6423SLionel Sambuc char regex[DS_MAX_KEYLEN]; 432*433d6423SLionel Sambuc struct machine machine; 433*433d6423SLionel Sambuc sys_getmachine(&machine); 434*433d6423SLionel Sambuc 435*433d6423SLionel Sambuc if (type != SEF_INIT_FRESH) { 436*433d6423SLionel Sambuc /* Restore a prior state. */ 437*433d6423SLionel Sambuc lu_state_restore(); 438*433d6423SLionel Sambuc } 439*433d6423SLionel Sambuc 440*433d6423SLionel Sambuc if (BOARD_IS_BBXM(machine.board_id) || BOARD_IS_BB(machine.board_id)){ 441*433d6423SLionel Sambuc /* Set callback and initialize the bus */ 442*433d6423SLionel Sambuc r = omap_interface_setup(&process, i2c_bus_id); 443*433d6423SLionel Sambuc if (r != OK) { 444*433d6423SLionel Sambuc return r; 445*433d6423SLionel Sambuc } 446*433d6423SLionel Sambuc } else { 447*433d6423SLionel Sambuc return ENODEV; 448*433d6423SLionel Sambuc } 449*433d6423SLionel Sambuc 450*433d6423SLionel Sambuc /* Announce we are up when necessary. */ 451*433d6423SLionel Sambuc if (type != SEF_INIT_LU) { 452*433d6423SLionel Sambuc 453*433d6423SLionel Sambuc /* only capture events for this particular bus */ 454*433d6423SLionel Sambuc snprintf(regex, DS_MAX_KEYLEN, "drv\\.i2c\\.%d\\..*", 455*433d6423SLionel Sambuc i2c_bus_id + 1); 456*433d6423SLionel Sambuc 457*433d6423SLionel Sambuc /* Subscribe to driver events for i2c drivers */ 458*433d6423SLionel Sambuc r = ds_subscribe(regex, DSF_INITIAL | DSF_OVERWRITE); 459*433d6423SLionel Sambuc if (r != OK) { 460*433d6423SLionel Sambuc log_warn(&log, "ds_subscribe() failed\n"); 461*433d6423SLionel Sambuc return r; 462*433d6423SLionel Sambuc } 463*433d6423SLionel Sambuc 464*433d6423SLionel Sambuc chardriver_announce(); 465*433d6423SLionel Sambuc } 466*433d6423SLionel Sambuc 467*433d6423SLionel Sambuc /* Save state */ 468*433d6423SLionel Sambuc sef_cb_lu_state_save(0); 469*433d6423SLionel Sambuc 470*433d6423SLionel Sambuc /* Initialization completed successfully. */ 471*433d6423SLionel Sambuc return OK; 472*433d6423SLionel Sambuc } 473*433d6423SLionel Sambuc 474*433d6423SLionel Sambuc static void 475*433d6423SLionel Sambuc sef_local_startup() 476*433d6423SLionel Sambuc { 477*433d6423SLionel Sambuc /* Register init callbacks. */ 478*433d6423SLionel Sambuc sef_setcb_init_fresh(sef_cb_init); 479*433d6423SLionel Sambuc sef_setcb_init_lu(sef_cb_init); 480*433d6423SLionel Sambuc sef_setcb_init_restart(sef_cb_init); 481*433d6423SLionel Sambuc 482*433d6423SLionel Sambuc /* Register live update callbacks */ 483*433d6423SLionel Sambuc /* Agree to update immediately when LU is requested in a valid state */ 484*433d6423SLionel Sambuc sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready); 485*433d6423SLionel Sambuc /* - Support live update starting from any standard state */ 486*433d6423SLionel Sambuc sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_standard); 487*433d6423SLionel Sambuc /* - Register a custom routine to save the state. */ 488*433d6423SLionel Sambuc sef_setcb_lu_state_save(sef_cb_lu_state_save); 489*433d6423SLionel Sambuc 490*433d6423SLionel Sambuc /* Let SEF perform startup. */ 491*433d6423SLionel Sambuc sef_startup(); 492*433d6423SLionel Sambuc } 493*433d6423SLionel Sambuc 494*433d6423SLionel Sambuc static int 495*433d6423SLionel Sambuc env_parse_instance(void) 496*433d6423SLionel Sambuc { 497*433d6423SLionel Sambuc int r; 498*433d6423SLionel Sambuc long instance; 499*433d6423SLionel Sambuc 500*433d6423SLionel Sambuc /* Parse the instance number passed to service */ 501*433d6423SLionel Sambuc instance = 0; 502*433d6423SLionel Sambuc r = env_parse("instance", "d", 0, &instance, 1, 3); 503*433d6423SLionel Sambuc if (r == -1) { 504*433d6423SLionel Sambuc log_warn(&log, 505*433d6423SLionel Sambuc "Expecting '-arg instance=N' argument (N=1..3)\n"); 506*433d6423SLionel Sambuc return EXIT_FAILURE; 507*433d6423SLionel Sambuc } 508*433d6423SLionel Sambuc 509*433d6423SLionel Sambuc /* Device files count from 1, hardware starts counting from 0 */ 510*433d6423SLionel Sambuc i2c_bus_id = instance - 1; 511*433d6423SLionel Sambuc 512*433d6423SLionel Sambuc return OK; 513*433d6423SLionel Sambuc } 514*433d6423SLionel Sambuc 515*433d6423SLionel Sambuc int 516*433d6423SLionel Sambuc main(int argc, char *argv[]) 517*433d6423SLionel Sambuc { 518*433d6423SLionel Sambuc int r; 519*433d6423SLionel Sambuc 520*433d6423SLionel Sambuc env_setargs(argc, argv); 521*433d6423SLionel Sambuc 522*433d6423SLionel Sambuc r = env_parse_instance(); 523*433d6423SLionel Sambuc if (r != OK) { 524*433d6423SLionel Sambuc return r; 525*433d6423SLionel Sambuc } 526*433d6423SLionel Sambuc 527*433d6423SLionel Sambuc memset(i2cdev, '\0', sizeof(i2cdev)); 528*433d6423SLionel Sambuc sef_local_startup(); 529*433d6423SLionel Sambuc chardriver_task(&i2c_tab); 530*433d6423SLionel Sambuc 531*433d6423SLionel Sambuc return OK; 532*433d6423SLionel Sambuc } 533