Module Name: src Committed By: hkenken Date: Sat Mar 22 09:28:08 UTC 2014
Modified Files: src/sys/arch/arm/imx: files.imx51 imx51_ccm.c imx51_ccmreg.h Added Files: src/sys/arch/arm/imx: imx51_spi.c imxcspireg.h imxecspireg.h imxspi.c imxspireg.h imxspivar.h Log Message: Add SPI driver. i.MX51 have two eCSPI, and one CSPI. To generate a diff of this commit: cvs rdiff -u -r1.7 -r1.8 src/sys/arch/arm/imx/files.imx51 cvs rdiff -u -r1.3 -r1.4 src/sys/arch/arm/imx/imx51_ccm.c cvs rdiff -u -r1.2 -r1.3 src/sys/arch/arm/imx/imx51_ccmreg.h cvs rdiff -u -r0 -r1.1 src/sys/arch/arm/imx/imx51_spi.c \ src/sys/arch/arm/imx/imxcspireg.h src/sys/arch/arm/imx/imxecspireg.h \ src/sys/arch/arm/imx/imxspi.c src/sys/arch/arm/imx/imxspireg.h \ src/sys/arch/arm/imx/imxspivar.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/arch/arm/imx/files.imx51 diff -u src/sys/arch/arm/imx/files.imx51:1.7 src/sys/arch/arm/imx/files.imx51:1.8 --- src/sys/arch/arm/imx/files.imx51:1.7 Sat Mar 22 05:19:18 2014 +++ src/sys/arch/arm/imx/files.imx51 Sat Mar 22 09:28:08 2014 @@ -1,4 +1,4 @@ -# $NetBSD: files.imx51,v 1.7 2014/03/22 05:19:18 hkenken Exp $ +# $NetBSD: files.imx51,v 1.8 2014/03/22 09:28:08 hkenken Exp $ # # Configuration info for the Freescale i.MX51 # @@ -104,9 +104,15 @@ file arch/arm/imx/imx51_esdhc.c sdhc_ax # attach imxi2c at aips with imxi2c_aips # file arch/arm/imx/imxi2c_aips.c imxi2c_aips -# spi bus controlloer -# device imxspi: spibus -# file arch/arm/imx/imx51_spi.c imxspi +# SPI bus controlloer +# attach of this driver need to be specified in paltform configuration +# use flags to module version +device imxspi : spibus +file arch/arm/imx/imxspi.c imxspi +defparam opt_imxspi.h IMXSPINSLAVES +defparam opt_imxspi.h IMXSPI_DEBUG +# attach imxspi at axi with imx51_spi +# file arch/arm/imx/imx51_spi.c imx51_spi # Smart Direct Memory Access Controller # device imxsdma: dmover_service, bus_dma_generic Index: src/sys/arch/arm/imx/imx51_ccm.c diff -u src/sys/arch/arm/imx/imx51_ccm.c:1.3 src/sys/arch/arm/imx/imx51_ccm.c:1.4 --- src/sys/arch/arm/imx/imx51_ccm.c:1.3 Wed Sep 19 07:28:38 2012 +++ src/sys/arch/arm/imx/imx51_ccm.c Sat Mar 22 09:28:08 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: imx51_ccm.c,v 1.3 2012/09/19 07:28:38 bsh Exp $ */ +/* $NetBSD: imx51_ccm.c,v 1.4 2014/03/22 09:28:08 hkenken Exp $ */ /* * Copyright (c) 2010, 2011, 2012 Genetec Corporation. All rights reserved. * Written by Hashimoto Kenichi for Genetec Corporation. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: imx51_ccm.c,v 1.3 2012/09/19 07:28:38 bsh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: imx51_ccm.c,v 1.4 2014/03/22 09:28:08 hkenken Exp $"); #include <sys/types.h> #include <sys/time.h> @@ -146,6 +146,7 @@ imx51_get_clock(enum imx51_clock clk) uint32_t cacrr; /* ARM clock root register */ uint32_t ccsr; uint32_t cscdr1; + uint32_t cscdr2; uint32_t cscmr1; uint32_t cbcdr; uint32_t cbcmr; @@ -293,6 +294,26 @@ imx51_get_clock(enum imx51_clock clk) break; } return freq; + case IMX51CLK_CSPI_CLK_ROOT: + cscmr1 = bus_space_read_4(iot, ioh, CCMC_CSCMR1); + cscdr2 = bus_space_read_4(iot, ioh, CCMC_CSCDR2); + + sel = __SHIFTOUT(cscmr1, CSCMR1_CSPI_CLK_SEL); + switch (sel) { + case 0: + case 1: + case 2: + freq = imx51_get_clock(IMX51CLK_PLL1SW + sel); + break; + case 3: + freq = imx51_get_clock(IMX51CLK_LP_APM); + break; + } + + freq = freq / (1 + __SHIFTOUT(cscdr2, CSCDR2_ECSPI_CLK_PRED)) / + (1 + __SHIFTOUT(cscdr2, CSCDR2_ECSPI_CLK_PODF)); + + return freq; default: aprint_error_dev(ccm_softc->sc_dev, "clock %d: not supported yet\n", clk); Index: src/sys/arch/arm/imx/imx51_ccmreg.h diff -u src/sys/arch/arm/imx/imx51_ccmreg.h:1.2 src/sys/arch/arm/imx/imx51_ccmreg.h:1.3 --- src/sys/arch/arm/imx/imx51_ccmreg.h:1.2 Sat Sep 1 00:07:32 2012 +++ src/sys/arch/arm/imx/imx51_ccmreg.h Sat Mar 22 09:28:08 2014 @@ -1,4 +1,4 @@ -/* $NetBSD: imx51_ccmreg.h,v 1.2 2012/09/01 00:07:32 matt Exp $ */ +/* $NetBSD: imx51_ccmreg.h,v 1.3 2014/03/22 09:28:08 hkenken Exp $ */ /* * Copyright (c) 2011, 2012 Genetec Corporation. All rights reserved. * Written by Hashimoto Kenichi for Genetec Corporation. @@ -85,6 +85,7 @@ #define CCMC_CSCMR1 0x001c #define CSCMR1_UART_CLK_SEL_SHIFT 24 #define CSCMR1_UART_CLK_SEL_MASK __BITS(25, CSCMR1_UART_CLK_SEL_SHIFT) +#define CSCMR1_CSPI_CLK_SEL __BITS(5, 4) #define CCMC_CSCMR2 0x0020 #define CCMC_CSCDR1 0x0024 #define CSCDR1_UART_CLK_PRED_SHIFT 3 @@ -96,6 +97,8 @@ #define CCMC_CDCDR 0x0030 #define CCMC_CHSCCDR 0x0034 // i.MX6 #define CCMC_CSCDR2 0x0038 +#define CSCDR2_ECSPI_CLK_PRED __BITS(27, 25) +#define CSCDR2_ECSPI_CLK_PODF __BITS(24, 19) #define CCMC_CSCDR3 0x003c #define CCMC_CSCDR4 0x0040 #define CCMC_CWDR 0x0044 Added files: Index: src/sys/arch/arm/imx/imx51_spi.c diff -u /dev/null src/sys/arch/arm/imx/imx51_spi.c:1.1 --- /dev/null Sat Mar 22 09:28:08 2014 +++ src/sys/arch/arm/imx/imx51_spi.c Sat Mar 22 09:28:08 2014 @@ -0,0 +1,99 @@ +/* $NetBSD: imx51_spi.c,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */ + +/*- + * Copyright (c) 2014 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 REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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: imx51_spi.c,v 1.1 2014/03/22 09:28:08 hkenken Exp $"); + +#include "locators.h" +#include "opt_imx.h" +#include "opt_imxspi.h" + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/device.h> + +#include <arm/imx/imxspivar.h> +#include <arm/imx/imx51reg.h> +#include <arm/imx/imx51var.h> +#include <arm/imx/imx51_ccmvar.h> + +struct imx51spi_softc { + struct imxspi_softc sc_spi; + struct spi_chipset_tag sc_tag; +}; + +CFATTACH_DECL_NEW(imx51_spi, sizeof(struct imx51spi_softc), + imxspi_match, imxspi_attach, NULL, NULL); + +static int +imxspi_cs_enable(void *arg, int slave) +{ + return 0; +} + +static int +imxspi_cs_disable(void *arg, int slave) +{ + return 0; +} + +int +imxspi_match(device_t parent, cfdata_t cf, void *aux) +{ + if (strcmp(cf->cf_name, "imxspi") == 0) + return 1; + + return 0; +} + +void +imxspi_attach(device_t parent, device_t self, void *aux) +{ + struct imx51spi_softc *sc = device_private(self); + struct axi_attach_args *aa = aux; + struct imxspi_attach_args saa; + int cf_flags = device_cfdata(self)->cf_flags; + + 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_spi.sc_dev = self; + + imxspi_attach_common(parent, &sc->sc_spi, &saa); +} Index: src/sys/arch/arm/imx/imxcspireg.h diff -u /dev/null src/sys/arch/arm/imx/imxcspireg.h:1.1 --- /dev/null Sat Mar 22 09:28:08 2014 +++ src/sys/arch/arm/imx/imxcspireg.h Sat Mar 22 09:28:08 2014 @@ -0,0 +1,93 @@ +/* $NetBSD: imxcspireg.h,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */ + +/* + * Copyright (c) 2014 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 GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + */ + +#ifndef _ARM_IMX_IMXCSPIREG_H_ +#define _ARM_IMX_IMXCSPIREG_H_ + +#define CSPI_RXDATA 0x00 +#define CSPI_TXDATA 0x04 +#define CSPI_CONREG 0x08 +#ifdef IMX51 +#define CSPI_CON_CS __BITS(13, 12) +#define CSPI_CON_DRCTL __BITS( 9, 8) +#define CSPI_CON_BITCOUNT __BITS(31, 20) +#else +#define CSPI_CON_CS __BITS(25, 24) +#define CSPI_CON_DRCTL __BITS(21, 20) +#define CSPI_CON_BITCOUNT __BITS(12, 8) +#endif +#define CSPI_CON_DIV __BITS(18, 16) +#define CSPI_CON_SSPOL __BIT(7) /* SPI SS Polarity Select */ +#define CSPI_CON_SSCTL __BIT(6) /* In master mode, this bit + * selects the output wave form + * for the SS signal. + */ +#define CSPI_CON_PHA __BIT(5) /* PHA */ +#define CSPI_CON_POL __BIT(4) /* POL */ +#define CSPI_CON_SMC __BIT(3) /* SMC */ +#define CSPI_CON_XCH __BIT(2) /* XCH */ +#define CSPI_CON_MODE __BIT(1) /* MODE */ +#define CSPI_CON_ENABLE __BIT(0) /* EN */ +#define CSPI_INTREG 0x0c +#define CSPI_INTR_ALL_EN 0x000001ff /* All Intarruption Enabled */ +#ifdef IMX51 +#define CSPI_INTR_TC_EN __BIT(7) /* TX Complete */ +#else +#define CSPI_INTR_TC_EN __BIT(8) /* TX Complete */ +#define CSPI_INTR_BO_EN __BIT(7) /* Bit Counter Overflow */ +#endif +#define CSPI_INTR_RO_EN __BIT(6) /* RXFIFO Overflow */ +#define CSPI_INTR_RF_EN __BIT(5) /* RXFIFO Full */ +#define CSPI_INTR_RH_EN __BIT(4) /* RXFIFO Half Full */ +#define CSPI_INTR_RR_EN __BIT(3) /* RXFIFO Ready */ +#define CSPI_INTR_TF_EN __BIT(2) /* TXFIFO Full */ +#define CSPI_INTR_TH_EN __BIT(1) /* TXFIFO Half Empty */ +#define CSPI_INTR_TE_EN __BIT(0) /* TXFIFO Empty */ +#define CSPI_DMAREG 0x10 +#define CSPI_STATREG 0x14 +#ifdef IMX51 +#define CSPI_STAT_CLR_TC __BIT(7) /* Clear TC of status register */ +#define CSPI_STAT_CLR CSPI_STAT_CLR_TC +#else +#define CSPI_STAT_CLR_TC __BIT(8) /* Clear TC of status register */ +#define CSPI_STAT_CLR_BO __BIT(7) /* Clear BO of status register */ +#define CSPI_STAT_CLR (CSPI_STAT_CLR_TC | CSPI_STAT_CLR_BO) +#endif +#define CSPI_STAT_RO __BIT(6) /* RXFIFO Overflow */ +#define CSPI_STAT_RF __BIT(5) /* RXFIFO Full */ +#define CSPI_STAT_RH __BIT(4) /* RXFIFO Half Full */ +#define CSPI_STAT_RR __BIT(3) /* RXFIFO Ready */ +#define CSPI_STAT_TF __BIT(2) /* TXFIFO Full */ +#define CSPI_STAT_TH __BIT(1) /* TXFIFO Half Empty */ +#define CSPI_STAT_TE __BIT(0) /* TXFIFO Empty */ +#define CSPI_PERIODREG 0x18 +#define CSPI_TESTREG 0x1c + +#define SPI_SIZE 0x100 + +#endif /* _ARM_IMX_IMXCSPIREG_H_ */ Index: src/sys/arch/arm/imx/imxecspireg.h diff -u /dev/null src/sys/arch/arm/imx/imxecspireg.h:1.1 --- /dev/null Sat Mar 22 09:28:08 2014 +++ src/sys/arch/arm/imx/imxecspireg.h Sat Mar 22 09:28:08 2014 @@ -0,0 +1,80 @@ +/* $NetBSD: imxecspireg.h,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */ + +/* + * Copyright (c) 2012 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 GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + */ + +#ifndef _ARM_IMX_IMXECSPIREG_H_ +#define _ARM_IMX_IMXECSPIREG_H_ + +#define ECSPI_RXDATA 0x00 +#define ECSPI_TXDATA 0x04 +#define ECSPI_CONREG 0x08 +#define ECSPI_CON_BITCOUNT __BITS(31, 20) +#define ECSPI_CON_CS __BITS(19,18) +#define ECSPI_CON_DRCTL __BITS(17,16) +#define ECSPI_CON_PREDIV __BITS(15,12) /* PRE DIVIDER */ +#define ECSPI_CON_DIV __BITS(11, 8) /* POST DIVIDER */ +#define ECSPI_CON_MODE __BITS( 7, 4) /* MODE */ +#define ECSPI_CON_SMC __BIT(3) /* SMC */ +#define ECSPI_CON_XCH __BIT(2) /* XCH */ +#define ECSPI_CON_HW __BIT(1) /* HW */ +#define ECSPI_CON_ENABLE __BIT(0) /* EN */ +#define ECSPI_CONFIGREG 0x0c +#define ECSPI_CONFIG_HT_LEN __BITS(28,24) /* HT LENGHT */ +#define ECSPI_CONFIG_SCLK_CTL __BITS(23,20) /* SCLK CTL */ +#define ECSPI_CONFIG_DATA_CTL __BITS(19,16) /* DATA CTL */ +#define ECSPI_CONFIG_SSB_POL __BITS(15,12) /* SSB POL */ +#define ECSPI_CONFIG_SSB_CTL __BITS(11, 8) /* SSB CTL */ +#define ECSPI_CONFIG_SCLK_POL __BITS( 7, 4) /* SCLK POL */ +#define ECSPI_CONFIG_SCLK_PHA __BITS( 3, 0) /* SCLK PHA */ +#define ECSPI_INTREG 0x10 +#define ECSPI_INTR_ALL_EN __BITS( 7, 0) /* All Intarruption Enabled */ +#define ECSPI_INTR_TC_EN __BIT(7) /* TX Complete */ +#define ECSPI_INTR_RO_EN __BIT(6) /* RXFIFO Overflow */ +#define ECSPI_INTR_RF_EN __BIT(5) /* RXFIFO Full */ +#define ECSPI_INTR_RD_EN __BIT(4) /* RXFIFO Data Request */ +#define ECSPI_INTR_RR_EN __BIT(3) /* RXFIFO Ready */ +#define ECSPI_INTR_TF_EN __BIT(2) /* TXFIFO Full */ +#define ECSPI_INTR_TD_EN __BIT(1) /* TXFIFO Data Request */ +#define ECSPI_INTR_TE_EN __BIT(0) /* TXFIFO Empty */ +#define ECSPI_DMAREG 0x14 +#define ECSPI_STATREG 0x18 +#define ECSPI_STAT_CLR_TC __BIT(7) /* Clear Transfer Completed */ +#define ECSPI_STAT_CLR_RO __BIT(6) /* Clear RXFIFO Overflow */ +#define ECSPI_STAT_CLR ECSPI_STAT_CLR_TC +#define ECSPI_STAT_RF __BIT(5) +#define ECSPI_STAT_RDR __BIT(4) +#define ECSPI_STAT_RR __BIT(3) +#define ECSPI_STAT_TF __BIT(2) +#define ECSPI_STAT_TDR __BIT(1) +#define ECSPI_STAT_TE __BIT(0) +#define ECSPI_PERIODREG 0x1c +#define ECSPI_TESTREG 0x20 +#define ECSPI_MSGDATA 0x40 + +#define ECSPI_SIZE 0x50 + +#endif /* _ARM_IMX_IMXECSPIREG_H_ */ Index: src/sys/arch/arm/imx/imxspi.c diff -u /dev/null src/sys/arch/arm/imx/imxspi.c:1.1 --- /dev/null Sat Mar 22 09:28:08 2014 +++ src/sys/arch/arm/imx/imxspi.c Sat Mar 22 09:28:08 2014 @@ -0,0 +1,419 @@ +/* $NetBSD: imxspi.c,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */ + +/*- + * Copyright (c) 2014 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 GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + */ + +/* + * this module support CSPI and eCSPI. + * i.MX51 have 2 eCSPI and 1 CSPI modules. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: imxspi.c,v 1.1 2014/03/22 09:28:08 hkenken Exp $"); + +#include "opt_imx.h" +#include "opt_imxspi.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/errno.h> +#include <sys/proc.h> +#include <sys/intr.h> + +#include <sys/bus.h> +#include <machine/cpu.h> +#include <machine/intr.h> + +#include <arm/imx/imxspivar.h> +#include <arm/imx/imxspireg.h> + +/* 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); +void imxspi_send(struct imxspi_softc *); +void imxspi_recv(struct imxspi_softc *); +void imxspi_sched(struct imxspi_softc *); + +#define IMXSPI(x) \ + ((sc->sc_enhanced) ? __CONCAT(ECSPI_, x) : __CONCAT(CSPI_, x)) +#define READ_REG(sc, x) \ + bus_space_read_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x)) +#define WRITE_REG(sc, x, v) \ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, IMXSPI(x), (v)) + +#ifdef IMXSPI_DEBUG +int imxspi_debug = IMXSPI_DEBUG; +#define DPRINTFN(n,x) if (imxspi_debug>(n)) printf x; +#else +#define DPRINTFN(n,x) +#endif + +int +imxspi_attach_common(device_t parent, struct imxspi_softc *sc, void *aux) +{ + 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; + + 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; + } + + aprint_normal(": i.MX %sCSPI Controller (clock %ld Hz)\n", + ((sc->sc_enhanced) ? "e" : ""), sc->sc_freq); + + /* Initialize SPI controller */ + sc->sc_spi.sct_cookie = sc; + if (sc->sc_enhanced) + sc->sc_spi.sct_configure = imxspi_configure_enhanced; + else + sc->sc_spi.sct_configure = imxspi_configure; + 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; + if (!sc->sc_spi.sct_nslaves) + aprint_error_dev(sc->sc_dev, "no slaves!\n"); + + sba.sba_controller = &sc->sc_spi; + + /* initialize the queue */ + SIMPLEQ_INIT(&sc->sc_q); + + /* configure SPI */ + /* Setup Control Register */ + WRITE_REG(sc, CONREG, __SHIFTIN(0, IMXSPI(CON_DRCTL)) | + __SHIFTIN(8 - 1, IMXSPI(CON_BITCOUNT)) | + __SHIFTIN(0xf, IMXSPI(CON_MODE)) | IMXSPI(CON_ENABLE)); + + /* TC and RR interruption */ + WRITE_REG(sc, INTREG, (IMXSPI(INTR_TC_EN) | IMXSPI(INTR_RR_EN))); + WRITE_REG(sc, STATREG, IMXSPI(STAT_CLR)); + + WRITE_REG(sc, PERIODREG, 0x0); + + /* enable device interrupts */ + sc->sc_ih = intr_establish(saa->saa_irq, IPL_BIO, IST_LEVEL, + imxspi_intr, sc); + + /* attach slave devices */ + (void)config_found_ia(sc->sc_dev, "spibus", &sba, spibus_print); + + return 0; +} + +static int +imxspi_configure(void *arg, int slave, int mode, int speed) +{ + struct imxspi_softc *sc = arg; + uint32_t div_cnt = 0; + uint32_t div; + uint32_t contrl = 0; + + div = (sc->sc_freq + (speed - 1)) / speed; + div = div - 1; + for (div_cnt = 0; div > 0; div_cnt++) + div >>= 1; + + div_cnt = div_cnt - 2; + if (div_cnt >= 7) + div_cnt = 7; + + contrl = READ_REG(sc, CONREG); + contrl &= ~CSPI_CON_DIV; + contrl |= __SHIFTIN(div_cnt, CSPI_CON_DIV); + + contrl &= ~(CSPI_CON_POL | CSPI_CON_PHA); + switch (mode) { + case SPI_MODE_0: + /* CPHA = 0, CPOL = 0 */ + break; + case SPI_MODE_1: + /* CPHA = 1, CPOL = 0 */ + contrl |= CSPI_CON_PHA; + break; + case SPI_MODE_2: + /* CPHA = 0, CPOL = 1 */ + contrl |= CSPI_CON_POL; + break; + case SPI_MODE_3: + /* CPHA = 1, CPOL = 1 */ + contrl |= CSPI_CON_POL; + contrl |= CSPI_CON_PHA; + break; + default: + return EINVAL; + } + WRITE_REG(sc, CONREG, contrl); + + DPRINTFN(3, ("%s: slave %d mode %d speed %d\n", + __func__, slave, mode, speed)); + + return 0; +} + +static int +imxspi_configure_enhanced(void *arg, int slave, int mode, int speed) +{ + struct imxspi_softc *sc = arg; + uint32_t div_cnt = 0; + uint32_t div; + uint32_t contrl = 0; + uint32_t config = 0; + + div = (sc->sc_freq + (speed - 1)) / speed; + for (div_cnt = 0; div > 0; div_cnt++) + div >>= 1; + + if (div_cnt >= 15) + div_cnt = 15; + + contrl = READ_REG(sc, CONREG); + contrl |= __SHIFTIN(div_cnt, ECSPI_CON_DIV); + contrl |= __SHIFTIN(slave, ECSPI_CON_CS); + contrl |= __SHIFTIN(__BIT(slave), ECSPI_CON_MODE); + WRITE_REG(sc, CONREG, contrl); + + config = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG); + config &= ~(__SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL) | + __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA)); + switch (mode) { + case SPI_MODE_0: + /* CPHA = 0, CPOL = 0 */ + break; + case SPI_MODE_1: + /* CPHA = 1, CPOL = 0 */ + config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA); + break; + case SPI_MODE_2: + /* CPHA = 0, CPOL = 1 */ + config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL); + break; + case SPI_MODE_3: + /* CPHA = 1, CPOL = 1 */ + config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_PHA); + config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SCLK_POL); + break; + default: + return EINVAL; + } + config |= __SHIFTIN(__BIT(slave), ECSPI_CONFIG_SSB_CTL); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, ECSPI_CONFIGREG, config); + + DPRINTFN(3, ("%s: slave %d mode %d speed %d\n", + __func__, slave, mode, speed)); + + return 0; +} + +void +imxspi_send(struct imxspi_softc *sc) +{ + uint32_t data; + struct spi_chunk *chunk; + + /* fill the fifo */ + while ((chunk = sc->sc_wchunk) != NULL) { + while (chunk->chunk_wresid) { + /* transmit fifo full? */ + if (READ_REG(sc, STATREG) & IMXSPI(STAT_TF)) + return; + + if (chunk->chunk_wptr) { + data = *chunk->chunk_wptr; + chunk->chunk_wptr++; + } else { + data = 0xff; + } + chunk->chunk_wresid--; + + WRITE_REG(sc, TXDATA, data); + } + /* advance to next transfer */ + sc->sc_wchunk = sc->sc_wchunk->chunk_next; + } + + if (!(READ_REG(sc, STATREG) & IMXSPI(INTR_TE_EN))) + WRITE_REG(sc, CONREG, READ_REG(sc, CONREG) | IMXSPI(CON_XCH)); +} + +void +imxspi_recv(struct imxspi_softc *sc) +{ + uint32_t data; + struct spi_chunk *chunk; + + while ((chunk = sc->sc_rchunk) != NULL) { + while (chunk->chunk_rresid) { + /* rx fifo empty? */ + if ((!(READ_REG(sc, STATREG) & IMXSPI(STAT_RR)))) + return; + + /* collect rx data */ + data = READ_REG(sc, RXDATA); + if (chunk->chunk_rptr) { + *chunk->chunk_rptr = data & 0xff; + chunk->chunk_rptr++; + } + + chunk->chunk_rresid--; + } + /* advance next to next transfer */ + sc->sc_rchunk = sc->sc_rchunk->chunk_next; + } +} + + +void +imxspi_sched(struct imxspi_softc *sc) +{ + struct spi_transfer *st; + uint32_t chipselect; + + while ((st = spi_transq_first(&sc->sc_q)) != NULL) { + /* remove the item */ + spi_transq_dequeue(&sc->sc_q); + + /* note that we are working on it */ + sc->sc_transfer = st; + + /* chip slect */ + if (sc->sc_tag->spi_cs_enable != NULL) + sc->sc_tag->spi_cs_enable(sc->sc_tag->cookie, + st->st_slave); + + /*chip slect*/ + chipselect = READ_REG(sc, CONREG); + chipselect &= ~IMXSPI(CON_CS); + chipselect |= __SHIFTIN(st->st_slave, IMXSPI(CON_CS)); + WRITE_REG(sc, CONREG, chipselect); + + delay(1); + + /* setup chunks */ + sc->sc_rchunk = sc->sc_wchunk = st->st_chunks; + + /* now kick the master start to get the chip running */ + imxspi_send(sc); + + sc->sc_running = TRUE; + return; + } + + DPRINTFN(2, ("%s: nothing to do anymore\n", __func__)); + sc->sc_running = FALSE; +} + +void +imxspi_done(struct imxspi_softc *sc, int err) +{ + struct spi_transfer *st; + + /* called from interrupt handler */ + if ((st = sc->sc_transfer) != NULL) { + if (sc->sc_tag->spi_cs_disable != NULL) + sc->sc_tag->spi_cs_disable(sc->sc_tag->cookie, + st->st_slave); + + sc->sc_transfer = NULL; + spi_done(st, err); + } + /* make sure we clear these bits out */ + sc->sc_wchunk = sc->sc_rchunk = NULL; + imxspi_sched(sc); +} + +static int +imxspi_intr(void *arg) +{ + struct imxspi_softc *sc = arg; + uint32_t intr, sr; + int err = 0; + + if ((intr = READ_REG(sc, INTREG)) == 0) { + /* interrupts are not enabled, get out */ + DPRINTFN(4, ("%s: interrupts are not enabled\n", __func__)); + return 0; + } + + sr = READ_REG(sc, STATREG); + if (!(sr & intr)) { + /* interrupt did not happen, get out */ + DPRINTFN(3, ("%s: interrupts did not happen\n", __func__)); + return 0; + } + + /* Transfer Conplete? */ + if (sr & IMXSPI(INTR_TC_EN)) { + /* complete TX */ + imxspi_send(sc); + } + + /* RXFIFO ready */ + if (sr & IMXSPI(INTR_RR_EN)) { + imxspi_recv(sc); + if(sc->sc_wchunk == NULL &&sc->sc_rchunk == NULL) + imxspi_done(sc, err); + } + + /* status register clear */ + WRITE_REG(sc, STATREG, sr); + + return 1; +} + +int +imxspi_transfer(void *arg, struct spi_transfer *st) +{ + struct imxspi_softc *sc = arg; + int s; + + /* make sure we select the right chip */ + s = splserial(); + spi_transq_enqueue(&sc->sc_q, st); + if (sc->sc_running == FALSE) + imxspi_sched(sc); + splx(s); + + return 0; +} + Index: src/sys/arch/arm/imx/imxspireg.h diff -u /dev/null src/sys/arch/arm/imx/imxspireg.h:1.1 --- /dev/null Sat Mar 22 09:28:08 2014 +++ src/sys/arch/arm/imx/imxspireg.h Sat Mar 22 09:28:08 2014 @@ -0,0 +1,37 @@ +/* $NetBSD: imxspireg.h,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */ + +/* + * Copyright (c) 2014 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 GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + */ + +#ifndef _ARM_IMX_IMXSPIREG_H_ +#define _ARM_IMX_IMXSPIREG_H_ + +#include <arm/imx/imxcspireg.h> +#include <arm/imx/imxecspireg.h> + +#define SPI_SIZE 0x100 + +#endif /* _ARM_IMX_IMXSPIREG_H_ */ Index: src/sys/arch/arm/imx/imxspivar.h diff -u /dev/null src/sys/arch/arm/imx/imxspivar.h:1.1 --- /dev/null Sat Mar 22 09:28:08 2014 +++ src/sys/arch/arm/imx/imxspivar.h Sat Mar 22 09:28:08 2014 @@ -0,0 +1,80 @@ +/* $NetBSD: imxspivar.h,v 1.1 2014/03/22 09:28:08 hkenken Exp $ */ + +/* + * Copyright (c) 2014 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 GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + */ + +#ifndef _ARM_IMX_IMXSPIVAR_H_ +#define _ARM_IMX_IMXSPIVAR_H_ + +#include <dev/spi/spivar.h> + +typedef struct spi_chipset_tag { + void *cookie; + + int (*spi_cs_enable)(void *, int); + 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; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + spi_chipset_tag_t sc_tag; + + struct spi_controller sc_spi; + unsigned long sc_freq; + struct spi_chunk *sc_wchunk; + struct spi_chunk *sc_rchunk; + void *sc_ih; + struct spi_transfer *sc_transfer; + bool sc_running; + SIMPLEQ_HEAD(,spi_transfer) sc_q; + + int sc_enhanced; +}; + +int imxspi_attach_common(device_t, struct imxspi_softc *, void *); + +/* + * defined in machine dependent code + */ +int imxspi_match(device_t, cfdata_t, void *); +void imxspi_attach(device_t, device_t, void *); + +#endif /* _ARM_IMX_IMXSPIVAR_H_ */