Module Name:    src
Committed By:   martin
Date:           Sun Feb 28 11:34:42 UTC 2010

Modified Files:
        src/sys/dev/i2c: i2c.c i2cvar.h

Log Message:
Generic (device property based) framework for optional direct configuration
of i2c devices, as discussed on tech-kern.


To generate a diff of this commit:
cvs rdiff -u -r1.23 -r1.24 src/sys/dev/i2c/i2c.c
cvs rdiff -u -r1.6 -r1.7 src/sys/dev/i2c/i2cvar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/i2c/i2c.c
diff -u src/sys/dev/i2c/i2c.c:1.23 src/sys/dev/i2c/i2c.c:1.24
--- src/sys/dev/i2c/i2c.c:1.23	Tue Feb  3 16:41:31 2009
+++ src/sys/dev/i2c/i2c.c	Sun Feb 28 11:34:42 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2c.c,v 1.23 2009/02/03 16:41:31 pgoyette Exp $	*/
+/*	$NetBSD: i2c.c,v 1.24 2010/02/28 11:34:42 martin Exp $	*/
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.23 2009/02/03 16:41:31 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.24 2010/02/28 11:34:42 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -59,6 +59,8 @@
 };
 
 static void	iic_smbus_intr_thread(void *);
+static void	iic_fill_compat(struct i2c_attach_args*, const char*,
+			size_t, char **);
 
 int
 iicbus_print(void *aux, const char *pnp)
@@ -71,6 +73,20 @@
 }
 
 static int
+iic_print_direct(void *aux, const char *pnp)
+{
+	struct i2c_attach_args *ia = aux;
+
+	if (pnp != NULL)
+		aprint_normal("%s at %s addr 0x%02x", ia->ia_name, pnp,
+			ia->ia_addr);
+	else
+		aprint_normal(" addr 0x%02x", ia->ia_addr);
+
+	return UNCONF;
+}
+
+static int
 iic_print(void *aux, const char *pnp)
 {
 	struct i2c_attach_args *ia = aux;
@@ -110,6 +126,8 @@
 {
 	struct iic_softc *sc = device_private(self);
 	struct i2cbus_attach_args *iba = aux;
+	prop_array_t child_devices;
+	char *buf;
 	i2c_tag_t ic;
 	int rv;
 
@@ -196,11 +214,65 @@
 	if (!pmf_device_register(self, NULL, NULL))
 		aprint_error_dev(self, "couldn't establish power handler\n");
 
-	/*
-	 * Attach all i2c devices described in the kernel
-	 * configuration file.
-	 */
-	config_search_ia(iic_search, self, "iic", NULL);
+	child_devices = prop_dictionary_get(device_properties(parent),
+		"i2c-child-devices");
+	if (child_devices) {
+		unsigned int i, count;
+		prop_dictionary_t dev;
+		prop_data_t cdata;
+		uint32_t addr, size;
+		uint64_t cookie;
+		const char *name;
+		struct i2c_attach_args ia;
+		int loc[2];
+
+		memset(loc, 0, sizeof loc);
+		count = prop_array_count(child_devices);
+		for (i = 0; i < count; i++) {
+			dev = prop_array_get(child_devices, i);
+			if (!dev) continue;
+ 			if (!prop_dictionary_get_cstring_nocopy(
+			    dev, "name", &name))
+				continue;
+			if (!prop_dictionary_get_uint32(dev, "addr", &addr))
+				continue;
+			if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
+				cookie = 0;
+			loc[0] = addr;
+			if (prop_dictionary_get_uint32(dev, "size", &size))
+				loc[1] = size;
+			else
+				loc[1] = -1;
+
+			memset(&ia, 0, sizeof ia);
+			ia.ia_addr = addr;
+			ia.ia_type = sc->sc_type;
+			ia.ia_tag = ic;
+			ia.ia_name = name;
+			ia.ia_cookie = cookie;
+
+			buf = NULL;
+			cdata = prop_dictionary_get(dev, "compatible");
+			if (cdata)
+				iic_fill_compat(&ia,
+				    prop_data_data_nocopy(cdata),
+				    prop_data_size(cdata), &buf);
+
+			config_found_sm_loc(self, "iic", loc, &ia,
+			    iic_print_direct, NULL);
+
+			if (ia.ia_compat)
+				free(ia.ia_compat, M_TEMP);
+			if (buf)
+				free(buf, M_TEMP);
+		}
+	} else {
+		/*
+		 * Attach all i2c devices described in the kernel
+		 * configuration file.
+		 */
+		config_search_ia(iic_search, self, "iic", NULL);
+	}
 }
 
 static void
@@ -303,5 +375,55 @@
 	return 1;
 }
 
