arm: K64 SPI module driver

Support for Freescale/NXP K64 SPI modules, limited to:

- Master mode
- A single active set of clock and transfer attributes (CTAR0), which
includes non-adjustable delay parameters
- Tx FIFO fill and Rx FIFO drain interrupt handling
- Standard, continuous select and continuous SCK SPI transfer formats

Also, divide-by-zero code generation in this driver is prevented.
The 'volatile' attribute is added to some of the variables in the baud
rate and delay calculation functions of the K64 SPI driver in order to
prevent bad code generation by gcc toolchains for ARM seen when an
optimization setting above -O0 is used.
Specifically, a register is loaded with the constant 0 and is used as
the divisor in a following divide instruction, resulting in a
divide-by-zero exception.
This issue has been seen with gcc versions 4.8.1 (the VxWorks toolchain)
and 5.2.0 (the Zephyr SDK toolchain).

Change-Id: Ib5b2b748aad8fdfd5e8d40544e6e1abef3713abe
Signed-off-by: Jeff Blais <jeff.blais@windriver.com>
This commit is contained in:
Jeff Blais 2016-02-18 14:38:32 -05:00 committed by Benjamin Walsh
commit 995a9ba72a
7 changed files with 1556 additions and 4 deletions

View file

@ -274,13 +274,34 @@ config PRESERVE_JTAG_IO_PINS
the Arduino header as D8, D3 and D5, respectively.
Enable this option to preserve these pins for the debug interface.
endif #PINMUX
endif # PINMUX
if PWM
config PWM_K64_FTM
def_bool y
config PWM_K64_FTM_0
def_bool y
endif
endif
config SPI
def_bool n
if SPI
config SPI_K64
def_bool y
config SPI_K64_0
def_bool y
config SPI_K64_1
def_bool n
config SPI_K64_2
def_bool n
endif
endif # SOC_FSL_FRDM_K64F

View file

@ -511,4 +511,168 @@ config SPI_QMSI_PORT_1_CS_GPIO_PIN
depends on SPI_QMSI_PORT_1 && SPI_QMSI_CS_GPIO
default 0
endif
config SPI_K64
bool
prompt "Freescale K64-based SPI controller driver"
depends on SPI
default n
help
Enable support for Freescale K64-based SPI controllers.
config SPI_K64_0
bool "Freescale K64-based SPI Module 0"
depends on SPI_K64
default n
help
Enable config options for Freescale K64-based SPI Module 0.
config SPI_K64_0_DEV_NAME
string "Freescale K64-based SPI Module 0 device name"
depends on SPI_K64_0
default "SPI_K64_0"
help
Specify the device name.
config SPI_K64_0_BASE_ADDR
hex "Freescale K64-based SPI Module 0 base address"
depends on SPI_K64_0
default 0x4002C000
config SPI_K64_0_PCS_NUM
int "Freescale K64-based SPI Module 0 peripheral chip selects"
depends on SPI_K64_0
default 6
help
Number of peripheral chip selects for K64 SPI Module 0
config SPI_K64_0_CLK_GATE_REG_ADDR
hex "Freescale K64-based SPI Module 0 clock gate register address"
depends on SPI_K64_0
default 0x4004803C
config SPI_K64_0_CLK_GATE_REG_BIT
int "Freescale K64-based SPI Module 0 clock gate register bit"
depends on SPI_K64_0
default 12
help
Bit position enable bit in the clock gate register for K64 SPI Module 0
config SPI_K64_0_IRQ
int "Freescale K64-based SPI Module 0 interrupt number"
depends on SPI_K64_0
default 26
help
K64 SPI Module 0 IRQ number for the interrupt controller
config SPI_K64_0_PRI
int "Freescale K64-based SPI Module 0 interrupt priority"
depends on SPI_K64_0
default 2
help
K64 SPI Module 0 IRQ priority
config SPI_K64_1
bool "Freescale K64-based SPI Module 1"
depends on SPI_K64
default n
help
Enable config options for Freescale K64-based SPI Module 1.
config SPI_K64_1_DEV_NAME
string "Freescale K64-based SPI Module 1 device name"
depends on SPI_K64_1
default "SPI_K64_1"
help
Specify the device name.
config SPI_K64_1_BASE_ADDR
hex "Freescale K64-based SPI Module 1 base address"
depends on SPI_K64_1
default 0x4002D000
config SPI_K64_1_PCS_NUM
int "Freescale K64-based SPI Module 1 peripheral chip selects"
depends on SPI_K64_1
default 4
help
Number of peripheral chip selects for K64 SPI Module 1
config SPI_K64_1_CLK_GATE_REG_ADDR
hex "Freescale K64-based SPI Module 1 clock gate register address"
depends on SPI_K64_1
default 0x4004803C
config SPI_K64_1_CLK_GATE_REG_BIT
int "Freescale K64-based SPI Module 0 clock gate register bit"
depends on SPI_K64_1
default 13
help
Bit position enable bit in the clock gate register for K64 SPI Module 1
config SPI_K64_1_IRQ
int "Freescale K64-based SPI Module 1 interrupt number"
depends on SPI_K64_1
default 27
help
K64 SPI Module 1 IRQ number for the interrupt controller
config SPI_K64_1_PRI
int "Freescale K64-based SPI Module 1 interrupt priority"
depends on SPI_K64_1
default 2
help
K64 SPI Module 1 IRQ priority
config SPI_K64_2
bool "Freescale K64-based SPI Module 2"
depends on SPI_K64
default n
help
Enable config options for Freescale K64-based SPI Module 2.
config SPI_K64_2_DEV_NAME
string "Freescale K64-based SPI Module 2 device name"
depends on SPI_K64_2
default "SPI_K64_2"
help
Specify the device name.
config SPI_K64_2_BASE_ADDR
hex "Freescale K64-based SPI Module 2 base address"
depends on SPI_K64_2
default 0x400AC000
config SPI_K64_2_PCS_NUM
int "Freescale K64-based SPI Module 2 peripheral chip selects"
depends on SPI_K64_2
default 2
help
Number of peripheral chip selects for K64 SPI Module 2
config SPI_K64_2_CLK_GATE_REG_ADDR
hex "Freescale K64-based SPI Module 2 clock gate register address"
depends on SPI_K64_2
default 0x40048030
config SPI_K64_2_CLK_GATE_REG_BIT
int "Freescale K64-based SPI Module 2 clock gate register bit"
depends on SPI_K64_2
default 12
help
Bit position enable bit in the clock gate register for K64 SPI Module 2
config SPI_K64_2_IRQ
int "Freescale K64-based SPI Module 2 interrupt number"
depends on SPI_K64_2
default 65
help
K64 SPI Module 2 IRQ number for the interrupt controller
config SPI_K64_2_PRI
int "Freescale K64-based SPI Module 2 interrupt priority"
depends on SPI_K64_2
default 2
help
K64 SPI Module 0 IRQ priority
endif # SPI

