xref: /OK3568_Linux_fs/kernel/drivers/power/supply/bq24735-charger.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Battery charger driver for TI BQ24735
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or modify
7*4882a593Smuzhiyun  * it under the terms of the GNU General Public License as published by
8*4882a593Smuzhiyun  * the Free Software Foundation;
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful, but WITHOUT
11*4882a593Smuzhiyun  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12*4882a593Smuzhiyun  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13*4882a593Smuzhiyun  * more details.
14*4882a593Smuzhiyun  *
15*4882a593Smuzhiyun  * You should have received a copy of the GNU General Public License along
16*4882a593Smuzhiyun  * with this program; if not, write to the Free Software Foundation, Inc.,
17*4882a593Smuzhiyun  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18*4882a593Smuzhiyun  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/gpio.h>
22*4882a593Smuzhiyun #include <linux/i2c.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/interrupt.h>
25*4882a593Smuzhiyun #include <linux/kernel.h>
26*4882a593Smuzhiyun #include <linux/module.h>
27*4882a593Smuzhiyun #include <linux/of.h>
28*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
29*4882a593Smuzhiyun #include <linux/power_supply.h>
30*4882a593Smuzhiyun #include <linux/slab.h>
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun #include <linux/power/bq24735-charger.h>
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define BQ24735_CHG_OPT			0x12
35*4882a593Smuzhiyun #define BQ24735_CHG_OPT_CHARGE_DISABLE	(1 << 0)
36*4882a593Smuzhiyun #define BQ24735_CHG_OPT_AC_PRESENT	(1 << 4)
37*4882a593Smuzhiyun #define BQ24735_CHARGE_CURRENT		0x14
38*4882a593Smuzhiyun #define BQ24735_CHARGE_CURRENT_MASK	0x1fc0
39*4882a593Smuzhiyun #define BQ24735_CHARGE_VOLTAGE		0x15
40*4882a593Smuzhiyun #define BQ24735_CHARGE_VOLTAGE_MASK	0x7ff0
41*4882a593Smuzhiyun #define BQ24735_INPUT_CURRENT		0x3f
42*4882a593Smuzhiyun #define BQ24735_INPUT_CURRENT_MASK	0x1f80
43*4882a593Smuzhiyun #define BQ24735_MANUFACTURER_ID		0xfe
44*4882a593Smuzhiyun #define BQ24735_DEVICE_ID		0xff
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun struct bq24735 {
47*4882a593Smuzhiyun 	struct power_supply		*charger;
48*4882a593Smuzhiyun 	struct power_supply_desc	charger_desc;
49*4882a593Smuzhiyun 	struct i2c_client		*client;
50*4882a593Smuzhiyun 	struct bq24735_platform		*pdata;
51*4882a593Smuzhiyun 	struct mutex			lock;
52*4882a593Smuzhiyun 	struct gpio_desc		*status_gpio;
53*4882a593Smuzhiyun 	struct delayed_work		poll;
54*4882a593Smuzhiyun 	u32				poll_interval;
55*4882a593Smuzhiyun 	bool				charging;
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun 
to_bq24735(struct power_supply * psy)58*4882a593Smuzhiyun static inline struct bq24735 *to_bq24735(struct power_supply *psy)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	return power_supply_get_drvdata(psy);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun static enum power_supply_property bq24735_charger_properties[] = {
64*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_STATUS,
65*4882a593Smuzhiyun 	POWER_SUPPLY_PROP_ONLINE,
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun 
bq24735_charger_property_is_writeable(struct power_supply * psy,enum power_supply_property psp)68*4882a593Smuzhiyun static int bq24735_charger_property_is_writeable(struct power_supply *psy,
69*4882a593Smuzhiyun 						 enum power_supply_property psp)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	switch (psp) {
72*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
73*4882a593Smuzhiyun 		return 1;
74*4882a593Smuzhiyun 	default:
75*4882a593Smuzhiyun 		break;
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 	return 0;
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
bq24735_write_word(struct i2c_client * client,u8 reg,u16 value)81*4882a593Smuzhiyun static inline int bq24735_write_word(struct i2c_client *client, u8 reg,
82*4882a593Smuzhiyun 				     u16 value)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	return i2c_smbus_write_word_data(client, reg, value);
85*4882a593Smuzhiyun }
86*4882a593Smuzhiyun 
bq24735_read_word(struct i2c_client * client,u8 reg)87*4882a593Smuzhiyun static inline int bq24735_read_word(struct i2c_client *client, u8 reg)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	return i2c_smbus_read_word_data(client, reg);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
bq24735_update_word(struct i2c_client * client,u8 reg,u16 mask,u16 value)92*4882a593Smuzhiyun static int bq24735_update_word(struct i2c_client *client, u8 reg,
93*4882a593Smuzhiyun 			       u16 mask, u16 value)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	unsigned int tmp;
96*4882a593Smuzhiyun 	int ret;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	ret = bq24735_read_word(client, reg);
99*4882a593Smuzhiyun 	if (ret < 0)
100*4882a593Smuzhiyun 		return ret;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	tmp = ret & ~mask;
103*4882a593Smuzhiyun 	tmp |= value & mask;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	return bq24735_write_word(client, reg, tmp);
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun 
bq24735_config_charger(struct bq24735 * charger)108*4882a593Smuzhiyun static int bq24735_config_charger(struct bq24735 *charger)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	struct bq24735_platform *pdata = charger->pdata;
111*4882a593Smuzhiyun 	int ret;
112*4882a593Smuzhiyun 	u16 value;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	if (pdata->ext_control)
115*4882a593Smuzhiyun 		return 0;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	if (pdata->charge_current) {
118*4882a593Smuzhiyun 		value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 		ret = bq24735_write_word(charger->client,
121*4882a593Smuzhiyun 					 BQ24735_CHARGE_CURRENT, value);
122*4882a593Smuzhiyun 		if (ret < 0) {
123*4882a593Smuzhiyun 			dev_err(&charger->client->dev,
124*4882a593Smuzhiyun 				"Failed to write charger current : %d\n",
125*4882a593Smuzhiyun 				ret);
126*4882a593Smuzhiyun 			return ret;
127*4882a593Smuzhiyun 		}
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	if (pdata->charge_voltage) {
131*4882a593Smuzhiyun 		value = pdata->charge_voltage & BQ24735_CHARGE_VOLTAGE_MASK;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 		ret = bq24735_write_word(charger->client,
134*4882a593Smuzhiyun 					 BQ24735_CHARGE_VOLTAGE, value);
135*4882a593Smuzhiyun 		if (ret < 0) {
136*4882a593Smuzhiyun 			dev_err(&charger->client->dev,
137*4882a593Smuzhiyun 				"Failed to write charger voltage : %d\n",
138*4882a593Smuzhiyun 				ret);
139*4882a593Smuzhiyun 			return ret;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 	}
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	if (pdata->input_current) {
144*4882a593Smuzhiyun 		value = pdata->input_current & BQ24735_INPUT_CURRENT_MASK;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 		ret = bq24735_write_word(charger->client,
147*4882a593Smuzhiyun 					 BQ24735_INPUT_CURRENT, value);
148*4882a593Smuzhiyun 		if (ret < 0) {
149*4882a593Smuzhiyun 			dev_err(&charger->client->dev,
150*4882a593Smuzhiyun 				"Failed to write input current : %d\n",
151*4882a593Smuzhiyun 				ret);
152*4882a593Smuzhiyun 			return ret;
153*4882a593Smuzhiyun 		}
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return 0;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
bq24735_enable_charging(struct bq24735 * charger)159*4882a593Smuzhiyun static inline int bq24735_enable_charging(struct bq24735 *charger)
160*4882a593Smuzhiyun {
161*4882a593Smuzhiyun 	int ret;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (charger->pdata->ext_control)
164*4882a593Smuzhiyun 		return 0;
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	ret = bq24735_config_charger(charger);
167*4882a593Smuzhiyun 	if (ret)
168*4882a593Smuzhiyun 		return ret;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
171*4882a593Smuzhiyun 				   BQ24735_CHG_OPT_CHARGE_DISABLE, 0);
172*4882a593Smuzhiyun }
173*4882a593Smuzhiyun 
bq24735_disable_charging(struct bq24735 * charger)174*4882a593Smuzhiyun static inline int bq24735_disable_charging(struct bq24735 *charger)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	if (charger->pdata->ext_control)
177*4882a593Smuzhiyun 		return 0;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun 	return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
180*4882a593Smuzhiyun 				   BQ24735_CHG_OPT_CHARGE_DISABLE,
181*4882a593Smuzhiyun 				   BQ24735_CHG_OPT_CHARGE_DISABLE);
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
bq24735_charger_is_present(struct bq24735 * charger)184*4882a593Smuzhiyun static bool bq24735_charger_is_present(struct bq24735 *charger)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	if (charger->status_gpio) {
187*4882a593Smuzhiyun 		return !gpiod_get_value_cansleep(charger->status_gpio);
188*4882a593Smuzhiyun 	} else {
189*4882a593Smuzhiyun 		int ac = 0;
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 		ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
192*4882a593Smuzhiyun 		if (ac < 0) {
193*4882a593Smuzhiyun 			dev_dbg(&charger->client->dev,
194*4882a593Smuzhiyun 				"Failed to read charger options : %d\n",
195*4882a593Smuzhiyun 				ac);
196*4882a593Smuzhiyun 			return false;
197*4882a593Smuzhiyun 		}
198*4882a593Smuzhiyun 		return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	return false;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
bq24735_charger_is_charging(struct bq24735 * charger)204*4882a593Smuzhiyun static int bq24735_charger_is_charging(struct bq24735 *charger)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	int ret;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	if (!bq24735_charger_is_present(charger))
209*4882a593Smuzhiyun 		return 0;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	ret  = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
212*4882a593Smuzhiyun 	if (ret < 0)
213*4882a593Smuzhiyun 		return ret;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	return !(ret & BQ24735_CHG_OPT_CHARGE_DISABLE);
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
bq24735_update(struct bq24735 * charger)218*4882a593Smuzhiyun static void bq24735_update(struct bq24735 *charger)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	mutex_lock(&charger->lock);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	if (charger->charging && bq24735_charger_is_present(charger))
223*4882a593Smuzhiyun 		bq24735_enable_charging(charger);
224*4882a593Smuzhiyun 	else
225*4882a593Smuzhiyun 		bq24735_disable_charging(charger);
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	mutex_unlock(&charger->lock);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	power_supply_changed(charger->charger);
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun 
bq24735_charger_isr(int irq,void * devid)232*4882a593Smuzhiyun static irqreturn_t bq24735_charger_isr(int irq, void *devid)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun 	struct power_supply *psy = devid;
235*4882a593Smuzhiyun 	struct bq24735 *charger = to_bq24735(psy);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	bq24735_update(charger);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	return IRQ_HANDLED;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
bq24735_poll(struct work_struct * work)242*4882a593Smuzhiyun static void bq24735_poll(struct work_struct *work)
243*4882a593Smuzhiyun {
244*4882a593Smuzhiyun 	struct bq24735 *charger = container_of(work, struct bq24735, poll.work);
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	bq24735_update(charger);
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	schedule_delayed_work(&charger->poll,
249*4882a593Smuzhiyun 			      msecs_to_jiffies(charger->poll_interval));
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
bq24735_charger_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)252*4882a593Smuzhiyun static int bq24735_charger_get_property(struct power_supply *psy,
253*4882a593Smuzhiyun 					enum power_supply_property psp,
254*4882a593Smuzhiyun 					union power_supply_propval *val)
255*4882a593Smuzhiyun {
256*4882a593Smuzhiyun 	struct bq24735 *charger = to_bq24735(psy);
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	switch (psp) {
259*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_ONLINE:
260*4882a593Smuzhiyun 		val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
261*4882a593Smuzhiyun 		break;
262*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
263*4882a593Smuzhiyun 		switch (bq24735_charger_is_charging(charger)) {
264*4882a593Smuzhiyun 		case 1:
265*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_STATUS_CHARGING;
266*4882a593Smuzhiyun 			break;
267*4882a593Smuzhiyun 		case 0:
268*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING;
269*4882a593Smuzhiyun 			break;
270*4882a593Smuzhiyun 		default:
271*4882a593Smuzhiyun 			val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
272*4882a593Smuzhiyun 			break;
273*4882a593Smuzhiyun 		}
274*4882a593Smuzhiyun 		break;
275*4882a593Smuzhiyun 	default:
276*4882a593Smuzhiyun 		return -EINVAL;
277*4882a593Smuzhiyun 	}
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	return 0;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun 
bq24735_charger_set_property(struct power_supply * psy,enum power_supply_property psp,const union power_supply_propval * val)282*4882a593Smuzhiyun static int bq24735_charger_set_property(struct power_supply *psy,
283*4882a593Smuzhiyun 					enum power_supply_property psp,
284*4882a593Smuzhiyun 					const union power_supply_propval *val)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	struct bq24735 *charger = to_bq24735(psy);
287*4882a593Smuzhiyun 	int ret;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	switch (psp) {
290*4882a593Smuzhiyun 	case POWER_SUPPLY_PROP_STATUS:
291*4882a593Smuzhiyun 		switch (val->intval) {
292*4882a593Smuzhiyun 		case POWER_SUPPLY_STATUS_CHARGING:
293*4882a593Smuzhiyun 			mutex_lock(&charger->lock);
294*4882a593Smuzhiyun 			charger->charging = true;
295*4882a593Smuzhiyun 			ret = bq24735_enable_charging(charger);
296*4882a593Smuzhiyun 			mutex_unlock(&charger->lock);
297*4882a593Smuzhiyun 			if (ret)
298*4882a593Smuzhiyun 				return ret;
299*4882a593Smuzhiyun 			break;
300*4882a593Smuzhiyun 		case POWER_SUPPLY_STATUS_DISCHARGING:
301*4882a593Smuzhiyun 		case POWER_SUPPLY_STATUS_NOT_CHARGING:
302*4882a593Smuzhiyun 			mutex_lock(&charger->lock);
303*4882a593Smuzhiyun 			charger->charging = false;
304*4882a593Smuzhiyun 			ret = bq24735_disable_charging(charger);
305*4882a593Smuzhiyun 			mutex_unlock(&charger->lock);
306*4882a593Smuzhiyun 			if (ret)
307*4882a593Smuzhiyun 				return ret;
308*4882a593Smuzhiyun 			break;
309*4882a593Smuzhiyun 		default:
310*4882a593Smuzhiyun 			return -EINVAL;
311*4882a593Smuzhiyun 		}
312*4882a593Smuzhiyun 		power_supply_changed(psy);
313*4882a593Smuzhiyun 		break;
314*4882a593Smuzhiyun 	default:
315*4882a593Smuzhiyun 		return -EPERM;
316*4882a593Smuzhiyun 	}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	return 0;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun 
bq24735_parse_dt_data(struct i2c_client * client)321*4882a593Smuzhiyun static struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun 	struct bq24735_platform *pdata;
324*4882a593Smuzhiyun 	struct device_node *np = client->dev.of_node;
325*4882a593Smuzhiyun 	u32 val;
326*4882a593Smuzhiyun 	int ret;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
329*4882a593Smuzhiyun 	if (!pdata) {
330*4882a593Smuzhiyun 		dev_err(&client->dev,
331*4882a593Smuzhiyun 			"Memory alloc for bq24735 pdata failed\n");
332*4882a593Smuzhiyun 		return NULL;
333*4882a593Smuzhiyun 	}
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "ti,charge-current", &val);
336*4882a593Smuzhiyun 	if (!ret)
337*4882a593Smuzhiyun 		pdata->charge_current = val;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "ti,charge-voltage", &val);
340*4882a593Smuzhiyun 	if (!ret)
341*4882a593Smuzhiyun 		pdata->charge_voltage = val;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	ret = of_property_read_u32(np, "ti,input-current", &val);
344*4882a593Smuzhiyun 	if (!ret)
345*4882a593Smuzhiyun 		pdata->input_current = val;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	pdata->ext_control = of_property_read_bool(np, "ti,external-control");
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	return pdata;
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun 
bq24735_charger_probe(struct i2c_client * client,const struct i2c_device_id * id)352*4882a593Smuzhiyun static int bq24735_charger_probe(struct i2c_client *client,
353*4882a593Smuzhiyun 				 const struct i2c_device_id *id)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	int ret;
356*4882a593Smuzhiyun 	struct bq24735 *charger;
357*4882a593Smuzhiyun 	struct power_supply_desc *supply_desc;
358*4882a593Smuzhiyun 	struct power_supply_config psy_cfg = {};
359*4882a593Smuzhiyun 	char *name;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL);
362*4882a593Smuzhiyun 	if (!charger)
363*4882a593Smuzhiyun 		return -ENOMEM;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	mutex_init(&charger->lock);
366*4882a593Smuzhiyun 	charger->charging = true;
367*4882a593Smuzhiyun 	charger->pdata = client->dev.platform_data;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
370*4882a593Smuzhiyun 		charger->pdata = bq24735_parse_dt_data(client);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	if (!charger->pdata) {
373*4882a593Smuzhiyun 		dev_err(&client->dev, "no platform data provided\n");
374*4882a593Smuzhiyun 		return -EINVAL;
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	name = (char *)charger->pdata->name;
378*4882a593Smuzhiyun 	if (!name) {
379*4882a593Smuzhiyun 		name = devm_kasprintf(&client->dev, GFP_KERNEL,
380*4882a593Smuzhiyun 				      "bq24735@%s",
381*4882a593Smuzhiyun 				      dev_name(&client->dev));
382*4882a593Smuzhiyun 		if (!name) {
383*4882a593Smuzhiyun 			dev_err(&client->dev, "Failed to alloc device name\n");
384*4882a593Smuzhiyun 			return -ENOMEM;
385*4882a593Smuzhiyun 		}
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	charger->client = client;
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	supply_desc = &charger->charger_desc;
391*4882a593Smuzhiyun 
392*4882a593Smuzhiyun 	supply_desc->name = name;
393*4882a593Smuzhiyun 	supply_desc->type = POWER_SUPPLY_TYPE_MAINS;
394*4882a593Smuzhiyun 	supply_desc->properties = bq24735_charger_properties;
395*4882a593Smuzhiyun 	supply_desc->num_properties = ARRAY_SIZE(bq24735_charger_properties);
396*4882a593Smuzhiyun 	supply_desc->get_property = bq24735_charger_get_property;
397*4882a593Smuzhiyun 	supply_desc->set_property = bq24735_charger_set_property;
398*4882a593Smuzhiyun 	supply_desc->property_is_writeable =
399*4882a593Smuzhiyun 				bq24735_charger_property_is_writeable;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	psy_cfg.supplied_to = charger->pdata->supplied_to;
402*4882a593Smuzhiyun 	psy_cfg.num_supplicants = charger->pdata->num_supplicants;
403*4882a593Smuzhiyun 	psy_cfg.of_node = client->dev.of_node;
404*4882a593Smuzhiyun 	psy_cfg.drv_data = charger;
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun 	i2c_set_clientdata(client, charger);
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	charger->status_gpio = devm_gpiod_get_optional(&client->dev,
409*4882a593Smuzhiyun 						       "ti,ac-detect",
410*4882a593Smuzhiyun 						       GPIOD_IN);
411*4882a593Smuzhiyun 	if (IS_ERR(charger->status_gpio)) {
412*4882a593Smuzhiyun 		ret = PTR_ERR(charger->status_gpio);
413*4882a593Smuzhiyun 		dev_err(&client->dev, "Getting gpio failed: %d\n", ret);
414*4882a593Smuzhiyun 		return ret;
415*4882a593Smuzhiyun 	}
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	if (bq24735_charger_is_present(charger)) {
418*4882a593Smuzhiyun 		ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
419*4882a593Smuzhiyun 		if (ret < 0) {
420*4882a593Smuzhiyun 			dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
421*4882a593Smuzhiyun 				ret);
422*4882a593Smuzhiyun 			return ret;
423*4882a593Smuzhiyun 		} else if (ret != 0x0040) {
424*4882a593Smuzhiyun 			dev_err(&client->dev,
425*4882a593Smuzhiyun 				"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
426*4882a593Smuzhiyun 			return -ENODEV;
427*4882a593Smuzhiyun 		}
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun 		ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
430*4882a593Smuzhiyun 		if (ret < 0) {
431*4882a593Smuzhiyun 			dev_err(&client->dev, "Failed to read device id : %d\n", ret);
432*4882a593Smuzhiyun 			return ret;
433*4882a593Smuzhiyun 		} else if (ret != 0x000B) {
434*4882a593Smuzhiyun 			dev_err(&client->dev,
435*4882a593Smuzhiyun 				"device id mismatch. 0x000b != 0x%04x\n", ret);
436*4882a593Smuzhiyun 			return -ENODEV;
437*4882a593Smuzhiyun 		}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun 		ret = bq24735_enable_charging(charger);
440*4882a593Smuzhiyun 		if (ret < 0) {
441*4882a593Smuzhiyun 			dev_err(&client->dev, "Failed to enable charging\n");
442*4882a593Smuzhiyun 			return ret;
443*4882a593Smuzhiyun 		}
444*4882a593Smuzhiyun 	}
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	charger->charger = devm_power_supply_register(&client->dev, supply_desc,
447*4882a593Smuzhiyun 						      &psy_cfg);
448*4882a593Smuzhiyun 	if (IS_ERR(charger->charger)) {
449*4882a593Smuzhiyun 		ret = PTR_ERR(charger->charger);
450*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to register power supply: %d\n",
451*4882a593Smuzhiyun 			ret);
452*4882a593Smuzhiyun 		return ret;
453*4882a593Smuzhiyun 	}
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	if (client->irq) {
456*4882a593Smuzhiyun 		ret = devm_request_threaded_irq(&client->dev, client->irq,
457*4882a593Smuzhiyun 						NULL, bq24735_charger_isr,
458*4882a593Smuzhiyun 						IRQF_TRIGGER_RISING |
459*4882a593Smuzhiyun 						IRQF_TRIGGER_FALLING |
460*4882a593Smuzhiyun 						IRQF_ONESHOT,
461*4882a593Smuzhiyun 						supply_desc->name,
462*4882a593Smuzhiyun 						charger->charger);
463*4882a593Smuzhiyun 		if (ret) {
464*4882a593Smuzhiyun 			dev_err(&client->dev,
465*4882a593Smuzhiyun 				"Unable to register IRQ %d err %d\n",
466*4882a593Smuzhiyun 				client->irq, ret);
467*4882a593Smuzhiyun 			return ret;
468*4882a593Smuzhiyun 		}
469*4882a593Smuzhiyun 	} else {
470*4882a593Smuzhiyun 		ret = device_property_read_u32(&client->dev, "poll-interval",
471*4882a593Smuzhiyun 					       &charger->poll_interval);
472*4882a593Smuzhiyun 		if (ret)
473*4882a593Smuzhiyun 			return 0;
474*4882a593Smuzhiyun 		if (!charger->poll_interval)
475*4882a593Smuzhiyun 			return 0;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 		INIT_DELAYED_WORK(&charger->poll, bq24735_poll);
478*4882a593Smuzhiyun 		schedule_delayed_work(&charger->poll,
479*4882a593Smuzhiyun 				      msecs_to_jiffies(charger->poll_interval));
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	return 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun 
bq24735_charger_remove(struct i2c_client * client)485*4882a593Smuzhiyun static int bq24735_charger_remove(struct i2c_client *client)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun 	struct bq24735 *charger = i2c_get_clientdata(client);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	if (charger->poll_interval)
490*4882a593Smuzhiyun 		cancel_delayed_work_sync(&charger->poll);
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	return 0;
493*4882a593Smuzhiyun }
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun static const struct i2c_device_id bq24735_charger_id[] = {
496*4882a593Smuzhiyun 	{ "bq24735-charger", 0 },
497*4882a593Smuzhiyun 	{}
498*4882a593Smuzhiyun };
499*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, bq24735_charger_id);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun static const struct of_device_id bq24735_match_ids[] = {
502*4882a593Smuzhiyun 	{ .compatible = "ti,bq24735", },
503*4882a593Smuzhiyun 	{ /* end */ }
504*4882a593Smuzhiyun };
505*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, bq24735_match_ids);
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun static struct i2c_driver bq24735_charger_driver = {
508*4882a593Smuzhiyun 	.driver = {
509*4882a593Smuzhiyun 		.name = "bq24735-charger",
510*4882a593Smuzhiyun 		.of_match_table = bq24735_match_ids,
511*4882a593Smuzhiyun 	},
512*4882a593Smuzhiyun 	.probe = bq24735_charger_probe,
513*4882a593Smuzhiyun 	.remove = bq24735_charger_remove,
514*4882a593Smuzhiyun 	.id_table = bq24735_charger_id,
515*4882a593Smuzhiyun };
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun module_i2c_driver(bq24735_charger_driver);
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun MODULE_DESCRIPTION("bq24735 battery charging driver");
520*4882a593Smuzhiyun MODULE_AUTHOR("Darbha Sriharsha <dsriharsha@nvidia.com>");
521*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
522