diff --git a/app/drivers/sensor/battery/CMakeLists.txt b/app/drivers/sensor/battery/CMakeLists.txt index 1203e53a6be..2826569ac15 100644 --- a/app/drivers/sensor/battery/CMakeLists.txt +++ b/app/drivers/sensor/battery/CMakeLists.txt @@ -2,6 +2,7 @@ # SPDX-License-Identifier: MIT zephyr_include_directories(.) +zephyr_include_directories(${CMAKE_SOURCE_DIR}/include) zephyr_library() diff --git a/app/drivers/sensor/battery/battery_common.c b/app/drivers/sensor/battery/battery_common.c index 36e98affd1f..5263c759a4f 100644 --- a/app/drivers/sensor/battery/battery_common.c +++ b/app/drivers/sensor/battery/battery_common.c @@ -7,6 +7,10 @@ #include #include +#if CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER +#include +#endif + #include "battery_common.h" int battery_channel_get(const struct battery_value *value, enum sensor_channel chan, @@ -21,6 +25,13 @@ int battery_channel_get(const struct battery_value *value, enum sensor_channel c val_out->val1 = value->state_of_charge; val_out->val2 = 0; break; + + #if CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER + case SENSOR_CHAN_CHARGING: + val_out->val1 = value->charging; + val_out->val2 = 0; + break; + #endif default: return -ENOTSUP; diff --git a/app/drivers/sensor/battery/battery_common.h b/app/drivers/sensor/battery/battery_common.h index d81c39e24d8..7a728a36a9b 100644 --- a/app/drivers/sensor/battery/battery_common.h +++ b/app/drivers/sensor/battery/battery_common.h @@ -13,6 +13,7 @@ struct battery_value { uint16_t adc_raw; uint16_t millivolts; uint8_t state_of_charge; + bool charging; }; int battery_channel_get(const struct battery_value *value, enum sensor_channel chan, diff --git a/app/drivers/sensor/battery/battery_voltage_divider.c b/app/drivers/sensor/battery/battery_voltage_divider.c index 09e5525ec57..7b3bf14f79d 100644 --- a/app/drivers/sensor/battery/battery_voltage_divider.c +++ b/app/drivers/sensor/battery/battery_voltage_divider.c @@ -14,6 +14,7 @@ #include #include "battery_common.h" +#include LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); @@ -30,6 +31,7 @@ struct gpio_channel_config { struct bvd_config { struct io_channel_config io_channel; struct gpio_channel_config power_gpios; + struct gpio_channel_config chg_gpios; uint32_t output_ohm; uint32_t full_ohm; }; @@ -37,6 +39,7 @@ struct bvd_config { struct bvd_data { const struct device *adc; const struct device *gpio; + const struct device *gpio2; struct adc_channel_cfg acc; struct adc_sequence as; struct battery_value value; @@ -48,7 +51,7 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) struct adc_sequence *as = &drv_data->as; // Make sure selected channel is supported - if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE && + if (chan != SENSOR_CHAN_GAUGE_VOLTAGE && chan != SENSOR_CHAN_GAUGE_STATE_OF_CHARGE && chan != SENSOR_CHAN_CHARGING && chan != SENSOR_CHAN_ALL) { LOG_DBG("Selected channel is not supported: %d.", chan); return -ENOTSUP; @@ -100,6 +103,17 @@ static int bvd_sample_fetch(const struct device *dev, enum sensor_channel chan) } } + if (drv_data->gpio2) { + int raw = gpio_pin_get(drv_data->gpio, drv_cfg->chg_gpios.pin); + if(raw == -EIO || raw == -EWOULDBLOCK) { + LOG_DBG("Failed to read chg status: %d", raw); + return raw; + } else { + bool charging = raw; + drv_data->value.charging = charging; + } + } + return rc; } @@ -140,6 +154,21 @@ static int bvd_init(const struct device *dev) { } } + if (drv_cfg->chg_gpios.label) { + drv_data->gpio2 = device_get_binding(drv_cfg->chg_gpios.label); + if (drv_data->gpio2 == NULL) { + LOG_ERR("Failed to get GPIO %s", drv_cfg->chg_gpios.label); + return -ENODEV; + } + rc = gpio_pin_configure(drv_data->gpio2, drv_cfg->chg_gpios.pin, + GPIO_INPUT | drv_cfg->chg_gpios.flags); + if (rc != 0) { + LOG_ERR("Failed to configure input %s.%u: %d", drv_cfg->chg_gpios.label, + drv_cfg->chg_gpios.pin, rc); + return rc; + } + } + drv_data->as = (struct adc_sequence){ .channels = BIT(0), .buffer = &drv_data->value.adc_raw, @@ -181,6 +210,14 @@ static const struct bvd_config bvd_cfg = { DT_INST_GPIO_PIN(0, power_gpios), DT_INST_GPIO_FLAGS(0, power_gpios), }, +#endif +#if DT_INST_NODE_HAS_PROP(0, chg_gpios) + .chg_gpios = + { + DT_INST_GPIO_LABEL(0, chg_gpios), + DT_INST_GPIO_PIN(0, chg_gpios), + DT_INST_GPIO_FLAGS(0, chg_gpios), + }, #endif .output_ohm = DT_INST_PROP(0, output_ohms), .full_ohm = DT_INST_PROP(0, full_ohms), diff --git a/app/drivers/zephyr/dts/bindings/sensor/zmk,battery-voltage-divider.yaml b/app/drivers/zephyr/dts/bindings/sensor/zmk,battery-voltage-divider.yaml index c4c6f80c5e8..f86426b6382 100644 --- a/app/drivers/zephyr/dts/bindings/sensor/zmk,battery-voltage-divider.yaml +++ b/app/drivers/zephyr/dts/bindings/sensor/zmk,battery-voltage-divider.yaml @@ -11,3 +11,7 @@ properties: label: required: true type: string + chg-gpios: + required: false + type: phandle-array + description: "A GPIO pin to report charging state to" \ No newline at end of file diff --git a/app/include/drivers/sensor/battery/battery_voltage_divider.h b/app/include/drivers/sensor/battery/battery_voltage_divider.h new file mode 100644 index 00000000000..45d0cc4b0bd --- /dev/null +++ b/app/include/drivers/sensor/battery/battery_voltage_divider.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022 The ZMK Contributors + * + * SPDX-License-Identifier: MIT + */ + +#ifndef ZEPHYR_INCLUDE_DRIVERS_SENSOR_BATTERY_BATTERY_VOLTAGE_DIVIDER_H_ +#define ZEPHYR_INCLUDE_DRIVERS_SENSOR_BATTERY_BATTERY_VOLTAGE_DIVIDER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum sensor_channel_bvd { + /** Charging state, bool **/ + SENSOR_CHAN_CHARGING = SENSOR_CHAN_PRIV_START, +}; + +#endif \ No newline at end of file diff --git a/app/src/battery.c b/app/src/battery.c index 3f66224126e..2f6c69e1725 100644 --- a/app/src/battery.c +++ b/app/src/battery.c @@ -19,9 +19,15 @@ LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL); #include #include +#if CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER +#include "drivers/sensor/battery/battery_voltage_divider.h" +#endif + static uint8_t last_state_of_charge = 0; +static bool charging = 0; uint8_t zmk_battery_state_of_charge() { return last_state_of_charge; } +bool zmk_battery_charging() { return charging; } #if DT_HAS_CHOSEN(zmk_battery) static const struct device *const battery = DEVICE_DT_GET(DT_CHOSEN(zmk_battery)); @@ -64,6 +70,16 @@ static int zmk_battery_update(const struct device *battery) { (struct zmk_battery_state_changed){.state_of_charge = last_state_of_charge})); } + #if CONFIG_ZMK_BATTERY_VOLTAGE_DIVIDER + struct sensor_value charging_state; + rc = sensor_channel_get(battery, SENSOR_CHAN_CHARGING, &charging_state); + if (rc != 0) { + LOG_DBG("Failed to get battery charging status: %d", rc); + return rc; + } + charging = charging_state.val1; + #endif + return rc; }