Re-architected SAM3/4 SPI interface; Change BUSY bit handling in the ADS7843E driver
This commit is contained in:
parent
20fdf8161f
commit
ab84bdd2d8
@ -49,6 +49,9 @@
|
||||
/****************************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************************/
|
||||
/* General definitions ******************************************************************/
|
||||
|
||||
#define SAM_SPI_NCS 4 /* Four chip selects */
|
||||
|
||||
/* SPI register offsets *****************************************************************/
|
||||
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
@ -67,6 +68,7 @@
|
||||
/****************************************************************************
|
||||
* Definitions
|
||||
****************************************************************************/
|
||||
/* Configuration ************************************************************/
|
||||
/* Select MCU-specific settings
|
||||
*
|
||||
* For the SAM3U, SPI is driven by the main clock.
|
||||
@ -81,6 +83,7 @@
|
||||
# error Unrecognized SAM architecture
|
||||
#endif
|
||||
|
||||
/* Debug *******************************************************************/
|
||||
/* Check if SPI debut is enabled (non-standard.. no support in
|
||||
* include/debug.h
|
||||
*/
|
||||
@ -106,26 +109,16 @@
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
||||
/* The state of one chip select */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
struct sam_chipselect_s
|
||||
{
|
||||
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
|
||||
|
||||
/* The overall state of the SPI interface */
|
||||
/* The state of the one chip select */
|
||||
|
||||
struct sam_spidev_s
|
||||
{
|
||||
struct spi_dev_s spidev; /* Externally visible part of the SPI interface */
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
sem_t exclsem; /* Held while chip is selected for mutual exclusion */
|
||||
struct sam_chipselect_s csstate[4];
|
||||
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
|
||||
uint8_t cs; /* Chip select number */
|
||||
};
|
||||
@ -194,12 +187,17 @@ static const struct spi_ops_s g_spiops =
|
||||
.registercallback = 0, /* Not implemented */
|
||||
};
|
||||
|
||||
/* SPI device structure */
|
||||
#ifdef CONFIG_SPI_OWNBUS
|
||||
/* Single chip select device structure structure */
|
||||
|
||||
static struct sam_spidev_s g_spidev =
|
||||
{
|
||||
.spidev = { &g_spiops },
|
||||
};
|
||||
static struct sam_spidev_s g_spidev;
|
||||
|
||||
#else
|
||||
/* Held while chip is selected for mutual exclusion */
|
||||
|
||||
static sem_t g_spisem;
|
||||
static bool g_spinitialized = false;
|
||||
#endif
|
||||
|
||||
/* This array maps chip select numbers (0-3) to CSR register addresses */
|
||||
|
||||
@ -330,14 +328,12 @@ static inline uint32_t spi_cs2pcs(FAR struct sam_spidev_s *priv)
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
|
||||
{
|
||||
FAR struct sam_spidev_s *priv = (FAR struct sam_spidev_s *)dev;
|
||||
|
||||
spivdbg("lock=%d\n", lock);
|
||||
if (lock)
|
||||
{
|
||||
/* Take the semaphore (perhaps waiting) */
|
||||
|
||||
while (sem_wait(&priv->exclsem) != 0)
|
||||
while (sem_wait(&g_spisem) != 0)
|
||||
{
|
||||
/* The only case that an error should occur here is if the wait was awakened
|
||||
* by a signal.
|
||||
@ -348,8 +344,9 @@ static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)sem_post(&priv->exclsem);
|
||||
(void)sem_post(&g_spisem);
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
#endif
|
||||
@ -381,15 +378,7 @@ static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
|
||||
spivdbg("selected=%d\n", selected);
|
||||
if (selected)
|
||||
{
|
||||
/* At this point, we expect no chip selected */
|
||||
|
||||
DEBUGASSERT(priv->cs == 0xff);
|
||||
|
||||
/* Get the chip select number used with this SPI device */
|
||||
|
||||
priv->cs = sam_spicsnumber(devid);
|
||||
spivdbg("cs=%d\n", priv->cs);
|
||||
DEBUGASSERT(priv->cs >= 0 && priv->cs <= 3);
|
||||
|
||||
/* Before writing the TDR, the PCS field in the SPI_MR register must be set
|
||||
* in order to select a slave.
|
||||
@ -400,19 +389,6 @@ static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
|
||||
regval |= (spi_cs2pcs(priv) << SPI_MR_PCS_SHIFT);
|
||||
putreg32(regval, SAM_SPI_MR);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* At this point, we expect the chip to have already been selected */
|
||||
|
||||
#ifdef CONFIG_DEBUG
|
||||
int cs = sam_spicsnumber(devid);
|
||||
DEBUGASSERT(priv->cs == cs);
|
||||
#endif
|
||||
|
||||
/* Mark no chip selected */
|
||||
|
||||
priv->cs = 0xff;
|
||||
}
|
||||
|
||||
/* Perform any board-specific chip select operations. PIO chip select
|
||||
* pins may be programmed by the board specific logic in one of two
|
||||
@ -429,7 +405,7 @@ static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
|
||||
*/
|
||||
|
||||
sam_spiselect(devid, selected);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: spi_setfrequency
|
||||
@ -457,16 +433,15 @@ static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency)
|
||||
uint32_t regaddr;
|
||||
|
||||
spivdbg("cs=%d frequency=%d\n", priv->cs, frequency);
|
||||
DEBUGASSERT(priv->cs >= 0 && priv->cs <= 3);
|
||||
|
||||
/* Check if the requested frequency is the same as the frequency selection */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
if (priv->csstate[priv->cs].frequency == frequency)
|
||||
if (priv->frequency == frequency)
|
||||
{
|
||||
/* We are already at this frequency. Return the actual. */
|
||||
|
||||
return priv->csstate[priv->cs].actual;
|
||||
return priv->actual;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -492,7 +467,7 @@ static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency)
|
||||
|
||||
regaddr = g_csraddr[priv->cs];
|
||||
regval = getreg32(regaddr);
|
||||
regval &= ~(SPI_CSR_SCBR_MASK|SPI_CSR_DLYBS_MASK|SPI_CSR_DLYBCT_MASK);
|
||||
regval &= ~(SPI_CSR_SCBR_MASK | SPI_CSR_DLYBS_MASK | SPI_CSR_DLYBCT_MASK);
|
||||
regval |= scbr << SPI_CSR_SCBR_SHIFT;
|
||||
|
||||
/* DLYBS: Delay Before SPCK. This field defines the delay from NPCS valid to the
|
||||
@ -534,8 +509,8 @@ static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency)
|
||||
/* Save the frequency setting */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
priv->csstate[priv->cs].frequency = frequency;
|
||||
priv->csstate[priv->cs].actual = actual;
|
||||
priv->frequency = frequency;
|
||||
priv->actual = actual;
|
||||
#endif
|
||||
|
||||
spidbg("Frequency %d->%d\n", frequency, actual);
|
||||
@ -564,19 +539,18 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
|
||||
uint32_t regaddr;
|
||||
|
||||
spivdbg("cs=%d mode=%d\n", priv->cs, mode);
|
||||
DEBUGASSERT(priv->cs >= 0 && priv->cs <= 3);
|
||||
|
||||
/* Has the mode changed? */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
if (mode != priv->csstate[priv->cs].mode)
|
||||
if (mode != priv->mode)
|
||||
{
|
||||
#endif
|
||||
/* Yes... Set the mode appropriately */
|
||||
|
||||
regaddr = g_csraddr[priv->cs];
|
||||
regval = getreg32(regaddr);
|
||||
regval &= ~(SPI_CSR_CPOL|SPI_CSR_NCPHA);
|
||||
regval &= ~(SPI_CSR_CPOL | SPI_CSR_NCPHA);
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
@ -606,7 +580,7 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
|
||||
/* Save the mode so that subsequent re-configurations will be faster */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
priv->csstate[priv->cs].mode = mode;
|
||||
priv->mode = mode;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -634,7 +608,6 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
|
||||
|
||||
spivdbg("cs=%d nbits=%d\n", priv->cs, nbits);
|
||||
DEBUGASSERT(priv && nbits > 7 && nbits < 17);
|
||||
DEBUGASSERT(priv->cs >= 0 && priv->cs <= 3);
|
||||
|
||||
/* NOTE: The logic in spi_send and in spi_exchange only handles 8-bit
|
||||
* data at the present time. So the following extra assertion is a
|
||||
@ -646,7 +619,7 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
|
||||
/* Has the number of bits changed? */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
if (nbits != priv->csstate[priv->cs].nbits)
|
||||
if (nbits != priv->nbits)
|
||||
{
|
||||
#endif
|
||||
/* Yes... Set number of bits appropriately */
|
||||
@ -662,7 +635,7 @@ static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
|
||||
/* Save the selection so the subsequence re-configurations will be faster */
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
priv->csstate[priv->cs].nbits = nbits;
|
||||
priv->nbits = nbits;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -889,70 +862,106 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nw
|
||||
* Initialize the selected SPI port
|
||||
*
|
||||
* Input Parameter:
|
||||
* Port number (for hardware that has mutiple SPI interfaces)
|
||||
* cs - Chip select number (identifying the "logical" SPI port)
|
||||
*
|
||||
* Returned Value:
|
||||
* Valid SPI device structure reference on succcess; a NULL on failure
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
FAR struct spi_dev_s *up_spiinitialize(int port)
|
||||
FAR struct spi_dev_s *up_spiinitialize(int cs)
|
||||
{
|
||||
FAR struct sam_spidev_s *priv = &g_spidev;
|
||||
FAR struct sam_spidev_s *priv;
|
||||
irqstate_t flags;
|
||||
|
||||
/* The SAM3U has only a single SPI port */
|
||||
/* The support SAM parts have only a single SPI port */
|
||||
|
||||
spivdbg("port=%d\n", port);
|
||||
DEBUGASSERT(port == 0);
|
||||
spivdbg("cs=%d\n", cs);
|
||||
DEBUGASSERT(cs >= 0 && cs <= SAM_SPI_NCS);
|
||||
|
||||
/* Set up the initial state */
|
||||
|
||||
priv->cs = 0xff;
|
||||
|
||||
/* Enable clocking to the SPI block */
|
||||
|
||||
flags = irqsave();
|
||||
sam_spi_enableclk();
|
||||
|
||||
/* Configure multiplexed pins as connected on the board. Chip select pins
|
||||
* must be configured by board-specific logic.
|
||||
#ifdef CONFIG_SPI_OWNBUS
|
||||
/* There is only one device on the bus and, therefore, there is only one
|
||||
* supported chip select. In this case, use the single, pre-allocated
|
||||
* chip select structure.
|
||||
*/
|
||||
|
||||
sam_configgpio(GPIO_SPI0_MISO);
|
||||
sam_configgpio(GPIO_SPI0_MOSI);
|
||||
sam_configgpio(GPIO_SPI0_SPCK);
|
||||
priv = &g_spidev;
|
||||
|
||||
/* Disable SPI clocking */
|
||||
#else
|
||||
/* Allocate a new state structure for this chip select. NOTE that there
|
||||
* is no protection if the same chip select is used in two different
|
||||
* chip select structures.
|
||||
*/
|
||||
|
||||
putreg32(SPI_CR_SPIDIS, SAM_SPI_CR);
|
||||
priv = (FAR struct sam_spidev_s *)zalloc(sizeof(struct sam_spidev_s));
|
||||
if (!priv)
|
||||
{
|
||||
spivdbg("ERROR: Failed to allocate a chip select structure\n", cs);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Execute a software reset of the SPI (twice) */
|
||||
/* Set up the initial state for this chip select structure. Other fields
|
||||
* were zeroed by zalloc().
|
||||
*/
|
||||
|
||||
putreg32(SPI_CR_SWRST, SAM_SPI_CR);
|
||||
putreg32(SPI_CR_SWRST, SAM_SPI_CR);
|
||||
irqrestore(flags);
|
||||
|
||||
/* Configure the SPI mode register */
|
||||
|
||||
putreg32(SPI_MR_MSTR | SPI_MR_MODFDIS, SAM_SPI_MR);
|
||||
|
||||
/* And enable the SPI */
|
||||
|
||||
putreg32(SPI_CR_SPIEN, SAM_SPI_CR);
|
||||
up_mdelay(20);
|
||||
|
||||
/* Flush any pending transfers */
|
||||
|
||||
(void)getreg32(SAM_SPI_SR);
|
||||
(void)getreg32(SAM_SPI_RDR);
|
||||
|
||||
/* Initialize the SPI semaphore that enforces mutually exclusive access */
|
||||
priv->spidev.ops = &g_spiops;
|
||||
priv->cs = cs;
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
sem_init(&priv->exclsem, 0, 1);
|
||||
/* Has the SPI hardware been initialized? */
|
||||
|
||||
if (!g_spinitialized)
|
||||
#endif
|
||||
spi_dumpregs("After initialization");
|
||||
{
|
||||
/* Enable clocking to the SPI block */
|
||||
|
||||
flags = irqsave();
|
||||
sam_spi_enableclk();
|
||||
|
||||
/* Configure multiplexed pins as connected on the board. Chip select
|
||||
* pins must be configured by board-specific logic.
|
||||
*/
|
||||
|
||||
sam_configgpio(GPIO_SPI0_MISO);
|
||||
sam_configgpio(GPIO_SPI0_MOSI);
|
||||
sam_configgpio(GPIO_SPI0_SPCK);
|
||||
|
||||
/* Disable SPI clocking */
|
||||
|
||||
putreg32(SPI_CR_SPIDIS, SAM_SPI_CR);
|
||||
|
||||
/* Execute a software reset of the SPI (twice) */
|
||||
|
||||
putreg32(SPI_CR_SWRST, SAM_SPI_CR);
|
||||
putreg32(SPI_CR_SWRST, SAM_SPI_CR);
|
||||
irqrestore(flags);
|
||||
|
||||
/* Configure the SPI mode register */
|
||||
|
||||
putreg32(SPI_MR_MSTR | SPI_MR_MODFDIS, SAM_SPI_MR);
|
||||
|
||||
/* And enable the SPI */
|
||||
|
||||
putreg32(SPI_CR_SPIEN, SAM_SPI_CR);
|
||||
up_mdelay(20);
|
||||
|
||||
/* Flush any pending transfers */
|
||||
|
||||
(void)getreg32(SAM_SPI_SR);
|
||||
(void)getreg32(SAM_SPI_RDR);
|
||||
|
||||
#ifndef CONFIG_SPI_OWNBUS
|
||||
/* Initialize the SPI semaphore that enforces mutually exclusive
|
||||
* access to the SPI registers.
|
||||
*/
|
||||
|
||||
sem_init(&g_spisem, 0, 1);
|
||||
g_spinitialized = true;
|
||||
#endif
|
||||
spi_dumpregs("After initialization");
|
||||
}
|
||||
|
||||
return &priv->spidev;
|
||||
}
|
||||
#endif /* CONFIG_SAM34_SPI */
|
||||
|
@ -79,15 +79,13 @@ extern "C"
|
||||
************************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_spicsnumber, sam_spiselect, sam_spistatus, and sam_spicmddata
|
||||
* Name: sam_spiselect, sam_spistatus, and sam_spicmddata
|
||||
*
|
||||
* Description:
|
||||
* These external functions must be provided by board-specific logic. They
|
||||
* include:
|
||||
*
|
||||
* o sam_spicsnumber and sam_spiselect which are helper functions to
|
||||
* manage the board-specific aspects of the unique SAM3/4 chip select
|
||||
* architecture.
|
||||
* o sam_spiselect is a functions tomanage the board-specific chip selects
|
||||
* o sam_spistatus and sam_spicmddata: Implementations of the status
|
||||
* and cmddata methods of the SPI interface defined by struct spi_ops_
|
||||
* (see include/nuttx/spi.h). All other methods including
|
||||
@ -97,10 +95,9 @@ extern "C"
|
||||
*
|
||||
* 1. Provide logic in sam_boardinitialize() to configure SPI chip select
|
||||
* pins.
|
||||
* 2. Provide sam_spicsnumber(), sam_spiselect() and sam_spistatus()
|
||||
* 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. Provide sam_spiselect() and sam_spistatus() 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
|
||||
* sam_spicmddata() functions in your board-specific logic. This
|
||||
* function will perform cmd/data selection operations using GPIOs in
|
||||
@ -118,31 +115,6 @@ extern "C"
|
||||
struct spi_dev_s;
|
||||
enum spi_dev_e;
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_spicsnumber
|
||||
*
|
||||
* Description:
|
||||
* The SAM3/4 has 4 CS registers for controlling device features. This
|
||||
* function must be provided by board-specific code. Given a logical device
|
||||
* ID, this function returns a number from 0 to 3 that identifies one of
|
||||
* these SAM3/4 CS resources.
|
||||
*
|
||||
* If CONFIG_SPI_OWNBUS is not defined and the GPIO is controlled by
|
||||
* sam_spiselect, then the same CS register may be used to control
|
||||
* multiple devices.
|
||||
*
|
||||
* Input Parameters:
|
||||
* dev - SPI device info
|
||||
* devid - Identifies the (logical) device
|
||||
*
|
||||
* Returned Values:
|
||||
* On success, a CS number from 0 to 3 is returned; A negated errno may
|
||||
* be returned on a failure.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int sam_spicsnumber(enum spi_dev_e devid);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: sam_spiselect
|
||||
*
|
||||
|
Loading…
x
Reference in New Issue
Block a user