Add eZ80 SPI driver

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@1668 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2009-03-29 20:34:58 +00:00
parent f7f7c531e0
commit 7b487e8dc9
6 changed files with 516 additions and 1 deletions
+4
View File
@@ -682,3 +682,7 @@
network setup to perform that testing now (I'm in a hotel).
0.4.5 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr>
* Add an enumeration argument to the SPI chip select and status methods so
that the interface can handle more than one device.
* eZ80Acclaim!: Add a generic SPI driver for all eZ80 boards.
+4
View File
@@ -1356,6 +1356,10 @@ buildroot-0.1.3 2009-02-28 &lt;spudmonkey@racsa.co.cr&gt;
<pre><ul>
nuttx-0.4.5 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
* Add an enumeration argument to the SPI chip select and status methods so
that the interface can handle more than one device.
* eZ80Acclaim!: Add a generic SPI driver for all eZ80 boards.
pascal-0.1.3 2009-xx-xx Gregory Nutt &lt;spudmonkey@racsa.co.cr&gt;
buildroot-0.1.4 2009-xx-xx &lt;spudmonkey@racsa.co.cr&gt;
+6
View File
@@ -688,6 +688,12 @@ o z80/z8/ez80 (arch/z80)
Status: Open
Priority: High if you happen to be working with XTRS.
Description: A "generic" SPI driver has been coded for the eZ80Acclaim!
However, this remains untested since I have no SPI devices for
the board (yet).
Status: Open
Priority: Med
o z16 (arch/z16)
^^^^^^^^^^^^^^^^
+1 -1
View File
@@ -52,7 +52,7 @@ endif
CHIP_SSRCS =
CHIP_CSRCS = ez80_clock.c ez80_initialstate.c ez80_irq.c ez80_copystate.c \
ez80_schedulesigaction.c ez80_sigdeliver.c ez80_timerisr.c \
ez80_lowuart.c ez80_serial.c ez80_registerdump.c
ez80_lowuart.c ez80_serial.c ez80_spi.c ez80_registerdump.c
ifeq ($(CONFIG_ARCH_CHIP_EZ80F91),y)
ifeq ($(CONFIG_EZ80_EMAC),y)
CHIP_CSRCS += ez80_emac.c
+376
View File
@@ -0,0 +1,376 @@
/****************************************************************************
* arch/z80/src/ez80/ez80_spi.c
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/spi.h>
#include <arch/board/board.h>
#include <nuttx/arch.h>
#include <nuttx/spi.h>
#include <arch/io.h>
#include "up_internal.h"
#include "up_arch.h"
#include "chip.h"
#include "ez80f91_spi.h"
/****************************************************************************
* Definitions
****************************************************************************/
#ifdef CONFIG_ARCH_CHIP_EZ80F91
# define GPIOB_SPI_PINSET 0x38 /* MISO+MSOI+SCK. Excludes SS */
#else
# error "Check GPIO initialization for this chip"
#endif
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency);
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch);
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);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct spi_ops_s g_spiops =
{
ez80_spiselect, /* Provided externally by board logic */
spi_setfrequency,
ez80_spistatus, /* Provided externally by board logic */
spi_sndbyte,
spi_sndblock,
spi_recvblock,
};
/* This supports is only a single SPI bus/port. There you port this to an
* architecture with multiple SPI busses/ports, then the following must
* become an array with one 'struct spi_dev_s' instance per bus.
*/
static struct spi_dev_s g_spidev = { &g_spiops };
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* 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 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency)
{
/* We want select divisor to provide the highest frequency (SPIR) that does NOT
* exceed the requested frequency.:
*
* SPIR <= System Clock Frequency / (2 * BRG)
*
* So
*
* BRG >= System Clock Frequency / (2 * SPIR)
*/
uint32 brg = ((EZ80_SYS_CLK_FREQ+1)/2 + frequency - 1) / frequency;
/* "When configured as a Master, the 16-bit divisor value must be between
* 0003h and FFFFh, inclusive. When configured as a Slave, the 16-bit
* divisor value must be between 0004h and FFFFh, inclusive."
*/
if (brg < 3)
{
brg = 3;
}
else if (brg > 0xffff)
{
brg = 0xfff;
}
outp(EZ80_SPI_BRG_L, brg & 0xff);
outp(EZ80_SPI_BRG_L, (brg >> 8) & 0xff);
return ((EZ80_SYS_CLK_FREQ+1)/2 + brg - 1) / brg;
}
/****************************************************************************
* Name: spi_waitspif
*
* Description:
* Wait for the SPIF bit to be set in the status register signifying the
* the data transfer was finished.
*
* Input Parameters:
* None
*
* Returned Value:
* Status register mode bits
*
****************************************************************************/
static ubyte spi_waitspif(void)
{
ubyte status;
/* Wait for the device to be ready to accept another byte (or for an error
* to be reported
*/
do
{
status = inp(EZ80_SPI_SR) & (SPI_SR_SPIF|SPI_SR_WCOL|SPI_SR_MODF);
}
while (status == 0);
return status;
}
/****************************************************************************
* Name: spi_transfer
*
* Description:
* Send one byte on SPI, return th response
*
* Input Parameters:
* ch - the byte to send
*
* Returned Value:
* response
*
****************************************************************************/
static ubyte spi_transfer(ubyte ch)
{
ubyte status;
/* Send the byte, repeating if some error occurs */
for(;;)
{
outp(EZ80_SPI_TSR, ch);
/* Wait for the device to be ready to accept another byte */
status = spi_waitspif();
if ((status & SPI_SR_SPIF) != 0)
{
return inp(EZ80_SPI_RBR);
}
}
}
/****************************************************************************
* Name: spi_sndbyte
*
* Description:
* Send one byte on SPI
*
* Input Parameters:
* dev - Device-specific state data
* ch - The byte to send
*
* Returned Value:
* response
*
****************************************************************************/
static ubyte spi_sndbyte(FAR struct spi_dev_s *dev, ubyte ch)
{
return spi_transfer(ch);
}
/*************************************************************************
* Name: spi_sndblock
*
* Description:
* Send a block of data on SPI
*
* Input Parameters:
* dev - Device-specific state data
* buffer - A pointer to the buffer of data to be sent
* buflen - the length of data to send from the buffer
*
* Returned Value:
* None
*
****************************************************************************/
static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen)
{
ubyte response;
/* Loop while thre are bytes remaining to be sent */
while (buflen-- > 0)
{
response = spi_transfer(*buffer++);
}
}
/****************************************************************************
* Name: spi_recvblock
*
* Description:
* Revice a block of data from SPI
*
* Input Parameters:
* dev - Device-specific state data
* buffer - A pointer to the buffer in which to recieve data
* buflen - the length of data that can be received in the buffer
*
* Returned Value:
* None
*
****************************************************************************/
static void spi_recvblock(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen)
{
ubyte response;
/* Loop while thre are bytes remaining to be sent */
while (buflen-- > 0)
{
*buffer = spi_transfer(0xff);
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: up_spiinitialize
*
* Description:
* Initialize common parts the selected SPI port. Initialization of
* chip select GPIOs must have been performed by board specific logic
* prior to calling this function. Specifically: GPIOs should have
* been configured for output, and all chip selects disabled.
*
* One GPIO, SS (PB2 on the eZ8F091) is reserved as a chip select. However,
* If multiple devices on on the bus, then multiple chip selects will be
* required. Theregore, all GPIO chip management is deferred to board-
* specific logic.
*
* Input Parameter:
* Port number (for hardware that has mutiple SPI interfaces)
*
* Returned Value:
* Valid SPI device structre reference on succcess; a NULL on failure
*
****************************************************************************/
FAR struct spi_dev_s *up_spiinitialize(int port)
{
ubyte regval;
/* Only the SPI1 interface is supported */
#ifdef CONFIG_DEBUG
if (port != 1)
{
return NULL;
}
#endif
/* Disable SPI */
outp(EZ80_SPI_CTL, 0);
/* Configure GPIOs. For the eZ80F91, the pin mapping for the four SPI pins
* is:
*
* GPIO ALT MASTER SLAVE COMMENT
* ---- ----- ------- ------- ---------------------------------
* PB2 SS INPUT INPUT Managed by board specific logic
* PB3 SCLK OUTPUT INPUT
* PB4 MISO INPUT OUTPUT
* PB5 MOSI OUTPUT INPUT
*
* Select the alternate function for PB2-5:
*/
#ifdef CONFIG_ARCH_CHIP_EZ80F91
regval = inp(EZ80_PB_DDR);
regval |= GPIOB_SPI_PINSET;
outp(EZ80_PB_DDR, regval);
regval = inp(EZ80_PB_ALT1);
regval &= ~GPIOB_SPI_PINSET;
outp(EZ80_PB_ALT1, regval);
regval = inp(EZ80_PB_ALT2);
regval |= GPIOB_SPI_PINSET;
outp(EZ80_PB_ALT2, regval);
#else
# error "Check GPIO initialization for this chip"
#endif
/* Set the initial clock frequency for indentification mode < 400kHz */
spi_setfrequency(NULL, 400000);
/* Enable the SPI.
* NOTE 1: Interrupts are not used in this driver version.
* NOTE 2: Certain devices may need changes to SCK polarity settings.
*/
outp(EZ80_SPI_CTL, SPI_CTL_SPIEN|SPI_CTL_MASTEREN);
return &g_spidev;
}
+125
View File
@@ -0,0 +1,125 @@
/************************************************************************************
* arch/z80/src/ez80/ez80f91_spi.h
* arch/z80/src/chip/ez80f91_spi.h
*
* Copyright (C) 2009 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
#ifndef __ARCH_Z80_SRC_EZ80_EZ80F91_SPI_H
#define __ARCH_Z80_SRC_EZ80_EZ80F91_SPI_H
/************************************************************************************
* Included Files
************************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/spi.h>
/************************************************************************************
* Definitions
************************************************************************************/
/* SPIC Registers *****************************************************************/
/* Provided in ez80f91.h */
/* SPIC Register Bit Definitions **************************************************/
/* Baud Rate Generator (BRG) H/L Register Definitions
*
* No bit definitions -- These two 8-bit registers set the 16-bit BRG divider value
*/
/*SPI Control (CTL} Register Definitions */
#define SPI_CTL_IRQEN (1 << 7) /* Bit 7: 1=SPI system interrupt is enabled */
#define SPI_CTL_SPIEN (1 << 5) /* Bit 5: 1=SPI is enabled */
#define SPI_CTL_MASTEREN (1 << 4) /* Bit 4: 1=SPI operates as a master */
#define SPI_CTL_CPOL (1 << 3) /* Bit 3: 1=Master SCK pin idles in a high (1) state */
#define SPI_CTL_CPHA (1 << 2) /* Bit 2: 1=SS remains Low to transfer any number of data bytes */
/* SR Register Definitions */
#define SPI_SR_SPIF (1 << 7) /* Bit x: 1=SPI data transfer is finished */
#define SPI_SR_WCOL (1 << 6) /* Bit x: 1=SPI write collision is detected*/
#define SPI_SR_MODF (1 << 4) /* Bit x: 1=Mode fault (multimaster conflict) is detected */
/* RBR/TSR Register Definitions */
/* No definitions: 8-bit SPI receive/transmit data */
/************************************************************************************
* Public Types
************************************************************************************/
/************************************************************************************
* Public Data
************************************************************************************/
#ifndef __ASSEMBLY__
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C" {
#else
#define EXTERN extern
#endif /* __cplusplus */
/************************************************************************************
* Public Functions
************************************************************************************/
/* The external functions, ez80_spiselect and ez80_spistatus must be provided by
* board-specific logic. The are implementations of the select and status methods
* SPI interface defined by struct spi_ops_s (see include/nuttx/spi.h). All other
* methods (including up_spiinitialize()) are provided by common logic. To use this
* common SPI logic on your board:
*
* 1. Provide ez80_spiselect() and ez80_spistatus() functions in your board-specific
* logic. This function will perform chip selection and status operations using
* GPIOs in the way your board is configured.
* 2. Add a call to up_spiinitialize() in your low level initialization logic
* 3. The handle returned by up_spiinitialize() may then be used to bind the
* SPI driver to higher level logic (e.g., calling mmcsd_spislotinitializ()
* will bind the SPI driver to the SPI MMC/SD driver.
*/
EXTERN void ez80_spiselect(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected);
EXTERN ubyte ez80_spistatus(FAR struct spi_dev_s *dev, enum spidev_e devid);
#undef EXTERN
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_Z80_SRC_EZ80_EZ80F91_SPI_H */