Skip to content

Commit

Permalink
cpu/kinetis/gpio: support LLWU
Browse files Browse the repository at this point in the history
  • Loading branch information
benemorius committed Jun 27, 2020
1 parent 2f1cd14 commit 1a9e373
Showing 1 changed file with 69 additions and 6 deletions.
75 changes: 69 additions & 6 deletions cpu/kinetis/periph/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
* @author Johann Fischer <j.fischer@phytec.de>
* @author Jonas Remmert <j.remmert@phytec.de>
* @author Joakim Nohlgård <joakim.nohlgard@eistec.se>
* @author Thomas Stilwell <stilwellt@openlabs.co>
*
* @}
*/
Expand All @@ -34,6 +35,10 @@
#include "bitarithm.h"
#include "periph/gpio.h"

#if MODULE_PERIPH_LLWU
#include "llwu.h"
#endif

#define ENABLE_DEBUG 0
#include "debug.h"

Expand Down Expand Up @@ -288,15 +293,36 @@ void gpio_write(gpio_t pin, int value)
}

#ifdef MODULE_PERIPH_GPIO_IRQ
#ifdef MODULE_PERIPH_LLWU
static llwu_wakeup_pin_t llwu_pin_from_gpio(gpio_t pin)
{
for (unsigned i = 0; i < LLWU_WAKEUP_PIN_NUMOF; ++i) {
if (llwu_wakeup_pin_to_port[i].port == port(pin)
&& llwu_wakeup_pin_to_port[i].isfr_mask == (1u << pin_num(pin))
) {
return i;
}
}
return LLWU_WAKEUP_PIN_UNDEF;
}
#endif /* MODULE_PERIPH_LLWU */

int gpio_init_int(gpio_t pin, gpio_mode_t mode, gpio_flank_t flank,
gpio_cb_t cb, void *arg)
{
if (gpio_init(pin, mode) < 0) {
return -1;
}

LOG_INFO("[gpio] will block power mode %u for pin interrupt while enabled\n",
KINETIS_PM_LLS);
#ifdef MODULE_PERIPH_LLWU
if (llwu_pin_from_gpio(pin) == LLWU_WAKEUP_PIN_UNDEF)
{
#else
{
#endif
LOG_INFO("[gpio] will block power mode %u for pin interrupt while enabled\n",
KINETIS_PM_LLS);
}

/* try go grab a free spot in the context array */
int ctx_num = get_free_ctx();
Expand Down Expand Up @@ -332,8 +358,29 @@ void gpio_irq_enable(gpio_t pin)
int ctx = get_ctx(port_num(pin), pin_num(pin));
port(pin)->PCR[pin_num(pin)] |= isr_ctx[ctx].state;

DEBUG("[gpio] blocking power mode %u for pin interrupt\n", KINETIS_PM_LLS);
PM_BLOCK(KINETIS_PM_LLS);
#ifdef MODULE_PERIPH_LLWU
/* Check if the pin can be used as LLWU source. Configure LLWU if so,
* but also leave the pin configured as a GPIO IRQ source because LLWU is
* not active in any non-LL mode. If not, block PM_LLS as we can't otherwise
* provide the requested pin interrupt.
*/
llwu_wakeup_pin_t llwu_pin = llwu_pin_from_gpio(pin);
if (llwu_pin != LLWU_WAKEUP_PIN_UNDEF) {
llwu_wakeup_edge_t edge = (isr_ctx[ctx].state >> PORT_PCR_IRQC_SHIFT)
- (GPIO_RISING >> PORT_PCR_IRQC_SHIFT)
+ LLWU_WAKEUP_EDGE_RISING;
llwu_wakeup_pin_set(llwu_pin, edge, isr_ctx[ctx].cb, isr_ctx[ctx].arg);
}

else
{
#else /* MODULE_PERIPH_LLWU */
{
#endif
DEBUG("[gpio] blocking power mode %u for pin interrupt\n",
KINETIS_PM_LLS);
PM_BLOCK(KINETIS_PM_LLS);
}
}

void gpio_irq_disable(gpio_t pin)
Expand All @@ -348,8 +395,24 @@ void gpio_irq_disable(gpio_t pin)

port(pin)->PCR[pin_num(pin)] &= ~(PORT_PCR_IRQC_MASK);

DEBUG("[gpio] unblocking power mode %u for pin interrupt\n", KINETIS_PM_LLS);
PM_UNBLOCK(KINETIS_PM_LLS);
#ifdef MODULE_PERIPH_LLWU
/* Disable LLWU for this pin if we had enabled it */
llwu_wakeup_pin_t llwu_pin = llwu_pin_from_gpio(pin);
if (llwu_pin != LLWU_WAKEUP_PIN_UNDEF)
{
llwu_wakeup_pin_set(llwu_pin, LLWU_WAKEUP_EDGE_NONE,
NULL, NULL);
}

else
{
#else /* MODULE_PERIPH_LLWU */
{
#endif
DEBUG("[gpio] unblocking power mode %u for pin interrupt\n",
KINETIS_PM_LLS);
PM_UNBLOCK(KINETIS_PM_LLS);
}
}

static inline void irq_handler(PORT_Type *port, int port_num)
Expand Down

0 comments on commit 1a9e373

Please sign in to comment.