1ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha/*
2ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * Battery charger driver for TI BQ24735
3ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha *
4ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * Copyright (c) 2013, NVIDIA CORPORATION.  All rights reserved.
5ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha *
6ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * This program is free software; you can redistribute it and/or modify
7ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * it under the terms of the GNU General Public License as published by
8ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * the Free Software Foundation;
9ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha *
10ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * This program is distributed in the hope that it will be useful, but WITHOUT
11ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * more details.
14ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha *
15ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * You should have received a copy of the GNU General Public License along
16ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * with this program; if not, write to the Free Software Foundation, Inc.,
17ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha */
19ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
20ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/err.h>
21ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/gpio.h>
22ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/i2c.h>
23ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/init.h>
24ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/interrupt.h>
25ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/kernel.h>
26ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/module.h>
27ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/of.h>
28ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/of_gpio.h>
29ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/power_supply.h>
30ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/slab.h>
31ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
32ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#include <linux/power/bq24735-charger.h>
33ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
34ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHG_OPT			0x12
35ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHG_OPT_CHARGE_DISABLE	(1 << 0)
36ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHG_OPT_AC_PRESENT	(1 << 4)
37ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHARGE_CURRENT		0x14
38ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHARGE_CURRENT_MASK	0x1fc0
39ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHARGE_VOLTAGE		0x15
40ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_CHARGE_VOLTAGE_MASK	0x7ff0
41ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_INPUT_CURRENT		0x3f
42ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_INPUT_CURRENT_MASK	0x1f80
43ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_MANUFACTURER_ID		0xfe
44ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha#define BQ24735_DEVICE_ID		0xff
45ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
46ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastruct bq24735 {
47ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct power_supply	charger;
48ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct i2c_client	*client;
49ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735_platform	*pdata;
50ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha};
51ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
52ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic inline struct bq24735 *to_bq24735(struct power_supply *psy)
53ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
54ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return container_of(psy, struct bq24735, charger);
55ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
56ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
57ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic enum power_supply_property bq24735_charger_properties[] = {
58ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	POWER_SUPPLY_PROP_ONLINE,
59ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha};
60ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
61ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic inline int bq24735_write_word(struct i2c_client *client, u8 reg,
62ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				     u16 value)
63ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
64ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return i2c_smbus_write_word_data(client, reg, le16_to_cpu(value));
65ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
66ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
67ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic inline int bq24735_read_word(struct i2c_client *client, u8 reg)
68ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
69ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	s32 ret = i2c_smbus_read_word_data(client, reg);
70ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
71ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return ret < 0 ? ret : le16_to_cpu(ret);
72ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
73ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
74ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic int bq24735_update_word(struct i2c_client *client, u8 reg,
75ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			       u16 mask, u16 value)
76ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
77ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	unsigned int tmp;
78ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	int ret;
79ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
80ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = bq24735_read_word(client, reg);
81ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (ret < 0)
82ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return ret;
83ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
84ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	tmp = ret & ~mask;
85ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	tmp |= value & mask;
86ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
87ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return bq24735_write_word(client, reg, tmp);
88ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
89ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
90ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic inline int bq24735_enable_charging(struct bq24735 *charger)
91ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
92ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
93ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				   BQ24735_CHG_OPT_CHARGE_DISABLE,
94ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				   ~BQ24735_CHG_OPT_CHARGE_DISABLE);
95ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
96ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
97ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic inline int bq24735_disable_charging(struct bq24735 *charger)
98ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
99ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return bq24735_update_word(charger->client, BQ24735_CHG_OPT,
100ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				   BQ24735_CHG_OPT_CHARGE_DISABLE,
101ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				   BQ24735_CHG_OPT_CHARGE_DISABLE);
102ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
103ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
104ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic int bq24735_config_charger(struct bq24735 *charger)
105ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
106ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735_platform *pdata = charger->pdata;
107ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	int ret;
108ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	u16 value;
109ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
110ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (pdata->charge_current) {
111ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		value = pdata->charge_current & BQ24735_CHARGE_CURRENT_MASK;
112ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
113ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = bq24735_write_word(charger->client,
114ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					 BQ24735_CHARGE_CURRENT, value);
115ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ret < 0) {
116ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&charger->client->dev,
117ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				"Failed to write charger current : %d\n",
118ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				ret);
119ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			return ret;
120ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
121ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
122ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
123ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (pdata->charge_voltage) {
124ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		value = pdata->charge_voltage & BQ24735_CHARGE_VOLTAGE_MASK;
125ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
126ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = bq24735_write_word(charger->client,
127ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					 BQ24735_CHARGE_VOLTAGE, value);
128ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ret < 0) {
129ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&charger->client->dev,
130ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				"Failed to write charger voltage : %d\n",
131ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				ret);
132ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			return ret;
133ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
134ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
135ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
136ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (pdata->input_current) {
137ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		value = pdata->input_current & BQ24735_INPUT_CURRENT_MASK;
138ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
139ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = bq24735_write_word(charger->client,
140ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					 BQ24735_INPUT_CURRENT, value);
141ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ret < 0) {
142ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&charger->client->dev,
143ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				"Failed to write input current : %d\n",
144ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				ret);
145ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			return ret;
146ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
147ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
148ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
149ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return 0;
150ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
151ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
152ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic bool bq24735_charger_is_present(struct bq24735 *charger)
153ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
154ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735_platform *pdata = charger->pdata;
155ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	int ret;
156ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
157ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (pdata->status_gpio_valid) {
158ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = gpio_get_value_cansleep(pdata->status_gpio);
159ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return ret ^= pdata->status_gpio_active_low == 0;
160ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	} else {
161ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		int ac = 0;
162ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
163ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ac = bq24735_read_word(charger->client, BQ24735_CHG_OPT);
164ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ac < 0) {
165ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&charger->client->dev,
166ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				"Failed to read charger options : %d\n",
167ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				ac);
168ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			return false;
169ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
170ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return (ac & BQ24735_CHG_OPT_AC_PRESENT) ? true : false;
171ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
172ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
173ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return false;
174ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
175ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
176ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic irqreturn_t bq24735_charger_isr(int irq, void *devid)
177ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
178ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct power_supply *psy = devid;
179ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735 *charger = to_bq24735(psy);
180ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
181ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (bq24735_charger_is_present(charger))
182ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		bq24735_enable_charging(charger);
183ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	else
184ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		bq24735_disable_charging(charger);
185ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
186ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	power_supply_changed(psy);
187ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
188ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return IRQ_HANDLED;
189ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
190ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
191ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic int bq24735_charger_get_property(struct power_supply *psy,
192ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					enum power_supply_property psp,
193ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					union power_supply_propval *val)
194ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
195ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735 *charger;
196ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
197ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	charger = container_of(psy, struct bq24735, charger);
198ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
199ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	switch (psp) {
200ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	case POWER_SUPPLY_PROP_ONLINE:
201ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		val->intval = bq24735_charger_is_present(charger) ? 1 : 0;
202ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		break;
203ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	default:
204ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return -EINVAL;
205ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
206ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
207ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return 0;
208ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
209ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
210ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic struct bq24735_platform *bq24735_parse_dt_data(struct i2c_client *client)
211ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
212ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735_platform *pdata;
213ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct device_node *np = client->dev.of_node;
214ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	u32 val;
215ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	int ret;
216ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	enum of_gpio_flags flags;
217ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
218ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
219ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!pdata) {
220ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev,
221ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			"Memory alloc for bq24735 pdata failed\n");
222ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return NULL;
223ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
224ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
225ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	pdata->status_gpio = of_get_named_gpio_flags(np, "ti,ac-detect-gpios",
226ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha						     0, &flags);
227ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
228ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (flags & OF_GPIO_ACTIVE_LOW)
229ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		pdata->status_gpio_active_low = 1;
230ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
231ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = of_property_read_u32(np, "ti,charge-current", &val);
232ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!ret)
233ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		pdata->charge_current = val;
234ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
235ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = of_property_read_u32(np, "ti,charge-voltage", &val);
236ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!ret)
237ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		pdata->charge_voltage = val;
238ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
239ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = of_property_read_u32(np, "ti,input-current", &val);
240ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!ret)
241ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		pdata->input_current = val;
242ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
243ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return pdata;
244ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
245ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
246ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic int bq24735_charger_probe(struct i2c_client *client,
247ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				 const struct i2c_device_id *id)
248ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
249ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	int ret;
250ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735 *charger;
251ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct power_supply *supply;
252ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	char *name;
253ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
254ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	charger = devm_kzalloc(&client->dev, sizeof(*charger), GFP_KERNEL);
255ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!charger)
256ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return -ENOMEM;
257ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
258ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	charger->pdata = client->dev.platform_data;
259ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
260ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (IS_ENABLED(CONFIG_OF) && !charger->pdata && client->dev.of_node)
261ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		charger->pdata = bq24735_parse_dt_data(client);
262ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
263ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!charger->pdata) {
264ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev, "no platform data provided\n");
265ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		return -EINVAL;
266ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
267ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
268ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	name = (char *)charger->pdata->name;
269ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (!name) {
270ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		name = kasprintf(GFP_KERNEL, "bq24735@%s",
271ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				 dev_name(&client->dev));
272ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (!name) {
273ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&client->dev, "Failed to alloc device name\n");
274ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			return -ENOMEM;
275ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
276ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
277ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
278ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	charger->client = client;
279ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
280ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply = &charger->charger;
281ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
282ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->name = name;
283ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->type = POWER_SUPPLY_TYPE_MAINS;
284ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->properties = bq24735_charger_properties;
285ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->num_properties = ARRAY_SIZE(bq24735_charger_properties);
286ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->get_property = bq24735_charger_get_property;
287ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->supplied_to = charger->pdata->supplied_to;
288ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->num_supplicants = charger->pdata->num_supplicants;
289ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	supply->of_node = client->dev.of_node;
290ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
291ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	i2c_set_clientdata(client, charger);
292ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
293ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = bq24735_read_word(client, BQ24735_MANUFACTURER_ID);
294ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (ret < 0) {
295ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev, "Failed to read manufacturer id : %d\n",
296ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			ret);
297ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		goto err_free_name;
298ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	} else if (ret != 0x0040) {
299ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev,
300ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			"manufacturer id mismatch. 0x0040 != 0x%04x\n", ret);
301ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = -ENODEV;
302ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		goto err_free_name;
303ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
304ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
305ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = bq24735_read_word(client, BQ24735_DEVICE_ID);
306ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (ret < 0) {
307ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev, "Failed to read device id : %d\n", ret);
308ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		goto err_free_name;
309ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	} else if (ret != 0x000B) {
310ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev,
311ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			"device id mismatch. 0x000b != 0x%04x\n", ret);
312ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = -ENODEV;
313ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		goto err_free_name;
314ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
315ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
316ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (gpio_is_valid(charger->pdata->status_gpio)) {
317ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = devm_gpio_request(&client->dev,
318ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					charger->pdata->status_gpio,
319ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha					name);
320ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ret) {
321ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&client->dev,
322ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				"Failed GPIO request for GPIO %d: %d\n",
323ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				charger->pdata->status_gpio, ret);
324ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
325ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
326ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		charger->pdata->status_gpio_valid = !ret;
327ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
328ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
329ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = bq24735_config_charger(charger);
330ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (ret < 0) {
331ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev, "failed in configuring charger");
332ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		goto err_free_name;
333ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
334ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
335ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	/* check for AC adapter presence */
336ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (bq24735_charger_is_present(charger)) {
337ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = bq24735_enable_charging(charger);
338ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ret < 0) {
339ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&client->dev, "Failed to enable charging\n");
340ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			goto err_free_name;
341ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
342ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
343ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
344ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	ret = power_supply_register(&client->dev, supply);
345ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (ret < 0) {
346ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		dev_err(&client->dev, "Failed to register power supply: %d\n",
347ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			ret);
348ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		goto err_free_name;
349ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
350ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
351ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (client->irq) {
352ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		ret = devm_request_threaded_irq(&client->dev, client->irq,
353ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha						NULL, bq24735_charger_isr,
354ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha						IRQF_TRIGGER_RISING |
355ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha						IRQF_TRIGGER_FALLING |
356ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha						IRQF_ONESHOT,
357ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha						supply->name, supply);
358ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		if (ret) {
359ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			dev_err(&client->dev,
360ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				"Unable to register IRQ %d err %d\n",
361ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha				client->irq, ret);
362ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			goto err_unregister_supply;
363ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		}
364ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	}
365ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
366ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return 0;
367ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshaerr_unregister_supply:
368ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	power_supply_unregister(supply);
369ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshaerr_free_name:
370ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (name != charger->pdata->name)
371ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		kfree(name);
372ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
373ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return ret;
374ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
375ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
376ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic int bq24735_charger_remove(struct i2c_client *client)
377ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha{
378ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	struct bq24735 *charger = i2c_get_clientdata(client);
379ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
380ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (charger->client->irq)
381ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		devm_free_irq(&charger->client->dev, charger->client->irq,
382ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha			      &charger->charger);
383ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
384ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	power_supply_unregister(&charger->charger);
385ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
386ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	if (charger->charger.name != charger->pdata->name)
387ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		kfree(charger->charger.name);
388ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
389ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	return 0;
390ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha}
391ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
392ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic const struct i2c_device_id bq24735_charger_id[] = {
393ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	{ "bq24735-charger", 0 },
394ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	{}
395ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha};
396ce77399226313a72578b5b0d67e289d3f165b8baDarbha SriharshaMODULE_DEVICE_TABLE(i2c, bq24735_charger_id);
397ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
398ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic const struct of_device_id bq24735_match_ids[] = {
399ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	{ .compatible = "ti,bq24735", },
400ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	{ /* end */ }
401ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha};
402ce77399226313a72578b5b0d67e289d3f165b8baDarbha SriharshaMODULE_DEVICE_TABLE(of, bq24735_match_ids);
403ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
404ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshastatic struct i2c_driver bq24735_charger_driver = {
405ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	.driver = {
406ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		.name = "bq24735-charger",
407ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		.owner = THIS_MODULE,
408ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha		.of_match_table = bq24735_match_ids,
409ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	},
410ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	.probe = bq24735_charger_probe,
411ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	.remove = bq24735_charger_remove,
412ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha	.id_table = bq24735_charger_id,
413ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha};
414ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
415ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharshamodule_i2c_driver(bq24735_charger_driver);
416ce77399226313a72578b5b0d67e289d3f165b8baDarbha Sriharsha
417ce77399226313a72578b5b0d67e289d3f165b8baDarbha SriharshaMODULE_DESCRIPTION("bq24735 battery charging driver");
418ce77399226313a72578b5b0d67e289d3f165b8baDarbha SriharshaMODULE_AUTHOR("Darbha Sriharsha <dsriharsha@nvidia.com>");
419ce77399226313a72578b5b0d67e289d3f165b8baDarbha SriharshaMODULE_LICENSE("GPL v2");
420