2 * Gas Gauge driver for TI's BQ20Z75
4 * Copyright (c) 2010, NVIDIA Corporation.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include <linux/init.h>
22 #include <linux/module.h>
23 #include <linux/kernel.h>
24 #include <linux/err.h>
25 #include <linux/power_supply.h>
26 #include <linux/i2c.h>
27 #include <linux/slab.h>
30 REG_MANUFACTURER_DATA
,
42 /* manufacturer access defines */
43 #define MANUFACTURER_ACCESS_STATUS 0x0006
44 #define MANUFACTURER_ACCESS_SLEEP 0x0011
46 /* battery status value bits */
47 #define BATTERY_CHARGING 0x40
48 #define BATTERY_FULL_CHARGED 0x20
49 #define BATTERY_FULL_DISCHARGED 0x10
51 #define BQ20Z75_DATA(_psp, _addr, _min_value, _max_value) { \
54 .min_value = _min_value, \
55 .max_value = _max_value, \
58 static const struct bq20z75_device_data
{
59 enum power_supply_property psp
;
64 [REG_MANUFACTURER_DATA
] =
65 BQ20Z75_DATA(POWER_SUPPLY_PROP_PRESENT
, 0x00, 0, 65535),
67 BQ20Z75_DATA(POWER_SUPPLY_PROP_TEMP
, 0x08, 0, 65535),
69 BQ20Z75_DATA(POWER_SUPPLY_PROP_VOLTAGE_NOW
, 0x09, 0, 20000),
71 BQ20Z75_DATA(POWER_SUPPLY_PROP_CURRENT_NOW
, 0x0A, -32768,
74 BQ20Z75_DATA(POWER_SUPPLY_PROP_CAPACITY
, 0x0E, 0, 100),
76 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG
, 0x12, 0,
79 BQ20Z75_DATA(POWER_SUPPLY_PROP_TIME_TO_FULL_AVG
, 0x13, 0,
82 BQ20Z75_DATA(POWER_SUPPLY_PROP_STATUS
, 0x16, 0, 65535),
84 BQ20Z75_DATA(POWER_SUPPLY_PROP_CYCLE_COUNT
, 0x17, 0, 65535),
86 BQ20Z75_DATA(POWER_SUPPLY_PROP_SERIAL_NUMBER
, 0x1C, 0, 65535),
89 static enum power_supply_property bq20z75_properties
[] = {
90 POWER_SUPPLY_PROP_STATUS
,
91 POWER_SUPPLY_PROP_HEALTH
,
92 POWER_SUPPLY_PROP_PRESENT
,
93 POWER_SUPPLY_PROP_TECHNOLOGY
,
94 POWER_SUPPLY_PROP_CYCLE_COUNT
,
95 POWER_SUPPLY_PROP_VOLTAGE_NOW
,
96 POWER_SUPPLY_PROP_CURRENT_NOW
,
97 POWER_SUPPLY_PROP_CAPACITY
,
98 POWER_SUPPLY_PROP_TEMP
,
99 POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG
,
100 POWER_SUPPLY_PROP_TIME_TO_FULL_AVG
,
101 POWER_SUPPLY_PROP_SERIAL_NUMBER
,
104 struct bq20z75_info
{
105 struct i2c_client
*client
;
106 struct power_supply power_supply
;
109 static int bq20z75_get_battery_presence_and_health(
110 struct i2c_client
*client
, enum power_supply_property psp
,
111 union power_supply_propval
*val
)
115 /* Write to ManufacturerAccess with
116 * ManufacturerAccess command and then
118 ret
= i2c_smbus_write_word_data(client
,
119 bq20z75_data
[REG_MANUFACTURER_DATA
].addr
,
120 MANUFACTURER_ACCESS_STATUS
);
122 dev_err(&client
->dev
,
123 "%s: i2c write for battery presence failed\n",
128 ret
= i2c_smbus_read_word_data(client
,
129 bq20z75_data
[REG_MANUFACTURER_DATA
].addr
);
131 dev_err(&client
->dev
,
132 "%s: i2c read for battery presence failed\n",
137 if (ret
< bq20z75_data
[REG_MANUFACTURER_DATA
].min_value
||
138 ret
> bq20z75_data
[REG_MANUFACTURER_DATA
].max_value
) {
143 /* Mask the upper nibble of 2nd byte and
144 * lower byte of response then
145 * shift the result by 8 to get status*/
148 if (psp
== POWER_SUPPLY_PROP_PRESENT
) {
150 /* battery removed */
154 } else if (psp
== POWER_SUPPLY_PROP_HEALTH
) {
156 val
->intval
= POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
;
157 else if (ret
== 0x0B)
158 val
->intval
= POWER_SUPPLY_HEALTH_OVERHEAT
;
159 else if (ret
== 0x0C)
160 val
->intval
= POWER_SUPPLY_HEALTH_DEAD
;
162 val
->intval
= POWER_SUPPLY_HEALTH_GOOD
;
168 static int bq20z75_get_battery_property(struct i2c_client
*client
,
169 int reg_offset
, enum power_supply_property psp
,
170 union power_supply_propval
*val
)
174 ret
= i2c_smbus_read_word_data(client
,
175 bq20z75_data
[reg_offset
].addr
);
177 dev_err(&client
->dev
,
178 "%s: i2c read for %d failed\n", __func__
, reg_offset
);
182 if (ret
>= bq20z75_data
[reg_offset
].min_value
&&
183 ret
<= bq20z75_data
[reg_offset
].max_value
) {
185 if (psp
== POWER_SUPPLY_PROP_STATUS
) {
186 if (ret
& BATTERY_CHARGING
)
187 val
->intval
= POWER_SUPPLY_STATUS_CHARGING
;
188 else if (ret
& BATTERY_FULL_CHARGED
)
189 val
->intval
= POWER_SUPPLY_STATUS_FULL
;
190 else if (ret
& BATTERY_FULL_DISCHARGED
)
191 val
->intval
= POWER_SUPPLY_STATUS_NOT_CHARGING
;
193 val
->intval
= POWER_SUPPLY_STATUS_DISCHARGING
;
195 /* bq20z75 provides battery tempreture in 0.1°K
196 * so convert it to °C */
197 else if (psp
== POWER_SUPPLY_PROP_TEMP
)
198 val
->intval
= ret
- 2731;
200 if (psp
== POWER_SUPPLY_PROP_STATUS
)
201 val
->intval
= POWER_SUPPLY_STATUS_UNKNOWN
;
209 static int bq20z75_get_battery_capacity(struct i2c_client
*client
,
210 union power_supply_propval
*val
)
214 ret
= i2c_smbus_read_byte_data(client
, bq20z75_data
[REG_CAPACITY
].addr
);
216 dev_err(&client
->dev
,
217 "%s: i2c read for %d failed\n", __func__
, REG_CAPACITY
);
221 /* bq20z75 spec says that this can be >100 %
222 * even if max value is 100 % */
223 val
->intval
= min(ret
, 100);
228 static int bq20z75_get_property(struct power_supply
*psy
,
229 enum power_supply_property psp
,
230 union power_supply_propval
*val
)
234 struct bq20z75_info
*bq20z75_device
= container_of(psy
,
235 struct bq20z75_info
, power_supply
);
236 struct i2c_client
*client
= bq20z75_device
->client
;
239 case POWER_SUPPLY_PROP_PRESENT
:
240 case POWER_SUPPLY_PROP_HEALTH
:
241 ret
= bq20z75_get_battery_presence_and_health(client
, psp
, val
);
246 case POWER_SUPPLY_PROP_TECHNOLOGY
:
247 val
->intval
= POWER_SUPPLY_TECHNOLOGY_LION
;
250 case POWER_SUPPLY_PROP_CAPACITY
:
251 ret
= bq20z75_get_battery_capacity(client
, val
);
256 case POWER_SUPPLY_PROP_STATUS
:
257 case POWER_SUPPLY_PROP_CYCLE_COUNT
:
258 case POWER_SUPPLY_PROP_VOLTAGE_NOW
:
259 case POWER_SUPPLY_PROP_CURRENT_NOW
:
260 case POWER_SUPPLY_PROP_TEMP
:
261 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG
:
262 case POWER_SUPPLY_PROP_TIME_TO_FULL_AVG
:
263 case POWER_SUPPLY_PROP_SERIAL_NUMBER
:
264 for (count
= 0; count
< ARRAY_SIZE(bq20z75_data
); count
++) {
265 if (psp
== bq20z75_data
[count
].psp
)
269 ret
= bq20z75_get_battery_property(client
, count
, psp
, val
);
275 dev_err(&client
->dev
,
276 "%s: INVALID property\n", __func__
);
280 dev_dbg(&client
->dev
,
281 "%s: property = %d, value = %d\n", __func__
, psp
, val
->intval
);
286 static int bq20z75_probe(struct i2c_client
*client
,
287 const struct i2c_device_id
*id
)
289 struct bq20z75_info
*bq20z75_device
;
292 bq20z75_device
= kzalloc(sizeof(struct bq20z75_info
), GFP_KERNEL
);
296 bq20z75_device
->client
= client
;
297 bq20z75_device
->power_supply
.name
= "battery";
298 bq20z75_device
->power_supply
.type
= POWER_SUPPLY_TYPE_BATTERY
;
299 bq20z75_device
->power_supply
.properties
= bq20z75_properties
;
300 bq20z75_device
->power_supply
.num_properties
=
301 ARRAY_SIZE(bq20z75_properties
);
302 bq20z75_device
->power_supply
.get_property
= bq20z75_get_property
;
304 i2c_set_clientdata(client
, bq20z75_device
);
306 rc
= power_supply_register(&client
->dev
, &bq20z75_device
->power_supply
);
308 dev_err(&client
->dev
,
309 "%s: Failed to register power supply\n", __func__
);
310 kfree(bq20z75_device
);
314 dev_info(&client
->dev
,
315 "%s: battery gas gauge device registered\n", client
->name
);
320 static int bq20z75_remove(struct i2c_client
*client
)
322 struct bq20z75_info
*bq20z75_device
= i2c_get_clientdata(client
);
324 power_supply_unregister(&bq20z75_device
->power_supply
);
325 kfree(bq20z75_device
);
326 bq20z75_device
= NULL
;
331 #if defined CONFIG_PM
332 static int bq20z75_suspend(struct i2c_client
*client
,
337 /* write to manufacturer access with sleep command */
338 ret
= i2c_smbus_write_word_data(client
,
339 bq20z75_data
[REG_MANUFACTURER_DATA
].addr
,
340 MANUFACTURER_ACCESS_SLEEP
);
342 dev_err(&client
->dev
,
343 "%s: i2c write for %d failed\n",
344 __func__
, MANUFACTURER_ACCESS_SLEEP
);
351 #define bq20z75_suspend NULL
353 /* any smbus transaction will wake up bq20z75 */
354 #define bq20z75_resume NULL
356 static const struct i2c_device_id bq20z75_id
[] = {
361 static struct i2c_driver bq20z75_battery_driver
= {
362 .probe
= bq20z75_probe
,
363 .remove
= bq20z75_remove
,
364 .suspend
= bq20z75_suspend
,
365 .resume
= bq20z75_resume
,
366 .id_table
= bq20z75_id
,
368 .name
= "bq20z75-battery",
372 static int __init
bq20z75_battery_init(void)
374 return i2c_add_driver(&bq20z75_battery_driver
);
376 module_init(bq20z75_battery_init
);
378 static void __exit
bq20z75_battery_exit(void)
380 i2c_del_driver(&bq20z75_battery_driver
);
382 module_exit(bq20z75_battery_exit
);
384 MODULE_DESCRIPTION("BQ20z75 battery monitor driver");
385 MODULE_LICENSE("GPL");