You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2020/01/28 14:33:04 UTC

[incubator-nuttx] branch master updated: Generic SPI interface for controlling an LCD display

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new e99a8d1  Generic SPI interface for controlling an LCD display
e99a8d1 is described below

commit e99a8d192ddeae83b5b6a88d9e13a6c56b58c256
Author: Dave Marples <da...@marples.net>
AuthorDate: Tue Jan 28 11:30:34 2020 -0300

    Generic SPI interface for controlling an LCD display
---
 arch/arm/src/imxrt/imxrt_lpspi.c | 317 ++++++++++++++++++++---------------
 drivers/lcd/Kconfig              |  17 ++
 drivers/lcd/Make.defs            |   4 +
 drivers/lcd/lcddrv_spiif.c       | 347 +++++++++++++++++++++++++++++++++++++++
 include/nuttx/lcd/lcddrv_spiif.h | 144 ++++++++++++++++
 5 files changed, 698 insertions(+), 131 deletions(-)

diff --git a/arch/arm/src/imxrt/imxrt_lpspi.c b/arch/arm/src/imxrt/imxrt_lpspi.c
index b33cee8..8c88386 100644
--- a/arch/arm/src/imxrt/imxrt_lpspi.c
+++ b/arch/arm/src/imxrt/imxrt_lpspi.c
@@ -1,4 +1,4 @@
-/************************************************************************************
+/*****************************************************************************
  * arm/arm/src/imxrt/imxrt_lpspi.c
  *
  *   Copyright (C) 2018 Gregory Nutt. All rights reserved.
@@ -32,34 +32,35 @@
  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  *
- ************************************************************************************/
+ *****************************************************************************/
 
-/************************************************************************************
- * The external functions, imxrt_lpspi1/2/3/4select and imxrt_lpspi1/2/3/4status
- * must be provided by board-specific logic.  They are implementations of the select
- * and status methods of the SPI interface defined by struct imxrt_lpspi_ops_s (see
- * include/nuttx/spi/spi.h). All other methods (including imxrt_lpspibus_initialize())
- * are provided by common IMXRT logic.  To use this common SPI logic on your
- * board:
+/*****************************************************************************
+ * The external functions, imxrt_lpspi1/2/3/4select and
+ * imxrt_lpspi1/2/3/4status must be provided by board-specific logic.
+ * They are implementations of the select and status methods of the SPI
+ * interface defined by struct imxrt_lpspi_ops_s (see
+ * include/nuttx/spi/spi.h). All other methods (including
+ * imxrt_lpspibus_initialize()) are provided by common IMXRT logic.
+ * To use this common SPI logic on your board:
  *
  *   1. Provide logic in imxrt_boardinitialize() to configure SPI chip select
  *      pins.
  *   2. Provide imxrt_lpspi1/2/3/4select() and imxrt_lpspi1/2/3/4status()
- *      functions in your board-specific logic.  These functions will perform chip
- *      selection and status operations using GPIOs in the way your board is
- *      configured.
- *   3. Add a calls to imxrt_lpspibus_initialize() in your low level application
- *      initialization logic
- *   4. The handle returned by imxrt_lpspibus_initialize() may then be used to bind the
- *      SPI driver to higher level logic (e.g., calling
+ *      functions in your board-specific logic.  These functions will perform
+ *      chip selection and status operations using GPIOs in the way your board
+ *      is configured.
+ *   3. Add a calls to imxrt_lpspibus_initialize() in your low level
+ *      application initialization logic
+ *   4. The handle returned by imxrt_lpspibus_initialize() may then be used to
+ *      bind the SPI driver to higher level logic (e.g., calling
  *      mmcsd_lpspislotinitialize(), for example, will bind the SPI driver to
  *      the SPI MMC/SD driver).
  *
- ************************************************************************************/
+ *****************************************************************************/
 
-/************************************************************************************
+/*****************************************************************************
  * Included Files
- ************************************************************************************/
+ *****************************************************************************/
 
 #include <nuttx/config.h>
 
@@ -94,11 +95,11 @@
 #if defined(CONFIG_IMXRT_LPSPI1) || defined(CONFIG_IMXRT_LPSPI2) || \
     defined(CONFIG_IMXRT_LPSPI3) || defined(CONFIG_IMXRT_LPSPI4)
 
-/************************************************************************************
+/*****************************************************************************
  * Pre-processor Definitions
- ************************************************************************************/
+ ****************************************************************************/
 
-/* Configuration ********************************************************************/
+/* Configuration ************************************************************/
 
 /* SPI interrupts */
 
@@ -116,9 +117,9 @@
 #  error "Cannot enable both interrupt mode and DMA mode for SPI"
 #endif
 
-/************************************************************************************
+/*****************************************************************************
  * Private Types
- ************************************************************************************/
+ ****************************************************************************/
 
 struct imxrt_lpspidev_s
 {
@@ -141,9 +142,9 @@ enum imxrt_delay_e
   LPSPI_BETWEEN_TRANSFER      /* Delay between transfers. */
 };
 
-/************************************************************************************
+/*****************************************************************************
  * Private Function Prototypes
- ************************************************************************************/
+ ****************************************************************************/
 
 /* Helpers */
 
@@ -151,17 +152,19 @@ static inline uint32_t imxrt_lpspi_getreg32(FAR struct imxrt_lpspidev_s *priv,
                                             uint8_t offset);
 static inline void imxrt_lpspi_putreg32(FAR struct imxrt_lpspidev_s *priv,
                                         uint8_t offset, uint32_t value);
-static inline uint16_t imxrt_lpspi_readword(FAR struct imxrt_lpspidev_s *priv);
+static inline uint16_t imxrt_lpspi_readword(
+                          FAR struct imxrt_lpspidev_s *priv);
 static inline void imxrt_lpspi_writeword(FAR struct imxrt_lpspidev_s *priv,
                                          uint16_t byte);
