Browse Source

Added driver to control the external power output

This PR adds support to control the external power output from controllers like nice!nano, nRFMicro etc

I have implemented based on my understanding of Pete suggestion on this feature.

Testing done:

    Tested by enabling and disabling the ext_power from application and verified
    Verified the application does not crash with boards that does not have ext_power support
    Note:
    I did not test this in nice!nano since I don't have the boards. Will get help from others once the behavior PR is up

Next Steps:

    Create a behavior PR to control enable/disable ext_power
xmkb
Mega Mind 4 years ago
parent
commit
4d81b10ba7
  1. 1
      app/CMakeLists.txt
  2. 4
      app/Kconfig
  3. 5
      app/boards/arm/nice_nano/nice_nano.dts
  4. 5
      app/boards/arm/nrfmicro/nrfmicro_11.dts
  5. 5
      app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts
  6. 5
      app/boards/arm/nrfmicro/nrfmicro_13.dts
  7. 11
      app/boards/arm/nrfmicro/pinmux.c
  8. 2
      app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml
  9. 20
      app/dts/bindings/zmk,ext-power-generic.yaml
  10. 5
      app/dts/bindings/zmk,keymap-sensors.yaml
  11. 104
      app/include/drivers/ext_power.h
  12. 91
      app/src/ext_power_generic.c
  13. 9
      app/src/main.c

1
app/CMakeLists.txt

@ -31,6 +31,7 @@ target_sources(app PRIVATE src/sensors.c)
target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c) target_sources_ifdef(CONFIG_ZMK_DISPLAY app PRIVATE src/display.c)
target_sources(app PRIVATE src/event_manager.c) target_sources(app PRIVATE src/event_manager.c)
target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c) target_sources_ifdef(CONFIG_ZMK_BLE app PRIVATE src/ble_unpair_combo.c)
target_sources_ifdef(CONFIG_ZMK_EXT_POWER app PRIVATE src/ext_power_generic.c)
target_sources(app PRIVATE src/events/position_state_changed.c) target_sources(app PRIVATE src/events/position_state_changed.c)
target_sources(app PRIVATE src/events/keycode_state_changed.c) target_sources(app PRIVATE src/events/keycode_state_changed.c)
target_sources(app PRIVATE src/events/modifiers_state_changed.c) target_sources(app PRIVATE src/events/modifiers_state_changed.c)

4
app/Kconfig

@ -95,6 +95,10 @@ config ZMK_IDLE_SLEEP_TIMEOUT
endif endif
config ZMK_EXT_POWER
bool "Enable support to control external power output"
default y
config ZMK_DISPLAY config ZMK_DISPLAY
bool "ZMK display support" bool "ZMK display support"
default n default n

5
app/boards/arm/nice_nano/nice_nano.dts

@ -29,6 +29,11 @@
}; };
}; };
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
control-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>;
};
}; };
&gpiote { &gpiote {

5
app/boards/arm/nrfmicro/nrfmicro_11.dts

@ -26,6 +26,11 @@
}; };
}; };
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
};
}; };
&gpio0 { &gpio0 {

5
app/boards/arm/nrfmicro/nrfmicro_11_flipped.dts

@ -26,6 +26,11 @@
}; };
}; };
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
control-gpios = <&gpio1 9 GPIO_ACTIVE_HIGH>;
};
}; };
&gpio0 { &gpio0 {

5
app/boards/arm/nrfmicro/nrfmicro_13.dts

@ -26,6 +26,11 @@
}; };
}; };
ext-power {
compatible = "zmk,ext-power-generic";
label = "EXT_POWER";
control-gpios = <&gpio1 9 GPIO_ACTIVE_LOW>;
};
}; };
&gpio0 { &gpio0 {

11
app/boards/arm/nrfmicro/pinmux.c

@ -14,25 +14,14 @@
static int pinmux_nrfmicro_init(struct device *port) { static int pinmux_nrfmicro_init(struct device *port) {
ARG_UNUSED(port); ARG_UNUSED(port);
struct device *p1 = device_get_binding("GPIO_1");
#if CONFIG_BOARD_NRFMICRO_13 #if CONFIG_BOARD_NRFMICRO_13
struct device *p0 = device_get_binding("GPIO_0"); struct device *p0 = device_get_binding("GPIO_0");
// enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1)
gpio_pin_configure(p1, 9, GPIO_OUTPUT);
gpio_pin_set(p1, 9, 0);
#if CONFIG_BOARD_NRFMICRO_CHARGER #if CONFIG_BOARD_NRFMICRO_CHARGER
gpio_pin_configure(p0, 5, GPIO_OUTPUT); gpio_pin_configure(p0, 5, GPIO_OUTPUT);
gpio_pin_set(p0, 5, 0); gpio_pin_set(p0, 5, 0);
#else #else
gpio_pin_configure(p0, 5, GPIO_INPUT); gpio_pin_configure(p0, 5, GPIO_INPUT);
#endif #endif
#else
// enable EXT_VCC (use 0 for nRFMicro 1.3, use 1 for nRFMicro 1.1)
gpio_pin_configure(p1, 9, GPIO_OUTPUT);
gpio_pin_set(p1, 9, 1);
#endif #endif
return 0; return 0;
} }

2
app/dts/bindings/behaviors/zmk,behavior-sensor-rotate-key-press.yaml

@ -1,4 +1,4 @@
# Copyright (c) 2020, Pete Johanson # Copyright (c) 2020, The ZMK Contributors
# SPDX-License-Identifier: MIT # SPDX-License-Identifier: MIT
description: Sensor rotate key press/release behavior description: Sensor rotate key press/release behavior

20
app/dts/bindings/zmk,ext-power-generic.yaml

@ -0,0 +1,20 @@
#
# Copyright (c) 2020, The ZMK Contributors
# SPDX-License-Identifier: MIT
#
description: |
Generic driver for controlling the external power output
by toggling the control-gpio pin status
(Only in supported hardware)
compatible: "zmk,ext-power-generic"
properties:
control-gpios:
type: phandle-array
required: true
label:
type: string
required: true

5
app/dts/bindings/zmk,keymap-sensors.yaml

@ -1,3 +1,8 @@
#
# Copyright (c) 2020, The ZMK Contributors
# SPDX-License-Identifier: MIT
#
description: | description: |
Allows defining the collection of sensors bound in the keymap layers Allows defining the collection of sensors bound in the keymap layers

104
app/include/drivers/ext_power.h

@ -0,0 +1,104 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <zephyr/types.h>
#include <stddef.h>
#include <device.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @cond INTERNAL_HIDDEN
*
* Behavior driver API definition and system call entry points.
*
* (Internal use only.)
*/
typedef int (*ext_power_enable_t)(struct device *dev);
typedef int (*ext_power_disable_t)(struct device *dev);
typedef int (*ext_power_get_t)(struct device *dev);
__subsystem struct ext_power_api {
ext_power_enable_t enable;
ext_power_disable_t disable;
ext_power_get_t get;
};
/**
* @endcond
*/
/**
* @brief Enable the external power output
* @param dev Pointer to the device structure for the driver instance.
*
* @retval 0 If successful.
* @retval Negative errno code if failure.
*/
__syscall int ext_power_enable(struct device *dev);
static inline int z_impl_ext_power_enable(struct device *dev) {
const struct ext_power_api *api = (const struct ext_power_api *)dev->driver_api;
if (api->enable == NULL) {
return -ENOTSUP;
}
return api->enable(dev);
}
/**
* @brief Disable the external power output
* @param dev Pointer to the device structure for the driver instance.
*
* @retval 0 If successful.
* @retval Negative errno code if failure.
*/
__syscall int ext_power_disable(struct device *dev);
static inline int z_impl_ext_power_disable(struct device *dev) {
const struct ext_power_api *api = (const struct ext_power_api *)dev->driver_api;
if (api->disable == NULL) {
return -ENOTSUP;
}
return api->disable(dev);
}
/**
* @brief Get the current status of the external power output
* @param dev Pointer to the device structure for the driver instance.
*
* @retval 0 If ext power is disabled.
* @retval 1 if ext power is enabled.
* @retval Negative errno code if failure.
*/
__syscall int ext_power_get(struct device *dev);
static inline int z_impl_ext_power_get(struct device *dev) {
const struct ext_power_api *api = (const struct ext_power_api *)dev->driver_api;
if (api->get == NULL) {
return -ENOTSUP;
}
return api->get(dev);
}
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#include <syscalls/ext_power.h>

91
app/src/ext_power_generic.c

@ -0,0 +1,91 @@
/*
* Copyright (c) 2020 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT zmk_ext_power_generic
#include <device.h>
#include <init.h>
#include <drivers/gpio.h>
#include <drivers/ext_power.h>
#if DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT)
#include <logging/log.h>
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
struct ext_power_generic_config {
const char *label;
const u8_t pin;
const u8_t flags;
};
struct ext_power_generic_data {
struct device *gpio;
bool status;
};
static int ext_power_generic_enable(struct device *dev) {
struct ext_power_generic_data *data = dev->driver_data;
const struct ext_power_generic_config *config = dev->config_info;
if (gpio_pin_set(data->gpio, config->pin, 1)) {
LOG_WRN("Failed to set ext-power control pin");
return -EIO;
}
data->status = true;
return 0;
}
static int ext_power_generic_disable(struct device *dev) {
struct ext_power_generic_data *data = dev->driver_data;
const struct ext_power_generic_config *config = dev->config_info;
if (gpio_pin_set(data->gpio, config->pin, 0)) {
LOG_WRN("Failed to clear ext-power control pin");
return -EIO;
}
data->status = false;
return 0;
}
static int ext_power_generic_get(struct device *dev) {
struct ext_power_generic_data *data = dev->driver_data;
return data->status;
}
static int ext_power_generic_init(struct device *dev) {
struct ext_power_generic_data *data = dev->driver_data;
const struct ext_power_generic_config *config = dev->config_info;
data->gpio = device_get_binding(config->label);
if (data->gpio == NULL) {
LOG_ERR("Failed to get ext-power control device");
return -EINVAL;
}
if (gpio_pin_configure(data->gpio, config->pin, config->flags | GPIO_OUTPUT)) {
LOG_ERR("Failed to configure ext-power control pin");
return -EIO;
}
return 0;
}
static const struct ext_power_generic_config config = {
.label = DT_INST_GPIO_LABEL(0, control_gpios),
.pin = DT_INST_GPIO_PIN(0, control_gpios),
.flags = DT_INST_GPIO_FLAGS(0, control_gpios)};
static struct ext_power_generic_data data = {.status = false};
static const struct ext_power_api api = {.enable = ext_power_generic_enable,
.disable = ext_power_generic_disable,
.get = ext_power_generic_get};
DEVICE_AND_API_INIT(ext_power_generic, DT_INST_LABEL(0), ext_power_generic_init, &data, &config,
APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &api);
#endif /* DT_HAS_COMPAT_STATUS_OKAY(DT_DRV_COMPAT) */

9
app/src/main.c

@ -15,16 +15,25 @@ LOG_MODULE_REGISTER(zmk, CONFIG_ZMK_LOG_LEVEL);
#include <zmk/matrix.h> #include <zmk/matrix.h>
#include <zmk/kscan.h> #include <zmk/kscan.h>
#include <zmk/display.h> #include <zmk/display.h>
#include <drivers/ext_power.h>
#define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID) #define ZMK_KSCAN_DEV DT_LABEL(ZMK_MATRIX_NODE_ID)
void main(void) { void main(void) {
struct device *ext_power;
LOG_INF("Welcome to ZMK!\n"); LOG_INF("Welcome to ZMK!\n");
if (zmk_kscan_init(ZMK_KSCAN_DEV) != 0) { if (zmk_kscan_init(ZMK_KSCAN_DEV) != 0) {
return; return;
} }
// Enable the external VCC output
ext_power = device_get_binding("EXT_POWER");
if (ext_power != NULL) {
const struct ext_power_api *ext_power_api = ext_power->driver_api;
ext_power_api->enable(ext_power);
}
#ifdef CONFIG_ZMK_DISPLAY #ifdef CONFIG_ZMK_DISPLAY
zmk_display_init(); zmk_display_init();

Loading…
Cancel
Save