| /* |
| * 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 |
| * resarding 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 <assert.h> |
| #include <string.h> |
| |
| #include "os/mynewt.h" |
| #include "hal/hal_gpio.h" |
| #include "bq24040/bq24040.h" |
| #include "console/console.h" |
| #include "log/log.h" |
| |
| /* Exports for the charge control API */ |
| static int bq24040_chg_ctrl_read(struct charge_control *, charge_control_type_t, |
| charge_control_data_func_t, void *, uint32_t); |
| static int bq24040_chg_ctrl_get_config(struct charge_control *, |
| charge_control_type_t, struct charge_control_cfg *); |
| static int bq24040_chg_ctrl_set_config(struct charge_control *, void *); |
| static int bq24040_chg_ctrl_get_status(struct charge_control *, int *); |
| static int bq24040_chg_ctrl_enable(struct charge_control *); |
| static int bq24040_chg_ctrl_disable(struct charge_control *); |
| |
| static const struct charge_control_driver g_bq24040_chg_ctrl_driver = { |
| .ccd_read = bq24040_chg_ctrl_read, |
| .ccd_get_config = bq24040_chg_ctrl_get_config, |
| .ccd_set_config = bq24040_chg_ctrl_set_config, |
| .ccd_get_status = bq24040_chg_ctrl_get_status, |
| .ccd_get_fault = NULL, |
| .ccd_enable = bq24040_chg_ctrl_enable, |
| .ccd_disable = bq24040_chg_ctrl_disable, |
| }; |
| |
| static int |
| bq24040_configure_pin(struct bq24040_pin *pin) |
| { |
| if ((!pin) || (pin->bp_pin_num == -1)) { |
| return 0; |
| } |
| |
| if (pin->bp_pin_direction == HAL_GPIO_MODE_IN) { |
| if (pin->bp_irq_trig != HAL_GPIO_TRIG_NONE) { |
| assert(pin->bp_irq_fn != NULL); |
| return hal_gpio_irq_init(pin->bp_pin_num, pin->bp_irq_fn, |
| NULL, pin->bp_irq_trig, pin->bp_pull); |
| } else { |
| return hal_gpio_init_in(pin->bp_pin_num, pin->bp_pull); |
| } |
| } else if (pin->bp_pin_direction == HAL_GPIO_MODE_OUT) { |
| return hal_gpio_init_out(pin->bp_pin_num, pin->bp_init_value); |
| } |
| |
| return SYS_EINVAL; |
| } |
| |
| int |
| bq24040_init(struct os_dev *dev, void *arg) |
| { |
| struct bq24040 *bq24040; |
| struct charge_control *cc; |
| int rc; |
| |
| if (!dev) { |
| rc = SYS_ENODEV; |
| goto err; |
| } |
| |
| bq24040 = (struct bq24040 *)dev; |
| |
| cc = &bq24040->b_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, |
| (struct charge_control_driver *)&g_bq24040_chg_ctrl_driver); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = charge_control_mgr_register(cc); |
| if (rc) { |
| goto err; |
| } |
| |
| bq24040->b_is_enabled = false; |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| int |
| bq24040_config(struct bq24040 *bq24040, struct bq24040_cfg *cfg) |
| { |
| int rc; |
| |
| rc = charge_control_set_type_mask(&(bq24040->b_chg_ctrl), cfg->bc_mask); |
| if (rc) { |
| goto err; |
| } |
| |
| bq24040->b_cfg = *cfg; |
| |
| rc = bq24040_configure_pin(cfg->bc_pg_pin); |
| if (rc) { |
| goto err; |
| } |
| |
| rc = bq24040_configure_pin(cfg->bc_chg_pin); |
| if (rc) { |
| goto err; |
| } |
| |
| if (cfg->bc_ts_mode == BQ24040_TS_MODE_DISABLED) { |
| rc = bq24040_configure_pin(cfg->bc_ts_pin); |
| if (rc) { |
| goto err; |
| } |
| } else { |
| bq24040->b_is_enabled = true; |
| } |
| |
| rc = bq24040_configure_pin(cfg->bc_iset2_pin); |
| if (rc) { |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return (rc); |
| } |
| |
| int |
| bq24040_get_charge_source_status(struct bq24040 *bq24040, int *status) |
| { |
| int read_val; |
| |
| if (bq24040->b_cfg.bc_pg_pin->bp_pin_num != -1) { |
| read_val = hal_gpio_read(bq24040->b_cfg.bc_pg_pin->bp_pin_num); |
| *status = read_val == 0 ? 1 : 0; |
| return 0; |
| } |
| return 1; |
| } |
| |
| int |
| bq24040_get_charging_status(struct bq24040 *bq24040, int *status) |
| { |
| int read_val; |
| |
| if (bq24040->b_cfg.bc_chg_pin->bp_pin_num != -1) { |
| read_val = hal_gpio_read(bq24040->b_cfg.bc_chg_pin->bp_pin_num); |
| *status = read_val == 0 ? 1 : 0; |
| return 0; |
| } |
| return 1; |
| } |
| |
| int |
| bq24040_enable(struct bq24040 *bq24040) |
| { |
| /* Don't enable if already enabled */ |
| if (bq24040->b_is_enabled) { |
| return 0; |
| } |
| |
| if (bq24040->b_cfg.bc_ts_pin->bp_pin_num != -1) { |
| hal_gpio_write(bq24040->b_cfg.bc_ts_pin->bp_pin_num, 1); |
| bq24040->b_is_enabled = true; |
| return 0; |
| } |
| return SYS_EINVAL; |
| } |
| |
| int |
| bq24040_disable(struct bq24040 *bq24040) |
| { |
| /* Don't disable if already disabled */ |
| if (!bq24040->b_is_enabled) { |
| return 0; |
| } |
| |
| if (bq24040->b_cfg.bc_ts_pin->bp_pin_num != -1) { |
| hal_gpio_write(bq24040->b_cfg.bc_ts_pin->bp_pin_num, 0); |
| bq24040->b_is_enabled = false; |
| return 0; |
| } |
| return SYS_EINVAL; |
| } |
| |
| /** |
| * Reads the charge source and charging status pins (if configured) |
| * |
| * @param The bq24040 charge controller to read from |
| * @param The type(s) of sensor values to read. Mask containing that type, provide |
| * all, to get all values. |
| * @param The function to call with each value read. If NULL, it calls all |
| * sensor listeners associated with this function. |
| * @param The argument to pass to the read callback. |
| * @param Timeout. If block until result, specify OS_TIMEOUT_NEVER, 0 returns |
| * immediately (no wait.) |
| * |
| * @return 0 on success, non-zero error code on failure. |
| */ |
| static int |
| bq24040_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) |
| { |
| int status; |
| int rc; |
| |
| if (!(type & CHARGE_CONTROL_TYPE_STATUS)) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| status = CHARGE_CONTROL_STATUS_DISABLED; |
| |
| rc = bq24040_chg_ctrl_get_status(cc, &status); |
| if (rc) { |
| goto err; |
| } |
| |
| data_func(cc, data_arg, (void*)&status, CHARGE_CONTROL_TYPE_STATUS); |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| /** |
| * Get the configuration of the bq24040. |
| * |
| * @param The type of sensor value to get configuration for |
| * @param A pointer to the config structure to place the returned result into. |
| * |
| * @return 0 on success, non-zero error code on failure. |
| */ |
| static int |
| bq24040_chg_ctrl_get_config(struct charge_control *cc, |
| charge_control_type_t type, struct charge_control_cfg * cfg) |
| { |
| int rc; |
| |
| if (!(type & CHARGE_CONTROL_TYPE_STATUS)) { |
| rc = SYS_EINVAL; |
| goto err; |
| } |
| |
| return 0; |
| err: |
| return rc; |
| } |
| |
| static int |
| bq24040_chg_ctrl_set_config(struct charge_control *cc, void *cfg) |
| { |
| struct bq24040* bq24040 = (struct bq24040 *)CHARGE_CONTROL_GET_DEVICE(cc); |
| |
| return bq24040_config(bq24040, (struct bq24040_cfg*)cfg); |
| } |
| |
| static int |
| bq24040_chg_ctrl_get_status(struct charge_control *cc, int * status) |
| { |
| struct bq24040 * bq24040; |
| int ch_src_present, is_charging; |
| int rc; |
| |
| bq24040 = (struct bq24040 *)CHARGE_CONTROL_GET_DEVICE(cc); |
| if (bq24040 == NULL) { |
| return SYS_ENODEV; |
| } |
| |
| if (bq24040->b_is_enabled) { |
| rc = bq24040_get_charge_source_status(bq24040, &ch_src_present); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = bq24040_get_charging_status(bq24040, &is_charging); |
| if (rc) { |
| return rc; |
| } |
| |
| if (ch_src_present) { |
| if (is_charging) { |
| *status = CHARGE_CONTROL_STATUS_CHARGING; |
| } else { |
| *status = CHARGE_CONTROL_STATUS_CHARGE_COMPLETE; |
| } |
| } else { |
| *status = CHARGE_CONTROL_STATUS_NO_SOURCE; |
| } |
| } else { |
| *status = CHARGE_CONTROL_STATUS_DISABLED; |
| } |
| |
| return 0; |
| } |
| |
| static int |
| bq24040_chg_ctrl_enable(struct charge_control *cc) |
| { |
| struct bq24040 *bq24040 = (struct bq24040 *)CHARGE_CONTROL_GET_DEVICE(cc); |
| |
| if (bq24040 == NULL) { |
| return SYS_ENODEV; |
| } |
| |
| return bq24040_enable(bq24040); |
| } |
| |
| static int |
| bq24040_chg_ctrl_disable(struct charge_control *cc) |
| { |
| struct bq24040 *bq24040 = (struct bq24040 *)CHARGE_CONTROL_GET_DEVICE(cc); |
| |
| if (bq24040 == NULL) { |
| return SYS_ENODEV; |
| } |
| |
| return bq24040_disable(bq24040); |
| } |