xref: /linux/drivers/power/supply/intel_dc_ti_battery.c (revision 4f38da1f027ea2c9f01bb71daa7a299c191b6940)
1*8c5795feSHans de Goede // SPDX-License-Identifier: GPL-2.0-only
2*8c5795feSHans de Goede /*
3*8c5795feSHans de Goede  * Battery driver for the coulomb-counter of the Intel Dollar Cove TI PMIC
4*8c5795feSHans de Goede  *
5*8c5795feSHans de Goede  * Note the Intel Dollar Cove TI PMIC coulomb-counter is not a full-featured
6*8c5795feSHans de Goede  * autonomous fuel-gauge. It is intended to work together with an always on
7*8c5795feSHans de Goede  * micro-controller monitoring it.
8*8c5795feSHans de Goede  *
9*8c5795feSHans de Goede  * Since Linux does not monitor coulomb-counter changes while the device
10*8c5795feSHans de Goede  * is off or suspended, voltage based capacity estimation from
11*8c5795feSHans de Goede  * the adc-battery-helper code is used.
12*8c5795feSHans de Goede  *
13*8c5795feSHans de Goede  * Copyright (C) 2024 Hans de Goede <hansg@kernel.org>
14*8c5795feSHans de Goede  *
15*8c5795feSHans de Goede  * Register definitions and calibration code was taken from
16*8c5795feSHans de Goede  * kernel/drivers/platform/x86/dc_ti_cc.c from the Acer A1-840 Android kernel
17*8c5795feSHans de Goede  * which has the following copyright header:
18*8c5795feSHans de Goede  *
19*8c5795feSHans de Goede  * Copyright (C) 2014 Intel Corporation
20*8c5795feSHans de Goede  * Author: Ramakrishna Pallala <ramakrishna.pallala@intel.com>
21*8c5795feSHans de Goede  *
22*8c5795feSHans de Goede  * dc_ti_cc.c is part of the Acer A1-840 Android kernel source-code archive
23*8c5795feSHans de Goede  * named: "App. Guide_Acer_20151221_A_A.zip"
24*8c5795feSHans de Goede  * which is distributed by Acer from the Acer A1-840 support page:
25*8c5795feSHans de Goede  * https://www.acer.com/us-en/support/product-support/A1-840/downloads
26*8c5795feSHans de Goede  */
27*8c5795feSHans de Goede 
28*8c5795feSHans de Goede #include <linux/acpi.h>
29*8c5795feSHans de Goede #include <linux/bits.h>
30*8c5795feSHans de Goede #include <linux/bitfield.h>
31*8c5795feSHans de Goede #include <linux/cleanup.h>
32*8c5795feSHans de Goede #include <linux/err.h>
33*8c5795feSHans de Goede #include <linux/gpio/consumer.h>
34*8c5795feSHans de Goede #include <linux/iio/consumer.h>
35*8c5795feSHans de Goede #include <linux/mfd/intel_soc_pmic.h>
36*8c5795feSHans de Goede #include <linux/module.h>
37*8c5795feSHans de Goede #include <linux/platform_device.h>
38*8c5795feSHans de Goede #include <linux/pm_runtime.h>
39*8c5795feSHans de Goede #include <linux/power_supply.h>
40*8c5795feSHans de Goede #include <linux/property.h>
41*8c5795feSHans de Goede #include <linux/regmap.h>
42*8c5795feSHans de Goede #include <linux/timekeeping.h>
43*8c5795feSHans de Goede 
44*8c5795feSHans de Goede #include "adc-battery-helper.h"
45*8c5795feSHans de Goede 
46*8c5795feSHans de Goede #define DC_TI_PMIC_VERSION_REG		0x00
47*8c5795feSHans de Goede #define PMIC_VERSION_A0			0xC0
48*8c5795feSHans de Goede #define PMIC_VERSION_A1			0xC1
49*8c5795feSHans de Goede 
50*8c5795feSHans de Goede #define DC_TI_CC_CNTL_REG		0x60
51*8c5795feSHans de Goede #define CC_CNTL_CC_CTR_EN		BIT(0)
52*8c5795feSHans de Goede #define CC_CNTL_CC_CLR_EN		BIT(1)
53*8c5795feSHans de Goede #define CC_CNTL_CC_CAL_EN		BIT(2)
54*8c5795feSHans de Goede #define CC_CNTL_CC_OFFSET_EN		BIT(3)
55*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL		GENMASK(5, 4)
56*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_15MS		FIELD_PREP(CC_CNTL_SMPL_INTVL, 0)
57*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_62MS		FIELD_PREP(CC_CNTL_SMPL_INTVL, 1)
58*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_125MS	FIELD_PREP(CC_CNTL_SMPL_INTVL, 2)
59*8c5795feSHans de Goede #define CC_CNTL_SMPL_INTVL_250MS	FIELD_PREP(CC_CNTL_SMPL_INTVL, 3)
60*8c5795feSHans de Goede 
61*8c5795feSHans de Goede #define DC_TI_SMPL_CTR0_REG		0x69
62*8c5795feSHans de Goede #define DC_TI_SMPL_CTR1_REG		0x68
63*8c5795feSHans de Goede #define DC_TI_SMPL_CTR2_REG		0x67
64*8c5795feSHans de Goede 
65*8c5795feSHans de Goede #define DC_TI_CC_OFFSET_HI_REG		0x61
66*8c5795feSHans de Goede #define CC_OFFSET_HI_MASK		0x3F
67*8c5795feSHans de Goede #define DC_TI_CC_OFFSET_LO_REG		0x62
68*8c5795feSHans de Goede 
69*8c5795feSHans de Goede #define DC_TI_SW_OFFSET_REG		0x6C
70*8c5795feSHans de Goede 
71*8c5795feSHans de Goede #define DC_TI_CC_ACC3_REG		0x63
72*8c5795feSHans de Goede #define DC_TI_CC_ACC2_REG		0x64
73*8c5795feSHans de Goede #define DC_TI_CC_ACC1_REG		0x65
74*8c5795feSHans de Goede #define DC_TI_CC_ACC0_REG		0x66
75*8c5795feSHans de Goede 
76*8c5795feSHans de Goede #define DC_TI_CC_INTG1_REG		0x6A
77*8c5795feSHans de Goede #define DC_TI_CC_INTG1_MASK		0x3F
78*8c5795feSHans de Goede #define DC_TI_CC_INTG0_REG		0x6B
79*8c5795feSHans de Goede 
80*8c5795feSHans de Goede #define DC_TI_EEPROM_ACCESS_CONTROL	0x88
81*8c5795feSHans de Goede #define EEPROM_UNLOCK			0xDA
82*8c5795feSHans de Goede #define EEPROM_LOCK			0x00
83*8c5795feSHans de Goede 
84*8c5795feSHans de Goede #define DC_TI_EEPROM_CC_GAIN_REG	0xF4
85*8c5795feSHans de Goede #define CC_TRIM_REVISION		GENMASK(3, 0)
86*8c5795feSHans de Goede #define CC_GAIN_CORRECTION		GENMASK(7, 4)
87*8c5795feSHans de Goede 
88*8c5795feSHans de Goede #define PMIC_VERSION_A0_TRIM_REV	3
89*8c5795feSHans de Goede #define PMIC_VERSION_A1_MIN_TRIM_REV	1
90*8c5795feSHans de Goede 
91*8c5795feSHans de Goede #define DC_TI_EEPROM_CC_OFFSET_REG	0xFD
92*8c5795feSHans de Goede 
93*8c5795feSHans de Goede #define DC_TI_EEPROM_CTRL		0xFE
94*8c5795feSHans de Goede #define EEPROM_BANK0_SEL		0x01
95*8c5795feSHans de Goede #define EEPROM_BANK1_SEL		0x02
96*8c5795feSHans de Goede 
97*8c5795feSHans de Goede #define SMPL_INTVL_US			15000
98*8c5795feSHans de Goede #define SMPL_INTVL_MS			(SMPL_INTVL_US / USEC_PER_MSEC)
99*8c5795feSHans de Goede #define CALIBRATION_TIME_US		(10 * SMPL_INTVL_US)
100*8c5795feSHans de Goede #define SLEEP_SLACK_US			2500
101*8c5795feSHans de Goede 
102*8c5795feSHans de Goede /* CC gain correction is in 0.0025 increments */
103*8c5795feSHans de Goede #define CC_GAIN_STEP			25
104*8c5795feSHans de Goede #define CC_GAIN_DIV			10000
105*8c5795feSHans de Goede 
106*8c5795feSHans de Goede /* CC offset is in 0.5 units per 250ms (default sample interval) */
107*8c5795feSHans de Goede #define CC_OFFSET_DIV			2
108*8c5795feSHans de Goede #define CC_OFFSET_SMPL_INTVL_MS		250
109*8c5795feSHans de Goede 
110*8c5795feSHans de Goede /* CC accumulator scale is 366.2 ųCoulumb / unit */
111*8c5795feSHans de Goede #define CC_ACC_TO_UA(acc, smpl_ctr)	\
112*8c5795feSHans de Goede 	((acc) * (3662 * MSEC_PER_SEC / 10) / ((smpl_ctr) * SMPL_INTVL_MS))
113*8c5795feSHans de Goede 
114*8c5795feSHans de Goede #define DEV_NAME			"chtdc_ti_battery"
115*8c5795feSHans de Goede 
116*8c5795feSHans de Goede struct dc_ti_battery_chip {
117*8c5795feSHans de Goede 	/* Must be the first member see adc-battery-helper documentation */
118*8c5795feSHans de Goede 	struct adc_battery_helper helper;
119*8c5795feSHans de Goede 	struct device *dev;
120*8c5795feSHans de Goede 	struct regmap *regmap;
121*8c5795feSHans de Goede 	struct iio_channel *vbat_channel;
122*8c5795feSHans de Goede 	struct power_supply *psy;
123*8c5795feSHans de Goede 	int cc_gain;
124*8c5795feSHans de Goede 	int cc_offset;
125*8c5795feSHans de Goede };
126*8c5795feSHans de Goede 
127*8c5795feSHans de Goede static int dc_ti_battery_get_voltage_and_current_now(struct power_supply *psy, int *volt, int *curr)
128*8c5795feSHans de Goede {
129*8c5795feSHans de Goede 	struct dc_ti_battery_chip *chip = power_supply_get_drvdata(psy);
130*8c5795feSHans de Goede 	s64 cnt_start_usec, now_usec, sleep_usec;
131*8c5795feSHans de Goede 	unsigned int reg_val;
132*8c5795feSHans de Goede 	s32 acc, smpl_ctr;
133*8c5795feSHans de Goede 	int ret;
134*8c5795feSHans de Goede 
135*8c5795feSHans de Goede 	/*
136*8c5795feSHans de Goede 	 * Enable coulomb-counter before reading Vbat from ADC, so that the CC
137*8c5795feSHans de Goede 	 * samples are from the same time period as the Vbat reading.
138*8c5795feSHans de Goede 	 */
139*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG,
140*8c5795feSHans de Goede 			   CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN | CC_CNTL_CC_CTR_EN);
141*8c5795feSHans de Goede 	if (ret)
142*8c5795feSHans de Goede 		goto out_err;
143*8c5795feSHans de Goede 
144*8c5795feSHans de Goede 	cnt_start_usec = ktime_get_ns() / NSEC_PER_USEC;
145*8c5795feSHans de Goede 
146*8c5795feSHans de Goede 	/* Read Vbat, convert IIO mV to power-supply ųV */
147*8c5795feSHans de Goede 	ret = iio_read_channel_processed_scale(chip->vbat_channel, volt, 1000);
148*8c5795feSHans de Goede 	if (ret < 0)
149*8c5795feSHans de Goede 		goto out_err;
150*8c5795feSHans de Goede 
151*8c5795feSHans de Goede 	/* Sleep at least 3 sample-times + slack to get 3+ CC samples */
152*8c5795feSHans de Goede 	now_usec = ktime_get_ns() / NSEC_PER_USEC;
153*8c5795feSHans de Goede 	sleep_usec = 3 * SMPL_INTVL_US + SLEEP_SLACK_US - (now_usec - cnt_start_usec);
154*8c5795feSHans de Goede 	if (sleep_usec > 0 && sleep_usec < 1000000)
155*8c5795feSHans de Goede 		usleep_range(sleep_usec, sleep_usec + SLEEP_SLACK_US);
156*8c5795feSHans de Goede 
157*8c5795feSHans de Goede 	/*
158*8c5795feSHans de Goede 	 * The PMIC latches the coulomb- and sample-counters upon reading the
159*8c5795feSHans de Goede 	 * CC_ACC0 register. Reading multiple registers at once is not supported.
160*8c5795feSHans de Goede 	 *
161*8c5795feSHans de Goede 	 * Step 1: Read CC_ACC0 - CC_ACC3
162*8c5795feSHans de Goede 	 */
163*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_CC_ACC0_REG, &reg_val);
164*8c5795feSHans de Goede 	if (ret)
165*8c5795feSHans de Goede 		goto out_err;
166*8c5795feSHans de Goede 
167*8c5795feSHans de Goede 	acc = reg_val;
168*8c5795feSHans de Goede 
169*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_CC_ACC1_REG, &reg_val);
170*8c5795feSHans de Goede 	if (ret)
171*8c5795feSHans de Goede 		goto out_err;
172*8c5795feSHans de Goede 
173*8c5795feSHans de Goede 	acc |= reg_val << 8;
174*8c5795feSHans de Goede 
175*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_CC_ACC2_REG, &reg_val);
176*8c5795feSHans de Goede 	if (ret)
177*8c5795feSHans de Goede 		goto out_err;
178*8c5795feSHans de Goede 
179*8c5795feSHans de Goede 	acc |= reg_val << 16;
180*8c5795feSHans de Goede 
181*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_CC_ACC3_REG, &reg_val);
182*8c5795feSHans de Goede 	if (ret)
183*8c5795feSHans de Goede 		goto out_err;
184*8c5795feSHans de Goede 
185*8c5795feSHans de Goede 	acc |= reg_val << 24;
186*8c5795feSHans de Goede 
187*8c5795feSHans de Goede 	/* Step 2: Read SMPL_CTR0 - SMPL_CTR2 */
188*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR0_REG, &reg_val);
189*8c5795feSHans de Goede 	if (ret)
190*8c5795feSHans de Goede 		goto out_err;
191*8c5795feSHans de Goede 
192*8c5795feSHans de Goede 	smpl_ctr = reg_val;
193*8c5795feSHans de Goede 
194*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR1_REG, &reg_val);
195*8c5795feSHans de Goede 	if (ret)
196*8c5795feSHans de Goede 		goto out_err;
197*8c5795feSHans de Goede 
198*8c5795feSHans de Goede 	smpl_ctr |= reg_val << 8;
199*8c5795feSHans de Goede 
200*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_SMPL_CTR2_REG, &reg_val);
201*8c5795feSHans de Goede 	if (ret)
202*8c5795feSHans de Goede 		goto out_err;
203*8c5795feSHans de Goede 
204*8c5795feSHans de Goede 	smpl_ctr |= reg_val << 16;
205*8c5795feSHans de Goede 
206*8c5795feSHans de Goede 	/* Disable the coulumb-counter again */
207*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG,
208*8c5795feSHans de Goede 			   CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN);
209*8c5795feSHans de Goede 	if (ret)
210*8c5795feSHans de Goede 		goto out_err;
211*8c5795feSHans de Goede 
212*8c5795feSHans de Goede 	/* Apply calibration */
213*8c5795feSHans de Goede 	acc -= chip->cc_offset * smpl_ctr * SMPL_INTVL_MS /
214*8c5795feSHans de Goede 	       (CC_OFFSET_SMPL_INTVL_MS * CC_OFFSET_DIV);
215*8c5795feSHans de Goede 	acc = acc * (CC_GAIN_DIV - chip->cc_gain * CC_GAIN_STEP) / CC_GAIN_DIV;
216*8c5795feSHans de Goede 	*curr = CC_ACC_TO_UA(acc, smpl_ctr);
217*8c5795feSHans de Goede 
218*8c5795feSHans de Goede 	return 0;
219*8c5795feSHans de Goede 
220*8c5795feSHans de Goede out_err:
221*8c5795feSHans de Goede 	dev_err(chip->dev, "IO-error %d communicating with PMIC\n", ret);
222*8c5795feSHans de Goede 	return ret;
223*8c5795feSHans de Goede }
224*8c5795feSHans de Goede 
225*8c5795feSHans de Goede static const struct power_supply_desc dc_ti_battery_psy_desc = {
226*8c5795feSHans de Goede 	.name		= "intel_dc_ti_battery",
227*8c5795feSHans de Goede 	.type		= POWER_SUPPLY_TYPE_BATTERY,
228*8c5795feSHans de Goede 	.get_property	= adc_battery_helper_get_property,
229*8c5795feSHans de Goede 	.external_power_changed	= adc_battery_helper_external_power_changed,
230*8c5795feSHans de Goede 	.properties	= adc_battery_helper_properties,
231*8c5795feSHans de Goede 	.num_properties	= ADC_HELPER_NUM_PROPERTIES,
232*8c5795feSHans de Goede };
233*8c5795feSHans de Goede 
234*8c5795feSHans de Goede static int dc_ti_battery_hw_init(struct dc_ti_battery_chip *chip)
235*8c5795feSHans de Goede {
236*8c5795feSHans de Goede 	u8 pmic_version, cc_trim_rev;
237*8c5795feSHans de Goede 	unsigned int reg_val;
238*8c5795feSHans de Goede 	int ret;
239*8c5795feSHans de Goede 
240*8c5795feSHans de Goede 	/* Set sample rate to 15 ms and calibrate the coulomb-counter */
241*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG,
242*8c5795feSHans de Goede 			   CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN |
243*8c5795feSHans de Goede 			   CC_CNTL_CC_CAL_EN | CC_CNTL_CC_CTR_EN);
244*8c5795feSHans de Goede 	if (ret)
245*8c5795feSHans de Goede 		goto out;
246*8c5795feSHans de Goede 
247*8c5795feSHans de Goede 	fsleep(CALIBRATION_TIME_US);
248*8c5795feSHans de Goede 
249*8c5795feSHans de Goede 	/* Disable coulomb-counter it is only used while getting the current */
250*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_CC_CNTL_REG,
251*8c5795feSHans de Goede 			   CC_CNTL_SMPL_INTVL_15MS | CC_CNTL_CC_OFFSET_EN);
252*8c5795feSHans de Goede 	if (ret)
253*8c5795feSHans de Goede 		goto out;
254*8c5795feSHans de Goede 
255*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_PMIC_VERSION_REG, &reg_val);
256*8c5795feSHans de Goede 	if (ret)
257*8c5795feSHans de Goede 		goto out;
258*8c5795feSHans de Goede 
259*8c5795feSHans de Goede 	pmic_version = reg_val;
260*8c5795feSHans de Goede 
261*8c5795feSHans de Goede 	/*
262*8c5795feSHans de Goede 	 * As per the PMIC vendor (TI), the calibration offset and gain err
263*8c5795feSHans de Goede 	 * values are stored in EEPROM Bank 0 and Bank 1 of the PMIC.
264*8c5795feSHans de Goede 	 * We need to read the stored offset and gain margins and need
265*8c5795feSHans de Goede 	 * to apply the corrections to the raw coulomb counter value.
266*8c5795feSHans de Goede 	 */
267*8c5795feSHans de Goede 
268*8c5795feSHans de Goede 	/* Unlock the EEPROM Access */
269*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_EEPROM_ACCESS_CONTROL, EEPROM_UNLOCK);
270*8c5795feSHans de Goede 	if (ret)
271*8c5795feSHans de Goede 		goto out;
272*8c5795feSHans de Goede 
273*8c5795feSHans de Goede 	/* Select Bank 1 to read CC GAIN Err correction */
274*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_EEPROM_CTRL, EEPROM_BANK1_SEL);
275*8c5795feSHans de Goede 	if (ret)
276*8c5795feSHans de Goede 		goto out;
277*8c5795feSHans de Goede 
278*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_EEPROM_CC_GAIN_REG, &reg_val);
279*8c5795feSHans de Goede 	if (ret)
280*8c5795feSHans de Goede 		goto out;
281*8c5795feSHans de Goede 
282*8c5795feSHans de Goede 	cc_trim_rev = FIELD_GET(CC_TRIM_REVISION, reg_val);
283*8c5795feSHans de Goede 
284*8c5795feSHans de Goede 	dev_dbg(chip->dev, "pmic-ver 0x%02x trim-rev %d\n", pmic_version, cc_trim_rev);
285*8c5795feSHans de Goede 
286*8c5795feSHans de Goede 	if (!(pmic_version == PMIC_VERSION_A0 && cc_trim_rev == PMIC_VERSION_A0_TRIM_REV) &&
287*8c5795feSHans de Goede 	    !(pmic_version == PMIC_VERSION_A1 && cc_trim_rev >= PMIC_VERSION_A1_MIN_TRIM_REV)) {
288*8c5795feSHans de Goede 		dev_dbg(chip->dev, "unsupported trim-revision, using uncalibrated CC values\n");
289*8c5795feSHans de Goede 		goto out_relock;
290*8c5795feSHans de Goede 	}
291*8c5795feSHans de Goede 
292*8c5795feSHans de Goede 	chip->cc_gain = 1 - (int)FIELD_GET(CC_GAIN_CORRECTION, reg_val);
293*8c5795feSHans de Goede 
294*8c5795feSHans de Goede 	/* Select Bank 0 to read CC OFFSET Correction */
295*8c5795feSHans de Goede 	ret = regmap_write(chip->regmap, DC_TI_EEPROM_CTRL, EEPROM_BANK0_SEL);
296*8c5795feSHans de Goede 	if (ret)
297*8c5795feSHans de Goede 		goto out_relock;
298*8c5795feSHans de Goede 
299*8c5795feSHans de Goede 	ret = regmap_read(chip->regmap, DC_TI_EEPROM_CC_OFFSET_REG, &reg_val);
300*8c5795feSHans de Goede 	if (ret)
301*8c5795feSHans de Goede 		goto out_relock;
302*8c5795feSHans de Goede 
303*8c5795feSHans de Goede 	chip->cc_offset = (s8)reg_val;
304*8c5795feSHans de Goede 
305*8c5795feSHans de Goede 	dev_dbg(chip->dev, "cc-offset %d cc-gain %d\n", chip->cc_offset, chip->cc_gain);
306*8c5795feSHans de Goede 
307*8c5795feSHans de Goede out_relock:
308*8c5795feSHans de Goede 	/* Re-lock the EEPROM Access */
309*8c5795feSHans de Goede 	regmap_write(chip->regmap, DC_TI_EEPROM_ACCESS_CONTROL, EEPROM_LOCK);
310*8c5795feSHans de Goede out:
311*8c5795feSHans de Goede 	if (ret)
312*8c5795feSHans de Goede 		dev_err(chip->dev, "IO-error %d initializing PMIC\n", ret);
313*8c5795feSHans de Goede 
314*8c5795feSHans de Goede 	return ret;
315*8c5795feSHans de Goede }
316*8c5795feSHans de Goede 
317*8c5795feSHans de Goede static int dc_ti_battery_probe(struct platform_device *pdev)
318*8c5795feSHans de Goede {
319*8c5795feSHans de Goede 	struct device *dev = &pdev->dev;
320*8c5795feSHans de Goede 	struct intel_soc_pmic *pmic = dev_get_drvdata(dev->parent);
321*8c5795feSHans de Goede 	struct power_supply_config psy_cfg = {};
322*8c5795feSHans de Goede 	struct fwnode_reference_args args;
323*8c5795feSHans de Goede 	struct gpio_desc *charge_finished;
324*8c5795feSHans de Goede 	struct dc_ti_battery_chip *chip;
325*8c5795feSHans de Goede 	int ret;
326*8c5795feSHans de Goede 
327*8c5795feSHans de Goede 	/* On most devices with a Dollar Cove TI the battery is handled by ACPI */
328*8c5795feSHans de Goede 	if (!acpi_quirk_skip_acpi_ac_and_battery())
329*8c5795feSHans de Goede 		return -ENODEV;
330*8c5795feSHans de Goede 
331*8c5795feSHans de Goede 	/* ACPI glue code adds a "monitored-battery" fwnode, wait for this */
332*8c5795feSHans de Goede 	ret = fwnode_property_get_reference_args(dev_fwnode(dev), "monitored-battery",
333*8c5795feSHans de Goede 						 NULL, 0, 0, &args);
334*8c5795feSHans de Goede 	if (ret) {
335*8c5795feSHans de Goede 		dev_dbg(dev, "fwnode_property_get_ref() ret %d\n", ret);
336*8c5795feSHans de Goede 		return dev_err_probe(dev, -EPROBE_DEFER, "Waiting for monitored-battery fwnode\n");
337*8c5795feSHans de Goede 	}
338*8c5795feSHans de Goede 
339*8c5795feSHans de Goede 	fwnode_handle_put(args.fwnode);
340*8c5795feSHans de Goede 
341*8c5795feSHans de Goede 	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
342*8c5795feSHans de Goede 	if (!chip)
343*8c5795feSHans de Goede 		return -ENOMEM;
344*8c5795feSHans de Goede 
345*8c5795feSHans de Goede 	chip->dev = dev;
346*8c5795feSHans de Goede 	chip->regmap = pmic->regmap;
347*8c5795feSHans de Goede 
348*8c5795feSHans de Goede 	chip->vbat_channel = devm_iio_channel_get(dev, "VBAT");
349*8c5795feSHans de Goede 	if (IS_ERR(chip->vbat_channel)) {
350*8c5795feSHans de Goede 		dev_dbg(dev, "devm_iio_channel_get() ret %ld\n", PTR_ERR(chip->vbat_channel));
351*8c5795feSHans de Goede 		return dev_err_probe(dev, -EPROBE_DEFER, "Waiting for VBAT IIO channel\n");
352*8c5795feSHans de Goede 	}
353*8c5795feSHans de Goede 
354*8c5795feSHans de Goede 	charge_finished = devm_gpiod_get_optional(dev, "charged", GPIOD_IN);
355*8c5795feSHans de Goede 	if (IS_ERR(charge_finished))
356*8c5795feSHans de Goede 		return dev_err_probe(dev, PTR_ERR(charge_finished), "Getting charged GPIO\n");
357*8c5795feSHans de Goede 
358*8c5795feSHans de Goede 	ret = dc_ti_battery_hw_init(chip);
359*8c5795feSHans de Goede 	if (ret)
360*8c5795feSHans de Goede 		return ret;
361*8c5795feSHans de Goede 
362*8c5795feSHans de Goede 	platform_set_drvdata(pdev, chip);
363*8c5795feSHans de Goede 
364*8c5795feSHans de Goede 	psy_cfg.drv_data = chip;
365*8c5795feSHans de Goede 	chip->psy = devm_power_supply_register(dev, &dc_ti_battery_psy_desc, &psy_cfg);
366*8c5795feSHans de Goede 	if (IS_ERR(chip->psy))
367*8c5795feSHans de Goede 		return PTR_ERR(chip->psy);
368*8c5795feSHans de Goede 
369*8c5795feSHans de Goede 	return adc_battery_helper_init(&chip->helper, chip->psy,
370*8c5795feSHans de Goede 				       dc_ti_battery_get_voltage_and_current_now,
371*8c5795feSHans de Goede 				       charge_finished);
372*8c5795feSHans de Goede }
373*8c5795feSHans de Goede 
374*8c5795feSHans de Goede static DEFINE_RUNTIME_DEV_PM_OPS(dc_ti_battery_pm_ops, adc_battery_helper_suspend,
375*8c5795feSHans de Goede 				 adc_battery_helper_resume, NULL);
376*8c5795feSHans de Goede 
377*8c5795feSHans de Goede static struct platform_driver dc_ti_battery_driver = {
378*8c5795feSHans de Goede 	.driver = {
379*8c5795feSHans de Goede 		.name = DEV_NAME,
380*8c5795feSHans de Goede 		.pm = pm_sleep_ptr(&dc_ti_battery_pm_ops),
381*8c5795feSHans de Goede 	},
382*8c5795feSHans de Goede 	.probe = dc_ti_battery_probe,
383*8c5795feSHans de Goede };
384*8c5795feSHans de Goede module_platform_driver(dc_ti_battery_driver);
385*8c5795feSHans de Goede 
386*8c5795feSHans de Goede MODULE_ALIAS("platform:" DEV_NAME);
387*8c5795feSHans de Goede MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>");
388*8c5795feSHans de Goede MODULE_DESCRIPTION("Intel Dollar Cove (TI) battery driver");
389*8c5795feSHans de Goede MODULE_LICENSE("GPL");
390