View file

@ -2,3 +2,4 @@ ccflags-$(CONFIG_SPI_QMSI) +=-I$(CONFIG_QMSI_INSTALL_PATH)/include
obj-$(CONFIG_SPI_INTEL) += spi_intel.o
obj-$(CONFIG_SPI_DW) += spi_dw.o
obj-$(CONFIG_SPI_QMSI) += spi_qmsi.o
obj-$(CONFIG_SPI_K64) += spi_k64.o

1115
drivers/spi/spi_k64.c Normal file

File diff suppressed because it is too large Load diff

173
drivers/spi/spi_k64_priv.h Normal file
View file

@ -0,0 +1,173 @@
/* spi_k64_priv.h - Freescale K64 SPI driver private definitions */
/*
* Copyright (c) 2015-2016 Wind River Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SPI_K64_PRIV_H__
#define __SPI_K64_PRIV_H__
typedef void (*spi_k64_config_t)(void);
struct spi_k64_config {
uint32_t regs; /* base address of SPI module registers */
uint32_t clk_gate_reg; /* SPI module's clock gate register addr. */
uint32_t clk_gate_bit; /* SPI module's clock gate bit position */
uint32_t irq; /* SPI module IRQ number */
spi_k64_config_t config_func; /* IRQ configuration function pointer */
};
struct spi_k64_data {
uint8_t frame_sz; /* frame/word size, in bits */
uint8_t cont_pcs_sel; /* continuous slave/PCS selection enable */
uint8_t pcs; /* slave/PCS selection */
const uint8_t *tx_buf;
uint32_t tx_buf_len;
uint8_t *rx_buf;
uint32_t rx_buf_len;
uint32_t xfer_len;
device_sync_call_t sync_info; /* sync call information */
uint8_t error; /* error condition */
};
/* Data transfer signal timing delays */
enum spi_k64_delay_id {
DELAY_PCS_TO_SCK,
DELAY_AFTER_SCK,
DELAY_AFTER_XFER
};
/* Register offsets */
#define SPI_K64_REG_MCR (0x00)
#define SPI_K64_REG_TCR (0x08)
#define SPI_K64_REG_CTAR0 (0x0C)
#define SPI_K64_REG_CTAR1 (0x10)
#define SPI_K64_REG_SR (0x2C)
#define SPI_K64_REG_RSER (0x30)
#define SPI_K64_REG_PUSHR (0x34)
#define SPI_K64_REG_POPR (0x38)
#define SPI_K64_REG_TXFR0 (0x3C)
#define SPI_K64_REG_RXFR0 (0x7C)
/* Module Control Register (MCR) settings */
#define SPI_K64_MCR_HALT (0x1)
#define SPI_K64_MCR_HALT_BIT (0)
#define SPI_K64_MCR_SMPL_PT_MSK (0x3 << 8)
#define SPI_K64_MCR_CLR_RXF (0x1 << 10)
#define SPI_K64_MCR_CLR_TXF (0x1 << 11)
#define SPI_K64_MCR_DIS_RXF (0x1 << 12)
#define SPI_K64_MCR_DIS_TXF (0x1 << 13)
#define SPI_K64_MCR_MDIS (0x1 << 14)
#define SPI_K64_MCR_MDIS_BIT (14)
#define SPI_K64_MCR_DOZE (0x1 << 15)
#define SPI_K64_MCR_PCSIS_MSK (0x3F << 16)
#define SPI_K64_MCR_PCSIS_SET(pcsis) ((pcsis) << 16)
#define SPI_K64_MCR_ROOE (0x1 << 24)
#define SPI_K64_MCR_PCSSE (0x1 << 25)
#define SPI_K64_MCR_MTFE (0x1 << 26)
#define SPI_K64_MCR_FRZ (0x1 << 27)
#define SPI_K64_MCR_DCONF_MSK (0x3 << 28)
#define SPI_K64_MCR_CONT_SCKE (0x1 << 30)
#define SPI_K64_MCR_CONT_SCKE_SET(cont) ((cont) << 30)
#define SPI_K64_MCR_MSTR (0x1 << 31)
/* Clock and Transfer Attributes Register (CTAR) settings */
#define SPI_K64_CTAR_BR_MSK (0xF)
#define SPI_K64_CTAR_DT_MSK (0xF << 4)
#define SPI_K64_CTAR_DT_SET(dt) ((dt) << 4)
#define SPI_K64_CTAR_ASC_MSK (0xF << 8)
#define SPI_K64_CTAR_ASC_SET(asc) ((asc) << 8)
#define SPI_K64_CTAR_CSSCK_MSK (0xF << 12)
#define SPI_K64_CTAR_CSSCK_SET(cssck) ((cssck) << 12)
#define SPI_K64_CTAR_PBR_MSK (0x3 << 16)
#define SPI_K64_CTAR_PBR_SET(pbr) ((pbr) << 16)
#define SPI_K64_CTAR_PDT_MSK (0xF << 18)
#define SPI_K64_CTAR_PDT_SET(pdt) ((pdt) << 18)
#define SPI_K64_CTAR_PASC_MSK (0xF << 20)
#define SPI_K64_CTAR_PASC_SET(pasc) ((pasc) << 20)
#define SPI_K64_CTAR_PCSSCK_MSK (0xF << 22)
#define SPI_K64_CTAR_PCSSCK_SET(pcssck) ((pcssck) << 22)
#define SPI_K64_CTAR_LSBFE (0x1 << 24)
#define SPI_K64_CTAR_CPHA (0x1 << 25)
#define SPI_K64_CTAR_CPOL (0x1 << 26)
#define SPI_K64_CTAR_FRMSZ_MSK (0xF << 27)
#define SPI_K64_CTAR_FRMSZ_SET(sz) ((sz) << 27)
#define SPI_K64_CTAR_DBR (0x1 << 31)
#define SPI_K64_CTAR_DBR_SET(dbr) ((dbr) << 31)
/* Status Register (SR) settings */
#define SPI_K64_SR_POPNXTPTR_MSK (0xF)
#define SPI_K64_SR_RXCTR_MSK (0xF << 4)
#define SPI_K64_SR_TXNXTPTR_MSK (0xF << 8)
#define SPI_K64_SR_TXCTR_MSK (0xF << 12)
#define SPI_K64_SR_RFDF (0x1 << 17)
#define SPI_K64_SR_RFOF (0x1 << 19)
#define SPI_K64_SR_TFFF (0x1 << 25)
#define SPI_K64_SR_TFUF (0x1 << 27)
#define SPI_K64_SR_EOQF (0x1 << 28)
#define SPI_K64_SR_TXRXS (0x1 << 30)
#define SPI_K64_SR_TCF (0x1 << 31)
/* DMA/Interrupt Request Select and Enable Register (RSER) settings */
#define SPI_K64_RSER_RFDF_DIRS (0x1 << 16)
#define SPI_K64_RSER_RFDF_RE (0x1 << 17)
#define SPI_K64_RSER_RFOF_RE (0x1 << 19)
#define SPI_K64_RSER_TFFF_DIRS (0x1 << 24)
#define SPI_K64_RSER_TFFF_RE (0x1 << 25)
#define SPI_K64_RSER_TFUF_RE (0x1 << 27)
#define SPI_K64_RSER_EOQF_RE (0x1 << 28)
#define SPI_K64_RSER_TCF_RE (0x1 << 31)
/* Push Tx FIFO Register (PUSHR) settings */
#define SPI_K64_PUSHR_TXDATA_MSK (0xFF)
#define SPI_K64_PUSHR_PCS_MSK (0x3F << 16)
#define SPI_K64_PUSHR_PCS_SET(pcs) ((pcs) << 16)
#define SPI_K64_PUSHR_CTCNT (0x1 << 26)
#define SPI_K64_PUSHR_EOQ (0x1 << 27)
#define SPI_K64_PUSHR_CTAS_MSK (0x7 << 28)
#define SPI_K64_PUSHR_CONT (0x1 << 31)
#define SPI_K64_PUSHR_CONT_SET(cont) ((cont) << 31)
/* Tx FIFO Register (TXFR) settings */
#define SPI_K64_TXFR_TXDATA_MSK (0xFFFF)
#define SPI_K64_TXFR_TXCMD_MSK (0xFFFF << 16)
#endif /* __SPI_K64_PRIV_H__ */

