* drivers/lcd/ssd1351.c
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/param.h>
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/arch.h>
#include <nuttx/spi/spi.h>
#include <nuttx/lcd/lcd.h>
#include <nuttx/lcd/ssd1351.h>
#ifdef CONFIG_LCD_SSD1351
* Pre-processor Definitions
****************************************************************************/
* CONFIG_SSD1351_PARALLEL8BIT - 8-bit parallel interface
* CONFIG_SSD1351_SPI3WIRE - 3-wire SPI interface
* CONFIG_SSD1351_SPI4WIRE - 4-wire SPI interface
* CONFIG_SSD1351_SPIMODE - SPI mode
* CONFIG_SSD1351_SPIFREQ - SPI frequency
* CONFIG_SSD1351_NINTERFACES - number of physical devices supported
* CONFIG_SSD1351_XRES - X resolution
* CONFIG_SSD1351_YRES - Y resolution
* CONFIG_SSD1351_MIRRORX - mirror along the X axis
* CONFIG_SSD1351_MIRRORY - mirror along the Y axis
* CONFIG_SSD1351_INVERT - invert the display
* CONFIG_SSD1351_VDDEXT - external VDD
* CONFIG_SSD1351_TRST - reset period
* CONFIG_SSD1351_TPRECHG1 - first pre-charge period
* CONFIG_SSD1351_PERFENHANCE - enhance display performance
* CONFIG_SSD1351_CLKDIV - clock divider
* CONFIG_SSD1351_OSCFREQ - oscillator frequency
* CONFIG_SSD1351_TPRECHG2 - second pre-charge period
* CONFIG_SSD1351_VPRECHG - pre-charge voltage level
* CONFIG_SSD1351_VCOMH - COM deselect voltage level
* CONFIG_SSD1351_CONTRASTA - color A contrast
* CONFIG_SSD1351_CONTRASTB - color B contrast
* CONFIG_SSD1351_CONTRASTC - color C contrast
* CONFIG_SSD1351_MSTRCONTRAST - master contrast ratio
*
* Required LCD driver settings:
* CONFIG_LCD_SSD1351 - enables SSD1351 support
* CONFIG_LCD_MAXPOWER - maximum power, must be 1
*
* Additional LCD driver settings:
* CONFIG_LCD_LANDSCAPE - landscape
* CONFIG_LCD_RLANDSCAPE - reverse landscape
* CONFIG_LCD_PORTRAIT - portrait
* CONFIG_LCD_RPORTRAIT - reverse portrait
*
* Required SPI driver settings:
* CONFIG_SPI - enables support for SPI
* CONFIG_SPI_CMDDATA - enables support for cmd/data selection
* (if using 4-wire SPI)
*/
#if CONFIG_LCD_MAXPOWER != 1
# error "CONFIG_LCD_MAXPOWER should be 1"
#endif
#ifdef CONFIG_SSD1351_SPI3WIRE
# define SSD1351_SPICMD 0
# define SSD1351_SPIDATA (1 << 8)
# define SSD1351_SPIBITS 9
#else
# define SSD1351_SPIBITS 8
#endif
#define SSD1351_CLAMP(n, a, b) MIN(MAX(n, a), b)
* Data 1: start address (0-127)
* Data 2: end address (0-127)
*/
#define SSD1351_CMD_COLADDR 0x15
* Data 1: start address (0-127)
* Data 2: end address (0-127)
*/
#define SSD1351_CMD_ROWADDR 0x75
#define SSD1351_CMD_RAMWRITE 0x5c
#define SSD1351_CMD_RAMREAD 0x5d
* scan direction, COM split, and color depth.
* One data byte.
*/
#define SSD1351_CMD_ORIENTATION 0xa0
#define SSD1351_ADDRINCHORIZ 0x00
#define SSD1351_ADDRINCVERT 0x01
#define SSD1351_REMAPCOL0 0x00
#define SSD1351_REMAPCOL127 0x02
#define SSD1351_COLORABC 0x00
#define SSD1351_COLORCBA 0x04
#define SSD1351_SCANFROMCOM0 0x00
#define SSD1351_SCANTOCOM0 0x10
#define SSD1351_SPLITDIS 0x00
#define SSD1351_SPLITEN 0x20
#define SSD1351_DEPTH65K 0x00
#define SSD1351_DEPTH262K1 0x80
#define SSD1351_DEPTH262K2 0xc0
#define SSD1351_CMD_STARTLINE 0xa1
#define SSD1351_STARTLINE(n) SSD1351_CLAMP(n, 0, 128)
#define SSD1351_CMD_OFFSET 0xa2
#define SSD1351_OFFSET(n) SSD1351_CLAMP(n, 0, 128)
#define SSD1351_CMD_ALLOFF 0xa4
#define SSD1351_CMD_ALLON 0xa5
#define SSD1351_CMD_NORMAL 0xa6
#define SSD1351_CMD_INVERSE 0xa7
#define SSD1351_CMD_VDDIFACE 0xab
#define SSD1351_VDDEXT 0x00
#define SSD1351_VDDINT 0x01
#define SSD1351_IFACE8BIT 0x00
#define SSD1351_IFACE16BIT 0x40
#define SSD1351_IFACE18BIT 0xc0
#define SSD1351_CMD_DISPOFF 0xae
#define SSD1351_CMD_DISPON 0xaf
* in DCLKs (3-15). One data byte.
*/
#define SSD1351_CMD_TRSTTPRECHG1 0xb1
#define SSD1351_TRST(n) (SSD1351_CLAMP(n, 5, 31) / 2)
#define SSD1351_TPRECHG1(n) (SSD1351_CLAMP(n, 3, 15) << 4)
#define SSD1351_CMD_PERF 0xb2
#define SSD1351_PERFNORMAL 0x00
#define SSD1351_PERFENHANCED 0xa4
#define SSD1351_PERFDATA2 0x00
#define SSD1351_PERFDATA3 0x00
* One data byte.
*/
#define SSD1351_CMD_DIVFREQ 0xb3
#define SSD1351_CLKDIV(r) (SSD1351_CLAMP(r, 0, 10) << 0)
#define SSD1351_OSCFREQ(r) (SSD1351_CLAMP(r, 0, 15) << 4)
#define SSD1351_CMD_VSL 0xb4
#define SSD1351_VSLEXT 0xa0
#define SSD1351_VSLDATA2 0xb5
#define SSD1351_VSLDATA3 0x55
#define SSD1351_CMD_GPIO 0xb5
#define SSD1351_GPIODIS 0x00
#define SSD1351_GPIOEN 0x01
#define SSD1351_GPIOLOW 0x02
#define SSD1351_GPIOHIGH 0x03
#define SSD1351_GPIO0(n) (((n) & 3) << 0)
#define SSD1351_GPIO1(n) (((n) & 3) << 2)
#define SSD1351_CMD_TPRECHG2 0xb6
#define SSD1351_TPRECHG2(n) SSD1351_CLAMP(n, 1, 15)
#define SSD1351_CMD_LUT 0xb8
#define SSD1351_CMD_LINEARLUT 0xb9
* One data byte.
*/
#define SSD1351_CMD_VPRECHG 0xbb
#define SSD1351_VPRECHG(n) (100 * (SSD1351_CLAMP(n, 20, 60) - 20) / \
(100 * (60 - 20) / 31))
* One data byte.
*/
#define SSD1351_CMD_VCOMH 0xbe
#define SSD1351_VCOMH(n) ((SSD1351_CLAMP(n, 72, 86) - 72) / 2)
* Three data bytes.
* Data 1: color A
* Data 2: color B
* Data 3: color C
*/
#define SSD1351_CMD_CONTRAST 0xc1
#define SSD1351_CONTRAST(n) SSD1351_CLAMP(n, 0, 255)
#define SSD1351_CMD_MSTRCONTRAST 0xc7
#define SSD1351_MSTRCONTRAST(n) (SSD1351_CLAMP(n, 1, 16) - 1)
#define SSD1351_CMD_MUXRATIO 0xca
#define SSD1351_MUXRATIO(n) (SSD1351_CLAMP(n, 16, 128) - 1)
#define SSD1351_CMD_LOCK 0xfd
#define SSD1351_UNLOCK 0x12
#define SSD1351_LOCK 0x16
#define SSD1351_INACCESSIBLE 0xb0
#define SSD1351_ACCESSIBLE 0xb1
* Data 1: 0x00: no scrolling
* 0x01-0x3f: scroll towards SEG127 with 1 column offset
* 0x40-0xff: scroll towards SEG0 with 1 column offset
* Data 2: start row address
* Data 3: number of rows to scroll
*/
#define SSD1351_CMD_HSCROLL 0x96
#define SSD1351_HSCROLLDATA4 0x00
#define SSD1351_HSCROLLTEST 0x00
#define SSD1351_HSCROLLNORMAL 0x01
#define SSD1351_HSCROLLSLOW 0x02
#define SSD1351_HSCROLLSLOWEST 0x03
#define SSD1351_CMD_STARTHSCROLL 0x9e
#define SSD1351_CMD_STOPHSCROLL 0x9f
#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
#define SSD1351_XRES CONFIG_SSD1351_XRES
#define SSD1351_YRES CONFIG_SSD1351_YRES
#else
#define SSD1351_XRES CONFIG_SSD1351_YRES
#define SSD1351_YRES CONFIG_SSD1351_XRES
#endif
#define SSD1351_BPP 16
#define SSD1351_COLORFMT FB_FMT_RGB16_565
#define SSD1351_STRIDE (2 * SSD1351_XRES)
#define SSD1351_PIX2BYTES(p) (2 * (p))
* Private Types
****************************************************************************/
struct ssd1351_dev_s
{
struct lcd_dev_s dev;
#ifdef CONFIG_SSD1351_PARALLEL8BIT
FAR struct ssd1351_lcd_s *lcd;
#elif defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
FAR struct spi_dev_s *spi;
#endif
uint8_t power;
* 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[SSD1351_XRES];
* to 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.
*/
#ifdef CONFIG_SSD1351_SPI3WIRE
uint16_t rowbuffer[SSD1351_STRIDE + 1];
#endif
};
* Private Function Prototypes
****************************************************************************/
#ifdef CONFIG_SSD1351_PARALLEL8BIT
#define ssd1351_select(priv)
#define ssd1351_deselect(priv)
#elif defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
static void ssd1351_select(FAR struct ssd1351_dev_s *priv);
static void ssd1351_deselect(FAR struct ssd1351_dev_s *priv);
#endif
#if defined(CONFIG_SSD1351_PARALLEL8BIT) && !defined(CONFIG_LCD_NOGETRUN)
static void ssd1351_read(FAR struct ssd1351_dev_s *priv, uint8_t cmd,
FAR uint8_t *data, size_t datlen);
#endif
static void ssd1351_write(FAR struct ssd1351_dev_s *priv, uint8_t cmd,
FAR const uint8_t *data, size_t datlen);
static int ssd1351_putrun(FAR struct lcd_dev_s *dev,
fb_coord_t row, fb_coord_t col,
FAR const uint8_t *buffer, size_t npixels);
static int ssd1351_getrun(FAR struct lcd_dev_s *dev,
fb_coord_t row, fb_coord_t col,
FAR uint8_t *buffer, size_t npixels);
static int ssd1351_getvideoinfo(FAR struct lcd_dev_s *dev,
FAR struct fb_videoinfo_s *vinfo);
static int ssd1351_getplaneinfo(FAR struct lcd_dev_s *dev,
unsigned int planeno,
FAR struct lcd_planeinfo_s *pinfo);
#ifdef CONFIG_FB_CMAP
# error "RGB color mapping not supported by this driver"
#endif
#ifdef CONFIG_FB_HWCURSOR
# error "Cursor control not supported by this driver"
#endif
static int ssd1351_getpower(struct lcd_dev_s *dev);
static int ssd1351_setpower(struct lcd_dev_s *dev, int power);
static int ssd1351_getcontrast(struct lcd_dev_s *dev);
static int ssd1351_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
static inline void ssd1351_hwinitialize(FAR struct ssd1351_dev_s *priv);
* Private Data
****************************************************************************/
static struct ssd1351_dev_s g_lcddev;
* Private Functions
****************************************************************************/
* Name: ssd1351_select
*
* Description:
* Select the SPI, locking and re-configuring if necessary.
*
****************************************************************************/
#if defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
static void ssd1351_select(FAR struct ssd1351_dev_s *priv)
{
FAR struct spi_dev_s *spi = priv->spi;
* competing for the SPI bus
*/
ginfo("SELECTED\n");
SPI_LOCK(spi, true);
SPI_SELECT(spi, SPIDEV_DISPLAY(0), true);
* have gotten configured for a different device while unlocked)
*/
SPI_SETMODE(spi, CONFIG_SSD1351_SPIMODE);
SPI_SETBITS(spi, SSD1351_SPIBITS);
SPI_HWFEATURES(spi, 0);
SPI_SETFREQUENCY(spi, CONFIG_SSD1351_SPIFREQ);
}
#endif
* Name: ssd1351_deselect
*
* Description:
* De-select the SPI.
*
****************************************************************************/
#if defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
static void ssd1351_deselect(FAR struct ssd1351_dev_s *priv)
{
FAR struct spi_dev_s *spi = priv->spi;
ginfo("DE-SELECTED\n");
SPI_SELECT(spi, SPIDEV_DISPLAY(0), false);
SPI_LOCK(spi, false);
}
#endif
* Name: ssd1351_read
*
* Description:
* Send a 1-byte command and read datlen data bytes.
*
****************************************************************************/
#if defined(CONFIG_SSD1351_PARALLEL8BIT) && !defined(CONFIG_LCD_NOGETRUN)
static void ssd1351_read(FAR struct ssd1351_dev_s *priv, uint8_t cmd,
FAR uint8_t *data, size_t datlen)
{
FAR struct ssd1351_lcd_s *lcd = priv->lcd;
size_t i;
DEBUGASSERT(priv != NULL);
DEBUGASSERT((data == NULL && datlen == 0) || (data != NULL && datlen > 0));
lcd->cmd(lcd, cmd);
if (cmd == SSD1351_CMD_RAMREAD)
{
lcd->read(lcd);
}
for (i = 0; i < datlen; i++)
{
data[i] = lcd->read(lcd);
}
}
#endif
* Name: ssd1351_write
*
* Description:
* Send a 1-byte command followed by datlen data bytes.
*
****************************************************************************/
#ifdef CONFIG_SSD1351_PARALLEL8BIT
static void ssd1351_write(FAR struct ssd1351_dev_s *priv, uint8_t cmd,
FAR const uint8_t *data, size_t datlen)
{
FAR struct ssd1351_lcd_s *lcd = priv->lcd;
size_t i;
DEBUGASSERT(priv != NULL);
DEBUGASSERT((data == NULL && datlen == 0) || (data != NULL && datlen > 0));
lcd->cmd(lcd, cmd);
for (i = 0; i < datlen; i++)
{
lcd->write(lcd, data[i]);
}
}
#elif defined(CONFIG_SSD1351_SPI3WIRE)
static void ssd1351_write(FAR struct ssd1351_dev_s *priv, uint8_t cmd,
FAR const uint8_t *data, size_t datlen)
{
size_t i;
DEBUGASSERT(priv != NULL);
DEBUGASSERT((data == NULL && datlen == 0) || (data != NULL && datlen > 0));
DEBUGASSERT(datlen <= SSD1351_STRIDE);
priv->rowbuffer[0] = (uint16_t)cmd | SSD1351_SPICMD;
for (i = 0; i < datlen; i++)
{
priv->rowbuffer[i + 1] = (uint16_t)data[i] | SSD1351_SPIDATA;
}
SPI_SNDBLOCK(priv->spi, priv->rowbuffer, datlen + 1);
}
#elif defined(CONFIG_SSD1351_SPI4WIRE)
static void ssd1351_write(FAR struct ssd1351_dev_s *priv, uint8_t cmd,
FAR const uint8_t *data, size_t datlen)
{
FAR struct spi_dev_s *spi = priv->spi;
DEBUGASSERT(priv != NULL);
DEBUGASSERT((data == NULL && datlen == 0) || (data != NULL && datlen > 0));
SPI_CMDDATA(spi, SPIDEV_DISPLAY(0), true);
SPI_SEND(spi, cmd);
if (datlen > 0)
{
SPI_CMDDATA(spi, SPIDEV_DISPLAY(0), false);
SPI_SNDBLOCK(spi, data, datlen);
}
}
#endif
* Name: ssd1351_setcursor
*
* Description:
* Set the cursor position.
*
****************************************************************************/
static void ssd1351_setcursor(FAR struct ssd1351_dev_s *priv, uint8_t col,
uint8_t row)
{
uint8_t buf[2];
#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
buf[0] = col;
buf[1] = SSD1351_XRES - 1;
ssd1351_write(priv, SSD1351_CMD_COLADDR, buf, 2);
buf[0] = row;
buf[1] = SSD1351_YRES - 1;
ssd1351_write(priv, SSD1351_CMD_ROWADDR, buf, 2);
#elif defined(CONFIG_LCD_PORTRAIT) || defined(CONFIG_LCD_RPORTRAIT)
buf[0] = row;
buf[1] = SSD1351_YRES - 1;
ssd1351_write(priv, SSD1351_CMD_COLADDR, buf, 2);
buf[0] = col;
buf[1] = SSD1351_XRES - 1;
ssd1351_write(priv, SSD1351_CMD_ROWADDR, buf, 2);
#endif
}
* Name: ssd1351_putrun
*
* Description:
* This method can be used to write a partial raster line to the LCD:
*
* Input Parameters:
* dev - The lcd device
* 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 ssd1351_putrun(FAR struct lcd_dev_s *dev,
fb_coord_t row, fb_coord_t col,
FAR const uint8_t *buffer, size_t npixels)
{
FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev;
DEBUGASSERT(buffer != NULL && ((uintptr_t)buffer & 1) == 0 &&
col >= 0 && col + npixels <= SSD1351_XRES &&
row >= 0 && row < SSD1351_YRES);
ssd1351_select(priv);
ssd1351_setcursor(priv, col, row);
ssd1351_write(priv, SSD1351_CMD_RAMWRITE, buffer,
SSD1351_PIX2BYTES(npixels));
ssd1351_deselect(priv);
return OK;
}
* Name: ssd1351_getrun
*
* Description:
* This method can be used to read a partial raster line from the LCD.
*
* Input Parameters:
* dev - The lcd device
* row - Starting row to read from (range: 0 <= row < yres)
* col - Starting column to read from (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 ssd1351_getrun(FAR struct lcd_dev_s *dev,
fb_coord_t row, fb_coord_t col,
FAR uint8_t *buffer, size_t npixels)
{
#if defined(CONFIG_SSD1351_PARALLEL8BIT) && !defined(CONFIG_LCD_NOGETRUN)
FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev;
DEBUGASSERT(buffer != NULL && ((uintptr_t)buffer & 1) == 0 &&
col >= 0 && col + npixels <= SSD1351_XRES &&
row >= 0 && row < SSD1351_YRES);
ssd1351_select(priv);
ssd1351_setcursor(priv, col, row);
ssd1351_read(priv, SSD1351_CMD_RAMREAD, buffer,
SSD1351_PIX2BYTES(npixels));
ssd1351_deselect(priv);
return OK;
#else
return -ENOSYS;
#endif
}
* Name: ssd1351_getvideoinfo
*
* Description:
* Get information about the LCD video controller configuration.
*
****************************************************************************/
static int ssd1351_getvideoinfo(FAR struct lcd_dev_s *dev,
FAR struct fb_videoinfo_s *vinfo)
{
DEBUGASSERT(dev != NULL && vinfo != NULL);
vinfo->fmt = SSD1351_COLORFMT;
vinfo->xres = SSD1351_XRES;
vinfo->yres = SSD1351_YRES;
vinfo->nplanes = 1;
ginfo("fmt: %u xres: %u yres: %u nplanes: %u\n",
vinfo->fmt, vinfo->xres, vinfo->yres, vinfo->nplanes);
return OK;
}
* Name: ssd1351_getplaneinfo
*
* Description:
* Get information about the configuration of each LCD color plane.
*
****************************************************************************/
static int ssd1351_getplaneinfo(FAR struct lcd_dev_s *dev,
unsigned int planeno,
FAR struct lcd_planeinfo_s *pinfo)
{
FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev;
DEBUGASSERT(dev != NULL && pinfo != NULL && planeno == 0);
pinfo->putrun = ssd1351_putrun;
pinfo->getrun = ssd1351_getrun;
pinfo->buffer = (FAR uint8_t *)priv->runbuffer;
pinfo->bpp = SSD1351_BPP;
pinfo->dev = dev;
ginfo("planeno: %u bpp: %u\n", planeno, pinfo->bpp);
return OK;
}
* Name: ssd1351_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 ssd1351_getpower(FAR struct lcd_dev_s *dev)
{
FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev;
DEBUGASSERT(priv != NULL);
ginfo("power: %d\n", priv->power);
return priv->power;
}
* Name: ssd1351_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 ssd1351_setpower(FAR struct lcd_dev_s *dev, int power)
{
FAR struct ssd1351_dev_s *priv = (FAR struct ssd1351_dev_s *)dev;
DEBUGASSERT(priv != NULL && (unsigned int)power <= LCD_FULL_ON);
ginfo("power: %d\n", power);
ssd1351_select(priv);
if (power > LCD_FULL_OFF)
{
ssd1351_write(priv, SSD1351_CMD_DISPON, NULL, 0);
priv->power = LCD_FULL_ON;
}
else
{
ssd1351_write(priv, SSD1351_CMD_DISPOFF, NULL, 0);
priv->power = LCD_FULL_OFF;
}
ssd1351_deselect(priv);
return OK;
}
* Name: ssd1351_getcontrast
*
* Description:
* Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
*
****************************************************************************/
static int ssd1351_getcontrast(FAR struct lcd_dev_s *dev)
{
return -ENOSYS;
}
* Name: ssd1351_setcontrast
*
* Description:
* Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
*
****************************************************************************/
static int ssd1351_setcontrast(FAR struct lcd_dev_s *dev,
unsigned int contrast)
{
return -ENOSYS;
}
* Name: ssd1351_hwinitialize
*
* Description:
* Initialize the video hardware.
*
****************************************************************************/
static inline void ssd1351_hwinitialize(FAR struct ssd1351_dev_s *priv)
{
size_t i;
uint8_t buf[3];
ssd1351_select(priv);
buf[0] = SSD1351_UNLOCK;
ssd1351_write(priv, SSD1351_CMD_LOCK, buf, 1);
buf[0] = SSD1351_ACCESSIBLE;
ssd1351_write(priv, SSD1351_CMD_LOCK, buf, 1);
ssd1351_write(priv, SSD1351_CMD_DISPOFF, NULL, 0);
* sequence, the scan direction, the COM split, and the color depth
*/
buf[0] = SSD1351_COLORABC | SSD1351_SPLITEN | SSD1351_DEPTH65K;
#if defined(CONFIG_LCD_LANDSCAPE) || defined(CONFIG_LCD_RLANDSCAPE)
buf[0] |= SSD1351_ADDRINCHORIZ;
#else
buf[0] |= SSD1351_ADDRINCVERT;
#endif
#if (defined(CONFIG_LCD_LANDSCAPE) && !defined(CONFIG_SSD1351_MIRRORX)) || \
(defined(CONFIG_LCD_RLANDSCAPE) && defined(CONFIG_SSD1351_MIRRORX)) || \
(defined(CONFIG_LCD_PORTRAIT) && !defined(CONFIG_SSD1351_MIRRORY)) || \
(defined(CONFIG_LCD_RPORTRAIT) && defined(CONFIG_SSD1351_MIRRORY))
buf[0] |= SSD1351_REMAPCOL0;
#else
buf[0] |= SSD1351_REMAPCOL127;
#endif
#if (defined(CONFIG_LCD_LANDSCAPE) && !defined(CONFIG_SSD1351_MIRRORY)) || \
(defined(CONFIG_LCD_RLANDSCAPE) && defined(CONFIG_SSD1351_MIRRORY)) || \
(defined(CONFIG_LCD_PORTRAIT) && defined(CONFIG_SSD1351_MIRRORX)) || \
(defined(CONFIG_LCD_RPORTRAIT) && !defined(CONFIG_SSD1351_MIRRORX))
buf[0] |= SSD1351_SCANTOCOM0;
#else
buf[0] |= SSD1351_SCANFROMCOM0;
#endif
ssd1351_write(priv, SSD1351_CMD_ORIENTATION, buf, 1);
#if (defined(CONFIG_LCD_LANDSCAPE) && !defined(CONFIG_SSD1351_MIRRORY)) || \
(defined(CONFIG_LCD_RLANDSCAPE) && defined(CONFIG_SSD1351_MIRRORY)) || \
(defined(CONFIG_LCD_PORTRAIT) && defined(CONFIG_SSD1351_MIRRORX)) || \
(defined(CONFIG_LCD_RPORTRAIT) && !defined(CONFIG_SSD1351_MIRRORX))
buf[0] = SSD1351_STARTLINE(CONFIG_SSD1351_YRES);
#else
buf[0] = SSD1351_STARTLINE(0);
#endif
ssd1351_write(priv, SSD1351_CMD_STARTLINE, buf, 1);
buf[0] = SSD1351_OFFSET(0);
ssd1351_write(priv, SSD1351_CMD_OFFSET, buf, 1);
#ifdef CONFIG_SSD1351_INVERT
ssd1351_write(priv, SSD1351_CMD_INVERSE, NULL, 0);
#else
ssd1351_write(priv, SSD1351_CMD_NORMAL, NULL, 0);
#endif
#ifdef CONFIG_SSD1351_VDDEXT
buf[0] = SSD1351_VDDEXT;
#else
buf[0] = SSD1351_VDDINT;
#endif
buf[0] |= SSD1351_IFACE8BIT;
ssd1351_write(priv, SSD1351_CMD_VDDIFACE, buf, 1);
buf[0] = SSD1351_TRST(CONFIG_SSD1351_TRST) |
SSD1351_TPRECHG1(CONFIG_SSD1351_TPRECHG1);
ssd1351_write(priv, SSD1351_CMD_TRSTTPRECHG1, buf, 1);
#ifdef CONFIG_SSD1351_PERFENHANCE
buf[0] = SSD1351_PERFENHANCE;
#else
buf[0] = SSD1351_PERFNORMAL;
#endif
buf[1] = SSD1351_PERFDATA2;
buf[2] = SSD1351_PERFDATA3;
ssd1351_write(priv, SSD1351_CMD_PERF, buf, 3);
buf[0] = SSD1351_CLKDIV(CONFIG_SSD1351_CLKDIV) |
SSD1351_OSCFREQ(CONFIG_SSD1351_OSCFREQ);
ssd1351_write(priv, SSD1351_CMD_DIVFREQ, buf, 1);
buf[0] = SSD1351_VSLEXT;
buf[1] = SSD1351_VSLDATA2;
buf[2] = SSD1351_VSLDATA3;
ssd1351_write(priv, SSD1351_CMD_VSL, buf, 3);
buf[0] = SSD1351_GPIO0(SSD1351_GPIOLOW) | SSD1351_GPIO1(SSD1351_GPIOLOW);
ssd1351_write(priv, SSD1351_CMD_GPIO, buf, 1);
buf[0] = SSD1351_TPRECHG2(CONFIG_SSD1351_TPRECHG2);
ssd1351_write(priv, SSD1351_CMD_TPRECHG2, buf, 1);
ssd1351_write(priv, SSD1351_CMD_LINEARLUT, NULL, 0);
buf[0] = SSD1351_VPRECHG(CONFIG_SSD1351_VPRECHG);
ssd1351_write(priv, SSD1351_CMD_VPRECHG, buf, 1);
buf[0] = SSD1351_VCOMH(CONFIG_SSD1351_VCOMH);
ssd1351_write(priv, SSD1351_CMD_VCOMH, buf, 1);
buf[0] = SSD1351_CONTRAST(CONFIG_SSD1351_CONTRASTA);
buf[1] = SSD1351_CONTRAST(CONFIG_SSD1351_CONTRASTB);
buf[2] = SSD1351_CONTRAST(CONFIG_SSD1351_CONTRASTC);
ssd1351_write(priv, SSD1351_CMD_CONTRAST, buf, 3);
buf[0] = SSD1351_MSTRCONTRAST(CONFIG_SSD1351_MSTRCONTRAST);
ssd1351_write(priv, SSD1351_CMD_MSTRCONTRAST, buf, 1);
buf[0] = SSD1351_MUXRATIO(128);
ssd1351_write(priv, SSD1351_CMD_MUXRATIO, buf, 1);
buf[0] = SSD1351_INACCESSIBLE;
ssd1351_write(priv, SSD1351_CMD_LOCK, buf, 1);
ssd1351_setcursor(priv, 0, 0);
buf[0] = 0;
buf[1] = 0;
for (i = 0; i < SSD1351_XRES * SSD1351_YRES; i++)
{
ssd1351_write(priv, SSD1351_CMD_RAMWRITE, buf, 2);
}
ssd1351_deselect(priv);
}
* Name: ssd1351_initialize
*
* Description:
* Initialize the video hardware. The initial state of the device
* is fully initialized, display memory cleared, and ready to use,
* but with the power setting at 0 (full off == sleep mode).
*
* Input Parameters:
* lcd - A reference to the platform-specific interface.
* spi - A reference to the SPI driver instance.
* devno - A value in the range of 0 through CONFIG_SSD1351_NINTERFACES-1.
* This allows support for multiple devices.
*
* Returned Value:
* On success, this function returns a reference to the LCD object for the
* specified device. NULL is returned on failure.
*
****************************************************************************/
#ifdef CONFIG_SSD1351_PARALLEL8BIT
FAR struct lcd_dev_s *ssd1351_initialize(FAR struct ssd1351_lcd_s *lcd,
unsigned int devno)
#elif defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
FAR struct lcd_dev_s *ssd1351_initialize(FAR struct spi_dev_s *spi,
unsigned int devno)
#endif
{
FAR struct ssd1351_dev_s *priv = &g_lcddev;
#ifdef CONFIG_SSD1351_PARALLEL8BIT
DEBUGASSERT(lcd != NULL);
#elif defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
DEBUGASSERT(spi != NULL);
#endif
DEBUGASSERT(devno == 0);
priv->dev.getvideoinfo = ssd1351_getvideoinfo;
priv->dev.getplaneinfo = ssd1351_getplaneinfo;
priv->dev.getpower = ssd1351_getpower;
priv->dev.setpower = ssd1351_setpower;
priv->dev.getcontrast = ssd1351_getcontrast;
priv->dev.setcontrast = ssd1351_setcontrast;
#ifdef CONFIG_SSD1351_PARALLEL8BIT
priv->lcd = lcd;
#elif defined(CONFIG_SSD1351_SPI3WIRE) || defined(CONFIG_SSD1351_SPI4WIRE)
priv->spi = spi;
#endif
priv->power = LCD_FULL_OFF;
ssd1351_hwinitialize(priv);
return &priv->dev;
}
#endif