144ff56c0SDan Murphy // SPDX-License-Identifier: GPL-2.0 28c0984e5SSebastian Reichel /* 38c0984e5SSebastian Reichel * BQ27xxx battery driver 48c0984e5SSebastian Reichel * 58c0984e5SSebastian Reichel * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> 68c0984e5SSebastian Reichel * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> 78c0984e5SSebastian Reichel * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> 8149ed3d4SPali Rohár * Copyright (C) 2011 Pali Rohár <pali@kernel.org> 90670c9b3SLiam Breck * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net> 108c0984e5SSebastian Reichel * 118c0984e5SSebastian Reichel * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. 128c0984e5SSebastian Reichel * 138c0984e5SSebastian Reichel * Datasheets: 1481bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27000 1581bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27200 1681bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27010 1781bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27210 1881bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27500 1981bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27510-g1 2081bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27510-g2 2181bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27510-g3 2281bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g1 2381bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g2 2481bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g3 2581bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g4 2681bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27530-g1 2781bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27531-g1 2881bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27541-g1 2981bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27542-g1 3081bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27546-g1 3181bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27742-g1 3281bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27545-g1 3381bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27421-g1 3481bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27425-g1 3581bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27426 3681bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27411-g1 3781bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27441-g1 3881bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27621-g1 396f24ff97SDan Murphy * https://www.ti.com/product/bq27z561 40707d678aSDan Murphy * https://www.ti.com/product/bq28z610 4141a7431dSKrzysztof Kozlowski * https://www.ti.com/product/bq34z100-g1 424eed7f5aSLI Qingwu * https://www.ti.com/product/bq78z100 438c0984e5SSebastian Reichel */ 448c0984e5SSebastian Reichel 458c0984e5SSebastian Reichel #include <linux/device.h> 468c0984e5SSebastian Reichel #include <linux/module.h> 471d72706fSMatt Ranostay #include <linux/mutex.h> 488c0984e5SSebastian Reichel #include <linux/param.h> 498c0984e5SSebastian Reichel #include <linux/jiffies.h> 508c0984e5SSebastian Reichel #include <linux/workqueue.h> 518c0984e5SSebastian Reichel #include <linux/delay.h> 528c0984e5SSebastian Reichel #include <linux/platform_device.h> 538c0984e5SSebastian Reichel #include <linux/power_supply.h> 548c0984e5SSebastian Reichel #include <linux/slab.h> 558c0984e5SSebastian Reichel #include <linux/of.h> 568c0984e5SSebastian Reichel 578c0984e5SSebastian Reichel #include <linux/power/bq27xxx_battery.h> 588c0984e5SSebastian Reichel 598c0984e5SSebastian Reichel #define BQ27XXX_MANUFACTURER "Texas Instruments" 608c0984e5SSebastian Reichel 618c0984e5SSebastian Reichel /* BQ27XXX Flags */ 628c0984e5SSebastian Reichel #define BQ27XXX_FLAG_DSC BIT(0) 638c0984e5SSebastian Reichel #define BQ27XXX_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ 648c0984e5SSebastian Reichel #define BQ27XXX_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ 650670c9b3SLiam Breck #define BQ27XXX_FLAG_CFGUP BIT(4) 668c0984e5SSebastian Reichel #define BQ27XXX_FLAG_FC BIT(9) 678c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OTD BIT(14) 688c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OTC BIT(15) 698c0984e5SSebastian Reichel #define BQ27XXX_FLAG_UT BIT(14) 708c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OT BIT(15) 718c0984e5SSebastian Reichel 728c0984e5SSebastian Reichel /* BQ27000 has different layout for Flags register */ 738c0984e5SSebastian Reichel #define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ 748c0984e5SSebastian Reichel #define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ 758c0984e5SSebastian Reichel #define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ 768c0984e5SSebastian Reichel #define BQ27000_FLAG_FC BIT(5) 778c0984e5SSebastian Reichel #define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ 788c0984e5SSebastian Reichel 796f24ff97SDan Murphy /* BQ27Z561 has different layout for Flags register */ 806f24ff97SDan Murphy #define BQ27Z561_FLAG_FDC BIT(4) /* Battery fully discharged */ 816f24ff97SDan Murphy #define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */ 826f24ff97SDan Murphy #define BQ27Z561_FLAG_DIS_CH BIT(6) /* Battery is discharging */ 836f24ff97SDan Murphy 840670c9b3SLiam Breck /* control register params */ 850670c9b3SLiam Breck #define BQ27XXX_SEALED 0x20 860670c9b3SLiam Breck #define BQ27XXX_SET_CFGUPDATE 0x13 870670c9b3SLiam Breck #define BQ27XXX_SOFT_RESET 0x42 880670c9b3SLiam Breck #define BQ27XXX_RESET 0x41 890670c9b3SLiam Breck 908c0984e5SSebastian Reichel #define BQ27XXX_RS (20) /* Resistor sense mOhm */ 918c0984e5SSebastian Reichel #define BQ27XXX_POWER_CONSTANT (29200) /* 29.2 µV^2 * 1000 */ 928c0984e5SSebastian Reichel #define BQ27XXX_CURRENT_CONSTANT (3570) /* 3.57 µV * 1000 */ 938c0984e5SSebastian Reichel 948c0984e5SSebastian Reichel #define INVALID_REG_ADDR 0xff 958c0984e5SSebastian Reichel 968c0984e5SSebastian Reichel /* 978c0984e5SSebastian Reichel * bq27xxx_reg_index - Register names 988c0984e5SSebastian Reichel * 998c0984e5SSebastian Reichel * These are indexes into a device's register mapping array. 1008c0984e5SSebastian Reichel */ 1018c0984e5SSebastian Reichel 1028c0984e5SSebastian Reichel enum bq27xxx_reg_index { 1038c0984e5SSebastian Reichel BQ27XXX_REG_CTRL = 0, /* Control */ 1048c0984e5SSebastian Reichel BQ27XXX_REG_TEMP, /* Temperature */ 1058c0984e5SSebastian Reichel BQ27XXX_REG_INT_TEMP, /* Internal Temperature */ 1068c0984e5SSebastian Reichel BQ27XXX_REG_VOLT, /* Voltage */ 1078c0984e5SSebastian Reichel BQ27XXX_REG_AI, /* Average Current */ 1088c0984e5SSebastian Reichel BQ27XXX_REG_FLAGS, /* Flags */ 1098c0984e5SSebastian Reichel BQ27XXX_REG_TTE, /* Time-to-Empty */ 1108c0984e5SSebastian Reichel BQ27XXX_REG_TTF, /* Time-to-Full */ 1118c0984e5SSebastian Reichel BQ27XXX_REG_TTES, /* Time-to-Empty Standby */ 1128c0984e5SSebastian Reichel BQ27XXX_REG_TTECP, /* Time-to-Empty at Constant Power */ 1138c0984e5SSebastian Reichel BQ27XXX_REG_NAC, /* Nominal Available Capacity */ 1143ed510f0SHermes Zhang BQ27XXX_REG_RC, /* Remaining Capacity */ 1158c0984e5SSebastian Reichel BQ27XXX_REG_FCC, /* Full Charge Capacity */ 1168c0984e5SSebastian Reichel BQ27XXX_REG_CYCT, /* Cycle Count */ 1178c0984e5SSebastian Reichel BQ27XXX_REG_AE, /* Available Energy */ 1188c0984e5SSebastian Reichel BQ27XXX_REG_SOC, /* State-of-Charge */ 1198c0984e5SSebastian Reichel BQ27XXX_REG_DCAP, /* Design Capacity */ 1208c0984e5SSebastian Reichel BQ27XXX_REG_AP, /* Average Power */ 1210670c9b3SLiam Breck BQ27XXX_DM_CTRL, /* Block Data Control */ 1220670c9b3SLiam Breck BQ27XXX_DM_CLASS, /* Data Class */ 1230670c9b3SLiam Breck BQ27XXX_DM_BLOCK, /* Data Block */ 1240670c9b3SLiam Breck BQ27XXX_DM_DATA, /* Block Data */ 1250670c9b3SLiam Breck BQ27XXX_DM_CKSUM, /* Block Data Checksum */ 1268c0984e5SSebastian Reichel BQ27XXX_REG_MAX, /* sentinel */ 1278c0984e5SSebastian Reichel }; 1288c0984e5SSebastian Reichel 1290670c9b3SLiam Breck #define BQ27XXX_DM_REG_ROWS \ 1300670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = 0x61, \ 1310670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = 0x3e, \ 1320670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = 0x3f, \ 1330670c9b3SLiam Breck [BQ27XXX_DM_DATA] = 0x40, \ 1340670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = 0x60 1350670c9b3SLiam Breck 1368c0984e5SSebastian Reichel /* Register mappings */ 1379aade6d8SLiam Breck static u8 1389aade6d8SLiam Breck bq27000_regs[BQ27XXX_REG_MAX] = { 1398c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1408c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1418c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 1428c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1438c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1448c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1458c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1468c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = 0x18, 1478c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1c, 1488c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = 0x26, 1498c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1503ed510f0SHermes Zhang [BQ27XXX_REG_RC] = INVALID_REG_ADDR, 1518c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1528c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1538c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = 0x22, 1548c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x0b, 1558c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x76, 1568c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 1570670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 1580670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 1590670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 1600670c9b3SLiam Breck [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 1610670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 1628c0984e5SSebastian Reichel }, 1639aade6d8SLiam Breck bq27010_regs[BQ27XXX_REG_MAX] = { 1648c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1658c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1668c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 1678c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1688c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1698c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1708c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1718c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = 0x18, 1728c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1c, 1738c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = 0x26, 1748c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1753ed510f0SHermes Zhang [BQ27XXX_REG_RC] = INVALID_REG_ADDR, 1768c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1778c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1788c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 1798c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x0b, 1808c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x76, 1818c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 1820670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 1830670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 1840670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 1850670c9b3SLiam Breck [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 1860670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 1878c0984e5SSebastian Reichel }, 1889aade6d8SLiam Breck bq2750x_regs[BQ27XXX_REG_MAX] = { 1898c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1908c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1918c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 1928c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1938c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1948c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1958c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1968c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 1978c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1a, 1988c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 1998c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 2003ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 2018c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 2028c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 2038c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 2048c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 2058c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 2068c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 2070670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 2088c0984e5SSebastian Reichel }, 2091059361fSLiam Breck #define bq2751x_regs bq27510g3_regs 2101059361fSLiam Breck #define bq2752x_regs bq27510g3_regs 2119aade6d8SLiam Breck bq27500_regs[BQ27XXX_REG_MAX] = { 21232833635SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 21332833635SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 21432833635SChris Lapa [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 21532833635SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 21632833635SChris Lapa [BQ27XXX_REG_AI] = 0x14, 21732833635SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 21832833635SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 21932833635SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 22032833635SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 22132833635SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 22232833635SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 2233ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 22432833635SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 22532833635SChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 22632833635SChris Lapa [BQ27XXX_REG_AE] = 0x22, 22732833635SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 22832833635SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 22932833635SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2300670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 23132833635SChris Lapa }, 2321059361fSLiam Breck #define bq27510g1_regs bq27500_regs 2331059361fSLiam Breck #define bq27510g2_regs bq27500_regs 2349aade6d8SLiam Breck bq27510g3_regs[BQ27XXX_REG_MAX] = { 23571375aa7SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 23671375aa7SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 23771375aa7SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x28, 23871375aa7SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 23971375aa7SChris Lapa [BQ27XXX_REG_AI] = 0x14, 24071375aa7SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 24171375aa7SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 24271375aa7SChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 24371375aa7SChris Lapa [BQ27XXX_REG_TTES] = 0x1a, 24471375aa7SChris Lapa [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 24571375aa7SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 2463ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 24771375aa7SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 24871375aa7SChris Lapa [BQ27XXX_REG_CYCT] = 0x1e, 24971375aa7SChris Lapa [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 25071375aa7SChris Lapa [BQ27XXX_REG_SOC] = 0x20, 25171375aa7SChris Lapa [BQ27XXX_REG_DCAP] = 0x2e, 25271375aa7SChris Lapa [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 2530670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 25471375aa7SChris Lapa }, 2559aade6d8SLiam Breck bq27520g1_regs[BQ27XXX_REG_MAX] = { 25668f2a813SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 25768f2a813SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 25868f2a813SChris Lapa [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 25968f2a813SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 26068f2a813SChris Lapa [BQ27XXX_REG_AI] = 0x14, 26168f2a813SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 26268f2a813SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 26368f2a813SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 26468f2a813SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 26568f2a813SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 26668f2a813SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 2673ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 26868f2a813SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 26968f2a813SChris Lapa [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 27068f2a813SChris Lapa [BQ27XXX_REG_AE] = 0x22, 27168f2a813SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 27268f2a813SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 27368f2a813SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2740670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 27568f2a813SChris Lapa }, 2769aade6d8SLiam Breck bq27520g2_regs[BQ27XXX_REG_MAX] = { 277a5deb9a9SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 278a5deb9a9SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 279a5deb9a9SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x36, 280a5deb9a9SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 281a5deb9a9SChris Lapa [BQ27XXX_REG_AI] = 0x14, 282a5deb9a9SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 283a5deb9a9SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 284a5deb9a9SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 285a5deb9a9SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 286a5deb9a9SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 287a5deb9a9SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 2883ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 289a5deb9a9SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 290a5deb9a9SChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 291a5deb9a9SChris Lapa [BQ27XXX_REG_AE] = 0x22, 292a5deb9a9SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 293a5deb9a9SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 294a5deb9a9SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2950670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 296a5deb9a9SChris Lapa }, 2979aade6d8SLiam Breck bq27520g3_regs[BQ27XXX_REG_MAX] = { 298825e915bSChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 299825e915bSChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 300825e915bSChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x36, 301825e915bSChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 302825e915bSChris Lapa [BQ27XXX_REG_AI] = 0x14, 303825e915bSChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 304825e915bSChris Lapa [BQ27XXX_REG_TTE] = 0x16, 305825e915bSChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 306825e915bSChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 307825e915bSChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 308825e915bSChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 3093ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 310825e915bSChris Lapa [BQ27XXX_REG_FCC] = 0x12, 311825e915bSChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 312825e915bSChris Lapa [BQ27XXX_REG_AE] = 0x22, 313825e915bSChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 314825e915bSChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 315825e915bSChris Lapa [BQ27XXX_REG_AP] = 0x24, 3160670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 317825e915bSChris Lapa }, 3189aade6d8SLiam Breck bq27520g4_regs[BQ27XXX_REG_MAX] = { 3198835cae5SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 3208835cae5SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 3218835cae5SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x28, 3228835cae5SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 3238835cae5SChris Lapa [BQ27XXX_REG_AI] = 0x14, 3248835cae5SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 3258835cae5SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 3268835cae5SChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3278835cae5SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 3288835cae5SChris Lapa [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3298835cae5SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 3303ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 3318835cae5SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 3328835cae5SChris Lapa [BQ27XXX_REG_CYCT] = 0x1e, 3338835cae5SChris Lapa [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3348835cae5SChris Lapa [BQ27XXX_REG_SOC] = 0x20, 3358835cae5SChris Lapa [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 3368835cae5SChris Lapa [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 3370670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3388835cae5SChris Lapa }, 33970a39e10SPavel Machek bq27521_regs[BQ27XXX_REG_MAX] = { 34070a39e10SPavel Machek [BQ27XXX_REG_CTRL] = 0x02, 34170a39e10SPavel Machek [BQ27XXX_REG_TEMP] = 0x0a, 34270a39e10SPavel Machek [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 34370a39e10SPavel Machek [BQ27XXX_REG_VOLT] = 0x0c, 34470a39e10SPavel Machek [BQ27XXX_REG_AI] = 0x0e, 34570a39e10SPavel Machek [BQ27XXX_REG_FLAGS] = 0x08, 34670a39e10SPavel Machek [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, 34770a39e10SPavel Machek [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 34870a39e10SPavel Machek [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 34970a39e10SPavel Machek [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 35070a39e10SPavel Machek [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 3513ed510f0SHermes Zhang [BQ27XXX_REG_RC] = INVALID_REG_ADDR, 35270a39e10SPavel Machek [BQ27XXX_REG_FCC] = INVALID_REG_ADDR, 35370a39e10SPavel Machek [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 35470a39e10SPavel Machek [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 35570a39e10SPavel Machek [BQ27XXX_REG_SOC] = INVALID_REG_ADDR, 35670a39e10SPavel Machek [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 35770a39e10SPavel Machek [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 35870a39e10SPavel Machek [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 35970a39e10SPavel Machek [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 36070a39e10SPavel Machek [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 36170a39e10SPavel Machek [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 36270a39e10SPavel Machek [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 36370a39e10SPavel Machek }, 3649aade6d8SLiam Breck bq27530_regs[BQ27XXX_REG_MAX] = { 3658c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3668c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3678c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x32, 3688c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 3698c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 3708c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 3718c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 3728c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3738c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 3748c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3758c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 3763ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 3778c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 3788c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 3798c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3808c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 3818c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 3828c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 3830670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3848c0984e5SSebastian Reichel }, 3853a731c64SLiam Breck #define bq27531_regs bq27530_regs 3869aade6d8SLiam Breck bq27541_regs[BQ27XXX_REG_MAX] = { 3878c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3888c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3898c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 3908c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 3918c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 3928c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 3938c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 3948c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3958c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 3968c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3978c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 3983ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 3998c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 4008c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 4018c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4028c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 4038c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 4048c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 4050670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4068c0984e5SSebastian Reichel }, 4073a731c64SLiam Breck #define bq27542_regs bq27541_regs 4083a731c64SLiam Breck #define bq27546_regs bq27541_regs 4093a731c64SLiam Breck #define bq27742_regs bq27541_regs 4109aade6d8SLiam Breck bq27545_regs[BQ27XXX_REG_MAX] = { 4118c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 4128c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 4138c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 4148c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 4158c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 4168c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 4178c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 4188c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 4198c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4208c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4218c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 4223ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 4238c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 4248c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 4258c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4268c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 4278c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 4288c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 4290670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4308c0984e5SSebastian Reichel }, 4319aade6d8SLiam Breck bq27421_regs[BQ27XXX_REG_MAX] = { 4328c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 4338c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x02, 4348c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x1e, 4358c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x04, 4368c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x10, 4378c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x06, 4388c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, 4398c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 4408c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4418c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4428c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x08, 4433ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x0c, 4448c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x0e, 4458c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 4468c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4478c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x1c, 4488c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 4498c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x18, 4500670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4516f24ff97SDan Murphy }, 452457b42f0SLiu Xiang #define bq27411_regs bq27421_regs 4533a731c64SLiam Breck #define bq27425_regs bq27421_regs 4545ef6a160SAndrew F. Davis #define bq27426_regs bq27421_regs 4553a731c64SLiam Breck #define bq27441_regs bq27421_regs 4563a731c64SLiam Breck #define bq27621_regs bq27421_regs 4576f24ff97SDan Murphy bq27z561_regs[BQ27XXX_REG_MAX] = { 4586f24ff97SDan Murphy [BQ27XXX_REG_CTRL] = 0x00, 4596f24ff97SDan Murphy [BQ27XXX_REG_TEMP] = 0x06, 4606f24ff97SDan Murphy [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 4616f24ff97SDan Murphy [BQ27XXX_REG_VOLT] = 0x08, 4626f24ff97SDan Murphy [BQ27XXX_REG_AI] = 0x14, 4636f24ff97SDan Murphy [BQ27XXX_REG_FLAGS] = 0x0a, 4646f24ff97SDan Murphy [BQ27XXX_REG_TTE] = 0x16, 4656f24ff97SDan Murphy [BQ27XXX_REG_TTF] = 0x18, 4666f24ff97SDan Murphy [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4676f24ff97SDan Murphy [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4686f24ff97SDan Murphy [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 4693ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 4706f24ff97SDan Murphy [BQ27XXX_REG_FCC] = 0x12, 4716f24ff97SDan Murphy [BQ27XXX_REG_CYCT] = 0x2a, 4726f24ff97SDan Murphy [BQ27XXX_REG_AE] = 0x22, 4736f24ff97SDan Murphy [BQ27XXX_REG_SOC] = 0x2c, 4746f24ff97SDan Murphy [BQ27XXX_REG_DCAP] = 0x3c, 4756f24ff97SDan Murphy [BQ27XXX_REG_AP] = 0x22, 4766f24ff97SDan Murphy BQ27XXX_DM_REG_ROWS, 477707d678aSDan Murphy }, 478707d678aSDan Murphy bq28z610_regs[BQ27XXX_REG_MAX] = { 479707d678aSDan Murphy [BQ27XXX_REG_CTRL] = 0x00, 480707d678aSDan Murphy [BQ27XXX_REG_TEMP] = 0x06, 481707d678aSDan Murphy [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 482707d678aSDan Murphy [BQ27XXX_REG_VOLT] = 0x08, 483707d678aSDan Murphy [BQ27XXX_REG_AI] = 0x14, 484707d678aSDan Murphy [BQ27XXX_REG_FLAGS] = 0x0a, 485707d678aSDan Murphy [BQ27XXX_REG_TTE] = 0x16, 486707d678aSDan Murphy [BQ27XXX_REG_TTF] = 0x18, 487707d678aSDan Murphy [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 488707d678aSDan Murphy [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 489707d678aSDan Murphy [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 4903ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x10, 491707d678aSDan Murphy [BQ27XXX_REG_FCC] = 0x12, 492707d678aSDan Murphy [BQ27XXX_REG_CYCT] = 0x2a, 493707d678aSDan Murphy [BQ27XXX_REG_AE] = 0x22, 494707d678aSDan Murphy [BQ27XXX_REG_SOC] = 0x2c, 495707d678aSDan Murphy [BQ27XXX_REG_DCAP] = 0x3c, 496707d678aSDan Murphy [BQ27XXX_REG_AP] = 0x22, 497707d678aSDan Murphy BQ27XXX_DM_REG_ROWS, 49841a7431dSKrzysztof Kozlowski }, 49941a7431dSKrzysztof Kozlowski bq34z100_regs[BQ27XXX_REG_MAX] = { 50041a7431dSKrzysztof Kozlowski [BQ27XXX_REG_CTRL] = 0x00, 50141a7431dSKrzysztof Kozlowski [BQ27XXX_REG_TEMP] = 0x0c, 50241a7431dSKrzysztof Kozlowski [BQ27XXX_REG_INT_TEMP] = 0x2a, 50341a7431dSKrzysztof Kozlowski [BQ27XXX_REG_VOLT] = 0x08, 50441a7431dSKrzysztof Kozlowski [BQ27XXX_REG_AI] = 0x0a, 50541a7431dSKrzysztof Kozlowski [BQ27XXX_REG_FLAGS] = 0x0e, 50641a7431dSKrzysztof Kozlowski [BQ27XXX_REG_TTE] = 0x18, 50741a7431dSKrzysztof Kozlowski [BQ27XXX_REG_TTF] = 0x1a, 50841a7431dSKrzysztof Kozlowski [BQ27XXX_REG_TTES] = 0x1e, 50941a7431dSKrzysztof Kozlowski [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 51041a7431dSKrzysztof Kozlowski [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 5113ed510f0SHermes Zhang [BQ27XXX_REG_RC] = 0x04, 51241a7431dSKrzysztof Kozlowski [BQ27XXX_REG_FCC] = 0x06, 51341a7431dSKrzysztof Kozlowski [BQ27XXX_REG_CYCT] = 0x2c, 51441a7431dSKrzysztof Kozlowski [BQ27XXX_REG_AE] = 0x24, 51541a7431dSKrzysztof Kozlowski [BQ27XXX_REG_SOC] = 0x02, 51641a7431dSKrzysztof Kozlowski [BQ27XXX_REG_DCAP] = 0x3c, 51741a7431dSKrzysztof Kozlowski [BQ27XXX_REG_AP] = 0x22, 51841a7431dSKrzysztof Kozlowski BQ27XXX_DM_REG_ROWS, 5194eed7f5aSLI Qingwu }, 5204eed7f5aSLI Qingwu bq78z100_regs[BQ27XXX_REG_MAX] = { 5214eed7f5aSLI Qingwu [BQ27XXX_REG_CTRL] = 0x00, 5224eed7f5aSLI Qingwu [BQ27XXX_REG_TEMP] = 0x06, 5234eed7f5aSLI Qingwu [BQ27XXX_REG_INT_TEMP] = 0x28, 5244eed7f5aSLI Qingwu [BQ27XXX_REG_VOLT] = 0x08, 5254eed7f5aSLI Qingwu [BQ27XXX_REG_AI] = 0x14, 5264eed7f5aSLI Qingwu [BQ27XXX_REG_FLAGS] = 0x0a, 5274eed7f5aSLI Qingwu [BQ27XXX_REG_TTE] = 0x16, 5284eed7f5aSLI Qingwu [BQ27XXX_REG_TTF] = 0x18, 5294eed7f5aSLI Qingwu [BQ27XXX_REG_TTES] = 0x1c, 5304eed7f5aSLI Qingwu [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 5314eed7f5aSLI Qingwu [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 5324eed7f5aSLI Qingwu [BQ27XXX_REG_RC] = 0x10, 5334eed7f5aSLI Qingwu [BQ27XXX_REG_FCC] = 0x12, 5344eed7f5aSLI Qingwu [BQ27XXX_REG_CYCT] = 0x2a, 5354eed7f5aSLI Qingwu [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 5364eed7f5aSLI Qingwu [BQ27XXX_REG_SOC] = 0x2c, 5374eed7f5aSLI Qingwu [BQ27XXX_REG_DCAP] = 0x3c, 5384eed7f5aSLI Qingwu [BQ27XXX_REG_AP] = 0x22, 5394eed7f5aSLI Qingwu BQ27XXX_DM_REG_ROWS, 5406f24ff97SDan Murphy }; 5418c0984e5SSebastian Reichel 5429aade6d8SLiam Breck static enum power_supply_property bq27000_props[] = { 5438c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 5448c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 5458c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 5468c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 5478c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 5488c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 5498c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 5508c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 5518c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 5528c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 5538c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 5548c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 5558c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 5568c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 5578c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 5588c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ENERGY_NOW, 5598c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 5608c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 5618c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 5628c0984e5SSebastian Reichel }; 5638c0984e5SSebastian Reichel 5649aade6d8SLiam Breck static enum power_supply_property bq27010_props[] = { 5658c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 5668c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 5678c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 5688c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 5698c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 5708c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 5718c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 5728c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 5738c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 5748c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 5758c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 5768c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 5778c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 5788c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 5798c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 5808c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 5818c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 5828c0984e5SSebastian Reichel }; 5838c0984e5SSebastian Reichel 5841059361fSLiam Breck #define bq2750x_props bq27510g3_props 5851059361fSLiam Breck #define bq2751x_props bq27510g3_props 5861059361fSLiam Breck #define bq2752x_props bq27510g3_props 5873bee9ea1SAndrew F. Davis 5889aade6d8SLiam Breck static enum power_supply_property bq27500_props[] = { 58932833635SChris Lapa POWER_SUPPLY_PROP_STATUS, 59032833635SChris Lapa POWER_SUPPLY_PROP_PRESENT, 59132833635SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 59232833635SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 59332833635SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 59432833635SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 59532833635SChris Lapa POWER_SUPPLY_PROP_TEMP, 59632833635SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 59732833635SChris Lapa POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 59832833635SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 59932833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 60032833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 60132833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 60232833635SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 60332833635SChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 60432833635SChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 60532833635SChris Lapa POWER_SUPPLY_PROP_HEALTH, 60632833635SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 60732833635SChris Lapa }; 6081059361fSLiam Breck #define bq27510g1_props bq27500_props 6091059361fSLiam Breck #define bq27510g2_props bq27500_props 610698a2bf5SChris Lapa 6119aade6d8SLiam Breck static enum power_supply_property bq27510g3_props[] = { 61271375aa7SChris Lapa POWER_SUPPLY_PROP_STATUS, 61371375aa7SChris Lapa POWER_SUPPLY_PROP_PRESENT, 61471375aa7SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 61571375aa7SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 61671375aa7SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 61771375aa7SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 61871375aa7SChris Lapa POWER_SUPPLY_PROP_TEMP, 61971375aa7SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 62071375aa7SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 62171375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 62271375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 62371375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 62471375aa7SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 62571375aa7SChris Lapa POWER_SUPPLY_PROP_HEALTH, 62671375aa7SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 62771375aa7SChris Lapa }; 62871375aa7SChris Lapa 6299aade6d8SLiam Breck static enum power_supply_property bq27520g1_props[] = { 63068f2a813SChris Lapa POWER_SUPPLY_PROP_STATUS, 63168f2a813SChris Lapa POWER_SUPPLY_PROP_PRESENT, 63268f2a813SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 63368f2a813SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 63468f2a813SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 63568f2a813SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 63668f2a813SChris Lapa POWER_SUPPLY_PROP_TEMP, 63768f2a813SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 63868f2a813SChris Lapa POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 63968f2a813SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 64068f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 64168f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 64268f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 64368f2a813SChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 64468f2a813SChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 64568f2a813SChris Lapa POWER_SUPPLY_PROP_HEALTH, 64668f2a813SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 64768f2a813SChris Lapa }; 64868f2a813SChris Lapa 6491059361fSLiam Breck #define bq27520g2_props bq27500_props 650a5deb9a9SChris Lapa 6519aade6d8SLiam Breck static enum power_supply_property bq27520g3_props[] = { 652825e915bSChris Lapa POWER_SUPPLY_PROP_STATUS, 653825e915bSChris Lapa POWER_SUPPLY_PROP_PRESENT, 654825e915bSChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 655825e915bSChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 656825e915bSChris Lapa POWER_SUPPLY_PROP_CAPACITY, 657825e915bSChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 658825e915bSChris Lapa POWER_SUPPLY_PROP_TEMP, 659825e915bSChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 660825e915bSChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 661825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 662825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 663825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 664825e915bSChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 665825e915bSChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 666825e915bSChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 667825e915bSChris Lapa POWER_SUPPLY_PROP_HEALTH, 668825e915bSChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 669825e915bSChris Lapa }; 670825e915bSChris Lapa 6719aade6d8SLiam Breck static enum power_supply_property bq27520g4_props[] = { 6728835cae5SChris Lapa POWER_SUPPLY_PROP_STATUS, 6738835cae5SChris Lapa POWER_SUPPLY_PROP_PRESENT, 6748835cae5SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 6758835cae5SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 6768835cae5SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 6778835cae5SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6788835cae5SChris Lapa POWER_SUPPLY_PROP_TEMP, 6798835cae5SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6808835cae5SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 6818835cae5SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 6828835cae5SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 6838835cae5SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 6848835cae5SChris Lapa POWER_SUPPLY_PROP_HEALTH, 6858835cae5SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 6868835cae5SChris Lapa }; 6878835cae5SChris Lapa 68870a39e10SPavel Machek static enum power_supply_property bq27521_props[] = { 68970a39e10SPavel Machek POWER_SUPPLY_PROP_STATUS, 69070a39e10SPavel Machek POWER_SUPPLY_PROP_PRESENT, 69170a39e10SPavel Machek POWER_SUPPLY_PROP_VOLTAGE_NOW, 69270a39e10SPavel Machek POWER_SUPPLY_PROP_CURRENT_NOW, 69370a39e10SPavel Machek POWER_SUPPLY_PROP_TEMP, 69470a39e10SPavel Machek POWER_SUPPLY_PROP_TECHNOLOGY, 69570a39e10SPavel Machek }; 69670a39e10SPavel Machek 6979aade6d8SLiam Breck static enum power_supply_property bq27530_props[] = { 6988c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6998c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 7008c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 7018c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 7028c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 7038c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7048c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 7058c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 7068c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 7078c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 7088c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 7098c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 7108c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 7118c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 7128c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7138c0984e5SSebastian Reichel }; 7143a731c64SLiam Breck #define bq27531_props bq27530_props 7158c0984e5SSebastian Reichel 7169aade6d8SLiam Breck static enum power_supply_property bq27541_props[] = { 7178c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 7188c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 7198c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 7208c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 7218c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 7228c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7238c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 7248c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 7258c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 7268c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 7278c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 7288c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7298c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 7308c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 7318c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 7328c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7338c0984e5SSebastian Reichel }; 7343a731c64SLiam Breck #define bq27542_props bq27541_props 7353a731c64SLiam Breck #define bq27546_props bq27541_props 7363a731c64SLiam Breck #define bq27742_props bq27541_props 7378c0984e5SSebastian Reichel 7389aade6d8SLiam Breck static enum power_supply_property bq27545_props[] = { 7398c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 7408c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 7418c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 7428c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 7438c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 7448c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7458c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 7468c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 7478c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 7488c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 7498c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 7508c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 7518c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 7528c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 7538c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7548c0984e5SSebastian Reichel }; 7558c0984e5SSebastian Reichel 7569aade6d8SLiam Breck static enum power_supply_property bq27421_props[] = { 7578c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 7588c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 7598c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 7608c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 7618c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 7628c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7638c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 7648c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 7658c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 7668c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 7678c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7688c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7698c0984e5SSebastian Reichel }; 770457b42f0SLiu Xiang #define bq27411_props bq27421_props 7713a731c64SLiam Breck #define bq27425_props bq27421_props 7725ef6a160SAndrew F. Davis #define bq27426_props bq27421_props 7733a731c64SLiam Breck #define bq27441_props bq27421_props 7743a731c64SLiam Breck #define bq27621_props bq27421_props 7758c0984e5SSebastian Reichel 7766f24ff97SDan Murphy static enum power_supply_property bq27z561_props[] = { 7776f24ff97SDan Murphy POWER_SUPPLY_PROP_STATUS, 7786f24ff97SDan Murphy POWER_SUPPLY_PROP_PRESENT, 7796f24ff97SDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 7806f24ff97SDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 7816f24ff97SDan Murphy POWER_SUPPLY_PROP_CAPACITY, 7826f24ff97SDan Murphy POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7836f24ff97SDan Murphy POWER_SUPPLY_PROP_TEMP, 7846f24ff97SDan Murphy POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 7856f24ff97SDan Murphy POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 7866f24ff97SDan Murphy POWER_SUPPLY_PROP_TECHNOLOGY, 7876f24ff97SDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL, 7883ed510f0SHermes Zhang POWER_SUPPLY_PROP_CHARGE_NOW, 7896f24ff97SDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7906f24ff97SDan Murphy POWER_SUPPLY_PROP_CYCLE_COUNT, 7916f24ff97SDan Murphy POWER_SUPPLY_PROP_POWER_AVG, 7926f24ff97SDan Murphy POWER_SUPPLY_PROP_HEALTH, 7936f24ff97SDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 7946f24ff97SDan Murphy }; 7956f24ff97SDan Murphy 796707d678aSDan Murphy static enum power_supply_property bq28z610_props[] = { 797707d678aSDan Murphy POWER_SUPPLY_PROP_STATUS, 798707d678aSDan Murphy POWER_SUPPLY_PROP_PRESENT, 799707d678aSDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 800707d678aSDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 801707d678aSDan Murphy POWER_SUPPLY_PROP_CAPACITY, 802707d678aSDan Murphy POWER_SUPPLY_PROP_CAPACITY_LEVEL, 803707d678aSDan Murphy POWER_SUPPLY_PROP_TEMP, 804707d678aSDan Murphy POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 805707d678aSDan Murphy POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 806707d678aSDan Murphy POWER_SUPPLY_PROP_TECHNOLOGY, 807707d678aSDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL, 8083ed510f0SHermes Zhang POWER_SUPPLY_PROP_CHARGE_NOW, 809707d678aSDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 810707d678aSDan Murphy POWER_SUPPLY_PROP_CYCLE_COUNT, 811707d678aSDan Murphy POWER_SUPPLY_PROP_POWER_AVG, 812707d678aSDan Murphy POWER_SUPPLY_PROP_HEALTH, 813707d678aSDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 814707d678aSDan Murphy }; 815707d678aSDan Murphy 81641a7431dSKrzysztof Kozlowski static enum power_supply_property bq34z100_props[] = { 81741a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_STATUS, 81841a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_PRESENT, 81941a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_VOLTAGE_NOW, 82041a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_CURRENT_NOW, 82141a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_CAPACITY, 82241a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_CAPACITY_LEVEL, 82341a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_TEMP, 82441a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 82541a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 82641a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 82741a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_TECHNOLOGY, 82841a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_CHARGE_FULL, 8293ed510f0SHermes Zhang POWER_SUPPLY_PROP_CHARGE_NOW, 83041a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 83141a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_CYCLE_COUNT, 83241a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_ENERGY_NOW, 83341a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_POWER_AVG, 83441a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_HEALTH, 83541a7431dSKrzysztof Kozlowski POWER_SUPPLY_PROP_MANUFACTURER, 83641a7431dSKrzysztof Kozlowski }; 83741a7431dSKrzysztof Kozlowski 8384eed7f5aSLI Qingwu static enum power_supply_property bq78z100_props[] = { 8394eed7f5aSLI Qingwu POWER_SUPPLY_PROP_STATUS, 8404eed7f5aSLI Qingwu POWER_SUPPLY_PROP_PRESENT, 8414eed7f5aSLI Qingwu POWER_SUPPLY_PROP_VOLTAGE_NOW, 8424eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CURRENT_NOW, 8434eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CAPACITY, 8444eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CAPACITY_LEVEL, 8454eed7f5aSLI Qingwu POWER_SUPPLY_PROP_TEMP, 8464eed7f5aSLI Qingwu POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 8474eed7f5aSLI Qingwu POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 8484eed7f5aSLI Qingwu POWER_SUPPLY_PROP_TECHNOLOGY, 8494eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CHARGE_FULL, 8504eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CHARGE_NOW, 8514eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 8524eed7f5aSLI Qingwu POWER_SUPPLY_PROP_CYCLE_COUNT, 8534eed7f5aSLI Qingwu POWER_SUPPLY_PROP_POWER_AVG, 8544eed7f5aSLI Qingwu POWER_SUPPLY_PROP_HEALTH, 8554eed7f5aSLI Qingwu POWER_SUPPLY_PROP_MANUFACTURER, 8564eed7f5aSLI Qingwu }; 8574eed7f5aSLI Qingwu 85805045379SLiam Breck struct bq27xxx_dm_reg { 85905045379SLiam Breck u8 subclass_id; 86005045379SLiam Breck u8 offset; 86105045379SLiam Breck u8 bytes; 86205045379SLiam Breck u16 min, max; 86305045379SLiam Breck }; 86405045379SLiam Breck 86505045379SLiam Breck enum bq27xxx_dm_reg_id { 86605045379SLiam Breck BQ27XXX_DM_DESIGN_CAPACITY = 0, 86705045379SLiam Breck BQ27XXX_DM_DESIGN_ENERGY, 86805045379SLiam Breck BQ27XXX_DM_TERMINATE_VOLTAGE, 86905045379SLiam Breck }; 87005045379SLiam Breck 87105045379SLiam Breck #define bq27000_dm_regs 0 87205045379SLiam Breck #define bq27010_dm_regs 0 87305045379SLiam Breck #define bq2750x_dm_regs 0 87405045379SLiam Breck #define bq2751x_dm_regs 0 87505045379SLiam Breck #define bq2752x_dm_regs 0 87605045379SLiam Breck 87705045379SLiam Breck #if 0 /* not yet tested */ 87805045379SLiam Breck static struct bq27xxx_dm_reg bq27500_dm_regs[] = { 87905045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 10, 2, 0, 65535 }, 88005045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { }, /* missing on chip */ 88105045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 }, 88205045379SLiam Breck }; 88305045379SLiam Breck #else 88405045379SLiam Breck #define bq27500_dm_regs 0 88505045379SLiam Breck #endif 88605045379SLiam Breck 88705045379SLiam Breck /* todo create data memory definitions from datasheets and test on chips */ 88805045379SLiam Breck #define bq27510g1_dm_regs 0 88905045379SLiam Breck #define bq27510g2_dm_regs 0 89005045379SLiam Breck #define bq27510g3_dm_regs 0 89105045379SLiam Breck #define bq27520g1_dm_regs 0 89205045379SLiam Breck #define bq27520g2_dm_regs 0 89305045379SLiam Breck #define bq27520g3_dm_regs 0 89405045379SLiam Breck #define bq27520g4_dm_regs 0 89570a39e10SPavel Machek #define bq27521_dm_regs 0 89605045379SLiam Breck #define bq27530_dm_regs 0 89705045379SLiam Breck #define bq27531_dm_regs 0 89805045379SLiam Breck #define bq27541_dm_regs 0 89905045379SLiam Breck #define bq27542_dm_regs 0 90005045379SLiam Breck #define bq27546_dm_regs 0 90105045379SLiam Breck #define bq27742_dm_regs 0 90205045379SLiam Breck 90305045379SLiam Breck #if 0 /* not yet tested */ 90405045379SLiam Breck static struct bq27xxx_dm_reg bq27545_dm_regs[] = { 90505045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 23, 2, 0, 32767 }, 90605045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 48, 25, 2, 0, 32767 }, 90705045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800, 3700 }, 90805045379SLiam Breck }; 90905045379SLiam Breck #else 91005045379SLiam Breck #define bq27545_dm_regs 0 91105045379SLiam Breck #endif 91205045379SLiam Breck 913457b42f0SLiu Xiang static struct bq27xxx_dm_reg bq27411_dm_regs[] = { 914457b42f0SLiu Xiang [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 32767 }, 915457b42f0SLiu Xiang [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, 916457b42f0SLiu Xiang [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, 917457b42f0SLiu Xiang }; 918457b42f0SLiu Xiang 91905045379SLiam Breck static struct bq27xxx_dm_reg bq27421_dm_regs[] = { 92005045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, 92105045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, 92205045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 }, 92305045379SLiam Breck }; 92405045379SLiam Breck 92505045379SLiam Breck static struct bq27xxx_dm_reg bq27425_dm_regs[] = { 92605045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 12, 2, 0, 32767 }, 92705045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 14, 2, 0, 32767 }, 92805045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800, 3700 }, 92905045379SLiam Breck }; 93005045379SLiam Breck 9315ef6a160SAndrew F. Davis static struct bq27xxx_dm_reg bq27426_dm_regs[] = { 9325ef6a160SAndrew F. Davis [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 6, 2, 0, 8000 }, 9335ef6a160SAndrew F. Davis [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 8, 2, 0, 32767 }, 9345ef6a160SAndrew F. Davis [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 10, 2, 2500, 3700 }, 9355ef6a160SAndrew F. Davis }; 9365ef6a160SAndrew F. Davis 93705045379SLiam Breck #if 0 /* not yet tested */ 93805045379SLiam Breck #define bq27441_dm_regs bq27421_dm_regs 93905045379SLiam Breck #else 94005045379SLiam Breck #define bq27441_dm_regs 0 94105045379SLiam Breck #endif 94205045379SLiam Breck 94305045379SLiam Breck #if 0 /* not yet tested */ 94405045379SLiam Breck static struct bq27xxx_dm_reg bq27621_dm_regs[] = { 94505045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 3, 2, 0, 8000 }, 94605045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 5, 2, 0, 32767 }, 94705045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500, 3700 }, 94805045379SLiam Breck }; 94905045379SLiam Breck #else 95005045379SLiam Breck #define bq27621_dm_regs 0 95105045379SLiam Breck #endif 95205045379SLiam Breck 9536f24ff97SDan Murphy #define bq27z561_dm_regs 0 954707d678aSDan Murphy #define bq28z610_dm_regs 0 955bffa569fSKrzysztof Kozlowski #define bq34z100_dm_regs 0 9564eed7f5aSLI Qingwu #define bq78z100_dm_regs 0 9576f24ff97SDan Murphy 958bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_ZERO BIT(0) 959bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_OTDC BIT(1) /* has OTC/OTD overtemperature flags */ 960bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_UTOT BIT(2) /* has OT overtemperature flag */ 961bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_CFGUP BIT(3) 962bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_RAM BIT(4) 963bffa569fSKrzysztof Kozlowski #define BQ27Z561_O_BITS BIT(5) 964c02ca201SKrzysztof Kozlowski #define BQ27XXX_O_SOC_SI BIT(6) /* SoC is single register */ 9657be64ae0SKrzysztof Kozlowski #define BQ27XXX_O_HAS_CI BIT(7) /* has Capacity Inaccurate flag */ 96641a7431dSKrzysztof Kozlowski #define BQ27XXX_O_MUL_CHEM BIT(8) /* multiple chemistries supported */ 9673a731c64SLiam Breck 96805045379SLiam Breck #define BQ27XXX_DATA(ref, key, opt) { \ 9693a731c64SLiam Breck .opts = (opt), \ 97005045379SLiam Breck .unseal_key = key, \ 9719aade6d8SLiam Breck .regs = ref##_regs, \ 97205045379SLiam Breck .dm_regs = ref##_dm_regs, \ 9739aade6d8SLiam Breck .props = ref##_props, \ 9749aade6d8SLiam Breck .props_size = ARRAY_SIZE(ref##_props) } 9758c0984e5SSebastian Reichel 9768c0984e5SSebastian Reichel static struct { 9773a731c64SLiam Breck u32 opts; 97805045379SLiam Breck u32 unseal_key; 9799aade6d8SLiam Breck u8 *regs; 98005045379SLiam Breck struct bq27xxx_dm_reg *dm_regs; 9818c0984e5SSebastian Reichel enum power_supply_property *props; 9829aade6d8SLiam Breck size_t props_size; 9839aade6d8SLiam Breck } bq27xxx_chip_data[] = { 9847be64ae0SKrzysztof Kozlowski [BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO | BQ27XXX_O_SOC_SI | BQ27XXX_O_HAS_CI), 9857be64ae0SKrzysztof Kozlowski [BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO | BQ27XXX_O_SOC_SI | BQ27XXX_O_HAS_CI), 98605045379SLiam Breck [BQ2750X] = BQ27XXX_DATA(bq2750x, 0 , BQ27XXX_O_OTDC), 98705045379SLiam Breck [BQ2751X] = BQ27XXX_DATA(bq2751x, 0 , BQ27XXX_O_OTDC), 98805045379SLiam Breck [BQ2752X] = BQ27XXX_DATA(bq2752x, 0 , BQ27XXX_O_OTDC), 98905045379SLiam Breck [BQ27500] = BQ27XXX_DATA(bq27500, 0x04143672, BQ27XXX_O_OTDC), 99005045379SLiam Breck [BQ27510G1] = BQ27XXX_DATA(bq27510g1, 0 , BQ27XXX_O_OTDC), 99105045379SLiam Breck [BQ27510G2] = BQ27XXX_DATA(bq27510g2, 0 , BQ27XXX_O_OTDC), 99205045379SLiam Breck [BQ27510G3] = BQ27XXX_DATA(bq27510g3, 0 , BQ27XXX_O_OTDC), 99305045379SLiam Breck [BQ27520G1] = BQ27XXX_DATA(bq27520g1, 0 , BQ27XXX_O_OTDC), 99405045379SLiam Breck [BQ27520G2] = BQ27XXX_DATA(bq27520g2, 0 , BQ27XXX_O_OTDC), 99505045379SLiam Breck [BQ27520G3] = BQ27XXX_DATA(bq27520g3, 0 , BQ27XXX_O_OTDC), 99605045379SLiam Breck [BQ27520G4] = BQ27XXX_DATA(bq27520g4, 0 , BQ27XXX_O_OTDC), 99770a39e10SPavel Machek [BQ27521] = BQ27XXX_DATA(bq27521, 0 , 0), 99805045379SLiam Breck [BQ27530] = BQ27XXX_DATA(bq27530, 0 , BQ27XXX_O_UTOT), 99905045379SLiam Breck [BQ27531] = BQ27XXX_DATA(bq27531, 0 , BQ27XXX_O_UTOT), 100005045379SLiam Breck [BQ27541] = BQ27XXX_DATA(bq27541, 0 , BQ27XXX_O_OTDC), 100105045379SLiam Breck [BQ27542] = BQ27XXX_DATA(bq27542, 0 , BQ27XXX_O_OTDC), 100205045379SLiam Breck [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), 100305045379SLiam Breck [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), 100405045379SLiam Breck [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), 1005457b42f0SLiu Xiang [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 100605045379SLiam Breck [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 100705045379SLiam Breck [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), 10085ef6a160SAndrew F. Davis [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 100905045379SLiam Breck [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 101005045379SLiam Breck [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 10116f24ff97SDan Murphy [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), 1012707d678aSDan Murphy [BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS), 101341a7431dSKrzysztof Kozlowski [BQ34Z100] = BQ27XXX_DATA(bq34z100, 0 , BQ27XXX_O_OTDC | BQ27XXX_O_SOC_SI | \ 101441a7431dSKrzysztof Kozlowski BQ27XXX_O_HAS_CI | BQ27XXX_O_MUL_CHEM), 10154eed7f5aSLI Qingwu [BQ78Z100] = BQ27XXX_DATA(bq78z100, 0 , BQ27Z561_O_BITS), 10168c0984e5SSebastian Reichel }; 10178c0984e5SSebastian Reichel 10181d72706fSMatt Ranostay static DEFINE_MUTEX(bq27xxx_list_lock); 10191d72706fSMatt Ranostay static LIST_HEAD(bq27xxx_battery_devices); 10201d72706fSMatt Ranostay 10210670c9b3SLiam Breck #define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500) 10220670c9b3SLiam Breck 10230670c9b3SLiam Breck #define BQ27XXX_DM_SZ 32 10240670c9b3SLiam Breck 10250670c9b3SLiam Breck /** 10260670c9b3SLiam Breck * struct bq27xxx_dm_buf - chip data memory buffer 10270670c9b3SLiam Breck * @class: data memory subclass_id 10280670c9b3SLiam Breck * @block: data memory block number 10290670c9b3SLiam Breck * @data: data from/for the block 10300670c9b3SLiam Breck * @has_data: true if data has been filled by read 10310670c9b3SLiam Breck * @dirty: true if data has changed since last read/write 10320670c9b3SLiam Breck * 10330670c9b3SLiam Breck * Encapsulates info required to manage chip data memory blocks. 10340670c9b3SLiam Breck */ 10350670c9b3SLiam Breck struct bq27xxx_dm_buf { 10360670c9b3SLiam Breck u8 class; 10370670c9b3SLiam Breck u8 block; 10380670c9b3SLiam Breck u8 data[BQ27XXX_DM_SZ]; 10390670c9b3SLiam Breck bool has_data, dirty; 10400670c9b3SLiam Breck }; 10410670c9b3SLiam Breck 1042ccce4409SLiam Breck #define BQ27XXX_DM_BUF(di, i) { \ 1043ccce4409SLiam Breck .class = (di)->dm_regs[i].subclass_id, \ 1044ccce4409SLiam Breck .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \ 1045ccce4409SLiam Breck } 1046ccce4409SLiam Breck 1047ccce4409SLiam Breck static inline u16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf, 1048ccce4409SLiam Breck struct bq27xxx_dm_reg *reg) 1049ccce4409SLiam Breck { 1050ccce4409SLiam Breck if (buf->class == reg->subclass_id && 1051ccce4409SLiam Breck buf->block == reg->offset / BQ27XXX_DM_SZ) 1052ccce4409SLiam Breck return (u16 *) (buf->data + reg->offset % BQ27XXX_DM_SZ); 1053ccce4409SLiam Breck 1054ccce4409SLiam Breck return NULL; 1055ccce4409SLiam Breck } 1056ccce4409SLiam Breck 1057ccce4409SLiam Breck static const char * const bq27xxx_dm_reg_name[] = { 1058ccce4409SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity", 1059ccce4409SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy", 1060ccce4409SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage", 1061ccce4409SLiam Breck }; 1062ccce4409SLiam Breck 1063ccce4409SLiam Breck 1064ccce4409SLiam Breck static bool bq27xxx_dt_to_nvm = true; 1065ccce4409SLiam Breck module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444); 1066ccce4409SLiam Breck MODULE_PARM_DESC(dt_monitored_battery_updates_nvm, 1067ccce4409SLiam Breck "Devicetree monitored-battery config updates data memory on NVM/flash chips.\n" 1068ccce4409SLiam Breck "Users must set this =0 when installing a different type of battery!\n" 1069ccce4409SLiam Breck "Default is =1." 1070ccce4409SLiam Breck #ifndef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 1071ccce4409SLiam Breck "\nSetting this affects future kernel updates, not the current configuration." 1072ccce4409SLiam Breck #endif 1073ccce4409SLiam Breck ); 10740670c9b3SLiam Breck 10751d72706fSMatt Ranostay static int poll_interval_param_set(const char *val, const struct kernel_param *kp) 10761d72706fSMatt Ranostay { 10771d72706fSMatt Ranostay struct bq27xxx_device_info *di; 1078950b6c2dSMatt Ranostay unsigned int prev_val = *(unsigned int *) kp->arg; 10791d72706fSMatt Ranostay int ret; 10801d72706fSMatt Ranostay 10811d72706fSMatt Ranostay ret = param_set_uint(val, kp); 1082950b6c2dSMatt Ranostay if (ret < 0 || prev_val == *(unsigned int *) kp->arg) 10831d72706fSMatt Ranostay return ret; 10841d72706fSMatt Ranostay 10851d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 10861d72706fSMatt Ranostay list_for_each_entry(di, &bq27xxx_battery_devices, list) { 10871d72706fSMatt Ranostay cancel_delayed_work_sync(&di->work); 10881d72706fSMatt Ranostay schedule_delayed_work(&di->work, 0); 10891d72706fSMatt Ranostay } 10901d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 10911d72706fSMatt Ranostay 10921d72706fSMatt Ranostay return ret; 10931d72706fSMatt Ranostay } 10941d72706fSMatt Ranostay 10951d72706fSMatt Ranostay static const struct kernel_param_ops param_ops_poll_interval = { 10961d72706fSMatt Ranostay .get = param_get_uint, 10971d72706fSMatt Ranostay .set = poll_interval_param_set, 10981d72706fSMatt Ranostay }; 10991d72706fSMatt Ranostay 11008c0984e5SSebastian Reichel static unsigned int poll_interval = 360; 11011d72706fSMatt Ranostay module_param_cb(poll_interval, ¶m_ops_poll_interval, &poll_interval, 0644); 11028c0984e5SSebastian Reichel MODULE_PARM_DESC(poll_interval, 11038c0984e5SSebastian Reichel "battery poll interval in seconds - 0 disables polling"); 11048c0984e5SSebastian Reichel 11058c0984e5SSebastian Reichel /* 11068c0984e5SSebastian Reichel * Common code for BQ27xxx devices 11078c0984e5SSebastian Reichel */ 11088c0984e5SSebastian Reichel 11098c0984e5SSebastian Reichel static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, 11108c0984e5SSebastian Reichel bool single) 11118c0984e5SSebastian Reichel { 111214073f66SMatt Ranostay int ret; 111314073f66SMatt Ranostay 11148c0984e5SSebastian Reichel if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 11158c0984e5SSebastian Reichel return -EINVAL; 11168c0984e5SSebastian Reichel 111714073f66SMatt Ranostay ret = di->bus.read(di, di->regs[reg_index], single); 111814073f66SMatt Ranostay if (ret < 0) 111914073f66SMatt Ranostay dev_dbg(di->dev, "failed to read register 0x%02x (index %d)\n", 112014073f66SMatt Ranostay di->regs[reg_index], reg_index); 112114073f66SMatt Ranostay 112214073f66SMatt Ranostay return ret; 112314073f66SMatt Ranostay } 112414073f66SMatt Ranostay 112514073f66SMatt Ranostay static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, 112614073f66SMatt Ranostay u16 value, bool single) 112714073f66SMatt Ranostay { 112814073f66SMatt Ranostay int ret; 112914073f66SMatt Ranostay 113014073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 113114073f66SMatt Ranostay return -EINVAL; 113214073f66SMatt Ranostay 113314073f66SMatt Ranostay if (!di->bus.write) 113414073f66SMatt Ranostay return -EPERM; 113514073f66SMatt Ranostay 113614073f66SMatt Ranostay ret = di->bus.write(di, di->regs[reg_index], value, single); 113714073f66SMatt Ranostay if (ret < 0) 113814073f66SMatt Ranostay dev_dbg(di->dev, "failed to write register 0x%02x (index %d)\n", 113914073f66SMatt Ranostay di->regs[reg_index], reg_index); 114014073f66SMatt Ranostay 114114073f66SMatt Ranostay return ret; 114214073f66SMatt Ranostay } 114314073f66SMatt Ranostay 114414073f66SMatt Ranostay static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_index, 114514073f66SMatt Ranostay u8 *data, int len) 114614073f66SMatt Ranostay { 114714073f66SMatt Ranostay int ret; 114814073f66SMatt Ranostay 114914073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 115014073f66SMatt Ranostay return -EINVAL; 115114073f66SMatt Ranostay 115214073f66SMatt Ranostay if (!di->bus.read_bulk) 115314073f66SMatt Ranostay return -EPERM; 115414073f66SMatt Ranostay 115514073f66SMatt Ranostay ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); 115614073f66SMatt Ranostay if (ret < 0) 115714073f66SMatt Ranostay dev_dbg(di->dev, "failed to read_bulk register 0x%02x (index %d)\n", 115814073f66SMatt Ranostay di->regs[reg_index], reg_index); 115914073f66SMatt Ranostay 116014073f66SMatt Ranostay return ret; 116114073f66SMatt Ranostay } 116214073f66SMatt Ranostay 116314073f66SMatt Ranostay static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_index, 116414073f66SMatt Ranostay u8 *data, int len) 116514073f66SMatt Ranostay { 116614073f66SMatt Ranostay int ret; 116714073f66SMatt Ranostay 116814073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 116914073f66SMatt Ranostay return -EINVAL; 117014073f66SMatt Ranostay 117114073f66SMatt Ranostay if (!di->bus.write_bulk) 117214073f66SMatt Ranostay return -EPERM; 117314073f66SMatt Ranostay 117414073f66SMatt Ranostay ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); 117514073f66SMatt Ranostay if (ret < 0) 117614073f66SMatt Ranostay dev_dbg(di->dev, "failed to write_bulk register 0x%02x (index %d)\n", 117714073f66SMatt Ranostay di->regs[reg_index], reg_index); 117814073f66SMatt Ranostay 117914073f66SMatt Ranostay return ret; 11808c0984e5SSebastian Reichel } 11818c0984e5SSebastian Reichel 11820670c9b3SLiam Breck static int bq27xxx_battery_seal(struct bq27xxx_device_info *di) 11830670c9b3SLiam Breck { 11840670c9b3SLiam Breck int ret; 11850670c9b3SLiam Breck 11860670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false); 11870670c9b3SLiam Breck if (ret < 0) { 11880670c9b3SLiam Breck dev_err(di->dev, "bus error on seal: %d\n", ret); 11890670c9b3SLiam Breck return ret; 11900670c9b3SLiam Breck } 11910670c9b3SLiam Breck 11920670c9b3SLiam Breck return 0; 11930670c9b3SLiam Breck } 11940670c9b3SLiam Breck 11950670c9b3SLiam Breck static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di) 11960670c9b3SLiam Breck { 11970670c9b3SLiam Breck int ret; 11980670c9b3SLiam Breck 11990670c9b3SLiam Breck if (di->unseal_key == 0) { 12000670c9b3SLiam Breck dev_err(di->dev, "unseal failed due to missing key\n"); 12010670c9b3SLiam Breck return -EINVAL; 12020670c9b3SLiam Breck } 12030670c9b3SLiam Breck 12040670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false); 12050670c9b3SLiam Breck if (ret < 0) 12060670c9b3SLiam Breck goto out; 12070670c9b3SLiam Breck 12080670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false); 12090670c9b3SLiam Breck if (ret < 0) 12100670c9b3SLiam Breck goto out; 12110670c9b3SLiam Breck 12120670c9b3SLiam Breck return 0; 12130670c9b3SLiam Breck 12140670c9b3SLiam Breck out: 12150670c9b3SLiam Breck dev_err(di->dev, "bus error on unseal: %d\n", ret); 12160670c9b3SLiam Breck return ret; 12170670c9b3SLiam Breck } 12180670c9b3SLiam Breck 12190670c9b3SLiam Breck static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf) 12200670c9b3SLiam Breck { 12210670c9b3SLiam Breck u16 sum = 0; 12220670c9b3SLiam Breck int i; 12230670c9b3SLiam Breck 12240670c9b3SLiam Breck for (i = 0; i < BQ27XXX_DM_SZ; i++) 12250670c9b3SLiam Breck sum += buf->data[i]; 12260670c9b3SLiam Breck sum &= 0xff; 12270670c9b3SLiam Breck 12280670c9b3SLiam Breck return 0xff - sum; 12290670c9b3SLiam Breck } 12300670c9b3SLiam Breck 12310670c9b3SLiam Breck static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di, 12320670c9b3SLiam Breck struct bq27xxx_dm_buf *buf) 12330670c9b3SLiam Breck { 12340670c9b3SLiam Breck int ret; 12350670c9b3SLiam Breck 12360670c9b3SLiam Breck buf->has_data = false; 12370670c9b3SLiam Breck 12380670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true); 12390670c9b3SLiam Breck if (ret < 0) 12400670c9b3SLiam Breck goto out; 12410670c9b3SLiam Breck 12420670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true); 12430670c9b3SLiam Breck if (ret < 0) 12440670c9b3SLiam Breck goto out; 12450670c9b3SLiam Breck 12460670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 12470670c9b3SLiam Breck 12480670c9b3SLiam Breck ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ); 12490670c9b3SLiam Breck if (ret < 0) 12500670c9b3SLiam Breck goto out; 12510670c9b3SLiam Breck 12520670c9b3SLiam Breck ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true); 12530670c9b3SLiam Breck if (ret < 0) 12540670c9b3SLiam Breck goto out; 12550670c9b3SLiam Breck 12560670c9b3SLiam Breck if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) { 12570670c9b3SLiam Breck ret = -EINVAL; 12580670c9b3SLiam Breck goto out; 12590670c9b3SLiam Breck } 12600670c9b3SLiam Breck 12610670c9b3SLiam Breck buf->has_data = true; 12620670c9b3SLiam Breck buf->dirty = false; 12630670c9b3SLiam Breck 12640670c9b3SLiam Breck return 0; 12650670c9b3SLiam Breck 12660670c9b3SLiam Breck out: 12670670c9b3SLiam Breck dev_err(di->dev, "bus error reading chip memory: %d\n", ret); 12680670c9b3SLiam Breck return ret; 12690670c9b3SLiam Breck } 12700670c9b3SLiam Breck 1271ccce4409SLiam Breck static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, 1272ccce4409SLiam Breck struct bq27xxx_dm_buf *buf, 1273ccce4409SLiam Breck enum bq27xxx_dm_reg_id reg_id, 1274ccce4409SLiam Breck unsigned int val) 1275ccce4409SLiam Breck { 1276ccce4409SLiam Breck struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id]; 1277ccce4409SLiam Breck const char *str = bq27xxx_dm_reg_name[reg_id]; 1278ccce4409SLiam Breck u16 *prev = bq27xxx_dm_reg_ptr(buf, reg); 1279ccce4409SLiam Breck 1280ccce4409SLiam Breck if (prev == NULL) { 1281ccce4409SLiam Breck dev_warn(di->dev, "buffer does not match %s dm spec\n", str); 1282ccce4409SLiam Breck return; 1283ccce4409SLiam Breck } 1284ccce4409SLiam Breck 1285ccce4409SLiam Breck if (reg->bytes != 2) { 1286ccce4409SLiam Breck dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str); 1287ccce4409SLiam Breck return; 1288ccce4409SLiam Breck } 1289ccce4409SLiam Breck 1290ccce4409SLiam Breck if (!buf->has_data) 1291ccce4409SLiam Breck return; 1292ccce4409SLiam Breck 1293ccce4409SLiam Breck if (be16_to_cpup(prev) == val) { 1294ccce4409SLiam Breck dev_info(di->dev, "%s has %u\n", str, val); 1295ccce4409SLiam Breck return; 1296ccce4409SLiam Breck } 1297ccce4409SLiam Breck 1298ccce4409SLiam Breck #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 129905045379SLiam Breck if (!(di->opts & BQ27XXX_O_RAM) && !bq27xxx_dt_to_nvm) { 1300ccce4409SLiam Breck #else 130105045379SLiam Breck if (!(di->opts & BQ27XXX_O_RAM)) { 1302ccce4409SLiam Breck #endif 1303ccce4409SLiam Breck /* devicetree and NVM differ; defer to NVM */ 1304ccce4409SLiam Breck dev_warn(di->dev, "%s has %u; update to %u disallowed " 1305ccce4409SLiam Breck #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 1306ccce4409SLiam Breck "by dt_monitored_battery_updates_nvm=0" 1307ccce4409SLiam Breck #else 1308ccce4409SLiam Breck "for flash/NVM data memory" 1309ccce4409SLiam Breck #endif 1310ccce4409SLiam Breck "\n", str, be16_to_cpup(prev), val); 1311ccce4409SLiam Breck return; 1312ccce4409SLiam Breck } 1313ccce4409SLiam Breck 1314ccce4409SLiam Breck dev_info(di->dev, "update %s to %u\n", str, val); 1315ccce4409SLiam Breck 1316ccce4409SLiam Breck *prev = cpu_to_be16(val); 1317ccce4409SLiam Breck buf->dirty = true; 1318ccce4409SLiam Breck } 1319ccce4409SLiam Breck 13200670c9b3SLiam Breck static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info *di, bool active) 13210670c9b3SLiam Breck { 13220670c9b3SLiam Breck const int limit = 100; 13230670c9b3SLiam Breck u16 cmd = active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET; 13240670c9b3SLiam Breck int ret, try = limit; 13250670c9b3SLiam Breck 13260670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, cmd, false); 13270670c9b3SLiam Breck if (ret < 0) 13280670c9b3SLiam Breck return ret; 13290670c9b3SLiam Breck 13300670c9b3SLiam Breck do { 13310670c9b3SLiam Breck BQ27XXX_MSLEEP(25); 13320670c9b3SLiam Breck ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false); 13330670c9b3SLiam Breck if (ret < 0) 13340670c9b3SLiam Breck return ret; 13350670c9b3SLiam Breck } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try); 13360670c9b3SLiam Breck 133705045379SLiam Breck if (!try && di->chip != BQ27425) { // 425 has a bug 13380670c9b3SLiam Breck dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active); 13390670c9b3SLiam Breck return -EINVAL; 13400670c9b3SLiam Breck } 13410670c9b3SLiam Breck 13420670c9b3SLiam Breck if (limit - try > 3) 13430670c9b3SLiam Breck dev_warn(di->dev, "cfgupdate %d, retries %d\n", active, limit - try); 13440670c9b3SLiam Breck 13450670c9b3SLiam Breck return 0; 13460670c9b3SLiam Breck } 13470670c9b3SLiam Breck 13480670c9b3SLiam Breck static inline int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di) 13490670c9b3SLiam Breck { 13500670c9b3SLiam Breck int ret = bq27xxx_battery_cfgupdate_priv(di, true); 13510670c9b3SLiam Breck if (ret < 0 && ret != -EINVAL) 13520670c9b3SLiam Breck dev_err(di->dev, "bus error on set_cfgupdate: %d\n", ret); 13530670c9b3SLiam Breck 13540670c9b3SLiam Breck return ret; 13550670c9b3SLiam Breck } 13560670c9b3SLiam Breck 13570670c9b3SLiam Breck static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di) 13580670c9b3SLiam Breck { 13590670c9b3SLiam Breck int ret = bq27xxx_battery_cfgupdate_priv(di, false); 13600670c9b3SLiam Breck if (ret < 0 && ret != -EINVAL) 13610670c9b3SLiam Breck dev_err(di->dev, "bus error on soft_reset: %d\n", ret); 13620670c9b3SLiam Breck 13630670c9b3SLiam Breck return ret; 13640670c9b3SLiam Breck } 13650670c9b3SLiam Breck 13660670c9b3SLiam Breck static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di, 13670670c9b3SLiam Breck struct bq27xxx_dm_buf *buf) 13680670c9b3SLiam Breck { 136905045379SLiam Breck bool cfgup = di->opts & BQ27XXX_O_CFGUP; 13700670c9b3SLiam Breck int ret; 13710670c9b3SLiam Breck 13720670c9b3SLiam Breck if (!buf->dirty) 13730670c9b3SLiam Breck return 0; 13740670c9b3SLiam Breck 13750670c9b3SLiam Breck if (cfgup) { 13760670c9b3SLiam Breck ret = bq27xxx_battery_set_cfgupdate(di); 13770670c9b3SLiam Breck if (ret < 0) 13780670c9b3SLiam Breck return ret; 13790670c9b3SLiam Breck } 13800670c9b3SLiam Breck 13810670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true); 13820670c9b3SLiam Breck if (ret < 0) 13830670c9b3SLiam Breck goto out; 13840670c9b3SLiam Breck 13850670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true); 13860670c9b3SLiam Breck if (ret < 0) 13870670c9b3SLiam Breck goto out; 13880670c9b3SLiam Breck 13890670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true); 13900670c9b3SLiam Breck if (ret < 0) 13910670c9b3SLiam Breck goto out; 13920670c9b3SLiam Breck 13930670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 13940670c9b3SLiam Breck 13950670c9b3SLiam Breck ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ); 13960670c9b3SLiam Breck if (ret < 0) 13970670c9b3SLiam Breck goto out; 13980670c9b3SLiam Breck 13990670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM, 14000670c9b3SLiam Breck bq27xxx_battery_checksum_dm_block(buf), true); 14010670c9b3SLiam Breck if (ret < 0) 14020670c9b3SLiam Breck goto out; 14030670c9b3SLiam Breck 14040670c9b3SLiam Breck /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM 14050670c9b3SLiam Breck * corruption on the '425 chip (and perhaps others), which can damage 14060670c9b3SLiam Breck * the chip. 14070670c9b3SLiam Breck */ 14080670c9b3SLiam Breck 14090670c9b3SLiam Breck if (cfgup) { 14100670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 14110670c9b3SLiam Breck ret = bq27xxx_battery_soft_reset(di); 14120670c9b3SLiam Breck if (ret < 0) 14130670c9b3SLiam Breck return ret; 14140670c9b3SLiam Breck } else { 14150670c9b3SLiam Breck BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */ 14160670c9b3SLiam Breck } 14170670c9b3SLiam Breck 14180670c9b3SLiam Breck buf->dirty = false; 14190670c9b3SLiam Breck 14200670c9b3SLiam Breck return 0; 14210670c9b3SLiam Breck 14220670c9b3SLiam Breck out: 14230670c9b3SLiam Breck if (cfgup) 14240670c9b3SLiam Breck bq27xxx_battery_soft_reset(di); 14250670c9b3SLiam Breck 14260670c9b3SLiam Breck dev_err(di->dev, "bus error writing chip memory: %d\n", ret); 14270670c9b3SLiam Breck return ret; 14280670c9b3SLiam Breck } 14290670c9b3SLiam Breck 1430ccce4409SLiam Breck static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, 1431ccce4409SLiam Breck struct power_supply_battery_info *info) 1432ccce4409SLiam Breck { 1433ccce4409SLiam Breck struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY); 1434ccce4409SLiam Breck struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE); 1435ccce4409SLiam Breck bool updated; 1436ccce4409SLiam Breck 1437ccce4409SLiam Breck if (bq27xxx_battery_unseal(di) < 0) 1438ccce4409SLiam Breck return; 1439ccce4409SLiam Breck 1440ccce4409SLiam Breck if (info->charge_full_design_uah != -EINVAL && 1441ccce4409SLiam Breck info->energy_full_design_uwh != -EINVAL) { 1442ccce4409SLiam Breck bq27xxx_battery_read_dm_block(di, &bd); 1443ccce4409SLiam Breck /* assume design energy & capacity are in same block */ 1444ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, &bd, 1445ccce4409SLiam Breck BQ27XXX_DM_DESIGN_CAPACITY, 1446ccce4409SLiam Breck info->charge_full_design_uah / 1000); 1447ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, &bd, 1448ccce4409SLiam Breck BQ27XXX_DM_DESIGN_ENERGY, 1449ccce4409SLiam Breck info->energy_full_design_uwh / 1000); 1450ccce4409SLiam Breck } 1451ccce4409SLiam Breck 1452ccce4409SLiam Breck if (info->voltage_min_design_uv != -EINVAL) { 1453ccce4409SLiam Breck bool same = bd.class == bt.class && bd.block == bt.block; 1454ccce4409SLiam Breck if (!same) 1455ccce4409SLiam Breck bq27xxx_battery_read_dm_block(di, &bt); 1456ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, same ? &bd : &bt, 1457ccce4409SLiam Breck BQ27XXX_DM_TERMINATE_VOLTAGE, 1458ccce4409SLiam Breck info->voltage_min_design_uv / 1000); 1459ccce4409SLiam Breck } 1460ccce4409SLiam Breck 1461ccce4409SLiam Breck updated = bd.dirty || bt.dirty; 1462ccce4409SLiam Breck 1463ccce4409SLiam Breck bq27xxx_battery_write_dm_block(di, &bd); 1464ccce4409SLiam Breck bq27xxx_battery_write_dm_block(di, &bt); 1465ccce4409SLiam Breck 1466ccce4409SLiam Breck bq27xxx_battery_seal(di); 1467ccce4409SLiam Breck 146805045379SLiam Breck if (updated && !(di->opts & BQ27XXX_O_CFGUP)) { 1469ccce4409SLiam Breck bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false); 1470ccce4409SLiam Breck BQ27XXX_MSLEEP(300); /* reset time is not documented */ 1471ccce4409SLiam Breck } 1472ccce4409SLiam Breck /* assume bq27xxx_battery_update() is called hereafter */ 1473ccce4409SLiam Breck } 1474ccce4409SLiam Breck 1475ccce4409SLiam Breck static void bq27xxx_battery_settings(struct bq27xxx_device_info *di) 1476ccce4409SLiam Breck { 1477*25fd3303SLinus Walleij struct power_supply_battery_info *info; 1478ccce4409SLiam Breck unsigned int min, max; 1479ccce4409SLiam Breck 1480ccce4409SLiam Breck if (power_supply_get_battery_info(di->bat, &info) < 0) 1481ccce4409SLiam Breck return; 1482ccce4409SLiam Breck 1483ccce4409SLiam Breck if (!di->dm_regs) { 1484ccce4409SLiam Breck dev_warn(di->dev, "data memory update not supported for chip\n"); 1485ccce4409SLiam Breck return; 1486ccce4409SLiam Breck } 1487ccce4409SLiam Breck 1488*25fd3303SLinus Walleij if (info->energy_full_design_uwh != info->charge_full_design_uah) { 1489*25fd3303SLinus Walleij if (info->energy_full_design_uwh == -EINVAL) 1490ccce4409SLiam Breck dev_warn(di->dev, "missing battery:energy-full-design-microwatt-hours\n"); 1491*25fd3303SLinus Walleij else if (info->charge_full_design_uah == -EINVAL) 1492ccce4409SLiam Breck dev_warn(di->dev, "missing battery:charge-full-design-microamp-hours\n"); 1493ccce4409SLiam Breck } 1494ccce4409SLiam Breck 1495ccce4409SLiam Breck /* assume min == 0 */ 1496ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max; 1497*25fd3303SLinus Walleij if (info->energy_full_design_uwh > max * 1000) { 1498ccce4409SLiam Breck dev_err(di->dev, "invalid battery:energy-full-design-microwatt-hours %d\n", 1499*25fd3303SLinus Walleij info->energy_full_design_uwh); 1500*25fd3303SLinus Walleij info->energy_full_design_uwh = -EINVAL; 1501ccce4409SLiam Breck } 1502ccce4409SLiam Breck 1503ccce4409SLiam Breck /* assume min == 0 */ 1504ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max; 1505*25fd3303SLinus Walleij if (info->charge_full_design_uah > max * 1000) { 1506ccce4409SLiam Breck dev_err(di->dev, "invalid battery:charge-full-design-microamp-hours %d\n", 1507*25fd3303SLinus Walleij info->charge_full_design_uah); 1508*25fd3303SLinus Walleij info->charge_full_design_uah = -EINVAL; 1509ccce4409SLiam Breck } 1510ccce4409SLiam Breck 1511ccce4409SLiam Breck min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min; 1512ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max; 1513*25fd3303SLinus Walleij if ((info->voltage_min_design_uv < min * 1000 || 1514*25fd3303SLinus Walleij info->voltage_min_design_uv > max * 1000) && 1515*25fd3303SLinus Walleij info->voltage_min_design_uv != -EINVAL) { 1516ccce4409SLiam Breck dev_err(di->dev, "invalid battery:voltage-min-design-microvolt %d\n", 1517*25fd3303SLinus Walleij info->voltage_min_design_uv); 1518*25fd3303SLinus Walleij info->voltage_min_design_uv = -EINVAL; 1519ccce4409SLiam Breck } 1520ccce4409SLiam Breck 1521*25fd3303SLinus Walleij if ((info->energy_full_design_uwh != -EINVAL && 1522*25fd3303SLinus Walleij info->charge_full_design_uah != -EINVAL) || 1523*25fd3303SLinus Walleij info->voltage_min_design_uv != -EINVAL) 1524*25fd3303SLinus Walleij bq27xxx_battery_set_config(di, info); 1525ccce4409SLiam Breck } 1526ccce4409SLiam Breck 15278c0984e5SSebastian Reichel /* 15288c0984e5SSebastian Reichel * Return the battery State-of-Charge 15298c0984e5SSebastian Reichel * Or < 0 if something fails. 15308c0984e5SSebastian Reichel */ 15318c0984e5SSebastian Reichel static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di) 15328c0984e5SSebastian Reichel { 15338c0984e5SSebastian Reichel int soc; 15348c0984e5SSebastian Reichel 1535c02ca201SKrzysztof Kozlowski if (di->opts & BQ27XXX_O_SOC_SI) 15368c0984e5SSebastian Reichel soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true); 15378c0984e5SSebastian Reichel else 15388c0984e5SSebastian Reichel soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false); 15398c0984e5SSebastian Reichel 15408c0984e5SSebastian Reichel if (soc < 0) 15418c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading State-of-Charge\n"); 15428c0984e5SSebastian Reichel 15438c0984e5SSebastian Reichel return soc; 15448c0984e5SSebastian Reichel } 15458c0984e5SSebastian Reichel 15468c0984e5SSebastian Reichel /* 15478c0984e5SSebastian Reichel * Return a battery charge value in µAh 15488c0984e5SSebastian Reichel * Or < 0 if something fails. 15498c0984e5SSebastian Reichel */ 15508c0984e5SSebastian Reichel static int bq27xxx_battery_read_charge(struct bq27xxx_device_info *di, u8 reg) 15518c0984e5SSebastian Reichel { 15528c0984e5SSebastian Reichel int charge; 15538c0984e5SSebastian Reichel 15548c0984e5SSebastian Reichel charge = bq27xxx_read(di, reg, false); 15558c0984e5SSebastian Reichel if (charge < 0) { 15568c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading charge register %02x: %d\n", 15578c0984e5SSebastian Reichel reg, charge); 15588c0984e5SSebastian Reichel return charge; 15598c0984e5SSebastian Reichel } 15608c0984e5SSebastian Reichel 15613a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15628c0984e5SSebastian Reichel charge *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 15638c0984e5SSebastian Reichel else 15648c0984e5SSebastian Reichel charge *= 1000; 15658c0984e5SSebastian Reichel 15668c0984e5SSebastian Reichel return charge; 15678c0984e5SSebastian Reichel } 15688c0984e5SSebastian Reichel 15698c0984e5SSebastian Reichel /* 15708c0984e5SSebastian Reichel * Return the battery Nominal available capacity in µAh 15718c0984e5SSebastian Reichel * Or < 0 if something fails. 15728c0984e5SSebastian Reichel */ 15738c0984e5SSebastian Reichel static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di) 15748c0984e5SSebastian Reichel { 15758c0984e5SSebastian Reichel int flags; 15768c0984e5SSebastian Reichel 15773a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 15788c0984e5SSebastian Reichel flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); 15798c0984e5SSebastian Reichel if (flags >= 0 && (flags & BQ27000_FLAG_CI)) 15808c0984e5SSebastian Reichel return -ENODATA; 15818c0984e5SSebastian Reichel } 15828c0984e5SSebastian Reichel 15838c0984e5SSebastian Reichel return bq27xxx_battery_read_charge(di, BQ27XXX_REG_NAC); 15848c0984e5SSebastian Reichel } 15858c0984e5SSebastian Reichel 15868c0984e5SSebastian Reichel /* 15873ed510f0SHermes Zhang * Return the battery Remaining Capacity in µAh 15883ed510f0SHermes Zhang * Or < 0 if something fails. 15893ed510f0SHermes Zhang */ 15903ed510f0SHermes Zhang static inline int bq27xxx_battery_read_rc(struct bq27xxx_device_info *di) 15913ed510f0SHermes Zhang { 15923ed510f0SHermes Zhang return bq27xxx_battery_read_charge(di, BQ27XXX_REG_RC); 15933ed510f0SHermes Zhang } 15943ed510f0SHermes Zhang 15953ed510f0SHermes Zhang /* 15968c0984e5SSebastian Reichel * Return the battery Full Charge Capacity in µAh 15978c0984e5SSebastian Reichel * Or < 0 if something fails. 15988c0984e5SSebastian Reichel */ 15998c0984e5SSebastian Reichel static inline int bq27xxx_battery_read_fcc(struct bq27xxx_device_info *di) 16008c0984e5SSebastian Reichel { 16018c0984e5SSebastian Reichel return bq27xxx_battery_read_charge(di, BQ27XXX_REG_FCC); 16028c0984e5SSebastian Reichel } 16038c0984e5SSebastian Reichel 16048c0984e5SSebastian Reichel /* 16058c0984e5SSebastian Reichel * Return the Design Capacity in µAh 16068c0984e5SSebastian Reichel * Or < 0 if something fails. 16078c0984e5SSebastian Reichel */ 16088c0984e5SSebastian Reichel static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) 16098c0984e5SSebastian Reichel { 16108c0984e5SSebastian Reichel int dcap; 16118c0984e5SSebastian Reichel 16123a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16138c0984e5SSebastian Reichel dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); 16148c0984e5SSebastian Reichel else 16158c0984e5SSebastian Reichel dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); 16168c0984e5SSebastian Reichel 16178c0984e5SSebastian Reichel if (dcap < 0) { 16188c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading initial last measured discharge\n"); 16198c0984e5SSebastian Reichel return dcap; 16208c0984e5SSebastian Reichel } 16218c0984e5SSebastian Reichel 16223a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16238c0984e5SSebastian Reichel dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 16248c0984e5SSebastian Reichel else 16258c0984e5SSebastian Reichel dcap *= 1000; 16268c0984e5SSebastian Reichel 16278c0984e5SSebastian Reichel return dcap; 16288c0984e5SSebastian Reichel } 16298c0984e5SSebastian Reichel 16308c0984e5SSebastian Reichel /* 16318c0984e5SSebastian Reichel * Return the battery Available energy in µWh 16328c0984e5SSebastian Reichel * Or < 0 if something fails. 16338c0984e5SSebastian Reichel */ 16348c0984e5SSebastian Reichel static int bq27xxx_battery_read_energy(struct bq27xxx_device_info *di) 16358c0984e5SSebastian Reichel { 16368c0984e5SSebastian Reichel int ae; 16378c0984e5SSebastian Reichel 16388c0984e5SSebastian Reichel ae = bq27xxx_read(di, BQ27XXX_REG_AE, false); 16398c0984e5SSebastian Reichel if (ae < 0) { 16408c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading available energy\n"); 16418c0984e5SSebastian Reichel return ae; 16428c0984e5SSebastian Reichel } 16438c0984e5SSebastian Reichel 16443a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16458c0984e5SSebastian Reichel ae *= BQ27XXX_POWER_CONSTANT / BQ27XXX_RS; 16468c0984e5SSebastian Reichel else 16478c0984e5SSebastian Reichel ae *= 1000; 16488c0984e5SSebastian Reichel 16498c0984e5SSebastian Reichel return ae; 16508c0984e5SSebastian Reichel } 16518c0984e5SSebastian Reichel 16528c0984e5SSebastian Reichel /* 16538c0984e5SSebastian Reichel * Return the battery temperature in tenths of degree Kelvin 16548c0984e5SSebastian Reichel * Or < 0 if something fails. 16558c0984e5SSebastian Reichel */ 16568c0984e5SSebastian Reichel static int bq27xxx_battery_read_temperature(struct bq27xxx_device_info *di) 16578c0984e5SSebastian Reichel { 16588c0984e5SSebastian Reichel int temp; 16598c0984e5SSebastian Reichel 16608c0984e5SSebastian Reichel temp = bq27xxx_read(di, BQ27XXX_REG_TEMP, false); 16618c0984e5SSebastian Reichel if (temp < 0) { 16628c0984e5SSebastian Reichel dev_err(di->dev, "error reading temperature\n"); 16638c0984e5SSebastian Reichel return temp; 16648c0984e5SSebastian Reichel } 16658c0984e5SSebastian Reichel 16663a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16678c0984e5SSebastian Reichel temp = 5 * temp / 2; 16688c0984e5SSebastian Reichel 16698c0984e5SSebastian Reichel return temp; 16708c0984e5SSebastian Reichel } 16718c0984e5SSebastian Reichel 16728c0984e5SSebastian Reichel /* 16738c0984e5SSebastian Reichel * Return the battery Cycle count total 16748c0984e5SSebastian Reichel * Or < 0 if something fails. 16758c0984e5SSebastian Reichel */ 16768c0984e5SSebastian Reichel static int bq27xxx_battery_read_cyct(struct bq27xxx_device_info *di) 16778c0984e5SSebastian Reichel { 16788c0984e5SSebastian Reichel int cyct; 16798c0984e5SSebastian Reichel 16808c0984e5SSebastian Reichel cyct = bq27xxx_read(di, BQ27XXX_REG_CYCT, false); 16818c0984e5SSebastian Reichel if (cyct < 0) 16828c0984e5SSebastian Reichel dev_err(di->dev, "error reading cycle count total\n"); 16838c0984e5SSebastian Reichel 16848c0984e5SSebastian Reichel return cyct; 16858c0984e5SSebastian Reichel } 16868c0984e5SSebastian Reichel 16878c0984e5SSebastian Reichel /* 16888c0984e5SSebastian Reichel * Read a time register. 16898c0984e5SSebastian Reichel * Return < 0 if something fails. 16908c0984e5SSebastian Reichel */ 16918c0984e5SSebastian Reichel static int bq27xxx_battery_read_time(struct bq27xxx_device_info *di, u8 reg) 16928c0984e5SSebastian Reichel { 16938c0984e5SSebastian Reichel int tval; 16948c0984e5SSebastian Reichel 16958c0984e5SSebastian Reichel tval = bq27xxx_read(di, reg, false); 16968c0984e5SSebastian Reichel if (tval < 0) { 16978c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading time register %02x: %d\n", 16988c0984e5SSebastian Reichel reg, tval); 16998c0984e5SSebastian Reichel return tval; 17008c0984e5SSebastian Reichel } 17018c0984e5SSebastian Reichel 17028c0984e5SSebastian Reichel if (tval == 65535) 17038c0984e5SSebastian Reichel return -ENODATA; 17048c0984e5SSebastian Reichel 17058c0984e5SSebastian Reichel return tval * 60; 17068c0984e5SSebastian Reichel } 17078c0984e5SSebastian Reichel 17088c0984e5SSebastian Reichel /* 17098c0984e5SSebastian Reichel * Returns true if a battery over temperature condition is detected 17108c0984e5SSebastian Reichel */ 17118c0984e5SSebastian Reichel static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) 17128c0984e5SSebastian Reichel { 17133a731c64SLiam Breck if (di->opts & BQ27XXX_O_OTDC) 17148c0984e5SSebastian Reichel return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD); 17153a731c64SLiam Breck if (di->opts & BQ27XXX_O_UTOT) 17168c0984e5SSebastian Reichel return flags & BQ27XXX_FLAG_OT; 17173a731c64SLiam Breck 17188c0984e5SSebastian Reichel return false; 17198c0984e5SSebastian Reichel } 17208c0984e5SSebastian Reichel 17218c0984e5SSebastian Reichel /* 17228c0984e5SSebastian Reichel * Returns true if a battery under temperature condition is detected 17238c0984e5SSebastian Reichel */ 17248c0984e5SSebastian Reichel static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags) 17258c0984e5SSebastian Reichel { 17263a731c64SLiam Breck if (di->opts & BQ27XXX_O_UTOT) 17278c0984e5SSebastian Reichel return flags & BQ27XXX_FLAG_UT; 17288c0984e5SSebastian Reichel 17298c0984e5SSebastian Reichel return false; 17308c0984e5SSebastian Reichel } 17318c0984e5SSebastian Reichel 17328c0984e5SSebastian Reichel /* 17338c0984e5SSebastian Reichel * Returns true if a low state of charge condition is detected 17348c0984e5SSebastian Reichel */ 17358c0984e5SSebastian Reichel static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) 17368c0984e5SSebastian Reichel { 17373a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 17388c0984e5SSebastian Reichel return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF); 17396f24ff97SDan Murphy else if (di->opts & BQ27Z561_O_BITS) 17406f24ff97SDan Murphy return flags & BQ27Z561_FLAG_FDC; 17418c0984e5SSebastian Reichel else 17428c0984e5SSebastian Reichel return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); 17438c0984e5SSebastian Reichel } 17448c0984e5SSebastian Reichel 17458c0984e5SSebastian Reichel static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) 17468c0984e5SSebastian Reichel { 17478c0984e5SSebastian Reichel /* Unlikely but important to return first */ 17489b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags))) 17498c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_OVERHEAT; 17509b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_undertemp(di, di->cache.flags))) 17518c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_COLD; 17529b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_dead(di, di->cache.flags))) 17538c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_DEAD; 17548c0984e5SSebastian Reichel 17558c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_GOOD; 17568c0984e5SSebastian Reichel } 17578c0984e5SSebastian Reichel 17588c0984e5SSebastian Reichel void bq27xxx_battery_update(struct bq27xxx_device_info *di) 17598c0984e5SSebastian Reichel { 17608c0984e5SSebastian Reichel struct bq27xxx_reg_cache cache = {0, }; 17617be64ae0SKrzysztof Kozlowski bool has_ci_flag = di->opts & BQ27XXX_O_HAS_CI; 17623a731c64SLiam Breck bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; 17638c0984e5SSebastian Reichel 17648c0984e5SSebastian Reichel cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); 17658c0984e5SSebastian Reichel if ((cache.flags & 0xff) == 0xff) 17668c0984e5SSebastian Reichel cache.flags = -1; /* read error */ 17678c0984e5SSebastian Reichel if (cache.flags >= 0) { 17688c0984e5SSebastian Reichel cache.temperature = bq27xxx_battery_read_temperature(di); 17698c0984e5SSebastian Reichel if (has_ci_flag && (cache.flags & BQ27000_FLAG_CI)) { 17708c0984e5SSebastian Reichel dev_info_once(di->dev, "battery is not calibrated! ignoring capacity values\n"); 17718c0984e5SSebastian Reichel cache.capacity = -ENODATA; 17728c0984e5SSebastian Reichel cache.energy = -ENODATA; 17738c0984e5SSebastian Reichel cache.time_to_empty = -ENODATA; 17748c0984e5SSebastian Reichel cache.time_to_empty_avg = -ENODATA; 17758c0984e5SSebastian Reichel cache.time_to_full = -ENODATA; 17768c0984e5SSebastian Reichel cache.charge_full = -ENODATA; 17778c0984e5SSebastian Reichel cache.health = -ENODATA; 17788c0984e5SSebastian Reichel } else { 17798c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) 17808c0984e5SSebastian Reichel cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); 17818c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) 17828c0984e5SSebastian Reichel cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); 17838c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) 17848c0984e5SSebastian Reichel cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); 17856f24ff97SDan Murphy 17868c0984e5SSebastian Reichel cache.charge_full = bq27xxx_battery_read_fcc(di); 17878c0984e5SSebastian Reichel cache.capacity = bq27xxx_battery_read_soc(di); 17888c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) 17898c0984e5SSebastian Reichel cache.energy = bq27xxx_battery_read_energy(di); 17909b2c945fSArthur Demchenkov di->cache.flags = cache.flags; 17918c0984e5SSebastian Reichel cache.health = bq27xxx_battery_read_health(di); 17928c0984e5SSebastian Reichel } 17938c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) 17948c0984e5SSebastian Reichel cache.cycle_count = bq27xxx_battery_read_cyct(di); 17958c0984e5SSebastian Reichel 17968c0984e5SSebastian Reichel /* We only have to read charge design full once */ 17978c0984e5SSebastian Reichel if (di->charge_design_full <= 0) 17988c0984e5SSebastian Reichel di->charge_design_full = bq27xxx_battery_read_dcap(di); 17998c0984e5SSebastian Reichel } 18008c0984e5SSebastian Reichel 1801243f8ffcSKrzysztof Kozlowski if ((di->cache.capacity != cache.capacity) || 1802243f8ffcSKrzysztof Kozlowski (di->cache.flags != cache.flags)) 18038c0984e5SSebastian Reichel power_supply_changed(di->bat); 18048c0984e5SSebastian Reichel 18058c0984e5SSebastian Reichel if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) 18068c0984e5SSebastian Reichel di->cache = cache; 18078c0984e5SSebastian Reichel 18088c0984e5SSebastian Reichel di->last_update = jiffies; 18098c0984e5SSebastian Reichel } 18108c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_update); 18118c0984e5SSebastian Reichel 18128c0984e5SSebastian Reichel static void bq27xxx_battery_poll(struct work_struct *work) 18138c0984e5SSebastian Reichel { 18148c0984e5SSebastian Reichel struct bq27xxx_device_info *di = 18158c0984e5SSebastian Reichel container_of(work, struct bq27xxx_device_info, 18168c0984e5SSebastian Reichel work.work); 18178c0984e5SSebastian Reichel 18188c0984e5SSebastian Reichel bq27xxx_battery_update(di); 18198c0984e5SSebastian Reichel 18208c0984e5SSebastian Reichel if (poll_interval > 0) 18218c0984e5SSebastian Reichel schedule_delayed_work(&di->work, poll_interval * HZ); 18228c0984e5SSebastian Reichel } 18238c0984e5SSebastian Reichel 1824c3a6d6a1SMatthias Schiffer static bool bq27xxx_battery_is_full(struct bq27xxx_device_info *di, int flags) 1825c3a6d6a1SMatthias Schiffer { 1826c3a6d6a1SMatthias Schiffer if (di->opts & BQ27XXX_O_ZERO) 1827c3a6d6a1SMatthias Schiffer return (flags & BQ27000_FLAG_FC); 1828c3a6d6a1SMatthias Schiffer else if (di->opts & BQ27Z561_O_BITS) 1829c3a6d6a1SMatthias Schiffer return (flags & BQ27Z561_FLAG_FC); 1830c3a6d6a1SMatthias Schiffer else 1831c3a6d6a1SMatthias Schiffer return (flags & BQ27XXX_FLAG_FC); 1832c3a6d6a1SMatthias Schiffer } 1833c3a6d6a1SMatthias Schiffer 18348c0984e5SSebastian Reichel /* 1835c3a6d6a1SMatthias Schiffer * Return the battery average current in µA and the status 18368c0984e5SSebastian Reichel * Note that current can be negative signed as well 18378c0984e5SSebastian Reichel * Or 0 if something fails. 18388c0984e5SSebastian Reichel */ 1839c3a6d6a1SMatthias Schiffer static int bq27xxx_battery_current_and_status( 1840c3a6d6a1SMatthias Schiffer struct bq27xxx_device_info *di, 1841c3a6d6a1SMatthias Schiffer union power_supply_propval *val_curr, 1842c3a6d6a1SMatthias Schiffer union power_supply_propval *val_status) 18438c0984e5SSebastian Reichel { 1844c3a6d6a1SMatthias Schiffer bool single_flags = (di->opts & BQ27XXX_O_ZERO); 18458c0984e5SSebastian Reichel int curr; 18468c0984e5SSebastian Reichel int flags; 18478c0984e5SSebastian Reichel 18488c0984e5SSebastian Reichel curr = bq27xxx_read(di, BQ27XXX_REG_AI, false); 18498c0984e5SSebastian Reichel if (curr < 0) { 18508c0984e5SSebastian Reichel dev_err(di->dev, "error reading current\n"); 18518c0984e5SSebastian Reichel return curr; 18528c0984e5SSebastian Reichel } 18538c0984e5SSebastian Reichel 1854c3a6d6a1SMatthias Schiffer flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, single_flags); 1855c3a6d6a1SMatthias Schiffer if (flags < 0) { 1856c3a6d6a1SMatthias Schiffer dev_err(di->dev, "error reading flags\n"); 1857c3a6d6a1SMatthias Schiffer return flags; 1858c3a6d6a1SMatthias Schiffer } 1859c3a6d6a1SMatthias Schiffer 18603a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 1861cd060b4dSAndreas Kemnade if (!(flags & BQ27000_FLAG_CHGS)) { 18628c0984e5SSebastian Reichel dev_dbg(di->dev, "negative current!\n"); 18638c0984e5SSebastian Reichel curr = -curr; 18648c0984e5SSebastian Reichel } 18658c0984e5SSebastian Reichel 1866c3a6d6a1SMatthias Schiffer curr = curr * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 18678c0984e5SSebastian Reichel } else { 18688c0984e5SSebastian Reichel /* Other gauges return signed value */ 1869c3a6d6a1SMatthias Schiffer curr = (int)((s16)curr) * 1000; 1870c3a6d6a1SMatthias Schiffer } 1871c3a6d6a1SMatthias Schiffer 1872c3a6d6a1SMatthias Schiffer if (val_curr) 1873c3a6d6a1SMatthias Schiffer val_curr->intval = curr; 1874c3a6d6a1SMatthias Schiffer 1875c3a6d6a1SMatthias Schiffer if (val_status) { 1876c3a6d6a1SMatthias Schiffer if (curr > 0) { 1877c3a6d6a1SMatthias Schiffer val_status->intval = POWER_SUPPLY_STATUS_CHARGING; 1878c3a6d6a1SMatthias Schiffer } else if (curr < 0) { 1879c3a6d6a1SMatthias Schiffer val_status->intval = POWER_SUPPLY_STATUS_DISCHARGING; 1880c3a6d6a1SMatthias Schiffer } else { 1881c3a6d6a1SMatthias Schiffer if (bq27xxx_battery_is_full(di, flags)) 1882c3a6d6a1SMatthias Schiffer val_status->intval = POWER_SUPPLY_STATUS_FULL; 1883c3a6d6a1SMatthias Schiffer else 1884c3a6d6a1SMatthias Schiffer val_status->intval = 1885c3a6d6a1SMatthias Schiffer POWER_SUPPLY_STATUS_NOT_CHARGING; 1886c3a6d6a1SMatthias Schiffer } 18878c0984e5SSebastian Reichel } 18888c0984e5SSebastian Reichel 18898c0984e5SSebastian Reichel return 0; 18908c0984e5SSebastian Reichel } 18918c0984e5SSebastian Reichel 1892c4d57c22SMatthias Schiffer /* 1893c4d57c22SMatthias Schiffer * Get the average power in µW 1894c4d57c22SMatthias Schiffer * Return < 0 if something fails. 1895c4d57c22SMatthias Schiffer */ 1896c4d57c22SMatthias Schiffer static int bq27xxx_battery_pwr_avg(struct bq27xxx_device_info *di, 1897c4d57c22SMatthias Schiffer union power_supply_propval *val) 1898c4d57c22SMatthias Schiffer { 1899c4d57c22SMatthias Schiffer int power; 1900c4d57c22SMatthias Schiffer 1901c4d57c22SMatthias Schiffer power = bq27xxx_read(di, BQ27XXX_REG_AP, false); 1902c4d57c22SMatthias Schiffer if (power < 0) { 1903c4d57c22SMatthias Schiffer dev_err(di->dev, 1904c4d57c22SMatthias Schiffer "error reading average power register %02x: %d\n", 1905c4d57c22SMatthias Schiffer BQ27XXX_REG_AP, power); 1906c4d57c22SMatthias Schiffer return power; 1907c4d57c22SMatthias Schiffer } 1908c4d57c22SMatthias Schiffer 1909c4d57c22SMatthias Schiffer if (di->opts & BQ27XXX_O_ZERO) 1910c4d57c22SMatthias Schiffer val->intval = (power * BQ27XXX_POWER_CONSTANT) / BQ27XXX_RS; 1911c4d57c22SMatthias Schiffer else 1912c4d57c22SMatthias Schiffer /* Other gauges return a signed value in units of 10mW */ 1913c4d57c22SMatthias Schiffer val->intval = (int)((s16)power) * 10000; 1914c4d57c22SMatthias Schiffer 1915c4d57c22SMatthias Schiffer return 0; 1916c4d57c22SMatthias Schiffer } 1917c4d57c22SMatthias Schiffer 19188c0984e5SSebastian Reichel static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, 19198c0984e5SSebastian Reichel union power_supply_propval *val) 19208c0984e5SSebastian Reichel { 19218c0984e5SSebastian Reichel int level; 19228c0984e5SSebastian Reichel 19233a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 19248c0984e5SSebastian Reichel if (di->cache.flags & BQ27000_FLAG_FC) 19258c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 19268c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_EDV1) 19278c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 19288c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_EDVF) 19298c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 19308c0984e5SSebastian Reichel else 19318c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 19326f24ff97SDan Murphy } else if (di->opts & BQ27Z561_O_BITS) { 19336f24ff97SDan Murphy if (di->cache.flags & BQ27Z561_FLAG_FC) 19346f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 19356f24ff97SDan Murphy else if (di->cache.flags & BQ27Z561_FLAG_FDC) 19366f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 19376f24ff97SDan Murphy else 19386f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 19398c0984e5SSebastian Reichel } else { 19408c0984e5SSebastian Reichel if (di->cache.flags & BQ27XXX_FLAG_FC) 19418c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 19428c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_SOC1) 19438c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 19448c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_SOCF) 19458c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 19468c0984e5SSebastian Reichel else 19478c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 19488c0984e5SSebastian Reichel } 19498c0984e5SSebastian Reichel 19508c0984e5SSebastian Reichel val->intval = level; 19518c0984e5SSebastian Reichel 19528c0984e5SSebastian Reichel return 0; 19538c0984e5SSebastian Reichel } 19548c0984e5SSebastian Reichel 19558c0984e5SSebastian Reichel /* 19568c0984e5SSebastian Reichel * Return the battery Voltage in millivolts 19578c0984e5SSebastian Reichel * Or < 0 if something fails. 19588c0984e5SSebastian Reichel */ 19598c0984e5SSebastian Reichel static int bq27xxx_battery_voltage(struct bq27xxx_device_info *di, 19608c0984e5SSebastian Reichel union power_supply_propval *val) 19618c0984e5SSebastian Reichel { 19628c0984e5SSebastian Reichel int volt; 19638c0984e5SSebastian Reichel 19648c0984e5SSebastian Reichel volt = bq27xxx_read(di, BQ27XXX_REG_VOLT, false); 19658c0984e5SSebastian Reichel if (volt < 0) { 19668c0984e5SSebastian Reichel dev_err(di->dev, "error reading voltage\n"); 19678c0984e5SSebastian Reichel return volt; 19688c0984e5SSebastian Reichel } 19698c0984e5SSebastian Reichel 19708c0984e5SSebastian Reichel val->intval = volt * 1000; 19718c0984e5SSebastian Reichel 19728c0984e5SSebastian Reichel return 0; 19738c0984e5SSebastian Reichel } 19748c0984e5SSebastian Reichel 19758c0984e5SSebastian Reichel static int bq27xxx_simple_value(int value, 19768c0984e5SSebastian Reichel union power_supply_propval *val) 19778c0984e5SSebastian Reichel { 19788c0984e5SSebastian Reichel if (value < 0) 19798c0984e5SSebastian Reichel return value; 19808c0984e5SSebastian Reichel 19818c0984e5SSebastian Reichel val->intval = value; 19828c0984e5SSebastian Reichel 19838c0984e5SSebastian Reichel return 0; 19848c0984e5SSebastian Reichel } 19858c0984e5SSebastian Reichel 19868c0984e5SSebastian Reichel static int bq27xxx_battery_get_property(struct power_supply *psy, 19878c0984e5SSebastian Reichel enum power_supply_property psp, 19888c0984e5SSebastian Reichel union power_supply_propval *val) 19898c0984e5SSebastian Reichel { 19908c0984e5SSebastian Reichel int ret = 0; 19918c0984e5SSebastian Reichel struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 19928c0984e5SSebastian Reichel 19938c0984e5SSebastian Reichel mutex_lock(&di->lock); 19948c0984e5SSebastian Reichel if (time_is_before_jiffies(di->last_update + 5 * HZ)) { 19958c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 19968c0984e5SSebastian Reichel bq27xxx_battery_poll(&di->work.work); 19978c0984e5SSebastian Reichel } 19988c0984e5SSebastian Reichel mutex_unlock(&di->lock); 19998c0984e5SSebastian Reichel 20008c0984e5SSebastian Reichel if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) 20018c0984e5SSebastian Reichel return -ENODEV; 20028c0984e5SSebastian Reichel 20038c0984e5SSebastian Reichel switch (psp) { 20048c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 2005c3a6d6a1SMatthias Schiffer ret = bq27xxx_battery_current_and_status(di, NULL, val); 20068c0984e5SSebastian Reichel break; 20078c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 20088c0984e5SSebastian Reichel ret = bq27xxx_battery_voltage(di, val); 20098c0984e5SSebastian Reichel break; 20108c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 20118c0984e5SSebastian Reichel val->intval = di->cache.flags < 0 ? 0 : 1; 20128c0984e5SSebastian Reichel break; 20138c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 2014c3a6d6a1SMatthias Schiffer ret = bq27xxx_battery_current_and_status(di, val, NULL); 20158c0984e5SSebastian Reichel break; 20168c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY: 20178c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.capacity, val); 20188c0984e5SSebastian Reichel break; 20198c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 20208c0984e5SSebastian Reichel ret = bq27xxx_battery_capacity_level(di, val); 20218c0984e5SSebastian Reichel break; 20228c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP: 20238c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.temperature, val); 20248c0984e5SSebastian Reichel if (ret == 0) 20258c0984e5SSebastian Reichel val->intval -= 2731; /* convert decidegree k to c */ 20268c0984e5SSebastian Reichel break; 20278c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 20288c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_empty, val); 20298c0984e5SSebastian Reichel break; 20308c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 20318c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_empty_avg, val); 20328c0984e5SSebastian Reichel break; 20338c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 20348c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_full, val); 20358c0984e5SSebastian Reichel break; 20368c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TECHNOLOGY: 203741a7431dSKrzysztof Kozlowski if (di->opts & BQ27XXX_O_MUL_CHEM) 203841a7431dSKrzysztof Kozlowski val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN; 203941a7431dSKrzysztof Kozlowski else 20408c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 20418c0984e5SSebastian Reichel break; 20428c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_NOW: 20433ed510f0SHermes Zhang if (di->regs[BQ27XXX_REG_NAC] != INVALID_REG_ADDR) 20448c0984e5SSebastian Reichel ret = bq27xxx_simple_value(bq27xxx_battery_read_nac(di), val); 20453ed510f0SHermes Zhang else 20463ed510f0SHermes Zhang ret = bq27xxx_simple_value(bq27xxx_battery_read_rc(di), val); 20478c0984e5SSebastian Reichel break; 20488c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL: 20498c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.charge_full, val); 20508c0984e5SSebastian Reichel break; 20518c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 20528c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->charge_design_full, val); 20538c0984e5SSebastian Reichel break; 2054ccce4409SLiam Breck /* 2055ccce4409SLiam Breck * TODO: Implement these to make registers set from 2056ccce4409SLiam Breck * power_supply_battery_info visible in sysfs. 2057ccce4409SLiam Breck */ 2058ccce4409SLiam Breck case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 2059ccce4409SLiam Breck case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 2060ccce4409SLiam Breck return -EINVAL; 20618c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CYCLE_COUNT: 20628c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.cycle_count, val); 20638c0984e5SSebastian Reichel break; 20648c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ENERGY_NOW: 20658c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.energy, val); 20668c0984e5SSebastian Reichel break; 20678c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_POWER_AVG: 2068c4d57c22SMatthias Schiffer ret = bq27xxx_battery_pwr_avg(di, val); 20698c0984e5SSebastian Reichel break; 20708c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 20718c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.health, val); 20728c0984e5SSebastian Reichel break; 20738c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 20748c0984e5SSebastian Reichel val->strval = BQ27XXX_MANUFACTURER; 20758c0984e5SSebastian Reichel break; 20768c0984e5SSebastian Reichel default: 20778c0984e5SSebastian Reichel return -EINVAL; 20788c0984e5SSebastian Reichel } 20798c0984e5SSebastian Reichel 20808c0984e5SSebastian Reichel return ret; 20818c0984e5SSebastian Reichel } 20828c0984e5SSebastian Reichel 20838c0984e5SSebastian Reichel static void bq27xxx_external_power_changed(struct power_supply *psy) 20848c0984e5SSebastian Reichel { 20858c0984e5SSebastian Reichel struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 20868c0984e5SSebastian Reichel 20878c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 20888c0984e5SSebastian Reichel schedule_delayed_work(&di->work, 0); 20898c0984e5SSebastian Reichel } 20908c0984e5SSebastian Reichel 20918c0984e5SSebastian Reichel int bq27xxx_battery_setup(struct bq27xxx_device_info *di) 20928c0984e5SSebastian Reichel { 20938c0984e5SSebastian Reichel struct power_supply_desc *psy_desc; 2094ccce4409SLiam Breck struct power_supply_config psy_cfg = { 2095ccce4409SLiam Breck .of_node = di->dev->of_node, 2096ccce4409SLiam Breck .drv_data = di, 2097ccce4409SLiam Breck }; 20988c0984e5SSebastian Reichel 20998c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); 21008c0984e5SSebastian Reichel mutex_init(&di->lock); 21013a731c64SLiam Breck 21029aade6d8SLiam Breck di->regs = bq27xxx_chip_data[di->chip].regs; 210305045379SLiam Breck di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key; 210405045379SLiam Breck di->dm_regs = bq27xxx_chip_data[di->chip].dm_regs; 21053a731c64SLiam Breck di->opts = bq27xxx_chip_data[di->chip].opts; 21068c0984e5SSebastian Reichel 21078c0984e5SSebastian Reichel psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL); 21088c0984e5SSebastian Reichel if (!psy_desc) 21098c0984e5SSebastian Reichel return -ENOMEM; 21108c0984e5SSebastian Reichel 21118c0984e5SSebastian Reichel psy_desc->name = di->name; 21128c0984e5SSebastian Reichel psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; 21139aade6d8SLiam Breck psy_desc->properties = bq27xxx_chip_data[di->chip].props; 21149aade6d8SLiam Breck psy_desc->num_properties = bq27xxx_chip_data[di->chip].props_size; 21158c0984e5SSebastian Reichel psy_desc->get_property = bq27xxx_battery_get_property; 21168c0984e5SSebastian Reichel psy_desc->external_power_changed = bq27xxx_external_power_changed; 21178c0984e5SSebastian Reichel 21188c0984e5SSebastian Reichel di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); 21194024810cSKrzysztof Kozlowski if (IS_ERR(di->bat)) 21204024810cSKrzysztof Kozlowski return dev_err_probe(di->dev, PTR_ERR(di->bat), 21214024810cSKrzysztof Kozlowski "failed to register battery\n"); 21228c0984e5SSebastian Reichel 2123ccce4409SLiam Breck bq27xxx_battery_settings(di); 21248c0984e5SSebastian Reichel bq27xxx_battery_update(di); 21258c0984e5SSebastian Reichel 21261d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 21271d72706fSMatt Ranostay list_add(&di->list, &bq27xxx_battery_devices); 21281d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 21291d72706fSMatt Ranostay 21308c0984e5SSebastian Reichel return 0; 21318c0984e5SSebastian Reichel } 21328c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_setup); 21338c0984e5SSebastian Reichel 21348c0984e5SSebastian Reichel void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) 21358c0984e5SSebastian Reichel { 21368c0984e5SSebastian Reichel /* 21378c0984e5SSebastian Reichel * power_supply_unregister call bq27xxx_battery_get_property which 21388c0984e5SSebastian Reichel * call bq27xxx_battery_poll. 21398c0984e5SSebastian Reichel * Make sure that bq27xxx_battery_poll will not call 21408c0984e5SSebastian Reichel * schedule_delayed_work again after unregister (which cause OOPS). 21418c0984e5SSebastian Reichel */ 21428c0984e5SSebastian Reichel poll_interval = 0; 21438c0984e5SSebastian Reichel 21448c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 21458c0984e5SSebastian Reichel 21468c0984e5SSebastian Reichel power_supply_unregister(di->bat); 21478c0984e5SSebastian Reichel 21481d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 21491d72706fSMatt Ranostay list_del(&di->list); 21501d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 21511d72706fSMatt Ranostay 21528c0984e5SSebastian Reichel mutex_destroy(&di->lock); 21538c0984e5SSebastian Reichel } 21548c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); 21558c0984e5SSebastian Reichel 21568c0984e5SSebastian Reichel MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 21578c0984e5SSebastian Reichel MODULE_DESCRIPTION("BQ27xxx battery monitor driver"); 21588c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 2159