drivers/lcd: Add FT80x interrupt framework. Interrupts are still not used by the driver.

This commit is contained in:
Gregory Nutt
2018-02-17 16:36:11 -06:00
parent 885ab75045
commit 758e94f7a7
4 changed files with 194 additions and 14 deletions
+1
View File
@@ -1177,6 +1177,7 @@ endif # LCD_RA8875
config LCD_FT80X
bool "FTDI FT80x GUI Controller"
default n
select SCHED_HPWORK
depends on EXPERIMENTAL
---help---
Integrated LCD, Audio, Touchscreen controller driver for the FTDI
+23
View File
@@ -48,6 +48,9 @@
* Included Files
*******************************************************************************************/
#include <nuttx/config.h>
#include <nuttx/wqueue.h>
/*******************************************************************************************
* Pre-processor Definitions
*******************************************************************************************/
@@ -244,6 +247,25 @@
* frame is scanned out (recommended).
*/
/* Interrupts ******************************************************************************/
/* The interrupt output pin is enabled by REG_INT_EN. When REG_INT_EN is 0, INT_N is
* tri-state (pulled to high by external pull-up resistor). When REG_INT_EN is 1, INT_N is
* driven low when any of the interrupt flags in REG_INT_FLAGS are high, after masking with
* REG_INT_MASK. Writing a 1 in any bit of REG_INT_MASK will enable the correspond
* interrupt. Each bit in REG_INT_FLAGS is set by a corresponding interrupt source.
* REG_INT_FLAGS is readable by the host at any time, and clears when read.
*/
#define FT80X_INT_SWAP (1 << 0) /* Bit 0: Display swap occurred */
#define FT80X_INT_TOUCH (1 << 1) /* Bit 1: Touch-screen touch detected */
#define FT80X_INT_TAG (1 << 2) /* Bit 2: Touch-screen tag value change */
#define FT80X_INT_SOUND (1 << 3) /* Bit 3: Sound effect ended */
#define FT80X_INT_PLAYBACK (1 << 4) /* Bit 4: Audio playback ended */
#define FT80X_INT_CMDEMPTY (1 << 5) /* Bit 5: Command FIFO empty */
#define FT80X_INT_CMDFLAG (1 << 6) /* Bit 6: Command FIFO flag */
#define FT80X_INT_CONVCOMPLETE (1 << 7) /* Bit 7: Touch-screen conversions completed */
/*******************************************************************************************
* Public Types
*******************************************************************************************/
@@ -359,6 +381,7 @@ struct ft80x_dev_s
FAR struct i2c_master_s *i2c; /* Cached SPI device reference */
#endif
FAR const struct ft80x_config_s *lower; /* Cached lower half instance */
struct work_s intwork; /* Support back end interrupt processing */
uint32_t frequency; /* Effective frequency */
sem_t exclsem; /* Mutual exclusion semaphore */
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
+161 -9
View File
@@ -60,6 +60,7 @@
#include <nuttx/arch.h>
#include <nuttx/semaphore.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <nuttx/fs/fs.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/spi/spi.h>
@@ -90,6 +91,8 @@
* Private Function Prototypes
****************************************************************************/
static void ft80x_interrupt_work(FAR void *arg);
static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg);
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static void ft80x_destroy(FAR struct ft80x_dev_s *priv);
#endif
@@ -105,7 +108,7 @@ static ssize_t ft80x_write(FAR struct file *filep, FAR const char *buffer,
size_t buflen);
static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
#ifndef CONFIG_DISABLE_PSEUDOFS_OPERATIONS
static int ft80x_unlink(FAR struct inode *inode);
static int ft80x_unlink(FAR struct inode *inode);
#endif
/* Initialization */
@@ -136,6 +139,123 @@ static const struct file_operations g_ft80x_fops =
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ft80x_interrupt_work
*
* Description:
* Back end handling for FT80x interrupts
*
****************************************************************************/
static void ft80x_interrupt_work(FAR void *arg)
{
FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg;
uint32_t intflags;
DEBUGASSERT(priv != NULL);
/* Get the set of pending interrupts. Note that simply reading this
* register is sufficient to clear all pending interrupts.
*/
intflags = ft80x_read_word(priv, FT80X_REG_INT_FLAGS);
/* And process each pending interrupt.
*
* REVISIT: No interrupt sources are ever enabled in the current
* implementation.
*/
if ((intflags & FT80X_INT_SWAP) != 0)
{
/* Display swap occurred */
lcdinfo("Display swap occurred\n");
}
if ((intflags & FT80X_INT_TOUCH) != 0)
{
/* Touch-screen touch detected */
lcdinfo("Touch-screen touch detected\n");
}
if ((intflags & FT80X_INT_TAG) != 0)
{
/* Touch-screen tag value change */
lcdinfo("Touch-screen tag value change\n");
}
if ((intflags & FT80X_INT_SOUND) != 0)
{
/* Sound effect ended */
lcdinfo(" Sound effect ended\n");
}
if ((intflags & FT80X_INT_PLAYBACK) != 0)
{
/* Audio playback ended */
lcdinfo("Audio playback ended\n");
}
if ((intflags & FT80X_INT_CMDEMPTY) != 0)
{
/* Command FIFO empty */
lcdinfo("Command FIFO empty\n");
}
if ((intflags & FT80X_INT_CMDFLAG) != 0)
{
/* Command FIFO flag */
lcdinfo("Command FIFO flag\n");
}
if ((intflags & FT80X_INT_CONVCOMPLETE) != 0)
{
/* Touch-screen conversions completed */
lcdinfo(" Touch-screen conversions completed\n");
}
/* Re-enable interrupts */
DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL);
priv->lower->enable(priv->lower, true);
}
/****************************************************************************
* Name: ft80x_interrupt
*
* Description:
* FT80x interrupt handler
*
****************************************************************************/
static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg)
{
FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg;
DEBUGASSERT(priv != NULL);
/* Schedule to perform the interrupt work on the high priority work queue. */
work_queue(HPWORK, &priv->intwork, ft80x_interrupt_work, priv, 0);
/* Disable further interrupts for the GPIO interrupt source.
* REVISIT: This assumes that interrupts will pend until re-enabled.
* In certain implementations, this can cause a loss of interrupts.
*/
DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL);
priv->lower->enable(priv->lower, false);
return OK;
}
/****************************************************************************
* Name: ft80x_destroy
*
@@ -419,20 +539,30 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
(FAR struct ft80x_displaylist_s *)((uintptr_t)arg);
if (dl == NULL || ((uintptr_t)&dl->cmd & 3) != 0 ||
dl->dlsize == 0 || (dl->dlsize & 3) != 0 ||
(dl->dlsize & 3) != 0 ||
dl->dlsize + filep->f_pos > FT80X_RAM_DL_SIZE)
{
ret = -EINVAL;
}
else
{
/* This IOCTL command simply copies the display list
* provided into the FT80x display list memory.
/* Check if there is a display list. It might be useful for
* the application to issue FT80X_IOC_CREATEDL with no data in
* order to initialize the display list, then form all of the
* list entries with FT80X_IOC_APPENDDL.
*/
ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos,
&dl->cmd, dl->dlsize);
filep->f_pos += dl->dlsize;
if (dl->dlsize > 0)
{
/* This IOCTL command simply copies the display list
* provided into the FT80x display list memory.
*/
ft80x_write_memory(priv, FT80X_RAM_DL + filep->f_pos,
&dl->cmd, dl->dlsize);
filep->f_pos += dl->dlsize;
}
ret = OK;
}
}
@@ -824,16 +954,38 @@ int ft80x_register(FAR struct i2c_master_s *i2c,
goto errout_with_sem;
}
/* Register the FT80x character driver */
/* Attach our interrupt handler */
ret = register_driver(DEVNAME, &g_ft80x_fops, 0666, priv);
DEBUGASSERT(lower->attach != NULL && lower->enable != NULL);
ret = lower->attach(lower, ft80x_interrupt, priv);
if (ret < 0)
{
goto errout_with_sem;
}
/* Disable all interrupt sources, but enable interrupts both in the lower
* half driver and in the FT80x.
*/
ft80x_write_word(priv, FT80X_REG_INT_MASK, 0);
ft80x_write_word(priv, FT80X_REG_INT_EN, 1);
lower->enable(lower, true);
/* Register the FT80x character driver */
ret = register_driver(DEVNAME, &g_ft80x_fops, 0666, priv);
if (ret < 0)
{
goto errout_with_interrupts;
}
return OK;
errout_with_interrupts:
lower->enable(lower, false);
ft80x_write_word(priv, FT80X_REG_INT_EN, 0);
lower->attach(lower, NULL, NULL);
errout_with_sem:
sem_destroy(&priv->exclsem);
return ret;
+9 -5
View File
@@ -85,9 +85,9 @@
* struct ft80x_displaylist_s below.
* Returns: None
*
* These two IOCTL command simply copies the display list as provided into
* the FT80x display list memory. Display lists should generally be formed
* as follows:
* These two IOCTL command simply copy the display list as provided into the
* FT80x display list memory. Display lists should generally be formed as
* follows:
*
* struct ft80x_cmd_dlstart_s dlstart; # Mark the start of the display list
* # Various display commands follow...
@@ -95,14 +95,18 @@
* struct ft80x_cmd_swap_s swap; # Swap to the new display list
*
* NOTE: The functionality of FT80X_IOC_CREATEDL is the equivalent to that of
* the driver write() method. Either the write method or the FT80X_IOC_CREATEDL
* IOCTL command can be used to write the display list.
* the driver write() method. Either the write() method or the FT80X_IOC_CREATEDL
* IOCTL command can be used to create the display list.
*
* The difference between appending and create a display list using write()
* is that it is necessary to lseek() to the beginning of the display list
* to create a new display list. Subsequent writes will behave then append
* to the end of the display list.
*
* Need to know the current display list offset? You can set that using lseek()
* too. Just seek to the current position; the returned value will be the current
* display list offset.
*
* Output values from display commands are not automatically written back in
* either case but must be subsequently obtained using FT80X_IOC_GETRESULT32.
*