-static inline bool imxrt_lpspi_9to16bitmode(FAR struct imxrt_lpspidev_s *priv);
+static inline bool imxrt_lpspi_9to16bitmode(
+                          FAR struct imxrt_lpspidev_s *priv);
 static inline void imxrt_lpspi_master_set_delays(FAR struct imxrt_lpspidev_s
                                                  *priv, uint32_t delay_ns,
                                                  enum imxrt_delay_e type);
-static inline void imxrt_lpspi_master_set_delay_scaler(FAR struct
-                                                       imxrt_lpspidev_s *priv,
-                                                       uint32_t scaler,
-                                                       enum imxrt_delay_e type);
+static inline void imxrt_lpspi_master_set_delay_scaler(
+                          FAR struct imxrt_lpspidev_s *priv,
+                          uint32_t scaler,
+                          enum imxrt_delay_e type);
 
 /* SPI methods */
 
@@ -182,7 +185,8 @@ static void imxrt_lpspi_exchange(FAR struct spi_dev_s *dev,
 #ifndef CONFIG_SPI_EXCHANGE
 static void imxrt_lpspi_sndblock(FAR struct spi_dev_s *dev,
                                  FAR const void *txbuffer, size_t nwords);
-static void imxrt_lpspi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer,
+static void imxrt_lpspi_recvblock(FAR struct spi_dev_s *dev,
+                                  FAR void *rxbuffer,
                                   size_t nwords);
 #endif
 
@@ -190,9 +194,9 @@ static void imxrt_lpspi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer,
 
 static void imxrt_lpspi_bus_initialize(FAR struct imxrt_lpspidev_s *priv);
 
-/************************************************************************************
+/*****************************************************************************
  * Private Data
- ************************************************************************************/
+ *****************************************************************************/
 
 #ifdef CONFIG_IMXRT_LPSPI1
 static const struct spi_ops_s g_spi1ops =
@@ -378,11 +382,11 @@ static struct imxrt_lpspidev_s g_lpspi4dev =
 };
 #endif
 
-/************************************************************************************
+/*****************************************************************************
  * Private Functions
- ************************************************************************************/
+ *****************************************************************************/
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_getreg8
  *
  * Description:
@@ -395,7 +399,7 @@ static struct imxrt_lpspidev_s g_lpspi4dev =
  * Returned Value:
  *   The contents of the 8-bit register
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline uint8_t imxrt_lpspi_getreg8(FAR struct imxrt_lpspidev_s *priv,
                                           uint8_t offset)
@@ -403,7 +407,7 @@ static inline uint8_t imxrt_lpspi_getreg8(FAR struct imxrt_lpspidev_s *priv,
   return getreg8(priv->spibase + offset);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_putreg8
  *
  * Description:
@@ -414,7 +418,7 @@ static inline uint8_t imxrt_lpspi_getreg8(FAR struct imxrt_lpspidev_s *priv,
  *   offset - offset to the register of interest
  *   value  - the 8-bit value to be written
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline void imxrt_lpspi_putreg8(FAR struct imxrt_lpspidev_s *priv,
                                        uint8_t offset, uint8_t value)
@@ -422,7 +426,7 @@ static inline void imxrt_lpspi_putreg8(FAR struct imxrt_lpspidev_s *priv,
   putreg8(value, priv->spibase + offset);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_getreg
  *
  * Description:
@@ -435,7 +439,7 @@ static inline void imxrt_lpspi_putreg8(FAR struct imxrt_lpspidev_s *priv,
  * Returned Value:
  *   The contents of the 32-bit register
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline uint32_t imxrt_lpspi_getreg32(FAR struct imxrt_lpspidev_s *priv,
                                             uint8_t offset)
@@ -443,7 +447,7 @@ static inline uint32_t imxrt_lpspi_getreg32(FAR struct imxrt_lpspidev_s *priv,
   return getreg32(priv->spibase + offset);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_putreg
  *
  * Description:
@@ -457,7 +461,7 @@ static inline uint32_t imxrt_lpspi_getreg32(FAR struct imxrt_lpspidev_s *priv,
  * Returned Value:
  *   The contents of the 32-bit register
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline void imxrt_lpspi_putreg32(FAR struct imxrt_lpspidev_s *priv,
                                         uint8_t offset, uint32_t value)
@@ -465,7 +469,7 @@ static inline void imxrt_lpspi_putreg32(FAR struct imxrt_lpspidev_s *priv,
   putreg32(value, priv->spibase + offset);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_readword
  *
  * Description:
@@ -477,20 +481,21 @@ static inline void imxrt_lpspi_putreg32(FAR struct imxrt_lpspidev_s *priv,
  * Returned Value:
  *   word as read
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline uint16_t imxrt_lpspi_readword(FAR struct imxrt_lpspidev_s *priv)
 {
   /* Wait until the receive buffer is not empty */
 
-  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET) & LPSPI_SR_RDF) == 0);
+  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET)
+                      & LPSPI_SR_RDF) == 0);
 
   /* Then return the received byte */
 
   return (uint16_t) imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_RDR_OFFSET);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_writeword
  *
  * Description:
@@ -503,21 +508,22 @@ static inline uint16_t imxrt_lpspi_readword(FAR struct imxrt_lpspidev_s *priv)
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline void imxrt_lpspi_writeword(FAR struct imxrt_lpspidev_s *priv,
                                          uint16_t word)
 {
   /* Wait until the transmit buffer is empty */
 
-  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET) & LPSPI_SR_TDF) == 0);
+  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET)
+                       & LPSPI_SR_TDF) == 0);
 
   /* Then send the word */
 
   imxrt_lpspi_putreg32(priv, IMXRT_LPSPI_TDR_OFFSET, word);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_readbyte
  *
  * Description:
@@ -529,20 +535,21 @@ static inline void imxrt_lpspi_writeword(FAR struct imxrt_lpspidev_s *priv,
  * Returned Value:
  *   Byte as read
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline uint8_t imxrt_lpspi_readbyte(FAR struct imxrt_lpspidev_s *priv)
 {
   /* Wait until the receive buffer is not empty */
 
-  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET) & LPSPI_SR_RDF) == 0);
+  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET)
+                       & LPSPI_SR_RDF) == 0);
 
   /* Then return the received byte */
 
   return imxrt_lpspi_getreg8(priv, IMXRT_LPSPI_RDR_OFFSET);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_writebyte
  *
  * Description:
@@ -555,21 +562,22 @@ static inline uint8_t imxrt_lpspi_readbyte(FAR struct imxrt_lpspidev_s *priv)
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline void imxrt_lpspi_writebyte(FAR struct imxrt_lpspidev_s *priv,
                                          uint8_t byte)
 {
   /* Wait until the transmit buffer is empty */
 
-  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET) & LPSPI_SR_TDF) == 0);
+  while ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_SR_OFFSET)
+                           & LPSPI_SR_TDF) == 0);
 
   /* Then send the byte */
 
   imxrt_lpspi_putreg8(priv, IMXRT_LPSPI_TDR_OFFSET, byte);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_9to16bitmode
  *
  * Description:
