xref: /OK3568_Linux_fs/kernel/drivers/power/supply/sc27xx_fuel_gauge.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun // Copyright (C) 2018 Spreadtrum Communications Inc.
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
5*4882a593Smuzhiyun #include <linux/iio/consumer.h>
6*4882a593Smuzhiyun #include <linux/interrupt.h>
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/math64.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/nvmem-consumer.h>
11*4882a593Smuzhiyun #include <linux/of.h>
12*4882a593Smuzhiyun #include <linux/platform_device.h>
13*4882a593Smuzhiyun #include <linux/power_supply.h>
14*4882a593Smuzhiyun #include <linux/regmap.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun /* PMIC global control registers definition */
18*4882a593Smuzhiyun #define SC27XX_MODULE_EN0		0xc08
19*4882a593Smuzhiyun #define SC27XX_CLK_EN0			0xc18
20*4882a593Smuzhiyun #define SC27XX_FGU_EN			BIT(7)
21*4882a593Smuzhiyun #define SC27XX_FGU_RTC_EN		BIT(6)
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* FGU registers definition */
24*4882a593Smuzhiyun #define SC27XX_FGU_START		0x0
25*4882a593Smuzhiyun #define SC27XX_FGU_CONFIG		0x4
26*4882a593Smuzhiyun #define SC27XX_FGU_ADC_CONFIG		0x8
27*4882a593Smuzhiyun #define SC27XX_FGU_STATUS		0xc
28*4882a593Smuzhiyun #define SC27XX_FGU_INT_EN		0x10
29*4882a593Smuzhiyun #define SC27XX_FGU_INT_CLR		0x14
30*4882a593Smuzhiyun #define SC27XX_FGU_INT_STS		0x1c
31*4882a593Smuzhiyun #define SC27XX_FGU_VOLTAGE		0x20
32*4882a593Smuzhiyun #define SC27XX_FGU_OCV			0x24
33*4882a593Smuzhiyun #define SC27XX_FGU_POCV			0x28
34*4882a593Smuzhiyun #define SC27XX_FGU_CURRENT		0x2c
35*4882a593Smuzhiyun #define SC27XX_FGU_LOW_OVERLOAD		0x34
36*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_SETH		0x50
37*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_SETL		0x54
38*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_DELTH		0x58
39*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_DELTL		0x5c
40*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_VALH		0x68
41*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_VALL		0x6c
42*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_QMAXL		0x74
43*4882a593Smuzhiyun #define SC27XX_FGU_USER_AREA_SET	0xa0
44*4882a593Smuzhiyun #define SC27XX_FGU_USER_AREA_CLEAR	0xa4
45*4882a593Smuzhiyun #define SC27XX_FGU_USER_AREA_STATUS	0xa8
46*4882a593Smuzhiyun #define SC27XX_FGU_VOLTAGE_BUF		0xd0
47*4882a593Smuzhiyun #define SC27XX_FGU_CURRENT_BUF		0xf0
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define SC27XX_WRITE_SELCLB_EN		BIT(0)
50*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_MASK		GENMASK(15, 0)
51*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_SHIFT		16
52*4882a593Smuzhiyun #define SC27XX_FGU_LOW_OVERLOAD_MASK	GENMASK(12, 0)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define SC27XX_FGU_INT_MASK		GENMASK(9, 0)
55*4882a593Smuzhiyun #define SC27XX_FGU_LOW_OVERLOAD_INT	BIT(0)
56*4882a593Smuzhiyun #define SC27XX_FGU_CLBCNT_DELTA_INT	BIT(2)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define SC27XX_FGU_MODE_AREA_MASK	GENMASK(15, 12)
59*4882a593Smuzhiyun #define SC27XX_FGU_CAP_AREA_MASK	GENMASK(11, 0)
60*4882a593Smuzhiyun #define SC27XX_FGU_MODE_AREA_SHIFT	12
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun #define SC27XX_FGU_FIRST_POWERTON	GENMASK(3, 0)
63*4882a593Smuzhiyun #define SC27XX_FGU_DEFAULT_CAP		GENMASK(11, 0)
64*4882a593Smuzhiyun #define SC27XX_FGU_NORMAIL_POWERTON	0x5
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define SC27XX_FGU_CUR_BASIC_ADC	8192
67*4882a593Smuzhiyun #define SC27XX_FGU_SAMPLE_HZ		2
68*4882a593Smuzhiyun /* micro Ohms */
69*4882a593Smuzhiyun #define SC27XX_FGU_IDEAL_RESISTANCE	20000
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /*
72*4882a593Smuzhiyun  * struct sc27xx_fgu_data: describe the FGU device
73*4882a593Smuzhiyun  * @regmap: regmap for register access
74*4882a593Smuzhiyun  * @dev: platform device
75*4882a593Smuzhiyun  * @battery: battery power supply
76*4882a593Smuzhiyun  * @base: the base offset for the controller
77*4882a593Smuzhiyun  * @lock: protect the structure
78*4882a593Smuzhiyun  * @gpiod: GPIO for battery detection
79*4882a593Smuzhiyun  * @channel: IIO channel to get battery temperature
80*4882a593Smuzhiyun  * @charge_chan: IIO channel to get charge voltage
81*4882a593Smuzhiyun  * @internal_resist: the battery internal resistance in mOhm
82*4882a593Smuzhiyun  * @total_cap: the total capacity of the battery in mAh
83*4882a593Smuzhiyun  * @init_cap: the initial capacity of the battery in mAh
84*4882a593Smuzhiyun  * @alarm_cap: the alarm capacity
85*4882a593Smuzhiyun  * @init_clbcnt: the initial coulomb counter
86*4882a593Smuzhiyun  * @max_volt: the maximum constant input voltage in millivolt
87*4882a593Smuzhiyun  * @min_volt: the minimum drained battery voltage in microvolt
88*4882a593Smuzhiyun  * @boot_volt: the voltage measured during boot in microvolt
89*4882a593Smuzhiyun  * @table_len: the capacity table length
90*4882a593Smuzhiyun  * @resist_table_len: the resistance table length
91*4882a593Smuzhiyun  * @cur_1000ma_adc: ADC value corresponding to 1000 mA
92*4882a593Smuzhiyun  * @vol_1000mv_adc: ADC value corresponding to 1000 mV
93*4882a593Smuzhiyun  * @calib_resist: the real resistance of coulomb counter chip in uOhm
94*4882a593Smuzhiyun  * @cap_table: capacity table with corresponding ocv
95*4882a593Smuzhiyun  * @resist_table: resistance percent table with corresponding temperature
96*4882a593Smuzhiyun  */
97*4882a593Smuzhiyun struct sc27xx_fgu_data {
98*4882a593Smuzhiyun 	struct regmap *regmap;
99*4882a593Smuzhiyun 	struct device *dev;
100*4882a593Smuzhiyun 	struct power_supply *battery;
101*4882a593Smuzhiyun 	u32 base;
102*4882a593Smuzhiyun 	struct mutex lock;
103*4882a593Smuzhiyun 	struct gpio_desc *gpiod;
104*4882a593Smuzhiyun 	struct iio_channel *channel;
105*4882a593Smuzhiyun 	struct iio_channel *charge_chan;
106*4882a593Smuzhiyun 	bool bat_present;
107*4882a593Smuzhiyun 	int internal_resist;
108*4882a593Smuzhiyun 	int total_cap;
109*4882a593Smuzhiyun 	int init_cap;
110*4882a593Smuzhiyun 	int alarm_cap;
111*4882a593Smuzhiyun 	int init_clbcnt;
112*4882a593Smuzhiyun 	int max_volt;
113*4882a593Smuzhiyun 	int min_volt;
114*4882a593Smuzhiyun 	int boot_volt;
115*4882a593Smuzhiyun 	int table_len;
116*4882a593Smuzhiyun 	int resist_table_len;
117*4882a593Smuzhiyun 	int cur_1000ma_adc;
118*4882a593Smuzhiyun 	int vol_1000mv_adc;
119*4882a593Smuzhiyun 	int calib_resist;
120*4882a593Smuzhiyun 	struct power_supply_battery_ocv_table *cap_table;
121*4882a593Smuzhiyun 	struct power_supply_resistance_temp_table *resist_table;
122*4882a593Smuzhiyun };
123*4882a593Smuzhiyun 
124*4882a593Smuzhiyun static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity);
125*4882a593Smuzhiyun static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
126*4882a593Smuzhiyun 					    int cap, bool int_mode);
127*4882a593Smuzhiyun static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap);
128*4882a593Smuzhiyun static int sc27xx_fgu_get_temp(struct sc27xx_fgu_data *data, int *temp);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun static const char * const sc27xx_charger_supply_name[] = {
131*4882a593Smuzhiyun 	"sc2731_charger",
132*4882a593Smuzhiyun 	"sc2720_charger",
133*4882a593Smuzhiyun 	"sc2721_charger",
134*4882a593Smuzhiyun 	"sc2723_charger",
135*4882a593Smuzhiyun };
136*4882a593Smuzhiyun 
sc27xx_fgu_adc_to_current(struct sc27xx_fgu_data * data,s64 adc)137*4882a593Smuzhiyun static int sc27xx_fgu_adc_to_current(struct sc27xx_fgu_data *data, s64 adc)
138*4882a593Smuzhiyun {
139*4882a593Smuzhiyun 	return DIV_S64_ROUND_CLOSEST(adc * 1000, data->cur_1000ma_adc);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
sc27xx_fgu_adc_to_voltage(struct sc27xx_fgu_data * data,s64 adc)142*4882a593Smuzhiyun static int sc27xx_fgu_adc_to_voltage(struct sc27xx_fgu_data *data, s64 adc)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	return DIV_S64_ROUND_CLOSEST(adc * 1000, data->vol_1000mv_adc);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
sc27xx_fgu_voltage_to_adc(struct sc27xx_fgu_data * data,int vol)147*4882a593Smuzhiyun static int sc27xx_fgu_voltage_to_adc(struct sc27xx_fgu_data *data, int vol)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	return DIV_ROUND_CLOSEST(vol * data->vol_1000mv_adc, 1000);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
sc27xx_fgu_is_first_poweron(struct sc27xx_fgu_data * data)152*4882a593Smuzhiyun static bool sc27xx_fgu_is_first_poweron(struct sc27xx_fgu_data *data)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	int ret, status, cap, mode;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	ret = regmap_read(data->regmap,
157*4882a593Smuzhiyun 			  data->base + SC27XX_FGU_USER_AREA_STATUS, &status);
158*4882a593Smuzhiyun 	if (ret)
159*4882a593Smuzhiyun 		return false;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	/*
162*4882a593Smuzhiyun 	 * We use low 4 bits to save the last battery capacity and high 12 bits
163*4882a593Smuzhiyun 	 * to save the system boot mode.
164*4882a593Smuzhiyun 	 */
165*4882a593Smuzhiyun 	mode = (status & SC27XX_FGU_MODE_AREA_MASK) >> SC27XX_FGU_MODE_AREA_SHIFT;
166*4882a593Smuzhiyun 	cap = status & SC27XX_FGU_CAP_AREA_MASK;
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	/*
169*4882a593Smuzhiyun 	 * When FGU has been powered down, the user area registers became
170*4882a593Smuzhiyun 	 * default value (0xffff), which can be used to valid if the system is
171*4882a593Smuzhiyun 	 * first power on or not.
172*4882a593Smuzhiyun 	 */
173*4882a593Smuzhiyun 	if (mode == SC27XX_FGU_FIRST_POWERTON || cap == SC27XX_FGU_DEFAULT_CAP)
174*4882a593Smuzhiyun 		return true;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	return false;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
sc27xx_fgu_save_boot_mode(struct sc27xx_fgu_data * data,int boot_mode)179*4882a593Smuzhiyun static int sc27xx_fgu_save_boot_mode(struct sc27xx_fgu_data *data,
180*4882a593Smuzhiyun 				     int boot_mode)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	int ret;
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap,
185*4882a593Smuzhiyun 				 data->base + SC27XX_FGU_USER_AREA_CLEAR,
186*4882a593Smuzhiyun 				 SC27XX_FGU_MODE_AREA_MASK,
187*4882a593Smuzhiyun 				 SC27XX_FGU_MODE_AREA_MASK);
188*4882a593Smuzhiyun 	if (ret)
189*4882a593Smuzhiyun 		return ret;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/*
192*4882a593Smuzhiyun 	 * Since the user area registers are put on power always-on region,
193*4882a593Smuzhiyun 	 * then these registers changing time will be a little long. Thus
194*4882a593Smuzhiyun 	 * here we should delay 200us to wait until values are updated
195*4882a593Smuzhiyun 	 * successfully according to the datasheet.
196*4882a593Smuzhiyun 	 */
197*4882a593Smuzhiyun 	udelay(200);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap,
200*4882a593Smuzhiyun 				 data->base + SC27XX_FGU_USER_AREA_SET,
201*4882a593Smuzhiyun 				 SC27XX_FGU_MODE_AREA_MASK,
202*4882a593Smuzhiyun 				 boot_mode << SC27XX_FGU_MODE_AREA_SHIFT);
203*4882a593Smuzhiyun 	if (ret)
204*4882a593Smuzhiyun 		return ret;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	/*
207*4882a593Smuzhiyun 	 * Since the user area registers are put on power always-on region,
208*4882a593Smuzhiyun 	 * then these registers changing time will be a little long. Thus
209*4882a593Smuzhiyun 	 * here we should delay 200us to wait until values are updated
210*4882a593Smuzhiyun 	 * successfully according to the datasheet.
211*4882a593Smuzhiyun 	 */
212*4882a593Smuzhiyun 	udelay(200);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	/*
215*4882a593Smuzhiyun 	 * According to the datasheet, we should set the USER_AREA_CLEAR to 0 to
216*4882a593Smuzhiyun 	 * make the user area data available, otherwise we can not save the user
217*4882a593Smuzhiyun 	 * area data.
218*4882a593Smuzhiyun 	 */
219*4882a593Smuzhiyun 	return regmap_update_bits(data->regmap,
220*4882a593Smuzhiyun 				  data->base + SC27XX_FGU_USER_AREA_CLEAR,
221*4882a593Smuzhiyun 				  SC27XX_FGU_MODE_AREA_MASK, 0);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data * data,int cap)224*4882a593Smuzhiyun static int sc27xx_fgu_save_last_cap(struct sc27xx_fgu_data *data, int cap)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	int ret;
227*4882a593Smuzhiyun 
228*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap,
229*4882a593Smuzhiyun 				 data->base + SC27XX_FGU_USER_AREA_CLEAR,
230*4882a593Smuzhiyun 				 SC27XX_FGU_CAP_AREA_MASK,
231*4882a593Smuzhiyun 				 SC27XX_FGU_CAP_AREA_MASK);
232*4882a593Smuzhiyun 	if (ret)
233*4882a593Smuzhiyun 		return ret;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/*
236*4882a593Smuzhiyun 	 * Since the user area registers are put on power always-on region,
237*4882a593Smuzhiyun 	 * then these registers changing time will be a little long. Thus
238*4882a593Smuzhiyun 	 * here we should delay 200us to wait until values are updated
239*4882a593Smuzhiyun 	 * successfully according to the datasheet.
240*4882a593Smuzhiyun 	 */
241*4882a593Smuzhiyun 	udelay(200);
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap,
244*4882a593Smuzhiyun 				 data->base + SC27XX_FGU_USER_AREA_SET,
245*4882a593Smuzhiyun 				 SC27XX_FGU_CAP_AREA_MASK, cap);
246*4882a593Smuzhiyun 	if (ret)
247*4882a593Smuzhiyun 		return ret;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	/*
250*4882a593Smuzhiyun 	 * Since the user area registers are put on power always-on region,
251*4882a593Smuzhiyun 	 * then these registers changing time will be a little long. Thus
252*4882a593Smuzhiyun 	 * here we should delay 200us to wait until values are updated
253*4882a593Smuzhiyun 	 * successfully according to the datasheet.
254*4882a593Smuzhiyun 	 */
255*4882a593Smuzhiyun 	udelay(200);
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/*
258*4882a593Smuzhiyun 	 * According to the datasheet, we should set the USER_AREA_CLEAR to 0 to
259*4882a593Smuzhiyun 	 * make the user area data available, otherwise we can not save the user
260*4882a593Smuzhiyun 	 * area data.
261*4882a593Smuzhiyun 	 */
262*4882a593Smuzhiyun 	return regmap_update_bits(data->regmap,
263*4882a593Smuzhiyun 				  data->base + SC27XX_FGU_USER_AREA_CLEAR,
264*4882a593Smuzhiyun 				  SC27XX_FGU_CAP_AREA_MASK, 0);
265*4882a593Smuzhiyun }
266*4882a593Smuzhiyun 
sc27xx_fgu_read_last_cap(struct sc27xx_fgu_data * data,int * cap)267*4882a593Smuzhiyun static int sc27xx_fgu_read_last_cap(struct sc27xx_fgu_data *data, int *cap)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	int ret, value;
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	ret = regmap_read(data->regmap,
272*4882a593Smuzhiyun 			  data->base + SC27XX_FGU_USER_AREA_STATUS, &value);
273*4882a593Smuzhiyun 	if (ret)
274*4882a593Smuzhiyun 		return ret;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	*cap = value & SC27XX_FGU_CAP_AREA_MASK;
277*4882a593Smuzhiyun 	return 0;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun /*
281*4882a593Smuzhiyun  * When system boots on, we can not read battery capacity from coulomb
282*4882a593Smuzhiyun  * registers, since now the coulomb registers are invalid. So we should
283*4882a593Smuzhiyun  * calculate the battery open circuit voltage, and get current battery
284*4882a593Smuzhiyun  * capacity according to the capacity table.
285*4882a593Smuzhiyun  */
sc27xx_fgu_get_boot_capacity(struct sc27xx_fgu_data * data,int * cap)286*4882a593Smuzhiyun static int sc27xx_fgu_get_boot_capacity(struct sc27xx_fgu_data *data, int *cap)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	int volt, cur, oci, ocv, ret;
289*4882a593Smuzhiyun 	bool is_first_poweron = sc27xx_fgu_is_first_poweron(data);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/*
292*4882a593Smuzhiyun 	 * If system is not the first power on, we should use the last saved
293*4882a593Smuzhiyun 	 * battery capacity as the initial battery capacity. Otherwise we should
294*4882a593Smuzhiyun 	 * re-calculate the initial battery capacity.
295*4882a593Smuzhiyun 	 */
296*4882a593Smuzhiyun 	if (!is_first_poweron) {
297*4882a593Smuzhiyun 		ret = sc27xx_fgu_read_last_cap(data, cap);
298*4882a593Smuzhiyun 		if (ret)
299*4882a593Smuzhiyun 			return ret;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 		return sc27xx_fgu_save_boot_mode(data, SC27XX_FGU_NORMAIL_POWERTON);
302*4882a593Smuzhiyun 	}
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	/*
305*4882a593Smuzhiyun 	 * After system booting on, the SC27XX_FGU_CLBCNT_QMAXL register saved
306*4882a593Smuzhiyun 	 * the first sampled open circuit current.
307*4882a593Smuzhiyun 	 */
308*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CLBCNT_QMAXL,
309*4882a593Smuzhiyun 			  &cur);
310*4882a593Smuzhiyun 	if (ret)
311*4882a593Smuzhiyun 		return ret;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	cur <<= 1;
314*4882a593Smuzhiyun 	oci = sc27xx_fgu_adc_to_current(data, cur - SC27XX_FGU_CUR_BASIC_ADC);
315*4882a593Smuzhiyun 
316*4882a593Smuzhiyun 	/*
317*4882a593Smuzhiyun 	 * Should get the OCV from SC27XX_FGU_POCV register at the system
318*4882a593Smuzhiyun 	 * beginning. It is ADC values reading from registers which need to
319*4882a593Smuzhiyun 	 * convert the corresponding voltage.
320*4882a593Smuzhiyun 	 */
321*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_POCV, &volt);
322*4882a593Smuzhiyun 	if (ret)
323*4882a593Smuzhiyun 		return ret;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	volt = sc27xx_fgu_adc_to_voltage(data, volt);
326*4882a593Smuzhiyun 	ocv = volt * 1000 - oci * data->internal_resist;
327*4882a593Smuzhiyun 	data->boot_volt = ocv;
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	/*
330*4882a593Smuzhiyun 	 * Parse the capacity table to look up the correct capacity percent
331*4882a593Smuzhiyun 	 * according to current battery's corresponding OCV values.
332*4882a593Smuzhiyun 	 */
333*4882a593Smuzhiyun 	*cap = power_supply_ocv2cap_simple(data->cap_table, data->table_len,
334*4882a593Smuzhiyun 					   ocv);
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	ret = sc27xx_fgu_save_last_cap(data, *cap);
337*4882a593Smuzhiyun 	if (ret)
338*4882a593Smuzhiyun 		return ret;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	return sc27xx_fgu_save_boot_mode(data, SC27XX_FGU_NORMAIL_POWERTON);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
sc27xx_fgu_set_clbcnt(struct sc27xx_fgu_data * data,int clbcnt)343*4882a593Smuzhiyun static int sc27xx_fgu_set_clbcnt(struct sc27xx_fgu_data *data, int clbcnt)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	int ret;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap,
348*4882a593Smuzhiyun 				 data->base + SC27XX_FGU_CLBCNT_SETL,
349*4882a593Smuzhiyun 				 SC27XX_FGU_CLBCNT_MASK, clbcnt);
350*4882a593Smuzhiyun 	if (ret)
351*4882a593Smuzhiyun 		return ret;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap,
354*4882a593Smuzhiyun 				 data->base + SC27XX_FGU_CLBCNT_SETH,
355*4882a593Smuzhiyun 				 SC27XX_FGU_CLBCNT_MASK,
356*4882a593Smuzhiyun 				 clbcnt >> SC27XX_FGU_CLBCNT_SHIFT);
357*4882a593Smuzhiyun 	if (ret)
358*4882a593Smuzhiyun 		return ret;
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	return regmap_update_bits(data->regmap, data->base + SC27XX_FGU_START,
361*4882a593Smuzhiyun 				 SC27XX_WRITE_SELCLB_EN,
362*4882a593Smuzhiyun 				 SC27XX_WRITE_SELCLB_EN);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
sc27xx_fgu_get_clbcnt(struct sc27xx_fgu_data * data,int * clb_cnt)365*4882a593Smuzhiyun static int sc27xx_fgu_get_clbcnt(struct sc27xx_fgu_data *data, int *clb_cnt)
366*4882a593Smuzhiyun {
367*4882a593Smuzhiyun 	int ccl, cch, ret;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CLBCNT_VALL,
370*4882a593Smuzhiyun 			  &ccl);
371*4882a593Smuzhiyun 	if (ret)
372*4882a593Smuzhiyun 		return ret;
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CLBCNT_VALH,
375*4882a593Smuzhiyun 			  &cch);
376*4882a593Smuzhiyun 	if (ret)
377*4882a593Smuzhiyun 		return ret;
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	*clb_cnt = ccl & SC27XX_FGU_CLBCNT_MASK;
380*4882a593Smuzhiyun 	*clb_cnt |= (cch & SC27XX_FGU_CLBCNT_MASK) << SC27XX_FGU_CLBCNT_SHIFT;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	return 0;
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
sc27xx_fgu_get_vol_now(struct sc27xx_fgu_data * data,int * val)385*4882a593Smuzhiyun static int sc27xx_fgu_get_vol_now(struct sc27xx_fgu_data *data, int *val)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	int ret;
388*4882a593Smuzhiyun 	u32 vol;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_VOLTAGE_BUF,
391*4882a593Smuzhiyun 			  &vol);
392*4882a593Smuzhiyun 	if (ret)
393*4882a593Smuzhiyun 		return ret;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	/*
396*4882a593Smuzhiyun 	 * It is ADC values reading from registers which need to convert to
397*4882a593Smuzhiyun 	 * corresponding voltage values.
398*4882a593Smuzhiyun 	 */
399*4882a593Smuzhiyun 	*val = sc27xx_fgu_adc_to_voltage(data, vol);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	return 0;
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun 
sc27xx_fgu_get_cur_now(struct sc27xx_fgu_data * data,int * val)404*4882a593Smuzhiyun static int sc27xx_fgu_get_cur_now(struct sc27xx_fgu_data *data, int *val)
405*4882a593Smuzhiyun {
406*4882a593Smuzhiyun 	int ret;
407*4882a593Smuzhiyun 	u32 cur;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CURRENT_BUF,
410*4882a593Smuzhiyun 			  &cur);
411*4882a593Smuzhiyun 	if (ret)
412*4882a593Smuzhiyun 		return ret;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 	/*
415*4882a593Smuzhiyun 	 * It is ADC values reading from registers which need to convert to
416*4882a593Smuzhiyun 	 * corresponding current values.
417*4882a593Smuzhiyun 	 */
418*4882a593Smuzhiyun 	*val = sc27xx_fgu_adc_to_current(data, cur - SC27XX_FGU_CUR_BASIC_ADC);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
sc27xx_fgu_get_capacity(struct sc27xx_fgu_data * data,int * cap)423*4882a593Smuzhiyun static int sc27xx_fgu_get_capacity(struct sc27xx_fgu_data *data, int *cap)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	int ret, cur_clbcnt, delta_clbcnt, delta_cap, temp;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/* Get current coulomb counters firstly */
428*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_clbcnt(data, &cur_clbcnt);
429*4882a593Smuzhiyun 	if (ret)
430*4882a593Smuzhiyun 		return ret;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	delta_clbcnt = cur_clbcnt - data->init_clbcnt;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	/*
435*4882a593Smuzhiyun 	 * Convert coulomb counter to delta capacity (mAh), and set multiplier
436*4882a593Smuzhiyun 	 * as 10 to improve the precision.
437*4882a593Smuzhiyun 	 */
438*4882a593Smuzhiyun 	temp = DIV_ROUND_CLOSEST(delta_clbcnt * 10, 36 * SC27XX_FGU_SAMPLE_HZ);
439*4882a593Smuzhiyun 	temp = sc27xx_fgu_adc_to_current(data, temp / 1000);
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	/*
442*4882a593Smuzhiyun 	 * Convert to capacity percent of the battery total capacity,
443*4882a593Smuzhiyun 	 * and multiplier is 100 too.
444*4882a593Smuzhiyun 	 */
445*4882a593Smuzhiyun 	delta_cap = DIV_ROUND_CLOSEST(temp * 100, data->total_cap);
446*4882a593Smuzhiyun 	*cap = delta_cap + data->init_cap;
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun 	/* Calibrate the battery capacity in a normal range. */
449*4882a593Smuzhiyun 	sc27xx_fgu_capacity_calibration(data, *cap, false);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	return 0;
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
sc27xx_fgu_get_vbat_vol(struct sc27xx_fgu_data * data,int * val)454*4882a593Smuzhiyun static int sc27xx_fgu_get_vbat_vol(struct sc27xx_fgu_data *data, int *val)
455*4882a593Smuzhiyun {
456*4882a593Smuzhiyun 	int ret, vol;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_VOLTAGE, &vol);
459*4882a593Smuzhiyun 	if (ret)
460*4882a593Smuzhiyun 		return ret;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	/*
463*4882a593Smuzhiyun 	 * It is ADC values reading from registers which need to convert to
464*4882a593Smuzhiyun 	 * corresponding voltage values.
465*4882a593Smuzhiyun 	 */
466*4882a593Smuzhiyun 	*val = sc27xx_fgu_adc_to_voltage(data, vol);
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	return 0;
469*4882a593Smuzhiyun }
470*4882a593Smuzhiyun 
sc27xx_fgu_get_current(struct sc27xx_fgu_data * data,int * val)471*4882a593Smuzhiyun static int sc27xx_fgu_get_current(struct sc27xx_fgu_data *data, int *val)
472*4882a593Smuzhiyun {
473*4882a593Smuzhiyun 	int ret, cur;
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_CURRENT, &cur);
476*4882a593Smuzhiyun 	if (ret)
477*4882a593Smuzhiyun 		return ret;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	/*
480*4882a593Smuzhiyun 	 * It is ADC values reading from registers which need to convert to
481*4882a593Smuzhiyun 	 * corresponding current values.
482*4882a593Smuzhiyun 	 */
483*4882a593Smuzhiyun 	*val = sc27xx_fgu_adc_to_current(data, cur - SC27XX_FGU_CUR_BASIC_ADC);
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	return 0;
486*4882a593Smuzhiyun }
487*4882a593Smuzhiyun 
sc27xx_fgu_get_vbat_ocv(struct sc27xx_fgu_data * data,int * val)488*4882a593Smuzhiyun static int sc27xx_fgu_get_vbat_ocv(struct sc27xx_fgu_data *data, int *val)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun 	int vol, cur, ret, temp, resistance;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_vbat_vol(data, &vol);
493*4882a593Smuzhiyun 	if (ret)
494*4882a593Smuzhiyun 		return ret;
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_current(data, &cur);
497*4882a593Smuzhiyun 	if (ret)
498*4882a593Smuzhiyun 		return ret;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	resistance = data->internal_resist;
501*4882a593Smuzhiyun 	if (data->resist_table_len > 0) {
502*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_temp(data, &temp);
503*4882a593Smuzhiyun 		if (ret)
504*4882a593Smuzhiyun 			return ret;
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 		resistance = power_supply_temp2resist_simple(data->resist_table,
507*4882a593Smuzhiyun 						data->resist_table_len, temp);
508*4882a593Smuzhiyun 		resistance = data->internal_resist * resistance / 100;
509*4882a593Smuzhiyun 	}
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	/* Return the battery OCV in micro volts. */
512*4882a593Smuzhiyun 	*val = vol * 1000 - cur * resistance;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	return 0;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun 
sc27xx_fgu_get_charge_vol(struct sc27xx_fgu_data * data,int * val)517*4882a593Smuzhiyun static int sc27xx_fgu_get_charge_vol(struct sc27xx_fgu_data *data, int *val)
518*4882a593Smuzhiyun {
519*4882a593Smuzhiyun 	int ret, vol;
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	ret = iio_read_channel_processed(data->charge_chan, &vol);
522*4882a593Smuzhiyun 	if (ret < 0)
523*4882a593Smuzhiyun 		return ret;
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	*val = vol * 1000;
526*4882a593Smuzhiyun 	return 0;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun 
sc27xx_fgu_get_temp(struct sc27xx_fgu_data * data,int * temp)529*4882a593Smuzhiyun static int sc27xx_fgu_get_temp(struct sc27xx_fgu_data *data, int *temp)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun 	return iio_read_channel_processed(data->channel, temp);
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
sc27xx_fgu_get_health(struct sc27xx_fgu_data * data,int * health)534*4882a593Smuzhiyun static int sc27xx_fgu_get_health(struct sc27xx_fgu_data *data, int *health)
535*4882a593Smuzhiyun {
536*4882a593Smuzhiyun 	int ret, vol;
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_vbat_vol(data, &vol);
539*4882a593Smuzhiyun 	if (ret)
540*4882a593Smuzhiyun 		return ret;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	if (vol > data->max_volt)
543*4882a593Smuzhiyun 		*health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
544*4882a593Smuzhiyun 	else
545*4882a593Smuzhiyun 		*health = POWER_SUPPLY_HEALTH_GOOD;
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun 	return 0;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
sc27xx_fgu_get_status(struct sc27xx_fgu_data * data,int * status)550*4882a593Smuzhiyun static int sc27xx_fgu_get_status(struct sc27xx_fgu_data *data, int *status)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	union power_supply_propval val;
553*4882a593Smuzhiyun 	struct power_supply *psy;
554*4882a593Smuzhiyun 	int i, ret = -EINVAL;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(sc27xx_charger_supply_name); i++) {
557*4882a593Smuzhiyun 		psy = power_supply_get_by_name(sc27xx_charger_supply_name[i]);
558*4882a593Smuzhiyun 		if (!psy)
559*4882a593Smuzhiyun 			continue;
560*4882a593Smuzhiyun 
561*4882a593Smuzhiyun 		ret = power_supply_get_property(psy, POWER_SUPPLY_PROP_STATUS,
562*4882a593Smuzhiyun 						&val);
563*4882a593Smuzhiyun 		power_supply_put(psy);
564*4882a593Smuzhiyun 		if (ret)
565*4882a593Smuzhiyun 			return ret;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 		*status = val.intval;
568*4882a593Smuzhiyun 	}
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	return ret;
571*4882a593Smuzhiyun }
572*4882a593Smuzhiyun 
sc27xx_fgu_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)573*4882a593Smuzhiyun static int sc27xx_fgu_get_property(struct power_supply *psy,
574*4882a593Smuzhiyun 				   enum power_supply_property psp,
575*4882a593Smuzhiyun 				   union power_supply_propval *val)
576*4882a593Smuzhiyun {
577*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy);
578*4882a593Smuzhiyun 	int ret = 0;
579*4882a593Smuzhiyun 	int value;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	mutex_lock(&data->lock);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	switch (psp) {
584*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
585*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_status(data, &value);
586*4882a593Smuzhiyun 		if (ret)
587*4882a593Smuzhiyun 			goto error;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 		val->intval = value;
590*4882a593Smuzhiyun 		break;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_HEALTH:
593*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_health(data, &value);
594*4882a593Smuzhiyun 		if (ret)
595*4882a593Smuzhiyun 			goto error;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 		val->intval = value;
598*4882a593Smuzhiyun 		break;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_PRESENT:
601*4882a593Smuzhiyun 		val->intval = data->bat_present;
602*4882a593Smuzhiyun 		break;
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_TEMP:
605*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_temp(data, &value);
606*4882a593Smuzhiyun 		if (ret)
607*4882a593Smuzhiyun 			goto error;
608*4882a593Smuzhiyun 
609*4882a593Smuzhiyun 		val->intval = value;
610*4882a593Smuzhiyun 		break;
611*4882a593Smuzhiyun 
612*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_TECHNOLOGY:
613*4882a593Smuzhiyun 		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
614*4882a593Smuzhiyun 		break;
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CAPACITY:
617*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_capacity(data, &value);
618*4882a593Smuzhiyun 		if (ret)
619*4882a593Smuzhiyun 			goto error;
620*4882a593Smuzhiyun 
621*4882a593Smuzhiyun 		val->intval = value;
622*4882a593Smuzhiyun 		break;
623*4882a593Smuzhiyun 
624*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
625*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_vbat_vol(data, &value);
626*4882a593Smuzhiyun 		if (ret)
627*4882a593Smuzhiyun 			goto error;
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 		val->intval = value * 1000;
630*4882a593Smuzhiyun 		break;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
633*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_vbat_ocv(data, &value);
634*4882a593Smuzhiyun 		if (ret)
635*4882a593Smuzhiyun 			goto error;
636*4882a593Smuzhiyun 
637*4882a593Smuzhiyun 		val->intval = value;
638*4882a593Smuzhiyun 		break;
639*4882a593Smuzhiyun 
640*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
641*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_charge_vol(data, &value);
642*4882a593Smuzhiyun 		if (ret)
643*4882a593Smuzhiyun 			goto error;
644*4882a593Smuzhiyun 
645*4882a593Smuzhiyun 		val->intval = value;
646*4882a593Smuzhiyun 		break;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_AVG:
649*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_current(data, &value);
650*4882a593Smuzhiyun 		if (ret)
651*4882a593Smuzhiyun 			goto error;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 		val->intval = value * 1000;
654*4882a593Smuzhiyun 		break;
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
657*4882a593Smuzhiyun 		val->intval = data->total_cap * 1000;
658*4882a593Smuzhiyun 		break;
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CHARGE_NOW:
661*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_clbcnt(data, &value);
662*4882a593Smuzhiyun 		if (ret)
663*4882a593Smuzhiyun 			goto error;
664*4882a593Smuzhiyun 
665*4882a593Smuzhiyun 		value = DIV_ROUND_CLOSEST(value * 10,
666*4882a593Smuzhiyun 					  36 * SC27XX_FGU_SAMPLE_HZ);
667*4882a593Smuzhiyun 		val->intval = sc27xx_fgu_adc_to_current(data, value);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 		break;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
672*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_vol_now(data, &value);
673*4882a593Smuzhiyun 		if (ret)
674*4882a593Smuzhiyun 			goto error;
675*4882a593Smuzhiyun 
676*4882a593Smuzhiyun 		val->intval = value * 1000;
677*4882a593Smuzhiyun 		break;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CURRENT_NOW:
680*4882a593Smuzhiyun 		ret = sc27xx_fgu_get_cur_now(data, &value);
681*4882a593Smuzhiyun 		if (ret)
682*4882a593Smuzhiyun 			goto error;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 		val->intval = value * 1000;
685*4882a593Smuzhiyun 		break;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_BOOT:
688*4882a593Smuzhiyun 		val->intval = data->boot_volt;
689*4882a593Smuzhiyun 		break;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	default:
692*4882a593Smuzhiyun 		ret = -EINVAL;
693*4882a593Smuzhiyun 		break;
694*4882a593Smuzhiyun 	}
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun error:
697*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
698*4882a593Smuzhiyun 	return ret;
699*4882a593Smuzhiyun }
700*4882a593Smuzhiyun 
sc27xx_fgu_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)701*4882a593Smuzhiyun static int sc27xx_fgu_set_property(struct power_supply *psy,
702*4882a593Smuzhiyun 				   enum power_supply_property psp,
703*4882a593Smuzhiyun 				   const union power_supply_propval *val)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy);
706*4882a593Smuzhiyun 	int ret;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	mutex_lock(&data->lock);
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	switch (psp) {
711*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CAPACITY:
712*4882a593Smuzhiyun 		ret = sc27xx_fgu_save_last_cap(data, val->intval);
713*4882a593Smuzhiyun 		if (ret < 0)
714*4882a593Smuzhiyun 			dev_err(data->dev, "failed to save battery capacity\n");
715*4882a593Smuzhiyun 		break;
716*4882a593Smuzhiyun 
717*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CALIBRATE:
718*4882a593Smuzhiyun 		sc27xx_fgu_adjust_cap(data, val->intval);
719*4882a593Smuzhiyun 		ret = 0;
720*4882a593Smuzhiyun 		break;
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN:
723*4882a593Smuzhiyun 		data->total_cap = val->intval / 1000;
724*4882a593Smuzhiyun 		ret = 0;
725*4882a593Smuzhiyun 		break;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	default:
728*4882a593Smuzhiyun 		ret = -EINVAL;
729*4882a593Smuzhiyun 	}
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun 	return ret;
734*4882a593Smuzhiyun }
735*4882a593Smuzhiyun 
sc27xx_fgu_external_power_changed(struct power_supply * psy)736*4882a593Smuzhiyun static void sc27xx_fgu_external_power_changed(struct power_supply *psy)
737*4882a593Smuzhiyun {
738*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = power_supply_get_drvdata(psy);
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun 	power_supply_changed(data->battery);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun 
sc27xx_fgu_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)743*4882a593Smuzhiyun static int sc27xx_fgu_property_is_writeable(struct power_supply *psy,
744*4882a593Smuzhiyun 					    enum power_supply_property psp)
745*4882a593Smuzhiyun {
746*4882a593Smuzhiyun 	return psp == POWER_SUPPLY_PROP_CAPACITY ||
747*4882a593Smuzhiyun 		psp == POWER_SUPPLY_PROP_CALIBRATE ||
748*4882a593Smuzhiyun 		psp == POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun static enum power_supply_property sc27xx_fgu_props[] = {
752*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_STATUS,
753*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_HEALTH,
754*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_PRESENT,
755*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_TEMP,
756*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_TECHNOLOGY,
757*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CAPACITY,
758*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
759*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_OCV,
760*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
761*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_BOOT,
762*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_NOW,
763*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CURRENT_AVG,
764*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
765*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN,
766*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CALIBRATE,
767*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CHARGE_NOW
768*4882a593Smuzhiyun };
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun static const struct power_supply_desc sc27xx_fgu_desc = {
771*4882a593Smuzhiyun 	.name			= "sc27xx-fgu",
772*4882a593Smuzhiyun 	.type			= POWER_SUPPLY_TYPE_BATTERY,
773*4882a593Smuzhiyun 	.properties		= sc27xx_fgu_props,
774*4882a593Smuzhiyun 	.num_properties		= ARRAY_SIZE(sc27xx_fgu_props),
775*4882a593Smuzhiyun 	.get_property		= sc27xx_fgu_get_property,
776*4882a593Smuzhiyun 	.set_property		= sc27xx_fgu_set_property,
777*4882a593Smuzhiyun 	.external_power_changed	= sc27xx_fgu_external_power_changed,
778*4882a593Smuzhiyun 	.property_is_writeable	= sc27xx_fgu_property_is_writeable,
779*4882a593Smuzhiyun 	.no_thermal		= true,
780*4882a593Smuzhiyun };
781*4882a593Smuzhiyun 
sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data * data,int cap)782*4882a593Smuzhiyun static void sc27xx_fgu_adjust_cap(struct sc27xx_fgu_data *data, int cap)
783*4882a593Smuzhiyun {
784*4882a593Smuzhiyun 	int ret;
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	data->init_cap = cap;
787*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_clbcnt(data, &data->init_clbcnt);
788*4882a593Smuzhiyun 	if (ret)
789*4882a593Smuzhiyun 		dev_err(data->dev, "failed to get init coulomb counter\n");
790*4882a593Smuzhiyun }
791*4882a593Smuzhiyun 
sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data * data,int cap,bool int_mode)792*4882a593Smuzhiyun static void sc27xx_fgu_capacity_calibration(struct sc27xx_fgu_data *data,
793*4882a593Smuzhiyun 					    int cap, bool int_mode)
794*4882a593Smuzhiyun {
795*4882a593Smuzhiyun 	int ret, ocv, chg_sts, adc;
796*4882a593Smuzhiyun 
797*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
798*4882a593Smuzhiyun 	if (ret) {
799*4882a593Smuzhiyun 		dev_err(data->dev, "get battery ocv error.\n");
800*4882a593Smuzhiyun 		return;
801*4882a593Smuzhiyun 	}
802*4882a593Smuzhiyun 
803*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_status(data, &chg_sts);
804*4882a593Smuzhiyun 	if (ret) {
805*4882a593Smuzhiyun 		dev_err(data->dev, "get charger status error.\n");
806*4882a593Smuzhiyun 		return;
807*4882a593Smuzhiyun 	}
808*4882a593Smuzhiyun 
809*4882a593Smuzhiyun 	/*
810*4882a593Smuzhiyun 	 * If we are in charging mode, then we do not need to calibrate the
811*4882a593Smuzhiyun 	 * lower capacity.
812*4882a593Smuzhiyun 	 */
813*4882a593Smuzhiyun 	if (chg_sts == POWER_SUPPLY_STATUS_CHARGING)
814*4882a593Smuzhiyun 		return;
815*4882a593Smuzhiyun 
816*4882a593Smuzhiyun 	if ((ocv > data->cap_table[0].ocv && cap < 100) || cap > 100) {
817*4882a593Smuzhiyun 		/*
818*4882a593Smuzhiyun 		 * If current OCV value is larger than the max OCV value in
819*4882a593Smuzhiyun 		 * OCV table, or the current capacity is larger than 100,
820*4882a593Smuzhiyun 		 * we should force the inititial capacity to 100.
821*4882a593Smuzhiyun 		 */
822*4882a593Smuzhiyun 		sc27xx_fgu_adjust_cap(data, 100);
823*4882a593Smuzhiyun 	} else if (ocv <= data->cap_table[data->table_len - 1].ocv) {
824*4882a593Smuzhiyun 		/*
825*4882a593Smuzhiyun 		 * If current OCV value is leass than the minimum OCV value in
826*4882a593Smuzhiyun 		 * OCV table, we should force the inititial capacity to 0.
827*4882a593Smuzhiyun 		 */
828*4882a593Smuzhiyun 		sc27xx_fgu_adjust_cap(data, 0);
829*4882a593Smuzhiyun 	} else if ((ocv > data->cap_table[data->table_len - 1].ocv && cap <= 0) ||
830*4882a593Smuzhiyun 		   (ocv > data->min_volt && cap <= data->alarm_cap)) {
831*4882a593Smuzhiyun 		/*
832*4882a593Smuzhiyun 		 * If current OCV value is not matchable with current capacity,
833*4882a593Smuzhiyun 		 * we should re-calculate current capacity by looking up the
834*4882a593Smuzhiyun 		 * OCV table.
835*4882a593Smuzhiyun 		 */
836*4882a593Smuzhiyun 		int cur_cap = power_supply_ocv2cap_simple(data->cap_table,
837*4882a593Smuzhiyun 							  data->table_len, ocv);
838*4882a593Smuzhiyun 
839*4882a593Smuzhiyun 		sc27xx_fgu_adjust_cap(data, cur_cap);
840*4882a593Smuzhiyun 	} else if (ocv <= data->min_volt) {
841*4882a593Smuzhiyun 		/*
842*4882a593Smuzhiyun 		 * If current OCV value is less than the low alarm voltage, but
843*4882a593Smuzhiyun 		 * current capacity is larger than the alarm capacity, we should
844*4882a593Smuzhiyun 		 * adjust the inititial capacity to alarm capacity.
845*4882a593Smuzhiyun 		 */
846*4882a593Smuzhiyun 		if (cap > data->alarm_cap) {
847*4882a593Smuzhiyun 			sc27xx_fgu_adjust_cap(data, data->alarm_cap);
848*4882a593Smuzhiyun 		} else {
849*4882a593Smuzhiyun 			int cur_cap;
850*4882a593Smuzhiyun 
851*4882a593Smuzhiyun 			/*
852*4882a593Smuzhiyun 			 * If current capacity is equal with 0 or less than 0
853*4882a593Smuzhiyun 			 * (some error occurs), we should adjust inititial
854*4882a593Smuzhiyun 			 * capacity to the capacity corresponding to current OCV
855*4882a593Smuzhiyun 			 * value.
856*4882a593Smuzhiyun 			 */
857*4882a593Smuzhiyun 			cur_cap = power_supply_ocv2cap_simple(data->cap_table,
858*4882a593Smuzhiyun 							      data->table_len,
859*4882a593Smuzhiyun 							      ocv);
860*4882a593Smuzhiyun 			sc27xx_fgu_adjust_cap(data, cur_cap);
861*4882a593Smuzhiyun 		}
862*4882a593Smuzhiyun 
863*4882a593Smuzhiyun 		if (!int_mode)
864*4882a593Smuzhiyun 			return;
865*4882a593Smuzhiyun 
866*4882a593Smuzhiyun 		/*
867*4882a593Smuzhiyun 		 * After adjusting the battery capacity, we should set the
868*4882a593Smuzhiyun 		 * lowest alarm voltage instead.
869*4882a593Smuzhiyun 		 */
870*4882a593Smuzhiyun 		data->min_volt = data->cap_table[data->table_len - 1].ocv;
871*4882a593Smuzhiyun 		data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table,
872*4882a593Smuzhiyun 							      data->table_len,
873*4882a593Smuzhiyun 							      data->min_volt);
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 		adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000);
876*4882a593Smuzhiyun 		regmap_update_bits(data->regmap,
877*4882a593Smuzhiyun 				   data->base + SC27XX_FGU_LOW_OVERLOAD,
878*4882a593Smuzhiyun 				   SC27XX_FGU_LOW_OVERLOAD_MASK, adc);
879*4882a593Smuzhiyun 	}
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun 
sc27xx_fgu_interrupt(int irq,void * dev_id)882*4882a593Smuzhiyun static irqreturn_t sc27xx_fgu_interrupt(int irq, void *dev_id)
883*4882a593Smuzhiyun {
884*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = dev_id;
885*4882a593Smuzhiyun 	int ret, cap;
886*4882a593Smuzhiyun 	u32 status;
887*4882a593Smuzhiyun 
888*4882a593Smuzhiyun 	mutex_lock(&data->lock);
889*4882a593Smuzhiyun 
890*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, data->base + SC27XX_FGU_INT_STS,
891*4882a593Smuzhiyun 			  &status);
892*4882a593Smuzhiyun 	if (ret)
893*4882a593Smuzhiyun 		goto out;
894*4882a593Smuzhiyun 
895*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_CLR,
896*4882a593Smuzhiyun 				 status, status);
897*4882a593Smuzhiyun 	if (ret)
898*4882a593Smuzhiyun 		goto out;
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 	/*
901*4882a593Smuzhiyun 	 * When low overload voltage interrupt happens, we should calibrate the
902*4882a593Smuzhiyun 	 * battery capacity in lower voltage stage.
903*4882a593Smuzhiyun 	 */
904*4882a593Smuzhiyun 	if (!(status & SC27XX_FGU_LOW_OVERLOAD_INT))
905*4882a593Smuzhiyun 		goto out;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_capacity(data, &cap);
908*4882a593Smuzhiyun 	if (ret)
909*4882a593Smuzhiyun 		goto out;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	sc27xx_fgu_capacity_calibration(data, cap, true);
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun out:
914*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
915*4882a593Smuzhiyun 
916*4882a593Smuzhiyun 	power_supply_changed(data->battery);
917*4882a593Smuzhiyun 	return IRQ_HANDLED;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun 
sc27xx_fgu_bat_detection(int irq,void * dev_id)920*4882a593Smuzhiyun static irqreturn_t sc27xx_fgu_bat_detection(int irq, void *dev_id)
921*4882a593Smuzhiyun {
922*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = dev_id;
923*4882a593Smuzhiyun 	int state;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	mutex_lock(&data->lock);
926*4882a593Smuzhiyun 
927*4882a593Smuzhiyun 	state = gpiod_get_value_cansleep(data->gpiod);
928*4882a593Smuzhiyun 	if (state < 0) {
929*4882a593Smuzhiyun 		dev_err(data->dev, "failed to get gpio state\n");
930*4882a593Smuzhiyun 		mutex_unlock(&data->lock);
931*4882a593Smuzhiyun 		return IRQ_RETVAL(state);
932*4882a593Smuzhiyun 	}
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	data->bat_present = !!state;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	mutex_unlock(&data->lock);
937*4882a593Smuzhiyun 
938*4882a593Smuzhiyun 	power_supply_changed(data->battery);
939*4882a593Smuzhiyun 	return IRQ_HANDLED;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun 
sc27xx_fgu_disable(void * _data)942*4882a593Smuzhiyun static void sc27xx_fgu_disable(void *_data)
943*4882a593Smuzhiyun {
944*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = _data;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	regmap_update_bits(data->regmap, SC27XX_CLK_EN0, SC27XX_FGU_RTC_EN, 0);
947*4882a593Smuzhiyun 	regmap_update_bits(data->regmap, SC27XX_MODULE_EN0, SC27XX_FGU_EN, 0);
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun 
sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data * data,int capacity)950*4882a593Smuzhiyun static int sc27xx_fgu_cap_to_clbcnt(struct sc27xx_fgu_data *data, int capacity)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	/*
953*4882a593Smuzhiyun 	 * Get current capacity (mAh) = battery total capacity (mAh) *
954*4882a593Smuzhiyun 	 * current capacity percent (capacity / 100).
955*4882a593Smuzhiyun 	 */
956*4882a593Smuzhiyun 	int cur_cap = DIV_ROUND_CLOSEST(data->total_cap * capacity, 100);
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	/*
959*4882a593Smuzhiyun 	 * Convert current capacity (mAh) to coulomb counter according to the
960*4882a593Smuzhiyun 	 * formula: 1 mAh =3.6 coulomb.
961*4882a593Smuzhiyun 	 */
962*4882a593Smuzhiyun 	return DIV_ROUND_CLOSEST(cur_cap * 36 * data->cur_1000ma_adc * SC27XX_FGU_SAMPLE_HZ, 10);
963*4882a593Smuzhiyun }
964*4882a593Smuzhiyun 
sc27xx_fgu_calibration(struct sc27xx_fgu_data * data)965*4882a593Smuzhiyun static int sc27xx_fgu_calibration(struct sc27xx_fgu_data *data)
966*4882a593Smuzhiyun {
967*4882a593Smuzhiyun 	struct nvmem_cell *cell;
968*4882a593Smuzhiyun 	int calib_data, cal_4200mv;
969*4882a593Smuzhiyun 	void *buf;
970*4882a593Smuzhiyun 	size_t len;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	cell = nvmem_cell_get(data->dev, "fgu_calib");
973*4882a593Smuzhiyun 	if (IS_ERR(cell))
974*4882a593Smuzhiyun 		return PTR_ERR(cell);
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	buf = nvmem_cell_read(cell, &len);
977*4882a593Smuzhiyun 	nvmem_cell_put(cell);
978*4882a593Smuzhiyun 
979*4882a593Smuzhiyun 	if (IS_ERR(buf))
980*4882a593Smuzhiyun 		return PTR_ERR(buf);
981*4882a593Smuzhiyun 
982*4882a593Smuzhiyun 	memcpy(&calib_data, buf, min(len, sizeof(u32)));
983*4882a593Smuzhiyun 
984*4882a593Smuzhiyun 	/*
985*4882a593Smuzhiyun 	 * Get the ADC value corresponding to 4200 mV from eFuse controller
986*4882a593Smuzhiyun 	 * according to below formula. Then convert to ADC values corresponding
987*4882a593Smuzhiyun 	 * to 1000 mV and 1000 mA.
988*4882a593Smuzhiyun 	 */
989*4882a593Smuzhiyun 	cal_4200mv = (calib_data & 0x1ff) + 6963 - 4096 - 256;
990*4882a593Smuzhiyun 	data->vol_1000mv_adc = DIV_ROUND_CLOSEST(cal_4200mv * 10, 42);
991*4882a593Smuzhiyun 	data->cur_1000ma_adc =
992*4882a593Smuzhiyun 		DIV_ROUND_CLOSEST(data->vol_1000mv_adc * 4 * data->calib_resist,
993*4882a593Smuzhiyun 				  SC27XX_FGU_IDEAL_RESISTANCE);
994*4882a593Smuzhiyun 
995*4882a593Smuzhiyun 	kfree(buf);
996*4882a593Smuzhiyun 	return 0;
997*4882a593Smuzhiyun }
998*4882a593Smuzhiyun 
sc27xx_fgu_hw_init(struct sc27xx_fgu_data * data)999*4882a593Smuzhiyun static int sc27xx_fgu_hw_init(struct sc27xx_fgu_data *data)
1000*4882a593Smuzhiyun {
1001*4882a593Smuzhiyun 	struct power_supply_battery_info info = { };
1002*4882a593Smuzhiyun 	struct power_supply_battery_ocv_table *table;
1003*4882a593Smuzhiyun 	int ret, delta_clbcnt, alarm_adc;
1004*4882a593Smuzhiyun 
1005*4882a593Smuzhiyun 	ret = power_supply_get_battery_info(data->battery, &info);
1006*4882a593Smuzhiyun 	if (ret) {
1007*4882a593Smuzhiyun 		dev_err(data->dev, "failed to get battery information\n");
1008*4882a593Smuzhiyun 		return ret;
1009*4882a593Smuzhiyun 	}
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	data->total_cap = info.charge_full_design_uah / 1000;
1012*4882a593Smuzhiyun 	data->max_volt = info.constant_charge_voltage_max_uv / 1000;
1013*4882a593Smuzhiyun 	data->internal_resist = info.factory_internal_resistance_uohm / 1000;
1014*4882a593Smuzhiyun 	data->min_volt = info.voltage_min_design_uv;
1015*4882a593Smuzhiyun 
1016*4882a593Smuzhiyun 	/*
1017*4882a593Smuzhiyun 	 * For SC27XX fuel gauge device, we only use one ocv-capacity
1018*4882a593Smuzhiyun 	 * table in normal temperature 20 Celsius.
1019*4882a593Smuzhiyun 	 */
1020*4882a593Smuzhiyun 	table = power_supply_find_ocv2cap_table(&info, 20, &data->table_len);
1021*4882a593Smuzhiyun 	if (!table)
1022*4882a593Smuzhiyun 		return -EINVAL;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	data->cap_table = devm_kmemdup(data->dev, table,
1025*4882a593Smuzhiyun 				       data->table_len * sizeof(*table),
1026*4882a593Smuzhiyun 				       GFP_KERNEL);
1027*4882a593Smuzhiyun 	if (!data->cap_table) {
1028*4882a593Smuzhiyun 		power_supply_put_battery_info(data->battery, &info);
1029*4882a593Smuzhiyun 		return -ENOMEM;
1030*4882a593Smuzhiyun 	}
1031*4882a593Smuzhiyun 
1032*4882a593Smuzhiyun 	data->alarm_cap = power_supply_ocv2cap_simple(data->cap_table,
1033*4882a593Smuzhiyun 						      data->table_len,
1034*4882a593Smuzhiyun 						      data->min_volt);
1035*4882a593Smuzhiyun 	if (!data->alarm_cap)
1036*4882a593Smuzhiyun 		data->alarm_cap += 1;
1037*4882a593Smuzhiyun 
1038*4882a593Smuzhiyun 	data->resist_table_len = info.resist_table_size;
1039*4882a593Smuzhiyun 	if (data->resist_table_len > 0) {
1040*4882a593Smuzhiyun 		data->resist_table = devm_kmemdup(data->dev, info.resist_table,
1041*4882a593Smuzhiyun 						  data->resist_table_len *
1042*4882a593Smuzhiyun 						  sizeof(struct power_supply_resistance_temp_table),
1043*4882a593Smuzhiyun 						  GFP_KERNEL);
1044*4882a593Smuzhiyun 		if (!data->resist_table) {
1045*4882a593Smuzhiyun 			power_supply_put_battery_info(data->battery, &info);
1046*4882a593Smuzhiyun 			return -ENOMEM;
1047*4882a593Smuzhiyun 		}
1048*4882a593Smuzhiyun 	}
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	power_supply_put_battery_info(data->battery, &info);
1051*4882a593Smuzhiyun 
1052*4882a593Smuzhiyun 	ret = sc27xx_fgu_calibration(data);
1053*4882a593Smuzhiyun 	if (ret)
1054*4882a593Smuzhiyun 		return ret;
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 	/* Enable the FGU module */
1057*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, SC27XX_MODULE_EN0,
1058*4882a593Smuzhiyun 				 SC27XX_FGU_EN, SC27XX_FGU_EN);
1059*4882a593Smuzhiyun 	if (ret) {
1060*4882a593Smuzhiyun 		dev_err(data->dev, "failed to enable fgu\n");
1061*4882a593Smuzhiyun 		return ret;
1062*4882a593Smuzhiyun 	}
1063*4882a593Smuzhiyun 
1064*4882a593Smuzhiyun 	/* Enable the FGU RTC clock to make it work */
1065*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, SC27XX_CLK_EN0,
1066*4882a593Smuzhiyun 				 SC27XX_FGU_RTC_EN, SC27XX_FGU_RTC_EN);
1067*4882a593Smuzhiyun 	if (ret) {
1068*4882a593Smuzhiyun 		dev_err(data->dev, "failed to enable fgu RTC clock\n");
1069*4882a593Smuzhiyun 		goto disable_fgu;
1070*4882a593Smuzhiyun 	}
1071*4882a593Smuzhiyun 
1072*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_CLR,
1073*4882a593Smuzhiyun 				 SC27XX_FGU_INT_MASK, SC27XX_FGU_INT_MASK);
1074*4882a593Smuzhiyun 	if (ret) {
1075*4882a593Smuzhiyun 		dev_err(data->dev, "failed to clear interrupt status\n");
1076*4882a593Smuzhiyun 		goto disable_clk;
1077*4882a593Smuzhiyun 	}
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun 	/*
1080*4882a593Smuzhiyun 	 * Set the voltage low overload threshold, which means when the battery
1081*4882a593Smuzhiyun 	 * voltage is lower than this threshold, the controller will generate
1082*4882a593Smuzhiyun 	 * one interrupt to notify.
1083*4882a593Smuzhiyun 	 */
1084*4882a593Smuzhiyun 	alarm_adc = sc27xx_fgu_voltage_to_adc(data, data->min_volt / 1000);
1085*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_LOW_OVERLOAD,
1086*4882a593Smuzhiyun 				 SC27XX_FGU_LOW_OVERLOAD_MASK, alarm_adc);
1087*4882a593Smuzhiyun 	if (ret) {
1088*4882a593Smuzhiyun 		dev_err(data->dev, "failed to set fgu low overload\n");
1089*4882a593Smuzhiyun 		goto disable_clk;
1090*4882a593Smuzhiyun 	}
1091*4882a593Smuzhiyun 
1092*4882a593Smuzhiyun 	/*
1093*4882a593Smuzhiyun 	 * Set the coulomb counter delta threshold, that means when the coulomb
1094*4882a593Smuzhiyun 	 * counter change is multiples of the delta threshold, the controller
1095*4882a593Smuzhiyun 	 * will generate one interrupt to notify the users to update the battery
1096*4882a593Smuzhiyun 	 * capacity. Now we set the delta threshold as a counter value of 1%
1097*4882a593Smuzhiyun 	 * capacity.
1098*4882a593Smuzhiyun 	 */
1099*4882a593Smuzhiyun 	delta_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, 1);
1100*4882a593Smuzhiyun 
1101*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_CLBCNT_DELTL,
1102*4882a593Smuzhiyun 				 SC27XX_FGU_CLBCNT_MASK, delta_clbcnt);
1103*4882a593Smuzhiyun 	if (ret) {
1104*4882a593Smuzhiyun 		dev_err(data->dev, "failed to set low delta coulomb counter\n");
1105*4882a593Smuzhiyun 		goto disable_clk;
1106*4882a593Smuzhiyun 	}
1107*4882a593Smuzhiyun 
1108*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_CLBCNT_DELTH,
1109*4882a593Smuzhiyun 				 SC27XX_FGU_CLBCNT_MASK,
1110*4882a593Smuzhiyun 				 delta_clbcnt >> SC27XX_FGU_CLBCNT_SHIFT);
1111*4882a593Smuzhiyun 	if (ret) {
1112*4882a593Smuzhiyun 		dev_err(data->dev, "failed to set high delta coulomb counter\n");
1113*4882a593Smuzhiyun 		goto disable_clk;
1114*4882a593Smuzhiyun 	}
1115*4882a593Smuzhiyun 
1116*4882a593Smuzhiyun 	/*
1117*4882a593Smuzhiyun 	 * Get the boot battery capacity when system powers on, which is used to
1118*4882a593Smuzhiyun 	 * initialize the coulomb counter. After that, we can read the coulomb
1119*4882a593Smuzhiyun 	 * counter to measure the battery capacity.
1120*4882a593Smuzhiyun 	 */
1121*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_boot_capacity(data, &data->init_cap);
1122*4882a593Smuzhiyun 	if (ret) {
1123*4882a593Smuzhiyun 		dev_err(data->dev, "failed to get boot capacity\n");
1124*4882a593Smuzhiyun 		goto disable_clk;
1125*4882a593Smuzhiyun 	}
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 	/*
1128*4882a593Smuzhiyun 	 * Convert battery capacity to the corresponding initial coulomb counter
1129*4882a593Smuzhiyun 	 * and set into coulomb counter registers.
1130*4882a593Smuzhiyun 	 */
1131*4882a593Smuzhiyun 	data->init_clbcnt = sc27xx_fgu_cap_to_clbcnt(data, data->init_cap);
1132*4882a593Smuzhiyun 	ret = sc27xx_fgu_set_clbcnt(data, data->init_clbcnt);
1133*4882a593Smuzhiyun 	if (ret) {
1134*4882a593Smuzhiyun 		dev_err(data->dev, "failed to initialize coulomb counter\n");
1135*4882a593Smuzhiyun 		goto disable_clk;
1136*4882a593Smuzhiyun 	}
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	return 0;
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun disable_clk:
1141*4882a593Smuzhiyun 	regmap_update_bits(data->regmap, SC27XX_CLK_EN0, SC27XX_FGU_RTC_EN, 0);
1142*4882a593Smuzhiyun disable_fgu:
1143*4882a593Smuzhiyun 	regmap_update_bits(data->regmap, SC27XX_MODULE_EN0, SC27XX_FGU_EN, 0);
1144*4882a593Smuzhiyun 
1145*4882a593Smuzhiyun 	return ret;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun 
sc27xx_fgu_probe(struct platform_device * pdev)1148*4882a593Smuzhiyun static int sc27xx_fgu_probe(struct platform_device *pdev)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
1151*4882a593Smuzhiyun 	struct device_node *np = dev->of_node;
1152*4882a593Smuzhiyun 	struct power_supply_config fgu_cfg = { };
1153*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data;
1154*4882a593Smuzhiyun 	int ret, irq;
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
1157*4882a593Smuzhiyun 	if (!data)
1158*4882a593Smuzhiyun 		return -ENOMEM;
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	data->regmap = dev_get_regmap(dev->parent, NULL);
1161*4882a593Smuzhiyun 	if (!data->regmap) {
1162*4882a593Smuzhiyun 		dev_err(dev, "failed to get regmap\n");
1163*4882a593Smuzhiyun 		return -ENODEV;
1164*4882a593Smuzhiyun 	}
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun 	ret = device_property_read_u32(dev, "reg", &data->base);
1167*4882a593Smuzhiyun 	if (ret) {
1168*4882a593Smuzhiyun 		dev_err(dev, "failed to get fgu address\n");
1169*4882a593Smuzhiyun 		return ret;
1170*4882a593Smuzhiyun 	}
1171*4882a593Smuzhiyun 
1172*4882a593Smuzhiyun 	ret = device_property_read_u32(&pdev->dev,
1173*4882a593Smuzhiyun 				       "sprd,calib-resistance-micro-ohms",
1174*4882a593Smuzhiyun 				       &data->calib_resist);
1175*4882a593Smuzhiyun 	if (ret) {
1176*4882a593Smuzhiyun 		dev_err(&pdev->dev,
1177*4882a593Smuzhiyun 			"failed to get fgu calibration resistance\n");
1178*4882a593Smuzhiyun 		return ret;
1179*4882a593Smuzhiyun 	}
1180*4882a593Smuzhiyun 
1181*4882a593Smuzhiyun 	data->channel = devm_iio_channel_get(dev, "bat-temp");
1182*4882a593Smuzhiyun 	if (IS_ERR(data->channel)) {
1183*4882a593Smuzhiyun 		dev_err(dev, "failed to get IIO channel\n");
1184*4882a593Smuzhiyun 		return PTR_ERR(data->channel);
1185*4882a593Smuzhiyun 	}
1186*4882a593Smuzhiyun 
1187*4882a593Smuzhiyun 	data->charge_chan = devm_iio_channel_get(dev, "charge-vol");
1188*4882a593Smuzhiyun 	if (IS_ERR(data->charge_chan)) {
1189*4882a593Smuzhiyun 		dev_err(dev, "failed to get charge IIO channel\n");
1190*4882a593Smuzhiyun 		return PTR_ERR(data->charge_chan);
1191*4882a593Smuzhiyun 	}
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 	data->gpiod = devm_gpiod_get(dev, "bat-detect", GPIOD_IN);
1194*4882a593Smuzhiyun 	if (IS_ERR(data->gpiod)) {
1195*4882a593Smuzhiyun 		dev_err(dev, "failed to get battery detection GPIO\n");
1196*4882a593Smuzhiyun 		return PTR_ERR(data->gpiod);
1197*4882a593Smuzhiyun 	}
1198*4882a593Smuzhiyun 
1199*4882a593Smuzhiyun 	ret = gpiod_get_value_cansleep(data->gpiod);
1200*4882a593Smuzhiyun 	if (ret < 0) {
1201*4882a593Smuzhiyun 		dev_err(dev, "failed to get gpio state\n");
1202*4882a593Smuzhiyun 		return ret;
1203*4882a593Smuzhiyun 	}
1204*4882a593Smuzhiyun 
1205*4882a593Smuzhiyun 	data->bat_present = !!ret;
1206*4882a593Smuzhiyun 	mutex_init(&data->lock);
1207*4882a593Smuzhiyun 	data->dev = dev;
1208*4882a593Smuzhiyun 	platform_set_drvdata(pdev, data);
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	fgu_cfg.drv_data = data;
1211*4882a593Smuzhiyun 	fgu_cfg.of_node = np;
1212*4882a593Smuzhiyun 	data->battery = devm_power_supply_register(dev, &sc27xx_fgu_desc,
1213*4882a593Smuzhiyun 						   &fgu_cfg);
1214*4882a593Smuzhiyun 	if (IS_ERR(data->battery)) {
1215*4882a593Smuzhiyun 		dev_err(dev, "failed to register power supply\n");
1216*4882a593Smuzhiyun 		return PTR_ERR(data->battery);
1217*4882a593Smuzhiyun 	}
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	ret = sc27xx_fgu_hw_init(data);
1220*4882a593Smuzhiyun 	if (ret) {
1221*4882a593Smuzhiyun 		dev_err(dev, "failed to initialize fgu hardware\n");
1222*4882a593Smuzhiyun 		return ret;
1223*4882a593Smuzhiyun 	}
1224*4882a593Smuzhiyun 
1225*4882a593Smuzhiyun 	ret = devm_add_action_or_reset(dev, sc27xx_fgu_disable, data);
1226*4882a593Smuzhiyun 	if (ret) {
1227*4882a593Smuzhiyun 		dev_err(dev, "failed to add fgu disable action\n");
1228*4882a593Smuzhiyun 		return ret;
1229*4882a593Smuzhiyun 	}
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
1232*4882a593Smuzhiyun 	if (irq < 0) {
1233*4882a593Smuzhiyun 		dev_err(dev, "no irq resource specified\n");
1234*4882a593Smuzhiyun 		return irq;
1235*4882a593Smuzhiyun 	}
1236*4882a593Smuzhiyun 
1237*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(data->dev, irq, NULL,
1238*4882a593Smuzhiyun 					sc27xx_fgu_interrupt,
1239*4882a593Smuzhiyun 					IRQF_NO_SUSPEND | IRQF_ONESHOT,
1240*4882a593Smuzhiyun 					pdev->name, data);
1241*4882a593Smuzhiyun 	if (ret) {
1242*4882a593Smuzhiyun 		dev_err(data->dev, "failed to request fgu IRQ\n");
1243*4882a593Smuzhiyun 		return ret;
1244*4882a593Smuzhiyun 	}
1245*4882a593Smuzhiyun 
1246*4882a593Smuzhiyun 	irq = gpiod_to_irq(data->gpiod);
1247*4882a593Smuzhiyun 	if (irq < 0) {
1248*4882a593Smuzhiyun 		dev_err(dev, "failed to translate GPIO to IRQ\n");
1249*4882a593Smuzhiyun 		return irq;
1250*4882a593Smuzhiyun 	}
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(dev, irq, NULL,
1253*4882a593Smuzhiyun 					sc27xx_fgu_bat_detection,
1254*4882a593Smuzhiyun 					IRQF_ONESHOT | IRQF_TRIGGER_RISING |
1255*4882a593Smuzhiyun 					IRQF_TRIGGER_FALLING,
1256*4882a593Smuzhiyun 					pdev->name, data);
1257*4882a593Smuzhiyun 	if (ret) {
1258*4882a593Smuzhiyun 		dev_err(dev, "failed to request IRQ\n");
1259*4882a593Smuzhiyun 		return ret;
1260*4882a593Smuzhiyun 	}
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 	return 0;
1263*4882a593Smuzhiyun }
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
sc27xx_fgu_resume(struct device * dev)1266*4882a593Smuzhiyun static int sc27xx_fgu_resume(struct device *dev)
1267*4882a593Smuzhiyun {
1268*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = dev_get_drvdata(dev);
1269*4882a593Smuzhiyun 	int ret;
1270*4882a593Smuzhiyun 
1271*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_EN,
1272*4882a593Smuzhiyun 				 SC27XX_FGU_LOW_OVERLOAD_INT |
1273*4882a593Smuzhiyun 				 SC27XX_FGU_CLBCNT_DELTA_INT, 0);
1274*4882a593Smuzhiyun 	if (ret) {
1275*4882a593Smuzhiyun 		dev_err(data->dev, "failed to disable fgu interrupts\n");
1276*4882a593Smuzhiyun 		return ret;
1277*4882a593Smuzhiyun 	}
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun 	return 0;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun 
sc27xx_fgu_suspend(struct device * dev)1282*4882a593Smuzhiyun static int sc27xx_fgu_suspend(struct device *dev)
1283*4882a593Smuzhiyun {
1284*4882a593Smuzhiyun 	struct sc27xx_fgu_data *data = dev_get_drvdata(dev);
1285*4882a593Smuzhiyun 	int ret, status, ocv;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_status(data, &status);
1288*4882a593Smuzhiyun 	if (ret)
1289*4882a593Smuzhiyun 		return ret;
1290*4882a593Smuzhiyun 
1291*4882a593Smuzhiyun 	/*
1292*4882a593Smuzhiyun 	 * If we are charging, then no need to enable the FGU interrupts to
1293*4882a593Smuzhiyun 	 * adjust the battery capacity.
1294*4882a593Smuzhiyun 	 */
1295*4882a593Smuzhiyun 	if (status != POWER_SUPPLY_STATUS_NOT_CHARGING &&
1296*4882a593Smuzhiyun 	    status != POWER_SUPPLY_STATUS_DISCHARGING)
1297*4882a593Smuzhiyun 		return 0;
1298*4882a593Smuzhiyun 
1299*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_EN,
1300*4882a593Smuzhiyun 				 SC27XX_FGU_LOW_OVERLOAD_INT,
1301*4882a593Smuzhiyun 				 SC27XX_FGU_LOW_OVERLOAD_INT);
1302*4882a593Smuzhiyun 	if (ret) {
1303*4882a593Smuzhiyun 		dev_err(data->dev, "failed to enable low voltage interrupt\n");
1304*4882a593Smuzhiyun 		return ret;
1305*4882a593Smuzhiyun 	}
1306*4882a593Smuzhiyun 
1307*4882a593Smuzhiyun 	ret = sc27xx_fgu_get_vbat_ocv(data, &ocv);
1308*4882a593Smuzhiyun 	if (ret)
1309*4882a593Smuzhiyun 		goto disable_int;
1310*4882a593Smuzhiyun 
1311*4882a593Smuzhiyun 	/*
1312*4882a593Smuzhiyun 	 * If current OCV is less than the minimum voltage, we should enable the
1313*4882a593Smuzhiyun 	 * coulomb counter threshold interrupt to notify events to adjust the
1314*4882a593Smuzhiyun 	 * battery capacity.
1315*4882a593Smuzhiyun 	 */
1316*4882a593Smuzhiyun 	if (ocv < data->min_volt) {
1317*4882a593Smuzhiyun 		ret = regmap_update_bits(data->regmap,
1318*4882a593Smuzhiyun 					 data->base + SC27XX_FGU_INT_EN,
1319*4882a593Smuzhiyun 					 SC27XX_FGU_CLBCNT_DELTA_INT,
1320*4882a593Smuzhiyun 					 SC27XX_FGU_CLBCNT_DELTA_INT);
1321*4882a593Smuzhiyun 		if (ret) {
1322*4882a593Smuzhiyun 			dev_err(data->dev,
1323*4882a593Smuzhiyun 				"failed to enable coulomb threshold int\n");
1324*4882a593Smuzhiyun 			goto disable_int;
1325*4882a593Smuzhiyun 		}
1326*4882a593Smuzhiyun 	}
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 	return 0;
1329*4882a593Smuzhiyun 
1330*4882a593Smuzhiyun disable_int:
1331*4882a593Smuzhiyun 	regmap_update_bits(data->regmap, data->base + SC27XX_FGU_INT_EN,
1332*4882a593Smuzhiyun 			   SC27XX_FGU_LOW_OVERLOAD_INT, 0);
1333*4882a593Smuzhiyun 	return ret;
1334*4882a593Smuzhiyun }
1335*4882a593Smuzhiyun #endif
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun static const struct dev_pm_ops sc27xx_fgu_pm_ops = {
1338*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(sc27xx_fgu_suspend, sc27xx_fgu_resume)
1339*4882a593Smuzhiyun };
1340*4882a593Smuzhiyun 
1341*4882a593Smuzhiyun static const struct of_device_id sc27xx_fgu_of_match[] = {
1342*4882a593Smuzhiyun 	{ .compatible = "sprd,sc2731-fgu", },
1343*4882a593Smuzhiyun 	{ }
1344*4882a593Smuzhiyun };
1345*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, sc27xx_fgu_of_match);
1346*4882a593Smuzhiyun 
1347*4882a593Smuzhiyun static struct platform_driver sc27xx_fgu_driver = {
1348*4882a593Smuzhiyun 	.probe = sc27xx_fgu_probe,
1349*4882a593Smuzhiyun 	.driver = {
1350*4882a593Smuzhiyun 		.name = "sc27xx-fgu",
1351*4882a593Smuzhiyun 		.of_match_table = sc27xx_fgu_of_match,
1352*4882a593Smuzhiyun 		.pm = &sc27xx_fgu_pm_ops,
1353*4882a593Smuzhiyun 	}
1354*4882a593Smuzhiyun };
1355*4882a593Smuzhiyun 
1356*4882a593Smuzhiyun module_platform_driver(sc27xx_fgu_driver);
1357*4882a593Smuzhiyun 
1358*4882a593Smuzhiyun MODULE_DESCRIPTION("Spreadtrum SC27XX PMICs Fual Gauge Unit Driver");
1359*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
1360