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 *);