OSStatus platform_gpio_irq_disable( const platform_gpio_t* gpio )
{
  OSStatus            err           = kNoErr;
  ioport_port_mask_t  mask          = ioport_pin_to_mask   ( gpio->pin );
  ioport_port_t       port          = ioport_pin_to_port_id( gpio->pin );
  volatile Pio*       port_register = arch_ioport_port_to_base( port );
  
  platform_mcu_powersave_disable();
  require_action_quiet( gpio != NULL, exit, err = kParamErr);

  /* Disable interrupt on pin */
  port_register->PIO_IDR = mask;

  /* Disable Cortex-M interrupt vector as well if no pin interrupt is enabled */
  if ( port_register->PIO_IMR == 0 )
  {
    NVIC_DisableIRQ( irq_vectors[port] );
  }

  gpio_irq_data[port][mask].wakeup_pin = false;
  gpio_irq_data[port][mask].arg        = 0;
  gpio_irq_data[port][mask].callback   = NULL;
  
exit:
  platform_mcu_powersave_enable();
  return err;
}
Example #2
0
/**
 * \brief Set callback for given GPIO pin
 *
 * \param [in] pin The pin number
 * \param [in] callback callback function pointer
 * \param [in] irq_level interrupt level
 *
 * \retval true Set successfully
 * \retval false Wrong parameters or maximum number of interrupt
 *                  sources has been exceeding
 */
bool gpio_set_pin_callback(ioport_pin_t pin, gpio_pin_callback_t callback,
		uint8_t irq_level)
{
	int8_t i;
	int8_t irq_line;

	if (gpio_nb_sources >= GPIO_MAX_INTERRUPT_SOURCES) {
		return false;
	}

	/*
	 * Get IRQ line for the given pin.
	 *
	 * \note Grouping interrupt generators into groups of eight, four
	 * different interrupt handlers can be installed for each GPIO port.
	 */
	for (i = 0; i < 4; i++) {
		if (ioport_pin_to_mask(pin) & (GPIO_INT_GROUP_MASK << (i * 8))) {
			break;
		}
	}
	irq_line = GPIO_0_IRQn + ioport_pin_to_port_id(pin) * 4 + i;

	gpio_int_sources[gpio_nb_sources].pin = pin;
	gpio_int_sources[gpio_nb_sources].callback = callback;
	NVIC_ClearPendingIRQ((IRQn_Type)irq_line);
	NVIC_SetPriority((IRQn_Type)irq_line, irq_level);
	NVIC_EnableIRQ((IRQn_Type)irq_line);

	gpio_nb_sources++;

	return true;
}
Example #3
0
/**
 * Common GPIO handler.
 */
static void gpio_common_handler(uint32_t port_id, uint32_t port_mask)
{
	GpioPort *gpio_port = &(GPIO->GPIO_PORT[port_id]);
	uint32_t i;
	uint32_t int_flags;
	ioport_pin_t pin;

	int_flags = gpio_port->GPIO_IFR;

	for (i = 0; i < gpio_nb_sources; i++) {
		pin = gpio_int_sources[i].pin;
		if ((ioport_pin_to_port_id(pin) == port_id) &&
				(ioport_pin_to_mask(pin) & int_flags)) {
			if (gpio_int_sources[i].callback != NULL) {
				gpio_int_sources[i].callback();
			} else {
				Assert(false); /* Catch unexpected interrupt */
			}
		}
	}

	gpio_port->GPIO_IFRC = (int_flags & port_mask);
}
OSStatus platform_gpio_irq_enable( const platform_gpio_t* gpio, platform_gpio_irq_trigger_t trigger, platform_gpio_irq_callback_t handler, void* arg )
{
  ioport_port_mask_t  mask                = ioport_pin_to_mask( gpio->pin );
  ioport_port_t       port                = ioport_pin_to_port_id( gpio->pin );
  volatile Pio*       port_register       = arch_ioport_port_to_base( port );
  uint8_t             pin_number          = (gpio->pin) & 0x1F;
  uint32_t            temp;
  uint8_t             samg5x_irq_trigger;
  OSStatus            err                 = kNoErr;
    
  platform_mcu_powersave_disable();
  require_action_quiet( gpio != NULL, exit, err = kParamErr);

  NVIC_DisableIRQ( irq_vectors[port] );
  NVIC_ClearPendingIRQ( irq_vectors[port] );

  gpio_irq_data[port][pin_number].wakeup_pin = gpio->is_wakeup_pin;
  gpio_irq_data[port][pin_number].arg        = arg;
  gpio_irq_data[port][pin_number].callback   = handler;

  switch ( trigger )
  {
    case IRQ_TRIGGER_RISING_EDGE:  samg5x_irq_trigger = IOPORT_SENSE_RISING;    break;
    case IRQ_TRIGGER_FALLING_EDGE: samg5x_irq_trigger = IOPORT_SENSE_FALLING;   break;
    case IRQ_TRIGGER_BOTH_EDGES:   samg5x_irq_trigger = IOPORT_SENSE_BOTHEDGES; break;
    default:
      err = kParamErr;
      goto exit;
  }

  if( gpio->is_wakeup_pin == true )
  {
    platform_powersave_enable_wakeup_pin( gpio );
  }

  if ( samg5x_irq_trigger == IOPORT_SENSE_RISING || samg5x_irq_trigger == IOPORT_SENSE_BOTHEDGES )
  {
   port_register->PIO_AIMER  |= mask;
   port_register->PIO_ESR    |= mask;
   port_register->PIO_REHLSR |= mask;
  }

  if ( samg5x_irq_trigger == IOPORT_SENSE_FALLING || samg5x_irq_trigger == IOPORT_SENSE_BOTHEDGES )
  {
    port_register->PIO_AIMER  |= mask;
    port_register->PIO_ESR    |= mask;
    port_register->PIO_FELLSR |= mask;
  }

  /* Read ISR to clear residual interrupt status */
  temp = port_register->PIO_ISR;
  UNUSED_PARAMETER( temp );

  /* Enable interrupt source */
  port_register->PIO_IER |= mask;

  NVIC_EnableIRQ( irq_vectors[port] );
  
exit:
  platform_mcu_powersave_enable();
  return err;
}