1 /*
2  * Copyright (c) 2023, Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include "spi_nrfx_common.h"
8 #include <zephyr/kernel.h>
9 
spi_nrfx_wake_init(const nrfx_gpiote_t * gpiote,uint32_t wake_pin)10 int spi_nrfx_wake_init(const nrfx_gpiote_t *gpiote, uint32_t wake_pin)
11 {
12 	nrf_gpio_pin_pull_t pull_config = NRF_GPIO_PIN_PULLDOWN;
13 	uint8_t ch;
14 	nrfx_gpiote_trigger_config_t trigger_config = {
15 		.trigger = NRFX_GPIOTE_TRIGGER_HITOLO,
16 		.p_in_channel = &ch,
17 	};
18 	nrfx_gpiote_input_pin_config_t input_config = {
19 		.p_pull_config = &pull_config,
20 		.p_trigger_config = &trigger_config,
21 		.p_handler_config = NULL,
22 	};
23 	nrfx_err_t res;
24 
25 	res = nrfx_gpiote_channel_alloc(gpiote, &ch);
26 	if (res != NRFX_SUCCESS) {
27 		return -ENODEV;
28 	}
29 
30 	res = nrfx_gpiote_input_configure(gpiote, wake_pin, &input_config);
31 	if (res != NRFX_SUCCESS) {
32 		nrfx_gpiote_channel_free(gpiote, ch);
33 		return -EIO;
34 	}
35 
36 	return 0;
37 }
38 
spi_nrfx_wake_request(const nrfx_gpiote_t * gpiote,uint32_t wake_pin)39 int spi_nrfx_wake_request(const nrfx_gpiote_t *gpiote, uint32_t wake_pin)
40 {
41 	nrf_gpiote_event_t trigger_event = nrfx_gpiote_in_event_get(gpiote, wake_pin);
42 	uint32_t start_cycles;
43 	uint32_t max_wait_cycles =
44 		DIV_ROUND_UP(CONFIG_SPI_NRFX_WAKE_TIMEOUT_US *
45 				 CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC,
46 			     1000000);
47 	int err = 0;
48 
49 	/* Enable the trigger (a high-to-low transition) without its interrupt.
50 	 * The expected time to wait is quite short so it is not worth paying
51 	 * the overhead of context switching to handle the interrupt.
52 	 */
53 	nrfx_gpiote_trigger_enable(gpiote, wake_pin, false);
54 	/* Enable pull-up on the WAKE line. After the slave device sees the
55 	 * WAKE line going high, it will force the line to go low. This will
56 	 * be caught by the enabled trigger and the loop below waits for that.
57 	 */
58 	nrf_gpio_cfg_input(wake_pin, NRF_GPIO_PIN_PULLUP);
59 
60 	start_cycles = k_cycle_get_32();
61 	while (!nrf_gpiote_event_check(gpiote->p_reg, trigger_event)) {
62 		uint32_t elapsed_cycles = k_cycle_get_32() - start_cycles;
63 
64 		if (elapsed_cycles >= max_wait_cycles) {
65 			err = -ETIMEDOUT;
66 			break;
67 		}
68 	}
69 
70 	nrfx_gpiote_trigger_disable(gpiote, wake_pin);
71 	nrf_gpio_cfg_input(wake_pin, NRF_GPIO_PIN_PULLDOWN);
72 
73 	return err;
74 }
75