diff --git a/arch/mips/src/pic32mx/pic32mx-spi.h b/arch/mips/src/pic32mx/pic32mx-spi.h index b32a173e45d..9f4b83a66f0 100644 --- a/arch/mips/src/pic32mx/pic32mx-spi.h +++ b/arch/mips/src/pic32mx/pic32mx-spi.h @@ -63,7 +63,7 @@ #define PIC32MX_SPI_BRGINV_OFFSET 0x003c /* SPI baud rate invert register */ #if defined(CHIP_PIC32MX1) || defined(CHIP_PIC32MX2) -#define PIC32MX_SPI_CON2_OFFSET 0x0020 /* SPI control register 2*/ +#define PIC32MX_SPI_CON2_OFFSET 0x0040 /* SPI control register 2*/ #endif /* Register Addresses *******************************************************/ @@ -168,10 +168,10 @@ # define SPI_CON_MODE_32BIT (2 << SPI_CON_MODE_SHIFT) /* 32-bit data width */ #if defined(CHIP_PIC32MX1) || defined(CHIP_PIC32MX2) /* With AUDEN=1: */ -# define SPI_CON_MODE_243232 (0 << SPI_CON_MODE_SHIFT) /* 24-bit data, 32-bit FIFO, 32-bit channel */ -# define SPI_CON_MODE_323232 (0 << SPI_CON_MODE_SHIFT) /* 32-bit data, 32-bit FIFO, 32-bit channel */ -# define SPI_CON_MODE_161632 (0 << SPI_CON_MODE_SHIFT) /* 16-bit data, 16-bit FIFO, 32-bit channel */ # define SPI_CON_MODE_161616 (0 << SPI_CON_MODE_SHIFT) /* 16-bit data, 16-bit FIFO, 16-bit channel */ +# define SPI_CON_MODE_161632 (1 << SPI_CON_MODE_SHIFT) /* 16-bit data, 16-bit FIFO, 32-bit channel */ +# define SPI_CON_MODE_323232 (2 << SPI_CON_MODE_SHIFT) /* 32-bit data, 32-bit FIFO, 32-bit channel */ +# define SPI_CON_MODE_243232 (3 << SPI_CON_MODE_SHIFT) /* 24-bit data, 32-bit FIFO, 32-bit channel */ #endif #define SPI_CON_DISSDO (1 << 12) /* Bits 12: Disable SDOx pin */ #define SPI_CON_SIDL (1 << 13) /* Bits 13: Stop in idle mode */ @@ -215,7 +215,7 @@ # define SPI2_CON2_AUDMOD_RJ (2 << SPI2_CON2_AUDMOD_SHIFT) /* Right Justified mode */ # define SPI2_CON2_AUDMOD_PCM (3 << SPI2_CON2_AUDMOD_SHIFT) /* PCM/DSP mode */ /* Bit 2: Reserved */ -# define SPI2_CON2_AUDMONO (1 << 6) /* Bit 3: Transmit Audio Data Format */ +# define SPI2_CON2_AUDMONO (1 << 3) /* Bit 3: Transmit Audio Data Format */ /* Bits 5-6: Reserved */ # define SPI2_CON2_AUDEN (1 << 7) /* Bit 7: Enable Audio CODEC Support */ # define SPI2_CON2_IGNTUR (1 << 8) /* Bit 8: Ignore Transmit Underrun bit */ diff --git a/arch/mips/src/pic32mz/Kconfig b/arch/mips/src/pic32mz/Kconfig index 54a5852af88..8a512701dee 100644 --- a/arch/mips/src/pic32mz/Kconfig +++ b/arch/mips/src/pic32mz/Kconfig @@ -33,6 +33,10 @@ config PIC32MZ_MVEC bool default n +config PIC32MZ_SPI + bool + default y + config PIC32MZ_T1 bool default y @@ -138,18 +142,32 @@ config PIC32MZ_I2C5 config PIC32MZ_SPI1 bool "SPI1" default n + select PIC32MX_SPI config PIC32MZ_SPI2 bool "SPI2" default n + select PIC32MX_SPI config PIC32MZ_SPI3 bool "SPI3" default n + select PIC32MX_SPI config PIC32MZ_SPI4 bool "SPI4" default n + select PIC32MX_SPI + +config PIC32MZ_SPI5 + bool "SPI5" + default n + select PIC32MX_SPI + +config PIC32MZ_SPI6 + bool "SPI6" + default n + select PIC32MX_SPI config PIC32MZ_UART1 bool "UART1" @@ -246,7 +264,7 @@ config PIC32MZ_CTMU bool "Charge Time Measurement Unit (CMTU)" default n -endmenu +endmenu # PIC32MX Peripheral Support menuconfig PIC32MZ_GPIOIRQ bool "GPIO Interrupt Support" @@ -256,48 +274,61 @@ menuconfig PIC32MZ_GPIOIRQ if PIC32MZ_GPIOIRQ -menuconfig PIC32MZ_GPIOIRQ_PORTA +config PIC32MZ_GPIOIRQ_PORTA bool "I/O PORTA Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTB +config PIC32MZ_GPIOIRQ_PORTB bool "I/O PORTB Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTC +config PIC32MZ_GPIOIRQ_PORTC bool "I/O PORTC Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTD +config PIC32MZ_GPIOIRQ_PORTD bool "I/O PORTD Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTE +config PIC32MZ_GPIOIRQ_PORTE bool "I/O PORTE Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTF +config PIC32MZ_GPIOIRQ_PORTF bool "I/O PORTF Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTG +config PIC32MZ_GPIOIRQ_PORTG bool "I/O PORTG Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTH +config PIC32MZ_GPIOIRQ_PORTH bool "I/O PORTH Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTJ +config PIC32MZ_GPIOIRQ_PORTJ bool "I/O PORTJ Interrupt Support" default n -menuconfig PIC32MZ_GPIOIRQ_PORTK +config PIC32MZ_GPIOIRQ_PORTK bool "I/O PORTK Interrupt Support" default n endif # PIC32MZ_GPIOIRQ +menu "SPI Driver Configuration" + depends on PIC32MZ_SPI && EXPERIMENTAL + +config PIC32MZ_SPI_INTERRUPTS + bool "SPI Interrupt Driven" + default n + +config PIC32MZ_SPI_ENHBUF + bool "SPI Enhanced Buffer Mode" + default n + +endmenu # SPI Driver Configuration + config PIC32MZ_T1_SOSC bool default n @@ -377,7 +408,7 @@ config NET_MULTICAST Enable receipt of multicast (and unicast) frames. Automatically set if NET_IGMP is selected. -endmenu +endmenu # PIC32MZ PHY/Ethernet device driver settings menu "Device Configuration 0 (DEVCFG0)" @@ -417,7 +448,7 @@ config PIC32MZ_ECC_OPTION 2: ECC / dynamic ECC disabled (locked) */ 3: ECC / dynamic ECC disabled (writable) */ -endmenu +endmenu # Device configuration 0 (DEVCFG0) menu "Device Configuration 1 (DEVCFG1)" @@ -440,7 +471,7 @@ config PIC32MZ_WDTENABLE 1: Watchdog enabled, cannot be disabled 0: Watchdog disabled, can be enabled -endmenu +endmenu # Device Configuration 2 (DEVCFG2) menu "Device Configuration 3 (DEVCFG3)" @@ -496,5 +527,5 @@ config PIC32MZ_FUSBIDIO 0 = USBID pin is controlled by the port function 1 = USBID pin is controlled by the USB module -endmenu +endmenu # Device Configuration 3 (DEVCFG3) endif diff --git a/arch/mips/src/pic32mz/Make.defs b/arch/mips/src/pic32mz/Make.defs index 8915bdd3072..c16c23ac214 100644 --- a/arch/mips/src/pic32mz/Make.defs +++ b/arch/mips/src/pic32mz/Make.defs @@ -73,3 +73,7 @@ CHIP_CSRCS += pic32mz-lowconsole.c pic32mz-serial.c ifeq ($(CONFIG_PIC32MZ_GPIOIRQ),y) CHIP_CSRCS += pic32mz-gpioirq.c endif + +ifeq ($(CONFIG_PIC32MZ_SPI),y) +CHIP_CSRCS += pic32mz-spi.c +endif diff --git a/arch/mips/src/pic32mz/chip/pic32mz-spi.h b/arch/mips/src/pic32mz/chip/pic32mz-spi.h new file mode 100644 index 00000000000..0c66649393c --- /dev/null +++ b/arch/mips/src/pic32mz/chip/pic32mz-spi.h @@ -0,0 +1,330 @@ +/**************************************************************************** + * arch/mips/src/pic32mz/chip/pic32mz-spi.h + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +#ifndef __ARCH_MIPS_SRC_PIC32MZ_CHIP_PIC32MZ_SPI_H +#define __ARCH_MIPS_SRC_PIC32MZ_CHIP_PIC32MZ_SPI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip/pic32mz-memorymap.h" + +#if CHIP_NSPI > 0 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* SPI Peripheral Offsets ***************************************************/ + +#define PIC32MZ_SPIn_OFFSET(n) ((n) << 9) +# define PIC32MZ_SPI1_OFFSET 0x0000 +# define PIC32MZ_SPI2_OFFSET 0x0200 +# define PIC32MZ_SPI3_OFFSET 0x0400 +# define PIC32MZ_SPI4_OFFSET 0x0600 +# define PIC32MZ_SPI5_OFFSET 0x0800 +# define PIC32MZ_SPI6_OFFSET 0x0a00 + +/* SPI Register Offsets *****************************************************/ + +#define PIC32MZ_SPI_CON_OFFSET 0x0000 /* SPI control register */ +#define PIC32MZ_SPI_CONCLR_OFFSET 0x0004 /* SPI control clear register */ +#define PIC32MZ_SPI_CONSET_OFFSET 0x0008 /* SPI control set register */ +#define PIC32MZ_SPI_CONINV_OFFSET 0x000c /* SPI control invert register */ + +#define PIC32MZ_SPI_STAT_OFFSET 0x0010 /* SPI status register */ +#define PIC32MZ_SPI_STATCLR_OFFSET 0x0014 /* SPI status clear register */ + +#define PIC32MZ_SPI_BUF_OFFSET 0x0020 /* SPI buffer register */ + +#define PIC32MZ_SPI_BRG_OFFSET 0x0030 /* SPI baud rate register */ +#define PIC32MZ_SPI_BRGCLR_OFFSET 0x0034 /* SPI baud rate clear register */ +#define PIC32MZ_SPI_BRGSET_OFFSET 0x0038 /* SPI baud rate set register */ +#define PIC32MZ_SPI_BRGINV_OFFSET 0x003c /* SPI baud rate invert register */ + +#define PIC32MZ_SPI_CON2_OFFSET 0x0040 /* SPI control register 2*/ +#define PIC32MZ_SPI_CON2CLR_OFFSET 0x0040 /* SPI control register 2*/ +#define PIC32MZ_SPI_CON2SET_OFFSET 0x0040 /* SPI control register 2*/ +#define PIC32MZ_SPI_CON2INV_OFFSET 0x0040 /* SPI control register 2*/ + +/* SPI Peripheral Addresses *************************************************/ + +#define PIC32MZ_SPIn_K1BASE(n) (PIC32MZ_SPI_K1BASE + PIC32MZ_SPIn_OFFSET(n)) +# define PIC32MZ_SPI1_K1BASE (PIC32MZ_SPI_K1BASE + PIC32MZ_SPI1_OFFSET) +# define PIC32MZ_SPI2_K1BASE (PIC32MZ_SPI_K1BASE + PIC32MZ_SPI2_OFFSET) +# define PIC32MZ_SPI3_K1BASE (PIC32MZ_SPI_K1BASE + PIC32MZ_SPI3_OFFSET) +# define PIC32MZ_SPI4_K1BASE (PIC32MZ_SPI_K1BASE + PIC32MZ_SPI4_OFFSET) +# define PIC32MZ_SPI5_K1BASE (PIC32MZ_SPI_K1BASE + PIC32MZ_SPI5_OFFSET) +# define PIC32MZ_SPI6_K1BASE (PIC32MZ_SPI_K1BASE + PIC32MZ_SPI6_OFFSET) + +/* SPI Register Addresses ***************************************************/ + +#define PIC32MZ_SPI1_CON (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CON_OFFSET) +#define PIC32MZ_SPI1_CONCLR (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CONCLR_OFFSET) +#define PIC32MZ_SPI1_CONSET (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CONSET_OFFSET) +#define PIC32MZ_SPI1_CONINV (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CONINV_OFFSET) +#define PIC32MZ_SPI1_STAT (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_STAT_OFFSET) +#define PIC32MZ_SPI1_STATCLR (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_STATCLR_OFFSET) +#define PIC32MZ_SPI1_BUF (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_BUF_OFFSET) +#define PIC32MZ_SPI1_BRG (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_BRG_OFFSET) +#define PIC32MZ_SPI1_BRGCLR (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_BRGCLR_OFFSET) +#define PIC32MZ_SPI1_BRGSET (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_BRGSET_OFFSET) +#define PIC32MZ_SPI1_BRGINV (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_BRGINV_OFFSET) +#define PIC32MZ_SPI1_CON2 (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CON2_OFFSET) +#define PIC32MZ_SPI1_CON2CLR (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CON2CLR_OFFSET) +#define PIC32MZ_SPI1_CON2SET (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CON2SET_OFFSET) +#define PIC32MZ_SPI1_CON2INV (PIC32MZ_SPI1_K1BASE+PIC32MZ_SPI_CON2INV_OFFSET) + +#if PIC32MZ_NSPI > 1 +# define PIC32MZ_SPI2_CON (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CON_OFFSET) +# define PIC32MZ_SPI2_CONCLR (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CONCLR_OFFSET) +# define PIC32MZ_SPI2_CONSET (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CONSET_OFFSET) +# define PIC32MZ_SPI2_CONINV (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CONINV_OFFSET) +# define PIC32MZ_SPI2_STAT (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_STAT_OFFSET) +# define PIC32MZ_SPI2_STATCLR (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_STATCLR_OFFSET) +# define PIC32MZ_SPI2_BUF (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_BUF_OFFSET) +# define PIC32MZ_SPI2_BRG (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_BRG_OFFSET) +# define PIC32MZ_SPI2_BRGCLR (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_BRGCLR_OFFSET) +# define PIC32MZ_SPI2_BRGSET (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_BRGSET_OFFSET) +# define PIC32MZ_SPI2_BRGINV (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_BRGINV_OFFSET) +# define PIC32MZ_SPI2_CON2 (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CON2_OFFSET) +# define PIC32MZ_SPI2_CON2CLR (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CON2CLR_OFFSET) +# define PIC32MZ_SPI2_CON2SET (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CON2SET_OFFSET) +# define PIC32MZ_SPI2_CON2INV (PIC32MZ_SPI2_K1BASE+PIC32MZ_SPI_CON2INV_OFFSET) +#endif + +#if PIC32MZ_NSPI > 2 +# define PIC32MZ_SPI3_CON (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CON_OFFSET) +# define PIC32MZ_SPI3_CONCLR (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CONCLR_OFFSET) +# define PIC32MZ_SPI3_CONSET (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CONSET_OFFSET) +# define PIC32MZ_SPI3_CONINV (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CONINV_OFFSET) +# define PIC32MZ_SPI3_STAT (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_STAT_OFFSET) +# define PIC32MZ_SPI3_STATCLR (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_STATCLR_OFFSET) +# define PIC32MZ_SPI3_BUF (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_BUF_OFFSET) +# define PIC32MZ_SPI3_BRG (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_BRG_OFFSET) +# define PIC32MZ_SPI3_BRGCLR (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_BRGCLR_OFFSET) +# define PIC32MZ_SPI3_BRGSET (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_BRGSET_OFFSET) +# define PIC32MZ_SPI3_BRGINV (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_BRGINV_OFFSET) +# define PIC32MZ_SPI3_CON2CLR (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CON2CLR_OFFSET) +# define PIC32MZ_SPI3_CON2SET (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CON2SET_OFFSET) +# define PIC32MZ_SPI3_CON2INV (PIC32MZ_SPI3_K1BASE+PIC32MZ_SPI_CON2INV_OFFSET) +#endif + +#if PIC32MZ_NSPI > 3 +# define PIC32MZ_SPI4_CON (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CON_OFFSET) +# define PIC32MZ_SPI4_CONCLR (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CONCLR_OFFSET) +# define PIC32MZ_SPI4_CONSET (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CONSET_OFFSET) +# define PIC32MZ_SPI4_CONINV (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CONINV_OFFSET) +# define PIC32MZ_SPI4_STAT (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_STAT_OFFSET) +# define PIC32MZ_SPI4_STATCLR (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_STATCLR_OFFSET) +# define PIC32MZ_SPI4_BUF (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_BUF_OFFSET) +# define PIC32MZ_SPI4_BRG (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_BRG_OFFSET) +# define PIC32MZ_SPI4_BRGCLR (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_BRGCLR_OFFSET) +# define PIC32MZ_SPI4_BRGSET (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_BRGSET_OFFSET) +# define PIC32MZ_SPI4_BRGINV (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_BRGINV_OFFSET) +# define PIC32MZ_SPI4_CON2CLR (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CON2CLR_OFFSET) +# define PIC32MZ_SPI4_CON2SET (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CON2SET_OFFSET) +# define PIC32MZ_SPI4_CON2INV (PIC32MZ_SPI4_K1BASE+PIC32MZ_SPI_CON2INV_OFFSET) +#endif + +#if PIC32MZ_NSPI > 4 +# define PIC32MZ_SPI5_CON (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CON_OFFSET) +# define PIC32MZ_SPI5_CONCLR (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CONCLR_OFFSET) +# define PIC32MZ_SPI5_CONSET (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CONSET_OFFSET) +# define PIC32MZ_SPI5_CONINV (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CONINV_OFFSET) +# define PIC32MZ_SPI5_STAT (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_STAT_OFFSET) +# define PIC32MZ_SPI5_STATCLR (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_STATCLR_OFFSET) +# define PIC32MZ_SPI5_BUF (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_BUF_OFFSET) +# define PIC32MZ_SPI5_BRG (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_BRG_OFFSET) +# define PIC32MZ_SPI5_BRGCLR (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_BRGCLR_OFFSET) +# define PIC32MZ_SPI5_BRGSET (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_BRGSET_OFFSET) +# define PIC32MZ_SPI5_BRGINV (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_BRGINV_OFFSET) +# define PIC32MZ_SPI5_CON2CLR (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CON2CLR_OFFSET) +# define PIC32MZ_SPI5_CON2SET (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CON2SET_OFFSET) +# define PIC32MZ_SPI5_CON2INV (PIC32MZ_SPI5_K1BASE+PIC32MZ_SPI_CON2INV_OFFSET) +#endif + +#if PIC32MZ_NSPI > 5 +# define PIC32MZ_SPI6_CON (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CON_OFFSET) +# define PIC32MZ_SPI6_CONCLR (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CONCLR_OFFSET) +# define PIC32MZ_SPI6_CONSET (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CONSET_OFFSET) +# define PIC32MZ_SPI6_CONINV (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CONINV_OFFSET) +# define PIC32MZ_SPI6_STAT (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_STAT_OFFSET) +# define PIC32MZ_SPI6_STATCLR (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_STATCLR_OFFSET) +# define PIC32MZ_SPI6_BUF (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_BUF_OFFSET) +# define PIC32MZ_SPI6_BRG (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_BRG_OFFSET) +# define PIC32MZ_SPI6_BRGCLR (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_BRGCLR_OFFSET) +# define PIC32MZ_SPI6_BRGSET (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_BRGSET_OFFSET) +# define PIC32MZ_SPI6_BRGINV (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_BRGINV_OFFSET) +# define PIC32MZ_SPI6_CON2CLR (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CON2CLR_OFFSET) +# define PIC32MZ_SPI6_CON2SET (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CON2SET_OFFSET) +# define PIC32MZ_SPI6_CON2INV (PIC32MZ_SPI6_K1BASE+PIC32MZ_SPI_CON2INV_OFFSET) +#endif + +/* Register Bit-Field Definitions *******************************************/ + +/* SPI control register */ + +#define SPI_CON_SRXISEL_SHIFT (0) /* Bits 0-1: SPI Receive Buffer Full Interrupt Mode */ +#define SPI_CON_SRXISEL_MASK (3 << SPI_CON_SRXISEL_SHIFT) +# define SPI_CON_SRXISEL_EMPTY (0 << SPI_CON_SRXISEL_SHIFT) /* Buffer empty */ +# define SPI_CON_SRXISEL_NEMPTY (1 << SPI_CON_SRXISEL_SHIFT) /* Buffer not empty */ +# define SPI_CON_SRXISEL_HALF (2 << SPI_CON_SRXISEL_SHIFT) /* Buffer half full or more */ +# define SPI_CON_SRXISEL_FULL (3 << SPI_CON_SRXISEL_SHIFT) /* Buffer full */ +#define SPI_CON_STXISEL_SHIFT (2) /* Bits 2-3: SPI Transmit Buffer Empty Interrupt Mode */ +#define SPI_CON_STXISEL_MASK (3 << SPI_CON_STXISEL_SHIFT) +# define SPI_CON_STXISEL_DONE (0 << SPI_CON_STXISEL_SHIFT) /* Buffer empty (and data shifted out) */ +# define SPI_CON_STXISEL_EMPTY (1 << SPI_CON_STXISEL_SHIFT) /* Buffer empty */ +# define SPI_CON_STXISEL_HALF (2 << SPI_CON_STXISEL_SHIFT) /* Buffer half empty or more */ +# define SPI_CON_STXISEL_NFULL (3 << SPI_CON_STXISEL_SHIFT) /* Buffer not full */ +#define SPI_CON_DISSDI (1 << 4) /* Bit 4: Disable SDI */ +#define SPI_CON_MSTEN (1 << 5) /* Bit 5: Master mode enable */ +#define SPI_CON_CKP (1 << 6) /* Bit 6: Clock polarity select */ +#define SPI_CON_SSEN (1 << 7) /* Bit 7: Slave select enable (slave mode) */ +#define SPI_CON_CKE (1 << 8) /* Bit 8: SPI clock edge select */ +#define SPI_CON_SMP (1 << 9) /* Bit 9: SPI data input sample phase */ +#define SPI_CON_MODE_SHIFT (10) /* Bits 10-11: 32/16-Bit Communication Select */ +#define SPI_CON_MODE_MASK (3 << SPI_CON_MODE_SHIFT) + /* With AUDEN=0: */ +# define SPI_CON_MODE_8BIT (0 << SPI_CON_MODE_SHIFT) /* 8-bit data width */ +# define SPI_CON_MODE_16BIT (1 << SPI_CON_MODE_SHIFT) /* 16-bit data width */ +# define SPI_CON_MODE_32BIT (2 << SPI_CON_MODE_SHIFT) /* 32-bit data width */ + /* With AUDEN=1: */ +# define SPI_CON_MODE_161616 (0 << SPI_CON_MODE_SHIFT) /* 16-bit data, 16-bit FIFO, 16-bit channel */ +# define SPI_CON_MODE_161632 (1 << SPI_CON_MODE_SHIFT) /* 16-bit data, 16-bit FIFO, 32-bit channel */ +# define SPI_CON_MODE_323232 (2 << SPI_CON_MODE_SHIFT) /* 32-bit data, 32-bit FIFO, 32-bit channel */ +# define SPI_CON_MODE_243232 (3 << SPI_CON_MODE_SHIFT) /* 24-bit data, 32-bit FIFO, 32-bit channel */ +#define SPI_CON_DISSDO (1 << 12) /* Bit 12: Disable SDOx pin */ +#define SPI_CON_SIDL (1 << 13) /* Bit 13: Stop in idle mode */ +#define SPI_CON_ON (1 << 15) /* Bit 15: SPI peripheral on */ +#define SPI_CON_ENHBUF (1 << 16) /* Bit 16: Enhanced buffer enable */ +#define SPI_CON_SPIFE (1 << 17) /* Bit 17: Frame sync pulse edge select */ + /* Bits 18-23: Reserved */ +#define SPI_CON_MCLKSEL (1 << 23) /* Bit 23: Master clock enable */ +#define SPI_CON_FRMCNT_SHIFT (24) /* Bits 24-26: Frame Sync Pulse Counter bits */ +#define SPI_CON_FRMCNT_MASK (7 << SPI_CON_FRMCNT_SHIFT) +# define SPI_CON_FRMCNT_CHAR1 (0 << SPI_CON_FRMCNT_SHIFT) /* Frame sync pulse each char */ +# define SPI_CON_FRMCNT_CHAR2 (1 << SPI_CON_FRMCNT_SHIFT) /* Frame sync pulse every 2 chars */ +# define SPI_CON_FRMCNT_CHAR4 (2 << SPI_CON_FRMCNT_SHIFT) /* Frame sync pulse every 4 chars */ +# define SPI_CON_FRMCNT_CHAR8 (3 << SPI_CON_FRMCNT_SHIFT) /* Frame sync pulse every 8 chars */ +# define SPI_CON_FRMCNT_CHAR16 (4 << SPI_CON_FRMCNT_SHIFT) /* Frame sync pulse every 16 chars */ +# define SPI_CON_FRMCNT_CHAR32 (5 << SPI_CON_FRMCNT_SHIFT) /* Frame sync pulse every 32 chars */ +#define SPI_CON_FRMSYPW (1 << 27) /* Bits 27: Frame sync pulse width */ +#define SPI_CON_MSSEN (1 << 28) /* Bits 28: Master mode slave select enable */ +#define SPI_CON_FRMPOL (1 << 29) /* Bits 29: Frame sync polarity */ +#define SPI_CON_FRMSYNC (1 << 30) /* Bits 30: Frame sync pulse direction control on SSx pin */ +#define SPI_CON_FRMEN (1 << 31) /* Bits 31: Framed SPI support */ + +/* SPI control register 2 */ + +#define SPI2_CON2_AUDMOD_SHIFT (0) /* Bits 0-1: Audio Protocol Mode */ +#define SPI2_CON2_AUDMOD_MASK (3 << SPI2_CON2_AUDMOD_SHIFT) +# define SPI2_CON2_AUDMOD_I2S (0 << SPI2_CON2_AUDMOD_SHIFT) /* I2S mode */ +# define SPI2_CON2_AUDMOD_LJ (1 << SPI2_CON2_AUDMOD_SHIFT) /* Left Justified mode */ +# define SPI2_CON2_AUDMOD_RJ (2 << SPI2_CON2_AUDMOD_SHIFT) /* Right Justified mode */ +# define SPI2_CON2_AUDMOD_PCM (3 << SPI2_CON2_AUDMOD_SHIFT) /* PCM/DSP mode */ + /* Bit 2: Reserved */ +#define SPI2_CON2_AUDMONO (1 << 3) /* Bit 3: Transmit Audio Data Format */ + /* Bits 5-6: Reserved */ +#define SPI2_CON2_AUDEN (1 << 7) /* Bit 7: Enable Audio CODEC Support */ +#define SPI2_CON2_IGNTUR (1 << 8) /* Bit 8: Ignore Transmit Underrun bit */ +#define SPI2_CON2_IGNROV (1 << 9) /* Bit 9: Ignore Receive Overflow */ +#define SPI2_CON2_SPITUREN (1 << 10) /* Bit 10: Enable Interrupt Events via SPITUR */ +#define SPI2_CON2_SPIROVEN (1 << 11) /* Bit 11: Enable Interrupt Events via SPIROV */ +#define SPI2_CON2_FRMERREN (1 << 12) /* Bit 12: Enable Interrupt Events via FRMERR */ + /* Bits 13-14: Reserved */ +#define SPI2_CON2_SPISGNEXT (1 << 15) /* Bit 15 : Sign Extend Read Data from the RX FIFO */ + /* Bits 16-31: Reserved */ + +/* SPI status register */ + +#define SPI_STAT_SPIRBF (1 << 0) /* Bit 0: SPI receive buffer full status */ +#define SPI_STAT_SPITBF (1 << 1) /* Bit 1: SPI transmit buffer full status */ +#define SPI_STAT_SPITBE (1 << 3) /* Bit 3: SPI transmit buffer empty status */ + /* Bit 4: Reserved */ +#define SPI_STAT_SPIRBE (1 << 5) /* Bit 5: RX FIFO Empty */ +#define SPI_STAT_SPIROV (1 << 6) /* Bit 6: Receive overflow flag */ +#define SPI_STAT_SRMT (1 << 7) /* Bit 6: Shift Register Empty */ +#define SPI_STAT_SPITUR (1 << 8) /* Bit 8: Transmit under run */ + /* Bits 9-10: Reserved */ +#define SPI_STAT_SPIBUSY (1 << 11) /* Bit 11: SPI activity status */ +#define SPI_STAT_FRMERR (1 << 12) /* Bit 12: SPI Frame Error status */ + /* Bits 13-15: Reserved */ +#define SPI_STAT_TXBUFELM_SHIFT (16) /* Bits 16-20: Transmit Buffer Element Count bits */ +#define SPI_STAT_TXBUFELM_MASK (31 << SPI_STAT_TXBUFELM_SHIFT) +# define SPI_STAT_TXBUFELM(n) ((uint32_t)(n) << SPI_STAT_TXBUFELM_SHIFT) + /* Bits 21-23: Reserved */ +#define SPI_STAT_RXBUFELM_SHIFT (24) /* Bits 24-28: Receive Buffer Element Count bits */ +#define SPI_STAT_RXBUFELM_MASK (31 << SPI_STAT_RXBUFELM_SHIFT) +# define SPI_STAT_RXBUFELM(n) ((uint32_t)(n) << SPI_STAT_RXBUFELM_SHIFT) + +/* SPI buffer register (32-bits wide) */ + +/* SPI baud rate register */ + +#define SPI_BRG_MASK 0x00001fff + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Inline Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" { +#else +#define EXTERN extern +#endif + +#undef EXTERN +#ifdef __cplusplus +} +#endif + +#endif /* __ASSEMBLY__ */ +#endif /* CHIP_NSPI > 0 */ +#endif /* __ARCH_MIPS_SRC_PIC32MZ_CHIP_PIC32MZ_SPI_H */ diff --git a/arch/mips/src/pic32mz/pic32mz-config.h b/arch/mips/src/pic32mz/pic32mz-config.h index 74ae32ac263..7dbd8af3ec8 100644 --- a/arch/mips/src/pic32mz/pic32mz-config.h +++ b/arch/mips/src/pic32mz/pic32mz-config.h @@ -191,6 +191,47 @@ # undef HAVE_SERIAL_CONSOLE #endif +/* SPI ******************************************************************************/ +/* Don't enable SPI peripherals not supported by the chip. */ + +#if CHIP_NSPI < 1 +# undef CONFIG_PIC32MZ_SPI1 +# undef CONFIG_PIC32MZ_SPI2 +# undef CONFIG_PIC32MZ_SPI3 +# undef CONFIG_PIC32MZ_SPI4 +# undef CONFIG_PIC32MZ_SPI5 +# undef CONFIG_PIC32MZ_SPI6 +#elif CHIP_NSPI < 2 +# undef CONFIG_PIC32MZ_SPI2 +# undef CONFIG_PIC32MZ_SPI3 +# undef CONFIG_PIC32MZ_SPI4 +# undef CONFIG_PIC32MZ_SPI5 +# undef CONFIG_PIC32MZ_SPI6 +#elif CHIP_NSPI < 3 +# undef CONFIG_PIC32MZ_SPI3 +# undef CONFIG_PIC32MZ_SPI4 +# undef CONFIG_PIC32MZ_SPI5 +# undef CONFIG_PIC32MZ_SPI6 +#elif CHIP_NSPI < 4 +# undef CONFIG_PIC32MZ_SPI4 +# undef CONFIG_PIC32MZ_SPI5 +# undef CONFIG_PIC32MZ_SPI6 +#elif CHIP_NSPI < 5 +# undef CONFIG_PIC32MZ_SPI5 +# undef CONFIG_PIC32MZ_SPI6 +#elif CHIP_NSPI < 6 +# undef CONFIG_PIC32MZ_SPI6 +#endif + +/* Are any SPI peripherals enabled? */ + +#undef CONFIG_PIC32MZ_SPI +#if defined(CONFIG_PIC32MZ_SPI1) || defined(CONFIG_PIC32MZ_SPI2) || \ + defined(CONFIG_PIC32MZ_SPI4) || defined(CONFIG_PIC32MZ_SPI4) || \ + defined(CONFIG_PIC32MZ_SPI5) || defined(CONFIG_PIC32MZ_SPI6) +# define CONFIG_PIC32MZ_SPI 1 +#endif + /* Device Configuration *************************************************************/ /* DEVCFG3 */ /* Configurable settings */ diff --git a/arch/mips/src/pic32mz/pic32mz-spi.c b/arch/mips/src/pic32mz/pic32mz-spi.c new file mode 100644 index 00000000000..96ee9046c4f --- /dev/null +++ b/arch/mips/src/pic32mz/pic32mz-spi.c @@ -0,0 +1,1161 @@ +/**************************************************************************** + * arch/mips/src/pic32mz/pic32mz-spi.c + * + * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 + * COPYRIGHT OWNER 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "chip/pic32mz-spi.h" +#include "chip/pic32mz-pps.h" +#include "pic32mz-spi.h" + +#ifdef CONFIG_PIC32MZ_SPI + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* All SPI peripherals are clocked by PBCLK2 */ + +#define BOARD_PBCLOCK BOARD_PBCLK2 + +/* Enables non-standard debug output from this file. + * + * CONFIG_SPI_DEBUG && CONFIG_DEBUG - Define to enable basic SPI debug + * CONFIG_DEBUG_VERBOSE - Define to enable verbose SPI debug + */ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_SPI +# undef CONFIG_DEBUG_VERBOSE +# undef CONFIG_SPI_REGDEBUG +#endif + +#ifdef CONFIG_DEBUG_SPI +# define spidbg lldbg +# ifdef CONFIG_DEBUG_VERBOSE +# define spivdbg lldbg +# else +# define spivdbg(x...) +# endif +#else +# define spidbg(x...) +# define spivdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* This structure describes the state of the SSP driver */ + +struct pic32mz_dev_s +{ + struct spi_dev_s spidev; /* Externally visible part of the SPI interface */ + uint32_t base; /* SPI register base address */ +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + uint8_t firq; /* SPI fault interrupt number */ + uint8_t rxirq; /* SPI receive done interrupt number */ + uint8_t txirq; /* SPI transfer done interrupt number */ +#endif + uint8_t sdipps; /* SDI peripheral pin selection */ + uint8_t sdopps; /* SDO peripheral pin selection */ + uintptr_t sdoreg; /* SDO peripheral pin configuration register */ +#ifndef CONFIG_SPI_OWNBUS + sem_t exclsem; /* Held while chip is selected for mutual exclusion */ + uint32_t frequency; /* Requested clock frequency */ + uint32_t actual; /* Actual clock frequency */ + uint8_t nbits; /* Width of word in bits (8 to 16) */ + uint8_t mode; /* Mode 0,1,2,3 */ +#endif +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* Low-level register access */ + +static uint32_t spi_getreg(FAR struct pic32mz_dev_s *priv, + unsigned int offset); +static void spi_putreg(FAR struct pic32mz_dev_s *priv, + unsigned int offset, uint32_t value); + +/* SPI methods */ + +#ifndef CONFIG_SPI_OWNBUS +static int spi_lock(FAR struct spi_dev_s *dev, bool lock); +#endif +static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency); +static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); +static void spi_setbits(FAR struct spi_dev_s *dev, int nbits); +static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t ch); +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords); +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_PIC32MZ_SPI1 + +static const struct spi_ops_s g_spi1ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = spi_lock, +#endif + .select = pic32mz_spi1select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .status = pic32mz_spi1status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = pic32mz_spi1cmddata, +#endif + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#ifdef CONFIG_SPI_CALLBACK + .registercallback = pic32mz_spi1register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +static struct pic32mz_dev_s g_spi1dev = +{ + .spidev = { &g_spi1ops }, + .base = PIC32MZ_SPI1_K1BASE, +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + .firq = PIC32MZ_IRQ_SPI1F, + .rxirq = PIC32MZ_IRQ_SPI1RX, + .txirq = PIC32MZ_IRQ_SPI1TX, +#endif + .sdipps = BOARD_SDI1_PPS, + .sdopps = PPS_OUTPUT_REGVAL(BOARD_SDO1_PPS), + .sdoreg = PPS_OUTPUT_REGADDR(BOARD_SDO1_PPS), +}; +#endif + +#ifdef CONFIG_PIC32MZ_SPI2 +static const struct spi_ops_s g_spi2ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = spi_lock, +#endif + .select = pic32mz_spi2select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .status = pic32mz_spi2status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = pic32mz_spi2cmddata, +#endif + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#ifdef CONFIG_SPI_CALLBACK + .registercallback = pic32mz_spi2register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +static struct pic32mz_dev_s g_spi2dev = +{ + .spidev = { &g_spi2ops }, + .base = PIC32MZ_SPI2_K1BASE, +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + .firq = PIC32MZ_IRQ_SPI2F, + .rxirq = PIC32MZ_IRQ_SPI2RX, + .txirq = PIC32MZ_IRQ_SPI2TX, +#endif + .sdipps = BOARD_SDI2_PPS, + .sdopps = PPS_OUTPUT_REGVAL(BOARD_SDO2_PPS), + .sdoreg = PPS_OUTPUT_REGADDR(BOARD_SDO2_PPS), +}; +#endif + +#ifdef CONFIG_PIC32MZ_SPI3 +static const struct spi_ops_s g_spi3ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = spi_lock, +#endif + .select = pic32mz_spi3select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .status = pic32mz_spi3status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = pic32mz_spi3cmddata, +#endif + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#ifdef CONFIG_SPI_CALLBACK + .registercallback = pic32mz_spi3register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +static struct pic32mz_dev_s g_spi3dev = +{ + .spidev = { &g_spi3ops }, + .base = PIC32MZ_SPI3_K1BASE, +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + .firq = PIC32MZ_IRQ_SPI3F, + .rxirq = PIC32MZ_IRQ_SPI3RX, + .txirq = PIC32MZ_IRQ_SPI3TX, +#endif + .sdipps = BOARD_SDI3_PPS, + .sdopps = PPS_OUTPUT_REGVAL(BOARD_SDO3_PPS), + .sdoreg = PPS_OUTPUT_REGADDR(BOARD_SDO3_PPS), +}; +#endif + +#ifdef CONFIG_PIC32MZ_SPI4 +static const struct spi_ops_s g_spi4ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = spi_lock, +#endif + .select = pic32mz_spi4select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .status = pic32mz_spi4status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = pic32mz_spi4cmddata, +#endif + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#ifdef CONFIG_SPI_CALLBACK + .registercallback = pic32mz_spi4register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +static struct pic32mz_dev_s g_spi4dev = +{ + .spidev = { &g_spi4ops }, + .base = PIC32MZ_SPI4_K1BASE, +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + .firq = PIC32MZ_IRQ_SPI4F, + .rxirq = PIC32MZ_IRQ_SPI4RX, + .txirq = PIC32MZ_IRQ_SPI4TX, +#endif + .sdipps = BOARD_SDI4_PPS, + .sdopps = PPS_OUTPUT_REGVAL(BOARD_SDO4_PPS), + .sdoreg = PPS_OUTPUT_REGADDR(BOARD_SDO4_PPS), +}; +#endif + +#ifdef CONFIG_PIC32MZ_SPI5 +static const struct spi_ops_s g_spi5ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = spi_lock, +#endif + .select = pic32mz_spi5select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .status = pic32mz_spi5status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = pic32mz_spi5cmddata, +#endif + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#ifdef CONFIG_SPI_CALLBACK + .registercallback = pic32mz_spi5register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +static struct pic32mz_dev_s g_spi5dev = +{ + .spidev = { &g_spi5ops }, + .base = PIC32MZ_SPI5_K1BASE, +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + .firq = PIC32MZ_IRQ_SPI5F, + .rxirq = PIC32MZ_IRQ_SPI5RX, + .txirq = PIC32MZ_IRQ_SPI5TX, +#endif + .sdipps = BOARD_SDI5_PPS, + .sdopps = PPS_OUTPUT_REGVAL(BOARD_SDO5_PPS), + .sdoreg = PPS_OUTPUT_REGADDR(BOARD_SDO5_PPS), +}; +#endif + +#ifdef CONFIG_PIC32MZ_SPI6 +static const struct spi_ops_s g_spi6ops = +{ +#ifndef CONFIG_SPI_OWNBUS + .lock = spi_lock, +#endif + .select = pic32mz_spi6select, + .setfrequency = spi_setfrequency, + .setmode = spi_setmode, + .setbits = spi_setbits, + .status = pic32mz_spi6status, +#ifdef CONFIG_SPI_CMDDATA + .cmddata = pic32mz_spi6cmddata, +#endif + .send = spi_send, + .sndblock = spi_sndblock, + .recvblock = spi_recvblock, +#ifdef CONFIG_SPI_CALLBACK + .registercallback = pic32mz_spi6register, /* Provided externally */ +#else + .registercallback = 0, /* Not implemented */ +#endif +}; + +static struct pic32mz_dev_s g_spi6dev = +{ + .spidev = { &g_spi6ops }, + .base = PIC32MZ_SPI6_K1BASE, +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + .firq = PIC32MZ_IRQ_SPI6F, + .rxirq = PIC32MZ_IRQ_SPI6RX, + .txirq = PIC32MZ_IRQ_SPI6TX, +#endif + .sdipps = BOARD_SDI6_PPS, + .sdopps = PPS_OUTPUT_REGVAL(BOARD_SDO6_PPS), + .sdoreg = PPS_OUTPUT_REGADDR(BOARD_SDO6_PPS), +}; +#endif + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: spi_getreg + * + * Description: + * Return the contents of one, 32-bit SPI register + * + * Input Parameters: + * priv - A pointer to a PIC32MZ SPI state structure + * offset - Offset from the SPI base address to the register of interest + * + * Returned Value: + * The current contents of the register + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_REGDEBUG +static uint32_t spi_getreg(FAR struct pic32mz_dev_s *priv, unsigned int offset) +{ + /* Last address, value, and count */ + + static uint32_t prevaddr = 0; + static uint32_t prevalue = 0; + static uint32_t count = 0; + + /* New address and value */ + + uint32_t addr; + uint32_t value; + + /* Read the value from the register */ + + addr = priv->base + offset; + value = getreg32(addr); + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && value == prevalue) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + lldbg("...\n"); + } + return value; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + lldbg("[repeats %d more times]\n", count-3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + prevalue = value; + count = 1; + } + + /* Show the register value read */ + + lldbg("%08x->%08x\n", addr, value); + return value; +} +#else +static uint32_t spi_getreg(FAR struct pic32mz_dev_s *priv, unsigned int offset) +{ + return getreg32(priv->base + offset); +} +#endif + +/**************************************************************************** + * Name: spi_putreg + * + * Description: + * Write a value to one, 32-bit SPI register + * + * Input Parameters: + * priv - A pointer to a PIC32MZ SPI state structure + * offset - Offset from the SPI base address to the register of interest + * value - The value to write to the SPI register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_SPI_REGDEBUG +static void spi_putreg(FAR struct pic32mz_dev_s *priv, unsigned int offset, + uint32_t value) +{ + uint32_t addr; + + /* Get the address to write to */ + + addr = priv->base + offset; + + /* Show the register value being written */ + + lldbg("%08x<-%08x\n", addr, value); + + /* Then do the write */ + + putreg32(value, addr); +} +#else +static void spi_putreg(FAR struct pic32mz_dev_s *priv, unsigned int offset, + uint32_t value) +{ + putreg32(value, priv->base + offset); +} +#endif + +/**************************************************************************** + * Name: spi_lock + * + * Description: + * On SPI busses where there are multiple devices, it will be necessary to + * lock SPI to have exclusive access to the busses for a sequence of + * transfers. The bus should be locked before the chip is selected. After + * locking the SPI bus, the caller should then also call the setfrequency, + * setbits, and setmode methods to make sure that the SPI is properly + * configured for the device. If the SPI buss is being shared, then it + * may have been left in an incompatible state. + * + * Input Parameters: + * dev - Device-specific state data + * lock - true: Lock spi bus, false: unlock SPI bus + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifndef CONFIG_SPI_OWNBUS +static int spi_lock(FAR struct spi_dev_s *dev, bool lock) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + + if (lock) + { + /* Take the semaphore (perhaps waiting) */ + + while (sem_wait(&priv->exclsem) != 0) + { + /* The only case that an error should occur here is if the wait was awakened + * by a signal. + */ + + ASSERT(errno == EINTR); + } + } + else + { + (void)sem_post(&priv->exclsem); + } + return OK; +} +#endif + +/**************************************************************************** + * Name: spi_setfrequency + * + * Description: + * Set the SPI frequency. + * + * Input Parameters: + * dev - Device-specific state data + * frequency - The SPI frequency requested + * + * Returned Value: + * Returns the actual frequency selected + * + ****************************************************************************/ + +static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + uint32_t divisor; + uint32_t actual; + uint32_t regval; + +#ifndef CONFIG_SPI_OWNBUS + spivdbg("Old frequency: %d actual: %d New frequency: %d\n", + priv->frequency, priv->actual, frequency); +#else + spivdbg("New frequency: %d\n", regval); +#endif + + /* Check if the requested frequency is the same as the frequency selection */ + +#ifndef CONFIG_SPI_OWNBUS + if (priv->frequency == frequency) + { + /* We are already at this frequency. Return the actual. */ + + return priv->actual; + } +#endif + + /* Calculate the divisor + * + * frequency = BOARD_PBCLOCK / (2 * divisor), or + * divisor = (BOARD_PBCLOCK / 2) / frequency + */ + + divisor = (BOARD_PBCLOCK / 2) / frequency; + + /* The a BRG register value is that divisor minus one + * + * frequency = BOARD_PBCLOCK /(2 * (BRG + 1)), or + * BRG = (BOARD_PBCLOCK / 2) / frequency - 1 + */ + + regval = divisor; + if (regval > 0) + { + regval--; + } + + /* Save the new BRG value */ + + spi_putreg(priv, PIC32MZ_SPI_BRG_OFFSET, regval); + spivdbg("PBCLOCK: %d frequency: %d divisor: %d BRG: %d\n", + BOARD_PBCLOCK, frequency, divisor, regval); + + /* Calculate the new actual frequency. + * + * frequency = BOARD_PBCLOCK / (2 * divisor) + */ + + actual = (BOARD_PBCLOCK / 2) / divisor; + + /* Save the frequency setting */ + +#ifndef CONFIG_SPI_OWNBUS + priv->frequency = frequency; + priv->actual = actual; +#endif + + spidbg("New frequency: %d Actual: %d\n", frequency, actual); + return actual; +} + +/**************************************************************************** + * Name: spi_setmode + * + * Description: + * Set the SPI mode. Optional. See enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + uint32_t regval; + +#ifndef CONFIG_SPI_OWNBUS + spivdbg("Old mode: %d New mode: %d\n", priv->mode, mode); +#else + spivdbg("New mode: %d\n", mode); +#endif + + /* Has the mode changed? */ + +#ifndef CONFIG_SPI_OWNBUS + if (mode != priv->mode) + { +#endif + /* Yes... Set CON register appropriately. + * + * Standard terminology is as follows: + * + * Mode CPOL CPHA + * 0 0 0 + * 1 0 1 + * 2 1 0 + * 3 1 1 + * + * CPOL=0: The inactive value of the clock is zero + * CPOL=1: The inactive value of the clock is one + * CPHA=0: Data is captured on the clock's inactive-to-active edge and + * data is propagated on a active-to-inactive edge. + * CPHA=1: Data is captured on the clock's active-to-inactive edge and + * data is propagated on a active-to-inactive edge. + * + * CON Register mapping: + * CPOL=0 corresponds to CON:CKP=0; CPOL=1 corresponds to CON:CKP=1 + * CPHA=0 corresponds to CON:CKE=1; CPHA=1 corresponds to CON:CKE=1 + * + * In addition, the CON register supports SMP: SPI Data Input Sample + * Phase bit: + * + * 1 = Input data sampled at end of data output time + * 0 = Input data sampled at middle of data output time + * + * Which is hardcoded to 1. + */ + + regval = spi_getreg(priv, PIC32MZ_SPI_CON_OFFSET); + regval &= ~(SPI_CON_CKP|SPI_CON_CKE); + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0; CPHA=0 */ + break; + + case SPIDEV_MODE1: /* CPOL=0; CPHA=1 */ + regval |= SPI_CON_CKE; + break; + + case SPIDEV_MODE2: /* CPOL=1; CPHA=0 */ + regval |= SPI_CON_CKP; + break; + + case SPIDEV_MODE3: /* CPOL=1; CPHA=1 */ + regval |= (SPI_CON_CKP|SPI_CON_CKE); + break; + + default: + DEBUGASSERT(FALSE); + return; + } + + spi_putreg(priv, PIC32MZ_SPI_CON_OFFSET, regval); + spivdbg("CON: %08x\n", regval); + + /* Save the mode so that subsequent re-configuratins will be faster */ + +#ifndef CONFIG_SPI_OWNBUS + priv->mode = mode; + } +#endif +} + +/**************************************************************************** + * Name: spi_setbits + * + * Description: + * Set the number if bits per word. + * + * Input Parameters: + * dev - Device-specific state data + * nbits - The number of bits requests + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setbits(FAR struct spi_dev_s *dev, int nbits) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + uint32_t setting; + uint32_t regval; + +#ifndef CONFIG_SPI_OWNBUS + spivdbg("Old nbits: %d New nbits: %d\n", priv->nbits, nbits); +#else + spivdbg("New nbits: %d\n", nbits); +#endif + + /* Has the number of bits changed? */ + + DEBUGASSERT(priv && nbits > 7 && nbits < 17); +#ifndef CONFIG_SPI_OWNBUS + if (nbits != priv->nbits) + { +#endif + /* Yes... Set the CON register appropriately */ + + if (nbits == 8) + { + setting = SPI_CON_MODE_8BIT; + } + else if (nbits == 16) + { + setting = SPI_CON_MODE_8BIT; + } + else if (nbits == 32) + { + setting = SPI_CON_MODE_8BIT; + } + else + { + spidbg("Unsupported nbits: %d\n", nbits); + return; + } + + regval = spi_getreg(priv, PIC32MZ_SPI_CON_OFFSET); + regval &= ~SPI_CON_MODE_MASK; + regval |= setting; + regval = spi_getreg(priv, PIC32MZ_SPI_CON_OFFSET); + spivdbg("CON: %08x\n", regval); + + /* Save the selection so the subsequence re-configurations will be faster */ + +#ifndef CONFIG_SPI_OWNBUS + priv->nbits = nbits; + } +#endif +} + +/**************************************************************************** + * Name: spi_send + * + * Description: + * Exchange one word on SPI + * + * Input Parameters: + * dev - Device-specific state data + * wd - The word to send. the size of the data is determined by the + * number of bits selected for the SPI interface. + * + * Returned Value: + * response + * + ****************************************************************************/ + +static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + + spivdbg("wd: %04x\n", wd); + + /* Write the data to transmitted to the SPI Data Register */ + + spi_putreg(priv, PIC32MZ_SPI_BUF_OFFSET, (uint32_t)wd); + +#ifdef CONFIG_PIC32MZ_SPI_ENHBUF + /* Wait for the SPIRBE bit in the SPI Status Register to be set to 0. In + * enhanced buffer mode, the SPIRBE bit will be cleared in when the + * receive buffer is not empty. + */ + + while ((spi_getreg(priv, PIC32MZ_SPI_STAT_OFFSET) & SPI_STAT_SPIRBE) != 0); +#else + /* Wait for the SPIRBF bit in the SPI Status Register to be set to 1. In + * normal mode, the SPIRBF bit will be set when receive data is available. + */ + + while ((spi_getreg(priv, PIC32MZ_SPI_STAT_OFFSET) & SPI_STAT_SPIRBF) == 0); +#endif + + /* Return the SPI data */ + + return (uint16_t)spi_getreg(priv, PIC32MZ_SPI_BUF_OFFSET); +} + +/************************************************************************* + * Name: spi_sndblock + * + * Description: + * Send a block of data on SPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer of data to be sent + * nwords - the length of data to send from the buffer in number of words. + * The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + FAR uint8_t *ptr = (FAR uint8_t*)buffer; + uint32_t regval; + uint8_t data; + + spivdbg("nwords: %d\n", nwords); + while (nwords) + { + /* Write the data to transmitted to the SPI Data Register */ + + data = *ptr++; + spi_putreg(priv, PIC32MZ_SPI_BUF_OFFSET, (uint32_t)data); + +#ifdef CONFIG_PIC32MZ_SPI_ENHBUF + /* Wait for the SPIRBE bit in the SPI Status Register to be set to 0. In + * enhanced buffer mode, the SPIRBE bit will be cleared in when the + * receive buffer is not empty. + */ + + while ((spi_getreg(priv, PIC32MZ_SPI_STAT_OFFSET) & SPI_STAT_SPIRBE) != 0); +#else + /* Wait for the SPIRBF bit in the SPI Status Register to be set to 1. In + * normal mode, the SPIRBF bit will be set when receive data is available. + */ + + while ((spi_getreg(priv, PIC32MZ_SPI_STAT_OFFSET) & SPI_STAT_SPIRBF) == 0); +#endif + + /* Read from the buffer register to clear the status bit */ + + regval = spi_getreg(priv, PIC32MZ_SPI_BUF_OFFSET); + UNUSED(regval); + nwords--; + } +} + +/**************************************************************************** + * Name: spi_recvblock + * + * Description: + * Revice a block of data from SPI + * + * Input Parameters: + * dev - Device-specific state data + * buffer - A pointer to the buffer in which to recieve data + * nwords - the length of data that can be received in the buffer in number + * of words. The wordsize is determined by the number of bits-per-word + * selected for the SPI interface. If nbits <= 8, the data is + * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords) +{ + FAR struct pic32mz_dev_s *priv = (FAR struct pic32mz_dev_s *)dev; + FAR uint8_t *ptr = (FAR uint8_t*)buffer; + + spivdbg("nwords: %d\n", nwords); + while (nwords) + { + /* Write some dummy data to the SPI Data Register in order to clock the + * read data. + */ + + spi_putreg(priv, PIC32MZ_SPI_BUF_OFFSET, 0xff); + +#ifdef CONFIG_PIC32MZ_SPI_ENHBUF + /* Wait for the SPIRBE bit in the SPI Status Register to be set to 0. In + * enhanced buffer mode, the SPIRBE bit will be cleared in when the + * receive buffer is not empty. + */ + + while ((spi_getreg(priv, PIC32MZ_SPI_STAT_OFFSET) & SPI_STAT_SPIRBE) != 0); +#else + /* Wait for the SPIRBF bit in the SPI Status Register to be set to 1. In + * normal mode, the SPIRBF bit will be set when receive data is available. + */ + + while ((spi_getreg(priv, PIC32MZ_SPI_STAT_OFFSET) & SPI_STAT_SPIRBF) == 0); +#endif + + /* Read the received data from the SPI Data Register */ + + *ptr++ = (uint8_t)spi_getreg(priv, PIC32MZ_SPI_BUF_OFFSET); + nwords--; + } +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_spiinitialize + * + * Description: + * Initialize the selected SPI port + * + * Input Parameter: + * Port number (for hardware that has mutiple SPI interfaces) + * + * Returned Value: + * Valid SPI device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct spi_dev_s *up_spiinitialize(int port) +{ + FAR struct pic32mz_dev_s *priv; + uintptr_t regaddr; + irqstate_t flags; + uint32_t regval; + + spivdbg("port: %d\n", port); + + /* Select the SPI state structure and SDI PPS register for this port */ + +#ifdef CONFIG_PIC32MZ_SPI1 + if (port == 1) + { + priv = &g_spi1dev; + regaddr = PIC32MZ_SDI1R; + } + else +#endif +#ifdef CONFIG_PIC32MZ_SPI2 + if (port == 2) + { + priv = &g_spi2dev; + regaddr = PIC32MZ_SDI2R; + } + else +#endif +#ifdef CONFIG_PIC32MZ_SPI3 + if (port == 3) + { + priv = &g_spi3dev; + regaddr = PIC32MZ_SDI3R; + } + else +#endif +#ifdef CONFIG_PIC32MZ_SPI4 + if (port == 4) + { + priv = &g_spi4dev; + regaddr = PIC32MZ_SDI4R; + } + else +#endif +#ifdef CONFIG_PIC32MZ_SPI5 + if (port == 5) + { + priv = &g_spi5dev; + regaddr = PIC32MZ_SDI5R; + } + else +#endif +#ifdef CONFIG_PIC32MZ_SPI6 + if (port == 6) + { + priv = &g_spi6dev; + regaddr = PIC32MZ_SDI6R; + } + else +#endif + { + spidbg("Unsuppport port: %d\n", port); + return NULL; + } + + /* Disable SPI interrupts */ + + flags = irqsave(); +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + up_disable_irq(priv->firq); + up_disable_irq(priv->txirq); + up_disable_irq(priv->rxirq); +#endif + + /* Stop and reset the SPI module by clearing the ON bit in the CON register. */ + + spi_putreg(priv, PIC32MZ_SPI_CON_OFFSET, 0); + + /* Clear the receive buffer by reading from the BUF register */ + + regval = spi_getreg(priv, PIC32MZ_SPI_BUF_OFFSET); + + /* Configure SPI SDI (input) and SDO (output) pins. SS (output) pins are + * managed as GPIOs; CLK (output) pins are not selectable. + */ + + putreg32((uint32_t)priv->sdipps, regaddr); + putreg32((uint32_t)priv->sdopps, priv->sdoreg); + +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + /* Attach the interrupt handlers. We do this early to make sure that the + * resources are available. + */ + + ret = irq_attach(priv->rxirq, spi_interrupt); + if (ret < 0) + { + spidbg("Failed to attach RX interrupt: %d port: %d\n", priv->rxirq, port); + goto errout; + } + + ret = irq_attach(priv->txirq, spi_interrupt); + if (ret < 0) + { + spidbg("Failed to attach TX interrupt: %d port: %d\n", priv->txirq, port); + goto errout_with_rxirq; + } + + ret = irq_attach(priv->firq, spi_interrupt); + if (ret < 0) + { + spidbg("Failed to attach fault interrupt: %d port: %d\n", priv->firq, port); + goto errout_with_txirq; + } +#endif + + /* Select a default frequency of approx. 400KHz */ + + spi_setfrequency((FAR struct spi_dev_s *)priv, 400000); + + /* Clear the SPIROV overflow bit (SPIxSTAT:6). */ + + spi_putreg(priv, PIC32MZ_SPI_STATCLR_OFFSET, SPI_STAT_SPIROV); + + /* Initial settings 8 bit + master mode + mode 0. NOTE that MSSEN + * not set: The slave select pin must be driven manually via the + * board-specific pic32mz_spiNselect() interface. + */ + + regval = (SPI_CON_MSTEN | SPI_CON_SMP | SPI_CON_MODE_8BIT | SPI_CON_ON); + + /* Set the ENHBUF bit if using Enhanced Buffer mode. */ + +#ifdef CONFIG_PIC32MZ_SPI_ENHBUF + regval |= (SPI_CON_ENHBUF | SPI_CON_SRXISEL_HALF | SPI_CON_STXISEL_HALF); +#endif + spi_putreg(priv, PIC32MZ_SPI_CON_OFFSET, regval); + spivdbg("CON: %08x\n", regval); + + /* Set the initial SPI configuration */ + +#ifndef CONFIG_SPI_OWNBUS + priv->nbits = 8; + priv->mode = SPIDEV_MODE0; +#endif + + /* Initialize the SPI semaphore that enforces mutually exclusive access */ + +#ifndef CONFIG_SPI_OWNBUS + sem_init(&priv->exclsem, 0, 1); +#endif + +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS + /* Enable interrupts at the SPI controller */ + + up_enable_irq(priv->firq); + up_enable_irq(priv->txirq); + up_enable_irq(priv->rxirq); +#endif + + /* Enable interrupts at the interrupt controller */ + + irqrestore(flags); + return &priv->spidev; + +#ifdef CONFIG_PIC32MZ_SPI_INTERRUPTS +errout_with_txirq: + irq_detatch(priv->txirq); +errout_with_rxirq: + irq_detatch(priv->rxirq); +errout: + irqrestore(flags); + return NULL; +#endif +} + +#endif /* CONFIG_PIC32MZ_SPI */