blob: 683e701306c35d2cb34186653c6c5c5e14da56a1 [file] [log] [blame]
/*
* 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 "os/mynewt.h"
#include "charge-control/charge_control.h"
#include "charge_control_priv.h"
/* =================================================================
* ====================== LOCAL FUNCTION DECLARATIONS ==============
* =================================================================
*/
/* ---------------------------- OS -------------------------------- */
static void charge_control_read_ev_cb(struct os_event *ev);
static void charge_control_mgr_wakeup_event(struct os_event *);
static void charge_control_base_ts_update_event(struct os_event *);
/* ---------------------- CHARGE CONTROL --------------------------- */
/**
* Prevents changes to a charge control device during an operation
*
* @param Charge control device to lock
*
* @return 0 on success, non-zero error code on failure
*/
static int charge_control_lock(struct charge_control *);
/**
* Releases mutex lock on charge control device
*
* @param Charge control device to release
*/
static void charge_control_unlock(struct charge_control *);
/**
* Thread-safe operation to change poll rate on charge control device
*/
static void
charge_control_update_poll_rate(struct charge_control *, uint32_t);
static os_time_t
charge_control_calc_nextrun_delta(struct charge_control *, os_time_t);
static struct charge_control *
charge_control_find_min_nextrun(os_time_t, os_time_t *);
static void
charge_control_update_nextrun(struct charge_control *, os_time_t);
static int
charge_control_read_data_func(struct charge_control *, void *, void *,
charge_control_type_t);
static void
charge_control_up_timestamp(struct charge_control *);
static int
charge_control_insert_type_trait(struct charge_control *,
struct charge_control_type_traits *);
static int
charge_control_remove_type_trait(struct charge_control *,
struct charge_control_type_traits *);
/**
* Search the charge control type traits list for a specific type of charge
* controller. Set the charge control pointer to NULL to start from the
* beginning of the list or to a specific charge control object to begin from
* that point in the list.
*
* @param The charge controller type to search for
* @param Pointer to a charge controller
*
* @return NULL when no charge control type is found, pointer to a
* charge_control_type_traits structure when found.
*/
static struct charge_control_type_traits *
charge_control_get_type_traits_bytype(charge_control_type_t,
struct charge_control *);
static struct charge_control *
charge_control_get_type_traits_byname(char *,
struct charge_control_type_traits **, charge_control_type_t);
static uint8_t
charge_control_type_traits_empty(struct charge_control *);
static void
charge_control_poll_per_type_trait(struct charge_control *, os_time_t,
os_time_t);
/* ---------------------- CHARGE CONTROL MANAGER ------------------- */
/**
* Pends on the charge control manager mutex indefinitely. Must be used prior
* to operations which iterate through the list of charge controllers.
*
* @return 0 on success, non-zero error code on failure.
*/
static int
charge_control_mgr_lock(void);
/** Releases the charge control manager mutex. */
static void
charge_control_mgr_unlock(void);
static int
charge_control_mgr_match_bydevname(struct charge_control *, void *arg);
static void
charge_control_mgr_remove(struct charge_control *);
static void
charge_control_mgr_insert(struct charge_control *);
static void
charge_control_mgr_poll_bytype(struct charge_control *, charge_control_type_t,
struct charge_control_type_traits *, os_time_t);
static void
charge_control_mgr_evq_set(struct os_eventq *);
static void
charge_control_mgr_init(void);
/* =================================================================
* ====================== LOCAL STRUCTS/VARIABLES ==================
* =================================================================
*/
/**
* Declaration and definition of manager for the list of charge control devices
*/
struct {
/** Locks list for manipulation/search operations */
struct os_mutex mgr_lock;
/** Manages poll rates of the charge control devices */
struct os_callout mgr_wakeup_callout;
/** Event queue to which wakeup events are added */
struct os_eventq *mgr_eventq;
/** Charge control device list */
SLIST_HEAD(, charge_control) mgr_charge_control_list;
} charge_control_mgr;
struct charge_control_read_ctx {
charge_control_data_func_t user_func;
void *user_arg;
};
struct charge_control_timestamp charge_control_base_ts;
/** OS Callout to update charge control timestamp */
struct os_callout cct_up_osco;
/** Event for performing a charge control read */
static struct os_event charge_control_read_event = {
.ev_cb = charge_control_read_ev_cb,
};
/* =================================================================
* ====================== PKG ======================================
* =================================================================
*/
void charge_control_pkg_init(void)
{
/* Ensure this function only gets called by sysinit. */
SYSINIT_ASSERT_ACTIVE();
charge_control_mgr_init();
#if MYNEWT_VAL(CHARGE_CONTROL_CLI)
charge_control_shell_register();
#endif
}
/* =================================================================
* ====================== OS =======================================
* =================================================================
*/
static void
charge_control_read_ev_cb(struct os_event *ev)
{
int rc;
struct charge_control_read_ev_ctx *ccrec;
ccrec = ev->ev_arg;
rc = charge_control_read(ccrec->ccrec_charge_control, ccrec->ccrec_type,
NULL, NULL, OS_TIMEOUT_NEVER);
assert(rc == 0);
}
static void
charge_control_mgr_wakeup_event(struct os_event *ev)
{
struct charge_control *cursor;
os_time_t now;
os_time_t next_wakeup;
now = os_time_get();
#if MYNEWT_VAL(SENSOR_POLL_TEST_LOG)
ccmgr_wakeup[ccmgr_wakeup_idx++%500] = now;
#endif
charge_control_mgr_lock();
cursor = NULL;
while (1) {
cursor = charge_control_find_min_nextrun(now, &next_wakeup);
charge_control_lock(cursor);
/* Charge controllers that are not periodic are inserted at the end of
* the charge_control list.
*/
if (!cursor->cc_poll_rate) {
charge_control_unlock(cursor);
charge_control_mgr_unlock();
return;
}
/* List is sorted by what runs first. If we reached the first element
* that doesn't run, break out.
*/
if (next_wakeup > 0) {
break;
}
if (charge_control_type_traits_empty(cursor)) {
charge_control_mgr_poll_bytype(cursor, cursor->cc_mask, NULL, now);
} else {
charge_control_poll_per_type_trait(cursor, now, next_wakeup);
}
charge_control_update_nextrun(cursor, now);
charge_control_unlock(cursor);
}
charge_control_mgr_unlock();
os_callout_reset(&charge_control_mgr.mgr_wakeup_callout, next_wakeup);
}
static void
charge_control_base_ts_update_event(struct os_event *ev)
{
os_time_t ticks;
int rc;
struct os_timeval ostv;
struct os_timezone ostz;
ticks = os_time_get();
rc = os_gettimeofday(&ostv, &ostz);
if (rc) {
/* There is nothing we can do here
* just reset the timer frequently if we
* fail to get time, till then we will keep using
* old timestamp values.
*/
ticks += OS_TICKS_PER_SEC * 600;
goto done;
}
/* CPU time gets wrapped in 4295 seconds since it is uint32_t,
* hence the hardcoded value of 3600 seconds, We want to make
* sure that the cputime never gets wrapped more than once.
* os_timeval usecs value gets wrapped in 2147 secs since it is int32_t.
* Hence, we take 2000 secs so that we update before it gets wrapped
* without cutting it too close.
*/
ticks += OS_TICKS_PER_SEC * 2000;
charge_control_base_ts.cct_ostv = ostv;
charge_control_base_ts.cct_ostz = ostz;
charge_control_base_ts.cct_cputime = os_cputime_get32();
done:
os_callout_reset(&cct_up_osco, ticks);
}
/* =================================================================
* ====================== CHARGE CONTROL ===========================
* =================================================================
*/
static int
charge_control_lock(struct charge_control *cc)
{
int rc;
rc = os_mutex_pend(&cc->cc_lock, OS_TIMEOUT_NEVER);
if (rc == 0 || rc == OS_NOT_STARTED) {
return (0);
}
return (rc);
}
static void
charge_control_unlock(struct charge_control *cc)
{
os_mutex_release(&cc->cc_lock);
}
static void
charge_control_update_poll_rate(struct charge_control * cc, uint32_t poll_rate)
{
charge_control_lock(cc);
cc->cc_poll_rate = poll_rate;
charge_control_unlock(cc);
}
static os_time_t
charge_control_calc_nextrun_delta(struct charge_control * cc, os_time_t now)
{
os_time_t charge_control_ticks;
int delta;
charge_control_lock(cc);
delta = (int32_t)(cc->cc_next_run - now);
if (delta < 0) {
/* This fires the callout right away */
charge_control_ticks = 0;
} else {
charge_control_ticks = delta;
}
charge_control_unlock(cc);
return charge_control_ticks;
}
static struct charge_control *
charge_control_find_min_nextrun(os_time_t now, os_time_t *min_nextrun)
{
struct charge_control *head;
head = NULL;
charge_control_mgr_lock();
head = SLIST_FIRST(&charge_control_mgr.mgr_charge_control_list);
*min_nextrun = charge_control_calc_nextrun_delta(head, now);
charge_control_mgr_unlock();
return head;
}
static void
charge_control_update_nextrun(struct charge_control *cc, os_time_t now)
{
os_time_t charge_control_ticks;
os_time_ms_to_ticks(cc->cc_poll_rate, &charge_control_ticks);
charge_control_lock(cc);
/* Remove the charge_control from the charge_control list for insert. */
charge_control_mgr_remove(cc);
/* Set next wakeup, and insert the charge_control back into the
* list.
*/
cc->cc_next_run = charge_control_ticks + now;
/* Re-insert the charge_control manager, with the new wakeup time. */
charge_control_mgr_insert(cc);
charge_control_unlock(cc);
}
static int
charge_control_read_data_func(struct charge_control *cc, void *arg,
void *data, charge_control_type_t type)
{
struct charge_control_listener *listener;
struct charge_control_read_ctx *ctx;
ctx = (struct charge_control_read_ctx *) arg;
if ((uint8_t)(uintptr_t)(ctx->user_arg) != CHARGE_CONTROL_IGN_LISTENER) {
/* Notify all listeners first */
SLIST_FOREACH(listener, &cc->cc_listener_list, ccl_next) {
if (listener->ccl_type & type) {
listener->ccl_func(cc, listener->ccl_arg, data, type);
}
}
}
/* Call data function */
if (ctx->user_func != NULL) {
return (ctx->user_func(cc, ctx->user_arg, data, type));
} else {
return (0);
}
}
static void charge_control_up_timestamp(struct charge_control *cc)
{
uint32_t curr_ts_ticks;
uint32_t ts;
curr_ts_ticks = os_cputime_get32();
ts = os_cputime_ticks_to_usecs(curr_ts_ticks -
charge_control_base_ts.cct_cputime);
/* Updating cputime */
charge_control_base_ts.cct_cputime = cc->cc_sts.cct_cputime = curr_ts_ticks;
/* Updating seconds */
charge_control_base_ts.cct_ostv.tv_sec =
charge_control_base_ts.cct_ostv.tv_sec
+ (ts + charge_control_base_ts.cct_ostv.tv_usec)/1000000;
cc->cc_sts.cct_ostv.tv_sec = charge_control_base_ts.cct_ostv.tv_sec;
/* Updating Micro seconds */
charge_control_base_ts.cct_ostv.tv_usec =
(charge_control_base_ts.cct_ostv.tv_usec + ts)%1000000;
cc->cc_sts.cct_ostv.tv_usec = charge_control_base_ts.cct_ostv.tv_usec;
}
static int
charge_control_insert_type_trait(struct charge_control *cc,
struct charge_control_type_traits *cctt)
{
struct charge_control_type_traits *cursor, *prev;
int rc;
rc = charge_control_lock(cc);
if (rc != 0) {
goto err;
}
prev = cursor = NULL;
SLIST_FOREACH(cursor, &cc->cc_type_traits_list, cctt_next) {
if (cursor->cctt_poll_n == 0) {
break;
}
if (OS_TIME_TICK_LT(cctt->cctt_poll_n, cursor->cctt_poll_n)) {
break;
}
prev = cursor;
}
if (prev == NULL) {
SLIST_INSERT_HEAD(&cc->cc_type_traits_list, cctt, cctt_next);
}
else {
SLIST_INSERT_AFTER(prev, cctt, cctt_next);
}
charge_control_unlock(cc);
return 0;
err:
return rc;
}
static int
charge_control_remove_type_trait(struct charge_control *cc,
struct charge_control_type_traits *cctt)
{
int rc;
rc = charge_control_lock(cc);
if (rc != 0) {
goto err;
}
/* Remove this entry from the list */
SLIST_REMOVE(&cc->cc_type_traits_list, cctt, charge_control_type_traits,
cctt_next);
charge_control_unlock(cc);
return (0);
err:
return (rc);
}
static struct charge_control_type_traits *
charge_control_get_type_traits_bytype(charge_control_type_t type,
struct charge_control * cc)
{
struct charge_control_type_traits *cctt;
cctt = NULL;
charge_control_lock(cc);
SLIST_FOREACH(cctt, &cc->cc_type_traits_list, cctt_next) {
if (cctt->cctt_charge_control_type == type) {
break;
}
}
charge_control_unlock(cc);
return cctt;
}
static struct charge_control *
charge_control_get_type_traits_byname(char *devname,
struct charge_control_type_traits **cctt, charge_control_type_t type)
{
struct charge_control *cc;
cc = charge_control_mgr_find_next_bydevname(devname, NULL);
if (!cc) {
goto err;
}
*cctt = charge_control_get_type_traits_bytype(type, cc);
err:
return cc;
}
static uint8_t
charge_control_type_traits_empty(struct charge_control * cc)
{
return SLIST_EMPTY(&cc->cc_type_traits_list);
}
static void
charge_control_poll_per_type_trait(struct charge_control *cc, os_time_t now,
os_time_t next_wakeup)
{
struct charge_control_type_traits *cctt;
/* Lock the charge controller */
charge_control_lock(cc);
SLIST_FOREACH(cctt, &cc->cc_type_traits_list, cctt_next) {
/* poll multiple is one if no multiple is specified,
* as a result, the charge controller would get polled at the
* poll rate if no multiple is specified
*
* If a multiple is specified, the charge controller would get polled
* at the poll multiple
*/
charge_control_mgr_poll_bytype(cc, cctt->cctt_charge_control_type, cctt,
now);
}
/* Unlock the charge controller to allow other access */
charge_control_unlock(cc);
}
int
charge_control_init(struct charge_control *cc, struct os_dev *dev)
{
int rc;
memset(cc, 0, sizeof(*cc));
rc = os_mutex_init(&cc->cc_lock);
if (rc != 0) {
goto err;
}
cc->cc_dev = dev;
return (0);
err:
return (rc);
}
int
charge_control_register_listener(struct charge_control *cc,
struct charge_control_listener *listener)
{
int rc;
rc = charge_control_lock(cc);
if (rc != 0) {
goto err;
}
SLIST_INSERT_HEAD(&cc->cc_listener_list, listener, ccl_next);
charge_control_unlock(cc);
return (0);
err:
return (rc);
}
int
charge_control_unregister_listener(struct charge_control *cc,
struct charge_control_listener *listener)
{
int rc;
rc = charge_control_lock(cc);
if (rc != 0) {
goto err;
}
/* Remove this entry from the list */
SLIST_REMOVE(&cc->cc_listener_list, listener, charge_control_listener,
ccl_next);
charge_control_unlock(cc);
return (0);
err:
return (rc);
}
int
charge_control_read(struct charge_control *cc, charge_control_type_t type,
charge_control_data_func_t data_func, void *arg, uint32_t timeout)
{
struct charge_control_read_ctx ccrc;
int rc;
rc = charge_control_lock(cc);
if (rc) {
goto err;
}
ccrc.user_func = data_func;
ccrc.user_arg = arg;
if (!charge_control_mgr_match_bytype(cc, (void *)&type)) {
rc = SYS_ENOENT;
goto err;
}
charge_control_up_timestamp(cc);
rc = cc->cc_funcs->ccd_read(cc, type, charge_control_read_data_func, &ccrc,
timeout);
if (rc) {
goto err;
}
err:
charge_control_unlock(cc);
return (rc);
}
/* =================================================================
* ====================== CHARGE CONTROL MANAGER ===================
* =================================================================
*/
static int
charge_control_mgr_lock(void)
{
int rc;
rc = os_mutex_pend(&charge_control_mgr.mgr_lock, OS_TIMEOUT_NEVER);
if (rc == 0 || rc == OS_NOT_STARTED) {
return (0);
}
return rc;
}
static void
charge_control_mgr_unlock(void)
{
(void) os_mutex_release(&charge_control_mgr.mgr_lock);
}
static int
charge_control_mgr_match_bydevname(struct charge_control *cc, void *arg)
{
char *devname;
devname = (char *) arg;
if (!strcmp(cc->cc_dev->od_name, devname)) {
return (1);
}
return (0);
}
static void
charge_control_mgr_remove(struct charge_control *cc)
{
SLIST_REMOVE(&charge_control_mgr.mgr_charge_control_list, cc,
charge_control, cc_next);
}
static void
charge_control_mgr_insert(struct charge_control *cc)
{
struct charge_control *cursor, *prev;
prev = cursor = NULL;
if (!cc->cc_poll_rate) {
SLIST_FOREACH(cursor, &charge_control_mgr.mgr_charge_control_list, cc_next) {
prev = cursor;
}
goto insert;
}
prev = cursor = NULL;
SLIST_FOREACH(cursor, &charge_control_mgr.mgr_charge_control_list, cc_next) {
if (!cursor->cc_poll_rate) {
break;
}
if (OS_TIME_TICK_LT(cc->cc_next_run, cursor->cc_next_run)) {
break;
}
prev = cursor;
}
insert:
if (prev == NULL) {
SLIST_INSERT_HEAD(&charge_control_mgr.mgr_charge_control_list, cc,
cc_next);
} else {
SLIST_INSERT_AFTER(prev, cc, cc_next);
}
}
static void
charge_control_mgr_poll_bytype(struct charge_control *cc,
charge_control_type_t type, struct charge_control_type_traits *cctt,
os_time_t now)
{
if (!cctt || !cctt->cctt_polls_left) {
/* Charge control read results. Every time a charge controller is read,
* all of its listeners are called by default. Specify NULL as a
* callback, because we just want to run all the listeners.
*/
charge_control_read(cc, type, NULL, NULL, OS_TIMEOUT_NEVER);
charge_control_lock(cc);
if (cctt) {
if (!cctt->cctt_polls_left && cctt->cctt_poll_n) {
cctt->cctt_polls_left = cctt->cctt_poll_n;
cctt->cctt_polls_left--;
}
}
/* Unlock the sensor to allow other access */
charge_control_unlock(cc);
} else {
cctt->cctt_polls_left--;
}
}
static void
charge_control_mgr_evq_set(struct os_eventq *evq)
{
assert(evq != NULL);
charge_control_mgr.mgr_eventq = evq;
}
static void
charge_control_mgr_init(void)
{
struct os_timeval ostv;
struct os_timezone ostz;
#ifdef MYNEWT_VAL_CHARGE_CONTROL_MGR_EVQ
charge_control_mgr_evq_set(MYNEWT_VAL(CHARGE_CONTROL_MGR_EVQ));
#else
charge_control_mgr_evq_set(os_eventq_dflt_get());
#endif
/**
* Initialize charge control polling callout and set it to fire on boot.
*/
os_callout_init(&charge_control_mgr.mgr_wakeup_callout,
charge_control_mgr_evq_get(), charge_control_mgr_wakeup_event,
NULL);
/* Initialize sensor cputime update callout and set it to fire after an
* hour, CPU time gets wrapped in 4295 seconds,
* hence the hardcoded value of 3600 seconds, We make sure that the
* cputime never gets wrapped more than once.
*/
os_gettimeofday(&ostv, &ostz);
charge_control_base_ts.cct_ostv = ostv;
charge_control_base_ts.cct_ostz = ostz;
charge_control_base_ts.cct_cputime = os_cputime_get32();
os_callout_init(&cct_up_osco, charge_control_mgr_evq_get(),
charge_control_base_ts_update_event, NULL);
os_callout_reset(&cct_up_osco, OS_TICKS_PER_SEC);
os_mutex_init(&charge_control_mgr.mgr_lock);
}
int
charge_control_mgr_register(struct charge_control *cc)
{
int rc;
rc = charge_control_mgr_lock();
if (rc != 0) {
goto err;
}
rc = charge_control_lock(cc);
if (rc != 0) {
goto err;
}
charge_control_mgr_insert(cc);
charge_control_unlock(cc);
charge_control_mgr_unlock();
return (0);
err:
return (rc);
}
struct os_eventq *
charge_control_mgr_evq_get(void)
{
return (charge_control_mgr.mgr_eventq);
}
struct charge_control *
charge_control_mgr_find_next(charge_control_mgr_compare_func_t compare_func,
void *arg, struct charge_control *prev_cursor)
{
struct charge_control *cursor;
int rc;
cursor = NULL;
/* Couldn't acquire lock of charge control list, exit */
rc = charge_control_mgr_lock();
if (rc != 0) {
goto done;
}
cursor = prev_cursor;
if (cursor == NULL) {
cursor = SLIST_FIRST(&charge_control_mgr.mgr_charge_control_list);
} else {
cursor = SLIST_NEXT(prev_cursor, cc_next);
}
while (cursor != NULL) {
if (compare_func(cursor, arg)) {
break;
}
cursor = SLIST_NEXT(cursor, cc_next);
}
charge_control_mgr_unlock();
done:
return (cursor);
}
struct charge_control *
charge_control_mgr_find_next_bytype(charge_control_type_t type,
struct charge_control *prev_cursor)
{
return (charge_control_mgr_find_next(charge_control_mgr_match_bytype,
(void *) &type, prev_cursor));
}
struct charge_control *
charge_control_mgr_find_next_bydevname(char *devname,
struct charge_control *prev_cursor)
{
return (charge_control_mgr_find_next(charge_control_mgr_match_bydevname,
devname, prev_cursor));
}
int
charge_control_mgr_match_bytype(struct charge_control *cc, void *arg)
{
charge_control_type_t *type;
type = (charge_control_type_t *) arg;
/* cc_types is a bitmask that contains the supported charge control types
* for this charge controller, and type is the bitmask we're searching for
* We also look at the mask as the driver might be configured to work in a
* mode where only some of the charge control types are supported but not
* all. Compare the three, and if there is a match, return 1. If it is not
* supported, return 0.
*/
return (*type & cc->cc_types & cc->cc_mask) ? 1 : 0;
}
int
charge_control_set_poll_rate_ms(char *devname, uint32_t poll_rate)
{
struct charge_control *charge_control;
os_time_t next_wakeup;
os_time_t now;
int rc;
os_callout_stop(&charge_control_mgr.mgr_wakeup_callout);
charge_control = charge_control_mgr_find_next_bydevname(devname, NULL);
if (!charge_control) {
rc = SYS_EINVAL;
goto err;
}
charge_control_lock(charge_control);
now = os_time_get();
os_time_ms_to_ticks(poll_rate, &next_wakeup);
charge_control_update_poll_rate(charge_control, poll_rate);
charge_control_update_nextrun(charge_control, now);
charge_control_unlock(charge_control);
charge_control = charge_control_find_min_nextrun(now, &next_wakeup);
os_callout_reset(&charge_control_mgr.mgr_wakeup_callout, next_wakeup);
return 0;
err:
return rc;
}
int
charge_control_set_n_poll_rate(char * devname,
struct charge_control_type_traits *cctt)
{
struct charge_control *cc;
struct charge_control_type_traits *cctt_tmp;
int rc;
if (!cctt) {
rc = SYS_EINVAL;
goto err;
}
cctt_tmp = NULL;
cc = charge_control_get_type_traits_byname(devname, &cctt_tmp,
cctt->cctt_charge_control_type);
if (!cc) {
rc = SYS_EINVAL;
goto err;
}
if (!cctt_tmp && cctt) {
rc = charge_control_insert_type_trait(cc, cctt);
rc |= charge_control_lock(cc);
if (rc) {
goto err;
}
cctt_tmp = cctt;
cctt_tmp->cctt_polls_left = cctt->cctt_poll_n;
charge_control_unlock(cc);
} else if (cctt_tmp) {
rc = charge_control_remove_type_trait(cc, cctt_tmp);
if (rc) {
goto err;
}
charge_control_lock(cc);
cctt_tmp->cctt_poll_n = cctt->cctt_poll_n;
cctt_tmp->cctt_polls_left = cctt->cctt_poll_n;
charge_control_unlock(cc);
rc = charge_control_insert_type_trait(cc, cctt_tmp);
if (rc) {
goto err;
}
} else {
rc = SYS_EINVAL;
goto err;
}
return 0;
err:
return rc;
}
void
charge_control_mgr_put_read_evt(void *arg)
{
charge_control_read_event.ev_arg = arg;
os_eventq_put(charge_control_mgr_evq_get(), &charge_control_read_event);
}