Skip to content

Commit 0f4ae76

Browse files
committed
drivers: gpio: Enable gpio_mcux wakeup feature
Enable gpio_mcux wakeup feature Signed-off-by: Zhaoxiang Jin <[email protected]>
1 parent 2c03fb2 commit 0f4ae76

File tree

2 files changed

+135
-45
lines changed

2 files changed

+135
-45
lines changed

drivers/gpio/gpio_mcux.c

Lines changed: 115 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@
1717

1818
#include <zephyr/drivers/gpio/gpio_utils.h>
1919

20+
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
21+
#if defined(CONFIG_SOC_FAMILY_MCXN) || defined(CONFIG_SOC_FAMILY_MCXA) || \
22+
defined(CONFIG_SOC_FAMILY_MCXW)
23+
#include <fsl_wuu.h>
24+
#endif
25+
#endif
26+
2027
#if defined(CONFIG_PINCTRL_NXP_IOCON)
2128
#include <fsl_iopctl.h>
2229
/* Use IOCON to configure electrical characteristic, set PORT_Type as void. */
@@ -30,6 +37,12 @@ struct gpio_mcux_config {
3037
PORT_Type *port_base;
3138
unsigned int flags;
3239
uint32_t port_no;
40+
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
41+
bool wakeup_source;
42+
uint8_t wakeup_pin;
43+
uint8_t wuu_index; /* Index used to configure wakeup unit (wuu). */
44+
uint8_t wakeup_signal_edge;
45+
#endif
3346
};
3447

3548
struct gpio_mcux_data {
@@ -200,6 +213,31 @@ static int gpio_mcux_port_configure(const struct device *dev, gpio_pin_t pin, gp
200213
/* Accessing by pin, we only need to write one PCR register. */
201214
port_base->PCR[pin] = (port_base->PCR[pin] & ~mask) | pcr;
202215

216+
217+
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
218+
#if defined(CONFIG_SOC_FAMILY_MCXN) || defined(CONFIG_SOC_FAMILY_MCXA) || \
219+
defined(CONFIG_SOC_FAMILY_MCXW)
220+
if ((config->wakeup_source) && (config->wakeup_pin == pin)) {
221+
wuu_external_wakeup_pin_config_t wakeup_pin_config;
222+
223+
wakeup_pin_config.edge = config->wakeup_signal_edge;
224+
wakeup_pin_config.event = kWUU_ExternalPinInterrupt;
225+
wakeup_pin_config.mode = kWUU_ExternalPinActiveAlways;
226+
227+
/* We get pin index here not WUU input index. */
228+
if (WUU_GetExternalWakeUpPinsFlag(WUU0) == BIT(config->wuu_index)) {
229+
WUU_ClearExternalWakeUpPinsFlag(WUU0, BIT(config->wuu_index));
230+
}
231+
232+
WUU_SetExternalWakeUpPinsConfig(WUU0, config->wuu_index, &wakeup_pin_config);
233+
}
234+
#elif
235+
/* Other platforms may also use gpio as the wakeup source, but the wakeup source
236+
* management is not done using WUU.
237+
*/
238+
#endif
239+
#endif
240+
203241
return 0;
204242
}
205243
#endif /* defined(CONFIG_PINCTRL_NXP_IOCON) */
@@ -405,6 +443,21 @@ static void gpio_mcux_port_isr(const struct device *dev)
405443
ARG_UNUSED(config);
406444
#endif /* !(defined(FSL_FEATURE_PORT_HAS_NO_INTERRUPT) */
407445

446+
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
447+
#if defined(CONFIG_SOC_FAMILY_MCXN) || defined(CONFIG_SOC_FAMILY_MCXA) || \
448+
defined(CONFIG_SOC_FAMILY_MCXW)
449+
if (config->wakeup_source) {
450+
if (WUU_GetExternalWakeUpPinsFlag(WUU0) == BIT(config->wuu_index)) {
451+
WUU_ClearExternalWakeUpPinsFlag(WUU0, BIT(config->wuu_index));
452+
}
453+
}
454+
#elif
455+
/* Other platforms may also use gpio as the wakeup source, but the wakeup source
456+
* management is not done using WUU.
457+
*/
458+
#endif
459+
#endif
460+
408461
gpio_fire_callbacks(&data->callbacks, dev, int_status);
409462
}
410463

@@ -423,18 +476,18 @@ static void gpio_mcux_shared_cluster_isr(const struct device *ports[])
423476