@@ -581,7 +589,7 @@ static inline void imxrt_lpspi_writebyte(FAR struct imxrt_lpspidev_s *priv,
  * Returned Value:
  *   true: >8 bit mode-bit mode, false: <= 8-bit mode
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static inline bool imxrt_lpspi_9to16bitmode(FAR struct imxrt_lpspidev_s *priv)
 {
@@ -600,7 +608,7 @@ static inline bool imxrt_lpspi_9to16bitmode(FAR struct imxrt_lpspidev_s *priv)
   return ret;
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_modifyreg
  *
  * Description:
@@ -615,7 +623,7 @@ static inline bool imxrt_lpspi_9to16bitmode(FAR struct imxrt_lpspidev_s *priv)
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static void imxrt_lpspi_modifyreg32(FAR struct imxrt_lpspidev_s *priv,
                                     uint8_t offset, uint32_t clrbits,
@@ -624,7 +632,7 @@ static void imxrt_lpspi_modifyreg32(FAR struct imxrt_lpspidev_s *priv,
   modifyreg32(priv->spibase + offset, clrbits, setbits);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_master_set_delays
  *
  * Description:
@@ -638,11 +646,12 @@ static void imxrt_lpspi_modifyreg32(FAR struct imxrt_lpspidev_s *priv,
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
-static inline void imxrt_lpspi_master_set_delay_scaler(FAR struct imxrt_lpspidev_s *priv,
-                                                       uint32_t scaler,
-                                                       enum imxrt_delay_e type)
+static inline void imxrt_lpspi_master_set_delay_scaler(
+                          FAR struct imxrt_lpspidev_s *priv,
+                          uint32_t scaler,
+                          enum imxrt_delay_e type)
 {
   switch (type)
     {
@@ -661,15 +670,15 @@ static inline void imxrt_lpspi_master_set_delay_scaler(FAR struct imxrt_lpspidev
       break;
 
     case LPSPI_BETWEEN_TRANSFER:
-      imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CCR_OFFSET, LPSPI_CCR_DBT_MASK,
-                              0);
+      imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CCR_OFFSET,
+                                    LPSPI_CCR_DBT_MASK, 0);
       imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CCR_OFFSET, 0,
                               LPSPI_CCR_DBT(scaler));
       break;
     }
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_master_set_delays
  *
  * Description:
@@ -683,10 +692,12 @@ static inline void imxrt_lpspi_master_set_delay_scaler(FAR struct imxrt_lpspidev
  * Returned Value:
  *   None
  *
- ************************************************************************************/
-static inline void imxrt_lpspi_master_set_delays(FAR struct imxrt_lpspidev_s *priv,
-                                                 uint32_t delay_ns,
-                                                 enum imxrt_delay_e type)
+ *****************************************************************************/
+
+static inline void imxrt_lpspi_master_set_delays(
+                             FAR struct imxrt_lpspidev_s *priv,
+                             uint32_t delay_ns,
+                             enum imxrt_delay_e type)
 {
   uint32_t pll3_div;
   uint32_t pll_freq;
@@ -719,8 +730,9 @@ static inline void imxrt_lpspi_master_set_delays(FAR struct imxrt_lpspidev_s *pr
    */
 
   src_freq  = pll_freq /
-              ((getreg32(IMXRT_CCM_ANALOG_PFD_480) & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >>
-              CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
+              ((getreg32(IMXRT_CCM_ANALOG_PFD_480)
+                         & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >>
+                         CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
   src_freq *= 18;
   src_freq /= ((getreg32(IMXRT_CCM_CBCMR) & CCM_CBCMR_LPSPI_PODF_MASK) >>
                CCM_CBCMR_LPSPI_PODF_SHIFT) + 1;
@@ -797,9 +809,9 @@ static inline void imxrt_lpspi_master_set_delays(FAR struct imxrt_lpspidev_s *pr
       for (scaler = 0; (scaler < 256) && min_diff; scaler++)
         {
           /* Calculate the real delay value as we cycle through the scaler
-           * values. Due to large size of calculated values (uint64_t), we need
-           * to break up the calculation into several steps to ensure accurate
-           * calculated results
+           * values. Due to large size of calculated values (uint64_t),
+           * we need to break up the calculation into several steps to
+           * ensure accurate calculated results
            */
 
           real_delay  = 1000000000U;
@@ -829,7 +841,7 @@ static inline void imxrt_lpspi_master_set_delays(FAR struct imxrt_lpspidev_s *pr
     }
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_lock
  *
  * Description:
@@ -848,7 +860,7 @@ static inline void imxrt_lpspi_master_set_delays(FAR struct imxrt_lpspidev_s *pr
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static int imxrt_lpspi_lock(FAR struct spi_dev_s *dev, bool lock)
 {
@@ -867,7 +879,7 @@ static int imxrt_lpspi_lock(FAR struct spi_dev_s *dev, bool lock)
   return ret;
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_setfrequency
  *
  * Description:
@@ -880,7 +892,7 @@ static int imxrt_lpspi_lock(FAR struct spi_dev_s *dev, bool lock)
  * Returned Value:
  *   Returns the actual frequency selected
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static uint32_t imxrt_lpspi_setfrequency(FAR struct spi_dev_s *dev,
                                          uint32_t frequency)
@@ -909,7 +921,8 @@ static uint32_t imxrt_lpspi_setfrequency(FAR struct spi_dev_s *dev,
       men = imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN;
       if (men)
         {
-          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, LPSPI_CR_MEN, 0);
+          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET,
+                                        LPSPI_CR_MEN, 0);
         }
 
       if ((getreg32(IMXRT_CCM_ANALOG_PLL_USB1) &
@@ -930,8 +943,9 @@ static uint32_t imxrt_lpspi_setfrequency(FAR struct spi_dev_s *dev,
        */
 
       src_freq  = pll_freq /
-                  ((getreg32(IMXRT_CCM_ANALOG_PFD_480) & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >>
-                  CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
+                  ((getreg32(IMXRT_CCM_ANALOG_PFD_480)
+                    & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >>
+                      CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
       src_freq *= 18;
       src_freq /= ((getreg32(IMXRT_CCM_CBCMR) & CCM_CBCMR_LPSPI_PODF_MASK) >>
                    CCM_CBCMR_LPSPI_PODF_SHIFT) + 1;
@@ -994,14 +1008,15 @@ static uint32_t imxrt_lpspi_setfrequency(FAR struct spi_dev_s *dev,
 
       if (men)
         {
-          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0, LPSPI_CR_MEN);
+          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0,
+                                        LPSPI_CR_MEN);
         }
     }
 
   return priv->actual;
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_setmode
  *
  * Description:
@@ -1014,9 +1029,10 @@ static uint32_t imxrt_lpspi_setfrequency(FAR struct spi_dev_s *dev,
  * Returned Value:
  *   Returns the actual frequency selected
  *
- ************************************************************************************/
+ *****************************************************************************/
 
-static void imxrt_lpspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
+static void imxrt_lpspi_setmode(FAR struct spi_dev_s *dev,
+                                enum spi_mode_e mode)
 {
   FAR struct imxrt_lpspidev_s *priv = (FAR struct imxrt_lpspidev_s *)dev;
   uint32_t setbits;
@@ -1034,7 +1050,8 @@ static void imxrt_lpspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
       men = imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN;
       if (men)
         {
-          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, LPSPI_CR_MEN, 0);
+          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET,
+                                        LPSPI_CR_MEN, 0);
         }
 
       switch (mode)
@@ -1081,12 +1098,13 @@ static void imxrt_lpspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
 
       if (men)
         {
-          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0, LPSPI_CR_MEN);
+          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0,
+                                        LPSPI_CR_MEN);
         }
     }
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_setbits
  *
  * Description:
@@ -1099,7 +1117,7 @@ static void imxrt_lpspi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static void imxrt_lpspi_setbits(FAR struct spi_dev_s *dev, int nbits)
 {
@@ -1113,7 +1131,6 @@ static void imxrt_lpspi_setbits(FAR struct spi_dev_s *dev, int nbits)
 
   if (nbits != priv->nbits)
     {
-
       if (nbits < 2 || nbits > 4096)
         {
           return;
@@ -1124,14 +1141,17 @@ static void imxrt_lpspi_setbits(FAR struct spi_dev_s *dev, int nbits)
       men = imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN;
       if (men)
         {
-          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, LPSPI_CR_MEN, 0);
+          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET,
+                                        LPSPI_CR_MEN, 0);
         }
 
       imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_TCR_OFFSET,
                               LPSPI_TCR_FRAMESZ_MASK,
                               LPSPI_TCR_FRAMESZ(nbits - 1));
 
-      /* Save the selection so the subsequence re-configurations will be faster */
+      /* Save the selection so the subsequence re-configurations
+       * will be faster
+       */
 
       priv->nbits = savbits;    /* nbits has been clobbered... save the signed
                                  * value. */
@@ -1140,12 +1160,13 @@ static void imxrt_lpspi_setbits(FAR struct spi_dev_s *dev, int nbits)
 
       if (men)
         {
-          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0, LPSPI_CR_MEN);
+          imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0,
+                                        LPSPI_CR_MEN);
         }
     }
 }
 
-/****************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_hwfeatures
  *
  * Description:
@@ -1197,7 +1218,7 @@ static int imxrt_lpspi_hwfeatures(FAR struct spi_dev_s *dev,
 }
 #endif
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_send
  *
  * Description:
@@ -1211,7 +1232,7 @@ static int imxrt_lpspi_hwfeatures(FAR struct spi_dev_s *dev,
  * Returned Value:
  *   response
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static uint16_t imxrt_lpspi_send(FAR struct spi_dev_s *dev, uint16_t wd)
 {
@@ -1240,7 +1261,7 @@ static uint16_t imxrt_lpspi_send(FAR struct spi_dev_s *dev, uint16_t wd)
   return ret;
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_exchange (no DMA).  aka imxrt_lpspi_exchange_nodma
  *
  * Description:
@@ -1253,12 +1274,13 @@ static uint16_t imxrt_lpspi_send(FAR struct spi_dev_s *dev, uint16_t wd)
  *   nwords   - the length of data to be exchaned 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
+ *              packed into uint8_t's; if nbits >8, the data is packed
+ *              into uint16_t's
  *
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 #if !defined(CONFIG_IMXRT_LPSPI_DMA) || defined(CONFIG_IMXRT_DMACAPABLE)
 #if !defined(CONFIG_IMXRT_LPSPI_DMA)
@@ -1359,12 +1381,13 @@ static void imxrt_lpspi_exchange_nodma(FAR struct spi_dev_s *dev,
  *   nwords   - 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 uint8_t's; if nbits >8, the data is packed into uint16_t's
+ *              packed into uint8_t's; if nbits >8, the data is packed into
+ *              uint16_t's
  *
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 #ifndef CONFIG_SPI_EXCHANGE
 static void imxrt_lpspi_sndblock(FAR struct spi_dev_s *dev,
@@ -1375,7 +1398,7 @@ static void imxrt_lpspi_sndblock(FAR struct spi_dev_s *dev,
 }
 #endif
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_recvblock
  *
  * Description:
@@ -1384,32 +1407,33 @@ static void imxrt_lpspi_sndblock(FAR struct spi_dev_s *dev,
  * Input Parameters:
  *   dev      - Device-specific state data
  *   rxbuffer - A pointer to the buffer in which to receive data
- *   nwords   - 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 uint8_t's; if nbits >8, the data is packed into uint16_t's
+ *   nwords   - 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 uint8_t's;
+ *              if nbits >8, the data is packed into uint16_t's
  *
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 #ifndef CONFIG_SPI_EXCHANGE
-static void imxrt_lpspi_recvblock(FAR struct spi_dev_s *dev, FAR void *rxbuffer,
-                                  size_t nwords)
+static void imxrt_lpspi_recvblock(FAR struct spi_dev_s *dev,
+                                  FAR void *rxbuffer, size_t nwords)
 {
   spiinfo("rxbuffer=%p nwords=%d\n", rxbuffer, nwords);
   return imxrt_lpspi_exchange(dev, NULL, rxbuffer, nwords);
 }
 #endif
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_clock_enable
  *
  * Description:
  *   Ungate LPSPI clock
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 void imxrt_lpspi_clock_enable(uint32_t base)
 {
@@ -1431,13 +1455,13 @@ void imxrt_lpspi_clock_enable(uint32_t base)
     }
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_clock_disable
  *
  * Description:
  *   Gate LPSPI clock
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 void imxrt_lpspi_clock_disable(uint32_t base)
 {
@@ -1459,11 +1483,12 @@ void imxrt_lpspi_clock_disable(uint32_t base)
     }
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspi_bus_initialize
  *
  * Description:
- *   Initialize the selected SPI bus in its default state (Master, 8-bit, mode 0, etc.)
+ *   Initialize the selected SPI bus in its default state
+ *   (Master, 8-bit, mode 0, etc.)
  *
  * Input Parameters:
  *   priv   - private SPI device structure
@@ -1471,7 +1496,7 @@ void imxrt_lpspi_clock_disable(uint32_t base)
  * Returned Value:
  *   None
  *
- ************************************************************************************/
+ *****************************************************************************/
 
 static void imxrt_lpspi_bus_initialize(struct imxrt_lpspidev_s *priv)
 {
@@ -1493,13 +1518,15 @@ static void imxrt_lpspi_bus_initialize(struct imxrt_lpspidev_s *priv)
   imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CFGR1_OFFSET, 0,
                           LPSPI_CFGR1_MASTER);
 
-  /* Set specific PCS to active high or low */
-  /* TODO: Not needed for now */
+  /* Set specific PCS to active high or low
+   * TODO: Not needed for now
+   */
 
   /* Set Configuration Register 1 related setting. */
 
   reg = imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CFGR1_OFFSET);
-  reg &= ~(LPSPI_CFGR1_OUTCFG | LPSPI_CFGR1_PINCFG_MASK | LPSPI_CFGR1_NOSTALL);
+  reg &= ~(LPSPI_CFGR1_OUTCFG | LPSPI_CFGR1_PINCFG_MASK
+           | LPSPI_CFGR1_NOSTALL);
   reg |= LPSPI_CFGR1_OUTCFG_RETAIN | LPSPI_CFGR1_PINCFG_SIN_SOUT;
   imxrt_lpspi_putreg32(priv, IMXRT_LPSPI_CFGR1_OFFSET, reg);
 
@@ -1527,11 +1554,11 @@ static void imxrt_lpspi_bus_initialize(struct imxrt_lpspidev_s *priv)
   imxrt_lpspi_modifyreg32(priv, IMXRT_LPSPI_CR_OFFSET, 0, LPSPI_CR_MEN);
 }
 
-/************************************************************************************
+/*****************************************************************************
  * Public Functions
- ************************************************************************************/
+ *****************************************************************************/
 
-/************************************************************************************
+/*****************************************************************************
  * Name: imxrt_lpspibus_initialize
  *
  * Description:
@@ -1543,7 +1570,7 @@ static void imxrt_lpspi_bus_initialize(struct imxrt_lpspidev_s *priv)
  * Returned Value:
  *   Valid SPI device structure reference on success; a NULL on failure
  *
- ************************************************************************************/
+ ****************************************************************************/
 
 FAR struct spi_dev_s *imxrt_lpspibus_initialize(int bus)
 {
@@ -1560,13 +1587,20 @@ FAR struct spi_dev_s *imxrt_lpspibus_initialize(int bus)
 
       /* Only configure if the bus is not already configured */
 
-      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN) == 0)
+      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET)
+           & LPSPI_CR_MEN) == 0)
         {
           /* Configure SPI1 pins: SCK, MISO, and MOSI */
 
           imxrt_config_gpio(GPIO_LPSPI1_SCK);
           imxrt_config_gpio(GPIO_LPSPI1_MISO);
           imxrt_config_gpio(GPIO_LPSPI1_MOSI);
+#ifdef GPIO_LPSPI1_CS
+          imxrt_config_gpio(GPIO_LPSPI1_CS);
+#endif
+#if defined(GPIO_LPSPI1_DC) && defined(CONFIG_SPI_CMDDATA)
+          imxrt_config_gpio(GPIO_LPSPI1_DC);
+#endif
 
           /* Set up default configuration: Master, 8-bit, etc. */
 
@@ -1584,13 +1618,20 @@ FAR struct spi_dev_s *imxrt_lpspibus_initialize(int bus)
 
       /* Only configure if the bus is not already configured */
 
-      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN) == 0)
+      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET)
+           & LPSPI_CR_MEN) == 0)
         {
           /* Configure SPI2 pins: SCK, MISO, and MOSI */
 
           imxrt_config_gpio(GPIO_LPSPI2_SCK);
           imxrt_config_gpio(GPIO_LPSPI2_MISO);
           imxrt_config_gpio(GPIO_LPSPI2_MOSI);
+#ifdef GPIO_LPSPI2_CS
+          imxrt_config_gpio(GPIO_LPSPI2_CS);
+#endif
+#if defined(GPIO_LPSPI2_DC) && defined(CONFIG_SPI_CMDDATA)
+          imxrt_config_gpio(GPIO_LPSPI2_DC);
+#endif
 
           /* Set up default configuration: Master, 8-bit, etc. */
 
@@ -1608,13 +1649,20 @@ FAR struct spi_dev_s *imxrt_lpspibus_initialize(int bus)
 
       /* Only configure if the bus is not already configured */
 
-      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN) == 0)
+      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET)
+           & LPSPI_CR_MEN) == 0)
         {
           /* Configure SPI3 pins: SCK, MISO, and MOSI */
 
           imxrt_config_gpio(GPIO_LPSPI3_SCK);
           imxrt_config_gpio(GPIO_LPSPI3_MISO);
           imxrt_config_gpio(GPIO_LPSPI3_MOSI);
+#ifdef GPIO_LPSPI3_CS
+          imxrt_config_gpio(GPIO_LPSPI3_CS);
+#endif
+#if defined(GPIO_LPSPI3_DC) && defined(CONFIG_SPI_CMDDATA)
+          imxrt_config_gpio(GPIO_LPSPI3_DC);
+#endif
 
           /* Set up default configuration: Master, 8-bit, etc. */
 
@@ -1632,13 +1680,20 @@ FAR struct spi_dev_s *imxrt_lpspibus_initialize(int bus)
 
       /* Only configure if the bus is not already configured */
 
-      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET) & LPSPI_CR_MEN) == 0)
+      if ((imxrt_lpspi_getreg32(priv, IMXRT_LPSPI_CR_OFFSET)
+           & LPSPI_CR_MEN) == 0)
         {
           /* Configure SPI4 pins: SCK, MISO, and MOSI */
 
           imxrt_config_gpio(GPIO_LPSPI4_SCK);
           imxrt_config_gpio(GPIO_LPSPI4_MISO);
           imxrt_config_gpio(GPIO_LPSPI4_MOSI);
+#ifdef GPIO_LPSPI4_CS
+          imxrt_config_gpio(GPIO_LPSPI4_CS);
+#endif
+#if defined(GPIO_LPSPI4_DC) && defined(CONFIG_SPI_CMDDATA)
+          imxrt_config_gpio(GPIO_LPSPI4_DC);
+#endif
 
           /* Set up default configuration: Master, 8-bit, etc. */
 
diff --git a/drivers/lcd/Kconfig b/drivers/lcd/Kconfig
index 9bc3ac2..88a9f5a 100644
--- a/drivers/lcd/Kconfig
+++ b/drivers/lcd/Kconfig
@@ -1134,6 +1134,23 @@ config LCD_ILI9341_IFACE1_RGB565
 endchoice
 endif
 
+config LCD_LCDDRV_SPIIF
+	bool "Generic SPI Interface Driver (for ILI9341 or others)"
+	default n
+	depends on LCD_ILI9341
+	---help---
+		SPI Interface shim to allow LCD and ePaper to be bound to
+		a normal SPI port.
+
+config LCD_LCDDRV_SPEED
+        int "Generic SPI Interface speed"
+	default 10000000
+	depends on LCD_LCDDRV_SPIIF
+	---help---
+		SPI Interface speed. According to the specification this is generally
+		quite limited, but people have had success with much faster
+		speeds than the spec sheets say. YMMV.
+
 config LCD_RA8875
 	bool "RA8875 LCD Display Controller"
 	default n
diff --git a/drivers/lcd/Make.defs b/drivers/lcd/Make.defs
index bfc50ba..b40aca2 100644
--- a/drivers/lcd/Make.defs
+++ b/drivers/lcd/Make.defs
@@ -124,6 +124,10 @@ ifeq ($(CONFIG_LCD_ILI9341),y)
   CSRCS += ili9341.c
 endif
 
+ifeq ($(CONFIG_LCD_LCDDRV_SPIIF),y)
+  CSRCS += lcddrv_spiif.c
+endif
+
 ifeq ($(CONFIG_LCD_RA8875),y)
   CSRCS += ra8875.c
 endif
diff --git a/drivers/lcd/lcddrv_spiif.c b/drivers/lcd/lcddrv_spiif.c
new file mode 100644
index 0000000..d1dbb3e
--- /dev/null
+++ b/drivers/lcd/lcddrv_spiif.c
@@ -0,0 +1,347 @@
+/****************************************************************************
+ * drivers/lcd/lcddrv_spiif.c
+ *
+ * Generic Driver interface for the Single Chip LCD driver connected
+ * via spi driver
+ *
+ *   Copyright (C) 2019 Greg Nutt. All rights reserved.
+ *   Author: Dave Marples <da...@marples.net>
+ *           Based on work from Marco Krahl <oc...@gmail.com>
+ *
+ * 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 writen 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 <sys/types.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <nuttx/kmalloc.h>
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/spi/spi.h>
+#include <nuttx/lcd/lcddrv_spiif.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Type Definition
+ ****************************************************************************/
+
+struct lcddrv_spiif_lcd_s
+{
+  /* Publically visible device structure */
+
+  struct lcddrv_lcd_s dev;
+
+  /* Reference to spi device structure */
+
+  struct spi_dev_s *spi;
+};
+
+/****************************************************************************
+ * Private Function Protototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lcddrv_spiif_backlight
+ *
+ * Description:
+ *   Set the backlight level of the connected display.
+ *
+ * Input Parameters:
+ *   spi   - Reference to the public driver structure
+ *   level - backlight level
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+static int lcddrv_spiif_backlight(struct lcddrv_lcd_s *lcd, int level)
+{
+  return spiif_backlight(lcd, level);
+}
+
+/****************************************************************************
+ * Name: lcddrv_spiif_select
+ *
+ * Description:
+ *   Select the SPI, locking and re-configuring if necessary
+ *
+ * Input Parameters:
+ *   spi  - Reference to the public driver structure
+ *   isCommand - Flag indicating is command mode
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void lcddrv_spiif_select(FAR struct lcddrv_lcd_s *lcd)
+{
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  SPI_LOCK(priv->spi, true);
+  SPI_SELECT(priv->spi, SPIDEV_DISPLAY(0), true);
+}
+
+/****************************************************************************
+ * Name: lcddrv_spiif_deselect
+ *
+ * Description:
+ *   De-select the SPI
+ *
+ * Input Parameters:
+ *   spi  - Reference to the public driver structure
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void lcddrv_spiif_deselect(FAR struct lcddrv_lcd_s *lcd)
+{
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), false);
+  SPI_SELECT(priv->spi, SPIDEV_DISPLAY(0), false);
+  SPI_LOCK(priv->spi, false);
+}
+
+/****************************************************************************
+ * Name: lcddrv_spiif_sendmulti
+ *
+ * Description:
+ *   Send a number of pixel words to the lcd driver gram.
+ *
+ * Input Parameters:
+ *   lcd    - Reference to the lcddrv_lcd_s driver structure
+ *   wd     - Reference to the words to send
+ *   nwords - number of words to send
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+static int lcddrv_spiif_sendmulti(FAR struct lcddrv_lcd_s *lcd,
+                                  FAR const uint16_t *wd, uint32_t nwords)
+{
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  SPI_SETBITS(priv->spi, 16);
+  for (uint32_t t = 0; t < nwords; t++)
+    {
+      SPI_SEND(priv->spi, *wd++);
+    }
+
+  SPI_SETBITS(priv->spi, 8);
+
+  return OK;
+};
+
+/****************************************************************************
+ * Name: lcddrv_spiif_recv
+ *
+ * Description:
+ *   Receive a parameter from the lcd driver.
+ *
+ * Input Parameters:
+ *   lcd    - Reference to the lcddrv_lcd_s driver structure
+ *   param  - Reference to where parameter receive
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+static int lcddrv_spiif_recv(FAR struct lcddrv_lcd_s *lcd,
+                             uint8_t *param)
+{
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  lcdinfo("param=%04x\n", param);
+  SPI_RECVBLOCK(priv->spi, param, 1);
+  return OK;
+}
+
+/****************************************************************************
+ * Name: lcddrv_spiif_send
+ *
+ * Description:
+ *   Send to the lcd
+ *
+ * Input Parameters:
+ *   lcd    - Reference to the lcddrv_lcd_s driver structure
+ *   param  - Reference to where parameter to send is located
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+static int lcddrv_spiif_send(FAR struct lcddrv_lcd_s *lcd,
+                             const uint8_t param)
+{
+  uint8_t r;
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  r = SPI_SEND(priv->spi, param);
+  return r;
+}
+
+/****************************************************************************
+ * Name: lcddrv_spiif_sendcmd
+ *
+ * Description:
+ *   Send command to the lcd
+ *
+ * Input Parameters:
+ *   lcd    - Reference to the lcddrv_lcd_s driver structure
+ *   param  - Reference to where parameter to send is located
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+static int lcddrv_spiif_sendcmd(FAR struct lcddrv_lcd_s *lcd,
+                                const uint8_t param)
+{
+  uint8_t r;
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  lcdinfo("param=%04x\n", param);
+  SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), true);
+  r = SPI_SEND(priv->spi, param);
+  SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY(0), false);
+  return r;
+}
+
+/****************************************************************************
+ * Name: lcddrv_spiif_recvmulti
+ *
+ * Description:
+ *   Receive pixel words from the lcd driver gram.
+ *
+ * Input Parameters:
+ *   lcd    - Reference to the public driver structure
+ *   wd     - Reference to where the pixel words receive
+ *   nwords - number of pixel words to receive
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+static int lcddrv_spiif_recvmulti(FAR struct lcddrv_lcd_s *lcd,
+                                  FAR uint16_t *wd, uint32_t nwords)
+{
+  FAR struct lcddrv_spiif_lcd_s *priv = (FAR struct lcddrv_spiif_lcd_s *)lcd;
+
+  lcdinfo("wd=%p, nwords=%d\n", wd, nwords);
+  SPI_SETBITS(priv->spi, 16);
+  SPI_RECVBLOCK(priv->spi, wd, nwords);
+  SPI_SETBITS(priv->spi, 8);
+  return OK;
+}
+
+/****************************************************************************
+ * Name:  FAR struct lcddrv_lcd_s *lcddrv_spiif_initialize
+ *
+ * Description:
+ *   Initialize the device structure to control the LCD Single chip driver.
+ *
+ * Input Parameters:
+ *   spi : handle to the spi to use
+ *
+ * Returned Value:
+ *   On success, this function returns a reference to the LCD control object
+ *   for the specified LCDDRV LCD Single chip driver.
+ *   NULL is returned on failure.
+ *
+ ****************************************************************************/
+
+FAR struct lcddrv_lcd_s *lcddrv_spiif_initialize(struct spi_dev_s *spi)
+{
+  FAR struct lcddrv_spiif_lcd_s *priv =
+  (struct lcddrv_spiif_lcd_s *)kmm_zalloc(sizeof(struct lcddrv_spiif_lcd_s));
+
+  if (!priv)
+    {
+      return NULL;
+    }
+
+  lcdinfo("initialize lcddrv spi subdriver\n");
+
+  priv->spi = spi;
+
+  if (!priv->spi)
+    {
+      kmm_free(priv);
+      return 0;
+    }
+
+  SPI_SETFREQUENCY(spi, CONFIG_LCD_LCDDRV_SPEED);
+  SPI_SETBITS(spi, 8);
+
+  /* Hook in our driver routines */
+
+  priv->dev.select      = lcddrv_spiif_select;
+  priv->dev.deselect    = lcddrv_spiif_deselect;
+  priv->dev.sendparam   = lcddrv_spiif_send;
+  priv->dev.sendcmd     = lcddrv_spiif_sendcmd;
+  priv->dev.recvparam   = lcddrv_spiif_recv;
+  priv->dev.sendgram    = lcddrv_spiif_sendmulti;
+  priv->dev.recvgram    = lcddrv_spiif_recvmulti;
+  priv->dev.backlight   = lcddrv_spiif_backlight;
+
+  return &priv->dev;
+}
diff --git a/include/nuttx/lcd/lcddrv_spiif.h b/include/nuttx/lcd/lcddrv_spiif.h
new file mode 100644
index 0000000..aefa5e3
--- /dev/null
+++ b/include/nuttx/lcd/lcddrv_spiif.h
@@ -0,0 +1,144 @@
+/*****************************************************************************
+ * include/nuttx/lcd/lcddrv_spiif.h
+ *
+ *   Copyright (C) 2014 Gregory Nutt. All rights reserved.
+ *   Authors: Gregory Nutt <gn...@nuttx.org>
+ *            Dave Marples <da...@marples.net>
+ *
+ * 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 __INCLUDE_NUTTX_LCD_LCDDRV_SPIIF_H
+#define __INCLUDE_NUTTX_LCD_LCDDRV_SPIIF_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <nuttx/spi/spi.h>
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+struct lcddrv_lcd_s
+{
+  /* Interface to control the ILI9341 lcd driver
+   *
+   *  - select      Select the device (as neccessary) before performing
+   *                any operations.
+   *  - deselect    Deselect the device (as necessary).
+   *  - send        Send specific parameter to the LCD driver.
+   *  - recv        Receive specific parameter from the LCD driver.
+   *  - sendmulti   Send pixel data to the LCD drivers gram.
+   *  - recvmulti   Receive pixel data from the LCD drivers gram.
+   *  - backlight   Change the backlight level of the connected display.
+   *                In the context of the ili9341 that means change the
+   *                backlight level of the connected LED driver.
+   *                The implementation in detail is part of the platform
+   *                specific sub driver.
+   */
+
+  CODE void (*select)(FAR struct lcddrv_lcd_s *lcd);
+  CODE void (*deselect)(FAR struct lcddrv_lcd_s *lcd);
+  CODE int (*sendcmd)(FAR struct lcddrv_lcd_s *lcd, const uint8_t cmd);
+  CODE int (*sendparam)(FAR struct lcddrv_lcd_s *lcd, const uint8_t param);
+  CODE int (*recvparam)(FAR struct lcddrv_lcd_s *lcd, uint8_t *param);
+  CODE int (*recvgram)(FAR struct lcddrv_lcd_s *lcd,
+                       uint16_t *wd, uint32_t nwords);
+  CODE int (*sendgram)(FAR struct lcddrv_lcd_s *lcd,
+                       const uint16_t *wd, uint32_t nwords);
+  CODE int (*backlight)(FAR struct lcddrv_lcd_s *lcd, int level);
+
+  /* mcu interface specific data following */
+};
+
+/*****************************************************************************
+ * Public Data
+ *****************************************************************************/
+
+#ifdef __cplusplus
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
+#endif
+
+/*****************************************************************************
+ * Public Function Prototypes
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: spiif_backlight
+ *       (Provided by integrating platform)
+ *
+ * Description:
+ *   Set the backlight level of the connected display.
+ *
+ * Input Parameters:
+ *   spi   - Reference to the public driver structure
+ *   level - backlight level
+ *
+ * Returned Value:
+ *   OK - On Success
+ *
+ ****************************************************************************/
+
+extern int spiif_backlight(struct lcddrv_lcd_s *lcd, int level);
+
+/****************************************************************************
+ * Name:  FAR struct lcddrv_lcd_s *lcddrv_spiif_initialize
+ *
+ * Description:
+ *   Initialize the device structure to control the LCD Single chip driver.
+ *
+ * Input Parameters:
+ *   path : path to spi device to use
+ *
+ * Returned Value:
+ *   On success, this function returns a reference to the LCD control object
+ *   for the specified LCDDRV LCD Single chip driver.
+ *   NULL is returned on failure.
+ *
+ ****************************************************************************/
+
+FAR struct lcddrv_lcd_s *lcddrv_spiif_initialize(struct spi_dev_s *spi);
+
+#undef EXTERN
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __INCLUDE_NUTTX_LCD_LCDDRV_SPIIF_H */