From aa4feeed4d1dca61b91272a24d398ed35ef49792 Mon Sep 17 00:00:00 2001 From: hyx0329 Date: Sun, 25 Jun 2023 13:06:17 +0800 Subject: [PATCH] feat(shields): M60 keyboard use back button as power switch --- app/boards/shields/m60/CMakeLists.txt | 3 ++ app/boards/shields/m60/pinmux.c | 66 +++++++++++++++++++++++++++ 2 files changed, 69 insertions(+) create mode 100644 app/boards/shields/m60/CMakeLists.txt create mode 100644 app/boards/shields/m60/pinmux.c diff --git a/app/boards/shields/m60/CMakeLists.txt b/app/boards/shields/m60/CMakeLists.txt new file mode 100644 index 00000000..05214a68 --- /dev/null +++ b/app/boards/shields/m60/CMakeLists.txt @@ -0,0 +1,3 @@ +zephyr_library() +zephyr_library_sources(pinmux.c) +zephyr_library_include_directories(${ZEPHYR_BASE}/drivers) \ No newline at end of file diff --git a/app/boards/shields/m60/pinmux.c b/app/boards/shields/m60/pinmux.c new file mode 100644 index 00000000..74d64540 --- /dev/null +++ b/app/boards/shields/m60/pinmux.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2024 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#include +#include +#include +#include +#include +#include + +/* The PMU(BQ24075) enable pin(LOW active) on M60 is controlled by a NAND gate. + * Partial reverse engineering shows: + * P0.28 affects the NAND gate. + * The button affects P0.27 the NAND gate. + * P0.03 is detection pin for charging state(possibly attached to PMU LED pin). + */ + +static const struct device *p0 = DEVICE_DT_GET(DT_NODELABEL(gpio0)); + +static inline void power_off(void) { + gpio_pin_set(p0, 28, 0); // turn off the PMU battery path +} + +static inline bool is_charging(void) { + // 0: charging + return gpio_pin_get_raw(p0, 3) == 0; +} + +static void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins) { + // wait the button stable at 0 so the keyboard won't be powered up accidentally + k_sleep(K_SECONDS(1)); + + if (!is_charging()) { + power_off(); + } +} + +static int pinmux_nrf52840_m2_init(void) { + // back button + // NOTE: if used to power off the keyboard, make sure the action is done + // AFTER the button is released. + // + // To wake up the keyboard from sleep with this button, must use interrupt. + // To avoid the callback triggered after keyboard woke up(powering off the + // keyboard), must use GPIO_INT_EDGE_FALLING(trigger on button pressed). + gpio_pin_interrupt_configure(p0, 27, GPIO_INT_EDGE_FALLING); + + // GPIO 0.28(LDO control) is already configured by bootloader, + // so configuring it here is just an ensurance. + gpio_pin_configure(p0, 28, GPIO_OUTPUT_ACTIVE | GPIO_PULL_UP | GPIO_OPEN_DRAIN); + + // this is the pin for charging detection + gpio_pin_configure(p0, 3, GPIO_INPUT | GPIO_PULL_UP); + + // setup the interrupt handler to poweroff the keyboard + static struct gpio_callback button_cb; + gpio_init_callback(&button_cb, button_pressed, BIT(27)); + gpio_add_callback(p0, &button_cb); + + return 0; +} + +SYS_INIT(pinmux_nrf52840_m2_init, APPLICATION, CONFIG_APPLICATION_INIT_PRIORITY);