424477
#define CLUSTER_ARRAY_ELEMENT(node_id) DEVICE_DT_GET(node_id),
425478

426-
#define GPIO_MCUX_CLUSTER_INIT(node_id) \
427-
const struct device *shared_array##node_id[DT_CHILD_NUM_STATUS_OKAY(node_id) + 1] = { \
428-
DT_FOREACH_CHILD_STATUS_OKAY(node_id, CLUSTER_ARRAY_ELEMENT) NULL}; \
429-
\
430-
static int gpio_mcux_shared_interrupt_init##node_id(void) \
431-
{ \
432-
IRQ_CONNECT(DT_IRQN(node_id), DT_IRQ(node_id, priority), \
433-
gpio_mcux_shared_cluster_isr, shared_array##node_id, 0); \
434-
irq_enable(DT_IRQN(node_id)); \
435-
\
436-
return 0; \
437-
} \
479+
#define GPIO_MCUX_CLUSTER_INIT(node_id) \
480+
const struct device *shared_array##node_id[DT_CHILD_NUM_STATUS_OKAY(node_id) + 1] = { \
481+
DT_FOREACH_CHILD_STATUS_OKAY(node_id, CLUSTER_ARRAY_ELEMENT) NULL}; \
482+
\
483+
static int gpio_mcux_shared_interrupt_init##node_id(void) \
484+
{ \
485+
IRQ_CONNECT(DT_IRQN(node_id), DT_IRQ(node_id, priority), \
486+
gpio_mcux_shared_cluster_isr, shared_array##node_id, 0); \
487+
irq_enable(DT_IRQN(node_id)); \
488+
\
489+
return 0; \
490+
} \
438491
SYS_INIT(gpio_mcux_shared_interrupt_init##node_id, POST_KERNEL, 0);
439492

440493
DT_FOREACH_STATUS_OKAY(nxp_gpio_cluster, GPIO_MCUX_CLUSTER_INIT)
@@ -479,44 +532,61 @@ static DEVICE_API(gpio, gpio_mcux_driver_api) = {
479532
#endif /* CONFIG_GPIO_GET_DIRECTION */
480533
};
481534

482-
#define GPIO_MCUX_IRQ_INIT(n) \
483-
do { \
484-
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_mcux_port_isr, \
485-
DEVICE_DT_INST_GET(n), 0); \
486-
\
487-
irq_enable(DT_INST_IRQN(n)); \
535+
536+
537+
#if defined(CONFIG_PM) || defined(CONFIG_POWEROFF)
538+
#define GPIO_ENABLED_WAKEUP_FUNCTION(n) \
539+
.wakeup_source = DT_INST_PROP_OR(n, wakeup_source, 0), \
540+
IF_ENABLED(DT_INST_PROP(n, wakeup_source), \
541+
(.wakeup_signal_edge = DT_INST_PROP(n, wakeup_signal_edge),)) \
542+
IF_ENABLED(DT_INST_PROP(n, wakeup_source), \
543+
(.wakeup_pin = DT_PROP_BY_IDX(DT_DRV_INST(n), wakeup_line, 0),)) \
544+
IF_ENABLED(DT_INST_PROP(n, wakeup_source), \
545+
(.wuu_index = DT_PROP_BY_IDX(DT_DRV_INST(n), wakeup_line, 1),)) \
546+
547+
#else
548+
#define GPIO_ENABLED_WAKEUP_FUNCTION(n)
549+
#endif
550+
551+
#define GPIO_MCUX_IRQ_INIT(n) \
552+
do { \
553+
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), gpio_mcux_port_isr, \
554+
DEVICE_DT_INST_GET(n), 0); \
555+
\
556+
irq_enable(DT_INST_IRQN(n)); \
488557
} while (false)
489558

490559
#define GPIO_PORT_BASE_ADDR(n) DT_REG_ADDR(DT_INST_PHANDLE(n, nxp_kinetis_port))
491-
#define GPIO_PORT_NUMBER(n) COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpio_port_offest), \
560+
#define GPIO_PORT_NUMBER(n) COND_CODE_1(DT_INST_NODE_HAS_PROP(n, gpio_port_offest), \
492561
(DT_INST_PROP(n, gpio_port_offest) + n), (n)) \
493562

