This is an automated email from the ASF dual-hosted git repository.

jerzy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 49a09e53045c7aa74c75d5bd8ccecccea602c493
Author: Jerzy Kasenberg <jerzy.kasenb...@codecoup.pl>
AuthorDate: Thu Apr 25 16:08:38 2019 +0200

    da1469x_charger: Add charger for DA1469x
    
    This adds basic charger functionality.
    Shell command is also added.
---
 .../include/da1469x_charger/da1469x_charger.h      |  269 +++++
 hw/drivers/chg_ctrl/da1469x_charger/pkg.yml        |   30 +
 .../chg_ctrl/da1469x_charger/src/da1469x_charger.c |  508 +++++++++
 .../da1469x_charger/src/da1469x_charger_shell.c    | 1202 ++++++++++++++++++++
 hw/drivers/chg_ctrl/da1469x_charger/syscfg.yml     |   76 ++
 5 files changed, 2085 insertions(+)

diff --git 
a/hw/drivers/chg_ctrl/da1469x_charger/include/da1469x_charger/da1469x_charger.h 
b/hw/drivers/chg_ctrl/da1469x_charger/include/da1469x_charger/da1469x_charger.h
new file mode 100644
index 0000000..7fbd8a2
--- /dev/null
+++ 
b/hw/drivers/chg_ctrl/da1469x_charger/include/da1469x_charger/da1469x_charger.h
@@ -0,0 +1,269 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef _DA1469X_CHARGER_H
+#define _DA1469X_CHARGER_H
+
+#include <os/os.h>
+#include "os/os_dev.h"
+#include "syscfg/syscfg.h"
+#include "os/os_time.h"
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+#include "charge-control/charge_control.h"
+#endif
+
+struct da1469x_charger_config {
+    uint32_t ctrl_valid:1;
+    uint32_t voltage_param_valid:1;
+    uint32_t current_param_valid:1;
+    uint32_t tempset_param_valid:1;
+    uint32_t pre_charge_timer_valid:1;
+    uint32_t cc_charge_timer_valid:1;
+    uint32_t cv_charge_timer_valid:1;
+    uint32_t total_charge_timer_valid:1;
+    uint32_t jeita_v_charge_valid:1;
+    uint32_t jeita_v_precharge_valid:1;
+    uint32_t jeita_v_replenish_valid:1;
+    uint32_t jeita_v_ovp_valid:1;
+    uint32_t jeita_current_valid:1;
+    uint32_t vbat_comp_timer_valid:1;
+    uint32_t vovp_comp_timer_valid:1;
+    uint32_t tdie_comp_timer_valid:1;
+    uint32_t tbat_mon_timer_valid:1;
+    uint32_t tbat_comp_timer_valid:1;
+    uint32_t thot_comp_timer_valid:1;
+    uint32_t pwr_up_timer_valid:1;
+
+    uint32_t ctrl;
+    uint32_t voltage_param;
+    uint32_t current_param;
+    uint32_t tempset_param;
+    uint16_t pre_charge_timer;
+    uint16_t cc_charge_timer;
+    uint16_t cv_charge_timer;
+    uint16_t total_charge_timer;
+    uint16_t jeita_v_charge;
+    uint16_t jeita_v_precharge;
+    uint16_t jeita_v_replenish;
+    uint16_t jeita_v_ovp;
+    uint32_t jeita_current;
+    uint16_t vbat_comp_timer;
+    uint16_t vovp_comp_timer;
+    uint16_t tdie_comp_timer;
+    uint16_t tbat_mon_timer;
+    uint16_t tbat_comp_timer;
+    uint16_t thot_comp_timer;
+    uint16_t pwr_up_timer;
+};
+
+struct da1469x_charger_dev {
+    struct os_dev dev;
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+    struct charge_control   chg_ctrl;
+#endif
+};
+
+#define DA1469X_ENCODE_V(v) \
+    (((v) < 3800) ? (((v) - 2800) / 50) : \
+                    (((v) < 4600) ? ((v) - 3800) / 20 + 20 : \
+                                    ((v) - 4600) / 100 + 60))
+
+#define DA1469X_ENCODE_CHG_I(i) \
+    (uint16_t)(((i) < 85) ? ((i) / 5) - 1 : \
+                  ((i) < 250 ? ((i) / 10) - 8 + 15 : \
+                               ((i) / 20) - 12 + 31))
+
+#define DA1469X_ENCODE_PRECHG_I(i) \
+    ((uint16_t)((i) < 9 ? (i) * 2 - 1 : \
+                (i) < 25 ? (i) - 8 + 15 : \
+                           (i) / 2 - 12 + 31) << \
+        CHARGER_CHARGER_CURRENT_PARAM_REG_I_PRECHARGE_Pos)
+
+#define DA1469X_ENCODE_EOC_I(i) \
+    ((uint16_t)((i) <= 10 ? ((i) - 4) * 2 / 3 : \
+                    (i) < 18 ? 4 + ((i) - 10) / 2 : \
+                    ((((i) - 12) / 4) + 8)) << \
+        CHARGER_CHARGER_CURRENT_PARAM_REG_I_END_OF_CHARGE_Pos)
+
+typedef enum {
+    DA1469X_CHARGER_STATE_POWER_UP,
+    DA1469X_CHARGER_STATE_INIT,
+    DA1469X_CHARGER_STATE_DISABLED,
+    DA1469X_CHARGER_STATE_PRE_CHARGE,
+    DA1469X_CHARGER_STATE_CC_CHARGE,
+    DA1469X_CHARGER_STATE_CV_CHARGE,
+    DA1469X_CHARGER_STATE_END_OF_CHARGE,
+    DA1469X_CHARGER_STATE_TDIE_PROT,
+    DA1469X_CHARGER_STATE_TBAT_PROT,
+    DA1469X_CHARGER_STATE_BYPASS,
+    DA1469X_CHARGER_STATE_ERROR,
+} da1469x_charger_state_t;
+
+typedef enum {
+    DA1469X_CHARGER_STATE_IRQ_NONE                      = 0x0000U,
+    DA1469X_CHARGER_STATE_IRQ_DISABLED_TO_PRECHARGE     = 0x0001U,
+    DA1469X_CHARGER_STATE_IRQ_PRECHARGE_TO_CC           = 0x0002U,
+    DA1469X_CHARGER_STATE_IRQ_CC_TO_CV                  = 0x0004U,
+    DA1469X_CHARGER_STATE_IRQ_CC_TO_EOC                 = 0x0008U,
+    DA1469X_CHARGER_STATE_IRQ_CV_TO_EOC                 = 0x0010U,
+    DA1469X_CHARGER_STATE_IRQ_EOC_TO_PRECHARGE          = 0x0020U,
+    DA1469X_CHARGER_STATE_IRQ_TDIE_PROT_TO_PRECHARGE    = 0x0040U,
+    DA1469X_CHARGER_STATE_IRQ_TBAT_PROT_TO_PRECHARGE    = 0x0080U,
+    DA1469X_CHARGER_STATE_IRQ_TBAT_STATUS_UPDATE        = 0x0100U,
+    DA1469X_CHARGER_STATE_IRQ_CV_TO_CC                  = 0x0200U,
+    DA1469X_CHARGER_STATE_IRQ_CC_TO_PRECHARGE           = 0x0400U,
+    DA1469X_CHARGER_STATE_IRQ_CV_TO_PRECHARGE           = 0x0800U,
+    DA1469X_CHARGER_STATE_IRQ_ALL                       = 0x0FFFU,
+} da1469x_charger_state_irq_t;
+
+typedef enum {
+    DA1469X_CHARGER_ERROR_IRQ_NONE                      = 0x00U,
+    DA1469X_CHARGER_ERROR_IRQ_PRECHARGE_TIMEOUT         = 0x01U,
+    DA1469X_CHARGER_ERROR_IRQ_CC_CHARGE_TIMEOUT         = 0x02U,
+    DA1469X_CHARGER_ERROR_IRQ_CV_CHARGE_TIMEOUT         = 0x04U,
+    DA1469X_CHARGER_ERROR_IRQ_TOTAL_CHARGE_TIMEOUT      = 0x08U,
+    DA1469X_CHARGER_ERROR_IRQ_VBAT_OVP_ERROR            = 0x10U,
+    DA1469X_CHARGER_ERROR_IRQ_TDIE_ERROR                = 0x20U,
+    DA1469X_CHARGER_ERROR_IRQ_TBAT_ERROR                = 0x40U,
+    DA1469X_CHARGER_ERROR_IRQ_ALL                       = 0x7FU,
+} da1469x_charger_error_irq_t;
+
+/**
+* Set charge currents
+*
+* @param dev the charger device
+* @param ichg charge current (5-560) mA
+* @param iprechg pre-charge current (1-56) mA
+* @param ieoc end-of-charge (percent of charge current 4-40)
+*
+* @return 0 - on success, SYS_EINVAL for invalid parameters
+*/
+int da1469x_charger_set_charge_currents(struct da1469x_charger_dev *dev,
+                                        uint16_t ichg, uint16_t iprechg,
+                                        uint8_t ieoc);
+
+/**
+* Set charge voltages
+*
+* @note: All voltage levels must be in 2800-4900 mV range
+*
+* @param dev the charger device
+* @param vchrg charge voltage threshold
+* @param vprechg pre-charge voltage threshold
+* @param vreplenish recharge voltage threshold
+* @param ov over voltage protection limit
+*
+* @return  0 - on success, SYS_EINVAL for invalid parameters
+*/
+int da1469x_charger_set_charge_voltages(struct da1469x_charger_dev *dev,
+                                        uint16_t vchrg, uint16_t vprechg,
+                                        uint16_t vreplenish, uint16_t ov);
+
+
+/**
+* Set charger configuration
+*
+* @param dev charger device
+* @param config new configuration to set
+*
+* @return  0 - on success, SYS_EINVAL for invalid parameters
+*/
+int da1469x_charger_set_config(struct da1469x_charger_dev *dev,
+                               const struct da1469x_charger_config *config);
+
+/**
+ * Set state change interrupt mask
+ *
+ * Interrupt will be trigger on each state change transition.
+ *
+ * @param dev charger device
+ * @param mask new bit mask of enabled state change interrupts
+ *             value should be a bitmask from da1469x_charger_state_irq_t
+ *
+ * @return  0 - on success, SYS_EINVAL for invalid parameters
+ */
+int da1469x_charger_set_state_change_irq_mask(struct da1469x_charger_dev *dev,
+                                              uint16_t mask);
+
+/**
+ * Set error interrupt mask
+ *
+ * @param dev charger device
+ * @param mask new bit mask of enabled error interrupts
+ *             value should be a bitmask from da1469x_charger_error_irq_t
+ *
+ * @return  0 - on success, SYS_EINVAL for invalid parameters
+ */
+int da1469x_charger_set_error_irq_mask(struct da1469x_charger_dev *dev,
+                                       uint16_t mask);
+
+static inline da1469x_charger_state_t
+da1469x_charger_get_state(struct da1469x_charger_dev *dev)
+{
+    return (da1469x_charger_state_t)((CHARGER->CHARGER_STATUS_REG &
+         CHARGER_CHARGER_STATUS_REG_CHARGER_STATE_Msk) >>
+                             CHARGER_CHARGER_STATUS_REG_CHARGER_STATE_Pos);
+}
+
+/**
+ * Function called from os_dev_create
+ *
+ * @note: In normal case use wrapper function da1469x_charger_create()
+ *
+ * @param dev ad1469x_charger_dev to initialize
+ * @param arg da1469x_charger_config initial configuration
+ *
+ * @return  0 - on success, SYS_EINVAL for invalid parameters
+ */
+int da1469x_charger_init(struct os_dev *dev, void *arg);
+
+/**
+ *
+ * @param dev ad1469x_charger_dev to initialize
+ * @param name device name to create
+ * @param cfg da1469x_charger_config initial configuration
+ * @return
+ */
+int da1469x_charger_create(struct da1469x_charger_dev *dev, const char *name,
+                           struct da1469x_charger_config *cfg);
+
+
+/**
+ * Function enable charging.
+ *
+ * @param dev ad1469x_charger_dev
+ *
+ * @return  0 - on success, non-zero on failure
+ */
+int da1469x_charger_charge_enable(struct da1469x_charger_dev *dev);
+
+/**
+ * Function disables charging.
+ *
+ * @param dev ad1469x_charger_dev
+ *
+ * @return  0 - on success, non-zero on failure
+ */
+int da1469x_charger_charge_disable(struct da1469x_charger_dev *dev);
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI)
+int da1469x_charger_shell_init(struct da1469x_charger_dev *dev);
+#endif
+
+#endif /* _DA1469X_CHARGER_H */
diff --git a/hw/drivers/chg_ctrl/da1469x_charger/pkg.yml 
b/hw/drivers/chg_ctrl/da1469x_charger/pkg.yml
new file mode 100644
index 0000000..098bfad
--- /dev/null
+++ b/hw/drivers/chg_ctrl/da1469x_charger/pkg.yml
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+pkg.name: hw/drivers/chg_ctrl/da1469x_charger
+pkg.description: 
+pkg.keywords:
+    - Charge Controller
+    - DA1469x
+
+pkg.deps:
+    - "@apache-mynewt-core/kernel/os"
+    - "@apache-mynewt-core/hw/hal"
+pkg.deps.DA1469X_CHARGER_USE_CHARGE_CONTROL:
+    - '@apache-mynewt-core/hw/charge-control'
diff --git a/hw/drivers/chg_ctrl/da1469x_charger/src/da1469x_charger.c 
b/hw/drivers/chg_ctrl/da1469x_charger/src/da1469x_charger.c
new file mode 100644
index 0000000..3f17bd1
--- /dev/null
+++ b/hw/drivers/chg_ctrl/da1469x_charger/src/da1469x_charger.c
@@ -0,0 +1,508 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <os/mynewt.h>
+#include <da1469x_charger/da1469x_charger.h>
+#include <bsp/bsp.h>
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+#include <charge-control/charge_control.h>
+#include <DA1469xAB.h>
+#endif
+
+int
+da1469x_charger_set_charge_currents(struct da1469x_charger_dev *dev,
+                            uint16_t ichg, uint16_t iprechg, uint8_t ieoc)
+{
+    uint16_t current_param;
+
+    if (dev == NULL || ichg < 5 || ichg > 560 || iprechg < 1 || iprechg > 56 ||
+        ieoc < 6 || ieoc > 40) {
+        return SYS_EINVAL;
+    }
+
+    /* Charge current */
+    current_param = DA1469X_ENCODE_CHG_I(ichg);
+
+    /* Pre-charge current */
+    current_param |= DA1469X_ENCODE_PRECHG_I(iprechg);
+
+    /* End of charge current as % of charge current */
+    current_param |= DA1469X_ENCODE_EOC_I(ieoc);
+
+    CHARGER->CHARGER_CURRENT_PARAM_REG = current_param;
+
+    return 0;
+}
+
+static inline bool
+bad_v(uint16_t v)
+{
+    return v < 2800 || v > 4900;
+}
+
+static uint16_t
+encode_v(uint16_t v)
+{
+    return (uint16_t)DA1469X_ENCODE_V(v);
+}
+
+int
+da1469x_charger_set_charge_voltages(struct da1469x_charger_dev *dev,
+                                    uint16_t vchrg, uint16_t vprechg,
+                                    uint16_t vreplenish, uint16_t ov)
+{
+    uint16_t voltage_param;
+
+    if (dev == NULL || bad_v(vchrg) || bad_v(vprechg) || bad_v(vreplenish) ||
+        bad_v(ov)) {
+        return SYS_EINVAL;
+    }
+
+    voltage_param = encode_v(vchrg) |
+        (encode_v(vprechg) << 
CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_PRECHARGE_Pos) |
+        (encode_v(vreplenish) << 
CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_REPLENISH_Pos) |
+        (encode_v(ov) << CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_OVP_Pos);
+
+    CHARGER->CHARGER_VOLTAGE_PARAM_REG = voltage_param;
+
+    return 0;
+}
+
+#define SET_IF_VALID(reg_name, field_name) \
+    if (config->field_name##_valid) { \
+        CHARGER->CHARGER_##reg_name##_REG = config->field_name; \
+    }
+
+int
+da1469x_charger_set_config(struct da1469x_charger_dev *dev,
+                           const struct da1469x_charger_config *config)
+{
+    (void)dev;
+
+    SET_IF_VALID(CTRL, ctrl);
+    SET_IF_VALID(VOLTAGE_PARAM, voltage_param);
+    SET_IF_VALID(CURRENT_PARAM, current_param);
+    SET_IF_VALID(TEMPSET_PARAM, tempset_param);
+    SET_IF_VALID(PRE_CHARGE_TIMER, pre_charge_timer);
+    SET_IF_VALID(CC_CHARGE_TIMER, cc_charge_timer);
+    SET_IF_VALID(CV_CHARGE_TIMER, cv_charge_timer);
+    SET_IF_VALID(JEITA_V_CHARGE, jeita_v_charge);
+    SET_IF_VALID(JEITA_V_PRECHARGE, jeita_v_precharge);
+    SET_IF_VALID(JEITA_V_REPLENISH, jeita_v_replenish);
+    SET_IF_VALID(JEITA_V_OVP, jeita_v_ovp);
+    SET_IF_VALID(JEITA_CURRENT, jeita_current);
+    SET_IF_VALID(VBAT_COMP_TIMER, vbat_comp_timer);
+    SET_IF_VALID(VOVP_COMP_TIMER, vovp_comp_timer);
+    SET_IF_VALID(TDIE_COMP_TIMER, tdie_comp_timer);
+    SET_IF_VALID(TBAT_MON_TIMER, tbat_mon_timer);
+    SET_IF_VALID(TBAT_COMP_TIMER, tbat_comp_timer);
+    SET_IF_VALID(THOT_COMP_TIMER, thot_comp_timer);
+    SET_IF_VALID(PWR_UP_TIMER, pwr_up_timer);
+
+    return 0;
+}
+
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+static void
+da1469x_vbus_state_changed_event_cb(struct os_event *ev)
+{
+    assert(ev);
+    NVIC_SetPendingIRQ(CHARGER_STATE_IRQn);
+}
+
+static struct os_event da1469x_vbus_state_changed_event = {
+    .ev_cb = da1469x_vbus_state_changed_event_cb,
+};
+
+static void
+da1469x_vbus_isr(void)
+{
+    CRG_TOP->VBUS_IRQ_CLEAR_REG = 1;
+    os_eventq_put(os_eventq_dflt_get(), &da1469x_vbus_state_changed_event);
+}
+
+void da1469x_usb_init(void)
+{
+    NVIC_SetVector(VBUS_IRQn, (uint32_t)da1469x_vbus_isr);
+    CRG_TOP->VBUS_IRQ_CLEAR_REG = 1;
+    NVIC_ClearPendingIRQ(VBUS_IRQn);
+    CRG_TOP->VBUS_IRQ_MASK_REG = 
CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_FALL_Msk |
+                                 
CRG_TOP_VBUS_IRQ_MASK_REG_VBUS_IRQ_EN_RISE_Msk;
+    NVIC_EnableIRQ(VBUS_IRQn);
+}
+
+static void
+da1469x_charger_state_changed_cb(struct os_event *ev)
+{
+    struct da1469x_charger_dev *dev;
+    uint32_t irq_state;
+
+    assert(ev);
+    dev = ev->ev_arg;
+
+    irq_state = CHARGER->CHARGER_STATE_IRQ_STATUS_REG;
+    CHARGER->CHARGER_STATE_IRQ_CLR_REG = irq_state;
+    /* Interrupt generated by charger triggers out of schedule read */
+    charge_control_read(&dev->chg_ctrl, CHARGE_CONTROL_TYPE_STATUS,
+                        NULL, NULL, OS_TIMEOUT_NEVER);
+}
+
+static struct os_event da1469x_charger_state_changed_event = {
+    .ev_cb = da1469x_charger_state_changed_cb,
+};
+
+static void
+da1469x_charger_state_isr(void)
+{
+    os_eventq_put(os_eventq_dflt_get(), &da1469x_charger_state_changed_event);
+}
+
+static void
+da1469x_charger_error_cb(struct os_event *ev)
+{
+    struct da1469x_charger_dev *dev;
+    uint32_t irq_state;
+
+    assert(ev);
+    dev = ev->ev_arg;
+
+    irq_state = CHARGER->CHARGER_ERROR_IRQ_STATUS_REG;
+    CHARGER->CHARGER_ERROR_IRQ_CLR_REG = irq_state;
+
+    /* Interrupt generated by charger triggers out of schedule read */
+    charge_control_read(&dev->chg_ctrl, CHARGE_CONTROL_TYPE_FAULT,
+                        NULL, NULL, OS_TIMEOUT_NEVER);
+}
+
+static struct os_event da1469x_charger_error_event = {
+    .ev_cb = da1469x_charger_error_cb,
+};
+
+static void
+da1469x_charger_error_isr(void)
+{
+    os_eventq_put(os_eventq_dflt_get(), &da1469x_charger_error_event);
+}
+#endif
+
+void
+da1469x_charger_clock_enable(struct da1469x_charger_dev *dev)
+{
+    (void)dev;
+
+    CRG_SYS->CLK_SYS_REG |= CRG_SYS_CLK_SYS_REG_CLK_CHG_EN_Msk;
+}
+
+void
+da1469x_charger_clock_disable(struct da1469x_charger_dev *dev)
+{
+    (void)dev;
+
+    CRG_SYS->CLK_SYS_REG &= ~CRG_SYS_CLK_SYS_REG_CLK_CHG_EN_Msk;
+}
+
+int
+da1469x_charger_charge_enable(struct da1469x_charger_dev *dev)
+{
+    const uint32_t mask = CHARGER_CHARGER_CTRL_REG_CHARGER_ENABLE_Msk |
+                          CHARGER_CHARGER_CTRL_REG_CHARGE_START_Msk;
+    da1469x_charger_clock_enable(dev);
+    if ((CHARGER->CHARGER_CTRL_REG & mask) != mask) {
+        CHARGER->CHARGER_CTRL_REG |= mask;
+    }
+
+    return 0;
+}
+
+int
+da1469x_charger_charge_disable(struct da1469x_charger_dev *dev)
+{
+    const uint32_t mask = CHARGER_CHARGER_CTRL_REG_CHARGER_ENABLE_Msk |
+                          CHARGER_CHARGER_CTRL_REG_CHARGE_START_Msk;
+    (void)dev;
+
+    if ((CHARGER->CHARGER_CTRL_REG & mask) != 0) {
+        CHARGER->CHARGER_CTRL_REG &= ~mask;
+        NVIC_SetPendingIRQ(CHARGER_STATE_IRQn);
+    }
+
+    return 0;
+}
+
+int
+da1469x_charger_set_state_change_irq_mask(struct da1469x_charger_dev *dev,
+                                          da1469x_charger_state_irq_t mask)
+{
+    (void)dev;
+
+    CHARGER->CHARGER_STATE_IRQ_MASK_REG = mask;
+
+    return 0;
+}
+
+int
+da1469x_charger_set_error_irq_mask(struct da1469x_charger_dev *dev,
+                                   uint16_t mask)
+{
+    (void)dev;
+
+    CHARGER->CHARGER_ERROR_IRQ_MASK_REG = mask;
+
+    return 0;
+}
+
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+static int
+da1469x_charger_chg_ctrl_read(struct charge_control *cc, charge_control_type_t 
type,
+        charge_control_data_func_t data_func, void *data_arg, uint32_t timeout)
+{
+    const uint32_t mask = CHARGER_CHARGER_CTRL_REG_CHARGER_ENABLE_Msk |
+                          CHARGER_CHARGER_CTRL_REG_CHARGE_START_Msk;
+    charge_control_status_t status = CHARGE_CONTROL_STATUS_DISABLED;
+    charge_control_fault_t fault = CHARGE_CONTROL_FAULT_NONE;
+    struct da1469x_charger_dev *dev = (struct da1469x_charger_dev *)cc->cc_dev;
+    (void)timeout;
+
+    if (type & CHARGE_CONTROL_TYPE_STATUS) {
+        if ((CHARGER->CHARGER_CTRL_REG & mask) != mask) {
+            status = CHARGE_CONTROL_STATUS_DISABLED;
+        } else if (!(CRG_TOP->ANA_STATUS_REG &
+              CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk)) {
+            status = CHARGE_CONTROL_STATUS_NO_SOURCE;
+        } else {
+            switch (da1469x_charger_get_state(dev)) {
+            case DA1469X_CHARGER_STATE_POWER_UP:
+            case DA1469X_CHARGER_STATE_INIT:
+            case DA1469X_CHARGER_STATE_DISABLED:
+                status = CHARGE_CONTROL_STATUS_DISABLED;
+                break;
+            case DA1469X_CHARGER_STATE_CC_CHARGE:
+            case DA1469X_CHARGER_STATE_CV_CHARGE:
+            case DA1469X_CHARGER_STATE_PRE_CHARGE:
+                status = CHARGE_CONTROL_STATUS_CHARGING;
+                break;
+            case DA1469X_CHARGER_STATE_END_OF_CHARGE:
+                status = CHARGE_CONTROL_STATUS_CHARGE_COMPLETE;
+                break;
+            case DA1469X_CHARGER_STATE_TBAT_PROT:
+            case DA1469X_CHARGER_STATE_TDIE_PROT:
+                status = CHARGE_CONTROL_STATUS_SUSPEND;
+                break;
+            case DA1469X_CHARGER_STATE_ERROR:
+                status = CHARGE_CONTROL_STATUS_FAULT;
+                break;
+            default:
+                break;
+            }
+        }
+        if (data_func) {
+            data_func(cc, data_arg, &status, CHARGE_CONTROL_TYPE_STATUS);
+        }
+    }
+    if (type & CHARGE_CONTROL_TYPE_FAULT) {
+        if (CHARGER->CHARGER_STATUS_REG &
+            CHARGER_CHARGER_STATUS_REG_OVP_EVENTS_DEBOUNCE_CNT_Msk) {
+            fault |= CHARGE_CONTROL_FAULT_OV;
+        }
+        if (CHARGER->CHARGER_STATUS_REG &
+            (CHARGER_CHARGER_STATUS_REG_TBAT_HOT_COMP_OUT_Msk |
+             CHARGER_CHARGER_STATUS_REG_TDIE_COMP_OUT_Msk)) {
+            fault |= CHARGE_CONTROL_FAULT_THERM;
+        }
+        if (fault && data_func) {
+            data_func(cc, data_arg, &fault, CHARGE_CONTROL_TYPE_FAULT);
+        }
+    }
+
+    return 0;
+}
+
+static int
+da1469x_charger_chg_ctrl_get_config(struct charge_control *cc,
+                                    charge_control_type_t type,
+                                    struct charge_control_cfg *cfg)
+{
+    (void)cc;
+    (void)type;
+    (void)cfg;
+
+    return SYS_ENOTSUP;
+}
+
+static int
+da1469x_charger_chg_ctrl_set_config(struct charge_control *cc, void *cfg)
+{
+    (void)cc;
+    (void)cfg;
+
+    return SYS_ENOTSUP;
+}
+
+static int
+da1469x_charger_chg_ctrl_get_status(struct charge_control *cc, int *status)
+{
+    struct da1469x_charger_dev *dev = (struct da1469x_charger_dev *)cc->cc_dev;
+
+    *status = (int)da1469x_charger_get_state(dev);
+
+    return 0;
+}
+
+static int
+da1469x_charger_chg_ctrl_get_fault(struct charge_control *cc,
+                                   charge_control_fault_t *fault)
+{
+    *fault = CHARGE_CONTROL_FAULT_NONE;
+
+    switch (da1469x_charger_get_state((struct da1469x_charger_dev 
*)cc->cc_dev)) {
+    case DA1469X_CHARGER_STATE_TDIE_PROT:
+    case DA1469X_CHARGER_STATE_TBAT_PROT:
+        *fault |= CHARGE_CONTROL_FAULT_THERM;
+        break;
+    default:
+        break;
+    }
+
+    if (CHARGER->CHARGER_STATUS_REG &
+        CHARGER_CHARGER_STATUS_REG_VBAT_OVP_COMP_OUT_Msk) {
+        *fault |= CHARGE_CONTROL_FAULT_OV;
+    }
+
+    return 0;
+}
+
+static int
+da1469x_charger_chg_ctrl_enable(struct charge_control *cc)
+{
+    return da1469x_charger_charge_enable((struct da1469x_charger_dev 
*)cc->cc_dev);
+}
+
+static int
+da1469x_charger_chg_ctrl_disable(struct charge_control *cc)
+{
+    return da1469x_charger_charge_disable((struct da1469x_charger_dev 
*)cc->cc_dev);
+}
+
+/* Exports for the charge control API */
+static const struct charge_control_driver da1469x_charger_chg_ctrl_driver = {
+    .ccd_read = da1469x_charger_chg_ctrl_read,
+    .ccd_get_config = da1469x_charger_chg_ctrl_get_config,
+    .ccd_set_config = da1469x_charger_chg_ctrl_set_config,
+    .ccd_get_status = da1469x_charger_chg_ctrl_get_status,
+    .ccd_get_fault = da1469x_charger_chg_ctrl_get_fault,
+    .ccd_enable = da1469x_charger_chg_ctrl_enable,
+    .ccd_disable = da1469x_charger_chg_ctrl_disable,
+};
+#endif /* DA1469X_CHARGER_USE_CHARGE_CONTROL */
+
+int
+da1469x_charger_init(struct os_dev *dev, void *arg)
+{
+    struct da1469x_charger_dev *charger = (struct da1469x_charger_dev *)dev;
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+    struct charge_control *cc;
+#endif
+    const struct da1469x_charger_config *cfg = arg;
+    int rc = 0;
+
+    if (!dev) {
+        rc = SYS_ENODEV;
+        goto err;
+    }
+
+    if (cfg) {
+        rc = da1469x_charger_set_config(charger, cfg);
+        if (rc) {
+            goto err;
+        }
+    }
+
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+    cc = &charger->chg_ctrl;
+
+    rc = charge_control_init(cc, dev);
+    if (rc) {
+        goto err;
+    }
+
+    /* Add the driver with all the supported types */
+    rc = charge_control_set_driver(cc, CHARGE_CONTROL_TYPE_STATUS |
+        CHARGE_CONTROL_TYPE_FAULT,
+        (struct charge_control_driver *)&da1469x_charger_chg_ctrl_driver);
+    if (rc) {
+        goto err;
+    }
+
+    charge_control_set_type_mask(cc,
+                                 CHARGE_CONTROL_TYPE_STATUS |
+                                 CHARGE_CONTROL_TYPE_FAULT);
+
+    rc = charge_control_mgr_register(cc);
+    if (rc) {
+        goto err;
+    }
+
+    da1469x_charger_state_changed_event.ev_arg = charger;
+    da1469x_charger_error_event.ev_arg = charger;
+
+    da1469x_charger_set_error_irq_mask(charger, DA1469X_CHARGER_ERROR_IRQ_ALL);
+    da1469x_charger_set_state_change_irq_mask(charger,
+                                              
DA1469X_CHARGER_STATE_IRQ_DISABLED_TO_PRECHARGE |
+                                              
DA1469X_CHARGER_STATE_IRQ_CC_TO_EOC |
+                                              
DA1469X_CHARGER_STATE_IRQ_CV_TO_EOC |
+                                              
DA1469X_CHARGER_STATE_IRQ_EOC_TO_PRECHARGE |
+                                              
DA1469X_CHARGER_STATE_IRQ_TDIE_PROT_TO_PRECHARGE |
+                                              
DA1469X_CHARGER_STATE_IRQ_TBAT_PROT_TO_PRECHARGE |
+                                              
DA1469X_CHARGER_STATE_IRQ_TBAT_STATUS_UPDATE);
+
+    NVIC_SetVector(CHARGER_STATE_IRQn, (uint32_t)da1469x_charger_state_isr);
+    NVIC_ClearPendingIRQ(CHARGER_STATE_IRQn);
+    NVIC_EnableIRQ(CHARGER_STATE_IRQn);
+
+    NVIC_SetVector(CHARGER_ERROR_IRQn, (uint32_t)da1469x_charger_error_isr);
+    NVIC_ClearPendingIRQ(CHARGER_ERROR_IRQn);
+    NVIC_EnableIRQ(CHARGER_ERROR_IRQn);
+
+    da1469x_usb_init();
+#endif /* DA1469X_CHARGER_USE_CHARGE_CONTROL */
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI)
+    da1469x_charger_shell_init(charger);
+#endif
+
+err:
+    return rc;
+}
+
+int
+da1469x_charger_create(struct da1469x_charger_dev *dev, const char *name,
+    struct da1469x_charger_config *cfg)
+{
+    int rc;
+
+    rc = os_dev_create(&dev->dev, name,
+                       OS_DEV_INIT_PRIMARY, OS_DEV_INIT_PRIO_DEFAULT,
+                       da1469x_charger_init, cfg);
+
+    return rc;
+}
diff --git a/hw/drivers/chg_ctrl/da1469x_charger/src/da1469x_charger_shell.c 
b/hw/drivers/chg_ctrl/da1469x_charger/src/da1469x_charger_shell.c
new file mode 100644
index 0000000..272770d
--- /dev/null
+++ b/hw/drivers/chg_ctrl/da1469x_charger/src/da1469x_charger_shell.c
@@ -0,0 +1,1202 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <os/mynewt.h>
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI)
+
+#include <console/console.h>
+#include <shell/shell.h>
+#include <da1469x_charger/da1469x_charger.h>
+#include <parse/parse.h>
+#include <stdio.h>
+#include <DA1469xAB.h>
+#if MYNEWT_VAL(SDADC_BATTERY)
+#include <sdadc_da1469x/sdadc_da1469x.h>
+#endif
+#if MYNEWT_VAL(GPADC_BATTERY)
+#include <gpadc_da1469x/gpadc_da1469x.h>
+#endif
+
+#if MYNEWT_VAL(SHELL_CMD_HELP)
+#define HELP(a) &(da1469x_charger_##a##_help)
+static const struct shell_cmd_help da1469x_charger_dump_help = {
+    .summary = "Displays charger related registers",
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    .usage = "dump [decode]",
+#else
+    .usage = NULL,
+#endif
+    .params = NULL,
+};
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+static const struct shell_cmd_help da1469x_charger_decode_help = {
+    .summary = "Enables or disables decoding of registers",
+    .usage = "decode 1 | 0",
+    .params = NULL,
+};
+#endif
+
+static const struct shell_cmd_help da1469x_charger_enable_help = {
+    .summary = "Enables charging",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help da1469x_charger_disable_help = {
+    .summary = "Disables charging",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help da1469x_charger_status_help = {
+    .summary = "Shows status of charger and battery",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help da1469x_charger_clear_irq_help = {
+    .summary = "Clears interrupts",
+    .usage = NULL,
+    .params = NULL,
+};
+
+static const struct shell_cmd_help da1469x_charger_set_i_help = {
+    .summary = "Sets charging currents",
+    .usage = "seti <charge_current> [precharge_current [eoc percentage]]",
+    .params = NULL,
+};
+
+static const struct shell_cmd_help da1469x_charger_set_v_help = {
+    .summary = "Sets charging voltages",
+    .usage = "setv <charge_v> [<precharge_v> [<replenish_v> [ovp_v]]]",
+    .params = NULL,
+};
+
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+static const struct shell_cmd_help da1469x_charger_listen_help = {
+    .summary = "Starts or stops charging state notifications",
+    .usage = "listen start | stop",
+    .params = NULL,
+};
+#endif
+
+static const struct shell_cmd_help da1469x_charger_reg_help = {
+    .summary = "Read or writes register",
+    .usage = "<reg_name> ",
+    .params = NULL,
+};
+
+#else
+#define HELP(a) NULL
+#endif
+
+/*
+ * Struct for field name description.
+ * Used for argument validation and field decoding
+ */
+struct reg_field {
+    /* Name of field */
+    const char *fld_name;
+    /* Position of field in register (LSB position) */
+    uint8_t fld_pos;
+    bool fld_show_bits;
+    /* Mask of bit field to set or extract */
+    uint32_t fld_mask;
+    /* Function that will convert register value to descriptive string */
+    const char *(*fld_decode_value)(const struct reg_field *field,
+            uint32_t reg_val, char *buf);
+    /* Argument that could be used by above function */
+    const void *fld_arg;
+};
+
+/**
+* Register structure
+*/
+struct reg {
+    /* Address of the register */
+    volatile uint32_t *addr;
+    /* Name of the register */
+    const char *name;
+    /* Array of bit fields */
+    const struct reg_field *fields;
+};
+
+static const char *const charger_state[] = {
+    "POWER_UP",
+    "INIT",
+    "DISABLED",
+    "PRE_CHARGE",
+    "CC_CHARGE",
+    "CV_CHARGE",
+    "END_OF_CHARGE",
+    "TDIE_PROT",
+    "TBAT_PROT",
+    "BYPASSED",
+    "ERROR",
+    NULL,
+};
+
+static const char *const tbat_status[] = {
+    "",
+    "COLD",
+    "COOL",
+    "",
+    "NORMAL",
+    "",
+    "",
+    "",
+    "WARM",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "",
+    "HOT",
+    NULL,
+};
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+
+bool da1469x_charger_cli_decode_fields;
+
+/* Change ix value to string from table.
+ * Table is NULL terminated. Access outside of range will result in
+ * returning ??? string
+ */
+static const char *
+val_decode_from_table(const char *const tab[], int ix)
+{
+    while (ix && tab[ix]) {
+        ix--;
+        tab++;
+    }
+    if (tab[0]) {
+        return tab[0];
+    } else {
+        return "???";
+    }
+}
+
+/* Decode bit field using table with mapped values */
+static const char *
+reg_decode_from_table(const struct reg_field *field,
+                      uint32_t reg_val, char *buf)
+{
+    uint32_t val = (reg_val & field->fld_mask) >> field->fld_pos;
+    const char *const *table = field->fld_arg;
+
+    return strcpy(buf, val_decode_from_table(table, val));
+}
+
+#define FIELD_NUM(reg, field) { .fld_name = #field, .fld_pos = 
CHARGER_CHARGER_##reg##_REG_##field##_Pos, \
+    .fld_show_bits = 0, .fld_mask = CHARGER_CHARGER_##reg##_REG_##field##_Msk }
+#define FIELD_TAB(reg, field, tab) { .fld_name = #field, .fld_pos = 
CHARGER_CHARGER_##reg##_REG_##field##_Pos, \
+    .fld_show_bits = 1, .fld_mask = CHARGER_CHARGER_##reg##_REG_##field##_Msk, 
.fld_decode_value = reg_decode_from_table, .fld_arg = tab }
+#define FIELD_FUN(reg, field, fun, arg) { .fld_name = #field, .fld_pos = 
CHARGER_CHARGER_##reg##_REG_##field##_Pos, \
+    .fld_show_bits = 1, .fld_mask = CHARGER_CHARGER_##reg##_REG_##field##_Msk, 
.fld_decode_value = fun, .fld_arg = arg }
+
+/* Fields for CTRL register */
+static const struct reg_field CTRL_fields[] = {
+    FIELD_NUM(CTRL, EOC_INTERVAL_CHECK_TIMER),
+    FIELD_NUM(CTRL, EOC_INTERVAL_CHECK_THRES),
+    FIELD_NUM(CTRL, REPLENISH_MODE),
+    FIELD_NUM(CTRL, PRE_CHARGE_MODE),
+    FIELD_NUM(CTRL, CHARGE_LOOP_HOLD),
+    FIELD_NUM(CTRL, JEITA_SUPPORT_DISABLED),
+    FIELD_NUM(CTRL, TBAT_MONITOR_MODE),
+    FIELD_NUM(CTRL, CHARGE_TIMERS_HALT_ENABLE),
+    FIELD_NUM(CTRL, NTC_LOW_DISABLE),
+    FIELD_NUM(CTRL, TBAT_PROT_ENABLE),
+    FIELD_NUM(CTRL, TDIE_ERROR_RESUME),
+    FIELD_NUM(CTRL, TDIE_PROT_ENABLE),
+    FIELD_NUM(CTRL, CHARGER_RESUME),
+    FIELD_NUM(CTRL, CHARGER_BYPASS),
+    FIELD_NUM(CTRL, CHARGE_START),
+    FIELD_NUM(CTRL, CHARGER_ENABLE),
+    { NULL }
+};
+
+static const char *const charger_jeita_state[] = {
+    "CHECK_IDLE",
+    "CHECK_THOT",
+    "CHECK_TCOLD",
+    "CHECK_TWORM",
+    "CHECK_TCOOL",
+    "CHECK_TNORMAL",
+    "UPDATE_TBAT",
+    NULL,
+};
+
+/* Fields for STATUS register */
+static const struct reg_field STATUS_fields[] = {
+    FIELD_NUM(STATUS, OVP_EVENTS_DEBOUNCE_CNT),
+    FIELD_NUM(STATUS, EOC_EVENTS_DEBOUNCE_CNT),
+    FIELD_NUM(STATUS, TDIE_ERROR_DEBOUNCE_CNT),
+    FIELD_TAB(STATUS, CHARGER_JEITA_STATE, charger_jeita_state),
+    FIELD_TAB(STATUS, CHARGER_STATE, charger_state),
+    FIELD_TAB(STATUS, TBAT_STATUS, tbat_status),
+    FIELD_NUM(STATUS, MAIN_TBAT_COMP_OUT),
+    FIELD_NUM(STATUS, TBAT_HOT_COMP_OUT),
+    FIELD_NUM(STATUS, TDIE_COMP_OUT),
+    FIELD_NUM(STATUS, VBAT_OVP_COMP_OUT),
+    FIELD_NUM(STATUS, MAIN_VBAT_COMP_OUT),
+    FIELD_NUM(STATUS, END_OF_CHARGE),
+    FIELD_NUM(STATUS, CHARGER_CV_MODE),
+    FIELD_NUM(STATUS, CHARGER_CC_MODE),
+    FIELD_NUM(STATUS, CHARGER_IS_POWERED_UP),
+    { NULL }
+};
+
+static const char *
+voltage_decode(const struct reg_field *field, uint32_t reg_val, char *buf)
+{
+    uint32_t val = (reg_val & field->fld_mask) >> field->fld_pos;
+
+    if (val < 20) {
+        val = 280 + 5 * val;
+    } else if (val < 60) {
+        val = 380 + 2 * (val - 20);
+    } else {
+        val = 460 + 10 * (val - 60);
+    }
+    sprintf(buf, "%d.%02d V", (int)val / 100, (int)val % 100);
+    return buf;
+}
+
+/* Fields for VOLTAGE_PARAM register */
+static const struct reg_field VOLTAGE_PARAM_fields[] = {
+    FIELD_FUN(VOLTAGE_PARAM, V_OVP, voltage_decode, NULL),
+    FIELD_FUN(VOLTAGE_PARAM, V_REPLENISH, voltage_decode, NULL),
+    FIELD_FUN(VOLTAGE_PARAM, V_PRECHARGE, voltage_decode, NULL),
+    FIELD_FUN(VOLTAGE_PARAM, V_CHARGE, voltage_decode, NULL),
+    { NULL }
+};
+
+static const uint16_t i_eoc[][8] = {
+    { 40, 55, 70, 85, 100, 120, 140, 160},
+    { 88, 121, 154, 187, 220, 264, 308, 352},
+};
+
+static const char *
+current_eoc_decode(const struct reg_field *field, uint32_t reg_val, char *buf)
+{
+    int val;
+    size_t ix = (reg_val & field->fld_mask) >> field->fld_pos;
+    size_t mul = 0;
+
+    if (reg_val & CHARGER_CHARGER_CURRENT_PARAM_REG_I_EOC_DOUBLE_RANGE_Msk) {
+        mul = 1;
+    }
+    val = i_eoc[mul][ix];
+
+    sprintf(buf, "%d.%d %%", val / 10, val % 10);
+
+    return buf;
+}
+
+static const char *
+current_precharge(const struct reg_field *field, uint32_t reg_val, char *buf)
+{
+    int val = (int)((reg_val & field->fld_mask) >> field->fld_pos);
+
+    if (val < 15) {
+        val = 5 + 5 * val;
+    } else if (val < 32) {
+        val = 80 + 10 * (val - 15);
+    } else if (val < 47) {
+        val = 240 + 20 * (val - 31);
+    } else {
+        val = 560;
+    }
+    sprintf(buf, "%d.%d mA", val / 10, val % 10);
+
+    return buf;
+}
+
+static const char *
+current_charge(const struct reg_field *field, uint32_t reg_val, char *buf)
+{
+    int val = (int)((reg_val & field->fld_mask) >> field->fld_pos);
+
+    if (val < 15) {
+        val = 5 + 5 * val;
+    } else if (val < 32) {
+        val = 80 + 10 * (val - 15);
+    } else if (val < 47) {
+        val = 240 + 20 * (val - 31);
+    } else {
+        val = 560;
+    }
+    sprintf(buf, "%d mA", val);
+
+    return buf;
+}
+
+/* Fields for CURRENT_PARAM register */
+static const struct reg_field CURRENT_PARAM_fields[] = {
+    FIELD_NUM(CURRENT_PARAM, I_EOC_DOUBLE_RANGE),
+    FIELD_FUN(CURRENT_PARAM, I_END_OF_CHARGE, current_eoc_decode, NULL),
+    FIELD_FUN(CURRENT_PARAM, I_PRECHARGE, current_precharge, NULL),
+    FIELD_FUN(CURRENT_PARAM, I_CHARGE, current_charge, NULL),
+    { NULL }
+};
+
+static const char *const tdie_max[] = {
+    "0 C",
+    "50 C",
+    "80 C",
+    "90 C",
+    "100 C",
+    "110 C",
+    "120 C",
+    "130 C",
+    NULL,
+};
+
+static const char *
+tbat_temp(const struct reg_field *field, uint32_t reg_val, char *buf)
+{
+    int val = (int)((reg_val & field->fld_mask) >> field->fld_pos);
+
+    val -= 10;
+    sprintf(buf, "%d C", val);
+    return buf;
+}
+
+/* Fields for TEMPSET_PARAM register */
+static const struct reg_field TEMPSET_PARAM_fields[] = {
+    FIELD_TAB(TEMPSET_PARAM, TDIE_MAX, tdie_max),
+    FIELD_FUN(TEMPSET_PARAM, TBAT_HOT, tbat_temp, NULL),
+    FIELD_FUN(TEMPSET_PARAM, TBAT_WARM, tbat_temp, NULL),
+    FIELD_FUN(TEMPSET_PARAM, TBAT_COOL, tbat_temp, NULL),
+    FIELD_FUN(TEMPSET_PARAM, TBAT_COLD, tbat_temp, NULL),
+    { NULL }
+};
+
+/* Fields for PRE_CHARGE_TIMER register */
+static const struct reg_field PRE_CHARGE_TIMER_fields[] = {
+    FIELD_NUM(PRE_CHARGE_TIMER, PRE_CHARGE_TIMER),
+    FIELD_NUM(PRE_CHARGE_TIMER, MAX_PRE_CHARGE_TIME),
+    { NULL }
+};
+
+/* Fields for CC_CHARGE_TIMER register */
+static const struct reg_field CC_CHARGE_TIMER_fields[] = {
+    FIELD_NUM(CC_CHARGE_TIMER, CC_CHARGE_TIMER),
+    FIELD_NUM(CC_CHARGE_TIMER, MAX_CC_CHARGE_TIME),
+    { NULL }
+};
+
+/* Fields for CV_CHARGE_TIMER register */
+static const struct reg_field CV_CHARGE_TIMER_fields[] = {
+    FIELD_NUM(CV_CHARGE_TIMER, CV_CHARGE_TIMER),
+    FIELD_NUM(CV_CHARGE_TIMER, MAX_CV_CHARGE_TIME),
+    { NULL }
+};
+
+/* Fields for TOTAL_CHARGE_TIMER register */
+static const struct reg_field TOTAL_CHARGE_TIMER_fields[] = {
+    FIELD_NUM(TOTAL_CHARGE_TIMER, TOTAL_CHARGE_TIMER),
+    FIELD_NUM(TOTAL_CHARGE_TIMER, MAX_TOTAL_CHARGE_TIME),
+    { NULL }
+};
+
+/* Fields for JEITA_V_CHARGE register */
+static const struct reg_field JEITA_V_CHARGE_fields[] = {
+    FIELD_FUN(JEITA_V_CHARGE, V_CHARGE_TWARM, voltage_decode, NULL),
+    FIELD_FUN(JEITA_V_CHARGE, V_CHARGE_TCOOL, voltage_decode, NULL),
+    { NULL }
+};
+
+/* Fields for JEITA_V_PRECHARGE register */
+static const struct reg_field JEITA_V_PRECHARGE_fields[] = {
+    FIELD_FUN(JEITA_V_PRECHARGE, V_PRECHARGE_TWARM, voltage_decode, NULL),
+    FIELD_FUN(JEITA_V_PRECHARGE, V_PRECHARGE_TCOOL, voltage_decode, NULL),
+    { NULL }
+};
+
+/* Fields for JEITA_V_REPLENISH register */
+static const struct reg_field JEITA_V_REPLENISH_fields[] = {
+    FIELD_FUN(JEITA_V_REPLENISH, V_REPLENISH_TWARM, voltage_decode, NULL),
+    FIELD_FUN(JEITA_V_REPLENISH, V_REPLENISH_TCOOL, voltage_decode, NULL),
+    { NULL }
+};
+
+/* Fields for JEITA_V_OVP register */
+static const struct reg_field JEITA_V_OVP_fields[] = {
+    FIELD_FUN(JEITA_V_OVP, V_OVP_TWARM, voltage_decode, NULL),
+    FIELD_FUN(JEITA_V_OVP, V_OVP_TCOOL, voltage_decode, NULL),
+    { NULL }
+};
+
+/* Fields for JEITA_CURRENT register */
+static const struct reg_field JEITA_CURRENT_fields[] = {
+    FIELD_FUN(JEITA_CURRENT, I_PRECHARGE_TWARM, current_precharge, NULL),
+    FIELD_FUN(JEITA_CURRENT, I_PRECHARGE_TCOOL, current_precharge, NULL),
+    FIELD_FUN(JEITA_CURRENT, I_CHARGE_TWARM, current_charge, NULL),
+    FIELD_FUN(JEITA_CURRENT, I_CHARGE_TCOOL, current_charge, NULL),
+    { NULL }
+};
+
+/* Fields for VBAT_COMP_TIMER register */
+static const struct reg_field VBAT_COMP_TIMER_fields[] = {
+    FIELD_NUM(VBAT_COMP_TIMER, VBAT_COMP_TIMER),
+    FIELD_NUM(VBAT_COMP_TIMER, VBAT_COMP_SETTLING),
+    { NULL }
+};
+
+/* Fields for VOVP_COMP_TIMER register */
+static const struct reg_field VOVP_COMP_TIMER_fields[] = {
+    FIELD_NUM(VOVP_COMP_TIMER, OVP_INTERVAL_CHECK_TIMER),
+    FIELD_NUM(VOVP_COMP_TIMER, VBAT_OVP_COMP_TIMER),
+    FIELD_NUM(VOVP_COMP_TIMER, OVP_INTERVAL_CHECK_THRES),
+    FIELD_NUM(VOVP_COMP_TIMER, VBAT_OVP_COMP_SETTLING),
+    { NULL }
+};
+
+/* Fields for TDIE_COMP_TIMER register */
+static const struct reg_field TDIE_COMP_TIMER_fields[] = {
+    FIELD_NUM(TDIE_COMP_TIMER, TDIE_COMP_TIMER),
+    FIELD_NUM(TDIE_COMP_TIMER, TDIE_COMP_SETTLING),
+    { NULL }
+};
+
+/* Fields for TBAT_MON_TIMER register */
+static const struct reg_field TBAT_MON_TIMER_fields[] = {
+    FIELD_NUM(TBAT_MON_TIMER, TBAT_MON_TIMER),
+    FIELD_NUM(TBAT_MON_TIMER, TBAT_MON_INTERVAL),
+    { NULL }
+};
+
+/* Fields for TBAT_COMP_TIMER register */
+static const struct reg_field TBAT_COMP_TIMER_fields[] = {
+    FIELD_NUM(TBAT_COMP_TIMER, TBAT_COMP_TIMER),
+    FIELD_NUM(TBAT_COMP_TIMER, TBAT_COMP_SETTLING),
+    { NULL }
+};
+
+/* Fields for THOT_COMP_TIMER register */
+static const struct reg_field THOT_COMP_TIMER_fields[] = {
+    FIELD_NUM(THOT_COMP_TIMER, THOT_COMP_TIMER),
+    FIELD_NUM(THOT_COMP_TIMER, THOT_COMP_SETTLING),
+    { NULL }
+};
+
+/* Fields for PWR_UP_TIMER register */
+static const struct reg_field PWR_UP_TIMER_fields[] = {
+    FIELD_NUM(PWR_UP_TIMER, CHARGER_PWR_UP_TIMER),
+    FIELD_NUM(PWR_UP_TIMER, CHARGER_PWR_UP_SETTLING),
+    { NULL }
+};
+
+/* Fields for STATE_IRQ_MASK register */
+static const struct reg_field STATE_IRQ_MASK_fields[] = {
+    FIELD_NUM(STATE_IRQ_MASK, CV_TO_PRECHARGE_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, CC_TO_PRECHARGE_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, CV_TO_CC_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, TBAT_STATUS_UPDATE_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, TBAT_PROT_TO_PRECHARGE_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, TDIE_PROT_TO_PRECHARGE_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, EOC_TO_PRECHARGE_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, CV_TO_EOC_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, CC_TO_EOC_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, CC_TO_CV_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, PRECHARGE_TO_CC_IRQ_EN),
+    FIELD_NUM(STATE_IRQ_MASK, DISABLED_TO_PRECHARGE_IRQ_EN),
+    { NULL }
+};
+
+/* Fields for ERROR_IRQ_MASK register */
+static const struct reg_field ERROR_IRQ_MASK_fields[] = {
+    FIELD_NUM(ERROR_IRQ_MASK, TBAT_ERROR_IRQ_EN),
+    FIELD_NUM(ERROR_IRQ_MASK, TDIE_ERROR_IRQ_EN),
+    FIELD_NUM(ERROR_IRQ_MASK, VBAT_OVP_ERROR_IRQ_EN),
+    FIELD_NUM(ERROR_IRQ_MASK, TOTAL_CHARGE_TIMEOUT_IRQ_EN),
+    FIELD_NUM(ERROR_IRQ_MASK, CV_CHARGE_TIMEOUT_IRQ_EN),
+    FIELD_NUM(ERROR_IRQ_MASK, CC_CHARGE_TIMEOUT_IRQ_EN),
+    FIELD_NUM(ERROR_IRQ_MASK, PRECHARGE_TIMEOUT_IRQ_EN),
+    { NULL }
+};
+
+/* Fields for STATE_IRQ_STATUS register */
+static const struct reg_field STATE_IRQ_STATUS_fields[] = {
+    FIELD_NUM(STATE_IRQ_STATUS, CV_TO_PRECHARGE_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, CC_TO_PRECHARGE_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, CV_TO_CC_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, TBAT_STATUS_UPDATE_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, TBAT_PROT_TO_PRECHARGE_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, TDIE_PROT_TO_PRECHARGE_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, EOC_TO_PRECHARGE_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, CV_TO_EOC_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, CC_TO_EOC_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, CC_TO_CV_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, PRECHARGE_TO_CC_IRQ),
+    FIELD_NUM(STATE_IRQ_STATUS, DISABLED_TO_PRECHARGE_IRQ),
+    { NULL }
+};
+
+/* Fields for ERROR_IRQ_STATUS register */
+static const struct reg_field ERROR_IRQ_STATUS_fields[] = {
+    FIELD_NUM(ERROR_IRQ_STATUS, TBAT_ERROR_IRQ),
+    FIELD_NUM(ERROR_IRQ_STATUS, TDIE_ERROR_IRQ),
+    FIELD_NUM(ERROR_IRQ_STATUS, VBAT_OVP_ERROR_IRQ),
+    FIELD_NUM(ERROR_IRQ_STATUS, TOTAL_CHARGE_TIMEOUT_IRQ),
+    FIELD_NUM(ERROR_IRQ_STATUS, CV_CHARGE_TIMEOUT_IRQ),
+    FIELD_NUM(ERROR_IRQ_STATUS, CC_CHARGE_TIMEOUT_IRQ),
+    FIELD_NUM(ERROR_IRQ_STATUS, PRECHARGE_TIMEOUT_IRQ),
+    { NULL }
+};
+
+/* Fields for STATE_IRQ_CLR register */
+static const struct reg_field STATE_IRQ_CLR_fields[] = {
+    FIELD_NUM(STATE_IRQ_CLR, CV_TO_PRECHARGE_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, CC_TO_PRECHARGE_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, CV_TO_CC_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, TBAT_STATUS_UPDATE_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, TBAT_PROT_TO_PRECHARGE_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, TDIE_PROT_TO_PRECHARGE_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, EOC_TO_PRECHARGE_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, CV_TO_EOC_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, CC_TO_EOC_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, CC_TO_CV_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, PRECHARGE_TO_CC_IRQ_CLR),
+    FIELD_NUM(STATE_IRQ_CLR, DISABLED_TO_PRECHARGE_IRQ_CLR),
+    { NULL }
+};
+
+/* Fields for ERROR_IRQ_CLR register */
+static const struct reg_field ERROR_IRQ_CLR_fields[] = {
+    FIELD_NUM(ERROR_IRQ_CLR, TBAT_ERROR_IRQ_CLR),
+    FIELD_NUM(ERROR_IRQ_CLR, TDIE_ERROR_IRQ_CLR),
+    FIELD_NUM(ERROR_IRQ_CLR, VBAT_OVP_ERROR_IRQ_CLR),
+    FIELD_NUM(ERROR_IRQ_CLR, TOTAL_CHARGE_TIMEOUT_IRQ_CLR),
+    FIELD_NUM(ERROR_IRQ_CLR, CV_CHARGE_TIMEOUT_IRQ_CLR),
+    FIELD_NUM(ERROR_IRQ_CLR, CC_CHARGE_TIMEOUT_IRQ_CLR),
+    FIELD_NUM(ERROR_IRQ_CLR, PRECHARGE_TIMEOUT_IRQ_CLR),
+    { NULL }
+};
+
+#define REG(reg_name) { .addr = &CHARGER->CHARGER_##reg_name##_REG, .name = 
"CHARGER_"#reg_name"_REG", .fields = reg_name##_fields }
+
+#else
+#define da1469x_charger_cli_decode_fields false
+
+#define REG(reg_name) { .addr = &CHARGER->CHARGER_##reg_name##_REG, .name = 
"CHARGER_"#reg_name"_REG", .fields = NULL }
+#endif
+
+#define REG_NAME(short_name) "CHARGER_"#short_name"_REG"
+
+static const struct reg charger_regs[] = {
+    REG(CTRL),
+    REG(STATUS),
+    REG(VOLTAGE_PARAM),
+    REG(CURRENT_PARAM),
+    REG(TEMPSET_PARAM),
+    REG(PRE_CHARGE_TIMER),
+    REG(CC_CHARGE_TIMER),
+    REG(CV_CHARGE_TIMER),
+    REG(TOTAL_CHARGE_TIMER),
+    REG(JEITA_V_CHARGE),
+    REG(JEITA_V_PRECHARGE),
+    REG(JEITA_V_REPLENISH),
+    REG(JEITA_V_OVP),
+    REG(JEITA_CURRENT),
+    REG(VBAT_COMP_TIMER),
+    REG(VOVP_COMP_TIMER),
+    REG(TDIE_COMP_TIMER),
+    REG(TBAT_MON_TIMER),
+    REG(TBAT_COMP_TIMER),
+    REG(THOT_COMP_TIMER),
+    REG(PWR_UP_TIMER),
+    REG(STATE_IRQ_MASK),
+    REG(ERROR_IRQ_MASK),
+    REG(STATE_IRQ_STATUS),
+    REG(ERROR_IRQ_STATUS),
+    REG(STATE_IRQ_CLR),
+    REG(ERROR_IRQ_CLR),
+};
+#define NUM_CHARGER_REGS ARRAY_SIZE(charger_regs)
+
+static const struct shell_cmd da1469x_charger_shell_cmd_struct;
+
+static int
+da1469x_charger_help(void)
+{
+    console_printf("%s cmd\n", da1469x_charger_shell_cmd_struct.sc_cmd);
+    console_printf("cmd:\n");
+    console_printf("\thelp\n");
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    console_printf("\tdump [decode]\n");
+#else
+    console_printf("\tdump\n");
+#endif
+    console_printf("\tread <reg_name>\n");
+    console_printf("\twrite <reg_anme> <value>\n");
+    console_printf("\tdisable\n");
+    console_printf("\tenable\n");
+    console_printf("\tstatus\n");
+    console_printf("\tseti <charge_i> [<precharge_i> [<eoc_percent>]]\n");
+    console_printf("\tsetv <charge_v> [<precharge_v> [<replenish_v> 
[<ovp_v>]]]\n");
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+    console_printf("\tlisten start | stop\n");
+#endif
+    return 0;
+}
+
+static int
+da1469x_charger_shell_err_too_many_args(const char *cmd_name)
+{
+    console_printf("Error: too many arguments for command \"%s\"\n",
+                   cmd_name);
+
+    return SYS_EINVAL;
+}
+
+static int
+da1469x_charger_shell_err_unknown_arg(const char *cmd_name)
+{
+    console_printf("Error: unknown argument \"%s\"\n",
+                   cmd_name);
+
+    return SYS_EINVAL;
+}
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+
+static const char *
+field_bin_value(const struct reg_field *field, uint32_t val, char *buf)
+{
+    uint32_t mask = field->fld_mask >> field->fld_pos;
+    int bits = 0;
+    val = (val & field->fld_mask) >> field->fld_pos;
+
+    for (bits = 0; mask; bits++) {
+        mask >>= 1;
+    }
+    mask = field->fld_mask >> field->fld_pos;
+    buf[bits] = '\0';
+    while (mask) {
+        buf[--bits] = (char)('0' + (val & 1));
+        mask >>= 1;
+        val >>= 1;
+    }
+
+    return buf;
+}
+
+static int
+field_int_value(const struct reg_field *field, uint32_t val)
+{
+    return (int)((val & field->fld_mask) >> field->fld_pos);
+}
+
+static int
+da1469x_charger_shell_cmd_decode(int argc, char **argv)
+{
+    long long val;
+    int status;
+
+    if (argc == 2) {
+        val = parse_ll_bounds(argv[1], 0, 1, &status);
+        if (status == 0) {
+            da1469x_charger_cli_decode_fields = val != 0;
+        }
+    }
+    console_printf("decode %d\n", (int)da1469x_charger_cli_decode_fields);
+
+    return 0;
+}
+
+#endif /* MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE) */
+
+static void
+da1469x_charger_dump_register(const struct reg *reg, uint32_t val, bool decode)
+{
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    const struct reg_field *field;
+    char binary[33];
+    char buf[50];
+#endif
+    console_printf("%-30s = 0x%08x \n", reg->name, (int)val);
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    if (decode && reg->fields) {
+        for (field = reg->fields; field->fld_name; ++field) {
+            if (field->fld_decode_value) {
+                field->fld_decode_value(field, val, buf);
+                if (field->fld_show_bits) {
+                    console_printf("%32s = %s %s\n", field->fld_name,
+                                   field_bin_value(field, val, binary), buf);
+                } else {
+                    console_printf("%32s = %s\n", field->fld_name, buf);
+                }
+            } else {
+                if (field->fld_show_bits) {
+                    console_printf("%32s = %s\n", field->fld_name,
+                                   field_bin_value(field, val, binary));
+                } else {
+                    console_printf("%32s = %d\n", field->fld_name,
+                                   field_int_value(field, val));
+                }
+            }
+        }
+    }
+#endif
+}
+
+static int
+da1469x_charger_shell_cmd_dump(int argc, char **argv)
+{
+    int i;
+    uint32_t val;
+    const struct reg *reg;
+    bool decode = da1469x_charger_cli_decode_fields;
+
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    if (argc > 2) {
+        return da1469x_charger_shell_err_too_many_args(argv[1]);
+    } else if (argc == 2) {
+        if (strcmp(argv[1], "decode") == 0) {
+            decode = true;
+        } else if (strcmp(argv[1], "nodecode") == 0) {
+            decode = false;
+        } else {
+            return da1469x_charger_shell_err_unknown_arg(argv[1]);
+        }
+    }
+#else
+    if (argc > 2) {
+        return da1469x_charger_shell_err_too_many_args(argv[1]);
+        return 0;
+    }
+#endif
+
+    console_printf("========== Charger Regs ==========\n");
+    console_printf("==================================\n\n");
+    for (i = 0; i < NUM_CHARGER_REGS; ++i) {
+        reg = &charger_regs[i];
+        val = *reg->addr;
+        da1469x_charger_dump_register(reg, val, decode);
+    }
+
+    return 0;
+}
+
+static int
+da1469x_charger_shell_cmd_enable(int argc, char **argv)
+{
+    struct da1469x_charger_dev *dev =
+        (struct da1469x_charger_dev *)os_dev_open("charger", 0, NULL);
+    (void)argc;
+    (void)argv;
+
+    if (dev) {
+        da1469x_charger_charge_enable(dev);
+        os_dev_close(&dev->dev);
+    }
+    return 0;
+}
+
+static int
+da1469x_charger_shell_cmd_disable(int argc, char **argv)
+{
+    struct da1469x_charger_dev *dev =
+        (struct da1469x_charger_dev *)os_dev_open("charger", 0, NULL);
+    (void)argc;
+    (void)argv;
+
+    if (dev) {
+        da1469x_charger_charge_disable(dev);
+        os_dev_close(&dev->dev);
+    }
+    return 0;
+}
+
+static int
+da1469x_charger_shell_cmd_status(int argc, char **argv)
+{
+#if MYNEWT_VAL(SDADC_BATTERY) || MYNEWT_VAL(GPADC_BATTERY)
+    struct adc_dev *adc;
+    int bat_val;
+#endif
+    uint32_t val = CHARGER->CHARGER_STATUS_REG;
+    uint32_t state = (val & CHARGER_CHARGER_STATUS_REG_CHARGER_STATE_Msk) >>
+                      CHARGER_CHARGER_STATUS_REG_CHARGER_STATE_Pos;
+    uint32_t bat_state = (val & CHARGER_CHARGER_STATUS_REG_TBAT_STATUS_Msk) >>
+                          CHARGER_CHARGER_STATUS_REG_TBAT_STATUS_Pos;
+    bool vbus_ok = (CRG_TOP->ANA_STATUS_REG & 
CRG_TOP_ANA_STATUS_REG_VBUS_AVAILABLE_Msk) != 0;
+    const uint32_t mask = CHARGER_CHARGER_CTRL_REG_CHARGER_ENABLE_Msk |
+                          CHARGER_CHARGER_CTRL_REG_CHARGE_START_Msk;
+
+    (void)argc;
+    (void)argv;
+    if ((CHARGER->CHARGER_CTRL_REG & mask) != mask) {
+        console_printf("status = disabled\n");
+    } else if (!vbus_ok) {
+        console_printf("status = enabled (not connected)\n");
+    } else {
+        console_printf("status = %s\n", charger_state[state]);
+    }
+    console_printf("  vbus = %s\n", vbus_ok ? "OK" : "NOK");
+    console_printf("  tbat = %s\n", tbat_status[bat_state]);
+#if MYNEWT_VAL(SDADC_BATTERY) || MYNEWT_VAL(GPADC_BATTERY)
+    adc = (struct adc_dev *)da1469x_open_battery_adc(BATTERY_ADC_DEV_NAME, 1);
+    if (adc) {
+        adc_read_channel(adc, 0, &bat_val);
+        os_dev_close(&adc->ad_dev);
+        console_printf("  vbat = %d mV\n", adc_result_mv(adc, 0, bat_val));
+    }
+#endif
+
+    return 0;
+}
+
+static int
+da1469x_charger_shell_cmd_clear_irq(int argc, char **argv)
+{
+    if (argc == 1) {
+        CHARGER->CHARGER_STATE_IRQ_CLR_REG = 0xFFFFFFFF;
+        CHARGER->CHARGER_ERROR_IRQ_CLR_REG = 0xFFFFFFFF;
+    } else if (0 == strcmp(argv[1], "state")) {
+        CHARGER->CHARGER_STATE_IRQ_CLR_REG = 0xFFFFFFFF;
+    } else if (0 == strcmp(argv[1], "error")) {
+        CHARGER->CHARGER_ERROR_IRQ_CLR_REG = 0xFFFFFFFF;
+    } else {
+        return -1;
+    }
+    return 0;
+}
+
+static int
+da1469x_charger_shell_cmd_set_i(int argc, char **argv)
+{
+    int rc;
+    uint32_t val = CHARGER->CHARGER_CURRENT_PARAM_REG;
+    uint32_t i_charge;
+    uint32_t i_precharge;
+    uint32_t i_eoc;
+
+    if (argc > 1) {
+        i_charge = (uint32_t)parse_ll_bounds(argv[1], 5, 560, &rc);
+        if (rc) {
+            console_printf("I_CHARGE should be in range 5-560\n");
+            return 0;
+        }
+        val &= ~CHARGER_CHARGER_CURRENT_PARAM_REG_I_CHARGE_Msk;
+        val |= DA1469X_ENCODE_CHG_I(i_charge);
+    }
+    if (argc > 2) {
+        i_precharge = (uint32_t)parse_ll_bounds(argv[2], 1, 56, &rc);
+        if (rc) {
+            console_printf("I_PRECHARGE should be in range 1-56\n");
+            return 0;
+        }
+        val &= ~CHARGER_CHARGER_CURRENT_PARAM_REG_I_PRECHARGE_Msk;
+        val |= DA1469X_ENCODE_PRECHG_I(i_precharge);
+    }
+    if (argc > 3) {
+        i_eoc = (uint32_t)parse_ll_bounds(argv[3], 4, 35, &rc);
+        if (rc) {
+            console_printf("I_EOC should be in range 4-35\n");
+            return 0;
+        }
+        val &= ~(CHARGER_CHARGER_CURRENT_PARAM_REG_I_END_OF_CHARGE_Msk |
+                 CHARGER_CHARGER_CURRENT_PARAM_REG_I_EOC_DOUBLE_RANGE_Msk);
+        val |= DA1469X_ENCODE_EOC_I(i_eoc);
+    }
+    CHARGER->CHARGER_CURRENT_PARAM_REG = val;
+
+    return 0;
+}
+
+static int
+da1469x_charger_shell_cmd_set_v(int argc, char **argv)
+{
+    int rc;
+    uint32_t val = CHARGER->CHARGER_VOLTAGE_PARAM_REG;
+    uint32_t v;
+
+    if (argc > 1 && strcmp("-", argv[1]) != 0) {
+        v = (uint32_t)parse_ll_bounds(argv[1], 2800, 4900, &rc);
+        if (rc) {
+            console_printf("V_CHARGE should be in range 2800-4900\n");
+            return 0;
+        }
+        val &= ~CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_CHARGE_Msk;
+        val |= DA1469X_ENCODE_V(v) << 
CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_CHARGE_Pos;
+    }
+    if (argc > 2 && strcmp("-", argv[2]) != 0) {
+        v = (uint32_t)parse_ll_bounds(argv[2], 2800, 4900, &rc);
+        if (rc) {
+            console_printf("V_PRECHARGE should be in range 2800-4900\n");
+            return 0;
+        }
+        val &= ~CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_PRECHARGE_Msk;
+        val |= DA1469X_ENCODE_V(v) << 
CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_PRECHARGE_Pos;
+    }
+    if (argc > 3 && strcmp("-", argv[3]) != 0) {
+        v = (uint32_t)parse_ll_bounds(argv[3], 2800, 4900, &rc);
+        if (rc) {
+            console_printf("V_REPLENISH should be in range 2800-4900\n");
+            return 0;
+        }
+        val &= ~CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_REPLENISH_Msk;
+        val |= DA1469X_ENCODE_V(v) << 
CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_REPLENISH_Pos;
+    }
+    if (argc > 4 && strcmp("-", argv[4]) != 0) {
+        v = (uint32_t)parse_ll_bounds(argv[4], 2800, 4900, &rc);
+        if (rc) {
+            console_printf("V_OVP should be in range 2800-4900\n");
+            return 0;
+        }
+        val &= ~CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_OVP_Msk;
+        val |= DA1469X_ENCODE_V(v) << 
CHARGER_CHARGER_VOLTAGE_PARAM_REG_V_OVP_Pos;
+    }
+    CHARGER->CHARGER_VOLTAGE_PARAM_REG = val;
+
+    return 0;
+}
+
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+
+int
+da1469x_charger_status_changed(struct charge_control *ctrl, void *arg,
+                               void *val, charge_control_type_t type)
+{
+    charge_control_status_t status;
+    charge_control_fault_t fault;
+
+    if (type == CHARGE_CONTROL_TYPE_STATUS) {
+        status = *(charge_control_status_t *)val;
+        switch (status) {
+        case CHARGE_CONTROL_STATUS_DISABLED:
+            console_printf("charger: charging disabled\n");
+            break;
+        case CHARGE_CONTROL_STATUS_NO_SOURCE:
+            console_printf("charger: not connected\n");
+            break;
+        case CHARGE_CONTROL_STATUS_CHARGING:
+            console_printf("charger: charging\n");
+            break;
+        case CHARGE_CONTROL_STATUS_CHARGE_COMPLETE:
+            console_printf("charger: charge complete\n");
+            break;
+        case CHARGE_CONTROL_STATUS_SUSPEND:
+            console_printf("charger: charge suspended due to temperature\n");
+            break;
+        case CHARGE_CONTROL_STATUS_FAULT:
+            console_printf("charger: fault Vbat to high or charge time 
exceeded\n");
+            break;
+        case CHARGE_CONTROL_STATUS_OTHER:
+            break;
+        }
+    } else if (type == CHARGE_CONTROL_TYPE_FAULT) {
+        fault = *(charge_control_fault_t *)val;
+        switch (fault) {
+        case CHARGE_CONTROL_FAULT_OV:
+            console_printf("charger: fault overvoltage\n");
+            break;
+        case CHARGE_CONTROL_FAULT_THERM:
+            console_printf("charger: fault over temperature\n");
+            break;
+        default:
+            break;
+        }
+    }
+    return 0;
+}
+
+struct charge_control_listener da1469x_listener = {
+    .ccl_type = CHARGE_CONTROL_TYPE_STATUS | CHARGE_CONTROL_TYPE_FAULT,
+    .ccl_func = da1469x_charger_status_changed,
+};
+
+static struct da1469x_charger_dev *charger;
+
+static int
+da1469x_charger_shell_cmd_listen(int argc, char **argv)
+{
+    if (argc > 1) {
+        if (strcmp("start", argv[1]) == 0) {
+            if (charger == NULL) {
+                charger = (struct da1469x_charger_dev *)os_dev_open("charger", 
1, NULL);
+                if (charger) {
+                    charge_control_register_listener(&charger->chg_ctrl, 
&da1469x_listener);
+                }
+
+            }
+        } else if (strcmp("stop", argv[1]) == 0) {
+            if (charger) {
+                charge_control_unregister_listener(&charger->chg_ctrl, 
&da1469x_listener);
+                os_dev_close(&charger->dev);
+                charger = NULL;
+            }
+        }
+    }
+    return 0;
+}
+
+#endif /* MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL) */
+
+static int
+da1469x_charger_shell_cmd(int argc, char **argv)
+{
+    if (argc == 1) {
+        return da1469x_charger_help();
+    }
+
+    argv++;
+    argc--;
+    if (strcmp(argv[0], "help") == 0) {
+        return da1469x_charger_help();
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    } else if (strcmp(argv[0], "decode") == 0) {
+        return da1469x_charger_shell_cmd_decode(argc, argv);
+#endif
+    } else if (strcmp(argv[0], "dump") == 0) {
+        return da1469x_charger_shell_cmd_dump(argc, argv);
+    } else if (strcmp(argv[0], "enable") == 0) {
+        return da1469x_charger_shell_cmd_enable(argc, argv);
+    } else if (strcmp(argv[0], "disable") == 0) {
+        return da1469x_charger_shell_cmd_disable(argc, argv);
+    } else if (strcmp(argv[0], "status") == 0) {
+        return da1469x_charger_shell_cmd_status(argc, argv);
+    } else if (strcmp(argv[0], "seti") == 0) {
+        return da1469x_charger_shell_cmd_set_i(argc, argv);
+    } else if (strcmp(argv[0], "setv") == 0) {
+        return da1469x_charger_shell_cmd_set_v(argc, argv);
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+    } else if (strcmp(argv[0], "listen") == 0) {
+        return da1469x_charger_shell_cmd_listen(argc, argv);
+#endif
+    }
+
+    return da1469x_charger_shell_err_unknown_arg(argv[1]);
+}
+
+static const struct shell_cmd da1469x_charger_shell_cmd_struct = {
+    .sc_cmd = "charger",
+    .sc_cmd_func = da1469x_charger_shell_cmd
+};
+
+static int
+da1469x_charger_reg_cmd(int argc, char **argv)
+{
+    const struct reg *reg = NULL;
+    uint32_t val;
+    int status;
+    int i;
+    bool dump = false;
+    bool decode = da1469x_charger_cli_decode_fields;
+
+    for (i = 0; i < NUM_CHARGER_REGS; ++i) {
+        if (strcasecmp(charger_regs[i].name, argv[0]) == 0) {
+            reg = charger_regs + i;
+        }
+    }
+    if (!reg) {
+        return 0;
+    }
+
+    if (argc == 1) {
+        dump = true;
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    } else if (strcmp(argv[1], "decode") == 0) {
+        dump = true;
+        decode = true;
+#endif
+    } else {
+        val = (uint32_t)parse_ull_bounds(argv[1], 0, 0xFFFFFFFF, &status);
+        if (status) {
+            console_printf("Invalid register value %s\n", argv[1]);
+            return 0;
+        }
+
+    }
+    if (dump) {
+        val = *reg->addr;
+        da1469x_charger_dump_register(reg, val, decode);
+    } else {
+        *reg->addr = val;
+    }
+
+    return 0;
+}
+
+static const struct shell_cmd da1469x_charger_cmds[] = {
+#if MYNEWT_VAL(DA1469X_CHARGER_CLI_DECODE)
+    { "decode", da1469x_charger_shell_cmd_decode, HELP(decode) },
+#endif
+    { "dump", da1469x_charger_shell_cmd_dump, HELP(dump) },
+    { "enable", da1469x_charger_shell_cmd_enable, HELP(enable) },
+    { "disable", da1469x_charger_shell_cmd_disable, HELP(disable) },
+    { "status", da1469x_charger_shell_cmd_status, HELP(status) },
+    { "clrirq", da1469x_charger_shell_cmd_clear_irq, HELP(clear_irq) },
+    { "seti", da1469x_charger_shell_cmd_set_i, HELP(set_i) },
+    { "setv", da1469x_charger_shell_cmd_set_v, HELP(set_v) },
+#if MYNEWT_VAL(DA1469X_CHARGER_USE_CHARGE_CONTROL)
+    { "listen", da1469x_charger_shell_cmd_listen, HELP(listen) },
+#endif
+    { REG_NAME(CTRL), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(STATUS), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(VOLTAGE_PARAM), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(CURRENT_PARAM), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(TEMPSET_PARAM), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(PRE_CHARGE_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(CC_CHARGE_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(CV_CHARGE_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(TOTAL_CHARGE_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(JEITA_V_CHARGE), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(JEITA_V_PRECHARGE), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(JEITA_V_REPLENISH), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(JEITA_V_OVP), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(JEITA_CURRENT), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(VBAT_COMP_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(VOVP_COMP_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(TDIE_COMP_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(TBAT_MON_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(TBAT_COMP_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(THOT_COMP_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(PWR_UP_TIMER), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(STATE_IRQ_MASK), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(ERROR_IRQ_MASK), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(STATE_IRQ_STATUS), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(ERROR_IRQ_STATUS), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(STATE_IRQ_CLR), da1469x_charger_reg_cmd, HELP(reg) },
+    { REG_NAME(ERROR_IRQ_CLR), da1469x_charger_reg_cmd, HELP(reg) },
+    { NULL, NULL, NULL }
+};
+
+int
+da1469x_charger_shell_init(struct da1469x_charger_dev *dev)
+{
+    int rc;
+    (void)dev;
+
+    rc = shell_cmd_register(&da1469x_charger_shell_cmd_struct);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    rc = shell_register("charger", da1469x_charger_cmds);
+    return rc;
+}
+
+#endif
diff --git a/hw/drivers/chg_ctrl/da1469x_charger/syscfg.yml 
b/hw/drivers/chg_ctrl/da1469x_charger/syscfg.yml
new file mode 100644
index 0000000..83ed95d
--- /dev/null
+++ b/hw/drivers/chg_ctrl/da1469x_charger/syscfg.yml
@@ -0,0 +1,76 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+syscfg.defs:
+    DA1469X_CHARGER:
+        description: 'Charger included in build'
+        value: 1
+    DA1469X_CHARGER_CLI:
+        description: 'Enable shell support for the charger'
+        value: 0
+    DA1469X_CHARGER_CLI_DECODE:
+        description: 'Decode registers fields in shell'
+        value: 0
+    DA1469X_CHARGER_USE_CHARGE_CONTROL:
+        description: 'Enable charge control integration'
+        value: 1
+    DA1469X_CHARGER_NTC_ENABLE:
+        description: >
+            Enable NTC. Set this only if NTC is connected to P0_7 and P1_0.
+            When left disable battery temperature will not be monitored.
+        value: 0
+    DA1469X_CHARGER_TBAT_MONITOR_MODE:
+        description: >
+            Battery monitor mode.
+            0 - Battery temperature state checked and updated once, as soon as 
the charger is powered-up and settled
+            1 - Battery temperature state checked periodically
+            2 - Battery temperature state checked periodically
+            3 - When selected, it freezes the Battery temperature monitor FSM
+            Set to 3 when NTC is not present, if not charging current can be 
changed by JEITA settings on false
+            temperature readings.
+        range: 0..3
+        value: 3
+    DA1469X_CHARGER_V_OVP:
+        descrition: >
+            Over-voltage protection level in (mV)
+        value: 4400
+    DA1469X_CHARGER_V_REPLENISH:
+        descrition: >
+            Voltage to start charging after reaching ond of charge state (mV)
+        value: 4060
+    DA1469X_CHARGER_V_PRECHARGE:
+        descrition: >
+            The voltage level at which the battery is considered as 
Pre-charged (mv)
+        value: 3200
+    DA1469X_CHARGER_V_CHARGE:
+        descrition: >
+            Charging voltage (mv)
+        value: 4260
+    DA1469X_CHARGER_I_PRECHARGE:
+        descrition: >
+            Pre-charge current (mA)
+        value: 2
+    DA1469X_CHARGER_I_CHARGE:
+        descrition: >
+            Charge current (mA)
+        value: 35
+    DA1469X_CHARGER_I_END_OF_CHARGE:
+        description: >
+            End of charge current settings, 4-35 (%).
+        value: 7

Reply via email to