blob: 33369098fa8505dfcca5d3ca06b2155e1b111fe2 [file] [log] [blame]
/****************************************************************************
* arch/arm/src/samd5e5/sam_eic.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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <sys/types.h>
#include <inttypes.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include "arm_internal.h"
#include "sam_gclk.h"
#include "sam_periphclks.h"
#include "sam_port.h"
#include "sam_eic.h"
#include "hardware/sam_pac.h"
#include <arch/board/board.h>
#ifdef CONFIG_SAMD5E5_EIC
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sam_eic_syncwait
*
* Description:
* Wait until the ENABLE synchronization is complete
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
static void sam_eic_syncwait(void)
{
while ((getreg8(SAM_EIC_SYNCBUSY) & EIC_SYNCBUSY_ENABLE) != 0);
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sam_eic_dumpregs
*
* Description:
* Dump all external interrupt controller (EIC) registers
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
void sam_eic_dumpregs(void)
{
irqinfo("EIC:\n");
irqinfo(" CTRLA: %02x\n", getreg8(SAM_EIC_CTRLA));
irqinfo(" NMICTRL: %02x\n", getreg8(SAM_EIC_NMICTRL));
irqinfo(" NMIFLAG: %04x\n", getreg16(SAM_EIC_NMIFLAG));
irqinfo(" SYNCBUSY: %08" PRIx32 "\n", getreg32(SAM_EIC_SYNCBUSY));
irqinfo(" EVCTRL: %08" PRIx32 "\n", getreg32(SAM_EIC_EVCTRL));
irqinfo(" INTENCLR: %08" PRIx32 "\n", getreg32(SAM_EIC_INTENCLR));
irqinfo(" INTENSET: %08" PRIx32 "\n", getreg32(SAM_EIC_INTENSET));
irqinfo(" INTFLAG: %08" PRIx32 "\n", getreg32(SAM_EIC_INTFLAG));
irqinfo(" ASYNCH: %08" PRIx32 "\n", getreg32(SAM_EIC_ASYNCH));
irqinfo(" CONFIG0: %08" PRIx32 "\n", getreg32(SAM_EIC_CONFIG0));
irqinfo(" CONFIG1: %08" PRIx32 "\n", getreg32(SAM_EIC_CONFIG1));
irqinfo(" DEBOUNCEN: %08" PRIx32 "\n", getreg32(SAM_EIC_DEBOUNCEN));
irqinfo(" DPRESCALER: %08" PRIx32 "\n", getreg32(SAM_EIC_DPRESCALER));
irqinfo(" PINSTATE: %08" PRIx32 "\n", getreg32(SAM_EIC_PINSTATE));
}
/****************************************************************************
* Name: sam_eic_initialize
*
* Description:
* Initialize the EIC. Called one timer during system bring-up.
*
* Input Parameters:
* None
*
* Returned Value:
* None
*
****************************************************************************/
int sam_eic_initialize(void)
{
uintptr_t regaddr;
uint32_t regval;
/* Configure the EIC APB clock */
sam_apb_eic_enableperiph(); /* SAM_MCLK_APBAMASK(MCLK_APBAMASK_EIC) */
/* Use the selected GCLK_EIC. Some optional functions need a peripheral
* clock, which can either be a generic clock (GCLK_EIC, for wider
* frequency selection) or a Ultra Low Power 32KHz clock (CLK_ULP32K, for
* highest power efficiency). One of the clock sources must be configured
* and enabled before using the peripheral.
*/
regaddr = SAM_GCLK_PCHCTRL(GCLK_CHAN_EIC); /* (GCLK_CHAN_EIC) */
regval = GCLK_PCHCTRL_GEN(BOARD_GCLK_EIC) | GCLK_PCHCTRL_CHEN;
putreg32(regval, regaddr);
/* Enable the EIC, selecting clocking via the GCLK_EIC */
putreg8(EIC_CTRLA_ENABLE, SAM_EIC_CTRLA);
sam_eic_syncwait();
sam_eic_dumpregs();
return OK;
}
/****************************************************************************
* Name: sam_eic_configure
*
* Description:
* Configure the interrupt edge sensitivity in CONFIGn register of the
* EIC. The interrupt will be enabled at the EIC (but not at the NVIC).
*
* Input Parameters:
* eirq - Pin to be configured (0..15)
* pinset - Configuration of the pin
*
* Returned Value:
* None
*
****************************************************************************/
int sam_eic_configure(uint8_t eirq, port_pinset_t pinset)
{
uint32_t reg;
uint32_t val;
uint32_t config;
/* Disable the EIC: 23.6.2.1 */
putreg8(0, SAM_EIC_CTRLA);
sam_eic_syncwait();
/* Determine which of the CONFIG[0:1] registers to write to */
if (eirq < 8)
{
reg = SAM_EIC_CONFIG0;
val = EIC_CONFIG0_SENSE_BOTH(eirq);
if ((pinset & PORT_INT_RISING) != 0)
{
val = EIC_CONFIG0_SENSE_RISE(eirq);
}
if ((pinset & PORT_INT_FALLING) != 0)
{
val = EIC_CONFIG0_SENSE_FALL(eirq);
}
if ((pinset & PORT_INT_HIGH) != 0)
{
val = EIC_CONFIG0_SENSE_HIGH(eirq);
}
val |= EIC_CONFIG0_FILTEN(eirq);
}
else /* if (eirq < 16) */
{
reg = SAM_EIC_CONFIG1;
val = EIC_CONFIG1_SENSE_BOTH(eirq);
if ((pinset & PORT_INT_RISING) != 0)
{
val = EIC_CONFIG1_SENSE_RISE(eirq);
}
if ((pinset & PORT_INT_FALLING) != 0)
{
val = EIC_CONFIG1_SENSE_FALL(eirq);
}
if ((pinset & PORT_INT_HIGH) != 0)
{
val = EIC_CONFIG1_SENSE_HIGH(eirq);
}
config = getreg32(SAM_EIC_EVCTRL);
config |= EIC_EXTINT(eirq);
putreg32(config, SAM_EIC_EVCTRL);
}
/* Write the new config to the CONFIGn register */
config = getreg32(reg);
config |= val;
putreg32(config, reg);
/* Enable the EIC, selecting clocking via the GCLK_EIC */
putreg8(EIC_CTRLA_ENABLE, SAM_EIC_CTRLA);
sam_eic_syncwait();
sam_eic_dumpregs();
return OK;
}
/****************************************************************************
* Name: sam_eic_irq_ack
*
* Description:
* Acknowledge receipt of an external interrupt.
*
* Input Parameters:
* irq - SAM_IRQ_EXTINTn IRQ to be acknowledged, n=0-15
*
* Returned Value:
* None
*
****************************************************************************/
int sam_eic_irq_ack(int irq)
{
int eirq = irq - SAM_IRQ_EXTINT0;
irqinfo("sam_eic_irq_ack: irq=%d eirq=%d EIC_EXTINT=0x%x\n", irq,
eirq, EIC_EXTINT(eirq));
putreg32(EIC_EXTINT(eirq), SAM_EIC_INTFLAG);
return OK;
}
#endif /* CONFIG_SAMD5E5_EIC */