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