| /* |
| * 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 <math.h> |
| #include <string.h> |
| |
| #include "os/mynewt.h" |
| #include "bq27z561/bq27z561.h" |
| #include "hal/hal_gpio.h" |
| #include "hal/hal_i2c.h" |
| #include "i2cn/i2cn.h" |
| |
| #include "battery/battery_prop.h" |
| |
| #if MYNEWT_VAL(BQ27Z561_LOG) |
| #include "modlog/modlog.h" |
| #endif |
| |
| #if MYNEWT_VAL(BQ27Z561_LOG) |
| |
| #define BQ27Z561_LOG(lvl_, ...) \ |
| MODLOG_ ## lvl_(MYNEWT_VAL(BQ27Z561_LOG_MODULE), __VA_ARGS__) |
| #else |
| #define BQ27Z561_LOG(lvl_, ...) |
| #endif |
| |
| static uint8_t |
| bq27z561_calc_chksum(uint8_t *tmpbuf, uint8_t len) |
| { |
| uint8_t i; |
| uint8_t chksum; |
| |
| chksum = 0; |
| if (len != 0) { |
| for (i = 0; i < len; ++i) { |
| chksum += tmpbuf[i]; |
| } |
| chksum = 0xFF - chksum; |
| } |
| return chksum; |
| } |
| |
| |
| static float |
| bq27z561_temp_to_celsius(uint16_t temp) |
| { |
| float temp_c; |
| |
| temp_c = ((float)temp * 0.1) - 273; |
| return temp_c; |
| } |
| |
| static int |
| bq27z561_open(struct os_dev *dev, uint32_t timeout, void *arg) |
| { |
| return 0; |
| } |
| |
| static int |
| bq27z561_close(struct os_dev *dev) |
| { |
| return 0; |
| } |
| |
| /** |
| * Lock access to the bq27z561_itf specified by si. Blocks until lock acquired. |
| * |
| * @param The bq27z561_itf to lock |
| * @param The timeout |
| * |
| * @return 0 on success, non-zero on failure. |
| */ |
| static int |
| bq27z561_itf_lock(struct bq27z561_itf *bi, uint32_t timeout) |
| { |
| int rc; |
| os_time_t ticks; |
| |
| if (!bi->itf_lock) { |
| return 0; |
| } |
| |
| rc = os_time_ms_to_ticks(timeout, &ticks); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = os_mutex_pend(bi->itf_lock, ticks); |
| if (rc == 0 || rc == OS_NOT_STARTED) { |
| return (0); |
| } |
| |
| return (rc); |
| } |
| |
| /** |
| * Unlock access to the bq27z561_itf specified by bi. |
| * |
| * @param The bq27z561_itf to unlock access to |
| * |
| * @return 0 on success, non-zero on failure. |
| */ |
| static void |
| bq27z561_itf_unlock(struct bq27z561_itf *bi) |
| { |
| if (!bi->itf_lock) { |
| return; |
| } |
| |
| os_mutex_release(bi->itf_lock); |
| } |
| |
| static int |
| bq27z561_rd_std_reg_byte(struct bq27z561 *dev, uint8_t reg, uint8_t *val) |
| { |
| int rc; |
| struct hal_i2c_master_data i2c; |
| |
| i2c.address = dev->bq27_itf.itf_addr; |
| i2c.len = 1; |
| i2c.buffer = ® |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 0, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", reg); |
| goto err; |
| } |
| |
| i2c.len = 1; |
| i2c.buffer = (uint8_t *)val; |
| rc = i2cn_master_read(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (rd) failed 0x%02X\n", reg); |
| goto err; |
| } |
| |
| err: |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| return rc; |
| } |
| |
| int |
| bq27z561_rd_std_reg_word(struct bq27z561 *dev, uint8_t reg, uint16_t *val) |
| { |
| int rc; |
| struct hal_i2c_master_data i2c; |
| |
| i2c.address = dev->bq27_itf.itf_addr; |
| i2c.len = 1; |
| i2c.buffer = ® |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 0, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", reg); |
| goto err; |
| } |
| |
| i2c.len = 2; |
| i2c.buffer = (uint8_t *)val; |
| rc = i2cn_master_read(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (rd) failed 0x%02X\n", reg); |
| goto err; |
| } |
| |
| err: |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| /* XXX: add big-endian support */ |
| |
| return rc; |
| } |
| |
| static int |
| bq27z561_wr_std_reg_byte(struct bq27z561 *dev, uint8_t reg, uint8_t val) |
| { |
| int rc; |
| uint8_t buf[2]; |
| struct hal_i2c_master_data i2c; |
| |
| buf[0] = reg; |
| buf[1] = val; |
| |
| i2c.address = dev->bq27_itf.itf_num; |
| i2c.len = 2; |
| i2c.buffer = buf; |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg write 0x%02X failed\n", reg); |
| } |
| |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| return rc; |
| } |
| |
| static int |
| bq27z561_wr_std_reg_word(struct bq27z561 *dev, uint8_t reg, uint16_t val) |
| { |
| int rc; |
| uint8_t buf[3]; |
| struct hal_i2c_master_data i2c; |
| |
| buf[0] = reg; |
| buf[1] = (uint8_t)val; |
| buf[2] = (uint8_t)(val >> 8); |
| |
| i2c.address = dev->bq27_itf.itf_num; |
| i2c.len = 3; |
| i2c.buffer = buf; |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg write 0x%02X failed\n", reg); |
| goto err; |
| } |
| |
| err: |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| return rc; |
| } |
| |
| bq27z561_err_t |
| bq27x561_wr_alt_mfg_cmd(struct bq27z561 *dev, uint16_t cmd, uint8_t *buf, |
| int len) |
| { |
| /* NOTE: add three here for register and two-byte command */ |
| int rc; |
| uint8_t tmpbuf[BQ27Z561_MAX_ALT_MFG_CMD_LEN + 3]; |
| struct hal_i2c_master_data i2c; |
| |
| if ((len > 0) && (buf == NULL)) { |
| return BQ27Z561_ERR_INV_PARAMS; |
| } |
| |
| /* Make sure length is not too long */ |
| if (len > BQ27Z561_MAX_ALT_MFG_CMD_LEN) { |
| return BQ27Z561_ERR_CMD_LEN; |
| } |
| |
| tmpbuf[0] = BQ27Z561_REG_MFRG_ACC; |
| tmpbuf[1] = (uint8_t)cmd; |
| tmpbuf[2] = (uint8_t)(cmd >> 8); |
| |
| if (len > 0) { |
| memcpy(&tmpbuf[3], buf, len); |
| } |
| |
| i2c.address = dev->bq27_itf.itf_addr; |
| i2c.len = len + 3; |
| i2c.buffer = tmpbuf; |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| } |
| |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| return rc; |
| } |
| |
| bq27z561_err_t |
| bq27x561_rd_alt_mfg_cmd(struct bq27z561 *dev, uint16_t cmd, uint8_t *val, |
| int val_len) |
| { |
| bq27z561_err_t rc; |
| uint8_t tmpbuf[36]; |
| uint8_t len; |
| uint16_t cmd_read; |
| uint8_t chksum; |
| struct hal_i2c_master_data i2c; |
| |
| if ((val_len == 0) || (val == NULL)) { |
| return BQ27Z561_ERR_INV_PARAMS; |
| } |
| |
| tmpbuf[0] = BQ27Z561_REG_CNTL; |
| tmpbuf[1] = (uint8_t)cmd; |
| tmpbuf[2] = (uint8_t)(cmd >> 8); |
| |
| i2c.address = dev->bq27_itf.itf_addr; |
| i2c.len = 3; |
| i2c.buffer = tmpbuf; |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| goto err; |
| } |
| |
| tmpbuf[0] = BQ27Z561_REG_MFRG_ACC; |
| i2c.len = 1; |
| i2c.buffer = tmpbuf; |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 0, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| goto err; |
| } |
| |
| i2c.len = 36; |
| i2c.buffer = tmpbuf; |
| rc = i2cn_master_read(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (rd) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| goto err; |
| } |
| |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| /* Verify that first two bytes are the command */ |
| cmd_read = tmpbuf[0]; |
| cmd_read |= ((uint16_t)tmpbuf[1]) << 8; |
| if (cmd_read != cmd) { |
| BQ27Z561_LOG(ERROR, "cmd mismatch (cmd=%x cmd_ret=%x\n", cmd, cmd_read); |
| rc = BQ27Z561_ERR_CMD_MISMATCH; |
| goto err; |
| } |
| |
| /* |
| * Verify length. The length contains two bytes for the command and |
| * another two for the checksum and length bytes. Thus, there better |
| * be at least 5 bytes here |
| */ |
| len = tmpbuf[35]; |
| if (len < 5) { |
| rc = BQ27Z561_ERR_ALT_MFG_LEN; |
| goto err; |
| } |
| |
| /* Subtract out checksum and length bytes from length */ |
| len -= 2; |
| chksum = bq27z561_calc_chksum(tmpbuf, len); |
| if (chksum != tmpbuf[34]) { |
| BQ27Z561_LOG(ERROR, "chksum failure for cmd %u (calc=%u read=%u)", cmd, |
| chksum, tmpbuf[34]); |
| rc = BQ27Z561_ERR_CHKSUM_FAIL; |
| } |
| |
| /* Now copy returned data. We subtract command from length */ |
| len -= 2; |
| if (val_len < len) { |
| val_len = len; |
| } |
| memcpy(val, &tmpbuf[2], val_len); |
| |
| rc = BQ27Z561_OK; |
| |
| err: |
| return rc; |
| } |
| |
| bq27z561_err_t |
| bq27x561_rd_flash(struct bq27z561 *dev, uint16_t addr, uint8_t *buf, int buflen) |
| { |
| uint8_t tmpbuf[BQ27Z561_MAX_FLASH_RW_LEN + 2]; |
| uint16_t addr_read; |
| bq27z561_err_t rc; |
| struct hal_i2c_master_data i2c; |
| |
| if ((buflen == 0) || !buf || (buflen > BQ27Z561_MAX_FLASH_RW_LEN)) { |
| return BQ27Z561_ERR_INV_PARAMS; |
| } |
| |
| if ((addr < BQ27Z561_FLASH_BEG_ADDR) || (addr > BQ27Z561_FLASH_END_ADDR)) { |
| return BQ27Z561_ERR_INV_FLASH_ADDR; |
| } |
| |
| tmpbuf[0] = BQ27Z561_REG_MFRG_ACC; |
| tmpbuf[1] = (uint8_t)addr; |
| tmpbuf[2] = (uint8_t)(addr >> 8); |
| |
| i2c.address = dev->bq27_itf.itf_addr; |
| i2c.len = 3; |
| i2c.buffer = tmpbuf; |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| goto err; |
| } |
| |
| tmpbuf[0] = BQ27Z561_REG_MFRG_ACC; |
| i2c.len = 1; |
| i2c.buffer = tmpbuf; |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 0, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| goto err; |
| } |
| |
| i2c.len = buflen + 2; |
| i2c.buffer = tmpbuf; |
| rc = i2cn_master_read(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (rd) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| goto err; |
| } |
| |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| /* Verify that first two bytes are the address*/ |
| addr_read = tmpbuf[0]; |
| addr_read |= ((uint16_t)tmpbuf[1]) << 8; |
| if (addr_read != addr) { |
| BQ27Z561_LOG(ERROR, "addr mismatch (addr_read=%x addr_ret=%x\n", addr_read, |
| addr); |
| rc = BQ27Z561_ERR_FLASH_ADDR_MISMATCH; |
| goto err; |
| } |
| |
| /* Now copy returned data. */ |
| memcpy(buf, &tmpbuf[2], buflen); |
| |
| rc = BQ27Z561_OK; |
| |
| err: |
| return rc; |
| } |
| |
| bq27z561_err_t |
| bq27x561_wr_flash(struct bq27z561 *dev, uint16_t addr, uint8_t *buf, int buflen) |
| { |
| uint8_t tmpbuf[BQ27Z561_MAX_FLASH_RW_LEN + 2]; |
| uint8_t chksum; |
| bq27z561_err_t rc; |
| struct hal_i2c_master_data i2c; |
| |
| if ((buflen == 0) || (!buf) || (buflen > BQ27Z561_MAX_FLASH_RW_LEN)) { |
| return BQ27Z561_ERR_INV_PARAMS; |
| } |
| |
| if ((addr < BQ27Z561_FLASH_BEG_ADDR) || (addr > BQ27Z561_FLASH_END_ADDR)) { |
| return BQ27Z561_ERR_INV_FLASH_ADDR; |
| } |
| |
| tmpbuf[0] = BQ27Z561_REG_MFRG_ACC; |
| tmpbuf[1] = (uint8_t)addr; |
| tmpbuf[2] = (uint8_t)(addr >> 8); |
| memcpy(&tmpbuf[3], buf, buflen); |
| |
| i2c.address = dev->bq27_itf.itf_addr; |
| i2c.len = buflen + 3; |
| i2c.buffer = tmpbuf; |
| |
| rc = bq27z561_itf_lock(&dev->bq27_itf, MYNEWT_VAL(BQ27Z561_ITF_LOCK_TMO)); |
| if (rc) { |
| return rc; |
| } |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| goto err; |
| } |
| |
| /* Calculate checksum */ |
| chksum = bq27z561_calc_chksum(&tmpbuf[1], buflen + 2); |
| |
| /* Write checksum and length */ |
| tmpbuf[0] = BQ27Z561_REG_CHKSUM; |
| tmpbuf[1] = chksum; |
| tmpbuf[2] = buflen + 4; |
| i2c.len = 3; |
| i2c.buffer = tmpbuf; |
| |
| rc = i2cn_master_write(dev->bq27_itf.itf_num, &i2c, MYNEWT_VAL(BQ27Z561_I2C_TIMEOUT_TICKS), 1, |
| MYNEWT_VAL(BQ27Z561_I2C_RETRIES)); |
| if (rc != 0) { |
| BQ27Z561_LOG(ERROR, "I2C reg read (wr) failed 0x%02X\n", tmpbuf[0]); |
| rc = BQ27Z561_ERR_I2C_ERR; |
| } |
| |
| err: |
| bq27z561_itf_unlock(&dev->bq27_itf); |
| |
| return rc; |
| } |
| |
| #if 0 |
| static int |
| bq27z561_get_chip_id(struct bq27z561 *dev, uint8_t *chip_id) |
| { |
| return 0; |
| } |
| #endif |
| |
| /* Check if bq27z561 is initialized and sets bq27z561 initialized flag */ |
| int |
| bq27z561_get_init_status(struct bq27z561 *dev, uint8_t *init_flag) |
| { |
| int rc; |
| uint16_t init; |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_FLAGS, &init); |
| if (init & BQ27Z561_BATTERY_STATUS_INIT) |
| { |
| *init_flag = 1; |
| } |
| else |
| { |
| *init_flag = 0; |
| } |
| return rc; |
| } |
| |
| /* XXX: no support for control register yet */ |
| |
| int |
| bq27z561_set_at_rate(struct bq27z561 *dev, int16_t current) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_word(dev, BQ27Z561_REG_AR, (uint16_t)current); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_at_rate(struct bq27z561 *dev, int16_t *current) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_AR, (uint16_t *)current); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_time_to_empty(struct bq27z561 *dev, uint16_t *tte) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_ARTTE, tte); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_temp(struct bq27z561 *dev, float *temp_c) |
| { |
| int rc; |
| uint16_t val; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_TEMP, &val); |
| if (!rc) { |
| /* Kelvin to Celsius */ |
| *temp_c = bq27z561_temp_to_celsius(val); |
| } |
| return rc; |
| } |
| |
| int |
| bq27z561_get_temp_lo_set_threshold(struct bq27z561 *dev, int8_t *temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_byte(dev, BQ27Z561_REG_TEMP_LO_SET_TH, |
| (uint8_t *)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_temp_lo_set_threshold(struct bq27z561 *dev, int8_t temp_c) |
| { |
| int rc; |
| uint8_t temp = (uint8_t)(temp_c); |
| |
| rc = bq27z561_wr_std_reg_byte(dev, BQ27Z561_REG_TEMP_LO_SET_TH, temp); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_temp_lo_clr_threshold(struct bq27z561 *dev, int8_t *temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_byte(dev, BQ27Z561_REG_TEMP_LO_CLR_TH, |
| (uint8_t *)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_temp_lo_clr_threshold(struct bq27z561 *dev, int8_t temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_byte(dev, BQ27Z561_REG_TEMP_LO_CLR_TH, |
| (uint8_t)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_temp_hi_set_threshold(struct bq27z561 *dev, int8_t *temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_byte(dev, BQ27Z561_REG_TEMP_HI_SET_TH, |
| (uint8_t *)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_temp_hi_set_threshold(struct bq27z561 *dev, int8_t temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_byte(dev, BQ27Z561_REG_TEMP_HI_SET_TH, |
| (uint8_t)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_temp_hi_clr_threshold(struct bq27z561 *dev, int8_t *temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_byte(dev, BQ27Z561_REG_TEMP_HI_CLR_TH, |
| (uint8_t *)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_temp_hi_clr_threshold(struct bq27z561 *dev, int8_t temp_c) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_byte(dev, BQ27Z561_REG_TEMP_HI_CLR_TH, |
| (uint8_t)temp_c); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_voltage(struct bq27z561 *dev, uint16_t *voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_VOLT, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_voltage_lo_set_threshold(struct bq27z561 *dev, uint16_t *voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_VOLT_LO_SET_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_voltage_lo_set_threshold(struct bq27z561 *dev, uint16_t voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_word(dev, BQ27Z561_REG_VOLT_LO_SET_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_voltage_lo_clr_threshold(struct bq27z561 *dev, uint16_t *voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_VOLT_LO_CLR_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_voltage_lo_clr_threshold(struct bq27z561 *dev, uint16_t voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_word(dev, BQ27Z561_REG_VOLT_LO_CLR_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_voltage_hi_set_threshold(struct bq27z561 *dev, uint16_t *voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_VOLT_HI_SET_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_voltage_hi_set_threshold(struct bq27z561 *dev, uint16_t voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_VOLT_HI_SET_TH, &voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_voltage_hi_clr_threshold(struct bq27z561 *dev, uint16_t *voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_VOLT_HI_CLR_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_set_voltage_hi_clr_threshold(struct bq27z561 *dev, uint16_t voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_wr_std_reg_word(dev, BQ27Z561_REG_VOLT_HI_CLR_TH, voltage); |
| |
| return rc; |
| } |
| |
| int |
| bq27z561_get_batt_status(struct bq27z561 *dev, uint16_t *status) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_FLAGS, status); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_current(struct bq27z561 *dev, int16_t *current) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_INSTCURR, |
| (uint16_t *)current); |
| return rc; |
| } |
| |
| /* XXX: no support for register IMAX */ |
| |
| int |
| bq27z561_get_rem_capacity(struct bq27z561 *dev, uint16_t *capacity) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_RM, capacity); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_full_chg_capacity(struct bq27z561 *dev, uint16_t *capacity) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_FCC, capacity); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_avg_current(struct bq27z561 *dev, int16_t *current) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_AI, (uint16_t *)current); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_avg_time_to_empty(struct bq27z561 *dev, uint16_t *tte) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_TTE, tte); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_avg_time_to_full(struct bq27z561 *dev, uint16_t *ttf) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_TTF, ttf); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_avg_power(struct bq27z561 *dev, int16_t *pwr) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_AP, (uint16_t *)pwr); |
| return rc; |
| } |
| |
| /* XXX: no support for max load current */ |
| /* XXX: no support for max load time to empty */ |
| |
| int |
| bq27z561_get_internal_temp(struct bq27z561 *dev, float *temp_c) |
| { |
| int rc; |
| uint16_t val; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_INT_TEMP, &val); |
| if (!rc) { |
| *temp_c = bq27z561_temp_to_celsius(val); |
| } |
| return rc; |
| } |
| |
| int |
| bq27z561_get_discharge_cycles(struct bq27z561 *dev, uint16_t *cycles) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_CC, cycles); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_relative_state_of_charge(struct bq27z561 *dev, uint8_t *pcnt) |
| { |
| int rc; |
| uint16_t val; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_RSOC, &val); |
| if (!rc) { |
| *pcnt = (uint8_t)val; |
| } |
| return rc; |
| } |
| |
| int |
| bq27z561_get_state_of_health(struct bq27z561 *dev, uint8_t *pcnt) |
| { |
| int rc; |
| uint16_t val; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_SOH, &val); |
| if (!rc) { |
| *pcnt = (uint8_t)val; |
| } |
| return rc; |
| } |
| |
| int |
| bq27z561_get_charging_voltage(struct bq27z561 *dev, uint16_t *voltage) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_CV, voltage); |
| return rc; |
| } |
| |
| int |
| bq27z561_get_charging_current(struct bq27z561 *dev, uint16_t *current) |
| { |
| int rc; |
| |
| rc = bq27z561_rd_std_reg_word(dev, BQ27Z561_REG_CHGC, current); |
| return rc; |
| } |
| |
| int |
| bq27z561_config(struct bq27z561 *dev, struct bq27z561_cfg *cfg) |
| { |
| return 0; |
| } |
| |
| /* Battery manager interface functions */ |
| |
| static int |
| bq27z561_battery_property_get(struct battery_driver *driver, |
| struct battery_property *property, uint32_t timeout) |
| { |
| int rc = 0; |
| struct bq27z561 * bq_dev; |
| bq_dev = (struct bq27z561 *)&driver->dev; |
| |
| if (!bq_dev->bq27_initialized) |
| { |
| rc = bq27z561_get_init_status((struct bq27z561 *) driver->bd_driver_data, |
| &bq_dev->bq27_initialized); |
| if (!bq_dev->bq27_initialized) |
| { |
| rc = -2; |
| property->bp_valid = 0; |
| return rc; |
| } |
| } |
| |
| battery_property_value_t val; |
| if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_voltage((struct bq27z561 *) driver->bd_driver_data, |
| &val.bpv_u16); |
| property->bp_value.bpv_voltage = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_get_voltage_lo_set_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_voltage = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_get_voltage_lo_clr_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_voltage = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_get_voltage_hi_set_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_voltage = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_get_voltage_hi_clr_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_voltage = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_STATUS && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_batt_status((struct bq27z561 *) driver->bd_driver_data, |
| &val.bpv_u16); |
| if (val.bpv_u16 & BQ27Z561_BATTERY_STATUS_DSG) { |
| property->bp_value.bpv_status = BATTERY_STATUS_DISCHARGING; |
| } else if (val.bpv_u16 & BQ27Z561_BATTERY_STATUS_FC) { |
| property->bp_value.bpv_status = BATTERY_STATUS_FULL; |
| } else { |
| property->bp_value.bpv_status = BATTERY_STATUS_CHARGING; |
| } |
| } else if (property->bp_type == BATTERY_PROP_CURRENT_NOW && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_current((struct bq27z561 *) driver->bd_driver_data, |
| &val.bpv_i16); |
| property->bp_value.bpv_current = val.bpv_i16; |
| } else if (property->bp_type == BATTERY_PROP_CAPACITY && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_rem_capacity((struct bq27z561 *) driver->bd_driver_data, |
| &val.bpv_u16); |
| property->bp_value.bpv_capacity = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_SOC && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_relative_state_of_charge( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u8); |
| property->bp_value.bpv_soc = val.bpv_u8; |
| } else if (property->bp_type == BATTERY_PROP_SOH && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_state_of_health( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u8); |
| property->bp_value.bpv_soh = val.bpv_u8; |
| } else if (property->bp_type == BATTERY_PROP_CYCLE_COUNT && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_discharge_cycles( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_cycle_count = val.bpv_u16; |
| } else if (property->bp_type == BATTERY_PROP_TIME_TO_EMPTY_NOW && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_time_to_empty( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_time_in_s = (uint8_t)val.bpv_u16 * 60; |
| } else if (property->bp_type == BATTERY_PROP_TIME_TO_FULL_NOW && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_avg_time_to_full( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_u16); |
| property->bp_value.bpv_time_in_s = val.bpv_u16 * 60; |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == 0) { |
| rc = bq27z561_get_temp( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_flt); |
| property->bp_value.bpv_temperature = val.bpv_flt; |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_get_temp_lo_set_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_i8); |
| property->bp_value.bpv_temperature = val.bpv_i8; |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_get_temp_lo_clr_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_i8); |
| property->bp_value.bpv_temperature = val.bpv_i8; |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_get_temp_hi_set_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_i8); |
| property->bp_value.bpv_temperature = val.bpv_i8; |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_get_temp_hi_clr_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, &val.bpv_i8); |
| property->bp_value.bpv_temperature = val.bpv_i8; |
| } else { |
| rc = -1; |
| return rc; |
| } |
| if (rc == 0) { |
| property->bp_valid = 1; |
| } else { |
| property->bp_valid = 0; |
| } |
| |
| return rc; |
| } |
| |
| static int |
| bq27z561_battery_property_set(struct battery_driver *driver, |
| struct battery_property *property) |
| { |
| int rc = 0; |
| |
| if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_set_voltage_lo_set_threshold( |
| (struct bq27z561 *)driver->bd_driver_data, |
| property->bp_value.bpv_voltage); |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_set_voltage_lo_clr_threshold( |
| (struct bq27z561 *)driver->bd_driver_data, |
| property->bp_value.bpv_voltage); |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_set_voltage_hi_set_threshold( |
| (struct bq27z561 *)driver->bd_driver_data, |
| property->bp_value.bpv_voltage); |
| } else if (property->bp_type == BATTERY_PROP_VOLTAGE_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_set_voltage_hi_clr_threshold( |
| (struct bq27z561 *)driver->bd_driver_data, |
| property->bp_value.bpv_voltage); |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_set_temp_lo_set_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, |
| (int8_t)property->bp_value.bpv_temperature); |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_LOW_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_set_temp_lo_clr_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, |
| (int16_t)property->bp_value.bpv_temperature); |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_SET_THRESHOLD) { |
| rc = bq27z561_set_temp_hi_set_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, |
| (int16_t)property->bp_value.bpv_temperature); |
| } else if (property->bp_type == BATTERY_PROP_TEMP_NOW && |
| property->bp_flags == BATTERY_PROPERTY_FLAGS_HIGH_ALARM_CLEAR_THRESHOLD) { |
| rc = bq27z561_set_temp_hi_clr_threshold( |
| (struct bq27z561 *) driver->bd_driver_data, |
| (int16_t)property->bp_value.bpv_temperature); |
| } else { |
| rc = -1; |
| } |
| return rc; |
| } |
| |
| static int |
| bq27z561_enable(struct battery *battery) |
| { |
| return 0; |
| } |
| |
| static int |
| bq27z561_disable(struct battery *battery) |
| { |
| return 0; |
| } |
| |
| static const struct battery_driver_functions bq27z561_drv_funcs = { |
| .bdf_property_get = bq27z561_battery_property_get, |
| .bdf_property_set = bq27z561_battery_property_set, |
| |
| .bdf_enable = bq27z561_enable, |
| .bdf_disable = bq27z561_disable, |
| }; |
| |
| static const struct battery_driver_property bq27z561_battery_properties[] = { |
| { BATTERY_PROP_STATUS, 0, "Status" }, |
| { BATTERY_PROP_CAPACITY, 0, "Capacity" }, |
| { BATTERY_PROP_TEMP_NOW, 0, "Temperature" }, |
| { BATTERY_PROP_VOLTAGE_NOW, 0, "Voltage" }, |
| { BATTERY_PROP_CURRENT_NOW, 0, "Current" }, |
| { BATTERY_PROP_SOC, 0, "SOC" }, |
| { BATTERY_PROP_SOH, 0, "SOH" }, |
| { BATTERY_PROP_TIME_TO_EMPTY_NOW, 0, "TimeToEmpty" }, |
| { BATTERY_PROP_TIME_TO_FULL_NOW, 0, "TimeToFull" }, |
| { BATTERY_PROP_CYCLE_COUNT, 0, "CycleCount" }, |
| { BATTERY_PROP_VOLTAGE_NOW, |
| BATTERY_PROPERTY_FLAGS_LOW_ALARM_SET_THRESHOLD, "LoVoltAlarmSet" }, |
| { BATTERY_PROP_VOLTAGE_NOW, |
| BATTERY_PROPERTY_FLAGS_LOW_ALARM_CLEAR_THRESHOLD, "LoVoltAlarmClear" }, |
| { BATTERY_PROP_VOLTAGE_NOW, |
| BATTERY_PROPERTY_FLAGS_HIGH_ALARM_SET_THRESHOLD, "HiVoltAlarmSet" }, |
| { BATTERY_PROP_VOLTAGE_NOW, |
| BATTERY_PROPERTY_FLAGS_HIGH_ALARM_CLEAR_THRESHOLD, "HiVoltAlarmClear" }, |
| { BATTERY_PROP_TEMP_NOW, |
| BATTERY_PROPERTY_FLAGS_LOW_ALARM_SET_THRESHOLD, "LoTempAlarmSet" }, |
| { BATTERY_PROP_TEMP_NOW, |
| BATTERY_PROPERTY_FLAGS_LOW_ALARM_CLEAR_THRESHOLD, "LoTempAlarmClear" }, |
| { BATTERY_PROP_TEMP_NOW, |
| BATTERY_PROPERTY_FLAGS_HIGH_ALARM_SET_THRESHOLD, "LoTempAlarmSet" }, |
| { BATTERY_PROP_TEMP_NOW, |
| BATTERY_PROPERTY_FLAGS_HIGH_ALARM_CLEAR_THRESHOLD, "HiTempAlarmClear" }, |
| { BATTERY_PROP_NONE }, |
| }; |
| |
| int |
| bq27z561_init(struct os_dev *dev, void *arg) |
| { |
| struct bq27z561 *bq27; |
| struct bq27z561_init_arg *init_arg = (struct bq27z561_init_arg *)arg; |
| |
| if (!dev || !arg) { |
| return SYS_ENODEV; |
| } |
| |
| OS_DEV_SETHANDLERS(dev, bq27z561_open, bq27z561_close); |
| |
| bq27 = (struct bq27z561 *)dev; |
| |
| bq27->bq27_initialized = 0; |
| |
| /* Copy the interface struct */ |
| bq27->bq27_itf = init_arg->itf; |
| |
| bq27->dev.bd_funcs = &bq27z561_drv_funcs; |
| bq27->dev.bd_driver_properties = bq27z561_battery_properties; |
| bq27->dev.bd_driver_data = bq27; |
| |
| battery_add_driver(init_arg->battery, &bq27->dev); |
| |
| return 0; |
| } |
| |
| int bq27z561_pkg_init(void) |
| { |
| #if MYNEWT_VAL(BQ27Z561_CLI) |
| return bq27z561_shell_init(); |
| #else |
| return 0; |
| #endif |
| } |