Module Name:    src
Committed By:   tnn
Date:           Tue Aug 13 16:37:15 UTC 2019

Modified Files:
        src/sys/dev/spi: spi.c spivar.h

Log Message:
spi: prepare for fdt direct attachment of spi slaves

Introduce sba_child_devices array in spibus_attach_args. If the parent has
populated sba_child_devices then attach them first. Then do any devices
devices the user has wired in the kernel config, if any.


To generate a diff of this commit:
cvs rdiff -u -r1.11 -r1.12 src/sys/dev/spi/spi.c
cvs rdiff -u -r1.7 -r1.8 src/sys/dev/spi/spivar.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/spi/spi.c
diff -u src/sys/dev/spi/spi.c:1.11 src/sys/dev/spi/spi.c:1.12
--- src/sys/dev/spi/spi.c:1.11	Sat Mar  9 07:53:12 2019
+++ src/sys/dev/spi/spi.c	Tue Aug 13 16:37:15 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: spi.c,v 1.11 2019/03/09 07:53:12 mlelstv Exp $ */
+/* $NetBSD: spi.c,v 1.12 2019/08/13 16:37:15 tnn Exp $ */
 
 /*-
  * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.11 2019/03/09 07:53:12 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.12 2019/08/13 16:37:15 tnn Exp $");
 
 #include "locators.h"
 
@@ -102,6 +102,8 @@ struct spi_handle {
 	int			sh_slave;
 	int			sh_mode;
 	int			sh_speed;
+	int			sh_flags;
+#define SPIH_ATTACHED		1
 };
 
 #define SPI_MAXDATA 4096
@@ -151,15 +153,123 @@ spi_search(device_t parent, cfdata_t cf,
 		return -1;
 	}
 
+	memset(&sa, 0, sizeof sa);
 	sa.sa_handle = &sc->sc_slaves[addr];
+	if (ISSET(sa.sa_handle->sh_flags, SPIH_ATTACHED))
+		return -1;
 
-	if (config_match(parent, cf, &sa) > 0)
+	if (config_match(parent, cf, &sa) > 0) {
+		SET(sa.sa_handle->sh_flags, SPIH_ATTACHED);
 		config_attach(parent, cf, &sa, spi_print);
+	}
 
 	return 0;
 }
 
 /*
+ * XXX this is the same as i2c_fill_compat. It could be refactored into a
+ * common fill_compat function with pointers to compat & ncompat instead
+ * of attach_args as the first parameter.
+ */
+static void
+spi_fill_compat(struct spi_attach_args *sa, 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;
+
+	sa->sa_compat = ptr;
+	sa->sa_ncompat = count;
+}
+
+static void
+spi_direct_attach_child_devices(device_t parent, struct spi_softc *sc,
+    prop_array_t child_devices)
+{
+	unsigned int count;
+	prop_dictionary_t child;
+	prop_data_t cdata;
+	uint32_t slave;
+	uint64_t cookie;
+	struct spi_attach_args sa;
+	int loc[SPICF_NLOCS];
+	char *buf;
+	int i;
+
+	memset(loc, 0, sizeof loc);
+	count = prop_array_count(child_devices);
+	for (i = 0; i < count; i++) {
+		child = prop_array_get(child_devices, i);
+		if (!child)
+			continue;
+		if (!prop_dictionary_get_uint32(child, "slave", &slave))
+			continue;
+		if(slave >= sc->sc_controller.sct_nslaves)
+			continue;
+		if (!prop_dictionary_get_uint64(child, "cookie", &cookie))
+			continue;
+		if (!(cdata = prop_dictionary_get(child, "compatible")))
+			continue;
+		loc[SPICF_SLAVE] = slave;
+
+		memset(&sa, 0, sizeof sa);
+		sa.sa_handle = &sc->sc_slaves[i];
+		if (ISSET(sa.sa_handle->sh_flags, SPIH_ATTACHED))
+			continue;
+		SET(sa.sa_handle->sh_flags, SPIH_ATTACHED);
+
+		buf = NULL;
+		spi_fill_compat(&sa,
+				prop_data_data_nocopy(cdata),
+				prop_data_size(cdata), &buf);
+		(void) config_found_sm_loc(parent, "spi",
+					   loc, &sa, spi_print,
+					   NULL);
+
+		if (sa.sa_compat)
+			free(sa.sa_compat, M_TEMP);
+		if (buf)
+			free(buf, M_TEMP);
+	}
+}
+
+int
+spi_compatible_match(const struct spi_attach_args *sa, const cfdata_t cf,
+		     const struct device_compatible_entry *compats)
+{
+	if (sa->sa_ncompat > 0)
+		return device_compatible_match(sa->sa_compat, sa->sa_ncompat,
+					       compats, NULL);
+
+	return 1;
+}
+
+/*
  * API for device drivers.
  *
  * We provide wrapper routines to decouple the ABI for the SPI
@@ -197,9 +307,11 @@ spi_attach(device_t parent, device_t sel
 		sc->sc_slaves[i].sh_controller = &sc->sc_controller;
 	}
 
-	/*
-	 * Locate and attach child devices
-	 */
+	/* First attach devices known to be present via fdt */
+	if (sba->sba_child_devices) {
+		spi_direct_attach_child_devices(self, sc, sba->sba_child_devices);
+	}
+	/* Then do any other devices the user may have manually wired */
 	config_search_ia(spi_search, self, "spi", NULL);
 }
 

Index: src/sys/dev/spi/spivar.h
diff -u src/sys/dev/spi/spivar.h:1.7 src/sys/dev/spi/spivar.h:1.8
--- src/sys/dev/spi/spivar.h:1.7	Sat Feb 23 10:43:25 2019
+++ src/sys/dev/spi/spivar.h	Tue Aug 13 16:37:15 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: spivar.h,v 1.7 2019/02/23 10:43:25 mlelstv Exp $ */
+/* $NetBSD: spivar.h,v 1.8 2019/08/13 16:37:15 tnn Exp $ */
 
 /*-
  * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
@@ -77,10 +77,16 @@ int spibus_print(void *, const char *);
 /* one per chip select */
 struct spibus_attach_args {
 	struct spi_controller	*sba_controller;
+	prop_array_t		sba_child_devices;
 };
 
 struct spi_attach_args {
 	struct spi_handle	*sa_handle;
+	/* only set if using direct config */
+	int		sa_ncompat;	/* number of pointers in the
+					   ia_compat array */
+	const char **	sa_compat;	/* chip names */
+	prop_dictionary_t sa_prop;	/* dictionary for this device */
 };
 
 /*
@@ -132,7 +138,9 @@ SIMPLEQ_HEAD(spi_transq, spi_transfer);
 #define	SPI_F_DONE		0x0001
 #define	SPI_F_ERROR		0x0002
 
-int spi_configure(struct spi_handle *, int mode, int speed);
+int spi_compatible_match(const struct spi_attach_args *, const cfdata_t,
+			  const struct device_compatible_entry *);
+int spi_configure(struct spi_handle *, int, int);
 int spi_transfer(struct spi_handle *, struct spi_transfer *);
 void spi_transfer_init(struct spi_transfer *);
 void spi_chunk_init(struct spi_chunk *, int, const uint8_t *, uint8_t *);

Reply via email to