xref: /OK3568_Linux_fs/kernel/drivers/power/supply/bq27xxx_battery_i2c.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * BQ27xxx battery monitor I2C driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2015 Texas Instruments Incorporated - https://www.ti.com/
6*4882a593Smuzhiyun  *	Andrew F. Davis <afd@ti.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/i2c.h>
10*4882a593Smuzhiyun #include <linux/interrupt.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <asm/unaligned.h>
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #include <linux/power/bq27xxx_battery.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun static DEFINE_IDR(battery_id);
17*4882a593Smuzhiyun static DEFINE_MUTEX(battery_mutex);
18*4882a593Smuzhiyun 
bq27xxx_battery_irq_handler_thread(int irq,void * data)19*4882a593Smuzhiyun static irqreturn_t bq27xxx_battery_irq_handler_thread(int irq, void *data)
20*4882a593Smuzhiyun {
21*4882a593Smuzhiyun 	struct bq27xxx_device_info *di = data;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	bq27xxx_battery_update(di);
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	return IRQ_HANDLED;
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun 
bq27xxx_battery_i2c_read(struct bq27xxx_device_info * di,u8 reg,bool single)28*4882a593Smuzhiyun static int bq27xxx_battery_i2c_read(struct bq27xxx_device_info *di, u8 reg,
29*4882a593Smuzhiyun 				    bool single)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(di->dev);
32*4882a593Smuzhiyun 	struct i2c_msg msg[2];
33*4882a593Smuzhiyun 	u8 data[2];
34*4882a593Smuzhiyun 	int ret;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	if (!client->adapter)
37*4882a593Smuzhiyun 		return -ENODEV;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	msg[0].addr = client->addr;
40*4882a593Smuzhiyun 	msg[0].flags = 0;
41*4882a593Smuzhiyun 	msg[0].buf = &reg;
42*4882a593Smuzhiyun 	msg[0].len = sizeof(reg);
43*4882a593Smuzhiyun 	msg[1].addr = client->addr;
44*4882a593Smuzhiyun 	msg[1].flags = I2C_M_RD;
45*4882a593Smuzhiyun 	msg[1].buf = data;
46*4882a593Smuzhiyun 	if (single)
47*4882a593Smuzhiyun 		msg[1].len = 1;
48*4882a593Smuzhiyun 	else
49*4882a593Smuzhiyun 		msg[1].len = 2;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
52*4882a593Smuzhiyun 	if (ret < 0)
53*4882a593Smuzhiyun 		return ret;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	if (!single)
56*4882a593Smuzhiyun 		ret = get_unaligned_le16(data);
57*4882a593Smuzhiyun 	else
58*4882a593Smuzhiyun 		ret = data[0];
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	return ret;
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
bq27xxx_battery_i2c_write(struct bq27xxx_device_info * di,u8 reg,int value,bool single)63*4882a593Smuzhiyun static int bq27xxx_battery_i2c_write(struct bq27xxx_device_info *di, u8 reg,
64*4882a593Smuzhiyun 				     int value, bool single)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(di->dev);
67*4882a593Smuzhiyun 	struct i2c_msg msg;
68*4882a593Smuzhiyun 	u8 data[4];
69*4882a593Smuzhiyun 	int ret;
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	if (!client->adapter)
72*4882a593Smuzhiyun 		return -ENODEV;
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	data[0] = reg;
75*4882a593Smuzhiyun 	if (single) {
76*4882a593Smuzhiyun 		data[1] = (u8) value;
77*4882a593Smuzhiyun 		msg.len = 2;
78*4882a593Smuzhiyun 	} else {
79*4882a593Smuzhiyun 		put_unaligned_le16(value, &data[1]);
80*4882a593Smuzhiyun 		msg.len = 3;
81*4882a593Smuzhiyun 	}
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	msg.buf = data;
84*4882a593Smuzhiyun 	msg.addr = client->addr;
85*4882a593Smuzhiyun 	msg.flags = 0;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, &msg, 1);
88*4882a593Smuzhiyun 	if (ret < 0)
89*4882a593Smuzhiyun 		return ret;
90*4882a593Smuzhiyun 	if (ret != 1)
91*4882a593Smuzhiyun 		return -EINVAL;
92*4882a593Smuzhiyun 	return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
bq27xxx_battery_i2c_bulk_read(struct bq27xxx_device_info * di,u8 reg,u8 * data,int len)95*4882a593Smuzhiyun static int bq27xxx_battery_i2c_bulk_read(struct bq27xxx_device_info *di, u8 reg,
96*4882a593Smuzhiyun 					 u8 *data, int len)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(di->dev);
99*4882a593Smuzhiyun 	int ret;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	if (!client->adapter)
102*4882a593Smuzhiyun 		return -ENODEV;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	ret = i2c_smbus_read_i2c_block_data(client, reg, len, data);
105*4882a593Smuzhiyun 	if (ret < 0)
106*4882a593Smuzhiyun 		return ret;
107*4882a593Smuzhiyun 	if (ret != len)
108*4882a593Smuzhiyun 		return -EINVAL;
109*4882a593Smuzhiyun 	return 0;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info * di,u8 reg,u8 * data,int len)112*4882a593Smuzhiyun static int bq27xxx_battery_i2c_bulk_write(struct bq27xxx_device_info *di,
113*4882a593Smuzhiyun 					  u8 reg, u8 *data, int len)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct i2c_client *client = to_i2c_client(di->dev);
116*4882a593Smuzhiyun 	struct i2c_msg msg;
117*4882a593Smuzhiyun 	u8 buf[33];
118*4882a593Smuzhiyun 	int ret;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	if (!client->adapter)
121*4882a593Smuzhiyun 		return -ENODEV;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	buf[0] = reg;
124*4882a593Smuzhiyun 	memcpy(&buf[1], data, len);
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	msg.buf = buf;
127*4882a593Smuzhiyun 	msg.addr = client->addr;
128*4882a593Smuzhiyun 	msg.flags = 0;
129*4882a593Smuzhiyun 	msg.len = len + 1;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	ret = i2c_transfer(client->adapter, &msg, 1);
132*4882a593Smuzhiyun 	if (ret < 0)
133*4882a593Smuzhiyun 		return ret;
134*4882a593Smuzhiyun 	if (ret != 1)
135*4882a593Smuzhiyun 		return -EINVAL;
136*4882a593Smuzhiyun 	return 0;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun 
bq27xxx_battery_i2c_probe(struct i2c_client * client,const struct i2c_device_id * id)139*4882a593Smuzhiyun static int bq27xxx_battery_i2c_probe(struct i2c_client *client,
140*4882a593Smuzhiyun 				     const struct i2c_device_id *id)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	struct bq27xxx_device_info *di;
143*4882a593Smuzhiyun 	int ret;
144*4882a593Smuzhiyun 	char *name;
145*4882a593Smuzhiyun 	int num;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	/* Get new ID for the new battery device */
148*4882a593Smuzhiyun 	mutex_lock(&battery_mutex);
149*4882a593Smuzhiyun 	num = idr_alloc(&battery_id, client, 0, 0, GFP_KERNEL);
150*4882a593Smuzhiyun 	mutex_unlock(&battery_mutex);
151*4882a593Smuzhiyun 	if (num < 0)
152*4882a593Smuzhiyun 		return num;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	name = devm_kasprintf(&client->dev, GFP_KERNEL, "%s-%d", id->name, num);
155*4882a593Smuzhiyun 	if (!name)
156*4882a593Smuzhiyun 		goto err_mem;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL);
159*4882a593Smuzhiyun 	if (!di)
160*4882a593Smuzhiyun 		goto err_mem;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	di->id = num;
163*4882a593Smuzhiyun 	di->dev = &client->dev;
164*4882a593Smuzhiyun 	di->chip = id->driver_data;
165*4882a593Smuzhiyun 	di->name = name;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	di->bus.read = bq27xxx_battery_i2c_read;
168*4882a593Smuzhiyun 	di->bus.write = bq27xxx_battery_i2c_write;
169*4882a593Smuzhiyun 	di->bus.read_bulk = bq27xxx_battery_i2c_bulk_read;
170*4882a593Smuzhiyun 	di->bus.write_bulk = bq27xxx_battery_i2c_bulk_write;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	ret = bq27xxx_battery_setup(di);
173*4882a593Smuzhiyun 	if (ret)
174*4882a593Smuzhiyun 		goto err_failed;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* Schedule a polling after about 1 min */
177*4882a593Smuzhiyun 	schedule_delayed_work(&di->work, 60 * HZ);
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	i2c_set_clientdata(client, di);
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	if (client->irq) {
182*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(&client->dev, client->irq,
183*4882a593Smuzhiyun 				NULL, bq27xxx_battery_irq_handler_thread,
184*4882a593Smuzhiyun 				IRQF_ONESHOT,
185*4882a593Smuzhiyun 				di->name, di);
186*4882a593Smuzhiyun 		if (ret) {
187*4882a593Smuzhiyun 			dev_err(&client->dev,
188*4882a593Smuzhiyun 				"Unable to register IRQ %d error %d\n",
189*4882a593Smuzhiyun 				client->irq, ret);
190*4882a593Smuzhiyun 			bq27xxx_battery_teardown(di);
191*4882a593Smuzhiyun 			goto err_failed;
192*4882a593Smuzhiyun 		}
193*4882a593Smuzhiyun 	}
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return 0;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun err_mem:
198*4882a593Smuzhiyun 	ret = -ENOMEM;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun err_failed:
201*4882a593Smuzhiyun 	mutex_lock(&battery_mutex);
202*4882a593Smuzhiyun 	idr_remove(&battery_id, num);
203*4882a593Smuzhiyun 	mutex_unlock(&battery_mutex);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return ret;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
bq27xxx_battery_i2c_remove(struct i2c_client * client)208*4882a593Smuzhiyun static int bq27xxx_battery_i2c_remove(struct i2c_client *client)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	struct bq27xxx_device_info *di = i2c_get_clientdata(client);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	bq27xxx_battery_teardown(di);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	mutex_lock(&battery_mutex);
215*4882a593Smuzhiyun 	idr_remove(&battery_id, di->id);
216*4882a593Smuzhiyun 	mutex_unlock(&battery_mutex);
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	return 0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun static const struct i2c_device_id bq27xxx_i2c_id_table[] = {
222*4882a593Smuzhiyun 	{ "bq27200", BQ27000 },
223*4882a593Smuzhiyun 	{ "bq27210", BQ27010 },
224*4882a593Smuzhiyun 	{ "bq27500", BQ2750X },
225*4882a593Smuzhiyun 	{ "bq27510", BQ2751X },
226*4882a593Smuzhiyun 	{ "bq27520", BQ2752X },
227*4882a593Smuzhiyun 	{ "bq27500-1", BQ27500 },
228*4882a593Smuzhiyun 	{ "bq27510g1", BQ27510G1 },
229*4882a593Smuzhiyun 	{ "bq27510g2", BQ27510G2 },
230*4882a593Smuzhiyun 	{ "bq27510g3", BQ27510G3 },
231*4882a593Smuzhiyun 	{ "bq27520g1", BQ27520G1 },
232*4882a593Smuzhiyun 	{ "bq27520g2", BQ27520G2 },
233*4882a593Smuzhiyun 	{ "bq27520g3", BQ27520G3 },
234*4882a593Smuzhiyun 	{ "bq27520g4", BQ27520G4 },
235*4882a593Smuzhiyun 	{ "bq27521", BQ27521 },
236*4882a593Smuzhiyun 	{ "bq27530", BQ27530 },
237*4882a593Smuzhiyun 	{ "bq27531", BQ27531 },
238*4882a593Smuzhiyun 	{ "bq27541", BQ27541 },
239*4882a593Smuzhiyun 	{ "bq27542", BQ27542 },
240*4882a593Smuzhiyun 	{ "bq27546", BQ27546 },
241*4882a593Smuzhiyun 	{ "bq27742", BQ27742 },
242*4882a593Smuzhiyun 	{ "bq27545", BQ27545 },
243*4882a593Smuzhiyun 	{ "bq27411", BQ27411 },
244*4882a593Smuzhiyun 	{ "bq27421", BQ27421 },
245*4882a593Smuzhiyun 	{ "bq27425", BQ27425 },
246*4882a593Smuzhiyun 	{ "bq27426", BQ27426 },
247*4882a593Smuzhiyun 	{ "bq27441", BQ27441 },
248*4882a593Smuzhiyun 	{ "bq27621", BQ27621 },
249*4882a593Smuzhiyun 	{ "bq27z561", BQ27Z561 },
250*4882a593Smuzhiyun 	{ "bq28z610", BQ28Z610 },
251*4882a593Smuzhiyun 	{ "bq34z100", BQ34Z100 },
252*4882a593Smuzhiyun 	{},
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, bq27xxx_i2c_id_table);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun #ifdef CONFIG_OF
257*4882a593Smuzhiyun static const struct of_device_id bq27xxx_battery_i2c_of_match_table[] = {
258*4882a593Smuzhiyun 	{ .compatible = "ti,bq27200" },
259*4882a593Smuzhiyun 	{ .compatible = "ti,bq27210" },
260*4882a593Smuzhiyun 	{ .compatible = "ti,bq27500" },
261*4882a593Smuzhiyun 	{ .compatible = "ti,bq27510" },
262*4882a593Smuzhiyun 	{ .compatible = "ti,bq27520" },
263*4882a593Smuzhiyun 	{ .compatible = "ti,bq27500-1" },
264*4882a593Smuzhiyun 	{ .compatible = "ti,bq27510g1" },
265*4882a593Smuzhiyun 	{ .compatible = "ti,bq27510g2" },
266*4882a593Smuzhiyun 	{ .compatible = "ti,bq27510g3" },
267*4882a593Smuzhiyun 	{ .compatible = "ti,bq27520g1" },
268*4882a593Smuzhiyun 	{ .compatible = "ti,bq27520g2" },
269*4882a593Smuzhiyun 	{ .compatible = "ti,bq27520g3" },
270*4882a593Smuzhiyun 	{ .compatible = "ti,bq27520g4" },
271*4882a593Smuzhiyun 	{ .compatible = "ti,bq27521" },
272*4882a593Smuzhiyun 	{ .compatible = "ti,bq27530" },
273*4882a593Smuzhiyun 	{ .compatible = "ti,bq27531" },
274*4882a593Smuzhiyun 	{ .compatible = "ti,bq27541" },
275*4882a593Smuzhiyun 	{ .compatible = "ti,bq27542" },
276*4882a593Smuzhiyun 	{ .compatible = "ti,bq27546" },
277*4882a593Smuzhiyun 	{ .compatible = "ti,bq27742" },
278*4882a593Smuzhiyun 	{ .compatible = "ti,bq27545" },
279*4882a593Smuzhiyun 	{ .compatible = "ti,bq27411" },
280*4882a593Smuzhiyun 	{ .compatible = "ti,bq27421" },
281*4882a593Smuzhiyun 	{ .compatible = "ti,bq27425" },
282*4882a593Smuzhiyun 	{ .compatible = "ti,bq27426" },
283*4882a593Smuzhiyun 	{ .compatible = "ti,bq27441" },
284*4882a593Smuzhiyun 	{ .compatible = "ti,bq27621" },
285*4882a593Smuzhiyun 	{ .compatible = "ti,bq27z561" },
286*4882a593Smuzhiyun 	{ .compatible = "ti,bq28z610" },
287*4882a593Smuzhiyun 	{ .compatible = "ti,bq34z100" },
288*4882a593Smuzhiyun 	{},
289*4882a593Smuzhiyun };
290*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, bq27xxx_battery_i2c_of_match_table);
291*4882a593Smuzhiyun #endif
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun static struct i2c_driver bq27xxx_battery_i2c_driver = {
294*4882a593Smuzhiyun 	.driver = {
295*4882a593Smuzhiyun 		.name = "bq27xxx-battery",
296*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(bq27xxx_battery_i2c_of_match_table),
297*4882a593Smuzhiyun 	},
298*4882a593Smuzhiyun 	.probe = bq27xxx_battery_i2c_probe,
299*4882a593Smuzhiyun 	.remove = bq27xxx_battery_i2c_remove,
300*4882a593Smuzhiyun 	.id_table = bq27xxx_i2c_id_table,
301*4882a593Smuzhiyun };
302*4882a593Smuzhiyun module_i2c_driver(bq27xxx_battery_i2c_driver);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun MODULE_AUTHOR("Andrew F. Davis <afd@ti.com>");
305*4882a593Smuzhiyun MODULE_DESCRIPTION("BQ27xxx battery monitor i2c driver");
306*4882a593Smuzhiyun MODULE_LICENSE("GPL");
307