xref: /OK3568_Linux_fs/kernel/drivers/power/supply/rt5033_battery.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Fuel gauge driver for Richtek RT5033
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
6*4882a593Smuzhiyun  * Author: Beomho Seo <beomho.seo@samsung.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/platform_device.h>
11*4882a593Smuzhiyun #include <linux/power_supply.h>
12*4882a593Smuzhiyun #include <linux/mfd/rt5033-private.h>
13*4882a593Smuzhiyun #include <linux/mfd/rt5033.h>
14*4882a593Smuzhiyun 
rt5033_battery_get_capacity(struct i2c_client * client)15*4882a593Smuzhiyun static int rt5033_battery_get_capacity(struct i2c_client *client)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	struct rt5033_battery *battery = i2c_get_clientdata(client);
18*4882a593Smuzhiyun 	u32 msb;
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	regmap_read(battery->regmap, RT5033_FUEL_REG_SOC_H, &msb);
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	return msb;
23*4882a593Smuzhiyun }
24*4882a593Smuzhiyun 
rt5033_battery_get_present(struct i2c_client * client)25*4882a593Smuzhiyun static int rt5033_battery_get_present(struct i2c_client *client)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	struct rt5033_battery *battery = i2c_get_clientdata(client);
28*4882a593Smuzhiyun 	u32 val;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	regmap_read(battery->regmap, RT5033_FUEL_REG_CONFIG_L, &val);
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	return (val & RT5033_FUEL_BAT_PRESENT) ? true : false;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun 
rt5033_battery_get_watt_prop(struct i2c_client * client,enum power_supply_property psp)35*4882a593Smuzhiyun static int rt5033_battery_get_watt_prop(struct i2c_client *client,
36*4882a593Smuzhiyun 		enum power_supply_property psp)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	struct rt5033_battery *battery = i2c_get_clientdata(client);
39*4882a593Smuzhiyun 	unsigned int regh, regl;
40*4882a593Smuzhiyun 	int ret;
41*4882a593Smuzhiyun 	u32 msb, lsb;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	switch (psp) {
44*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
45*4882a593Smuzhiyun 		regh = RT5033_FUEL_REG_VBAT_H;
46*4882a593Smuzhiyun 		regl = RT5033_FUEL_REG_VBAT_L;
47*4882a593Smuzhiyun 		break;
48*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
49*4882a593Smuzhiyun 		regh = RT5033_FUEL_REG_AVG_VOLT_H;
50*4882a593Smuzhiyun 		regl = RT5033_FUEL_REG_AVG_VOLT_L;
51*4882a593Smuzhiyun 		break;
52*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
53*4882a593Smuzhiyun 		regh = RT5033_FUEL_REG_OCV_H;
54*4882a593Smuzhiyun 		regl = RT5033_FUEL_REG_OCV_L;
55*4882a593Smuzhiyun 		break;
56*4882a593Smuzhiyun 	default:
57*4882a593Smuzhiyun 		return -EINVAL;
58*4882a593Smuzhiyun 	}
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	regmap_read(battery->regmap, regh, &msb);
61*4882a593Smuzhiyun 	regmap_read(battery->regmap, regl, &lsb);
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun 	ret = ((msb << 4) + (lsb >> 4)) * 1250;
64*4882a593Smuzhiyun 
65*4882a593Smuzhiyun 	return ret;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
rt5033_battery_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)68*4882a593Smuzhiyun static int rt5033_battery_get_property(struct power_supply *psy,
69*4882a593Smuzhiyun 		enum power_supply_property psp,
70*4882a593Smuzhiyun 		union power_supply_propval *val)
71*4882a593Smuzhiyun {
72*4882a593Smuzhiyun 	struct rt5033_battery *battery = power_supply_get_drvdata(psy);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	switch (psp) {
75*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
76*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_AVG:
77*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_VOLTAGE_OCV:
78*4882a593Smuzhiyun 		val->intval = rt5033_battery_get_watt_prop(battery->client,
79*4882a593Smuzhiyun 									psp);
80*4882a593Smuzhiyun 		break;
81*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_PRESENT:
82*4882a593Smuzhiyun 		val->intval = rt5033_battery_get_present(battery->client);
83*4882a593Smuzhiyun 		break;
84*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_CAPACITY:
85*4882a593Smuzhiyun 		val->intval = rt5033_battery_get_capacity(battery->client);
86*4882a593Smuzhiyun 		break;
87*4882a593Smuzhiyun 	default:
88*4882a593Smuzhiyun 		return -EINVAL;
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun 	return 0;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun static enum power_supply_property rt5033_battery_props[] = {
94*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
95*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_AVG,
96*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_VOLTAGE_OCV,
97*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_PRESENT,
98*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_CAPACITY,
99*4882a593Smuzhiyun };
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun static const struct regmap_config rt5033_battery_regmap_config = {
102*4882a593Smuzhiyun 	.reg_bits	= 8,
103*4882a593Smuzhiyun 	.val_bits	= 8,
104*4882a593Smuzhiyun 	.max_register	= RT5033_FUEL_REG_END,
105*4882a593Smuzhiyun };
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun static const struct power_supply_desc rt5033_battery_desc = {
108*4882a593Smuzhiyun 	.name		= "rt5033-battery",
109*4882a593Smuzhiyun 	.type		= POWER_SUPPLY_TYPE_BATTERY,
110*4882a593Smuzhiyun 	.get_property	= rt5033_battery_get_property,
111*4882a593Smuzhiyun 	.properties	= rt5033_battery_props,
112*4882a593Smuzhiyun 	.num_properties	= ARRAY_SIZE(rt5033_battery_props),
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun 
rt5033_battery_probe(struct i2c_client * client,const struct i2c_device_id * id)115*4882a593Smuzhiyun static int rt5033_battery_probe(struct i2c_client *client,
116*4882a593Smuzhiyun 		const struct i2c_device_id *id)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	struct i2c_adapter *adapter = client->adapter;
119*4882a593Smuzhiyun 	struct power_supply_config psy_cfg = {};
120*4882a593Smuzhiyun 	struct rt5033_battery *battery;
121*4882a593Smuzhiyun 	u32 ret;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
124*4882a593Smuzhiyun 		return -EIO;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL);
127*4882a593Smuzhiyun 	if (!battery)
128*4882a593Smuzhiyun 		return -ENOMEM;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	battery->client = client;
131*4882a593Smuzhiyun 	battery->regmap = devm_regmap_init_i2c(client,
132*4882a593Smuzhiyun 			&rt5033_battery_regmap_config);
133*4882a593Smuzhiyun 	if (IS_ERR(battery->regmap)) {
134*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to initialize regmap\n");
135*4882a593Smuzhiyun 		return -EINVAL;
136*4882a593Smuzhiyun 	}
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	i2c_set_clientdata(client, battery);
139*4882a593Smuzhiyun 	psy_cfg.drv_data = battery;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	battery->psy = power_supply_register(&client->dev,
142*4882a593Smuzhiyun 					     &rt5033_battery_desc, &psy_cfg);
143*4882a593Smuzhiyun 	if (IS_ERR(battery->psy)) {
144*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to register power supply\n");
145*4882a593Smuzhiyun 		ret = PTR_ERR(battery->psy);
146*4882a593Smuzhiyun 		return ret;
147*4882a593Smuzhiyun 	}
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
rt5033_battery_remove(struct i2c_client * client)152*4882a593Smuzhiyun static int rt5033_battery_remove(struct i2c_client *client)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	struct rt5033_battery *battery = i2c_get_clientdata(client);
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	power_supply_unregister(battery->psy);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun static const struct i2c_device_id rt5033_battery_id[] = {
162*4882a593Smuzhiyun 	{ "rt5033-battery", },
163*4882a593Smuzhiyun 	{ }
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, rt5033_battery_id);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun static const struct of_device_id rt5033_battery_of_match[] = {
168*4882a593Smuzhiyun 	{ .compatible = "richtek,rt5033-battery", },
169*4882a593Smuzhiyun 	{ }
170*4882a593Smuzhiyun };
171*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, rt5033_battery_of_match);
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static struct i2c_driver rt5033_battery_driver = {
174*4882a593Smuzhiyun 	.driver = {
175*4882a593Smuzhiyun 		.name = "rt5033-battery",
176*4882a593Smuzhiyun 		.of_match_table = rt5033_battery_of_match,
177*4882a593Smuzhiyun 	},
178*4882a593Smuzhiyun 	.probe = rt5033_battery_probe,
179*4882a593Smuzhiyun 	.remove = rt5033_battery_remove,
180*4882a593Smuzhiyun 	.id_table = rt5033_battery_id,
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun module_i2c_driver(rt5033_battery_driver);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver");
185*4882a593Smuzhiyun MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
186*4882a593Smuzhiyun MODULE_LICENSE("GPL");
187