From e1e8f4debe3b059a6770b9da120a32fe7a11db1f Mon Sep 17 00:00:00 2001 From: patacongo Date: Tue, 2 Apr 2013 16:36:19 +0000 Subject: [PATCH] SSP driver fixes for the LPC178x; Fixes for Open1788 touchscreen driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5812 42af7a65-404d-4744-a932-0658087f49c3 --- arch/arm/src/armv6-m/Toolchain.defs | 2 +- arch/arm/src/lpc17xx/chip/lpc17_ssp.h | 11 +++ arch/arm/src/lpc17xx/lpc17_gpio.c | 1 - arch/arm/src/lpc17xx/lpc17_ssp.c | 77 ++++++++++++----- configs/open1788/README.txt | 6 +- configs/open1788/include/board.h | 6 -- configs/open1788/src/lpc17_ssp.c | 2 +- configs/open1788/src/lpc17_touchscreen.c | 103 ++++++++++++++++------- drivers/input/Kconfig | 18 +++- 9 files changed, 161 insertions(+), 65 deletions(-) diff --git a/arch/arm/src/armv6-m/Toolchain.defs b/arch/arm/src/armv6-m/Toolchain.defs index 7fc4bf9cd1..22427d1889 100644 --- a/arch/arm/src/armv6-m/Toolchain.defs +++ b/arch/arm/src/armv6-m/Toolchain.defs @@ -160,6 +160,6 @@ endif ifeq ($(CONFIG_ARMV6M_TOOLCHAIN),GNU_EABI) CROSSDEV ?= arm-none-eabi- ARCROSSDEV ?= arm-none-eabi- - MAXOPTIMIZATION = -O3 + MAXOPTIMIZATION = -Os ARCHCPUFLAGS = -mcpu=cortex-m0 -mthumb -march=armv6-m -mfloat-abi=soft endif diff --git a/arch/arm/src/lpc17xx/chip/lpc17_ssp.h b/arch/arm/src/lpc17xx/chip/lpc17_ssp.h index e97a670a87..dd791327fb 100644 --- a/arch/arm/src/lpc17xx/chip/lpc17_ssp.h +++ b/arch/arm/src/lpc17xx/chip/lpc17_ssp.h @@ -89,6 +89,17 @@ #define LPC17_SSP1_ICR (LPC17_SSP1_BASE+LPC17_SSP_ICR_OFFSET) #define LPC17_SSP1_DMACR (LPC17_SSP1_BASE+LPC17_SSP_DMACR_OFFSET) +#define LPC17_SSP2_CR0 (LPC17_SSP2_BASE+LPC17_SSP_CR0_OFFSET) +#define LPC17_SSP2_CR1 (LPC17_SSP2_BASE+LPC17_SSP_CR1_OFFSET) +#define LPC17_SSP2_DR (LPC17_SSP2_BASE+LPC17_SSP_DR_OFFSET) +#define LPC17_SSP2_SR (LPC17_SSP2_BASE+LPC17_SSP_SR_OFFSET) +#define LPC17_SSP2_CPSR (LPC17_SSP2_BASE+LPC17_SSP_CPSR_OFFSET) +#define LPC17_SSP2_IMSC (LPC17_SSP2_BASE+LPC17_SSP_IMSC_OFFSET) +#define LPC17_SSP2_RIS (LPC17_SSP2_BASE+LPC17_SSP_RIS_OFFSET) +#define LPC17_SSP2_MIS (LPC17_SSP2_BASE+LPC17_SSP_MIS_OFFSET) +#define LPC17_SSP2_ICR (LPC17_SSP2_BASE+LPC17_SSP_ICR_OFFSET) +#define LPC17_SSP2_DMACR (LPC17_SSP2_BASE+LPC17_SSP_DMACR_OFFSET) + /* Register bit definitions *********************************************************/ /* Control Register 0 */ diff --git a/arch/arm/src/lpc17xx/lpc17_gpio.c b/arch/arm/src/lpc17xx/lpc17_gpio.c index 05c3caa208..43b2fc8912 100644 --- a/arch/arm/src/lpc17xx/lpc17_gpio.c +++ b/arch/arm/src/lpc17xx/lpc17_gpio.c @@ -52,7 +52,6 @@ #include "chip.h" #include "lpc17_gpio.h" - /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ diff --git a/arch/arm/src/lpc17xx/lpc17_ssp.c b/arch/arm/src/lpc17xx/lpc17_ssp.c index 3c9a519042..11f8da38b9 100644 --- a/arch/arm/src/lpc17xx/lpc17_ssp.c +++ b/arch/arm/src/lpc17xx/lpc17_ssp.c @@ -92,6 +92,7 @@ #endif /* SSP Clocking *************************************************************/ + #if defined(LPC176x) /* The CPU clock by 1, 2, 4, or 8 to get the SSP peripheral clock (SSP_CLOCK). * SSP_CLOCK may be further divided by 2-254 to get the SSP clock. If we @@ -106,17 +107,16 @@ # if LPC17_CCLK > 100000000 # error "CCLK <= 100,000,000 assumed" -# endif +# endif # define SSP_PCLKSET_DIV SYSCON_PCLKSEL_CCLK # define SSP_CLOCK LPC17_CCLK +#elif defined(LPC178x) /* All peripherals are clocked by the same peripheral clock in the LPC178x * family. */ -#elif defined(LPC178x) - # define SSP_CLOCK BOARD_PCLK_FREQUENCY #endif @@ -397,10 +397,12 @@ static int ssp_lock(FAR struct spi_dev_s *dev, bool lock) static uint32_t ssp_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency) { FAR struct lpc17_sspdev_s *priv = (FAR struct lpc17_sspdev_s *)dev; - uint32_t divisor; + uint32_t cpsdvsr; + uint32_t scr; + uint32_t regval; uint32_t actual; - /* Check if the requested frequence is the same as the frequency selection */ + /* Check if the requested frequency is the same as the frequency selection */ DEBUGASSERT(priv && frequency <= SSP_CLOCK / 2); #ifndef CONFIG_SPI_OWNBUS @@ -412,30 +414,65 @@ static uint32_t ssp_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency) } #endif - /* frequency = SSP_CLOCK / divisor, or divisor = SSP_CLOCK / frequency */ + /* The SSP bit frequency is given by: + * + * frequency = SSP_CLOCK / (CPSDVSR * (SCR+1)). + * + * Let's try for a solution with the smallest value of SCR. NOTES: + * (1) In the calculations below, the value of the variable 'scr' is + * (SCR+1) in the above equation. (2) On slower LPC17xx parts, SCR + * will probably always be zero. + */ - divisor = SSP_CLOCK / frequency; - - /* "In master mode, CPSDVSRmin = 2 or larger (even numbers only)" */ - - if (divisor < 2) + for (scr = 1; scr <= 256; scr++) { - divisor = 2; - } - else if (divisor > 254) - { - divisor = 254; + /* CPSDVSR = SSP_CLOCK / (SCR + 1) / frequency */ + + cpsdvsr = SSP_CLOCK / (scr * frequency); + + /* Break out on the first solution we find with the smallest value + * of SCR and with CPSDVSR within the maximum range or 254. + */ + + if (cpsdvsr < 255) + { + break; + } } - divisor = (divisor + 1) & ~1; + DEBUGASSERT(scr <= 256 && cpsdvsr <= 255); - /* Save the new divisor value */ + /* "In master mode, CPSDVSRmin = 2 or larger (even numbers only)" */ + + if (cpsdvsr < 2) + { + /* Clip to the minimum value. */ + + cpsdvsr = 2; + } + else if (cpsdvsr > 254) + { + /* This should never happen */ + + cpsdvsr = 254; + } + + /* Force even */ + + cpsdvsr = (cpsdvsr + 1) & ~1; + + /* Save the new CPSDVSR and SCR values */ - ssp_putreg(priv, LPC17_SSP_CPSR_OFFSET, divisor); + ssp_putreg(priv, LPC17_SSP_CPSR_OFFSET, cpsdvsr); + + regval = ssp_getreg(priv, LPC17_SSP_CR0_OFFSET); + regval &= ~SSP_CR0_SCR_MASK; + regval |= ((scr - 1) << SSP_CR0_SCR_SHIFT); + ssp_putreg(priv, LPC17_SSP_CR0_OFFSET, regval); /* Calculate the new actual */ - actual = SSP_CLOCK / divisor; + actual = SSP_CLOCK / (cpsdvsr * scr); /* Save the frequency setting */ diff --git a/configs/open1788/README.txt b/configs/open1788/README.txt index 61a01c3a76..1c3a5191eb 100644 --- a/configs/open1788/README.txt +++ b/configs/open1788/README.txt @@ -453,10 +453,11 @@ CONFIGURATION following ways: CONFIG_INPUT=y : Enable support for input devices - CONFIG_GPIO_IRQ=y : GPIO interrupt support CONFIG_INPUT_ADS7843E=y : Enable support for the XPT2048 + CONFIG_ADS7843E_SPIDEV=1 : Use SSP1 for communication CONFIG_SPI=y : Enable SPI support CONFIG_SPI_EXCHANGE=n : exchange() method is not supported + CONFIG_GPIO_IRQ=y : GPIO interrupt support CONFIG_LPC17_SSP1=y : Enable support for SSP1 CONFIG_EXAMPLES_TOUCHSCREEN=y : Enable the touchscreen built-int test CONFIG_EXAMPLES_TOUCHSCREEN_BUILTIN=y @@ -466,7 +467,8 @@ CONFIGURATION You will also have to disable SD card support to use this test. The SD card detect (CD) signal is on P0[13]. This signal is shared. It is also used for MOSI1 and USB_UP_LED. The CD pin may be disconnected. - There is a jumper on board that enables the CD pin. + There is a jumper on board that enables the CD pin. OR, you can simply + remove the SD module so that it does not drive the CD pin. CONFIG_LPC17_GPDMA=n : No DMA CONFIG_ARCH_DMA=n diff --git a/configs/open1788/include/board.h b/configs/open1788/include/board.h index 421476cabe..ffcdf72117 100644 --- a/configs/open1788/include/board.h +++ b/configs/open1788/include/board.h @@ -407,12 +407,6 @@ #define GPIO_SSP1_MOSI GPIO_SSP1_MOSI_2 #define GPIO_SSP1_SCK GPIO_SSP1_SCK_2 -#define GPIO_SSP1_SSEL_1 (GPIO_ALT2 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN6) -#define GPIO_SSP1_SSEL_2 (GPIO_ALT2 | GPIO_PULLUP | GPIO_PORT0 | GPIO_PIN14) -#define GPIO_SSP1_SSEL_3 (GPIO_ALT5 | GPIO_PULLUP | GPIO_PORT1 | GPIO_PIN26) -#define GPIO_SSP1_SSEL_4 (GPIO_ALT3 | GPIO_PULLUP | GPIO_PORT4 | GPIO_PIN21) - - /************************************************************************************ * Public Types ************************************************************************************/ diff --git a/configs/open1788/src/lpc17_ssp.c b/configs/open1788/src/lpc17_ssp.c index e27894e72c..4f3995243d 100644 --- a/configs/open1788/src/lpc17_ssp.c +++ b/configs/open1788/src/lpc17_ssp.c @@ -174,7 +174,7 @@ void lpc17_ssp1select(FAR struct spi_dev_s *dev, enum spi_dev_e devid, bool sel sspdbg("devid: %d CS: %s\n", (int)devid, selected ? "assert" : "de-assert"); if (devid == SPIDEV_TOUCHSCREEN) { - /* Assert/de-assert the CS pin to the card */ + /* Assert/de-assert the CS pin to the touchscreen */ ssp_dumpgpio(GPIO_TC_CS, "lpc17_ssp1select() Entry"); lpc17_gpiowrite(GPIO_TC_CS, !selected); diff --git a/configs/open1788/src/lpc17_touchscreen.c b/configs/open1788/src/lpc17_touchscreen.c index 1ee8d6237d..19b8b58057 100644 --- a/configs/open1788/src/lpc17_touchscreen.c +++ b/configs/open1788/src/lpc17_touchscreen.c @@ -80,17 +80,27 @@ #endif #ifndef CONFIG_ADS7843E_SPIDEV -# define CONFIG_ADS7843E_SPIDEV 3 +# define CONFIG_ADS7843E_SPIDEV 1 #endif -#if CONFIG_ADS7843E_SPIDEV != 3 -# error "CONFIG_ADS7843E_SPIDEV must be three" +#if CONFIG_ADS7843E_SPIDEV != 1 +# error "CONFIG_ADS7843E_SPIDEV must be one" #endif #ifndef CONFIG_ADS7843E_DEVMINOR # define CONFIG_ADS7843E_DEVMINOR 0 #endif +/* REVISIT: Currently, XPT2046 reports BUSY all of the time. This is + * probably GPIO setting issues. But there is this cryptic statement in + * the XPT2046 spec: "No DCLK delay required with dedicated serial port." + * + * The busy state is used by the XPT2046 driver to control the delay + * between sending the command, then reading the returned data. + */ + +#define XPT2046_NO_BUSY 1 + /**************************************************************************** * Private Types ****************************************************************************/ @@ -100,12 +110,12 @@ ****************************************************************************/ /* IRQ/GPIO access callbacks. These operations all hidden behind - * callbacks to isolate the ADS7843E driver from differences in GPIO + * callbacks to isolate the XPT2046 driver from differences in GPIO * interrupt handling by varying boards and MCUs. If possible, * interrupts should be configured on both rising and falling edges * so that contact and loss-of-contact events can be detected. * - * attach - Attach the ADS7843E interrupt handler to the GPIO interrupt + * attach - Attach the XPT2046 interrupt handler to the GPIO interrupt * enable - Enable or disable the GPIO interrupt * clear - Acknowledge/clear any pending GPIO interrupt * pendown - Return the state of the pen down GPIO input @@ -121,9 +131,9 @@ static bool tsc_pendown(FAR struct ads7843e_config_s *state); * Private Data ****************************************************************************/ -/* A reference to a structure of this type must be passed to the ADS7843E +/* A reference to a structure of this type must be passed to the XPT2046 * driver. This structure provides information about the configuration - * of the ADS7843E and provides some board-specific hooks. + * of the XPT2046 and provides some board-specific hooks. * * Memory for this structure is provided by the caller. It is not copied * by the driver and is presumed to persist while the driver is active. @@ -144,12 +154,12 @@ static struct ads7843e_config_s g_tscinfo = ****************************************************************************/ /* IRQ/GPIO access callbacks. These operations all hidden behind - * callbacks to isolate the ADS7843E driver from differences in GPIO + * callbacks to isolate the XPT2046 driver from differences in GPIO * interrupt handling by varying boards and MCUs. If possible, * interrupts should be configured on both rising and falling edges * so that contact and loss-of-contact events can be detected. * - * attach - Attach the ADS7843E interrupt handler to the GPIO interrupt + * attach - Attach the XPT2046 interrupt handler to the GPIO interrupt * enable - Enable or disable the GPIO interrupt * clear - Acknowledge/clear any pending GPIO interrupt * pendown - Return the state of the pen down GPIO input @@ -183,6 +193,20 @@ static void tsc_clear(FAR struct ads7843e_config_s *state) static bool tsc_busy(FAR struct ads7843e_config_s *state) { +/* The busy state is used by the XPT2046 driver to control the delay + * between sending the command, then reading the returned data. + */ + +#ifdef XPT2046_NO_BUSY +/* REVISIT: Currently, XPT2046 reports BUSY all of the time. This is + * probably GPIO setting issues. But there is this cryptic statement in + * the XPT2046 spec: "No DCLK delay required with dedicated serial port." + */ + + return false; + +#else /* XPT2046_NO_BUSY */ + #if defined(CONFIG_DEBUG_INPUT) && defined(CONFIG_DEBUG_VERBOSE) static bool last = (bool)-1; #endif @@ -199,6 +223,8 @@ static bool tsc_busy(FAR struct ads7843e_config_s *state) #endif return busy; + +#endif /* XPT2046_NO_BUSY */ } static bool tsc_pendown(FAR struct ads7843e_config_s *state) @@ -237,37 +263,50 @@ static bool tsc_pendown(FAR struct ads7843e_config_s *state) int arch_tcinitialize(int minor) { + static bool initialized = false; FAR struct spi_dev_s *dev; int ret; - idbg("minor %d\n", minor); + idbg("initialized:%d minor:%d\n", initialized, minor); DEBUGASSERT(minor == 0); - /* Configure and enable the ADS7843E PENIRQ pin as an interrupting input. */ + /* Since there is no uninitialized logic, this initialization can be + * performed only one time. + */ - (void)lpc17_configgpio(GPIO_TC_PENIRQ); - - /* Configure the ADS7843E BUSY pin as a normal input. */ - - (void)lpc17_configgpio(GPIO_TC_BUSY); - - /* Get an instance of the SPI interface */ - - dev = lpc17_sspinitialize(CONFIG_ADS7843E_SPIDEV); - if (!dev) + if (!initialized) { - idbg("Failed to initialize SPI bus %d\n", CONFIG_ADS7843E_SPIDEV); - return -ENODEV; - } + /* Configure and enable the XPT2046 PENIRQ pin as an interrupting input. */ - /* Initialize and register the SPI touschscreen device */ + (void)lpc17_configgpio(GPIO_TC_PENIRQ); - ret = ads7843e_register(dev, &g_tscinfo, CONFIG_ADS7843E_DEVMINOR); - if (ret < 0) - { - idbg("Failed to initialize SPI bus %d\n", CONFIG_ADS7843E_SPIDEV); - /* up_spiuninitialize(dev); */ - return -ENODEV; + /* Configure the XPT2046 BUSY pin as a normal input. */ + +#ifndef XPT2046_NO_BUSY + (void)lpc17_configgpio(GPIO_TC_BUSY); +#endif + + /* Get an instance of the SPI interface */ + + dev = lpc17_sspinitialize(CONFIG_ADS7843E_SPIDEV); + if (!dev) + { + idbg("Failed to initialize SPI bus %d\n", CONFIG_ADS7843E_SPIDEV); + return -ENODEV; + } + + /* Initialize and register the SPI touchscreen device */ + + ret = ads7843e_register(dev, &g_tscinfo, CONFIG_ADS7843E_DEVMINOR); + if (ret < 0) + { + idbg("Failed to register touchscreen device minor=%d\n", + CONFIG_ADS7843E_DEVMINOR); + /* up_spiuninitialize(dev); */ + return -ENODEV; + } + + initialized = true; } return OK; @@ -291,7 +330,7 @@ int arch_tcinitialize(int minor) void arch_tcuninitialize(void) { - /* No support for un-initializing the touchscreen ADS7843E device yet */ + /* No support for un-initializing the touchscreen XPT2046 device yet */ } #endif /* CONFIG_INPUT_ADS7843E */ diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 6da3a9f395..aafb5007b2 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -57,13 +57,27 @@ config ADS7843E_NPOLLWAITERS ---help--- Maximum number of threads that can be waiting on poll() +config ADS7843E_SPIDEV + int "SPI bus number" + default 0 + ---help--- + Selects the SPI bus number identying that SPI interface that + connects the ADS843E to the MCU. + +config ADS7843E_DEVMINOR + int "Input device minor number" + default 0 + ---help--- + The ADS7843E device will be registered as /dev/inputN where N is the + value provided by this setting. + 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. + Controls the SPI mode. The device should work in mode 0, but + sometimes you need to experiment. config ADS7843E_FREQUENCY int "SPI frequency"