123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730 |
- /****************************************************************************
- * drivers/lcd/memlcd.c
- * Driver for Sharp Memory LCD.
- *
- * Copyright (C) 2013 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt <gnutt@nuttx.org>
- * Librae <librae8226@gmail.com>
- *
- * 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 writen 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/spi.h>
- #include <nuttx/lcd/lcd.h>
- #include <nuttx/lcd/memlcd.h>
- #include <arch/irq.h>
- /****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
- /* Bit order H/W feature must be enabled in order to support LSB first
- * operation.
- */
- #if !defined(CONFIG_SPI_HWFEATURES) || !defined(CONFIG_SPI_BITORDER)
- # error CONFIG_SPI_HWFEATURES=y and CONFIG_SPI_BITORDER=y required by this driver
- #endif
- #ifndef CONFIG_ARCH_HAVE_SPI_BITORDER
- # warning This platform does not support SPI LSB-bit order
- #endif
- /* Cisplay resolution */
- #if defined CONFIG_MEMLCD_LS013B7DH01
- # define MEMLCD_XRES 144
- # define MEMLCD_YRES 168
- #elif defined CONFIG_MEMLCD_LS013B7DH03
- # define MEMLCD_XRES 128
- # define MEMLCD_YRES 128
- #else
- # error "This Memory LCD model is not supported yet."
- #endif
- /* lcd command */
- #define MEMLCD_CMD_UPDATE (0x01)
- #define MEMLCD_CMD_ALL_CLEAR (0x04)
- #define MEMLCD_CONTROL_BYTES (0)
- /* Dolor depth and format */
- #define MEMLCD_BPP 1
- #define MEMLCD_COLORFMT FB_FMT_Y1
- /* Bytes per logical row and column */
- #define MEMLCD_XSTRIDE (MEMLCD_XRES >> 3)
- #define MEMLCD_YSTRIDE (MEMLCD_YRES >> 3)
- /* display memory allocation */
- #define MEMLCD_FBSIZE (MEMLCD_XSTRIDE*MEMLCD_YRES)
- /* contrast setting, related to VCOM toggle frequency
- * higher frequency gives better contrast, instead, saves power
- */
- #define MEMLCD_CONTRAST 24
- #define MEMLCD_MAXCONTRAST 60
- #define MEMLCD_MINCONTRAST 1
- /* Other misc settings */
- #define MEMLCD_SPI_FREQUENCY 2250000
- #define MEMLCD_SPI_BITS 8
- #define MEMLCD_SPI_MODE SPIDEV_MODE0
- #define LS_BIT (1 << 0)
- #define MS_BIT (1 << 7)
- /****************************************************************************
- * Private Type Definition
- ****************************************************************************/
- struct memlcd_dev_s
- {
- /* Publically visible device structure */
- struct lcd_dev_s dev;
- /* Private lcd-specific information follows */
- FAR struct spi_dev_s *spi; /* Cached SPI device reference */
- FAR struct memlcd_priv_s *priv; /* Board specific structure */
- uint8_t contrast; /* Current contrast setting */
- uint8_t power; /* Current power setting */
- /* The memlcds does not support reading the display memory in SPI mode.
- * Since there is 1 BPP and is byte access, it is necessary to keep a
- * shadow copy of the framebuffer. At 128x128, it amounts to 2KB.
- */
- uint8_t fb[MEMLCD_FBSIZE];
- };
- /****************************************************************************
- * Private Function Protototypes
- ****************************************************************************/
- /* Low-level spi helpers */
- static void memlcd_select(FAR struct spi_dev_s *spi);
- static void memlcd_deselect(FAR struct spi_dev_s *spi);
- /* lcd data transfer methods */
- static int memlcd_putrun(fb_coord_t row, fb_coord_t col,
- FAR const uint8_t * buffer, size_t npixels);
- static int memlcd_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t * buffer,
- size_t npixels);
- /* lcd configuration */
- static int memlcd_getvideoinfo(FAR struct lcd_dev_s *dev,
- FAR struct fb_videoinfo_s *vinfo);
- static int memlcd_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
- FAR struct lcd_planeinfo_s *pinfo);
- /* lcd specific controls */
- static int memlcd_getpower(struct lcd_dev_s *dev);
- static int memlcd_setpower(struct lcd_dev_s *dev, int power);
- static int memlcd_getcontrast(struct lcd_dev_s *dev);
- static int memlcd_setcontrast(struct lcd_dev_s *dev, unsigned int contrast);
- /****************************************************************************
- * Private Data
- ****************************************************************************/
- static uint8_t g_runbuffer[MEMLCD_BPP * MEMLCD_XRES / 8];
- /* This structure describes the overall lcd video controller */
- static const struct fb_videoinfo_s g_videoinfo =
- {
- .fmt = MEMLCD_COLORFMT, /* Color format: rgb16-565: rrrr rggg gggb bbbb */
- .xres = MEMLCD_XRES, /* Horizontal resolution in pixel columns */
- .yres = MEMLCD_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 = memlcd_putrun, /* Put a run into lcd memory */
- .getrun = memlcd_getrun, /* Get a run from lcd memory */
- .buffer = (uint8_t *) g_runbuffer, /* Run scratch buffer */
- .bpp = MEMLCD_BPP, /* Bits-per-pixel */
- };
- /* This is the oled driver instance (only a single device is supported for now) */
- static struct memlcd_dev_s g_memlcddev =
- {
- .dev =
- {
- /* lcd configuration */
- .getvideoinfo = memlcd_getvideoinfo,
- .getplaneinfo = memlcd_getplaneinfo,
- /* lcd specific controls */
- .getpower = memlcd_getpower,
- .setpower = memlcd_setpower,
- .getcontrast = memlcd_getcontrast,
- .setcontrast = memlcd_setcontrast,
- },
- };
- /****************************************************************************
- * Private Functions
- ****************************************************************************/
- /****************************************************************************
- * __set_bit - Set a bit in memory
- *
- * @nr: the bit to set
- * @addr: the address to start counting from
- *
- * Unlike set_bit(), this function is non-atomic and may be reordered.
- * If it's called on the same region of memory simultaneously, the effect
- * may be that only one operation succeeds.
- *
- ****************************************************************************/
- #define BIT(nr) (1 << (nr))
- #define BITS_PER_BYTE 8
- #define BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
- #define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE)
- static inline void __set_bit(int nr, uint8_t * addr)
- {
- uint8_t mask = BIT_MASK(nr);
- uint8_t *p = ((uint8_t *) addr) + BIT_BYTE(nr);
- *p |= mask;
- }
- static inline void __clear_bit(int nr, uint8_t * addr)
- {
- uint8_t mask = BIT_MASK(nr);
- uint8_t *p = ((uint8_t *) addr) + BIT_BYTE(nr);
- *p &= ~mask;
- }
- static inline int __test_bit(int nr, const volatile uint8_t * addr)
- {
- return 1 & (addr[BIT_BYTE(nr)] >> (nr & (BITS_PER_BYTE - 1)));
- }
- /****************************************************************************
- * Name: memlcd_select
- *
- * Description:
- * Select the SPI, locking and re-configuring if necessary
- *
- * Input Parameters:
- * spi - Reference to the SPI driver structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
- static void memlcd_select(FAR struct spi_dev_s *spi)
- {
- int ret;
- /* Select memlcd (locking the SPI bus in case there are multiple
- * devices competing for the SPI bus
- */
- SPI_LOCK(spi, true);
- SPI_SELECT(spi, SPIDEV_DISPLAY(0), true);
- /* Now make sure that the SPI bus is configured for the memlcd (it
- * might have gotten configured for a different device while unlocked)
- */
- SPI_SETMODE(spi, MEMLCD_SPI_MODE);
- SPI_SETBITS(spi, MEMLCD_SPI_BITS);
- ret = SPI_HWFEATURES(spi, HWFEAT_LSBFIRST);
- if (ret < 0)
- {
- lcderr("ERROR: SPI_HWFEATURES failed to set bit order: %d\n", ret);
- }
- #ifdef CONFIG_MEMLCD_SPI_FREQUENCY
- (void)SPI_SETFREQUENCY(spi, CONFIG_MEMLCD_SPI_FREQUENCY);
- #else
- (void)SPI_SETFREQUENCY(spi, MEMLCD_SPI_FREQUENCY);
- #endif
- }
- /****************************************************************************
- * Name: memlcd_deselect
- *
- * Description:
- * De-select the SPI
- *
- * Input Parameters:
- * spi - Reference to the SPI driver structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
- static void memlcd_deselect(FAR struct spi_dev_s *spi)
- {
- /* De-select memlcd and relinquish the spi bus. */
- SPI_SELECT(spi, SPIDEV_DISPLAY(0), false);
- SPI_LOCK(spi, false);
- }
- /****************************************************************************
- * Name: memlcd_clear
- *
- * Description:
- * This method can be used to clear the entire display.
- *
- * Input Parameters:
- * mlcd - Reference to private driver structure
- *
- * Assumptions:
- *
- ****************************************************************************/
- static inline void memlcd_clear(FAR struct memlcd_dev_s *mlcd)
- {
- uint16_t cmd = MEMLCD_CMD_ALL_CLEAR;
- lcdinfo("Clear display\n");
- memlcd_select(mlcd->spi);
- /* XXX Ensure 2us here */
- SPI_SNDBLOCK(mlcd->spi, &cmd, 2);
- /* XXX Ensure 6us here */
- memlcd_deselect(mlcd->spi);
- }
- /****************************************************************************
- * Name: memlcd_extcominisr
- *
- * Description:
- * This method enables/disables the polarity (VCOM) toggling behavior for
- * the Memory LCD. Which is always used within setpower() call.
- * Basically, the frequency shall be 1Hz~60Hz.
- * If use hardware mode to toggle VCOM, we need to send specific command at a
- * constant frequency to trigger the LCD internal hardware logic.
- * While use software mode, we set up a timer to toggle EXTCOMIN connected IO,
- * basically, it is a hardware timer to ensure a constant frequency.
- *
- * Input Parameters:
- * mlcd - Reference to private driver structure
- *
- * Assumptions:
- * Board specific logic needs to be provided to support it.
- *
- ****************************************************************************/
- static int memlcd_extcominisr(int irq, FAR void *context, void *arg)
- {
- static bool pol = 0;
- struct memlcd_dev_s *mlcd = &g_memlcddev;
- #ifdef CONFIG_MEMLCD_EXTCOMIN_MODE_HW
- # error "CONFIG_MEMLCD_EXTCOMIN_MODE_HW unsupported yet!"
- /* Start a worker thread, do it in bottom half? */
- #else
- pol = !pol;
- mlcd->priv->setpolarity(pol);
- #endif
- return OK;
- }
- /****************************************************************************
- * Name: memlcd_putrun
- *
- * Description:
- * This method can be used to write a partial raster line to the LCD.
- *
- * Input Parameters:
- * row - Starting row to write to (range: 0 <= row < yres)
- * col - Starting column to write to (range: 0 <= col <= xres-npixels)
- * buffer - The buffer containing the run to be writen to the LCD
- * npixels - The number of pixels to write to the LCD
- * (range: 0 < npixels <= xres-col)
- *
- ****************************************************************************/
- static int memlcd_putrun(fb_coord_t row, fb_coord_t col,
- FAR const uint8_t * buffer, size_t npixels)
- {
- FAR struct memlcd_dev_s *mlcd = (FAR struct memlcd_dev_s *)&g_memlcddev;
- uint16_t cmd;
- uint8_t *p;
- uint8_t *pfb;
- uint8_t usrmask;
- int i;
- DEBUGASSERT(buffer);
- lcdinfo("row: %d col: %d npixels: %d\n", row, col, npixels);
- #ifdef CONFIG_LCD_PACKEDMSFIRST
- usrmask = MS_BIT;
- #else
- usrmask = LS_BIT;
- #endif
- pfb = &mlcd->fb[row * MEMLCD_XSTRIDE];
- p = pfb + (col >> 3);
- for (i = 0; i < npixels; i++)
- {
- if ((*buffer & usrmask) != 0)
- {
- __set_bit(col % 8 + i, p);
- }
- else
- {
- __clear_bit(col % 8 + i, p);
- }
- #ifdef CONFIG_LCD_PACKEDMSFIRST
- if (usrmask == LS_BIT)
- {
- buffer++;
- usrmask = MS_BIT;
- }
- else
- {
- usrmask >>= 1;
- }
- #else
- if (usrmask == MS_BIT)
- {
- buffer++;
- usrmask = LS_BIT;
- }
- else
- {
- usrmask <<= 1;
- }
- #endif
- }
- /* Need to adjust start row by one because Memory LCD starts counting
- * lines from 1, while the display interface starts from 0.
- */
- row++;
- memlcd_select(mlcd->spi);
- /* XXX Ensure 6us here */
- cmd = MEMLCD_CMD_UPDATE | row << 8;
- SPI_SNDBLOCK(mlcd->spi, &cmd, 2);
- SPI_SNDBLOCK(mlcd->spi, pfb, MEMLCD_YRES / 8 + MEMLCD_CONTROL_BYTES);
- cmd = 0xffff;
- SPI_SNDBLOCK(mlcd->spi, &cmd, 2);
- /* XXX Ensure 2us here */
- memlcd_deselect(mlcd->spi);
- return OK;
- }
- /****************************************************************************
- * Name: memlcd_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 memlcd_getrun(fb_coord_t row, fb_coord_t col, FAR uint8_t * buffer,
- size_t npixels)
- {
- FAR struct memlcd_dev_s *mlcd = (FAR struct memlcd_dev_s *)&g_memlcddev;
- uint8_t *p;
- uint8_t *pfb;
- uint8_t usrmask;
- int i;
- DEBUGASSERT(buffer);
- lcdinfo("row: %d col: %d npixels: %d\n", row, col, npixels);
- #ifdef CONFIG_LCD_PACKEDMSFIRST
- usrmask = MS_BIT;
- #else
- usrmask = LS_BIT;
- #endif
- pfb = &mlcd->fb[row * MEMLCD_XSTRIDE];
- p = pfb + (col >> 3);
- for (i = 0; i < npixels; i++)
- {
- if (__test_bit(col % 8 + i, p))
- {
- *buffer |= usrmask;
- }
- else
- {
- *buffer &= ~usrmask;
- }
- #ifdef CONFIG_LCD_PACKEDMSFIRST
- if (usrmask == LS_BIT)
- {
- buffer++;
- usrmask = MS_BIT;
- }
- else
- {
- usrmask >>= 1;
- }
- #else
- if (usrmask == MS_BIT)
- {
- buffer++;
- usrmask = LS_BIT;
- }
- else
- {
- usrmask <<= 1;
- }
- #endif
- }
- return OK;
- }
- /****************************************************************************
- * Name: memlcd_getvideoinfo
- *
- * Description:
- * Get information about the LCD video controller configuration.
- *
- ****************************************************************************/
- static int memlcd_getvideoinfo(FAR struct lcd_dev_s *dev,
- FAR struct fb_videoinfo_s *vinfo)
- {
- DEBUGASSERT(dev && vinfo);
- lcdinfo("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: memlcd_getplaneinfo
- *
- * Description:
- * Get information about the configuration of each LCD color plane.
- *
- ****************************************************************************/
- static int memlcd_getplaneinfo(FAR struct lcd_dev_s *dev, unsigned int planeno,
- FAR struct lcd_planeinfo_s *pinfo)
- {
- DEBUGASSERT(pinfo && planeno == 0);
- lcdinfo("planeno: %d bpp: %d\n", planeno, g_planeinfo.bpp);
- memcpy(pinfo, &g_planeinfo, sizeof(struct lcd_planeinfo_s));
- return OK;
- }
- /****************************************************************************
- * Name: memlcd_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 memlcd_getpower(FAR struct lcd_dev_s *dev)
- {
- FAR struct memlcd_dev_s *mlcd = (FAR struct memlcd_dev_s *)dev;
- DEBUGASSERT(mlcd);
- lcdinfo("%d\n", mlcd->power);
- return mlcd->power;
- }
- /****************************************************************************
- * Name: memlcd_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 memlcd_setpower(FAR struct lcd_dev_s *dev, int power)
- {
- struct memlcd_dev_s *mlcd = (struct memlcd_dev_s *)dev;
- DEBUGASSERT(mlcd && (unsigned)power <= CONFIG_LCD_MAXPOWER && mlcd->spi);
- lcdinfo("%d\n", power);
- mlcd->power = power;
- if (power > 0)
- {
- mlcd->priv->dispcontrol(1);
- memlcd_clear(mlcd);
- }
- else
- {
- mlcd->priv->dispcontrol(0);
- }
- return OK;
- }
- /****************************************************************************
- * Name: memlcd_getcontrast
- *
- * Description:
- * Get the current contrast setting (0-CONFIG_LCD_MAXCONTRAST).
- *
- ****************************************************************************/
- static int memlcd_getcontrast(struct lcd_dev_s *dev)
- {
- struct memlcd_dev_s *mlcd = (struct memlcd_dev_s *)dev;
- DEBUGASSERT(mlcd);
- lcdinfo("contrast: %d\n", mlcd->contrast);
- return mlcd->contrast;
- }
- /****************************************************************************
- * Name: memlcd_setcontrast
- *
- * Description:
- * Set LCD panel contrast (0-CONFIG_LCD_MAXCONTRAST).
- *
- ****************************************************************************/
- static int memlcd_setcontrast(struct lcd_dev_s *dev, unsigned int contrast)
- {
- struct memlcd_dev_s *mlcd = (struct memlcd_dev_s *)dev;
- DEBUGASSERT(mlcd);
- lcdinfo("contrast: %d\n", contrast);
- if (contrast > MEMLCD_MAXCONTRAST)
- {
- contrast = MEMLCD_MAXCONTRAST;
- }
- if (contrast < MEMLCD_MINCONTRAST)
- {
- contrast = MEMLCD_MINCONTRAST;
- }
- mlcd->contrast = contrast;
- mlcd->priv->setvcomfreq(contrast);
- return OK;
- }
- /****************************************************************************
- * Public Functions
- ****************************************************************************/
- /****************************************************************************
- * Name: memlcd_initialize
- *
- * Description:
- * Initialize the Sharp Memory LCD hardware. The initial state of the
- * OLED is fully initialized, display memory cleared, and the OLED ready
- * to use, but with the power setting at 0 (full off == sleep mode).
- *
- * Input Parameters:
- *
- * spi - A reference to the SPI driver instance.
- * devno - A value in the range of 0 through CONFIG_memlcd_NINTERFACES-1.
- * This allows support for multiple OLED devices.
- *
- * Returned Value:
- *
- * On success, this function returns a reference to the LCD object for
- * the specified LCD. NULL is returned on any failure.
- *
- ****************************************************************************/
- FAR struct lcd_dev_s *memlcd_initialize(FAR struct spi_dev_s *spi,
- FAR struct memlcd_priv_s *priv,
- unsigned int devno)
- {
- FAR struct memlcd_dev_s *mlcd = &g_memlcddev;
- DEBUGASSERT(spi && priv && devno == 0);
- /* Register board specific functions */
- mlcd->priv = priv;
- mlcd->spi = spi;
- mlcd->priv->attachirq(memlcd_extcominisr, mlcd);
- lcdinfo("done\n");
- return &mlcd->dev;
- }
|