diff --git a/arch/arm/include/max326xx/max32620_30_irq.h b/arch/arm/include/max326xx/max32620_30_irq.h index 8e87a1ec747..ae7be3dc398 100644 --- a/arch/arm/include/max326xx/max32620_30_irq.h +++ b/arch/arm/include/max326xx/max32620_30_irq.h @@ -104,7 +104,20 @@ /* Number of external interrupts and total number of vectors */ #define MAX326_IRQ_NEXTINT 50 -#define NR_IRQS (MAX326_IRQ_EXTINT + MAX326_IRQ_NEXTINT) + +#define MAX326_IRQ_NVECTORS (MAX326_IRQ_EXTINT + MAX326_IRQ_NEXTINT) + +/* If GPIO pin interrupts are used then there is a second level of interrupt decode */ + +#ifdef CONFIG_MAX326_GPIOIRQ +#warning Missing logic +#else +# define MAX326_IRQ_NPININT 0 +#endif + +/* Total number of interrupts handled by the OS */ + +#define NR_IRQS (MAX326_IRQ_NVECTORS + MAX326_IRQ_NPININT) /************************************************************************************************ * Public Types diff --git a/arch/arm/include/max326xx/max32660_irq.h b/arch/arm/include/max326xx/max32660_irq.h index eaa91b900e1..b898b664b80 100644 --- a/arch/arm/include/max326xx/max32660_irq.h +++ b/arch/arm/include/max326xx/max32660_irq.h @@ -86,10 +86,41 @@ /* 46-48 Reserved */ #define MAX326_IRQ_SPIS (MAX326_IRQ_EXTINT + 49) /* 49 SPI Slave */ -/* Number of external interrupts and total number of vectors */ +/* Number of external interrupts and number of true interrupt vectors */ #define MAX326_IRQ_NEXTINT 50 -#define NR_IRQS (MAX326_IRQ_EXTINT + MAX326_IRQ_NEXTINT) +#define MAX326_IRQ_NVECTORS (MAX326_IRQ_EXTINT + MAX326_IRQ_NEXTINT) + +/* If GPIO pin interrupts are used then there is a second level of interrupt decode */ + +#ifdef CONFIG_MAX326_GPIOIRQ +/* Up to 14 pins are available as interrupt sources, depending on the MAX32660 package */ + +# define MAX326_IRQ_P0_0 (MAX326_IRQ_NEXTINT + 0) +# define MAX326_IRQ_P0_1 (MAX326_IRQ_NEXTINT + 1) +# define MAX326_IRQ_P0_2 (MAX326_IRQ_NEXTINT + 2) +# define MAX326_IRQ_P0_3 (MAX326_IRQ_NEXTINT + 3) +# define MAX326_IRQ_P0_4 (MAX326_IRQ_NEXTINT + 4) +# define MAX326_IRQ_P0_5 (MAX326_IRQ_NEXTINT + 5) +# define MAX326_IRQ_P0_6 (MAX326_IRQ_NEXTINT + 6) +# define MAX326_IRQ_P0_7 (MAX326_IRQ_NEXTINT + 7) +# define MAX326_IRQ_P0_8 (MAX326_IRQ_NEXTINT + 8) +# define MAX326_IRQ_P0_9 (MAX326_IRQ_NEXTINT + 9) +# define MAX326_IRQ_P0_10 (MAX326_IRQ_NEXTINT + 10) +# define MAX326_IRQ_P0_11 (MAX326_IRQ_NEXTINT + 11) +# define MAX326_IRQ_P0_12 (MAX326_IRQ_NEXTINT + 12) +# define MAX326_IRQ_P0_13 (MAX326_IRQ_NEXTINT + 13) + +# define MAX326_IRQ_GPIO1ST MAX326_IRQ_P0_0 +# define MAX326_IRQ_GPIOLAST MAX326_IRQ_P0_13 +# define MAX326_IRQ_NPININT 14 +#else +# define MAX326_IRQ_NPININT 0 +#endif + +/* Total number of interrupts handled by the OS */ + +#define NR_IRQS (MAX326_IRQ_NVECTORS + MAX326_IRQ_NPININT) /************************************************************************************************ * Public Types diff --git a/arch/arm/src/max326xx/common/max326_irq.c b/arch/arm/src/max326xx/common/max326_irq.c index c9a048811a3..9d34d9c83ce 100644 --- a/arch/arm/src/max326xx/common/max326_irq.c +++ b/arch/arm/src/max326xx/common/max326_irq.c @@ -439,6 +439,15 @@ void up_disable_irq(int irq) uint32_t regval; uint32_t bit; +#ifdef CONFIG_MAX326_GPIOIRQ + /* Handle "fake" GPIO irq */ + + if (irq >= MAX326_IRQ_GPIO1ST && irq <= MAX326_IRQ_GPIOLAST) + { + max326_gpio_irqdisable(irq); + } + else +#endif if (max326_irqinfo(irq, ®addr, &bit, NVIC_CLRENA_OFFSET) == 0) { /* Modify the appropriate bit in the register to disable the interrupt. @@ -476,6 +485,15 @@ void up_enable_irq(int irq) uint32_t regval; uint32_t bit; +#ifdef CONFIG_MAX326_GPIOIRQ + /* Handle "fake" GPIO irq */ + + if (irq >= MAX326_IRQ_GPIO1ST && irq <= MAX326_IRQ_GPIOLAST) + { + max326_gpio_irqensable(irq); + } + else +#endif if (max326_irqinfo(irq, ®addr, &bit, NVIC_ENA_OFFSET) == 0) { /* Modify the appropriate bit in the register to enable the interrupt. @@ -542,13 +560,20 @@ int up_prioritize_irq(int irq, int priority) regaddr = NVIC_SYSH_PRIORITY(irq); irq -= 4; } - else + else if (irq < MAX326_IRQ_NVECTORS) { /* NVIC_IRQ_PRIORITY() maps {0..} to one of many priority registers */ irq -= MAX326_IRQ_EXTINT; regaddr = NVIC_IRQ_PRIORITY(irq); } + else + { +#ifndef CONFIG_MAX326_GPIOIRQ + DEBUGPANIC(); +#endif + return; + } regval = getreg32(regaddr); shift = ((irq & 3) << 3); diff --git a/arch/arm/src/max326xx/max32660/max32660_gpio.c b/arch/arm/src/max326xx/max32660/max32660_gpio.c new file mode 100644 index 00000000000..85aa0aac960 --- /dev/null +++ b/arch/arm/src/max326xx/max32660/max32660_gpio.c @@ -0,0 +1,599 @@ +/**************************************************************************** + * arch/arm/src/max32660/max326_gpio.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include + +#include + +#include "up_arch.h" + +#include "max326_gpio.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* MODE AF1 AF0 + * I/O 0 1 + * Alternate Function 1 0 0 + * Alternate Function 2 1 0 + * Alternate Function 3 1 1 + */ + +#define IO_MODE 1,0 +#define AF_FUNC1 0,0 +#define AF_FUNC2 0,1 +#define AF_FUNC3 1,1 + +/* Pins 0-1, 4-7, and 10-13 support 4 levels of drive strength */ + +#define DS1_SET 0x00003cf3 + +/* Pins 0-1, 4-7, and 10-13 support pull-up resistors */ + +#define PULLUP_SET 0x00003cf3 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_GPIO_INFO +static const char *g_afmode[4] = +{ + "Alt Function 1" + "GPIO" + "Alt Function 2" + "Alt Function 3" +}; + +static const char *g_pullmode[3] = +{ + "None" + "Pull-Down" + "Pull-Up" +}; + +static const char *g_dsmode[4] = +{ + "Low" + "Medium Low" + "Medium High" + "High" +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: max326_altfunc + * + * Description: + * Set the alternate function pins: + * + * MODE AF1 AF0 + * I/O 0 1 + * Alternate Function 1 0 0 + * Alternate Function 2 1 0 + * Alternate Function 3 1 1 + * + ****************************************************************************/ + +void max326_altfunc(uint32_t pinmask, bool af0, bool af1) +{ + uint32_t regval; + + regval = getreg32(MAX326_GPIO0_AF0SEL); + if (af0) + { + regval |= pinmask; + } + else + { + regval &= ~pinmask; + } + + putreg32(regval, MAX326_GPIO0_AF0SEL) + + regval = getreg32(MAX326_GPIO0_AF1SEL); + if (af1) + { + regval |= pinmask; + } + else + { + regval &= ~pinmask; + } + + putreg32(regval, MAX326_GPIO0_AF1SEL) +} + +/**************************************************************************** + * Name: max326_default + * + * Description: + * Configure a pin as a default GPIO input as it was on reset (unless this + * is an SWD pin) + * + ****************************************************************************/ + +void max326_default(uint32_t pinmask); +{ + uint32_t regval; + + /* Disable interrupts and wake-up events */ + + regval = getreg32(MAX326_GPIO0_INTEN); /* Pin interrupt disabled triggered */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_INTEN) + + regval = getreg32(MAX326_GPIO0_INTMODE); /* Level triggered */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_INTMODE) + + regval = getreg32(MAX326_GPIO0_INTPOL); /* Input low triggers */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_INTPOL) + + regval = getreg32(MAX326_GPIO0_INTDUALEDGE); /* Disable dual edge */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_INTDUALEDGE) + + regval = getreg32(MAX326_GPIO0_WAKEEN); /* Disable wakeup */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_WAKEEN) + + /* Make the pin an input */ + + regval = getreg32(MAX326_GPIO0_OUTEN); /* Disable output drivers */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_OUTEN) + + regval = getreg32(MAX326_GPIO0_OUT); /* Set the output value to zero */ + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_OUT) + + /* Set alternate functions to I/O */ + + max326_altfunc(pinmask, IO_MODE); + + /* Reset drive strength */ + + regval = getreg32(MAX326_GPIO0_DS0SEL); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_DS0SEL) + + regval = getreg32(MAX326_GPIO0_DS1SEL); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_DS1SEL) + + /* Disable pull up and pull down */ + + regval = getreg32(MAX326_GPIO0_PULLEN); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_PULLEN) + + regval = getreg32(MAX326_GPIO0_PULLSEL); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_PULLSEL) + + /* Disable slew and hysteresis */ + + regval = getreg32(MAX326_GPIO0_SRSEL); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_SRSEL) + + regval = getreg32(MAX326_GPIO0_INHYSEN); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_INHYSEN) +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: max326_gpio_config + * + * Description: + * Configure a GPIO pin based on bit-encoded description of the pin. + * + ****************************************************************************/ + +int max326_gpio_config(max326_pinset_t cfgset) +{ + unsigned int pin; + uint32_t pinmask; + uint32_t regval; + irqset_t flags; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + pinmask = 1 << pin; + + /* Modification of all registers must be atomic */ + + flags = spin_lock_irqsave(); + + /* First, force the pin configuration to the default generic input state. + * So that we know we are starting from a known state. + */ + + max326_default(pinmask); + + /* Then perform the actual pin configuration. We need only to set values + * that are not in the default, reset state. + */ + + /* Enable slew and hysteresis */ + + if ((cfgset & GPIO_SLEW) != 0) + { + regval = getreg32(MAX326_GPIO0_SRSEL); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_SRSEL) + } + + if ((cfgset & GPIO_HYSTERESIS) != 0) + { + regval = getreg32(MAX326_GPIO0_INHYSEN); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_INHYSEN) + } + + /* Enable pull up and pull down */ + + if ((cfgset & GPIO_MODE_MASK) != GPIO_FLOAT) + { + /* Enable pull-down resistor */ + + if ((PULLUP_SET & pinmask) != 0 || + (cfgset & GPIO_MODE_MASK) == GPIO_PULLDOWN) + { + regval = getreg32(AX326_GPIO_PULLEN); + regval |= pinmask; + putreg32(regval, AX326_GPIO_PULLEN) + + if ((PULLUP_SET & pinmask) != 0 && + (cfgset & GPIO_MODE_MASK) == GPIO_PULLUP) + { + /* Enable pull-up resistor */ + + regval = getreg32(MAX326_GPIO0_PULLSEL); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_PULLSEL) + } + } + + /* Set drive strength */ + + if ((DS1_SET & pinmask) == 0) + { + /* Only two levels of drive strength */ + + if ((cfgset & GPIO_DRIVE_MASK) != GPIO_DRIVE_MEDHI || + (cfgset & GPIO_DRIVE_MASK) != GPIO_DRIVE_HI) + { + regval = getreg32(MAX326_GPIO0_DS0SEL); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_DS0SEL) + } + } + else + { + /* Four levels of drive strength: Order by drive strength: + * + * LO DS0=0 DS1=0 + * MEDLO DS0=1 DS1=0 + * MEDHI DS0=0 DS1=1 + * HI DS0=1 DS1=1 + */ + + if ((cfgset & GPIO_DRIVE_MASK) != GPIO_DRIVE_MEDLO || + (cfgset & GPIO_DRIVE_MASK) != GPIO_DRIVE_HI) + { + regval = getreg32(MAX326_GPIO0_DS0SEL); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_DS0SEL) + } + + if ((cfgset & GPIO_DRIVE_MASK) != GPIO_DRIVE_MEDHI || + (cfgset & GPIO_DRIVE_MASK) != GPIO_DRIVE_HI) + { + regval = getreg32(MAX326_GPIO0_DS1SEL); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_DS1SEL) + } + } + + /* Handle the pin function */ + + switch (cfgset & GPIO_FUNC_MASK) + { + case GPIO_OUTPUT: + if ((cfgset & GPIO_VALUE) == GPIO_VALUE_ONE) + { + regval = getreg32(MAX326_GPIO0_OUT); /* Set output high */ + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_OUT) + } + + regval = getreg32(MAX326_GPIO0_OUTEN); /* Enable output drivers */ + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_OUTEN) + + case GPIO_ALT1: + max326_altfunc(pinmask, AF_FUNC1); + break; + + case GPIO_ALT2: + max326_altfunc(pinmask, AF_FUNC1); + break; + + case GPIO_ALT3: + max326_altfunc(pinmask, AF_FUNC1); + break; + + case GPIO_INPUT: /* Already done */ + case GPIO_INTFE: /* Treat interrupts as inputs for now */ + case GPIO_INTRE: + case GPIO_INTBOTH: + case GPIO_INTLOW: + case GPIO_INTHIGH: + break; + } + +#ifdef CONFIG_MAX326_GPIOIRQ + /* Configure the interrupt */ + + if (GPIO_IS_INTR(cfgset)) + { + max326_gpio_irqconfig(cfgset); + } +#endif + + /* Enable the wakeup event */ + + if ((cfgset & GPIO_WAKEUP) != 0) + { + regval = getreg32(MAX326_GPIO0_WAKEEN); /* Disable wakeup */ + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_WAKEEN) + } + + spin_unlock_restore(flags); + return OK; +} + +/**************************************************************************** + * Name: max326_gpio_write + * + * Description: + * Write one or zero to the selected GPIO pin + * + ****************************************************************************/ + +void max326_gpio_write(max326_pinset_t pinset, bool value) +{ + unsigned int pin; + uint32_t regval; + irqset_t flags; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + + /* Modification of registers must be atomic */ + + flags = spin_lock_irqsave(); + regval = getreg32(MAX326_GPIO0_OUT); /* Set output high */ + if (value) + { + regval |= (1 << pin); + } + else + { + regval &= ~(1 << pin); + } + + putreg32(regval, MAX326_GPIO0_OUT) + spin_unlock_restore(flags); +} + +/**************************************************************************** + * Name: max326_gpio_read + * + * Description: + * Read one or zero from the selected GPIO pin + * + ****************************************************************************/ + +bool max326_gpio_read(max326_pinset_t pinset) +{ + unsigned int pin; + uint32_t regval; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + + regval = getreg32(MAX326_GPIO0_IN); /* Set output high */ + return (regval & (1 << pin)) != 0; +} + +/**************************************************************************** + * Function: max326_gpio_dump + * + * Description: + * Decode and dump all GPIO registers associated with the port and pin + * numbers in the provided pinset. + * + ****************************************************************************/ + +#ifdef CONFIG_DEBUG_GPIO_INFO +int max326_gpio_dump(max326_pinset_t pinset, const char *msg); +{ + unsigned int pin; + uint32_t pinmask; + uint32_t regval; + unsigned int afmode; + unsigned int pullmode; + unsigned int dsmode; + bool edge; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + pinmask = 1 << pin; + + gpioinfo("P0.%u:\n", pin); + +/* MODE AF1 AF0 + * I/O 0 1 + * Alternate Function 1 0 0 + * Alternate Function 2 1 0 + * Alternate Function 3 1 1 + */ + + regval = getre32(MAX326_GPIO0_AF0SEL); + afmode = (regval & pinmask) != 0 ? 1 : 0; + regval = getre32(MAX326_GPIO0_AF1SEL); + afmode |= (regval & pinmask) != 0 ? 2 : 0; + gpioinfo(" Mode: %d\n", g_afmode[afmode]); + + + regval = getre32(MAX326_GPIO0_OUTEN); + gpioinfo(" Output Enable: %s\n", + (regval & pinmask) != 0 ? "Yes" : "No"); + + regval = getre32(MAX326_GPIO0_OUT); + gpioinfo(" Output Value: %s\n", + (regval & pinmask) != 0 ? "High" : "Low"); + + regval = getre32(MAX326_GPIO0_IN); + gpioinfo(" Input Value: %s\n", + (regval & pinmask) != 0 ? "High" : "Low"); + + regval = getre32(MAX326_GPIO0_INTMODE); + edge = (regval & pinmask) != 0 + gpioinfo(" Intr Mode: %s\n", edge ? "Yes" : "No"); + + regval = getre32(MAX326_GPIO0_INTPOL); + if (edge) + { + uint32_t dualedge = getre32(MAX326_GPIO0_INTDUALEDGE); + if ((dualedge & pinmask) != 0) + { + gpioinfo(" Intr Edge: Both edges\n"); + } + else + { + gpioinfo(" Intr Edge: %s\n", + (regval & pinmask) != 0 ? "Rising" : "Falling"); + } + } + else + { + gpioinfo(" Intr Level: %s\n", + (regval & pinmask) != 0 ? "High" : "Low"); + } + + regval = getre32(MAX326_GPIO0_INTEN); + gpioinfo(" Intr Enabled: %s\n", + (regval & pinmask) != 0 ? "Yes" : "No"); + + regval = getre32(MAX326_GPIO0_INTFL); + gpioinfo(" Intr Pending: %s\n", + (regval & pinmask) != 0 ? "Yes" : "No"); + + regval = getre32(MAX326_GPIO0_WAKEEN); + gpioinfo(" Wakeup Enabled: %s\n", + (regval & pinmask) != 0 ? "Yes" : "No"); + + pullmode = 0 + regval = getre32(MAX326_GPIO0_PULLEN); + if ((regval & pinmask) != 0) + { + if ((PULLUP_SET & pinmask) == 0) + { + pullmode = 1: + } + else + { + regval = getre32(MAX326_GPIO0_PULLSEL); + pullmode = (regval & pinmask) != 0 ? 2 : 1; + } + } + + gpioinfo(" Resister Mode: %s\n", g_pullmode[pullmode]); + + dsmode = (PULLUP_SET & pinmask) == 0 ? 1 : 0; + regval = getre32(MAX326_GPIO0_DS0SEL); + if ((regval & pinmask) != 0) + { + if (PULLUP_SET & pinmask) == 0) + { + dsmode = 3: + } + else + { + regval = getre32(MAX326_GPIO0_DS1SEL); + dsmode = (regval & pinmask) != 0 ? 3 : 1; + } + } + else if (PULLUP_SET & pinmask) != 0) + { + regval = getre32(MAX326_GPIO0_DS1SEL); + if (regval & pinmask) != 0) + { + dsmode = 2; + } + } + + gpioinfo(" Drive Strength: %s\n", g_dsmode[dsmode]); + + regval = getre32(MAX326_GPIO0_INHYSEN); + gpioinfo(" Hysteresis: %s\n", + (regval & pinmask) != 0 ? "Yes" : "No"); + + regval = getre32(MAX326_GPIO0_SRSEL); + gpioinfo(" Slew Enabled: %s\n", + (regval & pinmask) != 0 ? "Yes" : "No"); +} +#endif diff --git a/arch/arm/src/max326xx/max32660/max32660_gpio.h b/arch/arm/src/max326xx/max32660/max32660_gpio.h index 378f0e58cb7..6312aeb7f38 100644 --- a/arch/arm/src/max326xx/max32660/max32660_gpio.h +++ b/arch/arm/src/max326xx/max32660/max32660_gpio.h @@ -69,10 +69,9 @@ #define GPIO_FUNC_MASK (15 << GPIO_FUNC_SHIFT) # define GPIO_INPUT (0 << GPIO_FUNC_SHIFT) /* 0000 GPIO input pin */ # define GPIO_OUTPUT (1 << GPIO_FUNC_SHIFT) /* 0001 GPIO output pin */ -# define GPIO_ALT0 (4 << GPIO_FUNC_SHIFT) /* 0100 GPIO Alternate function 0 */ -# define GPIO_ALT1 (5 << GPIO_FUNC_SHIFT) /* 0101 GPIO Alternate function 1 */ -# define GPIO_ALT2 (6 << GPIO_FUNC_SHIFT) /* 0110 GPIO Alternate function 2 */ -# define GPIO_ALT3 (7 << GPIO_FUNC_SHIFT) /* 0111 GPIO Alternate function 3 */ +# define GPIO_ALT1 (5 << GPIO_FUNC_SHIFT) /* 0100 GPIO Alternate function 1 */ +# define GPIO_ALT2 (6 << GPIO_FUNC_SHIFT) /* 0101 GPIO Alternate function 2 */ +# define GPIO_ALT3 (7 << GPIO_FUNC_SHIFT) /* 0110 GPIO Alternate function 3 */ # define GPIO_INTFE (9 << GPIO_FUNC_SHIFT) /* 1001 GPIO interrupt falling edge */ # define GPIO_INTRE (10 << GPIO_FUNC_SHIFT) /* 1010 GPIO interrupt rising edge */ # define GPIO_INTBOTH (11 << GPIO_FUNC_SHIFT) /* 1011 GPIO interrupt both edges */ @@ -94,7 +93,7 @@ #define GPIO_IS_GPIO(ps) (((uint16_t)(ps) & GPIO_GPIO_MASK) == GPIO_GPIO_CODE) #define GPIO_IS_ALT(ps) (((uint16_t)(ps) & GPIO_ALT_MASK) == GPIO_ALT_CODE) -#define GPIO_IS_INTR(ps) (((uint16_t)(ps) & GPIO_ALT_MASK) == GPIO_ALT_CODE) +#define GPIO_IS_INTR(ps) (((uint16_t)(ps) & GPIO_ALT_MASK) == GPIO_INTR_CODE) #define GPIO_IS_INTEDGE(ps) (((uint16_t)(ps) & GPIO_INTEDGE_MASK) == GPIO_INTEDGE_CODE) #define GPIO_IS_INTLVL(ps) (((uint16_t)(ps) & GPIO_INTLVL_MASK) == GPIO_INTLVL_CODE) @@ -180,6 +179,9 @@ # define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) # define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) +# define GPIO_PINMIN 0 +# define GPIO_PINMAX 13 + /************************************************************************************ * Public Types ************************************************************************************/ diff --git a/arch/arm/src/max326xx/max32660/max32660_gpioirq.c b/arch/arm/src/max326xx/max32660/max32660_gpioirq.c new file mode 100644 index 00000000000..87cf444c461 --- /dev/null +++ b/arch/arm/src/max326xx/max32660/max32660_gpioirq.c @@ -0,0 +1,226 @@ +/**************************************************************************** + * arch/arm/src/max32660/max326_gpioirq.c + * + * Copyright (C) 2018 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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 + +#include + +#include + +#include "up_arch.h" + +#include "max326_gpio.h" + +#ifdef CONFIG_MAX326_GPIOIRQ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: max326_gpio_irqinitialize + * + * Description: + * Initialize logic to support interrupting GPIO pins. This function is + * called by the OS initialization logic and is not a user interface. + * + * Assumptions: + * Called early in the boot-up sequence + * + ****************************************************************************/ + +void max326_gpio_irqinitialize(void); +{ + /* Attach the GPIO0 interrupt handler and enable interrupts */ + + DEBUGVERIFY(irq_attach, MAX326_IRQ_GPIO0, NULL); + up_enable_irq(MAX326_IRQ_GPIO0); +} + +/**************************************************************************** + * Name: max326_gpio_irqconfig + * + * Description: + * Configure a pin for interrupt operation. This function should not be + * called directory but, rather, indirectly through max326_gpio_config(). + * + * Assumptions: + * - The pin interrupt has been disabled and all interrupt related bits + * have been set to zero by max436_gpio_config(). + * - We are called in a critical section. + * + ****************************************************************************/ + +void max326_gpio_irqconfig(max326_pinset_t cfgset) +{ + unsigned int pin; + uint32_t pinmask; + uint32_t intmode; + uint32_t intpol; + uint32_t intdual; + uint32_t regval; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + pinmask = 1 << pin; + + intmode = 0; + intpol = 0; + intdual = 0; + + switch (cfgset & GPIO_FUNC_MASK) + { + default: + case GPIO_INPUT: + case GPIO_OUTPUT: + case GPIO_ALT1: + case GPIO_ALT2: + case GPIO_ALT3: + DEBUGPANIC(); + return; + + case GPIO_INTFE: /* Edge triggered, falling edge */ + intmode = pinmask; /* Edge triggered */ + break; + + case GPIO_INTRE: /* Edge triggered, rising edge */ + intmode = pinmask; /* Edge triggered */ + intpol = pinmask; /* Rising edge */ + break; + + case GPIO_INTBOTH: /* Edge triggered, both edges */ + intmode = pinmask; /* Edge triggered */ + intdual = pinmask; /* Both edges */ + break; + + case GPIO_INTLOW: /* Level triggered, low level */ + break; + + case GPIO_INTHIGH: /* Level triggered, high level */ + intpol = pinmask; /* High level */ + break; + } + + /* Configure the interrupt */ + + regval = getreg32(MAX326_GPIO0_INTMODE); + regval &= ~pinmask; + regval |= intmode; + putreg32(regval, MAX326_GPIO0_INTMODE) + + regval = getreg32(MAX326_GPIO0_INTPOL); + regval &= ~pinmask; + regval |= intpol; + putreg32(regval, MAX326_GPIO0_INTPOL) + + regval = getreg32(MAX326_GPIO0_INTDUALEDGE); + regval &= ~pinmask; + regval |= intdual; + putreg32(regval, MAX326_GPIO0_INTDUALEDGE) +} + +/************************************************************************************ + * Name: max326_gpio_irqdisable + * + * Description: + * Disable a GPIO pin interrupt. This function should not be called directly but, + * rather through up_disable_irq(); + * + * Assumptions: + * We are in a critical section. + * + ************************************************************************************/ + +void max326_gpio_irqdisable(int irq) +{ + unsigned int pin; + uint32_t pinmask; + uint32_t regval; + irqset_t flags; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + pinmask = 1 << pin; + + /* Modification of registers must be atomic */ + + flags = spin_lock_irqsave(); + regval = getreg32(MAX326_GPIO0_INTEN); + regval &= ~pinmask; + putreg32(regval, MAX326_GPIO0_INTEN) + spin_unlock_restore(flags); +} + +/************************************************************************************ + * Name: max326_gpio_irqenable + * + * Description: + * Enable a GPIO pin interrupt. This function should not be called directly but, + * rather through up_enable_irq(); + * + * Assumptions: + * We are in a critical section. + * + ************************************************************************************/ + +void max326_gpio_irqenable(int irq) +{ + unsigned int pin; + uint32_t pinmask; + uint32_t regval; + irqset_t flags; + + pin = (cfgset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT; + DEBUGASSERT(pin <= GPIO_PINMAX); + pinmask = 1 << pin; + + /* Modification of registers must be atomic */ + + flags = spin_lock_irqsave(); + regval = getreg32(MAX326_GPIO0_INTEN); + regval |= pinmask; + putreg32(regval, MAX326_GPIO0_INTEN) + spin_unlock_restore(flags); +} + +#endif /* CONFIG_MAX326_GPIOIRQ */ diff --git a/arch/arm/src/max326xx/max326_gpio.h b/arch/arm/src/max326xx/max326_gpio.h index c857842cb40..decaa3df9a6 100644 --- a/arch/arm/src/max326xx/max326_gpio.h +++ b/arch/arm/src/max326xx/max326_gpio.h @@ -86,12 +86,13 @@ extern "C" * Initialize logic to support interrupting GPIO pins. This function is called by * the OS initialization logic and is not a user interface. * + * Assumptions: + * Called early in the boot-up sequence + * ************************************************************************************/ #ifdef CONFIG_MAX326_GPIOIRQ void max326_gpio_irqinitialize(void); -#else -# define max326_gpio_irqinitialize() #endif /************************************************************************************ @@ -100,10 +101,28 @@ void max326_gpio_irqinitialize(void); * Description: * Configure a GPIO pin based on bit-encoded description of the pin. * + * Assumptions: + * - The pin interrupt has been disabled and all interrupt related bits + * have been set to zero by max436_gpio_config(). + * - We are called in a critical section. + * ************************************************************************************/ int max326_gpio_config(max326_pinset_t cfgset); +/************************************************************************************ + * Name: max326_gpio_irqconfig + * + * Description: + * Configure a pin for interrupt operation. This function should not be called + * directory but, rather, indirectly through max326_gpio_config(). + * + ************************************************************************************/ + +#ifdef CONFIG_MAX326_GPIOIRQ +void max326_gpio_irqconfig(max326_pinset_t cfgset); +#endif + /************************************************************************************ * Name: max326_gpio_write * @@ -124,11 +143,44 @@ void max326_gpio_write(max326_pinset_t pinset, bool value); bool max326_gpio_read(max326_pinset_t pinset); +/************************************************************************************ + * Name: max326_gpio_irqdisable + * + * Description: + * Disable a GPIO pin interrupt. This function should not be called directly but, + * rather through up_disable_irq(); + * + * Assumptions: + * We are in a critical section. + * + ************************************************************************************/ + +#ifdef CONFIG_MAX326_GPIOIRQ +void max326_gpio_irqdisable(int irq); +#endif + +/************************************************************************************ + * Name: max326_gpio_irqenable + * + * Description: + * Enable a GPIO pin interrupt. This function should not be called directly but, + * rather through up_enable_irq(); + * + * Assumptions: + * We are in a critical section. + * + ************************************************************************************/ + +#ifdef CONFIG_MAX326_GPIOIRQ +void max326_gpio_irqenable(int irq); +#endif + /************************************************************************************ * Function: max326_gpio_dump * * Description: - * Dump all GPIO registers associated with the base address of the provided pinset. + * Decode and dump all GPIO registers associated with the port and pin + * numbers in the provided pinset. * ************************************************************************************/