incubator-nuttx/drivers/lcd/lpm013m091a.c

616 lines
17 KiB
C

/****************************************************************************
* drivers/lcd/lpm013m091a.c
*
* Driver for LPM013M091A LCD based on ili9341.c.
*
* Copyright (C) 2014 Marco Krahl. All rights reserved.
* Author: Marco Krahl <ocram.lhark@gmail.com>
*
* Copyright 2018 Sony Semiconductor Solutions Corporation
*
* 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/lcd/lcd.h>
#include <nuttx/lcd/lpm013m091a.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Display resolution */
#define LPM013M091A_XRES 320
#define LPM013M091A_YRES 300
/* TODO: Stride should be configurable by LCD orientation */
#define LPM013M091A_STRIDE LPM013M091A_XRES
/* Dolor depth and format */
#define LPM013M091A_BPP 16
#define LPM013M091A_COLORFMT FB_FMT_RGB16_565
/****************************************************************************
* Private types
****************************************************************************/
struct lpm013m091a_dev_s
{
/* Publicly visible device structure */
struct lcd_dev_s dev;
/* Private lcd-specific information follows */
struct lpm013m091a_lcd_s *lcd;
uint8_t power; /* Current power setting */
};
/****************************************************************************
* Private Function Protototypes
****************************************************************************/
static void lpm013m091a_selectarea(FAR struct lpm013m091a_lcd_s *lcd,
uint16_t x0, int16_t y0,
uint16_t x1, int16_t y1);
static int lpm013m091a_hwinitialize(FAR struct lpm013m091a_dev_s *dev);
/* lcd data transfer methods */
static int lpm013m091a_putrun(fb_coord_t row, fb_coord_t col,
FAR const uint8_t *buffer, size_t npixels);
#ifndef CONFIG_LCD_NOGETRUN
static int lpm013m091a_getrun(fb_coord_t row, fb_coord_t col,
FAR uint8_t *buffer,
size_t npixels);
#endif
/* lcd configuration */
static int lpm013m091a_getvideoinfo(FAR struct lcd_dev_s *dev,
FAR struct fb_videoinfo_s *vinfo);
static int lpm013m091a_getplaneinfo(FAR struct lcd_dev_s *dev,
unsigned int planeno,
FAR struct lcd_planeinfo_s *pinfo);
/* lcd specific controls */
static int lpm013m091a_getpower(FAR struct lcd_dev_s *dev);
static int lpm013m091a_setpower(FAR struct lcd_dev_s *dev, int power);
static int lpm013m091a_getcontrast(FAR struct lcd_dev_s *dev);
static int lpm013m091a_setcontrast(FAR struct lcd_dev_s *dev,
unsigned int contrast);
/****************************************************************************
* Private Data
****************************************************************************/
static uint16_t g_runbuffer[LPM013M091A_STRIDE];
/* This structure describes the overall lcd video controller */
static const struct fb_videoinfo_s g_videoinfo =
{
.fmt = LPM013M091A_COLORFMT, /* Color format: rgb16-565: rrrr rggg gggb bbbb */
.xres = LPM013M091A_XRES, /* Horizontal resolution in pixel columns */
.yres = LPM013M091A_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 = lpm013m091a_putrun, /* Put a run into lcd memory */
#ifndef CONFIG_LCD_NOGETRUN
.getrun = lpm013m091a_getrun, /* Get a run from lcd memory */
#endif
.buffer = (uint8_t *) g_runbuffer, /* Run scratch buffer */
.bpp = LPM013M091A_BPP, /* Bits-per-pixel */
};
static struct lpm013m091a_dev_s g_lpm013m091a_dev =
{
.dev =
{
/* lcd configuration */
.getvideoinfo = lpm013m091a_getvideoinfo,
.getplaneinfo = lpm013m091a_getplaneinfo,
/* lcd specific controls */
.getpower = lpm013m091a_getpower,
.setpower = lpm013m091a_setpower,
.getcontrast = lpm013m091a_getcontrast,
.setcontrast = lpm013m091a_setcontrast,
},
.lcd = 0,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: lpm013m091a_selectarea
*
* Description:
* Select the active area for displaying pixel
*
* Parameter:
* lcd - Reference to private driver structure
* x0 - Start x position
* y0 - Start y position
* x1 - End x position
* y1 - End y position
*
****************************************************************************/
static void lpm013m091a_selectarea(FAR struct lpm013m091a_lcd_s *lcd,
uint16_t x0, int16_t y0,
uint16_t x1, int16_t y1)
{
lcd->sendcmd(lcd, LPM013M091A_CASET);
lcd->sendparam(lcd, x0 >> 8);
lcd->sendparam(lcd, x0 & 0xff);
lcd->sendparam(lcd, x1 >> 8);
lcd->sendparam(lcd, x1 & 0xff);
lcd->sendcmd(lcd, LPM013M091A_PASET);
lcd->sendparam(lcd, y0 >> 8);
lcd->sendparam(lcd, y0 & 0xff);
lcd->sendparam(lcd, y1 >> 8);
lcd->sendparam(lcd, y1 & 0xff);
}
/****************************************************************************
* Name: lpm013m091a_hwinitialize
*
* Description:
* Initialize and configure the LPM013M091A LCD driver hardware.
*
* Parameter:
* dev - A reference to the driver specific structure
*
* Returned Value:
*
* On success - OK
* On error - EINVAL
*
****************************************************************************/
static int lpm013m091a_hwinitialize(FAR struct lpm013m091a_dev_s *dev)
{
FAR struct lpm013m091a_lcd_s *lcd = dev->lcd;
/* Soft reset */
lcd->sendcmd(lcd, LPM013M091A_SWRESET);
up_mdelay(10);
/* Analog mode */
lcd->sendcmd(lcd, 0xb3);
lcd->sendparam(lcd, 0x02);
/* Set Display Mode */
lcd->sendcmd(lcd, 0xbb);
lcd->sendparam(lcd, 0x10);
/* SPI GRAM access enable */
lcd->sendcmd(lcd, 0xf3);
lcd->sendparam(lcd, 0x02);
/* Bright Level Max */
lcd->sendcmd(lcd, 0x51);
lcd->sendparam(lcd, 0xff);
/* Backlight ON */
lcd->sendcmd(lcd, 0x53);
lcd->sendparam(lcd, 0x24);
/* Frame rate 60Hz */
lcd->sendcmd(lcd, 0xff);
lcd->sendparam(lcd, 0x24);
lcd->sendcmd(lcd, 0xd8);
lcd->sendparam(lcd, 0x41);
lcd->sendcmd(lcd, 0xd9);
lcd->sendparam(lcd, 0x1e);
lcd->sendcmd(lcd, 0xff);
lcd->sendparam(lcd, 0x10);
/* Set the color format (18bit:0x06, 16bit:0x05) */
lcd->sendcmd(lcd, LPM013M091A_PIXFMT);
lcd->sendparam(lcd, 0x05);
/* Sleep out */
lcd->sendcmd(lcd, LPM013M091A_SLPOUT);
up_mdelay(10);
/* Display on */
lcd->sendcmd(lcd, LPM013M091A_DISPON);
up_mdelay(120);
return OK;
}
/****************************************************************************
* Name: lpm013m091a_putrun
*
* Description:
* Write a partial raster line to the LCD.
*
* Parameters:
* devno - Number of 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
* (range: 0 < npixels <= xres-col)
*
* Returned Value:
*
* On success - OK
* On error - -EINVAL
*
****************************************************************************/
static int lpm013m091a_putrun(fb_coord_t row, fb_coord_t col,
FAR const uint8_t *buffer, size_t npixels)
{
FAR struct lpm013m091a_dev_s *dev = (FAR struct lpm013m091a_dev_s *)
&g_lpm013m091a_dev;
FAR struct lpm013m091a_lcd_s *lcd = dev->lcd;
FAR const uint16_t *src = (FAR const uint16_t *)buffer;
DEBUGASSERT(buffer && ((uintptr_t)buffer & 1) == 0);
/* Check if position outside of area */
if (col + npixels > LPM013M091A_XRES || row > LPM013M091A_YRES)
{
return -EINVAL;
}
/* Select lcd driver */
lcd->select(lcd);
/* Select column and area similar to the partial raster line */
lpm013m091a_selectarea(lcd, col, row, col + npixels - 1, row);
/* Send memory write cmd */
lcd->sendcmd(lcd, LPM013M091A_RAMWR);
/* Send pixel to gram */
lcd->sendgram(lcd, src, npixels);
/* Deselect the lcd driver */
lcd->deselect(lcd);
return OK;
}
/****************************************************************************
* Name: lpm013m091a_getrun
*
* Description:
* Read a partial raster line from the LCD.
*
* Parameter:
* devno - Number of the lcd device
* 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)
*
* Returned Value:
*
* On success - OK
* On error - -EINVAL
*
****************************************************************************/
#ifndef CONFIG_LCD_NOGETRUN
int lpm013m091a_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t * buffer,
size_t npixels)
{
lcderr("getrun is not supported for now.\n");
return -ENOSYS;
}
#endif
/****************************************************************************
* Name: lpm013m091a_getvideoinfo
*
* Description:
* Get information about the LCD video controller configuration.
*
* Parameter:
* dev - A reference to the driver specific structure
* vinfo - A reference to the videoinfo structure
*
* Returned Value:
*
* On success - OK
* On error - -EINVAL
*
****************************************************************************/
static int lpm013m091a_getvideoinfo(FAR struct lcd_dev_s *dev,
FAR struct fb_videoinfo_s *vinfo)
{
if (dev && vinfo)
{
memcpy(vinfo, &g_videoinfo, sizeof(struct fb_videoinfo_s));
lcdinfo("fmt: %d xres: %d yres: %d nplanes: %d\n",
vinfo->fmt, vinfo->xres, vinfo->yres, vinfo->nplanes);
return OK;
}
return -EINVAL;
}
/****************************************************************************
* Name: lpm013m091a_getplaneinfo
*
* Description:
* Get information about the configuration of each LCD color plane.
*
* Parameter:
* dev - A reference to the driver specific structure
* planeno - The plane number
* pinfo - A reference to the planeinfo structure
*
* Returned Value:
*
* On success - OK
* On error - -EINVAL
*
****************************************************************************/
static int lpm013m091a_getplaneinfo(FAR struct lcd_dev_s *dev,
unsigned int planeno,
FAR struct lcd_planeinfo_s *pinfo)
{
if (dev && pinfo && planeno == 0)
{
memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
lcdinfo("planeno: %d bpp: %d\n", planeno, pinfo->bpp);
return OK;
}
return -EINVAL;
}
/****************************************************************************
* Name: lpm013m091a_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.
*
* Parameter:
* dev - A reference to the driver specific structure
*
* Returned Value:
*
* On success - OK
* On error - -EINVAL
*
****************************************************************************/
static int lpm013m091a_getpower(FAR struct lcd_dev_s *dev)
{
FAR struct lpm013m091a_dev_s *priv = (FAR struct lpm013m091a_dev_s *)dev;
lcdinfo("%d\n", priv->power);
return priv->power;
}
/****************************************************************************
* Name: lpm013m091a_setpower
*
* Description:
* Enable/disable LCD panel power
* (0: full off - CONFIG_LCD_MAXPOWER: full on).
* On backlight LCDs, this setting may correspond to the backlight setting.
*
* Parameter:
* dev - A reference to the driver specific structure
* power - Value of the power
*
* Returned Value:
*
* On success - OK
* On error - -EINVAL
*
****************************************************************************/
static int lpm013m091a_setpower(FAR struct lcd_dev_s *dev, int power)
{
FAR struct lpm013m091a_dev_s *priv = (FAR struct lpm013m091a_dev_s *)dev;
FAR struct lpm013m091a_lcd_s *lcd = priv->lcd;
if (!dev)
{
return -EINVAL;
}
lcdinfo("%d\n", power);
lcd->select(lcd);
if (power > 0)
{
lcd->backlight(lcd, power);
lcd->sendcmd(lcd, LPM013M091A_DISPON);
up_mdelay(120);
}
else
{
lcd->sendcmd(lcd, LPM013M091A_DISPOFF);
}
lcd->deselect(lcd);
priv->power = power;
return OK;
}
/****************************************************************************
* Name: ili9340_getcontrast
*
* Description:
* Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
*
* Parameter:
* dev - A reference to the lcd driver structure
*
* Returned Value:
*
* On success - current contrast value
* On error - -ENOSYS, not supported by the ili9340.
*
****************************************************************************/
static int lpm013m091a_getcontrast(FAR struct lcd_dev_s *dev)
{
lcdinfo("Not implemented\n");
return -ENOSYS;
}
/****************************************************************************
* Name: ili9340_setcontrast
*
* Description:
* Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
*
* Parameter:
* dev - A reference to the lcd driver structure
*
* Returned Value:
*
* On success - OK
* On error - -ENOSYS, not supported by the ili9340.
*
****************************************************************************/
static int lpm013m091a_setcontrast(FAR struct lcd_dev_s *dev,
unsigned int contrast)
{
lcdinfo("Not implemented\n");
return -ENOSYS;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Initialize LCD
****************************************************************************/
FAR struct lcd_dev_s *
lpm013m091a_initialize(FAR struct lpm013m091a_lcd_s *lcd, int devno)
{
FAR struct lpm013m091a_dev_s *priv = &g_lpm013m091a_dev;
if (lcd && devno == 0)
{
if (!priv->lcd)
{
FAR struct lcd_dev_s *dev = &priv->dev;
int ret;
/* Initialize internal structure */
dev->getvideoinfo = lpm013m091a_getvideoinfo;
dev->getplaneinfo = lpm013m091a_getplaneinfo;
dev->getpower = lpm013m091a_getpower;
dev->setpower = lpm013m091a_setpower;
dev->getcontrast = lpm013m091a_getcontrast;
dev->setcontrast = lpm013m091a_setcontrast;
priv->lcd = lcd;
/* Initialize the LCD driver */
ret = lpm013m091a_hwinitialize(priv);
if (ret == OK)
{
return &priv->dev;
}
errno = EINVAL;
}
}
return NULL;
}