Extend SPI interface for word sizes >8bits

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1740 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2009-04-26 16:06:29 +00:00
parent f4988c7151
commit 9b5d310885
3 changed files with 147 additions and 81 deletions

View File

@ -131,6 +131,8 @@
#define CSPI_INTCS_ROEN (1 << 14) /* BIT 14: RXFIFO Overflow Interrupt Enable */ #define CSPI_INTCS_ROEN (1 << 14) /* BIT 14: RXFIFO Overflow Interrupt Enable */
#define CSPI_INTCS_BOEN (1 << 15) /* Bit 15: Bit Count Overflow Interrupt Enable */ #define CSPI_INTCS_BOEN (1 << 15) /* Bit 15: Bit Count Overflow Interrupt Enable */
#define CSPI_INTCS_ALLINTS 0x0000ff00
/* CSPI Sample Period Control Register */ /* CSPI Sample Period Control Register */
#define CSPI_SPCR_WAIT_SHIFT 0 #define CSPI_SPCR_WAIT_SHIFT 0

View File

@ -87,12 +87,17 @@
struct imx_spidev_s struct imx_spidev_s
{ {
const struct spi_ops_s *ops; /* Common SPI operations */ const struct spi_ops_s *ops; /* Common SPI operations */
#ifndef CONFIG_SPI_POLLWAIT
sem_t sem; /* Wait for transfer to complete */
#endif
uint32 base; /* SPI register base address */ uint32 base; /* SPI register base address */
uint32 frequency; /* Current desired SCLK frequency */ uint32 frequency; /* Current desired SCLK frequency */
uint32 actual; /* Current actual SCLK frequency */ uint32 actual; /* Current actual SCLK frequency */
ubyte mode; /* Current mode */ ubyte mode; /* Current mode */
ubyte nbytes; /* Current number of bits per word */ ubyte nbytes; /* Current number of bits per word */
#ifndef CONFIG_SPI_POLLWAIT
ubyte irq; /* SPI IRQ number */ ubyte irq; /* SPI IRQ number */
#endif
}; };
/**************************************************************************** /****************************************************************************
@ -103,16 +108,20 @@ struct imx_spidev_s
static inline uint32 spi_getreg(struct imx_spidev_s *priv, unsigned int offset); static inline uint32 spi_getreg(struct imx_spidev_s *priv, unsigned int offset);
static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, uint32 value); static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, uint32 value);
static ubyte spi_waitspif(struct imx_spidev_s *priv); #ifndef CONFIG_SPI_POLLWAIT
static ubyte spi_transfer(struct imx_spidev_s *priv, ubyte ch); static inline struct imx_spidev_s *spi_mapirq(int irq);
static int spi_interrupt(int irq, void *context);
#endif
static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer,
void *rxbuffer, unsigned int nwords);
/* SPI methods */ /* SPI methods */
static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);
static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch); static ubyte spi_send(FAR struct spi_dev_s *dev, uint16 wd);
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen); static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t buflen);
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen); static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen);
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
@ -122,13 +131,13 @@ static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t
static const struct spi_ops_s g_spiops = static const struct spi_ops_s g_spiops =
{ {
imx_spiselect, /* Provided externally by board logic */ .select = imx_spiselect, /* Provided externally by board logic */
spi_setfrequency, .frequency = spi_setfrequency,
spi_setmode, .setmode = spi_setmode,
imx_spistatus, /* Provided externally by board logic */ .status = imx_spistatus, /* Provided externally by board logic */
spi_sndbyte, .send = spi_send,
spi_sndblock, .sndblock = spi_sndblock,
spi_recvblock, .recvblock = spi_recvblock,
}; };
/* This supports is up to two SPI busses/ports */ /* This supports is up to two SPI busses/ports */
@ -139,14 +148,18 @@ static struct imx_spidev_s g_spidev[] =
{ {
.ops = &g_spiops, .ops = &g_spiops,
.base = IMX_CSPI1_VBASE .base = IMX_CSPI1_VBASE
#ifndef CONFIG_SPI_POLLWAIT
.irq = IMX_IRQ_CSPI1, .irq = IMX_IRQ_CSPI1,
#endif
}, },
#endif #endif
#ifndef CONFIG_SPI1_DISABLE #ifndef CONFIG_SPI2_DISABLE
{ {
.ops = &g_spiops, .ops = &g_spiops,
.base = IMX_CSPI2_VBASE .base = IMX_CSPI2_VBASE
#ifndef CONFIG_SPI_POLLWAIT
.irq = IMX_IRQ_CSPI2, .irq = IMX_IRQ_CSPI2,
#endif
}, },
#endif #endif
}; };
@ -201,62 +214,93 @@ static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, ui
} }
/**************************************************************************** /****************************************************************************
* Name: spi_waitspif * Name: spi_mapirq
* *
* Description: * Description:
* Wait space available in the Tx FIFO. * Map an IRQ number into the appropriate SPI device
* *
* Input Parameters: * Input Parameters:
* priv - Device-specific state data * irq - The IRQ number to be mapped
* *
* Returned Value: * Returned Value:
* Status register mode bits * On success, a reference to the private data structgure for this IRQ.
* NULL on failrue.
* *
****************************************************************************/ ****************************************************************************/
static uint32 spi_waitspif(struct imx_spidev_s *priv) #ifndef CONFIG_SPI_POLLWAIT
static inline struct imx_spidev_s *spi_mapirq(int irq)
{ {
uint32 status; switch (irq)
{
/* Wait for the device to be ready to accept another byte (or for an error #ifndef CONFIG_SPI1_DISABLE
* to be reported). case IMX_IRQ_CSPI1:
*/ return &g_spidev[SPI1_NDX];
#error "Missing logic" #endif
return status; #ifndef CONFIG_SPI2_DISABLE
case IMX_IRQ_CSPI2:
return &g_spidev[SPI2_NDX];
#endif
default:
return NULL;
}
} }
#endif
/**************************************************************************** /****************************************************************************
* Name: spi_transfer * Name: spi_transfer
* *
* Description: * Description:
* Send one byte on SPI, return the response * Exchange a block data with the SPI device
* *
* Input Parameters: * Input Parameters:
* priv - Device-specific state data * priv - Device-specific state data
* ch - the byte to send * txbuffer - The buffer of data to send to the device (may be NULL).
* rxbuffer - The buffer to receive data from the device (may be NULL).
* nwords - The total number of words to be exchanged. If the interface
* uses <= 8 bits per word, then this is the number of ubytes;
* if the interface uses >8 bits per word, then this is the
* number of uint16's
* *
* Returned Value: * Returned Value:
* response * 0: success, <0:Negated error number on failure
* *
****************************************************************************/ ****************************************************************************/
static ubyte spi_transfer(struct imx_spidev_s *priv, ubyte ch) #ifndef CONFIG_SPI_POLLWAIT
static int spi_interrupt(int irq, void *context)
{ {
ubyte status; struct imx_spidev_s *priv = spi_mapirq(irq);
DBGASSERT(priv != NULL);
# error "Missing logic"
return OK;
}
#endif
/* Send the byte, repeating if some error occurs */ /****************************************************************************
* Name: spi_transfer
*
* Description:
* Exchange a block data with the SPI device
*
* Input Parameters:
* priv - Device-specific state data
* txbuffer - The buffer of data to send to the device (may be NULL).
* rxbuffer - The buffer to receive data from the device (may be NULL).
* nwords - The total number of words to be exchanged. If the interface
* uses <= 8 bits per word, then this is the number of ubytes;
* if the interface uses >8 bits per word, then this is the
* number of uint16's
*
* Returned Value:
* 0: success, <0:Negated error number on failure
*
****************************************************************************/
for(;;) static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer,
{ void *rxbuffer, unsigned int nwords)
{
#error "Missing logic" #error "Missing logic"
/* Wait for the device to be ready to accept another byte */
status = spi_waitspif(oriv);
/* Return the next byte from the Rx FIFO */
#error "Missing logic"
}
} }
/**************************************************************************** /****************************************************************************
@ -396,24 +440,28 @@ static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
} }
/**************************************************************************** /****************************************************************************
* Name: spi_sndbyte * Name: spi_send
* *
* Description: * Description:
* Send one byte on SPI * Exchange one word on SPI
* *
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
* ch - The byte to send * wd - The word to send. the size of the data is determined by the
* number of bits selected for the SPI interface.
* *
* Returned Value: * Returned Value:
* response * response
* *
****************************************************************************/ ****************************************************************************/
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) static uint16 spi_send(FAR struct spi_dev_s *dev, uint16 wd)
{ {
struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; struct imx_spidev_s *priv = (struct imx_spidev_s*)dev;
return spi_transfer(priv, ch); uint16 response = 0;
(void)spi_transfer(priv, &wd, &response, 1);
return response;
} }
/************************************************************************* /*************************************************************************
@ -425,24 +473,20 @@ static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch)
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
* buffer - A pointer to the buffer of data to be sent * buffer - A pointer to the buffer of data to be sent
* buflen - the length of data to send from the buffer * buflen - 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 ubytes; if nbits >8, the data is packed into uint16's
* *
* Returned Value: * Returned Value:
* None * None
* *
****************************************************************************/ ****************************************************************************/
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen) static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t buflen)
{ {
struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
uint32 response; (void)spi_transfer(priv, buffer, NULL, buflen);
/* Loop while thre are bytes remaining to be sent */
while (buflen-- > 0)
{
response = spi_transfer(priv, *buffer++);
}
} }
/**************************************************************************** /****************************************************************************
@ -454,23 +498,20 @@ static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, siz
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
* buffer - A pointer to the buffer in which to recieve data * buffer - A pointer to the buffer in which to recieve data
* buflen - the length of data that can be received in the buffer * buflen - 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 ubytes; if nbits >8, the data is packed into uint16's
* *
* Returned Value: * Returned Value:
* None * None
* *
****************************************************************************/ ****************************************************************************/
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen) static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen)
{ {
struct imx_spidev_s *priv = (struct imx_spidev_s *)dev; struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
(void)spi_transfer(priv, NULL, buffer, buflen);
/* Loop while thre are bytes remaining to be sent */
while (buflen-- > 0)
{
*buffer = (ubyte)spi_transfer(prive, 0xff);
}
} }
/**************************************************************************** /****************************************************************************
@ -584,7 +625,13 @@ FAR struct spi_dev_s *up_spiinitialize(int port)
/* Disable SPI */ /* Disable SPI */
#error "Missing logic" #error "Missing logic"
/* Initialize control rebistger: min frequency, ignore ready, master mode, mode=0, 8-bit */ /* Initialize the state structure */
ifndef CONFIG_SPI_POLLWAIT
sem_init(&priv->sem, 0, 0);
#endif
/* Initialize control register: min frequency, ignore ready, master mode, mode=0, 8-bit */
spi_putreg(priv, IMX_CSPI_CTRL_OFFSET, spi_putreg(priv, IMX_CSPI_CTRL_OFFSET,
CSPI_CTRL_DIV512 | /* Lowest frequency */ CSPI_CTRL_DIV512 | /* Lowest frequency */
@ -603,10 +650,14 @@ FAR struct spi_dev_s *up_spiinitialize(int port)
/* Enable interrupts on data ready (and certain error conditions */ /* Enable interrupts on data ready (and certain error conditions */
ifndef CONFIG_SPI_POLLWAIT
spi_putreg(priv, CSPI_INTCS_OFFSET, spi_putreg(priv, CSPI_INTCS_OFFSET,
CSPI_INTCS_RREN | /* RXFIFO Data Ready Interrupt Enable */ CSPI_INTCS_RREN | /* RXFIFO Data Ready Interrupt Enable */
CSPI_INTCS_ROEN | /* RXFIFO Overflow Interrupt Enable */ CSPI_INTCS_ROEN | /* RXFIFO Overflow Interrupt Enable */
CSPI_INTCS_BOEN); /* Bit Count Overflow Interrupt Enable */ CSPI_INTCS_BOEN); /* Bit Count Overflow Interrupt Enable */
#else
spi_putreg(priv, CSPI_INTCS_OFFSET, 0); /* No interrupts */
#endif
/* Set the clock source=bit clock and number of clocks inserted between /* Set the clock source=bit clock and number of clocks inserted between
* transactions = 2. * transactions = 2.
@ -620,7 +671,9 @@ FAR struct spi_dev_s *up_spiinitialize(int port)
/* Attach the interrupt */ /* Attach the interrupt */
irq_attach(priv->irq, (xcpt_t)imx_spinterrupt); ifndef CONFIG_SPI_POLLWAIT
irq_attach(priv->irq, (xcpt_t)spi_interrupt);
#endif
/* Enable SPI */ /* Enable SPI */
@ -630,7 +683,9 @@ FAR struct spi_dev_s *up_spiinitialize(int port)
/* Enable SPI interrupts */ /* Enable SPI interrupts */
ifndef CONFIG_SPI_POLLWAIT
up_enable_irq(priv->irq); up_enable_irq(priv->irq);
#endif
return (FAR struct spi_dev_s *)priv; return (FAR struct spi_dev_s *)priv;
} }

