mirror of
https://github.com/apache/nuttx.git
synced 2026-06-07 01:05:54 +08:00
drivers/lcd: Add FT80x interrupt framework. Interrupts are still not used by the driver.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user