494-
#define GPIO_DEVICE_INIT_MCUX(n) \
495-
static int gpio_mcux_port##n##_init(const struct device *dev); \
496-
\
497-
static const struct gpio_mcux_config gpio_mcux_port##n##_config = { \
498-
.common = \
499-
{ \
500-
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
501-
}, \
502-
.gpio_base = (GPIO_Type *)DT_INST_REG_ADDR(n), \
503-
.port_base = (PORT_Type *)GPIO_PORT_BASE_ADDR(n), \
504-
.flags = UTIL_AND(UTIL_OR(DT_INST_IRQ_HAS_IDX(n, 0), GPIO_HAS_SHARED_IRQ), \
505-
GPIO_INT_ENABLE), \
506-
.port_no = GPIO_PORT_NUMBER(n), \
507-
}; \
508-
\
509-
static struct gpio_mcux_data gpio_mcux_port##n##_data; \
510-
\
511-
DEVICE_DT_INST_DEFINE(n, gpio_mcux_port##n##_init, NULL, &gpio_mcux_port##n##_data, \
512-
&gpio_mcux_port##n##_config, POST_KERNEL, CONFIG_GPIO_INIT_PRIORITY, \
513-
&gpio_mcux_driver_api); \
514-
\
515-
static int gpio_mcux_port##n##_init(const struct device *dev) \
516-
{ \
517-
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \
518-
(GPIO_MCUX_IRQ_INIT(n);)) \
519-
return 0; \
563+
#define GPIO_DEVICE_INIT_MCUX(n) \
564+
static int gpio_mcux_port##n##_init(const struct device *dev); \
565+
\
566+
static const struct gpio_mcux_config gpio_mcux_port##n##_config = { \
567+
.common = \
568+
{ \
569+
.port_pin_mask = GPIO_PORT_PIN_MASK_FROM_DT_INST(n), \
570+
}, \
571+
.gpio_base = (GPIO_Type *)DT_INST_REG_ADDR(n), \
572+
.port_base = (PORT_Type *)GPIO_PORT_BASE_ADDR(n), \
573+
.flags = UTIL_AND(UTIL_OR(DT_INST_IRQ_HAS_IDX(n, 0), GPIO_HAS_SHARED_IRQ), \
574+
GPIO_INT_ENABLE), \
575+
.port_no = GPIO_PORT_NUMBER(n), \
576+
GPIO_ENABLED_WAKEUP_FUNCTION(n) \
577+
}; \
578+
\
579+
static struct gpio_mcux_data gpio_mcux_port##n##_data; \
580+
\
581+
DEVICE_DT_INST_DEFINE(n, gpio_mcux_port##n##_init, NULL, &gpio_mcux_port##n##_data, \
582+
&gpio_mcux_port##n##_config, POST_KERNEL, \
583+
CONFIG_GPIO_INIT_PRIORITY, &gpio_mcux_driver_api); \
584+
\
585+
static int gpio_mcux_port##n##_init(const struct device *dev) \
586+
{ \
587+
IF_ENABLED(DT_INST_IRQ_HAS_IDX(n, 0), \
588+
(GPIO_MCUX_IRQ_INIT(n);)) \
589+
return 0; \
520590
}
521591

522592
DT_INST_FOREACH_STATUS_OKAY(GPIO_DEVICE_INIT_MCUX)

dts/bindings/gpio/nxp,kinetis-gpio.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,26 @@ properties:
2424
description: |
2525
Describes an offset between inst index and actual GPIO port number.
2626
27+
wakeup-line:
28+
type: array
29+
description: |
30+
On some NXP platforms, GPIO can wake up the MCU, but the wakeup capability
31+
is configured through a specific peripheral, such as the wakeup unit. We need
32+
to use this property to specify which pin has the wakeup capability and which
33+
register of the wakeup unit the pin is mapped to.
34+
For example, configure wakeup-line = <20 4> indicates GPIOn_20 can wakeup
35+
the SoC/MCU, and we need to configure wakeup unit register 4 to enable wakeup
36+
function.
37+
38+
wakeup-signal-edge:
39+
type: int
40+
enum:
41+
- 1 # External input Pin enabled with the rising edge detection
42+
- 2 # External input Pin enabled with the falling edge detection.
43+
- 3 # External input Pin enabled with any change detection.
44+
description: |
45+
Indicates which edge signal on the wakeup pin can wake up the MCU.
46+
2747
gpio-cells:
2848
- pin
2949
- flags

0 commit comments

Comments
 (0)