View File

@ -67,7 +67,7 @@
static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);
static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode); static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch); static uint16 spi_send(FAR struct spi_dev_s *dev, uint16 wd);
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen); static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen);
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen); static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen);
@ -81,7 +81,7 @@ static const struct spi_ops_s g_spiops =
spi_setfrequency, spi_setfrequency,
spi_setmode, spi_setmode,
ez80_spistatus, /* Provided externally by board logic */ ez80_spistatus, /* Provided externally by board logic */
spi_sndbyte, spi_send,
spi_sndblock, spi_sndblock,
spi_recvblock, spi_recvblock,
}; };
@ -268,23 +268,24 @@ static ubyte spi_transfer(ubyte ch)
} }
/**************************************************************************** /****************************************************************************
* Name: spi_sndbyte * Name: spi_send
* *
* Description: * Description:
* Send one byte on SPI * Exchange one word on SPI
* *
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
* ch - The byte to send * wd - The word to send. the size of the data is determined by the
* number of bits selected for the SPI interface.
* *
* Returned Value: * Returned Value:
* response * response
* *
****************************************************************************/ ****************************************************************************/
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch) static uint16 spi_send(FAR struct spi_dev_s *dev, uint16 wd)
{ {
return spi_transfer(ch); return spi_transfer((ubyte)wd);
} }
/************************************************************************* /*************************************************************************
@ -296,22 +297,26 @@ static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch)
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
* buffer - A pointer to the buffer of data to be sent * buffer - A pointer to the buffer of data to be sent
* buflen - the length of data to send from the buffer * buflen - 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 ubytes; if nbits >8, the data is packed into uint16's
* *
* Returned Value: * Returned Value:
* None * None
* *
****************************************************************************/ ****************************************************************************/
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen) static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t buflen)
{ {
FAR const ubyte *ptr = (FAR const ubyte*)buffer;
ubyte response; ubyte response;
/* Loop while thre are bytes remaining to be sent */ /* Loop while thre are bytes remaining to be sent */
while (buflen-- > 0) while (buflen-- > 0)
{ {
response = spi_transfer(*buffer++); response = spi_transfer(*ptr++);
} }
} }
@ -324,22 +329,26 @@ static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, siz
* Input Parameters: * Input Parameters:
* dev - Device-specific state data * dev - Device-specific state data
* buffer - A pointer to the buffer in which to recieve data * buffer - A pointer to the buffer in which to recieve data
* buflen - the length of data that can be received in the buffer * buflen - 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 ubytes; if nbits >8, the data is packed into uint16's
* *
* Returned Value: * Returned Value:
* None * None
* *
****************************************************************************/ ****************************************************************************/
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen) static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t buflen)
{ {
FAR ubyte *ptr = (FAR ubyte*)buffer;
ubyte response; ubyte response;
/* Loop while thre are bytes remaining to be sent */ /* Loop while thre are bytes remaining to be sent */
while (buflen-- > 0) while (buflen-- > 0)
{ {
*buffer = spi_transfer(0xff); *ptr++ = spi_transfer(0xff);
} }
} }