View file

@ -0,0 +1,78 @@
/* spi_k64.h - Freescale K64 SPI controller driver utilities */
/*
* Copyright (c) 2015 Wind River Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SPI_K64_H__
#define __SPI_K64_H__
/*
* Device configuration
*
* Device-independent configuration:
* Bits [0 : 11] in the config parameter of the spi_configure() API are defined
* with the following fields.
*
* SCK polarity [ 0 ] - SCK inactive state (0 = low, 1 = high)
* SCK phase [ 1 ] - Data captured/changed on which SCK edge:
* - 0 = leading/following edges, respectively
* - 1 = following/leading edges, respectively
* loop_mode [ 2 ] - Not used/Unsupported
* transfer_mode [ 3 ] - First significant bit (0 = MSB, 1 = LSB)
* word_size [ 4 : 7 ] - Size of a data train in bits
* unused [ 8 : 11 ] - Unused word_size field bits
*
* Device-specific configuration:
* Bits [12 : 31] in the config parameter of the spi_configure() API are
* available, with the following fields defined for this device.
*
* PCS0-5 polarity [ 12 : 17 ] - Periph. Chip Select inactive state, MCR[PCSIS]
* - (0 = low, 1 = high)
* Continuous SCK [ 18 ] - Continuous serial clocking, MCR[CONT_SCKE]
* - (0 = disabled, 1 = enabled)
* Continuous PCS [ 19 ] - Continuous selection format, PUSHR[CONT]
* - (0 = disabled, 1 = enabled)
*
* Note that the number of valid PCS signals differs for each
* K64 SPI module:
* - SPI0 uses PCS0-5;
* - SPI1 uses PCS0-3;
* - SPI2 uses PCS0-1;
*/
/* PCS polarity access macros */
#define SPI_PCS_POL_MASK (0x3F << 12)
#define SPI_PCS_POL_GET(_in_) (((_in_) & SPI_PCS_POL_MASK) >> 12)
#define SPI_PCS_POL_SET(_in_) ((_in_) << 12)
/* Continuous SCK access macros */
#define SPI_CONT_SCK_MASK (0x1 << 18)
#define SPI_CONT_SCK_GET(_in_) (((_in_) & SPI_CONT_SCK_MASK) >> 18)
#define SPI_CONT_SCK_SET(_in_) ((_in_) << 18)
/* Continuous PCS access macros */
#define SPI_CONT_PCS_MASK (0x1 << 19)
#define SPI_CONT_PCS_GET(_in_) (((_in_) & SPI_CONT_PCS_MASK) >> 19)
#define SPI_CONT_PCS_SET(_in_) ((_in_) << 19)
/* K64 SPI word/frame size is limited to 16 bits, represented as: (size - 1) */
#define SPI_K64_WORD_SIZE_MAX (16)
#endif /* __SPI_K64_H__ */

View file

@ -66,7 +66,7 @@ extern "C" {
* mode [ 0 : 2 ] - Polarity, phase and loop mode.
* transfer_mode [ 3 ] - LSB or MSB first transfer mode.
* word_size [ 4 : 11 ] - Size of a data frame in bits.
* RESERVED [ 12 : 31 ] - undefined usage.
* RESERVED [ 12 : 31 ] - Undefined or device-specific usage.
*
* max_sys_freq is the maximum frequency supported by the slave it
* will deal with. This value depends on the host controller. The driver