Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/spi spi: prepare for fdt direct attachment of spi sl...



details:   https://anonhg.NetBSD.org/src/rev/aacfaa24995d
branches:  trunk
changeset: 458855:aacfaa24995d
user:      tnn <tnn%NetBSD.org@localhost>
date:      Tue Aug 13 16:37:15 2019 +0000

description:
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.

diffstat:

 sys/dev/spi/spi.c    |  124 ++++++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/spi/spivar.h |   12 ++++-
 2 files changed, 128 insertions(+), 8 deletions(-)

diffs (204 lines):

diff -r 3f97c9ef9063 -r aacfaa24995d sys/dev/spi/spi.c
--- a/sys/dev/spi/spi.c Tue Aug 13 13:22:16 2019 +0000
+++ b/sys/dev/spi/spi.c Tue Aug 13 16:37:15 2019 +0000
@@ -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 @@
        int                     sh_slave;
        int                     sh_mode;
        int                     sh_speed;
+       int                     sh_flags;
+#define SPIH_ATTACHED          1
 };
 
 #define SPI_MAXDATA 4096
@@ -151,15 +153,123 @@
                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 @@
                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);
 }
 
diff -r 3f97c9ef9063 -r aacfaa24995d sys/dev/spi/spivar.h
--- a/sys/dev/spi/spivar.h      Tue Aug 13 13:22:16 2019 +0000
+++ b/sys/dev/spi/spivar.h      Tue Aug 13 16:37:15 2019 +0000
@@ -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 @@
 /* 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 @@
 #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 *);



Home | Main Index | Thread Index | Old Index