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 418c0984e5SSebastian Reichel */ 428c0984e5SSebastian Reichel 438c0984e5SSebastian Reichel #include <linux/device.h> 448c0984e5SSebastian Reichel #include <linux/module.h> 451d72706fSMatt Ranostay #include <linux/mutex.h> 468c0984e5SSebastian Reichel #include <linux/param.h> 478c0984e5SSebastian Reichel #include <linux/jiffies.h> 488c0984e5SSebastian Reichel #include <linux/workqueue.h> 498c0984e5SSebastian Reichel #include <linux/delay.h> 508c0984e5SSebastian Reichel #include <linux/platform_device.h> 518c0984e5SSebastian Reichel #include <linux/power_supply.h> 528c0984e5SSebastian Reichel #include <linux/slab.h> 538c0984e5SSebastian Reichel #include <linux/of.h> 548c0984e5SSebastian Reichel 558c0984e5SSebastian Reichel #include <linux/power/bq27xxx_battery.h> 568c0984e5SSebastian Reichel 578c0984e5SSebastian Reichel #define BQ27XXX_MANUFACTURER "Texas Instruments" 588c0984e5SSebastian Reichel 598c0984e5SSebastian Reichel /* BQ27XXX Flags */ 608c0984e5SSebastian Reichel #define BQ27XXX_FLAG_DSC BIT(0) 618c0984e5SSebastian Reichel #define BQ27XXX_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ 628c0984e5SSebastian Reichel #define BQ27XXX_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ 630670c9b3SLiam Breck #define BQ27XXX_FLAG_CFGUP BIT(4) 648c0984e5SSebastian Reichel #define BQ27XXX_FLAG_FC BIT(9) 658c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OTD BIT(14) 668c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OTC BIT(15) 678c0984e5SSebastian Reichel #define BQ27XXX_FLAG_UT BIT(14) 688c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OT BIT(15) 698c0984e5SSebastian Reichel 708c0984e5SSebastian Reichel /* BQ27000 has different layout for Flags register */ 718c0984e5SSebastian Reichel #define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ 728c0984e5SSebastian Reichel #define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ 738c0984e5SSebastian Reichel #define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ 748c0984e5SSebastian Reichel #define BQ27000_FLAG_FC BIT(5) 758c0984e5SSebastian Reichel #define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ 768c0984e5SSebastian Reichel 776f24ff97SDan Murphy /* BQ27Z561 has different layout for Flags register */ 786f24ff97SDan Murphy #define BQ27Z561_FLAG_FDC BIT(4) /* Battery fully discharged */ 796f24ff97SDan Murphy #define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */ 806f24ff97SDan Murphy #define BQ27Z561_FLAG_DIS_CH BIT(6) /* Battery is discharging */ 816f24ff97SDan Murphy 820670c9b3SLiam Breck /* control register params */ 830670c9b3SLiam Breck #define BQ27XXX_SEALED 0x20 840670c9b3SLiam Breck #define BQ27XXX_SET_CFGUPDATE 0x13 850670c9b3SLiam Breck #define BQ27XXX_SOFT_RESET 0x42 860670c9b3SLiam Breck #define BQ27XXX_RESET 0x41 870670c9b3SLiam Breck 888c0984e5SSebastian Reichel #define BQ27XXX_RS (20) /* Resistor sense mOhm */ 898c0984e5SSebastian Reichel #define BQ27XXX_POWER_CONSTANT (29200) /* 29.2 µV^2 * 1000 */ 908c0984e5SSebastian Reichel #define BQ27XXX_CURRENT_CONSTANT (3570) /* 3.57 µV * 1000 */ 918c0984e5SSebastian Reichel 928c0984e5SSebastian Reichel #define INVALID_REG_ADDR 0xff 938c0984e5SSebastian Reichel 948c0984e5SSebastian Reichel /* 958c0984e5SSebastian Reichel * bq27xxx_reg_index - Register names 968c0984e5SSebastian Reichel * 978c0984e5SSebastian Reichel * These are indexes into a device's register mapping array. 988c0984e5SSebastian Reichel */ 998c0984e5SSebastian Reichel 1008c0984e5SSebastian Reichel enum bq27xxx_reg_index { 1018c0984e5SSebastian Reichel BQ27XXX_REG_CTRL = 0, /* Control */ 1028c0984e5SSebastian Reichel BQ27XXX_REG_TEMP, /* Temperature */ 1038c0984e5SSebastian Reichel BQ27XXX_REG_INT_TEMP, /* Internal Temperature */ 1048c0984e5SSebastian Reichel BQ27XXX_REG_VOLT, /* Voltage */ 1058c0984e5SSebastian Reichel BQ27XXX_REG_AI, /* Average Current */ 1068c0984e5SSebastian Reichel BQ27XXX_REG_FLAGS, /* Flags */ 1078c0984e5SSebastian Reichel BQ27XXX_REG_TTE, /* Time-to-Empty */ 1088c0984e5SSebastian Reichel BQ27XXX_REG_TTF, /* Time-to-Full */ 1098c0984e5SSebastian Reichel BQ27XXX_REG_TTES, /* Time-to-Empty Standby */ 1108c0984e5SSebastian Reichel BQ27XXX_REG_TTECP, /* Time-to-Empty at Constant Power */ 1118c0984e5SSebastian Reichel BQ27XXX_REG_NAC, /* Nominal Available Capacity */ 1128c0984e5SSebastian Reichel BQ27XXX_REG_FCC, /* Full Charge Capacity */ 1138c0984e5SSebastian Reichel BQ27XXX_REG_CYCT, /* Cycle Count */ 1148c0984e5SSebastian Reichel BQ27XXX_REG_AE, /* Available Energy */ 1158c0984e5SSebastian Reichel BQ27XXX_REG_SOC, /* State-of-Charge */ 1168c0984e5SSebastian Reichel BQ27XXX_REG_DCAP, /* Design Capacity */ 1178c0984e5SSebastian Reichel BQ27XXX_REG_AP, /* Average Power */ 1180670c9b3SLiam Breck BQ27XXX_DM_CTRL, /* Block Data Control */ 1190670c9b3SLiam Breck BQ27XXX_DM_CLASS, /* Data Class */ 1200670c9b3SLiam Breck BQ27XXX_DM_BLOCK, /* Data Block */ 1210670c9b3SLiam Breck BQ27XXX_DM_DATA, /* Block Data */ 1220670c9b3SLiam Breck BQ27XXX_DM_CKSUM, /* Block Data Checksum */ 1238c0984e5SSebastian Reichel BQ27XXX_REG_MAX, /* sentinel */ 1248c0984e5SSebastian Reichel }; 1258c0984e5SSebastian Reichel 1260670c9b3SLiam Breck #define BQ27XXX_DM_REG_ROWS \ 1270670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = 0x61, \ 1280670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = 0x3e, \ 1290670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = 0x3f, \ 1300670c9b3SLiam Breck [BQ27XXX_DM_DATA] = 0x40, \ 1310670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = 0x60 1320670c9b3SLiam Breck 1338c0984e5SSebastian Reichel /* Register mappings */ 1349aade6d8SLiam Breck static u8 1359aade6d8SLiam Breck bq27000_regs[BQ27XXX_REG_MAX] = { 1368c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1378c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1388c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 1398c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1408c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1418c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1428c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1438c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = 0x18, 1448c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1c, 1458c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = 0x26, 1468c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1478c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1488c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1498c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = 0x22, 1508c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x0b, 1518c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x76, 1528c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 1530670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 1540670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 1550670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 1560670c9b3SLiam Breck [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 1570670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 1588c0984e5SSebastian Reichel }, 1599aade6d8SLiam Breck bq27010_regs[BQ27XXX_REG_MAX] = { 1608c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1618c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1628c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 1638c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1648c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1658c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1668c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1678c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = 0x18, 1688c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1c, 1698c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = 0x26, 1708c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1718c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1728c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1738c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 1748c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x0b, 1758c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x76, 1768c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 1770670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 1780670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 1790670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 1800670c9b3SLiam Breck [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 1810670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 1828c0984e5SSebastian Reichel }, 1839aade6d8SLiam Breck bq2750x_regs[BQ27XXX_REG_MAX] = { 1848c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1858c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1868c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 1878c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1888c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1898c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1908c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1918c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 1928c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1a, 1938c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 1948c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1958c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1968c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1978c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 1988c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 1998c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 2008c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 2010670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 2028c0984e5SSebastian Reichel }, 2031059361fSLiam Breck #define bq2751x_regs bq27510g3_regs 2041059361fSLiam Breck #define bq2752x_regs bq27510g3_regs 2059aade6d8SLiam Breck bq27500_regs[BQ27XXX_REG_MAX] = { 20632833635SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 20732833635SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 20832833635SChris Lapa [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 20932833635SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 21032833635SChris Lapa [BQ27XXX_REG_AI] = 0x14, 21132833635SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 21232833635SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 21332833635SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 21432833635SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 21532833635SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 21632833635SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 21732833635SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 21832833635SChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 21932833635SChris Lapa [BQ27XXX_REG_AE] = 0x22, 22032833635SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 22132833635SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 22232833635SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2230670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 22432833635SChris Lapa }, 2251059361fSLiam Breck #define bq27510g1_regs bq27500_regs 2261059361fSLiam Breck #define bq27510g2_regs bq27500_regs 2279aade6d8SLiam Breck bq27510g3_regs[BQ27XXX_REG_MAX] = { 22871375aa7SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 22971375aa7SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 23071375aa7SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x28, 23171375aa7SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 23271375aa7SChris Lapa [BQ27XXX_REG_AI] = 0x14, 23371375aa7SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 23471375aa7SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 23571375aa7SChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 23671375aa7SChris Lapa [BQ27XXX_REG_TTES] = 0x1a, 23771375aa7SChris Lapa [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 23871375aa7SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 23971375aa7SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 24071375aa7SChris Lapa [BQ27XXX_REG_CYCT] = 0x1e, 24171375aa7SChris Lapa [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 24271375aa7SChris Lapa [BQ27XXX_REG_SOC] = 0x20, 24371375aa7SChris Lapa [BQ27XXX_REG_DCAP] = 0x2e, 24471375aa7SChris Lapa [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 2450670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 24671375aa7SChris Lapa }, 2479aade6d8SLiam Breck bq27520g1_regs[BQ27XXX_REG_MAX] = { 24868f2a813SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 24968f2a813SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 25068f2a813SChris Lapa [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 25168f2a813SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 25268f2a813SChris Lapa [BQ27XXX_REG_AI] = 0x14, 25368f2a813SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 25468f2a813SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 25568f2a813SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 25668f2a813SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 25768f2a813SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 25868f2a813SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 25968f2a813SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 26068f2a813SChris Lapa [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 26168f2a813SChris Lapa [BQ27XXX_REG_AE] = 0x22, 26268f2a813SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 26368f2a813SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 26468f2a813SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2650670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 26668f2a813SChris Lapa }, 2679aade6d8SLiam Breck bq27520g2_regs[BQ27XXX_REG_MAX] = { 268a5deb9a9SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 269a5deb9a9SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 270a5deb9a9SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x36, 271a5deb9a9SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 272a5deb9a9SChris Lapa [BQ27XXX_REG_AI] = 0x14, 273a5deb9a9SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 274a5deb9a9SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 275a5deb9a9SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 276a5deb9a9SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 277a5deb9a9SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 278a5deb9a9SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 279a5deb9a9SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 280a5deb9a9SChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 281a5deb9a9SChris Lapa [BQ27XXX_REG_AE] = 0x22, 282a5deb9a9SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 283a5deb9a9SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 284a5deb9a9SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2850670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 286a5deb9a9SChris Lapa }, 2879aade6d8SLiam Breck bq27520g3_regs[BQ27XXX_REG_MAX] = { 288825e915bSChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 289825e915bSChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 290825e915bSChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x36, 291825e915bSChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 292825e915bSChris Lapa [BQ27XXX_REG_AI] = 0x14, 293825e915bSChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 294825e915bSChris Lapa [BQ27XXX_REG_TTE] = 0x16, 295825e915bSChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 296825e915bSChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 297825e915bSChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 298825e915bSChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 299825e915bSChris Lapa [BQ27XXX_REG_FCC] = 0x12, 300825e915bSChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 301825e915bSChris Lapa [BQ27XXX_REG_AE] = 0x22, 302825e915bSChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 303825e915bSChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 304825e915bSChris Lapa [BQ27XXX_REG_AP] = 0x24, 3050670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 306825e915bSChris Lapa }, 3079aade6d8SLiam Breck bq27520g4_regs[BQ27XXX_REG_MAX] = { 3088835cae5SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 3098835cae5SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 3108835cae5SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x28, 3118835cae5SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 3128835cae5SChris Lapa [BQ27XXX_REG_AI] = 0x14, 3138835cae5SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 3148835cae5SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 3158835cae5SChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3168835cae5SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 3178835cae5SChris Lapa [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3188835cae5SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 3198835cae5SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 3208835cae5SChris Lapa [BQ27XXX_REG_CYCT] = 0x1e, 3218835cae5SChris Lapa [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3228835cae5SChris Lapa [BQ27XXX_REG_SOC] = 0x20, 3238835cae5SChris Lapa [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 3248835cae5SChris Lapa [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 3250670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3268835cae5SChris Lapa }, 32770a39e10SPavel Machek bq27521_regs[BQ27XXX_REG_MAX] = { 32870a39e10SPavel Machek [BQ27XXX_REG_CTRL] = 0x02, 32970a39e10SPavel Machek [BQ27XXX_REG_TEMP] = 0x0a, 33070a39e10SPavel Machek [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 33170a39e10SPavel Machek [BQ27XXX_REG_VOLT] = 0x0c, 33270a39e10SPavel Machek [BQ27XXX_REG_AI] = 0x0e, 33370a39e10SPavel Machek [BQ27XXX_REG_FLAGS] = 0x08, 33470a39e10SPavel Machek [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, 33570a39e10SPavel Machek [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 33670a39e10SPavel Machek [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 33770a39e10SPavel Machek [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 33870a39e10SPavel Machek [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 33970a39e10SPavel Machek [BQ27XXX_REG_FCC] = INVALID_REG_ADDR, 34070a39e10SPavel Machek [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 34170a39e10SPavel Machek [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 34270a39e10SPavel Machek [BQ27XXX_REG_SOC] = INVALID_REG_ADDR, 34370a39e10SPavel Machek [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 34470a39e10SPavel Machek [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 34570a39e10SPavel Machek [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 34670a39e10SPavel Machek [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 34770a39e10SPavel Machek [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 34870a39e10SPavel Machek [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 34970a39e10SPavel Machek [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 35070a39e10SPavel Machek }, 3519aade6d8SLiam Breck bq27530_regs[BQ27XXX_REG_MAX] = { 3528c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3538c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3548c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x32, 3558c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 3568c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 3578c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 3588c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 3598c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3608c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 3618c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3628c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 3638c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 3648c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 3658c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3668c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 3678c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 3688c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 3690670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3708c0984e5SSebastian Reichel }, 3713a731c64SLiam Breck #define bq27531_regs bq27530_regs 3729aade6d8SLiam Breck bq27541_regs[BQ27XXX_REG_MAX] = { 3738c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3748c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3758c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 3768c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 3778c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 3788c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 3798c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 3808c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3818c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 3828c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3838c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 3848c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 3858c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 3868c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3878c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 3888c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 3898c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 3900670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3918c0984e5SSebastian Reichel }, 3923a731c64SLiam Breck #define bq27542_regs bq27541_regs 3933a731c64SLiam Breck #define bq27546_regs bq27541_regs 3943a731c64SLiam Breck #define bq27742_regs bq27541_regs 3959aade6d8SLiam Breck bq27545_regs[BQ27XXX_REG_MAX] = { 3968c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3978c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3988c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 3998c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 4008c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 4018c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 4028c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 4038c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 4048c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4058c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4068c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 4078c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 4088c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 4098c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4108c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 4118c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 4128c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 4130670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4148c0984e5SSebastian Reichel }, 4159aade6d8SLiam Breck bq27421_regs[BQ27XXX_REG_MAX] = { 4168c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 4178c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x02, 4188c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x1e, 4198c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x04, 4208c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x10, 4218c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x06, 4228c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, 4238c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 4248c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4258c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4268c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x08, 4278c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x0e, 4288c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 4298c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4308c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x1c, 4318c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 4328c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x18, 4330670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4346f24ff97SDan Murphy }, 435457b42f0SLiu Xiang #define bq27411_regs bq27421_regs 4363a731c64SLiam Breck #define bq27425_regs bq27421_regs 4375ef6a160SAndrew F. Davis #define bq27426_regs bq27421_regs 4383a731c64SLiam Breck #define bq27441_regs bq27421_regs 4393a731c64SLiam Breck #define bq27621_regs bq27421_regs 4406f24ff97SDan Murphy bq27z561_regs[BQ27XXX_REG_MAX] = { 4416f24ff97SDan Murphy [BQ27XXX_REG_CTRL] = 0x00, 4426f24ff97SDan Murphy [BQ27XXX_REG_TEMP] = 0x06, 4436f24ff97SDan Murphy [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 4446f24ff97SDan Murphy [BQ27XXX_REG_VOLT] = 0x08, 4456f24ff97SDan Murphy [BQ27XXX_REG_AI] = 0x14, 4466f24ff97SDan Murphy [BQ27XXX_REG_FLAGS] = 0x0a, 4476f24ff97SDan Murphy [BQ27XXX_REG_TTE] = 0x16, 4486f24ff97SDan Murphy [BQ27XXX_REG_TTF] = 0x18, 4496f24ff97SDan Murphy [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4506f24ff97SDan Murphy [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4516f24ff97SDan Murphy [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 4526f24ff97SDan Murphy [BQ27XXX_REG_FCC] = 0x12, 4536f24ff97SDan Murphy [BQ27XXX_REG_CYCT] = 0x2a, 4546f24ff97SDan Murphy [BQ27XXX_REG_AE] = 0x22, 4556f24ff97SDan Murphy [BQ27XXX_REG_SOC] = 0x2c, 4566f24ff97SDan Murphy [BQ27XXX_REG_DCAP] = 0x3c, 4576f24ff97SDan Murphy [BQ27XXX_REG_AP] = 0x22, 4586f24ff97SDan Murphy BQ27XXX_DM_REG_ROWS, 459707d678aSDan Murphy }, 460707d678aSDan Murphy bq28z610_regs[BQ27XXX_REG_MAX] = { 461707d678aSDan Murphy [BQ27XXX_REG_CTRL] = 0x00, 462707d678aSDan Murphy [BQ27XXX_REG_TEMP] = 0x06, 463707d678aSDan Murphy [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 464707d678aSDan Murphy [BQ27XXX_REG_VOLT] = 0x08, 465707d678aSDan Murphy [BQ27XXX_REG_AI] = 0x14, 466707d678aSDan Murphy [BQ27XXX_REG_FLAGS] = 0x0a, 467707d678aSDan Murphy [BQ27XXX_REG_TTE] = 0x16, 468707d678aSDan Murphy [BQ27XXX_REG_TTF] = 0x18, 469707d678aSDan Murphy [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 470707d678aSDan Murphy [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 471707d678aSDan Murphy [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 472707d678aSDan Murphy [BQ27XXX_REG_FCC] = 0x12, 473707d678aSDan Murphy [BQ27XXX_REG_CYCT] = 0x2a, 474707d678aSDan Murphy [BQ27XXX_REG_AE] = 0x22, 475707d678aSDan Murphy [BQ27XXX_REG_SOC] = 0x2c, 476707d678aSDan Murphy [BQ27XXX_REG_DCAP] = 0x3c, 477707d678aSDan Murphy [BQ27XXX_REG_AP] = 0x22, 478707d678aSDan Murphy BQ27XXX_DM_REG_ROWS, 4796f24ff97SDan Murphy }; 4808c0984e5SSebastian Reichel 4819aade6d8SLiam Breck static enum power_supply_property bq27000_props[] = { 4828c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 4838c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 4848c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 4858c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 4868c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 4878c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 4888c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 4898c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 4908c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 4918c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 4928c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 4938c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 4948c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 4958c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 4968c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 4978c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ENERGY_NOW, 4988c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 4998c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 5008c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 5018c0984e5SSebastian Reichel }; 5028c0984e5SSebastian Reichel 5039aade6d8SLiam Breck static enum power_supply_property bq27010_props[] = { 5048c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 5058c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 5068c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 5078c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 5088c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 5098c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 5108c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 5118c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 5128c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 5138c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 5148c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 5158c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 5168c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 5178c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 5188c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 5198c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 5208c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 5218c0984e5SSebastian Reichel }; 5228c0984e5SSebastian Reichel 5231059361fSLiam Breck #define bq2750x_props bq27510g3_props 5241059361fSLiam Breck #define bq2751x_props bq27510g3_props 5251059361fSLiam Breck #define bq2752x_props bq27510g3_props 5263bee9ea1SAndrew F. Davis 5279aade6d8SLiam Breck static enum power_supply_property bq27500_props[] = { 52832833635SChris Lapa POWER_SUPPLY_PROP_STATUS, 52932833635SChris Lapa POWER_SUPPLY_PROP_PRESENT, 53032833635SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 53132833635SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 53232833635SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 53332833635SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 53432833635SChris Lapa POWER_SUPPLY_PROP_TEMP, 53532833635SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 53632833635SChris Lapa POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 53732833635SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 53832833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 53932833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 54032833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 54132833635SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 54232833635SChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 54332833635SChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 54432833635SChris Lapa POWER_SUPPLY_PROP_HEALTH, 54532833635SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 54632833635SChris Lapa }; 5471059361fSLiam Breck #define bq27510g1_props bq27500_props 5481059361fSLiam Breck #define bq27510g2_props bq27500_props 549698a2bf5SChris Lapa 5509aade6d8SLiam Breck static enum power_supply_property bq27510g3_props[] = { 55171375aa7SChris Lapa POWER_SUPPLY_PROP_STATUS, 55271375aa7SChris Lapa POWER_SUPPLY_PROP_PRESENT, 55371375aa7SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 55471375aa7SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 55571375aa7SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 55671375aa7SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 55771375aa7SChris Lapa POWER_SUPPLY_PROP_TEMP, 55871375aa7SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 55971375aa7SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 56071375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 56171375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 56271375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 56371375aa7SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 56471375aa7SChris Lapa POWER_SUPPLY_PROP_HEALTH, 56571375aa7SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 56671375aa7SChris Lapa }; 56771375aa7SChris Lapa 5689aade6d8SLiam Breck static enum power_supply_property bq27520g1_props[] = { 56968f2a813SChris Lapa POWER_SUPPLY_PROP_STATUS, 57068f2a813SChris Lapa POWER_SUPPLY_PROP_PRESENT, 57168f2a813SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 57268f2a813SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 57368f2a813SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 57468f2a813SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 57568f2a813SChris Lapa POWER_SUPPLY_PROP_TEMP, 57668f2a813SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 57768f2a813SChris Lapa POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 57868f2a813SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 57968f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 58068f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 58168f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 58268f2a813SChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 58368f2a813SChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 58468f2a813SChris Lapa POWER_SUPPLY_PROP_HEALTH, 58568f2a813SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 58668f2a813SChris Lapa }; 58768f2a813SChris Lapa 5881059361fSLiam Breck #define bq27520g2_props bq27500_props 589a5deb9a9SChris Lapa 5909aade6d8SLiam Breck static enum power_supply_property bq27520g3_props[] = { 591825e915bSChris Lapa POWER_SUPPLY_PROP_STATUS, 592825e915bSChris Lapa POWER_SUPPLY_PROP_PRESENT, 593825e915bSChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 594825e915bSChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 595825e915bSChris Lapa POWER_SUPPLY_PROP_CAPACITY, 596825e915bSChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 597825e915bSChris Lapa POWER_SUPPLY_PROP_TEMP, 598825e915bSChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 599825e915bSChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 600825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 601825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 602825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 603825e915bSChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 604825e915bSChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 605825e915bSChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 606825e915bSChris Lapa POWER_SUPPLY_PROP_HEALTH, 607825e915bSChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 608825e915bSChris Lapa }; 609825e915bSChris Lapa 6109aade6d8SLiam Breck static enum power_supply_property bq27520g4_props[] = { 6118835cae5SChris Lapa POWER_SUPPLY_PROP_STATUS, 6128835cae5SChris Lapa POWER_SUPPLY_PROP_PRESENT, 6138835cae5SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 6148835cae5SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 6158835cae5SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 6168835cae5SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6178835cae5SChris Lapa POWER_SUPPLY_PROP_TEMP, 6188835cae5SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6198835cae5SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 6208835cae5SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 6218835cae5SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 6228835cae5SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 6238835cae5SChris Lapa POWER_SUPPLY_PROP_HEALTH, 6248835cae5SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 6258835cae5SChris Lapa }; 6268835cae5SChris Lapa 62770a39e10SPavel Machek static enum power_supply_property bq27521_props[] = { 62870a39e10SPavel Machek POWER_SUPPLY_PROP_STATUS, 62970a39e10SPavel Machek POWER_SUPPLY_PROP_PRESENT, 63070a39e10SPavel Machek POWER_SUPPLY_PROP_VOLTAGE_NOW, 63170a39e10SPavel Machek POWER_SUPPLY_PROP_CURRENT_NOW, 63270a39e10SPavel Machek POWER_SUPPLY_PROP_TEMP, 63370a39e10SPavel Machek POWER_SUPPLY_PROP_TECHNOLOGY, 63470a39e10SPavel Machek }; 63570a39e10SPavel Machek 6369aade6d8SLiam Breck static enum power_supply_property bq27530_props[] = { 6378c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6388c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6398c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6408c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 6418c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 6428c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6438c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 6448c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6458c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 6468c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 6478c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 6488c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 6498c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 6508c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 6518c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 6528c0984e5SSebastian Reichel }; 6533a731c64SLiam Breck #define bq27531_props bq27530_props 6548c0984e5SSebastian Reichel 6559aade6d8SLiam Breck static enum power_supply_property bq27541_props[] = { 6568c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6578c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6588c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6598c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 6608c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 6618c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6628c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 6638c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6648c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 6658c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 6668c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 6678c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 6688c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 6698c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 6708c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 6718c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 6728c0984e5SSebastian Reichel }; 6733a731c64SLiam Breck #define bq27542_props bq27541_props 6743a731c64SLiam Breck #define bq27546_props bq27541_props 6753a731c64SLiam Breck #define bq27742_props bq27541_props 6768c0984e5SSebastian Reichel 6779aade6d8SLiam Breck static enum power_supply_property bq27545_props[] = { 6788c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6798c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6808c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6818c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 6828c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 6838c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6848c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 6858c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6868c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 6878c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 6888c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 6898c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 6908c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 6918c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 6928c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 6938c0984e5SSebastian Reichel }; 6948c0984e5SSebastian Reichel 6959aade6d8SLiam Breck static enum power_supply_property bq27421_props[] = { 6968c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6978c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6988c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6998c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 7008c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 7018c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7028c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 7038c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 7048c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 7058c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 7068c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7078c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7088c0984e5SSebastian Reichel }; 709457b42f0SLiu Xiang #define bq27411_props bq27421_props 7103a731c64SLiam Breck #define bq27425_props bq27421_props 7115ef6a160SAndrew F. Davis #define bq27426_props bq27421_props 7123a731c64SLiam Breck #define bq27441_props bq27421_props 7133a731c64SLiam Breck #define bq27621_props bq27421_props 7148c0984e5SSebastian Reichel 7156f24ff97SDan Murphy static enum power_supply_property bq27z561_props[] = { 7166f24ff97SDan Murphy POWER_SUPPLY_PROP_STATUS, 7176f24ff97SDan Murphy POWER_SUPPLY_PROP_PRESENT, 7186f24ff97SDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 7196f24ff97SDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 7206f24ff97SDan Murphy POWER_SUPPLY_PROP_CAPACITY, 7216f24ff97SDan Murphy POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7226f24ff97SDan Murphy POWER_SUPPLY_PROP_TEMP, 7236f24ff97SDan Murphy POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 7246f24ff97SDan Murphy POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 7256f24ff97SDan Murphy POWER_SUPPLY_PROP_TECHNOLOGY, 7266f24ff97SDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL, 7276f24ff97SDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7286f24ff97SDan Murphy POWER_SUPPLY_PROP_CYCLE_COUNT, 7296f24ff97SDan Murphy POWER_SUPPLY_PROP_POWER_AVG, 7306f24ff97SDan Murphy POWER_SUPPLY_PROP_HEALTH, 7316f24ff97SDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 7326f24ff97SDan Murphy }; 7336f24ff97SDan Murphy 734707d678aSDan Murphy static enum power_supply_property bq28z610_props[] = { 735707d678aSDan Murphy POWER_SUPPLY_PROP_STATUS, 736707d678aSDan Murphy POWER_SUPPLY_PROP_PRESENT, 737707d678aSDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 738707d678aSDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 739707d678aSDan Murphy POWER_SUPPLY_PROP_CAPACITY, 740707d678aSDan Murphy POWER_SUPPLY_PROP_CAPACITY_LEVEL, 741707d678aSDan Murphy POWER_SUPPLY_PROP_TEMP, 742707d678aSDan Murphy POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 743707d678aSDan Murphy POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 744707d678aSDan Murphy POWER_SUPPLY_PROP_TECHNOLOGY, 745707d678aSDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL, 746707d678aSDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 747707d678aSDan Murphy POWER_SUPPLY_PROP_CYCLE_COUNT, 748707d678aSDan Murphy POWER_SUPPLY_PROP_POWER_AVG, 749707d678aSDan Murphy POWER_SUPPLY_PROP_HEALTH, 750707d678aSDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 751707d678aSDan Murphy }; 752707d678aSDan Murphy 75305045379SLiam Breck struct bq27xxx_dm_reg { 75405045379SLiam Breck u8 subclass_id; 75505045379SLiam Breck u8 offset; 75605045379SLiam Breck u8 bytes; 75705045379SLiam Breck u16 min, max; 75805045379SLiam Breck }; 75905045379SLiam Breck 76005045379SLiam Breck enum bq27xxx_dm_reg_id { 76105045379SLiam Breck BQ27XXX_DM_DESIGN_CAPACITY = 0, 76205045379SLiam Breck BQ27XXX_DM_DESIGN_ENERGY, 76305045379SLiam Breck BQ27XXX_DM_TERMINATE_VOLTAGE, 76405045379SLiam Breck }; 76505045379SLiam Breck 76605045379SLiam Breck #define bq27000_dm_regs 0 76705045379SLiam Breck #define bq27010_dm_regs 0 76805045379SLiam Breck #define bq2750x_dm_regs 0 76905045379SLiam Breck #define bq2751x_dm_regs 0 77005045379SLiam Breck #define bq2752x_dm_regs 0 77105045379SLiam Breck 77205045379SLiam Breck #if 0 /* not yet tested */ 77305045379SLiam Breck static struct bq27xxx_dm_reg bq27500_dm_regs[] = { 77405045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 10, 2, 0, 65535 }, 77505045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { }, /* missing on chip */ 77605045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 }, 77705045379SLiam Breck }; 77805045379SLiam Breck #else 77905045379SLiam Breck #define bq27500_dm_regs 0 78005045379SLiam Breck #endif 78105045379SLiam Breck 78205045379SLiam Breck /* todo create data memory definitions from datasheets and test on chips */ 78305045379SLiam Breck #define bq27510g1_dm_regs 0 78405045379SLiam Breck #define bq27510g2_dm_regs 0 78505045379SLiam Breck #define bq27510g3_dm_regs 0 78605045379SLiam Breck #define bq27520g1_dm_regs 0 78705045379SLiam Breck #define bq27520g2_dm_regs 0 78805045379SLiam Breck #define bq27520g3_dm_regs 0 78905045379SLiam Breck #define bq27520g4_dm_regs 0 79070a39e10SPavel Machek #define bq27521_dm_regs 0 79105045379SLiam Breck #define bq27530_dm_regs 0 79205045379SLiam Breck #define bq27531_dm_regs 0 79305045379SLiam Breck #define bq27541_dm_regs 0 79405045379SLiam Breck #define bq27542_dm_regs 0 79505045379SLiam Breck #define bq27546_dm_regs 0 79605045379SLiam Breck #define bq27742_dm_regs 0 79705045379SLiam Breck 79805045379SLiam Breck #if 0 /* not yet tested */ 79905045379SLiam Breck static struct bq27xxx_dm_reg bq27545_dm_regs[] = { 80005045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 23, 2, 0, 32767 }, 80105045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 48, 25, 2, 0, 32767 }, 80205045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800, 3700 }, 80305045379SLiam Breck }; 80405045379SLiam Breck #else 80505045379SLiam Breck #define bq27545_dm_regs 0 80605045379SLiam Breck #endif 80705045379SLiam Breck 808457b42f0SLiu Xiang static struct bq27xxx_dm_reg bq27411_dm_regs[] = { 809457b42f0SLiu Xiang [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 32767 }, 810457b42f0SLiu Xiang [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, 811457b42f0SLiu Xiang [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, 812457b42f0SLiu Xiang }; 813457b42f0SLiu Xiang 81405045379SLiam Breck static struct bq27xxx_dm_reg bq27421_dm_regs[] = { 81505045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, 81605045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, 81705045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 }, 81805045379SLiam Breck }; 81905045379SLiam Breck 82005045379SLiam Breck static struct bq27xxx_dm_reg bq27425_dm_regs[] = { 82105045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 12, 2, 0, 32767 }, 82205045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 14, 2, 0, 32767 }, 82305045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800, 3700 }, 82405045379SLiam Breck }; 82505045379SLiam Breck 8265ef6a160SAndrew F. Davis static struct bq27xxx_dm_reg bq27426_dm_regs[] = { 8275ef6a160SAndrew F. Davis [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 6, 2, 0, 8000 }, 8285ef6a160SAndrew F. Davis [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 8, 2, 0, 32767 }, 8295ef6a160SAndrew F. Davis [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 10, 2, 2500, 3700 }, 8305ef6a160SAndrew F. Davis }; 8315ef6a160SAndrew F. Davis 83205045379SLiam Breck #if 0 /* not yet tested */ 83305045379SLiam Breck #define bq27441_dm_regs bq27421_dm_regs 83405045379SLiam Breck #else 83505045379SLiam Breck #define bq27441_dm_regs 0 83605045379SLiam Breck #endif 83705045379SLiam Breck 83805045379SLiam Breck #if 0 /* not yet tested */ 83905045379SLiam Breck static struct bq27xxx_dm_reg bq27621_dm_regs[] = { 84005045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 3, 2, 0, 8000 }, 84105045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 5, 2, 0, 32767 }, 84205045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500, 3700 }, 84305045379SLiam Breck }; 84405045379SLiam Breck #else 84505045379SLiam Breck #define bq27621_dm_regs 0 84605045379SLiam Breck #endif 84705045379SLiam Breck 8486f24ff97SDan Murphy #define bq27z561_dm_regs 0 849707d678aSDan Murphy #define bq28z610_dm_regs 0 850bffa569fSKrzysztof Kozlowski #define bq34z100_dm_regs 0 8516f24ff97SDan Murphy 852bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_ZERO BIT(0) 853bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_OTDC BIT(1) /* has OTC/OTD overtemperature flags */ 854bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_UTOT BIT(2) /* has OT overtemperature flag */ 855bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_CFGUP BIT(3) 856bffa569fSKrzysztof Kozlowski #define BQ27XXX_O_RAM BIT(4) 857bffa569fSKrzysztof Kozlowski #define BQ27Z561_O_BITS BIT(5) 858*c02ca201SKrzysztof Kozlowski #define BQ27XXX_O_SOC_SI BIT(6) /* SoC is single register */ 8593a731c64SLiam Breck 86005045379SLiam Breck #define BQ27XXX_DATA(ref, key, opt) { \ 8613a731c64SLiam Breck .opts = (opt), \ 86205045379SLiam Breck .unseal_key = key, \ 8639aade6d8SLiam Breck .regs = ref##_regs, \ 86405045379SLiam Breck .dm_regs = ref##_dm_regs, \ 8659aade6d8SLiam Breck .props = ref##_props, \ 8669aade6d8SLiam Breck .props_size = ARRAY_SIZE(ref##_props) } 8678c0984e5SSebastian Reichel 8688c0984e5SSebastian Reichel static struct { 8693a731c64SLiam Breck u32 opts; 87005045379SLiam Breck u32 unseal_key; 8719aade6d8SLiam Breck u8 *regs; 87205045379SLiam Breck struct bq27xxx_dm_reg *dm_regs; 8738c0984e5SSebastian Reichel enum power_supply_property *props; 8749aade6d8SLiam Breck size_t props_size; 8759aade6d8SLiam Breck } bq27xxx_chip_data[] = { 876*c02ca201SKrzysztof Kozlowski [BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO | BQ27XXX_O_SOC_SI), 877*c02ca201SKrzysztof Kozlowski [BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO | BQ27XXX_O_SOC_SI), 87805045379SLiam Breck [BQ2750X] = BQ27XXX_DATA(bq2750x, 0 , BQ27XXX_O_OTDC), 87905045379SLiam Breck [BQ2751X] = BQ27XXX_DATA(bq2751x, 0 , BQ27XXX_O_OTDC), 88005045379SLiam Breck [BQ2752X] = BQ27XXX_DATA(bq2752x, 0 , BQ27XXX_O_OTDC), 88105045379SLiam Breck [BQ27500] = BQ27XXX_DATA(bq27500, 0x04143672, BQ27XXX_O_OTDC), 88205045379SLiam Breck [BQ27510G1] = BQ27XXX_DATA(bq27510g1, 0 , BQ27XXX_O_OTDC), 88305045379SLiam Breck [BQ27510G2] = BQ27XXX_DATA(bq27510g2, 0 , BQ27XXX_O_OTDC), 88405045379SLiam Breck [BQ27510G3] = BQ27XXX_DATA(bq27510g3, 0 , BQ27XXX_O_OTDC), 88505045379SLiam Breck [BQ27520G1] = BQ27XXX_DATA(bq27520g1, 0 , BQ27XXX_O_OTDC), 88605045379SLiam Breck [BQ27520G2] = BQ27XXX_DATA(bq27520g2, 0 , BQ27XXX_O_OTDC), 88705045379SLiam Breck [BQ27520G3] = BQ27XXX_DATA(bq27520g3, 0 , BQ27XXX_O_OTDC), 88805045379SLiam Breck [BQ27520G4] = BQ27XXX_DATA(bq27520g4, 0 , BQ27XXX_O_OTDC), 88970a39e10SPavel Machek [BQ27521] = BQ27XXX_DATA(bq27521, 0 , 0), 89005045379SLiam Breck [BQ27530] = BQ27XXX_DATA(bq27530, 0 , BQ27XXX_O_UTOT), 89105045379SLiam Breck [BQ27531] = BQ27XXX_DATA(bq27531, 0 , BQ27XXX_O_UTOT), 89205045379SLiam Breck [BQ27541] = BQ27XXX_DATA(bq27541, 0 , BQ27XXX_O_OTDC), 89305045379SLiam Breck [BQ27542] = BQ27XXX_DATA(bq27542, 0 , BQ27XXX_O_OTDC), 89405045379SLiam Breck [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), 89505045379SLiam Breck [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), 89605045379SLiam Breck [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), 897457b42f0SLiu Xiang [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 89805045379SLiam Breck [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 89905045379SLiam Breck [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), 9005ef6a160SAndrew F. Davis [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 90105045379SLiam Breck [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 90205045379SLiam Breck [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 9036f24ff97SDan Murphy [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), 904707d678aSDan Murphy [BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS), 9058c0984e5SSebastian Reichel }; 9068c0984e5SSebastian Reichel 9071d72706fSMatt Ranostay static DEFINE_MUTEX(bq27xxx_list_lock); 9081d72706fSMatt Ranostay static LIST_HEAD(bq27xxx_battery_devices); 9091d72706fSMatt Ranostay 9100670c9b3SLiam Breck #define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500) 9110670c9b3SLiam Breck 9120670c9b3SLiam Breck #define BQ27XXX_DM_SZ 32 9130670c9b3SLiam Breck 9140670c9b3SLiam Breck /** 9150670c9b3SLiam Breck * struct bq27xxx_dm_buf - chip data memory buffer 9160670c9b3SLiam Breck * @class: data memory subclass_id 9170670c9b3SLiam Breck * @block: data memory block number 9180670c9b3SLiam Breck * @data: data from/for the block 9190670c9b3SLiam Breck * @has_data: true if data has been filled by read 9200670c9b3SLiam Breck * @dirty: true if data has changed since last read/write 9210670c9b3SLiam Breck * 9220670c9b3SLiam Breck * Encapsulates info required to manage chip data memory blocks. 9230670c9b3SLiam Breck */ 9240670c9b3SLiam Breck struct bq27xxx_dm_buf { 9250670c9b3SLiam Breck u8 class; 9260670c9b3SLiam Breck u8 block; 9270670c9b3SLiam Breck u8 data[BQ27XXX_DM_SZ]; 9280670c9b3SLiam Breck bool has_data, dirty; 9290670c9b3SLiam Breck }; 9300670c9b3SLiam Breck 931ccce4409SLiam Breck #define BQ27XXX_DM_BUF(di, i) { \ 932ccce4409SLiam Breck .class = (di)->dm_regs[i].subclass_id, \ 933ccce4409SLiam Breck .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \ 934ccce4409SLiam Breck } 935ccce4409SLiam Breck 936ccce4409SLiam Breck static inline u16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf, 937ccce4409SLiam Breck struct bq27xxx_dm_reg *reg) 938ccce4409SLiam Breck { 939ccce4409SLiam Breck if (buf->class == reg->subclass_id && 940ccce4409SLiam Breck buf->block == reg->offset / BQ27XXX_DM_SZ) 941ccce4409SLiam Breck return (u16 *) (buf->data + reg->offset % BQ27XXX_DM_SZ); 942ccce4409SLiam Breck 943ccce4409SLiam Breck return NULL; 944ccce4409SLiam Breck } 945ccce4409SLiam Breck 946ccce4409SLiam Breck static const char * const bq27xxx_dm_reg_name[] = { 947ccce4409SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity", 948ccce4409SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy", 949ccce4409SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage", 950ccce4409SLiam Breck }; 951ccce4409SLiam Breck 952ccce4409SLiam Breck 953ccce4409SLiam Breck static bool bq27xxx_dt_to_nvm = true; 954ccce4409SLiam Breck module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444); 955ccce4409SLiam Breck MODULE_PARM_DESC(dt_monitored_battery_updates_nvm, 956ccce4409SLiam Breck "Devicetree monitored-battery config updates data memory on NVM/flash chips.\n" 957ccce4409SLiam Breck "Users must set this =0 when installing a different type of battery!\n" 958ccce4409SLiam Breck "Default is =1." 959ccce4409SLiam Breck #ifndef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 960ccce4409SLiam Breck "\nSetting this affects future kernel updates, not the current configuration." 961ccce4409SLiam Breck #endif 962ccce4409SLiam Breck ); 9630670c9b3SLiam Breck 9641d72706fSMatt Ranostay static int poll_interval_param_set(const char *val, const struct kernel_param *kp) 9651d72706fSMatt Ranostay { 9661d72706fSMatt Ranostay struct bq27xxx_device_info *di; 967950b6c2dSMatt Ranostay unsigned int prev_val = *(unsigned int *) kp->arg; 9681d72706fSMatt Ranostay int ret; 9691d72706fSMatt Ranostay 9701d72706fSMatt Ranostay ret = param_set_uint(val, kp); 971950b6c2dSMatt Ranostay if (ret < 0 || prev_val == *(unsigned int *) kp->arg) 9721d72706fSMatt Ranostay return ret; 9731d72706fSMatt Ranostay 9741d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 9751d72706fSMatt Ranostay list_for_each_entry(di, &bq27xxx_battery_devices, list) { 9761d72706fSMatt Ranostay cancel_delayed_work_sync(&di->work); 9771d72706fSMatt Ranostay schedule_delayed_work(&di->work, 0); 9781d72706fSMatt Ranostay } 9791d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 9801d72706fSMatt Ranostay 9811d72706fSMatt Ranostay return ret; 9821d72706fSMatt Ranostay } 9831d72706fSMatt Ranostay 9841d72706fSMatt Ranostay static const struct kernel_param_ops param_ops_poll_interval = { 9851d72706fSMatt Ranostay .get = param_get_uint, 9861d72706fSMatt Ranostay .set = poll_interval_param_set, 9871d72706fSMatt Ranostay }; 9881d72706fSMatt Ranostay 9898c0984e5SSebastian Reichel static unsigned int poll_interval = 360; 9901d72706fSMatt Ranostay module_param_cb(poll_interval, ¶m_ops_poll_interval, &poll_interval, 0644); 9918c0984e5SSebastian Reichel MODULE_PARM_DESC(poll_interval, 9928c0984e5SSebastian Reichel "battery poll interval in seconds - 0 disables polling"); 9938c0984e5SSebastian Reichel 9948c0984e5SSebastian Reichel /* 9958c0984e5SSebastian Reichel * Common code for BQ27xxx devices 9968c0984e5SSebastian Reichel */ 9978c0984e5SSebastian Reichel 9988c0984e5SSebastian Reichel static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, 9998c0984e5SSebastian Reichel bool single) 10008c0984e5SSebastian Reichel { 100114073f66SMatt Ranostay int ret; 100214073f66SMatt Ranostay 10038c0984e5SSebastian Reichel if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 10048c0984e5SSebastian Reichel return -EINVAL; 10058c0984e5SSebastian Reichel 100614073f66SMatt Ranostay ret = di->bus.read(di, di->regs[reg_index], single); 100714073f66SMatt Ranostay if (ret < 0) 100814073f66SMatt Ranostay dev_dbg(di->dev, "failed to read register 0x%02x (index %d)\n", 100914073f66SMatt Ranostay di->regs[reg_index], reg_index); 101014073f66SMatt Ranostay 101114073f66SMatt Ranostay return ret; 101214073f66SMatt Ranostay } 101314073f66SMatt Ranostay 101414073f66SMatt Ranostay static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, 101514073f66SMatt Ranostay u16 value, bool single) 101614073f66SMatt Ranostay { 101714073f66SMatt Ranostay int ret; 101814073f66SMatt Ranostay 101914073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 102014073f66SMatt Ranostay return -EINVAL; 102114073f66SMatt Ranostay 102214073f66SMatt Ranostay if (!di->bus.write) 102314073f66SMatt Ranostay return -EPERM; 102414073f66SMatt Ranostay 102514073f66SMatt Ranostay ret = di->bus.write(di, di->regs[reg_index], value, single); 102614073f66SMatt Ranostay if (ret < 0) 102714073f66SMatt Ranostay dev_dbg(di->dev, "failed to write register 0x%02x (index %d)\n", 102814073f66SMatt Ranostay di->regs[reg_index], reg_index); 102914073f66SMatt Ranostay 103014073f66SMatt Ranostay return ret; 103114073f66SMatt Ranostay } 103214073f66SMatt Ranostay 103314073f66SMatt Ranostay static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_index, 103414073f66SMatt Ranostay u8 *data, int len) 103514073f66SMatt Ranostay { 103614073f66SMatt Ranostay int ret; 103714073f66SMatt Ranostay 103814073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 103914073f66SMatt Ranostay return -EINVAL; 104014073f66SMatt Ranostay 104114073f66SMatt Ranostay if (!di->bus.read_bulk) 104214073f66SMatt Ranostay return -EPERM; 104314073f66SMatt Ranostay 104414073f66SMatt Ranostay ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); 104514073f66SMatt Ranostay if (ret < 0) 104614073f66SMatt Ranostay dev_dbg(di->dev, "failed to read_bulk register 0x%02x (index %d)\n", 104714073f66SMatt Ranostay di->regs[reg_index], reg_index); 104814073f66SMatt Ranostay 104914073f66SMatt Ranostay return ret; 105014073f66SMatt Ranostay } 105114073f66SMatt Ranostay 105214073f66SMatt Ranostay static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_index, 105314073f66SMatt Ranostay u8 *data, int len) 105414073f66SMatt Ranostay { 105514073f66SMatt Ranostay int ret; 105614073f66SMatt Ranostay 105714073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 105814073f66SMatt Ranostay return -EINVAL; 105914073f66SMatt Ranostay 106014073f66SMatt Ranostay if (!di->bus.write_bulk) 106114073f66SMatt Ranostay return -EPERM; 106214073f66SMatt Ranostay 106314073f66SMatt Ranostay ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); 106414073f66SMatt Ranostay if (ret < 0) 106514073f66SMatt Ranostay dev_dbg(di->dev, "failed to write_bulk register 0x%02x (index %d)\n", 106614073f66SMatt Ranostay di->regs[reg_index], reg_index); 106714073f66SMatt Ranostay 106814073f66SMatt Ranostay return ret; 10698c0984e5SSebastian Reichel } 10708c0984e5SSebastian Reichel 10710670c9b3SLiam Breck static int bq27xxx_battery_seal(struct bq27xxx_device_info *di) 10720670c9b3SLiam Breck { 10730670c9b3SLiam Breck int ret; 10740670c9b3SLiam Breck 10750670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false); 10760670c9b3SLiam Breck if (ret < 0) { 10770670c9b3SLiam Breck dev_err(di->dev, "bus error on seal: %d\n", ret); 10780670c9b3SLiam Breck return ret; 10790670c9b3SLiam Breck } 10800670c9b3SLiam Breck 10810670c9b3SLiam Breck return 0; 10820670c9b3SLiam Breck } 10830670c9b3SLiam Breck 10840670c9b3SLiam Breck static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di) 10850670c9b3SLiam Breck { 10860670c9b3SLiam Breck int ret; 10870670c9b3SLiam Breck 10880670c9b3SLiam Breck if (di->unseal_key == 0) { 10890670c9b3SLiam Breck dev_err(di->dev, "unseal failed due to missing key\n"); 10900670c9b3SLiam Breck return -EINVAL; 10910670c9b3SLiam Breck } 10920670c9b3SLiam Breck 10930670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false); 10940670c9b3SLiam Breck if (ret < 0) 10950670c9b3SLiam Breck goto out; 10960670c9b3SLiam Breck 10970670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false); 10980670c9b3SLiam Breck if (ret < 0) 10990670c9b3SLiam Breck goto out; 11000670c9b3SLiam Breck 11010670c9b3SLiam Breck return 0; 11020670c9b3SLiam Breck 11030670c9b3SLiam Breck out: 11040670c9b3SLiam Breck dev_err(di->dev, "bus error on unseal: %d\n", ret); 11050670c9b3SLiam Breck return ret; 11060670c9b3SLiam Breck } 11070670c9b3SLiam Breck 11080670c9b3SLiam Breck static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf) 11090670c9b3SLiam Breck { 11100670c9b3SLiam Breck u16 sum = 0; 11110670c9b3SLiam Breck int i; 11120670c9b3SLiam Breck 11130670c9b3SLiam Breck for (i = 0; i < BQ27XXX_DM_SZ; i++) 11140670c9b3SLiam Breck sum += buf->data[i]; 11150670c9b3SLiam Breck sum &= 0xff; 11160670c9b3SLiam Breck 11170670c9b3SLiam Breck return 0xff - sum; 11180670c9b3SLiam Breck } 11190670c9b3SLiam Breck 11200670c9b3SLiam Breck static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di, 11210670c9b3SLiam Breck struct bq27xxx_dm_buf *buf) 11220670c9b3SLiam Breck { 11230670c9b3SLiam Breck int ret; 11240670c9b3SLiam Breck 11250670c9b3SLiam Breck buf->has_data = false; 11260670c9b3SLiam Breck 11270670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true); 11280670c9b3SLiam Breck if (ret < 0) 11290670c9b3SLiam Breck goto out; 11300670c9b3SLiam Breck 11310670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true); 11320670c9b3SLiam Breck if (ret < 0) 11330670c9b3SLiam Breck goto out; 11340670c9b3SLiam Breck 11350670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 11360670c9b3SLiam Breck 11370670c9b3SLiam Breck ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ); 11380670c9b3SLiam Breck if (ret < 0) 11390670c9b3SLiam Breck goto out; 11400670c9b3SLiam Breck 11410670c9b3SLiam Breck ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true); 11420670c9b3SLiam Breck if (ret < 0) 11430670c9b3SLiam Breck goto out; 11440670c9b3SLiam Breck 11450670c9b3SLiam Breck if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) { 11460670c9b3SLiam Breck ret = -EINVAL; 11470670c9b3SLiam Breck goto out; 11480670c9b3SLiam Breck } 11490670c9b3SLiam Breck 11500670c9b3SLiam Breck buf->has_data = true; 11510670c9b3SLiam Breck buf->dirty = false; 11520670c9b3SLiam Breck 11530670c9b3SLiam Breck return 0; 11540670c9b3SLiam Breck 11550670c9b3SLiam Breck out: 11560670c9b3SLiam Breck dev_err(di->dev, "bus error reading chip memory: %d\n", ret); 11570670c9b3SLiam Breck return ret; 11580670c9b3SLiam Breck } 11590670c9b3SLiam Breck 1160ccce4409SLiam Breck static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, 1161ccce4409SLiam Breck struct bq27xxx_dm_buf *buf, 1162ccce4409SLiam Breck enum bq27xxx_dm_reg_id reg_id, 1163ccce4409SLiam Breck unsigned int val) 1164ccce4409SLiam Breck { 1165ccce4409SLiam Breck struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id]; 1166ccce4409SLiam Breck const char *str = bq27xxx_dm_reg_name[reg_id]; 1167ccce4409SLiam Breck u16 *prev = bq27xxx_dm_reg_ptr(buf, reg); 1168ccce4409SLiam Breck 1169ccce4409SLiam Breck if (prev == NULL) { 1170ccce4409SLiam Breck dev_warn(di->dev, "buffer does not match %s dm spec\n", str); 1171ccce4409SLiam Breck return; 1172ccce4409SLiam Breck } 1173ccce4409SLiam Breck 1174ccce4409SLiam Breck if (reg->bytes != 2) { 1175ccce4409SLiam Breck dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str); 1176ccce4409SLiam Breck return; 1177ccce4409SLiam Breck } 1178ccce4409SLiam Breck 1179ccce4409SLiam Breck if (!buf->has_data) 1180ccce4409SLiam Breck return; 1181ccce4409SLiam Breck 1182ccce4409SLiam Breck if (be16_to_cpup(prev) == val) { 1183ccce4409SLiam Breck dev_info(di->dev, "%s has %u\n", str, val); 1184ccce4409SLiam Breck return; 1185ccce4409SLiam Breck } 1186ccce4409SLiam Breck 1187ccce4409SLiam Breck #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 118805045379SLiam Breck if (!(di->opts & BQ27XXX_O_RAM) && !bq27xxx_dt_to_nvm) { 1189ccce4409SLiam Breck #else 119005045379SLiam Breck if (!(di->opts & BQ27XXX_O_RAM)) { 1191ccce4409SLiam Breck #endif 1192ccce4409SLiam Breck /* devicetree and NVM differ; defer to NVM */ 1193ccce4409SLiam Breck dev_warn(di->dev, "%s has %u; update to %u disallowed " 1194ccce4409SLiam Breck #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 1195ccce4409SLiam Breck "by dt_monitored_battery_updates_nvm=0" 1196ccce4409SLiam Breck #else 1197ccce4409SLiam Breck "for flash/NVM data memory" 1198ccce4409SLiam Breck #endif 1199ccce4409SLiam Breck "\n", str, be16_to_cpup(prev), val); 1200ccce4409SLiam Breck return; 1201ccce4409SLiam Breck } 1202ccce4409SLiam Breck 1203ccce4409SLiam Breck dev_info(di->dev, "update %s to %u\n", str, val); 1204ccce4409SLiam Breck 1205ccce4409SLiam Breck *prev = cpu_to_be16(val); 1206ccce4409SLiam Breck buf->dirty = true; 1207ccce4409SLiam Breck } 1208ccce4409SLiam Breck 12090670c9b3SLiam Breck static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info *di, bool active) 12100670c9b3SLiam Breck { 12110670c9b3SLiam Breck const int limit = 100; 12120670c9b3SLiam Breck u16 cmd = active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET; 12130670c9b3SLiam Breck int ret, try = limit; 12140670c9b3SLiam Breck 12150670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, cmd, false); 12160670c9b3SLiam Breck if (ret < 0) 12170670c9b3SLiam Breck return ret; 12180670c9b3SLiam Breck 12190670c9b3SLiam Breck do { 12200670c9b3SLiam Breck BQ27XXX_MSLEEP(25); 12210670c9b3SLiam Breck ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false); 12220670c9b3SLiam Breck if (ret < 0) 12230670c9b3SLiam Breck return ret; 12240670c9b3SLiam Breck } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try); 12250670c9b3SLiam Breck 122605045379SLiam Breck if (!try && di->chip != BQ27425) { // 425 has a bug 12270670c9b3SLiam Breck dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active); 12280670c9b3SLiam Breck return -EINVAL; 12290670c9b3SLiam Breck } 12300670c9b3SLiam Breck 12310670c9b3SLiam Breck if (limit - try > 3) 12320670c9b3SLiam Breck dev_warn(di->dev, "cfgupdate %d, retries %d\n", active, limit - try); 12330670c9b3SLiam Breck 12340670c9b3SLiam Breck return 0; 12350670c9b3SLiam Breck } 12360670c9b3SLiam Breck 12370670c9b3SLiam Breck static inline int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di) 12380670c9b3SLiam Breck { 12390670c9b3SLiam Breck int ret = bq27xxx_battery_cfgupdate_priv(di, true); 12400670c9b3SLiam Breck if (ret < 0 && ret != -EINVAL) 12410670c9b3SLiam Breck dev_err(di->dev, "bus error on set_cfgupdate: %d\n", ret); 12420670c9b3SLiam Breck 12430670c9b3SLiam Breck return ret; 12440670c9b3SLiam Breck } 12450670c9b3SLiam Breck 12460670c9b3SLiam Breck static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di) 12470670c9b3SLiam Breck { 12480670c9b3SLiam Breck int ret = bq27xxx_battery_cfgupdate_priv(di, false); 12490670c9b3SLiam Breck if (ret < 0 && ret != -EINVAL) 12500670c9b3SLiam Breck dev_err(di->dev, "bus error on soft_reset: %d\n", ret); 12510670c9b3SLiam Breck 12520670c9b3SLiam Breck return ret; 12530670c9b3SLiam Breck } 12540670c9b3SLiam Breck 12550670c9b3SLiam Breck static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di, 12560670c9b3SLiam Breck struct bq27xxx_dm_buf *buf) 12570670c9b3SLiam Breck { 125805045379SLiam Breck bool cfgup = di->opts & BQ27XXX_O_CFGUP; 12590670c9b3SLiam Breck int ret; 12600670c9b3SLiam Breck 12610670c9b3SLiam Breck if (!buf->dirty) 12620670c9b3SLiam Breck return 0; 12630670c9b3SLiam Breck 12640670c9b3SLiam Breck if (cfgup) { 12650670c9b3SLiam Breck ret = bq27xxx_battery_set_cfgupdate(di); 12660670c9b3SLiam Breck if (ret < 0) 12670670c9b3SLiam Breck return ret; 12680670c9b3SLiam Breck } 12690670c9b3SLiam Breck 12700670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true); 12710670c9b3SLiam Breck if (ret < 0) 12720670c9b3SLiam Breck goto out; 12730670c9b3SLiam Breck 12740670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true); 12750670c9b3SLiam Breck if (ret < 0) 12760670c9b3SLiam Breck goto out; 12770670c9b3SLiam Breck 12780670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true); 12790670c9b3SLiam Breck if (ret < 0) 12800670c9b3SLiam Breck goto out; 12810670c9b3SLiam Breck 12820670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 12830670c9b3SLiam Breck 12840670c9b3SLiam Breck ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ); 12850670c9b3SLiam Breck if (ret < 0) 12860670c9b3SLiam Breck goto out; 12870670c9b3SLiam Breck 12880670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM, 12890670c9b3SLiam Breck bq27xxx_battery_checksum_dm_block(buf), true); 12900670c9b3SLiam Breck if (ret < 0) 12910670c9b3SLiam Breck goto out; 12920670c9b3SLiam Breck 12930670c9b3SLiam Breck /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM 12940670c9b3SLiam Breck * corruption on the '425 chip (and perhaps others), which can damage 12950670c9b3SLiam Breck * the chip. 12960670c9b3SLiam Breck */ 12970670c9b3SLiam Breck 12980670c9b3SLiam Breck if (cfgup) { 12990670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 13000670c9b3SLiam Breck ret = bq27xxx_battery_soft_reset(di); 13010670c9b3SLiam Breck if (ret < 0) 13020670c9b3SLiam Breck return ret; 13030670c9b3SLiam Breck } else { 13040670c9b3SLiam Breck BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */ 13050670c9b3SLiam Breck } 13060670c9b3SLiam Breck 13070670c9b3SLiam Breck buf->dirty = false; 13080670c9b3SLiam Breck 13090670c9b3SLiam Breck return 0; 13100670c9b3SLiam Breck 13110670c9b3SLiam Breck out: 13120670c9b3SLiam Breck if (cfgup) 13130670c9b3SLiam Breck bq27xxx_battery_soft_reset(di); 13140670c9b3SLiam Breck 13150670c9b3SLiam Breck dev_err(di->dev, "bus error writing chip memory: %d\n", ret); 13160670c9b3SLiam Breck return ret; 13170670c9b3SLiam Breck } 13180670c9b3SLiam Breck 1319ccce4409SLiam Breck static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, 1320ccce4409SLiam Breck struct power_supply_battery_info *info) 1321ccce4409SLiam Breck { 1322ccce4409SLiam Breck struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY); 1323ccce4409SLiam Breck struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE); 1324ccce4409SLiam Breck bool updated; 1325ccce4409SLiam Breck 1326ccce4409SLiam Breck if (bq27xxx_battery_unseal(di) < 0) 1327ccce4409SLiam Breck return; 1328ccce4409SLiam Breck 1329ccce4409SLiam Breck if (info->charge_full_design_uah != -EINVAL && 1330ccce4409SLiam Breck info->energy_full_design_uwh != -EINVAL) { 1331ccce4409SLiam Breck bq27xxx_battery_read_dm_block(di, &bd); 1332ccce4409SLiam Breck /* assume design energy & capacity are in same block */ 1333ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, &bd, 1334ccce4409SLiam Breck BQ27XXX_DM_DESIGN_CAPACITY, 1335ccce4409SLiam Breck info->charge_full_design_uah / 1000); 1336ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, &bd, 1337ccce4409SLiam Breck BQ27XXX_DM_DESIGN_ENERGY, 1338ccce4409SLiam Breck info->energy_full_design_uwh / 1000); 1339ccce4409SLiam Breck } 1340ccce4409SLiam Breck 1341ccce4409SLiam Breck if (info->voltage_min_design_uv != -EINVAL) { 1342ccce4409SLiam Breck bool same = bd.class == bt.class && bd.block == bt.block; 1343ccce4409SLiam Breck if (!same) 1344ccce4409SLiam Breck bq27xxx_battery_read_dm_block(di, &bt); 1345ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, same ? &bd : &bt, 1346ccce4409SLiam Breck BQ27XXX_DM_TERMINATE_VOLTAGE, 1347ccce4409SLiam Breck info->voltage_min_design_uv / 1000); 1348ccce4409SLiam Breck } 1349ccce4409SLiam Breck 1350ccce4409SLiam Breck updated = bd.dirty || bt.dirty; 1351ccce4409SLiam Breck 1352ccce4409SLiam Breck bq27xxx_battery_write_dm_block(di, &bd); 1353ccce4409SLiam Breck bq27xxx_battery_write_dm_block(di, &bt); 1354ccce4409SLiam Breck 1355ccce4409SLiam Breck bq27xxx_battery_seal(di); 1356ccce4409SLiam Breck 135705045379SLiam Breck if (updated && !(di->opts & BQ27XXX_O_CFGUP)) { 1358ccce4409SLiam Breck bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false); 1359ccce4409SLiam Breck BQ27XXX_MSLEEP(300); /* reset time is not documented */ 1360ccce4409SLiam Breck } 1361ccce4409SLiam Breck /* assume bq27xxx_battery_update() is called hereafter */ 1362ccce4409SLiam Breck } 1363ccce4409SLiam Breck 1364ccce4409SLiam Breck static void bq27xxx_battery_settings(struct bq27xxx_device_info *di) 1365ccce4409SLiam Breck { 1366ccce4409SLiam Breck struct power_supply_battery_info info = {}; 1367ccce4409SLiam Breck unsigned int min, max; 1368ccce4409SLiam Breck 1369ccce4409SLiam Breck if (power_supply_get_battery_info(di->bat, &info) < 0) 1370ccce4409SLiam Breck return; 1371ccce4409SLiam Breck 1372ccce4409SLiam Breck if (!di->dm_regs) { 1373ccce4409SLiam Breck dev_warn(di->dev, "data memory update not supported for chip\n"); 1374ccce4409SLiam Breck return; 1375ccce4409SLiam Breck } 1376ccce4409SLiam Breck 1377ccce4409SLiam Breck if (info.energy_full_design_uwh != info.charge_full_design_uah) { 1378ccce4409SLiam Breck if (info.energy_full_design_uwh == -EINVAL) 1379ccce4409SLiam Breck dev_warn(di->dev, "missing battery:energy-full-design-microwatt-hours\n"); 1380ccce4409SLiam Breck else if (info.charge_full_design_uah == -EINVAL) 1381ccce4409SLiam Breck dev_warn(di->dev, "missing battery:charge-full-design-microamp-hours\n"); 1382ccce4409SLiam Breck } 1383ccce4409SLiam Breck 1384ccce4409SLiam Breck /* assume min == 0 */ 1385ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max; 1386ccce4409SLiam Breck if (info.energy_full_design_uwh > max * 1000) { 1387ccce4409SLiam Breck dev_err(di->dev, "invalid battery:energy-full-design-microwatt-hours %d\n", 1388ccce4409SLiam Breck info.energy_full_design_uwh); 1389ccce4409SLiam Breck info.energy_full_design_uwh = -EINVAL; 1390ccce4409SLiam Breck } 1391ccce4409SLiam Breck 1392ccce4409SLiam Breck /* assume min == 0 */ 1393ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max; 1394ccce4409SLiam Breck if (info.charge_full_design_uah > max * 1000) { 1395ccce4409SLiam Breck dev_err(di->dev, "invalid battery:charge-full-design-microamp-hours %d\n", 1396ccce4409SLiam Breck info.charge_full_design_uah); 1397ccce4409SLiam Breck info.charge_full_design_uah = -EINVAL; 1398ccce4409SLiam Breck } 1399ccce4409SLiam Breck 1400ccce4409SLiam Breck min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min; 1401ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max; 1402ccce4409SLiam Breck if ((info.voltage_min_design_uv < min * 1000 || 1403ccce4409SLiam Breck info.voltage_min_design_uv > max * 1000) && 1404ccce4409SLiam Breck info.voltage_min_design_uv != -EINVAL) { 1405ccce4409SLiam Breck dev_err(di->dev, "invalid battery:voltage-min-design-microvolt %d\n", 1406ccce4409SLiam Breck info.voltage_min_design_uv); 1407ccce4409SLiam Breck info.voltage_min_design_uv = -EINVAL; 1408ccce4409SLiam Breck } 1409ccce4409SLiam Breck 1410ccce4409SLiam Breck if ((info.energy_full_design_uwh != -EINVAL && 1411ccce4409SLiam Breck info.charge_full_design_uah != -EINVAL) || 1412ccce4409SLiam Breck info.voltage_min_design_uv != -EINVAL) 1413ccce4409SLiam Breck bq27xxx_battery_set_config(di, &info); 1414ccce4409SLiam Breck } 1415ccce4409SLiam Breck 14168c0984e5SSebastian Reichel /* 14178c0984e5SSebastian Reichel * Return the battery State-of-Charge 14188c0984e5SSebastian Reichel * Or < 0 if something fails. 14198c0984e5SSebastian Reichel */ 14208c0984e5SSebastian Reichel static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di) 14218c0984e5SSebastian Reichel { 14228c0984e5SSebastian Reichel int soc; 14238c0984e5SSebastian Reichel 1424*c02ca201SKrzysztof Kozlowski if (di->opts & BQ27XXX_O_SOC_SI) 14258c0984e5SSebastian Reichel soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true); 14268c0984e5SSebastian Reichel else 14278c0984e5SSebastian Reichel soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false); 14288c0984e5SSebastian Reichel 14298c0984e5SSebastian Reichel if (soc < 0) 14308c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading State-of-Charge\n"); 14318c0984e5SSebastian Reichel 14328c0984e5SSebastian Reichel return soc; 14338c0984e5SSebastian Reichel } 14348c0984e5SSebastian Reichel 14358c0984e5SSebastian Reichel /* 14368c0984e5SSebastian Reichel * Return a battery charge value in µAh 14378c0984e5SSebastian Reichel * Or < 0 if something fails. 14388c0984e5SSebastian Reichel */ 14398c0984e5SSebastian Reichel static int bq27xxx_battery_read_charge(struct bq27xxx_device_info *di, u8 reg) 14408c0984e5SSebastian Reichel { 14418c0984e5SSebastian Reichel int charge; 14428c0984e5SSebastian Reichel 14438c0984e5SSebastian Reichel charge = bq27xxx_read(di, reg, false); 14448c0984e5SSebastian Reichel if (charge < 0) { 14458c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading charge register %02x: %d\n", 14468c0984e5SSebastian Reichel reg, charge); 14478c0984e5SSebastian Reichel return charge; 14488c0984e5SSebastian Reichel } 14498c0984e5SSebastian Reichel 14503a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 14518c0984e5SSebastian Reichel charge *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 14528c0984e5SSebastian Reichel else 14538c0984e5SSebastian Reichel charge *= 1000; 14548c0984e5SSebastian Reichel 14558c0984e5SSebastian Reichel return charge; 14568c0984e5SSebastian Reichel } 14578c0984e5SSebastian Reichel 14588c0984e5SSebastian Reichel /* 14598c0984e5SSebastian Reichel * Return the battery Nominal available capacity in µAh 14608c0984e5SSebastian Reichel * Or < 0 if something fails. 14618c0984e5SSebastian Reichel */ 14628c0984e5SSebastian Reichel static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di) 14638c0984e5SSebastian Reichel { 14648c0984e5SSebastian Reichel int flags; 14658c0984e5SSebastian Reichel 14663a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 14678c0984e5SSebastian Reichel flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); 14688c0984e5SSebastian Reichel if (flags >= 0 && (flags & BQ27000_FLAG_CI)) 14698c0984e5SSebastian Reichel return -ENODATA; 14708c0984e5SSebastian Reichel } 14718c0984e5SSebastian Reichel 14728c0984e5SSebastian Reichel return bq27xxx_battery_read_charge(di, BQ27XXX_REG_NAC); 14738c0984e5SSebastian Reichel } 14748c0984e5SSebastian Reichel 14758c0984e5SSebastian Reichel /* 14768c0984e5SSebastian Reichel * Return the battery Full Charge Capacity in µAh 14778c0984e5SSebastian Reichel * Or < 0 if something fails. 14788c0984e5SSebastian Reichel */ 14798c0984e5SSebastian Reichel static inline int bq27xxx_battery_read_fcc(struct bq27xxx_device_info *di) 14808c0984e5SSebastian Reichel { 14818c0984e5SSebastian Reichel return bq27xxx_battery_read_charge(di, BQ27XXX_REG_FCC); 14828c0984e5SSebastian Reichel } 14838c0984e5SSebastian Reichel 14848c0984e5SSebastian Reichel /* 14858c0984e5SSebastian Reichel * Return the Design Capacity in µAh 14868c0984e5SSebastian Reichel * Or < 0 if something fails. 14878c0984e5SSebastian Reichel */ 14888c0984e5SSebastian Reichel static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) 14898c0984e5SSebastian Reichel { 14908c0984e5SSebastian Reichel int dcap; 14918c0984e5SSebastian Reichel 14923a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 14938c0984e5SSebastian Reichel dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); 14948c0984e5SSebastian Reichel else 14958c0984e5SSebastian Reichel dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); 14968c0984e5SSebastian Reichel 14978c0984e5SSebastian Reichel if (dcap < 0) { 14988c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading initial last measured discharge\n"); 14998c0984e5SSebastian Reichel return dcap; 15008c0984e5SSebastian Reichel } 15018c0984e5SSebastian Reichel 15023a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15038c0984e5SSebastian Reichel dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 15048c0984e5SSebastian Reichel else 15058c0984e5SSebastian Reichel dcap *= 1000; 15068c0984e5SSebastian Reichel 15078c0984e5SSebastian Reichel return dcap; 15088c0984e5SSebastian Reichel } 15098c0984e5SSebastian Reichel 15108c0984e5SSebastian Reichel /* 15118c0984e5SSebastian Reichel * Return the battery Available energy in µWh 15128c0984e5SSebastian Reichel * Or < 0 if something fails. 15138c0984e5SSebastian Reichel */ 15148c0984e5SSebastian Reichel static int bq27xxx_battery_read_energy(struct bq27xxx_device_info *di) 15158c0984e5SSebastian Reichel { 15168c0984e5SSebastian Reichel int ae; 15178c0984e5SSebastian Reichel 15188c0984e5SSebastian Reichel ae = bq27xxx_read(di, BQ27XXX_REG_AE, false); 15198c0984e5SSebastian Reichel if (ae < 0) { 15208c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading available energy\n"); 15218c0984e5SSebastian Reichel return ae; 15228c0984e5SSebastian Reichel } 15238c0984e5SSebastian Reichel 15243a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15258c0984e5SSebastian Reichel ae *= BQ27XXX_POWER_CONSTANT / BQ27XXX_RS; 15268c0984e5SSebastian Reichel else 15278c0984e5SSebastian Reichel ae *= 1000; 15288c0984e5SSebastian Reichel 15298c0984e5SSebastian Reichel return ae; 15308c0984e5SSebastian Reichel } 15318c0984e5SSebastian Reichel 15328c0984e5SSebastian Reichel /* 15338c0984e5SSebastian Reichel * Return the battery temperature in tenths of degree Kelvin 15348c0984e5SSebastian Reichel * Or < 0 if something fails. 15358c0984e5SSebastian Reichel */ 15368c0984e5SSebastian Reichel static int bq27xxx_battery_read_temperature(struct bq27xxx_device_info *di) 15378c0984e5SSebastian Reichel { 15388c0984e5SSebastian Reichel int temp; 15398c0984e5SSebastian Reichel 15408c0984e5SSebastian Reichel temp = bq27xxx_read(di, BQ27XXX_REG_TEMP, false); 15418c0984e5SSebastian Reichel if (temp < 0) { 15428c0984e5SSebastian Reichel dev_err(di->dev, "error reading temperature\n"); 15438c0984e5SSebastian Reichel return temp; 15448c0984e5SSebastian Reichel } 15458c0984e5SSebastian Reichel 15463a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15478c0984e5SSebastian Reichel temp = 5 * temp / 2; 15488c0984e5SSebastian Reichel 15498c0984e5SSebastian Reichel return temp; 15508c0984e5SSebastian Reichel } 15518c0984e5SSebastian Reichel 15528c0984e5SSebastian Reichel /* 15538c0984e5SSebastian Reichel * Return the battery Cycle count total 15548c0984e5SSebastian Reichel * Or < 0 if something fails. 15558c0984e5SSebastian Reichel */ 15568c0984e5SSebastian Reichel static int bq27xxx_battery_read_cyct(struct bq27xxx_device_info *di) 15578c0984e5SSebastian Reichel { 15588c0984e5SSebastian Reichel int cyct; 15598c0984e5SSebastian Reichel 15608c0984e5SSebastian Reichel cyct = bq27xxx_read(di, BQ27XXX_REG_CYCT, false); 15618c0984e5SSebastian Reichel if (cyct < 0) 15628c0984e5SSebastian Reichel dev_err(di->dev, "error reading cycle count total\n"); 15638c0984e5SSebastian Reichel 15648c0984e5SSebastian Reichel return cyct; 15658c0984e5SSebastian Reichel } 15668c0984e5SSebastian Reichel 15678c0984e5SSebastian Reichel /* 15688c0984e5SSebastian Reichel * Read a time register. 15698c0984e5SSebastian Reichel * Return < 0 if something fails. 15708c0984e5SSebastian Reichel */ 15718c0984e5SSebastian Reichel static int bq27xxx_battery_read_time(struct bq27xxx_device_info *di, u8 reg) 15728c0984e5SSebastian Reichel { 15738c0984e5SSebastian Reichel int tval; 15748c0984e5SSebastian Reichel 15758c0984e5SSebastian Reichel tval = bq27xxx_read(di, reg, false); 15768c0984e5SSebastian Reichel if (tval < 0) { 15778c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading time register %02x: %d\n", 15788c0984e5SSebastian Reichel reg, tval); 15798c0984e5SSebastian Reichel return tval; 15808c0984e5SSebastian Reichel } 15818c0984e5SSebastian Reichel 15828c0984e5SSebastian Reichel if (tval == 65535) 15838c0984e5SSebastian Reichel return -ENODATA; 15848c0984e5SSebastian Reichel 15858c0984e5SSebastian Reichel return tval * 60; 15868c0984e5SSebastian Reichel } 15878c0984e5SSebastian Reichel 15888c0984e5SSebastian Reichel /* 15898c0984e5SSebastian Reichel * Read an average power register. 15908c0984e5SSebastian Reichel * Return < 0 if something fails. 15918c0984e5SSebastian Reichel */ 15928c0984e5SSebastian Reichel static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di) 15938c0984e5SSebastian Reichel { 15948c0984e5SSebastian Reichel int tval; 15958c0984e5SSebastian Reichel 15968c0984e5SSebastian Reichel tval = bq27xxx_read(di, BQ27XXX_REG_AP, false); 15978c0984e5SSebastian Reichel if (tval < 0) { 15988c0984e5SSebastian Reichel dev_err(di->dev, "error reading average power register %02x: %d\n", 15998c0984e5SSebastian Reichel BQ27XXX_REG_AP, tval); 16008c0984e5SSebastian Reichel return tval; 16018c0984e5SSebastian Reichel } 16028c0984e5SSebastian Reichel 16033a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16048c0984e5SSebastian Reichel return (tval * BQ27XXX_POWER_CONSTANT) / BQ27XXX_RS; 16058c0984e5SSebastian Reichel else 16068c0984e5SSebastian Reichel return tval; 16078c0984e5SSebastian Reichel } 16088c0984e5SSebastian Reichel 16098c0984e5SSebastian Reichel /* 16108c0984e5SSebastian Reichel * Returns true if a battery over temperature condition is detected 16118c0984e5SSebastian Reichel */ 16128c0984e5SSebastian Reichel static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) 16138c0984e5SSebastian Reichel { 16143a731c64SLiam Breck if (di->opts & BQ27XXX_O_OTDC) 16158c0984e5SSebastian Reichel return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD); 16163a731c64SLiam Breck if (di->opts & BQ27XXX_O_UTOT) 16178c0984e5SSebastian Reichel return flags & BQ27XXX_FLAG_OT; 16183a731c64SLiam Breck 16198c0984e5SSebastian Reichel return false; 16208c0984e5SSebastian Reichel } 16218c0984e5SSebastian Reichel 16228c0984e5SSebastian Reichel /* 16238c0984e5SSebastian Reichel * Returns true if a battery under temperature condition is detected 16248c0984e5SSebastian Reichel */ 16258c0984e5SSebastian Reichel static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags) 16268c0984e5SSebastian Reichel { 16273a731c64SLiam Breck if (di->opts & BQ27XXX_O_UTOT) 16288c0984e5SSebastian Reichel return flags & BQ27XXX_FLAG_UT; 16298c0984e5SSebastian Reichel 16308c0984e5SSebastian Reichel return false; 16318c0984e5SSebastian Reichel } 16328c0984e5SSebastian Reichel 16338c0984e5SSebastian Reichel /* 16348c0984e5SSebastian Reichel * Returns true if a low state of charge condition is detected 16358c0984e5SSebastian Reichel */ 16368c0984e5SSebastian Reichel static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) 16378c0984e5SSebastian Reichel { 16383a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16398c0984e5SSebastian Reichel return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF); 16406f24ff97SDan Murphy else if (di->opts & BQ27Z561_O_BITS) 16416f24ff97SDan Murphy return flags & BQ27Z561_FLAG_FDC; 16428c0984e5SSebastian Reichel else 16438c0984e5SSebastian Reichel return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); 16448c0984e5SSebastian Reichel } 16458c0984e5SSebastian Reichel 16468c0984e5SSebastian Reichel static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) 16478c0984e5SSebastian Reichel { 16488c0984e5SSebastian Reichel /* Unlikely but important to return first */ 16499b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags))) 16508c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_OVERHEAT; 16519b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_undertemp(di, di->cache.flags))) 16528c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_COLD; 16539b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_dead(di, di->cache.flags))) 16548c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_DEAD; 16558c0984e5SSebastian Reichel 16568c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_GOOD; 16578c0984e5SSebastian Reichel } 16588c0984e5SSebastian Reichel 16598c0984e5SSebastian Reichel void bq27xxx_battery_update(struct bq27xxx_device_info *di) 16608c0984e5SSebastian Reichel { 16618c0984e5SSebastian Reichel struct bq27xxx_reg_cache cache = {0, }; 16623a731c64SLiam Breck bool has_ci_flag = di->opts & BQ27XXX_O_ZERO; 16633a731c64SLiam Breck bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; 16648c0984e5SSebastian Reichel 16658c0984e5SSebastian Reichel cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); 16668c0984e5SSebastian Reichel if ((cache.flags & 0xff) == 0xff) 16678c0984e5SSebastian Reichel cache.flags = -1; /* read error */ 16688c0984e5SSebastian Reichel if (cache.flags >= 0) { 16698c0984e5SSebastian Reichel cache.temperature = bq27xxx_battery_read_temperature(di); 16708c0984e5SSebastian Reichel if (has_ci_flag && (cache.flags & BQ27000_FLAG_CI)) { 16718c0984e5SSebastian Reichel dev_info_once(di->dev, "battery is not calibrated! ignoring capacity values\n"); 16728c0984e5SSebastian Reichel cache.capacity = -ENODATA; 16738c0984e5SSebastian Reichel cache.energy = -ENODATA; 16748c0984e5SSebastian Reichel cache.time_to_empty = -ENODATA; 16758c0984e5SSebastian Reichel cache.time_to_empty_avg = -ENODATA; 16768c0984e5SSebastian Reichel cache.time_to_full = -ENODATA; 16778c0984e5SSebastian Reichel cache.charge_full = -ENODATA; 16788c0984e5SSebastian Reichel cache.health = -ENODATA; 16798c0984e5SSebastian Reichel } else { 16808c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) 16818c0984e5SSebastian Reichel cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); 16828c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) 16838c0984e5SSebastian Reichel cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); 16848c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) 16858c0984e5SSebastian Reichel cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); 16866f24ff97SDan Murphy 16878c0984e5SSebastian Reichel cache.charge_full = bq27xxx_battery_read_fcc(di); 16888c0984e5SSebastian Reichel cache.capacity = bq27xxx_battery_read_soc(di); 16898c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) 16908c0984e5SSebastian Reichel cache.energy = bq27xxx_battery_read_energy(di); 16919b2c945fSArthur Demchenkov di->cache.flags = cache.flags; 16928c0984e5SSebastian Reichel cache.health = bq27xxx_battery_read_health(di); 16938c0984e5SSebastian Reichel } 16948c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) 16958c0984e5SSebastian Reichel cache.cycle_count = bq27xxx_battery_read_cyct(di); 16968c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_AP] != INVALID_REG_ADDR) 16978c0984e5SSebastian Reichel cache.power_avg = bq27xxx_battery_read_pwr_avg(di); 16988c0984e5SSebastian Reichel 16998c0984e5SSebastian Reichel /* We only have to read charge design full once */ 17008c0984e5SSebastian Reichel if (di->charge_design_full <= 0) 17018c0984e5SSebastian Reichel di->charge_design_full = bq27xxx_battery_read_dcap(di); 17028c0984e5SSebastian Reichel } 17038c0984e5SSebastian Reichel 1704243f8ffcSKrzysztof Kozlowski if ((di->cache.capacity != cache.capacity) || 1705243f8ffcSKrzysztof Kozlowski (di->cache.flags != cache.flags)) 17068c0984e5SSebastian Reichel power_supply_changed(di->bat); 17078c0984e5SSebastian Reichel 17088c0984e5SSebastian Reichel if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) 17098c0984e5SSebastian Reichel di->cache = cache; 17108c0984e5SSebastian Reichel 17118c0984e5SSebastian Reichel di->last_update = jiffies; 17128c0984e5SSebastian Reichel } 17138c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_update); 17148c0984e5SSebastian Reichel 17158c0984e5SSebastian Reichel static void bq27xxx_battery_poll(struct work_struct *work) 17168c0984e5SSebastian Reichel { 17178c0984e5SSebastian Reichel struct bq27xxx_device_info *di = 17188c0984e5SSebastian Reichel container_of(work, struct bq27xxx_device_info, 17198c0984e5SSebastian Reichel work.work); 17208c0984e5SSebastian Reichel 17218c0984e5SSebastian Reichel bq27xxx_battery_update(di); 17228c0984e5SSebastian Reichel 17238c0984e5SSebastian Reichel if (poll_interval > 0) 17248c0984e5SSebastian Reichel schedule_delayed_work(&di->work, poll_interval * HZ); 17258c0984e5SSebastian Reichel } 17268c0984e5SSebastian Reichel 17278c0984e5SSebastian Reichel /* 17288c0984e5SSebastian Reichel * Return the battery average current in µA 17298c0984e5SSebastian Reichel * Note that current can be negative signed as well 17308c0984e5SSebastian Reichel * Or 0 if something fails. 17318c0984e5SSebastian Reichel */ 17328c0984e5SSebastian Reichel static int bq27xxx_battery_current(struct bq27xxx_device_info *di, 17338c0984e5SSebastian Reichel union power_supply_propval *val) 17348c0984e5SSebastian Reichel { 17358c0984e5SSebastian Reichel int curr; 17368c0984e5SSebastian Reichel int flags; 17378c0984e5SSebastian Reichel 17388c0984e5SSebastian Reichel curr = bq27xxx_read(di, BQ27XXX_REG_AI, false); 17398c0984e5SSebastian Reichel if (curr < 0) { 17408c0984e5SSebastian Reichel dev_err(di->dev, "error reading current\n"); 17418c0984e5SSebastian Reichel return curr; 17428c0984e5SSebastian Reichel } 17438c0984e5SSebastian Reichel 17443a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 1745e4a404a0SH. Nikolaus Schaller flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); 17468c0984e5SSebastian Reichel if (flags & BQ27000_FLAG_CHGS) { 17478c0984e5SSebastian Reichel dev_dbg(di->dev, "negative current!\n"); 17488c0984e5SSebastian Reichel curr = -curr; 17498c0984e5SSebastian Reichel } 17508c0984e5SSebastian Reichel 17518c0984e5SSebastian Reichel val->intval = curr * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 17528c0984e5SSebastian Reichel } else { 17538c0984e5SSebastian Reichel /* Other gauges return signed value */ 17548c0984e5SSebastian Reichel val->intval = (int)((s16)curr) * 1000; 17558c0984e5SSebastian Reichel } 17568c0984e5SSebastian Reichel 17578c0984e5SSebastian Reichel return 0; 17588c0984e5SSebastian Reichel } 17598c0984e5SSebastian Reichel 17608c0984e5SSebastian Reichel static int bq27xxx_battery_status(struct bq27xxx_device_info *di, 17618c0984e5SSebastian Reichel union power_supply_propval *val) 17628c0984e5SSebastian Reichel { 17638c0984e5SSebastian Reichel int status; 17648c0984e5SSebastian Reichel 17653a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 17668c0984e5SSebastian Reichel if (di->cache.flags & BQ27000_FLAG_FC) 17678c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_FULL; 17688c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_CHGS) 17698c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_CHARGING; 17708c0984e5SSebastian Reichel else 17718c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_DISCHARGING; 17726f24ff97SDan Murphy } else if (di->opts & BQ27Z561_O_BITS) { 17736f24ff97SDan Murphy if (di->cache.flags & BQ27Z561_FLAG_FC) 17746f24ff97SDan Murphy status = POWER_SUPPLY_STATUS_FULL; 17756f24ff97SDan Murphy else if (di->cache.flags & BQ27Z561_FLAG_DIS_CH) 17766f24ff97SDan Murphy status = POWER_SUPPLY_STATUS_DISCHARGING; 17776f24ff97SDan Murphy else 17786f24ff97SDan Murphy status = POWER_SUPPLY_STATUS_CHARGING; 17798c0984e5SSebastian Reichel } else { 17808c0984e5SSebastian Reichel if (di->cache.flags & BQ27XXX_FLAG_FC) 17818c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_FULL; 17828c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_DSC) 17838c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_DISCHARGING; 17848c0984e5SSebastian Reichel else 17858c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_CHARGING; 17868c0984e5SSebastian Reichel } 17878c0984e5SSebastian Reichel 17887bf738baSKrzysztof Kozlowski if ((status == POWER_SUPPLY_STATUS_DISCHARGING) && 17897bf738baSKrzysztof Kozlowski (power_supply_am_i_supplied(di->bat) > 0)) 17907bf738baSKrzysztof Kozlowski status = POWER_SUPPLY_STATUS_NOT_CHARGING; 17917bf738baSKrzysztof Kozlowski 17928c0984e5SSebastian Reichel val->intval = status; 17938c0984e5SSebastian Reichel 17948c0984e5SSebastian Reichel return 0; 17958c0984e5SSebastian Reichel } 17968c0984e5SSebastian Reichel 17978c0984e5SSebastian Reichel static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, 17988c0984e5SSebastian Reichel union power_supply_propval *val) 17998c0984e5SSebastian Reichel { 18008c0984e5SSebastian Reichel int level; 18018c0984e5SSebastian Reichel 18023a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 18038c0984e5SSebastian Reichel if (di->cache.flags & BQ27000_FLAG_FC) 18048c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 18058c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_EDV1) 18068c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 18078c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_EDVF) 18088c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 18098c0984e5SSebastian Reichel else 18108c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 18116f24ff97SDan Murphy } else if (di->opts & BQ27Z561_O_BITS) { 18126f24ff97SDan Murphy if (di->cache.flags & BQ27Z561_FLAG_FC) 18136f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 18146f24ff97SDan Murphy else if (di->cache.flags & BQ27Z561_FLAG_FDC) 18156f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 18166f24ff97SDan Murphy else 18176f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 18188c0984e5SSebastian Reichel } else { 18198c0984e5SSebastian Reichel if (di->cache.flags & BQ27XXX_FLAG_FC) 18208c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 18218c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_SOC1) 18228c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 18238c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_SOCF) 18248c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 18258c0984e5SSebastian Reichel else 18268c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 18278c0984e5SSebastian Reichel } 18288c0984e5SSebastian Reichel 18298c0984e5SSebastian Reichel val->intval = level; 18308c0984e5SSebastian Reichel 18318c0984e5SSebastian Reichel return 0; 18328c0984e5SSebastian Reichel } 18338c0984e5SSebastian Reichel 18348c0984e5SSebastian Reichel /* 18358c0984e5SSebastian Reichel * Return the battery Voltage in millivolts 18368c0984e5SSebastian Reichel * Or < 0 if something fails. 18378c0984e5SSebastian Reichel */ 18388c0984e5SSebastian Reichel static int bq27xxx_battery_voltage(struct bq27xxx_device_info *di, 18398c0984e5SSebastian Reichel union power_supply_propval *val) 18408c0984e5SSebastian Reichel { 18418c0984e5SSebastian Reichel int volt; 18428c0984e5SSebastian Reichel 18438c0984e5SSebastian Reichel volt = bq27xxx_read(di, BQ27XXX_REG_VOLT, false); 18448c0984e5SSebastian Reichel if (volt < 0) { 18458c0984e5SSebastian Reichel dev_err(di->dev, "error reading voltage\n"); 18468c0984e5SSebastian Reichel return volt; 18478c0984e5SSebastian Reichel } 18488c0984e5SSebastian Reichel 18498c0984e5SSebastian Reichel val->intval = volt * 1000; 18508c0984e5SSebastian Reichel 18518c0984e5SSebastian Reichel return 0; 18528c0984e5SSebastian Reichel } 18538c0984e5SSebastian Reichel 18548c0984e5SSebastian Reichel static int bq27xxx_simple_value(int value, 18558c0984e5SSebastian Reichel union power_supply_propval *val) 18568c0984e5SSebastian Reichel { 18578c0984e5SSebastian Reichel if (value < 0) 18588c0984e5SSebastian Reichel return value; 18598c0984e5SSebastian Reichel 18608c0984e5SSebastian Reichel val->intval = value; 18618c0984e5SSebastian Reichel 18628c0984e5SSebastian Reichel return 0; 18638c0984e5SSebastian Reichel } 18648c0984e5SSebastian Reichel 18658c0984e5SSebastian Reichel static int bq27xxx_battery_get_property(struct power_supply *psy, 18668c0984e5SSebastian Reichel enum power_supply_property psp, 18678c0984e5SSebastian Reichel union power_supply_propval *val) 18688c0984e5SSebastian Reichel { 18698c0984e5SSebastian Reichel int ret = 0; 18708c0984e5SSebastian Reichel struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 18718c0984e5SSebastian Reichel 18728c0984e5SSebastian Reichel mutex_lock(&di->lock); 18738c0984e5SSebastian Reichel if (time_is_before_jiffies(di->last_update + 5 * HZ)) { 18748c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 18758c0984e5SSebastian Reichel bq27xxx_battery_poll(&di->work.work); 18768c0984e5SSebastian Reichel } 18778c0984e5SSebastian Reichel mutex_unlock(&di->lock); 18788c0984e5SSebastian Reichel 18798c0984e5SSebastian Reichel if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) 18808c0984e5SSebastian Reichel return -ENODEV; 18818c0984e5SSebastian Reichel 18828c0984e5SSebastian Reichel switch (psp) { 18838c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 18848c0984e5SSebastian Reichel ret = bq27xxx_battery_status(di, val); 18858c0984e5SSebastian Reichel break; 18868c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 18878c0984e5SSebastian Reichel ret = bq27xxx_battery_voltage(di, val); 18888c0984e5SSebastian Reichel break; 18898c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 18908c0984e5SSebastian Reichel val->intval = di->cache.flags < 0 ? 0 : 1; 18918c0984e5SSebastian Reichel break; 18928c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 18938c0984e5SSebastian Reichel ret = bq27xxx_battery_current(di, val); 18948c0984e5SSebastian Reichel break; 18958c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY: 18968c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.capacity, val); 18978c0984e5SSebastian Reichel break; 18988c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 18998c0984e5SSebastian Reichel ret = bq27xxx_battery_capacity_level(di, val); 19008c0984e5SSebastian Reichel break; 19018c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP: 19028c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.temperature, val); 19038c0984e5SSebastian Reichel if (ret == 0) 19048c0984e5SSebastian Reichel val->intval -= 2731; /* convert decidegree k to c */ 19058c0984e5SSebastian Reichel break; 19068c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 19078c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_empty, val); 19088c0984e5SSebastian Reichel break; 19098c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 19108c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_empty_avg, val); 19118c0984e5SSebastian Reichel break; 19128c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 19138c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_full, val); 19148c0984e5SSebastian Reichel break; 19158c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TECHNOLOGY: 19168c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 19178c0984e5SSebastian Reichel break; 19188c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_NOW: 19198c0984e5SSebastian Reichel ret = bq27xxx_simple_value(bq27xxx_battery_read_nac(di), val); 19208c0984e5SSebastian Reichel break; 19218c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL: 19228c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.charge_full, val); 19238c0984e5SSebastian Reichel break; 19248c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 19258c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->charge_design_full, val); 19268c0984e5SSebastian Reichel break; 1927ccce4409SLiam Breck /* 1928ccce4409SLiam Breck * TODO: Implement these to make registers set from 1929ccce4409SLiam Breck * power_supply_battery_info visible in sysfs. 1930ccce4409SLiam Breck */ 1931ccce4409SLiam Breck case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 1932ccce4409SLiam Breck case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 1933ccce4409SLiam Breck return -EINVAL; 19348c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CYCLE_COUNT: 19358c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.cycle_count, val); 19368c0984e5SSebastian Reichel break; 19378c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ENERGY_NOW: 19388c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.energy, val); 19398c0984e5SSebastian Reichel break; 19408c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_POWER_AVG: 19418c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.power_avg, val); 19428c0984e5SSebastian Reichel break; 19438c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 19448c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.health, val); 19458c0984e5SSebastian Reichel break; 19468c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 19478c0984e5SSebastian Reichel val->strval = BQ27XXX_MANUFACTURER; 19488c0984e5SSebastian Reichel break; 19498c0984e5SSebastian Reichel default: 19508c0984e5SSebastian Reichel return -EINVAL; 19518c0984e5SSebastian Reichel } 19528c0984e5SSebastian Reichel 19538c0984e5SSebastian Reichel return ret; 19548c0984e5SSebastian Reichel } 19558c0984e5SSebastian Reichel 19568c0984e5SSebastian Reichel static void bq27xxx_external_power_changed(struct power_supply *psy) 19578c0984e5SSebastian Reichel { 19588c0984e5SSebastian Reichel struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 19598c0984e5SSebastian Reichel 19608c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 19618c0984e5SSebastian Reichel schedule_delayed_work(&di->work, 0); 19628c0984e5SSebastian Reichel } 19638c0984e5SSebastian Reichel 19648c0984e5SSebastian Reichel int bq27xxx_battery_setup(struct bq27xxx_device_info *di) 19658c0984e5SSebastian Reichel { 19668c0984e5SSebastian Reichel struct power_supply_desc *psy_desc; 1967ccce4409SLiam Breck struct power_supply_config psy_cfg = { 1968ccce4409SLiam Breck .of_node = di->dev->of_node, 1969ccce4409SLiam Breck .drv_data = di, 1970ccce4409SLiam Breck }; 19718c0984e5SSebastian Reichel 19728c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); 19738c0984e5SSebastian Reichel mutex_init(&di->lock); 19743a731c64SLiam Breck 19759aade6d8SLiam Breck di->regs = bq27xxx_chip_data[di->chip].regs; 197605045379SLiam Breck di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key; 197705045379SLiam Breck di->dm_regs = bq27xxx_chip_data[di->chip].dm_regs; 19783a731c64SLiam Breck di->opts = bq27xxx_chip_data[di->chip].opts; 19798c0984e5SSebastian Reichel 19808c0984e5SSebastian Reichel psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL); 19818c0984e5SSebastian Reichel if (!psy_desc) 19828c0984e5SSebastian Reichel return -ENOMEM; 19838c0984e5SSebastian Reichel 19848c0984e5SSebastian Reichel psy_desc->name = di->name; 19858c0984e5SSebastian Reichel psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; 19869aade6d8SLiam Breck psy_desc->properties = bq27xxx_chip_data[di->chip].props; 19879aade6d8SLiam Breck psy_desc->num_properties = bq27xxx_chip_data[di->chip].props_size; 19888c0984e5SSebastian Reichel psy_desc->get_property = bq27xxx_battery_get_property; 19898c0984e5SSebastian Reichel psy_desc->external_power_changed = bq27xxx_external_power_changed; 19908c0984e5SSebastian Reichel 19918c0984e5SSebastian Reichel di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); 19924024810cSKrzysztof Kozlowski if (IS_ERR(di->bat)) 19934024810cSKrzysztof Kozlowski return dev_err_probe(di->dev, PTR_ERR(di->bat), 19944024810cSKrzysztof Kozlowski "failed to register battery\n"); 19958c0984e5SSebastian Reichel 1996ccce4409SLiam Breck bq27xxx_battery_settings(di); 19978c0984e5SSebastian Reichel bq27xxx_battery_update(di); 19988c0984e5SSebastian Reichel 19991d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 20001d72706fSMatt Ranostay list_add(&di->list, &bq27xxx_battery_devices); 20011d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 20021d72706fSMatt Ranostay 20038c0984e5SSebastian Reichel return 0; 20048c0984e5SSebastian Reichel } 20058c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_setup); 20068c0984e5SSebastian Reichel 20078c0984e5SSebastian Reichel void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) 20088c0984e5SSebastian Reichel { 20098c0984e5SSebastian Reichel /* 20108c0984e5SSebastian Reichel * power_supply_unregister call bq27xxx_battery_get_property which 20118c0984e5SSebastian Reichel * call bq27xxx_battery_poll. 20128c0984e5SSebastian Reichel * Make sure that bq27xxx_battery_poll will not call 20138c0984e5SSebastian Reichel * schedule_delayed_work again after unregister (which cause OOPS). 20148c0984e5SSebastian Reichel */ 20158c0984e5SSebastian Reichel poll_interval = 0; 20168c0984e5SSebastian Reichel 20178c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 20188c0984e5SSebastian Reichel 20198c0984e5SSebastian Reichel power_supply_unregister(di->bat); 20208c0984e5SSebastian Reichel 20211d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 20221d72706fSMatt Ranostay list_del(&di->list); 20231d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 20241d72706fSMatt Ranostay 20258c0984e5SSebastian Reichel mutex_destroy(&di->lock); 20268c0984e5SSebastian Reichel } 20278c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); 20288c0984e5SSebastian Reichel 20298c0984e5SSebastian Reichel MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 20308c0984e5SSebastian Reichel MODULE_DESCRIPTION("BQ27xxx battery monitor driver"); 20318c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 2032