Commit 6f24ff97 authored by Dan Murphy's avatar Dan Murphy Committed by Sebastian Reichel

power: supply: bq27xxx_battery: Add the BQ27Z561 Battery monitor

Add the Texas Instruments BQ27Z561 battery monitor.  The register address
map is laid out the same as compared to other devices within the file.
The battery status register has differing bits to determine if the
battery is full, discharging or dead.
Signed-off-by: default avatarDan Murphy <dmurphy@ti.com>
Signed-off-by: default avatarSebastian Reichel <sebastian.reichel@collabora.com>
parent 36d1b699
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
* https://www.ti.com/product/bq27411-g1 * https://www.ti.com/product/bq27411-g1
* https://www.ti.com/product/bq27441-g1 * https://www.ti.com/product/bq27441-g1
* https://www.ti.com/product/bq27621-g1 * https://www.ti.com/product/bq27621-g1
* https://www.ti.com/product/bq27z561
*/ */
#include <linux/device.h> #include <linux/device.h>
...@@ -79,6 +80,11 @@ ...@@ -79,6 +80,11 @@
#define BQ27000_FLAG_FC BIT(5) #define BQ27000_FLAG_FC BIT(5)
#define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ #define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */
/* BQ27Z561 has different layout for Flags register */
#define BQ27Z561_FLAG_FDC BIT(4) /* Battery fully discharged */
#define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */
#define BQ27Z561_FLAG_DIS_CH BIT(6) /* Battery is discharging */
/* control register params */ /* control register params */
#define BQ27XXX_SEALED 0x20 #define BQ27XXX_SEALED 0x20
#define BQ27XXX_SET_CFGUPDATE 0x13 #define BQ27XXX_SET_CFGUPDATE 0x13
...@@ -431,12 +437,32 @@ static u8 ...@@ -431,12 +437,32 @@ static u8
[BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_DCAP] = 0x3c,
[BQ27XXX_REG_AP] = 0x18, [BQ27XXX_REG_AP] = 0x18,
BQ27XXX_DM_REG_ROWS, BQ27XXX_DM_REG_ROWS,
}; },
#define bq27411_regs bq27421_regs #define bq27411_regs bq27421_regs
#define bq27425_regs bq27421_regs #define bq27425_regs bq27421_regs
#define bq27426_regs bq27421_regs #define bq27426_regs bq27421_regs
#define bq27441_regs bq27421_regs #define bq27441_regs bq27421_regs
#define bq27621_regs bq27421_regs #define bq27621_regs bq27421_regs
bq27z561_regs[BQ27XXX_REG_MAX] = {
[BQ27XXX_REG_CTRL] = 0x00,
[BQ27XXX_REG_TEMP] = 0x06,
[BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR,
[BQ27XXX_REG_VOLT] = 0x08,
[BQ27XXX_REG_AI] = 0x14,
[BQ27XXX_REG_FLAGS] = 0x0a,
[BQ27XXX_REG_TTE] = 0x16,
[BQ27XXX_REG_TTF] = 0x18,
[BQ27XXX_REG_TTES] = INVALID_REG_ADDR,
[BQ27XXX_REG_TTECP] = INVALID_REG_ADDR,
[BQ27XXX_REG_NAC] = INVALID_REG_ADDR,
[BQ27XXX_REG_FCC] = 0x12,
[BQ27XXX_REG_CYCT] = 0x2a,
[BQ27XXX_REG_AE] = 0x22,
[BQ27XXX_REG_SOC] = 0x2c,
[BQ27XXX_REG_DCAP] = 0x3c,
[BQ27XXX_REG_AP] = 0x22,
BQ27XXX_DM_REG_ROWS,
};
static enum power_supply_property bq27000_props[] = { static enum power_supply_property bq27000_props[] = {
POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_STATUS,
...@@ -672,6 +698,25 @@ static enum power_supply_property bq27421_props[] = { ...@@ -672,6 +698,25 @@ static enum power_supply_property bq27421_props[] = {
#define bq27441_props bq27421_props #define bq27441_props bq27421_props
#define bq27621_props bq27421_props #define bq27621_props bq27421_props
static enum power_supply_property bq27z561_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_CURRENT_NOW,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
POWER_SUPPLY_PROP_TIME_TO_FULL_NOW,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN,
POWER_SUPPLY_PROP_CYCLE_COUNT,
POWER_SUPPLY_PROP_POWER_AVG,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_MANUFACTURER,
};
struct bq27xxx_dm_reg { struct bq27xxx_dm_reg {
u8 subclass_id; u8 subclass_id;
u8 offset; u8 offset;
...@@ -767,11 +812,14 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = { ...@@ -767,11 +812,14 @@ static struct bq27xxx_dm_reg bq27621_dm_regs[] = {
#define bq27621_dm_regs 0 #define bq27621_dm_regs 0
#endif #endif
#define bq27z561_dm_regs 0
#define BQ27XXX_O_ZERO 0x00000001 #define BQ27XXX_O_ZERO 0x00000001
#define BQ27XXX_O_OTDC 0x00000002 /* has OTC/OTD overtemperature flags */ #define BQ27XXX_O_OTDC 0x00000002 /* has OTC/OTD overtemperature flags */
#define BQ27XXX_O_UTOT 0x00000004 /* has OT overtemperature flag */ #define BQ27XXX_O_UTOT 0x00000004 /* has OT overtemperature flag */
#define BQ27XXX_O_CFGUP 0x00000008 #define BQ27XXX_O_CFGUP 0x00000008
#define BQ27XXX_O_RAM 0x00000010 #define BQ27XXX_O_RAM 0x00000010
#define BQ27Z561_O_BITS 0x00000020
#define BQ27XXX_DATA(ref, key, opt) { \ #define BQ27XXX_DATA(ref, key, opt) { \
.opts = (opt), \ .opts = (opt), \
...@@ -816,6 +864,7 @@ static struct { ...@@ -816,6 +864,7 @@ static struct {
[BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
[BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
[BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM),
[BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS),
}; };
static DEFINE_MUTEX(bq27xxx_list_lock); static DEFINE_MUTEX(bq27xxx_list_lock);
...@@ -1551,6 +1600,8 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) ...@@ -1551,6 +1600,8 @@ static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags)
{ {
if (di->opts & BQ27XXX_O_ZERO) if (di->opts & BQ27XXX_O_ZERO)
return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF); return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF);
else if (di->opts & BQ27Z561_O_BITS)
return flags & BQ27Z561_FLAG_FDC;
else else
return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF);
} }
...@@ -1595,6 +1646,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di) ...@@ -1595,6 +1646,7 @@ void bq27xxx_battery_update(struct bq27xxx_device_info *di)
cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP);
if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR)
cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF);
cache.charge_full = bq27xxx_battery_read_fcc(di); cache.charge_full = bq27xxx_battery_read_fcc(di);
cache.capacity = bq27xxx_battery_read_soc(di); cache.capacity = bq27xxx_battery_read_soc(di);
if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR)
...@@ -1682,6 +1734,13 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di, ...@@ -1682,6 +1734,13 @@ static int bq27xxx_battery_status(struct bq27xxx_device_info *di,
status = POWER_SUPPLY_STATUS_NOT_CHARGING; status = POWER_SUPPLY_STATUS_NOT_CHARGING;
else else
status = POWER_SUPPLY_STATUS_DISCHARGING; status = POWER_SUPPLY_STATUS_DISCHARGING;
} else if (di->opts & BQ27Z561_O_BITS) {
if (di->cache.flags & BQ27Z561_FLAG_FC)
status = POWER_SUPPLY_STATUS_FULL;
else if (di->cache.flags & BQ27Z561_FLAG_DIS_CH)
status = POWER_SUPPLY_STATUS_DISCHARGING;
else
status = POWER_SUPPLY_STATUS_CHARGING;
} else { } else {
if (di->cache.flags & BQ27XXX_FLAG_FC) if (di->cache.flags & BQ27XXX_FLAG_FC)
status = POWER_SUPPLY_STATUS_FULL; status = POWER_SUPPLY_STATUS_FULL;
...@@ -1710,6 +1769,13 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, ...@@ -1710,6 +1769,13 @@ static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di,
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
else else
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
} else if (di->opts & BQ27Z561_O_BITS) {
if (di->cache.flags & BQ27Z561_FLAG_FC)
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
else if (di->cache.flags & BQ27Z561_FLAG_FDC)
level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
else
level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
} else { } else {
if (di->cache.flags & BQ27XXX_FLAG_FC) if (di->cache.flags & BQ27XXX_FLAG_FC)
level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; level = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
......
...@@ -253,6 +253,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { ...@@ -253,6 +253,7 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
{ "bq27426", BQ27426 }, { "bq27426", BQ27426 },
{ "bq27441", BQ27441 }, { "bq27441", BQ27441 },
{ "bq27621", BQ27621 }, { "bq27621", BQ27621 },
{ "bq27z561", BQ27Z561 },
{}, {},
}; };
MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table); MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
...@@ -286,6 +287,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = { ...@@ -286,6 +287,7 @@ static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
{ .compatible = "ti,bq27426" }, { .compatible = "ti,bq27426" },
{ .compatible = "ti,bq27441" }, { .compatible = "ti,bq27441" },
{ .compatible = "ti,bq27621" }, { .compatible = "ti,bq27621" },
{ .compatible = "ti,bq27z561" },
{}, {},
}; };
MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table); MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
......
...@@ -30,6 +30,7 @@ enum bq27xxx_chip { ...@@ -30,6 +30,7 @@ enum bq27xxx_chip {
BQ27426, BQ27426,
BQ27441, BQ27441,
BQ27621, BQ27621,
BQ27Z561,
}; };
struct bq27xxx_device_info; struct bq27xxx_device_info;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment