mbed-os/targets/TARGET_Samsung/TARGET_SIDK_S1SBP6A/gpio_irq_api.c

155 lines
4.2 KiB
C

/****************************************************************************
*
* Copyright 2020 Samsung Electronics All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed 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 <stddef.h>
#include "cmsis.h"
#include "gpio_irq_api.h"
#include "mbed_error.h"
/****************************************************************************
* Pre-processor definitions
****************************************************************************/
#define CHANNEL_NUM 48
#define MAX_PIN_PER_PORT 16
static gpio_irq_handler irq_handler;
static uint32_t channel_ids[CHANNEL_NUM];
static gpio_irq_event pins_event[CHANNEL_NUM];
static inline void handle_gpio_irq(uint32_t port)
{
int i;
uint32_t pin_name = port << 4;
BP_GPIO_TypeDef *gpio_base = (BP_GPIO_TypeDef *)GPIO_PORT_BASE(port);
for (i = 0; i < MAX_PIN_PER_PORT; i++) {
if (gpio_base->INTSTAT & (1u << i)) {
pin_name += i;
NVIC_ClearPendingIRQ(PORT0_0_IRQn + port * 16 + i);
gpio_base->INTCLR = 1u << i;
irq_handler(channel_ids[pin_name], pins_event[pin_name]);
break;
}
}
}
void gpio0_irq(void)
{
handle_gpio_irq(0);
NVIC_ClearPendingIRQ(PORT0_ALL_IRQn);
}
void gpio1_irq(void)
{
handle_gpio_irq(1);
NVIC_ClearPendingIRQ(PORT1_ALL_IRQn);
}
void gpio2_irq(void)
{
handle_gpio_irq(2);
NVIC_ClearPendingIRQ(PORT2_ALL_IRQn);
}
int gpio_irq_init(gpio_irq_t *obj, PinName pin,
gpio_irq_handler handler, uint32_t id)
{
if (pin == (PinName)NC) {
return -1;
}
obj->pin = pin;
irq_handler = handler;
channel_ids[pin] = id;
bp6a_gpio_set_dir(BP6A_PORT_IDX(obj->pin), BP6A_PIN_IDX(obj->pin), true);
return 0;
}
void gpio_irq_free(gpio_irq_t *obj)
{
channel_ids[obj->pin] = 0;
gpio_irq_disable(obj);
}
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
{
pins_event[obj->pin] = event;
if (event == IRQ_NONE) {
return;
}
if (event == IRQ_RISE) {
bp6a_gpio_set_int_type(BP6A_PORT_IDX(obj->pin), BP6A_PIN_IDX(obj->pin),
true, true);
} else {
bp6a_gpio_set_int_type(BP6A_PORT_IDX(obj->pin), BP6A_PIN_IDX(obj->pin),
false, true);
}
if (enable) {
gpio_irq_enable(obj);
} else {
gpio_irq_disable(obj);
}
}
void gpio_irq_enable(gpio_irq_t *obj)
{
uint32_t port = BP6A_PORT_IDX(obj->pin);
bp6a_gpio_set_int(port, BP6A_PIN_IDX(obj->pin), true);
void (*port_irq)(void) = NULL;
switch (port) {
case 0:
port_irq = &gpio0_irq;
break;
case 1:
port_irq = &gpio1_irq;
break;
case 2:
port_irq = &gpio2_irq;
break;
}
NVIC_SetVector((IRQn_Type)(PORT0_0_IRQn + port * 16 + BP6A_PIN_IDX(obj->pin)), (uint32_t)port_irq);
#if defined (__ICACHE_PRESENT) && (__ICACHE_PRESENT == 1U)
SCB_InvalidateICache();
#endif
NVIC_EnableIRQ((IRQn_Type)(PORT0_0_IRQn + port * 16 + BP6A_PIN_IDX(obj->pin)));
}
void gpio_irq_disable(gpio_irq_t *obj)
{
uint32_t port_n = BP6A_PORT_IDX(obj->pin);
uint32_t pin_n = BP6A_PIN_IDX(obj->pin);
NVIC_ClearPendingIRQ((IRQn_Type)(PORT0_ALL_IRQn + port_n));
bp6a_gpio_clear_pend(port_n, pin_n);
NVIC_DisableIRQ((IRQn_Type)(PORT0_ALL_IRQn + port_n));
bp6a_gpio_set_int(port_n, pin_n, false);
}