Annotation of src/sys/dev/i2c/i2c.c, Revision 1.39.2.2
1.39.2.2! rmind 1: /* $NetBSD: i2c.c,v 1.39.2.1 2013/08/28 23:59:25 rmind Exp $ */
1.1 thorpej 2:
3: /*
4: * Copyright (c) 2003 Wasabi Systems, Inc.
5: * All rights reserved.
6: *
7: * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed for the NetBSD Project by
20: * Wasabi Systems, Inc.
21: * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22: * or promote products derived from this software without specific prior
23: * written permission.
24: *
25: * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35: * POSSIBILITY OF SUCH DAMAGE.
36: */
37:
1.18 lukem 38: #include <sys/cdefs.h>
1.39.2.2! rmind 39: __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.39.2.1 2013/08/28 23:59:25 rmind Exp $");
1.18 lukem 40:
1.1 thorpej 41: #include <sys/param.h>
42: #include <sys/systm.h>
43: #include <sys/device.h>
44: #include <sys/event.h>
45: #include <sys/conf.h>
1.11 jmcneill 46: #include <sys/malloc.h>
1.34 jmcneill 47: #include <sys/kmem.h>
1.11 jmcneill 48: #include <sys/kthread.h>
49: #include <sys/proc.h>
50: #include <sys/kernel.h>
1.32 jmcneill 51: #include <sys/fcntl.h>
1.28 mbalmer 52: #include <sys/module.h>
1.1 thorpej 53:
54: #include <dev/i2c/i2cvar.h>
55:
56: #include "locators.h"
57:
1.27 pgoyette 58: #define I2C_MAX_ADDR 0x3ff /* 10-bit address, max */
59:
1.1 thorpej 60: struct iic_softc {
61: i2c_tag_t sc_tag;
1.6 jmcneill 62: int sc_type;
1.27 pgoyette 63: device_t sc_devices[I2C_MAX_ADDR + 1];
1.1 thorpej 64: };
65:
1.31 jmcneill 66: static dev_type_open(iic_open);
67: static dev_type_close(iic_close);
68: static dev_type_ioctl(iic_ioctl);
69:
70: const struct cdevsw iic_cdevsw = {
1.39.2.2! rmind 71: .d_open = iic_open,
! 72: .d_close = iic_close,
! 73: .d_read = noread,
! 74: .d_write = nowrite,
! 75: .d_ioctl = iic_ioctl,
! 76: .d_stop = nostop,
! 77: .d_tty = notty,
! 78: .d_poll = nopoll,
! 79: .d_mmap = nommap,
! 80: .d_kqfilter = nokqfilter,
! 81: .d_flag = D_OTHER
1.31 jmcneill 82: };
83:
84: extern struct cfdriver iic_cd;
85:
1.11 jmcneill 86: static void iic_smbus_intr_thread(void *);
1.24 martin 87: static void iic_fill_compat(struct i2c_attach_args*, const char*,
88: size_t, char **);
1.11 jmcneill 89:
1.1 thorpej 90: static int
1.24 martin 91: iic_print_direct(void *aux, const char *pnp)
92: {
93: struct i2c_attach_args *ia = aux;
94:
95: if (pnp != NULL)
96: aprint_normal("%s at %s addr 0x%02x", ia->ia_name, pnp,
97: ia->ia_addr);
98: else
99: aprint_normal(" addr 0x%02x", ia->ia_addr);
100:
101: return UNCONF;
102: }
103:
104: static int
1.10 christos 105: iic_print(void *aux, const char *pnp)
1.1 thorpej 106: {
107: struct i2c_attach_args *ia = aux;
108:
1.6 jmcneill 109: if (ia->ia_addr != (i2c_addr_t)-1)
110: aprint_normal(" addr 0x%x", ia->ia_addr);
1.1 thorpej 111:
1.30 mbalmer 112: return UNCONF;
1.1 thorpej 113: }
114:
115: static int
1.20 xtraeme 116: iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
1.1 thorpej 117: {
1.20 xtraeme 118: struct iic_softc *sc = device_private(parent);
1.1 thorpej 119: struct i2c_attach_args ia;
120:
121: ia.ia_tag = sc->sc_tag;
122: ia.ia_size = cf->cf_loc[IICCF_SIZE];
1.6 jmcneill 123: ia.ia_type = sc->sc_type;
1.1 thorpej 124:
1.25 njoly 125: ia.ia_name = NULL;
126: ia.ia_ncompat = 0;
127: ia.ia_compat = NULL;
128:
1.39.2.1 rmind 129: for (ia.ia_addr = 0; ia.ia_addr <= I2C_MAX_ADDR; ia.ia_addr++) {
130: if (sc->sc_devices[ia.ia_addr] != NULL)
131: continue;
132:
133: if (cf->cf_loc[IICCF_ADDR] != -1 &&
134: cf->cf_loc[IICCF_ADDR] != ia.ia_addr)
135: continue;
136:
137: if (config_match(parent, cf, &ia) > 0)
1.27 pgoyette 138: sc->sc_devices[ia.ia_addr] =
139: config_attach(parent, cf, &ia, iic_print);
140: }
1.39.2.1 rmind 141:
1.30 mbalmer 142: return 0;
1.1 thorpej 143: }
144:
1.27 pgoyette 145: static void
146: iic_child_detach(device_t parent, device_t child)
147: {
148: struct iic_softc *sc = device_private(parent);
149: int i;
150:
151: for (i = 0; i <= I2C_MAX_ADDR; i++)
152: if (sc->sc_devices[i] == child) {
153: sc->sc_devices[i] = NULL;
154: break;
1.39.2.1 rmind 155: }
1.27 pgoyette 156: }
157:
1.1 thorpej 158: static int
1.26 jmcneill 159: iic_rescan(device_t self, const char *ifattr, const int *locators)
160: {
161: config_search_ia(iic_search, self, ifattr, NULL);
162: return 0;
163: }
164:
165: static int
1.20 xtraeme 166: iic_match(device_t parent, cfdata_t cf, void *aux)
1.1 thorpej 167: {
168:
1.30 mbalmer 169: return 1;
1.1 thorpej 170: }
171:
172: static void
1.20 xtraeme 173: iic_attach(device_t parent, device_t self, void *aux)
1.1 thorpej 174: {
1.7 thorpej 175: struct iic_softc *sc = device_private(self);
1.1 thorpej 176: struct i2cbus_attach_args *iba = aux;
1.24 martin 177: prop_array_t child_devices;
1.39.2.2! rmind 178: prop_dictionary_t props;
1.24 martin 179: char *buf;
1.14 ad 180: i2c_tag_t ic;
181: int rv;
1.39.2.2! rmind 182: bool indirect_config;
1.1 thorpej 183:
1.33 jmcneill 184: aprint_naive("\n");
1.1 thorpej 185: aprint_normal(": I2C bus\n");
186:
187: sc->sc_tag = iba->iba_tag;
1.6 jmcneill 188: sc->sc_type = iba->iba_type;
1.14 ad 189: ic = sc->sc_tag;
1.19 cegger 190: ic->ic_devname = device_xname(self);
1.11 jmcneill 191:
1.13 jmcneill 192: LIST_INIT(&(sc->sc_tag->ic_list));
193: LIST_INIT(&(sc->sc_tag->ic_proc_list));
1.14 ad 194:
1.33 jmcneill 195: rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL,
196: iic_smbus_intr_thread, ic, &ic->ic_intr_thread,
197: "%s", ic->ic_devname);
1.14 ad 198: if (rv)
1.20 xtraeme 199: aprint_error_dev(self, "unable to create intr thread\n");
1.1 thorpej 200:
1.17 jmcneill 201: if (!pmf_device_register(self, NULL, NULL))
202: aprint_error_dev(self, "couldn't establish power handler\n");
203:
1.39.2.2! rmind 204: props = device_properties(parent);
! 205: if (!prop_dictionary_get_bool(props, "i2c-indirect-config",
! 206: &indirect_config))
! 207: indirect_config = true;
! 208: child_devices = prop_dictionary_get(props, "i2c-child-devices");
1.24 martin 209: if (child_devices) {
210: unsigned int i, count;
211: prop_dictionary_t dev;
212: prop_data_t cdata;
213: uint32_t addr, size;
214: uint64_t cookie;
215: const char *name;
216: struct i2c_attach_args ia;
217: int loc[2];
218:
219: memset(loc, 0, sizeof loc);
220: count = prop_array_count(child_devices);
221: for (i = 0; i < count; i++) {
222: dev = prop_array_get(child_devices, i);
223: if (!dev) continue;
224: if (!prop_dictionary_get_cstring_nocopy(
225: dev, "name", &name))
226: continue;
227: if (!prop_dictionary_get_uint32(dev, "addr", &addr))
228: continue;
229: if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
230: cookie = 0;
231: loc[0] = addr;
232: if (prop_dictionary_get_uint32(dev, "size", &size))
233: loc[1] = size;
234: else
235: loc[1] = -1;
236:
237: memset(&ia, 0, sizeof ia);
238: ia.ia_addr = addr;
239: ia.ia_type = sc->sc_type;
240: ia.ia_tag = ic;
241: ia.ia_name = name;
242: ia.ia_cookie = cookie;
1.39 jdc 243: ia.ia_size = size;
1.24 martin 244:
245: buf = NULL;
246: cdata = prop_dictionary_get(dev, "compatible");
247: if (cdata)
248: iic_fill_compat(&ia,
249: prop_data_data_nocopy(cdata),
250: prop_data_size(cdata), &buf);
251:
1.33 jmcneill 252: if (addr > I2C_MAX_ADDR) {
253: aprint_error_dev(self,
254: "WARNING: ignoring bad device address "
255: "@ 0x%02x\n", addr);
256: } else if (sc->sc_devices[addr] == NULL) {
257: sc->sc_devices[addr] =
258: config_found_sm_loc(self, "iic", loc, &ia,
259: iic_print_direct, NULL);
260: }
1.24 martin 261:
262: if (ia.ia_compat)
263: free(ia.ia_compat, M_TEMP);
264: if (buf)
265: free(buf, M_TEMP);
266: }
1.39.2.2! rmind 267: } else if (indirect_config) {
1.24 martin 268: /*
269: * Attach all i2c devices described in the kernel
270: * configuration file.
271: */
1.26 jmcneill 272: iic_rescan(self, "iic", NULL);
1.24 martin 273: }
1.1 thorpej 274: }
275:
1.33 jmcneill 276: static int
277: iic_detach(device_t self, int flags)
278: {
279: struct iic_softc *sc = device_private(self);
280: i2c_tag_t ic = sc->sc_tag;
281: int i, error;
282: void *hdl;
283:
284: for (i = 0; i <= I2C_MAX_ADDR; i++) {
285: if (sc->sc_devices[i]) {
286: error = config_detach(sc->sc_devices[i], flags);
287: if (error)
288: return error;
289: }
290: }
291:
292: if (ic->ic_running) {
293: ic->ic_running = 0;
294: wakeup(ic);
295: kthread_join(ic->ic_intr_thread);
296: }
297:
298: if (!LIST_EMPTY(&ic->ic_list)) {
299: device_printf(self, "WARNING: intr handler list not empty\n");
300: while (!LIST_EMPTY(&ic->ic_list)) {
301: hdl = LIST_FIRST(&ic->ic_list);
302: iic_smbus_intr_disestablish(ic, hdl);
303: }
304: }
305: if (!LIST_EMPTY(&ic->ic_proc_list)) {
306: device_printf(self, "WARNING: proc handler list not empty\n");
307: while (!LIST_EMPTY(&ic->ic_proc_list)) {
308: hdl = LIST_FIRST(&ic->ic_proc_list);
309: iic_smbus_intr_disestablish_proc(ic, hdl);
310: }
311: }
312:
313: pmf_device_deregister(self);
314:
315: return 0;
316: }
317:
1.11 jmcneill 318: static void
1.14 ad 319: iic_smbus_intr_thread(void *aux)
1.11 jmcneill 320: {
321: i2c_tag_t ic;
322: struct ic_intr_list *il;
323:
324: ic = (i2c_tag_t)aux;
325: ic->ic_running = 1;
326: ic->ic_pending = 0;
327:
328: while (ic->ic_running) {
329: if (ic->ic_pending == 0)
1.39.2.2! rmind 330: tsleep(ic, PZERO, "iicintr", hz);
1.11 jmcneill 331: if (ic->ic_pending > 0) {
332: LIST_FOREACH(il, &(ic->ic_proc_list), il_next) {
333: (*il->il_intr)(il->il_intrarg);
334: }
335: ic->ic_pending--;
336: }
337: }
338:
339: kthread_exit(0);
340: }
341:
342: void *
343: iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
344: {
345: struct ic_intr_list *il;
346:
347: il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
348: if (il == NULL)
349: return NULL;
1.28 mbalmer 350:
1.11 jmcneill 351: il->il_intr = intr;
352: il->il_intrarg = intrarg;
353:
354: LIST_INSERT_HEAD(&(ic->ic_list), il, il_next);
355:
356: return il;
357: }
358:
359: void
360: iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl)
361: {
362: struct ic_intr_list *il;
363:
364: il = (struct ic_intr_list *)hdl;
365:
366: LIST_REMOVE(il, il_next);
367: free(il, M_DEVBUF);
368:
369: return;
370: }
371:
372: void *
373: iic_smbus_intr_establish_proc(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
374: {
375: struct ic_intr_list *il;
376:
377: il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
378: if (il == NULL)
379: return NULL;
1.28 mbalmer 380:
1.11 jmcneill 381: il->il_intr = intr;
382: il->il_intrarg = intrarg;
383:
384: LIST_INSERT_HEAD(&(ic->ic_proc_list), il, il_next);
385:
386: return il;
387: }
388:
389: void
390: iic_smbus_intr_disestablish_proc(i2c_tag_t ic, void *hdl)
391: {
392: struct ic_intr_list *il;
393:
394: il = (struct ic_intr_list *)hdl;
395:
396: LIST_REMOVE(il, il_next);
397: free(il, M_DEVBUF);
398:
399: return;
400: }
401:
402: int
403: iic_smbus_intr(i2c_tag_t ic)
404: {
405: struct ic_intr_list *il;
406:
407: LIST_FOREACH(il, &(ic->ic_list), il_next) {
408: (*il->il_intr)(il->il_intrarg);
409: }
410:
411: ic->ic_pending++;
412: wakeup(ic);
413:
414: return 1;
415: }
416:
1.24 martin 417: static void
418: iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len,
419: char **buffer)
420: {
421: int count, i;
422: const char *c, *start, **ptr;
423:
424: *buffer = NULL;
425: for (i = count = 0, c = compat; i < len; i++, c++)
426: if (*c == 0)
427: count++;
428: count += 2;
429: ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK);
430: if (!ptr) return;
431:
432: for (i = count = 0, start = c = compat; i < len; i++, c++) {
433: if (*c == 0) {
434: ptr[count++] = start;
435: start = c+1;
436: }
437: }
438: if (start < compat+len) {
439: /* last string not 0 terminated */
440: size_t l = c-start;
441: *buffer = malloc(l+1, M_TEMP, M_WAITOK);
442: memcpy(*buffer, start, l);
443: (*buffer)[l] = 0;
444: ptr[count++] = *buffer;
445: }
446: ptr[count] = NULL;
447:
448: ia->ia_compat = ptr;
449: ia->ia_ncompat = count;
450: }
451:
452: int
453: iic_compat_match(struct i2c_attach_args *ia, const char ** compats)
454: {
455: int i;
456:
457: for (; compats && *compats; compats++) {
458: for (i = 0; i < ia->ia_ncompat; i++) {
459: if (strcmp(*compats, ia->ia_compat[i]) == 0)
460: return 1;
461: }
462: }
463: return 0;
464: }
465:
1.31 jmcneill 466: static int
467: iic_open(dev_t dev, int flag, int fmt, lwp_t *l)
468: {
469: struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
470:
471: if (sc == NULL)
472: return ENXIO;
473:
474: return 0;
475: }
476:
477: static int
478: iic_close(dev_t dev, int flag, int fmt, lwp_t *l)
479: {
480: return 0;
481: }
482:
483: static int
1.32 jmcneill 484: iic_ioctl_exec(struct iic_softc *sc, i2c_ioctl_exec_t *iie, int flag)
1.31 jmcneill 485: {
486: i2c_tag_t ic = sc->sc_tag;
487: uint8_t buf[I2C_EXEC_MAX_BUFLEN];
1.34 jmcneill 488: void *cmd = NULL;
1.31 jmcneill 489: int error;
490:
491: /* Validate parameters */
492: if (iie->iie_addr > I2C_MAX_ADDR)
493: return EINVAL;
494: if (iie->iie_cmdlen > I2C_EXEC_MAX_CMDLEN ||
495: iie->iie_buflen > I2C_EXEC_MAX_BUFLEN)
496: return EINVAL;
497: if (iie->iie_cmd != NULL && iie->iie_cmdlen == 0)
498: return EINVAL;
499: if (iie->iie_buf != NULL && iie->iie_buflen == 0)
500: return EINVAL;
1.32 jmcneill 501: if (I2C_OP_WRITE_P(iie->iie_op) && (flag & FWRITE) == 0)
502: return EBADF;
1.31 jmcneill 503:
504: #if 0
505: /* Disallow userspace access to devices that have drivers attached. */
506: if (sc->sc_devices[iie->iie_addr] != NULL)
507: return EBUSY;
508: #endif
509:
510: if (iie->iie_cmd != NULL) {
1.34 jmcneill 511: cmd = kmem_alloc(iie->iie_cmdlen, KM_SLEEP);
512: if (cmd == NULL)
513: return ENOMEM;
1.31 jmcneill 514: error = copyin(iie->iie_cmd, cmd, iie->iie_cmdlen);
1.34 jmcneill 515: if (error) {
516: kmem_free(cmd, iie->iie_cmdlen);
1.31 jmcneill 517: return error;
1.34 jmcneill 518: }
1.31 jmcneill 519: }
520:
521: iic_acquire_bus(ic, 0);
522: error = iic_exec(ic, iie->iie_op, iie->iie_addr, cmd, iie->iie_cmdlen,
523: buf, iie->iie_buflen, 0);
524: iic_release_bus(ic, 0);
525:
1.36 jmcneill 526: /*
527: * Some drivers return error codes on failure, and others return -1.
528: */
529: if (error < 0)
530: error = EIO;
531:
1.34 jmcneill 532: if (cmd)
533: kmem_free(cmd, iie->iie_cmdlen);
534:
1.31 jmcneill 535: if (error)
536: return error;
537:
538: if (iie->iie_buf)
539: error = copyout(buf, iie->iie_buf, iie->iie_buflen);
540:
541: return error;
542: }
543:
544: static int
545: iic_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
546: {
547: struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
548:
549: if (sc == NULL)
550: return ENXIO;
551:
552: switch (cmd) {
553: case I2C_IOCTL_EXEC:
1.32 jmcneill 554: return iic_ioctl_exec(sc, (i2c_ioctl_exec_t *)data, flag);
1.31 jmcneill 555: default:
556: return ENODEV;
557: }
558: }
559:
1.24 martin 560:
1.26 jmcneill 561: CFATTACH_DECL2_NEW(iic, sizeof(struct iic_softc),
1.33 jmcneill 562: iic_match, iic_attach, iic_detach, NULL, iic_rescan, iic_child_detach);
1.28 mbalmer 563:
564: MODULE(MODULE_CLASS_DRIVER, iic, NULL);
565:
566: #ifdef _MODULE
567: #include "ioconf.c"
568: #endif
569:
570: static int
571: iic_modcmd(modcmd_t cmd, void *opaque)
572: {
573: int error;
574:
575: error = 0;
576: switch (cmd) {
577: case MODULE_CMD_INIT:
578: #ifdef _MODULE
579: error = config_init_component(cfdriver_ioconf_iic,
580: cfattach_ioconf_iic, cfdata_ioconf_iic);
581: if (error)
582: aprint_error("%s: unable to init component\n",
583: iic_cd.cd_name);
584: #endif
585: break;
586: case MODULE_CMD_FINI:
587: #ifdef _MODULE
588: config_fini_component(cfdriver_ioconf_iic,
589: cfattach_ioconf_iic, cfdata_ioconf_iic);
590: #endif
591: break;
592: default:
593: error = ENOTTY;
594: }
595: return error;
596: }
CVSweb <webmaster@jp.NetBSD.org>