diff --git a/arch/mips/src/pic32mz/chip/pic32mz-ioport.h b/arch/mips/src/pic32mz/chip/pic32mz-ioport.h index 43336e7df29..8e590a3c806 100644 --- a/arch/mips/src/pic32mz/chip/pic32mz-ioport.h +++ b/arch/mips/src/pic32mz/chip/pic32mz-ioport.h @@ -1,7 +1,7 @@ /******************************************************************************************** * arch/mips/src/pic32mz/pic32mz-ioport.h * - * Copyright (C) 2015 Gregory Nutt. All rights reserved. + * Copyright (C) 2015, 2019 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -121,10 +121,30 @@ #define PIC32MZ_IOPORT_CNENSET_OFFSET 0x0088 /* Change Notice Interrupt Enable set register */ #define PIC32MZ_IOPORT_CNENINV_OFFSET 0x008c /* Change Notice Interrupt Enable invert register */ -#define PIC32MZ_IOPORT_CNSTAT_OFFSET 0x0080 /* Change Notice Control register */ -#define PIC32MZ_IOPORT_CNSTATCLR_OFFSET 0x0084 /* Change Notice Control clear register*/ -#define PIC32MZ_IOPORT_CNSTATSET_OFFSET 0x0088 /* Change Notice Control set register */ -#define PIC32MZ_IOPORT_CNSTATINV_OFFSET 0x008c /* Change Notice Control invert register */ +#define PIC32MZ_IOPORT_CNSTAT_OFFSET 0x0090 /* Change Notice Status register */ +#define PIC32MZ_IOPORT_CNSTATCLR_OFFSET 0x0094 /* Change Notice Status clear register*/ +#define PIC32MZ_IOPORT_CNSTATSET_OFFSET 0x0098 /* Change Notice Status set register */ +#define PIC32MZ_IOPORT_CNSTATINV_OFFSET 0x009c /* Change Notice Status invert register */ + +#define PIC32MZ_IOPORT_CNNE_OFFSET 0x00a0 /* Change Notice Interrupt Enable register */ +#define PIC32MZ_IOPORT_CNNECLR_OFFSET 0x00a4 /* Change Notice Interrupt Enable clear register */ +#define PIC32MZ_IOPORT_CNNESET_OFFSET 0x00a8 /* Change Notice Interrupt Enable set register */ +#define PIC32MZ_IOPORT_CNNEINV_OFFSET 0x00ac /* Change Notice Interrupt Enable invert register */ + +#define PIC32MZ_IOPORT_CNF_OFFSET 0x00b0 /* Change Notice Status register */ +#define PIC32MZ_IOPORT_CNFCLR_OFFSET 0x00b4 /* Change Notice Status clear register */ +#define PIC32MZ_IOPORT_CNFSET_OFFSET 0x00b8 /* Change Notice Status set register */ +#define PIC32MZ_IOPORT_CNFINV_OFFSET 0x00bc /* Change Notice Status invert register */ + +#define PIC32MZ_IOPORT_SRCON0_OFFSET 0x00c0 /* Slew Rate Control0 register */ +#define PIC32MZ_IOPORT_SRCON0CLR_OFFSET 0x00c4 /* Slew Rate Control0 clear register */ +#define PIC32MZ_IOPORT_SRCON0SET_OFFSET 0x00c8 /* Slew Rate Control0 set register */ +#define PIC32MZ_IOPORT_SRCON0INV_OFFSET 0x00cc /* Slew Rate Control0 invert register */ + +#define PIC32MZ_IOPORT_SRCON1_OFFSET 0x00d0 /* Slew Rate Control1 register */ +#define PIC32MZ_IOPORT_SRCON1CLR_OFFSET 0x00d4 /* Slew Rate Control1 clear register */ +#define PIC32MZ_IOPORT_SRCON1SET_OFFSET 0x00d8 /* Slew Rate Control1 set register */ +#define PIC32MZ_IOPORT_SRCON1INV_OFFSET 0x00dc /* Slew Rate Control1 invert register */ /* IOPort Peripheral Addresses **************************************************************/ @@ -823,7 +843,8 @@ /* Change Notice Control register */ -#define IOPORT_CNCON_SIDL (1 << 13) /* Bit 13: Stop in idle mode */ +#define IOPORT_CNCON_EDGEDETECT (1 << 11) /* Bit 11: Change Notification Style bit */ +#define IOPORT_CNCON_SIDL (1 << 13) /* Bit 13: Stop in Idle Control bit */ #define IOPORT_CNCON_ON (1 << 15) /* Bit 15: Change notice module enable */ /* Change Notice Interrupt Enable register */ @@ -836,6 +857,26 @@ #define IOPORT_CNSTAT(n) (1 << (n)) /* Bits 0-15: Change notice control pin n */ #define IOPORT_CNSTAT_ALL 0x0000ffff +/* Change Notice Interrupt Enable register (Negative edge) */ + +#define IOPORT_CNNE(n) (1 << (n)) /* Bits 0-15: 1=Interrupt enabled */ +#define IOPORT_CNNE_ALL 0x0000ffff + +/* Change Notice Status register */ + +#define IOPORT_CNF(n) (1 << (n)) /* Bits 0-15: Change notice control pin n */ +#define IOPORT_CNF_ALL 0x0000ffff + +/* Slew Rate Control0 register */ + +#define IOPORT_SRCON0(n) (1 << (n)) /* Bits 0-15: Slew Rate control pin n */ +#define IOPORT_SRCON0_ALL 0x0000ffff + +/* Slew Rate Control1 register */ + +#define IOPORT_SRCON1(n) (1 << (n)) /* Bits 0-15: Slew Rate control pin n */ +#define IOPORT_SRCON1_ALL 0x0000ffff + /******************************************************************************************** * Public Types ********************************************************************************************/ diff --git a/arch/mips/src/pic32mz/pic32mz-config.h b/arch/mips/src/pic32mz/pic32mz-config.h index 60944d0642d..71601c59580 100644 --- a/arch/mips/src/pic32mz/pic32mz-config.h +++ b/arch/mips/src/pic32mz/pic32mz-config.h @@ -507,7 +507,7 @@ #undef CONFIG_PIC32MZ_FWDTEN #ifdef CONFIG_PIC32MZ_WDTENABLE -# define CONFIG_PIC32MZ_FWDTEN DEVCFG1_FWDT_ENSABLED +# define CONFIG_PIC32MZ_FWDTEN DEVCFG1_FWDT_ENABLED #else # define CONFIG_PIC32MZ_FWDTEN DEVCFG1_FWDT_DISABLED #endif diff --git a/arch/mips/src/pic32mz/pic32mz-gpio.c b/arch/mips/src/pic32mz/pic32mz-gpio.c index 0ec2c44fecd..466754fde23 100644 --- a/arch/mips/src/pic32mz/pic32mz-gpio.c +++ b/arch/mips/src/pic32mz/pic32mz-gpio.c @@ -113,7 +113,7 @@ static inline bool pic32mz_output(pinset_t pinset) static inline bool pic32mz_opendrain(pinset_t pinset) { - return ((pinset & GPIO_MODE_MASK) == GPIO_OPENDRAN); + return ((pinset & GPIO_MODE_MASK) == GPIO_OPENDRAIN); } static inline bool pic32mz_outputhigh(pinset_t pinset) @@ -141,6 +141,21 @@ static inline unsigned int pic32mz_analog(pinset_t pinset) return ((pinset & GPIO_ANALOG_MASK) != 0); } +static inline unsigned int pic32mz_slewrate(pinset_t pinset) +{ + return ((pinset & GPIO_SR_MASK) >> GPIO_SR_SHIFT); +} + +static inline unsigned int pic32mz_slewratecon0(pinset_t pinset) +{ + return (pic32mz_slewrate(pinset) & GPIO_SR_CON0_MASK) >> GPIO_SR_CON0_SHIFT; +} + +static inline unsigned int pic32mz_slewratecon1(pinset_t pinset) +{ + return (pic32mz_slewrate(pinset) & GPIO_SR_CON1_MASK) >> GPIO_SR_CON1_SHIFT; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -172,9 +187,24 @@ int pic32mz_configgpio(pinset_t cfgset) base = g_gpiobase[port]; + sched_lock(); + + /* Is Slew Rate control enabled? */ + + if (pic32mz_slewrate(cfgset) != GPIO_FASTEST) + { + /* Note: not every port nor every pin has the Slew Rate feature. + * Writing to an unimplemented port/pin will have no effect. + */ + + putreg32(pic32mz_slewratecon0(cfgset), + base + PIC32MZ_IOPORT_SRCON0_OFFSET); + putreg32(pic32mz_slewratecon1(cfgset), + base + PIC32MZ_IOPORT_SRCON1_OFFSET); + } + /* Is this an input or an output? */ - sched_lock(); if (pic32mz_output(cfgset)) { /* Not analog */ @@ -308,7 +338,7 @@ bool pic32mz_gpioread(pinset_t pinset) ****************************************************************************/ #ifdef CONFIG_DEBUG_GPIO_INFO -void pic32mz_dumpgpio(uint32_t pinset, const char *msg) +void pic32mz_dumpgpio(pinset_t pinset, const char *msg) { unsigned int port = pic32mz_portno(pinset); irqstate_t flags; diff --git a/arch/mips/src/pic32mz/pic32mz-gpio.h b/arch/mips/src/pic32mz/pic32mz-gpio.h index 17e6e6add61..cc05afc7147 100644 --- a/arch/mips/src/pic32mz/pic32mz-gpio.h +++ b/arch/mips/src/pic32mz/pic32mz-gpio.h @@ -51,58 +51,119 @@ /* GPIO settings used in the configport, readport, writeport, etc. * * General encoding: - * MMAV IIDR RRRx PPPP + * xxxx xxxx xxxx xSSM MAVI IIII RRRR PPPP + * + * x = Not implemented + * S = Slew Rate + * M = Mode (input/output) + * I = Interrupt + * R = Register + * P = Pin */ -#define GPIO_MODE_SHIFT (14) /* Bits 14-15: I/O mode */ -#define GPIO_MODE_MASK (3 << GPIO_MODE_SHIFT) -# define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* 00 Normal input */ -# define GPIO_OUTPUT (2 << GPIO_MODE_SHIFT) /* 10 Normal output */ -# define GPIO_OPENDRAN (3 << GPIO_MODE_SHIFT) /* 11 Open drain output */ +/* Slew Rate Control. + * + * .... .... .... .SS. .... .... .... .... + */ -#define GPIO_ANALOG_MASK (1 << 13) /* Bit 13: Analog */ -# define GPIO_ANALOG (1 << 13) -# define GPIO_DIGITAL (0) +#define GPIO_SR_SHIFT (17) /* Bits 17-18: Slew Rate Control */ +#define GPIO_SR_MASK (3 << GPIO_SR_SHIFT) +# define GPIO_FASTEST (0 << GPIO_SR_SHIFT) /* 00: Disabled and set to fastest */ +# define GPIO_MEDIUM (1 << GPIO_SR_SHIFT) /* 01: Enabled and set to medium */ +# define GPIO_SLOW (2 << GPIO_SR_SHIFT) /* 10: Enabled and set to slow */ +# define GPIO_SLOWEST (3 << GPIO_SR_SHIFT) /* 11: Enabled and set to slowest */ +#define GPIO_SR_CON0_SHIFT (0) /* Bit 0: SRCON0x */ +#define GPIO_SR_CON0_MASK (1 << GPIO_SR_CON0_SHIFT) +#define GPIO_SR_CON1_SHIFT (1) /* Bit 1: SRCON1x */ +#define GPIO_SR_CON1_MASK (1 << GPIO_SR_CON1_SHIFT) -#define GPIO_VALUE_MASK (1 << 12) /* Bit 12: Initial output value */ -# define GPIO_VALUE_ONE (1 << 12) -# define GPIO_VALUE_ZERO (0) +/* Input/Output mode: + * + * .... .... .... ...M M... .... .... .... + */ -#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_MODE_SHIFT (15) /* Bits 15-16: I/O mode */ +#define GPIO_MODE_MASK (3 << GPIO_MODE_SHIFT) +# define GPIO_INPUT (0 << GPIO_MODE_SHIFT) /* 00 Normal input */ +# define GPIO_OUTPUT (2 << GPIO_MODE_SHIFT) /* 10 Normal output */ +# define GPIO_OPENDRAIN (3 << GPIO_MODE_SHIFT) /* 11 Open drain output */ -#define GPIO_PORT_SHIFT (5) /* Bits 5-8: Port number */ -#define GPIO_PORT_MASK (15 << GPIO_PORT_SHIFT) -# define GPIO_PORTA (0 << GPIO_PORT_SHIFT) -# define GPIO_PORTB (1 << GPIO_PORT_SHIFT) -# define GPIO_PORTC (2 << GPIO_PORT_SHIFT) -# define GPIO_PORTD (3 << GPIO_PORT_SHIFT) -# define GPIO_PORTE (4 << GPIO_PORT_SHIFT) -# define GPIO_PORTF (5 << GPIO_PORT_SHIFT) -# define GPIO_PORTG (6 << GPIO_PORT_SHIFT) -# define GPIO_PORTH (7 << GPIO_PORT_SHIFT) -# define GPIO_PORTJ (8 << GPIO_PORT_SHIFT) -# define GPIO_PORTK (9 << GPIO_PORT_SHIFT) +/* Analog mode. + * + * .... .... .... .... .A.. .... .... .... + */ -#define GPIO_PIN_SHIFT 0 /* Bits 0-3: GPIO number: 0-15 */ -#define GPIO_PIN_MASK (15 << GPIO_PIN_SHIFT) -#define GPIO_PIN0 (0 << GPIO_PIN_SHIFT) -#define GPIO_PIN1 (1 << GPIO_PIN_SHIFT) -#define GPIO_PIN2 (2 << GPIO_PIN_SHIFT) -#define GPIO_PIN3 (3 << GPIO_PIN_SHIFT) -#define GPIO_PIN4 (4 << GPIO_PIN_SHIFT) -#define GPIO_PIN5 (5 << GPIO_PIN_SHIFT) -#define GPIO_PIN6 (6 << GPIO_PIN_SHIFT) -#define GPIO_PIN7 (7 << GPIO_PIN_SHIFT) -#define GPIO_PIN8 (8 << GPIO_PIN_SHIFT) -#define GPIO_PIN9 (9 << GPIO_PIN_SHIFT) -#define GPIO_PIN10 (10 << GPIO_PIN_SHIFT) -#define GPIO_PIN11 (11 << GPIO_PIN_SHIFT) -#define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) -#define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) -#define GPIO_PIN14 (14 << GPIO_PIN_SHIFT) -#define GPIO_PIN15 (15 << GPIO_PIN_SHIFT) +#define GPIO_ANALOG_SHIFT (14) /* Bit 14: Analog */ +#define GPIO_ANALOG_MASK (1 << GPIO_ANALOG_SHIFT) +# define GPIO_ANALOG (1 << GPIO_ANALOG_SHIFT) +# define GPIO_DIGITAL (0) + +/* Pin Value. + * + * .... .... .... .... ..V. .... .... .... + */ + +#define GPIO_VALUE_SHIFT (13) /* Bit 13: Initializetial output value */ +#define GPIO_VALUE_MASK (1 << GPIO_VALUE_SHIFT) +# define GPIO_VALUE_ONE (1 << GPIO_VALUE_SHIFT) +# define GPIO_VALUE_ZERO (0) + +/* Change Notification config. + * + * .... .... .... .... ...I IIII .... .... + */ + +#define GPIO_CN_SHIFT (8) /* Bit 8 - 12: Change notification bits */ +#define GPIO_CN_MASK (31 << GPIO_CN_SHIFT) +# define GPIO_INTERRUPT (1 << GPIO_CN_SHIFT) /* Bit 8: Change notification enable bit */ +# define GPIO_PULLUP (2 << GPIO_CN_SHIFT) /* Bit 9: Change notification pull-up */ +# define GPIO_PULLDOWN (4 << GPIO_CN_SHIFT) /* Bit 10: Change notification pull-down */ +# define GPIO_EDGE_DETECT (8 << GPIO_CN_SHIFT) /* Bit 11: Change notification interrupt mode */ +# define GPIO_MISMATCH (0) +# define GPIO_EDGE_RISING (12 << GPIO_CN_SHIFT) /* Bit 12: Change notification edge type */ +# define GPIO_EDGE_FALLING (0) + +/* GPIO Port. + * + * .... .... .... .... .... .... RRRR .... + */ + +#define GPIO_PORT_SHIFT (4) /* Bits 4-7: Port number */ +#define GPIO_PORT_MASK (15 << GPIO_PORT_SHIFT) +# define GPIO_PORTA (0 << GPIO_PORT_SHIFT) +# define GPIO_PORTB (1 << GPIO_PORT_SHIFT) +# define GPIO_PORTC (2 << GPIO_PORT_SHIFT) +# define GPIO_PORTD (3 << GPIO_PORT_SHIFT) +# define GPIO_PORTE (4 << GPIO_PORT_SHIFT) +# define GPIO_PORTF (5 << GPIO_PORT_SHIFT) +# define GPIO_PORTG (6 << GPIO_PORT_SHIFT) +# define GPIO_PORTH (7 << GPIO_PORT_SHIFT) +# define GPIO_PORTJ (8 << GPIO_PORT_SHIFT) +# define GPIO_PORTK (9 << GPIO_PORT_SHIFT) + +/* GPIO Pin. + * + * .... .... .... .... .... .... .... PPPP + */ + +#define GPIO_PIN_SHIFT 0 /* Bits 0-3: GPIO number: 0-15 */ +#define GPIO_PIN_MASK (15 << GPIO_PIN_SHIFT) +#define GPIO_PIN0 (0 << GPIO_PIN_SHIFT) +#define GPIO_PIN1 (1 << GPIO_PIN_SHIFT) +#define GPIO_PIN2 (2 << GPIO_PIN_SHIFT) +#define GPIO_PIN3 (3 << GPIO_PIN_SHIFT) +#define GPIO_PIN4 (4 << GPIO_PIN_SHIFT) +#define GPIO_PIN5 (5 << GPIO_PIN_SHIFT) +#define GPIO_PIN6 (6 << GPIO_PIN_SHIFT) +#define GPIO_PIN7 (7 << GPIO_PIN_SHIFT) +#define GPIO_PIN8 (8 << GPIO_PIN_SHIFT) +#define GPIO_PIN9 (9 << GPIO_PIN_SHIFT) +#define GPIO_PIN10 (10 << GPIO_PIN_SHIFT) +#define GPIO_PIN11 (11 << GPIO_PIN_SHIFT) +#define GPIO_PIN12 (12 << GPIO_PIN_SHIFT) +#define GPIO_PIN13 (13 << GPIO_PIN_SHIFT) +#define GPIO_PIN14 (14 << GPIO_PIN_SHIFT) +#define GPIO_PIN15 (15 << GPIO_PIN_SHIFT) /************************************************************************************ * Public Types @@ -110,7 +171,7 @@ #ifndef __ASSEMBLY__ -typedef uint16_t pinset_t; +typedef uint32_t pinset_t; /************************************************************************************ * Public Data @@ -210,7 +271,7 @@ void pic32mz_gpioirqinitialize(void); ****************************************************************************/ #ifdef CONFIG_PIC32MZ_GPIOIRQ -int pic32mz_gpioattach(uint32_t pinset, xcpt_t handler, void *arg); +int pic32mz_gpioattach(pinset_t pinset, xcpt_t handler, void *arg); #else # define pic32mz_gpioattach(p,h,a) (0) #endif @@ -252,7 +313,7 @@ void pic32mz_gpioirqdisable(pinset_t pinset); ************************************************************************************/ #ifdef CONFIG_DEBUG_GPIO_INFO -void pic32mz_dumpgpio(uint32_t pinset, const char *msg); +void pic32mz_dumpgpio(pinset_t pinset, const char *msg); #else # define pic32mz_dumpgpio(p,m) #endif diff --git a/arch/mips/src/pic32mz/pic32mz-gpioirq.c b/arch/mips/src/pic32mz/pic32mz-gpioirq.c index ed6d3cdf459..44911fd40b7 100644 --- a/arch/mips/src/pic32mz/pic32mz-gpioirq.c +++ b/arch/mips/src/pic32mz/pic32mz-gpioirq.c @@ -70,6 +70,8 @@ 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_edgedetect(pinset_t pinset); +static inline unsigned int pic32mz_edgemode(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, FAR void *arg); @@ -174,7 +176,7 @@ static struct ioport_level2_s * const g_level2_handlers[CHIP_NPORTS] = static inline bool pic32mz_input(pinset_t pinset) { - return ((pinset & GPIO_MODE_MASK) != GPIO_INPUT); + return (((pinset & GPIO_MODE_MASK) >> GPIO_MODE_SHIFT) == GPIO_INPUT); } static inline bool pic32mz_interrupt(pinset_t pinset) @@ -182,6 +184,16 @@ static inline bool pic32mz_interrupt(pinset_t pinset) return ((pinset & GPIO_INTERRUPT) != 0); } +static inline bool pic32mz_edgedetect(pinset_t pinset) +{ + return ((pinset & GPIO_EDGE_DETECT) != 0); +} + +static inline unsigned int pic32mz_edgemode(pinset_t pinset) +{ + return ((pinset & GPIO_EDGE_RISING)); +} + static inline bool pic32mz_pullup(pinset_t pinset) { return ((pinset & GPIO_PULLUP) != 0); @@ -215,8 +227,11 @@ static int pic32mz_cninterrupt(int irq, FAR void *context, FAR void *arg) struct ioport_level2_s *handlers; xcpt_t handler; uintptr_t base; - uint32_t cnstat; + uint32_t cncon; uint32_t cnen; + uint32_t cnne; + uint32_t cnstat; + uint32_t cnf; uint32_t pending; uint32_t regval; int ioport; @@ -240,50 +255,105 @@ static int pic32mz_cninterrupt(int irq, FAR void *context, FAR void *arg) base = g_gpiobase[ioport]; DEBUGASSERT(handlers && base); + /* Get the control registers. It will be used to get the interrupt type. */ + + cncon = getreg32(base + PIC32MZ_IOPORT_CNCON_OFFSET); + if (handlers && base) { - /* Get the interrupt status associated with this interrupt */ + /* Mismatch mode selected? */ - 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++) + if ((cncon & IOPORT_CNCON_EDGEDETECT) == 0) { - /* Is this interrupt pending */ + /* Get the interrupt status associated with this interrupt */ - if ((pending & (1 << IOPORT_CNSTAT(i))) != 0) + cnstat = getreg32(base + PIC32MZ_IOPORT_CNSTAT_OFFSET); + cnen = getreg32(base + PIC32MZ_IOPORT_CNEN_OFFSET); + pending = cnstat & cnen; + + /* Call all attached handlers for each pending interrupt */ + + for (i = 0; i < 16; i++) { - /* Yes.. Has the user attached a handler? */ + /* Is this interrupt pending */ - handler = handlers->handler[i].entry; - if (handler) + if ((pending & (IOPORT_CNSTAT(i))) != 0) { - /* Yes.. call the attached handler */ + /* Yes.. Has the user attached a handler? */ - status = handler(irq, context, handlers->handler[i].arg); - - /* Keep track of the status of the last handler that - * failed. - */ - - if (status < 0) + handler = handlers->handler[i].entry; + if (handler) { - ret = status; + /* Yes.. call the attached handler */ + + status = handler(irq, context, handlers->handler[i].arg); + + /* Keep track of the status of the last handler that + * failed. + */ + + if (status < 0) + { + ret = status; + } } } } + + /* Clear pending status. */ + + regval = getreg32(base + PIC32MZ_IOPORT_PORT_OFFSET); + UNUSED(regval); } + + /* Edge detect mode selected. */ + + else + { + /* Get the interrupt status associated with this interrupt. + * The interrupt is controlled by either CNEN (positive edge) + * or CNNE (negative edge). + */ + + cnen = getreg32(base + PIC32MZ_IOPORT_CNEN_OFFSET); + cnne = getreg32(base + PIC32MZ_IOPORT_CNNE_OFFSET); + cnf = getreg32(base + PIC32MZ_IOPORT_CNF_OFFSET); + pending = cnf & (cnen | cnne); + + /* Call all attached handlers for each pending interrupt */ + + for (i = 0; i < 16; i++) + { + /* Is this interrupt pending */ + + if ((pending & (IOPORT_CNF(i))) != 0) + { + /* Yes.. Has the user attached a handler? */ + + handler = handlers->handler[i].entry; + if (handler) + { + /* Yes.. call the attached handler */ + + status = handler(irq, context, handlers->handler[i].arg); + + /* Keep track of the status of the last handler that + * failed. + */ + + if (status < 0) + { + ret = status; + } + } + } + } + + /* Clear pending status. */ + + putreg32(pending, base + PIC32MZ_IOPORT_CNFCLR_OFFSET); + } + } /* Clear the pending interrupt */ @@ -309,6 +379,7 @@ static int pic32mz_cninterrupt(int irq, FAR void *context, FAR void *arg) void pic32mz_gpioirqinitialize(void) { uintptr_t base; + uint32_t regval; int ret; int i; @@ -327,6 +398,7 @@ void pic32mz_gpioirqinitialize(void) /* Reset all registers and disable the CN module */ putreg32(IOPORT_CNEN_ALL, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + putreg32(IOPORT_CNNE_ALL, base + PIC32MZ_IOPORT_CNNECLR_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); @@ -350,9 +422,14 @@ void pic32mz_gpioirqinitialize(void) putreg32(IOPORT_CNCON_ON, base + PIC32MZ_IOPORT_CNCON_OFFSET); - /* And enable the GPIO interrupt. Same assumption as above. */ + /* Read the port to clear the interrupt. */ - up_enable_irq(PIC32MZ_IRQ_PORTA + i); + regval = getreg32(base + PIC32MZ_IOPORT_PORT_OFFSET); + UNUSED(regval); + + /* Clear the CN interrupt flag. Same assumption as above. */ + + up_clrpend_irq(PIC32MZ_IRQ_PORTA + i); } } } @@ -382,8 +459,7 @@ void pic32mz_gpioirqinitialize(void) * ****************************************************************************/ -#ifdef CONFIG_PIC32MZ_GPIOIRQ -int pic32mz_gpioattach(uint32_t pinset, xcpt_t handler, void *arg) +int pic32mz_gpioattach(pinset_t pinset, xcpt_t handler, void *arg) { struct ioport_level2_s *handlers; irqstate_t flags; @@ -391,8 +467,6 @@ int pic32mz_gpioattach(uint32_t pinset, xcpt_t handler, void *arg) int ioport; int pin; - DEBUGASSERT(pin < IOPORT_NUMCN); - /* First verify that the pinset is configured as an interrupting input */ if (pic32mz_input(pinset) && pic32mz_interrupt(pinset)) @@ -468,6 +542,7 @@ int pic32mz_gpioattach(uint32_t pinset, xcpt_t handler, void *arg) */ putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNNECLR_OFFSET); /* Set the new handler (perhaps NULLifying the current handler) */ @@ -506,12 +581,43 @@ void pic32mz_gpioirqenable(pinset_t pinset) DEBUGASSERT(base); if (base) { - /* And enable the interrupt. NOTE that we don't actually check if + /* Enable the correct CN 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); + if (!pic32mz_edgedetect(pinset)) + { + /* If Edge detect is not selected, then CNEN + * controls the interrupt. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENSET_OFFSET); + } + else + { + /* Enable edge detect. */ + + putreg32(IOPORT_CNCON_EDGEDETECT, base + PIC32MZ_IOPORT_CNCONSET_OFFSET); + + if (pic32mz_edgemode(pinset) == GPIO_EDGE_RISING) + { + /* Rising edge selected. CNEN controls the interrupt. */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENSET_OFFSET); + } + else + { + /* Falling edge selected. CNNE controls the interrupt. */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNNESET_OFFSET); + } + } + + /* And enable the interrupt. */ + + up_enable_irq(ioport + PIC32MZ_IRQ_PORTA); } } @@ -541,12 +647,39 @@ void pic32mz_gpioirqdisable(pinset_t pinset) DEBUGASSERT(base); if (base) { - /* And disable the interrupt. NOTE that we don't actually check if + /* And disable the correct 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); + if (!pic32mz_edgedetect(pinset)) + { + /* If Edge detect is not selected, then CNEN + * controls the interrupt. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + } + else + { + if (pic32mz_edgemode(pinset) == GPIO_EDGE_RISING) + { + /* Rising edge selected. + * CNEN controls the interrupt. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNENCLR_OFFSET); + } + else + { + /* Falling edge selected. + * CNNE controls the interrupt. + */ + + putreg32(1 << pin, base + PIC32MZ_IOPORT_CNNECLR_OFFSET); + } + } } }