aboutsummaryrefslogtreecommitdiff
path: root/nuttx/drivers/lcd
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/lcd')
-rw-r--r--nuttx/drivers/lcd/Kconfig175
-rw-r--r--nuttx/drivers/lcd/Make.defs68
-rw-r--r--nuttx/drivers/lcd/README.txt165
-rw-r--r--nuttx/drivers/lcd/mio283qt2.c1014
-rw-r--r--nuttx/drivers/lcd/nokia6100.c1230
-rw-r--r--nuttx/drivers/lcd/p14201.c1246
-rw-r--r--nuttx/drivers/lcd/pcf8833.h152
-rw-r--r--nuttx/drivers/lcd/s1d15g10.h141
-rw-r--r--nuttx/drivers/lcd/sd1329.h527
-rw-r--r--nuttx/drivers/lcd/skeleton.c401
-rw-r--r--nuttx/drivers/lcd/ssd1289.c1279
-rw-r--r--nuttx/drivers/lcd/ssd1289.h425
-rw-r--r--nuttx/drivers/lcd/ssd1305.h211
-rw-r--r--nuttx/drivers/lcd/ug-9664hswag01.c1049
14 files changed, 8083 insertions, 0 deletions
diff --git a/nuttx/drivers/lcd/Kconfig b/nuttx/drivers/lcd/Kconfig
new file mode 100644
index 000000000..af94ac16a
--- /dev/null
+++ b/nuttx/drivers/lcd/Kconfig
@@ -0,0 +1,175 @@
+#
+# For a description of the syntax of this configuration file,
+# see misc/tools/kconfig-language.txt.
+#
+config LCD_MAXCONTRAST
+ int "LCD maximum contrast"
+ default 63 if NOKIA6100_S1D15G10
+ default 127 if NOKIA6100_PCF8833
+ default 255 if LCD_P14201
+ default 63
+ ---help---
+ must be 63 with the Epson controller and 127 with
+ the Phillips controller.
+
+config LCD_MAXPOWER
+ int "LCD maximum power"
+ default 1
+ ---help---
+ Maximum value of backlight setting. The backlight
+ control is managed outside of the 6100 driver so this value has no
+ meaning to the driver. Board-specific logic may place restrictions on
+ this value.
+
+config LCD_P14201
+ bool "Rit P1402 series display"
+ default n
+ ---help---
+ p14201.c. Driver for RiT P14201 series display with SD1329 IC
+ controller. This OLED is used with older versions of the
+ TI/Luminary LM3S8962 Evaluation Kit.
+if LCD_P14201
+config P14201_NINTERFACES
+ int "Number of physical P14201 devices"
+ default 1
+ range 1,1
+ ---help---
+ Specifies the number of physical P14201
+ devices that will be supported.
+
+config P14201_SPIMODE
+ int "SPI mode"
+ default 2
+ range 0,3
+ ---help---
+ Controls the SPI mode
+
+config P14201_FREQUENCY
+ int "SPI frequency"
+ default 1000000
+ ---help---
+ Define to use a different bus frequency,FIXME DEFAULT VALUE OK?
+
+config P14201_FRAMEBUFFER
+ bool "Enable P14201 GDDRAM cache"
+ default y
+ ---help---
+ If defined, accesses will be performed
+ using an in-memory copy of the OLEDs GDDRAM. This cost of this
+ buffer is 128 * 96 / 2 = 6Kb. If this is defined, then the driver
+ will be fully functional. If not, then it will have the following
+ limitations:
+
+ Reading graphics memory cannot be supported, and
+
+ All pixel writes must be aligned to byte boundaries.
+ The latter limitation effectively reduces the 128x96 disply to 64x96.
+endif
+
+config LCD_NOKIA6100
+ bool "Nokia 6100 display support"
+ default n
+ ---help---
+ nokia6100.c. Supports the Nokia 6100 display with either the Philips
+ PCF883 or the Epson S1D15G10 display controller. This LCD is used
+ with the Olimex LPC1766-STK (but has not been fully integrated).
+if LCD_NOKIA6100
+config NOKIA6100_NINTERFACES
+ int "Number of physical NOKIA6100 devices"
+ default 1
+ range 1,1
+ ---help---
+ Specifies the number of physical Nokia
+ 6100 devices that will be supported.
+
+choice NOKIA6100_CONTROLLER
+ prompt "Controller Setup"
+ default NOKIA6100_S1D15G10
+config NOKIA6100_S1D15G10
+ bool "S1D15G10 controller"
+ ---help---
+ Selects the Epson S1D15G10 display controller
+
+config NOKIA6100_PCF8833
+ bool "PCF8833 controller"
+ ---help---
+ Selects the Phillips PCF8833 display controller
+endchoice
+
+config NOKIA6100_SPIMODE
+ int "SPI mode"
+ default 0
+ range 0,3
+ ---help---
+ Controls the SPI mode
+
+config NOKIA6100_FREQUENCY
+ int "SPI frequency"
+ default 1000000
+ ---help---
+ Define to use a different bus frequency
+
+config NOKIA6100_BLINIT
+ bool "Back light initial"
+ default n
+ ---help---
+ Initial backlight setting
+ The following may need to be tuned for your hardware:
+
+config NOKIA6100_BPP
+ int "Display bits per pixel"
+ default 8
+ ---help---
+ Device supports 8, 12, and 16 bits per pixel.
+
+config NOKIA6100_INVERT
+ int "Display inversion"
+ default 1
+ range 0,1
+ ---help---
+ Display inversion, 0 or 1, Default: 1
+
+config NOKIA6100_MY
+ int "Display row direction"
+ default 0
+ range 0,1
+ ---help---
+ Display row direction, 0 or 1, Default: 0
+
+config NOKIA6100_MX
+ int "Display column direction"
+ default 1
+ range 0,1
+ ---help---
+ Display column direction, 0 or 1, Default: 1
+
+config NOKIA6100_V
+ int "Display address direction"
+ default 0
+ range 0,1
+ ---help---
+ Display address direction, 0 or 1, Default: 0
+
+config NOKIA6100_ML
+ int "Display scan direction"
+ default 0
+ range 0,1
+ ---help---
+ Display scan direction, 0 or 1, Default: 0
+
+config NOKIA6100_RGBORD
+ int "Display RGB order"
+ default 0
+ range 0,1
+ ---help---
+ Display RGB order, 0 or 1, Default: 0
+ Required LCD driver settings:
+endif
+
+config LCD_UG9664HSWAG01
+ bool "9664HSWAG01 OLED Display Module"
+ default n
+ ---help---
+ ug-9664hswag01.c. OLED Display Module, UG-9664HSWAG01", Univision
+ Technology Inc. Used with the LPC Xpresso and Embedded Artists
+ base board.
diff --git a/nuttx/drivers/lcd/Make.defs b/nuttx/drivers/lcd/Make.defs
new file mode 100644
index 000000000..26b169391
--- /dev/null
+++ b/nuttx/drivers/lcd/Make.defs
@@ -0,0 +1,68 @@
+############################################################################
+# drivers/lcd/Make.defs
+#
+# Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
+# Author: Gregory Nutt <gnutt@nuttx.org>
+#
+# 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.
+#
+############################################################################
+
+# Don't build anything if there is no NX support for LCD drivers
+
+ifeq ($(CONFIG_NX_LCDDRIVER),y)
+
+# Include LCD drivers
+
+ifeq ($(CONFIG_LCD_P14201),y)
+ CSRCS += p14201.c
+endif
+
+ifeq ($(CONFIG_LCD_NOKIA6100),y)
+ CSRCS += nokia6100.c
+endif
+
+ifeq ($(CONFIG_LCD_UG9664HSWAG01),y)
+ CSRCS += ug-9664hswag01.c
+endif
+
+ifeq ($(CONFIG_LCD_SSD1289),y)
+ CSRCS += ssd1289.c
+endif
+
+ifeq ($(CONFIG_LCD_MIO283QT2),y)
+ CSRCS += mio283qt2.c
+endif
+
+# Include LCD driver build support
+
+DEPPATH += --dep-path lcd
+VPATH += :lcd
+CFLAGS += ${shell $(TOPDIR)/tools/incdir.sh $(INCDIROPT) "$(CC)" $(TOPDIR)/drivers/lcd}
+endif
+
diff --git a/nuttx/drivers/lcd/README.txt b/nuttx/drivers/lcd/README.txt
new file mode 100644
index 000000000..77ae536b2
--- /dev/null
+++ b/nuttx/drivers/lcd/README.txt
@@ -0,0 +1,165 @@
+nuttx/drivers/lcd README
+========================
+
+This is the README.txt file for the drivers/lcd/ directory.
+
+Contents
+========
+
+ - LCD Header files
+ include/nuttx/lcd/lcd.h
+ struct lcd_dev_s
+ - Binding LCD Drivers
+ - Examples: /drivers/lcd/
+ - Examples: configs/
+ - graphics/
+
+LCD Header files
+================
+
+ include/nuttx/lcd/lcd.h
+
+ Structures and APIs needed to work with LCD drivers are provided in
+ this header file. This header file also depends on some of the same
+ definitions used for the frame buffer driver as privided in
+ include/nuttx/fb.h.
+
+ struct lcd_dev_s
+
+ Each LCD device driver must implement an instance of struct lcd_dev_s.
+ That structure defines a call table with the following methods:
+
+ - Get information about the LCD video controller configuration and the
+ configuration of each LCD color plane.
+
+ int (*getvideoinfo)(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+ int (*getplaneinfo)(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+ - The following are provided only if the video hardware supports RGB
+ color mapping:
+
+ int (*getcmap)(FAR struct lcd_dev_s *dev,
+ FAR struct fb_cmap_s *cmap);
+ int (*putcmap)(FAR struct lcd_dev_s *dev,
+ FAR const struct fb_cmap_s *cmap);
+
+ - The following are provided only if the video hardware supports a
+ hardware cursor:
+
+ int (*getcursor)(FAR struct lcd_dev_s *dev,
+ FAR struct fb_cursorattrib_s *attrib);
+ int (*setcursor)(FAR struct lcd_dev_s *dev,
+ FAR struct fb_setcursor_s *settings);
+
+ - Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER:
+ full on). On backlit LCDs, this setting may correspond to the
+ backlight setting.
+
+ int (*getpower)(struct lcd_dev_s *dev);
+
+ - Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER:
+ full on). On backlit LCDs, this setting may correspond to the
+ backlight setting.
+
+ int (*setpower)(struct lcd_dev_s *dev, int power);
+
+ - Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST) */
+
+ int (*getcontrast)(struct lcd_dev_s *dev);
+
+ - Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST)
+
+ int (*setcontrast)(struct lcd_dev_s *dev, unsigned int contrast);
+
+Binding LCD Drivers
+===================
+
+ LCD drivers are not normally directly accessed by user code, but are
+ usually bound to another, higher level device driver. In general, the
+ binding sequence is:
+
+ 1. Get an instance of struct lcd_dev_s from the hardware-specific LCD
+ device driver, and
+ 2. Provide that instance to the initialization method of the higher
+ level device driver.
+
+Examples: /drivers/lcd/
+=======================
+
+Re-usable LCD drivers reside in the drivers/lcd directory:
+
+ mio283qt2.c. This is a driver for the MI0283QT-2 LCD from Multi-Inno
+ Technology Co., Ltd. This LCD is based on the Himax HX8347-D LCD
+ controller.
+
+ nokia6100.c. Supports the Nokia 6100 display with either the Philips
+ PCF883 or the Epson S1D15G10 display controller. This LCD is used
+ with the Olimex LPC1766-STK (but has not been fully integrated).
+
+ p14201.c. Driver for RiT P14201 series display with SD1329 IC
+ controller. This OLED is used with older versions of the
+ TI/Luminary LM3S8962 Evaluation Kit.
+
+ ssd12989.c. Generic LCD driver for LCDs based on the Solomon Systech
+ SSD1289 LCD controller. Think of this as a template for an LCD driver
+ that you will proably ahve to customize for any particular LCD
+ hardware. (see also configs/hymini-stm32v/src/ssd1289.c below).
+
+ ug-9664hswag01.c. OLED Display Module, UG-9664HSWAG01", Univision
+ Technology Inc. Used with the LPC Xpresso and Embedded Artists
+ base board.
+
+Examples: configs/
+==================
+
+There are additional LCD drivers in the configs/<board>/src directory
+that support additional LCDs. LCD drivers in the configuration directory
+if they support some differ LCD interface (such as a parallel interface)
+that makes then less re-usable:
+
+ configs/compal_e99/src/ssd1783.c
+
+ SSD1783
+
+ configs/hymini-stm32v/src/ssd1289.c. See also drivers/lcd/ssd1298.c
+ above.
+
+ SSD1289
+
+ configs/kwikstik-k40/src/up_lcd.c. Don't waste your time. This is
+ just a stub.
+
+ configs/olimex-lpc1766stk/src/up_lcd.c. This examples is the
+ bottom half for the SSD1289 driver at drivers/lcd/nokia6100.c.
+ This was never completedly debugged ... there are probably issues
+ with that nasty 9-bit SPI interfaces.
+
+ configs/sam3u-ek/src/up_lcd.c
+
+ The SAM3U-EK developement board features a TFT/Transmissive color
+ LCD module with touch-screen, FTM280C12D, with integrated driver IC
+ HX8346.
+
+ configs/skp16c26/src/up_lcd.c. Untested alphanumeric LCD driver.
+
+ configs/stm3210e-eval/src/up_lcd.c
+
+ This driver supports the following LCDs:
+
+ 1. Ampire AM-240320LTNQW00H
+ 2. Orise Tech SPFD5408B
+ 3. RenesasSP R61580
+
+ configs/stm3220g-eval/src/up_lcd.c and configs/stm3240g-eval/src/up_lcd.c.
+ AM-240320L8TNQW00H (LCD_ILI9320 or LCD_ILI9321) and
+ AM-240320D5TOQW01H (LCD_ILI9325)
+
+ configs/stm32f4discovery/src/up_ssd1289.c. This examples is the
+ bottom half for the SSD1289 driver at drivers/lcd/ssd1289.c
+
+graphics/
+=========
+
+ See also the usage of the LCD driver in the graphics/ directory.
diff --git a/nuttx/drivers/lcd/mio283qt2.c b/nuttx/drivers/lcd/mio283qt2.c
new file mode 100644
index 000000000..1758e230c
--- /dev/null
+++ b/nuttx/drivers/lcd/mio283qt2.c
@@ -0,0 +1,1014 @@
+/**************************************************************************************
+ * drivers/lcd/mio283qt2.c
+ *
+ * This is a driver for the MI0283QT-2 LCD from Multi-Inno Technology Co., Ltd. This
+ * LCD is based on the Himax HX8347-D LCD controller.
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * References:
+ * 1) LCD Module Specification, Model : MI0283QT-2, Multi-Inno Technology Co.,
+ * Ltd., Revision 1.0
+ * 2) Data Sheet: HX8347-D(T), 240RGB x 320 dot, 262K color, with internal GRAM, TFT
+ * Mobile Single Chip Driver Version 02 March, Doc No. HX8347-D(T)-DS, Himax
+ * Technologies, Inc., 2009,
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+#include <nuttx/lcd/lcd.h>
+#include <nuttx/lcd/mio283qt2.h>
+
+#ifdef CONFIG_LCD_MIO283QT2
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+/* Configuration **********************************************************************/
+
+/* Check contrast selection */
+
+#if !defined(CONFIG_LCD_MAXCONTRAST)
+# define CONFIG_LCD_MAXCONTRAST 1
+#endif
+
+/* Check power setting */
+
+#if !defined(CONFIG_LCD_MAXPOWER) || CONFIG_LCD_MAXPOWER < 1
+# define CONFIG_LCD_MAXPOWER 1
+#endif
+
+#if CONFIG_LCD_MAXPOWER > 255
+# error "CONFIG_LCD_MAXPOWER must be less than 256 to fit in uint8_t"
+#endif
+
+/* Check orientation */
+
+#if defined(CONFIG_LCD_PORTRAIT)
+# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) || defined(CONFIG_LCD_RPORTRAIT)
+# error "Cannot define both portrait and any other orientations"
+# endif
+#elif defined(CONFIG_LCD_RPORTRAIT)
+# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
+# error "Cannot define both rportrait and any other orientations"
+# endif
+#elif defined(CONFIG_LCD_LANDSCAPE)
+# ifdef CONFIG_LCD_RLANDSCAPE
+# error "Cannot define both landscape and any other orientations"
+# endif
+#elif !defined(CONFIG_LCD_RLANDSCAPE)
+# define CONFIG_LCD_LANDSCAPE 1
+#endif
+
+/* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug must
+ * also be enabled.
+ */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_GRAPHICS
+# undef CONFIG_DEBUG_LCD
+#endif
+
+#ifndef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_LCD
+#endif
+
+/* Display/Color Properties ***********************************************************/
+/* Display Resolution */
+
+#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
+# define MIO283QT2_XRES 320
+# define MIO283QT2_YRES 240
+#else
+# define MIO283QT2_XRES 240
+# define MIO283QT2_YRES 320
+#endif
+
+/* Color depth and format */
+
+#define MIO283QT2_BPP 16
+#define MIO283QT2_COLORFMT FB_FMT_RGB16_565
+
+/* Hardware LCD/LCD controller definitions ********************************************/
+/* In this driver, I chose to use all literal constants for register address and
+ * values. Some recent experiences have shown me that during LCD bringup, it is more
+ * important to know the binary values rather than nice, people friendly names. Sad,
+ * but true.
+ */
+
+#define HIMAX_ID 0x0047
+
+/* LCD Profiles ***********************************************************************/
+/* Many details of the controller initialization must, unfortunately, vary from LCD to
+ * LCD. I have looked at the spec and at three different drivers for LCDs that have
+ * MIO283QT2 controllers. I have tried to summarize these differences as "LCD profiles"
+ *
+ * Most of the differences between LCDs are nothing more than a few minor bit
+ * settings. The most significant difference betwen LCD drivers in is the
+ * manner in which the LCD is powered up and in how the power controls are set.
+ * My suggestion is that if you have working LCD initialization code, you should
+ * simply replace the code in mio283qt2_hwinitialize with your working code.
+ */
+
+#if defined (CONFIG_MIO283QT2_PROFILE2)
+# undef MIO283QT2_USE_SIMPLE_INIT
+
+ /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */
+
+# define PWRCTRL1_SETTING \
+ (MIO283QT2_PWRCTRL1_AP_SMMED | MIO283QT2_PWRCTRL1_DC_FLINEx24 | \
+ MIO283QT2_PWRCTRL1_BT_p5m4 | MIO283QT2_PWRCTRL1_DCT_FLINEx24)
+
+ /* PWRCTRL2: 5.1v */
+
+# define PWRCTRL2_SETTING MIO283QT2_PWRCTRL2_VRC_5p1V
+
+ /* PWRCTRL3: x 2.165
+ * NOTE: Many drivers have bit 8 set which is not defined in the MIO283QT2 spec.
+ */
+
+# define PWRCTRL3_SETTING MIO283QT2_PWRCTRL3_VRH_x2p165
+
+ /* PWRCTRL4: VDV=9 + VCOMG */
+
+# define PWRCTRL4_SETTING (MIO283QT2_PWRCTRL4_VDV(9) | MIO283QT2_PWRCTRL4_VCOMG)
+
+ /* PWRCTRL5: VCM=56 + NOTP */
+
+# define PWRCTRL5_SETTING (MIO283QT2_PWRCTRL5_VCM(56) | MIO283QT2_PWRCTRL5_NOTP)
+
+#elif defined (CONFIG_MIO283QT2_PROFILE3)
+# undef MIO283QT2_USE_SIMPLE_INIT
+
+ /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */
+
+# define PWRCTRL1_SETTING \
+ (MIO283QT2_PWRCTRL1_AP_SMMED | MIO283QT2_PWRCTRL1_DC_FLINEx24 | \
+ MIO283QT2_PWRCTRL1_BT_p5m4 | MIO283QT2_PWRCTRL1_DCT_FLINEx24)
+
+ /* PWRCTRL2: 5.1v */
+
+# define PWRCTRL2_SETTING MIO283QT2_PWRCTRL2_VRC_5p1V
+
+ /* PWRCTRL3: x 2.165
+ * NOTE: Many drivers have bit 8 set which is not defined in the MIO283QT2 spec.
+ */
+
+# define PWRCTRL3_SETTING MIO283QT2_PWRCTRL3_VRH_x2p165
+
+ /* PWRCTRL4: VDV=9 + VCOMG */
+
+# define PWRCTRL4_SETTING (MIO283QT2_PWRCTRL4_VDV(9) | MIO283QT2_PWRCTRL4_VCOMG)
+
+ /* PWRCTRL5: VCM=56 + NOTP */
+
+# define PWRCTRL5_SETTING (MIO283QT2_PWRCTRL5_VCM(56) | MIO283QT2_PWRCTRL5_NOTP)
+
+#else /* if defined (CONFIG_MIO283QT2_PROFILE1) */
+# undef MIO283QT2_USE_SIMPLE_INIT
+# define MIO283QT2_USE_SIMPLE_INIT 1
+
+ /* PWRCTRL1: AP=medium-to-large, DC=Fosc/4, BT=+5/-4, DCT=Fosc/4 */
+
+# define PWRCTRL1_SETTING \
+ (MIO283QT2_PWRCTRL1_AP_MEDLG | MIO283QT2_PWRCTRL1_DC_FOSd4 | \
+ MIO283QT2_PWRCTRL1_BT_p5m4 | MIO283QT2_PWRCTRL1_DCT_FOSd4)
+
+ /* PWRCTRL2: 5.3v */
+
+# define PWRCTRL2_SETTING MIO283QT2_PWRCTRL2_VRC_5p3V
+
+ /* PWRCTRL3: x 2.570
+ * NOTE: Many drivers have bit 8 set which is not defined in the MIO283QT2 spec.
+ */
+
+# define PWRCTRL3_SETTING MIO283QT2_PWRCTRL3_VRH_x2p570
+
+ /* PWRCTRL4: VDV=12 + VCOMG */
+
+# define PWRCTRL4_SETTING (MIO283QT2_PWRCTRL4_VDV(12) | MIO283QT2_PWRCTRL4_VCOMG)
+
+ /* PWRCTRL5: VCM=60 + NOTP */
+
+# define PWRCTRL5_SETTING (MIO283QT2_PWRCTRL5_VCM(60) | MIO283QT2_PWRCTRL5_NOTP)
+
+#endif
+
+/* Debug ******************************************************************************/
+
+#ifdef CONFIG_DEBUG_LCD
+# define lcddbg dbg
+# define lcdvdbg vdbg
+#else
+# define lcddbg(x...)
+# define lcdvdbg(x...)
+#endif
+
+/**************************************************************************************
+ * Private Type Definition
+ **************************************************************************************/
+
+/* This structure describes the state of this driver */
+
+struct mio283qt2_dev_s
+{
+ /* Publically visible device structure */
+
+ struct lcd_dev_s dev;
+
+ /* Private LCD-specific information follows */
+
+ FAR struct mio283qt2_lcd_s *lcd; /* The contained platform-specific, LCD interface */
+ uint8_t power; /* Current power setting */
+
+ /* This is working memory allocated by the LCD driver for each LCD device
+ * and for each color plane. This memory will hold one raster line of data.
+ * The size of the allocated run buffer must therefore be at least
+ * (bpp * xres / 8). Actual alignment of the buffer must conform to the
+ * bitwidth of the underlying pixel type.
+ *
+ * If there are multiple planes, they may share the same working buffer
+ * because different planes will not be operate on concurrently. However,
+ * if there are multiple LCD devices, they must each have unique run buffers.
+ */
+
+ uint16_t runbuffer[MIO283QT2_XRES];
+};
+
+/**************************************************************************************
+ * Private Function Protototypes
+ **************************************************************************************/
+/* Low Level LCD access */
+
+static void mio283qt2_putreg(FAR struct mio283qt2_lcd_s *lcd, uint8_t regaddr,
+ uint16_t regval);
+#ifndef CONFIG_LCD_NOGETRUN
+static uint16_t mio283qt2_readreg(FAR struct mio283qt2_lcd_s *lcd, uint8_t regaddr);
+#endif
+static inline void mio283qt2_gramwrite(FAR struct mio283qt2_lcd_s *lcd,
+ uint16_t rgbcolor);
+#ifndef CONFIG_LCD_NOGETRUN
+static inline void mio283qt2_readsetup(FAR struct mio283qt2_lcd_s *lcd,
+ FAR uint16_t *accum);
+static inline uint16_t mio283qt2_gramread(FAR struct mio283qt2_lcd_s *lcd,
+ FAR uint16_t *accum);
+#endif
+static void mio283qt2_setarea(FAR struct mio283qt2_lcd_s *lcd,
+ uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
+
+/* LCD Data Transfer Methods */
+
+static int mio283qt2_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels);
+static int mio283qt2_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels);
+
+/* LCD Configuration */
+
+static int mio283qt2_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+static int mio283qt2_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+/* LCD RGB Mapping */
+
+#ifdef CONFIG_FB_CMAP
+# error "RGB color mapping not supported by this driver"
+#endif
+
+/* Cursor Controls */
+
+#ifdef CONFIG_FB_HWCURSOR
+# error "Cursor control not supported by this driver"
+#endif
+
+/* LCD Specific Controls */
+
+static int mio283qt2_getpower(FAR struct lcd_dev_s *dev);
+static int mio283qt2_setpower(FAR struct lcd_dev_s *dev, int power);
+static int mio283qt2_getcontrast(FAR struct lcd_dev_s *dev);
+static int mio283qt2_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast);
+
+/* Initialization */
+
+static inline int mio283qt2_hwinitialize(FAR struct mio283qt2_dev_s *priv);
+
+/**************************************************************************************
+ * Private Data
+ **************************************************************************************/
+
+/* This driver can support only a signal MIO283QT2 device. This is due to an
+ * unfortunate decision made whent he getrun and putrun methods were designed. The
+ * following is the single MIO283QT2 driver state instance:
+ */
+
+static struct mio283qt2_dev_s g_lcddev;
+
+/**************************************************************************************
+ * Private Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: mio283qt2_putreg(lcd,
+ *
+ * Description:
+ * Write to an LCD register
+ *
+ **************************************************************************************/
+
+static void mio283qt2_putreg(FAR struct mio283qt2_lcd_s *lcd,
+ uint8_t regaddr, uint16_t regval)
+{
+ /* Set the index register to the register address and write the register contents */
+
+ lcd->index(lcd, regaddr);
+ lcd->write(lcd, regval);
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_readreg
+ *
+ * Description:
+ * Read from an LCD register
+ *
+ **************************************************************************************/
+
+#ifndef CONFIG_LCD_NOGETRUN
+static uint16_t mio283qt2_readreg(FAR struct mio283qt2_lcd_s *lcd, uint8_t regaddr)
+{
+ /* Set the index register to the register address and read the register contents. */
+
+ lcd->index(lcd, regaddr);
+ return lcd->read(lcd);
+}
+#endif
+
+/**************************************************************************************
+ * Name: mio283qt2_gramselect
+ *
+ * Description:
+ * Setup to read or write multiple pixels to the GRAM memory
+ *
+ **************************************************************************************/
+
+static inline void mio283qt2_gramselect(FAR struct mio283qt2_lcd_s *lcd)
+{
+ lcd->index(lcd, 0x22);
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_gramwrite
+ *
+ * Description:
+ * Setup to read or write multiple pixels to the GRAM memory
+ *
+ **************************************************************************************/
+
+static inline void mio283qt2_gramwrite(FAR struct mio283qt2_lcd_s *lcd, uint16_t data)
+{
+ lcd->write(lcd, data);
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_readsetup
+ *
+ * Description:
+ * Prime the operation by reading one pixel from the GRAM memory if necessary for
+ * this LCD type. When reading 16-bit gram data, there may be some shifts in the
+ * returned data:
+ *
+ * - ILI932x: Discard first dummy read; no shift in the return data
+ *
+ **************************************************************************************/
+
+#ifndef CONFIG_LCD_NOGETRUN
+static inline void mio283qt2_readsetup(FAR struct mio283qt2_lcd_s *lcd,
+ FAR uint16_t *accum)
+{
+#if 0 /* Probably not necessary... untested */
+ /* Read-ahead one pixel */
+
+ *accum = lcd->read(lcd);
+#endif
+}
+#endif
+
+/**************************************************************************************
+ * Name: mio283qt2_gramread
+ *
+ * Description:
+ * Read one correctly aligned pixel from the GRAM memory. Possibly shifting the
+ * data and possibly swapping red and green components.
+ *
+ * - ILI932x: Unknown -- assuming colors are in the color order
+ *
+ **************************************************************************************/
+
+#ifndef CONFIG_LCD_NOGETRUN
+static inline uint16_t mio283qt2_gramread(FAR struct mio283qt2_lcd_s *lcd,
+ FAR uint16_t *accum)
+{
+ /* Read the value (GRAM register already selected) */
+
+ return lcd->read(lcd);
+}
+#endif
+
+/**************************************************************************************
+ * Name: mio283qt2_setarea
+ *
+ * Description:
+ * Set the cursor position. In landscape mode, the "column" is actually the physical
+ * Y position and the "row" is the physical X position.
+ *
+ **************************************************************************************/
+
+static void mio283qt2_setarea(FAR struct mio283qt2_lcd_s *lcd,
+ uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
+{
+ mio283qt2_putreg(lcd, 0x03, (x0 & 0x00ff)); /* set x0 */
+ mio283qt2_putreg(lcd, 0x02, (x0 >> 8)); /* set x0 */
+ mio283qt2_putreg(lcd, 0x05, (x1 & 0x00ff)); /* set x1 */
+ mio283qt2_putreg(lcd, 0x04, (x1 >> 8)); /* set x1 */
+ mio283qt2_putreg(lcd, 0x07, (y0 & 0x00ff)); /* set y0 */
+ mio283qt2_putreg(lcd, 0x06, (y0 >> 8)); /* set y0 */
+ mio283qt2_putreg(lcd, 0x09, (y1 & 0x00ff)); /* set y1 */
+ mio283qt2_putreg(lcd, 0x08, (y1 >> 8)); /* set y1 */
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_dumprun
+ *
+ * Description:
+ * Dump the contexts of the run buffer:
+ *
+ * run - The buffer in containing the run read to be dumped
+ * npixels - The number of pixels to dump
+ *
+ **************************************************************************************/
+
+#if 0 /* Sometimes useful */
+static void mio283qt2_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels)
+{
+ int i, j;
+
+ lib_rawprintf("\n%s:\n", msg);
+ for (i = 0; i < npixels; i += 16)
+ {
+ up_putc(' ');
+ lib_rawprintf(" ");
+ for (j = 0; j < 16; j++)
+ {
+ lib_rawprintf(" %04x", *run++);
+ }
+ up_putc('\n');
+ }
+}
+#endif
+
+/**************************************************************************************
+ * Name: mio283qt2_putrun
+ *
+ * Description:
+ * This method can be used to write a partial raster line to the LCD:
+ *
+ * row - Starting row to write to (range: 0 <= row < yres)
+ * col - Starting column to write to (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer containing the run to be written to the LCD
+ * npixels - The number of pixels to write to the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int mio283qt2_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ FAR struct mio283qt2_dev_s *priv = &g_lcddev;
+ FAR struct mio283qt2_lcd_s *lcd = priv->lcd;
+ FAR const uint16_t *src = (FAR const uint16_t*)buffer;
+ int i;
+
+ /* Buffer must be provided and aligned to a 16-bit address boundary */
+
+ lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+ /* Write the run to GRAM. */
+
+ mio283qt2_setarea(lcd, col, row, col + npixels - 1, row);
+ mio283qt2_gramselect(lcd);
+
+ for (i = 0; i < npixels; i++)
+ {
+ mio283qt2_gramwrite(lcd, *src);
+ src++;
+ }
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_getrun
+ *
+ * Description:
+ * This method can be used to read a partial raster line from the LCD:
+ *
+ * row - Starting row to read from (range: 0 <= row < yres)
+ * col - Starting column to read read (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer in which to return the run read from the LCD
+ * npixels - The number of pixels to read from the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int mio283qt2_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+#ifndef CONFIG_LCD_NOGETRUN
+ FAR struct mio283qt2_dev_s *priv = &g_lcddev;
+ FAR struct mio283qt2_lcd_s *lcd = priv->lcd;
+ FAR uint16_t *dest = (FAR uint16_t*)buffer;
+ uint16_t accum;
+ int i;
+
+ /* Buffer must be provided and aligned to a 16-bit address boundary */
+
+ lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+ /* Read the run from GRAM. */
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+ /* Red the run fram GRAM. */
+
+ mio283qt2_setarea(lcd, col, row, col + npixels - 1, row);
+ mio283qt2_gramselect(lcd);
+
+ /* Prime the pump for unaligned read data */
+
+ mio283qt2_readsetup(lcd, &accum);
+
+ for (i = 0; i < npixels; i++)
+ {
+ *dest++ = mio283qt2_gramread(lcd, &accum);
+ }
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+ return OK;
+#else
+ return -ENOSYS;
+#endif
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_getvideoinfo
+ *
+ * Description:
+ * Get information about the LCD video controller configuration.
+ *
+ **************************************************************************************/
+
+static int mio283qt2_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo)
+{
+ DEBUGASSERT(dev && vinfo);
+ lcdvdbg("fmt: %d xres: %d yres: %d nplanes: 1\n",
+ MIO283QT2_COLORFMT, MIO283QT2_XRES, MIO283QT2_XRES);
+
+ vinfo->fmt = MIO283QT2_COLORFMT; /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
+ vinfo->xres = MIO283QT2_XRES; /* Horizontal resolution in pixel columns */
+ vinfo->yres = MIO283QT2_YRES; /* Vertical resolution in pixel rows */
+ vinfo->nplanes = 1; /* Number of color planes supported */
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_getplaneinfo
+ *
+ * Description:
+ * Get information about the configuration of each LCD color plane.
+ *
+ **************************************************************************************/
+
+static int mio283qt2_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo)
+{
+ FAR struct mio283qt2_dev_s *priv = (FAR struct mio283qt2_dev_s *)dev;
+
+ DEBUGASSERT(dev && pinfo && planeno == 0);
+ lcdvdbg("planeno: %d bpp: %d\n", planeno, MIO283QT2_BPP);
+
+ pinfo->putrun = mio283qt2_putrun; /* Put a run into LCD memory */
+ pinfo->getrun = mio283qt2_getrun; /* Get a run from LCD memory */
+ pinfo->buffer = (uint8_t*)priv->runbuffer; /* Run scratch buffer */
+ pinfo->bpp = MIO283QT2_BPP; /* Bits-per-pixel */
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_getpower
+ *
+ * Description:
+ * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int mio283qt2_getpower(FAR struct lcd_dev_s *dev)
+{
+ lcdvdbg("power: %d\n", 0);
+ return g_lcddev.power;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_poweroff
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int mio283qt2_poweroff(FAR struct mio283qt2_lcd_s *lcd)
+{
+ /* Set the backlight off */
+
+ lcd->backlight(lcd, 0);
+
+ /* Turn the display off */
+
+ mio283qt2_putreg(lcd, 0x28, 0x0000); /* GON=0, DTE=0, D=0 */
+
+ /* Remember the power off state */
+
+ g_lcddev.power = 0;
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_setpower
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int mio283qt2_setpower(FAR struct lcd_dev_s *dev, int power)
+{
+ FAR struct mio283qt2_dev_s *priv = (FAR struct mio283qt2_dev_s *)dev;
+ FAR struct mio283qt2_lcd_s *lcd = priv->lcd;
+
+ lcdvdbg("power: %d\n", power);
+ DEBUGASSERT((unsigned)power <= CONFIG_LCD_MAXPOWER);
+
+ /* Set new power level */
+
+ if (power > 0)
+ {
+ /* Set the backlight level */
+
+ lcd->backlight(lcd, power);
+
+ /* Then turn the display on:
+ * D=ON(3) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0
+ */
+
+ /* Display on */
+
+ mio283qt2_putreg(lcd, 0x28, 0x0038); /* GON=1, DTE=1, D=2 */
+ up_mdelay(40);
+ mio283qt2_putreg(lcd, 0x28, 0x003c); /* GON=1, DTE=1, D=3 */
+
+ g_lcddev.power = power;
+ }
+ else
+ {
+ /* Turn the display off */
+
+ mio283qt2_poweroff(lcd);
+ }
+
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_getcontrast
+ *
+ * Description:
+ * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int mio283qt2_getcontrast(FAR struct lcd_dev_s *dev)
+{
+ lcdvdbg("Not implemented\n");
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_setcontrast
+ *
+ * Description:
+ * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int mio283qt2_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast)
+{
+ lcdvdbg("contrast: %d\n", contrast);
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_hwinitialize
+ *
+ * Description:
+ * Initialize the LCD hardware.
+ *
+ **************************************************************************************/
+
+static inline int mio283qt2_hwinitialize(FAR struct mio283qt2_dev_s *priv)
+{
+ FAR struct mio283qt2_lcd_s *lcd = priv->lcd;
+#ifndef CONFIG_LCD_NOGETRUN
+ uint16_t id;
+#endif
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+ /* Read the HIMAX ID registger (0x00) */
+
+#ifndef CONFIG_LCD_NOGETRUN
+ id = mio283qt2_readreg(lcd, 0x00);
+ lcddbg("LCD ID: %04x\n", id);
+
+ /* Check if the ID is for the MIO283QT2 */
+
+ if (id == HIMAX_ID)
+#endif
+ {
+ /* Driving ability */
+
+ mio283qt2_putreg(lcd, 0xea, 0x0000); /* PTBA[15:8] */
+ mio283qt2_putreg(lcd, 0xeb, 0x0020); /* PTBA[7:0] */
+ mio283qt2_putreg(lcd, 0xec, 0x000c); /* STBA[15:8] */
+ mio283qt2_putreg(lcd, 0xed, 0x00c4); /* STBA[7:0] */
+ mio283qt2_putreg(lcd, 0xe8, 0x0040); /* OPON[7:0] */
+ mio283qt2_putreg(lcd, 0xe9, 0x0038); /* OPON1[7:0] */
+ mio283qt2_putreg(lcd, 0xf1, 0x0001); /* OTPS1B */
+ mio283qt2_putreg(lcd, 0xf2, 0x0010); /* GEN */
+ mio283qt2_putreg(lcd, 0x27, 0x00a3);
+
+ /* Power voltage */
+
+ mio283qt2_putreg(lcd, 0x1b, 0x001b); /* VRH = 4.65 */
+ mio283qt2_putreg(lcd, 0x1a, 0x0001); /* BT */
+ mio283qt2_putreg(lcd, 0x24, 0x002f); /* VMH */
+ mio283qt2_putreg(lcd, 0x25, 0x0057); /* VML */
+
+ /* Vcom offset */
+
+ mio283qt2_putreg(lcd, 0x23, 0x008d); /* For flicker adjust */
+
+ /* Power on */
+
+ mio283qt2_putreg(lcd, 0x18, 0x0036);
+ mio283qt2_putreg(lcd, 0x19, 0x0001); /* Start oscillator */
+ mio283qt2_putreg(lcd, 0x01, 0x0000); /* Wakeup */
+ mio283qt2_putreg(lcd, 0x1f, 0x0088);
+ up_mdelay(5);
+ mio283qt2_putreg(lcd, 0x1f, 0x0080);
+ up_mdelay(5);
+ mio283qt2_putreg(lcd, 0x1f, 0x0090);
+ up_mdelay(5);
+ mio283qt2_putreg(lcd, 0x1f, 0x00d0);
+ up_mdelay(5);
+
+ /* Gamma 2.8 setting */
+
+ mio283qt2_putreg(lcd, 0x40, 0x0000);
+ mio283qt2_putreg(lcd, 0x41, 0x0000);
+ mio283qt2_putreg(lcd, 0x42, 0x0001);
+ mio283qt2_putreg(lcd, 0x43, 0x0013);
+ mio283qt2_putreg(lcd, 0x44, 0x0010);
+ mio283qt2_putreg(lcd, 0x45, 0x0026);
+ mio283qt2_putreg(lcd, 0x46, 0x0008);
+ mio283qt2_putreg(lcd, 0x47, 0x0051);
+ mio283qt2_putreg(lcd, 0x48, 0x0002);
+ mio283qt2_putreg(lcd, 0x49, 0x0012);
+ mio283qt2_putreg(lcd, 0x4a, 0x0018);
+ mio283qt2_putreg(lcd, 0x4b, 0x0019);
+ mio283qt2_putreg(lcd, 0x4c, 0x0014);
+
+ mio283qt2_putreg(lcd, 0x50, 0x0019);
+ mio283qt2_putreg(lcd, 0x51, 0x002f);
+ mio283qt2_putreg(lcd, 0x52, 0x002c);
+ mio283qt2_putreg(lcd, 0x53, 0x003e);
+ mio283qt2_putreg(lcd, 0x54, 0x003f);
+ mio283qt2_putreg(lcd, 0x55, 0x003f);
+ mio283qt2_putreg(lcd, 0x56, 0x002e);
+ mio283qt2_putreg(lcd, 0x57, 0x0077);
+ mio283qt2_putreg(lcd, 0x58, 0x000b);
+ mio283qt2_putreg(lcd, 0x59, 0x0006);
+ mio283qt2_putreg(lcd, 0x5a, 0x0007);
+ mio283qt2_putreg(lcd, 0x5b, 0x000d);
+ mio283qt2_putreg(lcd, 0x5c, 0x001d);
+ mio283qt2_putreg(lcd, 0x5d, 0x00cc);
+
+ /* 4K Color Selection */
+
+ mio283qt2_putreg(lcd, 0x17, 0x0003);
+ mio283qt2_putreg(lcd, 0x17, 0x0005); /* 0x0005=65k, 0x0006=262k */
+
+ /* Panel characteristics */
+
+ mio283qt2_putreg(lcd, 0x36, 0x0000);
+
+ /* Display Setting */
+
+ mio283qt2_putreg(lcd, 0x01, 0x0000); /* IDMON=0, INVON=0, NORON=0, PTLON=0 */
+
+#if defined(CONFIG_LCD_LANDSCAPE)
+ mio283qt2_putreg(lcd, 0x16, 0x00a8); /* MY=1, MX=0, MV=1, ML=0, BGR=1 */
+#elif defined(CONFIG_LCD_PORTRAIT)
+ mio283qt2_putreg(lcd, 0x16, 0x0008); /* MY=0, MX=0, MV=0, ML=0, BGR=1 */
+#elif defined(CONFIG_LCD_RLANDSCAPE)
+ mio283qt2_putreg(lcd, 0x16, 0x0068); /* MY=0, MX=1, MV=1, ML=0, BGR=1 */
+#elif defined(CONFIG_LCD_RPORTRAIT)
+ mio283qt2_putreg(lcd, 0x16, 0x00c8); /* MY=1, MX=0, MV=1, ML=0, BGR=1 */
+#endif
+
+ /* Window setting */
+
+ mio283qt2_setarea(lcd, 0, 0, (MIO283QT2_XRES-1), (MIO283QT2_YRES-1));
+ return OK;
+ }
+#ifndef CONFIG_LCD_NOGETRUN
+ else
+ {
+ lcddbg("Unsupported LCD type\n");
+ return -ENODEV;
+ }
+#endif
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+}
+
+ /*************************************************************************************
+ * Public Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: mio283qt2_lcdinitialize
+ *
+ * Description:
+ * Initialize the LCD video hardware. The initial state of the LCD is fully
+ * initialized, display memory cleared, and the LCD ready to use, but with the power
+ * setting at 0 (full off).
+ *
+ **************************************************************************************/
+
+FAR struct lcd_dev_s *mio283qt2_lcdinitialize(FAR struct mio283qt2_lcd_s *lcd)
+{
+ int ret;
+
+ lcdvdbg("Initializing\n");
+
+ /* If we ccould support multiple MIO283QT2 devices, this is where we would allocate
+ * a new driver data structure... but we can't. Why not? Because of a bad should
+ * the form of the getrun() and putrun methods.
+ */
+
+ FAR struct mio283qt2_dev_s *priv = &g_lcddev;
+
+ /* Initialize the driver data structure */
+
+ priv->dev.getvideoinfo = mio283qt2_getvideoinfo;
+ priv->dev.getplaneinfo = mio283qt2_getplaneinfo;
+ priv->dev.getpower = mio283qt2_getpower;
+ priv->dev.setpower = mio283qt2_setpower;
+ priv->dev.getcontrast = mio283qt2_getcontrast;
+ priv->dev.setcontrast = mio283qt2_setcontrast;
+ priv->lcd = lcd;
+
+ /* Configure and enable LCD */
+
+ ret = mio283qt2_hwinitialize(priv);
+ if (ret == OK)
+ {
+ /* Clear the display (setting it to the color 0=black) */
+
+ mio283qt2_clear(&priv->dev, 0);
+
+ /* Turn the display off */
+
+ mio283qt2_poweroff(lcd);
+ return &g_lcddev.dev;
+ }
+
+ return NULL;
+}
+
+/**************************************************************************************
+ * Name: mio283qt2_clear
+ *
+ * Description:
+ * This is a non-standard LCD interface just for the stm3240g-EVAL board. Because
+ * of the various rotations, clearing the display in the normal way by writing a
+ * sequences of runs that covers the entire display can be very slow. Here the
+ * display is cleared by simply setting all GRAM memory to the specified color.
+ *
+ **************************************************************************************/
+
+void mio283qt2_clear(FAR struct lcd_dev_s *dev, uint16_t color)
+{
+ FAR struct mio283qt2_dev_s *priv = (FAR struct mio283qt2_dev_s *)dev;
+ FAR struct mio283qt2_lcd_s *lcd = priv->lcd;
+ uint32_t i;
+
+ /* Select the LCD and set the drawring area */
+
+ lcd->select(lcd);
+ mio283qt2_setarea(lcd, 0, 0, (MIO283QT2_XRES-1), (MIO283QT2_YRES-1));
+
+ /* Prepare to write GRAM data */
+
+ mio283qt2_gramselect(lcd);
+
+ /* Copy color into all of GRAM. Orientation does not matter in this case. */
+
+ for (i = 0; i < MIO283QT2_XRES * MIO283QT2_YRES; i++)
+ {
+ mio283qt2_gramwrite(lcd, color);
+ }
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+}
+
+#endif /* CONFIG_LCD_MIO283QT2 */
diff --git a/nuttx/drivers/lcd/nokia6100.c b/nuttx/drivers/lcd/nokia6100.c
new file mode 100644
index 000000000..d450e05db
--- /dev/null
+++ b/nuttx/drivers/lcd/nokia6100.c
@@ -0,0 +1,1230 @@
+/**************************************************************************************
+ * drivers/lcd/nokia6100.c
+ * Nokia 6100 LCD Display Driver
+ *
+ * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * References:
+ * "Nokia 6100 LCD Display Driver," Revision 1, James P. Lynch ("Nokia 6100 LCD
+ * Display Driver.pdf")
+ * "S1D15G0D08B000," Seiko Epson Corportation, 2002.
+ * "Data Sheet, PCF8833 STN RGB 132x132x3 driver," Phillips, 2003 Feb 14.
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+#include <nuttx/lcd/lcd.h>
+#include <nuttx/lcd/nokia6100.h>
+
+#ifdef CONFIG_NOKIA6100_PCF8833
+# include "pcf8833.h"
+#endif
+#ifdef CONFIG_NOKIA6100_S1D15G10
+# include "s1d15g10.h"
+#endif
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+
+/* Configuration **********************************************************************/
+/* Verify that all configuration requirements have been met */
+
+/* Nokia 6100 Configuration Settings:
+ *
+ * CONFIG_NOKIA6100_SPIMODE - Controls the SPI mode
+ * CONFIG_NOKIA6100_FREQUENCY - Define to use a different bus frequency
+ * CONFIG_NOKIA6100_NINTERFACES - Specifies the number of physical Nokia 6100 devices that
+ * will be supported.
+ * CONFIG_NOKIA6100_BPP - Device supports 8, 12, and 16 bits per pixel.
+ * CONFIG_NOKIA6100_S1D15G10 - Selects the Epson S1D15G10 display controller
+ * CONFIG_NOKIA6100_PCF8833 - Selects the Phillips PCF8833 display controller
+ * CONFIG_NOKIA6100_BLINIT - Initial backlight setting
+ *
+ * The following may need to be tuned for your hardware:
+ * CONFIG_NOKIA6100_INVERT - Display inversion, 0 or 1, Default: 1
+ * CONFIG_NOKIA6100_MY - Display row direction, 0 or 1, Default: 0
+ * CONFIG_NOKIA6100_MX - Display column direction, 0 or 1, Default: 1
+ * CONFIG_NOKIA6100_V - Display address direction, 0 or 1, Default: 0
+ * CONFIG_NOKIA6100_ML - Display scan direction, 0 or 1, Default: 0
+ * CONFIG_NOKIA6100_RGBORD - Display RGB order, 0 or 1, Default: 0
+ *
+ * Required LCD driver settings:
+ * CONFIG_LCD_NOKIA6100 - Enable Nokia 6100 support
+ * CONFIG_LCD_MAXCONTRAST - must be 63 with the Epson controller and 127 with
+ * the Phillips controller.
+ * CONFIG_LCD_MAXPOWER - Maximum value of backlight setting. The backlight control is
+ * managed outside of the 6100 driver so this value has no meaning to the driver.
+ */
+
+/* Mode 0,0 should be use. However, somtimes you need to tinker with these things. */
+
+#ifndef CONFIG_NOKIA6100_SPIMODE
+# define CONFIG_NOKIA6100_SPIMODE SPIDEV_MODE0
+#endif
+
+/* Default frequency: 1Mhz */
+
+#ifndef CONFIG_NOKIA6100_FREQUENCY
+# define CONFIG_NOKIA6100_FREQUENCY 1000000
+#endif
+
+/* CONFIG_NOKIA6100_NINTERFACES determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#ifndef CONFIG_NOKIA6100_NINTERFACES
+# define CONFIG_NOKIA6100_NINTERFACES 1
+#endif
+
+#if CONFIG_NOKIA6100_NINTERFACES != 1
+# error "This implementation supports only a single LCD device"
+#endif
+
+/* Only support for 8 and 12 BPP currently implemented */
+
+#if !defined(CONFIG_NOKIA6100_BPP)
+# warning "Assuming 8BPP"
+# define CONFIG_NOKIA6100_BPP 8
+#endif
+
+#if CONFIG_NOKIA6100_BPP != 8 && CONFIG_NOKIA6100_BPP != 12
+# if CONFIG_NOKIA6100_BPP == 16
+# error "Support for 16BPP no yet implemented"
+# else
+# error "LCD supports only 8, 12, and 16BPP"
+# endif
+#endif
+
+#if CONFIG_NOKIA6100_BPP == 8
+# ifdef CONFIG_NX_DISABLE_8BPP
+# warning "8-bit pixel support needed"
+# endif
+#elif CONFIG_NOKIA6100_BPP == 12
+# if defined(CONFIG_NX_DISABLE_12BPP) || !defined(CONFIG_NX_PACKEDMSFIRST)
+# warning "12-bit, big-endian pixel support needed"
+# endif
+#elif CONFIG_NOKIA6100_BPP == 16
+# ifdef CONFIG_NX_DISABLE_16BPP
+# warning "16-bit pixel support needed"
+# endif
+#endif
+
+/* Exactly one LCD controller must be selected. "The Olimex boards have both display
+ * controllers possible; if the LCD has a GE-12 sticker on it, it’s a Philips PCF8833.
+ * If it has a GE-8 sticker, it’s an Epson controller."
+ */
+
+#if defined(CONFIG_NOKIA6100_S1D15G10) && defined(CONFIG_NOKIA6100_PCF8833)
+# error "Both CONFIG_NOKIA6100_S1D15G10 and CONFIG_NOKIA6100_PCF8833 are defined"
+#endif
+
+#if !defined(CONFIG_NOKIA6100_S1D15G10) && !defined(CONFIG_NOKIA6100_PCF8833)
+# error "One of CONFIG_NOKIA6100_S1D15G10 or CONFIG_NOKIA6100_PCF8833 must be defined"
+#endif
+
+/* Delay geometry defaults */
+
+#ifndef CONFIG_NOKIA6100_INVERT
+# define CONFIG_NOKIA6100_INVERT 1
+#endif
+
+#ifndef CONFIG_NOKIA6100_MY
+# define CONFIG_NOKIA6100_MY 0
+#endif
+
+#ifndef CONFIG_NOKIA6100_MX
+# define CONFIG_NOKIA6100_MX 1
+#endif
+
+#ifndef CONFIG_NOKIA6100_V
+# define CONFIG_NOKIA6100_V 0
+#endif
+
+#ifndef CONFIG_NOKIA6100_ML
+# define CONFIG_NOKIA6100_ML 0
+#endif
+
+#ifndef CONFIG_NOKIA6100_RGBORD
+# define CONFIG_NOKIA6100_RGBORD 0
+#endif
+
+/* Check contrast selection */
+
+#ifdef CONFIG_NOKIA6100_S1D15G10
+
+# if !defined(CONFIG_LCD_MAXCONTRAST)
+# define CONFIG_LCD_MAXCONTRAST 63
+# endif
+# if CONFIG_LCD_MAXCONTRAST != 63
+# error "CONFIG_LCD_MAXCONTRAST must be 63 with the Epson LCD controller"
+# endif
+# define NOKIA_DEFAULT_CONTRAST 32
+
+#else /* CONFIG_NOKIA6100_PCF8833 */
+
+# if !defined(CONFIG_LCD_MAXCONTRAST)
+# define CONFIG_LCD_MAXCONTRAST 127
+# endif
+# if CONFIG_LCD_MAXCONTRAST != 127
+# error "CONFIG_LCD_MAXCONTRAST must be 127 with the Phillips LCD controller"
+# endif
+# define NOKIA_DEFAULT_CONTRAST 48
+
+#endif
+
+/* Check initial backlight setting */
+
+#ifndef CONFIG_NOKIA6100_BLINIT
+# define CONFIG_NOKIA6100_BLINIT (NOKIA_DEFAULT_CONTRAST/3)
+#endif
+
+/* Word width must be 9 bits */
+
+#if defined(CONFIG_NOKIA6100_WORDWIDTH) && CONFIG_NOKIA6100_WORDWIDTH != 9
+# error "CONFIG_NOKIA6100_WORDWIDTH must be 9"
+#endif
+#ifndef CONFIG_NOKIA6100_WORDWIDTH
+# define CONFIG_NOKIA6100_WORDWIDTH 9
+#endif
+
+/* If bit 9 is set, the byte is data; clear for commands */
+
+#define NOKIA_LCD_DATA (1 << 8)
+
+/* Define CONFIG_LCD_REGDEBUG to enable register-level debug output.
+ * (Verbose debug must also be enabled)
+ */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_GRAPHICS
+#endif
+
+#ifndef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_LCD_REGDEBUG
+#endif
+
+/* Controller independent definitions *************************************************/
+
+#ifdef CONFIG_NOKIA6100_PCF8833
+# define LCD_NOP PCF8833_NOP
+# define LCD_RAMWR PCF8833_RAMWR
+# define LCD_PASET PCF8833_PASET
+# define LCD_CASET PCF8833_CASET
+#endif
+#ifdef CONFIG_NOKIA6100_S1D15G10
+# define LCD_NOP S1D15G10_NOP
+# define LCD_RAMWR S1D15G10_RAMWR
+# define LCD_PASET S1D15G10_PASET
+# define LCD_CASET S1D15G10_CASET
+#endif
+
+/* Color Properties *******************************************************************/
+
+/* Display Resolution */
+
+#define NOKIA_XRES 132
+#define NOKIA_YRES 132
+
+/* Color depth and format */
+
+#if CONFIG_NOKIA6100_BPP == 8
+# define NOKIA_BPP 8
+# define NOKIA_COLORFMT FB_FMT_RGB8_332
+# define NOKIA_STRIDE NOKIA_XRES
+# define NOKIA_PIX2BYTES(p) (p)
+#elif CONFIG_NOKIA6100_BPP == 12
+# define NOKIA_BPP 12
+# define NOKIA_COLORFMT FB_FMT_RGB12_444
+# define NOKIA_STRIDE ((3*NOKIA_XRES+1)/2)
+# define NOKIA_PIX2BYTES(p) ((3*(p)+1)/2)
+#elif CONFIG_NOKIA6100_BPP == 16
+# define NOKIA_BPP 16
+# define NOKIA_COLORFMT FB_FMT_RGB16_565
+# define NOKIA_STRIDE (2*NOKIA_XRES)
+# define NOKIA_PIX2BYTES(p) (2*(p))
+#endif
+
+/* Handle any potential strange behavior at edges */
+
+#if 0 /* REVISIT */
+#define NOKIA_PGBIAS 2 /* May not be necessary */
+#define NOKIA_COLBIAS 0
+#define NOKIA_XBIAS 2 /* May not be necessary, if so need to subtract from XRES */
+#define NOKIA_YBIAS 0
+#else
+#define NOKIA_PGBIAS 0
+#define NOKIA_COLBIAS 0
+#define NOKIA_XBIAS 0
+#define NOKIA_YBIAS 0
+#endif
+
+#define NOKIA_ENDPAGE 131
+#define NOKIA_ENDCOL 131
+
+/* Debug ******************************************************************************/
+
+#ifdef CONFIG_LCD_REGDEBUG
+# define lcddbg(format, arg...) llvdbg(format, ##arg)
+#else
+# define lcddbg(x...)
+#endif
+
+/**************************************************************************************
+ * Private Type Definition
+ **************************************************************************************/
+
+/* This structure describes the state of this driver */
+
+struct nokia_dev_s
+{
+ /* Publically visible device structure */
+
+ struct lcd_dev_s dev;
+
+ /* Private LCD-specific information follows */
+
+ FAR struct spi_dev_s *spi; /* Contained SPI driver instance */
+ uint8_t contrast; /* Current contrast setting */
+ uint8_t power; /* Current power (backlight) setting */
+};
+
+/**************************************************************************************
+ * Private Function Protototypes
+ **************************************************************************************/
+
+/* SPI support */
+
+static inline void nokia_configspi(FAR struct spi_dev_s *spi);
+#ifdef CONFIG_SPI_OWNBUS
+static inline void nokia_select(FAR struct spi_dev_s *spi);
+static inline void nokia_deselect(FAR struct spi_dev_s *spi);
+#else
+static void nokia_select(FAR struct spi_dev_s *spi);
+static void nokia_deselect(FAR struct spi_dev_s *spi);
+#endif
+static void nokia_sndcmd(FAR struct spi_dev_s *spi, const uint8_t cmd);
+static void nokia_cmdarray(FAR struct spi_dev_s *spi, int len, const uint8_t *cmddata);
+static void nokia_clrram(FAR struct spi_dev_s *spi);
+
+/* LCD Data Transfer Methods */
+
+static int nokia_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels);
+static int nokia_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels);
+
+/* LCD Configuration */
+
+static int nokia_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+static int nokia_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+/* LCD RGB Mapping */
+
+#ifdef CONFIG_FB_CMAP
+# error "RGB color mapping not supported by this driver"
+#endif
+
+/* Cursor Controls */
+
+#ifdef CONFIG_FB_HWCURSOR
+# error "Cursor control not supported by this driver"
+#endif
+
+/* LCD Specific Controls */
+
+static int nokia_getpower(struct lcd_dev_s *dev);
+static int nokia_setpower(struct lcd_dev_s *dev, int power);
+static int nokia_getcontrast(struct lcd_dev_s *dev);
+static int nokia_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
+
+/* Initialization */
+
+static int nokia_initialize(struct nokia_dev_s *priv);
+
+/**************************************************************************************
+ * Private Data
+ **************************************************************************************/
+
+/* This is working memory allocated by the LCD driver for each LCD device
+ * and for each color plane. This memory will hold one raster line of data.
+ * The size of the allocated run buffer must therefore be at least
+ * (bpp * xres / 8). Actual alignment of the buffer must conform to the
+ * bitwidth of the underlying pixel type.
+ *
+ * If there are multiple planes, they may share the same working buffer
+ * because different planes will not be operate on concurrently. However,
+ * if there are multiple LCD devices, they must each have unique run buffers.
+ */
+
+#if CONFIG_NOKIA6100_BPP == 8
+static uint8_t g_runbuffer[NOKIA_XRES];
+#elif CONFIG_NOKIA6100_BPP == 12
+static uint8_t g_runbuffer[(3*NOKIA_XRES+1)/2];
+#else /* CONFIG_NOKIA6100_BPP == 16 */
+static uint16_t g_runbuffer[NOKIA_XRES];
+#endif
+
+/* g_rowbuf is another buffer, but used internally by the Nokia 6100 driver in order
+ * expand the pixel data into 9-bit data needed by the LCD. There are some
+ * customizations that would eliminate the need for this extra buffer and for the
+ * extra expansion/copy, but those customizations would require a special, non-standard
+ * SPI driver that could expand 8- to 9-bit data on the fly.
+ */
+
+static uint16_t g_rowbuf[NOKIA_STRIDE+1];
+
+/* Device Driver Data Structures ******************************************************/
+
+/* This structure describes the overall LCD video controller */
+
+static const struct fb_videoinfo_s g_videoinfo =
+{
+ .fmt = NOKIA_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
+ .xres = NOKIA_XRES, /* Horizontal resolution in pixel columns */
+ .yres = NOKIA_YRES, /* Vertical resolution in pixel rows */
+ .nplanes = 1, /* Number of color planes supported */
+};
+
+/* This is the standard, NuttX Plane information object */
+
+static const struct lcd_planeinfo_s g_planeinfo =
+{
+ .putrun = nokia_putrun, /* Put a run into LCD memory */
+ .getrun = nokia_getrun, /* Get a run from LCD memory */
+ .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */
+ .bpp = NOKIA_BPP, /* Bits-per-pixel */
+};
+
+/* This is the standard, NuttX LCD driver object */
+
+static struct nokia_dev_s g_lcddev =
+{
+ .dev =
+ {
+ /* LCD Configuration */
+
+ .getvideoinfo = nokia_getvideoinfo,
+ .getplaneinfo = nokia_getplaneinfo,
+
+ /* LCD RGB Mapping -- Not supported */
+ /* Cursor Controls -- Not supported */
+
+ /* LCD Specific Controls */
+
+ .getpower = nokia_getpower,
+ .setpower = nokia_setpower,
+ .getcontrast = nokia_getcontrast,
+ .setcontrast = nokia_setcontrast,
+ },
+};
+
+/* LCD Command Strings ****************************************************************/
+
+#ifdef CONFIG_NOKIA6100_S1D15G10
+/* Display control:
+ * P1: Specifies the CL dividing ratio, F1 and F2 drive-pattern switching period.
+ * P2: Specifies the duty of the module on block basis
+ * P3: Specify number of lines to be inversely highlighted on LCD panel
+ * P4: 0: Dispersion P40= 1: Non-dispersion
+ */
+
+#if 1 // CONFIG_NOKIA6100_BPP == 12
+static const uint8_t g_disctl[] =
+{
+ S1D15G10_DISCTL, /* Display control */
+ DISCTL_CLDIV_2|DISCTL_PERIOD_8, /* P1: Divide clock by 2; switching period = 8 */
+//DISCTL_CLDIV_NONE|DISCTL_PERIOD_8, /* P1: No clock division; switching period = 8 */
+ 32, /* P2: nlines/4 - 1 = 132/4 - 1 = 32 */
+ 0, /* P3: No inversely highlighted lines */
+ 0 /* P4: No disperion */
+};
+#else /* CONFIG_NOKIA6100_BPP == 8 */
+static const uint8_t g_disctl[] =
+{
+ S1D15G10_DISCTL, /* Display control */
+ DISCTL_CLDIV_2|DISCTL_PERIOD_FLD, /* P1: Divide clock by 2; switching period = field */
+ 32, /* P2: nlines/4 - 1 = 132/4 - 1 = 32 */
+ 0, /* P3: No inversely highlighted lines */
+ 0 /* P4: No disperion */
+};
+#endif
+
+/* Common scan direction:
+ * P1: Cpecify the common output scan direction.
+ */
+
+static const uint8_t g_comscn[] =
+{
+ S1D15G10_COMSCN, /* Common scan direction */
+ 1 /* 0x01 = Scan 1->68, 132<-69 */
+};
+
+/* Power control:
+ * P1: Turn on or off the liquid crystal driving power circuit, booster/step-down
+ * circuits and voltage follower circuit.
+ */
+
+static const uint8_t g_pwrctr[] =
+{
+ S1D15G10_PWRCTR, /* Power control */
+ PWCTR_REFVOLTAGE|PWCTR_REGULATOR|PWCTR_BOOSTER2|PWCTR_BOOSTER1
+};
+
+/* Data control:
+ * P1: Specify the normal or inverse display of the page address and also to specify
+ * the page address scanning direction
+ * P2: RGB sequence
+ * P3: Grayscale setup
+ */
+
+static const uint8_t g_datctl[] =
+{
+ S1D15G10_DATCTL, /* Data control */
+ 0
+#if CONFIG_NOKIA6100_MY != 0 /* Display row direction */
+ |DATCTL_PGADDR_INV /* Page address inverted */
+#endif
+#if CONFIG_NOKIA6100_MX != 0 /* Display column direction */
+ |DATCTL_COLADDR_REV /* Column address reversed */
+#endif
+#if CONFIG_NOKIA6100_V != 0 /* Display address direction */
+ |DATCTL_ADDR_PGDIR /* Address scan in page direction */
+#endif
+ ,
+#if CONFIG_NOKIA6100_RGBORD != 0
+ DATCTL_BGR, /* RGB->BGR */
+#else
+ 0, /* RGB->RGB */
+#endif
+#if CONFIG_NOKIA6100_BPP == 8
+ DATCTL_8GRAY /* Selects 8-bit color */
+#elif CONFIG_NOKIA6100_BPP == 12
+ DATCTL_16GRAY_A /* Selects 16-bit color, Type A */
+#else
+# error "16-bit mode not yet implemented"
+#endif
+};
+
+/* Voltage control (contrast setting):
+ * P1: Volume value
+ * P2: Resistance ratio
+ * (May need to be tuned for individual displays)
+ */
+
+static const uint8_t g_volctr[] =
+{
+ S1D15G10_VOLCTR, /* Volume control */
+ NOKIA_DEFAULT_CONTRAST, /* Volume value */
+ 2 /* Resistance ratio */
+};
+
+/* 256-color position set (RGBSET8) */
+
+#if CONFIG_NOKIA6100_BPP == 8
+static const uint8_t g_rgbset8[] =
+{
+ S1D15G10_RGBSET8, /* 256-color position set */
+ 0, 2, 4, 6, 9, 11, 13, 15, /* Red tones */
+ 0, 2, 4, 6, 9, 11, 13, 15, /* Green tones */
+ 0, 5, 10, 15 /* Blue tones */
+};
+#endif
+
+/* Page address set (PASET) */
+
+static const uint8_t g_paset[] =
+{
+ S1D15G10_PASET, /* Page start address set */
+ NOKIA_PGBIAS,
+ 131
+};
+
+/* Column address set (CASET) */
+
+static const uint8_t g_caset[] =
+{
+ S1D15G10_CASET, /* Column start address set */
+ NOKIA_COLBIAS,
+ 131
+};
+#endif /* CONFIG_NOKIA6100_S1D15G10 */
+
+#ifdef CONFIG_NOKIA6100_PCF8833
+
+/* Color interface pixel format (COLMOD) */
+
+#if CONFIG_NOKIA6100_BPP == 12
+static const uint8_t g_colmod[] =
+{
+ PCF8833_COLMOD, /* Color interface pixel format */
+ PCF8833_FMT_12BPS /* 12 bits-per-pixel */
+};
+#else /* CONFIG_NOKIA6100_BPP == 8 */
+static const uint8_t g_colmod[] =
+{
+ PCF8833_COLMOD, /* Color interface pixel format */
+ PCF8833_FMT_8BPS /* 8 bits-per-pixel */
+};
+#endif
+
+/* Memory data access control(MADCTL) */
+
+static const uint8_t g_madctl[] =
+{
+ PCF8833_MADCTL, /* Memory data access control*/
+ 0
+#ifdef CONFIG_NOKIA6100_RGBORD != 0
+ |MADCTL_RGB /* RGB->BGR */
+#endif
+#ifdef CONFIG_NOKIA6100_MY != 0 /* Display row direction */
+ |MADCTL_MY /* Mirror Y */
+#endif
+#ifdef CONFIG_NOKIA6100_MX != 0 /* Display column direction */
+ |MADCTL_MX /* Mirror X */
+#endif
+#ifdef CONFIG_NOKIA6100_V != 0 /* Display address direction */
+ |MADCTL_V /* ertical RAM write; in Y direction */
+#endif
+#ifdef CONFIG_NOKIA6100_ML != 0 /* Display scan direction */
+ |MADCTL_LAO /* Line address order bottom to top */
+#endif
+};
+
+/* Set contrast (SETCON) */
+
+static const uint8_t g_setcon[] =
+{
+ PCF8833_SETCON, /* Set contrast */
+ NOKIA_DEFAULT_CONTRAST
+};
+
+#endif /* CONFIG_NOKIA6100_PCF8833 */
+
+/**************************************************************************************
+ * Private Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Function: nokia_configspi
+ *
+ * Description:
+ * Configure the SPI for use with the Nokia 6100
+ *
+ * Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+static inline void nokia_configspi(FAR struct spi_dev_s *spi)
+{
+ lcddbg("Mode: %d Bits: %d Frequency: %d\n",
+ CONFIG_NOKIA6100_SPIMODE, CONFIG_NOKIA6100_WORDWIDTH, CONFIG_NOKIA6100_FREQUENCY);
+
+ /* Configure SPI for the Nokia 6100. But only if we own the SPI bus. Otherwise, don't
+ * bother because it might change.
+ */
+
+#ifdef CONFIG_SPI_OWNBUS
+ SPI_SETMODE(spi, CONFIG_NOKIA6100_SPIMODE);
+ SPI_SETBITS(spi, CONFIG_NOKIA6100_WORDWIDTH);
+ SPI_SETFREQUENCY(spi, CONFIG_NOKIA6100_FREQUENCY)
+#endif
+}
+
+/**************************************************************************************
+ * Function: nokia_select
+ *
+ * Description:
+ * Select the SPI, locking and re-configuring if necessary
+ *
+ * Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void nokia_select(FAR struct spi_dev_s *spi)
+{
+ /* We own the SPI bus, so just select the chip */
+
+ lcddbg("SELECTED\n");
+ SPI_SELECT(spi, SPIDEV_DISPLAY, true);
+}
+#else
+static void nokia_select(FAR struct spi_dev_s *spi)
+{
+ /* Select Nokia 6100 chip (locking the SPI bus in case there are multiple
+ * devices competing for the SPI bus
+ */
+
+ lcddbg("SELECTED\n");
+ SPI_LOCK(spi, true);
+ SPI_SELECT(spi, SPIDEV_DISPLAY, true);
+
+ /* Now make sure that the SPI bus is configured for the Nokia 6100 (it
+ * might have gotten configured for a different device while unlocked)
+ */
+
+ SPI_SETMODE(spi, CONFIG_NOKIA6100_SPIMODE);
+ SPI_SETBITS(spi, CONFIG_NOKIA6100_WORDWIDTH);
+ SPI_SETFREQUENCY(spi, CONFIG_NOKIA6100_FREQUENCY);
+}
+#endif
+
+/**************************************************************************************
+ * Function: nokia_deselect
+ *
+ * Description:
+ * De-select the SPI
+ *
+ * Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void nokia_deselect(FAR struct spi_dev_s *spi)
+{
+ /* We own the SPI bus, so just de-select the chip */
+
+ lcddbg("DE-SELECTED\n");
+ SPI_SELECT(spi, SPIDEV_DISPLAY, false);
+}
+#else
+static void nokia_deselect(FAR struct spi_dev_s *spi)
+{
+ /* De-select Nokia 6100 chip and relinquish the SPI bus. */
+
+ lcddbg("DE-SELECTED\n");
+ SPI_SELECT(spi, SPIDEV_DISPLAY, false);
+ SPI_LOCK(spi, false);
+}
+#endif
+
+/**************************************************************************************
+ * Name: nokia_sndcmd
+ *
+ * Description:
+ * Send a 1-byte command.
+ *
+ **************************************************************************************/
+
+static void nokia_sndcmd(FAR struct spi_dev_s *spi, const uint8_t cmd)
+{
+ /* Select the LCD */
+
+ lcddbg("cmd: %02x\n", cmd);
+ nokia_select(spi);
+
+ /* Send the command. Bit 8 == 0 denotes a command */
+
+ (void)SPI_SEND(spi, (uint16_t)cmd);
+
+ /* De-select the LCD */
+
+ nokia_deselect(spi);
+}
+
+/**************************************************************************************
+ * Name: nokia_cmddata
+ *
+ * Description:
+ * Send a 1-byte command followed by datlen data bytes.
+ *
+ **************************************************************************************/
+
+static void nokia_cmddata(FAR struct spi_dev_s *spi, uint8_t cmd, int datlen,
+ const uint8_t *data)
+{
+ uint16_t *rowbuf = g_rowbuf;
+ int i;
+
+ lcddbg("cmd: %02x datlen: %d\n", cmd, datlen);
+ DEBUGASSERT(datlen <= NOKIA_STRIDE);
+
+ /* Copy the command into the line buffer. Bit 8 == 0 denotes a command. */
+
+ *rowbuf++ = cmd;
+
+ /* Copy any data after the command into the line buffer */
+
+ for (i = 0; i < datlen; i++)
+ {
+ /* Bit 8 == 1 denotes data */
+
+ *rowbuf++ = (uint16_t)*data++ | NOKIA_LCD_DATA;
+ }
+
+ /* Select the LCD */
+
+ nokia_select(spi);
+
+ /* Send the line buffer. */
+
+ (void)SPI_SNDBLOCK(spi, g_rowbuf, datlen+1);
+
+ /* De-select the LCD */
+
+ nokia_deselect(spi);
+}
+
+/**************************************************************************************
+ * Name: nokia_ramwr
+ *
+ * Description:
+ * Send a RAMWR command followed by datlen data bytes.
+ *
+ **************************************************************************************/
+
+static void nokia_ramwr(FAR struct spi_dev_s *spi, int datlen, const uint8_t *data)
+{
+ nokia_cmddata(spi, LCD_RAMWR, datlen, data);
+}
+
+/**************************************************************************************
+ * Name: nokia_cmdarray
+ *
+ * Description:
+ * Send a RAMWR command followed by len-1 data bytes.
+ *
+ **************************************************************************************/
+
+static void nokia_cmdarray(FAR struct spi_dev_s *spi, int len, const uint8_t *cmddata)
+{
+#ifdef CONFIG_LCD_REGDEBUG
+ int i;
+
+ for (i = 0; i < len; i++)
+ {
+ lcddbg("cmddata[%d]: %02x\n", i, cmddata[i]);
+ }
+#endif
+ nokia_cmddata(spi, cmddata[0], len-1, &cmddata[1]);
+}
+
+/**************************************************************************************
+ * Name: nokia_clrram
+ *
+ * Description:
+ * Send a 1-byte command followed by len-1 data bytes.
+ *
+ **************************************************************************************/
+
+static void nokia_clrram(FAR struct spi_dev_s *spi)
+{
+ uint16_t *rowbuf = g_rowbuf;
+ int i;
+
+ /* Set all zero data in the line buffer */
+
+ for (i = 0; i < NOKIA_STRIDE; i++)
+ {
+ /* Bit 8 == 1 denotes data */
+
+ *rowbuf++ = NOKIA_LCD_DATA;
+ }
+
+ /* Select the LCD and send the RAMWR command */
+
+ nokia_select(spi);
+ SPI_SEND(spi, LCD_RAMWR);
+
+ /* Send the line buffer, once for each row. */
+
+ for (i = 0; i < NOKIA_YRES; i++)
+ {
+ (void)SPI_SNDBLOCK(spi, g_rowbuf, NOKIA_STRIDE);
+ }
+
+ /* De-select the LCD */
+
+ nokia_deselect(spi);
+}
+
+/**************************************************************************************
+ * Name: nokia_putrun
+ *
+ * Description:
+ * This method can be used to write a partial raster line to the LCD:
+ *
+ * row - Starting row to write to (range: 0 <= row < yres)
+ * col - Starting column to write to (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer containing the run to be written to the LCD
+ * npixels - The number of pixels to write to the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int nokia_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ struct nokia_dev_s *priv = &g_lcddev;
+ FAR struct spi_dev_s *spi = priv->spi;
+ uint16_t cmd[3];
+
+ gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+
+#if NOKIA_XBIAS > 0
+ col += NOKIA_XBIAS;
+#endif
+#if NOKIA_YBIAS > 0
+ row += NOKIA_YBIAS;
+#endif
+ DEBUGASSERT(buffer && col >=0 && (col + npixels) <= NOKIA_XRES && row >= 0 && row < NOKIA_YRES);
+
+ /* Set up to write the run. */
+
+ nokia_select(spi);
+ cmd[0] = LCD_PASET;
+ cmd[1] = col | NOKIA_LCD_DATA;
+ cmd[2] = NOKIA_ENDPAGE | NOKIA_LCD_DATA;
+ (void)SPI_SNDBLOCK(spi, cmd, 3);
+ nokia_deselect(spi);
+
+ /* De-select the LCD */
+
+ nokia_select(spi);
+ cmd[0] = LCD_CASET;
+ cmd[1] = row | NOKIA_LCD_DATA;
+ cmd[2] = NOKIA_ENDCOL | NOKIA_LCD_DATA;
+ (void)SPI_SNDBLOCK(spi, cmd, 3);
+ nokia_deselect(spi);
+
+ /* Then send the run */
+
+ nokia_ramwr(spi, NOKIA_PIX2BYTES(npixels), buffer);
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: nokia_getrun
+ *
+ * Description:
+ * This method can be used to read a partial raster line from the LCD:
+ *
+ * row - Starting row to read from (range: 0 <= row < yres)
+ * col - Starting column to read read (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer in which to return the run read from the LCD
+ * npixels - The number of pixels to read from the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int nokia_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+ gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+ /* At present, this is a write-only LCD driver */
+
+#warning "Not implemented"
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: nokia_getvideoinfo
+ *
+ * Description:
+ * Get information about the LCD video controller configuration.
+ *
+ **************************************************************************************/
+
+static int nokia_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo)
+{
+ DEBUGASSERT(dev && vinfo);
+ gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n",
+ g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes);
+ memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: nokia_getplaneinfo
+ *
+ * Description:
+ * Get information about the configuration of each LCD color plane.
+ *
+ **************************************************************************************/
+
+static int nokia_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo)
+{
+ DEBUGASSERT(dev && pinfo && planeno == 0);
+ gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
+ memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: nokia_getpower
+ *
+ * Description:
+ * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int nokia_getpower(struct lcd_dev_s *dev)
+{
+ struct nokia_dev_s *priv = (struct nokia_dev_s *)dev;
+ gvdbg("power: %d\n", priv->power);
+ return priv->power;
+}
+
+/**************************************************************************************
+ * Name: nokia_setpower
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int nokia_setpower(struct lcd_dev_s *dev, int power)
+{
+ struct nokia_dev_s *priv = (struct nokia_dev_s *)dev;
+ int ret;
+
+ gvdbg("power: %d\n", power);
+ DEBUGASSERT(power <= CONFIG_LCD_MAXPOWER);
+
+ /* Set new power level. The backlight power is controlled outside of the LCD
+ * assembly and must be managmed by board-specific logic.
+ */
+
+ ret = nokia_backlight(power);
+ if (ret == OK)
+ {
+ priv->power = power;
+ }
+ return ret;
+}
+
+/**************************************************************************************
+ * Name: nokia_getcontrast
+ *
+ * Description:
+ * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int nokia_getcontrast(struct lcd_dev_s *dev)
+{
+ struct nokia_dev_s *priv = (struct nokia_dev_s *)dev;
+ gvdbg("contrast: %d\n", priv->contrast);
+ return priv->contrast;
+}
+
+/**************************************************************************************
+ * Name: nokia_setcontrast
+ *
+ * Description:
+ * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int nokia_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
+{
+ struct nokia_dev_s *priv = (struct nokia_dev_s *)dev;
+
+ if (contrast < CONFIG_LCD_MAXCONTRAST)
+ {
+#ifdef CONFIG_NOKIA6100_S1D15G10
+ while (priv->contrast < contrast)
+ {
+ nokia_sndcmd(priv->spi, S1D15G10_VOLUP);
+ priv->contrast++;
+ }
+ while (priv->contrast > contrast)
+ {
+ nokia_sndcmd(priv->spi, S1D15G10_VOLDOWN);
+ priv->contrast--;
+ }
+#else /* CONFIG_NOKIA6100_PCF8833 */
+ uint8_t cmd[2];
+
+ cmd[0] = PCF8833_SETCON;
+ cmd[1] = priv->contrast;
+ nokia_sndarry(priv->spi, 2, cmd);
+ priv->contrast = contrast;
+#endif
+ }
+
+ gvdbg("contrast: %d\n", contrast);
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: nokia_initialize
+ *
+ * Description:
+ * Initialize the LCD controller.
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_NOKIA6100_S1D15G10
+static int nokia_initialize(struct nokia_dev_s *priv)
+{
+ struct spi_dev_s *spi = priv->spi;
+
+ /* Configure the display */
+
+ nokia_cmdarray(spi, sizeof(g_disctl), g_disctl); /* Display control */
+ nokia_cmdarray(spi, sizeof(g_comscn), g_comscn); /* Common scan direction */
+ nokia_sndcmd(spi, S1D15G10_OSCON); /* Internal oscilator ON */
+ nokia_sndcmd(spi, S1D15G10_SLPOUT); /* Sleep out */
+ nokia_cmdarray(spi, sizeof(g_volctr), g_volctr); /* Volume control (contrast) */
+ nokia_cmdarray(spi, sizeof(g_pwrctr), g_pwrctr); /* Turn on voltage regulators */
+ up_mdelay(100);
+#ifdef CONFIG_NOKIA6100_INVERT
+ nokia_sndcmd(spi, S1D15G10_DISINV); /* Invert display */
+#else
+ nokia_sndcmd(spi, S1D15G10_DISNOR); /* Normal display */
+#endif
+ nokia_cmdarray(spi, sizeof(g_datctl), g_datctl); /* Data control */
+#if CONFIG_NOKIA6100_BPP == 8
+ nokia_cmdarray(spi, sizeof(g_rgbset8), g_rgbset8); /* Set up color lookup table */
+ nokia_sndcmd(spi, S1D15G10_NOP);
+#endif
+ nokia_cmdarray(spi, sizeof(g_paset), g_paset); /* Page address set */
+ nokia_cmdarray(spi, sizeof(g_paset), g_caset); /* Column address set */
+ nokia_clrram(spi);
+ nokia_sndcmd(spi, S1D15G10_DISON); /* Display on */
+ return OK;
+}
+#endif
+
+#ifdef CONFIG_NOKIA6100_PCF8833
+static int nokia_initialize(struct nokia_dev_s *priv)
+{
+ struct struct spi_dev_s *spi = priv->spi;
+
+ nokia_sndcmd(spi, PCF8833_SLEEPOUT); /* Exit sleep mode */
+ nokia_sndcmd(spi, PCF8833_BSTRON); /* Turn on voltage booster */
+#ifdef CONFIG_NOKIA6100_INVERT
+ nokia_sndcmd(spi, PCF8833_INVON); /* Invert display */
+#else
+ nokia_sndcmd(spi, PCF8833_INVOFF); /* Don't invert display */
+#endif
+ nokia_cmdarray(spi, sizeof(g_madctl), g_madctl); /* Memory data access control */
+ nokia_cmdarray(spi, sizeof(g_colmod), g_colmod); /* Color interface pixel format */
+ nokia_cmdarray(spi, sizeof(g_setcon), g_setcon); /* Set contrast */
+ nokia_sndcmd(spi, PCF8833_NOP); /* No operation */
+ nokia_clrram(spi);
+ nokia_sndcmd(spi, PCF8833_DISPON); /* Display on */
+ return OK;
+}
+#endif /* CONFIG_NOKIA6100_PCF8833 */
+
+/**************************************************************************************
+ * Public Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: nokia_lcdinitialize
+ *
+ * Description:
+ * Initialize the NOKIA6100 video hardware. The initial state of the LCD is fully
+ * initialized, display memory cleared, and the LCD ready to use, but with the power
+ * setting at 0 (full off == sleep mode).
+ *
+ * Input Parameters:
+ *
+ * spi - A reference to the SPI driver instance.
+ * devno - A value in the range of 0 throuh CONFIG_NOKIA6100_NINTERFACES-1. This
+ * allows support for multiple LCD devices.
+ *
+ * Returned Value:
+ *
+ * On success, this function returns a reference to the LCD object for the specified
+ * LCD. NULL is returned on any failure.
+ *
+ **************************************************************************************/
+
+FAR struct lcd_dev_s *nokia_lcdinitialize(FAR struct spi_dev_s *spi, unsigned int devno)
+{
+ struct nokia_dev_s *priv = &g_lcddev;
+
+ gvdbg("Initializing\n");
+ DEBUGASSERT(devno == 0);
+
+ /* Initialize the driver data structure */
+
+ priv->spi = spi; /* Save the SPI instance */
+ priv->contrast = NOKIA_DEFAULT_CONTRAST; /* Initial contrast setting */
+
+ /* Configure and enable the LCD controller */
+
+ nokia_configspi(spi);
+ if (nokia_initialize(priv) == OK)
+ {
+ /* Turn on the backlight */
+
+ nokia_backlight(CONFIG_NOKIA6100_BLINIT);
+ return &priv->dev;
+ }
+ return NULL;
+}
diff --git a/nuttx/drivers/lcd/p14201.c b/nuttx/drivers/lcd/p14201.c
new file mode 100644
index 000000000..934d251ca
--- /dev/null
+++ b/nuttx/drivers/lcd/p14201.c
@@ -0,0 +1,1246 @@
+/**************************************************************************************
+ * drivers/lcd/p14201.c
+ * Driver for RiT P14201 series display (wih sd1329 IC controller)
+ *
+ * Copyright (C) 2010, 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+#include <nuttx/lcd/lcd.h>
+#include <nuttx/lcd/p14201.h>
+
+#include <arch/irq.h>
+
+#include "sd1329.h"
+
+#ifdef CONFIG_LCD_P14201
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+
+/* Configuration **********************************************************************/
+
+/* P14201 Configuration Settings:
+ *
+ * CONFIG_P14201_SPIMODE - Controls the SPI mode
+ * CONFIG_P14201_FREQUENCY - Define to use a different bus frequency
+ * CONFIG_P14201_NINTERFACES - Specifies the number of physical P14201 devices that
+ * will be supported.
+ * CONFIG_P14201_FRAMEBUFFER - If defined, accesses will be performed using an in-memory
+ * copy of the OLEDs GDDRAM. This cost of this buffer is 128 * 96 / 2 = 6Kb. If this
+ * is defined, then the driver will be fully functional. If not, then it will have the
+ * following limitations:
+ *
+ * - Reading graphics memory cannot be supported, and
+ * - All pixel writes must be aligned to byte boundaries.
+ *
+ * The latter limitation effectively reduces the 128x96 disply to 64x96.
+ *
+ * Required LCD driver settings:
+ * CONFIG_LCD_P14201 - Enable P14201 support
+ * CONFIG_LCD_MAXCONTRAST should be 255, but any value >0 and <=255 will be accepted.
+ * CONFIG_LCD_MAXPOWER must be 1
+ *
+ * Required SPI driver settings:
+ * CONFIG_SPI_CMDDATA - Include support for cmd/data selection.
+ */
+
+#ifndef CONFIG_SPI_CMDDATA
+# error "CONFIG_SPI_CMDDATA must be defined in your NuttX configuration"
+#endif
+
+/* The P14201 spec says that is supports SPI mode 0,0 only. However,
+ * somtimes you need to tinker with these things.
+ */
+
+#ifndef CONFIG_P14201_SPIMODE
+# define CONFIG_P14201_SPIMODE SPIDEV_MODE2
+#endif
+
+/* CONFIG_P14201_NINTERFACES determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#ifndef CONFIG_P14201_NINTERFACES
+# define CONFIG_P14201_NINTERFACES 1
+#endif
+
+#if CONFIG_P14201_NINTERFACES != 1
+# error "This implementation supports only a single OLED device"
+#endif
+
+/* Check contrast selection */
+
+#if !defined(CONFIG_LCD_MAXCONTRAST)
+# define CONFIG_LCD_MAXCONTRAST 255
+#endif
+
+#if CONFIG_LCD_MAXCONTRAST <= 0|| CONFIG_LCD_MAXCONTRAST > 255
+# error "CONFIG_LCD_MAXCONTRAST exceeds supported maximum"
+#endif
+
+/* Check power setting */
+
+#if !defined(CONFIG_LCD_MAXPOWER)
+# define CONFIG_LCD_MAXPOWER 1
+#endif
+
+#if CONFIG_LCD_MAXPOWER != 1
+# warning "CONFIG_LCD_MAXPOWER exceeds supported maximum"
+# undef CONFIG_LCD_MAXPOWER
+# define CONFIG_LCD_MAXPOWER 1
+#endif
+
+/* Color is 4bpp greyscale with leftmost column contained in bits 7:4 */
+
+#if defined(CONFIG_NX_DISABLE_4BPP) || !defined(CONFIG_NX_PACKEDMSFIRST)
+# warning "4-bit, big-endian pixel support needed"
+#endif
+
+/* Define the CONFIG_LCD_RITDEBUG to enable detailed debug output (stuff you would
+ * never want to see unless you are debugging this file).
+ *
+ * Verbose debug must also be enabled
+ */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_GRAPHICS
+#endif
+
+#ifndef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_LCD_RITDEBUG
+#endif
+
+/* Color Properties *******************************************************************/
+
+/* Display Resolution */
+
+#define RIT_XRES 128
+#define RIT_YRES 96
+
+/* Color depth and format */
+
+#define RIT_BPP 4
+#define RIT_COLORFMT FB_FMT_Y4
+
+/* Default contrast */
+
+#define RIT_CONTRAST ((23 * (CONFIG_LCD_MAXCONTRAST+1) / 32) - 1)
+
+/* Helper Macros **********************************************************************/
+
+#define rit_sndcmd(p,b,l) rit_sndbytes(p,b,l,true);
+#define rit_snddata(p,b,l) rit_sndbytes(p,b,l,false);
+
+/* Debug ******************************************************************************/
+
+#ifdef CONFIG_LCD_RITDEBUG
+# define ritdbg(format, arg...) vdbg(format, ##arg)
+#else
+# define ritdbg(x...)
+#endif
+
+/**************************************************************************************
+ * Private Type Definition
+ **************************************************************************************/
+
+/* This structure describes the state of this driver */
+
+struct rit_dev_s
+{
+ struct lcd_dev_s dev; /* Publically visible device structure */
+ FAR struct spi_dev_s *spi; /* Cached SPI device reference */
+ uint8_t contrast; /* Current contrast setting */
+ bool on; /* true: display is on */
+};
+
+/**************************************************************************************
+ * Private Function Protototypes
+ **************************************************************************************/
+
+/* Low-level SPI helpers */
+
+static inline void rit_configspi(FAR struct spi_dev_s *spi);
+#ifdef CONFIG_SPI_OWNBUS
+static inline void rit_select(FAR struct spi_dev_s *spi);
+static inline void rit_deselect(FAR struct spi_dev_s *spi);
+#else
+static void rit_select(FAR struct spi_dev_s *spi);
+static void rit_deselect(FAR struct spi_dev_s *spi);
+#endif
+static void rit_sndbytes(FAR struct rit_dev_s *priv, FAR const uint8_t *buffer,
+ size_t buflen, bool cmd);
+static void rit_sndcmds(FAR struct rit_dev_s *priv, FAR const uint8_t *table);
+
+/* LCD Data Transfer Methods */
+
+static int rit_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels);
+static int rit_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels);
+
+/* LCD Configuration */
+
+static int rit_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+static int rit_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+/* LCD RGB Mapping */
+
+#ifdef CONFIG_FB_CMAP
+# error "RGB color mapping not supported by this driver"
+#endif
+
+/* Cursor Controls */
+
+#ifdef CONFIG_FB_HWCURSOR
+# error "Cursor control not supported by this driver"
+#endif
+
+/* LCD Specific Controls */
+
+static int rit_getpower(struct lcd_dev_s *dev);
+static int rit_setpower(struct lcd_dev_s *dev, int power);
+static int rit_getcontrast(struct lcd_dev_s *dev);
+static int rit_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
+
+/**************************************************************************************
+ * Private Data
+ **************************************************************************************/
+
+/* This is working memory allocated by the LCD driver for each LCD device
+ * and for each color plane. This memory will hold one raster line of data.
+ * The size of the allocated run buffer must therefore be at least
+ * (bpp * xres / 8). Actual alignment of the buffer must conform to the
+ * bitwidth of the underlying pixel type.
+ *
+ * If there are multiple planes, they may share the same working buffer
+ * because different planes will not be operate on concurrently. However,
+ * if there are multiple LCD devices, they must each have unique run buffers.
+ */
+
+static uint8_t g_runbuffer[RIT_XRES / 2];
+
+/* CONFIG_P14201_FRAMEBUFFER - If defined, accesses will be performed using an in-memory
+ * copy of the OLEDs GDDRAM. This cost of this buffer is 128 * 64 / 2 = 4Kb. If this
+ * is defined, then the driver will be full functional. If not, then:
+ *
+ * - Reading graphics memory cannot be supported, and
+ * - All pixel writes must be aligned to byte boundaries.
+ */
+
+#ifdef CONFIG_P14201_FRAMEBUFFER
+static uint8_t g_framebuffer[RIT_YRES * RIT_XRES / 2];
+#endif
+
+/* This structure describes the overall LCD video controller */
+
+static const struct fb_videoinfo_s g_videoinfo =
+{
+ .fmt = RIT_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
+ .xres = RIT_XRES, /* Horizontal resolution in pixel columns */
+ .yres = RIT_YRES, /* Vertical resolution in pixel rows */
+ .nplanes = 1, /* Number of color planes supported */
+};
+
+/* This is the standard, NuttX Plane information object */
+
+static const struct lcd_planeinfo_s g_planeinfo =
+{
+ .putrun = rit_putrun, /* Put a run into LCD memory */
+ .getrun = rit_getrun, /* Get a run from LCD memory */
+ .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */
+ .bpp = RIT_BPP, /* Bits-per-pixel */
+};
+
+/* This is the OLED driver instance (only a single device is supported for now) */
+
+static struct rit_dev_s g_oleddev =
+{
+ .dev =
+ {
+ /* LCD Configuration */
+
+ .getvideoinfo = rit_getvideoinfo,
+ .getplaneinfo = rit_getplaneinfo,
+
+ /* LCD RGB Mapping -- Not supported */
+ /* Cursor Controls -- Not supported */
+
+ /* LCD Specific Controls */
+
+ .getpower = rit_getpower,
+ .setpower = rit_setpower,
+ .getcontrast = rit_getcontrast,
+ .setcontrast = rit_setcontrast,
+ },
+};
+
+/* A table of magic initialization commands. This initialization sequence is
+ * derived from RiT Application Note for the P14201 (with a few tweaked values
+ * as discovered in some Luminary code examples).
+ */
+
+static const uint8_t g_initcmds[] =
+{
+ 3, SSD1329_CMD_LOCK, /* Set lock command */
+ SSD1329_LOCK_OFF, /* Disable locking */
+ SSD1329_NOOP,
+ 2, SSD1329_SLEEP_ON, /* Matrix display OFF */
+ SSD1329_NOOP,
+ 3, SSD1329_ICON_ALL, /* Set all ICONs to OFF */
+ SSD1329_ICON_OFF, /* OFF selection */
+ SSD1329_NOOP,
+ 3, SSD1329_MUX_RATIO, /* Set MUX ratio */
+ 95, /* 96 MUX */
+ SSD1329_NOOP,
+ 3, SSD1329_SET_CONTRAST, /* Set contrast */
+ RIT_CONTRAST, /* Default contrast */
+ SSD1329_NOOP,
+ 3, SSD1329_PRECHRG2_SPEED, /* Set second pre-charge speed */
+ (31 << 1) | SSD1329_PRECHRG2_DBL, /* Pre-charge speed == 32, doubled */
+ SSD1329_NOOP,
+ 3, SSD1329_GDDRAM_REMAP, /* Set GDDRAM re-map */
+ (SSD1329_COM_SPLIT| /* Enable COM slip even/odd */
+ SSD1329_COM_REMAP| /* Enable COM re-map */
+ SSD1329_NIBBLE_REMAP), /* Enable nibble re-map */
+ SSD1329_NOOP,
+ 3, SSD1329_VERT_START, /* Set Display Start Line */
+ 0, /* Line = 0 */
+ SSD1329_NOOP,
+ 3, SSD1329_VERT_OFFSET, /* Set Display Offset */
+ 0, /* Offset = 0 */
+ SSD1329_NOOP,
+ 2, SSD1329_DISP_NORMAL, /* Display mode normal */
+ SSD1329_NOOP,
+ 3, SSD1329_PHASE_LENGTH, /* Set Phase Length */
+ 1 | /* Phase 1 period = 1 DCLK */
+ (1 << 4), /* Phase 2 period = 1 DCLK */
+ SSD1329_NOOP,
+ 3, SSD1329_FRAME_FREQ,
+ 35, /* 35 DCLK's per row */
+ SSD1329_NOOP,
+ 3, SSD1329_DCLK_DIV, /* Set Front Clock Divider / Oscillator Frequency */
+ 2 | /* Divide ration = 3 */
+ (14 << 4), /* Oscillator Frequency, FOSC, setting */
+ SSD1329_NOOP,
+ 17, SSD1329_GSCALE_LOOKUP, /* Look Up Table for Gray Scale Pulse width */
+ 1, 2, 3, 4, 5, /* Value for GS1-5 level Pulse width */
+ 6, 8, 10, 12, 14, /* Value for GS6-10 level Pulse width */
+ 16, 19, 22, 26, 30, /* Value for GS11-15 level Pulse width */
+ SSD1329_NOOP,
+ 3, SSD1329_PRECHRG2_PERIOD, /* Set Second Pre-charge Period */
+ 1, /* 1 DCLK */
+ SSD1329_NOOP,
+ 3, SSD1329_PRECHRG1_VOLT, /* Set First Precharge voltage, VP */
+ 0x3f, /* 1.00 x Vcc */
+ SSD1329_NOOP,
+ 0 /* Zero length command terminates table */
+};
+
+/* Turn the maxtrix display on (sleep mode off) */
+
+static const uint8_t g_sleepoff[] =
+{
+ SSD1329_SLEEP_OFF, /* Matrix display ON */
+ SSD1329_NOOP,
+};
+
+/* Turn the maxtrix display off (sleep mode on) */
+
+static const uint8_t g_sleepon[] =
+{
+ SSD1329_SLEEP_ON, /* Matrix display OFF */
+ SSD1329_NOOP,
+};
+
+/* Set horizontal increment mode */
+
+static const uint8_t g_horzinc[] =
+{
+ SSD1329_GDDRAM_REMAP,
+ (SSD1329_COM_SPLIT|SSD1329_COM_REMAP|SSD1329_NIBBLE_REMAP),
+};
+
+/* The following set a window that covers the entire display */
+
+static const uint8_t g_setallcol[] =
+{
+ SSD1329_SET_COLADDR,
+ 0,
+ (RIT_XRES/2)-1
+};
+
+static const uint8_t g_setallrow[] =
+{
+ SSD1329_SET_ROWADDR,
+ 0,
+ RIT_YRES-1
+};
+
+/**************************************************************************************
+ * Private Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: rit_configspi
+ *
+ * Description:
+ * Configure the SPI for use with the P14201
+ *
+ * Input Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+static inline void rit_configspi(FAR struct spi_dev_s *spi)
+{
+#ifdef CONFIG_P14201_FREQUENCY
+ ritdbg("Mode: %d Bits: 8 Frequency: %d\n",
+ CONFIG_P14201_SPIMODE, CONFIG_P14201_FREQUENCY);
+#else
+ ritdbg("Mode: %d Bits: 8\n", CONFIG_P14201_SPIMODE);
+#endif
+
+ /* Configure SPI for the P14201. But only if we own the SPI bus. Otherwise, don't
+ * bother because it might change.
+ */
+
+#ifdef CONFIG_SPI_OWNBUS
+ SPI_SETMODE(spi, CONFIG_P14201_SPIMODE);
+ SPI_SETBITS(spi, 8);
+#ifdef CONFIG_P14201_FREQUENCY
+ SPI_SETFREQUENCY(spi, CONFIG_P14201_FREQUENCY)
+#endif
+#endif
+}
+
+/**************************************************************************************
+ * Name: rit_select
+ *
+ * Description:
+ * Select the SPI, locking and re-configuring if necessary
+ *
+ * Input Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void rit_select(FAR struct spi_dev_s *spi)
+{
+ /* We own the SPI bus, so just select the chip */
+
+ SPI_SELECT(spi, SPIDEV_DISPLAY, true);
+}
+#else
+static void rit_select(FAR struct spi_dev_s *spi)
+{
+ /* Select P14201 chip (locking the SPI bus in case there are multiple
+ * devices competing for the SPI bus
+ */
+
+ SPI_LOCK(spi, true);
+ SPI_SELECT(spi, SPIDEV_DISPLAY, true);
+
+ /* Now make sure that the SPI bus is configured for the P14201 (it
+ * might have gotten configured for a different device while unlocked)
+ */
+
+ SPI_SETMODE(spi, CONFIG_P14201_SPIMODE);
+ SPI_SETBITS(spi, 8);
+#ifdef CONFIG_P14201_FREQUENCY
+ SPI_SETFREQUENCY(spi, CONFIG_P14201_FREQUENCY);
+#endif
+}
+#endif
+
+/**************************************************************************************
+ * Name: rit_deselect
+ *
+ * Description:
+ * De-select the SPI
+ *
+ * Input Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void rit_deselect(FAR struct spi_dev_s *spi)
+{
+ /* We own the SPI bus, so just de-select the chip */
+
+ SPI_SELECT(spi, SPIDEV_DISPLAY, false);
+}
+#else
+static void rit_deselect(FAR struct spi_dev_s *spi)
+{
+ /* De-select P14201 chip and relinquish the SPI bus. */
+
+ SPI_SELECT(spi, SPIDEV_DISPLAY, false);
+ SPI_LOCK(spi, false);
+}
+#endif
+
+/**************************************************************************************
+ * Name: rit_sndbytes
+ *
+ * Description:
+ * Send a sequence of command or data bytes to the SSD1329 controller.
+ *
+ * Input Parameters:
+ * spi - Reference to the SPI driver structure
+ * buffer - A reference to memory containing the command bytes to be sent.
+ * buflen - The number of command bytes in buffer to be sent
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The caller as selected the OLED device.
+ *
+ **************************************************************************************/
+
+static void rit_sndbytes(FAR struct rit_dev_s *priv, FAR const uint8_t *buffer,
+ size_t buflen, bool cmd)
+{
+ FAR struct spi_dev_s *spi = priv->spi;
+ uint8_t tmp;
+
+ ritdbg("buflen: %d cmd: %s [%02x %02x %02x]\n",
+ buflen, cmd ? "YES" : "NO", buffer[0], buffer[1], buffer[2] );
+ DEBUGASSERT(spi);
+
+ /* Clear/set the D/Cn bit to enable command or data mode */
+
+ (void)SPI_CMDDATA(spi, SPIDEV_DISPLAY, cmd);
+
+ /* Loop until the entire command/data block is transferred */
+
+ while (buflen-- > 0)
+ {
+ /* Write the next byte to the controller */
+
+ tmp = *buffer++;
+ (void)SPI_SEND(spi, tmp);
+ }
+}
+
+/**************************************************************************************
+ * Name: rit_sndcmd
+ *
+ * Description:
+ * Send multiple commands from a table of commands.
+ *
+ * Input Parameters:
+ * spi - Reference to the SPI driver structure
+ * table - A reference to table containing all of the commands to be sent.
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+static void rit_sndcmds(FAR struct rit_dev_s *priv, FAR const uint8_t *table)
+{
+ int cmdlen;
+
+ /* Table terminates with a zero length command */
+
+ while ((cmdlen = *table++) != 0)
+ {
+ ritdbg("command: %02x cmdlen: %d\n", *table, cmdlen);
+ rit_sndcmd(priv, table, cmdlen);
+ table += cmdlen;
+ }
+}
+
+/**************************************************************************************
+ * Name: rit_clear
+ *
+ * Description:
+ * This method can be used to clear the entire display.
+ *
+ * Input Parameters:
+ * priv - Reference to private driver structure
+ *
+ * Assumptions:
+ * Caller has selected the OLED section.
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_P14201_FRAMEBUFFER
+static inline void rit_clear(FAR struct rit_dev_s *priv)
+{
+ FAR uint8_t *ptr = g_framebuffer;
+ unsigned int row;
+
+ ritdbg("Clear display\n");
+
+ /* Initialize the framebuffer */
+
+ memset(g_framebuffer, (RIT_Y4_BLACK << 4) | RIT_Y4_BLACK, RIT_YRES * RIT_XRES / 2);
+
+ /* Set a window to fill the entire display */
+
+ rit_sndcmd(priv, g_setallcol, sizeof(g_setallcol));
+ rit_sndcmd(priv, g_setallrow, sizeof(g_setallrow));
+ rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc));
+
+ /* Display each row */
+
+ for(row = 0; row < RIT_YRES; row++)
+ {
+ /* Display a horizontal run */
+
+ rit_snddata(priv, ptr, RIT_XRES / 2);
+ ptr += RIT_XRES / 2;
+ }
+}
+#else
+static inline void rit_clear(FAR struct rit_dev_s *priv)
+{
+ unsigned int row;
+
+ ritdbg("Clear display\n");
+
+ /* Create a black row */
+
+ memset(g_runbuffer, (RIT_Y4_BLACK << 4) | RIT_Y4_BLACK, RIT_XRES / 2);
+
+ /* Set a window to fill the entire display */
+
+ rit_sndcmd(priv, g_setallcol, sizeof(g_setallcol));
+ rit_sndcmd(priv, g_setallrow, sizeof(g_setallrow));
+ rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc));
+
+ /* Display each row */
+
+ for(row = 0; row < RIT_YRES; row++)
+ {
+ /* Display a horizontal run */
+
+ rit_snddata(priv, g_runbuffer, RIT_XRES / 2);
+ }
+}
+#endif
+
+/**************************************************************************************
+ * Name: rit_putrun
+ *
+ * Description:
+ * This method can be used to write a partial raster line to the LCD.
+ *
+ * Input Parameters:
+ * row - Starting row to write to (range: 0 <= row < yres)
+ * col - Starting column to write to (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer containing the run to be written to the LCD
+ * npixels - The number of pixels to write to the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_P14201_FRAMEBUFFER
+static int rit_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)&g_oleddev;
+ uint8_t cmd[3];
+ uint8_t *run;
+ int start;
+ int end;
+ int aend;
+ int i;
+
+ ritdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer);
+
+ /* Toss out the special case of the empty run now */
+
+ if (npixels < 1)
+ {
+ return OK;
+ }
+
+ /* Get the beginning of the line containing run in the framebuffer */
+
+ run = g_framebuffer + row * RIT_XRES / 2;
+
+ /* Get the starting and ending byte offsets containing the run.
+ * the run starts at &run[start] and continues through run[end-1].
+ * However, the first and final pixels at these locations may
+ * not be byte aligned.
+ */
+
+ start = col >> 1;
+ aend = (col + npixels) >> 1;
+ end = (col + npixels + 1) >> 1;
+ ritdbg("start: %d aend: %d end: %d\n", start, aend, end);
+
+ /* Copy the run into the framebuffer, handling nibble alignment.
+ *
+ * CASE 1: First pixel X position is byte aligned
+ *
+ * example col=6 npixels = 8 example col=6 npixels=7
+ *
+ * Run: |AB|AB|AB|AB| |AB|AB|AB|AB|
+ * GDDRAM row:
+ * Byte | 0| 1| 2| 3| 4| 5| 6| | 0| 1| 2| 3| 4| 5| 6|
+ * Pixel: |--|--|--|AB|AB|AB|AB| |--|--|--|AB|AB|AB|A-|
+ *
+ * start = 3 start = 3
+ * aend = 6 aend = 6
+ * end = 6 end = 7
+ *
+ */
+
+ if ((col & 1) == 0)
+ {
+ /* Check for the special case of only 1 pixel being blitted */
+
+ if (npixels > 1)
+ {
+ /* Beginning of buffer is properly aligned, from start to aend */
+
+ memcpy(&run[start], buffer, aend - start);
+ }
+
+ /* An even number of byte-aligned pixel pairs have been written (where
+ * zero counts as an even number). If npixels was was odd (including
+ * npixels == 1), then handle the final, byte aligned pixel.
+ */
+
+ if (aend != end)
+ {
+ /* The leftmost column is contained in source bits 7:4 and in
+ * destination bits 7:4
+ */
+
+ run[aend] = (run[aend] & 0x0f) | (buffer[aend - start] & 0xf0);
+ }
+ }
+
+ /* CASE 2: First pixel X position is byte aligned
+ *
+ * example col=7 npixels = 8 example col=7 npixels=7
+ *
+ * Run: |AB|AB|AB|AB| |AB|AB|AB|AB|
+ * GDDRAM row:
+ * Byte | 0| 1| 2| 3| 4| 5| 6| 7| | 0| 1| 2| 3| 4| 5| 6|
+ * Pixel: |--|--|--|-A|BA|BA|BA|B-| |--|--|--|-A|BA|BA|BA|
+ *
+ * start = 3 start = 3
+ * aend = 7 aend = 7
+ * end = 8 end = 7
+ */
+
+ else
+ {
+ uint8_t curr = buffer[0];
+ uint8_t last;
+
+ /* Handle the initial unaligned pixel. Source bits 7:4 into
+ * destination bits 3:0. In the special case of npixel == 1,
+ * this finished the job.
+ */
+
+ run[start] = (run[start] & 0xf0) | (curr >> 4);
+
+ /* Now construct the rest of the bytes in the run (possibly special
+ * casing the final, partial byte below).
+ */
+
+ for (i = start + 1; i < aend; i++)
+ {
+ /* bits 3:0 from previous byte to run bits 7:4;
+ * bits 7:4 of current byte to run bits 3:0
+ */
+
+ last = curr;
+ curr = buffer[i-start];
+ run[i] = (last << 4) | (curr >> 4);
+ }
+
+ /* An odd number of unaligned pixel have been written (where npixels
+ * may have been as small as one). If npixels was was even, then handle
+ * the final, unaligned pixel.
+ */
+
+ if (aend != end)
+ {
+ /* The leftmost column is contained in source bits 3:0 and in
+ * destination bits 7:4
+ */
+
+ run[aend] = (run[aend] & 0x0f) | (curr << 4);
+ }
+ }
+
+ /* Select the SD1329 controller */
+
+ rit_select(priv->spi);
+
+ /* Setup a window that describes a run starting at the specified column
+ * and row, and ending at the column + npixels on the same row.
+ */
+
+ cmd[0] = SSD1329_SET_COLADDR;
+ cmd[1] = start;
+ cmd[2] = end - 1;
+ rit_sndcmd(priv, cmd, 3);
+
+ cmd[0] = SSD1329_SET_ROWADDR;
+ cmd[1] = row;
+ cmd[2] = row;
+ rit_sndcmd(priv, cmd, 3);
+
+ /* Write the run to GDDRAM. */
+
+ rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc));
+ rit_snddata(priv, &run[start], end - start);
+
+ /* De-select the SD1329 controller */
+
+ rit_deselect(priv->spi);
+ return OK;
+}
+#else
+static int rit_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)&g_oleddev;
+ uint8_t cmd[3];
+
+ ritdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer);
+
+ if (npixels > 0)
+ {
+ /* Check that the X and Y coordinates are within range */
+
+ DEBUGASSERT(col < RIT_XRES && (col + npixels) <= RIT_XRES && row < RIT_YRES);
+
+ /* Check that the X coordinates are aligned to 8-bit boundaries
+ * (this needs to get fixed somehow)
+ */
+
+ DEBUGASSERT((col & 1) == 0 && (npixels & 1) == 0);
+
+ /* Select the SD1329 controller */
+
+ rit_select(priv->spi);
+
+ /* Setup a window that describes a run starting at the specified column
+ * and row, and ending at the column + npixels on the same row.
+ */
+
+ cmd[0] = SSD1329_SET_COLADDR;
+ cmd[1] = col >> 1;
+ cmd[2] = ((col + npixels) >> 1) - 1;
+ rit_sndcmd(priv, cmd, 3);
+
+ cmd[0] = SSD1329_SET_ROWADDR;
+ cmd[1] = row;
+ cmd[2] = row;
+ rit_sndcmd(priv, cmd, 3);
+
+ /* Write the run to GDDRAM. */
+
+ rit_sndcmd(priv, g_horzinc, sizeof(g_horzinc));
+ rit_snddata(priv, buffer, npixels >> 1);
+
+ /* De-select the SD1329 controller */
+
+ rit_deselect(priv->spi);
+ }
+
+ return OK;
+}
+#endif
+
+/**************************************************************************************
+ * Name: rit_getrun
+ *
+ * Description:
+ * This method can be used to read a partial raster line from the LCD:
+ *
+ * row - Starting row to read from (range: 0 <= row < yres)
+ * col - Starting column to read read (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer in which to return the run read from the LCD
+ * npixels - The number of pixels to read from the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_P14201_FRAMEBUFFER
+static int rit_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+ uint8_t *run;
+ int start;
+ int end;
+ int aend;
+ int i;
+
+ ritdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer);
+
+ /* Can't read from OLED GDDRAM in SPI mode, but we can read from the framebuffer */
+ /* Toss out the special case of the empty run now */
+
+ if (npixels < 1)
+ {
+ return OK;
+ }
+
+ /* Get the beginning of the line containing run in the framebuffer */
+
+ run = g_framebuffer + row * RIT_XRES / 2;
+
+ /* Get the starting and ending byte offsets containing the run.
+ * the run starts at &run[start] and continues through run[end-1].
+ * However, the first and final pixels at these locations may
+ * not be byte aligned (see examples in putrun()).
+ */
+
+ start = col >> 1;
+ aend = (col + npixels) >> 1;
+ end = (col + npixels + 1) >> 1;
+
+ /* Copy the run into the framebuffer, handling nibble alignment */
+
+ if ((col & 1) == 0)
+ {
+ /* Check for the special case of only 1 pixels being copied */
+
+ if (npixels > 1)
+ {
+ /* Beginning of buffer is properly aligned, from start to aend */
+
+ memcpy(buffer, &run[start], aend - start + 1);
+ }
+
+ /* Handle any final pixel (including the special case where npixels == 1). */
+
+ if (aend != end)
+ {
+ /* The leftmost column is contained in source bits 7:4 and in
+ * destination bits 7:4
+ */
+
+ buffer[aend - start] = run[aend] & 0xf0;
+ }
+ }
+ else
+ {
+ uint8_t curr = run[start];
+ uint8_t last;
+
+ /* Now construct the rest of the bytes in the run (possibly special
+ * casing the final, partial byte below).
+ */
+
+ for (i = start + 1; i < aend; i++)
+ {
+ /* bits 3:0 from previous byte to run bits 7:4;
+ * bits 7:4 of current byte to run bits 3:0
+ */
+
+ last = curr;
+ curr = run[i];
+ *buffer++ = (last << 4) | (curr >> 4);
+ }
+
+ /* Handle any final pixel (including the special case where npixels == 1). */
+
+ if (aend != end)
+ {
+ /* The leftmost column is contained in source bits 3:0 and in
+ * destination bits 7:4
+ */
+
+ *buffer = (curr << 4);
+ }
+ }
+
+ return OK;
+}
+#else
+static int rit_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+ /* Can't read from OLED GDDRAM in SPI mode */
+
+ return -ENOSYS;
+}
+#endif
+
+/**************************************************************************************
+ * Name: rit_getvideoinfo
+ *
+ * Description:
+ * Get information about the LCD video controller configuration.
+ *
+ **************************************************************************************/
+
+static int rit_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo)
+{
+ DEBUGASSERT(dev && vinfo);
+ gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n",
+ g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes);
+ memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: rit_getplaneinfo
+ *
+ * Description:
+ * Get information about the configuration of each LCD color plane.
+ *
+ **************************************************************************************/
+
+static int rit_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo)
+{
+ DEBUGASSERT(pinfo && planeno == 0);
+ gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
+ memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: rit_getpower
+ *
+ * Description:
+ * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int rit_getpower(FAR struct lcd_dev_s *dev)
+{
+ FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)dev;
+ DEBUGASSERT(priv);
+
+ gvdbg("power: %s\n", priv->on ? "ON" : "OFF");
+ return priv->on ? CONFIG_LCD_MAXPOWER : 0;
+}
+
+/**************************************************************************************
+ * Name: rit_setpower
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int rit_setpower(struct lcd_dev_s *dev, int power)
+{
+ struct rit_dev_s *priv = (struct rit_dev_s *)dev;
+ DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER && priv->spi);
+
+ gvdbg("power: %d\n", power);
+
+ /* Select the SD1329 controller */
+
+ rit_select(priv->spi);
+
+ /* Only two power settings -- 0: sleep on, 1: sleep off */
+
+ if (power > 0)
+ {
+ /* Re-initialize the SSD1329 controller */
+
+ rit_sndcmds(priv, g_initcmds);
+
+ /* Take the display out of sleep mode */
+
+ rit_sndcmd(priv, g_sleepoff, sizeof(g_sleepoff));
+ priv->on = true;
+ }
+ else
+ {
+ /* Put the display into sleep mode */
+
+ rit_sndcmd(priv, g_sleepon, sizeof(g_sleepon));
+ priv->on = false;
+ }
+
+ /* De-select the SD1329 controller */
+
+ rit_deselect(priv->spi);
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: rit_getcontrast
+ *
+ * Description:
+ * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int rit_getcontrast(struct lcd_dev_s *dev)
+{
+ struct rit_dev_s *priv = (struct rit_dev_s *)dev;
+
+ gvdbg("contrast: %d\n", priv->contrast);
+ return priv->contrast;
+}
+
+/**************************************************************************************
+ * Name: rit_setcontrast
+ *
+ * Description:
+ * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int rit_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
+{
+ struct rit_dev_s *priv = (struct rit_dev_s *)dev;
+ uint8_t cmd[3];
+
+ gvdbg("contrast: %d\n", contrast);
+ DEBUGASSERT(contrast <= CONFIG_LCD_MAXCONTRAST);
+
+ /* Select the SD1329 controller */
+
+ rit_select(priv->spi);
+
+ /* Set new contrast */
+
+ cmd[0] = SSD1329_SET_CONTRAST;
+ cmd[1] = contrast;
+ cmd[2] = SSD1329_NOOP;
+ rit_sndcmd(priv, cmd, 3);
+
+ /* De-select the SD1329 controller */
+
+ rit_deselect(priv->spi);
+ priv->contrast = contrast;
+ return OK;
+}
+
+/**************************************************************************************
+ * Public Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: rit_initialize
+ *
+ * Description:
+ * Initialize the P14201 video hardware. The initial state of the OLED is fully
+ * initialized, display memory cleared, and the OLED ready to use, but with the power
+ * setting at 0 (full off == sleep mode).
+ *
+ * Input Parameters:
+ * spi - A reference to the SPI driver instance.
+ * devno - A value in the range of 0 throuh CONFIG_P14201_NINTERFACES-1. This allows
+ * support for multiple OLED devices.
+ *
+ * Returned Value:
+ * On success, this function returns a reference to the LCD object for the specified
+ * OLED. NULL is returned on any failure.
+ *
+ **************************************************************************************/
+
+FAR struct lcd_dev_s *rit_initialize(FAR struct spi_dev_s *spi, unsigned int devno)
+{
+ FAR struct rit_dev_s *priv = (FAR struct rit_dev_s *)&g_oleddev;
+ DEBUGASSERT(devno == 0 && spi);
+
+ gvdbg("Initializing devno: %d\n", devno);
+
+ /* Driver state data */
+
+ priv->spi = spi;
+ priv->contrast = RIT_CONTRAST;
+ priv->on = false;
+
+ /* Select the SD1329 controller */
+
+ rit_configspi(spi);
+ rit_select(spi);
+
+ /* Clear the display */
+
+ rit_clear(priv);
+
+ /* Configure (but don't enable) the OLED */
+
+ rit_sndcmds(priv, g_initcmds);
+
+ /* De-select the SD1329 controller */
+
+ rit_deselect(spi);
+ return &priv->dev;
+}
+#endif /* CONFIG_LCD_P14201 */
diff --git a/nuttx/drivers/lcd/pcf8833.h b/nuttx/drivers/lcd/pcf8833.h
new file mode 100644
index 000000000..b0a7e14d4
--- /dev/null
+++ b/nuttx/drivers/lcd/pcf8833.h
@@ -0,0 +1,152 @@
+/**************************************************************************************
+ * drivers/lcd/pcf8833.h
+ * Definitions for the Phillips PCF8833 LCD controller
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * References: "Data Sheet, PCF8833 STN RGB 132x132x3 driver," Phillips, 2003 Feb 14.
+ *
+ * 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 __DRIVERS_LCD_PCF8833_H
+#define __DRIVERS_LCD_PCF8833_H
+
+/**************************************************************************************
+ * Included Files
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+/* Pixel format codes */
+
+#define PCF8833_FMT_8BPS (2)
+#define PCF8833_FMT_12BPS (3)
+#define PCF8833_FMT_16BPS (5)
+
+/* LCD Commands */
+
+#define PCF8833_NOP 0x00 /* No operation; Data: none */
+#define PCF8833_SWRESET 0x01 /* Software reset ; Data: none */
+#define PCF8833_BSTROFF 0x02 /* Booster voltage off; Data: none */
+#define PCF8833_BSTRON 0x03 /* Booster voltage on; Data: none */
+#define PCF8833_RDDIDIF 0x04 /* Read display identification; Data: none */
+#define PCF8833_RDDST 0x09 /* Read display status; Data: none */
+#define PCF8833_SLEEPIN 0x10 /* Sleep_IN; Data: none */
+#define PCF8833_SLEEPOUT 0x11 /* Sleep_OUT; Data: none */
+#define PCF8833_PTLON 0x12 /* Partial mode on; Data: none */
+#define PCF8833_NORON 0x13 /* Normal Display mode on; Data: none */
+#define PCF8833_INVOFF 0x20 /* Display inversion off; Data: none */
+#define PCF8833_INVON 0x21 /* Display inversion on; Data: none */
+#define PCF8833_DALO 0x22 /* All pixel off; Data: none */
+#define PCF8833_DAL 0x23 /* All pixel on; Data: none */
+#define PCF8833_SETCON 0x25 /* Set contrast; Data: (1) contrast */
+#define PCF8833_DISPOFF 0x28 /* Display off; Data: none */
+#define PCF8833_DISPON 0x29 /* Display on; Data: none */
+#define PCF8833_CASET 0x2a /* Column address set; Data: (1) X start (2) X end */
+#define PCF8833_PASET 0x2b /* Page address set Data: (1) Y start (2) Y end */
+#define PCF8833_RAMWR 0x2c /* Memory write; Data: (1) write data */
+#define PCF8833_RGBSET 0x2d /* Colour set; Data: (1-8) red tones, (9-16) green tones, (17-20) blue tones */
+#define PCF8833_PTLAR 0x30 /* Partial area; Data: (1) start address (2) end address */
+#define PCF8833_VSCRDEF 0x33 /* Vertical scroll definition; Data: (1) top fixed, (2) scrol area, (3) bottom fixed */
+#define PCF8833_TEOFF 0x34 /* Tearing line off; Data: none */
+#define PCF8833_TEON 0x35 /* Tearing line on; Data: (1) don't care */
+#define PCF8833_MADCTL 0x36 /* Memory data access control; Data: (1) access control settings */
+#define PCF8833_SEP 0x37 /* Set Scroll Entry Point; Data: (1) scroll entry point */
+#define PCF8833_IDMOFF 0x38 /* Idle mode off; Data: none */
+#define PCF8833_IDMON 0x39 /* Idle mode on; Data: none */
+#define PCF8833_COLMOD 0x3a /* Interface pixel format; Data: (1) color interface format */
+#define PCF8833_SETVOP 0xb0 /* Set VOP; Data: (1) VOP5-8 (2) VOP0-4 */
+#define PCF8833_BRS 0xb4 /* Bottom Row Swap; Data: none */
+#define PCF8833_TRS 0xb6 /* Top Row Swap; Data: none */
+#define PCF8833_FINV 0xb9 /* Super Frame INVersion; Data: none */
+#define PCF8833_DOR 0xba /* Data ORder; Data: none */
+#define PCF8833_TCDFE 0xbd /* Enable/disable DF temp comp; Data: none */
+#define PCF8833_TCVOPE 0xbf /* Enable or disable VOP temp comp; Data: none */
+#define PCF8833_EC 0xc0 /* Internal or external oscillator; Data: none */
+#define PCF8833_SETMUL 0xc2 /* Set multiplication factor; Data: (1) Multiplication factor */
+#define PCF8833_TCVOPAB 0xc3 /* Set TCVOP slopes A and B; Data: (1) SLB and SLA */
+#define PCF8833_TCVOPCD 0xc4 /* Set TCVOP slopes C and D; Data: (1) SLD and SLC */
+#define PCF8833_TCDF 0xc5 /* Set divider frequency; Data: Divider factor in region (1) A (2) B (3) C (4) D */
+#define PCF8833_DF8COLOR 0xc6 /* Set divider frequency 8-colour mode; Data: (1) DF80-6 */
+#define PCF8833_SETBS 0xc7 /* Set bias system; Data: (1) Bias systems */
+#define PCF8833_RDTEMP 0xc8 /* Temperature read back; Data: none */
+#define PCF8833_NLI 0xc9 /* N-Line Inversion; Data: (1) NLI time slots invervsion */
+#define PCF8833_RDID1 0xda /* Read ID1; Data: none */
+#define PCF8833_RDID2 0xdb /* Read ID2; Data: none */
+#define PCF8833_RDID3 0xdc /* Read ID3; Data: none */
+#define PCF8833_SFD 0xef /* Select factory defaults; Data: none */
+#define PCF8833_ECM 0xf0 /* Enter Calibration mode; Data: (1) Calibration control settings */
+#define PCF8833_OTPSHTIN 0xf1 /* Shift data in OTP shift registers; Data: Any number of bytes */
+
+/* Memory data access control (MADCTL) bit definitions */
+
+#define MADCTL_RGB (1 << 3) /* Bit 3: BGR */
+#define MADCTL_LAO (1 << 4) /* Bit 4: Line address order bottom to top */
+#define MADCTL_V (1 << 5) /* Bit 5: Vertical RAM write; in Y direction */
+#define MADCTL_MX (1 << 6) /* Bit 6: Mirror X */
+#define MADCTL_MY (1 << 7) /* Bit 7: Mirror Y */
+
+/* PCF8833 status register bit definitions */
+/* CMD format: RDDST command followed by four status bytes: */
+/* Byte 1: D31 d30 D29 D28 D27 D26 --- --- */
+
+#define PCF8833_ST_RGB (1 << 2) /* Bit 2: D26 - RGB/BGR order */
+#define PCF8833_ST_LINEADDR (1 << 3) /* Bit 3: D27 - Line address order */
+#define PCF8833_ST_ADDRMODE (1 << 4) /* Bit 4: D28 - Vertical/horizontal addressing mode */
+#define PCF8833_ST_XADDR (1 << 5) /* Bit 5: D29 - X address order */
+#define PCF8833_ST_YADDR (1 << 6) /* Bit 6: D30 - Y address order */
+#define PCF8833_ST_BOOSTER (1 << 7) /* Bit 7: D31 - Booster voltage status */
+
+/* Byte 2: --- D22 D21 D20 D19 D18 D17 D16 */
+
+#define PCF8833_ST_NORMAL (1 << 0) /* Bit 0: D16 - Normal display mode */
+#define PCF8833_ST_SLEEPIN (1 << 1) /* Bit 1: D17 - Sleep in selected */
+#define PCF8833_ST_PARTIAL (1 << 2) /* Bit 2: D18 - Partial mode on */
+#define PCF8833_ST_IDLE (1 << 3) /* Bit 3: D19 - Idle mode selected */
+#define PCF8833_ST_PIXELFMT_SHIFT (4) /* Bits 4-6: D20-D22 - Interface pixel format */
+#define PCF8833_ST_PIXELFMT_MASK (7 << PCF8833_ST_PIXELFMT_SHIFT)
+# define PCF8833_ST_PIXELFMT_8BPS (PCF8833_FMT_8BPS << PCF8833_ST_PIXELFMT_SHIFT)
+# define PCF8833_ST_PIXELFMT_12BPS (PCF8833_FMT_12BPS << PCF8833_ST_PIXELFMT_SHIFT)
+# define PCF8833_ST_PIXELFMT_16BPS (PCF8833_FMT_16BPS << PCF8833_ST_PIXELFMT_SHIFT)
+
+/* Byte 3: D15 -- D13 D12 D11 D10 D9 --- */
+
+#define PCF8833_ST_TEARING (1 << 1) /* Bit 1: D9 - Tearing effect on */
+#define PCF8833_ST_DISPLAYON (1 << 2) /* Bit 2: D10 - Display on */
+#define PCF8833_ST_PIXELSOFF (1 << 3) /* Bit 3: D11 - All pixels off */
+#define PCF8833_ST_PIXELSON (1 << 4) /* Bit 4: D12 - All pixels on */
+#define PCF8833_ST_INV (1 << 5) /* Bit 5: D13 - Display inversion */
+#define PCF8833_ST_VSCROLL (1 << 7) /* Bit 6: D15 - Vertical scroll mode */
+
+/* Byte 4: All zero */
+
+#endif /* __DRIVERS_LCD_PCF8833_H */ \ No newline at end of file
diff --git a/nuttx/drivers/lcd/s1d15g10.h b/nuttx/drivers/lcd/s1d15g10.h
new file mode 100644
index 000000000..df2dd8be2
--- /dev/null
+++ b/nuttx/drivers/lcd/s1d15g10.h
@@ -0,0 +1,141 @@
+/**************************************************************************************
+ * drivers/lcd/s1d15g10.h
+ * Definitions for the Epson S1D15G0 LCD controller
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * References: S1D15G0D08B000, Seiko Epson Corportation, 2002.
+ *
+ * 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 __DRIVERS_LCD_S1D15G10_H
+#define __DRIVERS_LCD_S1D15G10_H
+
+/**************************************************************************************
+ * Included Files
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+
+/* Epson S1D15G10 Command Set */
+
+#define S1D15G10_DISON 0xaf /* Display on; Data: none */
+#define S1D15G10_DISOFF 0xae /* Display off; Data: none */
+#define S1D15G10_DISNOR 0xa6 /* Normal display; Data: none */
+#define S1D15G10_DISINV 0xa7 /* Inverse display; Data: none */
+#define S1D15G10_COMSCN 0xbb /* Common scan direction; Data: (1) common scan direction */
+#define S1D15G10_DISCTL 0xca /* Display control; Data: Data: (1) CL div, F1/2 pat, (2) duty, (3) FR inverse (4) dispersion */
+#define S1D15G10_SLPIN 0x95 /* Sleep in; Data: none */
+#define S1D15G10_SLPOUT 0x94 /* Sleep out; Data: none */
+#define S1D15G10_PASET 0x75 /* Page address set; Data: (1) start page, (2) end page */
+#define S1D15G10_CASET 0x15 /* Column address set; Data: (1) start addr, (2) end addr */
+#define S1D15G10_DATCTL 0xbc /* Data scan direction, etc.; Data: (1) inverse, scan dir (2) RGB, (3) gray-scale */
+#define S1D15G10_RGBSET8 0xce /* 256-color position set; Data: (1-8) red tones, (9-16) green tones, (17-20) blue tones */
+#define S1D15G10_RAMWR 0x5c /* Writing to memory; Data: (1) write data */
+#define S1D15G10_RAMRD 0x5d /* Reading from memory; Data: (1) read data */
+#define S1D15G10_PTLIN 0xa8 /* Partial display in; Data: (1) start addr, (2) end addr */
+#define S1D15G10_PTLOUT 0xa9 /* Partial display out; Data: none */
+#define S1D15G10_RMWIN 0xe0 /* Read and modify write; Data: none */
+#define S1D15G10_RMWOUT 0xee /* End; Data: none */
+#define S1D15G10_ASCSET 0xaa /* Area scroll set; Data: (1) top addr, (2) bottom addr, (3) Num blocks, (4) scroll mode */
+#define S1D15G10_SCSTART 0xab /* Scroll start set; Data: (1) start block addr */
+#define S1D15G10_OSCON 0xd1 /* Internal oscillation on; Data: none */
+#define S1D15G10_OSCOFF 0xd2 /* Internal oscillation off; Data: none */
+#define S1D15G10_PWRCTR 0x20 /* Power control; Data: (1) LCD drive power */
+#define S1D15G10_VOLCTR 0x81 /* Electronic volume control; Data: (1) volume value, (2) resistance ratio */
+#define S1D15G10_VOLUP 0xd6 /* Increment electronic control by 1; Data: none */
+#define S1D15G10_VOLDOWN 0xd7 /* Decrement electronic control by 1; Data: none */
+#define S1D15G10_TMPGRD 0x82 /* Temperature gradient set; Data: (1-14) temperature gradient */
+#define S1D15G10_EPCTIN 0xcd /* Control EEPROM; Data: (1) read/write */
+#define S1D15G10_EPCOUT 0xcc /* Cancel EEPROM control; Data: none */
+#define S1D15G10_EPMWR 0xfc /* Write into EEPROM; Data: none */
+#define S1D15G10_EPMRD 0xfd /* Read from EEPROM; Data: none */
+#define S1D15G10_EPSRRD1 0x7c /* Read register 1; Data: none */
+#define S1D15G10_EPSRRD2 0x7d /* Read regiser 2; Data: none */
+#define S1D15G10_NOP 0x25 /* NOP intruction (0x45?); Data: none */
+#define S1D15G10_STREAD 0x20 /* Status read; Data: none */
+
+/* Display control (DISCTL) bit definitions */
+
+#define DISCTL_PERIOD_SHIFT (0) /* P1: Bits 0-1, F1 and F2 drive-pattern switching period */
+#define DISCTL_PERIOD_MASK (3 << DISCTL_PERIOD_SHIFT)
+# define DISCTL_PERIOD_8 (0 << DISCTL_PERIOD_SHIFT)
+# define DISCTL_PERIOD_4 (1 << DISCTL_PERIOD_SHIFT)
+# define DISCTL_PERIOD_16 (2 << DISCTL_PERIOD_SHIFT)
+# define DISCTL_PERIOD_FLD (3 << DISCTL_PERIOD_SHIFT)
+#define DISCTL_CLDIV_SHIFT (2) /* P1: Bits 2-4, Clock divider */
+#define DISCTL_CLDIV_MASK (7 << DISCTL_CLDIV_SHIFT)
+# define DISCTL_CLDIV_2 (0 << DISCTL_CLDIV_SHIFT)
+# define DISCTL_CLDIV_4 (1 << DISCTL_CLDIV_SHIFT)
+# define DISCTL_CLDIV_8 (2 << DISCTL_CLDIV_SHIFT)
+# define DISCTL_CLDIV_NONE (3 << DISCTL_CLDIV_SHIFT)
+
+/* Power control (PWRCTR) bit definitions */
+
+#define PWCTR_REFVOLTAGE (1 << 0) /* P1: Bit 0, Turn on reference voltage generation circuit. */
+#define PWCTR_REGULATOR (1 << 1) /* P1: Bit 1, Turn on voltage regulator and circuit voltage follower. */
+#define PWCTR_BOOSTER2 (1 << 2) /* P1: Bit 2, Turn on secondary booster/step-down circuit. */
+#define PWCTR_BOOSTER1 (1 << 3) /* P1: Bit 3, Turn on primary booster circuit. */
+#define PWCTR_EXTR (1 << 4) /* P1: Bit 4, Use external resistance to adjust voltage. */
+
+/* Data control (DATCTL) bit definitions */
+
+#define DATCTL_PGADDR_INV (1 << 0) /* P1: Bit 0, Inverse display of the page address. */
+#define DATCTL_COLADDR_REV (1 << 1) /* P1: Bit 1, Reverse turn of column address. */
+#define DATCTL_ADDR_PGDIR (1 << 2) /* P1: Bit 2, Address-scan direction in page (vs column) direction. */
+
+#define DATCTL_BGR (1 << 0) /* P2: Bit0, RGB->BGR */
+
+#define DATCTL_8GRAY (1) /* P3: Bits 0-2 = 001, 8 gray-scale */
+#define DATCTL_16GRAY_A (2) /* P3: Bits 0-2 = 010, 16 gray-scale display type A */
+#define DATCTL_16GRAY_B (4) /* P3: Bits 0-2 = 100, 16 gray-scale display type B */
+
+/* Status register bit definions (after reset or NOP) */
+
+#define S1D15G10_SR_PARTIAL (1 << 0) /* Bit 0: Partial display */
+#define S1D15G10_SR_NORMAL (1 << 1) /* Bit 1: Normal (vs. inverse) display */
+#define S1D15G10_SR_EEPROM (1 << 2) /* Bit 2: EEPROM access */
+#define S1D15G10_SR_DISPON (1 << 3) /* Bit 3: Display on */
+#define S1D15G10_SR_COLSCAN (1 << 4) /* Bit 4: Column (vs. page) scan direction */
+#define S1D15G10_SR_RMW (1 << 5) /* Bit 5: Read modify write */
+#define S1D15G10_SR_SCROLL (3 << 6) /* Bits 6-7: Area scroll mode */
+
+/* Status register bit definions (after EPSRRD1) */
+
+#define S1D15G10_SR_VOLUME 0x3f /* Bits 0-5: Electronic volume control values */
+
+/* Status register bit definions (after EPSRRD2) */
+
+#define S1D15G10_SR_RRATIO 0x07 /* Bits 0-2: Built-in resistance ratio */
+
+#endif /* __DRIVERS_LCD_S1D15G10_H */ \ No newline at end of file
diff --git a/nuttx/drivers/lcd/sd1329.h b/nuttx/drivers/lcd/sd1329.h
new file mode 100644
index 000000000..5d2ad4948
--- /dev/null
+++ b/nuttx/drivers/lcd/sd1329.h
@@ -0,0 +1,527 @@
+/****************************************************************************
+ * drivers/lcd/sd1329.h
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * 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 __DRIVERS_LCD_SD1329_H
+#define __DRIVERS_LCD_SD1329_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include <stdint.h>
+
+/****************************************************************************
+ * Pre-Processor Definitions
+ ****************************************************************************/
+
+/* SD1329 Commands **********************************************************/
+/* Set column Address.
+ *
+ * This triple byte command specifies column start address and end address of
+ * the display data RAM. This command also sets the column address pointer to
+ * column start address. This pointer is used to define the current read/write
+ * column address in graphic display data RAM. If horizontal address increment
+ * mode is enabled by command 0xa0, after finishing read/write one column data,
+ * it is incremented automatically to the next column address. Whenever the
+ * column address pointer finishes accessing the end column address, it is
+ * reset back to start column address and the row address is incremented to the
+ * next row.
+ *
+ * Byte 1: 0x15
+ * Byte 2: A[5:0]: Start Address, range: 0x00-0x3f
+ * Byte 3: B[5:0]: End Address, range: 0x00-0x3f
+ */
+
+#define SSD1329_SET_COLADDR 0x15
+
+/* Set Row Address.
+ *
+ * This triple byte command specifies row start address and end address of the
+ * display data RAM. This command also sets the row address pointer to row
+ * start address. This pointer is used to define the current read/write row
+ * address in graphic display data RAM. If vertical address increment mode is
+ * enabled by command 0xa0, after finishing read/write one row data, it is
+ * incremented automatically to the next row address. Whenever the row address
+ * pointer finishes accessing the end row address, it is reset back to start
+ * row address.
+ *
+ * Byte 1: 0x75
+ * Byte 2: A[6:0]: Start Address, range: 0x00-0x7f
+ * Byte 3: B[6:0]: End Address, range: 0x00-0x7f
+ */
+
+#define SSD1329_SET_ROWADDR 0x75
+
+/* Set Contract Current
+ *
+ * This double byte command is to set Contrast Setting of the display. The
+ * chip has 256 contrast steps from 0x00 to 0xff. The segment output current
+ * increases linearly with the increase of contrast step.
+ *
+ * Byte 1: 0x81
+ * Byte 2: A[7:0]: Contrast Value, range: 0-255
+ */
+
+#define SSD1329_SET_CONTRAST 0x81
+
+/* Set Second Pre-Charge Speed
+ *
+ * This command is used to set the speed of second pre-charge in phase 3.
+ * This speed can be doubled to achieve faster pre-charging through setting
+ * 0x82 A[0].
+ *
+ * Byte 1: 0x82
+ * Byte 2: A[7:1]: Second Pre-charge Speed
+ * A[0] = 1, Enable doubling the Second Pre-charge speed
+ */
+
+#define SSD1329_PRECHRG2_SPEED 0x82
+# define SSD1329_PRECHRG2_DBL 0x01
+
+/* Set Master Icon Control
+ *
+ * This double command is used to set the ON / OFF conditions of internal
+ * charge pump, icon circuits and overall icon status.
+ *
+ * Byte 1: 0x90
+ * Byte 2: Icon control (OR of bits 0-1,4-5)
+ */
+
+#define SSD1329_ICON_CONTROL 0x90
+# define SSD1329_ICON_NORMAL 0x00 /* A[1:0]1=00: Icon RESET to normal display */
+# define SSD1329_ICON_ALLON 0x01 /* A[1:0]1=01: Icon All ON */
+# define SSD1329_ICON_ALLOFF 0x02 /* A[1:0]=10: Icon All OFF */
+# define SSD1329_ICON_DISABLE 0x00 /* A[4]=0: Disable Icon display */
+# define SSD1329_ICON_ENABLE 0x10 /* A[4]=1: Enable Icon display */
+# define SSD1329_VICON_DISABLE 0x00 /* A[5]=0: Disable VICON charge pump circuit */
+# define SSD1329_VICON_ENABLE 0x20 /* A[5]=1: Enable VICON charge pump circuit */
+
+/* Set Icon Current Range
+ *
+ * This double byte command is used to set one fix current range for all icons
+ * between the range of 0uA and 127.5uA. The uniformity improves as the icon
+ * current range increases.
+ *
+ * Byte 1: 0x91
+ * Byte 2: A[7:0]: Max icon current:
+ * 00 = 0.0 uA
+ * 01 = 0.5 uA
+ * ...
+ * ff = 127.5 uA
+ */
+
+#define SSD1329_ICON_CURRRNG 0x91
+
+/* Set Individual Icon Current
+ *
+ * This multiple byte command is used to fine tune the current for each of the
+ * 64 icons. Command 0x92 followed by 64 single byte data. These 64 byte data
+ * have to be entered in order to make this command function. Below is the
+ * formula for calculating the icon current.
+ *
+ * Icon Current = Single byte value / 127 x Maximum icon current set with command 0x91
+ *
+ * Byte 1: 0x92
+ * Byte 2-65: An[6:0]: icon current for ICSn, range: 0x00-0x7f
+ * Icon Current of ICSn = An[6:0]/127) x max icon current
+ */
+
+#define SSD1329_ICON_CURRENT 0x92
+
+/* Set Individual Icon ON / OFF Register
+ *
+ * This double byte command is used to select one of the 64 icons and choose the
+ * ON, OFF or blinking condition of the selected icon.
+ *
+ * Byte 1: 0x93
+ * Byte 2: A[5:0]: Select one of the 64 icons from ICS0 ~ ICS63
+ * A[7:6]: OFF/ON/BLINK
+ */
+
+#define SSD1329_ICON_SELECT 0x93
+# define SSD1329_ICON_OFF 0x00
+# define SSD1329_ICON_ON 0x40
+# define SSD1329_ICON_BLINK 0xc0
+
+/* Set Icon ON / OFF Registers
+ *
+ * This double byte command is used to set the ON / OFF status of all 64 icons.
+ *
+ * Byte 1: 0x94
+ * Byte 2: A[7:6]: OFF/ON/BLINK (Same as 0x93)
+ */
+
+#define SSD1329_ICON_ALL 0x94
+
+/* Set Icon Blinking Cycle
+ *
+ * This double byte command is used to set icon oscillator frequency and
+ * blinking cycle selected with above command 0x93.
+ *
+ * Byte 1: 0x95
+ * Byte 2:
+ * - A[2:0]:Icon Blinking cycle
+ * - A[5:4]:Icon oscillation frequency
+ */
+
+#define SSD1329_ICON_BLINKING 0x95
+# define SSD1329_ICON_BLINK_0p25S 0x00 /* 0.25 sec */
+# define SSD1329_ICON_BLINK_0p50S 0x01 /* 0.50 sec */
+# define SSD1329_ICON_BLINK_0p75S 0x02 /* 0.75 sec */
+# define SSD1329_ICON_BLINK_0p100S 0x03 /* 1.00 sec */
+# define SSD1329_ICON_BLINK_0p125S 0x04 /* 1.25 sec */
+# define SSD1329_ICON_BLINK_0p150S 0x05 /* 1.50 sec */
+# define SSD1329_ICON_BLINK_0p175S 0x06 /* 1.75 sec */
+# define SSD1329_ICON_BLINK_0p200S 0x07 /* 2.00 sec */
+# define SSD1329_ICON_BLINK_61KHZ 0x00 /* 61 KHz */
+# define SSD1329_ICON_BLINK_64KHZ 0x10 /* 64 KHz */
+# define SSD1329_ICON_BLINK_68KHZ 0x20 /* 68 KHz */
+# define SSD1329_ICON_BLINK_73KHZ 0x30 /* 73 KHz */
+
+/* Set Icon Duty
+ *
+ * This double byte command is used to set the icon frame frequency and icon AC
+ * drive duty ratio.
+ *
+ * Byte 1: 0x96
+ * Byte 2:
+ * - A[2:0]: AC Drive
+ * - A[7:4]: con frame frequency
+ */
+
+#define SSD1329_ICON_ACDRIVE 0x96
+# define SSD1329_ICON_DUTY_DC 0x00
+# define SSD1329_ICON_DUTY_63_64 0x01
+# define SSD1329_ICON_DUTY_62_64 0x02
+# define SSD1329_ICON_DUTY_61_64 0x03
+# define SSD1329_ICON_DUTY_60_64 0x04
+# define SSD1329_ICON_DUTY_59_64 0x05
+# define SSD1329_ICON_DUTY_58_64 0x06
+# define SSD1329_ICON_DUTY_57_64 0x07
+
+/* Set Re-map
+ *
+ * This double command has multiple configurations and each bit setting is
+ * described as follows:
+ *
+ * Column Address Remapping (A[0])
+ * This bit is made for increase the flexibility layout of segment signals in
+ * OLED module with segment arranged from left to right (when A[0] is set to 0)
+ * or from right to left (when A[0] is set to 1).
+ *
+ * Nibble Remapping (A[1])
+ * When A[1] is set to 1, the two nibbles of the data bus for RAM access are
+ * re-mapped, such that (D7, D6, D5, D4, D3, D2, D1, D0) acts like (D3, D2, D1,
+ * D0, D7, D6, D5, D4) If this feature works together with Column Address
+ * Re-map, it would produce an effect of flipping the outputs from SEG0-127 to
+ * SEG127-SEG0.
+ *
+ * Address increment mode (A[2])
+ * When A[2] is set to 0, the driver is set as horizontal address incremen
+ * mode. After the display RAM is read/written, the column address pointer is
+ * increased automatically by 1. If the column address pointer reaches column
+ * end address, the column address pointer is reset to column start address and
+ * row address pointer is increased by 1.
+ *
+ * When A[2] is set to 1, the driver is set to vertical address increment mode.
+ * After the display RAM is read/written, the row address pointer is increased
+ * automatically by 1. If the row address pointer reaches the row end address,
+ * the row address pointer is reset to row start address and column address
+ * pointer is increased by 1.
+ *
+ * COM Remapping (A[4])
+ * This bit defines the scanning direction of the common for flexible layout
+ * of common signals in OLED module either from up to down (when A[4] is set to
+ * 0) or from bottom to up (when A[4] is set to 1).
+ *
+ * Splitting of Odd / Even COM Signals (A[6])
+ * This bit is made to match the COM layout connection on the panel. When A[6]
+ * is set to 0, no splitting odd / even of the COM signal is performed. When
+ * A[6] is set to 1, splitting odd / even of the COM signal is performed,
+ * output pin assignment sequence is shown as below (for 128MUX ratio):
+ *
+ * Byte 1: 0xa0
+ * Byte 2: A[7:0]
+ */
+
+#define SSD1329_GDDRAM_REMAP 0xa0
+# define SSD1329_COLADDR_REMAP 0x01 /* A[0]: Enable column re-map */
+# define SSD1329_NIBBLE_REMAP 0x02 /* A[1]: Enable nibble re-map */
+# define SSD1329_VADDR_INCR 0x04 /* A[1]: Enable vertical address increment */
+# define SSD1329_COM_REMAP 0x10 /* A[4]: Enable COM re-map */
+# define SSD1329_COM_SPLIT 0x40 /* A[6]: Enable COM slip even/odd */
+
+/* Set Display Start Line
+ *
+ * This double byte command is to set Display Start Line register for
+ * determining the starting address of display RAM to be displayed by selecting
+ * a value from 0 to 127.
+ *
+ * Byte 1: 0xa1
+ * Byte 2: A[6:0]: Vertical scroll by setting the starting address of
+ * display RAM from 0-127
+ */
+
+#define SSD1329_VERT_START 0xa1
+
+/* Set Display Offset
+ *
+ * This double byte command specifies the mapping of display start line (it is
+ * assumed that COM0 is the display start line, display start line register
+ * equals to 0) to one of COM0-COM127.
+ *
+ * Byte 1: 0xa2
+ * Byte 2: A[6:0]: Set vertical offset by COM from 0-127
+ */
+
+#define SSD1329_VERT_OFFSET 0xa2
+
+/* Set Display Mode - Normal, all on, all off, inverse
+ *
+ * These are single byte commands and are used to set display status to Normal
+ * Display, Entire Display ON, Entire Display OFF or Inverse Display.
+ *
+ * Normal Display (0xa4)
+ * Reset the “Entire Display ON, Entire Display OFF or Inverse Display” effects
+ * and turn the data to ON at the corresponding gray level.
+ *
+ * Set Entire Display ON (0xa5)
+ * Force the entire display to be at gray scale level GS15, regardless of the
+ * contents of the display data RAM.
+ *
+ * Set Entire Display OFF (0xa6)
+ * Force the entire display to be at gray scale level GS0, regardless of the
+ * contents of the display data RAM.
+ *
+ * Inverse Display (0xa7)
+ * The gray scale level of display data are swapped such that “GS0” <-> “GS15”,
+ * “GS1” <-> “GS14”, etc.
+ *
+ * Byte 1: Display mode command
+ */
+
+#define SSD1329_DISP_NORMAL 0xa4
+#define SSD1329_DISP_OFF 0xa5
+#define SSD1329_DISP_ON 0xa6
+#define SSD1329_DISP_INVERT 0xa7
+
+/* Set MUX Ratio
+ *
+ * This double byte command sets multiplex ratio (MUX ratio) from 16MUX to
+ * 128MUX. In POR, multiplex ratio is 128MUX.
+ *
+ * Byte 1: 0xa8
+ * Byte 2: A[6:0] 15-127 representing 16-128 MUX
+ */
+
+#define SSD1329_MUX_RATIO 0xa8
+
+/* Set Sleep mode ON / OFF
+ *
+ * These single byte commands are used to turn the matrix display on the OLED
+ * panel display either ON or OFF. When the sleep mode is set to ON (0xae), the
+ * display is OFF, the segment and common output are in high impedance state
+ * and circuits will be turned OFF. When the sleep mode is set to OFF (0xaf),
+ * the display is ON.
+ *
+ * Byte 1: sleep mode command
+ */
+
+#define SSD1329_SLEEP_ON 0xae
+#define SSD1329_SLEEP_OFF 0xaf
+
+/* Set Phase Length
+ *
+ * In the second byte of this double command, lower nibble and higher nibble is
+ * defined separately. The lower nibble adjusts the phase length of Reset (phase
+ * 1). The higher nibble is used to select the phase length of first pre-charge
+ * phase (phase 2). The phase length is ranged from 1 to 16 DCLK's. RESET for
+ * A[3:0] is set to 3 which means 4 DCLK’s selected for Reset phase. POR for
+ * A[7:4] is set to 5 which means 6 DCLK’s is selected for first pre-charge
+ * phase. Please refer to Table 9-1 for detail breakdown levels of each step.
+ *
+ * Byte 1: 0xb1
+ * Byte 2: A[3:0]: Phase 1 period of 1~16 DCLK’s
+ * A[7:4]: Phase 2 period of 1~16 DCLK’s
+ */
+
+#define SSD1329_PHASE_LENGTH 0xb1
+
+/* Set Frame Frequency
+ *
+ * This double byte command is used to set the number of DCLK’s per row between
+ * the range of 0x14 and 0x7f. Then the Frame frequency of the matrix display
+ * is equal to DCLK frequency / A[6:0].
+ *
+ * Byte 1: 0xb2
+ * Byte 2: A[6:0]:Total number of DCLK’s per row. Ranging from
+ * 0x14 to 0x4e DCLK’s. frame Frequency = DCLK freq /A[6:0].
+ */
+
+#define SSD1329_FRAME_FREQ 0xb2
+
+/* Set Front Clock Divider / Oscillator Frequency
+ *
+ * This double command is used to set the frequency of the internal display
+ * clocks, DCLK's. It is defined by dividing the oscillator frequency by the
+ * divide ratio (Value from 1 to 16). Frame frequency is determined by divide
+ * ratio, number of display clocks per row, MUX ratio and oscillator frequency.
+ * The lower nibble of the second byte is used to select the oscillator
+ * frequency. Please refer to Table 9-1 for detail breakdown levels of each
+ * step.
+ *
+ * Byte 1: 0xb3
+ * Byte 2: A[3:0]: Define divide ratio (D) of display clock (DCLK)
+ * Divide ratio=A[3:0]+1
+ * A[7:4] : Set the Oscillator Frequency, FOSC. Range:0-15
+ */
+
+#define SSD1329_DCLK_DIV 0xb3
+
+/* Set Default Gray Scale Table
+ *
+ * This single byte command is used to set the gray scale table to initial
+ * default setting.
+ *
+ * Byte 1: 0xb7
+ */
+
+#define SSD1329_GSCALE_TABLE 0xb7
+
+/* Look Up Table for Gray Scale Pulse width
+ *
+ * This command is used to set each individual gray scale level for the display.
+ * Except gray scale level GS0 that has no pre-charge and current drive, each
+ * gray scale level is programmed in the length of current drive stage pulse
+ * width with unit of DCLK. The longer the length of the pulse width, the
+ * brighter the OLED pixel when it’s turned ON.
+ *
+ * The setting of gray scale table entry can perform gamma correction on OLED
+ * panel display. Normally, it is desired that the brightness response of the
+ * panel is linearly proportional to the image data value in display data RAM.
+ * However, the OLED panel is somehow responded in non-linear way. Appropriate
+ * gray scale table setting like example below can compensate this effect.
+ *
+ * Byte 1: 0xb8
+ * Bytes 2-16: An[5:0], value for GSn level Pulse width
+ */
+
+#define SSD1329_GSCALE_LOOKUP 0xb8
+
+/* Set Second Pre-charge Period
+ *
+ * This double byte command is used to set the phase 3 second pre-charge period.
+ * The period of phase 3 can be programmed by command 0xbb and it is ranged from
+ * 0 to 15 DCLK's.
+ *
+ * Byte 1: 0xbb
+ * Byte 2: 0-15 DCLKs
+ */
+
+#define SSD1329_PRECHRG2_PERIOD 0xbb
+
+/* Set First Precharge voltage, VP
+ *
+ * This double byte command is used to set phase 2 first pre-charge voltage
+ * level. It can be programmed to set the first pre-charge voltage reference to
+ * VCC or VCOMH.
+ *
+ * Byte 1: 0xbc
+ * Byte 2: A[5] == 0, Pre-charge voltage is (0.30 + A[4:0]) * Vcc
+ * A{5] == 1, 1.00 x VCC or connect to VCOMH if VCC > VCOMH
+ */
+
+#define SSD1329_PRECHRG1_VOLT 0xbc
+
+/* Set VCOMH
+ *
+ * This double byte command sets the high voltage level of common pins, VCOMH.
+ * The level of VCOMH is programmed with reference to VCC.
+ *
+ * Byte 1: 0xbe
+ * Byte 2: (0.51 + A[5:0]) * Vcc
+ */
+
+#define SSD1329_COM_HIGH 0xbe
+
+/* NOOP
+ *
+ * This is a no operation command.
+ *
+ * Byte 1: 0xe3
+ */
+
+#define SSD1329_NOOP 0xe3
+
+/* Set Command Lock
+ *
+ * This command is used to lock the MCU from accepting any command.
+ *
+ * Byte 1: 0xfd
+ * Byte 2: 0x12 | A[2]
+ * A[2] == 1, Enable locking the MCU from entering command
+ */
+
+#define SSD1329_CMD_LOCK 0xfd
+# define SSD1329_LOCK_ON 0x13
+# define SSD1329_LOCK_OFF 0x12
+
+/* SD1329 Status ************************************************************/
+
+#define SDD1329_STATUS_ON 0x00 /* D[6]=0: indicates the display is ON */
+#define SDD1329_STATUS_OFF 0x40 /* D[6]=1: indicates the display is OFF */
+
+/****************************************************************************
+ * Public Types
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C" {
+#else
+#define EXTERN extern
+#endif
+
+#undef EXTERN
+#if defined(__cplusplus)
+}
+#endif
+#endif /* __DRIVERS_LCD_SD1329_H */
diff --git a/nuttx/drivers/lcd/skeleton.c b/nuttx/drivers/lcd/skeleton.c
new file mode 100644
index 000000000..1cb8b5955
--- /dev/null
+++ b/nuttx/drivers/lcd/skeleton.c
@@ -0,0 +1,401 @@
+/**************************************************************************************
+ * drivers/lcd/skeleton.c
+ *
+ * Copyright (C) 2011 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+#include <nuttx/lcd/lcd.h>
+
+#include "up_arch.h"
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+
+/* Configuration **********************************************************************/
+/* Verify that all configuration requirements have been met */
+
+/* Debug ******************************************************************************/
+/* Define the following to enable register-level debug output */
+
+#undef CONFIG_LCD_SKELDEBUG
+
+/* Verbose debug must also be enabled */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_GRAPHICS
+#endif
+
+#ifndef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_LCD_SKELDEBUG
+#endif
+
+/* Color Properties *******************************************************************/
+
+/* Display Resolution */
+
+#define SKEL_XRES 320
+#define SKEL_YRES 240
+
+/* Color depth and format */
+
+#define SKEL_BPP 16
+#define SKEL_COLORFMT FB_FMT_RGB16_565
+
+/* Debug ******************************************************************************/
+
+#ifdef CONFIG_LCD_SKELDEBUG
+# define skeldbg(format, arg...) vdbg(format, ##arg)
+#else
+# define skeldbg(x...)
+#endif
+
+/**************************************************************************************
+ * Private Type Definition
+ **************************************************************************************/
+
+/* This structure describes the state of this driver */
+
+struct skel_dev_s
+{
+ /* Publically visible device structure */
+
+ struct lcd_dev_s dev;
+
+ /* Private LCD-specific information follows */
+};
+
+/**************************************************************************************
+ * Private Function Protototypes
+ **************************************************************************************/
+
+/* LCD Data Transfer Methods */
+
+static int skel_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels);
+static int skel_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels);
+
+/* LCD Configuration */
+
+static int skel_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+static int skel_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+/* LCD RGB Mapping */
+
+#ifdef CONFIG_FB_CMAP
+# error "RGB color mapping not supported by this driver"
+#endif
+
+/* Cursor Controls */
+
+#ifdef CONFIG_FB_HWCURSOR
+# error "Cursor control not supported by this driver"
+#endif
+
+/* LCD Specific Controls */
+
+static int skel_getpower(struct lcd_dev_s *dev);
+static int skel_setpower(struct lcd_dev_s *dev, int power);
+static int skel_getcontrast(struct lcd_dev_s *dev);
+static int skel_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
+
+/**************************************************************************************
+ * Private Data
+ **************************************************************************************/
+
+/* This is working memory allocated by the LCD driver for each LCD device
+ * and for each color plane. This memory will hold one raster line of data.
+ * The size of the allocated run buffer must therefore be at least
+ * (bpp * xres / 8). Actual alignment of the buffer must conform to the
+ * bitwidth of the underlying pixel type.
+ *
+ * If there are multiple planes, they may share the same working buffer
+ * because different planes will not be operate on concurrently. However,
+ * if there are multiple LCD devices, they must each have unique run buffers.
+ */
+
+static uint16_t g_runbuffer[SKEL_XRES];
+
+/* This structure describes the overall LCD video controller */
+
+static const struct fb_videoinfo_s g_videoinfo =
+{
+ .fmt = SKEL_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
+ .xres = SKEL_XRES, /* Horizontal resolution in pixel columns */
+ .yres = SKEL_YRES, /* Vertical resolution in pixel rows */
+ .nplanes = 1, /* Number of color planes supported */
+};
+
+/* This is the standard, NuttX Plane information object */
+
+static const struct lcd_planeinfo_s g_planeinfo =
+{
+ .putrun = skel_putrun, /* Put a run into LCD memory */
+ .getrun = skel_getrun, /* Get a run from LCD memory */
+ .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */
+ .bpp = SKEL_BPP, /* Bits-per-pixel */
+};
+
+/* This is the standard, NuttX LCD driver object */
+
+static struct skel_dev_s g_lcddev =
+{
+ .dev =
+ {
+ /* LCD Configuration */
+
+ .getvideoinfo = skel_getvideoinfo,
+ .getplaneinfo = skel_getplaneinfo,
+
+ /* LCD RGB Mapping -- Not supported */
+ /* Cursor Controls -- Not supported */
+
+ /* LCD Specific Controls */
+
+ .getpower = skel_getpower,
+ .setpower = skel_setpower,
+ .getcontrast = skel_getcontrast,
+ .setcontrast = skel_setcontrast,
+ },
+};
+
+/**************************************************************************************
+ * Private Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: skel_putrun
+ *
+ * Description:
+ * This method can be used to write a partial raster line to the LCD:
+ *
+ * row - Starting row to write to (range: 0 <= row < yres)
+ * col - Starting column to write to (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer containing the run to be written to the LCD
+ * npixels - The number of pixels to write to the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int skel_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ /* Buffer must be provided and aligned to a 16-bit address boundary */
+
+ gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+ /* Set up to write the run. */
+
+ /* Write the run to GRAM. */
+#warning "Missing logic"
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: skel_getrun
+ *
+ * Description:
+ * This method can be used to read a partial raster line from the LCD:
+ *
+ * row - Starting row to read from (range: 0 <= row < yres)
+ * col - Starting column to read read (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer in which to return the run read from the LCD
+ * npixels - The number of pixels to read from the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int skel_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+ /* Buffer must be provided and aligned to a 16-bit address boundary */
+
+ gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+#warning "Missing logic"
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: skel_getvideoinfo
+ *
+ * Description:
+ * Get information about the LCD video controller configuration.
+ *
+ **************************************************************************************/
+
+static int skel_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo)
+{
+ DEBUGASSERT(dev && vinfo);
+ gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n",
+ g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes);
+ memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: skel_getplaneinfo
+ *
+ * Description:
+ * Get information about the configuration of each LCD color plane.
+ *
+ **************************************************************************************/
+
+static int skel_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo)
+{
+ DEBUGASSERT(dev && pinfo && planeno == 0);
+ gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
+ memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: skel_getpower
+ *
+ * Description:
+ * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int skel_getpower(struct lcd_dev_s *dev)
+{
+ struct skel_dev_s *priv = (struct skel_dev_s *)dev;
+ gvdbg("power: %d\n", 0);
+#warning "Missing logic"
+ return 0;
+}
+
+/**************************************************************************************
+ * Name: skel_setpower
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int skel_setpower(struct lcd_dev_s *dev, int power)
+{
+ struct skel_dev_s *priv = (struct skel_dev_s *)dev;
+
+ gvdbg("power: %d\n", power);
+ DEBUGASSERT(power <= CONFIG_LCD_MAXPOWER);
+
+ /* Set new power level */
+#warning "Missing logic"
+
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: skel_getcontrast
+ *
+ * Description:
+ * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int skel_getcontrast(struct lcd_dev_s *dev)
+{
+ gvdbg("Not implemented\n");
+#warning "Missing logic"
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: skel_setcontrast
+ *
+ * Description:
+ * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int skel_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
+{
+ gvdbg("contrast: %d\n", contrast);
+#warning "Missing logic"
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Public Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: up_oledinitialize
+ *
+ * Description:
+ * Initialize the LCD video hardware. The initial state of the LCD is fully
+ * initialized, display memory cleared, and the LCD ready to use, but with the power
+ * setting at 0 (full off).
+ *
+ **************************************************************************************/
+
+FAR struct lcd_dev_s *up_oledinitialize(FAR struct spi_dev_s *spi)
+{
+ gvdbg("Initializing\n");
+
+ /* Configure GPIO pins */
+#warning "Missing logic"
+
+ /* Enable clocking */
+#warning "Missing logic"
+
+ /* Configure and enable LCD */
+ #warning "Missing logic"
+
+ return &g_lcddev.dev;
+}
diff --git a/nuttx/drivers/lcd/ssd1289.c b/nuttx/drivers/lcd/ssd1289.c
new file mode 100644
index 000000000..58c606968
--- /dev/null
+++ b/nuttx/drivers/lcd/ssd1289.c
@@ -0,0 +1,1279 @@
+/**************************************************************************************
+ * drivers/lcd/ssd1289.c
+ *
+ * Generic LCD driver for LCDs based on the Solomon Systech SSD1289 LCD controller.
+ * Think of this as a template for an LCD driver that you will proably ahve to
+ * customize for any particular LCD hardware.
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Authors: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * References: SSD1289, Rev 1.3, Apr 2007, Solomon Systech Limited
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+#include <nuttx/lcd/lcd.h>
+#include <nuttx/lcd/ssd1289.h>
+
+#include "ssd1289.h"
+
+#ifdef CONFIG_LCD_SSD1289
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+/* Configuration **********************************************************************/
+
+/* Check contrast selection */
+
+#if !defined(CONFIG_LCD_MAXCONTRAST)
+# define CONFIG_LCD_MAXCONTRAST 1
+#endif
+
+/* Check power setting */
+
+#if !defined(CONFIG_LCD_MAXPOWER) || CONFIG_LCD_MAXPOWER < 1
+# define CONFIG_LCD_MAXPOWER 1
+#endif
+
+#if CONFIG_LCD_MAXPOWER > 255
+# error "CONFIG_LCD_MAXPOWER must be less than 256 to fit in uint8_t"
+#endif
+
+/* Check orientation */
+
+#if defined(CONFIG_LCD_PORTRAIT)
+# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE) || defined(CONFIG_LCD_RPORTRAIT)
+# error "Cannot define both portrait and any other orientations"
+# endif
+#elif defined(CONFIG_LCD_RPORTRAIT)
+# if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
+# error "Cannot define both rportrait and any other orientations"
+# endif
+#elif defined(CONFIG_LCD_LANDSCAPE)
+# ifdef CONFIG_LCD_RLANDSCAPE
+# error "Cannot define both landscape and any other orientations"
+# endif
+#elif !defined(CONFIG_LCD_RLANDSCAPE)
+# define CONFIG_LCD_LANDSCAPE 1
+#endif
+
+/* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug must
+ * also be enabled.
+ */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_GRAPHICS
+# undef CONFIG_DEBUG_LCD
+#endif
+
+#ifndef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_LCD
+#endif
+
+/* Display/Color Properties ***********************************************************/
+/* Display Resolution */
+
+#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
+# define SSD1289_XRES 320
+# define SSD1289_YRES 240
+#else
+# define SSD1289_XRES 240
+# define SSD1289_YRES 320
+#endif
+
+/* Color depth and format */
+
+#define SSD1289_BPP 16
+#define SSD1289_COLORFMT FB_FMT_RGB16_565
+
+/* LCD Profiles ***********************************************************************/
+/* Many details of the controller initialization must, unfortunately, vary from LCD to
+ * LCD. I have looked at the spec and at three different drivers for LCDs that have
+ * SSD1289 controllers. I have tried to summarize these differences as "LCD profiles"
+ *
+ * Most of the differences between LCDs are nothing more than a few minor bit
+ * settings. The most significant difference betwen LCD drivers in is the
+ * manner in which the LCD is powered up and in how the power controls are set.
+ * My suggestion is that if you have working LCD initialization code, you should
+ * simply replace the code in ssd1289_hwinitialize with your working code.
+ */
+
+#if defined (CONFIG_SSD1289_PROFILE2)
+# undef SSD1289_USE_SIMPLE_INIT
+
+ /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */
+
+# define PWRCTRL1_SETTING \
+ (SSD1289_PWRCTRL1_AP_SMMED | SSD1289_PWRCTRL1_DC_FLINEx24 | \
+ SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FLINEx24)
+
+ /* PWRCTRL2: 5.1v */
+
+# define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p1V
+
+ /* PWRCTRL3: x 2.165
+ * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec.
+ */
+
+# define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p165
+
+ /* PWRCTRL4: VDV=9 + VCOMG */
+
+# define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(9) | SSD1289_PWRCTRL4_VCOMG)
+
+ /* PWRCTRL5: VCM=56 + NOTP */
+
+# define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(56) | SSD1289_PWRCTRL5_NOTP)
+
+#elif defined (CONFIG_SSD1289_PROFILE3)
+# undef SSD1289_USE_SIMPLE_INIT
+
+ /* PWRCTRL1: AP=smalll-to-medium, DC=Flinex24, BT=+5/-4, DCT=Flinex24 */
+
+# define PWRCTRL1_SETTING \
+ (SSD1289_PWRCTRL1_AP_SMMED | SSD1289_PWRCTRL1_DC_FLINEx24 | \
+ SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FLINEx24)
+
+ /* PWRCTRL2: 5.1v */
+
+# define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p1V
+
+ /* PWRCTRL3: x 2.165
+ * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec.
+ */
+
+# define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p165
+
+ /* PWRCTRL4: VDV=9 + VCOMG */
+
+# define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(9) | SSD1289_PWRCTRL4_VCOMG)
+
+ /* PWRCTRL5: VCM=56 + NOTP */
+
+# define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(56) | SSD1289_PWRCTRL5_NOTP)
+
+#else /* if defined (CONFIG_SSD1289_PROFILE1) */
+# undef SSD1289_USE_SIMPLE_INIT
+# define SSD1289_USE_SIMPLE_INIT 1
+
+ /* PWRCTRL1: AP=medium-to-large, DC=Fosc/4, BT=+5/-4, DCT=Fosc/4 */
+
+# define PWRCTRL1_SETTING \
+ (SSD1289_PWRCTRL1_AP_MEDLG | SSD1289_PWRCTRL1_DC_FOSd4 | \
+ SSD1289_PWRCTRL1_BT_p5m4 | SSD1289_PWRCTRL1_DCT_FOSd4)
+
+ /* PWRCTRL2: 5.3v */
+
+# define PWRCTRL2_SETTING SSD1289_PWRCTRL2_VRC_5p3V
+
+ /* PWRCTRL3: x 2.570
+ * NOTE: Many drivers have bit 8 set which is not defined in the SSD1289 spec.
+ */
+
+# define PWRCTRL3_SETTING SSD1289_PWRCTRL3_VRH_x2p570
+
+ /* PWRCTRL4: VDV=12 + VCOMG */
+
+# define PWRCTRL4_SETTING (SSD1289_PWRCTRL4_VDV(12) | SSD1289_PWRCTRL4_VCOMG)
+
+ /* PWRCTRL5: VCM=60 + NOTP */
+
+# define PWRCTRL5_SETTING (SSD1289_PWRCTRL5_VCM(60) | SSD1289_PWRCTRL5_NOTP)
+
+#endif
+
+/* Debug ******************************************************************************/
+
+#ifdef CONFIG_DEBUG_LCD
+# define lcddbg dbg
+# define lcdvdbg vdbg
+#else
+# define lcddbg(x...)
+# define lcdvdbg(x...)
+#endif
+
+/**************************************************************************************
+ * Private Type Definition
+ **************************************************************************************/
+
+/* This structure describes the state of this driver */
+
+struct ssd1289_dev_s
+{
+ /* Publically visible device structure */
+
+ struct lcd_dev_s dev;
+
+ /* Private LCD-specific information follows */
+
+ FAR struct ssd1289_lcd_s *lcd; /* The contained platform-specific, LCD interface */
+ uint8_t power; /* Current power setting */
+
+ /* This is working memory allocated by the LCD driver for each LCD device
+ * and for each color plane. This memory will hold one raster line of data.
+ * The size of the allocated run buffer must therefore be at least
+ * (bpp * xres / 8). Actual alignment of the buffer must conform to the
+ * bitwidth of the underlying pixel type.
+ *
+ * If there are multiple planes, they may share the same working buffer
+ * because different planes will not be operate on concurrently. However,
+ * if there are multiple LCD devices, they must each have unique run buffers.
+ */
+
+ uint16_t runbuffer[SSD1289_XRES];
+};
+
+/**************************************************************************************
+ * Private Function Protototypes
+ **************************************************************************************/
+/* Low Level LCD access */
+
+static void ssd1289_putreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr,
+ uint16_t regval);
+#ifndef CONFIG_LCD_NOGETRUN
+static uint16_t ssd1289_readreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr);
+#endif
+static inline void ssd1289_gramwrite(FAR struct ssd1289_lcd_s *lcd, uint16_t rgbcolor);
+#ifndef CONFIG_LCD_NOGETRUN
+static inline void ssd1289_readsetup(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum);
+static inline uint16_t ssd1289_gramread(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum);
+#endif
+static void ssd1289_setcursor(FAR struct ssd1289_lcd_s *lcd, uint16_t column,
+ uint16_t row);
+
+/* LCD Data Transfer Methods */
+
+static int ssd1289_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels);
+static int ssd1289_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels);
+
+/* LCD Configuration */
+
+static int ssd1289_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+static int ssd1289_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+/* LCD RGB Mapping */
+
+#ifdef CONFIG_FB_CMAP
+# error "RGB color mapping not supported by this driver"
+#endif
+
+/* Cursor Controls */
+
+#ifdef CONFIG_FB_HWCURSOR
+# error "Cursor control not supported by this driver"
+#endif
+
+/* LCD Specific Controls */
+
+static int ssd1289_getpower(FAR struct lcd_dev_s *dev);
+static int ssd1289_setpower(FAR struct lcd_dev_s *dev, int power);
+static int ssd1289_getcontrast(FAR struct lcd_dev_s *dev);
+static int ssd1289_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast);
+
+/* Initialization */
+
+static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv);
+
+/**************************************************************************************
+ * Private Data
+ **************************************************************************************/
+
+/* This driver can support only a signal SSD1289 device. This is due to an
+ * unfortunate decision made whent he getrun and putrun methods were designed. The
+ * following is the single SSD1289 driver state instance:
+ */
+
+static struct ssd1289_dev_s g_lcddev;
+
+/**************************************************************************************
+ * Private Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: ssd1289_putreg(lcd,
+ *
+ * Description:
+ * Write to an LCD register
+ *
+ **************************************************************************************/
+
+static void ssd1289_putreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr, uint16_t regval)
+{
+ /* Set the index register to the register address and write the register contents */
+
+ lcd->index(lcd, regaddr);
+ lcd->write(lcd, regval);
+}
+
+/**************************************************************************************
+ * Name: ssd1289_readreg
+ *
+ * Description:
+ * Read from an LCD register
+ *
+ **************************************************************************************/
+
+#ifndef CONFIG_LCD_NOGETRUN
+static uint16_t ssd1289_readreg(FAR struct ssd1289_lcd_s *lcd, uint8_t regaddr)
+{
+ /* Set the index register to the register address and read the register contents */
+
+ lcd->index(lcd, regaddr);
+ return lcd->read(lcd);
+}
+#endif
+
+/**************************************************************************************
+ * Name: ssd1289_gramselect
+ *
+ * Description:
+ * Setup to read or write multiple pixels to the GRAM memory
+ *
+ **************************************************************************************/
+
+static inline void ssd1289_gramselect(FAR struct ssd1289_lcd_s *lcd)
+{
+ lcd->index(lcd, SSD1289_DATA);
+}
+
+/**************************************************************************************
+ * Name: ssd1289_gramwrite
+ *
+ * Description:
+ * Setup to read or write multiple pixels to the GRAM memory
+ *
+ **************************************************************************************/
+
+static inline void ssd1289_gramwrite(FAR struct ssd1289_lcd_s *lcd, uint16_t data)
+{
+ lcd->write(lcd, data);
+}
+
+/**************************************************************************************
+ * Name: ssd1289_readsetup
+ *
+ * Description:
+ * Prime the operation by reading one pixel from the GRAM memory if necessary for
+ * this LCD type. When reading 16-bit gram data, there may be some shifts in the
+ * returned data:
+ *
+ * - ILI932x: Discard first dummy read; no shift in the return data
+ *
+ **************************************************************************************/
+
+#ifndef CONFIG_LCD_NOGETRUN
+static inline void ssd1289_readsetup(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum)
+{
+ /* Read-ahead one pixel */
+
+ *accum = lcd->read(lcd);
+}
+#endif
+
+/**************************************************************************************
+ * Name: ssd1289_gramread
+ *
+ * Description:
+ * Read one correctly aligned pixel from the GRAM memory. Possibly shifting the
+ * data and possibly swapping red and green components.
+ *
+ * - ILI932x: Unknown -- assuming colors are in the color order
+ *
+ **************************************************************************************/
+
+#ifndef CONFIG_LCD_NOGETRUN
+static inline uint16_t ssd1289_gramread(FAR struct ssd1289_lcd_s *lcd, FAR uint16_t *accum)
+{
+ /* Read the value (GRAM register already selected) */
+
+ return lcd->read(lcd);
+}
+#endif
+
+/**************************************************************************************
+ * Name: ssd1289_setcursor
+ *
+ * Description:
+ * Set the cursor position. In landscape mode, the "column" is actually the physical
+ * Y position and the "row" is the physical X position.
+ *
+ **************************************************************************************/
+
+static void ssd1289_setcursor(FAR struct ssd1289_lcd_s *lcd, uint16_t column, uint16_t row)
+{
+#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
+ ssd1289_putreg(lcd, SSD1289_XADDR, column); /* 0-239 */
+ ssd1289_putreg(lcd, SSD1289_YADDR, row); /* 0-319 */
+#elif defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
+ ssd1289_putreg(lcd, SSD1289_XADDR, row); /* 0-239 */
+ ssd1289_putreg(lcd, SSD1289_YADDR, column); /* 0-319 */
+#endif
+}
+
+/**************************************************************************************
+ * Name: ssd1289_dumprun
+ *
+ * Description:
+ * Dump the contexts of the run buffer:
+ *
+ * run - The buffer in containing the run read to be dumped
+ * npixels - The number of pixels to dump
+ *
+ **************************************************************************************/
+
+#if 0 /* Sometimes useful */
+static void ssd1289_dumprun(FAR const char *msg, FAR uint16_t *run, size_t npixels)
+{
+ int i, j;
+
+ lib_rawprintf("\n%s:\n", msg);
+ for (i = 0; i < npixels; i += 16)
+ {
+ up_putc(' ');
+ lib_rawprintf(" ");
+ for (j = 0; j < 16; j++)
+ {
+ lib_rawprintf(" %04x", *run++);
+ }
+ up_putc('\n');
+ }
+}
+#endif
+
+/**************************************************************************************
+ * Name: ssd1289_putrun
+ *
+ * Description:
+ * This method can be used to write a partial raster line to the LCD:
+ *
+ * row - Starting row to write to (range: 0 <= row < yres)
+ * col - Starting column to write to (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer containing the run to be written to the LCD
+ * npixels - The number of pixels to write to the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int ssd1289_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ FAR struct ssd1289_dev_s *priv = &g_lcddev;
+ FAR struct ssd1289_lcd_s *lcd = priv->lcd;
+ FAR const uint16_t *src = (FAR const uint16_t*)buffer;
+ int i;
+
+ /* Buffer must be provided and aligned to a 16-bit address boundary */
+
+ lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+ /* Write the run to GRAM. */
+
+#ifdef CONFIG_LCD_LANDSCAPE
+ /* Convert coordinates -- Here the edge away from the row of buttons on
+ * the STM3240G-EVAL is used as the top.
+ */
+
+ /* Write the GRAM data, manually incrementing X */
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Write the next pixel to this position */
+
+ ssd1289_setcursor(lcd, col, row);
+ ssd1289_gramselect(lcd);
+ ssd1289_gramwrite(lcd, *src);
+
+ /* Increment to next column */
+
+ src++;
+ col++;
+ }
+#elif defined(CONFIG_LCD_RLANDSCAPE)
+ /* Convert coordinates -- Here the edge next to the row of buttons on
+ * the STM3240G-EVAL is used as the top.
+ */
+
+ col = (SSD1289_XRES-1) - col;
+ row = (SSD1289_YRES-1) - row;
+
+ /* Set the cursor position */
+
+ ssd1289_setcursor(lcd, col, row);
+
+ /* Then write the GRAM data, auto-decrementing X */
+
+ ssd1289_gramselect(lcd);
+ for (i = 0; i < npixels; i++)
+ {
+ /* Write the next pixel to this position (auto-decrements to the next column) */
+
+ ssd1289_gramwrite(lcd, *src);
+ src++;
+ }
+#elif defined(CONFIG_LCD_PORTRAIT)
+ /* Convert coordinates. In this configuration, the top of the display is to the left
+ * of the buttons (if the board is held so that the buttons are at the botton of the
+ * board).
+ */
+
+ col = (SSD1289_XRES-1) - col;
+
+ /* Then write the GRAM data, manually incrementing Y (which is col) */
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Write the next pixel to this position */
+
+ ssd1289_setcursor(lcd, row, col);
+ ssd1289_gramselect(lcd);
+ ssd1289_gramwrite(lcd, *src);
+
+ /* Increment to next column */
+
+ src++;
+ col--;
+ }
+#else /* CONFIG_LCD_RPORTRAIT */
+ /* Convert coordinates. In this configuration, the top of the display is to the right
+ * of the buttons (if the board is held so that the buttons are at the botton of the
+ * board).
+ */
+
+ row = (SSD1289_YRES-1) - row;
+
+ /* Then write the GRAM data, manually incrementing Y (which is col) */
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Write the next pixel to this position */
+
+ ssd1289_setcursor(lcd, row, col);
+ ssd1289_gramselect(lcd);
+ ssd1289_gramwrite(lcd, *src);
+
+ /* Decrement to next column */
+
+ src++;
+ col++;
+ }
+#endif
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_getrun
+ *
+ * Description:
+ * This method can be used to read a partial raster line from the LCD:
+ *
+ * row - Starting row to read from (range: 0 <= row < yres)
+ * col - Starting column to read read (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer in which to return the run read from the LCD
+ * npixels - The number of pixels to read from the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int ssd1289_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+#ifndef CONFIG_LCD_NOGETRUN
+ FAR struct ssd1289_dev_s *priv = &g_lcddev;
+ FAR struct ssd1289_lcd_s *lcd = priv->lcd;
+ FAR uint16_t *dest = (FAR uint16_t*)buffer;
+ uint16_t accum;
+ int i;
+
+ /* Buffer must be provided and aligned to a 16-bit address boundary */
+
+ lcdvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+ /* Read the run from GRAM. */
+
+#ifdef CONFIG_LCD_LANDSCAPE
+ /* Convert coordinates -- Here the edge away from the row of buttons on
+ * the STM3240G-EVAL is used as the top.
+ */
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Read the next pixel from this position */
+
+ ssd1289_setcursor(lcd, row, col);
+ ssd1289_gramselect(lcd);
+ ssd1289_readsetup(lcd, &accum);
+ *dest++ = ssd1289_gramread(lcd, &accum);
+
+ /* Increment to next column */
+
+ col++;
+ }
+#elif defined(CONFIG_LCD_RLANDSCAPE)
+ /* Convert coordinates -- Here the edge next to the row of buttons on
+ * the STM3240G-EVAL is used as the top.
+ */
+
+ col = (SSD1289_XRES-1) - col;
+ row = (SSD1289_YRES-1) - row;
+
+ /* Set the cursor position */
+
+ ssd1289_setcursor(lcd, col, row);
+
+ /* Then read the GRAM data, auto-decrementing Y */
+
+ ssd1289_gramselect(lcd);
+
+ /* Prime the pump for unaligned read data */
+
+ ssd1289_readsetup(lcd, &accum);
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Read the next pixel from this position (autoincrements to the next row) */
+
+ *dest++ = ssd1289_gramread(lcd, &accum);
+ }
+#elif defined(CONFIG_LCD_PORTRAIT)
+ /* Convert coordinates. In this configuration, the top of the display is to the left
+ * of the buttons (if the board is held so that the buttons are at the botton of the
+ * board).
+ */
+
+ col = (SSD1289_XRES-1) - col;
+
+ /* Then read the GRAM data, manually incrementing Y (which is col) */
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Read the next pixel from this position */
+
+ ssd1289_setcursor(lcd, row, col);
+ ssd1289_gramselect(lcd);
+ ssd1289_readsetup(lcd, &accum);
+ *dest++ = ssd1289_gramread(lcd, &accum);
+
+ /* Increment to next column */
+
+ col--;
+ }
+#else /* CONFIG_LCD_RPORTRAIT */
+ /* Convert coordinates. In this configuration, the top of the display is to the right
+ * of the buttons (if the board is held so that the buttons are at the botton of the
+ * board).
+ */
+
+ row = (SSD1289_YRES-1) - row;
+
+ /* Then write the GRAM data, manually incrementing Y (which is col) */
+
+ for (i = 0; i < npixels; i++)
+ {
+ /* Write the next pixel to this position */
+
+ ssd1289_setcursor(lcd, row, col);
+ ssd1289_gramselect(lcd);
+ ssd1289_readsetup(lcd, &accum);
+ *dest++ = ssd1289_gramread(lcd, &accum);
+
+ /* Decrement to next column */
+
+ col++;
+ }
+#endif
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+ return OK;
+#else
+ return -ENOSYS;
+#endif
+}
+
+/**************************************************************************************
+ * Name: ssd1289_getvideoinfo
+ *
+ * Description:
+ * Get information about the LCD video controller configuration.
+ *
+ **************************************************************************************/
+
+static int ssd1289_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo)
+{
+ DEBUGASSERT(dev && vinfo);
+ lcdvdbg("fmt: %d xres: %d yres: %d nplanes: 1\n",
+ SSD1289_COLORFMT, SSD1289_XRES, SSD1289_XRES);
+
+ vinfo->fmt = SSD1289_COLORFMT; /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
+ vinfo->xres = SSD1289_XRES; /* Horizontal resolution in pixel columns */
+ vinfo->yres = SSD1289_YRES; /* Vertical resolution in pixel rows */
+ vinfo->nplanes = 1; /* Number of color planes supported */
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_getplaneinfo
+ *
+ * Description:
+ * Get information about the configuration of each LCD color plane.
+ *
+ **************************************************************************************/
+
+static int ssd1289_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo)
+{
+ FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev;
+
+ DEBUGASSERT(dev && pinfo && planeno == 0);
+ lcdvdbg("planeno: %d bpp: %d\n", planeno, SSD1289_BPP);
+
+ pinfo->putrun = ssd1289_putrun; /* Put a run into LCD memory */
+ pinfo->getrun = ssd1289_getrun; /* Get a run from LCD memory */
+ pinfo->buffer = (uint8_t*)priv->runbuffer; /* Run scratch buffer */
+ pinfo->bpp = SSD1289_BPP; /* Bits-per-pixel */
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_getpower
+ *
+ * Description:
+ * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int ssd1289_getpower(FAR struct lcd_dev_s *dev)
+{
+ lcdvdbg("power: %d\n", 0);
+ return g_lcddev.power;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_poweroff
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int ssd1289_poweroff(FAR struct ssd1289_lcd_s *lcd)
+{
+ /* Set the backlight off */
+
+ lcd->backlight(lcd, 0);
+
+ /* Turn the display off */
+
+ ssd1289_putreg(lcd, SSD1289_DSPCTRL, 0);
+
+ /* Remember the power off state */
+
+ g_lcddev.power = 0;
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_setpower
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int ssd1289_setpower(FAR struct lcd_dev_s *dev, int power)
+{
+ FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev;
+ FAR struct ssd1289_lcd_s *lcd = priv->lcd;
+
+ lcdvdbg("power: %d\n", power);
+ DEBUGASSERT((unsigned)power <= CONFIG_LCD_MAXPOWER);
+
+ /* Set new power level */
+
+ if (power > 0)
+ {
+ /* Set the backlight level */
+
+ lcd->backlight(lcd, power);
+
+ /* Then turn the display on:
+ * D=ON(3) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_DSPCTRL,
+ (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON |
+ SSD1289_DSPCTRL_DTE | SSD1289_DSPCTRL_VLE(0)));
+
+ g_lcddev.power = power;
+ }
+ else
+ {
+ /* Turn the display off */
+
+ ssd1289_poweroff(lcd);
+ }
+
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_getcontrast
+ *
+ * Description:
+ * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int ssd1289_getcontrast(FAR struct lcd_dev_s *dev)
+{
+ lcdvdbg("Not implemented\n");
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_setcontrast
+ *
+ * Description:
+ * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int ssd1289_setcontrast(FAR struct lcd_dev_s *dev, unsigned int contrast)
+{
+ lcdvdbg("contrast: %d\n", contrast);
+ return -ENOSYS;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_hwinitialize
+ *
+ * Description:
+ * Initialize the LCD hardware.
+ *
+ **************************************************************************************/
+
+static inline int ssd1289_hwinitialize(FAR struct ssd1289_dev_s *priv)
+{
+ FAR struct ssd1289_lcd_s *lcd = priv->lcd;
+#ifndef CONFIG_LCD_NOGETRUN
+ uint16_t id;
+#endif
+
+ /* Select the LCD */
+
+ lcd->select(lcd);
+
+#ifndef CONFIG_LCD_NOGETRUN
+ id = ssd1289_readreg(lcd, SSD1289_DEVCODE);
+ lcddbg("LCD ID: %04x\n", id);
+
+ /* Check if the ID is for the SSD1289 */
+
+ if (id == SSD1289_DEVCODE_VALUE)
+#endif
+ {
+ /* LCD controller configuration. Many details of the controller initialization
+ * must, unfortunately, vary from LCD to LCD. I have looked at the spec and at
+ * three different drivers for LCDs that have SSD1289 controllers. I have tried
+ * to summarize these differences as profiles (defined above). Some other
+ * alternatives are noted below.
+ *
+ * Most of the differences between LCDs are nothing more than a few minor bit
+ * settings. The most significant difference betwen LCD drivers in is the
+ * manner in which the LCD is powered up and in how the power controls are set.
+ * My suggestion is that if you have working LCD initialization code, you should
+ * simply replace the following guesses with your working code.
+ */
+
+ /* Most drivers just enable the oscillator */
+
+#ifdef SSD1289_USE_SIMPLE_INIT
+ ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN);
+#else
+ /* But one goes through a more complex start-up sequence. Something like the
+ * following:
+ *
+ * First, put the display in INTERNAL operation:
+ * D=INTERNAL(1) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_DSPCTRL,
+ (SSD1289_DSPCTRL_INTERNAL | SSD1289_DSPCTRL_GON |
+ SSD1289_DSPCTRL_VLE(0)));
+
+ /* Then enable the oscillator */
+
+ ssd1289_putreg(lcd, SSD1289_OSCSTART, SSD1289_OSCSTART_OSCEN);
+
+ /* Turn the display on:
+ * D=ON(3) CM=0 DTE=0 GON=1 SPT=0 VLE=0 PT=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_DSPCTRL,
+ (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_GON |
+ SSD1289_DSPCTRL_VLE(0)));
+
+ /* Take the LCD out of sleep mode */
+
+ ssd1289_putreg(lcd, SSD1289_SLEEP, 0);
+ up_mdelay(30);
+
+ /* Turn the display on:
+ * D=INTERNAL(1) CM=0 DTE=1 GON=1 SPT=0 VLE=0 PT=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_DSPCTRL,
+ (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE |
+ SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(0)));
+#endif
+
+ /* Set up power control registers. There is a lot of variability
+ * from LCD-to-LCD in how the power registers are configured.
+ */
+
+ ssd1289_putreg(lcd, SSD1289_PWRCTRL1, PWRCTRL1_SETTING);
+ ssd1289_putreg(lcd, SSD1289_PWRCTRL2, PWRCTRL2_SETTING);
+
+ /* One driver adds a delay here.. I doubt that this is really necessary. */
+ /* up_mdelay(15); */
+
+ ssd1289_putreg(lcd, SSD1289_PWRCTRL3, PWRCTRL3_SETTING);
+ ssd1289_putreg(lcd, SSD1289_PWRCTRL4, PWRCTRL4_SETTING);
+ ssd1289_putreg(lcd, SSD1289_PWRCTRL5, PWRCTRL5_SETTING);
+
+ /* One driver does an odd setting of the the driver output control.
+ * No idea why.
+ */
+#if 0
+ ssd1289_putreg(lcd, SSD1289_OUTCTRL,
+ (SSD1289_OUTCTRL_MUX(12) | SSD1289_OUTCTRL_TB |
+ SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_CAD));
+
+ /* The same driver does another small delay here */
+
+ up_mdelay(15);
+#endif
+
+ /* After this point, the drivers differ only in some varying register
+ * bit settings.
+ */
+
+ /* Set the driver output control.
+ * PORTRAIT MODES:
+ * MUX=319, TB=1, SM=0, BGR=1, CAD=0, REV=1, RL=0
+ * LANDSCAPE MODES:
+ * MUX=319, TB=0, SM=0, BGR=1, CAD=0, REV=1, RL=0
+ */
+
+#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
+ ssd1289_putreg(lcd, SSD1289_OUTCTRL,
+ (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_TB |
+ SSD1289_OUTCTRL_BGR | SSD1289_OUTCTRL_REV);
+#else
+ ssd1289_putreg(lcd, SSD1289_OUTCTRL,
+ (SSD1289_OUTCTRL_MUX(319) | SSD1289_OUTCTRL_BGR |
+ SSD1289_OUTCTRL_REV));
+#endif
+
+ /* Set the LCD driving AC waveform
+ * NW=0, WSMD=0, EOR=1, BC=1, ENWD=0, FLD=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_ACCTRL,
+ (SSD1289_ACCTRL_EOR | SSD1289_ACCTRL_BC));
+
+ /* Take the LCD out of sleep mode (isn't this redundant in the non-
+ * simple case?)
+ */
+
+ ssd1289_putreg(lcd, SSD1289_SLEEP, 0);
+
+ /* Set entry mode */
+
+#if defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
+ /* LG=0, AM=0, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3
+ * Alternative TY=2 (But TY only applies in 262K color mode anyway)
+ */
+
+ ssd1289_putreg(lcd, SSD1289_ENTRY,
+ (SSD1289_ENTRY_ID_HINCVINC | SSD1289_ENTRY_TY_C |
+ SSD1289_ENTRY_DMODE_RAM | SSD1289_ENTRY_DFM_65K));
+#else
+ /* LG=0, AM=1, ID=3, TY=2, DMODE=0, WMODE=0, OEDEF=0, TRANS=0, DRM=3 */
+ /* Alternative TY=2 (But TY only applies in 262K color mode anyway) */
+
+ ssd1289_putreg(lcd, SSD1289_ENTRY,
+ (SSD1289_ENTRY_AM | SSD1289_ENTRY_ID_HINCVINC |
+ SSD1289_ENTRY_TY_C | SSD1289_ENTRY_DMODE_RAM |
+ SSD1289_ENTRY_DFM_65K));
+#endif
+
+ /* Clear compare registers */
+
+ ssd1289_putreg(lcd, SSD1289_CMP1, 0);
+ ssd1289_putreg(lcd, SSD1289_CMP2, 0);
+
+ /* One driver puts a huge, 100 millisecond delay here */
+ /* up_mdelay(100); */
+
+ /* Set Horizontal and vertical porch.
+ * Horizontal porch: 239 pixels per line, delay=28
+ * Vertical porch: VBP=3, XFP=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_HPORCH,
+ (28 << SSD1289_HPORCH_HBP_SHIFT) | (239 << SSD1289_HPORCH_XL_SHIFT));
+ ssd1289_putreg(lcd, SSD1289_VPORCH,
+ (3 << SSD1289_VPORCH_VBP_SHIFT) | (0 << SSD1289_VPORCH_XFP_SHIFT));
+
+ /* Set display control.
+ * D=ON(3), CM=0 (not 8-color), DTE=1, GON=1, SPT=0, VLE=1 PT=0
+ */
+
+ ssd1289_putreg(lcd, SSD1289_DSPCTRL,
+ (SSD1289_DSPCTRL_ON | SSD1289_DSPCTRL_DTE |
+ SSD1289_DSPCTRL_GON | SSD1289_DSPCTRL_VLE(1)));
+
+ /* Frame cycle control. Alternative: SSD1289_FCYCCTRL_DIV8 */
+
+ ssd1289_putreg(lcd, SSD1289_FCYCCTRL, 0);
+
+ /* Gate scan start position = 0 */
+
+ ssd1289_putreg(lcd, SSD1289_GSTART, 0);
+
+ /* Clear vertical scrolling */
+
+ ssd1289_putreg(lcd, SSD1289_VSCROLL1, 0);
+ ssd1289_putreg(lcd, SSD1289_VSCROLL2, 0);
+
+ /* Setup window 1 (0-319) */
+
+ ssd1289_putreg(lcd, SSD1289_W1START, 0);
+ ssd1289_putreg(lcd, SSD1289_W1END, 319);
+
+ /* Disable window 2 (0-0) */
+
+ ssd1289_putreg(lcd, SSD1289_W2START, 0);
+ ssd1289_putreg(lcd, SSD1289_W2END, 0);
+
+ /* Horizontal start and end (0-239) */
+
+ ssd1289_putreg(lcd, SSD1289_HADDR,
+ (0 << SSD1289_HADDR_HSA_SHIFT) | (239 << SSD1289_HADDR_HEA_SHIFT));
+
+ /* Vertical start and end (0-319) */
+
+ ssd1289_putreg(lcd, SSD1289_VSTART, 0);
+ ssd1289_putreg(lcd, SSD1289_VEND, 319);
+
+ /* Gamma controls */
+
+ ssd1289_putreg(lcd, SSD1289_GAMMA1, 0x0707);
+ ssd1289_putreg(lcd, SSD1289_GAMMA2, 0x0204); /* Alternative: 0x0704 */
+ ssd1289_putreg(lcd, SSD1289_GAMMA3, 0x0204);
+ ssd1289_putreg(lcd, SSD1289_GAMMA4, 0x0502);
+ ssd1289_putreg(lcd, SSD1289_GAMMA5, 0x0507);
+ ssd1289_putreg(lcd, SSD1289_GAMMA6, 0x0204);
+ ssd1289_putreg(lcd, SSD1289_GAMMA7, 0x0204);
+ ssd1289_putreg(lcd, SSD1289_GAMMA8, 0x0502);
+ ssd1289_putreg(lcd, SSD1289_GAMMA9, 0x0302);
+ ssd1289_putreg(lcd, SSD1289_GAMMA10, 0x0302); /* Alternative: 0x1f00 */
+
+ /* Clear write mask */
+
+ ssd1289_putreg(lcd, SSD1289_WRMASK1, 0);
+ ssd1289_putreg(lcd, SSD1289_WRMASK2, 0);
+
+ /* Set frame frequency = 65Hz (This should not be necessary since this
+ * is the default POR value)
+ */
+
+ ssd1289_putreg(lcd, SSD1289_FFREQ, SSD1289_FFREQ_OSC_FF65);
+
+ /* Set the cursor at the home position and set the index register to
+ * the gram data register (I can't imagine these are necessary).
+ */
+
+ ssd1289_setcursor(lcd, 0, 0);
+ ssd1289_gramselect(lcd);
+
+ /* One driver has a 50 msec delay here */
+ /* up_mdelay(50); */
+
+ return OK;
+ }
+#ifndef CONFIG_LCD_NOGETRUN
+ else
+ {
+ lcddbg("Unsupported LCD type\n");
+ return -ENODEV;
+ }
+#endif
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+}
+
+ /*************************************************************************************
+ * Public Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: ssd1289_lcdinitialize
+ *
+ * Description:
+ * Initialize the LCD video hardware. The initial state of the LCD is fully
+ * initialized, display memory cleared, and the LCD ready to use, but with the power
+ * setting at 0 (full off).
+ *
+ **************************************************************************************/
+
+FAR struct lcd_dev_s *ssd1289_lcdinitialize(FAR struct ssd1289_lcd_s *lcd)
+{
+ int ret;
+
+ lcdvdbg("Initializing\n");
+
+ /* If we ccould support multiple SSD1289 devices, this is where we would allocate
+ * a new driver data structure... but we can't. Why not? Because of a bad should
+ * the form of the getrun() and putrun methods.
+ */
+
+ FAR struct ssd1289_dev_s *priv = &g_lcddev;
+
+ /* Initialize the driver data structure */
+
+ priv->dev.getvideoinfo = ssd1289_getvideoinfo;
+ priv->dev.getplaneinfo = ssd1289_getplaneinfo;
+ priv->dev.getpower = ssd1289_getpower;
+ priv->dev.setpower = ssd1289_setpower;
+ priv->dev.getcontrast = ssd1289_getcontrast;
+ priv->dev.setcontrast = ssd1289_setcontrast;
+ priv->lcd = lcd;
+
+ /* Configure and enable LCD */
+
+ ret = ssd1289_hwinitialize(priv);
+ if (ret == OK)
+ {
+ /* Clear the display (setting it to the color 0=black) */
+
+ ssd1289_clear(&priv->dev, 0);
+
+ /* Turn the display off */
+
+ ssd1289_poweroff(lcd);
+ return &g_lcddev.dev;
+ }
+
+ return NULL;
+}
+
+/**************************************************************************************
+ * Name: ssd1289_clear
+ *
+ * Description:
+ * This is a non-standard LCD interface just for the stm3240g-EVAL board. Because
+ * of the various rotations, clearing the display in the normal way by writing a
+ * sequences of runs that covers the entire display can be very slow. Here the
+ * display is cleared by simply setting all GRAM memory to the specified color.
+ *
+ **************************************************************************************/
+
+void ssd1289_clear(FAR struct lcd_dev_s *dev, uint16_t color)
+{
+ FAR struct ssd1289_dev_s *priv = (FAR struct ssd1289_dev_s *)dev;
+ FAR struct ssd1289_lcd_s *lcd = priv->lcd;
+ uint32_t i;
+
+ /* Select the LCD and home the cursor position */
+
+ lcd->select(lcd);
+ ssd1289_setcursor(lcd, 0, 0);
+
+ /* Prepare to write GRAM data */
+
+ ssd1289_gramselect(lcd);
+
+ /* Copy color into all of GRAM. Orientation does not matter in this case. */
+
+ for (i = 0; i < SSD1289_XRES * SSD1289_YRES; i++)
+ {
+ ssd1289_gramwrite(lcd, color);
+ }
+
+ /* De-select the LCD */
+
+ lcd->deselect(lcd);
+}
+
+#endif /* CONFIG_LCD_SSD1289 */
diff --git a/nuttx/drivers/lcd/ssd1289.h b/nuttx/drivers/lcd/ssd1289.h
new file mode 100644
index 000000000..6d5d1c3cb
--- /dev/null
+++ b/nuttx/drivers/lcd/ssd1289.h
@@ -0,0 +1,425 @@
+/**************************************************************************************
+ * drivers/lcd/ssd1289.h
+ * Definitions for the Solomon Systech SSD1289 LCD controller
+ *
+ * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <gnutt@nuttx.org>
+ *
+ * References: SSD1289, Rev 1.3, Apr 2007, Solomon Systech Limited
+ *
+ * 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 __DRIVERS_LCD_SSD1289_H
+#define __DRIVERS_LCD_SSD1289_H
+
+/**************************************************************************************
+ * Included Files
+ **************************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_LCD_SSD1289
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+
+/* SSD1289 Register Addresses (All with DC=1) */
+
+#define SSD1289_OSCSTART 0x00 /* Oscillation Start (write) */
+#define SSD1289_DEVCODE 0x00 /* Oscillation Start (read) */
+#define SSD1289_OUTCTRL 0x01 /* Driver output control */
+#define SSD1289_ACCTRL 0x02 /* LCD drive AC control */
+#define SSD1289_PWRCTRL1 0x03 /* Power control 1 */
+#define SSD1289_CMP1 0x05 /* Compare register 1 */
+#define SSD1289_CMP2 0x06 /* Compare register 2 */
+#define SSD1289_DSPCTRL 0x07 /* Display control */
+#define SSD1289_FCYCCTRL 0x0b /* Frame cycle control */
+#define SSD1289_PWRCTRL2 0x0c /* Power control 2 */
+#define SSD1289_PWRCTRL3 0x0d /* Power control 3 */
+#define SSD1289_PWRCTRL4 0x0e /* Power control 4 */
+#define SSD1289_GSTART 0x0f /* Gate scan start position */
+#define SSD1289_SLEEP 0x10 /* Sleep mode */
+#define SSD1289_ENTRY 0x11 /* Entry mode */
+#define SSD1289_OPT3 0x12 /* Optimize Access Speed 3 */
+#define SSD1289_GIFCTRL 0x15 /* Generic Interface Control */
+#define SSD1289_HPORCH 0x16 /* Horizontal Porch */
+#define SSD1289_VPORCH 0x17 /* Vertical Porch */
+#define SSD1289_PWRCTRL5 0x1e /* Power control 5 */
+#define SSD1289_DATA 0x22 /* RAM data/write data */
+#define SSD1289_WRMASK1 0x23 /* RAM write data mask 1 */
+#define SSD1289_WRMASK2 0x24 /* RAM write data mask 2 */
+#define SSD1289_FFREQ 0x25 /* Frame Frequency */
+#define SSD1289_VCOMOTP1 0x28 /* VCOM OTP */
+#define SSD1289_OPT1 0x28 /* Optimize Access Speed 1 */
+#define SSD1289_VCOMOTP2 0x29 /* VCOM OTP */
+#define SSD1289_OPT2 0x2f /* Optimize Access Speed 2 */
+#define SSD1289_GAMMA1 0x30 /* Gamma control 1 */
+#define SSD1289_GAMMA2 0x31 /* Gamma control 2 */
+#define SSD1289_GAMMA3 0x32 /* Gamma control 3 */
+#define SSD1289_GAMMA4 0x33 /* Gamma control 4 */
+#define SSD1289_GAMMA5 0x34 /* Gamma control 5 */
+#define SSD1289_GAMMA6 0x35 /* Gamma control 6 */
+#define SSD1289_GAMMA7 0x36 /* Gamma control 7 */
+#define SSD1289_GAMMA8 0x37 /* Gamma control 8 */
+#define SSD1289_GAMMA9 0x3a /* Gamma control 9 */
+#define SSD1289_GAMMA10 0x3b /* Gamma control 10 */
+#define SSD1289_VSCROLL1 0x41 /* Vertical scroll control 1 */
+#define SSD1289_VSCROLL2 0x42 /* Vertical scroll control 2 */
+#define SSD1289_HADDR 0x44 /* Horizontal RAM address position */
+#define SSD1289_VSTART 0x45 /* Vertical RAM address start position */
+#define SSD1289_VEND 0x46 /* Vertical RAM address end position */
+#define SSD1289_W1START 0x48 /* First window start */
+#define SSD1289_W1END 0x49 /* First window end */
+#define SSD1289_W2START 0x4a /* Second window start */
+#define SSD1289_W2END 0x4b /* Second window end */
+#define SSD1289_XADDR 0x4e /* Set GDDRAM X address counter */
+#define SSD1289_YADDR 0x4f /* Set GDDRAM Y address counter */
+
+/* SSD1289 Register Bit definitions */
+
+/* Index register (DC=0) */
+
+#define SSD1289_INDEX_MASK 0xff
+
+/* Device code (read) */
+
+#define SSD1289_DEVCODE_VALUE 0x8989
+
+/* Oscillation Start (write) */
+
+#define SSD1289_OSCSTART_OSCEN (1 << 0) /* Enable oscillator */
+
+/* Driver output control */
+
+#define SSD1289_OUTCTRL_MUX_SHIFT (0) /* Number of lines for the LCD driver */
+#define SSD1289_OUTCTRL_MUX_MASK (0x1ff << SSD1289_OUTCTRL_MUX_SHIFT)
+# define SSD1289_OUTCTRL_MUX(n) ((n) << SSD1289_OUTCTRL_MUX_SHIFT)
+#define SSD1289_OUTCTRL_TB (1 << 9) /* Selects the output shift direction of the gate driver */
+#define SSD1289_OUTCTRL_SM (1 << 10) /* Scanning order of gate driver */
+#define SSD1289_OUTCTRL_BGR (1 << 11) /* Order from RGB to BGR in 18-bit GDDRAM data */
+#define SSD1289_OUTCTRL_CAD (1 << 12) /* Retention capacitor configuration of the TFT panel */
+#define SSD1289_OUTCTRL_REV (1 << 13) /* Reversed display */
+#define SSD1289_OUTCTRL_RL (1 << 14) /* RL pin state */
+
+/* LCD drive AC control */
+
+#define SSD1289_ACCTRL_NW_SHIFT (0) /* Number of lines to alternate in N-line inversion */
+#define SSD1289_ACCTRL_NW_MASK (0xff << SSD1289_ACCTRL_NW_SHIFT)
+#define SSD1289_ACCTRL_WSMD (1 << 8) /* Waveform of WSYNC output */
+#define SSD1289_ACCTRL_EOR (1 << 9) /* EOR signals */
+#define SSD1289_ACCTRL_BC (1 << 10) /* Select the liquid crystal drive waveform */
+#define SSD1289_ACCTRL_ENWS (1 << 11) /* Enables WSYNC output pin */
+#define SSD1289_ACCTRL_FLD (1 << 12) /* Set display in interlace drive mode */
+
+/* Power control 1 */
+
+#define SSD1289_PWRCTRL1_AP_SHIFT (1) /* Current from internal operational amplifier */
+#define SSD1289_PWRCTRL1_AP_MASK (7 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_LEAST (0 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_SMALL (1 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_SMMED (2 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_MEDIUM (3 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_MEDLG (4 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_LARGE (5 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_LGMX (6 << SSD1289_PWRCTRL1_AP_SHIFT)
+# define SSD1289_PWRCTRL1_AP_MAX (7 << SSD1289_PWRCTRL1_AP_SHIFT)
+#define SSD1289_PWRCTRL1_DC_SHIFT (4) /* Set the step-up cycle of the step-up circuit for 262k-color mode */
+#define SSD1289_PWRCTRL1_DC_MASK (15 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx24 (0 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx16 (1 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx12 (2 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx8 (3 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx6 (4 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx5 (5 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx4 (6 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx3 (7 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx2 (8 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FLINEx1 (9 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FOSd4 (10 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FOSd6 (11 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FOSd8 (12 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FOSd10 (13 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FOSd12 (14 << SSD1289_PWRCTRL1_DC_SHIFT)
+# define SSD1289_PWRCTRL1_DC_FOSd16 (15 << SSD1289_PWRCTRL1_DC_SHIFT)
+#define SSD1289_PWRCTRL1_BT_SHIFT (9) /* Control the step-up factor of the step-up circuit */
+#define SSD1289_PWRCTRL1_BT_MASK (7 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p6m5 (0 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p6m4 (1 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p6m6 (2 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p5m5 (3 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p5m4 (4 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p5m3 (5 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p4m4 (6 << SSD1289_PWRCTRL1_BT_SHIFT)
+# define SSD1289_PWRCTRL1_BT_p4m3 (7 << SSD1289_PWRCTRL1_BT_SHIFT)
+#define SSD1289_PWRCTRL1_DCT_SHIFT (12) /* Step-up cycle of the step-up circuit for 8-color mode */
+#define SSD1289_PWRCTRL1_DCT_MASK (15 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx24 (0 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx16 (1 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx12 (2 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx8 (3 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx6 (4 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx5 (5 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx4 (6 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx3 (7 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx2 (8 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FLINEx1 (9 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FOSd4 (10 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FOSd6 (11 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FOSd8 (12 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FOSd10 (13 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FOSd12 (14 << SSD1289_PWRCTRL1_DCT_SHIFT)
+# define SSD1289_PWRCTRL1_DCT_FOSd16 (15 << SSD1289_PWRCTRL1_DCT_SHIFT)
+
+/* Compare register 1 and 2 */
+
+#define SSD1289_CMP1_CPG_SHIFT (2)
+#define SSD1289_CMP1_CPG_MASK (0x3f << SSD1289_CMP1_CPG_SHIFT)
+#define SSD1289_CMP1_CPR_SHIFT (10)
+#define SSD1289_CMP1_CPR_MASK (0x3f << SSD1289_CMP1_CPR_SHIFT)
+
+#define SSD1289_CMP2_CPB_SHIFT (2)
+#define SSD1289_CMP2_CPB_MASK (0x3f << SSD1289_CMP2_CPB_SHIFT)
+
+/* Display control */
+
+#define SSD1289_DSPCTRL_D_SHIFT (0) /* Display control */
+#define SSD1289_DSPCTRL_D_MASK (3 << SSD1289_DSPCTRL_D_SHIFT)
+# define SSD1289_DSPCTRL_OFF (0 << SSD1289_DSPCTRL_D_SHIFT)
+# define SSD1289_DSPCTRL_INTERNAL (1 << SSD1289_DSPCTRL_D_SHIFT)
+# define SSD1289_DSPCTRL_ON (3 << SSD1289_DSPCTRL_D_SHIFT)
+#define SSD1289_DSPCTRL_CM (1 << 3) /* 8-color mode setting */
+#define SSD1289_DSPCTRL_DTE (1 << 4) /* Selected gate level */
+#define SSD1289_DSPCTRL_GON (1 << 5) /* Gate off level */
+#define SSD1289_DSPCTRL_SPT (1 << 8) /* 2-division LCD drive */
+#define SSD1289_DSPCTRL_VLE_SHIFT (9) /* Vertical scroll control */
+#define SSD1289_DSPCTRL_VLE_MASK (3 << SSD1289_DSPCTRL_VLE_SHIFT)
+# define SSD1289_DSPCTRL_VLE(n) ((n) << SSD1289_DSPCTRL_VLE_SHIFT)
+#define SSD1289_DSPCTRL_PT_SHIFT (11) /* Normalize the source outputs */
+#define SSD1289_DSPCTRL_PT_MASK (3 << SSD1289_DSPCTRL_PT_SHIFT)
+# define SSD1289_DSPCTRL_PT(n) ((n) << SSD1289_DSPCTRL_PT_SHIFT)
+
+/* Frame cycle control */
+
+#define SSD1289_FCYCCTRL_RTN_SHIFT (0) /* Number of clocks in each line */
+#define SSD1289_FCYCCTRL_RTN_MASK (3 << SSD1289_FCYCCTRL_RTN_SHIFT)
+# define SSD1289_FCYCCTRL_RTN(n) (((n)-16) << SSD1289_FCYCCTRL_RTN_SHIFT)
+#define SSD1289_FCYCCTRL_SRTN (1 << 4) /* When SRTN =1, RTN3-0 value will be count */
+#define SSD1289_FCYCCTRL_SDIV (1 << 5) /* When SDIV = 1, DIV1-0 value will be count */
+#define SSD1289_FCYCCTRL_DIV_SHIFT (6) /* Set the division ratio of clocks */
+#define SSD1289_FCYCCTRL_DIV_MASK (3 << SSD1289_FCYCCTRL_DIV_SHIFT)
+# define SSD1289_FCYCCTRL_DIV1 (0 << SSD1289_FCYCCTRL_DIV_SHIFT)
+# define SSD1289_FCYCCTRL_DIV2 (1 << SSD1289_FCYCCTRL_DIV_SHIFT)
+# define SSD1289_FCYCCTRL_DIV4 (2 << SSD1289_FCYCCTRL_DIV_SHIFT)
+# define SSD1289_FCYCCTRL_DIV8 (3 << SSD1289_FCYCCTRL_DIV_SHIFT)
+#define SSD1289_FCYCCTRL_EQ_SHIFT (8) /* Sets the equalizing period */
+#define SSD1289_FCYCCTRL_EQ_MASK (3 << SSD1289_FCYCCTRL_EQ_SHIFT)
+# define SSD1289_FCYCCTRL_EQ(n) (((n)-1) << SSD1289_FCYCCTRL_EQ_SHIFT) /* n = 2-8 clocks */
+#define SSD1289_FCYCCTRL_SDT_SHIFT (12) /* Set delay amount from the gate output */
+#define SSD1289_FCYCCTRL_SDT_MASK (3 << SSD1289_FCYCCTRL_SDT_SHIFT)
+# define SSD1289_FCYCCTRL_SDT(n) ((n) << SSD1289_FCYCCTRL_SDT_SHIFT) /* n = 1-3 clocks */
+#define SSD1289_FCYCCTRL_NO_SHIFT (14) /* Sets amount of non-overlap of the gate output */
+#define SSD1289_FCYCCTRL_NO_MASK (3 << SSD1289_FCYCCTRL_NO_SHIFT)
+# define SSD1289_FCYCCTRL_NO(n) ((n) << SSD1289_FCYCCTRL_NO_SHIFT) /* n = 1-3 clocks */
+
+/* Power control 2 */
+
+#define SSD1289_PWRCTRL2_VRC_SHIFT (0) /* Adjust VCIX2 output voltage */
+#define SSD1289_PWRCTRL2_VRC_MASK (7 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p1V (0 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p2V (1 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p3V (2 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p4V (3 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p5V (4 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p6V (5 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p7V (6 << SSD1289_PWRCTRL2_VRC_SHIFT)
+# define SSD1289_PWRCTRL2_VRC_5p8V (7 << SSD1289_PWRCTRL2_VRC_SHIFT)
+
+/* Power control 3 */
+
+#define SSD1289_PWRCTRL3_VRH_SHIFT (0) /* Set amplitude magnification of VLCD63 */
+#define SSD1289_PWRCTRL3_VRH_MASK (15 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x1p540 (0 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x1p620 (1 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x1p700 (2 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x1p780 (3 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x1p850 (4 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x1p930 (5 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p020 (6 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p090 (7 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p165 (8 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p245 (9 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p335 (10 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p400 (11 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p500 (12 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p570 (13 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p645 (14 << SSD1289_PWRCTRL3_VRH_SHIFT)
+# define SSD1289_PWRCTRL3_VRH_x2p725 (15 << SSD1289_PWRCTRL3_VRH_SHIFT)
+
+/* Power control 4 */
+
+#define SSD1289_PWRCTRL4_VDV_SHIFT (8) /* Set amplitude magnification of VLCD63 */
+#define SSD1289_PWRCTRL4_VDV_MASK (32 << SSD1289_PWRCTRL4_VDV_SHIFT)
+# define SSD1289_PWRCTRL4_VDV(n) ((n) << SSD1289_PWRCTRL4_VDV_SHIFT)
+#define SSD1289_PWRCTRL4_VCOMG (1 << 13) /* VcomL variable */
+
+/* Gate scan start position */
+
+#define SSD1289_GSTART_MASK 0x1ff
+
+/* Sleep mode */
+
+#define SSD1289_SLEEP_ON (1 << 0)
+
+/* Entry mode */
+
+#define SSD1289_ENTRY_LG_SHIFT (0) /* Write after comparing */
+#define SSD1289_ENTRY_LG_MASK (7 << SSD1289_ENTRY_LG_SHIFT)
+#define SSD1289_ENTRY_AM (1 << 3) /* Address counter direction */
+#define SSD1289_ENTRY_ID_SHIFT (4) /* Address increment mode */
+#define SSD1289_ENTRY_ID_MASK (3 << SSD1289_ENTRY_ID_SHIFT)
+# define SSD1289_ENTRY_ID_HDECVDEC (0 << SSD1289_ENTRY_ID_SHIFT)
+# define SSD1289_ENTRY_ID_HINCVDEC (1 << SSD1289_ENTRY_ID_SHIFT)
+# define SSD1289_ENTRY_ID_HDECVINC (2 << SSD1289_ENTRY_ID_SHIFT)
+# define SSD1289_ENTRY_ID_HINCVINC (3 << SSD1289_ENTRY_ID_SHIFT)
+#define SSD1289_ENTRY_TY_SHIFT (6) /* RAM data write method */
+#define SSD1289_ENTRY_TY_MASK (3 << SSD1289_ENTRY_TY_SHIFT)
+# define SSD1289_ENTRY_TY_A (0 << SSD1289_ENTRY_TY_SHIFT)
+# define SSD1289_ENTRY_TY_B (1 << SSD1289_ENTRY_TY_SHIFT)
+# define SSD1289_ENTRY_TY_C (2 << SSD1289_ENTRY_TY_SHIFT)
+#define SSD1289_ENTRY_DMODE_SHIFT (8) /* Data display mode */
+#define SSD1289_ENTRY_DMODE_MASK (3 << SSD1289_ENTRY_DMODE_SHIFT)
+# define SSD1289_ENTRY_DMODE_RAM (0 << SSD1289_ENTRY_DMODE_SHIFT)
+# define SSD1289_ENTRY_DMODE_GENERIC (1 << SSD1289_ENTRY_DMODE_SHIFT)
+# define SSD1289_ENTRY_DMODE_RAMGEN (2 << SSD1289_ENTRY_DMODE_SHIFT)
+# define SSD1289_ENTRY_DMODE_GENRAM (3 << SSD1289_ENTRY_DMODE_SHIFT)
+#define SSD1289_ENTRY_WMODE (1 << 10) /* Select source of data in RAM */
+#define SSD1289_ENTRY_OEDEF (1 << 11) /* Define display window */
+#define SSD1289_ENTRY_TRANS (1 << 12) /* Transparent display */
+#define SSD1289_ENTRY_DFM_SHIFT (13) /* Color display mode */
+#define SSD1289_ENTRY_DFM_MASK (3 << SSD1289_ENTRY_DFM_SHIFT)
+# define SSD1289_ENTRY_DFM_262K (2 << SSD1289_ENTRY_DFM_SHIFT)
+# define SSD1289_ENTRY_DFM_65K (3 << SSD1289_ENTRY_DFM_SHIFT)
+#define SSD1289_ENTRY_VSMODE (1 << 15) /* Frame frequency depends on VSYNC */
+
+/* Generic Interface Control */
+
+#define SSD1289_GIFCTRL_INVVS (1 << 0) /* Sets the signal polarity of DOTCLK pin */
+#define SSD1289_GIFCTRL_INVHS (1 << 1) /* Sets the signal polarity of DEN pin */
+#define SSD1289_GIFCTRL_NVDEN (1 << 2) /* Sets the signal polarity of HSYNC pin */
+#define SSD1289_GIFCTRL_INVDOT (1 << 3) /* Sets the signal polarity of VSYNC pin */
+
+/* Horizontal Porch */
+
+#define SSD1289_HPORCH_HBP_SHIFT (0) /* Set delay from falling edge of HSYNC signal to data */
+#define SSD1289_HPORCH_HBP_MASK (0xff << SSD1289_HPORCH_HBP_SHIFT)
+#define SSD1289_HPORCH_XL_SHIFT (8) /* number of valid pixel per line */
+#define SSD1289_HPORCH_XL_MASK (0xff << SSD1289_HPORCH_XL_SHIFT)
+
+/* Vertical Porch */
+
+#define SSD1289_VPORCH_VBP_SHIFT (0) /* Set delay from falling edge of VSYNC signal to line */
+#define SSD1289_VPORCH_VBP_MASK (0xff << SSD1289_VPORCH_VBP_SHIFT)
+#define SSD1289_VPORCH_XFP_SHIFT (8) /* Delay from last line to falling edge of VSYNC of next frame */
+#define SSD1289_VPORCH_XFP_MASK (0xff << SSD1289_VPORCH_XFP_SHIFT)
+#define SSD1289_VPORCH_
+
+/* Power control 5 */
+
+#define SSD1289_PWRCTRL5_VCM_SHIFT (0) /* Set the VcomH voltage */
+#define SSD1289_PWRCTRL5_VCM_MASK (0x3f << SSD1289_PWRCTRL5_VCM_SHIFT)
+# define SSD1289_PWRCTRL5_VCM(n) ((n) << SSD1289_PWRCTRL5_VCM_SHIFT)
+#define SSD1289_PWRCTRL5_NOTP (1 << 7) /* 1=VCM valid */
+
+/* RAM write data mask 1 */
+
+#define SSD1289_WRMASK1_WMG_SHIFT (2)
+#define SSD1289_WRMASK1_WMG_MASK (0x3f << SSD1289_WRMASK1_WMG_SHIFT)
+#define SSD1289_WRMASK1_WMR_SHIFT (10)
+#define SSD1289_WRMASK1_WMR_MASK (0x3f << SSD1289_WRMASK1_WMR_SHIFT)
+
+#define SSD1289_WRMASK2_WMB_SHIFT (2)
+#define SSD1289_WRMASK2_WMB_MASK (0x3f << SSD1289_WRMASK2_WMB_SHIFT)
+
+/* Frame Frequency */
+
+#define SSD1289_FFREQ_OSC_SHIFT (12) /* Set the frame frequency */
+#define SSD1289_FFREQ_OSC_MASK (15 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF50 (0 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF55 (2 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF60 (5 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF65 (8 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF70 (10 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF75 (12 << SSD1289_FFREQ_OSC_SHIFT)
+# define SSD1289_FFREQ_OSC_FF80 (14 << SSD1289_FFREQ_OSC_SHIFT)
+
+/* VCOM OTP */
+
+#define SSD1289_VCOMOTP1_ACTIVATE 0x0006
+#define SSD1289_VCOMOTP1_FIRE 0x000a
+#define SSD1289_VCOMOTP2_ACTIVATE 0x80c0
+
+/* Optimize Access Speed 1, 2, 3 (omitted) */
+
+/* Gamma control 1-10. Magic values. I won't try to represent the fields. */
+
+/* Vertical scroll control 1 and 2 */
+
+#define SSD1289_VSCROLL_MASK 0x1ff /* Scroll length */
+
+/* Horizontal RAM address position */
+
+#define SSD1289_HADDR_HSA_SHIFT (0) /* Window horizontal start address */
+#define SSD1289_HADDR_HSA_MASK (0xff << SSD1289_HADDR_HSA_SHIFT)
+#define SSD1289_HADDR_HEA_SHIFT (8) /* Window horizontal end address */
+#define SSD1289_HADDR_HEA_MASK (0xff << SSD1289_HADDR_HEA_SHIFT)
+
+/* Vertical RAM address start/end position */
+
+#define SSD1289_VSTART_MASK 0x1ff /* Window Vertical start address */
+#define SSD1289_VEND_MASK 0x1ff /* Window Vertical end address */
+
+/* First window start/end */
+
+#define SSD1289_W1START_MASK 0x1ff /* Start line for first screen */
+#define SSD1289_W1END_MASK 0x1ff /* End line for first screen */
+
+/* Second window start/end */
+
+#define SSD1289_W2START_MASK 0x1ff /* Start line for second screen */
+#define SSD1289_W2END_MASK 0x1ff /* End line for second screen */
+
+/* Set GDDRAM X/Y address counter */
+
+#define SSD1289_XADDR_MASK 0xff /* GDDRAM X address in the address counter */
+#define SSD1289_YADDR_MASK 0x1ff /* GDDRAM Y address in the address counter */
+
+#endif /* CONFIG_LCD_SSD1289 */
+#endif /* __DRIVERS_LCD_SSD1289_H */
diff --git a/nuttx/drivers/lcd/ssd1305.h b/nuttx/drivers/lcd/ssd1305.h
new file mode 100644
index 000000000..87c955de4
--- /dev/null
+++ b/nuttx/drivers/lcd/ssd1305.h
@@ -0,0 +1,211 @@
+/**************************************************************************************
+ * drivers/lcd/ssd1305.h
+ * Definitions for the Solomon Systech SSD1305 132x64 Dot Matrix OLED/PLED
+ * Segment/Common Driver with C
+ *
+ * Copyright (C) 2010 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * References: SSD1305.pdf, "Solomon Systech SSD1305 132x64 Dot Matrix OLED/PLED
+ * Segment/Common Driver with Controller," Solomon Systech Limited,
+ * http://www.solomon-systech.com, May, 2008.
+ *
+ * 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 __DRIVERS_LCD_SSD1305_H
+#define __DRIVERS_LCD_SSD1305_H
+
+/**************************************************************************************
+ * Included Files
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+/* General Definitions ******************************************************/
+
+#define SSD1305_COLORA 0
+#define SSD1305_COLORB 1
+#define SSD1305_COLORC 2
+#define SSD1305_COLORD 3
+
+/* Fundamental Commands *****************************************************/
+#define SSD1305_SETCOLL 0x00 /* 0x00-0x0f: Set lower column address */
+# define SSD1305_COLL_MASK 0x0f
+#define SSD1305_SETCOLH 0x10 /* 0x10-0x1f: Set higher column address */
+# define SSD1305_COLH_MASK 0x0f
+#define SSD1305_ADDRMODE 0x20 /* 0x20: Set memory address mode */
+# define SSD1305_ADDRMODE_HOR 0x00 /* Data 1: Set horizontal address mode */
+# define SSD1305_ADDRMODE_VIRT 0x01 /* Data 1: Set virtal address mode */
+# define SSD1305_ADDRMODE_PAGE 0x02 /* Data 1: Set page address mode */
+#define SSD1305_SETCOLADDR 0x21 /* 0x21: Set column address */
+ /* Data 1: Column start address: 0-131 */
+ /* Data 2: Column end address: 0-131 */
+#define SSD1305_SETPAGEADDR 0x22 /* 0x22: Set page address */
+ /* Data 1: Page start address: 0x00-0x7d */
+ /* Data 2: Page end address: 0x00-0x7d */
+#define SSD1305_SETSTARTLINE 0x40 /* 0x40-7f: Set display start line */
+# define SSD1305_STARTLINE_MASK 0x3f
+
+#define SSD1305_SETCONTRAST 0x81 /* 0x81: Set contrast control */
+ /* Data 1: Set 1 of 256 contrast steps */
+#define SSD1305_SETBRIGHTNESS 0x82 /* 0x82: Set brightness */
+ /* Data 1: Set 1 of 256 contrast steps */
+#define SSD1305_SETLUT 0x91 /* 0x01: Set lookup table */
+ /* Data 1: Pulse width: 31-63 */
+ /* Data 2: Color A: 31-63 */
+ /* Data 3: Color B: 31-63 */
+ /* Data 4: Color C: 31-63 */
+#define SSD1305_SETBANKCOLOR1 0x92 /* 0x92: Set bank 1-16 color */
+# define SSD1305_SETBANK1(c) (c) /* Data 1, Bits 0-1: Bank 1 color */
+# define SSD1305_SETBANK2(c) (c << 2) /* Data 1, Bits 2-3: Bank 2 color */
+# define SSD1305_SETBANK3(c) (c << 4) /* Data 1, Bits 4-5: Bank 3 color */
+# define SSD1305_SETBANK4(c) (c << 6) /* Data 1, Bits 6-7: Bank 4 color */
+# define SSD1305_SETBANK5(c) (c) /* Data 2, Bits 0-1: Bank 5 color */
+# define SSD1305_SETBANK6(c) (c << 2) /* Data 2, Bits 2-3: Bank 6 color */
+# define SSD1305_SETBANK7(c) (c << 4) /* Data 2, Bits 4-5: Bank 7 color */
+# define SSD1305_SETBANK8(c) (c << 6) /* Data 2, Bits 6-7: Bank 8 color */
+# define SSD1305_SETBANK9(c) (c) /* Data 3, Bits 0-1: Bank 9 color */
+# define SSD1305_SETBANK10(c) (c << 2) /* Data 3, Bits 2-3: Bank 10 color */
+# define SSD1305_SETBANK11(c) (c << 4) /* Data 3, Bits 4-5: Bank 11 color */
+# define SSD1305_SETBANK12(c) (c << 6) /* Data 3, Bits 6-7: Bank 12 color */
+# define SSD1305_SETBANK13(c) (c) /* Data 4, Bits 0-1: Bank 13 color */
+# define SSD1305_SETBANK14(c) (c << 2) /* Data 4, Bits 2-3: Bank 14 color */
+# define SSD1305_SETBANK15(c) (c << 4) /* Data 4, Bits 4-5: Bank 15 color */
+# define SSD1305_SETBANK16(c) (c << 6) /* Data 4, Bits 6-7: Bank 16 color */
+#define SSD1305_SETBANKCOLOR2 0x93 /* 0x93: Set bank 17-32 color */
+# define SSD1305_SETBANK17(c) (c) /* Data 1, Bits 0-1: Bank 17 color */
+# define SSD1305_SETBANK18(c) (c << 2) /* Data 1, Bits 2-3: Bank 18 color */
+# define SSD1305_SETBANK19(c) (c << 4) /* Data 1, Bits 4-5: Bank 19 color */
+# define SSD1305_SETBANK20(c) (c << 6) /* Data 1, Bits 6-7: Bank 20 color */
+# define SSD1305_SETBANK21(c) (c) /* Data 2, Bits 0-1: Bank 21 color */
+# define SSD1305_SETBANK22(c) (c << 2) /* Data 2, Bits 2-3: Bank 22 color */
+# define SSD1305_SETBANK23(c) (c << 4) /* Data 2, Bits 4-5: Bank 23 color */
+# define SSD1305_SETBANK24(c) (c << 6) /* Data 2, Bits 6-7: Bank 24 color */
+# define SSD1305_SETBANK25(c) (c) /* Data 3, Bits 0-1: Bank 25 color */
+# define SSD1305_SETBANK26(c) (c << 2) /* Data 3, Bits 2-3: Bank 26 color */
+# define SSD1305_SETBANK27(c) (c << 4) /* Data 3, Bits 4-5: Bank 27 color */
+# define SSD1305_SETBANK28(c) (c << 6) /* Data 3, Bits 6-7: Bank 28 color */
+# define SSD1305_SETBANK29(c) (c) /* Data 4, Bits 0-1: Bank 29 color */
+# define SSD1305_SETBANK30(c) (c << 2) /* Data 4, Bits 2-3: Bank 30 color */
+# define SSD1305_SETBANK31(c) (c << 4) /* Data 4, Bits 4-5: Bank 31 color */
+# define SSD1305_SETBANK32(c) (c << 6) /* Data 4, Bits 6-7: Bank 32 color */
+#define SSD1305_MAPCOL0 0xa0 /* 0xa0: Column address 0 is mapped to SEG0 */
+#define SSD1305_MAPCOL131 0xa1 /* 0xa1: Column address 131 is mapped to SEG0 */
+#define SSD1305_DISPRAM 0xa4 /* 0xa4: Resume to RAM content display */
+#define SSD1305_DISPENTIRE 0xa5 /* 0xa5: Entire display ON */
+#define SSD1305_DISPNORMAL 0xa6 /* 0xa6: Normal display */
+#define SSD1305_DISPINVERTED 0xa7 /* 0xa7: Inverse display */
+
+#define SSD1305_SETMUX 0xa8 /* 0xa8: Set Multiplex Ratio*/
+ /* Data 1: MUX ratio -1: 15-63 */
+#define SSD1305_DIMMODE 0xab /* 0xab: Dim mode setting */
+ /* Data 1: Reserverd, must be zero */
+ /* Data 2: Contrast for bank1: 0-255 */
+ /* Data 3: Brightness for color bank: 0-255 */
+#define SSD1305_MSTRCONFIG 0xad /* 0xad: Master configuration */
+# define SSD1305_MSTRCONFIG_EXTVCC 0x8e /* Data 1: Select external Vcc */
+#define SSD1305_DISPONDIM 0xac /* 0xac: Display ON in dim mode */
+#define SSD1305_DISPOFF 0xae /* 0xae: Display OFF (sleep mode) */
+#define SSD1305_DISPON 0xaf /* 0xaf: Display ON in normal mode */
+#define SSD1305_SETPAGESTART 0xb0 /* 0xb0-b7: Set page start address */
+# define SSD1305_PAGESTART_MASK 0x07
+#define SSD1305_SETCOMNORMAL 0xc0 /* 0xc0: Set COM output, normal mode */
+#define SSD1305_SETCOMREMAPPED 0xc8 /* 0xc8: Set COM output, remapped mode */
+
+#define SSD1305_SETOFFSET 0xd3 /* 0xd3: Set display offset */
+ /* Data 1: Vertical shift by COM: 0-63 */
+#define SSD1305_SETDCLK 0xd5 /* 0xd5: Set display clock divide ratio/oscillator */
+# define SSD1305_DCLKDIV_SHIFT (0) /* Data 1, Bits 0-3: DCLK divide ratio/frequency*/
+# define SSD1305_DCLKDIV_MASK 0x0f
+# define SSD1305_DCLKFREQ_SHIFT (4) /* Data 1, Bits 4-7: DCLK divide oscillator frequency */
+# define SSD1305_DCLKFREQ_MASK 0xf0
+#define SSD1305_SETCOLORMODE 0xd8 /* 0xd: Set area color and low power display modes */
+# define SSD1305_COLORMODE_MONO 0x00 /* Data 1, Bits 4-5: 00=monochrome */
+# define SSD1305_COLORMODE_COLOR 0x30 /* Data 1, Bits 4-5: 11=area color enable */
+# define SSD1305_POWERMODE_NORMAL 0x00 /* Data 1, Bits 0,2: 00=normal power mode */
+# define SSD1305_POWERMODE_LOW 0x05 /* Data 1, Bits 0,2: 11=low power display mode */
+#define SSD1305_SETPRECHARGE 0xd9 /* 0xd9: Set pre-charge period */
+# define SSD1305_PHASE1_SHIFT (0) /* Data 1, Bits 0-3: Phase 1 period of up to 15 DCLK clocks */
+# define SSD1305_PHASE1_MASK 0x0f
+# define SSD1305_PHASE2_SHIFT (4) /* Data 1, Bits 4-7: Phase 2 period of up to 15 DCLK clocks */
+# define SSD1305_PHASE2_MASK 0xf0
+#define SSD1305_SETCOMCONFIG 0xda /* 0xda: Set COM configuration */
+# define SSD1305_COMCONFIG_SEQ 0x02 /* Data 1, Bit 4: 0=Sequential COM pin configuration */
+# define SSD1305_COMCONFIG_ALT 0x12 /* Data 1, Bit 4: 1=Alternative COM pin configuration */
+# define SSD1305_COMCONFIG_NOREMAP 0x02 /* Data 1, Bit 5: 0=Disable COM Left/Right remap */
+# define SSD1305_COMCONFIG_REMAP 0x22 /* Data 1, Bit 5: 1=Enable COM Left/Right remap */
+#define SSD1305_SETVCOMHDESEL 0xdb /* 0xdb: Set VCOMH delselect level */
+# define SSD1305_VCOMH_x4p3 0x00 /* Data 1: ~0.43 x Vcc */
+# define SSD1305_VCOMH_x7p7 0x34 /* Data 1: ~0.77 x Vcc */
+# define SSD1305_VCOMH_x8p3 0x3c /* Data 1: ~0.83 x Vcc */
+#define SSD1305_ENTER_RMWMODE 0xe0 /* 0xe0: Enter the Read Modify Write mode */
+#define SSD1305_NOP 0xe3 /* 0xe3: NOP Command for no operation */
+#define SSD1305_EXIT_RMWMODE 0xee /* 0xee: Leave the Read Modify Write mode */
+
+/* Graphic Acceleration Commands ********************************************/
+
+#define SSD1305_HSCROLL_RIGHT 0x26 /* 0x26: Right horizontal scroll */
+#define SSD1305_HSCROLL_LEFT 0x27 /* 0x27: Left horizontal scroll */
+ /* Data 1, Bits 0-2: Column scroll offset: 0-4 */
+ /* Data 2, Bits 0-2: Start page address: 0-7 */
+#define SSD1305_HSCROLL_FRAMES6 0x00 /* Data 3, Bits 0-2: Timer interval, 000=6 frames */
+#define SSD1305_HSCROLL_FRAMES32 0x01 /* Data 3, Bits 0-2: Timer interval, 001=32 frames */
+#define SSD1305_HSCROLL_FRAMES64 0x02 /* Data 3, Bits 0-2: Timer interval, 010=64 frames */
+#define SSD1305_HSCROLL_FRAMES128 0x03 /* Data 3, Bits 0-2: Timer interval, 011=128 frames */
+#define SSD1305_HSCROLL_FRAMES3 0x04 /* Data 3, Bits 0-2: Timer interval, 100=3 frames */
+#define SSD1305_HSCROLL_FRAMES4 0x05 /* Data 3, Bits 0-2: Timer interval, 101=4 frames */
+#define SSD1305_HSCROLL_FRAMES2 0x06 /* Data 3, Bits 0-2: Timer interval, 110=2 frames */
+ /* Data 4, Bits 0-2: End page address: 0-7 */
+
+#define SSD1305_VSCROLL_RIGHT 0x29 /* 0x26: Vertical and right horizontal scroll */
+#define SSD1305_VSCROLL_LEFT 0x2a /* 0x27: Vertical and left horizontal scroll */
+ /* Data 1, Bits 0-2: Column scroll offset: 0-4 */
+ /* Data 2, Bits 0-2: Start page address: 0-7 */
+#define SSD1305_VSCROLL_FRAMES6 0x00 /* Data 3, Bits 0-2: Timer interval, 000=6 frames */
+#define SSD1305_VSCROLL_FRAMES32 0x01 /* Data 3, Bits 0-2: Timer interval, 001=32 frames */
+#define SSD1305_VSCROLL_FRAMES64 0x02 /* Data 3, Bits 0-2: Timer interval, 010=64 frames */
+#define SSD1305_VSCROLL_FRAMES128 0x03 /* Data 3, Bits 0-2: Timer interval, 011=128 frames */
+#define SSD1305_VSCROLL_FRAMES3 0x04 /* Data 3, Bits 0-2: Timer interval, 100=3 frames */
+#define SSD1305_VSCROLL_FRAMES4 0x05 /* Data 3, Bits 0-2: Timer interval, 101=4 frames */
+#define SSD1305_VSCROLL_FRAMES2 0x06 /* Data 3, Bits 0-2: Timer interval, 110=2 frames */
+ /* Data 4, Bits 0-2: End page address: 0-7 */
+ /* Data 5, Bits 0-5: Vertical scrolling offset: 0-63 */
+#define SSD1305_SCROLL_STOP 0x2e /* 0x2e: Deactivate scroll */
+#define SSD1305_SCROLL_START 0x2f /* 0x2f: Activate scroll */
+#define SSD1305_VSCROLL_AREA 0xa3 /* 0xa3: Set vertical scroll area */
+ /* Data 1: Number of rows in the top fixed area */
+ /* Data 1: Number of rows in the scroll area */
+
+/* Status register bit definitions ******************************************/
+
+#define SSD1305_STATUS_DISPOFF (1 << 6) /* Bit 6: 1=Display off */
+
+#endif /* __DRIVERS_LCD_SSD1305_H */
diff --git a/nuttx/drivers/lcd/ug-9664hswag01.c b/nuttx/drivers/lcd/ug-9664hswag01.c
new file mode 100644
index 000000000..bb49f20e6
--- /dev/null
+++ b/nuttx/drivers/lcd/ug-9664hswag01.c
@@ -0,0 +1,1049 @@
+/**************************************************************************************
+ * drivers/lcd/ug-9664hswag01.c
+ * Driver for the Univision UG-9664HSWAG01 Display with the Solomon Systech SSD1305 LCD
+ * controller.
+ *
+ * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
+ *
+ * Reference: "Product Specification, OEL Display Module, UG-9664HSWAG01", Univision
+ * Technology Inc., SAS1-6020-B, January 3, 2008.
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/spi.h>
+#include <nuttx/lcd/lcd.h>
+#include <nuttx/lcd/ug-9664hswag01.h>
+
+#include "ssd1305.h"
+
+/**************************************************************************************
+ * Pre-processor Definitions
+ **************************************************************************************/
+
+/* Configuration **********************************************************************/
+/* UG-9664HSWAG01 Configuration Settings:
+ *
+ * CONFIG_UG9664HSWAG01_SPIMODE - Controls the SPI mode
+ * CONFIG_UG9664HSWAG01_FREQUENCY - Define to use a different bus frequency
+ * CONFIG_UG9664HSWAG01_NINTERFACES - Specifies the number of physical
+ * UG-9664HSWAG01 devices that will be supported. NOTE: At present, this
+ * must be undefined or defined to be 1.
+ * CONFIG_UG9664HSWAG01_POWER
+ * If the hardware supports a controllable OLED a power supply, this
+ * configuration shold be defined. (See ug_power() below).
+ * CONFIG_LCD_UGDEBUG - Enable detailed UG-9664HSWAG01 debug output
+ * (CONFIG_DEBUG and CONFIG_VERBOSE must also be enabled).
+ *
+ * Required LCD driver settings:
+ * CONFIG_LCD_UG9664HSWAG01 - Enable UG-9664HSWAG01 support
+ * CONFIG_LCD_MAXCONTRAST should be 255, but any value >0 and <=255 will be accepted.
+ * CONFIG_LCD_MAXPOWER should be 2: 0=off, 1=dim, 2=normal
+ *
+ * Required SPI driver settings:
+ * CONFIG_SPI_CMDDATA - Include support for cmd/data selection.
+ */
+
+/* Verify that all configuration requirements have been met */
+
+/* The UG-9664HSWAG01 spec says that is supports SPI mode 0,0 only. However, somtimes
+ * you need to tinker with these things.
+ */
+
+#ifndef CONFIG_UG9664HSWAG01_SPIMODE
+# define CONFIG_UG9664HSWAG01_SPIMODE SPIDEV_MODE0
+#endif
+
+/* SPI frequency */
+
+#ifndef CONFIG_UG9664HSWAG01_FREQUENCY
+# define CONFIG_UG9664HSWAG01_FREQUENCY 3500000
+#endif
+
+/* CONFIG_UG9664HSWAG01_NINTERFACES determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#ifndef CONFIG_UG9664HSWAG01_NINTERFACES
+# define CONFIG_UG9664HSWAG01_NINTERFACES 1
+#endif
+
+#if CONFIG_UG9664HSWAG01_NINTERFACES != 1
+# warning "Only a single UG-9664HSWAG01 interface is supported"
+# undef CONFIG_UG9664HSWAG01_NINTERFACES
+# define CONFIG_UG9664HSWAG01_NINTERFACES 1
+#endif
+
+/* Verbose debug must also be enabled to use the extra OLED debug */
+
+#ifndef CONFIG_DEBUG
+# undef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_DEBUG_GRAPHICS
+#endif
+
+#ifndef CONFIG_DEBUG_VERBOSE
+# undef CONFIG_LCD_UGDEBUG
+#endif
+
+/* Check contrast selection */
+
+#ifndef CONFIG_LCD_MAXCONTRAST
+# define CONFIG_LCD_MAXCONTRAST 255
+#endif
+
+#if CONFIG_LCD_MAXCONTRAST <= 0 || CONFIG_LCD_MAXCONTRAST > 255
+# error "CONFIG_LCD_MAXCONTRAST exceeds supported maximum"
+#endif
+
+#if CONFIG_LCD_MAXCONTRAST < 255
+# warning "Optimal setting of CONFIG_LCD_MAXCONTRAST is 255"
+#endif
+
+/* Check power setting */
+
+#if !defined(CONFIG_LCD_MAXPOWER)
+# define CONFIG_LCD_MAXPOWER 2
+#endif
+
+#if CONFIG_LCD_MAXPOWER != 2
+# warning "CONFIG_LCD_MAXPOWER should be 2"
+# undef CONFIG_LCD_MAXPOWER
+# define CONFIG_LCD_MAXPOWER 2
+#endif
+
+/* The OLED requires CMD/DATA SPI support */
+
+#ifndef CONFIG_SPI_CMDDATA
+# error "CONFIG_SPI_CMDDATA must be defined in your NuttX configuration"
+#endif
+
+/* Color is 1bpp monochrome with leftmost column contained in bits 0 */
+
+#ifdef CONFIG_NX_DISABLE_1BPP
+# warning "1 bit-per-pixel support needed"
+#endif
+
+/* Color Properties *******************************************************************/
+/* The SSD1305 display controller can handle a resolution of 132x64. The OLED
+ * on the base board is 96x64.
+ */
+
+#define UG_DEV_XRES 132
+#define UG_XOFFSET 18
+
+/* Display Resolution */
+
+#define UG_XRES 96
+#define UG_YRES 64
+
+/* Color depth and format */
+
+#define UG_BPP 1
+#define UG_COLORFMT FB_FMT_Y1
+
+/* Bytes per logical row andactual device row */
+
+#define UG_XSTRIDE (UG_XRES >> 3) /* Pixels arrange "horizontally for user" */
+#define UG_YSTRIDE (UG_YRES >> 3) /* But actual device arrangement is "vertical" */
+
+/* The size of the shadow frame buffer */
+
+#define UG_FBSIZE (UG_XRES * UG_YSTRIDE)
+
+/* Bit helpers */
+
+#define LS_BIT (1 << 0)
+#define MS_BIT (1 << 7)
+
+/* Debug ******************************************************************************/
+
+#ifdef CONFIG_LCD_UGDEBUG
+# define ugdbg(format, arg...) vdbg(format, ##arg)
+#else
+# define ugdbg(x...)
+#endif
+
+/**************************************************************************************
+ * Private Type Definition
+ **************************************************************************************/
+
+/* This structure describes the state of this driver */
+
+struct ug_dev_s
+{
+ /* Publically visible device structure */
+
+ struct lcd_dev_s dev;
+
+ /* Private LCD-specific information follows */
+
+ FAR struct spi_dev_s *spi;
+ uint8_t contrast;
+ uint8_t powered;
+
+ /* The SSD1305 does not support reading from the display memory in SPI mode.
+ * Since there is 1 BPP and access is byte-by-byte, it is necessary to keep
+ * a shadow copy of the framebuffer memory.
+ */
+
+ uint8_t fb[UG_FBSIZE];
+};
+
+/**************************************************************************************
+ * Private Function Protototypes
+ **************************************************************************************/
+
+/* SPI helpers */
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void ug_select(FAR struct spi_dev_s *spi);
+static inline void ug_deselect(FAR struct spi_dev_s *spi);
+#else
+static void ug_select(FAR struct spi_dev_s *spi);
+static void ug_deselect(FAR struct spi_dev_s *spi);
+#endif
+
+/* LCD Data Transfer Methods */
+
+static int ug_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels);
+static int ug_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels);
+
+/* LCD Configuration */
+
+static int ug_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo);
+static int ug_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo);
+
+/* LCD RGB Mapping */
+
+#ifdef CONFIG_FB_CMAP
+# error "RGB color mapping not supported by this driver"
+#endif
+
+/* Cursor Controls */
+
+#ifdef CONFIG_FB_HWCURSOR
+# error "Cursor control not supported by this driver"
+#endif
+
+/* LCD Specific Controls */
+
+static int ug_getpower(struct lcd_dev_s *dev);
+static int ug_setpower(struct lcd_dev_s *dev, int power);
+static int ug_getcontrast(struct lcd_dev_s *dev);
+static int ug_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
+
+/* Initialization */
+
+static inline void up_clear(FAR struct ug_dev_s *priv);
+
+/**************************************************************************************
+ * Private Data
+ **************************************************************************************/
+
+/* This is working memory allocated by the LCD driver for each LCD device
+ * and for each color plane. This memory will hold one raster line of data.
+ * The size of the allocated run buffer must therefore be at least
+ * (bpp * xres / 8). Actual alignment of the buffer must conform to the
+ * bitwidth of the underlying pixel type.
+ *
+ * If there are multiple planes, they may share the same working buffer
+ * because different planes will not be operate on concurrently. However,
+ * if there are multiple LCD devices, they must each have unique run buffers.
+ */
+
+static uint8_t g_runbuffer[UG_XSTRIDE+1];
+
+/* This structure describes the overall LCD video controller */
+
+static const struct fb_videoinfo_s g_videoinfo =
+{
+ .fmt = UG_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */
+ .xres = UG_XRES, /* Horizontal resolution in pixel columns */
+ .yres = UG_YRES, /* Vertical resolution in pixel rows */
+ .nplanes = 1, /* Number of color planes supported */
+};
+
+/* This is the standard, NuttX Plane information object */
+
+static const struct lcd_planeinfo_s g_planeinfo =
+{
+ .putrun = ug_putrun, /* Put a run into LCD memory */
+ .getrun = ug_getrun, /* Get a run from LCD memory */
+ .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */
+ .bpp = UG_BPP, /* Bits-per-pixel */
+};
+
+/* This is the standard, NuttX LCD driver object */
+
+static struct ug_dev_s g_ugdev =
+{
+ .dev =
+ {
+ /* LCD Configuration */
+
+ .getvideoinfo = ug_getvideoinfo,
+ .getplaneinfo = ug_getplaneinfo,
+
+ /* LCD RGB Mapping -- Not supported */
+ /* Cursor Controls -- Not supported */
+
+ /* LCD Specific Controls */
+
+ .getpower = ug_getpower,
+ .setpower = ug_setpower,
+ .getcontrast = ug_getcontrast,
+ .setcontrast = ug_setcontrast,
+ },
+};
+
+/**************************************************************************************
+ * Private Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: ug_powerstring
+ *
+ * Description:
+ * Convert the power setting to a string.
+ *
+ **************************************************************************************/
+
+
+static inline FAR const char *ug_powerstring(uint8_t power)
+{
+ if (power == UG_POWER_OFF)
+ {
+ return "OFF";
+ }
+ else if (power == UG_POWER_DIM)
+ {
+ return "DIM";
+ }
+ else if (power == UG_POWER_ON)
+ {
+ return "ON";
+ }
+ else
+ {
+ return "ERROR";
+ }
+}
+
+/**************************************************************************************
+ * Function: ug_select
+ *
+ * Description:
+ * Select the SPI, locking and re-configuring if necessary
+ *
+ * Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void ug_select(FAR struct spi_dev_s *spi)
+{
+ /* We own the SPI bus, so just select the chip */
+
+ SPI_SELECT(spi, SPIDEV_DISPLAY, true);
+}
+#else
+static void ug_select(FAR struct spi_dev_s *spi)
+{
+ /* Select UG-9664HSWAG01 chip (locking the SPI bus in case there are multiple
+ * devices competing for the SPI bus
+ */
+
+ SPI_LOCK(spi, true);
+ SPI_SELECT(spi, SPIDEV_DISPLAY, true);
+
+ /* Now make sure that the SPI bus is configured for the UG-9664HSWAG01 (it
+ * might have gotten configured for a different device while unlocked)
+ */
+
+ SPI_SETMODE(spi, CONFIG_UG9664HSWAG01_SPIMODE);
+ SPI_SETBITS(spi, 8);
+#ifdef CONFIG_UG9664HSWAG01_FREQUENCY
+ SPI_SETFREQUENCY(spi, CONFIG_UG9664HSWAG01_FREQUENCY);
+#endif
+}
+#endif
+
+/**************************************************************************************
+ * Function: ug_deselect
+ *
+ * Description:
+ * De-select the SPI
+ *
+ * Parameters:
+ * spi - Reference to the SPI driver structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ **************************************************************************************/
+
+#ifdef CONFIG_SPI_OWNBUS
+static inline void ug_deselect(FAR struct spi_dev_s *spi)
+{
+ /* We own the SPI bus, so just de-select the chip */
+
+ SPI_SELECT(spi, SPIDEV_DISPLAY, false);
+}
+#else
+static void ug_deselect(FAR struct spi_dev_s *spi)
+{
+ /* De-select UG-9664HSWAG01 chip and relinquish the SPI bus. */
+
+ SPI_SELECT(spi, SPIDEV_DISPLAY, false);
+ SPI_LOCK(spi, false);
+}
+#endif
+
+/**************************************************************************************
+ * Name: ug_putrun
+ *
+ * Description:
+ * This method can be used to write a partial raster line to the LCD:
+ *
+ * row - Starting row to write to (range: 0 <= row < yres)
+ * col - Starting column to write to (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer containing the run to be written to the LCD
+ * npixels - The number of pixels to write to the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int ug_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer,
+ size_t npixels)
+{
+ /* Because of this line of code, we will only be able to support a single UG device */
+
+ FAR struct ug_dev_s *priv = &g_ugdev;
+ FAR uint8_t *fbptr;
+ FAR uint8_t *ptr;
+ uint8_t devcol;
+ uint8_t fbmask;
+ uint8_t page;
+ uint8_t usrmask;
+ uint8_t i;
+ int pixlen;
+
+ gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer);
+
+ /* Clip the run to the display */
+
+ pixlen = npixels;
+ if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG_XRES)
+ {
+ pixlen = (int)UG_XRES - (int)col;
+ }
+
+ /* Verify that some portion of the run remains on the display */
+
+ if (pixlen <= 0 || row > UG_YRES)
+ {
+ return OK;
+ }
+
+ /* Get the page number. The range of 64 lines is divided up into eight
+ * pages of 8 lines each.
+ */
+
+ page = row >> 3;
+
+ /* Update the shadow frame buffer memory. First determine the pixel
+ * position in the frame buffer memory. Pixels are organized like
+ * this:
+ *
+ * --------+---+---+---+---+-...-+-----+
+ * Segment | 0 | 1 | 2 | 3 | ... | 131 |
+ * --------+---+---+---+---+-...-+-----+
+ * Bit 0 | | X | | | | |
+ * Bit 1 | | X | | | | |
+ * Bit 2 | | X | | | | |
+ * Bit 3 | | X | | | | |
+ * Bit 4 | | X | | | | |
+ * Bit 5 | | X | | | | |
+ * Bit 6 | | X | | | | |
+ * Bit 7 | | X | | | | |
+ * --------+---+---+---+---+-...-+-----+
+ *
+ * So, in order to draw a white, horizontal line, at row 45. we
+ * would have to modify all of the bytes in page 45/8 = 5. We
+ * would have to set bit 45%8 = 5 in every byte in the page.
+ */
+
+ fbmask = 1 << (row & 7);
+ fbptr = &priv->fb[page * UG_XRES + col];
+ ptr = fbptr;
+#ifdef CONFIG_NX_PACKEDMSFIRST
+ usrmask = MS_BIT;
+#else
+ usrmask = LS_BIT;
+#endif
+
+ for (i = 0; i < pixlen; i++)
+ {
+ /* Set or clear the corresponding bit */
+
+ if ((*buffer & usrmask) != 0)
+ {
+ *ptr++ |= fbmask;
+ }
+ else
+ {
+ *ptr++ &= ~fbmask;
+ }
+
+ /* Inc/Decrement to the next source pixel */
+
+#ifdef CONFIG_NX_PACKEDMSFIRST
+ if (usrmask == LS_BIT)
+ {
+ buffer++;
+ usrmask = MS_BIT;
+ }
+ else
+ {
+ usrmask >>= 1;
+ }
+#else
+ if (usrmask == MS_BIT)
+ {
+ buffer++;
+ usrmask = LS_BIT;
+ }
+ else
+ {
+ usrmask <<= 1;
+ }
+#endif
+ }
+
+ /* Offset the column position to account for smaller horizontal
+ * display range.
+ */
+
+ devcol = col + UG_XOFFSET;
+
+ /* Select and lock the device */
+
+ ug_select(priv->spi);
+
+ /* Select command transfer */
+
+ SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true);
+
+ /* Set the starting position for the run */
+
+ (void)SPI_SEND(priv->spi, SSD1305_SETPAGESTART+page); /* Set the page start */
+ (void)SPI_SEND(priv->spi, SSD1305_SETCOLL + (devcol & 0x0f)); /* Set the low column */
+ (void)SPI_SEND(priv->spi, SSD1305_SETCOLH + (devcol >> 4)); /* Set the high column */
+
+ /* Select data transfer */
+
+ SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, false);
+
+ /* Then transfer all of the data */
+
+ (void)SPI_SNDBLOCK(priv->spi, fbptr, pixlen);
+
+ /* Unlock and de-select the device */
+
+ ug_deselect(priv->spi);
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ug_getrun
+ *
+ * Description:
+ * This method can be used to read a partial raster line from the LCD:
+ *
+ * row - Starting row to read from (range: 0 <= row < yres)
+ * col - Starting column to read read (range: 0 <= col <= xres-npixels)
+ * buffer - The buffer in which to return the run read from the LCD
+ * npixels - The number of pixels to read from the LCD
+ * (range: 0 < npixels <= xres-col)
+ *
+ **************************************************************************************/
+
+static int ug_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer,
+ size_t npixels)
+{
+ /* Because of this line of code, we will only be able to support a single UG device */
+
+ FAR struct ug_dev_s *priv = &g_ugdev;
+ FAR uint8_t *fbptr;
+ uint8_t page;
+ uint8_t fbmask;
+ uint8_t usrmask;
+ uint8_t i;
+ int pixlen;
+
+ gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels);
+ DEBUGASSERT(buffer);
+
+ /* Clip the run to the display */
+
+ pixlen = npixels;
+ if ((unsigned int)col + (unsigned int)pixlen > (unsigned int)UG_XRES)
+ {
+ pixlen = (int)UG_XRES - (int)col;
+ }
+
+ /* Verify that some portion of the run is actually the display */
+
+ if (pixlen <= 0 || row > UG_YRES)
+ {
+ return -EINVAL;
+ }
+
+ /* Then transfer the display data from the shadow frame buffer memory */
+ /* Get the page number. The range of 64 lines is divided up into eight
+ * pages of 8 lines each.
+ */
+
+ page = row >> 3;
+
+ /* Update the shadow frame buffer memory. First determine the pixel
+ * position in the frame buffer memory. Pixels are organized like
+ * this:
+ *
+ * --------+---+---+---+---+-...-+-----+
+ * Segment | 0 | 1 | 2 | 3 | ... | 131 |
+ * --------+---+---+---+---+-...-+-----+
+ * Bit 0 | | X | | | | |
+ * Bit 1 | | X | | | | |
+ * Bit 2 | | X | | | | |
+ * Bit 3 | | X | | | | |
+ * Bit 4 | | X | | | | |
+ * Bit 5 | | X | | | | |
+ * Bit 6 | | X | | | | |
+ * Bit 7 | | X | | | | |
+ * --------+---+---+---+---+-...-+-----+
+ *
+ * So, in order to draw a white, horizontal line, at row 45. we
+ * would have to modify all of the bytes in page 45/8 = 5. We
+ * would have to set bit 45%8 = 5 in every byte in the page.
+ */
+
+ fbmask = 1 << (row & 7);
+ fbptr = &priv->fb[page * UG_XRES + col];
+#ifdef CONFIG_NX_PACKEDMSFIRST
+ usrmask = MS_BIT;
+#else
+ usrmask = LS_BIT;
+#endif
+
+ *buffer = 0;
+ for (i = 0; i < pixlen; i++)
+ {
+ /* Set or clear the corresponding bit */
+
+ uint8_t byte = *fbptr++;
+ if ((byte & fbmask) != 0)
+ {
+ *buffer |= usrmask;
+ }
+
+ /* Inc/Decrement to the next destination pixel. Hmmmm. It looks like
+ * this logic could write past the end of the user buffer. Revisit
+ * this!
+ */
+
+#ifdef CONFIG_NX_PACKEDMSFIRST
+ if (usrmask == LS_BIT)
+ {
+ buffer++;
+ *buffer = 0;
+ usrmask = MS_BIT;
+ }
+ else
+ {
+ usrmask >>= 1;
+ }
+#else
+ if (usrmask == MS_BIT)
+ {
+ buffer++;
+ *buffer = 0;
+ usrmask = LS_BIT;
+ }
+ else
+ {
+ usrmask <<= 1;
+ }
+#endif
+ }
+
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ug_getvideoinfo
+ *
+ * Description:
+ * Get information about the LCD video controller configuration.
+ *
+ **************************************************************************************/
+
+static int ug_getvideoinfo(FAR struct lcd_dev_s *dev,
+ FAR struct fb_videoinfo_s *vinfo)
+{
+ DEBUGASSERT(dev && vinfo);
+ gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n",
+ g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes);
+ memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ug_getplaneinfo
+ *
+ * Description:
+ * Get information about the configuration of each LCD color plane.
+ *
+ **************************************************************************************/
+
+static int ug_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
+ FAR struct lcd_planeinfo_s *pinfo)
+{
+ DEBUGASSERT(dev && pinfo && planeno == 0);
+ gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
+ memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ug_getpower
+ *
+ * Description:
+ * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int ug_getpower(struct lcd_dev_s *dev)
+{
+ struct ug_dev_s *priv = (struct ug_dev_s *)dev;
+ DEBUGASSERT(priv);
+ gvdbg("powered: %s\n", ug_powerstring(priv->powered));
+ return priv->powered;
+}
+
+/**************************************************************************************
+ * Name: ug_setpower
+ *
+ * Description:
+ * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On
+ * backlit LCDs, this setting may correspond to the backlight setting.
+ *
+ **************************************************************************************/
+
+static int ug_setpower(struct lcd_dev_s *dev, int power)
+{
+ struct ug_dev_s *priv = (struct ug_dev_s *)dev;
+
+ DEBUGASSERT(priv && (unsigned)power <= CONFIG_LCD_MAXPOWER);
+ gvdbg("power: %s powered: %s\n",
+ ug_powerstring(power), ug_powerstring(priv->powered));
+
+ /* Select and lock the device */
+
+ ug_select(priv->spi);
+ if (power <= UG_POWER_OFF)
+ {
+ /* Turn the display off */
+
+ (void)SPI_SEND(priv->spi, SSD1305_DISPOFF); /* Display off */
+
+ /* Remove power to the device */
+
+ ug_power(0, false);
+ priv->powered = UG_POWER_OFF;
+ }
+ else
+ {
+ /* Turn the display on, dim or normal */
+
+ if (power == UG_POWER_DIM)
+ {
+ (void)SPI_SEND(priv->spi, SSD1305_DISPONDIM); /* Display on, dim mode */
+ }
+ else /* if (power > UG_POWER_DIM) */
+ {
+ (void)SPI_SEND(priv->spi, SSD1305_DISPON); /* Display on, normal mode */
+ power = UG_POWER_ON;
+ }
+ (void)SPI_SEND(priv->spi, SSD1305_DISPRAM); /* Resume to RAM content display */
+
+ /* Restore power to the device */
+
+ ug_power(0, true);
+ priv->powered = power;
+ }
+ ug_deselect(priv->spi);
+
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: ug_getcontrast
+ *
+ * Description:
+ * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int ug_getcontrast(struct lcd_dev_s *dev)
+{
+ struct ug_dev_s *priv = (struct ug_dev_s *)dev;
+ DEBUGASSERT(priv);
+ return (int)priv->contrast;
+}
+
+/**************************************************************************************
+ * Name: ug_setcontrast
+ *
+ * Description:
+ * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
+ *
+ **************************************************************************************/
+
+static int ug_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
+{
+ struct ug_dev_s *priv = (struct ug_dev_s *)dev;
+
+ gvdbg("contrast: %d\n", contrast);
+ DEBUGASSERT(priv);
+
+ if (contrast > 255)
+ {
+ return -EINVAL;
+ }
+
+ /* Select and lock the device */
+
+ ug_select(priv->spi);
+
+ /* Select command transfer */
+
+ SPI_CMDDATA(priv->spi, SPIDEV_DISPLAY, true);
+
+ /* Set the contrast */
+
+ (void)SPI_SEND(priv->spi, SSD1305_SETCONTRAST); /* Set contrast control register */
+ (void)SPI_SEND(priv->spi, contrast); /* Data 1: Set 1 of 256 contrast steps */
+ priv->contrast = contrast;
+
+ /* Unlock and de-select the device */
+
+ ug_deselect(priv->spi);
+ return OK;
+}
+
+/**************************************************************************************
+ * Name: up_clear
+ *
+ * Description:
+ * Clear the display.
+ *
+ **************************************************************************************/
+
+static inline void up_clear(FAR struct ug_dev_s *priv)
+{
+ FAR struct spi_dev_s *spi = priv->spi;
+ int page;
+ int i;
+
+ /* Clear the framebuffer */
+
+ memset(priv->fb, UG_Y1_BLACK, UG_FBSIZE);
+
+ /* Select and lock the device */
+
+ ug_select(priv->spi);
+
+ /* Go through all 8 pages */
+
+ for (page = 0, i = 0; i < 8; i++)
+ {
+ /* Select command transfer */
+
+ SPI_CMDDATA(spi, SPIDEV_DISPLAY, true);
+
+ /* Set the starting position for the run */
+
+ (void)SPI_SEND(priv->spi, SSD1305_SETPAGESTART+i);
+ (void)SPI_SEND(priv->spi, SSD1305_SETCOLL + (UG_XOFFSET & 0x0f));
+ (void)SPI_SEND(priv->spi, SSD1305_SETCOLH + (UG_XOFFSET >> 4));
+
+ /* Select data transfer */
+
+ SPI_CMDDATA(spi, SPIDEV_DISPLAY, false);
+
+ /* Then transfer all 96 columns of data */
+
+ (void)SPI_SNDBLOCK(priv->spi, &priv->fb[page * UG_XRES], UG_XRES);
+ }
+
+ /* Unlock and de-select the device */
+
+ ug_deselect(spi);
+}
+
+/**************************************************************************************
+ * Public Functions
+ **************************************************************************************/
+
+/**************************************************************************************
+ * Name: ug_initialize
+ *
+ * Description:
+ * Initialize the UG-9664HSWAG01 video hardware. The initial state of the
+ * OLED is fully initialized, display memory cleared, and the OLED ready to
+ * use, but with the power setting at 0 (full off == sleep mode).
+ *
+ * Input Parameters:
+ *
+ * spi - A reference to the SPI driver instance.
+ * devno - A value in the range of 0 through CONFIG_UG9664HSWAG01_NINTERFACES-1.
+ * This allows support for multiple OLED devices.
+ *
+ * Returned Value:
+ *
+ * On success, this function returns a reference to the LCD object for the specified
+ * OLED. NULL is returned on any failure.
+ *
+ **************************************************************************************/
+
+FAR struct lcd_dev_s *ug_initialize(FAR struct spi_dev_s *spi, unsigned int devno)
+{
+ /* Configure and enable LCD */
+
+ FAR struct ug_dev_s *priv = &g_ugdev;
+
+ gvdbg("Initializing\n");
+ DEBUGASSERT(spi && devno == 0);
+
+ /* Save the reference to the SPI device */
+
+ priv->spi = spi;
+
+ /* Select and lock the device */
+
+ ug_select(spi);
+
+ /* Make sure that the OLED off */
+
+ ug_power(0, false);
+
+ /* Select command transfer */
+
+ SPI_CMDDATA(spi, SPIDEV_DISPLAY, true);
+
+ /* Set the starting position for the run */
+
+ (void)SPI_SEND(spi, SSD1305_SETCOLL + 2); /* Set low column address */
+ (void)SPI_SEND(spi, SSD1305_SETCOLH + 2); /* Set high column address */
+ (void)SPI_SEND(spi, SSD1305_SETSTARTLINE+0); /* Display start set */
+ (void)SPI_SEND(spi, SSD1305_SCROLL_STOP); /* Stop horizontal scroll */
+ (void)SPI_SEND(spi, SSD1305_SETCONTRAST); /* Set contrast control register */
+ (void)SPI_SEND(spi, 0x32); /* Data 1: Set 1 of 256 contrast steps */
+ (void)SPI_SEND(spi, SSD1305_SETBRIGHTNESS); /* Brightness for color bank */
+ (void)SPI_SEND(spi, 0x80); /* Data 1: Set 1 of 256 contrast steps */
+ (void)SPI_SEND(spi, SSD1305_MAPCOL131); /* Set segment re-map */
+ (void)SPI_SEND(spi, SSD1305_DISPNORMAL); /* Set normal display */
+/*(void)SPI_SEND(spi, SSD1305_DISPINVERTED); Set inverse display */
+ (void)SPI_SEND(spi, SSD1305_SETMUX); /* Set multiplex ratio */
+ (void)SPI_SEND(spi, 0x3f); /* Data 1: MUX ratio -1: 15-63 */
+ (void)SPI_SEND(spi, SSD1305_SETOFFSET); /* Set display offset */
+ (void)SPI_SEND(spi, 0x40); /* Data 1: Vertical shift by COM: 0-63 */
+ (void)SPI_SEND(spi, SSD1305_MSTRCONFIG); /* Set dc-dc on/off */
+ (void)SPI_SEND(spi, SSD1305_MSTRCONFIG_EXTVCC); /* Data 1: Select external Vcc */
+ (void)SPI_SEND(spi, SSD1305_SETCOMREMAPPED); /* Set com output scan direction */
+ (void)SPI_SEND(spi, SSD1305_SETDCLK); /* Set display clock divide
+ * ratio/oscillator/frequency */
+ (void)SPI_SEND(spi, 15 << SSD1305_DCLKFREQ_SHIFT | 0 << SSD1305_DCLKDIV_SHIFT);
+ (void)SPI_SEND(spi, SSD1305_SETCOLORMODE); /* Set area color mode on/off & low power
+ * display mode */
+ (void)SPI_SEND(spi, SSD1305_COLORMODE_MONO | SSD1305_POWERMODE_LOW);
+ (void)SPI_SEND(spi, SSD1305_SETPRECHARGE); /* Set pre-charge period */
+ (void)SPI_SEND(spi, 15 << SSD1305_PHASE2_SHIFT | 1 << SSD1305_PHASE1_SHIFT);
+ (void)SPI_SEND(spi, SSD1305_SETCOMCONFIG); /* Set COM configuration */
+ (void)SPI_SEND(spi, SSD1305_COMCONFIG_ALT); /* Data 1, Bit 4: 1=Alternative COM pin configuration */
+ (void)SPI_SEND(spi, SSD1305_SETVCOMHDESEL); /* Set VCOMH deselect level */
+ (void)SPI_SEND(spi, SSD1305_VCOMH_x7p7); /* Data 1: ~0.77 x Vcc */
+ (void)SPI_SEND(spi, SSD1305_SETLUT); /* Set look up table for area color */
+ (void)SPI_SEND(spi, 0x3f); /* Data 1: Pulse width: 31-63 */
+ (void)SPI_SEND(spi, 0x3f); /* Data 2: Color A: 31-63 */
+ (void)SPI_SEND(spi, 0x3f); /* Data 3: Color B: 31-63 */
+ (void)SPI_SEND(spi, 0x3f); /* Data 4: Color C: 31-63 */
+ (void)SPI_SEND(spi, SSD1305_DISPON); /* Display on, normal mode */
+ (void)SPI_SEND(spi, SSD1305_DISPRAM); /* Resume to RAM content display */
+
+ /* Let go of the SPI lock and de-select the device */
+
+ ug_deselect(spi);
+
+ /* Clear the framebuffer */
+
+ up_mdelay(100);
+ up_clear(priv);
+ return &priv->dev;
+}