Module Name: src
Committed By: hkenken
Date: Mon Aug 19 11:41:36 UTC 2019
Modified Files:
src/sys/arch/arm/imx: imx51_spi.c imx51reg.h imxspi.c imxspivar.h
src/sys/arch/arm/imx/fdt: files.imx6
src/sys/arch/evbarm/conf: IMX
src/sys/arch/evbarm/netwalker: netwalker_spi.c
Added Files:
src/sys/arch/arm/imx/fdt: imx6_spi.c
Log Message:
Add support SPI driver for i.MX6.
To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 src/sys/arch/arm/imx/imx51_spi.c \
src/sys/arch/arm/imx/imxspivar.h
cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/imx/imx51reg.h
cvs rdiff -u -r1.4 -r1.5 src/sys/arch/arm/imx/imxspi.c
cvs rdiff -u -r1.5 -r1.6 src/sys/arch/arm/imx/fdt/files.imx6
cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/imx/fdt/imx6_spi.c
cvs rdiff -u -r1.3 -r1.4 src/sys/arch/evbarm/conf/IMX
cvs rdiff -u -r1.2 -r1.3 src/sys/arch/evbarm/netwalker/netwalker_spi.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/arch/arm/imx/imx51_spi.c
diff -u src/sys/arch/arm/imx/imx51_spi.c:1.1 src/sys/arch/arm/imx/imx51_spi.c:1.2
--- src/sys/arch/arm/imx/imx51_spi.c:1.1 Sat Mar 22 09:28:08 2014
+++ src/sys/arch/arm/imx/imx51_spi.c Mon Aug 19 11:41:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: imx51_spi.c,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */
+/* $NetBSD: imx51_spi.c,v 1.2 2019/08/19 11:41:36 hkenken Exp $ */
/*-
* Copyright (c) 2014 Genetec Corporation. All rights reserved.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imx51_spi.c,v 1.1 2014/03/22 09:28:08 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imx51_spi.c,v 1.2 2019/08/19 11:41:36 hkenken Exp $");
#include "locators.h"
#include "opt_imx.h"
@@ -43,7 +43,8 @@ __KERNEL_RCSID(0, "$NetBSD: imx51_spi.c,
#include <arm/imx/imx51_ccmvar.h>
struct imx51spi_softc {
- struct imxspi_softc sc_spi;
+ struct imxspi_softc sc_spi; /* Must be first */
+
struct spi_chipset_tag sc_tag;
};
@@ -74,26 +75,39 @@ imxspi_match(device_t parent, cfdata_t c
void
imxspi_attach(device_t parent, device_t self, void *aux)
{
- struct imx51spi_softc *sc = device_private(self);
+ struct imx51spi_softc *isc = device_private(self);
+ struct imxspi_softc *sc = &isc->sc_spi;
struct axi_attach_args *aa = aux;
struct imxspi_attach_args saa;
int cf_flags = device_cfdata(self)->cf_flags;
+ bus_addr_t addr;
+ bus_size_t size;
+ int error;
+
+ addr = aa->aa_addr;
+ size = aa->aa_size;
+ if (size <= 0)
+ size = SPI_SIZE;
sc->sc_tag.cookie = sc;
sc->sc_tag.spi_cs_enable = imxspi_cs_enable;
sc->sc_tag.spi_cs_disable = imxspi_cs_disable;
- saa.saa_iot = aa->aa_iot;
- saa.saa_addr = aa->aa_addr;
- saa.saa_size = aa->aa_size;
- saa.saa_irq = aa->aa_irq;
- saa.saa_enhanced = cf_flags;
-
- saa.saa_nslaves = IMXSPINSLAVES;
- saa.saa_freq = imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT);
- saa.saa_tag = &sc->sc_tag;
+ sc->sc_iot = aa->aa_iot;
+ sc->sc_enhanced = cf_flags;
- sc->sc_spi.sc_dev = self;
+ sc->sc_nslaves = IMXSPINSLAVES;
+ sc->sc_freq = imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT);
+ sc->sc_tag = &sc->sc_tag;
+
+ if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
+ aprint_error_dev(sc->sc_dev, "couldn't map registers\n");
+ return;
+ }
+
+ /* enable device interrupts */
+ sc->sc_ih = intr_establish(aa->aa_irq, IPL_BIO, IST_LEVEL,
+ imxspi_intr, sc);
- imxspi_attach_common(parent, &sc->sc_spi, &saa);
+ imxspi_attach_common(self);
}
Index: src/sys/arch/arm/imx/imxspivar.h
diff -u src/sys/arch/arm/imx/imxspivar.h:1.1 src/sys/arch/arm/imx/imxspivar.h:1.2
--- src/sys/arch/arm/imx/imxspivar.h:1.1 Sat Mar 22 09:28:08 2014
+++ src/sys/arch/arm/imx/imxspivar.h Mon Aug 19 11:41:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: imxspivar.h,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */
+/* $NetBSD: imxspivar.h,v 1.2 2019/08/19 11:41:36 hkenken Exp $ */
/*
* Copyright (c) 2014 Genetec Corporation. All rights reserved.
@@ -38,21 +38,10 @@ typedef struct spi_chipset_tag {
int (*spi_cs_disable)(void *, int);
} *spi_chipset_tag_t;
-struct imxspi_attach_args {
- bus_space_tag_t saa_iot;
- bus_addr_t saa_addr;
- bus_size_t saa_size;
- int saa_irq;
-
- spi_chipset_tag_t saa_tag;
- int saa_nslaves;
- unsigned long saa_freq;
-
- int saa_enhanced;
-};
-
struct imxspi_softc {
device_t sc_dev;
+ int sc_phandle;
+
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
spi_chipset_tag_t sc_tag;
@@ -66,10 +55,12 @@ struct imxspi_softc {
bool sc_running;
SIMPLEQ_HEAD(,spi_transfer) sc_q;
+ int sc_nslaves;
int sc_enhanced;
};
-int imxspi_attach_common(device_t, struct imxspi_softc *, void *);
+int imxspi_attach_common(device_t);
+int imxspi_intr(void *);
/*
* defined in machine dependent code
Index: src/sys/arch/arm/imx/imx51reg.h
diff -u src/sys/arch/arm/imx/imx51reg.h:1.7 src/sys/arch/arm/imx/imx51reg.h:1.8
--- src/sys/arch/arm/imx/imx51reg.h:1.7 Thu May 7 04:37:29 2015
+++ src/sys/arch/arm/imx/imx51reg.h Mon Aug 19 11:41:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: imx51reg.h,v 1.7 2015/05/07 04:37:29 hkenken Exp $ */
+/* $NetBSD: imx51reg.h,v 1.8 2019/08/19 11:41:36 hkenken Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
@@ -140,7 +140,6 @@
#define ECSPI1_BASE (AIPSTZ1_BASE + 0x00010000)
#define ECSPI2_BASE (AIPSTZ2_BASE + 0x03fac000)
-#define ECSPI_SIZE 0x4000
#define SSI1_BASE (AIPSTZ2_BASE + 0x03fcc000)
#define SSI2_BASE (AIPSTZ1_BASE + 0x00014000)
Index: src/sys/arch/arm/imx/imxspi.c
diff -u src/sys/arch/arm/imx/imxspi.c:1.4 src/sys/arch/arm/imx/imxspi.c:1.5
--- src/sys/arch/arm/imx/imxspi.c:1.4 Tue Aug 13 17:03:10 2019
+++ src/sys/arch/arm/imx/imxspi.c Mon Aug 19 11:41:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: imxspi.c,v 1.4 2019/08/13 17:03:10 tnn Exp $ */
+/* $NetBSD: imxspi.c,v 1.5 2019/08/19 11:41:36 hkenken Exp $ */
/*-
* Copyright (c) 2014 Genetec Corporation. All rights reserved.
@@ -32,10 +32,11 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: imxspi.c,v 1.4 2019/08/13 17:03:10 tnn Exp $");
+__KERNEL_RCSID(0, "$NetBSD: imxspi.c,v 1.5 2019/08/19 11:41:36 hkenken Exp $");
#include "opt_imx.h"
#include "opt_imxspi.h"
+#include "opt_fdt.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -52,11 +53,14 @@ __KERNEL_RCSID(0, "$NetBSD: imxspi.c,v 1
#include <arm/imx/imxspivar.h>
#include <arm/imx/imxspireg.h>
+#ifdef FDT
+#include <dev/fdt/fdtvar.h>
+#endif
+
/* SPI service routines */
static int imxspi_configure_enhanced(void *, int, int, int);
static int imxspi_configure(void *, int, int, int);
static int imxspi_transfer(void *, struct spi_transfer *);
-static int imxspi_intr(void *);
/* internal stuff */
void imxspi_done(struct imxspi_softc *, int);
@@ -78,30 +82,30 @@ int imxspi_debug = IMXSPI_DEBUG;
#define DPRINTFN(n,x)
#endif
-int
-imxspi_attach_common(device_t parent, struct imxspi_softc *sc, void *aux)
+#ifdef FDT
+static struct spi_controller *
+imxspi_get_controller(device_t dev)
{
- struct imxspi_attach_args *saa = aux;
- struct spibus_attach_args sba;
- bus_addr_t addr = saa->saa_addr;
- bus_size_t size = saa->saa_size;
+ struct imxspi_softc * const sc = device_private(dev);
- sc->sc_iot = saa->saa_iot;
- sc->sc_freq = saa->saa_freq;
- sc->sc_tag = saa->saa_tag;
- sc->sc_enhanced = saa->saa_enhanced;
- if (size <= 0)
- size = SPI_SIZE;
-
- if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
- aprint_error_dev(sc->sc_dev, "couldn't map registers\n");
- return 1;
- }
+ return &sc->sc_spi;
+}
+
+static const struct fdtbus_spi_controller_func imxspi_funcs = {
+ .get_controller = imxspi_get_controller
+};
+#endif
+
+int
+imxspi_attach_common(device_t self)
+{
+ struct imxspi_softc * const sc = device_private(self);
- aprint_normal(": i.MX %sCSPI Controller (clock %ld Hz)\n",
+ aprint_normal("i.MX %sCSPI Controller (clock %ld Hz)\n",
((sc->sc_enhanced) ? "e" : ""), sc->sc_freq);
/* Initialize SPI controller */
+ sc->sc_dev = self;
sc->sc_spi.sct_cookie = sc;
if (sc->sc_enhanced)
sc->sc_spi.sct_configure = imxspi_configure_enhanced;
@@ -110,13 +114,10 @@ imxspi_attach_common(device_t parent, st
sc->sc_spi.sct_transfer = imxspi_transfer;
/* sc->sc_spi.sct_nslaves must have been initialized by machdep code */
- sc->sc_spi.sct_nslaves = saa->saa_nslaves;
+ sc->sc_spi.sct_nslaves = sc->sc_nslaves;
if (!sc->sc_spi.sct_nslaves)
aprint_error_dev(sc->sc_dev, "no slaves!\n");
- memset(&sba, 0, sizeof(sba));
- sba.sba_controller = &sc->sc_spi;
-
/* initialize the queue */
SIMPLEQ_INIT(&sc->sc_q);
@@ -132,12 +133,19 @@ imxspi_attach_common(device_t parent, st
WRITE_REG(sc, PERIODREG, 0x0);
- /* enable device interrupts */
- sc->sc_ih = intr_establish(saa->saa_irq, IPL_BIO, IST_LEVEL,
- imxspi_intr, sc);
+#ifdef FDT
+ KASSERT(sc->sc_phandle != 0);
+
+ fdtbus_register_spi_controller(self, sc->sc_phandle, &imxspi_funcs);
+ (void) fdtbus_attach_spibus(self, sc->sc_phandle, spibus_print);
+#else
+ struct spibus_attach_args sba;
+ memset(&sba, 0, sizeof(sba));
+ sba.sba_controller = &sc->sc_spi;
/* attach slave devices */
(void)config_found_ia(sc->sc_dev, "spibus", &sba, spibus_print);
+#endif
return 0;
}
@@ -363,7 +371,7 @@ imxspi_done(struct imxspi_softc *sc, int
imxspi_sched(sc);
}
-static int
+int
imxspi_intr(void *arg)
{
struct imxspi_softc *sc = arg;
Index: src/sys/arch/arm/imx/fdt/files.imx6
diff -u src/sys/arch/arm/imx/fdt/files.imx6:1.5 src/sys/arch/arm/imx/fdt/files.imx6:1.6
--- src/sys/arch/arm/imx/fdt/files.imx6:1.5 Mon Aug 12 11:45:53 2019
+++ src/sys/arch/arm/imx/fdt/files.imx6 Mon Aug 19 11:41:36 2019
@@ -1,4 +1,4 @@
-# $NetBSD: files.imx6,v 1.5 2019/08/12 11:45:53 skrll Exp $
+# $NetBSD: files.imx6,v 1.6 2019/08/19 11:41:36 hkenken Exp $
#
# Configuration info for the Freescale i.MX6
#
@@ -76,3 +76,11 @@ device imxi2c: motoi2c, i2cbus, i2cexec
attach imxi2c at fdt
file arch/arm/imx/imxi2c.c imxi2c
file arch/arm/imx/fdt/imx6_i2c.c imxi2c
+
+# SPI bus controlloer
+device imxspi : spibus
+attach imxspi at fdt with imxspi_fdt
+file arch/arm/imx/imxspi.c imxspi
+file arch/arm/imx/fdt/imx6_spi.c imxspi_fdt
+defparam opt_imxspi.h IMXSPINSLAVES
+
Index: src/sys/arch/evbarm/conf/IMX
diff -u src/sys/arch/evbarm/conf/IMX:1.3 src/sys/arch/evbarm/conf/IMX:1.4
--- src/sys/arch/evbarm/conf/IMX:1.3 Mon Aug 12 11:46:39 2019
+++ src/sys/arch/evbarm/conf/IMX Mon Aug 19 11:41:36 2019
@@ -1,5 +1,5 @@
#
-# $NetBSD: IMX,v 1.3 2019/08/12 11:46:39 skrll Exp $
+# $NetBSD: IMX,v 1.4 2019/08/19 11:41:36 hkenken Exp $
#
# NXP(Freescale) I.MX family SoCs
#
@@ -15,6 +15,7 @@ makeoptions DTS="
imx6dl-hummingboard.dts
imx6q-hummingboard2.dts
imx6dl-hummingboard2.dts
+ imx6qp-sabresd.dts
"
options MULTIPROCESSOR
@@ -136,5 +137,14 @@ pci* at ppb?
imxi2c* at fdt?
iic* at imxi2c?
+# SPI
+imxspi* at fdt?
+spi* at imxspi?
+options IMXSPINSLAVES=1
+
+# SPI NOR-Flash
+spiflash* at spiflashbus?
+m25p* at spi? slave ?
+
cinclude "arch/evbarm/conf/IMX.local"
Index: src/sys/arch/evbarm/netwalker/netwalker_spi.c
diff -u src/sys/arch/evbarm/netwalker/netwalker_spi.c:1.2 src/sys/arch/evbarm/netwalker/netwalker_spi.c:1.3
--- src/sys/arch/evbarm/netwalker/netwalker_spi.c:1.2 Wed Jul 24 12:33:18 2019
+++ src/sys/arch/evbarm/netwalker/netwalker_spi.c Mon Aug 19 11:41:36 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: netwalker_spi.c,v 1.2 2019/07/24 12:33:18 hkenken Exp $ */
+/* $NetBSD: netwalker_spi.c,v 1.3 2019/08/19 11:41:36 hkenken Exp $ */
/*-
* Copyright (c) 2009 Genetec Corporation. All rights reserved.
@@ -27,7 +27,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: netwalker_spi.c,v 1.2 2019/07/24 12:33:18 hkenken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: netwalker_spi.c,v 1.3 2019/08/19 11:41:36 hkenken Exp $");
#include "opt_imxspi.h"
@@ -45,9 +45,11 @@ __KERNEL_RCSID(0, "$NetBSD: netwalker_sp
#include <arm/imx/imx51_iomuxreg.h>
#include <arm/imx/imxgpiovar.h>
#include <arm/imx/imxspivar.h>
+#include <arm/imx/imxspireg.h>
struct imx51spi_softc {
- struct imxspi_softc sc_spi;
+ struct imxspi_softc sc_spi; /* Must be first */
+
struct spi_chipset_tag sc_tag;
};
@@ -110,14 +112,22 @@ imxspi_match(device_t parent, cfdata_t c
void
imxspi_attach(device_t parent, device_t self, void *aux)
{
- struct imx51spi_softc *sc = device_private(self);
+ struct imx51spi_softc *isc = device_private(self);
+ struct imxspi_softc *sc = &isc->sc_spi;
struct axi_attach_args *aa = aux;
- struct imxspi_attach_args saa;
int cf_flags = device_cfdata(self)->cf_flags;
+ bus_addr_t addr;
+ bus_size_t size;
+
+ addr = aa->aa_addr;
+ size = aa->aa_size;
+ if (size <= 0)
+ size = SPI_SIZE;
- sc->sc_tag.cookie = sc;
+ isc->sc_tag.cookie = sc;
- if (device_cfdata(self)->cf_unit == 0) {
+ switch (device_unit(self)) {
+ case 0:
/* CS 0 GPIO setting */
gpio_data_write(GPIO_NO(4, 24), GPIO_PIN_HIGH);
gpio_set_direction(GPIO_NO(4, 24), GPIO_PIN_INPUT);
@@ -135,21 +145,26 @@ imxspi_attach(device_t parent, device_t
gpio_data_write(GPIO_NO(3, 0), GPIO_PIN_HIGH);
gpio_set_direction(GPIO_NO(3, 0), GPIO_PIN_INPUT);
- sc->sc_tag.spi_cs_enable = imxspi_cs_enable;
- sc->sc_tag.spi_cs_disable = imxspi_cs_disable;
+ isc->sc_tag.spi_cs_enable = imxspi_cs_enable;
+ isc->sc_tag.spi_cs_disable = imxspi_cs_disable;
+ break;
}
- saa.saa_iot = aa->aa_iot;
- saa.saa_addr = aa->aa_addr;
- saa.saa_size = aa->aa_size;
- saa.saa_irq = aa->aa_irq;
- saa.saa_enhanced = cf_flags;
-
- saa.saa_nslaves = IMXSPINSLAVES;
- saa.saa_freq = imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT);
- saa.saa_tag = &sc->sc_tag;
+ sc->sc_iot = aa->aa_iot;
+ sc->sc_enhanced = cf_flags;
+
+ sc->sc_nslaves = IMXSPINSLAVES;
+ sc->sc_freq = imx51_get_clock(IMX51CLK_CSPI_CLK_ROOT);
+ sc->sc_tag = &isc->sc_tag;
+
+ if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
+ aprint_error_dev(sc->sc_dev, "couldn't map registers\n");
+ return;
+ }
- sc->sc_spi.sc_dev = self;
+ /* enable device interrupts */
+ sc->sc_ih = intr_establish(aa->aa_irq, IPL_BIO, IST_LEVEL,
+ imxspi_intr, sc);
- imxspi_attach_common(parent, &sc->sc_spi, &saa);
+ imxspi_attach_common(self);
}
Added files:
Index: src/sys/arch/arm/imx/fdt/imx6_spi.c
diff -u /dev/null src/sys/arch/arm/imx/fdt/imx6_spi.c:1.1
--- /dev/null Mon Aug 19 11:41:36 2019
+++ src/sys/arch/arm/imx/fdt/imx6_spi.c Mon Aug 19 11:41:36 2019
@@ -0,0 +1,156 @@
+/* $NetBSD: imx6_spi.c,v 1.1 2019/08/19 11:41:36 hkenken Exp $ */
+/*-
+ * Copyright (c) 2019 Genetec Corporation. All rights reserved.
+ * Written by Hashimoto Kenichi for Genetec Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: imx6_spi.c,v 1.1 2019/08/19 11:41:36 hkenken Exp $");
+
+#include "opt_imxspi.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/device.h>
+#include <sys/kmem.h>
+#include <sys/gpio.h>
+
+#include <arm/imx/imxspivar.h>
+
+#include <dev/fdt/fdtvar.h>
+
+struct imxspi_fdt_softc {
+ struct imxspi_softc sc_imxspi; /* Must be first */
+
+ struct spi_chipset_tag sc_tag;
+ struct clk *sc_clk;
+
+ struct fdtbus_gpio_pin **sc_pin_cs;
+};
+
+static const struct of_compat_data compat_data[] = {
+ { "fsl,imx6q-ecspi", true },
+ { NULL }
+};
+
+CFATTACH_DECL_NEW(imxspi_fdt, sizeof(struct imxspi_fdt_softc),
+ imxspi_match, imxspi_attach, NULL, NULL);
+
+static int
+imxspi_cs_enable(void *arg, int slave)
+{
+ struct imxspi_fdt_softc * const sc = arg;
+ fdtbus_gpio_write(sc->sc_pin_cs[slave], 1);
+ return 0;
+}
+
+static int
+imxspi_cs_disable(void *arg, int slave)
+{
+ struct imxspi_fdt_softc * const sc = arg;
+ fdtbus_gpio_write(sc->sc_pin_cs[slave], 0);
+ return 0;
+}
+
+int
+imxspi_match(device_t parent, cfdata_t cf, void *aux)
+{
+ struct fdt_attach_args * const faa = aux;
+
+ return of_match_compat_data(faa->faa_phandle, compat_data);
+}
+
+void
+imxspi_attach(device_t parent, device_t self, void *aux)
+{
+ struct imxspi_fdt_softc * const ifsc = device_private(self);
+ struct imxspi_softc * const sc = &ifsc->sc_imxspi;
+ struct fdt_attach_args * const faa = aux;
+ char intrstr[128];
+ const int phandle = faa->faa_phandle;
+ bus_addr_t addr;
+ bus_size_t size;
+ int error;
+
+ u_int nslaves;
+ error = of_getprop_uint32(phandle, "fsl,spi-num-chipselects", &nslaves);
+ if (error)
+ nslaves = IMXSPINSLAVES;
+
+ ifsc->sc_pin_cs = kmem_alloc(sizeof(struct fdtbus_gpio_pin *) * nslaves, KM_SLEEP);
+
+ for (int i = 0; i < nslaves; i++) {
+ ifsc->sc_pin_cs[i] = fdtbus_gpio_acquire_index(phandle, "cs-gpios", i,
+ GPIO_PIN_OUTPUT);
+ }
+
+ ifsc->sc_clk = fdtbus_clock_get_index(phandle, 0);
+ if (ifsc->sc_clk == NULL) {
+ aprint_error(": couldn't get clock\n");
+ return;
+ }
+
+ error = clk_enable(ifsc->sc_clk);
+ if (error) {
+ aprint_error_dev(sc->sc_dev, "couldn't enable: %d\n", error);
+ return;
+ }
+
+ ifsc->sc_tag.cookie = ifsc;
+ ifsc->sc_tag.spi_cs_enable = imxspi_cs_enable;
+ ifsc->sc_tag.spi_cs_disable = imxspi_cs_disable;
+
+ sc->sc_phandle = phandle;
+ sc->sc_iot = faa->faa_bst;
+ sc->sc_enhanced = of_search_compatible(phandle, compat_data)->data;
+
+ sc->sc_nslaves = nslaves;
+ sc->sc_freq = clk_get_rate(ifsc->sc_clk);
+ sc->sc_tag = &ifsc->sc_tag;
+
+ if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) {
+ aprint_error(": couldn't get iomux registers\n");
+ return;
+ }
+
+ if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh)) {
+ aprint_error_dev(sc->sc_dev, "couldn't map registers\n");
+ return;
+ }
+
+ if (!fdtbus_intr_str(faa->faa_phandle, 0, intrstr, sizeof(intrstr))) {
+ aprint_error_dev(self, "failed to decode interrupt\n");
+ return;
+ }
+
+ sc->sc_ih = fdtbus_intr_establish(phandle, 0, IPL_VM,
+ FDT_INTR_MPSAFE, imxspi_intr, &ifsc->sc_imxspi);
+ if (sc->sc_ih == NULL) {
+ aprint_error_dev(self, "couldn't establish interrupt on %s\n",
+ intrstr);
+ return;
+ }
+ aprint_normal_dev(self, "interrupting on %s\n", intrstr);
+
+ imxspi_attach_common(self);
+}