diff options
Diffstat (limited to 'nuttx/drivers/input')
-rw-r--r-- | nuttx/drivers/input/Kconfig | 228 | ||||
-rw-r--r-- | nuttx/drivers/input/Make.defs | 76 | ||||
-rw-r--r-- | nuttx/drivers/input/ads7843e.c | 1283 | ||||
-rw-r--r-- | nuttx/drivers/input/ads7843e.h | 179 | ||||
-rw-r--r-- | nuttx/drivers/input/max11802.c | 1313 | ||||
-rw-r--r-- | nuttx/drivers/input/max11802.h | 167 | ||||
-rw-r--r-- | nuttx/drivers/input/stmpe811.h | 245 | ||||
-rw-r--r-- | nuttx/drivers/input/stmpe811_adc.c | 266 | ||||
-rw-r--r-- | nuttx/drivers/input/stmpe811_base.c | 546 | ||||
-rw-r--r-- | nuttx/drivers/input/stmpe811_gpio.c | 454 | ||||
-rw-r--r-- | nuttx/drivers/input/stmpe811_temp.c | 174 | ||||
-rw-r--r-- | nuttx/drivers/input/stmpe811_tsc.c | 1144 | ||||
-rw-r--r-- | nuttx/drivers/input/tsc2007.c | 1336 | ||||
-rw-r--r-- | nuttx/drivers/input/tsc2007.h | 120 |
14 files changed, 0 insertions, 7531 deletions
diff --git a/nuttx/drivers/input/Kconfig b/nuttx/drivers/input/Kconfig deleted file mode 100644 index 6da3a9f39..000000000 --- a/nuttx/drivers/input/Kconfig +++ /dev/null @@ -1,228 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see misc/tools/kconfig-language.txt. -# - -config INPUT_TSC2007 - bool "TI TSC2007 touchscreen controller" - default n - select I2C - ---help--- - Enable support for the TI TSC2007 touchscreen controller - -if INPUT_TSC2007 - -config TSC2007_8BIT - bool "8-bit Conversions" - default n - ---help--- - Use faster, but less accurate, 8-bit conversions. Default: 12-bit conversions. - -config TSC2007_MULTIPLE - bool "Multiple TSC2007 Devices" - default n - ---help--- - Can be defined to support multiple TSC2007 devices on board. - -config TSC2007_NPOLLWAITERS - int "Number poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - Maximum number of threads that can be waiting on poll() - -endif - -config INPUT_ADS7843E - bool "TI ADS7843/TSC2046 touchscreen controller" - default n - select SPI - ---help--- - Enable support for the TI/Burr-Brown ADS7842 touchscreen controller. I believe - that driver should be compatibile with the TI/Burr-Brown TSC2046 and XPT2046 - touchscreen controllers as well. - -if INPUT_ADS7843E - -config ADS7843E_MULTIPLE - bool "Multiple ADS7843E Devices" - default n - ---help--- - Can be defined to support multiple ADS7843E devices on board. - -config ADS7843E_NPOLLWAITERS - int "Number poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - Maximum number of threads that can be waiting on poll() - -config ADS7843E_SPIMODE - int "SPI mode" - default 0 - range 0,3 - ---help--- - Controls the SPI mode. The device should work in mode 0, but sometimes - you need to experiment. - -config ADS7843E_FREQUENCY - int "SPI frequency" - default 100000 - ---help--- - Define to use a different SPI bus frequency. - -config ADS7843E_SWAPXY - bool "Swap X/Y" - default n - ---help--- - Reverse the meaning of X and Y to handle different LCD orientations. - -config ADS7843E_THRESHX - int "X threshold" - default 12 - ---help--- - New touch positions will only be reported when the X or Y data changes by these - thresholds. This trades reduces data rate for some loss in dragging accuracy. For - 12-bit values so the raw ranges are 0-4095. So for example, if your display is - 320x240, then THRESHX=13 and THRESHY=17 would correspond to one pixel. Default: 12 - -config ADS7843E_THRESHY - int "Y threshold" - default 12 - ---help--- - New touch positions will only be reported when the X or Y data changes by these - thresholds. This trades reduces data rate for some loss in dragging accuracy. For - 12-bit values so the raw ranges are 0-4095. So for example, if your display is - 320x240, then THRESHX=13 and THRESHY=17 would correspond to one pixel. Default: 12 - -endif - -config INPUT_STMPE811 - bool "STMicro STMPE811 Driver" - default n - ---help--- - Enables support for the STMPE811 driver - -if INPUT_STMPE811 - -choice - prompt "STMPE Interface" - default STMPE811_I2C - -config STMPE811_SPI - bool "SPI Interface" - select SPI - ---help--- - Enables support for the SPI interface (not currently supported) - -config STMPE811_I2C - bool "STMPE811 I2C Interface" - select I2C - ---help--- - Enables support for the I2C interface - -endchoice - -config STMPE811_ACTIVELOW - bool "Active Low Interrupt" - default n - ---help--- - The STMPE811 interrupt is provided by a discrete input (usually a - GPIO interrupt on most MCU architectures). This setting determines - whether the interrupt is active high (or rising edge triggered) or - active low (or falling edge triggered). Default: Active - high/rising edge. - -config STMPE811_EDGE - bool "Edge triggered Interrupt" - default n - ---help--- - The STMPE811 interrupt is provided by a discrete input (usually a - GPIO interrupt on most MCU architectures). This setting determines - whether the interrupt is edge or level triggered. Default: Level - triggered. - -config STMPE811_MULTIPLE - bool "Multiple STMPE811 Devices" - default n - ---help--- - Can be defined to support multiple STMPE811 devices on board. - -config STMPE811_NPOLLWAITERS - int "Number poll waiters" - default 4 - depends on !DISABLE_POLL - ---help--- - Maximum number of threads that can be waiting on poll() - -config STMPE811_TSC_DISABLE - bool "Disable STMPE811 Touchscreen Support" - default n - ---help--- - Disable driver touchscreen functionality. - -config STMPE811_SWAPXY - bool "Swap X/Y" - default n - depends on !STMPE811_TSC_DISABLE - ---help--- - Reverse the meaning of X and Y to handle different LCD orientations. - -config STMPE811_THRESHX - int "X threshold" - default 12 - depends on !STMPE811_TSC_DISABLE - ---help--- - STMPE811 touchscreen data comes in a a very high rate. New touch positions - will only be reported when the X or Y data changes by these thresholds. - This trades reduces data rate for some loss in dragging accuracy. The - STMPE811 is configure for 12-bit values so the raw ranges are 0-4095. So - for example, if your display is 320x240, then THRESHX=13 and THRESHY=17 - would correspond to one pixel. Default: 12 - -config STMPE811_THRESHY - int "Y threshold" - default 12 - depends on !STMPE811_TSC_DISABLE - ---help--- - STMPE811 touchscreen data comes in a a very high rate. New touch positions - will only be reported when the X or Y data changes by these thresholds. - This trades reduces data rate for some loss in dragging accuracy. The - STMPE811 is configure for 12-bit values so the raw ranges are 0-4095. So - for example, if your display is 320x240, then THRESHX=13 and THRESHY=17 - would correspond to one pixel. Default: 12 - -config STMPE811_ADC_DISABLE - bool "Disable STMPE811 ADC Support" - default y - ---help--- - Disable driver ADC functionality. - -config STMPE811_GPIO_DISABLE - bool "Disable STMPE811 GPIO Support" - default y - ---help--- - Disable driver GPIO functionality. - -config STMPE811_GPIOINT_DISABLE - bool "Disable STMPE811 GPIO Interrupt Support" - default y - depends on !STMPE811_GPIO_DISABLE - ---help--- - Disable driver GPIO interrupt functionlality (ignored if GPIO functionality is - disabled). - -config STMPE811_TEMP_DISABLE - bool "Disable STMPE811 Temperature Sensor Support" - default y - ---help--- - Disable driver temperature sensor functionality. - -config STMPE811_REGDEBUG - bool "Enable Register-Level STMPE811 Debug" - default n - depends on DEBUG - ---help--- - Enable very low register-level debug output. - -endif diff --git a/nuttx/drivers/input/Make.defs b/nuttx/drivers/input/Make.defs deleted file mode 100644 index 10e6db62f..000000000 --- a/nuttx/drivers/input/Make.defs +++ /dev/null @@ -1,76 +0,0 @@ -############################################################################ -# drivers/input/Make.defs -# -# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt <gnutt@nuttx.org> -# -# 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. -# -############################################################################ - -# Don't build anything if there is no NX support for input devices - -ifeq ($(CONFIG_INPUT),y) - -# Include the selected touchscreen drivers - -ifeq ($(CONFIG_INPUT_TSC2007),y) - CSRCS += tsc2007.c -endif - -ifeq ($(CONFIG_INPUT_ADS7843E),y) - CSRCS += ads7843e.c -endif - -ifeq ($(CONFIG_INPUT_MAX11802),y) - CSRCS += max11802.c -endif - -ifeq ($(CONFIG_INPUT_STMPE811),y) - CSRCS += stmpe811_base.c -ifneq ($(CONFIG_INPUT_STMPE811_TSC_DISABLE),y) - CSRCS += stmpe811_tsc.c -endif -ifneq ($(CONFIG_INPUT_STMPE811_GPIO_DISABLE),y) - CSRCS += stmpe811_gpio.c -endif -ifneq ($(CONFIG_INPUT_STMPE811_ADC_DISABLE),y) - CSRCS += stmpe811_adc.c -endif -ifneq ($(CONFIG_INPUT_STMPE811_TEMP_DISABLE),y) - CSRCS += stmpe811_temp.c -endif -endif - -# Include input device driver build support - -DEPPATH += --dep-path input -VPATH += :input -CFLAGS += ${shell $(INCDIR) $(INCDIROPT) "$(CC)" $(TOPDIR)$(DELIM)drivers$(DELIM)input} -endif - diff --git a/nuttx/drivers/input/ads7843e.c b/nuttx/drivers/input/ads7843e.c deleted file mode 100644 index 06969e6d2..000000000 --- a/nuttx/drivers/input/ads7843e.c +++ /dev/null @@ -1,1283 +0,0 @@ -/**************************************************************************** - * drivers/input/ads7843e.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt <gnutt@nuttx.org> - * Diego Sanchez <dsanchez@nx-engineering.com> - * - * References: - * "Touch Screen Controller, ADS7843," Burr-Brown Products from Texas - * Instruments, SBAS090B, September 2000, Revised May 2002" - * - * See also: - * "Low Voltage I/O Touch Screen Controller, TSC2046," Burr-Brown Products - * from Texas Instruments, SBAS265F, October 2002, Revised August 2007. - * - * "XPT2046 Data Sheet," Shenzhen XPTek Technology Co., Ltd, 2007 - * - * 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 <stdbool.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <semaphore.h> -#include <poll.h> -#include <wdog.h> -#include <errno.h> -#include <assert.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/arch.h> -#include <nuttx/fs/fs.h> -#include <nuttx/spi.h> -#include <nuttx/wqueue.h> - -#include <nuttx/input/touchscreen.h> -#include <nuttx/input/ads7843e.h> - -#include "ads7843e.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* This is a value for the threshold that guantees a big difference on the - * first pendown (but can't overflow). - */ - -#define INVALID_THRESHOLD 0x1000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ads7843e_configspi(FAR struct spi_dev_s *spi); -# define ads7843e_lock(spi) -# define ads7843e_unlock(spi) -#else -# define ads7843e_configspi(spi); -static void ads7843e_lock(FAR struct spi_dev_s *spi); -static void ads7843e_unlock(FAR struct spi_dev_s *spi); -#endif - -static inline void ads7843e_waitbusy(FAR struct ads7843e_dev_s *priv); -static uint16_t ads7843e_sendcmd(FAR struct ads7843e_dev_s *priv, uint8_t cmd); - -/* Interrupts and data sampling */ - -static void ads7843e_notify(FAR struct ads7843e_dev_s *priv); -static int ads7843e_sample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample); -static int ads7843e_waitsample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample); -static void ads7843e_worker(FAR void *arg); -static int ads7843e_interrupt(int irq, FAR void *context); - -/* Character driver methods */ - -static int ads7843e_open(FAR struct file *filep); -static int ads7843e_close(FAR struct file *filep); -static ssize_t ads7843e_read(FAR struct file *filep, FAR char *buffer, size_t len); -static int ads7843e_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int ads7843e_poll(FAR struct file *filep, struct pollfd *fds, bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations ads7843e_fops = -{ - ads7843e_open, /* open */ - ads7843e_close, /* close */ - ads7843e_read, /* read */ - 0, /* write */ - 0, /* seek */ - ads7843e_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , ads7843e_poll /* poll */ -#endif -}; - -/* If only a single ADS7843E device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_ADS7843E_MULTIPLE -static struct ads7843e_dev_s g_ads7843e; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct ads7843e_dev_s *g_ads7843elist; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: ads7843e_lock - * - * Description: - * Lock the SPI bus and re-configure as necessary. This function must be - * to assure: (1) exclusive access to the SPI bus, and (2) to assure that - * the shared bus is properly configured for the touchscreen controller. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void ads7843e_lock(FAR struct spi_dev_s *spi) -{ - /* Lock the SPI bus because there are multiple devices competing for the - * SPI bus - */ - - (void)SPI_LOCK(spi, true); - - /* We have the lock. Now make sure that the SPI bus is configured for the - * ADS7843 (it might have gotten configured for a different device while - * unlocked) - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_ADS7843E_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ADS7843E_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Function: ads7843e_unlock - * - * Description: - * If we are sharing the SPI bus with other devices (CONFIG_SPI_OWNBUS - * undefined) then we need to un-lock the SPI bus for each transfer, - * possibly losing the current configuration. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void ads7843e_unlock(FAR struct spi_dev_s *spi) -{ - /* Relinquish the SPI bus. */ - - (void)SPI_LOCK(spi, false); -} -#endif - -/**************************************************************************** - * Function: ads7843e_configspi - * - * Description: - * Configure the SPI for use with the ADS7843E. This function should be - * called once during touchscreen initialization to configure the SPI - * bus. Note that if CONFIG_SPI_OWNBUS is not defined, then this function - * does nothing. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void ads7843e_configspi(FAR struct spi_dev_s *spi) -{ - /* Configure SPI for the ADS7843. But only if we own the SPI bus. Otherwise, don't - * bother because it might change. - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_ADS7843E_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_ADS7843E_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Name: ads7843e_waitbusy - ****************************************************************************/ - -static inline void ads7843e_waitbusy(FAR struct ads7843e_dev_s *priv) -{ - while (priv->config->busy(priv->config)); -} - -/**************************************************************************** - * Name: ads7843e_sendcmd - ****************************************************************************/ - -static uint16_t ads7843e_sendcmd(FAR struct ads7843e_dev_s *priv, uint8_t cmd) -{ - uint8_t buffer[2]; - uint16_t result; - - /* Select the ADS7843E */ - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - - /* Send the command */ - - (void)SPI_SEND(priv->spi, cmd); - ads7843e_waitbusy(priv); - - /* Read the data */ - - SPI_RECVBLOCK(priv->spi, buffer, 2); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]; - result = result >> 4; - - ivdbg("cmd:%02x response:%04x\n", cmd, result); - return result; -} - -/**************************************************************************** - * Name: ads7843e_notify - ****************************************************************************/ - -static void ads7843e_notify(FAR struct ads7843e_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the ADS7843E - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for ADS7843E data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_ADS7843E_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: ads7843e_sample - ****************************************************************************/ - -static int ads7843e_sample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample) -{ - irqstate_t flags; - int ret = -EAGAIN; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - */ - - flags = irqsave(); - - /* Is there new ADS7843E sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct ads7843e_sample_s )); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* Next.. no contact. Increment the ID so that next contact ID - * will be unique. X/Y positions are no longer valid. - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* First report -- next report will be a movement */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_waitsample - ****************************************************************************/ - -static int ads7843e_waitsample(FAR struct ads7843e_dev_s *priv, - FAR struct ads7843e_sample_s *sample) -{ - irqstate_t flags; - int ret; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - * - * In addition, we will also disable pre-emption to prevent other threads - * from getting control while we muck with the semaphores. - */ - - sched_lock(); - flags = irqsave(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->devsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is available. - */ - - while (ads7843e_sample(priv, sample) < 0) - { - /* Wait for a change in the ADS7843E state */ - - ivdbg("Waiting..\n"); - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - if (ret < 0) - { - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - ret = -EINTR; - goto errout; - } - } - - ivdbg("Sampled\n"); - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->devsem); - -errout: - /* Then re-enable interrupts. We might get interrupt here and there - * could be a new sample. But no new threads will run because we still - * have pre-emption disabled. - */ - - irqrestore(flags); - - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the ADS7843E for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_schedule - ****************************************************************************/ - -static int ads7843e_schedule(FAR struct ads7843e_dev_s *priv) -{ - FAR struct ads7843e_config_s *config; - int ret; - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts. ADS7843E interrupts will be re-enabled - * after the worker thread executes. - */ - - config->enable(config, false); - - /* Disable the watchdog timer. It will be re-enabled in the worker thread - * while the pen remains down. - */ - - wd_cancel(priv->wdog); - - /* Transfer processing to the worker thread. Since ADS7843E interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. - */ - - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - - return OK; -} - -/**************************************************************************** - * Name: ads7843e_wdog - ****************************************************************************/ - -static void ads7843e_wdog(int argc, uint32_t arg1, ...) -{ - FAR struct ads7843e_dev_s *priv = (FAR struct ads7843e_dev_s *)((uintptr_t)arg1); - (void)ads7843e_schedule(priv); -} - -/**************************************************************************** - * Name: ads7843e_worker - ****************************************************************************/ - -static void ads7843e_worker(FAR void *arg) -{ - FAR struct ads7843e_dev_s *priv = (FAR struct ads7843e_dev_s *)arg; - FAR struct ads7843e_config_s *config; - uint16_t x; - uint16_t y; - uint16_t xdiff; - uint16_t ydiff; - bool pendown; - int ret; - - ASSERT(priv != NULL); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable the watchdog timer. This is safe because it is started only - * by this function and this function is serialized on the worker thread. - */ - - wd_cancel(priv->wdog); - - /* Lock the SPI bus so that we have exclusive access */ - - ads7843e_lock(priv->spi); - - /* Get exclusive access to the driver data structure */ - - do - { - ret = sem_wait(&priv->devsem); - - /* This should only fail if the wait was canceled by an signal - * (and the worker thread will receive a lot of signals). - */ - - DEBUGASSERT(ret == OK || errno == EINTR); - } - while (ret < 0); - - /* Check for pen up or down by reading the PENIRQ GPIO. */ - - pendown = config->pendown(config); - - /* Handle the change from pen down to pen up */ - - if (!pendown) - { - /* The pen is up.. reset thresholding variables. */ - - priv->threshx = INVALID_THRESHOLD; - priv->threshy = INVALID_THRESHOLD; - - /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up - * and already reported; CONTACT_UP == pen up, but not reported) - */ - - if (priv->sample.contact == CONTACT_NONE || - priv->sample.contact == CONTACT_UP) - - { - goto ignored; - } - - /* The pen is up. NOTE: We know from a previous test, that this is a - * loss of contact condition. This will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* It is a pen down event. If the last loss-of-contact event has not been - * processed yet, then we have to ignore the pen down event (or else it will - * look like a drag event) - */ - - else if (priv->sample.contact == CONTACT_UP) - { - /* If we have not yet processed the last pen up event, then we - * cannot handle this pen down event. We will have to discard it. That - * should be okay because we will set the timer to to sample again - * later. - */ - - wd_start(priv->wdog, ADS7843E_WDOG_DELAY, ads7843e_wdog, 1, (uint32_t)priv); - goto ignored; - } - else - { - /* Handle pen down events. First, sample positional values. */ - -#ifdef CONFIG_ADS7843E_SWAPXY - x = ads7843e_sendcmd(priv, ADS7843_CMD_YPOSITION); - y = ads7843e_sendcmd(priv, ADS7843_CMD_XPOSITION); -#else - x = ads7843e_sendcmd(priv, ADS7843_CMD_XPOSITION); - y = ads7843e_sendcmd(priv, ADS7843_CMD_YPOSITION); -#endif - - /* Perform a thresholding operation so that the results will be more stable. - * If the difference from the last sample is small, then ignore the event. - * REVISIT: Should a large change in pressure also generate a event? - */ - - xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); - ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); - - /* Continue to sample the position while the pen is down */ - - wd_start(priv->wdog, ADS7843E_WDOG_DELAY, ads7843e_wdog, 1, (uint32_t)priv); - - /* Check the thresholds. Bail if there is no significant difference */ - - if (xdiff < CONFIG_ADS7843E_THRESHX && ydiff < CONFIG_ADS7843E_THRESHY) - { - /* Little or no change in either direction ... don't report anything. */ - - goto ignored; - } - - /* When we see a big difference, snap to the new x/y thresholds */ - - priv->threshx = x; - priv->threshy = y; - - /* Update the x/y position in the sample data */ - - priv->sample.x = priv->threshx; - priv->sample.y = priv->threshy; - - /* The X/Y positional data is now valid */ - - priv->sample.valid = true; - - /* If this is the first (acknowledged) pen down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - - /* Indicate the availability of new sample data for this ID */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that new ADS7843E data is available */ - - ads7843e_notify(priv); - - /* Exit, re-enabling ADS7843E interrupts */ - -ignored: - - (void)ads7843e_sendcmd(priv, ADS7843_CMD_ENABPINIRQ); - config->enable(config, true); - - /* Release our lock on the state structure and unlock the SPI bus */ - - sem_post(&priv->devsem); - ads7843e_unlock(priv->spi); -} - -/**************************************************************************** - * Name: ads7843e_interrupt - ****************************************************************************/ - -static int ads7843e_interrupt(int irq, FAR void *context) -{ - FAR struct ads7843e_dev_s *priv; - FAR struct ads7843e_config_s *config; - int ret; - - /* Which ADS7843E device caused the interrupt? */ - -#ifndef CONFIG_ADS7843E_MULTIPLE - priv = &g_ads7843e; -#else - for (priv = g_ads7843elist; - priv && priv->configs->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Schedule sampling to occur on the worker thread */ - - ret = ads7843e_schedule(priv); - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_open - ****************************************************************************/ - -static int ads7843e_open(FAR struct file *filep) -{ -#ifdef CONFIG_ADS7843E_REFCNT - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - uint8_t tmp; - int ret; - - ivdbg("Opening\n"); - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->devsem); - return ret; -#else - ivdbg("Opening\n"); - return OK; -#endif -} - -/**************************************************************************** - * Name: ads7843e_close - ****************************************************************************/ - -static int ads7843e_close(FAR struct file *filep) -{ -#ifdef CONFIG_ADS7843E_REFCNT - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - int ret; - - ivdbg("Closing\n"); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->devsem); -#endif - ivdbg("Closing\n"); - return OK; -} - -/**************************************************************************** - * Name: ads7843e_read - ****************************************************************************/ - -static ssize_t ads7843e_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - FAR struct touch_sample_s *report; - struct ads7843e_sample_s sample; - int ret; - - ivdbg("buffer:%p len:%d\n", buffer, len); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - idbg("Unsupported read size: %d\n", len); - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = ads7843e_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - ivdbg("Sample data is not available\n"); - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = ads7843e_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - idbg("ads7843e_waitsample: %d\n", ret); - goto errout; - } - } - - /* In any event, we now have sampled ADS7843E data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = sample.id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - - ivdbg(" id: %d\n", report->point[0].id); - ivdbg(" flags: %02x\n", report->point[0].flags); - ivdbg(" x: %d\n", report->point[0].x); - ivdbg(" y: %d\n", report->point[0].y); - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->devsem); - ivdbg("Returning: %d\n", ret); - return ret; -} - -/**************************************************************************** - * Name:ads7843e_ioctl - ****************************************************************************/ - -static int ads7843e_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name: ads7843e_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int ads7843e_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct ads7843e_dev_s *priv; - pollevent_t eventset; - int ndx; - int ret = OK; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct ads7843e_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_ADS7843E_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_ADS7843E_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - ads7843e_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->devsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: ads7843e_register - * - * Description: - * Configure the ADS7843E to use the provided SPI device instance. This - * will register the driver as /dev/inputN where N is the minor device - * number - * - * Input Parameters: - * dev - An SPI driver instance - * config - Persistent board configuration data - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int ads7843e_register(FAR struct spi_dev_s *spi, - FAR struct ads7843e_config_s *config, int minor) -{ - FAR struct ads7843e_dev_s *priv; - char devname[DEV_NAMELEN]; -#ifdef CONFIG_ADS7843E_MULTIPLE - irqstate_t flags; -#endif - int ret; - - ivdbg("spi: %p minor: %d\n", spi, minor); - - /* Debug-only sanity checks */ - - DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100); - - /* Create and initialize a ADS7843E device driver instance */ - -#ifndef CONFIG_ADS7843E_MULTIPLE - priv = &g_ads7843e; -#else - priv = (FAR struct ads7843e_dev_s *)kmalloc(sizeof(struct ads7843e_dev_s)); - if (!priv) - { - idbg("kmalloc(%d) failed\n", sizeof(struct ads7843e_dev_s)); - return -ENOMEM; - } -#endif - - /* Initialize the ADS7843E device driver instance */ - - memset(priv, 0, sizeof(struct ads7843e_dev_s)); - priv->spi = spi; /* Save the SPI device handle */ - priv->config = config; /* Save the board configuration */ - priv->wdog = wd_create(); /* Create a watchdog timer */ - priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */ - priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */ - - sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ - sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ - - /* Make sure that interrupts are disabled */ - - config->clear(config); - config->enable(config, false); - - /* Attach the interrupt handler */ - - ret = config->attach(config, ads7843e_interrupt); - if (ret < 0) - { - idbg("Failed to attach interrupt\n"); - goto errout_with_priv; - } - - idbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_ADS7843E_SPIMODE, CONFIG_ADS7843E_FREQUENCY); - - /* Lock the SPI bus so that we have exclusive access */ - - ads7843e_lock(spi); - - /* Configure the SPI interface */ - - ads7843e_configspi(spi); - - /* Enable the PEN IRQ */ - - ads7843e_sendcmd(priv, ADS7843_CMD_ENABPINIRQ); - - /* Unlock the bus */ - - ads7843e_unlock(spi); - - /* Register the device as an input device */ - - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ivdbg("Registering %s\n", devname); - - ret = register_driver(devname, &ads7843e_fops, 0666, priv); - if (ret < 0) - { - idbg("register_driver() failed: %d\n", ret); - goto errout_with_priv; - } - - /* If multiple ADS7843E devices are supported, then we will need to add - * this new instance to a list of device instances so that it can be - * found by the interrupt handler based on the recieved IRQ number. - */ - -#ifdef CONFIG_ADS7843E_MULTIPLE - priv->flink = g_ads7843elist; - g_ads7843elist = priv; - irqrestore(flags); -#endif - - /* Schedule work to perform the initial sampling and to set the data - * availability conditions. - */ - - ret = work_queue(HPWORK, &priv->work, ads7843e_worker, priv, 0); - if (ret != 0) - { - idbg("Failed to queue work: %d\n", ret); - goto errout_with_priv; - } - - /* And return success (?) */ - - return OK; - -errout_with_priv: - sem_destroy(&priv->devsem); -#ifdef CONFIG_ADS7843E_MULTIPLE - kfree(priv); -#endif - return ret; -} diff --git a/nuttx/drivers/input/ads7843e.h b/nuttx/drivers/input/ads7843e.h deleted file mode 100644 index 6fd70d98b..000000000 --- a/nuttx/drivers/input/ads7843e.h +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************************************** - * drivers/input/ads7843e.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "Touch Screen Controller, ADS7843," Burr-Brown Products from Texas - * Instruments, SBAS090B, September 2000, Revised May 2002" - * - * See also: - * "Low Voltage I/O Touch Screen Controller, TSC2046," Burr-Brown Products - * from Texas Instruments, SBAS265F, October 2002, Revised August 2007." - * - * "XPT2046 Data Sheet," Shenzhen XPTek Technology Co., Ltd, 2007 - * - * 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. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_INPUT_ADS7843E_H -#define __DRIVERS_INPUT_ADS7843E_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include <nuttx/config.h> - -#include <stdint.h> -#include <semaphore.h> -#include <poll.h> -#include <wdog.h> -#include <nuttx/wqueue.h> - -#include <nuttx/spi.h> -#include <nuttx/clock.h> -#include <nuttx/input/ads7843e.h> - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ -/* Configuration ****************************************************************************/ -/* Reference counting is partially implemented, but not needed in the current design. */ - -#undef CONFIG_ADS7843E_REFCNT - -/* ADS7843E Interfaces *********************************************************************/ -/* ADS7843E command bit settings */ - -#define ADS7843E_CMD_PD0 (1 << 0) /* PD0 */ -#define ADS7843E_CMD_PD1 (1 << 1) /* PD1 */ -#define ADS7843E_CMD_DFR (1 << 2) /* SER/DFR */ -#define ADS7843E_CMD_EIGHT_BITS_MOD (1 << 3) /* Mode */ -#define ADS7843E_CMD_START (1 << 7) /* Start Bit */ -#define ADS7843E_CMD_SWITCH_SHIFT 4 /* Address setting */ - -/* ADS7843E Commands */ - -#define ADS7843_CMD_YPOSITION \ - ((1 << ADS7843E_CMD_SWITCH_SHIFT)|ADS7843E_CMD_START|ADS7843E_CMD_PD0|ADS7843E_CMD_PD1) -#define ADS7843_CMD_XPOSITION \ - ((5 << ADS7843E_CMD_SWITCH_SHIFT)|ADS7843E_CMD_START|ADS7843E_CMD_PD0|ADS7843E_CMD_PD1) -#define ADS7843_CMD_ENABPINIRQ \ - ((1 << ADS7843E_CMD_SWITCH_SHIFT)|ADS7843E_CMD_START) - -/* Driver support **************************************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* Poll the pen position while the pen is down at this rate (50MS): */ - -#define ADS7843E_WDOG_DELAY ((50 + (MSEC_PER_TICK-1))/ MSEC_PER_TICK) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/* This describes the state of one contact */ - -enum ads7843e_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one ADS7843E sample */ - -struct ads7843e_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum ads7843e_contact_e) */ - bool valid; /* True: x,y contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ -}; - -/* This structure describes the state of one ADS7843E driver instance */ - -struct ads7843e_dev_s -{ -#ifdef CONFIG_ADS7843E_MULTIPLE - FAR struct ads7843e_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif -#ifdef CONFIG_ADS7843E_REFCNT - uint8_t crefs; /* Number of times the device has been opened */ -#endif - uint8_t nwaiters; /* Number of threads waiting for ADS7843E data */ - uint8_t id; /* Current touch point ID */ - volatile bool penchange; /* An unreported event is buffered */ - uint16_t threshx; /* Thresholding X value */ - uint16_t threshy; /* Thresholding Y value */ - sem_t devsem; /* Manages exclusive access to this structure */ - sem_t waitsem; /* Used to wait for the availability of data */ - - FAR struct ads7843e_config_s *config; /* Board configuration data */ - FAR struct spi_dev_s *spi; /* Saved SPI driver instance */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - struct ads7843e_sample_s sample; /* Last sampled touch point data */ - WDOG_ID wdog; /* Poll the position while the pen is down */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_ADS7843E_NPOLLWAITERS]; -#endif -}; - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_INPUT_ADS7843E_H */ diff --git a/nuttx/drivers/input/max11802.c b/nuttx/drivers/input/max11802.c deleted file mode 100644 index ea3883cd0..000000000 --- a/nuttx/drivers/input/max11802.c +++ /dev/null @@ -1,1313 +0,0 @@ -/**************************************************************************** - * drivers/input/max11802.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt <gnutt@nuttx.org> - * Petteri Aimonen <jpa@nx.mail.kapsi.fi> - * - * References: - * "Low-Power, Ultra-Small Resistive Touch-Screen Controllers - * with I2C/SPI Interface" Maxim IC, Rev 3, 10/2010 - * - * 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 <stdbool.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <semaphore.h> -#include <poll.h> -#include <wdog.h> -#include <errno.h> -#include <assert.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/arch.h> -#include <nuttx/fs/fs.h> -#include <nuttx/spi.h> -#include <nuttx/wqueue.h> - -#include <nuttx/input/touchscreen.h> -#include <nuttx/input/max11802.h> - -#include "max11802.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* This is a value for the threshold that guantees a big difference on the - * first pendown (but can't overflow). - */ - -#define INVALID_THRESHOLD 0x1000 - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* Low-level SPI helpers */ - -#ifdef CONFIG_SPI_OWNBUS -static inline void max11802_configspi(FAR struct spi_dev_s *spi); -# define max11802_lock(spi) -# define max11802_unlock(spi) -#else -# define max11802_configspi(spi); -static void max11802_lock(FAR struct spi_dev_s *spi); -static void max11802_unlock(FAR struct spi_dev_s *spi); -#endif - -static uint16_t max11802_sendcmd(FAR struct max11802_dev_s *priv, uint8_t cmd, int *tags); - -/* Interrupts and data sampling */ - -static void max11802_notify(FAR struct max11802_dev_s *priv); -static int max11802_sample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample); -static int max11802_waitsample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample); -static void max11802_worker(FAR void *arg); -static int max11802_interrupt(int irq, FAR void *context); - -/* Character driver methods */ - -static int max11802_open(FAR struct file *filep); -static int max11802_close(FAR struct file *filep); -static ssize_t max11802_read(FAR struct file *filep, FAR char *buffer, size_t len); -static int max11802_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int max11802_poll(FAR struct file *filep, struct pollfd *fds, bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations max11802_fops = -{ - max11802_open, /* open */ - max11802_close, /* close */ - max11802_read, /* read */ - 0, /* write */ - 0, /* seek */ - max11802_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , max11802_poll /* poll */ -#endif -}; - -/* If only a single MAX11802 device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_MAX11802_MULTIPLE -static struct max11802_dev_s g_max11802; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct max11802_dev_s *g_max11802list; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Function: max11802_lock - * - * Description: - * Lock the SPI bus and re-configure as necessary. This function must be - * to assure: (1) exclusive access to the SPI bus, and (2) to assure that - * the shared bus is properly configured for the touchscreen controller. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void max11802_lock(FAR struct spi_dev_s *spi) -{ - /* Lock the SPI bus because there are multiple devices competing for the - * SPI bus - */ - - (void)SPI_LOCK(spi, true); - - /* We have the lock. Now make sure that the SPI bus is configured for the - * MAX11802 (it might have gotten configured for a different device while - * unlocked) - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_MAX11802_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_MAX11802_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Function: max11802_unlock - * - * Description: - * If we are sharing the SPI bus with other devices (CONFIG_SPI_OWNBUS - * undefined) then we need to un-lock the SPI bus for each transfer, - * possibly losing the current configuration. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifndef CONFIG_SPI_OWNBUS -static void max11802_unlock(FAR struct spi_dev_s *spi) -{ - /* Relinquish the SPI bus. */ - - (void)SPI_LOCK(spi, false); -} -#endif - -/**************************************************************************** - * Function: max11802_configspi - * - * Description: - * Configure the SPI for use with the MAX11802. This function should be - * called once during touchscreen initialization to configure the SPI - * bus. Note that if CONFIG_SPI_OWNBUS is not defined, then this function - * does nothing. - * - * Parameters: - * spi - Reference to the SPI driver structure - * - * Returned Value: - * None - * - * Assumptions: - * - ****************************************************************************/ - -#ifdef CONFIG_SPI_OWNBUS -static inline void max11802_configspi(FAR struct spi_dev_s *spi) -{ - /* Configure SPI for the MAX11802. But only if we own the SPI bus. Otherwise, don't - * bother because it might change. - */ - - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, true); - SPI_SETMODE(spi, CONFIG_MAX11802_SPIMODE); - SPI_SETBITS(spi, 8); - SPI_SETFREQUENCY(spi, CONFIG_MAX11802_FREQUENCY); - SPI_SELECT(spi, SPIDEV_TOUCHSCREEN, false); -} -#endif - -/**************************************************************************** - * Name: max11802_sendcmd - ****************************************************************************/ - -static uint16_t max11802_sendcmd(FAR struct max11802_dev_s *priv, uint8_t cmd, int *tags) -{ - uint8_t buffer[2]; - uint16_t result; - - /* Select the MAX11802 */ - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - - /* Send the command */ - - (void)SPI_SEND(priv->spi, cmd); - - /* Read the data */ - - SPI_RECVBLOCK(priv->spi, buffer, 2); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - result = ((uint16_t)buffer[0] << 8) | (uint16_t)buffer[1]; - *tags = result & 0xF; - result >>= 4; // Get rid of tags - - ivdbg("cmd:%02x response:%04x\n", cmd, result); - return result; -} - -/**************************************************************************** - * Name: max11802_notify - ****************************************************************************/ - -static void max11802_notify(FAR struct max11802_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the sample - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for MAX11802 data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: max11802_sample - ****************************************************************************/ - -static int max11802_sample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample) -{ - irqstate_t flags; - int ret = -EAGAIN; - - /* Interrupts must be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - */ - - flags = irqsave(); - - /* Is there new MAX11802 sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct max11802_sample_s )); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* Next.. no contact. Increment the ID so that next contact ID - * will be unique. X/Y positions are no longer valid. - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* First report -- next report will be a movement */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: max11802_waitsample - ****************************************************************************/ - -static int max11802_waitsample(FAR struct max11802_dev_s *priv, - FAR struct max11802_sample_s *sample) -{ - irqstate_t flags; - int ret; - - /* Interrupts must be disabled when this is called to (1) prevent posting - * of semaphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - * - * In addition, we will also disable pre-emption to prevent other threads - * from getting control while we muck with the semaphores. - */ - - sched_lock(); - flags = irqsave(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->devsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is available. - */ - - while (max11802_sample(priv, sample) < 0) - { - /* Wait for a change in the MAX11802 state */ - - ivdbg("Waiting..\n"); - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - if (ret < 0) - { - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - ret = -EINTR; - goto errout; - } - } - - ivdbg("Sampled\n"); - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->devsem); - -errout: - /* Then re-enable interrupts. We might get interrupt here and there - * could be a new sample. But no new threads will run because we still - * have pre-emption disabled. - */ - - irqrestore(flags); - - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the MAX11802 for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: max11802_schedule - ****************************************************************************/ - -static int max11802_schedule(FAR struct max11802_dev_s *priv) -{ - FAR struct max11802_config_s *config; - int ret; - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts. MAX11802 interrupts will be re-enabled - * after the worker thread executes. - */ - - config->enable(config, false); - - /* Disable the watchdog timer. It will be re-enabled in the worker thread - * while the pen remains down. - */ - - wd_cancel(priv->wdog); - - /* Transfer processing to the worker thread. Since MAX11802 interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. - */ - - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - - return OK; -} - -/**************************************************************************** - * Name: max11802_wdog - ****************************************************************************/ - -static void max11802_wdog(int argc, uint32_t arg1, ...) -{ - FAR struct max11802_dev_s *priv = (FAR struct max11802_dev_s *)((uintptr_t)arg1); - (void)max11802_schedule(priv); -} - -/**************************************************************************** - * Name: max11802_worker - ****************************************************************************/ - -static void max11802_worker(FAR void *arg) -{ - FAR struct max11802_dev_s *priv = (FAR struct max11802_dev_s *)arg; - FAR struct max11802_config_s *config; - uint16_t x; - uint16_t y; - uint16_t xdiff; - uint16_t ydiff; - bool pendown; - int ret; - int tags, tags2; - - ASSERT(priv != NULL); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable the watchdog timer. This is safe because it is started only - * by this function and this function is serialized on the worker thread. - */ - - wd_cancel(priv->wdog); - - /* Lock the SPI bus so that we have exclusive access */ - - max11802_lock(priv->spi); - - /* Start coordinate measurement */ - (void)max11802_sendcmd(priv, MAX11802_CMD_MEASUREXY, &tags); - - /* Get exclusive access to the driver data structure */ - - do - { - ret = sem_wait(&priv->devsem); - - /* This should only fail if the wait was canceled by an signal - * (and the worker thread will receive a lot of signals). - */ - - DEBUGASSERT(ret == OK || errno == EINTR); - } - while (ret < 0); - - /* Check for pen up or down by reading the PENIRQ GPIO. */ - - pendown = config->pendown(config); - - /* Handle the change from pen down to pen up */ - - if (pendown) - ivdbg("\nPD\n"); - else - ivdbg("\nPU\n"); - - if (!pendown) - { - /* The pen is up.. reset thresholding variables. */ - - priv->threshx = INVALID_THRESHOLD; - priv->threshy = INVALID_THRESHOLD; - - /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up - * and already reported; CONTACT_UP == pen up, but not reported) - */ - - ivdbg("\nPC%d\n", priv->sample.contact); - - if (priv->sample.contact == CONTACT_NONE || - priv->sample.contact == CONTACT_UP) - - { - goto ignored; - } - - /* The pen is up. NOTE: We know from a previous test, that this is a - * loss of contact condition. This will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* It is a pen down event. If the last loss-of-contact event has not been - * processed yet, then we have to ignore the pen down event (or else it will - * look like a drag event) - */ - - else if (priv->sample.contact == CONTACT_UP) - { - /* If we have not yet processed the last pen up event, then we - * cannot handle this pen down event. We will have to discard it. That - * should be okay because we will set the timer to to sample again - * later. - */ - - ivdbg("Previous pen up event still in buffer\n"); - max11802_notify(priv); - wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, (uint32_t)priv); - goto ignored; - } - else - { - /* Wait for data ready */ - do { - /* Handle pen down events. First, sample positional values. */ - -#ifdef CONFIG_MAX11802_SWAPXY - x = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags); - y = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags2); -#else - x = max11802_sendcmd(priv, MAX11802_CMD_XPOSITION, &tags); - y = max11802_sendcmd(priv, MAX11802_CMD_YPOSITION, &tags2); -#endif - } while (tags == 0xF || tags2 == 0xF); - - /* Continue to sample the position while the pen is down */ - wd_start(priv->wdog, MAX11802_WDOG_DELAY, max11802_wdog, 1, (uint32_t)priv); - - /* Check if data is valid */ - if ((tags & 0x03) != 0) - { - ivdbg("Touch ended before measurement\n"); - goto ignored; - } - - /* Perform a thresholding operation so that the results will be more stable. - * If the difference from the last sample is small, then ignore the event. - * REVISIT: Should a large change in pressure also generate a event? - */ - - xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); - ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); - - /* Check the thresholds. Bail if there is no significant difference */ - - if (xdiff < CONFIG_MAX11802_THRESHX && ydiff < CONFIG_MAX11802_THRESHY) - { - /* Little or no change in either direction ... don't report anything. */ - - goto ignored; - } - - /* When we see a big difference, snap to the new x/y thresholds */ - - priv->threshx = x; - priv->threshy = y; - - /* Update the x/y position in the sample data */ - - priv->sample.x = priv->threshx; - priv->sample.y = priv->threshy; - - /* The X/Y positional data is now valid */ - - priv->sample.valid = true; - - /* If this is the first (acknowledged) pen down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - - /* Indicate the availability of new sample data for this ID */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that new MAX11802 data is available */ - - max11802_notify(priv); - -ignored: - config->enable(config, true); - - /* Release our lock on the state structure and unlock the SPI bus */ - - sem_post(&priv->devsem); - max11802_unlock(priv->spi); -} - -/**************************************************************************** - * Name: max11802_interrupt - ****************************************************************************/ - -static int max11802_interrupt(int irq, FAR void *context) -{ - FAR struct max11802_dev_s *priv; - FAR struct max11802_config_s *config; - int ret; - - /* Which MAX11802 device caused the interrupt? */ - -#ifndef CONFIG_MAX11802_MULTIPLE - priv = &g_max11802; -#else - for (priv = g_max11802list; - priv && priv->configs->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Schedule sampling to occur on the worker thread */ - - ret = max11802_schedule(priv); - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return ret; -} - -/**************************************************************************** - * Name: max11802_open - ****************************************************************************/ - -static int max11802_open(FAR struct file *filep) -{ -#ifdef CONFIG_MAX11802_REFCNT - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - uint8_t tmp; - int ret; - - ivdbg("Opening\n"); - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->devsem); - return ret; -#else - ivdbg("Opening\n"); - return OK; -#endif -} - -/**************************************************************************** - * Name: max11802_close - ****************************************************************************/ - -static int max11802_close(FAR struct file *filep) -{ -#ifdef CONFIG_MAX11802_REFCNT - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - int ret; - - ivdbg("Closing\n"); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->devsem); -#endif - ivdbg("Closing\n"); - return OK; -} - -/**************************************************************************** - * Name: max11802_read - ****************************************************************************/ - -static ssize_t max11802_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - FAR struct touch_sample_s *report; - struct max11802_sample_s sample; - int ret; - - ivdbg("buffer:%p len:%d\n", buffer, len); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - idbg("Unsupported read size: %d\n", len); - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - idbg("sem_wait: %d\n", errno); - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = max11802_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - ivdbg("Sample data is not available\n"); - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = max11802_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - idbg("max11802_waitsample: %d\n", ret); - goto errout; - } - } - - /* In any event, we now have sampled MAX11802 data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = sample.id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - - ivdbg(" id: %d\n", report->point[0].id); - ivdbg(" flags: %02x\n", report->point[0].flags); - ivdbg(" x: %d\n", report->point[0].x); - ivdbg(" y: %d\n", report->point[0].y); - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->devsem); - ivdbg("Returning: %d\n", ret); - return ret; -} - -/**************************************************************************** - * Name:max11802_ioctl - ****************************************************************************/ - -static int max11802_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = SPI_SETFREQUENCY(priv->spi, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name: max11802_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int max11802_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct max11802_dev_s *priv; - pollevent_t eventset; - int ndx; - int ret = OK; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct max11802_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_MAX11802_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_MAX11802_NPOLLWAITERS) - { - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - max11802_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->devsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: max11802_register - * - * Description: - * Configure the MAX11802 to use the provided SPI device instance. This - * will register the driver as /dev/inputN where N is the minor device - * number - * - * Input Parameters: - * dev - An SPI driver instance - * config - Persistent board configuration data - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int max11802_register(FAR struct spi_dev_s *spi, - FAR struct max11802_config_s *config, int minor) -{ - FAR struct max11802_dev_s *priv; - char devname[DEV_NAMELEN]; -#ifdef CONFIG_MAX11802_MULTIPLE - irqstate_t flags; -#endif - int ret; - - ivdbg("spi: %p minor: %d\n", spi, minor); - - /* Debug-only sanity checks */ - - DEBUGASSERT(spi != NULL && config != NULL && minor >= 0 && minor < 100); - - /* Create and initialize a MAX11802 device driver instance */ - -#ifndef CONFIG_MAX11802_MULTIPLE - priv = &g_max11802; -#else - priv = (FAR struct max11802_dev_s *)kmalloc(sizeof(struct max11802_dev_s)); - if (!priv) - { - idbg("kmalloc(%d) failed\n", sizeof(struct max11802_dev_s)); - return -ENOMEM; - } -#endif - - /* Initialize the MAX11802 device driver instance */ - - memset(priv, 0, sizeof(struct max11802_dev_s)); - priv->spi = spi; /* Save the SPI device handle */ - priv->config = config; /* Save the board configuration */ - priv->wdog = wd_create(); /* Create a watchdog timer */ - priv->threshx = INVALID_THRESHOLD; /* Initialize thresholding logic */ - priv->threshy = INVALID_THRESHOLD; /* Initialize thresholding logic */ - - sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ - sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ - - /* Make sure that interrupts are disabled */ - - config->clear(config); - config->enable(config, false); - - /* Attach the interrupt handler */ - - ret = config->attach(config, max11802_interrupt); - if (ret < 0) - { - idbg("Failed to attach interrupt\n"); - goto errout_with_priv; - } - - idbg("Mode: %d Bits: 8 Frequency: %d\n", - CONFIG_MAX11802_SPIMODE, CONFIG_MAX11802_FREQUENCY); - - /* Lock the SPI bus so that we have exclusive access */ - - max11802_lock(spi); - - /* Configure the SPI interface */ - - max11802_configspi(spi); - - /* Configure MAX11802 registers */ - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_WR); - (void)SPI_SEND(priv->spi, MAX11802_MODE); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_AVG_WR); - (void)SPI_SEND(priv->spi, MAX11802_AVG); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_TIMING_WR); - (void)SPI_SEND(priv->spi, MAX11802_TIMING); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_DELAY_WR); - (void)SPI_SEND(priv->spi, MAX11802_DELAY); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - /* Test that the device access was successful. */ - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, true); - (void)SPI_SEND(priv->spi, MAX11802_CMD_MODE_RD); - ret = SPI_SEND(priv->spi, 0); - SPI_SELECT(priv->spi, SPIDEV_TOUCHSCREEN, false); - - /* Unlock the bus */ - max11802_unlock(spi); - - if (ret != MAX11802_MODE) - { - idbg("max11802 mode readback failed: %02x\n", ret); - goto errout_with_priv; - } - - /* Register the device as an input device */ - - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ivdbg("Registering %s\n", devname); - - ret = register_driver(devname, &max11802_fops, 0666, priv); - if (ret < 0) - { - idbg("register_driver() failed: %d\n", ret); - goto errout_with_priv; - } - - /* If multiple MAX11802 devices are supported, then we will need to add - * this new instance to a list of device instances so that it can be - * found by the interrupt handler based on the recieved IRQ number. - */ - -#ifdef CONFIG_MAX11802_MULTIPLE - priv->flink = g_max11802list; - g_max11802list = priv; - irqrestore(flags); -#endif - - /* Schedule work to perform the initial sampling and to set the data - * availability conditions. - */ - - ret = work_queue(HPWORK, &priv->work, max11802_worker, priv, 0); - if (ret != 0) - { - idbg("Failed to queue work: %d\n", ret); - goto errout_with_priv; - } - - /* And return success (?) */ - - return OK; - -errout_with_priv: - sem_destroy(&priv->devsem); -#ifdef CONFIG_MAX11802_MULTIPLE - kfree(priv); -#endif - return ret; -} diff --git a/nuttx/drivers/input/max11802.h b/nuttx/drivers/input/max11802.h deleted file mode 100644 index b6beec045..000000000 --- a/nuttx/drivers/input/max11802.h +++ /dev/null @@ -1,167 +0,0 @@ -/******************************************************************************************** - * drivers/input/max11802.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Authors: Gregory Nutt <gnutt@nuttx.org> - * Petteri Aimonen <jpa@nx.mail.kapsi.fi> - * - * References: - * "Low-Power, Ultra-Small Resistive Touch-Screen Controllers - * with I2C/SPI Interface" Maxim IC, Rev 3, 10/2010 - * - * 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. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_INPUT_MAX11802_H -#define __DRIVERS_INPUT_MAX11802_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include <nuttx/config.h> - -#include <stdint.h> -#include <semaphore.h> -#include <poll.h> -#include <wdog.h> -#include <nuttx/wqueue.h> - -#include <nuttx/spi.h> -#include <nuttx/clock.h> -#include <nuttx/input/max11802.h> - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ -/* Configuration ****************************************************************************/ - -/* MAX11802 Interfaces *********************************************************************/ - -/* LSB of register addresses specifies read (1) or write (0). */ -#define MAX11802_CMD_XPOSITION ((0x52 << 1) | 1) -#define MAX11802_CMD_YPOSITION ((0x54 << 1) | 1) -#define MAX11802_CMD_MEASUREXY (0x70 << 1) -#define MAX11802_CMD_MODE_WR (0x0B << 1) -#define MAX11802_CMD_MODE_RD ((0x0B << 1) | 1) -#define MAX11802_CMD_AVG_WR (0x03 << 1) -#define MAX11802_CMD_TIMING_WR (0x05 << 1) -#define MAX11802_CMD_DELAY_WR (0x06 << 1) - -/* Register values to set */ -#define MAX11802_MODE 0x0E -#define MAX11802_AVG 0x55 -#define MAX11802_TIMING 0x77 -#define MAX11802_DELAY 0x55 - -/* Driver support **************************************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* Poll the pen position while the pen is down at this rate (50MS): */ - -#define MAX11802_WDOG_DELAY ((50 + (MSEC_PER_TICK-1))/ MSEC_PER_TICK) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/* This describes the state of one contact */ - -enum max11802_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one MAX11802 sample */ - -struct max11802_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum ads7843e_contact_e) */ - bool valid; /* True: x,y contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ -}; - -/* This structure describes the state of one MAX11802 driver instance */ - -struct max11802_dev_s -{ -#ifdef CONFIG_ADS7843E_MULTIPLE - FAR struct ads7843e_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif - uint8_t nwaiters; /* Number of threads waiting for MAX11802 data */ - uint8_t id; /* Current touch point ID */ - volatile bool penchange; /* An unreported event is buffered */ - uint16_t threshx; /* Thresholding X value */ - uint16_t threshy; /* Thresholding Y value */ - sem_t devsem; /* Manages exclusive access to this structure */ - sem_t waitsem; /* Used to wait for the availability of data */ - - FAR struct max11802_config_s *config; /* Board configuration data */ - FAR struct spi_dev_s *spi; /* Saved SPI driver instance */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - struct max11802_sample_s sample; /* Last sampled touch point data */ - WDOG_ID wdog; /* Poll the position while the pen is down */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_ADS7843E_NPOLLWAITERS]; -#endif -}; - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_INPUT_ADS7843E_H */ diff --git a/nuttx/drivers/input/stmpe811.h b/nuttx/drivers/input/stmpe811.h deleted file mode 100644 index f6d646527..000000000 --- a/nuttx/drivers/input/stmpe811.h +++ /dev/null @@ -1,245 +0,0 @@ -/******************************************************************************************** - * drivers/input/stmpe811.h - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * 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. - * - ********************************************************************************************/ - -#ifndef __DRIVERS_INPUT_STMPE811_H -#define __DRIVERS_INPUT_STMPE811_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -#include <nuttx/config.h> - -#include <wdog.h> -#include <semaphore.h> - -#include <nuttx/clock.h> -#include <nuttx/wqueue.h> -#include <nuttx/input/stmpe811.h> - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ -/* Configuration ****************************************************************************/ -/* Reference counting is partially implemented, but not needed in the current design. - */ - -#undef CONFIG_STMPE811_REFCNT - -/* No support for the SPI interface yet */ - -#ifdef CONFIG_STMPE811_SPI -# error "Only the STMPE811 I2C interface is supported by this driver" -#endif - -/* Driver support ***************************************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It defined here - * so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* STMPE811 Resources ************************************************************************/ -#ifndef CONFIG_STMPE811_TSC_DISABLE -# define STMPE811_ADC_NPINS 4 /* Only pins 0-3 can be used for ADC */ -# define STMPE811_GPIO_NPINS 4 /* Only pins 0-3 can be used as GPIOs */ -#else -# define STMPE811_ADC_NPINS 8 /* All pins can be used for ADC */ -# define STMPE811_GPIO_NPINS 8 /* All pins can be used as GPIOs */ -#endif - -/* Driver flags */ - -#define STMPE811_FLAGS_TSC_INITIALIZED (1 << 0) /* 1: The TSC block has been initialized */ -#define STMPE811_FLAGS_GPIO_INITIALIZED (1 << 1) /* 1: The GIO block has been initialized */ -#define STMPE811_FLAGS_ADC_INITIALIZED (1 << 2) /* 1: The ADC block has been initialized */ -#define STMPE811_FLAGS_TS_INITIALIZED (1 << 3) /* 1: The TS block has been initialized */ - -/* Timeout to detect missing pen up events */ - -#define STMPE811_PENUP_TICKS ((100 + (MSEC_PER_TICK-1)) / MSEC_PER_TICK) - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ -/* This describes the state of one contact */ - -enum stmpe811_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one STMPE811 sample */ - -struct stmpe811_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum stmpe811_contact_e) */ - bool valid; /* True: x,y,z contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ - uint8_t z; /* Measured Z index */ -}; - -/* This structure represents the state of the STMPE811 driver */ - -struct stmpe811_dev_s -{ -#ifdef CONFIG_STMPE811_MULTIPLE - FAR struct stmpe811_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif - - /* Common fields */ - - FAR struct stmpe811_config_s *config; /* Board configuration data */ - sem_t exclsem; /* Manages exclusive access to this structure */ -#ifdef CONFIG_STMPE811_SPI - FAR struct spi_dev_s *spi; /* Saved SPI driver instance */ -#else - FAR struct i2c_dev_s *i2c; /* Saved I2C driver instance */ -#endif - - uint8_t inuse; /* STMPE811 pins in use */ - uint8_t flags; /* See STMPE811_FLAGS_* definitions */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - - /* Fields that may be disabled to save size if touchscreen support is not used. */ - -#ifndef CONFIG_STMPE811_TSC_DISABLE -#ifdef CONFIG_STMPE811_REFCNT - uint8_t crefs; /* Number of times the device has been opened */ -#endif - uint8_t nwaiters; /* Number of threads waiting for STMPE811 data */ - uint8_t id; /* Current touch point ID */ - uint8_t minor; /* Touchscreen minor device number */ - volatile bool penchange; /* An unreported event is buffered */ - - uint16_t threshx; /* Thresholded X value */ - uint16_t threshy; /* Thresholded Y value */ - sem_t waitsem; /* Used to wait for the availability of data */ - - struct work_s timeout; /* Supports tiemeout work */ - WDOG_ID wdog; /* Timeout to detect missing pen down events */ - struct stmpe811_sample_s sample; /* Last sampled touch point data */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_STMPE811_NPOLLWAITERS]; -#endif -#endif - - /* Fields that may be disabled to save size of GPIO support is not used */ - -#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE) - stmpe811_handler_t handlers[STMPE811_GPIO_NPINS]; /* GPIO "interrupt handlers" */ -#endif -}; - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -/******************************************************************************************** - * Name: stmpe811_getreg8 - * - * Description: - * Read from an 8-bit STMPE811 register - * - ********************************************************************************************/ - -uint8_t stmpe811_getreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr); - -/******************************************************************************************** - * Name: stmpe811_putreg8 - * - * Description: - * Write a value to an 8-bit STMPE811 register - * - ********************************************************************************************/ - -void stmpe811_putreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr, uint8_t regval); - -/******************************************************************************************** - * Name: stmpe811_getreg16 - * - * Description: - * Read 16-bits of data from an STMPE-11 register - * - ********************************************************************************************/ - -uint16_t stmpe811_getreg16(FAR struct stmpe811_dev_s *priv, uint8_t regaddr); - -/******************************************************************************************** - * Name: stmpe811_tscint - * - * Description: - * Handle touchscreen interrupt events (this function actually executes in the context of - * the worker thread). - * - ********************************************************************************************/ - -#ifndef CONFIG_STMPE811_TSC_DISABLE -void stmpe811_tscworker(FAR struct stmpe811_dev_s *priv, uint8_t intsta) weak_function; -#endif - -/******************************************************************************************** - * Name: stmpe811_gpioworker - * - * Description: - * Handle GPIO interrupt events (this function actually executes in the context of the - * worker thread). - * - ********************************************************************************************/ - -#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE) -void stmpe811_gpioworker(FAR struct stmpe811_dev_s *priv) weak_function; -#endif - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 */ -#endif /* __DRIVERS_INPUT_STMPE811_H */ diff --git a/nuttx/drivers/input/stmpe811_adc.c b/nuttx/drivers/input/stmpe811_adc.c deleted file mode 100644 index 1ffe987e6..000000000 --- a/nuttx/drivers/input/stmpe811_adc.c +++ /dev/null @@ -1,266 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_adc.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * 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 <unistd.h> -#include <assert.h> -#include <errno.h> -#include <debug.h> - -#include <nuttx/arch.h> -#include <nuttx/input/stmpe811.h> - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_ADC_DISABLE) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_adcinitialize - * - * Description: - * Configure for ADC mode operation. Set overall ADC ADC timing that - * applies to all pins. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_adcinitialize(STMPE811_HANDLE handle) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t regval; - int ret; - - DEBUGASSERT(handle); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Enable Clocking for ADC */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~SYS_CTRL2_ADC_OFF; - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Select Sample Time, bit number and ADC Reference */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL1, priv->config->ctrl1); - - /* Wait for 20 ms */ - - up_mdelay(20); - - /* Select the ADC clock speed */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL2, priv->config->ctrl2); - - /* Mark ADC initialized */ - - priv->flags |= STMPE811_FLAGS_ADC_INITIALIZED; - sem_post(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_adcconfig - * - * Description: - * Configure a pin for ADC input. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pin - The ADC pin number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_adcconfig(STMPE811_HANDLE handle, int pin) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t pinmask = GPIO_PIN(pin); - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_ADC_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the pin is not already in use */ - - if ((priv->inuse & pinmask) != 0) - { - idbg("PIN%d is already in-use\n", pin); - sem_post(&priv->exclsem); - return -EBUSY; - } - - /* Clear the alternate function bit for the pin, making it an ADC input - * (or perhaps an an external reference, depending on the state of the - * ADC_CTRL1_REF_SEL bit). - */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_AF); - regval &= ~pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval); - - /* Mark the pin as 'in use' */ - - priv->inuse |= pinmask; - sem_post(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_adcread - * - * Description: - * Read the converted analog input value from the select pin. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pin - The ADC pin number - * - * Returned Value: - * The converted value (there is no error reporting mechanism). - * - ****************************************************************************/ - -uint16_t stmpe811_adcread(STMPE811_HANDLE handle, int pin) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t pinmask = GPIO_PIN(pin); - uint8_t regval; - int i; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < 8); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Request AD conversion by setting the bit corresponding the pin in the - * ADC CAPT register. - */ - - stmpe811_putreg8(priv, STMPE811_ADC_CAPT, pinmask); - - /* Wait for the conversion to complete. The ADC CAPT register reads '1' - * if conversion is completed. Reads '0' if conversion is in progress. - * Try three times before giving up. - */ - - for (i = 0; i < 3; i++) - { - /* The worst case ADC conversion time is (nominally) 56.4 uS. The - * following usleep() looks nice but in reality, the usleep() - * does not have that kind of precision (it will probably end up - * waiting 10 MS). - */ - - usleep(57); - - /* Check if the conversion is complete */ - - regval = stmpe811_getreg8(priv, STMPE811_ADC_CAPT); - if ((regval & pinmask) != 0) - { - break; - } - } - - /* At the completion of the conversion, return whatever we read from - * from the channel register associated with the pin. - */ - - return stmpe811_getreg16(priv, STMPE811_ADC_DATACH(pin)); -} - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_ADC_DISABLE */ - diff --git a/nuttx/drivers/input/stmpe811_base.c b/nuttx/drivers/input/stmpe811_base.c deleted file mode 100644 index f37c24622..000000000 --- a/nuttx/drivers/input/stmpe811_base.c +++ /dev/null @@ -1,546 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_base.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * 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 <unistd.h> -#include <errno.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/input/stmpe811.h> - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* If only a single STMPE811 device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_STMPE811_MULTIPLE -static struct stmpe811_dev_s g_stmpe811; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct stmpe811_dev_s *g_stmpe811list; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_worker - * - * Description: - * This is the "bottom half" of the STMPE811 interrupt handler - * - ****************************************************************************/ - -static void stmpe811_worker(FAR void *arg) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg; - uint8_t regval; - - DEBUGASSERT(priv && priv->config); - - /* Get the global interrupt status */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_STA); - - /* Check for a touchscreen interrupt */ - -#ifndef CONFIG_STMPE811_TSC_DISABLE - if ((regval & (INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW)) != 0) - { - /* Dispatch the touchscreen interrupt if it was brought into the link */ - -#ifdef CONFIG_HAVE_WEAKFUNCTIONS - if (stmpe811_tscworker) -#endif - { - stmpe811_tscworker(priv, regval); - } - - stmpe811_putreg8(priv, STMPE811_INT_STA, (INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW)); - regval &= ~(INT_TOUCH_DET|INT_FIFO_TH|INT_FIFO_OFLOW); - } -#endif - -#if !defined(CONFIG_STMPE811_GPIO_DISABLE) && !defined(CONFIG_STMPE811_GPIOINT_DISABLE) - if ((regval & INT_GPIO) != 0) - { - /* Dispatch the GPIO interrupt if it was brought into the link */ - -#ifdef CONFIG_HAVE_WEAKFUNCTIONS - if (stmpe811_gpioworker) -#endif - { - stmpe811_gpioworker(priv); - } - - stmpe811_putreg8(priv, STMPE811_INT_STA, INT_GPIO); - regval &= ~INT_GPIO; - } -#endif - - /* Clear any other residual, unhandled pending interrupt */ - - if (regval != 0) - { - stmpe811_putreg8(priv, STMPE811_INT_STA, regval); - } - - /* Re-enable the STMPE811 GPIO interrupt */ - - priv->config->enable(priv->config, true); -} - -/**************************************************************************** - * Name: stmpe811_interrupt - * - * Description: - * The STMPE811 interrupt handler - * - ****************************************************************************/ - -static int stmpe811_interrupt(int irq, FAR void *context) -{ - FAR struct stmpe811_dev_s *priv; - FAR struct stmpe811_config_s *config; - int ret; - - /* Which STMPE811 device caused the interrupt? */ - -#ifndef CONFIG_STMPE811_MULTIPLE - priv = &g_stmpe811; -#else - for (priv = g_stmpe811list; - priv && priv->config->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts */ - - config->enable(config, false); - - /* Check if interrupt work is already queue. If it is already busy, then - * we already have interrupt processing in the pipeline and we need to do - * nothing more. - */ - - if (work_available(&priv->work)) - { - /* Yes.. Transfer processing to the worker thread. Since STMPE811 - * interrupts are disabled while the work is pending, no special - * action should be required to protect the work queue. - */ - - ret = work_queue(HPWORK, &priv->work, stmpe811_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - } - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_checkid - * - * Description: - * Read and verify the STMPE811 chip ID - * - ****************************************************************************/ - -static int stmpe811_checkid(FAR struct stmpe811_dev_s *priv) -{ - uint16_t devid = 0; - - /* Read device ID */ - - devid = stmpe811_getreg8(priv, STMPE811_CHIP_ID); - devid = (uint32_t)(devid << 8); - devid |= (uint32_t)stmpe811_getreg8(priv, STMPE811_CHIP_ID+1); - ivdbg("devid: %04x\n", devid); - - if (devid != (uint16_t)CHIP_ID) - { - /* ID is not Correct */ - - return -ENODEV; - } - - return OK; -} - -/**************************************************************************** - * Name: stmpe811_reset - * - * Description: - * Reset the STMPE811 - * - ****************************************************************************/ - -static void stmpe811_reset(FAR struct stmpe811_dev_s *priv) -{ - /* Power Down the STMPE811 */ - - stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, SYS_CTRL1_SOFTRESET); - - /* Wait a bit */ - - usleep(20*1000); - - /* Then power on again. All registers will be in their reset state. */ - - stmpe811_putreg8(priv, STMPE811_SYS_CTRL1, 0); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_instantiate - * - * Description: - * Instantiate and configure the STMPE811 device driver to use the provided - * I2C or SPIdevice instance. - * - * Input Parameters: - * dev - An I2C or SPI driver instance - * config - Persistant board configuration data - * - * Returned Value: - * A non-zero handle is returned on success. This handle may then be used - * to configure the STMPE811 driver as necessary. A NULL handle value is - * returned on failure. - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_SPI -STMPE811_HANDLE stmpe811_instantiate(FAR struct spi_dev_s *dev, - FAR struct stmpe811_config_s *config) -#else -STMPE811_HANDLE stmpe811_instantiate(FAR struct i2c_dev_s *dev, - FAR struct stmpe811_config_s *config) -#endif -{ - FAR struct stmpe811_dev_s *priv; - uint8_t regval; - int ret; - - /* Allocate the device state structure */ - -#ifdef CONFIG_STMPE811_MULTIPLE - priv = (FAR struct stmpe811_dev_s *)kzalloc(sizeof(struct stmpe811_dev_s)); - if (!priv) - { - return NULL; - } - - /* And save the device structure in the list of STMPE811 so that we can find it later */ - - priv->flink = g_stmpe811list; - g_stmpe811list = priv; -#else - - /* Use the one-and-only STMPE811 driver instance */ - - priv = &g_stmpe811; -#endif - - /* Initialize the device state structure */ - - sem_init(&priv->exclsem, 0, 1); - priv->config = config; - -#ifdef CONFIG_STMPE811_SPI - priv->spi = dev; -#else - priv->i2c = dev; - - /* Set the I2C address and frequency. REVISIT: This logic would be - * insufficient if we share the I2C bus with any other devices that also - * modify the address and frequency. - */ - - I2C_SETADDRESS(dev, config->address, 7); - I2C_SETFREQUENCY(dev, config->frequency); -#endif - - /* Read and verify the STMPE811 chip ID */ - - ret = stmpe811_checkid(priv); - if (ret < 0) - { -#ifdef CONFIG_STMPE811_MULTIPLE - kfree(priv); -#endif - return NULL; - } - - /* Generate STMPE811 Software reset */ - - stmpe811_reset(priv); - - /* Configure the interrupt output pin to generate interrupts on high or low level. */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_CTRL); -#ifdef CONFIG_STMPE811_ACTIVELOW - regval &= ~INT_CTRL_INT_POLARITY; /* Pin polarity: Active low / falling edge */ -#else - regval |= INT_CTRL_INT_POLARITY; /* Pin polarity: Active high / rising edge */ -#endif -#ifdef CONFIG_STMPE811_EDGE - regval |= INT_CTRL_INT_TYPE; /* Edge interrupt */ -#else - regval &= ~INT_CTRL_INT_TYPE; /* Level interrupt */ -#endif - stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval); - - /* Attach the STMPE811 interrupt handler. */ - - config->attach(config, stmpe811_interrupt); - - /* Clear any pending interrupts */ - - stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL); - config->clear(config); - config->enable(config, true); - - /* Enable global interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_CTRL); - regval |= INT_CTRL_GLOBAL_INT; - stmpe811_putreg8(priv, STMPE811_INT_CTRL, regval); - - /* Return our private data structure as an opaque handle */ - - return (STMPE811_HANDLE)priv; -} - -/**************************************************************************** - * Name: stmpe811_getreg8 - * - * Description: - * Read from an 8-bit STMPE811 register - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_I2C -uint8_t stmpe811_getreg8(FAR struct stmpe811_dev_s *priv, uint8_t regaddr) -{ - /* 8-bit data read sequence: - * - * Start - I2C_Write_Address - STMPE811_Reg_Address - - * Repeated_Start - I2C_Read_Address - STMPE811_Read_Data - STOP - */ - - struct i2c_msg_s msg[2]; - uint8_t regval; - int ret; - - /* Setup 8-bit STMPE811 address write message */ - - msg[0].addr = priv->config->address; /* 7-bit address */ - msg[0].flags = 0; /* Write transaction, beginning with START */ - msg[0].buffer = ®addr; /* Transfer from this address */ - msg[0].length = 1; /* Send one byte following the address - * (no STOP) */ - - /* Set up the 8-bit STMPE811 data read message */ - - msg[1].addr = priv->config->address; /* 7-bit address */ - msg[1].flags = I2C_M_READ; /* Read transaction, beginning with Re-START */ - msg[1].buffer = ®val; /* Transfer to this address */ - msg[1].length = 1; /* Receive one byte following the address - * (then STOP) */ - - /* Perform the transfer */ - - ret = I2C_TRANSFER(priv->i2c, msg, 2); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return 0; - } - -#ifdef CONFIG_STMPE811_REGDEBUG - dbg("%02x->%02x\n", regaddr, regval); -#endif - return regval; -} -#endif - -/**************************************************************************** - * Name: stmpe811_putreg8 - * - * Description: - * Write a value to an 8-bit STMPE811 register - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_I2C -void stmpe811_putreg8(FAR struct stmpe811_dev_s *priv, - uint8_t regaddr, uint8_t regval) -{ - /* 8-bit data read sequence: - * - * Start - I2C_Write_Address - STMPE811_Reg_Address - STMPE811_Write_Data - STOP - */ - - struct i2c_msg_s msg; - uint8_t txbuffer[2]; - int ret; - -#ifdef CONFIG_STMPE811_REGDEBUG - dbg("%02x<-%02x\n", regaddr, regval); -#endif - - /* Setup to the data to be transferred. Two bytes: The STMPE811 register - * address followed by one byte of data. - */ - - txbuffer[0] = regaddr; - txbuffer[1] = regval; - - /* Setup 8-bit STMPE811 address write message */ - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = txbuffer; /* Transfer from this address */ - msg.length = 2; /* Send two byte following the address - * (then STOP) */ - - /* Perform the transfer */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - } -} -#endif - -/**************************************************************************** - * Name: stmpe811_getreg16 - * - * Description: - * Read 16-bits of data from an STMPE-11 register - * - ****************************************************************************/ - -#ifdef CONFIG_STMPE811_I2C -uint16_t stmpe811_getreg16(FAR struct stmpe811_dev_s *priv, uint8_t regaddr) -{ - /* 16-bit data read sequence: - * - * Start - I2C_Write_Address - STMPE811_Reg_Address - - * Repeated_Start - I2C_Read_Address - STMPE811_Read_Data_1 - - * STMPE811_Read_Data_2 - STOP - */ - - - struct i2c_msg_s msg[2]; - uint8_t rxbuffer[2]; - int ret; - - /* Setup 8-bit STMPE811 address write message */ - - msg[0].addr = priv->config->address; /* 7-bit address */ - msg[0].flags = 0; /* Write transaction, beginning with START */ - msg[0].buffer = ®addr; /* Transfer from this address */ - msg[0].length = 1; /* Send one byte following the address - * (no STOP) */ - - /* Set up the 8-bit STMPE811 data read message */ - - msg[1].addr = priv->config->address; /* 7-bit address */ - msg[1].flags = I2C_M_READ; /* Read transaction, beginning with Re-START */ - msg[1].buffer = rxbuffer; /* Transfer to this address */ - msg[1].length = 2; /* Receive two bytes following the address - * (then STOP) */ - - /* Perform the transfer */ - - ret = I2C_TRANSFER(priv->i2c, msg, 2); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return 0; - } - -#ifdef CONFIG_STMPE811_REGDEBUG - dbg("%02x->%02x%02x\n", regaddr, rxbuffer[0], rxbuffer[1]); -#endif - return (uint16_t)rxbuffer[0] << 8 | (uint16_t)rxbuffer[1]; -} -#endif - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 */ - diff --git a/nuttx/drivers/input/stmpe811_gpio.c b/nuttx/drivers/input/stmpe811_gpio.c deleted file mode 100644 index b545828d1..000000000 --- a/nuttx/drivers/input/stmpe811_gpio.c +++ /dev/null @@ -1,454 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_gpio.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * 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 <assert.h> -#include <errno.h> -#include <debug.h> - -#include <nuttx/input/stmpe811.h> - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_GPIO_DISABLE) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_gpioinit - * - * Description: - * Initialize the GPIO interrupt subsystem - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -static void stmpe811_gpioinit(FAR struct stmpe811_dev_s *priv) -{ - uint8_t regval; - - if ((priv->flags & STMPE811_FLAGS_GPIO_INITIALIZED) == 0) - { - /* Enable Clocking for GPIO */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~SYS_CTRL2_GPIO_OFF; - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Disable all GPIO interrupts */ - - stmpe811_putreg8(priv, STMPE811_GPIO_EN, 0); - - /* Enable global GPIO interrupts */ - -#ifndef CONFIG_STMPE811_GPIOINT_DISABLE - regval = stmpe811_getreg8(priv, STMPE811_INT_EN); - regval |= INT_GPIO; - stmpe811_putreg8(priv, STMPE811_INT_EN, regval); -#endif - - priv->flags |= STMPE811_FLAGS_GPIO_INITIALIZED; - } -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_gpioconfig - * - * Description: - * Configure an STMPE811 GPIO pin - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_gpioconfig(STMPE811_HANDLE handle, uint8_t pinconfig) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - uint8_t pinmask = (1 << pin); - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the pin is not already in use */ - - if ((priv->inuse & pinmask) != 0) - { - idbg("PIN%d is already in-use\n", pin); - sem_post(&priv->exclsem); - return -EBUSY; - } - - /* Make sure that the GPIO block has been initialized */ - - stmpe811_gpioinit(priv); - - /* Set the alternate function bit for the pin, making it a GPIO */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_AF); - regval |= pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval); - - /* Is the pin an input or an output? */ - - if ((pinconfig & STMPE811_GPIO_DIR) == STMPE811_GPIO_OUTPUT) - { - /* The pin is an output */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_DIR); - regval &= ~pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_DIR, regval); - - /* Set its initial output value */ - - stmpe811_gpiowrite(handle, pinconfig, - (pinconfig & STMPE811_GPIO_VALUE) != STMPE811_GPIO_ZERO); - } - else - { - /* It is an input */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_DIR); - regval |= pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_DIR, regval); - - /* Set up the falling edge detection */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_FE); - if ((pinconfig & STMPE811_GPIO_FALLING) != 0) - { - regval |= pinmask; - } - else - { - regval &= pinmask; - } - stmpe811_putreg8(priv, STMPE811_GPIO_FE, regval); - - /* Set up the rising edge detection */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_RE); - if ((pinconfig & STMPE811_GPIO_FALLING) != 0) - { - regval |= pinmask; - } - else - { - regval &= pinmask; - } - stmpe811_putreg8(priv, STMPE811_GPIO_RE, regval); - - /* Disable interrupts for now */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_EN); - regval &= ~pinmask; - stmpe811_putreg8(priv, STMPE811_GPIO_EN, regval); - } - - /* Mark the pin as 'in use' */ - - priv->inuse |= pinmask; - sem_post(&priv->exclsem); - return OK; -} - -/**************************************************************************** - * Name: stmpe811_gpiowrite - * - * Description: - * Set or clear the GPIO output - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * value = true: write logic '1'; false: write logic '0; - * - * Returned Value: - * None - * - ****************************************************************************/ - -void stmpe811_gpiowrite(STMPE811_HANDLE handle, uint8_t pinconfig, bool value) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - idbg("sem_wait failed: %d\n", errno); - return; - } - - /* Are we setting or clearing outputs? */ - - if (value) - { - /* Set the output valu(s)e by writing to the SET register */ - - stmpe811_putreg8(priv, STMPE811_GPIO_SETPIN, (1 << pin)); - } - else - { - /* Clear the output value(s) by writing to the CLR register */ - - stmpe811_putreg8(priv, STMPE811_GPIO_CLRPIN, (1 << pin)); - } - - sem_post(&priv->exclsem); -} - -/**************************************************************************** - * Name: stmpe811_gpioread - * - * Description: - * Set or clear the GPIO output - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * value - The location to return the state of the GPIO pin - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_gpioread(STMPE811_HANDLE handle, uint8_t pinconfig, bool *value) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_MPSTA); - *value = ((regval & GPIO_PIN(pin)) != 0); - sem_post(&priv->exclsem); - return OK; -} - -/*********************************************************************************** - * Name: stmpe811_gpioattach - * - * Description: - * Attach to a GPIO interrupt input pin and enable interrupts on the pin. Using - * the value NULL for the handler address will disable interrupts from the pin and - * detach the handler. - * - * NOTE: Callbacks do not occur from an interrupt handler but rather from the - * context of the worker thread. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * pinconfig - Bit-encoded pin configuration - * handler - The handler that will be called when the interrupt occurs. - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is returned - * to indicate the nature of the failure. - * - ************************************************************************************/ - -#ifndef CONFIG_STMPE811_GPIOINT_DISABLE -int stmpe811_gpioattach(STMPE811_HANDLE handle, uint8_t pinconfig, - stmpe811_handler_t handler) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - int pin = (pinconfig & STMPE811_GPIO_PIN_MASK) >> STMPE811_GPIO_PIN_SHIFT; - uint8_t regval; - int ret; - - DEBUGASSERT(handle && (unsigned)pin < STMPE811_GPIO_NPINS); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the GPIO interrupt system has been gpioinitialized */ - - stmpe811_gpioinit(priv); - - /* Set/clear the handler */ - - priv->handlers[pin] = handler; - - /* If an handler has provided, then we are enabling interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_EN); - if (handler) - { - /* Enable interrupts for this GPIO */ - - regval &= ~GPIO_PIN(pin); - } - else - { - /* Disable interrupts for this GPIO */ - - regval &= ~GPIO_PIN(pin); - } - stmpe811_putreg8(priv, STMPE811_GPIO_EN, regval); - - sem_post(&priv->exclsem); - return OK; -} -#endif - -/**************************************************************************** - * Name: stmpe811_gpioworker - * - * Description: - * Handle GPIO interrupt events (this function actually executes in the - * context of the worker thread). - * - ****************************************************************************/ - -#ifndef CONFIG_STMPE811_GPIOINT_DISABLE -void stmpe811_gpioworker(FAR struct stmpe811_dev_s *priv) -{ - uint8_t regval; - uint8_t pinmask; - int pin; - - /* Get the set of pending GPIO interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_INTSTA); - - /* Look at each pin */ - - for (pin = 0; pin < STMPE811_GPIO_NPINS; pin++) - { - pinmask = GPIO_INT(pin); - if ((regval & pinmask) != 0) - { - /* Check if we have a handler for this interrupt (there should - * be one) - */ - - if (priv->handlers[pin]) - { - /* Interrupt is pending... dispatch the interrupt to the - * callback - */ - - priv->handlers[pin](pin); - } - else - { - illdbg("No handler for PIN%d, GPIO_INTSTA: %02x\n", pin, regval); - } - - /* Clear the pending GPIO interrupt by writing a '1' to the - * pin position in the status register. - */ - - stmpe811_putreg8(priv, STMPE811_GPIO_INTSTA, pinmask); - } - } -} -#endif - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_GPIO_DISABLE */ - diff --git a/nuttx/drivers/input/stmpe811_temp.c b/nuttx/drivers/input/stmpe811_temp.c deleted file mode 100644 index 0fefd2069..000000000 --- a/nuttx/drivers/input/stmpe811_temp.c +++ /dev/null @@ -1,174 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_temp.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * 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 <assert.h> -#include <errno.h> -#include <debug.h> - -#include <nuttx/input/stmpe811.h> - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_TEMP_DISABLE) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_tempinitialize - * - * Description: - * Configure the temperature sensor. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_tempinitialize(STMPE811_HANDLE handle) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint8_t regval; - - /* Enable clocking for ADC and the temperature sensor */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~(SYS_CTRL2_TS_OFF | SYS_CTRL2_ADC_OFF); - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Enable the temperature sensor */ - - stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, TEMP_CTRL_ENABLE); - - /* Aquire data enable */ - - stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, (TEMP_CTRL_ACQ|TEMP_CTRL_ENABLE)); - - return OK; -} - -/**************************************************************************** - * Name: stmpe811_tempread - * - * Description: - * Configure the temperature sensor. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -uint16_t stmpe811_tempread(STMPE811_HANDLE handle) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - uint32_t temp = 0; - uint8_t temp1; - uint8_t temp2; - - /* Acquire data enable */ - - stmpe811_putreg8(priv, STMPE811_TEMP_CTRL, (TEMP_CTRL_ACQ|TEMP_CTRL_ENABLE)); - - /* Read the temperature */ - - temp1 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - temp2 = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2+1); - - /* Scale the temperature (where Vio is assumed to be .33) */ - - temp = ((uint32_t)(temp1 & 3) << 8) | temp2; - temp = (uint32_t)((33 * temp * 100) / 751); - temp = (uint32_t)((temp + 5) / 10); - - return (uint16_t)temp; -} - -/**************************************************************************** - * Name: stmpe811_tempinterrupt - * - * Description: - * Configure the temperature sensor to sample the temperature periodically. - * Set the temperature threshold to generate an interrupt and notify - * to the client using the provide callback function pointer. - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_instantiate - * threshold - The threshold temperature value - * direction - True: Generate an interrupt if the temperate exceeds the - * threshold value; False: Generate an interrupt if the - * temperature falls below the threshold value. - * callback - The client callback function that will be called when - * the termperature crosses the threshold. - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ -/* Not implemented */ - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_TEMP_DISABLE */ - diff --git a/nuttx/drivers/input/stmpe811_tsc.c b/nuttx/drivers/input/stmpe811_tsc.c deleted file mode 100644 index c7f8b473b..000000000 --- a/nuttx/drivers/input/stmpe811_tsc.c +++ /dev/null @@ -1,1144 +0,0 @@ -/**************************************************************************** - * drivers/input/stmpe811_tsc.c - * - * Copyright (C) 2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "STMPE811 S-Touch® advanced resistive touchscreen controller with 8-bit - * GPIO expander," Doc ID 14489 Rev 6, CD00186725, STMicroelectronics" - * - * 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 <stdbool.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <semaphore.h> - -#include <poll.h> -#include <errno.h> -#include <assert.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/arch.h> -#include <nuttx/fs/fs.h> -#include <nuttx/i2c.h> -#include <nuttx/wqueue.h> - -#include <nuttx/arch.h> -#include <nuttx/input/touchscreen.h> -#include <nuttx/input/stmpe811.h> - -#include "stmpe811.h" - -#if defined(CONFIG_INPUT) && defined(CONFIG_INPUT_STMPE811) && !defined(CONFIG_STMPE811_TSC_DISABLE) - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#define Direction_IN 0x00 -#define Direction_OUT 0x01 - -#define Polarity_Low 0x00 -#define Polarity_High 0x04 -#define Type_Level 0x00 -#define Type_Edge 0x02 - -#define IO_IT_0 0x01 -#define IO_IT_1 0x02 -#define IO_IT_2 0x04 -#define IO_IT_3 0x08 -#define IO_IT_4 0x10 -#define IO_IT_5 0x20 -#define IO_IT_6 0x40 -#define IO_IT_7 0x80 -#define ALL_IT 0xFF -#define IOE_JOY_IT (uint8_t)(IO_IT_3 | IO_IT_4 | IO_IT_5 | IO_IT_6 | IO_IT_7) -#define IOE_TS_IT (uint8_t)(IO_IT_0 | IO_IT_1 | IO_IT_2) -#define IOE_INMEMS_IT (uint8_t)(IO_IT_2 | IO_IT_3) - -#define EDGE_FALLING 0x01 -#define EDGE_RISING 0x02 - -#define TIMEOUT_MAX 0x3000 /*<! The value of the maximal timeout for I2C waiting loops */ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ -/* Internal logic */ - -static void stmpe811_notify(FAR struct stmpe811_dev_s *priv); -static int stmpe811_sample(FAR struct stmpe811_dev_s *priv, - FAR struct stmpe811_sample_s *sample); -static inline int stmpe811_waitsample(FAR struct stmpe811_dev_s *priv, - FAR struct stmpe811_sample_s *sample); - -/* Character driver methods */ - -static int stmpe811_open(FAR struct file *filep); -static int stmpe811_close(FAR struct file *filep); -static ssize_t stmpe811_read(FAR struct file *filep, FAR char *buffer, - size_t len); -static int stmpe811_ioctl(FAR struct file *filep, int cmd, - unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int stmpe811_poll(FAR struct file *filep, struct pollfd *fds, - bool setup); -#endif - -/* Initialization logic */ - -static inline void stmpe811_tscinitialize(FAR struct stmpe811_dev_s *priv); - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations g_stmpe811fops = -{ - stmpe811_open, /* open */ - stmpe811_close, /* close */ - stmpe811_read, /* read */ - 0, /* write */ - 0, /* seek */ - stmpe811_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , stmpe811_poll /* poll */ -#endif -}; - -/**************************************************************************** - * Private Functions - ****************************************************************************/ -/**************************************************************************** - * Name: stmpe811_notify - * - * Description: - * Notify any threads waiting on touchscreen data that data is now - * available for reading. - * - ****************************************************************************/ - -static void stmpe811_notify(FAR struct stmpe811_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the STMPE811 - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for STMPE811 data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_STMPE811_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: stmpe811_sample - * - * Description: - * Check if touchscreen sample data is available now and, if so, return - * the sample data. This is part of the stmpe811_read logic. - * - * Assumption: - * Pre-emption is disable to prevent the worker thread from running. - * Otherwise, sampled data may continue to change. - * - ****************************************************************************/ - -static int stmpe811_sample(FAR struct stmpe811_dev_s *priv, - FAR struct stmpe811_sample_s *sample) -{ - int ret = -EAGAIN; - - /* Is there new STMPE811 sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct stmpe811_sample_s)); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* The sampling logic has detected pen-up in some condition other - * than CONTACT_NONE. Set the next state to CONTACT_NONE: Further - * pen-down reports will be ignored. Increment the ID so that - * next contact ID will be unique - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* The sampling logic has detected pen-up in some condition other - * than CONTACT_MOVE. Set the next state to CONTACT_MOVE: Further - * samples collected while the pen is down will reported as movement - * events. - */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - return ret; -} - -/**************************************************************************** - * Name: stmpe811_waitsample - * - * Description: - * Wait for a sample to become available (this is really part of the - * stmpe811_read logic). - * - ****************************************************************************/ - -static inline int stmpe811_waitsample(FAR struct stmpe811_dev_s *priv, - FAR struct stmpe811_sample_s *sample) -{ - int ret; - - /* Disable pre-emption to prevent the worker thread from running - * asynchronously. - */ - - sched_lock(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->exclsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is availble. - */ - - while (stmpe811_sample(priv, sample) < 0) - { - /* Wait for a change in the STMPE811 state */ - - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - /* When we are re-awakened, pre-emption will again be disabled */ - - if (ret < 0) - { -#ifdef CONFIG_DEBUG - // Sample the errno (debug output could change it) - - int errval = errno; - - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - idbg("ERROR: sem_wait failed: %d\n", errval); - DEBUGASSERT(errval == EINTR); -#endif - ret = -EINTR; - goto errout; - } - } - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->exclsem); - -errout: - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the STMPE811 for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_open - * - * Description: - * Standard character driver open method. - * - ****************************************************************************/ - -static int stmpe811_open(FAR struct file *filep) -{ -#ifdef CONFIG_STMPE811_REFCNT - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - uint8_t tmp; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->exclsem); - return ret; -#else - return OK; -#endif -} - -/**************************************************************************** - * Name: stmpe811_close - * - * Description: - * Standard character driver close method. - * - ****************************************************************************/ - -static int stmpe811_close(FAR struct file *filep) -{ -#ifdef CONFIG_STMPE811_REFCNT - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->exclsem); -#endif - return OK; -} - -/**************************************************************************** - * Name: stmpe811_read - * - * Description: - * Standard character driver read method. - * - ****************************************************************************/ - -static ssize_t stmpe811_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - FAR struct touch_sample_s *report; - struct stmpe811_sample_s sample; - int ret; - - ivdbg("len=%d\n", len); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = stmpe811_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = stmpe811_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - goto errout; - } - } - - /* In any event, we now have sampled STMPE811 data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = sample.id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - report->point[0].pressure = sample.z; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_ioctl - * - * Description: - * Standard character driver ioctl method. - * -****************************************************************************/ - -static int stmpe811_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = I2C_SETFREQUENCY(priv->i2c, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_poll - * - * Description: - * Standard character driver poll method. - * - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int stmpe811_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct stmpe811_dev_s *priv; - int ret; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct stmpe811_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - idbg("ERROR: Missing POLLIN: revents: %08x\n", fds->revents); - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_STMPE811_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_STMPE811_NPOLLWAITERS) - { - idbg("ERROR: No availabled slot found: %d\n", i); - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - stmpe811_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->exclsem); - return ret; -} -#endif - -/**************************************************************************** - * Name: stmpe811_timeoutworker - * - * Description: - * A timer has expired without receiving a pen up event. Check again. - * - ****************************************************************************/ - -static void stmpe811_timeoutworker(FAR void *arg) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)arg; - - DEBUGASSERT(priv); - - /* Treat the timeout just like an interrupt occurred */ - - stmpe811_tscworker(priv, stmpe811_getreg8(priv, STMPE811_INT_STA)); -} - -/**************************************************************************** - * Name: stmpe811_timeout - * - * Description: - * A timer has expired without receiving a pen up event. Schedule work - * to check again. - * - ****************************************************************************/ - -static void stmpe811_timeout(int argc, uint32_t arg1, ...) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)((uintptr_t)arg1); - int ret; - - /* Are we still stuck in the pen down state? */ - - if (priv->sample.contact == CONTACT_MOVE || - priv->sample.contact == CONTACT_MOVE) - { - /* Yes... is the worker thread available? If not, then apparently - * we have work already pending? - */ - - if (work_available(&priv->timeout)) - { - /* Yes.. Transfer processing to the worker thread. Since STMPE811 - * interrupts are disabled while the work is pending, no special - * action should be required to protect the work queue. - */ - - ret = work_queue(HPWORK, &priv->timeout, stmpe811_timeoutworker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - } - } -} - -/**************************************************************************** - * Name: stmpe811_tscinitialize - * - * Description: - * Initialize the touchscreen controller. This is really a part of the - * stmpe811_register logic, - * - ****************************************************************************/ - -static inline void stmpe811_tscinitialize(FAR struct stmpe811_dev_s *priv) -{ - uint8_t regval; - - ivdbg("Initializing touchscreen controller\n"); - - /* Enable TSC and ADC functions */ - - regval = stmpe811_getreg8(priv, STMPE811_SYS_CTRL2); - regval &= ~(SYS_CTRL2_TSC_OFF | SYS_CTRL2_ADC_OFF); - stmpe811_putreg8(priv, STMPE811_SYS_CTRL2, regval); - - /* Enable the TSC global interrupts */ - - regval = stmpe811_getreg8(priv, STMPE811_INT_EN); - regval |= (uint32_t)(INT_TOUCH_DET | INT_FIFO_TH | INT_FIFO_OFLOW); - stmpe811_putreg8(priv, STMPE811_INT_EN, regval); - - /* Select Sample Time, bit number and ADC Reference */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL1, priv->config->ctrl1); - - /* Wait for 20 ms */ - - up_mdelay(20); - - /* Select the ADC clock speed */ - - stmpe811_putreg8(priv, STMPE811_ADC_CTRL2, priv->config->ctrl2); - - /* Select TSC pins in non-GPIO mode (AF=0) */ - - regval = stmpe811_getreg8(priv, STMPE811_GPIO_AF); - regval &= ~(uint8_t)TSC_PIN_SET; - stmpe811_putreg8(priv, STMPE811_GPIO_AF, regval); - - /* Select 2 nF filter capacitor */ - - stmpe811_putreg8(priv, STMPE811_TSC_CFG, - (TSC_CFG_AVE_CTRL_4SAMPLES | TSC_CFG_TOUCH_DELAY_500US | TSC_CFG_SETTLING_500US)); - - /* Select single point reading */ - - stmpe811_putreg8(priv, STMPE811_FIFO_TH, 1); - - /* Reset and clear the FIFO. */ - - stmpe811_putreg8(priv, STMPE811_FIFO_STA, FIFO_STA_FIFO_RESET); - stmpe811_putreg8(priv, STMPE811_FIFO_STA, 0); - - /* set the data format for Z value: 7 fractional part and 1 whole part */ - - stmpe811_putreg8(priv, STMPE811_TSC_FRACTIONZ, 0x01); - - /* Set the driving capability of the device for TSC pins: 50mA */ - - stmpe811_putreg8(priv, STMPE811_TSC_IDRIVE, TSC_IDRIVE_50MA); - - /* Enable the TSC. Use no tracking index, touch-screen controller - * operation mode (XYZ). - */ - - stmpe811_putreg8(priv, STMPE811_TSC_CTRL, TSC_CTRL_EN); - - /* Clear all the status pending bits */ - - stmpe811_putreg8(priv, STMPE811_INT_STA, INT_ALL); -} - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: stmpe811_register - * - * Description: - * Enable TSC functionality. GPIO4-7 must be available. This function - * will register the touchsceen driver as /dev/inputN where N is the minor - * device number - * - * Input Parameters: - * handle - The handle previously returned by stmpe811_register - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int stmpe811_register(STMPE811_HANDLE handle, int minor) -{ - FAR struct stmpe811_dev_s *priv = (FAR struct stmpe811_dev_s *)handle; - char devname[DEV_NAMELEN]; - int ret; - - ivdbg("handle=%p minor=%d\n", handle, minor); - DEBUGASSERT(priv); - - /* Get exclusive access to the device structure */ - - ret = sem_wait(&priv->exclsem); - if (ret < 0) - { - int errval = errno; - idbg("ERROR: sem_wait failed: %d\n", errval); - return -errval; - } - - /* Make sure that the pins (4-7) need by the TSC are not already in use */ - - if ((priv->inuse & TSC_PIN_SET) != 0) - { - idbg("ERROR: TSC pins is already in-use: %02x\n", priv->inuse); - sem_post(&priv->exclsem); - return -EBUSY; - } - - /* Initialize the TS structure fields to their default values */ - - priv->minor = minor; - priv->penchange = false; - priv->threshx = 0; - priv->threshy = 0; - - /* Create a timer for catching missed pen up conditions */ - - priv->wdog = wd_create(); - if (!priv->wdog) - { - idbg("ERROR: Failed to create a watchdog\n", errno); - sem_post(&priv->exclsem); - return -ENOSPC; - } - - /* Register the character driver */ - - snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ret = register_driver(devname, &g_stmpe811fops, 0666, priv); - if (ret < 0) - { - idbg("ERROR: Failed to register driver %s: %d\n", devname, ret); - sem_post(&priv->exclsem); - return ret; - } - - /* Initialize the touchscreen controller */ - - stmpe811_tscinitialize(priv); - - /* Inidicate that the touchscreen controller was successfully initialized */ - - priv->inuse |= TSC_PIN_SET; /* Pins 4-7 are now in-use */ - priv->flags |= STMPE811_FLAGS_TSC_INITIALIZED; /* TSC function is initialized */ - sem_post(&priv->exclsem); - return ret; -} - -/**************************************************************************** - * Name: stmpe811_tscworker - * - * Description: - * This function is called to handle a TSC interrupt. It is not really - * an interrupt handle because it is called from the STMPE811 "bottom half" - * logic that runs on the worker thread. - * - ****************************************************************************/ - -void stmpe811_tscworker(FAR struct stmpe811_dev_s *priv, uint8_t intsta) -{ - FAR struct stmpe811_config_s *config; /* Convenience pointer */ - bool pendown; /* true: pend is down */ - uint16_t xdiff; /* X difference used in thresholding */ - uint16_t ydiff; /* Y difference used in thresholding */ - uint16_t x; /* X position */ - uint16_t y; /* Y position */ - - ASSERT(priv != NULL); - - /* Cancel the missing pen up timer */ - - (void)wd_cancel(priv->wdog); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Check for pen up or down from the TSC_STA ibit n the STMPE811_TSC_CTRL register. */ - - pendown = (stmpe811_getreg8(priv, STMPE811_TSC_CTRL) & TSC_CTRL_TSC_STA) != 0; - - /* Handle the change from pen down to pen up */ - - if (!pendown) - { - /* The pen is up.. reset thresholding variables. FIFOs will read zero if - * there is no data available (hence the choice of (0,0)) - */ - - priv->threshx = 0; - priv->threshy = 0; - - /* Ignore the interrupt if the pen was already up (CONTACT_NONE == pen up and - * already reported; CONTACT_UP == pen up, but not reported) - */ - - if (priv->sample.contact == CONTACT_NONE || - priv->sample.contact == CONTACT_UP) - { - goto ignored; - } - - /* A pen-down to up transition has been detected. CONTACT_UP indicates the - * initial loss of contzt. The state will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* The pen is down... check for data in the FIFO */ - - else if ((intsta & (INT_FIFO_TH|INT_FIFO_OFLOW)) != 0) - { - /* Read the next x and y positions from the FIFO. */ - -#ifdef CONFIG_STMPE811_SWAPXY - x = stmpe811_getreg16(priv, STMPE811_TSC_DATAX); - y = stmpe811_getreg16(priv, STMPE811_TSC_DATAY); -#else - x = stmpe811_getreg16(priv, STMPE811_TSC_DATAY); - y = stmpe811_getreg16(priv, STMPE811_TSC_DATAX); -#endif - - /* If we have not yet processed the last pen up event, then we - * cannot handle this pen down event. We will have to discard it. That - * should be okay because there will be another FIFO event right behind - * this one. Other kinds of data overruns are not harmful. - * - * Hmm.. a better design might be to disable FIFO interrupts when we - * detect pen up. Then re-enable them when CONTACT_UP is reported. - * That would save processing interrupts just to discard the data. - */ - - if (priv->sample.contact == CONTACT_UP) - { - /* We have not closed the loop on the last touch ... don't report - * anything. - */ - - goto ignored; - } - - /* Perform a thresholding operation so that the results will be more stable. - * If the difference from the last sample is small, then ignore the event. - * REVISIT: Should a large change in pressure also generate a event? - */ - - xdiff = x > priv->threshx ? (x - priv->threshx) : (priv->threshx - x); - ydiff = y > priv->threshy ? (y - priv->threshy) : (priv->threshy - y); - - if (xdiff < CONFIG_STMPE811_THRESHX && ydiff < CONFIG_STMPE811_THRESHY) - { - /* Little or no change in either direction ... don't report anything. */ - - goto ignored; - } - - /* When we see a big difference, snap to the new x/y thresholds */ - - priv->threshx = x; - priv->threshy = y; - - /* Update the x/y position in the sample data */ - - priv->sample.x = priv->threshx; - priv->sample.y = priv->threshy; - - /* Update the Z pressure index */ - - priv->sample.z = stmpe811_getreg8(priv, STMPE811_TSC_DATAZ); - priv->sample.valid = true; - - /* If this is the first (acknowledged) pen down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - - /* Pen down, but no data in FIFO */ - - else - { - /* Ignore the interrupt... wait until there is data in the FIFO */ - - goto ignored; - } - - /* We get here if (1) we just went from a pen down to a pen up state OR (2) - * We just get a measurement from the FIFO in a pen down state. Indicate - * the availability of new sample data for this ID. - */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that new STMPE811 data is available */ - - stmpe811_notify(priv); - - /* If we think that the pend is still down, the start/re-start the pen up - * timer. - */ - -ignored: - if (priv->sample.contact == CONTACT_MOVE || - priv->sample.contact == CONTACT_MOVE) - { - (void)wd_start(priv->wdog, STMPE811_PENUP_TICKS, stmpe811_timeout, - 1, (uint32_t)((uintptr_t)priv)); - } - - /* Reset and clear all data in the FIFO */ - - stmpe811_putreg8(priv, STMPE811_FIFO_STA, FIFO_STA_FIFO_RESET); - stmpe811_putreg8(priv, STMPE811_FIFO_STA, 0); -} - -#endif /* CONFIG_INPUT && CONFIG_INPUT_STMPE811 && !CONFIG_STMPE811_TSC_DISABLE */ - diff --git a/nuttx/drivers/input/tsc2007.c b/nuttx/drivers/input/tsc2007.c deleted file mode 100644 index 163118b95..000000000 --- a/nuttx/drivers/input/tsc2007.c +++ /dev/null @@ -1,1336 +0,0 @@ -/**************************************************************************** - * drivers/input/tsc2007.c - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "1.2V to 3.6V, 12-Bit, Nanopower, 4-Wire Micro TOUCH SCREEN CONTROLLER - * with I2C Interface," SBAS405A March 2007, Revised, March 2009, Texas - * Instruments Incorporated - * - * 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. - * - ****************************************************************************/ - -/* The TSC2007 is an analog interface circuit for a human interface touch - * screen device. All peripheral functions are controlled through the command - * byte and onboard state machines. - */ - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include <nuttx/config.h> - -#include <sys/types.h> - -#include <stdbool.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <fcntl.h> -#include <semaphore.h> -#include <poll.h> -#include <errno.h> -#include <assert.h> -#include <debug.h> - -#include <nuttx/kmalloc.h> -#include <nuttx/arch.h> -#include <nuttx/fs/fs.h> -#include <nuttx/i2c.h> -#include <nuttx/wqueue.h> - -#include <nuttx/input/touchscreen.h> -#include <nuttx/input/tsc2007.h> - -#include "tsc2007.h" - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ -/* Configuration ************************************************************/ -/* Reference counting is partially implemented, but not needed in the - * current design. - */ - -#undef CONFIG_TSC2007_REFCNT - -/* I don't think that it is necessary to activate the converters before - * making meaurements. However, I will keep this functionality enabled - * until I have a change to prove that that activation is unnecessary. - */ - -#undef CONFIG_TSC2007_ACTIVATE -#define CONFIG_TSC2007_ACTIVATE 1 - -/* Driver support ***********************************************************/ -/* This format is used to construct the /dev/input[n] device driver path. It - * defined here so that it will be used consistently in all places. - */ - -#define DEV_FORMAT "/dev/input%d" -#define DEV_NAMELEN 16 - -/* Commands *****************************************************************/ - -#define TSC2007_SETUP (TSC2007_CMD_FUNC_SETUP) -#ifdef CONFIG_TSC2007_8BIT -# define TSC2007_ACTIVATE_Y (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YON) -# define TSC2007_MEASURE_Y (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YPOS) -# define TSC2007_ACTIVATE_X (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XON) -# define TSC2007_MEASURE_X (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XPOS) -# define TSC2007_ACTIVATE_Z (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YXON) -# define TSC2007_MEASURE_Z1 (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z1POS) -# define TSC2007_MEASURE_Z2 (TSC2007_CMD_8BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z2POS) -# define TSC2007_ENABLE_PENIRQ (TSC2007_CMD_8BIT | TSC2007_CMD_PWRDN_IRQEN) -#else -# define TSC2007_ACTIVATE_Y (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YON) -# define TSC2007_MEASURE_Y (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YPOS) -# define TSC2007_ACTIVATE_X (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XON) -# define TSC2007_MEASURE_X (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_XPOS) -# define TSC2007_ACTIVATE_Z (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_YXON) -# define TSC2007_MEASURE_Z1 (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z1POS) -# define TSC2007_MEASURE_Z2 (TSC2007_CMD_12BIT | TSC2007_CMD_ADCON_IRQDIS | TSC2007_CMD_FUNC_Z2POS) -# define TSC2007_ENABLE_PENIRQ (TSC2007_CMD_12BIT | TSC2007_CMD_PWRDN_IRQEN) -#endif - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* This describes the state of one contact */ - -enum tsc2007_contact_3 -{ - CONTACT_NONE = 0, /* No contact */ - CONTACT_DOWN, /* First contact */ - CONTACT_MOVE, /* Same contact, possibly different position */ - CONTACT_UP, /* Contact lost */ -}; - -/* This structure describes the results of one TSC2007 sample */ - -struct tsc2007_sample_s -{ - uint8_t id; /* Sampled touch point ID */ - uint8_t contact; /* Contact state (see enum tsc2007_contact_e) */ - bool valid; /* True: x,y,pressure contain valid, sampled data */ - uint16_t x; /* Measured X position */ - uint16_t y; /* Measured Y position */ - uint16_t pressure; /* Calculated pressure */ -}; - -/* This structure describes the state of one TSC2007 driver instance */ - -struct tsc2007_dev_s -{ -#ifdef CONFIG_TSC2007_MULTIPLE - FAR struct tsc2007_dev_s *flink; /* Supports a singly linked list of drivers */ -#endif -#ifdef CONFIG_TSC2007_REFCNT - uint8_t crefs; /* Number of times the device has been opened */ -#endif - uint8_t nwaiters; /* Number of threads waiting for TSC2007 data */ - uint8_t id; /* Current touch point ID */ - volatile bool penchange; /* An unreported event is buffered */ - sem_t devsem; /* Manages exclusive access to this structure */ - sem_t waitsem; /* Used to wait for the availability of data */ - - FAR struct tsc2007_config_s *config; /* Board configuration data */ - FAR struct i2c_dev_s *i2c; /* Saved I2C driver instance */ - struct work_s work; /* Supports the interrupt handling "bottom half" */ - struct tsc2007_sample_s sample; /* Last sampled touch point data */ - - /* The following is a list if poll structures of threads waiting for - * driver events. The 'struct pollfd' reference for each open is also - * retained in the f_priv field of the 'struct file'. - */ - -#ifndef CONFIG_DISABLE_POLL - struct pollfd *fds[CONFIG_TSC2007_NPOLLWAITERS]; -#endif -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -static void tsc2007_notify(FAR struct tsc2007_dev_s *priv); -static int tsc2007_sample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample); -static int tsc2007_waitsample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample); -#ifdef CONFIG_TSC2007_ACTIVATE -static int tsc2007_activate(FAR struct tsc2007_dev_s *priv, uint8_t cmd); -#endif -static int tsc2007_transfer(FAR struct tsc2007_dev_s *priv, uint8_t cmd); -static void tsc2007_worker(FAR void *arg); -static int tsc2007_interrupt(int irq, FAR void *context); - -/* Character driver methods */ - -static int tsc2007_open(FAR struct file *filep); -static int tsc2007_close(FAR struct file *filep); -static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len); -static int tsc2007_ioctl(FAR struct file *filep, int cmd, unsigned long arg); -#ifndef CONFIG_DISABLE_POLL -static int tsc2007_poll(FAR struct file *filep, struct pollfd *fds, bool setup); -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* This the the vtable that supports the character driver interface */ - -static const struct file_operations tsc2007_fops = -{ - tsc2007_open, /* open */ - tsc2007_close, /* close */ - tsc2007_read, /* read */ - 0, /* write */ - 0, /* seek */ - tsc2007_ioctl /* ioctl */ -#ifndef CONFIG_DISABLE_POLL - , tsc2007_poll /* poll */ -#endif -}; - -/* If only a single TSC2007 device is supported, then the driver state - * structure may as well be pre-allocated. - */ - -#ifndef CONFIG_TSC2007_MULTIPLE -static struct tsc2007_dev_s g_tsc2007; - -/* Otherwise, we will need to maintain allocated driver instances in a list */ - -#else -static struct tsc2007_dev_s *g_tsc2007list; -#endif - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: tsc2007_notify - ****************************************************************************/ - -static void tsc2007_notify(FAR struct tsc2007_dev_s *priv) -{ -#ifndef CONFIG_DISABLE_POLL - int i; -#endif - - /* If there are threads waiting for read data, then signal one of them - * that the read data is available. - */ - - if (priv->nwaiters > 0) - { - /* After posting this semaphore, we need to exit because the TSC2007 - * is no longer available. - */ - - sem_post(&priv->waitsem); - } - - /* If there are threads waiting on poll() for TSC2007 data to become available, - * then wake them up now. NOTE: we wake up all waiting threads because we - * do not know that they are going to do. If they all try to read the data, - * then some make end up blocking after all. - */ - -#ifndef CONFIG_DISABLE_POLL - for (i = 0; i < CONFIG_TSC2007_NPOLLWAITERS; i++) - { - struct pollfd *fds = priv->fds[i]; - if (fds) - { - fds->revents |= POLLIN; - ivdbg("Report events: %02x\n", fds->revents); - sem_post(fds->sem); - } - } -#endif -} - -/**************************************************************************** - * Name: tsc2007_sample - ****************************************************************************/ - -static int tsc2007_sample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample) -{ - irqstate_t flags; - int ret = -EAGAIN; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - */ - - flags = irqsave(); - - /* Is there new TSC2007 sample data available? */ - - if (priv->penchange) - { - /* Yes.. the state has changed in some way. Return a copy of the - * sampled data. - */ - - memcpy(sample, &priv->sample, sizeof(struct tsc2007_sample_s )); - - /* Now manage state transitions */ - - if (sample->contact == CONTACT_UP) - { - /* Next.. no contact. Increment the ID so that next contact ID - * will be unique. X/Y positions are no longer valid. - */ - - priv->sample.contact = CONTACT_NONE; - priv->sample.valid = false; - priv->id++; - } - else if (sample->contact == CONTACT_DOWN) - { - /* First report -- next report will be a movement */ - - priv->sample.contact = CONTACT_MOVE; - } - - priv->penchange = false; - ret = OK; - } - - irqrestore(flags); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_waitsample - ****************************************************************************/ - -static int tsc2007_waitsample(FAR struct tsc2007_dev_s *priv, - FAR struct tsc2007_sample_s *sample) -{ - irqstate_t flags; - int ret; - - /* Interrupts me be disabled when this is called to (1) prevent posting - * of semphores from interrupt handlers, and (2) to prevent sampled data - * from changing until it has been reported. - * - * In addition, we will also disable pre-emption to prevent other threads - * from getting control while we muck with the semaphores. - */ - - sched_lock(); - flags = irqsave(); - - /* Now release the semaphore that manages mutually exclusive access to - * the device structure. This may cause other tasks to become ready to - * run, but they cannot run yet because pre-emption is disabled. - */ - - sem_post(&priv->devsem); - - /* Try to get the a sample... if we cannot, then wait on the semaphore - * that is posted when new sample data is availble. - */ - - while (tsc2007_sample(priv, sample) < 0) - { - /* Wait for a change in the TSC2007 state */ - - priv->nwaiters++; - ret = sem_wait(&priv->waitsem); - priv->nwaiters--; - - if (ret < 0) - { - /* If we are awakened by a signal, then we need to return - * the failure now. - */ - - DEBUGASSERT(errno == EINTR); - ret = -EINTR; - goto errout; - } - } - - /* Re-acquire the the semaphore that manages mutually exclusive access to - * the device structure. We may have to wait here. But we have our sample. - * Interrupts and pre-emption will be re-enabled while we wait. - */ - - ret = sem_wait(&priv->devsem); - -errout: - /* Then re-enable interrupts. We might get interrupt here and there - * could be a new sample. But no new threads will run because we still - * have pre-emption disabled. - */ - - irqrestore(flags); - - /* Restore pre-emption. We might get suspended here but that is okay - * because we already have our sample. Note: this means that if there - * were two threads reading from the TSC2007 for some reason, the data - * might be read out of order. - */ - - sched_unlock(); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_activate - ****************************************************************************/ - -#ifdef CONFIG_TSC2007_ACTIVATE -static int tsc2007_activate(FAR struct tsc2007_dev_s *priv, uint8_t cmd) -{ - struct i2c_msg_s msg; - uint8_t data; - int ret; - - /* Send the setup command (with no ACK) followed by the A/D converter - * activation command (ACKed). - */ - - data = TSC2007_SETUP; - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = &data; /* Transfer from this address */ - msg.length = 1; /* Send one byte following the address */ - - /* Ignore errors from the setup command (because it is not ACKed) */ - - (void)I2C_TRANSFER(priv->i2c, &msg, 1); - - /* Now activate the A/D converter */ - - data = cmd; - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = &data; /* Transfer from this address */ - msg.length = 1; /* Send one byte following the address */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - } - return ret; -} -#else -# define tsc2007_activate(p,c) -#endif - -/**************************************************************************** - * Name: tsc2007_transfer - ****************************************************************************/ - -static int tsc2007_transfer(FAR struct tsc2007_dev_s *priv, uint8_t cmd) -{ - struct i2c_msg_s msg; - uint8_t data12[2]; - int ret; - - /* "A conversion/write cycle begins when the master issues the address - * byte containing the slave address of the TSC2007, with the eighth bit - * equal to a 0 (R/W = 0)... Once the eighth bit has been received... - * the TSC2007 issues an acknowledge. - * - * "When the master receives the acknowledge bit from the TSC2007, the - * master writes the command byte to the slave... After the command byte - * is received by the slave, the slave issues another acknowledge bit. - * The master then ends the write cycle by issuing a repeated START or a - * STOP condition... - */ - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = 0; /* Write transaction, beginning with START */ - msg.buffer = &cmd; /* Transfer from this address */ - msg.length = 1; /* Send one byte following the address */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return ret; - } - - /* "The input multiplexer channel for the A/D converter is selected when - * bits C3 through C0 are clocked in. If the selected channel is an X-,Y-, - * or Z-position measurement, the appropriate drivers turn on once the - * acquisition period begins. - * - * "... the input sample acquisition period starts on the falling edge of - * SCL when the C0 bit of the command byte has been latched, and ends - * when a STOP or repeated START condition has been issued. A/D conversion - * starts immediately after the acquisition period... - * - * "For best performance, the I2C bus should remain in an idle state while - * an A/D conversion is taking place. ... The master should wait for at - * least 10ms before attempting to read data from the TSC2007... - */ - - usleep(10*1000); - - /* "Data access begins with the master issuing a START condition followed - * by the address byte ... with R/W = 1. - * - * "When the eighth bit has been received and the address matches, the - * slave issues an acknowledge. The first byte of serial data then follows - * (D11-D4, MSB first). - * - * "After the first byte has been sent by the slave, it releases the SDA line - * for the master to issue an acknowledge. The slave responds with the - * second byte of serial data upon receiving the acknowledge from the master - * (D3-D0, followed by four 0 bits). The second byte is followed by a NOT - * acknowledge bit (ACK = 1) from the master to indicate that the last - * data byte has been received... - */ - - msg.addr = priv->config->address; /* 7-bit address */ - msg.flags = I2C_M_READ; /* Read transaction, beginning with START */ - msg.buffer = data12; /* Transfer to this address */ - msg.length = 2; /* Read two bytes following the address */ - - ret = I2C_TRANSFER(priv->i2c, &msg, 1); - if (ret < 0) - { - idbg("I2C_TRANSFER failed: %d\n", ret); - return ret; - } - - /* Get the MS 8 bits from the first byte and the remaining LS 4 bits from - * the second byte. The valid range of data is then from 0 to 4095 with - * the LSB unit corresponding to Vref/4096. - */ - - ret = (unsigned int)data12[0] << 4 | (unsigned int)data12[1] >> 4; - ivdbg("data: 0x%04x\n", ret); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_worker - ****************************************************************************/ - -static void tsc2007_worker(FAR void *arg) -{ - FAR struct tsc2007_dev_s *priv = (FAR struct tsc2007_dev_s *)arg; - FAR struct tsc2007_config_s *config; /* Convenience pointer */ - bool pendown; /* true: pend is down */ - uint16_t x; /* X position */ - uint16_t y; /* Y position */ - uint16_t z1; /* Z1 position */ - uint16_t z2; /* Z2 position */ - uint32_t pressure; /* Measured pressure */ - - ASSERT(priv != NULL); - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Check for pen up or down by reading the PENIRQ GPIO. */ - - pendown = config->pendown(config); - - /* Handle the change from pen down to pen up */ - - if (!pendown) - { - /* Ignore the interrupt if the pen was already down (CONTACT_NONE == pen up and - * already reported. CONTACT_UP == pen up, but not reported) - */ - - if (priv->sample.contact == CONTACT_NONE) - { - goto errout; - } - } - - /* It is a pen down event. If the last loss-of-contact event has not been - * processed yet, then we have to ignore the pen down event (or else it will - * look like a drag event) - */ - - else if (priv->sample.contact == CONTACT_UP) - { - goto errout; - } - else - { - /* Handle all pen down events. First, sample X, Y, Z1, and Z2 values. - * - * "A resistive touch screen operates by applying a voltage across a - * resistor network and measuring the change in resistance at a given - * point on the matrix where the screen is touched by an input (stylus, - * pen, or finger). The change in the resistance ratio marks the location - * on the touch screen. - * - * "The 4-wire touch screen panel works by applying a voltage across the - * vertical or horizontal resistive network. The A/D converter converts - * the voltage measured at the point where the panel is touched. A measurement - * of the Y position of the pointing device is made by connecting the X+ - * input to a data converter chip, turning on the Y+ and Y– drivers, and - * digitizing the voltage seen at the X+ input ..." - * - * "... it is recommended that whenever the host writes to the TSC2007, the - * master processor masks the interrupt associated to PENIRQ. This masking - * prevents false triggering of interrupts when the PENIRQ line is disabled - * in the cases previously listed." - */ - - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_X); - y = tsc2007_transfer(priv, TSC2007_MEASURE_Y); - - - /* "Voltage is then applied to the other axis, and the A/D converter - * converts the voltage representing the X position on the screen. This - * process provides the X and Y coordinates to the associated processor." - */ - - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_Y); - x = tsc2007_transfer(priv, TSC2007_MEASURE_X); - - /* "... To determine pen or finger touch, the pressure of the touch must be - * determined. ... There are several different ways of performing this - * measurement. The TSC2007 supports two methods. The first method requires - * knowing the X-plate resistance, the measurement of the X-position, and two - * additional cross panel measurements (Z2 and Z1) of the touch screen." - * - * Rtouch = Rxplate * (X / 4096)* (Z2/Z1 - 1) - * - * "The second method requires knowing both the X-plate and Y-plate - * resistance, measurement of X-position and Y-position, and Z1 ..." - * - * Rtouch = Rxplate * (X / 4096) * (4096/Z1 - 1) - Ryplate * (1 - Y/4096) - * - * Read Z1 and Z2 values. - */ - - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_Z); - z1 = tsc2007_transfer(priv, TSC2007_MEASURE_Z1); - (void)tsc2007_activate(priv, TSC2007_ACTIVATE_Z); - z2 = tsc2007_transfer(priv, TSC2007_MEASURE_Z2); - - /* Power down ADC and enable PENIRQ */ - - (void)tsc2007_transfer(priv, TSC2007_ENABLE_PENIRQ); - - /* Now calculate the pressure using the first method, reduced to: - * - * Rtouch = X * Rxplate *(Z2 - Z1) * / Z1 / 4096 - */ - - if (z1 == 0) - { - idbg("Z1 zero\n"); - pressure = 0; - } - else - { - pressure = (x * config->rxplate * (z2 - z1)) / z1; - pressure = (pressure + 2048) >> 12; - - ivdbg("Position: (%d,%4d) pressure: %u z1/2: (%d,%d)\n", - x, y, pressure, z1, z2); - - /* Ignore out of range caculcations */ - - if (pressure > 0x0fff) - { - idbg("Dropped out-of-range pressure: %d\n", pressure); - pressure = 0; - } - } - - /* Save the measurements */ - - priv->sample.x = x; - priv->sample.y = y; - priv->sample.pressure = pressure; - priv->sample.valid = true; - } - - /* Note the availability of new measurements */ - - if (pendown) - { - /* If this is the first (acknowledged) pend down report, then report - * this as the first contact. If contact == CONTACT_DOWN, it will be - * set to set to CONTACT_MOVE after the contact is first sampled. - */ - - if (priv->sample.contact != CONTACT_MOVE) - { - /* First contact */ - - priv->sample.contact = CONTACT_DOWN; - } - } - else /* if (priv->sample.contact != CONTACT_NONE) */ - { - /* The pen is up. NOTE: We know from a previous test, that this is a - * loss of contact condition. This will be changed to CONTACT_NONE - * after the loss of contact is sampled. - */ - - priv->sample.contact = CONTACT_UP; - } - - /* Indicate the availability of new sample data for this ID */ - - priv->sample.id = priv->id; - priv->penchange = true; - - /* Notify any waiters that nes TSC2007 data is available */ - - tsc2007_notify(priv); - - /* Exit, re-enabling TSC2007 interrupts */ - -errout: - config->enable(config, true); -} - -/**************************************************************************** - * Name: tsc2007_interrupt - ****************************************************************************/ - -static int tsc2007_interrupt(int irq, FAR void *context) -{ - FAR struct tsc2007_dev_s *priv; - FAR struct tsc2007_config_s *config; - int ret; - - /* Which TSC2007 device caused the interrupt? */ - -#ifndef CONFIG_TSC2007_MULTIPLE - priv = &g_tsc2007; -#else - for (priv = g_tsc2007list; - priv && priv->configs->irq != irq; - priv = priv->flink); - - ASSERT(priv != NULL); -#endif - - /* Get a pointer the callbacks for convenience (and so the code is not so - * ugly). - */ - - config = priv->config; - DEBUGASSERT(config != NULL); - - /* Disable further interrupts */ - - config->enable(config, false); - - /* Transfer processing to the worker thread. Since TSC2007 interrupts are - * disabled while the work is pending, no special action should be required - * to protected the work queue. - */ - - DEBUGASSERT(priv->work.worker == NULL); - ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0); - if (ret != 0) - { - illdbg("Failed to queue work: %d\n", ret); - } - - /* Clear any pending interrupts and return success */ - - config->clear(config); - return OK; -} - -/**************************************************************************** - * Name: tsc2007_open - ****************************************************************************/ - -static int tsc2007_open(FAR struct file *filep) -{ -#ifdef CONFIG_TSC2007_REFCNT - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - uint8_t tmp; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Increment the reference count */ - - tmp = priv->crefs + 1; - if (tmp == 0) - { - /* More than 255 opens; uint8_t overflows to zero */ - - ret = -EMFILE; - goto errout_with_sem; - } - - /* When the reference increments to 1, this is the first open event - * on the driver.. and an opportunity to do any one-time initialization. - */ - - /* Save the new open count on success */ - - priv->crefs = tmp; - -errout_with_sem: - sem_post(&priv->devsem); - return ret; -#else - return OK; -#endif -} - -/**************************************************************************** - * Name: tsc2007_close - ****************************************************************************/ - -static int tsc2007_close(FAR struct file *filep) -{ -#ifdef CONFIG_TSC2007_REFCNT - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Decrement the reference count unless it would decrement a negative - * value. When the count decrements to zero, there are no further - * open references to the driver. - */ - - if (priv->crefs >= 1) - { - priv->crefs--; - } - - sem_post(&priv->devsem); -#endif - return OK; -} - -/**************************************************************************** - * Name: tsc2007_read - ****************************************************************************/ - -static ssize_t tsc2007_read(FAR struct file *filep, FAR char *buffer, size_t len) -{ - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - FAR struct touch_sample_s *report; - struct tsc2007_sample_s sample; - int ret; - - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Verify that the caller has provided a buffer large enough to receive - * the touch data. - */ - - if (len < SIZEOF_TOUCH_SAMPLE_S(1)) - { - /* We could provide logic to break up a touch report into segments and - * handle smaller reads... but why? - */ - - return -ENOSYS; - } - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Try to read sample data. */ - - ret = tsc2007_sample(priv, &sample); - if (ret < 0) - { - /* Sample data is not available now. We would ave to wait to get - * receive sample data. If the user has specified the O_NONBLOCK - * option, then just return an error. - */ - - if (filep->f_oflags & O_NONBLOCK) - { - ret = -EAGAIN; - goto errout; - } - - /* Wait for sample data */ - - ret = tsc2007_waitsample(priv, &sample); - if (ret < 0) - { - /* We might have been awakened by a signal */ - - goto errout; - } - } - - /* In any event, we now have sampled TSC2007 data that we can report - * to the caller. - */ - - report = (FAR struct touch_sample_s *)buffer; - memset(report, 0, SIZEOF_TOUCH_SAMPLE_S(1)); - report->npoints = 1; - report->point[0].id = priv->id; - report->point[0].x = sample.x; - report->point[0].y = sample.y; - report->point[0].pressure = sample.pressure; - - /* Report the appropriate flags */ - - if (sample.contact == CONTACT_UP) - { - /* Pen is now up. Is the positional data valid? This is important to - * know because the release will be sent to the window based on its - * last positional data. - */ - - if (sample.valid) - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID | - TOUCH_POS_VALID | TOUCH_PRESSURE_VALID; - } - else - { - report->point[0].flags = TOUCH_UP | TOUCH_ID_VALID; - } - } - else - { - if (sample.contact == CONTACT_DOWN) - { - /* First contact */ - - report->point[0].flags = TOUCH_DOWN | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - else /* if (sample->contact == CONTACT_MOVE) */ - { - /* Movement of the same contact */ - - report->point[0].flags = TOUCH_MOVE | TOUCH_ID_VALID | TOUCH_POS_VALID; - } - - /* A pressure measurement of zero means that pressure is not available */ - - if (report->point[0].pressure != 0) - { - report->point[0].flags |= TOUCH_PRESSURE_VALID; - } - } - - ret = SIZEOF_TOUCH_SAMPLE_S(1); - -errout: - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name:tsc2007_ioctl - ****************************************************************************/ - -static int tsc2007_ioctl(FAR struct file *filep, int cmd, unsigned long arg) -{ - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - int ret; - - ivdbg("cmd: %d arg: %ld\n", cmd, arg); - DEBUGASSERT(filep); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Get exclusive access to the driver data structure */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - /* Process the IOCTL by command */ - - switch (cmd) - { - case TSIOC_SETCALIB: /* arg: Pointer to int calibration value */ - { - FAR int *ptr = (FAR int *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->rxplate = *ptr; - } - break; - - case TSIOC_GETCALIB: /* arg: Pointer to int calibration value */ - { - FAR int *ptr = (FAR int *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->rxplate; - } - break; - - case TSIOC_SETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - priv->config->frequency = I2C_SETFREQUENCY(priv->i2c, *ptr); - } - break; - - case TSIOC_GETFREQUENCY: /* arg: Pointer to uint32_t frequency value */ - { - FAR uint32_t *ptr = (FAR uint32_t *)((uintptr_t)arg); - DEBUGASSERT(priv->config != NULL && ptr != NULL); - *ptr = priv->config->frequency; - } - break; - - default: - ret = -ENOTTY; - break; - } - - sem_post(&priv->devsem); - return ret; -} - -/**************************************************************************** - * Name: tsc2007_poll - ****************************************************************************/ - -#ifndef CONFIG_DISABLE_POLL -static int tsc2007_poll(FAR struct file *filep, FAR struct pollfd *fds, - bool setup) -{ - FAR struct inode *inode; - FAR struct tsc2007_dev_s *priv; - int ret; - int i; - - ivdbg("setup: %d\n", (int)setup); - DEBUGASSERT(filep && fds); - inode = filep->f_inode; - - DEBUGASSERT(inode && inode->i_private); - priv = (FAR struct tsc2007_dev_s *)inode->i_private; - - /* Are we setting up the poll? Or tearing it down? */ - - ret = sem_wait(&priv->devsem); - if (ret < 0) - { - /* This should only happen if the wait was canceled by an signal */ - - DEBUGASSERT(errno == EINTR); - return -EINTR; - } - - if (setup) - { - /* Ignore waits that do not include POLLIN */ - - if ((fds->events & POLLIN) == 0) - { - idbg("Missing POLLIN: revents: %08x\n", fds->revents); - ret = -EDEADLK; - goto errout; - } - - /* This is a request to set up the poll. Find an available - * slot for the poll structure reference - */ - - for (i = 0; i < CONFIG_TSC2007_NPOLLWAITERS; i++) - { - /* Find an available slot */ - - if (!priv->fds[i]) - { - /* Bind the poll structure and this slot */ - - priv->fds[i] = fds; - fds->priv = &priv->fds[i]; - break; - } - } - - if (i >= CONFIG_TSC2007_NPOLLWAITERS) - { - idbg("No availabled slot found: %d\n", i); - fds->priv = NULL; - ret = -EBUSY; - goto errout; - } - - /* Should we immediately notify on any of the requested events? */ - - if (priv->penchange) - { - tsc2007_notify(priv); - } - } - else if (fds->priv) - { - /* This is a request to tear down the poll. */ - - struct pollfd **slot = (struct pollfd **)fds->priv; - DEBUGASSERT(slot != NULL); - - /* Remove all memory of the poll setup */ - - *slot = NULL; - fds->priv = NULL; - } - -errout: - sem_post(&priv->devsem); - return ret; -} -#endif - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: tsc2007_register - * - * Description: - * Configure the TSC2007 to use the provided I2C device instance. This - * will register the driver as /dev/inputN where N is the minor device - * number - * - * Input Parameters: - * dev - An I2C driver instance - * config - Persistant board configuration data - * minor - The input device minor number - * - * Returned Value: - * Zero is returned on success. Otherwise, a negated errno value is - * returned to indicate the nature of the failure. - * - ****************************************************************************/ - -int tsc2007_register(FAR struct i2c_dev_s *dev, - FAR struct tsc2007_config_s *config, int minor) -{ - FAR struct tsc2007_dev_s *priv; - char devname[DEV_NAMELEN]; -#ifdef CONFIG_TSC2007_MULTIPLE - irqstate_t flags; -#endif - int ret; - - ivdbg("dev: %p minor: %d\n", dev, minor); - - /* Debug-only sanity checks */ - - DEBUGASSERT(dev != NULL && config != NULL && minor >= 0 && minor < 100); - DEBUGASSERT((config->address & 0xfc) == 0x48); - DEBUGASSERT(config->attach != NULL && config->enable != NULL && - config->clear != NULL && config->pendown != NULL); - - /* Create and initialize a TSC2007 device driver instance */ - -#ifndef CONFIG_TSC2007_MULTIPLE - priv = &g_tsc2007; -#else - priv = (FAR struct tsc2007_dev_s *)kmalloc(sizeof(struct tsc2007_dev_s)); - if (!priv) - { - idbg("kmalloc(%d) failed\n", sizeof(struct tsc2007_dev_s)); - return -ENOMEM; - } -#endif - - /* Initialize the TSC2007 device driver instance */ - - memset(priv, 0, sizeof(struct tsc2007_dev_s)); - priv->i2c = dev; /* Save the I2C device handle */ - priv->config = config; /* Save the board configuration */ - sem_init(&priv->devsem, 0, 1); /* Initialize device structure semaphore */ - sem_init(&priv->waitsem, 0, 0); /* Initialize pen event wait semaphore */ - - /* Set the I2C frequency (saving the actual frequency) */ - - config->frequency = I2C_SETFREQUENCY(dev, config->frequency); - - /* Set the I2C address and address size */ - - ret = I2C_SETADDRESS(dev, config->address, 7); - if (ret < 0) - { - idbg("I2C_SETADDRESS failed: %d\n", ret); - goto errout_with_priv; - } - - /* Make sure that interrupts are disabled */ - - config->clear(config); - config->enable(config, false); - - /* Attach the interrupt handler */ - - ret = config->attach(config, tsc2007_interrupt); - if (ret < 0) - { - idbg("Failed to attach interrupt\n"); - goto errout_with_priv; - } - - /* Power down the ADC and enable PENIRQ. This is the normal state while - * waiting for a touch event. - */ - - ret = tsc2007_transfer(priv, TSC2007_ENABLE_PENIRQ); - if (ret < 0) - { - idbg("tsc2007_transfer failed: %d\n", ret); - goto errout_with_priv; - } - - /* Register the device as an input device */ - - (void)snprintf(devname, DEV_NAMELEN, DEV_FORMAT, minor); - ivdbg("Registering %s\n", devname); - - ret = register_driver(devname, &tsc2007_fops, 0666, priv); - if (ret < 0) - { - idbg("register_driver() failed: %d\n", ret); - goto errout_with_priv; - } - - /* If multiple TSC2007 devices are supported, then we will need to add - * this new instance to a list of device instances so that it can be - * found by the interrupt handler based on the recieved IRQ number. - */ - -#ifdef CONFIG_TSC2007_MULTIPLE - flags = irqsave(); - priv->flink = g_tsc2007list; - g_tsc2007list = priv; - irqrestore(flags); -#endif - - /* Schedule work to perform the initial sampling and to set the data - * availability conditions. - */ - - ret = work_queue(HPWORK, &priv->work, tsc2007_worker, priv, 0); - if (ret != 0) - { - idbg("Failed to queue work: %d\n", ret); - goto errout_with_priv; - } - - /* And return success (?) */ - - return OK; - -errout_with_priv: - sem_destroy(&priv->devsem); -#ifdef CONFIG_TSC2007_MULTIPLE - kfree(priv); -#endif - return ret; -} diff --git a/nuttx/drivers/input/tsc2007.h b/nuttx/drivers/input/tsc2007.h deleted file mode 100644 index 76d5962bf..000000000 --- a/nuttx/drivers/input/tsc2007.h +++ /dev/null @@ -1,120 +0,0 @@ -/******************************************************************************************** - * drivers/input/tsc2007.h - * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt <gnutt@nuttx.org> - * - * References: - * "1.2V to 3.6V, 12-Bit, Nanopower, 4-Wire Micro TOUCH SCREEN CONTROLLER - * with I2C Interface," SBAS405A March 2007, Revised, March 2009, Texas - * Instruments Incorporated - * - * 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. - * - ********************************************************************************************/ - -/* The TSC2007 is an analog interface circuit for a human interface touch screen device. - * All peripheral functions are controlled through the command byte and onboard state - * machines. - */ - -#ifndef __DRIVERS_INPUT_TSC2007_H -#define __DRIVERS_INPUT_TSC2007_H - -/******************************************************************************************** - * Included Files - ********************************************************************************************/ - -/******************************************************************************************** - * Pre-Processor Definitions - ********************************************************************************************/ - -/* TSC2007 Address */ - -#define TSC2007_ADDRESS_MASK (0xf8) /* Bits 3-7: Invariant part of TSC2007 address */ -#define TSC2007_ADDRESS (0x90) /* Bits 3-7: Always set at '10010' */ -#define TSC2007_A1 (1 << 2) /* Bit 2: A1 */ -#define TSC2007_A0 (1 << 1) /* Bit 1: A1 */ -#define TSC2007_READ (1 << 0) /* Bit0=1: Selects read operation */ -#define TSC2007_WRITE (0) /* Bit0=0: Selects write operation */ - -/* TSC2007 Command Byte */ - -#define TSC2007_CMD_FUNC_SHIFT (4) /* Bits 4-7: Converter function select bits */ -#define TSC2007_CMD_FUNC_MASK (15 << TSC2007_CMD_FUNC_SHIFT) -# define TSC2007_CMD_FUNC_TEMP0 (0 << TSC2007_CMD_FUNC_SHIFT) /* Measure TEMP0 */ -# define TSC2007_CMD_FUNC_AUX (2 << TSC2007_CMD_FUNC_SHIFT) /* Measure AUX */ -# define TSC2007_CMD_FUNC_TEMP1 (4 << TSC2007_CMD_FUNC_SHIFT) /* Measure TEMP1 */ -# define TSC2007_CMD_FUNC_XON (8 << TSC2007_CMD_FUNC_SHIFT) /* Activate X-drivers */ -# define TSC2007_CMD_FUNC_YON (9 << TSC2007_CMD_FUNC_SHIFT) /* Activate Y-drivers */ -# define TSC2007_CMD_FUNC_YXON (10 << TSC2007_CMD_FUNC_SHIFT) /* Activate Y+, X-drivers */ -# define TSC2007_CMD_FUNC_SETUP (11 << TSC2007_CMD_FUNC_SHIFT) /* Setup command */ -# define TSC2007_CMD_FUNC_XPOS (12 << TSC2007_CMD_FUNC_SHIFT) /* Measure X position */ -# define TSC2007_CMD_FUNC_YPOS (13 << TSC2007_CMD_FUNC_SHIFT) /* Measure Y position */ -# define TSC2007_CMD_FUNC_Z1POS (14 << TSC2007_CMD_FUNC_SHIFT) /* Measure Z1 position */ -# define TSC2007_CMD_FUNC_Z2POS (15 << TSC2007_CMD_FUNC_SHIFT) /* Measure Z2 positionn */ -#define TSC2007_CMD_PWRDN_SHIFT (2) /* Bits 2-3: Power-down bits */ -#define TSC2007_CMD_PWRDN_MASK (3 << TSC2007_CMD_PWRDN_SHIFT) -# define TSC2007_CMD_PWRDN_IRQEN (0 << TSC2007_CMD_PWRDN_SHIFT) /* 00: Power down between cycles; PENIRQ enabled */ -# define TSC2007_CMD_ADCON_IRQDIS (1 << TSC2007_CMD_PWRDN_SHIFT) /* 01: A/D converter on; PENIRQ disabled */ -# define TSC2007_CMD_ADCOFF_IRQEN (2 << TSC2007_CMD_PWRDN_SHIFT) /* 10: A/D converter off; PENIRQ enabled. */ - /* 11: A/D converter on; PENIRQ disabled. */ -#define TSC2007_CMD_12BIT (0) /* Bit 1: 0=12-bit */ -#define TSC2007_CMD_8BIT (1 << 1) /* Bit 1: 1=8-bit */ - /* Bit 0: Don't care */ - -/* TSC2007 Setup Command */ - -#define TSC2007_SETUP_CMD TSC2007_CMD_FUNC_SETUP /* Bits 4-7: Setup command */ - /* Bits 2-3: Must be zero */ -#define TSC2007_CMD_USEMAV (0) /* Bit 1: 0: Use the onboard MAV filter (default) */ -#define TSC2007_CMD_BYPASSMAV (1 << 1) /* Bit 1: 1: Bypass the onboard MAV filter */ -#define TSC2007_CMD_PU_50KOHM (0) /* Bit 0: 0: RIRQ = 50kOhm (default). */ -#define TSC2007_CMD_PU_90KOHM (1 << 1) /* Bit 0: 1: 1: RIRQ = 90kOhm */ - -/******************************************************************************************** - * Public Types - ********************************************************************************************/ - -/******************************************************************************************** - * Public Function Prototypes - ********************************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" { -#else -#define EXTERN extern -#endif - -#undef EXTERN -#ifdef __cplusplus -} -#endif - -#endif /* __DRIVERS_INPUT_TSC2007_H */ |