diff options
Diffstat (limited to 'nuttx/drivers/lcd/nokia6100.c')
-rw-r--r-- | nuttx/drivers/lcd/nokia6100.c | 1230 |
1 files changed, 1230 insertions, 0 deletions
diff --git a/nuttx/drivers/lcd/nokia6100.c b/nuttx/drivers/lcd/nokia6100.c new file mode 100644 index 000000000..d450e05db --- /dev/null +++ b/nuttx/drivers/lcd/nokia6100.c @@ -0,0 +1,1230 @@ +/************************************************************************************** + * drivers/lcd/nokia6100.c + * Nokia 6100 LCD Display Driver + * + * Copyright (C) 2010-2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <spudmonkey@racsa.co.cr> + * + * References: + * "Nokia 6100 LCD Display Driver," Revision 1, James P. Lynch ("Nokia 6100 LCD + * Display Driver.pdf") + * "S1D15G0D08B000," Seiko Epson Corportation, 2002. + * "Data Sheet, PCF8833 STN RGB 132x132x3 driver," Phillips, 2003 Feb 14. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + **************************************************************************************/ + +/************************************************************************************** + * Included Files + **************************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/types.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <errno.h> +#include <debug.h> + +#include <nuttx/arch.h> +#include <nuttx/spi.h> +#include <nuttx/lcd/lcd.h> +#include <nuttx/lcd/nokia6100.h> + +#ifdef CONFIG_NOKIA6100_PCF8833 +# include "pcf8833.h" +#endif +#ifdef CONFIG_NOKIA6100_S1D15G10 +# include "s1d15g10.h" +#endif + +/************************************************************************************** + * Pre-processor Definitions + **************************************************************************************/ + +/* Configuration **********************************************************************/ +/* Verify that all configuration requirements have been met */ + +/* Nokia 6100 Configuration Settings: + * + * CONFIG_NOKIA6100_SPIMODE - Controls the SPI mode + * CONFIG_NOKIA6100_FREQUENCY - Define to use a different bus frequency + * CONFIG_NOKIA6100_NINTERFACES - Specifies the number of physical Nokia 6100 devices that + * will be supported. + * CONFIG_NOKIA6100_BPP - Device supports 8, 12, and 16 bits per pixel. + * CONFIG_NOKIA6100_S1D15G10 - Selects the Epson S1D15G10 display controller + * CONFIG_NOKIA6100_PCF8833 - Selects the Phillips PCF8833 display controller + * CONFIG_NOKIA6100_BLINIT - Initial backlight setting + * + * The following may need to be tuned for your hardware: + * CONFIG_NOKIA6100_INVERT - Display inversion, 0 or 1, Default: 1 + * CONFIG_NOKIA6100_MY - Display row direction, 0 or 1, Default: 0 + * CONFIG_NOKIA6100_MX - Display column direction, 0 or 1, Default: 1 + * CONFIG_NOKIA6100_V - Display address direction, 0 or 1, Default: 0 + * CONFIG_NOKIA6100_ML - Display scan direction, 0 or 1, Default: 0 + * CONFIG_NOKIA6100_RGBORD - Display RGB order, 0 or 1, Default: 0 + * + * Required LCD driver settings: + * CONFIG_LCD_NOKIA6100 - Enable Nokia 6100 support + * CONFIG_LCD_MAXCONTRAST - must be 63 with the Epson controller and 127 with + * the Phillips controller. + * CONFIG_LCD_MAXPOWER - Maximum value of backlight setting. The backlight control is + * managed outside of the 6100 driver so this value has no meaning to the driver. + */ + +/* Mode 0,0 should be use. However, somtimes you need to tinker with these things. */ + +#ifndef CONFIG_NOKIA6100_SPIMODE +# define CONFIG_NOKIA6100_SPIMODE SPIDEV_MODE0 +#endif + +/* Default frequency: 1Mhz */ + +#ifndef CONFIG_NOKIA6100_FREQUENCY +# define CONFIG_NOKIA6100_FREQUENCY 1000000 +#endif + +/* CONFIG_NOKIA6100_NINTERFACES determines the number of physical interfaces + * that will be supported. + */ + +#ifndef CONFIG_NOKIA6100_NINTERFACES +# define CONFIG_NOKIA6100_NINTERFACES 1 +#endif + +#if CONFIG_NOKIA6100_NINTERFACES != 1 +# error "This implementation supports only a single LCD device" +#endif + +/* Only support for 8 and 12 BPP currently implemented */ + +#if !defined(CONFIG_NOKIA6100_BPP) +# warning "Assuming 8BPP" +# define CONFIG_NOKIA6100_BPP 8 +#endif + +#if CONFIG_NOKIA6100_BPP != 8 && CONFIG_NOKIA6100_BPP != 12 +# if CONFIG_NOKIA6100_BPP == 16 +# error "Support for 16BPP no yet implemented" +# else +# error "LCD supports only 8, 12, and 16BPP" +# endif +#endif + +#if CONFIG_NOKIA6100_BPP == 8 +# ifdef CONFIG_NX_DISABLE_8BPP +# warning "8-bit pixel support needed" +# endif +#elif CONFIG_NOKIA6100_BPP == 12 +# if defined(CONFIG_NX_DISABLE_12BPP) || !defined(CONFIG_NX_PACKEDMSFIRST) +# warning "12-bit, big-endian pixel support needed" +# endif +#elif CONFIG_NOKIA6100_BPP == 16 +# ifdef CONFIG_NX_DISABLE_16BPP +# warning "16-bit pixel support needed" +# endif +#endif + +/* Exactly one LCD controller must be selected. "The Olimex boards have both display + * controllers possible; if the LCD has a GE-12 sticker on it, it’s a Philips PCF8833. + * If it has a GE-8 sticker, it’s an Epson controller." + */ + +#if defined(CONFIG_NOKIA6100_S1D15G10) && defined(CONFIG_NOKIA6100_PCF8833) +# error "Both CONFIG_NOKIA6100_S1D15G10 and CONFIG_NOKIA6100_PCF8833 are defined" +#endif + +#if !defined(CONFIG_NOKIA6100_S1D15G10) && !defined(CONFIG_NOKIA6100_PCF8833) +# error "One of CONFIG_NOKIA6100_S1D15G10 or CONFIG_NOKIA6100_PCF8833 must be defined" +#endif + +/* Delay geometry defaults */ + +#ifndef CONFIG_NOKIA6100_INVERT +# define CONFIG_NOKIA6100_INVERT 1 +#endif + +#ifndef CONFIG_NOKIA6100_MY +# define CONFIG_NOKIA6100_MY 0 +#endif + +#ifndef CONFIG_NOKIA6100_MX +# define CONFIG_NOKIA6100_MX 1 +#endif + +#ifndef CONFIG_NOKIA6100_V +# define CONFIG_NOKIA6100_V 0 +#endif + +#ifndef CONFIG_NOKIA6100_ML +# define CONFIG_NOKIA6100_ML 0 +#endif + +#ifndef CONFIG_NOKIA6100_RGBORD +# define CONFIG_NOKIA6100_RGBORD 0 +#endif + +/* Check contrast selection */ + +#ifdef CONFIG_NOKIA6100_S1D15G10 + +# if !defined(CONFIG_LCD_MAXCONTRAST) +# define CONFIG_LCD_MAXCONTRAST 63 +# endif +# if CONFIG_LCD_MAXCONTRAST != 63 +# error "CONFIG_LCD_MAXCONTRAST must be 63 with the Epson LCD controller" +# endif +# define NOKIA_DEFAULT_CONTRAST 32 + +#else /* CONFIG_NOKIA6100_PCF8833 */ + +# if !defined(CONFIG_LCD_MAXCONTRAST) +# define CONFIG_LCD_MAXCONTRAST 127 +# endif +# if CONFIG_LCD_MAXCONTRAST != 127 +# error "CONFIG_LCD_MAXCONTRAST must be 127 with the Phillips LCD controller" +# endif +# define NOKIA_DEFAULT_CONTRAST 48 + +#endif + +/* Check initial backlight setting */ + +#ifndef CONFIG_NOKIA6100_BLINIT +# define CONFIG_NOKIA6100_BLINIT (NOKIA_DEFAULT_CONTRAST/3) +#endif + +/* Word width must be 9 bits */ + +#if defined(CONFIG_NOKIA6100_WORDWIDTH) && CONFIG_NOKIA6100_WORDWIDTH != 9 +# error "CONFIG_NOKIA6100_WORDWIDTH must be 9" +#endif +#ifndef CONFIG_NOKIA6100_WORDWIDTH +# define CONFIG_NOKIA6100_WORDWIDTH 9 +#endif + +/* If bit 9 is set, the byte is data; clear for commands */ + +#define NOKIA_LCD_DATA (1 << 8) + +/* Define CONFIG_LCD_REGDEBUG to enable register-level debug output. + * (Verbose debug must also be enabled) + */ + +#ifndef CONFIG_DEBUG +# undef CONFIG_DEBUG_VERBOSE +# undef CONFIG_DEBUG_GRAPHICS +#endif + +#ifndef CONFIG_DEBUG_VERBOSE +# undef CONFIG_LCD_REGDEBUG +#endif + +/* Controller independent definitions *************************************************/ + +#ifdef CONFIG_NOKIA6100_PCF8833 +# define LCD_NOP PCF8833_NOP +# define LCD_RAMWR PCF8833_RAMWR +# define LCD_PASET PCF8833_PASET +# define LCD_CASET PCF8833_CASET +#endif +#ifdef CONFIG_NOKIA6100_S1D15G10 +# define LCD_NOP S1D15G10_NOP +# define LCD_RAMWR S1D15G10_RAMWR +# define LCD_PASET S1D15G10_PASET +# define LCD_CASET S1D15G10_CASET +#endif + +/* Color Properties *******************************************************************/ + +/* Display Resolution */ + +#define NOKIA_XRES 132 +#define NOKIA_YRES 132 + +/* Color depth and format */ + +#if CONFIG_NOKIA6100_BPP == 8 +# define NOKIA_BPP 8 +# define NOKIA_COLORFMT FB_FMT_RGB8_332 +# define NOKIA_STRIDE NOKIA_XRES +# define NOKIA_PIX2BYTES(p) (p) +#elif CONFIG_NOKIA6100_BPP == 12 +# define NOKIA_BPP 12 +# define NOKIA_COLORFMT FB_FMT_RGB12_444 +# define NOKIA_STRIDE ((3*NOKIA_XRES+1)/2) +# define NOKIA_PIX2BYTES(p) ((3*(p)+1)/2) +#elif CONFIG_NOKIA6100_BPP == 16 +# define NOKIA_BPP 16 +# define NOKIA_COLORFMT FB_FMT_RGB16_565 +# define NOKIA_STRIDE (2*NOKIA_XRES) +# define NOKIA_PIX2BYTES(p) (2*(p)) +#endif + +/* Handle any potential strange behavior at edges */ + +#if 0 /* REVISIT */ +#define NOKIA_PGBIAS 2 /* May not be necessary */ +#define NOKIA_COLBIAS 0 +#define NOKIA_XBIAS 2 /* May not be necessary, if so need to subtract from XRES */ +#define NOKIA_YBIAS 0 +#else +#define NOKIA_PGBIAS 0 +#define NOKIA_COLBIAS 0 +#define NOKIA_XBIAS 0 +#define NOKIA_YBIAS 0 +#endif + +#define NOKIA_ENDPAGE 131 +#define NOKIA_ENDCOL 131 + +/* Debug ******************************************************************************/ + +#ifdef CONFIG_LCD_REGDEBUG +# define lcddbg(format, arg...) llvdbg(format, ##arg) +#else +# define lcddbg(x...) +#endif + +/************************************************************************************** + * Private Type Definition + **************************************************************************************/ + +/* This structure describes the state of this driver */ + +struct nokia_dev_s +{ + /* Publically visible device structure */ + + struct lcd_dev_s dev; + + /* Private LCD-specific information follows */ + + FAR struct spi_dev_s *spi; /* Contained SPI driver instance */ + uint8_t contrast; /* Current contrast setting */ + uint8_t power; /* Current power (backlight) setting */ +}; + +/************************************************************************************** + * Private Function Protototypes + **************************************************************************************/ + +/* SPI support */ + +static inline void nokia_configspi(FAR struct spi_dev_s *spi); +#ifdef CONFIG_SPI_OWNBUS +static inline void nokia_select(FAR struct spi_dev_s *spi); +static inline void nokia_deselect(FAR struct spi_dev_s *spi); +#else +static void nokia_select(FAR struct spi_dev_s *spi); +static void nokia_deselect(FAR struct spi_dev_s *spi); +#endif +static void nokia_sndcmd(FAR struct spi_dev_s *spi, const uint8_t cmd); +static void nokia_cmdarray(FAR struct spi_dev_s *spi, int len, const uint8_t *cmddata); +static void nokia_clrram(FAR struct spi_dev_s *spi); + +/* LCD Data Transfer Methods */ + +static int nokia_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, + size_t npixels); +static int nokia_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, + size_t npixels); + +/* LCD Configuration */ + +static int nokia_getvideoinfo(FAR struct lcd_dev_s *dev, + FAR struct fb_videoinfo_s *vinfo); +static int nokia_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, + FAR struct lcd_planeinfo_s *pinfo); + +/* LCD RGB Mapping */ + +#ifdef CONFIG_FB_CMAP +# error "RGB color mapping not supported by this driver" +#endif + +/* Cursor Controls */ + +#ifdef CONFIG_FB_HWCURSOR +# error "Cursor control not supported by this driver" +#endif + +/* LCD Specific Controls */ + +static int nokia_getpower(struct lcd_dev_s *dev); +static int nokia_setpower(struct lcd_dev_s *dev, int power); +static int nokia_getcontrast(struct lcd_dev_s *dev); +static int nokia_setcontrast(struct lcd_dev_s *dev, unsigned int contrast); + +/* Initialization */ + +static int nokia_initialize(struct nokia_dev_s *priv); + +/************************************************************************************** + * Private Data + **************************************************************************************/ + +/* This is working memory allocated by the LCD driver for each LCD device + * and for each color plane. This memory will hold one raster line of data. + * The size of the allocated run buffer must therefore be at least + * (bpp * xres / 8). Actual alignment of the buffer must conform to the + * bitwidth of the underlying pixel type. + * + * If there are multiple planes, they may share the same working buffer + * because different planes will not be operate on concurrently. However, + * if there are multiple LCD devices, they must each have unique run buffers. + */ + +#if CONFIG_NOKIA6100_BPP == 8 +static uint8_t g_runbuffer[NOKIA_XRES]; +#elif CONFIG_NOKIA6100_BPP == 12 +static uint8_t g_runbuffer[(3*NOKIA_XRES+1)/2]; +#else /* CONFIG_NOKIA6100_BPP == 16 */ +static uint16_t g_runbuffer[NOKIA_XRES]; +#endif + +/* g_rowbuf is another buffer, but used internally by the Nokia 6100 driver in order + * expand the pixel data into 9-bit data needed by the LCD. There are some + * customizations that would eliminate the need for this extra buffer and for the + * extra expansion/copy, but those customizations would require a special, non-standard + * SPI driver that could expand 8- to 9-bit data on the fly. + */ + +static uint16_t g_rowbuf[NOKIA_STRIDE+1]; + +/* Device Driver Data Structures ******************************************************/ + +/* This structure describes the overall LCD video controller */ + +static const struct fb_videoinfo_s g_videoinfo = +{ + .fmt = NOKIA_COLORFMT, /* Color format: RGB16-565: RRRR RGGG GGGB BBBB */ + .xres = NOKIA_XRES, /* Horizontal resolution in pixel columns */ + .yres = NOKIA_YRES, /* Vertical resolution in pixel rows */ + .nplanes = 1, /* Number of color planes supported */ +}; + +/* This is the standard, NuttX Plane information object */ + +static const struct lcd_planeinfo_s g_planeinfo = +{ + .putrun = nokia_putrun, /* Put a run into LCD memory */ + .getrun = nokia_getrun, /* Get a run from LCD memory */ + .buffer = (uint8_t*)g_runbuffer, /* Run scratch buffer */ + .bpp = NOKIA_BPP, /* Bits-per-pixel */ +}; + +/* This is the standard, NuttX LCD driver object */ + +static struct nokia_dev_s g_lcddev = +{ + .dev = + { + /* LCD Configuration */ + + .getvideoinfo = nokia_getvideoinfo, + .getplaneinfo = nokia_getplaneinfo, + + /* LCD RGB Mapping -- Not supported */ + /* Cursor Controls -- Not supported */ + + /* LCD Specific Controls */ + + .getpower = nokia_getpower, + .setpower = nokia_setpower, + .getcontrast = nokia_getcontrast, + .setcontrast = nokia_setcontrast, + }, +}; + +/* LCD Command Strings ****************************************************************/ + +#ifdef CONFIG_NOKIA6100_S1D15G10 +/* Display control: + * P1: Specifies the CL dividing ratio, F1 and F2 drive-pattern switching period. + * P2: Specifies the duty of the module on block basis + * P3: Specify number of lines to be inversely highlighted on LCD panel + * P4: 0: Dispersion P40= 1: Non-dispersion + */ + +#if 1 // CONFIG_NOKIA6100_BPP == 12 +static const uint8_t g_disctl[] = +{ + S1D15G10_DISCTL, /* Display control */ + DISCTL_CLDIV_2|DISCTL_PERIOD_8, /* P1: Divide clock by 2; switching period = 8 */ +//DISCTL_CLDIV_NONE|DISCTL_PERIOD_8, /* P1: No clock division; switching period = 8 */ + 32, /* P2: nlines/4 - 1 = 132/4 - 1 = 32 */ + 0, /* P3: No inversely highlighted lines */ + 0 /* P4: No disperion */ +}; +#else /* CONFIG_NOKIA6100_BPP == 8 */ +static const uint8_t g_disctl[] = +{ + S1D15G10_DISCTL, /* Display control */ + DISCTL_CLDIV_2|DISCTL_PERIOD_FLD, /* P1: Divide clock by 2; switching period = field */ + 32, /* P2: nlines/4 - 1 = 132/4 - 1 = 32 */ + 0, /* P3: No inversely highlighted lines */ + 0 /* P4: No disperion */ +}; +#endif + +/* Common scan direction: + * P1: Cpecify the common output scan direction. + */ + +static const uint8_t g_comscn[] = +{ + S1D15G10_COMSCN, /* Common scan direction */ + 1 /* 0x01 = Scan 1->68, 132<-69 */ +}; + +/* Power control: + * P1: Turn on or off the liquid crystal driving power circuit, booster/step-down + * circuits and voltage follower circuit. + */ + +static const uint8_t g_pwrctr[] = +{ + S1D15G10_PWRCTR, /* Power control */ + PWCTR_REFVOLTAGE|PWCTR_REGULATOR|PWCTR_BOOSTER2|PWCTR_BOOSTER1 +}; + +/* Data control: + * P1: Specify the normal or inverse display of the page address and also to specify + * the page address scanning direction + * P2: RGB sequence + * P3: Grayscale setup + */ + +static const uint8_t g_datctl[] = +{ + S1D15G10_DATCTL, /* Data control */ + 0 +#if CONFIG_NOKIA6100_MY != 0 /* Display row direction */ + |DATCTL_PGADDR_INV /* Page address inverted */ +#endif +#if CONFIG_NOKIA6100_MX != 0 /* Display column direction */ + |DATCTL_COLADDR_REV /* Column address reversed */ +#endif +#if CONFIG_NOKIA6100_V != 0 /* Display address direction */ + |DATCTL_ADDR_PGDIR /* Address scan in page direction */ +#endif + , +#if CONFIG_NOKIA6100_RGBORD != 0 + DATCTL_BGR, /* RGB->BGR */ +#else + 0, /* RGB->RGB */ +#endif +#if CONFIG_NOKIA6100_BPP == 8 + DATCTL_8GRAY /* Selects 8-bit color */ +#elif CONFIG_NOKIA6100_BPP == 12 + DATCTL_16GRAY_A /* Selects 16-bit color, Type A */ +#else +# error "16-bit mode not yet implemented" +#endif +}; + +/* Voltage control (contrast setting): + * P1: Volume value + * P2: Resistance ratio + * (May need to be tuned for individual displays) + */ + +static const uint8_t g_volctr[] = +{ + S1D15G10_VOLCTR, /* Volume control */ + NOKIA_DEFAULT_CONTRAST, /* Volume value */ + 2 /* Resistance ratio */ +}; + +/* 256-color position set (RGBSET8) */ + +#if CONFIG_NOKIA6100_BPP == 8 +static const uint8_t g_rgbset8[] = +{ + S1D15G10_RGBSET8, /* 256-color position set */ + 0, 2, 4, 6, 9, 11, 13, 15, /* Red tones */ + 0, 2, 4, 6, 9, 11, 13, 15, /* Green tones */ + 0, 5, 10, 15 /* Blue tones */ +}; +#endif + +/* Page address set (PASET) */ + +static const uint8_t g_paset[] = +{ + S1D15G10_PASET, /* Page start address set */ + NOKIA_PGBIAS, + 131 +}; + +/* Column address set (CASET) */ + +static const uint8_t g_caset[] = +{ + S1D15G10_CASET, /* Column start address set */ + NOKIA_COLBIAS, + 131 +}; +#endif /* CONFIG_NOKIA6100_S1D15G10 */ + +#ifdef CONFIG_NOKIA6100_PCF8833 + +/* Color interface pixel format (COLMOD) */ + +#if CONFIG_NOKIA6100_BPP == 12 +static const uint8_t g_colmod[] = +{ + PCF8833_COLMOD, /* Color interface pixel format */ + PCF8833_FMT_12BPS /* 12 bits-per-pixel */ +}; +#else /* CONFIG_NOKIA6100_BPP == 8 */ +static const uint8_t g_colmod[] = +{ + PCF8833_COLMOD, /* Color interface pixel format */ + PCF8833_FMT_8BPS /* 8 bits-per-pixel */ +}; +#endif + +/* Memory data access control(MADCTL) */ + +static const uint8_t g_madctl[] = +{ + PCF8833_MADCTL, /* Memory data access control*/ + 0 +#ifdef CONFIG_NOKIA6100_RGBORD != 0 + |MADCTL_RGB /* RGB->BGR */ +#endif +#ifdef CONFIG_NOKIA6100_MY != 0 /* Display row direction */ + |MADCTL_MY /* Mirror Y */ +#endif +#ifdef CONFIG_NOKIA6100_MX != 0 /* Display column direction */ + |MADCTL_MX /* Mirror X */ +#endif +#ifdef CONFIG_NOKIA6100_V != 0 /* Display address direction */ + |MADCTL_V /* ertical RAM write; in Y direction */ +#endif +#ifdef CONFIG_NOKIA6100_ML != 0 /* Display scan direction */ + |MADCTL_LAO /* Line address order bottom to top */ +#endif +}; + +/* Set contrast (SETCON) */ + +static const uint8_t g_setcon[] = +{ + PCF8833_SETCON, /* Set contrast */ + NOKIA_DEFAULT_CONTRAST +}; + +#endif /* CONFIG_NOKIA6100_PCF8833 */ + +/************************************************************************************** + * Private Functions + **************************************************************************************/ + +/************************************************************************************** + * Function: nokia_configspi + * + * Description: + * Configure the SPI for use with the Nokia 6100 + * + * Parameters: + * spi - Reference to the SPI driver structure + * + * Returned Value: + * None + * + * Assumptions: + * + **************************************************************************************/ + +static inline void nokia_configspi(FAR struct spi_dev_s *spi) +{ + lcddbg("Mode: %d Bits: %d Frequency: %d\n", + CONFIG_NOKIA6100_SPIMODE, CONFIG_NOKIA6100_WORDWIDTH, CONFIG_NOKIA6100_FREQUENCY); + + /* Configure SPI for the Nokia 6100. But only if we own the SPI bus. Otherwise, don't + * bother because it might change. + */ + +#ifdef CONFIG_SPI_OWNBUS + SPI_SETMODE(spi, CONFIG_NOKIA6100_SPIMODE); + SPI_SETBITS(spi, CONFIG_NOKIA6100_WORDWIDTH); + SPI_SETFREQUENCY(spi, CONFIG_NOKIA6100_FREQUENCY) +#endif +} + +/************************************************************************************** + * Function: nokia_select + * + * Description: + * Select the SPI, locking and re-configuring if necessary + * + * Parameters: + * spi - Reference to the SPI driver structure + * + * Returned Value: + * None + * + * Assumptions: + * + **************************************************************************************/ + +#ifdef CONFIG_SPI_OWNBUS +static inline void nokia_select(FAR struct spi_dev_s *spi) +{ + /* We own the SPI bus, so just select the chip */ + + lcddbg("SELECTED\n"); + SPI_SELECT(spi, SPIDEV_DISPLAY, true); +} +#else +static void nokia_select(FAR struct spi_dev_s *spi) +{ + /* Select Nokia 6100 chip (locking the SPI bus in case there are multiple + * devices competing for the SPI bus + */ + + lcddbg("SELECTED\n"); + SPI_LOCK(spi, true); + SPI_SELECT(spi, SPIDEV_DISPLAY, true); + + /* Now make sure that the SPI bus is configured for the Nokia 6100 (it + * might have gotten configured for a different device while unlocked) + */ + + SPI_SETMODE(spi, CONFIG_NOKIA6100_SPIMODE); + SPI_SETBITS(spi, CONFIG_NOKIA6100_WORDWIDTH); + SPI_SETFREQUENCY(spi, CONFIG_NOKIA6100_FREQUENCY); +} +#endif + +/************************************************************************************** + * Function: nokia_deselect + * + * Description: + * De-select the SPI + * + * Parameters: + * spi - Reference to the SPI driver structure + * + * Returned Value: + * None + * + * Assumptions: + * + **************************************************************************************/ + +#ifdef CONFIG_SPI_OWNBUS +static inline void nokia_deselect(FAR struct spi_dev_s *spi) +{ + /* We own the SPI bus, so just de-select the chip */ + + lcddbg("DE-SELECTED\n"); + SPI_SELECT(spi, SPIDEV_DISPLAY, false); +} +#else +static void nokia_deselect(FAR struct spi_dev_s *spi) +{ + /* De-select Nokia 6100 chip and relinquish the SPI bus. */ + + lcddbg("DE-SELECTED\n"); + SPI_SELECT(spi, SPIDEV_DISPLAY, false); + SPI_LOCK(spi, false); +} +#endif + +/************************************************************************************** + * Name: nokia_sndcmd + * + * Description: + * Send a 1-byte command. + * + **************************************************************************************/ + +static void nokia_sndcmd(FAR struct spi_dev_s *spi, const uint8_t cmd) +{ + /* Select the LCD */ + + lcddbg("cmd: %02x\n", cmd); + nokia_select(spi); + + /* Send the command. Bit 8 == 0 denotes a command */ + + (void)SPI_SEND(spi, (uint16_t)cmd); + + /* De-select the LCD */ + + nokia_deselect(spi); +} + +/************************************************************************************** + * Name: nokia_cmddata + * + * Description: + * Send a 1-byte command followed by datlen data bytes. + * + **************************************************************************************/ + +static void nokia_cmddata(FAR struct spi_dev_s *spi, uint8_t cmd, int datlen, + const uint8_t *data) +{ + uint16_t *rowbuf = g_rowbuf; + int i; + + lcddbg("cmd: %02x datlen: %d\n", cmd, datlen); + DEBUGASSERT(datlen <= NOKIA_STRIDE); + + /* Copy the command into the line buffer. Bit 8 == 0 denotes a command. */ + + *rowbuf++ = cmd; + + /* Copy any data after the command into the line buffer */ + + for (i = 0; i < datlen; i++) + { + /* Bit 8 == 1 denotes data */ + + *rowbuf++ = (uint16_t)*data++ | NOKIA_LCD_DATA; + } + + /* Select the LCD */ + + nokia_select(spi); + + /* Send the line buffer. */ + + (void)SPI_SNDBLOCK(spi, g_rowbuf, datlen+1); + + /* De-select the LCD */ + + nokia_deselect(spi); +} + +/************************************************************************************** + * Name: nokia_ramwr + * + * Description: + * Send a RAMWR command followed by datlen data bytes. + * + **************************************************************************************/ + +static void nokia_ramwr(FAR struct spi_dev_s *spi, int datlen, const uint8_t *data) +{ + nokia_cmddata(spi, LCD_RAMWR, datlen, data); +} + +/************************************************************************************** + * Name: nokia_cmdarray + * + * Description: + * Send a RAMWR command followed by len-1 data bytes. + * + **************************************************************************************/ + +static void nokia_cmdarray(FAR struct spi_dev_s *spi, int len, const uint8_t *cmddata) +{ +#ifdef CONFIG_LCD_REGDEBUG + int i; + + for (i = 0; i < len; i++) + { + lcddbg("cmddata[%d]: %02x\n", i, cmddata[i]); + } +#endif + nokia_cmddata(spi, cmddata[0], len-1, &cmddata[1]); +} + +/************************************************************************************** + * Name: nokia_clrram + * + * Description: + * Send a 1-byte command followed by len-1 data bytes. + * + **************************************************************************************/ + +static void nokia_clrram(FAR struct spi_dev_s *spi) +{ + uint16_t *rowbuf = g_rowbuf; + int i; + + /* Set all zero data in the line buffer */ + + for (i = 0; i < NOKIA_STRIDE; i++) + { + /* Bit 8 == 1 denotes data */ + + *rowbuf++ = NOKIA_LCD_DATA; + } + + /* Select the LCD and send the RAMWR command */ + + nokia_select(spi); + SPI_SEND(spi, LCD_RAMWR); + + /* Send the line buffer, once for each row. */ + + for (i = 0; i < NOKIA_YRES; i++) + { + (void)SPI_SNDBLOCK(spi, g_rowbuf, NOKIA_STRIDE); + } + + /* De-select the LCD */ + + nokia_deselect(spi); +} + +/************************************************************************************** + * Name: nokia_putrun + * + * Description: + * This method can be used to write a partial raster line to the LCD: + * + * row - Starting row to write to (range: 0 <= row < yres) + * col - Starting column to write to (range: 0 <= col <= xres-npixels) + * buffer - The buffer containing the run to be written to the LCD + * npixels - The number of pixels to write to the LCD + * (range: 0 < npixels <= xres-col) + * + **************************************************************************************/ + +static int nokia_putrun(fb_coord_t row, fb_coord_t col, FAR const uint8_t *buffer, + size_t npixels) +{ + struct nokia_dev_s *priv = &g_lcddev; + FAR struct spi_dev_s *spi = priv->spi; + uint16_t cmd[3]; + + gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); + +#if NOKIA_XBIAS > 0 + col += NOKIA_XBIAS; +#endif +#if NOKIA_YBIAS > 0 + row += NOKIA_YBIAS; +#endif + DEBUGASSERT(buffer && col >=0 && (col + npixels) <= NOKIA_XRES && row >= 0 && row < NOKIA_YRES); + + /* Set up to write the run. */ + + nokia_select(spi); + cmd[0] = LCD_PASET; + cmd[1] = col | NOKIA_LCD_DATA; + cmd[2] = NOKIA_ENDPAGE | NOKIA_LCD_DATA; + (void)SPI_SNDBLOCK(spi, cmd, 3); + nokia_deselect(spi); + + /* De-select the LCD */ + + nokia_select(spi); + cmd[0] = LCD_CASET; + cmd[1] = row | NOKIA_LCD_DATA; + cmd[2] = NOKIA_ENDCOL | NOKIA_LCD_DATA; + (void)SPI_SNDBLOCK(spi, cmd, 3); + nokia_deselect(spi); + + /* Then send the run */ + + nokia_ramwr(spi, NOKIA_PIX2BYTES(npixels), buffer); + return OK; +} + +/************************************************************************************** + * Name: nokia_getrun + * + * Description: + * This method can be used to read a partial raster line from the LCD: + * + * row - Starting row to read from (range: 0 <= row < yres) + * col - Starting column to read read (range: 0 <= col <= xres-npixels) + * buffer - The buffer in which to return the run read from the LCD + * npixels - The number of pixels to read from the LCD + * (range: 0 < npixels <= xres-col) + * + **************************************************************************************/ + +static int nokia_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t *buffer, + size_t npixels) +{ + gvdbg("row: %d col: %d npixels: %d\n", row, col, npixels); + DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0); + + /* At present, this is a write-only LCD driver */ + +#warning "Not implemented" + return -ENOSYS; +} + +/************************************************************************************** + * Name: nokia_getvideoinfo + * + * Description: + * Get information about the LCD video controller configuration. + * + **************************************************************************************/ + +static int nokia_getvideoinfo(FAR struct lcd_dev_s *dev, + FAR struct fb_videoinfo_s *vinfo) +{ + DEBUGASSERT(dev && vinfo); + gvdbg("fmt: %d xres: %d yres: %d nplanes: %d\n", + g_videoinfo.fmt, g_videoinfo.xres, g_videoinfo.yres, g_videoinfo.nplanes); + memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s)); + return OK; +} + +/************************************************************************************** + * Name: nokia_getplaneinfo + * + * Description: + * Get information about the configuration of each LCD color plane. + * + **************************************************************************************/ + +static int nokia_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno, + FAR struct lcd_planeinfo_s *pinfo) +{ + DEBUGASSERT(dev && pinfo && planeno == 0); + gvdbg("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp); + memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s)); + return OK; +} + +/************************************************************************************** + * Name: nokia_getpower + * + * Description: + * Get the LCD panel power status (0: full off - CONFIG_LCD_MAXPOWER: full on. On + * backlit LCDs, this setting may correspond to the backlight setting. + * + **************************************************************************************/ + +static int nokia_getpower(struct lcd_dev_s *dev) +{ + struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; + gvdbg("power: %d\n", priv->power); + return priv->power; +} + +/************************************************************************************** + * Name: nokia_setpower + * + * Description: + * Enable/disable LCD panel power (0: full off - CONFIG_LCD_MAXPOWER: full on). On + * backlit LCDs, this setting may correspond to the backlight setting. + * + **************************************************************************************/ + +static int nokia_setpower(struct lcd_dev_s *dev, int power) +{ + struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; + int ret; + + gvdbg("power: %d\n", power); + DEBUGASSERT(power <= CONFIG_LCD_MAXPOWER); + + /* Set new power level. The backlight power is controlled outside of the LCD + * assembly and must be managmed by board-specific logic. + */ + + ret = nokia_backlight(power); + if (ret == OK) + { + priv->power = power; + } + return ret; +} + +/************************************************************************************** + * Name: nokia_getcontrast + * + * Description: + * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST). + * + **************************************************************************************/ + +static int nokia_getcontrast(struct lcd_dev_s *dev) +{ + struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; + gvdbg("contrast: %d\n", priv->contrast); + return priv->contrast; +} + +/************************************************************************************** + * Name: nokia_setcontrast + * + * Description: + * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST). + * + **************************************************************************************/ + +static int nokia_setcontrast(struct lcd_dev_s *dev, unsigned int contrast) +{ + struct nokia_dev_s *priv = (struct nokia_dev_s *)dev; + + if (contrast < CONFIG_LCD_MAXCONTRAST) + { +#ifdef CONFIG_NOKIA6100_S1D15G10 + while (priv->contrast < contrast) + { + nokia_sndcmd(priv->spi, S1D15G10_VOLUP); + priv->contrast++; + } + while (priv->contrast > contrast) + { + nokia_sndcmd(priv->spi, S1D15G10_VOLDOWN); + priv->contrast--; + } +#else /* CONFIG_NOKIA6100_PCF8833 */ + uint8_t cmd[2]; + + cmd[0] = PCF8833_SETCON; + cmd[1] = priv->contrast; + nokia_sndarry(priv->spi, 2, cmd); + priv->contrast = contrast; +#endif + } + + gvdbg("contrast: %d\n", contrast); + return -ENOSYS; +} + +/************************************************************************************** + * Name: nokia_initialize + * + * Description: + * Initialize the LCD controller. + * + **************************************************************************************/ + +#ifdef CONFIG_NOKIA6100_S1D15G10 +static int nokia_initialize(struct nokia_dev_s *priv) +{ + struct spi_dev_s *spi = priv->spi; + + /* Configure the display */ + + nokia_cmdarray(spi, sizeof(g_disctl), g_disctl); /* Display control */ + nokia_cmdarray(spi, sizeof(g_comscn), g_comscn); /* Common scan direction */ + nokia_sndcmd(spi, S1D15G10_OSCON); /* Internal oscilator ON */ + nokia_sndcmd(spi, S1D15G10_SLPOUT); /* Sleep out */ + nokia_cmdarray(spi, sizeof(g_volctr), g_volctr); /* Volume control (contrast) */ + nokia_cmdarray(spi, sizeof(g_pwrctr), g_pwrctr); /* Turn on voltage regulators */ + up_mdelay(100); +#ifdef CONFIG_NOKIA6100_INVERT + nokia_sndcmd(spi, S1D15G10_DISINV); /* Invert display */ +#else + nokia_sndcmd(spi, S1D15G10_DISNOR); /* Normal display */ +#endif + nokia_cmdarray(spi, sizeof(g_datctl), g_datctl); /* Data control */ +#if CONFIG_NOKIA6100_BPP == 8 + nokia_cmdarray(spi, sizeof(g_rgbset8), g_rgbset8); /* Set up color lookup table */ + nokia_sndcmd(spi, S1D15G10_NOP); +#endif + nokia_cmdarray(spi, sizeof(g_paset), g_paset); /* Page address set */ + nokia_cmdarray(spi, sizeof(g_paset), g_caset); /* Column address set */ + nokia_clrram(spi); + nokia_sndcmd(spi, S1D15G10_DISON); /* Display on */ + return OK; +} +#endif + +#ifdef CONFIG_NOKIA6100_PCF8833 +static int nokia_initialize(struct nokia_dev_s *priv) +{ + struct struct spi_dev_s *spi = priv->spi; + + nokia_sndcmd(spi, PCF8833_SLEEPOUT); /* Exit sleep mode */ + nokia_sndcmd(spi, PCF8833_BSTRON); /* Turn on voltage booster */ +#ifdef CONFIG_NOKIA6100_INVERT + nokia_sndcmd(spi, PCF8833_INVON); /* Invert display */ +#else + nokia_sndcmd(spi, PCF8833_INVOFF); /* Don't invert display */ +#endif + nokia_cmdarray(spi, sizeof(g_madctl), g_madctl); /* Memory data access control */ + nokia_cmdarray(spi, sizeof(g_colmod), g_colmod); /* Color interface pixel format */ + nokia_cmdarray(spi, sizeof(g_setcon), g_setcon); /* Set contrast */ + nokia_sndcmd(spi, PCF8833_NOP); /* No operation */ + nokia_clrram(spi); + nokia_sndcmd(spi, PCF8833_DISPON); /* Display on */ + return OK; +} +#endif /* CONFIG_NOKIA6100_PCF8833 */ + +/************************************************************************************** + * Public Functions + **************************************************************************************/ + +/************************************************************************************** + * Name: nokia_lcdinitialize + * + * Description: + * Initialize the NOKIA6100 video hardware. The initial state of the LCD is fully + * initialized, display memory cleared, and the LCD ready to use, but with the power + * setting at 0 (full off == sleep mode). + * + * Input Parameters: + * + * spi - A reference to the SPI driver instance. + * devno - A value in the range of 0 throuh CONFIG_NOKIA6100_NINTERFACES-1. This + * allows support for multiple LCD devices. + * + * Returned Value: + * + * On success, this function returns a reference to the LCD object for the specified + * LCD. NULL is returned on any failure. + * + **************************************************************************************/ + +FAR struct lcd_dev_s *nokia_lcdinitialize(FAR struct spi_dev_s *spi, unsigned int devno) +{ + struct nokia_dev_s *priv = &g_lcddev; + + gvdbg("Initializing\n"); + DEBUGASSERT(devno == 0); + + /* Initialize the driver data structure */ + + priv->spi = spi; /* Save the SPI instance */ + priv->contrast = NOKIA_DEFAULT_CONTRAST; /* Initial contrast setting */ + + /* Configure and enable the LCD controller */ + + nokia_configspi(spi); + if (nokia_initialize(priv) == OK) + { + /* Turn on the backlight */ + + nokia_backlight(CONFIG_NOKIA6100_BLINIT); + return &priv->dev; + } + return NULL; +} |