mirror of
https://github.com/apache/nuttx.git
synced 2026-08-31 22:23:03 +00:00
Add support for SPI through i.MX8MP ecspi module.
Configure SPI for Verdin evaluation board
This commit is contained in:
parent
21beb284bc
commit
f38cdb09b4
13 changed files with 1310 additions and 3 deletions
|
|
@ -84,6 +84,45 @@ if MX8MP_I2C
|
|||
in any real driver application.
|
||||
|
||||
endif # MX8MP_I2C
|
||||
|
||||
#####################################################################
|
||||
# SPI Configuration (Master)
|
||||
#####################################################################
|
||||
|
||||
config MX8MP_SPI
|
||||
bool "SPI Master"
|
||||
select SPI
|
||||
---help---
|
||||
Build in support for SPI master mode.
|
||||
|
||||
if MX8MP_SPI
|
||||
|
||||
config MX8MP_SPI1
|
||||
bool "SPI1"
|
||||
default n
|
||||
select SPI
|
||||
|
||||
config MX8MP_SPI2
|
||||
bool "SPI2"
|
||||
default n
|
||||
select SPI
|
||||
|
||||
config MX8MP_SPI3
|
||||
bool "SPI3"
|
||||
default n
|
||||
select SPI
|
||||
|
||||
config MX8MP_SPI_DRIVER
|
||||
bool "SPI character driver"
|
||||
default n
|
||||
select SPI_DRIVER
|
||||
---help---
|
||||
Build in support for a character driver at /dev/spi[N] that may b
|
||||
used to perform SPI bus transfers from applications. The intent of
|
||||
this driver is to support SPI testing.
|
||||
|
||||
endif # MX8MP_SPI
|
||||
|
||||
endmenu
|
||||
|
||||
# These "hidden" settings determine whether a peripheral option is available
|
||||
|
|
|
|||
|
|
@ -39,3 +39,7 @@ endif
|
|||
ifeq ($(CONFIG_I2C),y)
|
||||
CHIP_CSRCS += mx8mp_i2c.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SPI),y)
|
||||
CHIP_CSRCS += mx8mp_ecspi.c
|
||||
endif
|
||||
|
|
|
|||
102
arch/arm/src/mx8mp/hardware/mx8mp_ecspi.h
Normal file
102
arch/arm/src/mx8mp/hardware/mx8mp_ecspi.h
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/mx8mp/hardware/mx8mp_ecspi.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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 __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_ECSPI_H
|
||||
#define __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_ECSPI_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/* ECSPI Register Offsets ***************************************************/
|
||||
|
||||
#define RXDATA_OFFSET 0x0000
|
||||
#define TXDATA_OFFSET 0x0004
|
||||
#define CONREG_OFFSET 0x0008
|
||||
#define CONFIGREG_OFFSET 0x000c
|
||||
#define INTREG_OFFSET 0x0010
|
||||
#define DMAREG_OFFSET 0x0014
|
||||
#define STATREG_OFFSET 0x0018
|
||||
#define PERIODREG_OFFSET 0x001C
|
||||
#define TESTREG_OFFSET 0x0020
|
||||
#define MSGDATA_OFFSET 0x0040
|
||||
|
||||
/* ECSPI Register Bit Definitions *******************************************/
|
||||
|
||||
#define CONREG_BURST_LENGTH (20)
|
||||
#define CONREG_CHANNEL_SELECT (18)
|
||||
#define CONREG_PRE_DIVIDER (12)
|
||||
#define CONREG_POST_DIVIDER (8)
|
||||
#define CONREG_CHANNEL_MODE (4)
|
||||
#define CONREG_SMC (1 << 3)
|
||||
#define CONREG_XCH (1 << 2)
|
||||
#define CONREG_HT (1 << 1)
|
||||
#define CONREG_EN (1 << 0)
|
||||
|
||||
#define CONFIGREG_HT_LENGTH (24)
|
||||
#define CONFIGREG_SLCK_CTL (20)
|
||||
#define CONFIGREG_DATA_CTL (16)
|
||||
#define CONFIGREG_SS_POL (12)
|
||||
#define CONFIGREG_SS_CTL (8)
|
||||
#define CONFIGREG_SCLK_POL (4)
|
||||
#define CONFIGREG_SCLK_PHA (0)
|
||||
|
||||
#define INTREG_TCEN (1 << 7)
|
||||
#define INTREG_ROEN (1 << 6)
|
||||
#define INTREG_RFEN (1 << 5)
|
||||
#define INTREG_RDREN (1 << 4)
|
||||
#define INTREG_RREN (1 << 3)
|
||||
#define INTREG_TFEN (1 << 2)
|
||||
#define INTREG_TDREN (1 << 1)
|
||||
#define INTREG_TEEN (1 << 0)
|
||||
|
||||
#define DMAREG_RXTDEN (1 << 31)
|
||||
#define DMAREG_RX_DMA_LENGTH (24)
|
||||
#define DMAREG_RXDEN (1 << 23)
|
||||
#define DMAREG_RX_THRESHOLD (16)
|
||||
#define DMAREG_TEDEN (1 << 7)
|
||||
#define DMAREG_TX_THRESHOLD (0)
|
||||
|
||||
#define STATREG_TC (1 << 7)
|
||||
#define STATREG_RO (1 << 6)
|
||||
#define STATREG_RF (1 << 5)
|
||||
#define STATREG_RDR (1 << 4)
|
||||
#define STATREG_RR (1 << 3)
|
||||
#define STATREG_TF (1 << 2)
|
||||
#define STATREG_TDR (1 << 1)
|
||||
#define STATREG_TE (1 << 0)
|
||||
|
||||
#define PERIODREG_CSD_CTL (16)
|
||||
#define PERIODREG_CSRC (1 << 15)
|
||||
#define PERIODREG_SAMPLE_PERIOD (0)
|
||||
|
||||
#define TESTREG_LBC (1 << 31)
|
||||
#define TESTREG_RXCNT (8)
|
||||
#define TESTREG_TXCNT (0)
|
||||
|
||||
/****************************************************************************
|
||||
* Inline Functions
|
||||
****************************************************************************/
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_ECSPI_H */
|
||||
|
|
@ -924,5 +924,6 @@
|
|||
|
||||
#define GPIO_PAD_CTRL (PAD_CTL_HYS | PAD_CTL_PUE | PAD_CTL_PE | PAD_CTL_DSE2)
|
||||
#define UART_PAD_CTRL (PAD_CTL_PUE | PAD_CTL_PE)
|
||||
#define SPI_PAD_CTRL (PAD_CTL_PUE)
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_MX8MP_HARDWARE_MX8MP_PINMUX_H */
|
||||
|
|
|
|||
747
arch/arm/src/mx8mp/mx8mp_ecspi.c
Normal file
747
arch/arm/src/mx8mp/mx8mp_ecspi.c
Normal file
|
|
@ -0,0 +1,747 @@
|
|||
/******************************************************************************
|
||||
* arch/arm/src/mx8mp/mx8mp_ecspi.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* Included Files
|
||||
******************************************************************************/
|
||||
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/spi/spi.h>
|
||||
|
||||
#include "mx8mp_ecspi.h"
|
||||
#include "mx8mp_ccm.h"
|
||||
#include "hardware/mx8mp_memorymap.h"
|
||||
#include "hardware/mx8mp_ecspi.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include "arm_internal.h"
|
||||
|
||||
/******************************************************************************
|
||||
* Pre-processor Definitions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* Private Function Prototypes
|
||||
******************************************************************************/
|
||||
|
||||
struct mx8mp_spi_s;
|
||||
|
||||
static void mx8mp_spi_enable(struct mx8mp_spi_s *dev);
|
||||
static int mx8mp_spi_interrupt(int irq, void *context, void *arg);
|
||||
static int mx8mp_spi_transfer(struct mx8mp_spi_s *priv,
|
||||
const uint8_t *out, uint8_t *in, int size);
|
||||
|
||||
/* SPI methods */
|
||||
|
||||
static int spi_lock(struct spi_dev_s *dev, bool lock);
|
||||
static uint32_t spi_setfrequency(struct spi_dev_s *dev, uint32_t frequency);
|
||||
static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode);
|
||||
static void spi_setbits(struct spi_dev_s *dev, int nbits);
|
||||
#ifdef CONFIG_SPI_HWFEATURES
|
||||
static int spi_hwfeatures(struct spi_dev_s *dev, spi_hwfeatures_t features);
|
||||
#endif
|
||||
static uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd);
|
||||
static void spi_exchange(struct spi_dev_s *dev,
|
||||
const void *txbuffer, void *rxbuffer, size_t nwords);
|
||||
#ifdef CONFIG_SPI_TRIGGER
|
||||
static int spi_trigger(struct spi_dev_s *dev);
|
||||
#endif
|
||||
#ifndef CONFIG_SPI_EXCHANGE
|
||||
static void spi_sndblock (struct spi_dev_s *dev,
|
||||
const void *txbuffer, size_t nwords);
|
||||
static void spi_recvblock(struct spi_dev_s *dev,
|
||||
void *rxbuffer, size_t nwords);
|
||||
#endif
|
||||
|
||||
/* Initialization */
|
||||
|
||||
static void spi_bus_initialize(struct mx8mp_spi_s *priv);
|
||||
|
||||
/******************************************************************************
|
||||
* Private Types
|
||||
******************************************************************************/
|
||||
|
||||
struct mx8mp_spi_s
|
||||
{
|
||||
struct spi_dev_s dev; /* Externally visible part of the SPI interface */
|
||||
uint32_t base; /* SPI base address */
|
||||
int clock; /* Peripheral clock as described in hardware/mx8mp_ccm.h */
|
||||
uint16_t irq; /* IRQ number */
|
||||
uint32_t frequency; /* Current desired SCLK frequency */
|
||||
uint32_t actual; /* TODO: check use - Current actual SCLK frequency */
|
||||
uint8_t nbits; /* Width of word in bits (8 to 16) */
|
||||
uint8_t mode; /* Mode 0,1,2,3 */
|
||||
mutex_t lock; /* Only one thread can access at a time */
|
||||
sem_t wait; /* IRQ wait sync */
|
||||
uint32_t byte_duration; /* Byte duration - depend on clock */
|
||||
};
|
||||
|
||||
/* SPI device structures */
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI1
|
||||
static const struct spi_ops_s g_spi1_ops =
|
||||
{
|
||||
.lock = spi_lock,
|
||||
.select = mx8mp_spi1_select, /* Provided externally by board logic */
|
||||
.setfrequency = spi_setfrequency,
|
||||
.setmode = spi_setmode,
|
||||
.setbits = spi_setbits,
|
||||
#ifdef CONFIG_SPI_HWFEATURES
|
||||
.hwfeatures = 0, /* Not supported */
|
||||
#endif
|
||||
.status = mx8mp_spi1_status, /* Provided externally by board logic */
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
.cmddata = mx8mp_spi1_cmddata,
|
||||
#endif
|
||||
.send = spi_send,
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
.exchange = spi_exchange,
|
||||
#else
|
||||
.sndblock = spi_sndblock,
|
||||
.recvblock = spi_recvblock,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct mx8mp_spi_s g_spi1_dev =
|
||||
{
|
||||
.dev.ops = &g_spi1_ops,
|
||||
.base = MX8M_ECSPI1,
|
||||
.clock = ECSPI1_CLK_ROOT,
|
||||
.irq = MX8MP_IRQ_ECSPI1,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.wait = SEM_INITIALIZER(0),
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI2
|
||||
static const struct spi_ops_s g_spi2_ops =
|
||||
{
|
||||
.lock = spi_lock,
|
||||
.select = mx8mp_spi2_select, /* Provided externally by board logic */
|
||||
.setfrequency = spi_setfrequency,
|
||||
.setmode = spi_setmode,
|
||||
.setbits = spi_setbits,
|
||||
#ifdef CONFIG_SPI_HWFEATURES
|
||||
.hwfeatures = 0, /* Not supported */
|
||||
#endif
|
||||
.status = mx8mp_spi2_status, /* Provided externally by board logic */
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
.cmddata = mx8mp_spi2_cmddata,
|
||||
#endif
|
||||
.send = spi_send,
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
.exchange = spi_exchange,
|
||||
#else
|
||||
.sndblock = spi_sndblock,
|
||||
.recvblock = spi_recvblock,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct mx8mp_spi_s g_spi1_dev =
|
||||
{
|
||||
.dev.ops = &g_spi2_ops,
|
||||
.base = MX8M_ECSPI2,
|
||||
.clock = ECSPI2_CLK_ROOT,
|
||||
.irq = MX8MP_IRQ_ECSPI2,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.wait = SEM_INITIALIZER(0),
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI3
|
||||
static const struct spi_ops_s g_spi3_ops =
|
||||
{
|
||||
.lock = spi_lock,
|
||||
.select = mx8mp_spi3_select, /* Provided externally by board logic */
|
||||
.setfrequency = spi_setfrequency,
|
||||
.setmode = spi_setmode,
|
||||
.setbits = spi_setbits,
|
||||
#ifdef CONFIG_SPI_HWFEATURES
|
||||
.hwfeatures = 0, /* Not supported */
|
||||
#endif
|
||||
.status = mx8mp_spi3_status, /* Provided externally by board logic */
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
.cmddata = mx8mp_spi3_cmddata,
|
||||
#endif
|
||||
.send = spi_send,
|
||||
#ifdef CONFIG_SPI_EXCHANGE
|
||||
.exchange = spi_exchange,
|
||||
#else
|
||||
.sndblock = spi_sndblock,
|
||||
.recvblock = spi_recvblock,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct mx8mp_spi_s g_spi3_dev =
|
||||
{
|
||||
.dev.ops = &g_spi3_ops,
|
||||
.base = MX8M_ECSPI3,
|
||||
.clock = ECSPI3_CLK_ROOT,
|
||||
.irq = MX8MP_IRQ_ECSPI3,
|
||||
.lock = NXMUTEX_INITIALIZER,
|
||||
.wait = SEM_INITIALIZER(0),
|
||||
};
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
* Private Data
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* Private Functions
|
||||
******************************************************************************/
|
||||
|
||||
static void mx8mp_spi_enable(struct mx8mp_spi_s *priv)
|
||||
{
|
||||
/* enable and set all channels to master mode */
|
||||
|
||||
modreg32(CONREG_EN, CONREG_EN, priv->base + CONREG_OFFSET);
|
||||
modreg32(0xf << CONREG_CHANNEL_MODE,
|
||||
0xf << CONREG_CHANNEL_MODE, priv->base + CONREG_OFFSET);
|
||||
|
||||
/* select channel 0 (the only one available) */
|
||||
|
||||
modreg32(0, 0x3 << CONREG_CHANNEL_SELECT, priv->base + CONREG_OFFSET);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: mx8mp_spi_wait_irq
|
||||
*
|
||||
* Description:
|
||||
* Wait for the IRQ to be triggered.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static inline int mx8mp_spi_wait_irq(struct mx8mp_spi_s *priv, int usec)
|
||||
{
|
||||
return nxsem_tickwait(&priv->wait, USEC2TICK(usec));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: mx8mp_spi_interrupt
|
||||
*
|
||||
* Description:
|
||||
* The SPI common interrupt handler
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static int mx8mp_spi_interrupt(int irq, void *context, void *arg)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)arg;
|
||||
nxsem_post(&priv->wait);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: mx8mp_spi_transfer
|
||||
*
|
||||
* Description:
|
||||
* Do a transfer on the SPI bus. It may be needed to call it multiple times
|
||||
* since SPI FIFO is limited to 256 bytes (64 x 32bits)
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static int mx8mp_spi_transfer(struct mx8mp_spi_s *priv,
|
||||
const uint8_t *out, uint8_t *in, int size)
|
||||
{
|
||||
/* max 256 bytes per access (64 x 32 bits) */
|
||||
|
||||
if (size > 256)
|
||||
{
|
||||
size = 256;
|
||||
}
|
||||
|
||||
/* WARNING: SPI FIFO works on 32 bits data only */
|
||||
|
||||
/* 1. clear IRQs */
|
||||
|
||||
modreg32(0, STATREG_TC | STATREG_RO, priv->base + STATREG_OFFSET);
|
||||
|
||||
/* 2. compute words to process */
|
||||
|
||||
uint16_t words = size / 4;
|
||||
uint16_t remaining_bytes = size % 4;
|
||||
|
||||
/* 3. Configure burst size (in bits) and RX IT threshold (in words) */
|
||||
|
||||
uint16_t const burst_length = ((words * 4 + remaining_bytes) * 8) & 0xfff;
|
||||
modreg32((burst_length - 1) << CONREG_BURST_LENGTH,
|
||||
0xfff << CONREG_BURST_LENGTH,
|
||||
priv->base + CONREG_OFFSET);
|
||||
|
||||
uint16_t threshold = words;
|
||||
if (remaining_bytes)
|
||||
{
|
||||
++threshold;
|
||||
}
|
||||
|
||||
putreg32((threshold - 1) << DMAREG_RX_THRESHOLD, priv->base + DMAREG_OFFSET);
|
||||
|
||||
/* 4. Load TX FIFO - remaining byte on the first word */
|
||||
|
||||
if (remaining_bytes)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
for (int32_t i = 0; i < remaining_bytes; ++i)
|
||||
{
|
||||
data = (data << 8) | out[i];
|
||||
}
|
||||
|
||||
putreg32(data, priv->base + TXDATA_OFFSET);
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < words; ++i)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
memcpy(&data, out + i * 4 + remaining_bytes, 4);
|
||||
data = __builtin_bswap32(data);
|
||||
putreg32(data, priv->base + TXDATA_OFFSET);
|
||||
}
|
||||
|
||||
/* 5. start transfer and wait for it */
|
||||
|
||||
modreg32(CONREG_XCH, CONREG_XCH, priv->base + CONREG_OFFSET);
|
||||
int ret = mx8mp_spi_wait_irq(priv, priv->byte_duration * (size + 1)); /* add one byte duration of leeway */
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* 6. Unload RX FIFO (even if an error occured to empty the queue) */
|
||||
|
||||
if (remaining_bytes)
|
||||
{
|
||||
uint32_t data = getreg32(priv->base + RXDATA_OFFSET);
|
||||
data = __builtin_bswap32(data);
|
||||
data >>= (4 - remaining_bytes) * 8;
|
||||
memcpy(in, &data, remaining_bytes);
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < words; ++i)
|
||||
{
|
||||
uint32_t data = getreg32(priv->base + RXDATA_OFFSET);
|
||||
data = __builtin_bswap32(data);
|
||||
memcpy(in + i * 4 + remaining_bytes, &data, 4);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: spi_lock
|
||||
*
|
||||
* Description:
|
||||
* On SPI buses where there are multiple devices, it will be necessary to
|
||||
* lock SPI to have exclusive access to the buses 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 bus 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
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static int spi_lock(struct spi_dev_s *dev, bool lock)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)dev;
|
||||
int ret;
|
||||
|
||||
if (lock)
|
||||
{
|
||||
ret = nxmutex_lock(&priv->lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = nxmutex_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* 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(struct spi_dev_s *dev, uint32_t frequency)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)dev;
|
||||
|
||||
if (frequency == priv->frequency)
|
||||
{
|
||||
return priv->actual;
|
||||
}
|
||||
|
||||
uint32_t clock = mx8mp_ccm_get_clock(priv->clock);
|
||||
DEBUGASSERT(clock > frequency);
|
||||
|
||||
uint8_t pre_div = 0;
|
||||
uint8_t post_div = 0;
|
||||
uint32_t old_frequency = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 16; ++i)
|
||||
{
|
||||
for (uint8_t j = 0; j < 16; ++j)
|
||||
{
|
||||
uint32_t current_frequency = clock / ((1 << i) * (j + 1));
|
||||
if ((current_frequency <= frequency) &&
|
||||
(current_frequency > old_frequency))
|
||||
{
|
||||
pre_div = j;
|
||||
post_div = i;
|
||||
old_frequency = current_frequency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
priv->actual = clock / ((1 << post_div) * (pre_div + 1));
|
||||
|
||||
spiinfo("Source clock: %lu", clock);
|
||||
spiinfo("Requested freq: %lu", frequency);
|
||||
spiinfo("pre_divider: %u", pre_div);
|
||||
spiinfo("post_divider: %u", post_div);
|
||||
spiinfo("Actual freq: %lu", priv->actual);
|
||||
|
||||
modreg32(pre_div << CONREG_PRE_DIVIDER, 0xf << CONREG_PRE_DIVIDER,
|
||||
priv->base + CONREG_OFFSET);
|
||||
modreg32(post_div << CONREG_POST_DIVIDER, 0xf << CONREG_POST_DIVIDER,
|
||||
priv->base + CONREG_OFFSET);
|
||||
|
||||
/* Store byte duration to adapt irq waiting time */
|
||||
|
||||
priv->byte_duration = (USEC_PER_SEC / priv->actual) * 8;
|
||||
|
||||
return priv->actual;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: spi_setmode
|
||||
*
|
||||
* Description:
|
||||
* Set the SPI mode. see enum spi_mode_e for mode definitions
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* mode - The SPI mode requested
|
||||
*
|
||||
* Returned Value:
|
||||
* Returns the actual frequency selected
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void spi_setmode(struct spi_dev_s *dev, enum spi_mode_e mode)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)dev;
|
||||
uint8_t CPOL;
|
||||
uint8_t CPHA;
|
||||
|
||||
spiinfo("mode=%d\n", mode);
|
||||
|
||||
/* Has the mode changed? */
|
||||
|
||||
if (mode == priv->mode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case SPIDEV_MODE0:
|
||||
{
|
||||
CPOL = 0;
|
||||
CPHA = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SPIDEV_MODE1:
|
||||
{
|
||||
CPOL = 0;
|
||||
CPHA = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SPIDEV_MODE2:
|
||||
{
|
||||
CPOL = 1;
|
||||
CPHA = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SPIDEV_MODE3:
|
||||
{
|
||||
CPOL = 1;
|
||||
CPHA = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t configreg = 0;
|
||||
configreg |= (0xf << CONFIGREG_SLCK_CTL);
|
||||
configreg |= (0xf << CONFIGREG_DATA_CTL);
|
||||
configreg |= (0x0 << CONFIGREG_SS_POL);
|
||||
configreg |= (0x0 << CONFIGREG_SS_CTL);
|
||||
configreg |= (CPOL << CONFIGREG_SCLK_POL);
|
||||
configreg |= (CPHA << CONFIGREG_SCLK_PHA);
|
||||
putreg32(configreg, priv->base + CONFIGREG_OFFSET);
|
||||
|
||||
/* Save the mode so that subsequent re-configurations will be
|
||||
* faster
|
||||
*/
|
||||
|
||||
priv->mode = mode;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: spi_setbits
|
||||
*
|
||||
* Description:
|
||||
* Set the number of bits per word.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* nbits - The number of bits requested
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void spi_setbits(struct spi_dev_s *dev, int nbits)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)dev;
|
||||
|
||||
spiinfo("nbits=%d\n", nbits);
|
||||
|
||||
/* Has the number of bits changed? */
|
||||
|
||||
if (nbits == priv->nbits)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
modreg32(nbits << CONREG_BURST_LENGTH,
|
||||
0xfff << CONREG_BURST_LENGTH,
|
||||
priv->base + CONREG_OFFSET);
|
||||
|
||||
/* Save the selection so that subsequent re-configurations will be faster. */
|
||||
|
||||
priv->nbits = nbits;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* 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 uint32_t spi_send(struct spi_dev_s *dev, uint32_t wd)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)dev;
|
||||
uint32_t ret;
|
||||
|
||||
DEBUGASSERT(priv && priv->base);
|
||||
|
||||
uint32_t dummy;
|
||||
ret = mx8mp_spi_transfer(priv, (const uint8_t *)&wd,
|
||||
(uint8_t *)&dummy,
|
||||
priv->nbits % 8);
|
||||
|
||||
spiinfo("Sent: %04" PRIx32 " Return: %04" PRIx32
|
||||
" Status: %02" PRIx32 "\n", wd, ret, dummy);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: spi_exchange (no DMA)
|
||||
*
|
||||
* Description:
|
||||
* Exchange a block of data on SPI without using DMA
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - Device-specific state data
|
||||
* txbuffer - A pointer to the buffer of data to be sent
|
||||
* rxbuffer - A pointer to a buffer in which to receive data
|
||||
* nwords - the length of data to be exchanged in units 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_exchange(struct spi_dev_s *dev, const void *txbuffer,
|
||||
void *rxbuffer, size_t nwords)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = (struct mx8mp_spi_s *)dev;
|
||||
|
||||
int size = nwords;
|
||||
if (priv->nbits > 8)
|
||||
{
|
||||
size = size * 2;
|
||||
}
|
||||
|
||||
int transfered = 0;
|
||||
while (transfered < size)
|
||||
{
|
||||
int ret = mx8mp_spi_transfer(priv,
|
||||
(const uint8_t *)txbuffer + transfered,
|
||||
(uint8_t *)rxbuffer + transfered,
|
||||
size - transfered);
|
||||
if (ret < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
transfered += ret;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Name: spi_bus_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the selected SPI bus in its default state (Master, 8-bit,
|
||||
* mode 0, etc.)
|
||||
*
|
||||
* Input Parameters:
|
||||
* priv - private SPI device structure
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static void spi_bus_initialize(struct mx8mp_spi_s *priv)
|
||||
{
|
||||
priv->frequency = 0;
|
||||
priv->nbits = 0;
|
||||
priv->mode = SPIDEV_MODE1; /* Ensure that mode0 is applied */
|
||||
|
||||
/* Enable SPI */
|
||||
|
||||
mx8mp_spi_enable(priv);
|
||||
|
||||
/* Select a default frequency of approx. 400KHz */
|
||||
|
||||
spi_setfrequency((struct spi_dev_s *)priv, 400000);
|
||||
|
||||
/* Apply a default configuration */
|
||||
|
||||
spi_setbits((struct spi_dev_s *)priv, 8);
|
||||
spi_setmode((struct spi_dev_s *)priv, SPIDEV_MODE0);
|
||||
|
||||
/* Attach Interrupt Handler */
|
||||
|
||||
irq_attach(priv->irq, mx8mp_spi_interrupt, priv);
|
||||
|
||||
/* Enable Interrupt Handler */
|
||||
|
||||
up_enable_irq(priv->irq);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Public Functions
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
* Name: mx8mp_spibus_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the selected SPI bus
|
||||
*
|
||||
* Input Parameters:
|
||||
* Port number (for hardware that has multiple SPI interfaces)
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid SPI device structure reference on success; a NULL on failure
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct spi_dev_s *mx8mp_spibus_initialize(int bus)
|
||||
{
|
||||
struct mx8mp_spi_s *priv = NULL;
|
||||
|
||||
irqstate_t flags = enter_critical_section();
|
||||
|
||||
switch (bus)
|
||||
{
|
||||
#ifdef CONFIG_MX8MP_SPI1
|
||||
case 1:
|
||||
priv = &g_spi1_dev;
|
||||
spi_bus_initialize(priv);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI2
|
||||
case 2:
|
||||
priv = &g_spi2_dev;
|
||||
spi_bus_initialize(priv);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI3
|
||||
case 3:
|
||||
priv = &g_spi3_dev;
|
||||
spi_bus_initialize(priv);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
spierr("ERROR: Unsupported SPI bus: %d\n", bus);
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return (struct spi_dev_s *)priv;
|
||||
}
|
||||
114
arch/arm/src/mx8mp/mx8mp_ecspi.h
Normal file
114
arch/arm/src/mx8mp/mx8mp_ecspi.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/****************************************************************************
|
||||
* arch/arm/src/mx8mp/mx8mp_ecspi.h
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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 __ARCH_ARM_SRC_MX8MP_MX8MP_ECSPI_H
|
||||
#define __ARCH_ARM_SRC_MX8MP_MX8MP_ECSPI_H
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
struct spi_dev_s;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mx8mp_spibus_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize the selected SPI bus
|
||||
*
|
||||
* Input Parameters:
|
||||
* bus number (for hardware that has multiple SPI interfaces)
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid SPI device structure reference on success; a NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
struct spi_dev_s *mx8mp_spibus_initialize(int bus);
|
||||
|
||||
/****************************************************************************
|
||||
* Name:
|
||||
* mx8mp_spi[n]select, mx8mp_spi[n]status, and mx8mp_spi[n]cmddata
|
||||
*
|
||||
* Description:
|
||||
* These external functions must be provided by board-specific logic.
|
||||
* They are implementations of the select, status, and cmddata methods of
|
||||
* the SPI interface defined by struct spi_ops_s
|
||||
* (see include/nuttx/spi/spi.h). All other methods including
|
||||
* mx8mp_spibus_initialize()) are provided by common Kinetis logic.
|
||||
* To use this common SPI logic on your board:
|
||||
*
|
||||
* 1. Provide logic in mx8mp_boardinitialize() to configure SPI chip
|
||||
* select pins.
|
||||
* 2. Provide mx8mp_spi[n]select() and mx8mp_spi[n]status() functions
|
||||
* in your board-specific logic. These functions will perform chip
|
||||
* selection and status operations using GPIOs in the way your board is
|
||||
* configured.
|
||||
* 2. If CONFIG_SPI_CMDDATA is defined in the NuttX configuration, provide
|
||||
* mx8mp_spi[n]cmddata() functions in your board-specific logic.
|
||||
* These functions will perform cmd/data selection operations using
|
||||
* GPIOs in the way your board is configured.
|
||||
* 3. Add a call to mx8mp_spibus_initialize() in your low level
|
||||
* application initialization logic
|
||||
* 4. The handle returned by mx8mp_spibus_initialize() may then be used
|
||||
* to bind the SPI driver to higher level logic (e.g., calling
|
||||
* mmcsd_spislotinitialize(), for example, will bind the SPI driver to
|
||||
* the SPI MMC/SD driver).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI1
|
||||
void mx8mp_spi1_select(struct spi_dev_s *dev,
|
||||
uint32_t devid, bool selected);
|
||||
uint8_t mx8mp_spi1_status(struct spi_dev_s *dev, uint32_t devid);
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
int mx8mp_spi1_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI2
|
||||
void mx8mp_spi2_select(struct spi_dev_s *dev,
|
||||
uint32_t devid, bool selected);
|
||||
uint8_t mx8mp_spi2_status(struct spi_dev_s *dev, uint32_t devid);
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
int mx8mp_spi2_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI3
|
||||
void mx8mp_spi3_select(struct spi_dev_s *dev,
|
||||
uint32_t devid, bool selected);
|
||||
uint8_t mx8mp_spi3_status(struct spi_dev_s *dev, uint32_t devid);
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
int mx8mp_spi3_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif /* __ARCH_ARM_SRC_MX8MP_MX8MP_ECSPI_H */
|
||||
|
|
@ -22,12 +22,13 @@
|
|||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include <nuttx/signal.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
|
||||
#include "mx8mp_i2c.h"
|
||||
#include "mx8mp_ccm.h"
|
||||
#include "hardware/mx8mp_memorymap.h"
|
||||
#include "hardware/mx8mp_i2c.h"
|
||||
|
||||
#include <debug.h>
|
||||
#include "arm_internal.h"
|
||||
|
|
|
|||
|
|
@ -26,8 +26,12 @@
|
|||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/i2c/i2c_master.h>
|
||||
#include "hardware/mx8mp_i2c.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
|
||||
struct i2c_master_s;
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@ ifeq ($(CONFIG_MX8MP_I2C_DRIVER),y)
|
|||
CSRCS += mx8mp_i2cdev.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SPI),y)
|
||||
CSRCS += mx8mp_spi.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_MX8MP_SPI_DRIVER),y)
|
||||
CSRCS += mx8mp_spidev.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ARCH_LEDS),y)
|
||||
CSRCS += mx8mp_autoleds.c
|
||||
else
|
||||
|
|
|
|||
|
|
@ -115,5 +115,15 @@ int mx8mp_bringup(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI_DRIVER
|
||||
/* Initialize SPI buses */
|
||||
|
||||
ret = mx8mp_spidev_initialize();
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "ERROR: spidev_initialize() failed: %d\n", ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
122
boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_spi.c
Normal file
122
boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_spi.c
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/****************************************************************************
|
||||
* boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_spi.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/spi/spi.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "chip.h"
|
||||
#include "mx8mp_gpio.h"
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mx8mp_spi1/2/3select and mx8mp_spi1/2/3status
|
||||
*
|
||||
* Description:
|
||||
* The external functions, mx8mp_spi1/2/3select and mx8mp_spi1/2/3status
|
||||
* must be provided by board-specific logic.
|
||||
* They are implementations of the select and status methods of the SPI
|
||||
* interface defined by struct spi_ops_s (see include/nuttx/spi/spi.h).
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI1
|
||||
void mx8mp_spi1_select(struct spi_dev_s *dev, uint32_t devid,
|
||||
bool selected)
|
||||
{
|
||||
spiinfo("devid: %d CS: %s\n", (int)devid,
|
||||
selected ? "assert" : "de-assert");
|
||||
|
||||
/* nothing to do : CS handled by module */
|
||||
}
|
||||
|
||||
uint8_t mx8mp_spi1_status(struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
int mx8mp_spi1_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI2
|
||||
void mx8mp_spi2_select(struct spi_dev_s *dev, uint32_t devid,
|
||||
bool selected)
|
||||
{
|
||||
spiinfo("devid: %d CS: %s\n", (int)devid,
|
||||
selected ? "assert" : "de-assert");
|
||||
|
||||
mx8mp_gpio_write(GPIO_SPI2_CS, !selected);
|
||||
}
|
||||
|
||||
uint8_t mx8mp_spi2_status(struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
int mx8mp_spi2_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI3
|
||||
void mx8mp_spi3_select(struct spi_dev_s *dev, uint32_t devid,
|
||||
bool selected)
|
||||
{
|
||||
spiinfo("devid: %d CS: %s\n", (int)devid,
|
||||
selected ? "assert" : "de-assert");
|
||||
|
||||
mx8mp_gpio_write(GPIO_SPI3_CS, !selected);
|
||||
}
|
||||
|
||||
uint8_t mx8mp_spi3_status(struct spi_dev_s *dev, uint32_t devid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SPI_CMDDATA
|
||||
int mx8mp_spi3_cmddata(struct spi_dev_s *dev, uint32_t devid, bool cmd)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
138
boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_spidev.c
Normal file
138
boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_spidev.c
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/****************************************************************************
|
||||
* boards/arm/mx8mp/verdin-mx8mp/src/mx8mp_spidev.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you 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.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/spi/spi_transfer.h>
|
||||
|
||||
#include "arm_internal.h"
|
||||
#include "chip.h"
|
||||
#include "mx8mp_ecspi.h"
|
||||
#include "verdin-mx8mp.h"
|
||||
|
||||
#include <arch/board/board.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: board_spidev_initialize
|
||||
*
|
||||
* Description:
|
||||
* Initialize and register spi driver for the specified spi port
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int board_spidev_initialize(int port)
|
||||
{
|
||||
int ret;
|
||||
struct spi_dev_s *spi;
|
||||
|
||||
spiinfo("Initializing /dev/spi%d..\n", port);
|
||||
|
||||
/* Initialize spi device */
|
||||
|
||||
spi = mx8mp_spibus_initialize(port);
|
||||
if (!spi)
|
||||
{
|
||||
i2cerr("ERROR: Failed to initialize spi%d.\n", port);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = spi_register(spi, port);
|
||||
if (ret < 0)
|
||||
{
|
||||
i2cerr("ERROR: Failed to register spi%d: %d\n", port, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mx8mp_spidev_initialize
|
||||
*
|
||||
* Description:
|
||||
* Called to configure all spi drivers
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mx8mp_spidev_initialize(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI1
|
||||
mx8mp_iomuxc_config(IOMUX_SPI1_MISO);
|
||||
mx8mp_iomuxc_config(IOMUX_SPI1_MOSI);
|
||||
mx8mp_iomuxc_config(IOMUX_SPI1_CLK);
|
||||
mx8mp_iomuxc_config(IOMUX_SPI1_CS);
|
||||
|
||||
ret = board_spidev_initialize(1);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize I2C1.\n");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI2
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI2_MISO);
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI2_MOSI);
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI2_CLK);
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI2_CS);
|
||||
mx8mp_gpio_config(GPIO_SPI2_CS);
|
||||
|
||||
ret = board_spidev_initialize(2);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize I2C2.\n");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MX8MP_SPI3
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI3_MISO);
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI3_MOSI);
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI3_CLK);
|
||||
mx8mp_iomuxc_config(IOMUXC_SPI3_CS);
|
||||
mx8mp_gpio_config(GPIO_SPI3_CS);
|
||||
|
||||
ret = board_spidev_initialize(3);
|
||||
if (ret < 0)
|
||||
{
|
||||
syslog(LOG_ERR, "Failed to initialize I2C3.\n");
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -51,6 +51,13 @@
|
|||
#define BUTTON_1_IRQ MX8MP_IRQ_SOFT_GPIO1_7
|
||||
#define BUTTON_1_IOMUX IOMUXC_GPIO1_IO07_GPIO1_IO07, 0, GPIO_PAD_CTRL
|
||||
|
||||
/* SPIs */
|
||||
|
||||
#define IOMUX_SPI1_CLK IOMUXC_ECSPI1_SCLK_ECSPI1_SCLK, 0, SPI_PAD_CTRL
|
||||
#define IOMUX_SPI1_MOSI IOMUXC_ECSPI1_MISO_ECSPI1_MISO, 0, SPI_PAD_CTRL
|
||||
#define IOMUX_SPI1_MISO IOMUXC_ECSPI1_MOSI_ECSPI1_MOSI, 0, SPI_PAD_CTRL
|
||||
#define IOMUX_SPI1_CS IOMUXC_ECSPI1_SS0_ECSPI1_SS0, 0, SPI_PAD_CTRL
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
|
|
@ -85,5 +92,15 @@ int mx8mp_bringup(void);
|
|||
|
||||
int mx8mp_i2cdev_initialize(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: mx8mp_spidev_initialize
|
||||
*
|
||||
* Description:
|
||||
* Called to configure all spi
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int mx8mp_spidev_initialize(void);
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __BOARDS_ARM_MX8MP_MX8MP_VERDIN_SRC_VERDIN_MX8MP_H */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue