Browse Source
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_powerxmkb
Mega Mind
4 years ago
13 changed files with 255 additions and 12 deletions
@ -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 |
||||||
|
|
@ -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> |
@ -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) */ |
Loading…
Reference in new issue