18c0984e5SSebastian Reichel /* 28c0984e5SSebastian Reichel * BQ27xxx battery driver 38c0984e5SSebastian Reichel * 48c0984e5SSebastian Reichel * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> 58c0984e5SSebastian Reichel * Copyright (C) 2008 Eurotech S.p.A. <info@eurotech.it> 68c0984e5SSebastian Reichel * Copyright (C) 2010-2011 Lars-Peter Clausen <lars@metafoo.de> 7149ed3d4SPali Rohár * Copyright (C) 2011 Pali Rohár <pali@kernel.org> 80670c9b3SLiam Breck * Copyright (C) 2017 Liam Breck <kernel@networkimprov.net> 98c0984e5SSebastian Reichel * 108c0984e5SSebastian Reichel * Based on a previous work by Copyright (C) 2008 Texas Instruments, Inc. 118c0984e5SSebastian Reichel * 128c0984e5SSebastian Reichel * This package is free software; you can redistribute it and/or modify 138c0984e5SSebastian Reichel * it under the terms of the GNU General Public License version 2 as 148c0984e5SSebastian Reichel * published by the Free Software Foundation. 158c0984e5SSebastian Reichel * 168c0984e5SSebastian Reichel * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 178c0984e5SSebastian Reichel * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 188c0984e5SSebastian Reichel * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198c0984e5SSebastian Reichel * 208c0984e5SSebastian Reichel * Datasheets: 2181bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27000 2281bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27200 2381bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27010 2481bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27210 2581bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27500 2681bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27510-g1 2781bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27510-g2 2881bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27510-g3 2981bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g1 3081bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g2 3181bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g3 3281bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27520-g4 3381bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27530-g1 3481bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27531-g1 3581bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27541-g1 3681bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27542-g1 3781bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27546-g1 3881bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27742-g1 3981bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27545-g1 4081bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27421-g1 4181bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27425-g1 4281bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27426 4381bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27411-g1 4481bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27441-g1 4581bd45fcSAlexander A. Klimov * https://www.ti.com/product/bq27621-g1 466f24ff97SDan Murphy * https://www.ti.com/product/bq27z561 47*707d678aSDan Murphy * https://www.ti.com/product/bq28z610 488c0984e5SSebastian Reichel */ 498c0984e5SSebastian Reichel 508c0984e5SSebastian Reichel #include <linux/device.h> 518c0984e5SSebastian Reichel #include <linux/module.h> 521d72706fSMatt Ranostay #include <linux/mutex.h> 538c0984e5SSebastian Reichel #include <linux/param.h> 548c0984e5SSebastian Reichel #include <linux/jiffies.h> 558c0984e5SSebastian Reichel #include <linux/workqueue.h> 568c0984e5SSebastian Reichel #include <linux/delay.h> 578c0984e5SSebastian Reichel #include <linux/platform_device.h> 588c0984e5SSebastian Reichel #include <linux/power_supply.h> 598c0984e5SSebastian Reichel #include <linux/slab.h> 608c0984e5SSebastian Reichel #include <linux/of.h> 618c0984e5SSebastian Reichel 628c0984e5SSebastian Reichel #include <linux/power/bq27xxx_battery.h> 638c0984e5SSebastian Reichel 648c0984e5SSebastian Reichel #define BQ27XXX_MANUFACTURER "Texas Instruments" 658c0984e5SSebastian Reichel 668c0984e5SSebastian Reichel /* BQ27XXX Flags */ 678c0984e5SSebastian Reichel #define BQ27XXX_FLAG_DSC BIT(0) 688c0984e5SSebastian Reichel #define BQ27XXX_FLAG_SOCF BIT(1) /* State-of-Charge threshold final */ 698c0984e5SSebastian Reichel #define BQ27XXX_FLAG_SOC1 BIT(2) /* State-of-Charge threshold 1 */ 700670c9b3SLiam Breck #define BQ27XXX_FLAG_CFGUP BIT(4) 718c0984e5SSebastian Reichel #define BQ27XXX_FLAG_FC BIT(9) 728c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OTD BIT(14) 738c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OTC BIT(15) 748c0984e5SSebastian Reichel #define BQ27XXX_FLAG_UT BIT(14) 758c0984e5SSebastian Reichel #define BQ27XXX_FLAG_OT BIT(15) 768c0984e5SSebastian Reichel 778c0984e5SSebastian Reichel /* BQ27000 has different layout for Flags register */ 788c0984e5SSebastian Reichel #define BQ27000_FLAG_EDVF BIT(0) /* Final End-of-Discharge-Voltage flag */ 798c0984e5SSebastian Reichel #define BQ27000_FLAG_EDV1 BIT(1) /* First End-of-Discharge-Voltage flag */ 808c0984e5SSebastian Reichel #define BQ27000_FLAG_CI BIT(4) /* Capacity Inaccurate flag */ 818c0984e5SSebastian Reichel #define BQ27000_FLAG_FC BIT(5) 828c0984e5SSebastian Reichel #define BQ27000_FLAG_CHGS BIT(7) /* Charge state flag */ 838c0984e5SSebastian Reichel 846f24ff97SDan Murphy /* BQ27Z561 has different layout for Flags register */ 856f24ff97SDan Murphy #define BQ27Z561_FLAG_FDC BIT(4) /* Battery fully discharged */ 866f24ff97SDan Murphy #define BQ27Z561_FLAG_FC BIT(5) /* Battery fully charged */ 876f24ff97SDan Murphy #define BQ27Z561_FLAG_DIS_CH BIT(6) /* Battery is discharging */ 886f24ff97SDan Murphy 890670c9b3SLiam Breck /* control register params */ 900670c9b3SLiam Breck #define BQ27XXX_SEALED 0x20 910670c9b3SLiam Breck #define BQ27XXX_SET_CFGUPDATE 0x13 920670c9b3SLiam Breck #define BQ27XXX_SOFT_RESET 0x42 930670c9b3SLiam Breck #define BQ27XXX_RESET 0x41 940670c9b3SLiam Breck 958c0984e5SSebastian Reichel #define BQ27XXX_RS (20) /* Resistor sense mOhm */ 968c0984e5SSebastian Reichel #define BQ27XXX_POWER_CONSTANT (29200) /* 29.2 µV^2 * 1000 */ 978c0984e5SSebastian Reichel #define BQ27XXX_CURRENT_CONSTANT (3570) /* 3.57 µV * 1000 */ 988c0984e5SSebastian Reichel 998c0984e5SSebastian Reichel #define INVALID_REG_ADDR 0xff 1008c0984e5SSebastian Reichel 1018c0984e5SSebastian Reichel /* 1028c0984e5SSebastian Reichel * bq27xxx_reg_index - Register names 1038c0984e5SSebastian Reichel * 1048c0984e5SSebastian Reichel * These are indexes into a device's register mapping array. 1058c0984e5SSebastian Reichel */ 1068c0984e5SSebastian Reichel 1078c0984e5SSebastian Reichel enum bq27xxx_reg_index { 1088c0984e5SSebastian Reichel BQ27XXX_REG_CTRL = 0, /* Control */ 1098c0984e5SSebastian Reichel BQ27XXX_REG_TEMP, /* Temperature */ 1108c0984e5SSebastian Reichel BQ27XXX_REG_INT_TEMP, /* Internal Temperature */ 1118c0984e5SSebastian Reichel BQ27XXX_REG_VOLT, /* Voltage */ 1128c0984e5SSebastian Reichel BQ27XXX_REG_AI, /* Average Current */ 1138c0984e5SSebastian Reichel BQ27XXX_REG_FLAGS, /* Flags */ 1148c0984e5SSebastian Reichel BQ27XXX_REG_TTE, /* Time-to-Empty */ 1158c0984e5SSebastian Reichel BQ27XXX_REG_TTF, /* Time-to-Full */ 1168c0984e5SSebastian Reichel BQ27XXX_REG_TTES, /* Time-to-Empty Standby */ 1178c0984e5SSebastian Reichel BQ27XXX_REG_TTECP, /* Time-to-Empty at Constant Power */ 1188c0984e5SSebastian Reichel BQ27XXX_REG_NAC, /* Nominal Available Capacity */ 1198c0984e5SSebastian Reichel BQ27XXX_REG_FCC, /* Full Charge Capacity */ 1208c0984e5SSebastian Reichel BQ27XXX_REG_CYCT, /* Cycle Count */ 1218c0984e5SSebastian Reichel BQ27XXX_REG_AE, /* Available Energy */ 1228c0984e5SSebastian Reichel BQ27XXX_REG_SOC, /* State-of-Charge */ 1238c0984e5SSebastian Reichel BQ27XXX_REG_DCAP, /* Design Capacity */ 1248c0984e5SSebastian Reichel BQ27XXX_REG_AP, /* Average Power */ 1250670c9b3SLiam Breck BQ27XXX_DM_CTRL, /* Block Data Control */ 1260670c9b3SLiam Breck BQ27XXX_DM_CLASS, /* Data Class */ 1270670c9b3SLiam Breck BQ27XXX_DM_BLOCK, /* Data Block */ 1280670c9b3SLiam Breck BQ27XXX_DM_DATA, /* Block Data */ 1290670c9b3SLiam Breck BQ27XXX_DM_CKSUM, /* Block Data Checksum */ 1308c0984e5SSebastian Reichel BQ27XXX_REG_MAX, /* sentinel */ 1318c0984e5SSebastian Reichel }; 1328c0984e5SSebastian Reichel 1330670c9b3SLiam Breck #define BQ27XXX_DM_REG_ROWS \ 1340670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = 0x61, \ 1350670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = 0x3e, \ 1360670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = 0x3f, \ 1370670c9b3SLiam Breck [BQ27XXX_DM_DATA] = 0x40, \ 1380670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = 0x60 1390670c9b3SLiam Breck 1408c0984e5SSebastian Reichel /* Register mappings */ 1419aade6d8SLiam Breck static u8 1429aade6d8SLiam Breck bq27000_regs[BQ27XXX_REG_MAX] = { 1438c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1448c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1458c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 1468c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1478c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1488c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1498c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1508c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = 0x18, 1518c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1c, 1528c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = 0x26, 1538c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1548c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1558c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1568c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = 0x22, 1578c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x0b, 1588c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x76, 1598c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 1600670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 1610670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 1620670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 1630670c9b3SLiam Breck [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 1640670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 1658c0984e5SSebastian Reichel }, 1669aade6d8SLiam Breck bq27010_regs[BQ27XXX_REG_MAX] = { 1678c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1688c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1698c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 1708c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1718c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1728c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1738c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1748c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = 0x18, 1758c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1c, 1768c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = 0x26, 1778c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 1788c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 1798c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 1808c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 1818c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x0b, 1828c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x76, 1838c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 1840670c9b3SLiam Breck [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 1850670c9b3SLiam Breck [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 1860670c9b3SLiam Breck [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 1870670c9b3SLiam Breck [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 1880670c9b3SLiam Breck [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 1898c0984e5SSebastian Reichel }, 1909aade6d8SLiam Breck bq2750x_regs[BQ27XXX_REG_MAX] = { 1918c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 1928c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 1938c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 1948c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 1958c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 1968c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 1978c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 1988c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 1998c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = 0x1a, 2008c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 2018c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 2028c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 2038c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 2048c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 2058c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 2068c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 2078c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 2080670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 2098c0984e5SSebastian Reichel }, 2101059361fSLiam Breck #define bq2751x_regs bq27510g3_regs 2111059361fSLiam Breck #define bq2752x_regs bq27510g3_regs 2129aade6d8SLiam Breck bq27500_regs[BQ27XXX_REG_MAX] = { 21332833635SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 21432833635SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 21532833635SChris Lapa [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 21632833635SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 21732833635SChris Lapa [BQ27XXX_REG_AI] = 0x14, 21832833635SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 21932833635SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 22032833635SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 22132833635SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 22232833635SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 22332833635SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 22432833635SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 22532833635SChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 22632833635SChris Lapa [BQ27XXX_REG_AE] = 0x22, 22732833635SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 22832833635SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 22932833635SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2300670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 23132833635SChris Lapa }, 2321059361fSLiam Breck #define bq27510g1_regs bq27500_regs 2331059361fSLiam Breck #define bq27510g2_regs bq27500_regs 2349aade6d8SLiam Breck bq27510g3_regs[BQ27XXX_REG_MAX] = { 23571375aa7SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 23671375aa7SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 23771375aa7SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x28, 23871375aa7SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 23971375aa7SChris Lapa [BQ27XXX_REG_AI] = 0x14, 24071375aa7SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 24171375aa7SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 24271375aa7SChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 24371375aa7SChris Lapa [BQ27XXX_REG_TTES] = 0x1a, 24471375aa7SChris Lapa [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 24571375aa7SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 24671375aa7SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 24771375aa7SChris Lapa [BQ27XXX_REG_CYCT] = 0x1e, 24871375aa7SChris Lapa [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 24971375aa7SChris Lapa [BQ27XXX_REG_SOC] = 0x20, 25071375aa7SChris Lapa [BQ27XXX_REG_DCAP] = 0x2e, 25171375aa7SChris Lapa [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 2520670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 25371375aa7SChris Lapa }, 2549aade6d8SLiam Breck bq27520g1_regs[BQ27XXX_REG_MAX] = { 25568f2a813SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 25668f2a813SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 25768f2a813SChris Lapa [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 25868f2a813SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 25968f2a813SChris Lapa [BQ27XXX_REG_AI] = 0x14, 26068f2a813SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 26168f2a813SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 26268f2a813SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 26368f2a813SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 26468f2a813SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 26568f2a813SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 26668f2a813SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 26768f2a813SChris Lapa [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 26868f2a813SChris Lapa [BQ27XXX_REG_AE] = 0x22, 26968f2a813SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 27068f2a813SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 27168f2a813SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2720670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 27368f2a813SChris Lapa }, 2749aade6d8SLiam Breck bq27520g2_regs[BQ27XXX_REG_MAX] = { 275a5deb9a9SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 276a5deb9a9SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 277a5deb9a9SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x36, 278a5deb9a9SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 279a5deb9a9SChris Lapa [BQ27XXX_REG_AI] = 0x14, 280a5deb9a9SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 281a5deb9a9SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 282a5deb9a9SChris Lapa [BQ27XXX_REG_TTF] = 0x18, 283a5deb9a9SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 284a5deb9a9SChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 285a5deb9a9SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 286a5deb9a9SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 287a5deb9a9SChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 288a5deb9a9SChris Lapa [BQ27XXX_REG_AE] = 0x22, 289a5deb9a9SChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 290a5deb9a9SChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 291a5deb9a9SChris Lapa [BQ27XXX_REG_AP] = 0x24, 2920670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 293a5deb9a9SChris Lapa }, 2949aade6d8SLiam Breck bq27520g3_regs[BQ27XXX_REG_MAX] = { 295825e915bSChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 296825e915bSChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 297825e915bSChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x36, 298825e915bSChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 299825e915bSChris Lapa [BQ27XXX_REG_AI] = 0x14, 300825e915bSChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 301825e915bSChris Lapa [BQ27XXX_REG_TTE] = 0x16, 302825e915bSChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 303825e915bSChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 304825e915bSChris Lapa [BQ27XXX_REG_TTECP] = 0x26, 305825e915bSChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 306825e915bSChris Lapa [BQ27XXX_REG_FCC] = 0x12, 307825e915bSChris Lapa [BQ27XXX_REG_CYCT] = 0x2a, 308825e915bSChris Lapa [BQ27XXX_REG_AE] = 0x22, 309825e915bSChris Lapa [BQ27XXX_REG_SOC] = 0x2c, 310825e915bSChris Lapa [BQ27XXX_REG_DCAP] = 0x3c, 311825e915bSChris Lapa [BQ27XXX_REG_AP] = 0x24, 3120670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 313825e915bSChris Lapa }, 3149aade6d8SLiam Breck bq27520g4_regs[BQ27XXX_REG_MAX] = { 3158835cae5SChris Lapa [BQ27XXX_REG_CTRL] = 0x00, 3168835cae5SChris Lapa [BQ27XXX_REG_TEMP] = 0x06, 3178835cae5SChris Lapa [BQ27XXX_REG_INT_TEMP] = 0x28, 3188835cae5SChris Lapa [BQ27XXX_REG_VOLT] = 0x08, 3198835cae5SChris Lapa [BQ27XXX_REG_AI] = 0x14, 3208835cae5SChris Lapa [BQ27XXX_REG_FLAGS] = 0x0a, 3218835cae5SChris Lapa [BQ27XXX_REG_TTE] = 0x16, 3228835cae5SChris Lapa [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3238835cae5SChris Lapa [BQ27XXX_REG_TTES] = 0x1c, 3248835cae5SChris Lapa [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3258835cae5SChris Lapa [BQ27XXX_REG_NAC] = 0x0c, 3268835cae5SChris Lapa [BQ27XXX_REG_FCC] = 0x12, 3278835cae5SChris Lapa [BQ27XXX_REG_CYCT] = 0x1e, 3288835cae5SChris Lapa [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3298835cae5SChris Lapa [BQ27XXX_REG_SOC] = 0x20, 3308835cae5SChris Lapa [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 3318835cae5SChris Lapa [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 3320670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3338835cae5SChris Lapa }, 33470a39e10SPavel Machek bq27521_regs[BQ27XXX_REG_MAX] = { 33570a39e10SPavel Machek [BQ27XXX_REG_CTRL] = 0x02, 33670a39e10SPavel Machek [BQ27XXX_REG_TEMP] = 0x0a, 33770a39e10SPavel Machek [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 33870a39e10SPavel Machek [BQ27XXX_REG_VOLT] = 0x0c, 33970a39e10SPavel Machek [BQ27XXX_REG_AI] = 0x0e, 34070a39e10SPavel Machek [BQ27XXX_REG_FLAGS] = 0x08, 34170a39e10SPavel Machek [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, 34270a39e10SPavel Machek [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 34370a39e10SPavel Machek [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 34470a39e10SPavel Machek [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 34570a39e10SPavel Machek [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 34670a39e10SPavel Machek [BQ27XXX_REG_FCC] = INVALID_REG_ADDR, 34770a39e10SPavel Machek [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 34870a39e10SPavel Machek [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 34970a39e10SPavel Machek [BQ27XXX_REG_SOC] = INVALID_REG_ADDR, 35070a39e10SPavel Machek [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 35170a39e10SPavel Machek [BQ27XXX_REG_AP] = INVALID_REG_ADDR, 35270a39e10SPavel Machek [BQ27XXX_DM_CTRL] = INVALID_REG_ADDR, 35370a39e10SPavel Machek [BQ27XXX_DM_CLASS] = INVALID_REG_ADDR, 35470a39e10SPavel Machek [BQ27XXX_DM_BLOCK] = INVALID_REG_ADDR, 35570a39e10SPavel Machek [BQ27XXX_DM_DATA] = INVALID_REG_ADDR, 35670a39e10SPavel Machek [BQ27XXX_DM_CKSUM] = INVALID_REG_ADDR, 35770a39e10SPavel Machek }, 3589aade6d8SLiam Breck bq27530_regs[BQ27XXX_REG_MAX] = { 3598c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3608c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3618c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x32, 3628c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 3638c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 3648c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 3658c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 3668c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3678c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 3688c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3698c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 3708c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 3718c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 3728c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3738c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 3748c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 3758c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 3760670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3778c0984e5SSebastian Reichel }, 3783a731c64SLiam Breck #define bq27531_regs bq27530_regs 3799aade6d8SLiam Breck bq27541_regs[BQ27XXX_REG_MAX] = { 3808c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 3818c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 3828c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 3838c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 3848c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 3858c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 3868c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 3878c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 3888c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 3898c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 3908c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 3918c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 3928c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 3938c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 3948c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 3958c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 3968c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 3970670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 3988c0984e5SSebastian Reichel }, 3993a731c64SLiam Breck #define bq27542_regs bq27541_regs 4003a731c64SLiam Breck #define bq27546_regs bq27541_regs 4013a731c64SLiam Breck #define bq27742_regs bq27541_regs 4029aade6d8SLiam Breck bq27545_regs[BQ27XXX_REG_MAX] = { 4038c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 4048c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x06, 4058c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x28, 4068c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x08, 4078c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x14, 4088c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x0a, 4098c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = 0x16, 4108c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 4118c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4128c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4138c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x0c, 4148c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x12, 4158c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = 0x2a, 4168c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4178c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x2c, 4188c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = INVALID_REG_ADDR, 4198c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x24, 4200670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4218c0984e5SSebastian Reichel }, 4229aade6d8SLiam Breck bq27421_regs[BQ27XXX_REG_MAX] = { 4238c0984e5SSebastian Reichel [BQ27XXX_REG_CTRL] = 0x00, 4248c0984e5SSebastian Reichel [BQ27XXX_REG_TEMP] = 0x02, 4258c0984e5SSebastian Reichel [BQ27XXX_REG_INT_TEMP] = 0x1e, 4268c0984e5SSebastian Reichel [BQ27XXX_REG_VOLT] = 0x04, 4278c0984e5SSebastian Reichel [BQ27XXX_REG_AI] = 0x10, 4288c0984e5SSebastian Reichel [BQ27XXX_REG_FLAGS] = 0x06, 4298c0984e5SSebastian Reichel [BQ27XXX_REG_TTE] = INVALID_REG_ADDR, 4308c0984e5SSebastian Reichel [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, 4318c0984e5SSebastian Reichel [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4328c0984e5SSebastian Reichel [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4338c0984e5SSebastian Reichel [BQ27XXX_REG_NAC] = 0x08, 4348c0984e5SSebastian Reichel [BQ27XXX_REG_FCC] = 0x0e, 4358c0984e5SSebastian Reichel [BQ27XXX_REG_CYCT] = INVALID_REG_ADDR, 4368c0984e5SSebastian Reichel [BQ27XXX_REG_AE] = INVALID_REG_ADDR, 4378c0984e5SSebastian Reichel [BQ27XXX_REG_SOC] = 0x1c, 4388c0984e5SSebastian Reichel [BQ27XXX_REG_DCAP] = 0x3c, 4398c0984e5SSebastian Reichel [BQ27XXX_REG_AP] = 0x18, 4400670c9b3SLiam Breck BQ27XXX_DM_REG_ROWS, 4416f24ff97SDan Murphy }, 442457b42f0SLiu Xiang #define bq27411_regs bq27421_regs 4433a731c64SLiam Breck #define bq27425_regs bq27421_regs 4445ef6a160SAndrew F. Davis #define bq27426_regs bq27421_regs 4453a731c64SLiam Breck #define bq27441_regs bq27421_regs 4463a731c64SLiam Breck #define bq27621_regs bq27421_regs 4476f24ff97SDan Murphy bq27z561_regs[BQ27XXX_REG_MAX] = { 4486f24ff97SDan Murphy [BQ27XXX_REG_CTRL] = 0x00, 4496f24ff97SDan Murphy [BQ27XXX_REG_TEMP] = 0x06, 4506f24ff97SDan Murphy [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 4516f24ff97SDan Murphy [BQ27XXX_REG_VOLT] = 0x08, 4526f24ff97SDan Murphy [BQ27XXX_REG_AI] = 0x14, 4536f24ff97SDan Murphy [BQ27XXX_REG_FLAGS] = 0x0a, 4546f24ff97SDan Murphy [BQ27XXX_REG_TTE] = 0x16, 4556f24ff97SDan Murphy [BQ27XXX_REG_TTF] = 0x18, 4566f24ff97SDan Murphy [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 4576f24ff97SDan Murphy [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 4586f24ff97SDan Murphy [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 4596f24ff97SDan Murphy [BQ27XXX_REG_FCC] = 0x12, 4606f24ff97SDan Murphy [BQ27XXX_REG_CYCT] = 0x2a, 4616f24ff97SDan Murphy [BQ27XXX_REG_AE] = 0x22, 4626f24ff97SDan Murphy [BQ27XXX_REG_SOC] = 0x2c, 4636f24ff97SDan Murphy [BQ27XXX_REG_DCAP] = 0x3c, 4646f24ff97SDan Murphy [BQ27XXX_REG_AP] = 0x22, 4656f24ff97SDan Murphy BQ27XXX_DM_REG_ROWS, 466*707d678aSDan Murphy }, 467*707d678aSDan Murphy bq28z610_regs[BQ27XXX_REG_MAX] = { 468*707d678aSDan Murphy [BQ27XXX_REG_CTRL] = 0x00, 469*707d678aSDan Murphy [BQ27XXX_REG_TEMP] = 0x06, 470*707d678aSDan Murphy [BQ27XXX_REG_INT_TEMP] = INVALID_REG_ADDR, 471*707d678aSDan Murphy [BQ27XXX_REG_VOLT] = 0x08, 472*707d678aSDan Murphy [BQ27XXX_REG_AI] = 0x14, 473*707d678aSDan Murphy [BQ27XXX_REG_FLAGS] = 0x0a, 474*707d678aSDan Murphy [BQ27XXX_REG_TTE] = 0x16, 475*707d678aSDan Murphy [BQ27XXX_REG_TTF] = 0x18, 476*707d678aSDan Murphy [BQ27XXX_REG_TTES] = INVALID_REG_ADDR, 477*707d678aSDan Murphy [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, 478*707d678aSDan Murphy [BQ27XXX_REG_NAC] = INVALID_REG_ADDR, 479*707d678aSDan Murphy [BQ27XXX_REG_FCC] = 0x12, 480*707d678aSDan Murphy [BQ27XXX_REG_CYCT] = 0x2a, 481*707d678aSDan Murphy [BQ27XXX_REG_AE] = 0x22, 482*707d678aSDan Murphy [BQ27XXX_REG_SOC] = 0x2c, 483*707d678aSDan Murphy [BQ27XXX_REG_DCAP] = 0x3c, 484*707d678aSDan Murphy [BQ27XXX_REG_AP] = 0x22, 485*707d678aSDan Murphy BQ27XXX_DM_REG_ROWS, 4866f24ff97SDan Murphy }; 4878c0984e5SSebastian Reichel 4889aade6d8SLiam Breck static enum power_supply_property bq27000_props[] = { 4898c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 4908c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 4918c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 4928c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 4938c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 4948c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 4958c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 4968c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 4978c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 4988c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 4998c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 5008c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 5018c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 5028c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 5038c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 5048c0984e5SSebastian Reichel POWER_SUPPLY_PROP_ENERGY_NOW, 5058c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 5068c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 5078c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 5088c0984e5SSebastian Reichel }; 5098c0984e5SSebastian Reichel 5109aade6d8SLiam Breck static enum power_supply_property bq27010_props[] = { 5118c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 5128c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 5138c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 5148c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 5158c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 5168c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 5178c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 5188c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 5198c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, 5208c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 5218c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 5228c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 5238c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 5248c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 5258c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 5268c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 5278c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 5288c0984e5SSebastian Reichel }; 5298c0984e5SSebastian Reichel 5301059361fSLiam Breck #define bq2750x_props bq27510g3_props 5311059361fSLiam Breck #define bq2751x_props bq27510g3_props 5321059361fSLiam Breck #define bq2752x_props bq27510g3_props 5333bee9ea1SAndrew F. Davis 5349aade6d8SLiam Breck static enum power_supply_property bq27500_props[] = { 53532833635SChris Lapa POWER_SUPPLY_PROP_STATUS, 53632833635SChris Lapa POWER_SUPPLY_PROP_PRESENT, 53732833635SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 53832833635SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 53932833635SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 54032833635SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 54132833635SChris Lapa POWER_SUPPLY_PROP_TEMP, 54232833635SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 54332833635SChris Lapa POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 54432833635SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 54532833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 54632833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 54732833635SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 54832833635SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 54932833635SChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 55032833635SChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 55132833635SChris Lapa POWER_SUPPLY_PROP_HEALTH, 55232833635SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 55332833635SChris Lapa }; 5541059361fSLiam Breck #define bq27510g1_props bq27500_props 5551059361fSLiam Breck #define bq27510g2_props bq27500_props 556698a2bf5SChris Lapa 5579aade6d8SLiam Breck static enum power_supply_property bq27510g3_props[] = { 55871375aa7SChris Lapa POWER_SUPPLY_PROP_STATUS, 55971375aa7SChris Lapa POWER_SUPPLY_PROP_PRESENT, 56071375aa7SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 56171375aa7SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 56271375aa7SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 56371375aa7SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 56471375aa7SChris Lapa POWER_SUPPLY_PROP_TEMP, 56571375aa7SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 56671375aa7SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 56771375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 56871375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 56971375aa7SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 57071375aa7SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 57171375aa7SChris Lapa POWER_SUPPLY_PROP_HEALTH, 57271375aa7SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 57371375aa7SChris Lapa }; 57471375aa7SChris Lapa 5759aade6d8SLiam Breck static enum power_supply_property bq27520g1_props[] = { 57668f2a813SChris Lapa POWER_SUPPLY_PROP_STATUS, 57768f2a813SChris Lapa POWER_SUPPLY_PROP_PRESENT, 57868f2a813SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 57968f2a813SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 58068f2a813SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 58168f2a813SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 58268f2a813SChris Lapa POWER_SUPPLY_PROP_TEMP, 58368f2a813SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 58468f2a813SChris Lapa POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 58568f2a813SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 58668f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 58768f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 58868f2a813SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 58968f2a813SChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 59068f2a813SChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 59168f2a813SChris Lapa POWER_SUPPLY_PROP_HEALTH, 59268f2a813SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 59368f2a813SChris Lapa }; 59468f2a813SChris Lapa 5951059361fSLiam Breck #define bq27520g2_props bq27500_props 596a5deb9a9SChris Lapa 5979aade6d8SLiam Breck static enum power_supply_property bq27520g3_props[] = { 598825e915bSChris Lapa POWER_SUPPLY_PROP_STATUS, 599825e915bSChris Lapa POWER_SUPPLY_PROP_PRESENT, 600825e915bSChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 601825e915bSChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 602825e915bSChris Lapa POWER_SUPPLY_PROP_CAPACITY, 603825e915bSChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 604825e915bSChris Lapa POWER_SUPPLY_PROP_TEMP, 605825e915bSChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 606825e915bSChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 607825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 608825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 609825e915bSChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 610825e915bSChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 611825e915bSChris Lapa POWER_SUPPLY_PROP_ENERGY_NOW, 612825e915bSChris Lapa POWER_SUPPLY_PROP_POWER_AVG, 613825e915bSChris Lapa POWER_SUPPLY_PROP_HEALTH, 614825e915bSChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 615825e915bSChris Lapa }; 616825e915bSChris Lapa 6179aade6d8SLiam Breck static enum power_supply_property bq27520g4_props[] = { 6188835cae5SChris Lapa POWER_SUPPLY_PROP_STATUS, 6198835cae5SChris Lapa POWER_SUPPLY_PROP_PRESENT, 6208835cae5SChris Lapa POWER_SUPPLY_PROP_VOLTAGE_NOW, 6218835cae5SChris Lapa POWER_SUPPLY_PROP_CURRENT_NOW, 6228835cae5SChris Lapa POWER_SUPPLY_PROP_CAPACITY, 6238835cae5SChris Lapa POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6248835cae5SChris Lapa POWER_SUPPLY_PROP_TEMP, 6258835cae5SChris Lapa POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6268835cae5SChris Lapa POWER_SUPPLY_PROP_TECHNOLOGY, 6278835cae5SChris Lapa POWER_SUPPLY_PROP_CHARGE_FULL, 6288835cae5SChris Lapa POWER_SUPPLY_PROP_CHARGE_NOW, 6298835cae5SChris Lapa POWER_SUPPLY_PROP_CYCLE_COUNT, 6308835cae5SChris Lapa POWER_SUPPLY_PROP_HEALTH, 6318835cae5SChris Lapa POWER_SUPPLY_PROP_MANUFACTURER, 6328835cae5SChris Lapa }; 6338835cae5SChris Lapa 63470a39e10SPavel Machek static enum power_supply_property bq27521_props[] = { 63570a39e10SPavel Machek POWER_SUPPLY_PROP_STATUS, 63670a39e10SPavel Machek POWER_SUPPLY_PROP_PRESENT, 63770a39e10SPavel Machek POWER_SUPPLY_PROP_VOLTAGE_NOW, 63870a39e10SPavel Machek POWER_SUPPLY_PROP_CURRENT_NOW, 63970a39e10SPavel Machek POWER_SUPPLY_PROP_TEMP, 64070a39e10SPavel Machek POWER_SUPPLY_PROP_TECHNOLOGY, 64170a39e10SPavel Machek }; 64270a39e10SPavel Machek 6439aade6d8SLiam Breck static enum power_supply_property bq27530_props[] = { 6448c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6458c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6468c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6478c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 6488c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 6498c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6508c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 6518c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6528c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 6538c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 6548c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 6558c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 6568c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 6578c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 6588c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 6598c0984e5SSebastian Reichel }; 6603a731c64SLiam Breck #define bq27531_props bq27530_props 6618c0984e5SSebastian Reichel 6629aade6d8SLiam Breck static enum power_supply_property bq27541_props[] = { 6638c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6648c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6658c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6668c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 6678c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 6688c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6698c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 6708c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6718c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 6728c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 6738c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 6748c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 6758c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 6768c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 6778c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 6788c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 6798c0984e5SSebastian Reichel }; 6803a731c64SLiam Breck #define bq27542_props bq27541_props 6813a731c64SLiam Breck #define bq27546_props bq27541_props 6823a731c64SLiam Breck #define bq27742_props bq27541_props 6838c0984e5SSebastian Reichel 6849aade6d8SLiam Breck static enum power_supply_property bq27545_props[] = { 6858c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 6868c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 6878c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 6888c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 6898c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 6908c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 6918c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 6928c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 6938c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 6948c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 6958c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 6968c0984e5SSebastian Reichel POWER_SUPPLY_PROP_HEALTH, 6978c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CYCLE_COUNT, 6988c0984e5SSebastian Reichel POWER_SUPPLY_PROP_POWER_AVG, 6998c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7008c0984e5SSebastian Reichel }; 7018c0984e5SSebastian Reichel 7029aade6d8SLiam Breck static enum power_supply_property bq27421_props[] = { 7038c0984e5SSebastian Reichel POWER_SUPPLY_PROP_STATUS, 7048c0984e5SSebastian Reichel POWER_SUPPLY_PROP_PRESENT, 7058c0984e5SSebastian Reichel POWER_SUPPLY_PROP_VOLTAGE_NOW, 7068c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CURRENT_NOW, 7078c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY, 7088c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7098c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TEMP, 7108c0984e5SSebastian Reichel POWER_SUPPLY_PROP_TECHNOLOGY, 7118c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL, 7128c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_NOW, 7138c0984e5SSebastian Reichel POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7148c0984e5SSebastian Reichel POWER_SUPPLY_PROP_MANUFACTURER, 7158c0984e5SSebastian Reichel }; 716457b42f0SLiu Xiang #define bq27411_props bq27421_props 7173a731c64SLiam Breck #define bq27425_props bq27421_props 7185ef6a160SAndrew F. Davis #define bq27426_props bq27421_props 7193a731c64SLiam Breck #define bq27441_props bq27421_props 7203a731c64SLiam Breck #define bq27621_props bq27421_props 7218c0984e5SSebastian Reichel 7226f24ff97SDan Murphy static enum power_supply_property bq27z561_props[] = { 7236f24ff97SDan Murphy POWER_SUPPLY_PROP_STATUS, 7246f24ff97SDan Murphy POWER_SUPPLY_PROP_PRESENT, 7256f24ff97SDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 7266f24ff97SDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 7276f24ff97SDan Murphy POWER_SUPPLY_PROP_CAPACITY, 7286f24ff97SDan Murphy POWER_SUPPLY_PROP_CAPACITY_LEVEL, 7296f24ff97SDan Murphy POWER_SUPPLY_PROP_TEMP, 7306f24ff97SDan Murphy POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 7316f24ff97SDan Murphy POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 7326f24ff97SDan Murphy POWER_SUPPLY_PROP_TECHNOLOGY, 7336f24ff97SDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL, 7346f24ff97SDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 7356f24ff97SDan Murphy POWER_SUPPLY_PROP_CYCLE_COUNT, 7366f24ff97SDan Murphy POWER_SUPPLY_PROP_POWER_AVG, 7376f24ff97SDan Murphy POWER_SUPPLY_PROP_HEALTH, 7386f24ff97SDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 7396f24ff97SDan Murphy }; 7406f24ff97SDan Murphy 741*707d678aSDan Murphy static enum power_supply_property bq28z610_props[] = { 742*707d678aSDan Murphy POWER_SUPPLY_PROP_STATUS, 743*707d678aSDan Murphy POWER_SUPPLY_PROP_PRESENT, 744*707d678aSDan Murphy POWER_SUPPLY_PROP_VOLTAGE_NOW, 745*707d678aSDan Murphy POWER_SUPPLY_PROP_CURRENT_NOW, 746*707d678aSDan Murphy POWER_SUPPLY_PROP_CAPACITY, 747*707d678aSDan Murphy POWER_SUPPLY_PROP_CAPACITY_LEVEL, 748*707d678aSDan Murphy POWER_SUPPLY_PROP_TEMP, 749*707d678aSDan Murphy POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, 750*707d678aSDan Murphy POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, 751*707d678aSDan Murphy POWER_SUPPLY_PROP_TECHNOLOGY, 752*707d678aSDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL, 753*707d678aSDan Murphy POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, 754*707d678aSDan Murphy POWER_SUPPLY_PROP_CYCLE_COUNT, 755*707d678aSDan Murphy POWER_SUPPLY_PROP_POWER_AVG, 756*707d678aSDan Murphy POWER_SUPPLY_PROP_HEALTH, 757*707d678aSDan Murphy POWER_SUPPLY_PROP_MANUFACTURER, 758*707d678aSDan Murphy }; 759*707d678aSDan Murphy 76005045379SLiam Breck struct bq27xxx_dm_reg { 76105045379SLiam Breck u8 subclass_id; 76205045379SLiam Breck u8 offset; 76305045379SLiam Breck u8 bytes; 76405045379SLiam Breck u16 min, max; 76505045379SLiam Breck }; 76605045379SLiam Breck 76705045379SLiam Breck enum bq27xxx_dm_reg_id { 76805045379SLiam Breck BQ27XXX_DM_DESIGN_CAPACITY = 0, 76905045379SLiam Breck BQ27XXX_DM_DESIGN_ENERGY, 77005045379SLiam Breck BQ27XXX_DM_TERMINATE_VOLTAGE, 77105045379SLiam Breck }; 77205045379SLiam Breck 77305045379SLiam Breck #define bq27000_dm_regs 0 77405045379SLiam Breck #define bq27010_dm_regs 0 77505045379SLiam Breck #define bq2750x_dm_regs 0 77605045379SLiam Breck #define bq2751x_dm_regs 0 77705045379SLiam Breck #define bq2752x_dm_regs 0 77805045379SLiam Breck 77905045379SLiam Breck #if 0 /* not yet tested */ 78005045379SLiam Breck static struct bq27xxx_dm_reg bq27500_dm_regs[] = { 78105045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 10, 2, 0, 65535 }, 78205045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { }, /* missing on chip */ 78305045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 48, 2, 1000, 32767 }, 78405045379SLiam Breck }; 78505045379SLiam Breck #else 78605045379SLiam Breck #define bq27500_dm_regs 0 78705045379SLiam Breck #endif 78805045379SLiam Breck 78905045379SLiam Breck /* todo create data memory definitions from datasheets and test on chips */ 79005045379SLiam Breck #define bq27510g1_dm_regs 0 79105045379SLiam Breck #define bq27510g2_dm_regs 0 79205045379SLiam Breck #define bq27510g3_dm_regs 0 79305045379SLiam Breck #define bq27520g1_dm_regs 0 79405045379SLiam Breck #define bq27520g2_dm_regs 0 79505045379SLiam Breck #define bq27520g3_dm_regs 0 79605045379SLiam Breck #define bq27520g4_dm_regs 0 79770a39e10SPavel Machek #define bq27521_dm_regs 0 79805045379SLiam Breck #define bq27530_dm_regs 0 79905045379SLiam Breck #define bq27531_dm_regs 0 80005045379SLiam Breck #define bq27541_dm_regs 0 80105045379SLiam Breck #define bq27542_dm_regs 0 80205045379SLiam Breck #define bq27546_dm_regs 0 80305045379SLiam Breck #define bq27742_dm_regs 0 80405045379SLiam Breck 80505045379SLiam Breck #if 0 /* not yet tested */ 80605045379SLiam Breck static struct bq27xxx_dm_reg bq27545_dm_regs[] = { 80705045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 48, 23, 2, 0, 32767 }, 80805045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 48, 25, 2, 0, 32767 }, 80905045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 80, 67, 2, 2800, 3700 }, 81005045379SLiam Breck }; 81105045379SLiam Breck #else 81205045379SLiam Breck #define bq27545_dm_regs 0 81305045379SLiam Breck #endif 81405045379SLiam Breck 815457b42f0SLiu Xiang static struct bq27xxx_dm_reg bq27411_dm_regs[] = { 816457b42f0SLiu Xiang [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 32767 }, 817457b42f0SLiu Xiang [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, 818457b42f0SLiu Xiang [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2800, 3700 }, 819457b42f0SLiu Xiang }; 820457b42f0SLiu Xiang 82105045379SLiam Breck static struct bq27xxx_dm_reg bq27421_dm_regs[] = { 82205045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 10, 2, 0, 8000 }, 82305045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 12, 2, 0, 32767 }, 82405045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 16, 2, 2500, 3700 }, 82505045379SLiam Breck }; 82605045379SLiam Breck 82705045379SLiam Breck static struct bq27xxx_dm_reg bq27425_dm_regs[] = { 82805045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 12, 2, 0, 32767 }, 82905045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 14, 2, 0, 32767 }, 83005045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 18, 2, 2800, 3700 }, 83105045379SLiam Breck }; 83205045379SLiam Breck 8335ef6a160SAndrew F. Davis static struct bq27xxx_dm_reg bq27426_dm_regs[] = { 8345ef6a160SAndrew F. Davis [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 6, 2, 0, 8000 }, 8355ef6a160SAndrew F. Davis [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 8, 2, 0, 32767 }, 8365ef6a160SAndrew F. Davis [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 10, 2, 2500, 3700 }, 8375ef6a160SAndrew F. Davis }; 8385ef6a160SAndrew F. Davis 83905045379SLiam Breck #if 0 /* not yet tested */ 84005045379SLiam Breck #define bq27441_dm_regs bq27421_dm_regs 84105045379SLiam Breck #else 84205045379SLiam Breck #define bq27441_dm_regs 0 84305045379SLiam Breck #endif 84405045379SLiam Breck 84505045379SLiam Breck #if 0 /* not yet tested */ 84605045379SLiam Breck static struct bq27xxx_dm_reg bq27621_dm_regs[] = { 84705045379SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = { 82, 3, 2, 0, 8000 }, 84805045379SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = { 82, 5, 2, 0, 32767 }, 84905045379SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = { 82, 9, 2, 2500, 3700 }, 85005045379SLiam Breck }; 85105045379SLiam Breck #else 85205045379SLiam Breck #define bq27621_dm_regs 0 85305045379SLiam Breck #endif 85405045379SLiam Breck 8556f24ff97SDan Murphy #define bq27z561_dm_regs 0 856*707d678aSDan Murphy #define bq28z610_dm_regs 0 8576f24ff97SDan Murphy 8583a731c64SLiam Breck #define BQ27XXX_O_ZERO 0x00000001 85970a39e10SPavel Machek #define BQ27XXX_O_OTDC 0x00000002 /* has OTC/OTD overtemperature flags */ 86070a39e10SPavel Machek #define BQ27XXX_O_UTOT 0x00000004 /* has OT overtemperature flag */ 86105045379SLiam Breck #define BQ27XXX_O_CFGUP 0x00000008 86205045379SLiam Breck #define BQ27XXX_O_RAM 0x00000010 8636f24ff97SDan Murphy #define BQ27Z561_O_BITS 0x00000020 8643a731c64SLiam Breck 86505045379SLiam Breck #define BQ27XXX_DATA(ref, key, opt) { \ 8663a731c64SLiam Breck .opts = (opt), \ 86705045379SLiam Breck .unseal_key = key, \ 8689aade6d8SLiam Breck .regs = ref##_regs, \ 86905045379SLiam Breck .dm_regs = ref##_dm_regs, \ 8709aade6d8SLiam Breck .props = ref##_props, \ 8719aade6d8SLiam Breck .props_size = ARRAY_SIZE(ref##_props) } 8728c0984e5SSebastian Reichel 8738c0984e5SSebastian Reichel static struct { 8743a731c64SLiam Breck u32 opts; 87505045379SLiam Breck u32 unseal_key; 8769aade6d8SLiam Breck u8 *regs; 87705045379SLiam Breck struct bq27xxx_dm_reg *dm_regs; 8788c0984e5SSebastian Reichel enum power_supply_property *props; 8799aade6d8SLiam Breck size_t props_size; 8809aade6d8SLiam Breck } bq27xxx_chip_data[] = { 88105045379SLiam Breck [BQ27000] = BQ27XXX_DATA(bq27000, 0 , BQ27XXX_O_ZERO), 88205045379SLiam Breck [BQ27010] = BQ27XXX_DATA(bq27010, 0 , BQ27XXX_O_ZERO), 88305045379SLiam Breck [BQ2750X] = BQ27XXX_DATA(bq2750x, 0 , BQ27XXX_O_OTDC), 88405045379SLiam Breck [BQ2751X] = BQ27XXX_DATA(bq2751x, 0 , BQ27XXX_O_OTDC), 88505045379SLiam Breck [BQ2752X] = BQ27XXX_DATA(bq2752x, 0 , BQ27XXX_O_OTDC), 88605045379SLiam Breck [BQ27500] = BQ27XXX_DATA(bq27500, 0x04143672, BQ27XXX_O_OTDC), 88705045379SLiam Breck [BQ27510G1] = BQ27XXX_DATA(bq27510g1, 0 , BQ27XXX_O_OTDC), 88805045379SLiam Breck [BQ27510G2] = BQ27XXX_DATA(bq27510g2, 0 , BQ27XXX_O_OTDC), 88905045379SLiam Breck [BQ27510G3] = BQ27XXX_DATA(bq27510g3, 0 , BQ27XXX_O_OTDC), 89005045379SLiam Breck [BQ27520G1] = BQ27XXX_DATA(bq27520g1, 0 , BQ27XXX_O_OTDC), 89105045379SLiam Breck [BQ27520G2] = BQ27XXX_DATA(bq27520g2, 0 , BQ27XXX_O_OTDC), 89205045379SLiam Breck [BQ27520G3] = BQ27XXX_DATA(bq27520g3, 0 , BQ27XXX_O_OTDC), 89305045379SLiam Breck [BQ27520G4] = BQ27XXX_DATA(bq27520g4, 0 , BQ27XXX_O_OTDC), 89470a39e10SPavel Machek [BQ27521] = BQ27XXX_DATA(bq27521, 0 , 0), 89505045379SLiam Breck [BQ27530] = BQ27XXX_DATA(bq27530, 0 , BQ27XXX_O_UTOT), 89605045379SLiam Breck [BQ27531] = BQ27XXX_DATA(bq27531, 0 , BQ27XXX_O_UTOT), 89705045379SLiam Breck [BQ27541] = BQ27XXX_DATA(bq27541, 0 , BQ27XXX_O_OTDC), 89805045379SLiam Breck [BQ27542] = BQ27XXX_DATA(bq27542, 0 , BQ27XXX_O_OTDC), 89905045379SLiam Breck [BQ27546] = BQ27XXX_DATA(bq27546, 0 , BQ27XXX_O_OTDC), 90005045379SLiam Breck [BQ27742] = BQ27XXX_DATA(bq27742, 0 , BQ27XXX_O_OTDC), 90105045379SLiam Breck [BQ27545] = BQ27XXX_DATA(bq27545, 0x04143672, BQ27XXX_O_OTDC), 902457b42f0SLiu Xiang [BQ27411] = BQ27XXX_DATA(bq27411, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 90305045379SLiam Breck [BQ27421] = BQ27XXX_DATA(bq27421, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 90405045379SLiam Breck [BQ27425] = BQ27XXX_DATA(bq27425, 0x04143672, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP), 9055ef6a160SAndrew F. Davis [BQ27426] = BQ27XXX_DATA(bq27426, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 90605045379SLiam Breck [BQ27441] = BQ27XXX_DATA(bq27441, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 90705045379SLiam Breck [BQ27621] = BQ27XXX_DATA(bq27621, 0x80008000, BQ27XXX_O_UTOT | BQ27XXX_O_CFGUP | BQ27XXX_O_RAM), 9086f24ff97SDan Murphy [BQ27Z561] = BQ27XXX_DATA(bq27z561, 0 , BQ27Z561_O_BITS), 909*707d678aSDan Murphy [BQ28Z610] = BQ27XXX_DATA(bq28z610, 0 , BQ27Z561_O_BITS), 9108c0984e5SSebastian Reichel }; 9118c0984e5SSebastian Reichel 9121d72706fSMatt Ranostay static DEFINE_MUTEX(bq27xxx_list_lock); 9131d72706fSMatt Ranostay static LIST_HEAD(bq27xxx_battery_devices); 9141d72706fSMatt Ranostay 9150670c9b3SLiam Breck #define BQ27XXX_MSLEEP(i) usleep_range((i)*1000, (i)*1000+500) 9160670c9b3SLiam Breck 9170670c9b3SLiam Breck #define BQ27XXX_DM_SZ 32 9180670c9b3SLiam Breck 9190670c9b3SLiam Breck /** 9200670c9b3SLiam Breck * struct bq27xxx_dm_buf - chip data memory buffer 9210670c9b3SLiam Breck * @class: data memory subclass_id 9220670c9b3SLiam Breck * @block: data memory block number 9230670c9b3SLiam Breck * @data: data from/for the block 9240670c9b3SLiam Breck * @has_data: true if data has been filled by read 9250670c9b3SLiam Breck * @dirty: true if data has changed since last read/write 9260670c9b3SLiam Breck * 9270670c9b3SLiam Breck * Encapsulates info required to manage chip data memory blocks. 9280670c9b3SLiam Breck */ 9290670c9b3SLiam Breck struct bq27xxx_dm_buf { 9300670c9b3SLiam Breck u8 class; 9310670c9b3SLiam Breck u8 block; 9320670c9b3SLiam Breck u8 data[BQ27XXX_DM_SZ]; 9330670c9b3SLiam Breck bool has_data, dirty; 9340670c9b3SLiam Breck }; 9350670c9b3SLiam Breck 936ccce4409SLiam Breck #define BQ27XXX_DM_BUF(di, i) { \ 937ccce4409SLiam Breck .class = (di)->dm_regs[i].subclass_id, \ 938ccce4409SLiam Breck .block = (di)->dm_regs[i].offset / BQ27XXX_DM_SZ, \ 939ccce4409SLiam Breck } 940ccce4409SLiam Breck 941ccce4409SLiam Breck static inline u16 *bq27xxx_dm_reg_ptr(struct bq27xxx_dm_buf *buf, 942ccce4409SLiam Breck struct bq27xxx_dm_reg *reg) 943ccce4409SLiam Breck { 944ccce4409SLiam Breck if (buf->class == reg->subclass_id && 945ccce4409SLiam Breck buf->block == reg->offset / BQ27XXX_DM_SZ) 946ccce4409SLiam Breck return (u16 *) (buf->data + reg->offset % BQ27XXX_DM_SZ); 947ccce4409SLiam Breck 948ccce4409SLiam Breck return NULL; 949ccce4409SLiam Breck } 950ccce4409SLiam Breck 951ccce4409SLiam Breck static const char * const bq27xxx_dm_reg_name[] = { 952ccce4409SLiam Breck [BQ27XXX_DM_DESIGN_CAPACITY] = "design-capacity", 953ccce4409SLiam Breck [BQ27XXX_DM_DESIGN_ENERGY] = "design-energy", 954ccce4409SLiam Breck [BQ27XXX_DM_TERMINATE_VOLTAGE] = "terminate-voltage", 955ccce4409SLiam Breck }; 956ccce4409SLiam Breck 957ccce4409SLiam Breck 958ccce4409SLiam Breck static bool bq27xxx_dt_to_nvm = true; 959ccce4409SLiam Breck module_param_named(dt_monitored_battery_updates_nvm, bq27xxx_dt_to_nvm, bool, 0444); 960ccce4409SLiam Breck MODULE_PARM_DESC(dt_monitored_battery_updates_nvm, 961ccce4409SLiam Breck "Devicetree monitored-battery config updates data memory on NVM/flash chips.\n" 962ccce4409SLiam Breck "Users must set this =0 when installing a different type of battery!\n" 963ccce4409SLiam Breck "Default is =1." 964ccce4409SLiam Breck #ifndef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 965ccce4409SLiam Breck "\nSetting this affects future kernel updates, not the current configuration." 966ccce4409SLiam Breck #endif 967ccce4409SLiam Breck ); 9680670c9b3SLiam Breck 9691d72706fSMatt Ranostay static int poll_interval_param_set(const char *val, const struct kernel_param *kp) 9701d72706fSMatt Ranostay { 9711d72706fSMatt Ranostay struct bq27xxx_device_info *di; 972950b6c2dSMatt Ranostay unsigned int prev_val = *(unsigned int *) kp->arg; 9731d72706fSMatt Ranostay int ret; 9741d72706fSMatt Ranostay 9751d72706fSMatt Ranostay ret = param_set_uint(val, kp); 976950b6c2dSMatt Ranostay if (ret < 0 || prev_val == *(unsigned int *) kp->arg) 9771d72706fSMatt Ranostay return ret; 9781d72706fSMatt Ranostay 9791d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 9801d72706fSMatt Ranostay list_for_each_entry(di, &bq27xxx_battery_devices, list) { 9811d72706fSMatt Ranostay cancel_delayed_work_sync(&di->work); 9821d72706fSMatt Ranostay schedule_delayed_work(&di->work, 0); 9831d72706fSMatt Ranostay } 9841d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 9851d72706fSMatt Ranostay 9861d72706fSMatt Ranostay return ret; 9871d72706fSMatt Ranostay } 9881d72706fSMatt Ranostay 9891d72706fSMatt Ranostay static const struct kernel_param_ops param_ops_poll_interval = { 9901d72706fSMatt Ranostay .get = param_get_uint, 9911d72706fSMatt Ranostay .set = poll_interval_param_set, 9921d72706fSMatt Ranostay }; 9931d72706fSMatt Ranostay 9948c0984e5SSebastian Reichel static unsigned int poll_interval = 360; 9951d72706fSMatt Ranostay module_param_cb(poll_interval, ¶m_ops_poll_interval, &poll_interval, 0644); 9968c0984e5SSebastian Reichel MODULE_PARM_DESC(poll_interval, 9978c0984e5SSebastian Reichel "battery poll interval in seconds - 0 disables polling"); 9988c0984e5SSebastian Reichel 9998c0984e5SSebastian Reichel /* 10008c0984e5SSebastian Reichel * Common code for BQ27xxx devices 10018c0984e5SSebastian Reichel */ 10028c0984e5SSebastian Reichel 10038c0984e5SSebastian Reichel static inline int bq27xxx_read(struct bq27xxx_device_info *di, int reg_index, 10048c0984e5SSebastian Reichel bool single) 10058c0984e5SSebastian Reichel { 100614073f66SMatt Ranostay int ret; 100714073f66SMatt Ranostay 10088c0984e5SSebastian Reichel if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 10098c0984e5SSebastian Reichel return -EINVAL; 10108c0984e5SSebastian Reichel 101114073f66SMatt Ranostay ret = di->bus.read(di, di->regs[reg_index], single); 101214073f66SMatt Ranostay if (ret < 0) 101314073f66SMatt Ranostay dev_dbg(di->dev, "failed to read register 0x%02x (index %d)\n", 101414073f66SMatt Ranostay di->regs[reg_index], reg_index); 101514073f66SMatt Ranostay 101614073f66SMatt Ranostay return ret; 101714073f66SMatt Ranostay } 101814073f66SMatt Ranostay 101914073f66SMatt Ranostay static inline int bq27xxx_write(struct bq27xxx_device_info *di, int reg_index, 102014073f66SMatt Ranostay u16 value, bool single) 102114073f66SMatt Ranostay { 102214073f66SMatt Ranostay int ret; 102314073f66SMatt Ranostay 102414073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 102514073f66SMatt Ranostay return -EINVAL; 102614073f66SMatt Ranostay 102714073f66SMatt Ranostay if (!di->bus.write) 102814073f66SMatt Ranostay return -EPERM; 102914073f66SMatt Ranostay 103014073f66SMatt Ranostay ret = di->bus.write(di, di->regs[reg_index], value, single); 103114073f66SMatt Ranostay if (ret < 0) 103214073f66SMatt Ranostay dev_dbg(di->dev, "failed to write register 0x%02x (index %d)\n", 103314073f66SMatt Ranostay di->regs[reg_index], reg_index); 103414073f66SMatt Ranostay 103514073f66SMatt Ranostay return ret; 103614073f66SMatt Ranostay } 103714073f66SMatt Ranostay 103814073f66SMatt Ranostay static inline int bq27xxx_read_block(struct bq27xxx_device_info *di, int reg_index, 103914073f66SMatt Ranostay u8 *data, int len) 104014073f66SMatt Ranostay { 104114073f66SMatt Ranostay int ret; 104214073f66SMatt Ranostay 104314073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 104414073f66SMatt Ranostay return -EINVAL; 104514073f66SMatt Ranostay 104614073f66SMatt Ranostay if (!di->bus.read_bulk) 104714073f66SMatt Ranostay return -EPERM; 104814073f66SMatt Ranostay 104914073f66SMatt Ranostay ret = di->bus.read_bulk(di, di->regs[reg_index], data, len); 105014073f66SMatt Ranostay if (ret < 0) 105114073f66SMatt Ranostay dev_dbg(di->dev, "failed to read_bulk register 0x%02x (index %d)\n", 105214073f66SMatt Ranostay di->regs[reg_index], reg_index); 105314073f66SMatt Ranostay 105414073f66SMatt Ranostay return ret; 105514073f66SMatt Ranostay } 105614073f66SMatt Ranostay 105714073f66SMatt Ranostay static inline int bq27xxx_write_block(struct bq27xxx_device_info *di, int reg_index, 105814073f66SMatt Ranostay u8 *data, int len) 105914073f66SMatt Ranostay { 106014073f66SMatt Ranostay int ret; 106114073f66SMatt Ranostay 106214073f66SMatt Ranostay if (!di || di->regs[reg_index] == INVALID_REG_ADDR) 106314073f66SMatt Ranostay return -EINVAL; 106414073f66SMatt Ranostay 106514073f66SMatt Ranostay if (!di->bus.write_bulk) 106614073f66SMatt Ranostay return -EPERM; 106714073f66SMatt Ranostay 106814073f66SMatt Ranostay ret = di->bus.write_bulk(di, di->regs[reg_index], data, len); 106914073f66SMatt Ranostay if (ret < 0) 107014073f66SMatt Ranostay dev_dbg(di->dev, "failed to write_bulk register 0x%02x (index %d)\n", 107114073f66SMatt Ranostay di->regs[reg_index], reg_index); 107214073f66SMatt Ranostay 107314073f66SMatt Ranostay return ret; 10748c0984e5SSebastian Reichel } 10758c0984e5SSebastian Reichel 10760670c9b3SLiam Breck static int bq27xxx_battery_seal(struct bq27xxx_device_info *di) 10770670c9b3SLiam Breck { 10780670c9b3SLiam Breck int ret; 10790670c9b3SLiam Breck 10800670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_SEALED, false); 10810670c9b3SLiam Breck if (ret < 0) { 10820670c9b3SLiam Breck dev_err(di->dev, "bus error on seal: %d\n", ret); 10830670c9b3SLiam Breck return ret; 10840670c9b3SLiam Breck } 10850670c9b3SLiam Breck 10860670c9b3SLiam Breck return 0; 10870670c9b3SLiam Breck } 10880670c9b3SLiam Breck 10890670c9b3SLiam Breck static int bq27xxx_battery_unseal(struct bq27xxx_device_info *di) 10900670c9b3SLiam Breck { 10910670c9b3SLiam Breck int ret; 10920670c9b3SLiam Breck 10930670c9b3SLiam Breck if (di->unseal_key == 0) { 10940670c9b3SLiam Breck dev_err(di->dev, "unseal failed due to missing key\n"); 10950670c9b3SLiam Breck return -EINVAL; 10960670c9b3SLiam Breck } 10970670c9b3SLiam Breck 10980670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)(di->unseal_key >> 16), false); 10990670c9b3SLiam Breck if (ret < 0) 11000670c9b3SLiam Breck goto out; 11010670c9b3SLiam Breck 11020670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, (u16)di->unseal_key, false); 11030670c9b3SLiam Breck if (ret < 0) 11040670c9b3SLiam Breck goto out; 11050670c9b3SLiam Breck 11060670c9b3SLiam Breck return 0; 11070670c9b3SLiam Breck 11080670c9b3SLiam Breck out: 11090670c9b3SLiam Breck dev_err(di->dev, "bus error on unseal: %d\n", ret); 11100670c9b3SLiam Breck return ret; 11110670c9b3SLiam Breck } 11120670c9b3SLiam Breck 11130670c9b3SLiam Breck static u8 bq27xxx_battery_checksum_dm_block(struct bq27xxx_dm_buf *buf) 11140670c9b3SLiam Breck { 11150670c9b3SLiam Breck u16 sum = 0; 11160670c9b3SLiam Breck int i; 11170670c9b3SLiam Breck 11180670c9b3SLiam Breck for (i = 0; i < BQ27XXX_DM_SZ; i++) 11190670c9b3SLiam Breck sum += buf->data[i]; 11200670c9b3SLiam Breck sum &= 0xff; 11210670c9b3SLiam Breck 11220670c9b3SLiam Breck return 0xff - sum; 11230670c9b3SLiam Breck } 11240670c9b3SLiam Breck 11250670c9b3SLiam Breck static int bq27xxx_battery_read_dm_block(struct bq27xxx_device_info *di, 11260670c9b3SLiam Breck struct bq27xxx_dm_buf *buf) 11270670c9b3SLiam Breck { 11280670c9b3SLiam Breck int ret; 11290670c9b3SLiam Breck 11300670c9b3SLiam Breck buf->has_data = false; 11310670c9b3SLiam Breck 11320670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true); 11330670c9b3SLiam Breck if (ret < 0) 11340670c9b3SLiam Breck goto out; 11350670c9b3SLiam Breck 11360670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true); 11370670c9b3SLiam Breck if (ret < 0) 11380670c9b3SLiam Breck goto out; 11390670c9b3SLiam Breck 11400670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 11410670c9b3SLiam Breck 11420670c9b3SLiam Breck ret = bq27xxx_read_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ); 11430670c9b3SLiam Breck if (ret < 0) 11440670c9b3SLiam Breck goto out; 11450670c9b3SLiam Breck 11460670c9b3SLiam Breck ret = bq27xxx_read(di, BQ27XXX_DM_CKSUM, true); 11470670c9b3SLiam Breck if (ret < 0) 11480670c9b3SLiam Breck goto out; 11490670c9b3SLiam Breck 11500670c9b3SLiam Breck if ((u8)ret != bq27xxx_battery_checksum_dm_block(buf)) { 11510670c9b3SLiam Breck ret = -EINVAL; 11520670c9b3SLiam Breck goto out; 11530670c9b3SLiam Breck } 11540670c9b3SLiam Breck 11550670c9b3SLiam Breck buf->has_data = true; 11560670c9b3SLiam Breck buf->dirty = false; 11570670c9b3SLiam Breck 11580670c9b3SLiam Breck return 0; 11590670c9b3SLiam Breck 11600670c9b3SLiam Breck out: 11610670c9b3SLiam Breck dev_err(di->dev, "bus error reading chip memory: %d\n", ret); 11620670c9b3SLiam Breck return ret; 11630670c9b3SLiam Breck } 11640670c9b3SLiam Breck 1165ccce4409SLiam Breck static void bq27xxx_battery_update_dm_block(struct bq27xxx_device_info *di, 1166ccce4409SLiam Breck struct bq27xxx_dm_buf *buf, 1167ccce4409SLiam Breck enum bq27xxx_dm_reg_id reg_id, 1168ccce4409SLiam Breck unsigned int val) 1169ccce4409SLiam Breck { 1170ccce4409SLiam Breck struct bq27xxx_dm_reg *reg = &di->dm_regs[reg_id]; 1171ccce4409SLiam Breck const char *str = bq27xxx_dm_reg_name[reg_id]; 1172ccce4409SLiam Breck u16 *prev = bq27xxx_dm_reg_ptr(buf, reg); 1173ccce4409SLiam Breck 1174ccce4409SLiam Breck if (prev == NULL) { 1175ccce4409SLiam Breck dev_warn(di->dev, "buffer does not match %s dm spec\n", str); 1176ccce4409SLiam Breck return; 1177ccce4409SLiam Breck } 1178ccce4409SLiam Breck 1179ccce4409SLiam Breck if (reg->bytes != 2) { 1180ccce4409SLiam Breck dev_warn(di->dev, "%s dm spec has unsupported byte size\n", str); 1181ccce4409SLiam Breck return; 1182ccce4409SLiam Breck } 1183ccce4409SLiam Breck 1184ccce4409SLiam Breck if (!buf->has_data) 1185ccce4409SLiam Breck return; 1186ccce4409SLiam Breck 1187ccce4409SLiam Breck if (be16_to_cpup(prev) == val) { 1188ccce4409SLiam Breck dev_info(di->dev, "%s has %u\n", str, val); 1189ccce4409SLiam Breck return; 1190ccce4409SLiam Breck } 1191ccce4409SLiam Breck 1192ccce4409SLiam Breck #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 119305045379SLiam Breck if (!(di->opts & BQ27XXX_O_RAM) && !bq27xxx_dt_to_nvm) { 1194ccce4409SLiam Breck #else 119505045379SLiam Breck if (!(di->opts & BQ27XXX_O_RAM)) { 1196ccce4409SLiam Breck #endif 1197ccce4409SLiam Breck /* devicetree and NVM differ; defer to NVM */ 1198ccce4409SLiam Breck dev_warn(di->dev, "%s has %u; update to %u disallowed " 1199ccce4409SLiam Breck #ifdef CONFIG_BATTERY_BQ27XXX_DT_UPDATES_NVM 1200ccce4409SLiam Breck "by dt_monitored_battery_updates_nvm=0" 1201ccce4409SLiam Breck #else 1202ccce4409SLiam Breck "for flash/NVM data memory" 1203ccce4409SLiam Breck #endif 1204ccce4409SLiam Breck "\n", str, be16_to_cpup(prev), val); 1205ccce4409SLiam Breck return; 1206ccce4409SLiam Breck } 1207ccce4409SLiam Breck 1208ccce4409SLiam Breck dev_info(di->dev, "update %s to %u\n", str, val); 1209ccce4409SLiam Breck 1210ccce4409SLiam Breck *prev = cpu_to_be16(val); 1211ccce4409SLiam Breck buf->dirty = true; 1212ccce4409SLiam Breck } 1213ccce4409SLiam Breck 12140670c9b3SLiam Breck static int bq27xxx_battery_cfgupdate_priv(struct bq27xxx_device_info *di, bool active) 12150670c9b3SLiam Breck { 12160670c9b3SLiam Breck const int limit = 100; 12170670c9b3SLiam Breck u16 cmd = active ? BQ27XXX_SET_CFGUPDATE : BQ27XXX_SOFT_RESET; 12180670c9b3SLiam Breck int ret, try = limit; 12190670c9b3SLiam Breck 12200670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_REG_CTRL, cmd, false); 12210670c9b3SLiam Breck if (ret < 0) 12220670c9b3SLiam Breck return ret; 12230670c9b3SLiam Breck 12240670c9b3SLiam Breck do { 12250670c9b3SLiam Breck BQ27XXX_MSLEEP(25); 12260670c9b3SLiam Breck ret = bq27xxx_read(di, BQ27XXX_REG_FLAGS, false); 12270670c9b3SLiam Breck if (ret < 0) 12280670c9b3SLiam Breck return ret; 12290670c9b3SLiam Breck } while (!!(ret & BQ27XXX_FLAG_CFGUP) != active && --try); 12300670c9b3SLiam Breck 123105045379SLiam Breck if (!try && di->chip != BQ27425) { // 425 has a bug 12320670c9b3SLiam Breck dev_err(di->dev, "timed out waiting for cfgupdate flag %d\n", active); 12330670c9b3SLiam Breck return -EINVAL; 12340670c9b3SLiam Breck } 12350670c9b3SLiam Breck 12360670c9b3SLiam Breck if (limit - try > 3) 12370670c9b3SLiam Breck dev_warn(di->dev, "cfgupdate %d, retries %d\n", active, limit - try); 12380670c9b3SLiam Breck 12390670c9b3SLiam Breck return 0; 12400670c9b3SLiam Breck } 12410670c9b3SLiam Breck 12420670c9b3SLiam Breck static inline int bq27xxx_battery_set_cfgupdate(struct bq27xxx_device_info *di) 12430670c9b3SLiam Breck { 12440670c9b3SLiam Breck int ret = bq27xxx_battery_cfgupdate_priv(di, true); 12450670c9b3SLiam Breck if (ret < 0 && ret != -EINVAL) 12460670c9b3SLiam Breck dev_err(di->dev, "bus error on set_cfgupdate: %d\n", ret); 12470670c9b3SLiam Breck 12480670c9b3SLiam Breck return ret; 12490670c9b3SLiam Breck } 12500670c9b3SLiam Breck 12510670c9b3SLiam Breck static inline int bq27xxx_battery_soft_reset(struct bq27xxx_device_info *di) 12520670c9b3SLiam Breck { 12530670c9b3SLiam Breck int ret = bq27xxx_battery_cfgupdate_priv(di, false); 12540670c9b3SLiam Breck if (ret < 0 && ret != -EINVAL) 12550670c9b3SLiam Breck dev_err(di->dev, "bus error on soft_reset: %d\n", ret); 12560670c9b3SLiam Breck 12570670c9b3SLiam Breck return ret; 12580670c9b3SLiam Breck } 12590670c9b3SLiam Breck 12600670c9b3SLiam Breck static int bq27xxx_battery_write_dm_block(struct bq27xxx_device_info *di, 12610670c9b3SLiam Breck struct bq27xxx_dm_buf *buf) 12620670c9b3SLiam Breck { 126305045379SLiam Breck bool cfgup = di->opts & BQ27XXX_O_CFGUP; 12640670c9b3SLiam Breck int ret; 12650670c9b3SLiam Breck 12660670c9b3SLiam Breck if (!buf->dirty) 12670670c9b3SLiam Breck return 0; 12680670c9b3SLiam Breck 12690670c9b3SLiam Breck if (cfgup) { 12700670c9b3SLiam Breck ret = bq27xxx_battery_set_cfgupdate(di); 12710670c9b3SLiam Breck if (ret < 0) 12720670c9b3SLiam Breck return ret; 12730670c9b3SLiam Breck } 12740670c9b3SLiam Breck 12750670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CTRL, 0, true); 12760670c9b3SLiam Breck if (ret < 0) 12770670c9b3SLiam Breck goto out; 12780670c9b3SLiam Breck 12790670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CLASS, buf->class, true); 12800670c9b3SLiam Breck if (ret < 0) 12810670c9b3SLiam Breck goto out; 12820670c9b3SLiam Breck 12830670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_BLOCK, buf->block, true); 12840670c9b3SLiam Breck if (ret < 0) 12850670c9b3SLiam Breck goto out; 12860670c9b3SLiam Breck 12870670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 12880670c9b3SLiam Breck 12890670c9b3SLiam Breck ret = bq27xxx_write_block(di, BQ27XXX_DM_DATA, buf->data, BQ27XXX_DM_SZ); 12900670c9b3SLiam Breck if (ret < 0) 12910670c9b3SLiam Breck goto out; 12920670c9b3SLiam Breck 12930670c9b3SLiam Breck ret = bq27xxx_write(di, BQ27XXX_DM_CKSUM, 12940670c9b3SLiam Breck bq27xxx_battery_checksum_dm_block(buf), true); 12950670c9b3SLiam Breck if (ret < 0) 12960670c9b3SLiam Breck goto out; 12970670c9b3SLiam Breck 12980670c9b3SLiam Breck /* DO NOT read BQ27XXX_DM_CKSUM here to verify it! That may cause NVM 12990670c9b3SLiam Breck * corruption on the '425 chip (and perhaps others), which can damage 13000670c9b3SLiam Breck * the chip. 13010670c9b3SLiam Breck */ 13020670c9b3SLiam Breck 13030670c9b3SLiam Breck if (cfgup) { 13040670c9b3SLiam Breck BQ27XXX_MSLEEP(1); 13050670c9b3SLiam Breck ret = bq27xxx_battery_soft_reset(di); 13060670c9b3SLiam Breck if (ret < 0) 13070670c9b3SLiam Breck return ret; 13080670c9b3SLiam Breck } else { 13090670c9b3SLiam Breck BQ27XXX_MSLEEP(100); /* flash DM updates in <100ms */ 13100670c9b3SLiam Breck } 13110670c9b3SLiam Breck 13120670c9b3SLiam Breck buf->dirty = false; 13130670c9b3SLiam Breck 13140670c9b3SLiam Breck return 0; 13150670c9b3SLiam Breck 13160670c9b3SLiam Breck out: 13170670c9b3SLiam Breck if (cfgup) 13180670c9b3SLiam Breck bq27xxx_battery_soft_reset(di); 13190670c9b3SLiam Breck 13200670c9b3SLiam Breck dev_err(di->dev, "bus error writing chip memory: %d\n", ret); 13210670c9b3SLiam Breck return ret; 13220670c9b3SLiam Breck } 13230670c9b3SLiam Breck 1324ccce4409SLiam Breck static void bq27xxx_battery_set_config(struct bq27xxx_device_info *di, 1325ccce4409SLiam Breck struct power_supply_battery_info *info) 1326ccce4409SLiam Breck { 1327ccce4409SLiam Breck struct bq27xxx_dm_buf bd = BQ27XXX_DM_BUF(di, BQ27XXX_DM_DESIGN_CAPACITY); 1328ccce4409SLiam Breck struct bq27xxx_dm_buf bt = BQ27XXX_DM_BUF(di, BQ27XXX_DM_TERMINATE_VOLTAGE); 1329ccce4409SLiam Breck bool updated; 1330ccce4409SLiam Breck 1331ccce4409SLiam Breck if (bq27xxx_battery_unseal(di) < 0) 1332ccce4409SLiam Breck return; 1333ccce4409SLiam Breck 1334ccce4409SLiam Breck if (info->charge_full_design_uah != -EINVAL && 1335ccce4409SLiam Breck info->energy_full_design_uwh != -EINVAL) { 1336ccce4409SLiam Breck bq27xxx_battery_read_dm_block(di, &bd); 1337ccce4409SLiam Breck /* assume design energy & capacity are in same block */ 1338ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, &bd, 1339ccce4409SLiam Breck BQ27XXX_DM_DESIGN_CAPACITY, 1340ccce4409SLiam Breck info->charge_full_design_uah / 1000); 1341ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, &bd, 1342ccce4409SLiam Breck BQ27XXX_DM_DESIGN_ENERGY, 1343ccce4409SLiam Breck info->energy_full_design_uwh / 1000); 1344ccce4409SLiam Breck } 1345ccce4409SLiam Breck 1346ccce4409SLiam Breck if (info->voltage_min_design_uv != -EINVAL) { 1347ccce4409SLiam Breck bool same = bd.class == bt.class && bd.block == bt.block; 1348ccce4409SLiam Breck if (!same) 1349ccce4409SLiam Breck bq27xxx_battery_read_dm_block(di, &bt); 1350ccce4409SLiam Breck bq27xxx_battery_update_dm_block(di, same ? &bd : &bt, 1351ccce4409SLiam Breck BQ27XXX_DM_TERMINATE_VOLTAGE, 1352ccce4409SLiam Breck info->voltage_min_design_uv / 1000); 1353ccce4409SLiam Breck } 1354ccce4409SLiam Breck 1355ccce4409SLiam Breck updated = bd.dirty || bt.dirty; 1356ccce4409SLiam Breck 1357ccce4409SLiam Breck bq27xxx_battery_write_dm_block(di, &bd); 1358ccce4409SLiam Breck bq27xxx_battery_write_dm_block(di, &bt); 1359ccce4409SLiam Breck 1360ccce4409SLiam Breck bq27xxx_battery_seal(di); 1361ccce4409SLiam Breck 136205045379SLiam Breck if (updated && !(di->opts & BQ27XXX_O_CFGUP)) { 1363ccce4409SLiam Breck bq27xxx_write(di, BQ27XXX_REG_CTRL, BQ27XXX_RESET, false); 1364ccce4409SLiam Breck BQ27XXX_MSLEEP(300); /* reset time is not documented */ 1365ccce4409SLiam Breck } 1366ccce4409SLiam Breck /* assume bq27xxx_battery_update() is called hereafter */ 1367ccce4409SLiam Breck } 1368ccce4409SLiam Breck 1369ccce4409SLiam Breck static void bq27xxx_battery_settings(struct bq27xxx_device_info *di) 1370ccce4409SLiam Breck { 1371ccce4409SLiam Breck struct power_supply_battery_info info = {}; 1372ccce4409SLiam Breck unsigned int min, max; 1373ccce4409SLiam Breck 1374ccce4409SLiam Breck if (power_supply_get_battery_info(di->bat, &info) < 0) 1375ccce4409SLiam Breck return; 1376ccce4409SLiam Breck 1377ccce4409SLiam Breck if (!di->dm_regs) { 1378ccce4409SLiam Breck dev_warn(di->dev, "data memory update not supported for chip\n"); 1379ccce4409SLiam Breck return; 1380ccce4409SLiam Breck } 1381ccce4409SLiam Breck 1382ccce4409SLiam Breck if (info.energy_full_design_uwh != info.charge_full_design_uah) { 1383ccce4409SLiam Breck if (info.energy_full_design_uwh == -EINVAL) 1384ccce4409SLiam Breck dev_warn(di->dev, "missing battery:energy-full-design-microwatt-hours\n"); 1385ccce4409SLiam Breck else if (info.charge_full_design_uah == -EINVAL) 1386ccce4409SLiam Breck dev_warn(di->dev, "missing battery:charge-full-design-microamp-hours\n"); 1387ccce4409SLiam Breck } 1388ccce4409SLiam Breck 1389ccce4409SLiam Breck /* assume min == 0 */ 1390ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_DESIGN_ENERGY].max; 1391ccce4409SLiam Breck if (info.energy_full_design_uwh > max * 1000) { 1392ccce4409SLiam Breck dev_err(di->dev, "invalid battery:energy-full-design-microwatt-hours %d\n", 1393ccce4409SLiam Breck info.energy_full_design_uwh); 1394ccce4409SLiam Breck info.energy_full_design_uwh = -EINVAL; 1395ccce4409SLiam Breck } 1396ccce4409SLiam Breck 1397ccce4409SLiam Breck /* assume min == 0 */ 1398ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_DESIGN_CAPACITY].max; 1399ccce4409SLiam Breck if (info.charge_full_design_uah > max * 1000) { 1400ccce4409SLiam Breck dev_err(di->dev, "invalid battery:charge-full-design-microamp-hours %d\n", 1401ccce4409SLiam Breck info.charge_full_design_uah); 1402ccce4409SLiam Breck info.charge_full_design_uah = -EINVAL; 1403ccce4409SLiam Breck } 1404ccce4409SLiam Breck 1405ccce4409SLiam Breck min = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].min; 1406ccce4409SLiam Breck max = di->dm_regs[BQ27XXX_DM_TERMINATE_VOLTAGE].max; 1407ccce4409SLiam Breck if ((info.voltage_min_design_uv < min * 1000 || 1408ccce4409SLiam Breck info.voltage_min_design_uv > max * 1000) && 1409ccce4409SLiam Breck info.voltage_min_design_uv != -EINVAL) { 1410ccce4409SLiam Breck dev_err(di->dev, "invalid battery:voltage-min-design-microvolt %d\n", 1411ccce4409SLiam Breck info.voltage_min_design_uv); 1412ccce4409SLiam Breck info.voltage_min_design_uv = -EINVAL; 1413ccce4409SLiam Breck } 1414ccce4409SLiam Breck 1415ccce4409SLiam Breck if ((info.energy_full_design_uwh != -EINVAL && 1416ccce4409SLiam Breck info.charge_full_design_uah != -EINVAL) || 1417ccce4409SLiam Breck info.voltage_min_design_uv != -EINVAL) 1418ccce4409SLiam Breck bq27xxx_battery_set_config(di, &info); 1419ccce4409SLiam Breck } 1420ccce4409SLiam Breck 14218c0984e5SSebastian Reichel /* 14228c0984e5SSebastian Reichel * Return the battery State-of-Charge 14238c0984e5SSebastian Reichel * Or < 0 if something fails. 14248c0984e5SSebastian Reichel */ 14258c0984e5SSebastian Reichel static int bq27xxx_battery_read_soc(struct bq27xxx_device_info *di) 14268c0984e5SSebastian Reichel { 14278c0984e5SSebastian Reichel int soc; 14288c0984e5SSebastian Reichel 14293a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 14308c0984e5SSebastian Reichel soc = bq27xxx_read(di, BQ27XXX_REG_SOC, true); 14318c0984e5SSebastian Reichel else 14328c0984e5SSebastian Reichel soc = bq27xxx_read(di, BQ27XXX_REG_SOC, false); 14338c0984e5SSebastian Reichel 14348c0984e5SSebastian Reichel if (soc < 0) 14358c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading State-of-Charge\n"); 14368c0984e5SSebastian Reichel 14378c0984e5SSebastian Reichel return soc; 14388c0984e5SSebastian Reichel } 14398c0984e5SSebastian Reichel 14408c0984e5SSebastian Reichel /* 14418c0984e5SSebastian Reichel * Return a battery charge value in µAh 14428c0984e5SSebastian Reichel * Or < 0 if something fails. 14438c0984e5SSebastian Reichel */ 14448c0984e5SSebastian Reichel static int bq27xxx_battery_read_charge(struct bq27xxx_device_info *di, u8 reg) 14458c0984e5SSebastian Reichel { 14468c0984e5SSebastian Reichel int charge; 14478c0984e5SSebastian Reichel 14488c0984e5SSebastian Reichel charge = bq27xxx_read(di, reg, false); 14498c0984e5SSebastian Reichel if (charge < 0) { 14508c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading charge register %02x: %d\n", 14518c0984e5SSebastian Reichel reg, charge); 14528c0984e5SSebastian Reichel return charge; 14538c0984e5SSebastian Reichel } 14548c0984e5SSebastian Reichel 14553a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 14568c0984e5SSebastian Reichel charge *= BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 14578c0984e5SSebastian Reichel else 14588c0984e5SSebastian Reichel charge *= 1000; 14598c0984e5SSebastian Reichel 14608c0984e5SSebastian Reichel return charge; 14618c0984e5SSebastian Reichel } 14628c0984e5SSebastian Reichel 14638c0984e5SSebastian Reichel /* 14648c0984e5SSebastian Reichel * Return the battery Nominal available capacity in µAh 14658c0984e5SSebastian Reichel * Or < 0 if something fails. 14668c0984e5SSebastian Reichel */ 14678c0984e5SSebastian Reichel static inline int bq27xxx_battery_read_nac(struct bq27xxx_device_info *di) 14688c0984e5SSebastian Reichel { 14698c0984e5SSebastian Reichel int flags; 14708c0984e5SSebastian Reichel 14713a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 14728c0984e5SSebastian Reichel flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); 14738c0984e5SSebastian Reichel if (flags >= 0 && (flags & BQ27000_FLAG_CI)) 14748c0984e5SSebastian Reichel return -ENODATA; 14758c0984e5SSebastian Reichel } 14768c0984e5SSebastian Reichel 14778c0984e5SSebastian Reichel return bq27xxx_battery_read_charge(di, BQ27XXX_REG_NAC); 14788c0984e5SSebastian Reichel } 14798c0984e5SSebastian Reichel 14808c0984e5SSebastian Reichel /* 14818c0984e5SSebastian Reichel * Return the battery Full Charge Capacity in µAh 14828c0984e5SSebastian Reichel * Or < 0 if something fails. 14838c0984e5SSebastian Reichel */ 14848c0984e5SSebastian Reichel static inline int bq27xxx_battery_read_fcc(struct bq27xxx_device_info *di) 14858c0984e5SSebastian Reichel { 14868c0984e5SSebastian Reichel return bq27xxx_battery_read_charge(di, BQ27XXX_REG_FCC); 14878c0984e5SSebastian Reichel } 14888c0984e5SSebastian Reichel 14898c0984e5SSebastian Reichel /* 14908c0984e5SSebastian Reichel * Return the Design Capacity in µAh 14918c0984e5SSebastian Reichel * Or < 0 if something fails. 14928c0984e5SSebastian Reichel */ 14938c0984e5SSebastian Reichel static int bq27xxx_battery_read_dcap(struct bq27xxx_device_info *di) 14948c0984e5SSebastian Reichel { 14958c0984e5SSebastian Reichel int dcap; 14968c0984e5SSebastian Reichel 14973a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 14988c0984e5SSebastian Reichel dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, true); 14998c0984e5SSebastian Reichel else 15008c0984e5SSebastian Reichel dcap = bq27xxx_read(di, BQ27XXX_REG_DCAP, false); 15018c0984e5SSebastian Reichel 15028c0984e5SSebastian Reichel if (dcap < 0) { 15038c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading initial last measured discharge\n"); 15048c0984e5SSebastian Reichel return dcap; 15058c0984e5SSebastian Reichel } 15068c0984e5SSebastian Reichel 15073a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15088c0984e5SSebastian Reichel dcap = (dcap << 8) * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 15098c0984e5SSebastian Reichel else 15108c0984e5SSebastian Reichel dcap *= 1000; 15118c0984e5SSebastian Reichel 15128c0984e5SSebastian Reichel return dcap; 15138c0984e5SSebastian Reichel } 15148c0984e5SSebastian Reichel 15158c0984e5SSebastian Reichel /* 15168c0984e5SSebastian Reichel * Return the battery Available energy in µWh 15178c0984e5SSebastian Reichel * Or < 0 if something fails. 15188c0984e5SSebastian Reichel */ 15198c0984e5SSebastian Reichel static int bq27xxx_battery_read_energy(struct bq27xxx_device_info *di) 15208c0984e5SSebastian Reichel { 15218c0984e5SSebastian Reichel int ae; 15228c0984e5SSebastian Reichel 15238c0984e5SSebastian Reichel ae = bq27xxx_read(di, BQ27XXX_REG_AE, false); 15248c0984e5SSebastian Reichel if (ae < 0) { 15258c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading available energy\n"); 15268c0984e5SSebastian Reichel return ae; 15278c0984e5SSebastian Reichel } 15288c0984e5SSebastian Reichel 15293a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15308c0984e5SSebastian Reichel ae *= BQ27XXX_POWER_CONSTANT / BQ27XXX_RS; 15318c0984e5SSebastian Reichel else 15328c0984e5SSebastian Reichel ae *= 1000; 15338c0984e5SSebastian Reichel 15348c0984e5SSebastian Reichel return ae; 15358c0984e5SSebastian Reichel } 15368c0984e5SSebastian Reichel 15378c0984e5SSebastian Reichel /* 15388c0984e5SSebastian Reichel * Return the battery temperature in tenths of degree Kelvin 15398c0984e5SSebastian Reichel * Or < 0 if something fails. 15408c0984e5SSebastian Reichel */ 15418c0984e5SSebastian Reichel static int bq27xxx_battery_read_temperature(struct bq27xxx_device_info *di) 15428c0984e5SSebastian Reichel { 15438c0984e5SSebastian Reichel int temp; 15448c0984e5SSebastian Reichel 15458c0984e5SSebastian Reichel temp = bq27xxx_read(di, BQ27XXX_REG_TEMP, false); 15468c0984e5SSebastian Reichel if (temp < 0) { 15478c0984e5SSebastian Reichel dev_err(di->dev, "error reading temperature\n"); 15488c0984e5SSebastian Reichel return temp; 15498c0984e5SSebastian Reichel } 15508c0984e5SSebastian Reichel 15513a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 15528c0984e5SSebastian Reichel temp = 5 * temp / 2; 15538c0984e5SSebastian Reichel 15548c0984e5SSebastian Reichel return temp; 15558c0984e5SSebastian Reichel } 15568c0984e5SSebastian Reichel 15578c0984e5SSebastian Reichel /* 15588c0984e5SSebastian Reichel * Return the battery Cycle count total 15598c0984e5SSebastian Reichel * Or < 0 if something fails. 15608c0984e5SSebastian Reichel */ 15618c0984e5SSebastian Reichel static int bq27xxx_battery_read_cyct(struct bq27xxx_device_info *di) 15628c0984e5SSebastian Reichel { 15638c0984e5SSebastian Reichel int cyct; 15648c0984e5SSebastian Reichel 15658c0984e5SSebastian Reichel cyct = bq27xxx_read(di, BQ27XXX_REG_CYCT, false); 15668c0984e5SSebastian Reichel if (cyct < 0) 15678c0984e5SSebastian Reichel dev_err(di->dev, "error reading cycle count total\n"); 15688c0984e5SSebastian Reichel 15698c0984e5SSebastian Reichel return cyct; 15708c0984e5SSebastian Reichel } 15718c0984e5SSebastian Reichel 15728c0984e5SSebastian Reichel /* 15738c0984e5SSebastian Reichel * Read a time register. 15748c0984e5SSebastian Reichel * Return < 0 if something fails. 15758c0984e5SSebastian Reichel */ 15768c0984e5SSebastian Reichel static int bq27xxx_battery_read_time(struct bq27xxx_device_info *di, u8 reg) 15778c0984e5SSebastian Reichel { 15788c0984e5SSebastian Reichel int tval; 15798c0984e5SSebastian Reichel 15808c0984e5SSebastian Reichel tval = bq27xxx_read(di, reg, false); 15818c0984e5SSebastian Reichel if (tval < 0) { 15828c0984e5SSebastian Reichel dev_dbg(di->dev, "error reading time register %02x: %d\n", 15838c0984e5SSebastian Reichel reg, tval); 15848c0984e5SSebastian Reichel return tval; 15858c0984e5SSebastian Reichel } 15868c0984e5SSebastian Reichel 15878c0984e5SSebastian Reichel if (tval == 65535) 15888c0984e5SSebastian Reichel return -ENODATA; 15898c0984e5SSebastian Reichel 15908c0984e5SSebastian Reichel return tval * 60; 15918c0984e5SSebastian Reichel } 15928c0984e5SSebastian Reichel 15938c0984e5SSebastian Reichel /* 15948c0984e5SSebastian Reichel * Read an average power register. 15958c0984e5SSebastian Reichel * Return < 0 if something fails. 15968c0984e5SSebastian Reichel */ 15978c0984e5SSebastian Reichel static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di) 15988c0984e5SSebastian Reichel { 15998c0984e5SSebastian Reichel int tval; 16008c0984e5SSebastian Reichel 16018c0984e5SSebastian Reichel tval = bq27xxx_read(di, BQ27XXX_REG_AP, false); 16028c0984e5SSebastian Reichel if (tval < 0) { 16038c0984e5SSebastian Reichel dev_err(di->dev, "error reading average power register %02x: %d\n", 16048c0984e5SSebastian Reichel BQ27XXX_REG_AP, tval); 16058c0984e5SSebastian Reichel return tval; 16068c0984e5SSebastian Reichel } 16078c0984e5SSebastian Reichel 16083a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16098c0984e5SSebastian Reichel return (tval * BQ27XXX_POWER_CONSTANT) / BQ27XXX_RS; 16108c0984e5SSebastian Reichel else 16118c0984e5SSebastian Reichel return tval; 16128c0984e5SSebastian Reichel } 16138c0984e5SSebastian Reichel 16148c0984e5SSebastian Reichel /* 16158c0984e5SSebastian Reichel * Returns true if a battery over temperature condition is detected 16168c0984e5SSebastian Reichel */ 16178c0984e5SSebastian Reichel static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) 16188c0984e5SSebastian Reichel { 16193a731c64SLiam Breck if (di->opts & BQ27XXX_O_OTDC) 16208c0984e5SSebastian Reichel return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD); 16213a731c64SLiam Breck if (di->opts & BQ27XXX_O_UTOT) 16228c0984e5SSebastian Reichel return flags & BQ27XXX_FLAG_OT; 16233a731c64SLiam Breck 16248c0984e5SSebastian Reichel return false; 16258c0984e5SSebastian Reichel } 16268c0984e5SSebastian Reichel 16278c0984e5SSebastian Reichel /* 16288c0984e5SSebastian Reichel * Returns true if a battery under temperature condition is detected 16298c0984e5SSebastian Reichel */ 16308c0984e5SSebastian Reichel static bool bq27xxx_battery_undertemp(struct bq27xxx_device_info *di, u16 flags) 16318c0984e5SSebastian Reichel { 16323a731c64SLiam Breck if (di->opts & BQ27XXX_O_UTOT) 16338c0984e5SSebastian Reichel return flags & BQ27XXX_FLAG_UT; 16348c0984e5SSebastian Reichel 16358c0984e5SSebastian Reichel return false; 16368c0984e5SSebastian Reichel } 16378c0984e5SSebastian Reichel 16388c0984e5SSebastian Reichel /* 16398c0984e5SSebastian Reichel * Returns true if a low state of charge condition is detected 16408c0984e5SSebastian Reichel */ 16418c0984e5SSebastian Reichel static bool bq27xxx_battery_dead(struct bq27xxx_device_info *di, u16 flags) 16428c0984e5SSebastian Reichel { 16433a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) 16448c0984e5SSebastian Reichel return flags & (BQ27000_FLAG_EDV1 | BQ27000_FLAG_EDVF); 16456f24ff97SDan Murphy else if (di->opts & BQ27Z561_O_BITS) 16466f24ff97SDan Murphy return flags & BQ27Z561_FLAG_FDC; 16478c0984e5SSebastian Reichel else 16488c0984e5SSebastian Reichel return flags & (BQ27XXX_FLAG_SOC1 | BQ27XXX_FLAG_SOCF); 16498c0984e5SSebastian Reichel } 16508c0984e5SSebastian Reichel 16518c0984e5SSebastian Reichel static int bq27xxx_battery_read_health(struct bq27xxx_device_info *di) 16528c0984e5SSebastian Reichel { 16538c0984e5SSebastian Reichel /* Unlikely but important to return first */ 16549b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_overtemp(di, di->cache.flags))) 16558c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_OVERHEAT; 16569b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_undertemp(di, di->cache.flags))) 16578c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_COLD; 16589b2c945fSArthur Demchenkov if (unlikely(bq27xxx_battery_dead(di, di->cache.flags))) 16598c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_DEAD; 16608c0984e5SSebastian Reichel 16618c0984e5SSebastian Reichel return POWER_SUPPLY_HEALTH_GOOD; 16628c0984e5SSebastian Reichel } 16638c0984e5SSebastian Reichel 16648c0984e5SSebastian Reichel void bq27xxx_battery_update(struct bq27xxx_device_info *di) 16658c0984e5SSebastian Reichel { 16668c0984e5SSebastian Reichel struct bq27xxx_reg_cache cache = {0, }; 16673a731c64SLiam Breck bool has_ci_flag = di->opts & BQ27XXX_O_ZERO; 16683a731c64SLiam Breck bool has_singe_flag = di->opts & BQ27XXX_O_ZERO; 16698c0984e5SSebastian Reichel 16708c0984e5SSebastian Reichel cache.flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, has_singe_flag); 16718c0984e5SSebastian Reichel if ((cache.flags & 0xff) == 0xff) 16728c0984e5SSebastian Reichel cache.flags = -1; /* read error */ 16738c0984e5SSebastian Reichel if (cache.flags >= 0) { 16748c0984e5SSebastian Reichel cache.temperature = bq27xxx_battery_read_temperature(di); 16758c0984e5SSebastian Reichel if (has_ci_flag && (cache.flags & BQ27000_FLAG_CI)) { 16768c0984e5SSebastian Reichel dev_info_once(di->dev, "battery is not calibrated! ignoring capacity values\n"); 16778c0984e5SSebastian Reichel cache.capacity = -ENODATA; 16788c0984e5SSebastian Reichel cache.energy = -ENODATA; 16798c0984e5SSebastian Reichel cache.time_to_empty = -ENODATA; 16808c0984e5SSebastian Reichel cache.time_to_empty_avg = -ENODATA; 16818c0984e5SSebastian Reichel cache.time_to_full = -ENODATA; 16828c0984e5SSebastian Reichel cache.charge_full = -ENODATA; 16838c0984e5SSebastian Reichel cache.health = -ENODATA; 16848c0984e5SSebastian Reichel } else { 16858c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTE] != INVALID_REG_ADDR) 16868c0984e5SSebastian Reichel cache.time_to_empty = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTE); 16878c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTECP] != INVALID_REG_ADDR) 16888c0984e5SSebastian Reichel cache.time_to_empty_avg = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTECP); 16898c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_TTF] != INVALID_REG_ADDR) 16908c0984e5SSebastian Reichel cache.time_to_full = bq27xxx_battery_read_time(di, BQ27XXX_REG_TTF); 16916f24ff97SDan Murphy 16928c0984e5SSebastian Reichel cache.charge_full = bq27xxx_battery_read_fcc(di); 16938c0984e5SSebastian Reichel cache.capacity = bq27xxx_battery_read_soc(di); 16948c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_AE] != INVALID_REG_ADDR) 16958c0984e5SSebastian Reichel cache.energy = bq27xxx_battery_read_energy(di); 16969b2c945fSArthur Demchenkov di->cache.flags = cache.flags; 16978c0984e5SSebastian Reichel cache.health = bq27xxx_battery_read_health(di); 16988c0984e5SSebastian Reichel } 16998c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_CYCT] != INVALID_REG_ADDR) 17008c0984e5SSebastian Reichel cache.cycle_count = bq27xxx_battery_read_cyct(di); 17018c0984e5SSebastian Reichel if (di->regs[BQ27XXX_REG_AP] != INVALID_REG_ADDR) 17028c0984e5SSebastian Reichel cache.power_avg = bq27xxx_battery_read_pwr_avg(di); 17038c0984e5SSebastian Reichel 17048c0984e5SSebastian Reichel /* We only have to read charge design full once */ 17058c0984e5SSebastian Reichel if (di->charge_design_full <= 0) 17068c0984e5SSebastian Reichel di->charge_design_full = bq27xxx_battery_read_dcap(di); 17078c0984e5SSebastian Reichel } 17088c0984e5SSebastian Reichel 1709243f8ffcSKrzysztof Kozlowski if ((di->cache.capacity != cache.capacity) || 1710243f8ffcSKrzysztof Kozlowski (di->cache.flags != cache.flags)) 17118c0984e5SSebastian Reichel power_supply_changed(di->bat); 17128c0984e5SSebastian Reichel 17138c0984e5SSebastian Reichel if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) 17148c0984e5SSebastian Reichel di->cache = cache; 17158c0984e5SSebastian Reichel 17168c0984e5SSebastian Reichel di->last_update = jiffies; 17178c0984e5SSebastian Reichel } 17188c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_update); 17198c0984e5SSebastian Reichel 17208c0984e5SSebastian Reichel static void bq27xxx_battery_poll(struct work_struct *work) 17218c0984e5SSebastian Reichel { 17228c0984e5SSebastian Reichel struct bq27xxx_device_info *di = 17238c0984e5SSebastian Reichel container_of(work, struct bq27xxx_device_info, 17248c0984e5SSebastian Reichel work.work); 17258c0984e5SSebastian Reichel 17268c0984e5SSebastian Reichel bq27xxx_battery_update(di); 17278c0984e5SSebastian Reichel 17288c0984e5SSebastian Reichel if (poll_interval > 0) 17298c0984e5SSebastian Reichel schedule_delayed_work(&di->work, poll_interval * HZ); 17308c0984e5SSebastian Reichel } 17318c0984e5SSebastian Reichel 17328c0984e5SSebastian Reichel /* 17338c0984e5SSebastian Reichel * Return the battery average current in µA 17348c0984e5SSebastian Reichel * Note that current can be negative signed as well 17358c0984e5SSebastian Reichel * Or 0 if something fails. 17368c0984e5SSebastian Reichel */ 17378c0984e5SSebastian Reichel static int bq27xxx_battery_current(struct bq27xxx_device_info *di, 17388c0984e5SSebastian Reichel union power_supply_propval *val) 17398c0984e5SSebastian Reichel { 17408c0984e5SSebastian Reichel int curr; 17418c0984e5SSebastian Reichel int flags; 17428c0984e5SSebastian Reichel 17438c0984e5SSebastian Reichel curr = bq27xxx_read(di, BQ27XXX_REG_AI, false); 17448c0984e5SSebastian Reichel if (curr < 0) { 17458c0984e5SSebastian Reichel dev_err(di->dev, "error reading current\n"); 17468c0984e5SSebastian Reichel return curr; 17478c0984e5SSebastian Reichel } 17488c0984e5SSebastian Reichel 17493a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 1750e4a404a0SH. Nikolaus Schaller flags = bq27xxx_read(di, BQ27XXX_REG_FLAGS, true); 17518c0984e5SSebastian Reichel if (flags & BQ27000_FLAG_CHGS) { 17528c0984e5SSebastian Reichel dev_dbg(di->dev, "negative current!\n"); 17538c0984e5SSebastian Reichel curr = -curr; 17548c0984e5SSebastian Reichel } 17558c0984e5SSebastian Reichel 17568c0984e5SSebastian Reichel val->intval = curr * BQ27XXX_CURRENT_CONSTANT / BQ27XXX_RS; 17578c0984e5SSebastian Reichel } else { 17588c0984e5SSebastian Reichel /* Other gauges return signed value */ 17598c0984e5SSebastian Reichel val->intval = (int)((s16)curr) * 1000; 17608c0984e5SSebastian Reichel } 17618c0984e5SSebastian Reichel 17628c0984e5SSebastian Reichel return 0; 17638c0984e5SSebastian Reichel } 17648c0984e5SSebastian Reichel 17658c0984e5SSebastian Reichel static int bq27xxx_battery_status(struct bq27xxx_device_info *di, 17668c0984e5SSebastian Reichel union power_supply_propval *val) 17678c0984e5SSebastian Reichel { 17688c0984e5SSebastian Reichel int status; 17698c0984e5SSebastian Reichel 17703a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 17718c0984e5SSebastian Reichel if (di->cache.flags & BQ27000_FLAG_FC) 17728c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_FULL; 17738c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_CHGS) 17748c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_CHARGING; 1775f72c14adSSebastian Reichel else if (power_supply_am_i_supplied(di->bat) > 0) 17768c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_NOT_CHARGING; 17778c0984e5SSebastian Reichel else 17788c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_DISCHARGING; 17796f24ff97SDan Murphy } else if (di->opts & BQ27Z561_O_BITS) { 17806f24ff97SDan Murphy if (di->cache.flags & BQ27Z561_FLAG_FC) 17816f24ff97SDan Murphy status = POWER_SUPPLY_STATUS_FULL; 17826f24ff97SDan Murphy else if (di->cache.flags & BQ27Z561_FLAG_DIS_CH) 17836f24ff97SDan Murphy status = POWER_SUPPLY_STATUS_DISCHARGING; 17846f24ff97SDan Murphy else 17856f24ff97SDan Murphy status = POWER_SUPPLY_STATUS_CHARGING; 17868c0984e5SSebastian Reichel } else { 17878c0984e5SSebastian Reichel if (di->cache.flags & BQ27XXX_FLAG_FC) 17888c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_FULL; 17898c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_DSC) 17908c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_DISCHARGING; 17918c0984e5SSebastian Reichel else 17928c0984e5SSebastian Reichel status = POWER_SUPPLY_STATUS_CHARGING; 17938c0984e5SSebastian Reichel } 17948c0984e5SSebastian Reichel 17958c0984e5SSebastian Reichel val->intval = status; 17968c0984e5SSebastian Reichel 17978c0984e5SSebastian Reichel return 0; 17988c0984e5SSebastian Reichel } 17998c0984e5SSebastian Reichel 18008c0984e5SSebastian Reichel static int bq27xxx_battery_capacity_level(struct bq27xxx_device_info *di, 18018c0984e5SSebastian Reichel union power_supply_propval *val) 18028c0984e5SSebastian Reichel { 18038c0984e5SSebastian Reichel int level; 18048c0984e5SSebastian Reichel 18053a731c64SLiam Breck if (di->opts & BQ27XXX_O_ZERO) { 18068c0984e5SSebastian Reichel if (di->cache.flags & BQ27000_FLAG_FC) 18078c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 18088c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_EDV1) 18098c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 18108c0984e5SSebastian Reichel else if (di->cache.flags & BQ27000_FLAG_EDVF) 18118c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 18128c0984e5SSebastian Reichel else 18138c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 18146f24ff97SDan Murphy } else if (di->opts & BQ27Z561_O_BITS) { 18156f24ff97SDan Murphy if (di->cache.flags & BQ27Z561_FLAG_FC) 18166f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 18176f24ff97SDan Murphy else if (di->cache.flags & BQ27Z561_FLAG_FDC) 18186f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 18196f24ff97SDan Murphy else 18206f24ff97SDan Murphy level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 18218c0984e5SSebastian Reichel } else { 18228c0984e5SSebastian Reichel if (di->cache.flags & BQ27XXX_FLAG_FC) 18238c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_FULL; 18248c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_SOC1) 18258c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_LOW; 18268c0984e5SSebastian Reichel else if (di->cache.flags & BQ27XXX_FLAG_SOCF) 18278c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL; 18288c0984e5SSebastian Reichel else 18298c0984e5SSebastian Reichel level = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL; 18308c0984e5SSebastian Reichel } 18318c0984e5SSebastian Reichel 18328c0984e5SSebastian Reichel val->intval = level; 18338c0984e5SSebastian Reichel 18348c0984e5SSebastian Reichel return 0; 18358c0984e5SSebastian Reichel } 18368c0984e5SSebastian Reichel 18378c0984e5SSebastian Reichel /* 18388c0984e5SSebastian Reichel * Return the battery Voltage in millivolts 18398c0984e5SSebastian Reichel * Or < 0 if something fails. 18408c0984e5SSebastian Reichel */ 18418c0984e5SSebastian Reichel static int bq27xxx_battery_voltage(struct bq27xxx_device_info *di, 18428c0984e5SSebastian Reichel union power_supply_propval *val) 18438c0984e5SSebastian Reichel { 18448c0984e5SSebastian Reichel int volt; 18458c0984e5SSebastian Reichel 18468c0984e5SSebastian Reichel volt = bq27xxx_read(di, BQ27XXX_REG_VOLT, false); 18478c0984e5SSebastian Reichel if (volt < 0) { 18488c0984e5SSebastian Reichel dev_err(di->dev, "error reading voltage\n"); 18498c0984e5SSebastian Reichel return volt; 18508c0984e5SSebastian Reichel } 18518c0984e5SSebastian Reichel 18528c0984e5SSebastian Reichel val->intval = volt * 1000; 18538c0984e5SSebastian Reichel 18548c0984e5SSebastian Reichel return 0; 18558c0984e5SSebastian Reichel } 18568c0984e5SSebastian Reichel 18578c0984e5SSebastian Reichel static int bq27xxx_simple_value(int value, 18588c0984e5SSebastian Reichel union power_supply_propval *val) 18598c0984e5SSebastian Reichel { 18608c0984e5SSebastian Reichel if (value < 0) 18618c0984e5SSebastian Reichel return value; 18628c0984e5SSebastian Reichel 18638c0984e5SSebastian Reichel val->intval = value; 18648c0984e5SSebastian Reichel 18658c0984e5SSebastian Reichel return 0; 18668c0984e5SSebastian Reichel } 18678c0984e5SSebastian Reichel 18688c0984e5SSebastian Reichel static int bq27xxx_battery_get_property(struct power_supply *psy, 18698c0984e5SSebastian Reichel enum power_supply_property psp, 18708c0984e5SSebastian Reichel union power_supply_propval *val) 18718c0984e5SSebastian Reichel { 18728c0984e5SSebastian Reichel int ret = 0; 18738c0984e5SSebastian Reichel struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 18748c0984e5SSebastian Reichel 18758c0984e5SSebastian Reichel mutex_lock(&di->lock); 18768c0984e5SSebastian Reichel if (time_is_before_jiffies(di->last_update + 5 * HZ)) { 18778c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 18788c0984e5SSebastian Reichel bq27xxx_battery_poll(&di->work.work); 18798c0984e5SSebastian Reichel } 18808c0984e5SSebastian Reichel mutex_unlock(&di->lock); 18818c0984e5SSebastian Reichel 18828c0984e5SSebastian Reichel if (psp != POWER_SUPPLY_PROP_PRESENT && di->cache.flags < 0) 18838c0984e5SSebastian Reichel return -ENODEV; 18848c0984e5SSebastian Reichel 18858c0984e5SSebastian Reichel switch (psp) { 18868c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_STATUS: 18878c0984e5SSebastian Reichel ret = bq27xxx_battery_status(di, val); 18888c0984e5SSebastian Reichel break; 18898c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_VOLTAGE_NOW: 18908c0984e5SSebastian Reichel ret = bq27xxx_battery_voltage(di, val); 18918c0984e5SSebastian Reichel break; 18928c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_PRESENT: 18938c0984e5SSebastian Reichel val->intval = di->cache.flags < 0 ? 0 : 1; 18948c0984e5SSebastian Reichel break; 18958c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CURRENT_NOW: 18968c0984e5SSebastian Reichel ret = bq27xxx_battery_current(di, val); 18978c0984e5SSebastian Reichel break; 18988c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY: 18998c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.capacity, val); 19008c0984e5SSebastian Reichel break; 19018c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CAPACITY_LEVEL: 19028c0984e5SSebastian Reichel ret = bq27xxx_battery_capacity_level(di, val); 19038c0984e5SSebastian Reichel break; 19048c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TEMP: 19058c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.temperature, val); 19068c0984e5SSebastian Reichel if (ret == 0) 19078c0984e5SSebastian Reichel val->intval -= 2731; /* convert decidegree k to c */ 19088c0984e5SSebastian Reichel break; 19098c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: 19108c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_empty, val); 19118c0984e5SSebastian Reichel break; 19128c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG: 19138c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_empty_avg, val); 19148c0984e5SSebastian Reichel break; 19158c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TIME_TO_FULL_NOW: 19168c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.time_to_full, val); 19178c0984e5SSebastian Reichel break; 19188c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_TECHNOLOGY: 19198c0984e5SSebastian Reichel val->intval = POWER_SUPPLY_TECHNOLOGY_LION; 19208c0984e5SSebastian Reichel break; 19218c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_NOW: 19228c0984e5SSebastian Reichel ret = bq27xxx_simple_value(bq27xxx_battery_read_nac(di), val); 19238c0984e5SSebastian Reichel break; 19248c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL: 19258c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.charge_full, val); 19268c0984e5SSebastian Reichel break; 19278c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: 19288c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->charge_design_full, val); 19298c0984e5SSebastian Reichel break; 1930ccce4409SLiam Breck /* 1931ccce4409SLiam Breck * TODO: Implement these to make registers set from 1932ccce4409SLiam Breck * power_supply_battery_info visible in sysfs. 1933ccce4409SLiam Breck */ 1934ccce4409SLiam Breck case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: 1935ccce4409SLiam Breck case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: 1936ccce4409SLiam Breck return -EINVAL; 19378c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_CYCLE_COUNT: 19388c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.cycle_count, val); 19398c0984e5SSebastian Reichel break; 19408c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_ENERGY_NOW: 19418c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.energy, val); 19428c0984e5SSebastian Reichel break; 19438c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_POWER_AVG: 19448c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.power_avg, val); 19458c0984e5SSebastian Reichel break; 19468c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_HEALTH: 19478c0984e5SSebastian Reichel ret = bq27xxx_simple_value(di->cache.health, val); 19488c0984e5SSebastian Reichel break; 19498c0984e5SSebastian Reichel case POWER_SUPPLY_PROP_MANUFACTURER: 19508c0984e5SSebastian Reichel val->strval = BQ27XXX_MANUFACTURER; 19518c0984e5SSebastian Reichel break; 19528c0984e5SSebastian Reichel default: 19538c0984e5SSebastian Reichel return -EINVAL; 19548c0984e5SSebastian Reichel } 19558c0984e5SSebastian Reichel 19568c0984e5SSebastian Reichel return ret; 19578c0984e5SSebastian Reichel } 19588c0984e5SSebastian Reichel 19598c0984e5SSebastian Reichel static void bq27xxx_external_power_changed(struct power_supply *psy) 19608c0984e5SSebastian Reichel { 19618c0984e5SSebastian Reichel struct bq27xxx_device_info *di = power_supply_get_drvdata(psy); 19628c0984e5SSebastian Reichel 19638c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 19648c0984e5SSebastian Reichel schedule_delayed_work(&di->work, 0); 19658c0984e5SSebastian Reichel } 19668c0984e5SSebastian Reichel 19678c0984e5SSebastian Reichel int bq27xxx_battery_setup(struct bq27xxx_device_info *di) 19688c0984e5SSebastian Reichel { 19698c0984e5SSebastian Reichel struct power_supply_desc *psy_desc; 1970ccce4409SLiam Breck struct power_supply_config psy_cfg = { 1971ccce4409SLiam Breck .of_node = di->dev->of_node, 1972ccce4409SLiam Breck .drv_data = di, 1973ccce4409SLiam Breck }; 19748c0984e5SSebastian Reichel 19758c0984e5SSebastian Reichel INIT_DELAYED_WORK(&di->work, bq27xxx_battery_poll); 19768c0984e5SSebastian Reichel mutex_init(&di->lock); 19773a731c64SLiam Breck 19789aade6d8SLiam Breck di->regs = bq27xxx_chip_data[di->chip].regs; 197905045379SLiam Breck di->unseal_key = bq27xxx_chip_data[di->chip].unseal_key; 198005045379SLiam Breck di->dm_regs = bq27xxx_chip_data[di->chip].dm_regs; 19813a731c64SLiam Breck di->opts = bq27xxx_chip_data[di->chip].opts; 19828c0984e5SSebastian Reichel 19838c0984e5SSebastian Reichel psy_desc = devm_kzalloc(di->dev, sizeof(*psy_desc), GFP_KERNEL); 19848c0984e5SSebastian Reichel if (!psy_desc) 19858c0984e5SSebastian Reichel return -ENOMEM; 19868c0984e5SSebastian Reichel 19878c0984e5SSebastian Reichel psy_desc->name = di->name; 19888c0984e5SSebastian Reichel psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; 19899aade6d8SLiam Breck psy_desc->properties = bq27xxx_chip_data[di->chip].props; 19909aade6d8SLiam Breck psy_desc->num_properties = bq27xxx_chip_data[di->chip].props_size; 19918c0984e5SSebastian Reichel psy_desc->get_property = bq27xxx_battery_get_property; 19928c0984e5SSebastian Reichel psy_desc->external_power_changed = bq27xxx_external_power_changed; 19938c0984e5SSebastian Reichel 19948c0984e5SSebastian Reichel di->bat = power_supply_register_no_ws(di->dev, psy_desc, &psy_cfg); 19958c0984e5SSebastian Reichel if (IS_ERR(di->bat)) { 1996583b53ecSDmitry Osipenko if (PTR_ERR(di->bat) == -EPROBE_DEFER) 1997583b53ecSDmitry Osipenko dev_dbg(di->dev, "failed to register battery, deferring probe\n"); 1998583b53ecSDmitry Osipenko else 19998c0984e5SSebastian Reichel dev_err(di->dev, "failed to register battery\n"); 20008c0984e5SSebastian Reichel return PTR_ERR(di->bat); 20018c0984e5SSebastian Reichel } 20028c0984e5SSebastian Reichel 2003ccce4409SLiam Breck bq27xxx_battery_settings(di); 20048c0984e5SSebastian Reichel bq27xxx_battery_update(di); 20058c0984e5SSebastian Reichel 20061d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 20071d72706fSMatt Ranostay list_add(&di->list, &bq27xxx_battery_devices); 20081d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 20091d72706fSMatt Ranostay 20108c0984e5SSebastian Reichel return 0; 20118c0984e5SSebastian Reichel } 20128c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_setup); 20138c0984e5SSebastian Reichel 20148c0984e5SSebastian Reichel void bq27xxx_battery_teardown(struct bq27xxx_device_info *di) 20158c0984e5SSebastian Reichel { 20168c0984e5SSebastian Reichel /* 20178c0984e5SSebastian Reichel * power_supply_unregister call bq27xxx_battery_get_property which 20188c0984e5SSebastian Reichel * call bq27xxx_battery_poll. 20198c0984e5SSebastian Reichel * Make sure that bq27xxx_battery_poll will not call 20208c0984e5SSebastian Reichel * schedule_delayed_work again after unregister (which cause OOPS). 20218c0984e5SSebastian Reichel */ 20228c0984e5SSebastian Reichel poll_interval = 0; 20238c0984e5SSebastian Reichel 20248c0984e5SSebastian Reichel cancel_delayed_work_sync(&di->work); 20258c0984e5SSebastian Reichel 20268c0984e5SSebastian Reichel power_supply_unregister(di->bat); 20278c0984e5SSebastian Reichel 20281d72706fSMatt Ranostay mutex_lock(&bq27xxx_list_lock); 20291d72706fSMatt Ranostay list_del(&di->list); 20301d72706fSMatt Ranostay mutex_unlock(&bq27xxx_list_lock); 20311d72706fSMatt Ranostay 20328c0984e5SSebastian Reichel mutex_destroy(&di->lock); 20338c0984e5SSebastian Reichel } 20348c0984e5SSebastian Reichel EXPORT_SYMBOL_GPL(bq27xxx_battery_teardown); 20358c0984e5SSebastian Reichel 20368c0984e5SSebastian Reichel MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 20378c0984e5SSebastian Reichel MODULE_DESCRIPTION("BQ27xxx battery monitor driver"); 20388c0984e5SSebastian Reichel MODULE_LICENSE("GPL"); 2039