diff --git a/drivers/lcd/Make.defs b/drivers/lcd/Make.defs index 7bb92132752..94a9fe7eb6a 100644 --- a/drivers/lcd/Make.defs +++ b/drivers/lcd/Make.defs @@ -44,7 +44,7 @@ endif # Include support for Graphics LCD drivers ifeq ($(CONFIG_LCD_FT80X),y) - CSRCS += ft80x_base.c + CSRCS += ft80x.c ifeq ($(CONFIG_LCD_FT80X_SPI),y) CSRCS += ft80x_spi.c else ifeq ($(CONFIG_LCD_FT80X_I2C),y) diff --git a/drivers/lcd/ft80x_base.c b/drivers/lcd/ft80x.c similarity index 85% rename from drivers/lcd/ft80x_base.c rename to drivers/lcd/ft80x.c index bac6a91c368..75cc973d306 100644 --- a/drivers/lcd/ft80x_base.c +++ b/drivers/lcd/ft80x.c @@ -1,5 +1,5 @@ /************************************************************************************** - * drivers/lcd/ft80x_base.c + * drivers/lcd/ft80x.c * * Copyright (C) 2018 Gregory Nutt. All rights reserved. * Author: Gregory Nutt @@ -53,12 +53,13 @@ #include #include #include -#include +#include #include #include #include #include +#include #include #include #include @@ -91,6 +92,8 @@ * Private Function Prototypes ****************************************************************************/ +static void ft80x_notify(FAR struct ft80x_dev_s *priv, + enum ft80x_notify_e event, int value); 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 @@ -139,6 +142,39 @@ static const struct file_operations g_ft80x_fops = * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: ft80x_notify + * + * Description: + * Notify any registered client of the FT80x event + * + ****************************************************************************/ + +static void ft80x_notify(FAR struct ft80x_dev_s *priv, + enum ft80x_notify_e event, int arg) +{ + FAR struct ft80x_eventinfo_s *info = &priv->notify[event]; +#ifdef CONFIG_CAN_PASS_STRUCTS + union sigval value; +#endif + + /* Are notifications enabled for this event? */ + + if (info->enable) + { + DEBUGASSERT(info->signo > 0 && GOOD_SIGNAL(info->signo) && info->pid > 0); + + /* Yes.. Signal the client */ + +#ifdef CONFIG_CAN_PASS_STRUCTS + value.sival_int = arg; + (void)nxsig_queue(info->pid, info->signo, value); +#else + (void)nxsig_queue(info->pid, info->signo, (FAR void *)arg); +#endif + } +} + /**************************************************************************** * Name: ft80x_interrupt_work * @@ -151,9 +187,20 @@ static void ft80x_interrupt_work(FAR void *arg) { FAR struct ft80x_dev_s *priv = (FAR struct ft80x_dev_s *)arg; uint32_t intflags; + uint32_t regval; + int ret; DEBUGASSERT(priv != NULL); + /* Get exclusive access to the device structures */ + + do + { + ret = nxsem_wait(&priv->exclsem); + DEBUGASSERT(ret == OK || ret == -EINTR); + } + while (ret < 0); + /* Get the set of pending interrupts. Note that simply reading this * register is sufficient to clear all pending interrupts. */ @@ -171,6 +218,7 @@ static void ft80x_interrupt_work(FAR void *arg) /* Display swap occurred */ lcdinfo("Display swap occurred\n"); + ft80x_notify(priv, FT80X_NOTIFY_SWAP, 0); } if ((intflags & FT80X_INT_TOUCH) != 0) @@ -178,6 +226,7 @@ static void ft80x_interrupt_work(FAR void *arg) /* Touch-screen touch detected */ lcdinfo("Touch-screen touch detected\n"); + ft80x_notify(priv, FT80X_NOTIFY_TOUCH, 0); } if ((intflags & FT80X_INT_TAG) != 0) @@ -185,6 +234,12 @@ static void ft80x_interrupt_work(FAR void *arg) /* Touch-screen tag value change */ lcdinfo("Touch-screen tag value change\n"); +#ifdef CONFIG_LCD_FT800 + regval = ft80x_read_word(priv, FT80X_REG_TOUCH_TAG); +#else + regval = ft80x_read_word(priv, FT80X_REG_CTOUCH_TAG); +#endif + ft80x_notify(priv, FT80X_NOTIFY_TAG, (int)(regval & TOUCH_TAG_MASK)); } if ((intflags & FT80X_INT_SOUND) != 0) @@ -192,6 +247,7 @@ static void ft80x_interrupt_work(FAR void *arg) /* Sound effect ended */ lcdinfo(" Sound effect ended\n"); + ft80x_notify(priv, FT80X_NOTIFY_SOUND, 0); } if ((intflags & FT80X_INT_PLAYBACK) != 0) @@ -199,6 +255,7 @@ static void ft80x_interrupt_work(FAR void *arg) /* Audio playback ended */ lcdinfo("Audio playback ended\n"); + ft80x_notify(priv, FT80X_NOTIFY_PLAYBACK, 0); } if ((intflags & FT80X_INT_CMDEMPTY) != 0) @@ -206,6 +263,7 @@ static void ft80x_interrupt_work(FAR void *arg) /* Command FIFO empty */ lcdinfo("Command FIFO empty\n"); + ft80x_notify(priv, FT80X_NOTIFY_CMDEMPTY, 0); } if ((intflags & FT80X_INT_CMDFLAG) != 0) @@ -213,6 +271,7 @@ static void ft80x_interrupt_work(FAR void *arg) /* Command FIFO flag */ lcdinfo("Command FIFO flag\n"); + ft80x_notify(priv, FT80X_NOTIFY_CMDFLAG, 0); } if ((intflags & FT80X_INT_CONVCOMPLETE) != 0) @@ -220,12 +279,14 @@ static void ft80x_interrupt_work(FAR void *arg) /* Touch-screen conversions completed */ lcdinfo(" Touch-screen conversions completed\n"); + ft80x_notify(priv, FT80X_NOTIFY_CONVCOMPLETE, 0); } /* Re-enable interrupts */ DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL); priv->lower->enable(priv->lower, true); + nxsem_post(&priv->exclsem); } /**************************************************************************** @@ -247,8 +308,9 @@ static int ft80x_interrupt(int irq, FAR void *context, FAR void *arg) 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. + * REVISIT: This assumes that GPIO interrupts will pend until re-enabled. + * In certain implementations, that assumption is not true and could cause + * a loss of interrupts. */ DEBUGASSERT(priv->lower != NULL && priv->lower->enable != NULL); @@ -522,18 +584,18 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg) /* FALLTHROUGH */ - /* FT80X_IOC_APPENDDL: - * Description: Write additional display list entries to the FT80x - * display list memory at the current display list offset. - * This IOCTL command permits display lists to be completed - * incrementally, starting with FT80X_IOC_CREATEDL and - * finishing the display list using FT80XIO_APPENDDL. - * Argument: A reference to a display list structure instance. See - * struct ft80x_displaylist_s. - * Returns: None - */ + /* FT80X_IOC_APPENDDL: + * Description: Write additional display list entries to the FT80x + * display list memory at the current display list offset. + * This IOCTL command permits display lists to be completed + * incrementally, starting with FT80X_IOC_CREATEDL and + * finishing the display list using FT80XIO_APPENDDL. + * Argument: A reference to a display list structure instance. See + * struct ft80x_displaylist_s. + * Returns: None + */ - case FT80X_IOC_APPENDDL: + case FT80X_IOC_APPENDDL: { FAR struct ft80x_displaylist_s *dl = (FAR struct ft80x_displaylist_s *)((uintptr_t)arg); @@ -617,6 +679,72 @@ static int ft80x_ioctl(FAR struct file *filep, int cmd, unsigned long arg) } break; + /* FT80X_IOC_EVENTNOTIFY: + * Description: Setup to receive a signal when an event occurs. + * Argument: A reference to an instance of struct ft80x_notify_s. + * Returns: None + */ + + case FT80X_IOC_EVENTNOTIFY: + { + FAR struct ft80x_notify_s *notify = + (FAR struct ft80x_notify_s *)((uintptr_t)arg); + + if (notify == NULL || !GOOD_SIGNO(notify->signo) || notify->pid < 0 || + (unsigned int)notify->event >= FT80X_INT_NEVENTS) + { + ret = -EINVAL; + } + else + { + FAR struct ft80x_eventinfo_s *info = &priv->notify[notify->event]; + uint32_t regval; + + /* Are we enabling or disabling */ + + if (notify->enable) + { + /* Make sure that arguments are valid for the enable */ + + if (notify->signo == 0 || notify->pid == 0) + { + ret = -EINVAL; + } + else + { + /* Setup the new notification information */ + + info->signo = notify->signo; + info->pid = notify->pid; + info->enable = true; + + /* Enable interrupts associated with the event */ + + regval = ft80x_read_word(priv, FT80X_REG_INT_MASK); + regval |= (1 << notify->event); + ft80x_write_word(priv, FT80X_REG_INT_MASK, regval); + ret = OK; + } + } + else + { + /* Disable the notification */ + + info->signo = 0; + info->pid = 0; + info->enable = false; + + /* Disable interrupts associated with the event */ + + regval = ft80x_read_word(priv, FT80X_REG_INT_MASK); + regval &= ~(1 << notify->event); + ft80x_write_word(priv, FT80X_REG_INT_MASK, regval); + ret = OK; + } + } + } + break; + /* Unrecognized IOCTL command */ default: @@ -968,7 +1096,7 @@ int ft80x_register(FAR struct i2c_master_s *i2c, */ ft80x_write_word(priv, FT80X_REG_INT_MASK, 0); - ft80x_write_word(priv, FT80X_REG_INT_EN, 1); + ft80x_write_word(priv, FT80X_REG_INT_EN, FT80X_INT_ENABLE); lower->enable(lower, true); /* Register the FT80x character driver */ @@ -983,7 +1111,7 @@ int ft80x_register(FAR struct i2c_master_s *i2c, errout_with_interrupts: lower->enable(lower, false); - ft80x_write_word(priv, FT80X_REG_INT_EN, 0); + ft80x_write_word(priv, FT80X_REG_INT_EN, FT80X_INT_DISABLE); lower->attach(lower, NULL, NULL); errout_with_sem: diff --git a/drivers/lcd/ft80x.h b/drivers/lcd/ft80x.h index 2eb7d7f8a81..da9f87e0e4e 100644 --- a/drivers/lcd/ft80x.h +++ b/drivers/lcd/ft80x.h @@ -237,7 +237,12 @@ /* FT80x Register Bit Definitions **********************************************************/ +/* FT80X_REG_ID */ + #define ID_MASK 0xff /* Bits 0-7: Register ID */ + +/* FT80X_REG_DLSWAP */ + #define DLSWAP_LINE 1 /* Bits 0-1: 1=Graphics engine will render * the screen immediately after current line. * May cause a tearing effect. @@ -246,17 +251,26 @@ * the screen immediately after the current * frame is scanned out (recommended). */ +/* FT80X_REG_TOUCH_TAG */ + +#define TOUCH_TAG_MASK 0xff /* Bits 0-7: Tag of touched graphic object */ /* 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 +/* 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_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. */ +/* FT80X_REG_INT_EN */ + +#define FT80X_INT_ENABLE (0) /* Bit 0: 0=Interrupts disabled */ +#define FT80X_INT_DISABLE (1 << 0) /* 1=Interrupts enabled */ + +/* FT80X_REG_INT_FLAGS and FT80X_REG_INT_MASK */ + #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 */ @@ -266,6 +280,9 @@ #define FT80X_INT_CMDFLAG (1 << 6) /* Bit 6: Command FIFO flag */ #define FT80X_INT_CONVCOMPLETE (1 << 7) /* Bit 7: Touch-screen conversions completed */ +#define FT80X_INT_NEVENTS 8 +#define FT80X_INT(n) (1 << (n)) + /******************************************************************************************* * Public Types *******************************************************************************************/ @@ -368,6 +385,15 @@ struct ft80x_i2cwrite_s /* Write data follows */ }; +/* This structure describes one signal notification */ + +struct ft80x_eventinfo_s +{ + uint8_t signo; /* Notify using this signal number */ + bool enable; /* True: enable notification; false: disable */ + int16_t pid; /* Send the notification to this task */ +}; + /* This structure describes the overall state of the FT80x driver */ struct spi_dev_s; /* Forward reference */ @@ -375,12 +401,17 @@ struct i2c_master_s; /* Forward reference */ struct ft80x_dev_s { + /* Cached interface instances */ + #ifdef CONFIG_LCD_FT80X_SPI FAR struct spi_dev_s *spi; /* Cached SPI device reference */ #else FAR struct i2c_master_s *i2c; /* Cached SPI device reference */ #endif FAR const struct ft80x_config_s *lower; /* Cached lower half instance */ + + /* Internal driver logic */ + struct work_s intwork; /* Support back end interrupt processing */ uint32_t frequency; /* Effective frequency */ sem_t exclsem; /* Mutual exclusion semaphore */ @@ -388,6 +419,10 @@ struct ft80x_dev_s uint8_t crefs; /* Number of open references */ bool unlinked; /* True if the driver has been unlinked */ #endif + + /* Event notification support */ + + struct ft80x_eventinfo_s notify[FT80X_INT_NEVENTS]; }; /**************************************************************************** diff --git a/include/nuttx/lcd/ft80x.h b/include/nuttx/lcd/ft80x.h index d6fbe12bdef..831b440db6a 100644 --- a/include/nuttx/lcd/ft80x.h +++ b/include/nuttx/lcd/ft80x.h @@ -62,6 +62,11 @@ /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ +/* Configuration */ + +#ifdef CONFIG_DISABLE_SIGNALS +# error Signal support is required by this driver +#endif /* FT80x IOCTL commands: * @@ -116,16 +121,28 @@ * Returns: The 32-bit value read from the display list. * * FT80X_IOC_GETTRACKER: - * Description: After CMD_TRACK has been issued, the coprocessor will update + * Description: After CMD_TRACK has been issued, the co-processor will update * the TRACKER register with new position data. * Argument: A pointer to a writable uint32_t memory location. * Returns: The new content of the tracker register. + * + * FT80X_IOC_EVENTNOTIFY: + * Description: Setup to receive a signal when there is a change in any + * touch tag value. Additional information may be provided in + * the signinfo.si_val file of the notification: + * + * For touch tag events, siginfo.si_value will indicate the + * touch tag. For the FT801 in extended mode, it will + * indicate only the tag value for TOUCH0. + * Argument: A reference to an instance of struct ft80x_notify_s. + * Returns: None */ #define FT80X_IOC_CREATEDL _LCDIOC(FT80X_NIOCTL_BASE + 0) #define FT80X_IOC_APPENDDL _LCDIOC(FT80X_NIOCTL_BASE + 1) #define FT80X_IOC_GETRESULT32 _LCDIOC(FT80X_NIOCTL_BASE + 2) #define FT80X_IOC_GETTRACKER _LCDIOC(FT80X_NIOCTL_BASE + 3) +#define FT80X_IOC_EVENTNOTIFY _LCDIOC(FT80X_NIOCTL_BASE + 4) /* Host commands. 3 word commands. The first word begins with 0b01, the next two are zero */ @@ -1037,6 +1054,30 @@ struct ft80x_result32_s uint32_t value; /* 32-bit value read from display list + offset */ }; +/* This structure is used with the FT80X_IOC_EVENTNOTIFY IOCTL command to describe + * the requested event notification. + */ + +enum ft80x_notify_e +{ + FT80X_NOTIFY_SWAP = 0, /* Bit 0: Display swap occurred */ + FT80X_NOTIFY_TOUCH, /* Touch-screen touch detected */ + FT80X_NOTIFY_TAG, /* Touch-screen tag value change */ + FT80X_NOTIFY_SOUND, /* Sound effect ended */ + FT80X_NOTIFY_PLAYBACK, /* Audio playback ended */ + FT80X_NOTIFY_CMDEMPTY, /* Bit 5: Command FIFO empty */ + FT80X_NOTIFY_CMDFLAG, /* Command FIFO flag */ + FT80X_NOTIFY_CONVCOMPLETE /* Touch-screen conversions completed */ +}; + +struct ft80x_notify_s +{ + int signo; /* Notify using this signal number */ + pid_t pid; /* Send the notification to this task */ + enum ft80x_notify_e event; /* Notify on this event */ + bool enable; /* True: enable notification; false: disable */ +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/