diff --git a/arch/mips/src/pic32mz/Kconfig b/arch/mips/src/pic32mz/Kconfig index b32b4b24ae..54a5852af8 100644 --- a/arch/mips/src/pic32mz/Kconfig +++ b/arch/mips/src/pic32mz/Kconfig @@ -248,13 +248,56 @@ config PIC32MZ_CTMU endmenu -config PIC32MZ_GPIOIRQ - bool "GPIO Interrupt" +menuconfig PIC32MZ_GPIOIRQ + bool "GPIO Interrupt Support" default n - depends on EXPERIMENTAL ---help--- Build in support for interrupts based on GPIO inputs from IOPorts +if PIC32MZ_GPIOIRQ + +menuconfig PIC32MZ_GPIOIRQ_PORTA + bool "I/O PORTA Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTB + bool "I/O PORTB Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTC + bool "I/O PORTC Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTD + bool "I/O PORTD Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTE + bool "I/O PORTE Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTF + bool "I/O PORTF Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTG + bool "I/O PORTG Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTH + bool "I/O PORTH Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTJ + bool "I/O PORTJ Interrupt Support" + default n + +menuconfig PIC32MZ_GPIOIRQ_PORTK + bool "I/O PORTK Interrupt Support" + default n + +endif # PIC32MZ_GPIOIRQ + config PIC32MZ_T1_SOSC bool default n diff --git a/arch/mips/src/pic32mz/chip/pic32mz-ioport.h b/arch/mips/src/pic32mz/chip/pic32mz-ioport.h index 905bf9213f..43336e7df2 100644 --- a/arch/mips/src/pic32mz/chip/pic32mz-ioport.h +++ b/arch/mips/src/pic32mz/chip/pic32mz-ioport.h @@ -51,16 +51,16 @@ ********************************************************************************************/ /* IOPort Peripheral Offsets ****************************************************************/ -#define PI32MZ_IOPORTA 0 -#define PI32MZ_IOPORTB 1 -#define PI32MZ_IOPORTC 2 -#define PI32MZ_IOPORTD 3 -#define PI32MZ_IOPORTE 4 -#define PI32MZ_IOPORTF 5 -#define PI32MZ_IOPORTG 6 -#define PI32MZ_IOPORTH 7 -#define PI32MZ_IOPORTJ 8 -#define PI32MZ_IOPORTK 9 +#define PIC32MZ_IOPORTA 0 +#define PIC32MZ_IOPORTB 1 +#define PIC32MZ_IOPORTC 2 +#define PIC32MZ_IOPORTD 3 +#define PIC32MZ_IOPORTE 4 +#define PIC32MZ_IOPORTF 5 +#define PIC32MZ_IOPORTG 6 +#define PIC32MZ_IOPORTH 7 +#define PIC32MZ_IOPORTJ 8 +#define PIC32MZ_IOPORTK 9 #define PIC32MZ_IOPORTn_OFFSET(n) ((n)<<8) # define PIC32MZ_IOPORTA_OFFSET 0x0000 @@ -789,30 +789,37 @@ /* Analog select register */ #define IOPORT_ANSEL(n) (1 << (n)) /* Bits 0-15: Analog select */ +#define IOPORT_ANSEL_ALL 0x0000ffff /* Tri-state register */ #define IOPORT_TRIS(n) (1 << (n)) /* Bits 0-15: 1: Input 0: Output */ +#define IOPORT_TRIS_ALL 0x0000ffff /* Port register */ #define IOPORT_PORT(n) (1 << (n)) /* Bits 0-15: Pin value */ +#define IOPORT_PORT_ALL 0x0000ffff /* Port data latch register */ #define IOPORT_LAT(n) (1 << (n)) /* Bits 0-15: Port latch value */ +#define IOPORT_LAT_ALL 0x0000ffff /* Open drain control register */ #define IOPORT_ODC(n) (1 << (n)) /* Bits 0-15: 1: OD output enabled, 0: Disabled */ +#define IOPORT_ODC_ALL 0x0000ffff /* Change Notice Pull-up register */ #define IOPORT_CNPU(n) (1 << (n)) /* Bits 0:15: 1=Pull-up enabled */ +#define IOPORT_CNPU_ALL 0x0000ffff /* Change Notice Pull-down register */ #define IOPORT_CNPD(n) (1 << (n)) /* Bits 0:15: 1=Pull-down enabled */ +#define IOPORT_CNPD_ALL 0x0000ffff /* Change Notice Control register */ @@ -822,10 +829,12 @@ /* Change Notice Interrupt Enable register */ #define IOPORT_CNEN(n) (1 << (n)) /* Bits 0-15: 1=Interrupt enabled */ +#define IOPORT_CNEN_ALL 0x0000ffff -/* Change Notice Control register */ +/* Change Notice Status register */ -#define IOPORT_CNSTAT(n) (1 << (n) /* Bits 0-15: Change notice control pin n */ +#define IOPORT_CNSTAT(n) (1 << (n)) /* Bits 0-15: Change notice control pin n */ +#define IOPORT_CNSTAT_ALL 0x0000ffff /******************************************************************************************** * Public Types diff --git a/arch/mips/src/pic32mz/pic32mz-config.h b/arch/mips/src/pic32mz/pic32mz-config.h index 0d356b6e79..74ae32ac26 100644 --- a/arch/mips/src/pic32mz/pic32mz-config.h +++ b/arch/mips/src/pic32mz/pic32mz-config.h @@ -48,6 +48,52 @@ /************************************************************************************ * Pre-processor Definitions ************************************************************************************/ +/* GPIO IRQs ************************************************************************/ + +#ifndef PIC32MZ_GPIOIRQ +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTA +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTB +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTC +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTD +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTE +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTF +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTG +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTH +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTJ +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTK +#endif + +#if CHIP_NPORTS < 1 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTA +#endif +#if CHIP_NPORTS < 2 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTB +#endif +#if CHIP_NPORTS < 3 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTC +#endif +#if CHIP_NPORTS < 4 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTD +#endif +#if CHIP_NPORTS < 5 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTE +#endif +#if CHIP_NPORTS < 6 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTF +#endif +#if CHIP_NPORTS < 7 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTG +#endif +#if CHIP_NPORTS < 8 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTH +#endif +#if CHIP_NPORTS < 9 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTJ +#endif +#if CHIP_NPORTS < 10 +# undef CONFIG_PIC32MZ_GPIOIRQ_PORTK +#endif + /* UARTs ****************************************************************************/ /* Don't enable UARTs not supported by the chip. */ diff --git a/arch/mips/src/pic32mz/pic32mz-gpio.c b/arch/mips/src/pic32mz/pic32mz-gpio.c index c4008a9520..8bec677343 100644 --- a/arch/mips/src/pic32mz/pic32mz-gpio.c +++ b/arch/mips/src/pic32mz/pic32mz-gpio.c @@ -61,12 +61,12 @@ /**************************************************************************** * Public Data ****************************************************************************/ +/* This table can be used to map a port number to a IOPORT base address. For + * example, an index of zero would correspond to IOPORTA, one with IOPORTB, + * etc. + */ -/**************************************************************************** - * Private Data - ****************************************************************************/ - -static const uintptr_t g_gpiobase[CHIP_NPORTS] = +const uintptr_t g_gpiobase[CHIP_NPORTS] = { PIC32MZ_IOPORTA_K1BASE #if CHIP_NPORTS > 1 @@ -106,37 +106,37 @@ static const uintptr_t g_gpiobase[CHIP_NPORTS] = * Name: Inline PIN set field extractors ****************************************************************************/ -static inline bool pic32mz_output(uint16_t pinset) +static inline bool pic32mz_output(pinset_t pinset) { return ((pinset & GPIO_OUTPUT) != 0); } -static inline bool pic32mz_opendrain(uint16_t pinset) +static inline bool pic32mz_opendrain(pinset_t pinset) { return ((pinset & GPIO_MODE_MASK) == GPIO_OPENDRAN); } -static inline bool pic32mz_outputhigh(uint16_t pinset) +static inline bool pic32mz_outputhigh(pinset_t pinset) { return ((pinset & GPIO_VALUE_MASK) != 0); } -static inline bool pic32mz_value(uint16_t pinset) +static inline bool pic32mz_value(pinset_t pinset) { return ((pinset & GPIO_VALUE_MASK) != GPIO_VALUE_ZERO); } -static inline unsigned int pic32mz_portno(uint16_t pinset) +static inline unsigned int pic32mz_portno(pinset_t pinset) { return ((pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT); } -static inline unsigned int pic32mz_pinno(uint16_t pinset) +static inline unsigned int pic32mz_pinno(pinset_t pinset) { return ((pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT); } -static inline unsigned int pic32mz_analog(uint16_t pinset) +static inline unsigned int pic32mz_analog(pinset_t pinset) { return ((pinset & GPIO_ANALOG_MASK) != 0); } @@ -157,7 +157,7 @@ static inline unsigned int pic32mz_analog(uint16_t pinset) * ****************************************************************************/ -int pic32mz_configgpio(uint16_t cfgset) +int pic32mz_configgpio(pinset_t cfgset) { unsigned int port = pic32mz_portno(cfgset); unsigned int pin = pic32mz_pinno(cfgset); @@ -242,7 +242,7 @@ int pic32mz_configgpio(uint16_t cfgset) * ****************************************************************************/ -void pic32mz_gpiowrite(uint16_t pinset, bool value) +void pic32mz_gpiowrite(pinset_t pinset, bool value) { unsigned int port = pic32mz_portno(pinset); unsigned int pin = pic32mz_pinno(pinset); @@ -277,7 +277,7 @@ void pic32mz_gpiowrite(uint16_t pinset, bool value) * ****************************************************************************/ -bool pic32mz_gpioread(uint16_t pinset) +bool pic32mz_gpioread(pinset_t pinset) { unsigned int port = pic32mz_portno(pinset); unsigned int pin = pic32mz_pinno(pinset); diff --git a/arch/mips/src/pic32mz/pic32mz-gpio.h b/arch/mips/src/pic32mz/pic32mz-gpio.h index 6162e31d93..b9ef55da4c 100644 --- a/arch/mips/src/pic32mz/pic32mz-gpio.h +++ b/arch/mips/src/pic32mz/pic32mz-gpio.h @@ -42,6 +42,8 @@ #include #include +#include +#include /************************************************************************************ * Pre-processor Definitions @@ -66,15 +68,9 @@ # define GPIO_VALUE_ONE (1 << 12) # define GPIO_VALUE_ZERO (0) -#define GPIO_PULLUP (1 << 11) /* Bit 11: Change notification pull-up */ - -#define GPIO_INT_SHIFT (10) /* Bits 10-11: Interrupt mode */ -#define GPIO_INT_MASK (3 << GPIO_INT_SHIFT) -# define GPIO_INT_NONE (0 << GPIO_INT_SHIFT) /* Bit 00: No interrupt */ -# define GPIO_INT (1 << GPIO_INT_SHIFT) /* Bit 01: Change notification enable */ -# define GPIO_PUINT (3 << GPIO_INT_SHIFT) /* Bit 11: Pulled-up interrupt input */ - -#define GPIO_PULLDOWN (1 << 9) /* Bit 11: Change notification pull-down */ +#define GPIO_INTERRUPT (1 << 11) /* Bit 11: Change notification enable */ +#define GPIO_PULLUP (1 << 10) /* Bit 10: Change notification pull-up */ +#define GPIO_PULLDOWN (1 << 9) /* Bit 9: Change notification pull-down */ #define GPIO_PORT_SHIFT (5) /* Bits 5-8: Port number */ #define GPIO_PORT_MASK (15 << GPIO_PORT_SHIFT) @@ -114,6 +110,8 @@ #ifndef __ASSEMBLY__ +typedef uint16_t pinset_t; + /************************************************************************************ * Public Data ************************************************************************************/ @@ -127,6 +125,13 @@ extern "C" #define EXTERN extern #endif +/* This table can be used to map a port number to a IOPORT base address. For + * example, an index of zero would correspond to IOPORTA, one with IOPORTB, + * etc. + */ + +EXTERN const uintptr_t g_gpiobase[CHIP_NPORTS]; + /************************************************************************************ * Public Function Prototypes ************************************************************************************/ @@ -143,7 +148,7 @@ extern "C" * ************************************************************************************/ -int pic32mz_configgpio(uint16_t cfgset); +int pic32mz_configgpio(pinset_t cfgset); /************************************************************************************ * Name: pic32mz_gpiowrite @@ -207,7 +212,7 @@ void pic32mz_gpioirqinitialize(void); ************************************************************************************/ #ifdef CONFIG_PIC32MZ_GPIOIRQ -xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler); +xcpt_t pic32mz_gpioattach(uint32_t pinset, xcpt_t handler); #else # define pic32mz_gpioattach(p,f) (NULL) #endif @@ -221,7 +226,7 @@ xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler); ************************************************************************************/ #ifdef CONFIG_PIC32MZ_GPIOIRQ -void pic32mz_gpioirqenable(unsigned int cn); +void pic32mz_gpioirqenable(pinset_t pinset); #else # define pic32mz_gpioirqenable(irq) #endif @@ -235,7 +240,7 @@ void pic32mz_gpioirqenable(unsigned int cn); ************************************************************************************/ #ifdef CONFIG_PIC32MZ_GPIOIRQ -void pic32mz_gpioirqdisable(unsigned int cn); +void pic32mz_gpioirqdisable(pinset_t pinset); #else # define pic32mz_gpioirqdisable(irq) #endif diff --git a/arch/mips/src/pic32mz/pic32mz-gpioirq.c b/arch/mips/src/pic32mz/pic32mz-gpioirq.c index be1363f60b..323f13d82c 100644 --- a/arch/mips/src/pic32mz/pic32mz-gpioirq.c +++ b/arch/mips/src/pic32mz/pic32mz-gpioirq.c @@ -45,8 +45,10 @@ #include #include #include +#include #include "up_arch.h" +#include "up_internal.h" #include "chip/pic32mz-ioport.h" #include "pic32mz-gpio.h" @@ -60,15 +62,101 @@ * Private Types ****************************************************************************/ +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static inline unsigned int pic32mz_ioport(pinset_t pinset); +static inline unsigned int pic32mz_pin(pinset_t pinset); +static inline bool pic32mz_input(pinset_t pinset); +static inline bool pic32mz_interrupt(pinset_t pinset); +static inline bool pic32mz_pullup(pinset_t pinset); +static inline bool pic32mz_pulldown(pinset_t pinset); +static int pic32mz_cninterrupt(int irq, FAR void *context); + /**************************************************************************** * Public Data ****************************************************************************/ +struct ioport_level2_s +{ + xcpt_t handler[16]; +}; + /**************************************************************************** * Private Data ****************************************************************************/ -static xcpt_t g_cnisrs[IOPORT_NUMCN]; +/* Arrays of second level interrupt handlers for each pin of each enabled + * I/O port. + */ + +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTA +static struct ioport_level2_s g_ioporta_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTB +static struct ioport_level2_s g_ioportb_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTC +static struct ioport_level2_s g_ioportc_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTD +static struct ioport_level2_s g_ioportd_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTE +static struct ioport_level2_s g_ioporte_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTF +static struct ioport_level2_s g_ioportf_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTG +static struct ioport_level2_s g_ioportg_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTH +static struct ioport_level2_s g_ioporth_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTJ +static struct ioport_level2_s g_ioportj_cnisrs; +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTK +static struct ioport_level2_s g_ioportk_cnisrs; +#endif + +/* Look-up of port to interrupt handler array */ + +static struct ioport_level2_s * const g_level2_handlers[CHIP_NPORTS] = +{ +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTA + [PIC32MZ_IOPORTA] = &g_ioporta_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTB + [PIC32MZ_IOPORTB] = &g_ioportb_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTC + [PIC32MZ_IOPORTC] = &g_ioportc_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTD + [PIC32MZ_IOPORTD] = &g_ioportd_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTE + [PIC32MZ_IOPORTE] = &g_ioporte_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTF + [PIC32MZ_IOPORTF] = &g_ioportf_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTG + [PIC32MZ_IOPORTG] = &g_ioportg_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTH + [PIC32MZ_IOPORTH] = &g_ioporth_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTJ + [PIC32MZ_IOPORTJ] = &g_ioportj_cnisrs, +#endif +#ifdef CONFIG_PIC32MZ_GPIOIRQ_PORTK + [PIC32MZ_IOPORTK] = &g_ioportk_cnisrs, +#endif +}; /**************************************************************************** * Private Functions @@ -78,58 +166,123 @@ static xcpt_t g_cnisrs[IOPORT_NUMCN]; * Name: Inline PIN set field extractors ****************************************************************************/ -static inline bool pic32mz_input(uint16_t pinset) +static inline bool pic32mz_input(pinset_t pinset) { return ((pinset & GPIO_MODE_MASK) != GPIO_INPUT); } -static inline bool pic32mz_interrupt(uint16_t pinset) +static inline bool pic32mz_interrupt(pinset_t pinset) { return ((pinset & GPIO_INTERRUPT) != 0); } -static inline bool pic32mz_pullup(uint16_t pinset) +static inline bool pic32mz_pullup(pinset_t pinset) { - return ((pinset & GPIO_INT_MASK) == GPIO_PUINT); + return ((pinset & GPIO_PULLUP) != 0); +} + +static inline bool pic32mz_pulldown(pinset_t pinset) +{ + return ((pinset & GPIO_PULLDOWN) != 0); +} + +static inline unsigned int pic32mz_ioport(pinset_t pinset) +{ + return ((pinset & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT); +} + +static inline unsigned int pic32mz_pin(pinset_t pinset) +{ + return ((pinset & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT); } /**************************************************************************** * Name: pic32mz_cninterrupt * * Description: - * Change notification interrupt handler. + * Common change notification interrupt handler. * ****************************************************************************/ static int pic32mz_cninterrupt(int irq, FAR void *context) { + struct ioport_level2_s *handlers; + xcpt_t handler; + uintptr_t base; + uint32_t cnstat; + uint32_t cnen; + uint32_t pending; + uint32_t regval; + int ioport; int status; int ret = OK; int i; - /* Call all attached handlers */ + /* Get the IO port index from the IRQ number. This, of course, + * assumes that the irq numbers are consecutive beginning with + * IOPORTA. + */ - for (i = 0; i < IOPORT_NUMCN; i++) + ioport = irq - PIC32MZ_IRQ_PORTA; + DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS); + + /* If we got this interrupt, then there must also be an array + * of second level handlers (and a base address) for the IOPORT. + */ + + handlers = g_level2_handlers[ioport]; + base = g_gpiobase[ioport]; + DEBUGASSERT(handlers && base); + + if (handlers && base) { - /* Is this one attached */ + /* Get the interrupt status associated with this interrupt */ - if (g_cnisrs[i]) + cnstat = getreg32(base + PIC32MZ_IOPORT_CNSTAT_OFFSET); + cnen = getreg32(base + PIC32MZ_IOPORT_CNSTAT_OFFSET); + pending = cnstat & cnen; + + /* Hmmm.. the data sheet implies that the status will pend + * until the corresponding PORTx registers is read? Clear + * pending status. + */ + + regval = getreg32(base + PIC32MZ_IOPORT_PORT_OFFSET); + UNUSED(regval); + + /* Call all attached handlers for each pending interrupt */ + + for (i = 0; i < 16; i++) { - /* Call the attached handler */ + /* Is this interrupt pending */ - status = g_cnisrs[i](irq, context); - - /* Keep track of the status of the last handler that failed */ - - if (status < 0) + if ((pending & (1 << IOPORT_CNSTAT(i))) != 0) { - ret = status; + /* Yes.. Has the user attached a handler? */ + + handler = handlers->handler[i]; + if (handler) + { + /* Yes.. call the attached handler */ + + status = handler(irq, context); + + /* Keep track of the status of the last handler that + * failed. + */ + + if (status < 0) + { + ret = status; + } + } } + } } /* Clear the pending interrupt */ - up_clrpend_irq(PIC32MZ_IRQ_CN); + up_clrpend_irq(irq); return ret; } @@ -149,30 +302,53 @@ static int pic32mz_cninterrupt(int irq, FAR void *context) void pic32mz_gpioirqinitialize(void) { + uintptr_t base; int ret; + int i; - /* Attach the change notice interrupt handler */ + /* Perform initialization for each IO port that has interrupt support + * enabled. We can tell this because there will be an array of second + * level handlers for each enabled IO port. + */ - ret = irqattach(PIC32MZ_IRQ_CN, pic32mz_cninterrupt); - DEBUGASSERT(ret == OK); + for (i = 0; i < CHIP_NPORTS; i++) + { + /* Get the base address of this IO port peripheral */ - /* Set the interrupt priority */ + base = g_gpiobase[i]; + DEBUGASSERT(base); -#ifdef CONFIG_ARCH_IRQPRIO - ret = up_prioritize_irq(PIC32MZ_IRQ_CN, CONFIG_PIC32MZ_CNPRIO); - DEBUGASSERT(ret == OK); -#endif + /* Reset all registers and disable the CN module */ - /* Reset all registers and enable the CN module */ + putreg32(IOPORT_CNEN_ALL, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + putreg32(IOPORT_CNPU_ALL, base + PIC32MZ_IOPORT_CNPUCLR_OFFSET); + putreg32(IOPORT_CNPD_ALL, base + PIC32MZ_IOPORT_CNPDCLR_OFFSET); + putreg32(0, base + PIC32MZ_IOPORT_CNCON_OFFSET); - putreg32(IOPORT_CN_ALL, PIC32MZ_IOPORT_CNENCLR); - putreg32(IOPORT_CN_ALL, PIC32MZ_IOPORT_CNPUECLR); - putreg32(IOPORT_CNCON_ON, PIC32MZ_IOPORT_CNCON); + /* Is interrupt support selected for this IO port? */ - /* And enable the GPIO interrupt */ + if (g_level2_handlers[i] != NULL) + { + /* Yes.. Attach the common change notice interrupt handler + * to the IO port interrupt. Notice that this assumes that + * each IRQ number is consecutive beginning with IOPORTA. + */ - ret = up_enable_irq(PIC32MZ_IRQSRC_CN); - DEBUGASSERT(ret == OK); + ret = irq_attach(PIC32MZ_IRQ_PORTA + i, pic32mz_cninterrupt); + DEBUGASSERT(ret == OK); + UNUSED(ret); + + /* Enable the CN module. NOTE that the CN module is active when + * in sleep mode. + */ + + putreg32(IOPORT_CNCON_ON, base + PIC32MZ_IOPORT_CNCON_OFFSET); + + /* And enable the GPIO interrupt. Same assumption as above. */ + + up_enable_irq(PIC32MZ_IRQ_PORTA + i); + } + } } /**************************************************************************** @@ -187,11 +363,11 @@ void pic32mz_gpioirqinitialize(void) * * When an interrupt occurs, it is due to a change on the GPIO input pin. * In that case, all attached handlers will be called. Each handler must - * maintain state and determine if the unlying GPIO input value changed. + * maintain state and determine if the underlying GPIO input value changed. * * Parameters: * - pinset: GPIO pin configuration - * - cn: The change notification number associated with the pin. + * - pin: The change notification number associated with the pin. * - handler: Interrupt handler (may be NULL to detach) * * Returns: @@ -201,57 +377,99 @@ void pic32mz_gpioirqinitialize(void) * ****************************************************************************/ -xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler) +xcpt_t pic32mz_gpioattach(uint32_t pinset, xcpt_t handler) { + struct ioport_level2_s *handlers; xcpt_t oldhandler = NULL; irqstate_t flags; + uintptr_t base; + int ioport; + int pin; - DEBUGASSERT(cn < IOPORT_NUMCN); + DEBUGASSERT(pin < IOPORT_NUMCN); /* First verify that the pinset is configured as an interrupting input */ if (pic32mz_input(pinset) && pic32mz_interrupt(pinset)) { - /* Get the previously attached handler as the return value */ + /* Get the ioport index and pin number from the pinset */ - flags = irqsave(); - oldhandler = g_cnisrs[cn]; + ioport = pic32mz_ioport(pinset); + pin = pic32mz_pin(pinset); + DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS); - /* Are we attaching or detaching? */ + /* Get the register base address for this port */ - if (handler != NULL) + base = g_gpiobase[ioport]; + DEBUGASSERT(base); + + /* If this IO port has been properly configured for interrupts, then + * there should be an array of second level interrupt handlers + * allocated for it. + */ + + handlers = g_level2_handlers[ioport]; + DEBUGASSERT(handlers); + if (handlers) { - /* Attaching... Make sure that the GPIO is properly configured as - * an input - */ + /* Get the previously attached handler as the return value */ - pic32mz_configgpio(pinset); + flags = irqsave(); + oldhandler = handlers->handler[pin]; - /* Pull-up requested? */ + /* Are we attaching or detaching? */ - if (pic32mz_pullup(pinset)) + if (handler != NULL) { - putreg32(1 << cn, PIC32MZ_IOPORT_CNPUESET); + /* Attaching... Make sure that the GPIO is properly configured + * as an input + */ + + pic32mz_configgpio(pinset); + + /* Pull-up requested? */ + + if (pic32mz_pullup(pinset)) + { + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPUSET_OFFSET); + } + else + { + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPUCLR_OFFSET); + } + + /* Pull-down requested? */ + + if (pic32mz_pulldown(pinset)) + { + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPDSET_OFFSET); + } + else + { + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPDCLR_OFFSET); + } } else { - putreg32(1 << cn, PIC32MZ_IOPORT_CNPUECLR); + /* Disable the pull-up/downs (just so things look better in + * the debugger). + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPUCLR_OFFSET); + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNPDCLR_OFFSET); } + + /* Whether attaching or detaching, the next state of the interrupt + * should be disabled. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + + /* Set the new handler (perhaps NULLifying the current handler) */ + + handlers->handler[pin] = handler; + irqrestore(flags); } - else - { - /* Make sure that any further interrupts are disabled. - * (disable the pull-up as well). - */ - - putreg32(1 << cn, PIC32MZ_IOPORT_CNENCLR); - putreg32(1 << cn, PIC32MZ_IOPORT_CNPUECLR); - } - - /* Set the new handler (perhaps NULLifying the current handler) */ - - g_cnisrs[cn] = handler; - irqrestore(flags); } return oldhandler; @@ -265,10 +483,31 @@ xcpt_t pic32mz_gpioattach(uint32_t pinset, unsigned int cn, xcpt_t handler) * ****************************************************************************/ -void pic32mz_gpioirqenable(unsigned int cn) +void pic32mz_gpioirqenable(pinset_t pinset) { - DEBUGASSERT(cn < IOPORT_NUMCN); - putreg32(1 << cn, PIC32MZ_IOPORT_CNENSET); + uintptr_t base; + int ioport; + int pin; + + /* Get the ioport index and pin number from the pinset */ + + ioport = pic32mz_ioport(pinset); + pin = pic32mz_pin(pinset); + DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS); + + /* Get the register base address for this port */ + + base = g_gpiobase[ioport]; + DEBUGASSERT(base); + if (base) + { + /* And enable the interrupt. NOTE that we don't actually check if + * interrupts are configured for this IO port. If not, this operation + * should do nothing. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENSET_OFFSET); + } } /**************************************************************************** @@ -279,10 +518,31 @@ void pic32mz_gpioirqenable(unsigned int cn) * ****************************************************************************/ -void pic32mz_gpioirqdisable(unsigned int cn) +void pic32mz_gpioirqdisable(pinset_t pinset) { - DEBUGASSERT(cn < IOPORT_NUMCN); - putreg32(1 << cn, PIC32MZ_IOPORT_CNENCLR); + uintptr_t base; + int ioport; + int pin; + + /* Get the ioport index and pin number from the pinset */ + + ioport = pic32mz_ioport(pinset); + pin = pic32mz_pin(pinset); + DEBUGASSERT(ioport >= 0 && ioport < CHIP_NPORTS); + + /* Get the register base address for this port */ + + base = g_gpiobase[ioport]; + DEBUGASSERT(base); + if (base) + { + /* And disable the interrupt. NOTE that we don't actually check if + * interrupts are configured for this IO port. If not, this operation + * should do nothing. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + } } #endif /* CONFIG_PIC32MZ_GPIOIRQ */