linux/drivers/power/supply/ug3105_battery.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * Battery monitor driver for the uPI uG3105 battery monitor
 *
 * Note the uG3105 is not a full-featured autonomous fuel-gauge. Instead it is
 * expected to be use in combination with some always on microcontroller reading
 * its coulomb-counter before it can wrap (must be read every 400 seconds!).
 *
 * Since Linux does not monitor coulomb-counter changes while the device
 * is off or suspended, the coulomb counter is not used atm.
 *
 * Possible improvements:
 * 1. Activate commented out total_coulomb_count code
 * 2. Reset total_coulomb_count val to 0 when the battery is as good as empty
 *    and remember that we did this (and clear the flag for this on susp/resume)
 * 3. When the battery is full check if the flag that we set total_coulomb_count
 *    to when the battery was empty is set. If so we now know the capacity,
 *    not the design, but actual capacity, of the battery
 * 4. Add some mechanism (needs userspace help, or maybe use efivar?) to remember
 *    the actual capacity of the battery over reboots
 * 5. When we know the actual capacity at probe time, add energy_now and
 *    energy_full attributes. Guess boot + resume energy_now value based on ocv
 *    and then use total_coulomb_count to report energy_now over time, resetting
 *    things to adjust for drift when empty/full. This should give more accurate
 *    readings, esp. in the 30-70% range and allow userspace to estimate time
 *    remaining till empty/full
 * 6. Maybe unregister + reregister the psy device when we learn the actual
 *    capacity during run-time ?
 *
 * The above will also require some sort of mwh_per_unit calculation. Testing
 * has shown that an estimated 7404mWh increase of the battery's energy results
 * in a total_coulomb_count increase of 3277 units with a 5 milli-ohm sense R.
 *
 * Copyright (C) 2021 Hans de Goede <[email protected]>
 */

#include <linux/devm-helpers.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mod_devicetable.h>
#include <linux/power_supply.h>
#include <linux/workqueue.h>

#define UG3105_MOV_AVG_WINDOW
#define UG3105_INIT_POLL_TIME
#define UG3105_POLL_TIME
#define UG3105_SETTLE_TIME

#define UG3105_INIT_POLL_COUNT

#define UG3105_REG_MODE
#define UG3105_REG_CTRL1
#define UG3105_REG_COULOMB_CNT
#define UG3105_REG_BAT_VOLT
#define UG3105_REG_BAT_CURR

#define UG3105_MODE_STANDBY
#define UG3105_MODE_RUN

#define UG3105_CTRL1_RESET_COULOMB_CNT

#define UG3105_CURR_HYST_UA

#define UG3105_LOW_BAT_UV
#define UG3105_FULL_BAT_HYST_UV

struct ug3105_chip {};

static int ug3105_read_word(struct i2c_client *client, u8 reg)
{}

static int ug3105_get_status(struct ug3105_chip *chip)
{}

static int ug3105_get_capacity(struct ug3105_chip *chip)
{}

static void ug3105_work(struct work_struct *work)
{}

static enum power_supply_property ug3105_battery_props[] =;

static int ug3105_get_property(struct power_supply *psy,
			       enum power_supply_property psp,
			       union power_supply_propval *val)
{}

static void ug3105_external_power_changed(struct power_supply *psy)
{}

static const struct power_supply_desc ug3105_psy_desc =;

static void ug3105_init(struct ug3105_chip *chip)
{}

static int ug3105_probe(struct i2c_client *client)
{}

static int __maybe_unused ug3105_suspend(struct device *dev)
{}

static int __maybe_unused ug3105_resume(struct device *dev)
{}

static SIMPLE_DEV_PM_OPS(ug3105_pm_ops, ug3105_suspend,
			ug3105_resume);

static const struct i2c_device_id ug3105_id[] =;
MODULE_DEVICE_TABLE(i2c, ug3105_id);

static struct i2c_driver ug3105_i2c_driver =;
module_i2c_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();