xref: /minix3/minix/drivers/bus/i2c/i2c.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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