From 57623d42ebb04f0a0b9e6eb7c0847a3ece2aa0ff Mon Sep 17 00:00:00 2001 From: patacongo Date: Mon, 17 Sep 2012 18:18:44 +0000 Subject: Resync new repository with old repo r5166 git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/drivers/lcd/Kconfig | 214 ++++++ nuttx/drivers/lcd/Make.defs | 68 ++ nuttx/drivers/lcd/README.txt | 165 +++++ nuttx/drivers/lcd/mio283qt2.c | 1014 ++++++++++++++++++++++++++++ nuttx/drivers/lcd/nokia6100.c | 1230 ++++++++++++++++++++++++++++++++++ nuttx/drivers/lcd/p14201.c | 1246 +++++++++++++++++++++++++++++++++++ nuttx/drivers/lcd/pcf8833.h | 152 +++++ nuttx/drivers/lcd/s1d15g10.h | 141 ++++ nuttx/drivers/lcd/sd1329.h | 527 +++++++++++++++ nuttx/drivers/lcd/skeleton.c | 401 +++++++++++ nuttx/drivers/lcd/ssd1289.c | 1279 ++++++++++++++++++++++++++++++++++++ nuttx/drivers/lcd/ssd1289.h | 425 ++++++++++++ nuttx/drivers/lcd/ssd1305.h | 211 ++++++ nuttx/drivers/lcd/ug-9664hswag01.c | 1049 +++++++++++++++++++++++++++++ 14 files changed, 8122 insertions(+) create mode 100644 nuttx/drivers/lcd/Kconfig create mode 100644 nuttx/drivers/lcd/Make.defs create mode 100644 nuttx/drivers/lcd/README.txt create mode 100644 nuttx/drivers/lcd/mio283qt2.c create mode 100644 nuttx/drivers/lcd/nokia6100.c create mode 100644 nuttx/drivers/lcd/p14201.c create mode 100644 nuttx/drivers/lcd/pcf8833.h create mode 100644 nuttx/drivers/lcd/s1d15g10.h create mode 100644 nuttx/drivers/lcd/sd1329.h create mode 100644 nuttx/drivers/lcd/skeleton.c create mode 100644 nuttx/drivers/lcd/ssd1289.c create mode 100644 nuttx/drivers/lcd/ssd1289.h create mode 100644 nuttx/drivers/lcd/ssd1305.h create mode 100644 nuttx/drivers/lcd/ug-9664hswag01.c (limited to 'nuttx/drivers/lcd') diff --git a/nuttx/drivers/lcd/Kconfig b/nuttx/drivers/lcd/Kconfig new file mode 100644 index 000000000..081a79c89 --- /dev/null +++ b/nuttx/drivers/lcd/Kconfig @@ -0,0 +1,214 @@ +# +# 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. + +choice + prompt "LCD Orientation" + default LCD_LANDSCAPE + depends on LCD + ---help--- + Some LCD drivers may support displays in different orientations. + If the LCD driver supports this capability, than these are configuration + options to select that display orientation. + +config LCD_LANDSCAPE + bool "Landscape orientation" + ---help--- + Define for "landscape" orientation support. Landscape mode refers one + of two orientations where the the display is wider than it is tall + (LCD_RLANDSCAPE is the other). This is the default orientation. + +config LCD_PORTRAIT + bool "Portrait orientation" + ---help--- + Define for "portrait" orientation support. Portrait mode refers one + of two orientations where the the display is taller than it is wide + (LCD_RPORTAIT is the other). + +config LCD_RPORTRAIT + bool "Reverse portrait display" + ---help--- + Define for "reverse portrait" orientation support. Reverse portrait mode + refers one of two orientations where the the display is taller than it is + wide (LCD_PORTAIT is the other). + +config LCD_RLANDSCAPE + bool "Reverse landscape orientation" + ---help--- + Define for "reverse landscape" orientation support. Reverse landscape mode + refers one of two orientations where the the display is wider than it is + tall (LCD_LANDSCAPE is the other). + +endchoice 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 +# +# 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//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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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..7354b8a91 --- /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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#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..36dc65ac3 --- /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 + * + * 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..9b5f7738f --- /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 + * + * 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 + * + * 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 +#include + +/**************************************************************************** + * 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..83aa92018 --- /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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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 + * + * 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 + +#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..34678fa80 --- /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 + * + * 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..e0e8e8e3a --- /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 + * + * 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 + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3