| /**************************************************************************** |
| * arch/arm/src/lpc43xx/lpc43_gpioint.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /* GPIO pin interrupts |
| * |
| * From all available GPIO pins, up to eight pins can be selected in the |
| * system control block to serve as external interrupt pins. The external |
| * interrupt pins are connected to eight individual interrupts in the NVIC |
| * and are created based on rising or falling edges or on the input level |
| * on the pin. |
| * |
| * GPIO group interrupt |
| * |
| * For each port/pin connected to one of the two the GPIO Grouped Interrupt |
| * blocks (GROUP0 and GROUP1), the GPIO grouped interrupt registers |
| * determine which pins are enabled to generate interrupts and what the |
| * active polarities of each of those inputs are. The GPIO grouped |
| * interrupt registers also select whether the interrupt output will be |
| * level or edge triggered and whether it will be based on the OR or the |
| * AND of all of the enabled inputs. |
| */ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <arch/board/board.h> |
| #include <nuttx/config.h> |
| |
| #include <assert.h> |
| #include <debug.h> |
| #include <errno.h> |
| |
| #include <nuttx/irq.h> |
| #include <nuttx/arch.h> |
| |
| #include "arm_internal.h" |
| #include "chip.h" |
| #include "hardware/lpc43_scu.h" |
| #include "hardware/lpc43_gpio.h" |
| #include "lpc43_gpio.h" |
| #include "lpc43_gpioint.h" |
| |
| #ifdef CONFIG_LPC43_GPIO_IRQ |
| |
| /**************************************************************************** |
| * Pre-processor Definitions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Data |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Private Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: lpc43_gpioint_grpinitialize |
| * |
| * Description: |
| * Initialize the properties of a GPIO group. The properties of the group |
| * should be configured before any pins are added to the group by |
| * lpc32_gpioint_grpconfig(). As side effects, this call also removes |
| * all pins from the group and disables the group interrupt. On return, |
| * this is a properly configured, empty GPIO interrupt group. |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| * Assumptions: |
| * Interrupts are disabled so that read-modify-write operations are safe. |
| * |
| ****************************************************************************/ |
| |
| int lpc43_gpioint_grpinitialize(int group, bool anded, bool level) |
| { |
| irqstate_t flags; |
| uintptr_t grpbase; |
| uint32_t regval; |
| int i; |
| |
| DEBUGASSERT(group >= 0 && group < NUM_GPIO_NGROUPS); |
| |
| /* Select the group register base address and disable the group interrupt */ |
| |
| flags = enter_critical_section(); |
| if (group == 0) |
| { |
| grpbase = LPC43_GRP0INT_BASE; |
| up_disable_irq(LPC43M4_IRQ_GINT0); |
| } |
| else |
| { |
| grpbase = LPC43_GRP1INT_BASE; |
| up_disable_irq(LPC43M4_IRQ_GINT1); |
| } |
| |
| /* Clear all group polarity and membership settings */ |
| |
| for (i = 0; i < NUM_GPIO_PORTS; i++) |
| { |
| putreg32(0, grpbase + LPC43_GRPINT_POL_OFFSET(i)); |
| putreg32(0, grpbase + LPC43_GRPINT_ENA_OFFSET(i)); |
| } |
| |
| /* Configure the group. Note that writing "1" to the status bit will also |
| * clear any pending group interrupts. |
| */ |
| |
| regval = GRPINT_CTRL_INT; |
| if (anded) |
| { |
| regval |= GRPINT_CTRL_COMB; |
| } |
| |
| if (level) |
| { |
| regval |= GRPINT_CTRL_TRIG; |
| } |
| |
| putreg32(regval, grpbase + LPC43_GRPINT_CTRL_OFFSET); |
| |
| leave_critical_section(flags); |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: lpc43_gpioint_pinconfig |
| * |
| * Description: |
| * Configure a GPIO pin as an GPIO pin interrupt source (after it has been |
| * configured as an input). |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| * Assumptions: |
| * Interrupts are disabled so that read-modify-write operations are safe. |
| * |
| ****************************************************************************/ |
| |
| int lpc43_gpioint_pinconfig(uint16_t gpiocfg) |
| { |
| unsigned int port = ((gpiocfg & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT); |
| unsigned int pin = ((gpiocfg & GPIO_PIN_MASK) >> GPIO_PIN_SHIFT); |
| unsigned int pinint = ((gpiocfg & GPIO_PININT_MASK) >> GPIO_PININT_SHIFT); |
| uint32_t bitmask = (1 << pinint); |
| uint32_t pinsel; |
| uint32_t isel; |
| uint32_t einr; |
| uint32_t einf; |
| |
| DEBUGASSERT(port < NUM_GPIO_PORTS && |
| pin < NUM_GPIO_PINS && GPIO_IS_PININT(gpiocfg)); |
| |
| /* Make sure that pin interrupts are initially disabled at the NVIC. |
| * After the pin is configured, the caller will need to manually enable |
| * the pin interrupt. |
| */ |
| |
| up_disable_irq(LPC43M4_IRQ_PININT0 + pinint); |
| |
| /* Select the pin as the input in the SCU PINTSELn register |
| * (overwriting any previous selection). |
| */ |
| |
| if (pinint < 4) |
| { |
| pinsel = getreg32(LPC43_SCU_PINTSEL0); |
| pinsel &= ~SCU_PINTSEL0_MASK(pinint); |
| pinsel |= ((pin << SCU_PINTSEL0_INTPIN_SHIFT(pinint)) | |
| (port << SCU_PINTSEL0_PORTSEL_SHIFT(pinint))); |
| putreg32(pinsel, LPC43_SCU_PINTSEL0); |
| } |
| else |
| { |
| pinsel = getreg32(LPC43_SCU_PINTSEL1); |
| pinsel &= ~SCU_PINTSEL1_MASK(pinint); |
| pinsel |= ((pin << SCU_PINTSEL1_INTPIN_SHIFT(pinint)) | |
| (port << SCU_PINTSEL1_PORTSEL_SHIFT(pinint))); |
| putreg32(pinsel, LPC43_SCU_PINTSEL1); |
| } |
| |
| /* Configure the active level or rising/falling edge |
| * |
| * ISEL |
| * 0 = Edge sensitive |
| * 1 = Level sensitive |
| * EINR 0-7: |
| * 0 = Disable rising edge or level interrupt. |
| * 1 = Enable rising edge or level interrupt. |
| * EINF 0-7: |
| * 0 = Disable falling edge interrupt or set active interrupt level |
| * LOW. |
| * 1 = Enable falling edge interrupt enabled or set active interrupt |
| * level HIGH |
| */ |
| |
| isel = getreg32(LPC43_GPIOINT_ISEL) & ~bitmask; |
| einr = getreg32(LPC43_GPIOINT_IENR) & ~bitmask; |
| einf = getreg32(LPC43_GPIOINT_IENF) & ~bitmask; |
| |
| switch (gpiocfg & GPIO_INT_MASK) |
| { |
| case GPIO_INT_LEVEL_HI: |
| einf |= bitmask; /* Enable active level HI */ |
| case GPIO_INT_LEVEL_LOW: |
| isel |= bitmask; /* Level sensitive */ |
| einr |= bitmask; /* Enable level interrupt */ |
| break; |
| |
| case GPIO_INT_EDGE_RISING: |
| einr |= bitmask; /* Enable rising edge interrupt */ |
| break; |
| |
| case GPIO_INT_EDGE_BOTH: |
| einr |= bitmask; /* Enable rising edge interrupt */ |
| case GPIO_INT_EDGE_FALLING: |
| einf |= bitmask; /* Enable falling edge interrupt */ |
| break; |
| |
| /* Default is edge sensitive but with both edges disabled. */ |
| |
| default: |
| break; |
| } |
| |
| putreg32(isel, LPC43_GPIOINT_ISEL); |
| putreg32(einr, LPC43_GPIOINT_IENR); |
| putreg32(einf, LPC43_GPIOINT_IENF); |
| |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: lpc43_gpioint_grpconfig |
| * |
| * Description: |
| * Configure a GPIO pin as an GPIO group interrupt member (after it has |
| * been configured as an input). |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| * Assumptions: |
| * Interrupts are disabled so that read-modify-write operations are safe. |
| * |
| ****************************************************************************/ |
| |
| int lpc43_gpioint_grpconfig(uint16_t gpiocfg) |
| { |
| unsigned int port = ((gpiocfg & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT); |
| unsigned int pin = ((gpiocfg & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT); |
| irqstate_t flags; |
| uintptr_t grpbase; |
| uintptr_t regaddr; |
| uint32_t regval; |
| uint32_t bitmask = (1 << pin); |
| |
| /* Select the group register base address */ |
| |
| flags = enter_critical_section(); |
| if (GPIO_IS_GROUP0(gpiocfg)) |
| { |
| grpbase = LPC43_GRP0INT_BASE; |
| } |
| else |
| { |
| grpbase = LPC43_GRP1INT_BASE; |
| } |
| |
| /* Set/clear the polarity for this pin */ |
| |
| regaddr = grpbase + LPC43_GRPINT_POL_OFFSET(port); |
| regval = getreg32(regaddr); |
| |
| if (GPIO_IS_POLARITY_HI(gpiocfg)) |
| { |
| regval |= bitmask; |
| } |
| else |
| { |
| regval &= ~bitmask; |
| } |
| |
| putreg32(regval, regaddr); |
| |
| /* Set the corresponding bit in the port enable register so that this pin |
| * will contribute to the group interrupt. |
| */ |
| |
| regaddr = grpbase + LPC43_GRPINT_ENA_OFFSET(port); |
| regval = getreg32(regaddr); |
| regval |= bitmask; |
| putreg32(regval, regaddr); |
| |
| leave_critical_section(flags); |
| return OK; |
| } |
| |
| /**************************************************************************** |
| * Name: lpc43_gpioint_ack |
| * |
| * Description: |
| * Acknowledge the interrupt for a given pint interrupt number. Call this |
| * inside the interrupt handler. For edge sensitive interrupts, the |
| * interrupt status is cleared. For level sensitive interrupts, the |
| * active-high/-low sensitivity is inverted. |
| * |
| * Returned Value: |
| * Zero on success; a negated errno value on failure. |
| * |
| ****************************************************************************/ |
| |
| int lpc43_gpioint_ack(uint8_t intnumber) |
| { |
| uint32_t regval; |
| |
| regval = getreg32(LPC43_GPIOINT_IST); |
| regval |= (1 << intnumber); |
| putreg32(regval, LPC43_GPIOINT_IST); |
| |
| return OK; |
| } |
| |
| #endif /* CONFIG_LPC43_GPIO_IRQ */ |