+static void
+iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len,
+	char **buffer)
+{
+	int count, i;
+	const char *c, *start, **ptr;
+
+	*buffer = NULL;
+	for (i = count = 0, c = compat; i < len; i++, c++)
+		if (*c == 0)
+			count++;
+	count += 2;
+	ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK);
+	if (!ptr) return;
+
+	for (i = count = 0, start = c = compat; i < len; i++, c++) {
+		if (*c == 0) {
+			ptr[count++] = start;
+			start = c+1;
+		}
+	}
+	if (start < compat+len) {
+		/* last string not 0 terminated */
+		size_t l = c-start;
+		*buffer = malloc(l+1, M_TEMP, M_WAITOK);
+		memcpy(*buffer, start, l);
+		(*buffer)[l] = 0;
+		ptr[count++] = *buffer;
+	}
+	ptr[count] = NULL;
+
+	ia->ia_compat = ptr;
+	ia->ia_ncompat = count;
+}
+
+int
+iic_compat_match(struct i2c_attach_args *ia, const char ** compats)
+{
+	int i;
+
+	for (; compats && *compats; compats++) {
+		for (i = 0; i < ia->ia_ncompat; i++) {
+			if (strcmp(*compats, ia->ia_compat[i]) == 0)
+				return 1;
+		}
+	}
+	return 0;
+}
+
+
 CFATTACH_DECL_NEW(iic, sizeof(struct iic_softc),
     iic_match, iic_attach, NULL, NULL);

Index: src/sys/dev/i2c/i2cvar.h
diff -u src/sys/dev/i2c/i2cvar.h:1.6 src/sys/dev/i2c/i2cvar.h:1.7
--- src/sys/dev/i2c/i2cvar.h:1.6	Mon Jul  9 21:00:33 2007
+++ src/sys/dev/i2c/i2cvar.h	Sun Feb 28 11:34:42 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: i2cvar.h,v 1.6 2007/07/09 21:00:33 ad Exp $	*/
+/*	$NetBSD: i2cvar.h,v 1.7 2010/02/28 11:34:42 martin Exp $	*/
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -118,12 +118,29 @@
 	i2c_addr_t	ia_addr;	/* address of device */
 	int		ia_size;	/* size (for EEPROMs) */
 	int		ia_type;	/* bus type */
+	/* only set if using direct config */
+	const char *	ia_name;	/* name of the device */
+	int		ia_ncompat;	/* number of pointers in the
+					   ia_compat array */
+	const char **	ia_compat;	/* chip names */
+	/*
+	 * The following is of limited usefullness and should only be used
+	 * in rare cases where we realy know what we are doing. Example:
+	 * a machine depended i2c driver (located in sys/arch/$arch/dev)
+	 * needing to access some firmware properties.
+	 * Depending on the firmware in use, an identifier for the device
+	 * may be present. Example: on OpenFirmware machines the device
+	 * tree OF node - if available. This info is hard to transport
+	 * down to MD drivers through the MI i2c bus otherwise.
+	 */
+	uintptr_t	ia_cookie;	/* OF node in openfirmware machines */
 };
 
 /*
  * API presented to i2c controllers.
  */
 int	iicbus_print(void *, const char *);
+int	iic_compat_match(struct i2c_attach_args*, const char **);
 
 #ifdef _I2C_PRIVATE
 /*

Reply via email to