616 lines
17 KiB
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;
|
|
}
|