diff --git a/drivers/power/battery/Kconfig b/drivers/power/battery/Kconfig index fcbf39f3cea..07de5b4b0fd 100644 --- a/drivers/power/battery/Kconfig +++ b/drivers/power/battery/Kconfig @@ -153,4 +153,11 @@ config BQ769X0_USE_INTERNAL_TS default n endif +config GOLDFISH_BATTERY + bool "Goldfish Battery charger support" + default n + depends on BATTERY_GAUGE + ---help--- + The GOLDFISH_BATTERY are battery charger for emulate batteries. + endmenu diff --git a/drivers/power/battery/Make.defs b/drivers/power/battery/Make.defs index 3931d0872ef..6cedba89d03 100644 --- a/drivers/power/battery/Make.defs +++ b/drivers/power/battery/Make.defs @@ -84,5 +84,9 @@ endif endif +ifeq ($(CONFIG_GOLDFISH_BATTERY),y) +CSRCS += goldfish_battery.c +endif + DEPPATH += --dep-path power/battery VPATH += power/battery diff --git a/drivers/power/battery/goldfish_battery.c b/drivers/power/battery/goldfish_battery.c new file mode 100644 index 00000000000..7da4946b309 --- /dev/null +++ b/drivers/power/battery/goldfish_battery.c @@ -0,0 +1,330 @@ +/**************************************************************************** + * drivers/power/battery/goldfish_battery.c + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GOLDFISH_BATTERY_READ(data, addr) \ + (*(FAR volatile uint32_t *)(data->reg_base + addr)) +#define GOLDFISH_BATTERY_WRITE(data, addr, x) \ + (*(FAR volatile uint32_t *)(data->reg_base + addr) = (x)) +#define GOLDFISH_GAUGE "/dev/charge/goldfish_battery" + +/**************************************************************************** + * Private type + ****************************************************************************/ + +enum +{ + /* Status register */ + + BATTERY_INT_STATUS = 0x00, + + /* Set this to enable IRQ */ + + BATTERY_INT_ENABLE = 0x04, + BATTERY_AC_ONLINE = 0x08, + BATTERY_STATUS = 0x0c, + BATTERY_HEALTH = 0x10, + BATTERY_PRESENT = 0x14, + BATTERY_CAPACITY = 0x18, + BATTERY_VOLTAGE = 0x1c, + BATTERY_TEMP = 0x20, + BATTERY_CHARGE_COUNTER = 0x24, + BATTERY_VOLTAGE_MAX = 0x28, + BATTERY_CURRENT_MAX = 0x2c, + BATTERY_CURRENT_NOW = 0x30, + BATTERY_CURRENT_AVG = 0x34, + BATTERY_CHARGE_FULL_UAH = 0x38, + BATTERY_CYCLE_COUNT = 0x40, + BATTERY_STATUS_CHANGED = 1u << 0, + AC_STATUS_CHANGED = 1u << 1, + BATTERY_INT_MASK = BATTERY_STATUS_CHANGED | AC_STATUS_CHANGED, +}; + +enum +{ + POWER_SUPPLY_STATUS_UNKNOWN, + POWER_SUPPLY_STATUS_CHARGING, + POWER_SUPPLY_STATUS_DISCHARGING, + POWER_SUPPLY_STATUS_NOT_CHARGING, + POWER_SUPPLY_STATUS_FULL, +}; + +struct goldfish_battery_data_s +{ + FAR void *reg_base; + int irq; + struct battery_gauge_dev_s battery; + struct work_s work; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int goldfish_charger_online(FAR struct battery_gauge_dev_s *dev, + FAR bool *status); +static int goldfish_battery_state(FAR struct battery_gauge_dev_s *dev, + FAR int *status); +static int goldfish_battery_voltage(FAR struct battery_gauge_dev_s *dev, + FAR b16_t *value); +static int goldfish_battery_capacity(FAR struct battery_gauge_dev_s *dev, + FAR b16_t *value); +static int goldfish_battery_current(FAR struct battery_gauge_dev_s *dev, + FAR b16_t *value); +static int goldfish_battery_temp(FAR struct battery_gauge_dev_s *dev, + FAR b8_t *value); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct battery_gauge_operations_s g_goldfish_gauge_ops = +{ + .online = goldfish_charger_online, + .state = goldfish_battery_state, + .voltage = goldfish_battery_voltage, + .current = goldfish_battery_current, + .capacity = goldfish_battery_capacity, + .temp = goldfish_battery_temp, +}; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int goldfish_charger_online(FAR struct battery_gauge_dev_s *dev, + FAR bool *status) +{ + FAR struct goldfish_battery_data_s *priv = + container_of(dev, struct goldfish_battery_data_s, battery); + + *status = GOLDFISH_BATTERY_READ(priv, BATTERY_AC_ONLINE) & 0x1; + return OK; +} + +static int goldfish_battery_state(FAR struct battery_gauge_dev_s *dev, + FAR int *status) +{ + FAR struct goldfish_battery_data_s *priv = + container_of(dev, struct goldfish_battery_data_s, battery); + uint32_t regval; + + regval = GOLDFISH_BATTERY_READ(priv, BATTERY_STATUS); + + switch (regval) + { + case POWER_SUPPLY_STATUS_UNKNOWN: + *status = BATTERY_UNKNOWN; + break; + case POWER_SUPPLY_STATUS_CHARGING: + *status = BATTERY_CHARGING; + break; + case POWER_SUPPLY_STATUS_DISCHARGING: + *status = BATTERY_DISCHARGING; + break; + case POWER_SUPPLY_STATUS_NOT_CHARGING: + *status = BATTERY_IDLE; + break; + case POWER_SUPPLY_STATUS_FULL: + *status = BATTERY_FULL; + break; + default: + *status = BATTERY_UNKNOWN; + break; + } + + return OK; +} + +static int goldfish_battery_voltage(FAR struct battery_gauge_dev_s *dev, + FAR b16_t *value) +{ + FAR struct goldfish_battery_data_s *data = + container_of(dev, struct goldfish_battery_data_s, battery); + uint32_t regval; + float vol; + + /* BATTERY_VOLTAGE units is µV */ + + regval = GOLDFISH_BATTERY_READ(data, BATTERY_VOLTAGE); + + /* convert to unit V and fill b16_t */ + + vol = regval / 1000000.0f; + *value = ftob16(vol); + return OK; +} + +static int goldfish_battery_capacity(FAR struct battery_gauge_dev_s *dev, + FAR b16_t *value) +{ + FAR struct goldfish_battery_data_s *data = + container_of(dev, struct goldfish_battery_data_s, battery); + uint32_t regval; + + /* BATTERY_CAPACITY units is percentage */ + + regval = GOLDFISH_BATTERY_READ(data, BATTERY_CAPACITY); + *value = uitoub16(regval); + return OK; +} + +static int goldfish_battery_current(FAR struct battery_gauge_dev_s *dev, + FAR b16_t *value) +{ + FAR struct goldfish_battery_data_s *data = + container_of(dev, struct goldfish_battery_data_s, battery); + uint32_t regval; + float current; + + /* BATTERY_CURRENT_NOW units is µA */ + + regval = GOLDFISH_BATTERY_READ(data, BATTERY_CURRENT_NOW); + + /* convert to unit mA and fill b16_t */ + + current = regval / 1000.0f; + *value = ftob16(current); + return OK; +} + +static int goldfish_battery_temp(FAR struct battery_gauge_dev_s *dev, + FAR b8_t *value) +{ + FAR struct goldfish_battery_data_s *data = + container_of(dev, struct goldfish_battery_data_s, battery); + int32_t regval; + float temp; + + /* BATTERY_TEMP units is 0.1 celsuis */ + + regval = GOLDFISH_BATTERY_READ(data, BATTERY_TEMP); + + /* convert to unit celsuis and fill b16_t */ + + temp = regval / 10.0f; + *value = ftob8(temp); + return OK; +} + +static void goldfish_battery_work(FAR void *arg) +{ + FAR struct goldfish_battery_data_s *data = arg; + uint32_t mask = BATTERY_STATE_CHANGED | BATTERY_VOLTAGE_CHANGED | + BATTERY_CURRENT_CHANGED | BATTERY_CAPACITY_CHANGED | + BATTERY_TEMPERATURE_CHANGED | BATTERY_ONLINE_CHANGED; + int ret; + + ret = battery_gauge_changed(&data->battery, mask); + if (ret < 0) + { + baterr("goldfish battery changed failed %d\n", ret); + } + + return; +} + +static int goldfish_battery_interrupt(int irq, FAR void *context, void *arg) +{ + FAR struct goldfish_battery_data_s *data = arg; + uint32_t status; + int ret; + + /* read status flags, which will clear the interrupt */ + + status = GOLDFISH_BATTERY_READ(data, BATTERY_INT_STATUS); + status &= BATTERY_INT_MASK; + if (status) + { + ret = work_queue(HPWORK, &data->work, + goldfish_battery_work, data, 0); + if (ret < 0) + { + baterr("battery interrupt %"PRIu32 + "work_battery ret:%d\n", status, ret); + } + } + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int goldfish_battery_register(FAR void *regs, int irq) +{ + int ret; + FAR struct goldfish_battery_data_s *data; + + if (NULL == regs || irq < 0) + { + baterr(" regs:%p irq:%d\n", regs, irq); + return -EINVAL; + } + + data = kmm_zalloc(sizeof(struct goldfish_battery_data_s)); + if (NULL == data) + { + baterr(" no enough memory\n"); + return -ENOMEM; + } + + data->irq = irq; + data->reg_base = regs; + ret = irq_attach(data->irq, goldfish_battery_interrupt, data); + if (ret < 0) + { + baterr(" attach irq %d failed\n", irq); + goto fail; + } + + data->battery.ops = &g_goldfish_gauge_ops; + ret = battery_gauge_register(GOLDFISH_GAUGE, &data->battery); + if (ret < 0) + { + baterr("battery_gauge_register %s failed", GOLDFISH_GAUGE); + irq_detach(data->irq); + goto fail; + } + + GOLDFISH_BATTERY_WRITE(data, BATTERY_INT_ENABLE, BATTERY_INT_MASK); + up_enable_irq(data->irq); + batinfo("goldfish_battery_register over"); + return 0; +fail: + kmm_free(data); + return ret; +} + diff --git a/include/nuttx/power/battery_gauge.h b/include/nuttx/power/battery_gauge.h index d7a503c4199..9fbac410859 100644 --- a/include/nuttx/power/battery_gauge.h +++ b/include/nuttx/power/battery_gauge.h @@ -251,6 +251,25 @@ FAR struct battery_gauge_dev_s *max1704x_initialize( uint32_t frequency); #endif +#if defined(CONFIG_GOLDFISH_BATTERY) +/**************************************************************************** + * Name: goldfish_battery_register + * + * Description: + * Register a emulate battery to tyhe upper-half battery driver. + * + * Input Parameters: + * regs - the base address for the goldfish battery. + * irq - An irq num for the goldfish battery. + * + * Returned Value: + * Zero on success or a negated errno value on failure. + * + ****************************************************************************/ + +int goldfish_battery_register(FAR void *regs, int irq); +#endif + #undef EXTERN #ifdef __cplusplus }