diff --git a/ChangeLog b/ChangeLog index 6a506625ab..94676ceff5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -686,3 +686,5 @@ * 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. + * Add a setmode() method to the SPI interface to handle parts with differing + mode requirements. diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index db4da8152e..e8e9e3e622 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -1359,6 +1359,8 @@ nuttx-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. + * Add a setmode() method to the SPI interface to handle parts with differing + mode requirements. pascal-0.1.3 2009-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/arch/z80/src/ez80/ez80_spi.c b/arch/z80/src/ez80/ez80_spi.c index aea2947d7f..5af30fd066 100755 --- a/arch/z80/src/ez80/ez80_spi.c +++ b/arch/z80/src/ez80/ez80_spi.c @@ -66,6 +66,7 @@ ****************************************************************************/ 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 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); @@ -78,6 +79,7 @@ static const struct spi_ops_s g_spiops = { ez80_spiselect, /* Provided externally by board logic */ spi_setfrequency, + spi_setmode, ez80_spistatus, /* Provided externally by board logic */ spi_sndbyte, spi_sndblock, @@ -148,6 +150,58 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) return ((EZ80_SYS_CLK_FREQ+1)/2 + brg - 1) / brg; } +/**************************************************************************** + * Name: spi_setmode + * + * Description: + * Set the SPI mode. Optional. See enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode) +{ + ubyte modebits; + ubyte regval; + + /* Select the CTL register bits based on the selected mode */ + + switch (mode) + { + case SPIDEV_MODE0: /* CPOL=0 CHPHA=0 */ + modebits = 0; + break; + + case SPIDEV_MODE1: /* CPOL=0 CHPHA=1 */ + modebits = SPI_CTL_CPHA; + break; + + case SPIDEV_MODE2: /* CPOL=1 CHPHA=0 */ + modebits = SPI_CTL_CPOL; + break; + + case SPIDEV_MODE3: /* CPOL=1 CHPHA=1 */ + modebits = (SPI_CTL_CPOL|SPI_CTL_CPHA); + break; + + default: + return; + } + + /* Then set those bits in the CTL register */ + + regval = inp(EZ80_SPI_CTL); + regval &= ~(SPI_CTL_CPOL|SPI_CTL_CPHA); + regval |= modebits; + outp(EZ80_SPI_CTL, regval); +} + /**************************************************************************** * Name: spi_waitspif * @@ -367,7 +421,7 @@ FAR struct spi_dev_s *up_spiinitialize(int port) /* Enable the SPI. * NOTE 1: Interrupts are not used in this driver version. - * NOTE 2: Certain devices may need changes to SCK polarity settings. + * NOTE 2: Initial mode is mode=0. */ outp(EZ80_SPI_CTL, SPI_CTL_SPIEN|SPI_CTL_MASTEREN); diff --git a/arch/z80/src/ez80/ez80f91_spi.h b/arch/z80/src/ez80/ez80f91_spi.h index 1d03c10cd6..3334e472bd 100644 --- a/arch/z80/src/ez80/ez80f91_spi.h +++ b/arch/z80/src/ez80/ez80f91_spi.h @@ -113,8 +113,8 @@ extern "C" { * 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); +EXTERN void ez80_spiselect(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected); +EXTERN ubyte ez80_spistatus(FAR struct spi_dev_s *dev, enum spi_dev_e devid); #undef EXTERN #ifdef __cplusplus diff --git a/configs/mcu123-lpc214x/src/up_spi.c b/configs/mcu123-lpc214x/src/up_spi.c index 210f3d736f..a33b0ea768 100644 --- a/configs/mcu123-lpc214x/src/up_spi.c +++ b/configs/mcu123-lpc214x/src/up_spi.c @@ -86,9 +86,9 @@ * Private Function Prototypes ****************************************************************************/ -static void spi_select(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected); +static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected); static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); -static ubyte spi_status(FAR struct spi_dev_s *dev, enum spidev_e devid); +static ubyte spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); 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); @@ -135,7 +135,7 @@ static struct spi_dev_s g_spidev = { &g_spiops }; * ****************************************************************************/ -static void spi_select(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected) +static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected) { uint32 bit = 1 << 20; @@ -222,7 +222,7 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) * ****************************************************************************/ -static ubyte spi_status(FAR struct spi_dev_s *dev, enum spidev_e devid) +static ubyte spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid) { /* I don't think there is anyway to determine these things on the mcu123.com * board. diff --git a/configs/olimex-strp711/src/up_spi.c b/configs/olimex-strp711/src/up_spi.c index c7cfa0a277..33b3a87176 100644 --- a/configs/olimex-strp711/src/up_spi.c +++ b/configs/olimex-strp711/src/up_spi.c @@ -263,9 +263,9 @@ static inline void spi_putreg(FAR struct str71x_spidev_s *priv, ubyte offset, /* SPI methods */ -static void spi_select(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected); +static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected); static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency); -static ubyte spi_status(FAR struct spi_dev_s *dev, enum spidev_e devid); +static ubyte spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid); 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); @@ -369,7 +369,7 @@ static inline void spi_putreg(FAR struct str71x_spidev_s *priv, ubyte offset, ui * ****************************************************************************/ -static void spi_select(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected) +static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected) { FAR struct str71x_spidev_s *priv = (FAR struct str71x_spidev_s *)dev; uint16 reg16; @@ -499,7 +499,7 @@ static uint32 spi_setfrequency(FAR struct spi_dev_s *dev, uint32 frequency) * ****************************************************************************/ -static ubyte spi_status(FAR struct spi_dev_s *dev, enum spidev_e devid) +static ubyte spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid) { ubyte ret = 0; uint16 reg16 = getreg16(STR71X_GPIO1_PD); diff --git a/include/nuttx/spi.h b/include/nuttx/spi.h index e07ca6123d..57da343041 100644 --- a/include/nuttx/spi.h +++ b/include/nuttx/spi.h @@ -1,7 +1,7 @@ /**************************************************************************** - * drivers/usbdev/spi.h + * include/nuttx/spi.h * - * Copyright(C) 2008 Gregory Nutt. All rights reserved. + * Copyright(C) 2008-2009 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -87,6 +87,23 @@ #define SPI_SETFREQUENCY(d,f) ((d)->ops->setfrequency(d,f)) +/**************************************************************************** + * Name: SPI_SETMODE + * + * Description: + * Set the SPI mode. Optional. See enum spi_mode_e for mode definitions + * + * Input Parameters: + * dev - Device-specific state data + * mode - The SPI mode requested + * + * Returned Value: + * none + * + ****************************************************************************/ + +#define SPI_SETMODE(d,m) ((d)->ops->mode(d,m)) + /**************************************************************************** * Name: SPI_STATUS * @@ -198,21 +215,32 @@ typedef void (*mediachange_t)(void *arg); * which is selected or de-seleted. */ -enum spidev_e +enum spi_dev_e { SPIDEV_NONE = 0, /* Not a valid value */ SPIDEV_MMCSD, /* Select SPI MMC/SD device */ SPIDEV_ETHERNET /* Select SPI ethernet device */ }; +/* Certain SPI devices may required differnt clocking modes */ + +enum spi_mode_e +{ + SPIDEV_MODE0 = 0, /* CPOL=0 CHPHA=0 */ + SPIDEV_MODE1, /* CPOL=0 CHPHA=1 */ + SPIDEV_MODE2, /* CPOL=1 CHPHA=0 */ + SPIDEV_MODE3 /* CPOL=1 CHPHA=1 */ +}; + /* The SPI vtable */ struct spi_dev_s; struct spi_ops_s { - void (*select)(FAR struct spi_dev_s *dev, enum spidev_e devid, boolean selected); + void (*select)(FAR struct spi_dev_s *dev, enum spi_dev_e devid, boolean selected); uint32 (*setfrequency)(FAR struct spi_dev_s *dev, uint32 frequency); - ubyte (*status)(FAR struct spi_dev_s *dev, enum spidev_e devid); + void (*setmode)(FAR struct spi_dev_s *dev, enum spi_mode_e mode); + ubyte (*status)(FAR struct spi_dev_s *dev, enum spi_dev_e devid); ubyte (*sndbyte)(FAR struct spi_dev_s *dev, ubyte ch); void (*sndblock)(FAR struct spi_dev_s *dev, FAR const ubyte *buffer, size_t buflen); void (*recvblock)(FAR struct spi_dev_s *dev, FAR ubyte *buffer, size_t buflen);