blob: 50171fd3cc6db6f31ed1ee489af04884cafaa687 [file] [log] [blame]
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001/*
2 * Driver for the TI bq24190 battery charger.
3 *
4 * Author: Mark A. Greer <mgreer@animalcreek.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/module.h>
12#include <linux/interrupt.h>
13#include <linux/delay.h>
14#include <linux/of_irq.h>
15#include <linux/of_device.h>
16#include <linux/pm_runtime.h>
17#include <linux/power_supply.h>
18#include <linux/gpio.h>
19#include <linux/i2c.h>
20
21#include <linux/power/bq24190_charger.h>
22
23
24#define BQ24190_MANUFACTURER "Texas Instruments"
25
26#define BQ24190_REG_ISC 0x00 /* Input Source Control */
27#define BQ24190_REG_ISC_EN_HIZ_MASK BIT(7)
28#define BQ24190_REG_ISC_EN_HIZ_SHIFT 7
29#define BQ24190_REG_ISC_VINDPM_MASK (BIT(6) | BIT(5) | BIT(4) | \
30 BIT(3))
31#define BQ24190_REG_ISC_VINDPM_SHIFT 3
32#define BQ24190_REG_ISC_IINLIM_MASK (BIT(2) | BIT(1) | BIT(0))
33#define BQ24190_REG_ISC_IINLIM_SHIFT 0
34
35#define BQ24190_REG_POC 0x01 /* Power-On Configuration */
36#define BQ24190_REG_POC_RESET_MASK BIT(7)
37#define BQ24190_REG_POC_RESET_SHIFT 7
38#define BQ24190_REG_POC_WDT_RESET_MASK BIT(6)
39#define BQ24190_REG_POC_WDT_RESET_SHIFT 6
40#define BQ24190_REG_POC_CHG_CONFIG_MASK (BIT(5) | BIT(4))
41#define BQ24190_REG_POC_CHG_CONFIG_SHIFT 4
42#define BQ24190_REG_POC_SYS_MIN_MASK (BIT(3) | BIT(2) | BIT(1))
43#define BQ24190_REG_POC_SYS_MIN_SHIFT 1
44#define BQ24190_REG_POC_BOOST_LIM_MASK BIT(0)
45#define BQ24190_REG_POC_BOOST_LIM_SHIFT 0
46
47#define BQ24190_REG_CCC 0x02 /* Charge Current Control */
48#define BQ24190_REG_CCC_ICHG_MASK (BIT(7) | BIT(6) | BIT(5) | \
49 BIT(4) | BIT(3) | BIT(2))
50#define BQ24190_REG_CCC_ICHG_SHIFT 2
51#define BQ24190_REG_CCC_FORCE_20PCT_MASK BIT(0)
52#define BQ24190_REG_CCC_FORCE_20PCT_SHIFT 0
53
54#define BQ24190_REG_PCTCC 0x03 /* Pre-charge/Termination Current Cntl */
55#define BQ24190_REG_PCTCC_IPRECHG_MASK (BIT(7) | BIT(6) | BIT(5) | \
56 BIT(4))
57#define BQ24190_REG_PCTCC_IPRECHG_SHIFT 4
58#define BQ24190_REG_PCTCC_ITERM_MASK (BIT(3) | BIT(2) | BIT(1) | \
59 BIT(0))
60#define BQ24190_REG_PCTCC_ITERM_SHIFT 0
61
62#define BQ24190_REG_CVC 0x04 /* Charge Voltage Control */
63#define BQ24190_REG_CVC_VREG_MASK (BIT(7) | BIT(6) | BIT(5) | \
64 BIT(4) | BIT(3) | BIT(2))
65#define BQ24190_REG_CVC_VREG_SHIFT 2
66#define BQ24190_REG_CVC_BATLOWV_MASK BIT(1)
67#define BQ24190_REG_CVC_BATLOWV_SHIFT 1
68#define BQ24190_REG_CVC_VRECHG_MASK BIT(0)
69#define BQ24190_REG_CVC_VRECHG_SHIFT 0
70
71#define BQ24190_REG_CTTC 0x05 /* Charge Term/Timer Control */
72#define BQ24190_REG_CTTC_EN_TERM_MASK BIT(7)
73#define BQ24190_REG_CTTC_EN_TERM_SHIFT 7
74#define BQ24190_REG_CTTC_TERM_STAT_MASK BIT(6)
75#define BQ24190_REG_CTTC_TERM_STAT_SHIFT 6
76#define BQ24190_REG_CTTC_WATCHDOG_MASK (BIT(5) | BIT(4))
77#define BQ24190_REG_CTTC_WATCHDOG_SHIFT 4
78#define BQ24190_REG_CTTC_EN_TIMER_MASK BIT(3)
79#define BQ24190_REG_CTTC_EN_TIMER_SHIFT 3
80#define BQ24190_REG_CTTC_CHG_TIMER_MASK (BIT(2) | BIT(1))
81#define BQ24190_REG_CTTC_CHG_TIMER_SHIFT 1
82#define BQ24190_REG_CTTC_JEITA_ISET_MASK BIT(0)
83#define BQ24190_REG_CTTC_JEITA_ISET_SHIFT 0
84
85#define BQ24190_REG_ICTRC 0x06 /* IR Comp/Thermal Regulation Control */
86#define BQ24190_REG_ICTRC_BAT_COMP_MASK (BIT(7) | BIT(6) | BIT(5))
87#define BQ24190_REG_ICTRC_BAT_COMP_SHIFT 5
88#define BQ24190_REG_ICTRC_VCLAMP_MASK (BIT(4) | BIT(3) | BIT(2))
89#define BQ24190_REG_ICTRC_VCLAMP_SHIFT 2
90#define BQ24190_REG_ICTRC_TREG_MASK (BIT(1) | BIT(0))
91#define BQ24190_REG_ICTRC_TREG_SHIFT 0
92
93#define BQ24190_REG_MOC 0x07 /* Misc. Operation Control */
94#define BQ24190_REG_MOC_DPDM_EN_MASK BIT(7)
95#define BQ24190_REG_MOC_DPDM_EN_SHIFT 7
96#define BQ24190_REG_MOC_TMR2X_EN_MASK BIT(6)
97#define BQ24190_REG_MOC_TMR2X_EN_SHIFT 6
98#define BQ24190_REG_MOC_BATFET_DISABLE_MASK BIT(5)
99#define BQ24190_REG_MOC_BATFET_DISABLE_SHIFT 5
100#define BQ24190_REG_MOC_JEITA_VSET_MASK BIT(4)
101#define BQ24190_REG_MOC_JEITA_VSET_SHIFT 4
102#define BQ24190_REG_MOC_INT_MASK_MASK (BIT(1) | BIT(0))
103#define BQ24190_REG_MOC_INT_MASK_SHIFT 0
104
105#define BQ24190_REG_SS 0x08 /* System Status */
106#define BQ24190_REG_SS_VBUS_STAT_MASK (BIT(7) | BIT(6))
107#define BQ24190_REG_SS_VBUS_STAT_SHIFT 6
108#define BQ24190_REG_SS_CHRG_STAT_MASK (BIT(5) | BIT(4))
109#define BQ24190_REG_SS_CHRG_STAT_SHIFT 4
110#define BQ24190_REG_SS_DPM_STAT_MASK BIT(3)
111#define BQ24190_REG_SS_DPM_STAT_SHIFT 3
112#define BQ24190_REG_SS_PG_STAT_MASK BIT(2)
113#define BQ24190_REG_SS_PG_STAT_SHIFT 2
114#define BQ24190_REG_SS_THERM_STAT_MASK BIT(1)
115#define BQ24190_REG_SS_THERM_STAT_SHIFT 1
116#define BQ24190_REG_SS_VSYS_STAT_MASK BIT(0)
117#define BQ24190_REG_SS_VSYS_STAT_SHIFT 0
118
119#define BQ24190_REG_F 0x09 /* Fault */
120#define BQ24190_REG_F_WATCHDOG_FAULT_MASK BIT(7)
121#define BQ24190_REG_F_WATCHDOG_FAULT_SHIFT 7
122#define BQ24190_REG_F_BOOST_FAULT_MASK BIT(6)
123#define BQ24190_REG_F_BOOST_FAULT_SHIFT 6
124#define BQ24190_REG_F_CHRG_FAULT_MASK (BIT(5) | BIT(4))
125#define BQ24190_REG_F_CHRG_FAULT_SHIFT 4
126#define BQ24190_REG_F_BAT_FAULT_MASK BIT(3)
127#define BQ24190_REG_F_BAT_FAULT_SHIFT 3
128#define BQ24190_REG_F_NTC_FAULT_MASK (BIT(2) | BIT(1) | BIT(0))
129#define BQ24190_REG_F_NTC_FAULT_SHIFT 0
130
131#define BQ24190_REG_VPRS 0x0A /* Vendor/Part/Revision Status */
132#define BQ24190_REG_VPRS_PN_MASK (BIT(5) | BIT(4) | BIT(3))
133#define BQ24190_REG_VPRS_PN_SHIFT 3
134#define BQ24190_REG_VPRS_PN_24190 0x4
135#define BQ24190_REG_VPRS_PN_24192 0x5 /* Also 24193 */
136#define BQ24190_REG_VPRS_PN_24192I 0x3
137#define BQ24190_REG_VPRS_TS_PROFILE_MASK BIT(2)
138#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT 2
139#define BQ24190_REG_VPRS_DEV_REG_MASK (BIT(1) | BIT(0))
140#define BQ24190_REG_VPRS_DEV_REG_SHIFT 0
141
142/*
143 * The FAULT register is latched by the bq24190 (except for NTC_FAULT)
144 * so the first read after a fault returns the latched value and subsequent
145 * reads return the current value. In order to return the fault status
146 * to the user, have the interrupt handler save the reg's value and retrieve
Liam Breck7f2b4ad2017-01-18 09:26:53 -0800147 * it in the appropriate health/status routine.
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700148 */
149struct bq24190_dev_info {
150 struct i2c_client *client;
151 struct device *dev;
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100152 struct power_supply *charger;
153 struct power_supply *battery;
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700154 char model_name[I2C_NAME_SIZE];
155 kernel_ulong_t model;
156 unsigned int gpio_int;
157 unsigned int irq;
158 struct mutex f_reg_lock;
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700159 u8 f_reg;
160 u8 ss_reg;
161 u8 watchdog;
162};
163
164/*
165 * The tables below provide a 2-way mapping for the value that goes in
166 * the register field and the real-world value that it represents.
167 * The index of the array is the value that goes in the register; the
168 * number at that index in the array is the real-world value that it
169 * represents.
170 */
171/* REG02[7:2] (ICHG) in uAh */
172static const int bq24190_ccc_ichg_values[] = {
173 512000, 576000, 640000, 704000, 768000, 832000, 896000, 960000,
174 1024000, 1088000, 1152000, 1216000, 1280000, 1344000, 1408000, 1472000,
175 1536000, 1600000, 1664000, 1728000, 1792000, 1856000, 1920000, 1984000,
176 2048000, 2112000, 2176000, 2240000, 2304000, 2368000, 2432000, 2496000,
177 2560000, 2624000, 2688000, 2752000, 2816000, 2880000, 2944000, 3008000,
178 3072000, 3136000, 3200000, 3264000, 3328000, 3392000, 3456000, 3520000,
179 3584000, 3648000, 3712000, 3776000, 3840000, 3904000, 3968000, 4032000,
180 4096000, 4160000, 4224000, 4288000, 4352000, 4416000, 4480000, 4544000
181};
182
183/* REG04[7:2] (VREG) in uV */
184static const int bq24190_cvc_vreg_values[] = {
185 3504000, 3520000, 3536000, 3552000, 3568000, 3584000, 3600000, 3616000,
186 3632000, 3648000, 3664000, 3680000, 3696000, 3712000, 3728000, 3744000,
187 3760000, 3776000, 3792000, 3808000, 3824000, 3840000, 3856000, 3872000,
188 3888000, 3904000, 3920000, 3936000, 3952000, 3968000, 3984000, 4000000,
189 4016000, 4032000, 4048000, 4064000, 4080000, 4096000, 4112000, 4128000,
190 4144000, 4160000, 4176000, 4192000, 4208000, 4224000, 4240000, 4256000,
191 4272000, 4288000, 4304000, 4320000, 4336000, 4352000, 4368000, 4384000,
192 4400000
193};
194
195/* REG06[1:0] (TREG) in tenths of degrees Celcius */
196static const int bq24190_ictrc_treg_values[] = {
197 600, 800, 1000, 1200
198};
199
200/*
201 * Return the index in 'tbl' of greatest value that is less than or equal to
202 * 'val'. The index range returned is 0 to 'tbl_size' - 1. Assumes that
203 * the values in 'tbl' are sorted from smallest to largest and 'tbl_size'
204 * is less than 2^8.
205 */
206static u8 bq24190_find_idx(const int tbl[], int tbl_size, int v)
207{
208 int i;
209
210 for (i = 1; i < tbl_size; i++)
211 if (v < tbl[i])
212 break;
213
214 return i - 1;
215}
216
217/* Basic driver I/O routines */
218
219static int bq24190_read(struct bq24190_dev_info *bdi, u8 reg, u8 *data)
220{
221 int ret;
222
223 ret = i2c_smbus_read_byte_data(bdi->client, reg);
224 if (ret < 0)
225 return ret;
226
227 *data = ret;
228 return 0;
229}
230
231static int bq24190_write(struct bq24190_dev_info *bdi, u8 reg, u8 data)
232{
233 return i2c_smbus_write_byte_data(bdi->client, reg, data);
234}
235
236static int bq24190_read_mask(struct bq24190_dev_info *bdi, u8 reg,
237 u8 mask, u8 shift, u8 *data)
238{
239 u8 v;
240 int ret;
241
242 ret = bq24190_read(bdi, reg, &v);
243 if (ret < 0)
244 return ret;
245
246 v &= mask;
247 v >>= shift;
248 *data = v;
249
250 return 0;
251}
252
253static int bq24190_write_mask(struct bq24190_dev_info *bdi, u8 reg,
254 u8 mask, u8 shift, u8 data)
255{
256 u8 v;
257 int ret;
258
259 ret = bq24190_read(bdi, reg, &v);
260 if (ret < 0)
261 return ret;
262
263 v &= ~mask;
264 v |= ((data << shift) & mask);
265
266 return bq24190_write(bdi, reg, v);
267}
268
269static int bq24190_get_field_val(struct bq24190_dev_info *bdi,
270 u8 reg, u8 mask, u8 shift,
271 const int tbl[], int tbl_size,
272 int *val)
273{
274 u8 v;
275 int ret;
276
277 ret = bq24190_read_mask(bdi, reg, mask, shift, &v);
278 if (ret < 0)
279 return ret;
280
281 v = (v >= tbl_size) ? (tbl_size - 1) : v;
282 *val = tbl[v];
283
284 return 0;
285}
286
287static int bq24190_set_field_val(struct bq24190_dev_info *bdi,
288 u8 reg, u8 mask, u8 shift,
289 const int tbl[], int tbl_size,
290 int val)
291{
292 u8 idx;
293
294 idx = bq24190_find_idx(tbl, tbl_size, val);
295
296 return bq24190_write_mask(bdi, reg, mask, shift, idx);
297}
298
299#ifdef CONFIG_SYSFS
300/*
301 * There are a numerous options that are configurable on the bq24190
302 * that go well beyond what the power_supply properties provide access to.
303 * Provide sysfs access to them so they can be examined and possibly modified
304 * on the fly. They will be provided for the charger power_supply object only
305 * and will be prefixed by 'f_' to make them easier to recognize.
306 */
307
308#define BQ24190_SYSFS_FIELD(_name, r, f, m, store) \
309{ \
310 .attr = __ATTR(f_##_name, m, bq24190_sysfs_show, store), \
311 .reg = BQ24190_REG_##r, \
312 .mask = BQ24190_REG_##r##_##f##_MASK, \
313 .shift = BQ24190_REG_##r##_##f##_SHIFT, \
314}
315
316#define BQ24190_SYSFS_FIELD_RW(_name, r, f) \
317 BQ24190_SYSFS_FIELD(_name, r, f, S_IWUSR | S_IRUGO, \
318 bq24190_sysfs_store)
319
320#define BQ24190_SYSFS_FIELD_RO(_name, r, f) \
321 BQ24190_SYSFS_FIELD(_name, r, f, S_IRUGO, NULL)
322
323static ssize_t bq24190_sysfs_show(struct device *dev,
324 struct device_attribute *attr, char *buf);
325static ssize_t bq24190_sysfs_store(struct device *dev,
326 struct device_attribute *attr, const char *buf, size_t count);
327
328struct bq24190_sysfs_field_info {
329 struct device_attribute attr;
330 u8 reg;
331 u8 mask;
332 u8 shift;
333};
334
Anton Vorontsovd24fed32013-08-28 17:45:07 -0700335/* On i386 ptrace-abi.h defines SS that breaks the macro calls below. */
336#undef SS
337
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700338static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
339 /* sysfs name reg field in reg */
340 BQ24190_SYSFS_FIELD_RW(en_hiz, ISC, EN_HIZ),
341 BQ24190_SYSFS_FIELD_RW(vindpm, ISC, VINDPM),
342 BQ24190_SYSFS_FIELD_RW(iinlim, ISC, IINLIM),
343 BQ24190_SYSFS_FIELD_RW(chg_config, POC, CHG_CONFIG),
344 BQ24190_SYSFS_FIELD_RW(sys_min, POC, SYS_MIN),
345 BQ24190_SYSFS_FIELD_RW(boost_lim, POC, BOOST_LIM),
346 BQ24190_SYSFS_FIELD_RW(ichg, CCC, ICHG),
347 BQ24190_SYSFS_FIELD_RW(force_20_pct, CCC, FORCE_20PCT),
348 BQ24190_SYSFS_FIELD_RW(iprechg, PCTCC, IPRECHG),
349 BQ24190_SYSFS_FIELD_RW(iterm, PCTCC, ITERM),
350 BQ24190_SYSFS_FIELD_RW(vreg, CVC, VREG),
351 BQ24190_SYSFS_FIELD_RW(batlowv, CVC, BATLOWV),
352 BQ24190_SYSFS_FIELD_RW(vrechg, CVC, VRECHG),
353 BQ24190_SYSFS_FIELD_RW(en_term, CTTC, EN_TERM),
354 BQ24190_SYSFS_FIELD_RW(term_stat, CTTC, TERM_STAT),
355 BQ24190_SYSFS_FIELD_RO(watchdog, CTTC, WATCHDOG),
356 BQ24190_SYSFS_FIELD_RW(en_timer, CTTC, EN_TIMER),
357 BQ24190_SYSFS_FIELD_RW(chg_timer, CTTC, CHG_TIMER),
358 BQ24190_SYSFS_FIELD_RW(jeta_iset, CTTC, JEITA_ISET),
359 BQ24190_SYSFS_FIELD_RW(bat_comp, ICTRC, BAT_COMP),
360 BQ24190_SYSFS_FIELD_RW(vclamp, ICTRC, VCLAMP),
361 BQ24190_SYSFS_FIELD_RW(treg, ICTRC, TREG),
362 BQ24190_SYSFS_FIELD_RW(dpdm_en, MOC, DPDM_EN),
363 BQ24190_SYSFS_FIELD_RW(tmr2x_en, MOC, TMR2X_EN),
364 BQ24190_SYSFS_FIELD_RW(batfet_disable, MOC, BATFET_DISABLE),
365 BQ24190_SYSFS_FIELD_RW(jeita_vset, MOC, JEITA_VSET),
366 BQ24190_SYSFS_FIELD_RO(int_mask, MOC, INT_MASK),
367 BQ24190_SYSFS_FIELD_RO(vbus_stat, SS, VBUS_STAT),
368 BQ24190_SYSFS_FIELD_RO(chrg_stat, SS, CHRG_STAT),
369 BQ24190_SYSFS_FIELD_RO(dpm_stat, SS, DPM_STAT),
370 BQ24190_SYSFS_FIELD_RO(pg_stat, SS, PG_STAT),
371 BQ24190_SYSFS_FIELD_RO(therm_stat, SS, THERM_STAT),
372 BQ24190_SYSFS_FIELD_RO(vsys_stat, SS, VSYS_STAT),
373 BQ24190_SYSFS_FIELD_RO(watchdog_fault, F, WATCHDOG_FAULT),
374 BQ24190_SYSFS_FIELD_RO(boost_fault, F, BOOST_FAULT),
375 BQ24190_SYSFS_FIELD_RO(chrg_fault, F, CHRG_FAULT),
376 BQ24190_SYSFS_FIELD_RO(bat_fault, F, BAT_FAULT),
377 BQ24190_SYSFS_FIELD_RO(ntc_fault, F, NTC_FAULT),
378 BQ24190_SYSFS_FIELD_RO(pn, VPRS, PN),
379 BQ24190_SYSFS_FIELD_RO(ts_profile, VPRS, TS_PROFILE),
380 BQ24190_SYSFS_FIELD_RO(dev_reg, VPRS, DEV_REG),
381};
382
383static struct attribute *
384 bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
385
386static const struct attribute_group bq24190_sysfs_attr_group = {
387 .attrs = bq24190_sysfs_attrs,
388};
389
390static void bq24190_sysfs_init_attrs(void)
391{
392 int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
393
394 for (i = 0; i < limit; i++)
395 bq24190_sysfs_attrs[i] = &bq24190_sysfs_field_tbl[i].attr.attr;
396
397 bq24190_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
398}
399
400static struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup(
401 const char *name)
402{
403 int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
404
405 for (i = 0; i < limit; i++)
406 if (!strcmp(name, bq24190_sysfs_field_tbl[i].attr.attr.name))
407 break;
408
409 if (i >= limit)
410 return NULL;
411
412 return &bq24190_sysfs_field_tbl[i];
413}
414
415static ssize_t bq24190_sysfs_show(struct device *dev,
416 struct device_attribute *attr, char *buf)
417{
418 struct power_supply *psy = dev_get_drvdata(dev);
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100419 struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700420 struct bq24190_sysfs_field_info *info;
421 int ret;
422 u8 v;
423
424 info = bq24190_sysfs_field_lookup(attr->attr.name);
425 if (!info)
426 return -EINVAL;
427
428 ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
429 if (ret)
430 return ret;
431
432 return scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
433}
434
435static ssize_t bq24190_sysfs_store(struct device *dev,
436 struct device_attribute *attr, const char *buf, size_t count)
437{
438 struct power_supply *psy = dev_get_drvdata(dev);
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100439 struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700440 struct bq24190_sysfs_field_info *info;
441 int ret;
442 u8 v;
443
444 info = bq24190_sysfs_field_lookup(attr->attr.name);
445 if (!info)
446 return -EINVAL;
447
448 ret = kstrtou8(buf, 0, &v);
449 if (ret < 0)
450 return ret;
451
452 ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
453 if (ret)
454 return ret;
455
456 return count;
457}
458
459static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
460{
461 bq24190_sysfs_init_attrs();
462
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100463 return sysfs_create_group(&bdi->charger->dev.kobj,
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700464 &bq24190_sysfs_attr_group);
465}
466
467static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
468{
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100469 sysfs_remove_group(&bdi->charger->dev.kobj, &bq24190_sysfs_attr_group);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700470}
471#else
472static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
473{
474 return 0;
475}
476
477static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
478#endif
479
480/*
481 * According to the "Host Mode and default Mode" section of the
482 * manual, a write to any register causes the bq24190 to switch
483 * from default mode to host mode. It will switch back to default
484 * mode after a WDT timeout unless the WDT is turned off as well.
485 * So, by simply turning off the WDT, we accomplish both with the
486 * same write.
487 */
488static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
489{
490 int ret;
491 u8 v;
492
493 ret = bq24190_read(bdi, BQ24190_REG_CTTC, &v);
494 if (ret < 0)
495 return ret;
496
497 bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >>
498 BQ24190_REG_CTTC_WATCHDOG_SHIFT);
499 v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
500
501 return bq24190_write(bdi, BQ24190_REG_CTTC, v);
502}
503
504static int bq24190_register_reset(struct bq24190_dev_info *bdi)
505{
506 int ret, limit = 100;
507 u8 v;
508
509 /* Reset the registers */
510 ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
511 BQ24190_REG_POC_RESET_MASK,
512 BQ24190_REG_POC_RESET_SHIFT,
513 0x1);
514 if (ret < 0)
515 return ret;
516
517 /* Reset bit will be cleared by hardware so poll until it is */
518 do {
519 ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
520 BQ24190_REG_POC_RESET_MASK,
521 BQ24190_REG_POC_RESET_SHIFT,
522 &v);
523 if (ret < 0)
524 return ret;
525
526 if (!v)
527 break;
528
529 udelay(10);
530 } while (--limit);
531
532 if (!limit)
533 return -EIO;
534
535 return 0;
536}
537
538/* Charger power supply property routines */
539
540static int bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi,
541 union power_supply_propval *val)
542{
543 u8 v;
544 int type, ret;
545
546 ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
547 BQ24190_REG_POC_CHG_CONFIG_MASK,
548 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
549 &v);
550 if (ret < 0)
551 return ret;
552
553 /* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */
554 if (!v) {
555 type = POWER_SUPPLY_CHARGE_TYPE_NONE;
556 } else {
557 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
558 BQ24190_REG_CCC_FORCE_20PCT_MASK,
559 BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
560 &v);
561 if (ret < 0)
562 return ret;
563
564 type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE :
565 POWER_SUPPLY_CHARGE_TYPE_FAST;
566 }
567
568 val->intval = type;
569
570 return 0;
571}
572
573static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
574 const union power_supply_propval *val)
575{
576 u8 chg_config, force_20pct, en_term;
577 int ret;
578
579 /*
580 * According to the "Termination when REG02[0] = 1" section of
581 * the bq24190 manual, the trickle charge could be less than the
582 * termination current so it recommends turning off the termination
583 * function.
584 *
585 * Note: AFAICT from the datasheet, the user will have to manually
586 * turn off the charging when in 20% mode. If its not turned off,
587 * there could be battery damage. So, use this mode at your own risk.
588 */
589 switch (val->intval) {
590 case POWER_SUPPLY_CHARGE_TYPE_NONE:
591 chg_config = 0x0;
592 break;
593 case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
594 chg_config = 0x1;
595 force_20pct = 0x1;
596 en_term = 0x0;
597 break;
598 case POWER_SUPPLY_CHARGE_TYPE_FAST:
599 chg_config = 0x1;
600 force_20pct = 0x0;
601 en_term = 0x1;
602 break;
603 default:
604 return -EINVAL;
605 }
606
607 if (chg_config) { /* Enabling the charger */
608 ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
609 BQ24190_REG_CCC_FORCE_20PCT_MASK,
610 BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
611 force_20pct);
612 if (ret < 0)
613 return ret;
614
615 ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC,
616 BQ24190_REG_CTTC_EN_TERM_MASK,
617 BQ24190_REG_CTTC_EN_TERM_SHIFT,
618 en_term);
619 if (ret < 0)
620 return ret;
621 }
622
623 return bq24190_write_mask(bdi, BQ24190_REG_POC,
624 BQ24190_REG_POC_CHG_CONFIG_MASK,
625 BQ24190_REG_POC_CHG_CONFIG_SHIFT, chg_config);
626}
627
628static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
629 union power_supply_propval *val)
630{
631 u8 v;
Liam Breck7f2b4ad2017-01-18 09:26:53 -0800632 int health;
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700633
634 mutex_lock(&bdi->f_reg_lock);
Liam Breck7f2b4ad2017-01-18 09:26:53 -0800635 v = bdi->f_reg;
636 mutex_unlock(&bdi->f_reg_lock);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700637
638 if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
639 /*
640 * This could be over-current or over-voltage but there's
641 * no way to tell which. Return 'OVERVOLTAGE' since there
642 * isn't an 'OVERCURRENT' value defined that we can return
643 * even if it was over-current.
644 */
645 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
646 } else {
647 v &= BQ24190_REG_F_CHRG_FAULT_MASK;
648 v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
649
650 switch (v) {
651 case 0x0: /* Normal */
652 health = POWER_SUPPLY_HEALTH_GOOD;
653 break;
654 case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
655 /*
656 * This could be over-voltage or under-voltage
657 * and there's no way to tell which. Instead
658 * of looking foolish and returning 'OVERVOLTAGE'
659 * when its really under-voltage, just return
660 * 'UNSPEC_FAILURE'.
661 */
662 health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
663 break;
664 case 0x2: /* Thermal Shutdown */
665 health = POWER_SUPPLY_HEALTH_OVERHEAT;
666 break;
667 case 0x3: /* Charge Safety Timer Expiration */
668 health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
669 break;
670 default:
671 health = POWER_SUPPLY_HEALTH_UNKNOWN;
672 }
673 }
674
675 val->intval = health;
676
677 return 0;
678}
679
680static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
681 union power_supply_propval *val)
682{
683 u8 v;
684 int ret;
685
686 ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
687 BQ24190_REG_SS_PG_STAT_MASK,
688 BQ24190_REG_SS_PG_STAT_SHIFT, &v);
689 if (ret < 0)
690 return ret;
691
692 val->intval = v;
693 return 0;
694}
695
696static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
697 union power_supply_propval *val)
698{
699 u8 v;
700 int curr, ret;
701
702 ret = bq24190_get_field_val(bdi, BQ24190_REG_CCC,
703 BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
704 bq24190_ccc_ichg_values,
705 ARRAY_SIZE(bq24190_ccc_ichg_values), &curr);
706 if (ret < 0)
707 return ret;
708
709 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
710 BQ24190_REG_CCC_FORCE_20PCT_MASK,
711 BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
712 if (ret < 0)
713 return ret;
714
715 /* If FORCE_20PCT is enabled, then current is 20% of ICHG value */
716 if (v)
717 curr /= 5;
718
719 val->intval = curr;
720 return 0;
721}
722
723static int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi,
724 union power_supply_propval *val)
725{
726 int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
727
728 val->intval = bq24190_ccc_ichg_values[idx];
729 return 0;
730}
731
732static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
733 const union power_supply_propval *val)
734{
735 u8 v;
736 int ret, curr = val->intval;
737
738 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
739 BQ24190_REG_CCC_FORCE_20PCT_MASK,
740 BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
741 if (ret < 0)
742 return ret;
743
744 /* If FORCE_20PCT is enabled, have to multiply value passed in by 5 */
745 if (v)
746 curr *= 5;
747
748 return bq24190_set_field_val(bdi, BQ24190_REG_CCC,
749 BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
750 bq24190_ccc_ichg_values,
751 ARRAY_SIZE(bq24190_ccc_ichg_values), curr);
752}
753
754static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
755 union power_supply_propval *val)
756{
757 int voltage, ret;
758
759 ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC,
760 BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
761 bq24190_cvc_vreg_values,
762 ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage);
763 if (ret < 0)
764 return ret;
765
766 val->intval = voltage;
767 return 0;
768}
769
770static int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi,
771 union power_supply_propval *val)
772{
773 int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
774
775 val->intval = bq24190_cvc_vreg_values[idx];
776 return 0;
777}
778
779static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
780 const union power_supply_propval *val)
781{
782 return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
783 BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
784 bq24190_cvc_vreg_values,
785 ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
786}
787
788static int bq24190_charger_get_property(struct power_supply *psy,
789 enum power_supply_property psp, union power_supply_propval *val)
790{
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100791 struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700792 int ret;
793
794 dev_dbg(bdi->dev, "prop: %d\n", psp);
795
796 pm_runtime_get_sync(bdi->dev);
797
798 switch (psp) {
799 case POWER_SUPPLY_PROP_CHARGE_TYPE:
800 ret = bq24190_charger_get_charge_type(bdi, val);
801 break;
802 case POWER_SUPPLY_PROP_HEALTH:
803 ret = bq24190_charger_get_health(bdi, val);
804 break;
805 case POWER_SUPPLY_PROP_ONLINE:
806 ret = bq24190_charger_get_online(bdi, val);
807 break;
808 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
809 ret = bq24190_charger_get_current(bdi, val);
810 break;
811 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
812 ret = bq24190_charger_get_current_max(bdi, val);
813 break;
814 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
815 ret = bq24190_charger_get_voltage(bdi, val);
816 break;
817 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
818 ret = bq24190_charger_get_voltage_max(bdi, val);
819 break;
820 case POWER_SUPPLY_PROP_SCOPE:
821 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
822 ret = 0;
823 break;
824 case POWER_SUPPLY_PROP_MODEL_NAME:
825 val->strval = bdi->model_name;
826 ret = 0;
827 break;
828 case POWER_SUPPLY_PROP_MANUFACTURER:
829 val->strval = BQ24190_MANUFACTURER;
830 ret = 0;
831 break;
832 default:
833 ret = -ENODATA;
834 }
835
836 pm_runtime_put_sync(bdi->dev);
837 return ret;
838}
839
840static int bq24190_charger_set_property(struct power_supply *psy,
841 enum power_supply_property psp,
842 const union power_supply_propval *val)
843{
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100844 struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700845 int ret;
846
847 dev_dbg(bdi->dev, "prop: %d\n", psp);
848
849 pm_runtime_get_sync(bdi->dev);
850
851 switch (psp) {
852 case POWER_SUPPLY_PROP_CHARGE_TYPE:
853 ret = bq24190_charger_set_charge_type(bdi, val);
854 break;
855 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
856 ret = bq24190_charger_set_current(bdi, val);
857 break;
858 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
859 ret = bq24190_charger_set_voltage(bdi, val);
860 break;
861 default:
862 ret = -EINVAL;
863 }
864
865 pm_runtime_put_sync(bdi->dev);
866 return ret;
867}
868
869static int bq24190_charger_property_is_writeable(struct power_supply *psy,
870 enum power_supply_property psp)
871{
872 int ret;
873
874 switch (psp) {
875 case POWER_SUPPLY_PROP_CHARGE_TYPE:
876 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
877 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
878 ret = 1;
879 break;
880 default:
881 ret = 0;
882 }
883
884 return ret;
885}
886
887static enum power_supply_property bq24190_charger_properties[] = {
Andreas Dannenbergc9f85a92015-08-04 11:36:17 -0500888 POWER_SUPPLY_PROP_CHARGE_TYPE,
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700889 POWER_SUPPLY_PROP_HEALTH,
890 POWER_SUPPLY_PROP_ONLINE,
891 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
892 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
893 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
894 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
895 POWER_SUPPLY_PROP_SCOPE,
896 POWER_SUPPLY_PROP_MODEL_NAME,
897 POWER_SUPPLY_PROP_MANUFACTURER,
898};
899
900static char *bq24190_charger_supplied_to[] = {
901 "main-battery",
902};
903
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +0100904static const struct power_supply_desc bq24190_charger_desc = {
905 .name = "bq24190-charger",
906 .type = POWER_SUPPLY_TYPE_USB,
907 .properties = bq24190_charger_properties,
908 .num_properties = ARRAY_SIZE(bq24190_charger_properties),
909 .get_property = bq24190_charger_get_property,
910 .set_property = bq24190_charger_set_property,
911 .property_is_writeable = bq24190_charger_property_is_writeable,
912};
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700913
914/* Battery power supply property routines */
915
916static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
917 union power_supply_propval *val)
918{
919 u8 ss_reg, chrg_fault;
920 int status, ret;
921
922 mutex_lock(&bdi->f_reg_lock);
Liam Breck7f2b4ad2017-01-18 09:26:53 -0800923 chrg_fault = bdi->f_reg;
924 mutex_unlock(&bdi->f_reg_lock);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700925
926 chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
927 chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
928
929 ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
930 if (ret < 0)
931 return ret;
932
933 /*
934 * The battery must be discharging when any of these are true:
935 * - there is no good power source;
936 * - there is a charge fault.
937 * Could also be discharging when in "supplement mode" but
938 * there is no way to tell when its in that mode.
939 */
940 if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) {
941 status = POWER_SUPPLY_STATUS_DISCHARGING;
942 } else {
943 ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK;
944 ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT;
945
946 switch (ss_reg) {
947 case 0x0: /* Not Charging */
948 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
949 break;
950 case 0x1: /* Pre-charge */
951 case 0x2: /* Fast Charging */
952 status = POWER_SUPPLY_STATUS_CHARGING;
953 break;
954 case 0x3: /* Charge Termination Done */
955 status = POWER_SUPPLY_STATUS_FULL;
956 break;
957 default:
958 ret = -EIO;
959 }
960 }
961
962 if (!ret)
963 val->intval = status;
964
965 return ret;
966}
967
968static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
969 union power_supply_propval *val)
970{
971 u8 v;
Liam Breck7f2b4ad2017-01-18 09:26:53 -0800972 int health;
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700973
974 mutex_lock(&bdi->f_reg_lock);
Liam Breck7f2b4ad2017-01-18 09:26:53 -0800975 v = bdi->f_reg;
976 mutex_unlock(&bdi->f_reg_lock);
Mark A. Greerd7bf3532013-08-23 19:21:03 -0700977
978 if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
979 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
980 } else {
981 v &= BQ24190_REG_F_NTC_FAULT_MASK;
982 v >>= BQ24190_REG_F_NTC_FAULT_SHIFT;
983
984 switch (v) {
985 case 0x0: /* Normal */
986 health = POWER_SUPPLY_HEALTH_GOOD;
987 break;
988 case 0x1: /* TS1 Cold */
989 case 0x3: /* TS2 Cold */
990 case 0x5: /* Both Cold */
991 health = POWER_SUPPLY_HEALTH_COLD;
992 break;
993 case 0x2: /* TS1 Hot */
994 case 0x4: /* TS2 Hot */
995 case 0x6: /* Both Hot */
996 health = POWER_SUPPLY_HEALTH_OVERHEAT;
997 break;
998 default:
999 health = POWER_SUPPLY_HEALTH_UNKNOWN;
1000 }
1001 }
1002
1003 val->intval = health;
1004 return 0;
1005}
1006
1007static int bq24190_battery_get_online(struct bq24190_dev_info *bdi,
1008 union power_supply_propval *val)
1009{
1010 u8 batfet_disable;
1011 int ret;
1012
1013 ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
1014 BQ24190_REG_MOC_BATFET_DISABLE_MASK,
1015 BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
1016 if (ret < 0)
1017 return ret;
1018
1019 val->intval = !batfet_disable;
1020 return 0;
1021}
1022
1023static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
1024 const union power_supply_propval *val)
1025{
1026 return bq24190_write_mask(bdi, BQ24190_REG_MOC,
1027 BQ24190_REG_MOC_BATFET_DISABLE_MASK,
1028 BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, !val->intval);
1029}
1030
1031static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
1032 union power_supply_propval *val)
1033{
1034 int temp, ret;
1035
1036 ret = bq24190_get_field_val(bdi, BQ24190_REG_ICTRC,
1037 BQ24190_REG_ICTRC_TREG_MASK,
1038 BQ24190_REG_ICTRC_TREG_SHIFT,
1039 bq24190_ictrc_treg_values,
1040 ARRAY_SIZE(bq24190_ictrc_treg_values), &temp);
1041 if (ret < 0)
1042 return ret;
1043
1044 val->intval = temp;
1045 return 0;
1046}
1047
1048static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
1049 const union power_supply_propval *val)
1050{
1051 return bq24190_set_field_val(bdi, BQ24190_REG_ICTRC,
1052 BQ24190_REG_ICTRC_TREG_MASK,
1053 BQ24190_REG_ICTRC_TREG_SHIFT,
1054 bq24190_ictrc_treg_values,
1055 ARRAY_SIZE(bq24190_ictrc_treg_values), val->intval);
1056}
1057
1058static int bq24190_battery_get_property(struct power_supply *psy,
1059 enum power_supply_property psp, union power_supply_propval *val)
1060{
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001061 struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001062 int ret;
1063
1064 dev_dbg(bdi->dev, "prop: %d\n", psp);
1065
1066 pm_runtime_get_sync(bdi->dev);
1067
1068 switch (psp) {
1069 case POWER_SUPPLY_PROP_STATUS:
1070 ret = bq24190_battery_get_status(bdi, val);
1071 break;
1072 case POWER_SUPPLY_PROP_HEALTH:
1073 ret = bq24190_battery_get_health(bdi, val);
1074 break;
1075 case POWER_SUPPLY_PROP_ONLINE:
1076 ret = bq24190_battery_get_online(bdi, val);
1077 break;
1078 case POWER_SUPPLY_PROP_TECHNOLOGY:
1079 /* Could be Li-on or Li-polymer but no way to tell which */
1080 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
1081 ret = 0;
1082 break;
1083 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1084 ret = bq24190_battery_get_temp_alert_max(bdi, val);
1085 break;
1086 case POWER_SUPPLY_PROP_SCOPE:
1087 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1088 ret = 0;
1089 break;
1090 default:
1091 ret = -ENODATA;
1092 }
1093
1094 pm_runtime_put_sync(bdi->dev);
1095 return ret;
1096}
1097
1098static int bq24190_battery_set_property(struct power_supply *psy,
1099 enum power_supply_property psp,
1100 const union power_supply_propval *val)
1101{
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001102 struct bq24190_dev_info *bdi = power_supply_get_drvdata(psy);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001103 int ret;
1104
1105 dev_dbg(bdi->dev, "prop: %d\n", psp);
1106
Tony Lindgrendf386a02016-11-14 19:38:31 -08001107 pm_runtime_get_sync(bdi->dev);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001108
1109 switch (psp) {
1110 case POWER_SUPPLY_PROP_ONLINE:
1111 ret = bq24190_battery_set_online(bdi, val);
1112 break;
1113 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1114 ret = bq24190_battery_set_temp_alert_max(bdi, val);
1115 break;
1116 default:
1117 ret = -EINVAL;
1118 }
1119
1120 pm_runtime_put_sync(bdi->dev);
1121 return ret;
1122}
1123
1124static int bq24190_battery_property_is_writeable(struct power_supply *psy,
1125 enum power_supply_property psp)
1126{
1127 int ret;
1128
1129 switch (psp) {
1130 case POWER_SUPPLY_PROP_ONLINE:
1131 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1132 ret = 1;
1133 break;
1134 default:
1135 ret = 0;
1136 }
1137
1138 return ret;
1139}
1140
1141static enum power_supply_property bq24190_battery_properties[] = {
1142 POWER_SUPPLY_PROP_STATUS,
1143 POWER_SUPPLY_PROP_HEALTH,
1144 POWER_SUPPLY_PROP_ONLINE,
1145 POWER_SUPPLY_PROP_TECHNOLOGY,
1146 POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
1147 POWER_SUPPLY_PROP_SCOPE,
1148};
1149
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001150static const struct power_supply_desc bq24190_battery_desc = {
1151 .name = "bq24190-battery",
1152 .type = POWER_SUPPLY_TYPE_BATTERY,
1153 .properties = bq24190_battery_properties,
1154 .num_properties = ARRAY_SIZE(bq24190_battery_properties),
1155 .get_property = bq24190_battery_get_property,
1156 .set_property = bq24190_battery_set_property,
1157 .property_is_writeable = bq24190_battery_property_is_writeable,
1158};
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001159
1160static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
1161{
1162 struct bq24190_dev_info *bdi = data;
Liam Breck4b7dac02017-01-18 09:26:52 -08001163 const u8 battery_mask_ss = BQ24190_REG_SS_CHRG_STAT_MASK;
1164 const u8 battery_mask_f = BQ24190_REG_F_BAT_FAULT_MASK
1165 | BQ24190_REG_F_NTC_FAULT_MASK;
1166 bool alert_charger = false, alert_battery = false;
Lad, Prabhakar31f50e42014-12-04 14:56:04 +00001167 u8 ss_reg = 0, f_reg = 0;
Liam Breck7f2b4ad2017-01-18 09:26:53 -08001168 int i, ret;
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001169
1170 pm_runtime_get_sync(bdi->dev);
1171
1172 ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
1173 if (ret < 0) {
1174 dev_err(bdi->dev, "Can't read SS reg: %d\n", ret);
1175 goto out;
1176 }
1177
Liam Breck7f2b4ad2017-01-18 09:26:53 -08001178 i = 0;
1179 do {
1180 ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
1181 if (ret < 0) {
1182 dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
1183 goto out;
1184 }
1185 } while (f_reg && ++i < 2);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001186
1187 if (f_reg != bdi->f_reg) {
Liam Breck7f2b4ad2017-01-18 09:26:53 -08001188 dev_info(bdi->dev,
1189 "Fault: boost %d, charge %d, battery %d, ntc %d\n",
1190 !!(f_reg & BQ24190_REG_F_BOOST_FAULT_MASK),
1191 !!(f_reg & BQ24190_REG_F_CHRG_FAULT_MASK),
1192 !!(f_reg & BQ24190_REG_F_BAT_FAULT_MASK),
1193 !!(f_reg & BQ24190_REG_F_NTC_FAULT_MASK));
1194
1195 mutex_lock(&bdi->f_reg_lock);
Liam Breck4b7dac02017-01-18 09:26:52 -08001196 if ((bdi->f_reg & battery_mask_f) != (f_reg & battery_mask_f))
1197 alert_battery = true;
1198 if ((bdi->f_reg & ~battery_mask_f) != (f_reg & ~battery_mask_f))
1199 alert_charger = true;
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001200 bdi->f_reg = f_reg;
Liam Breck7f2b4ad2017-01-18 09:26:53 -08001201 mutex_unlock(&bdi->f_reg_lock);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001202 }
1203
Liam Brecke7b34f42017-01-18 09:26:54 -08001204 if (ss_reg != bdi->ss_reg) {
1205 /*
1206 * The device is in host mode so when PG_STAT goes from 1->0
1207 * (i.e., power removed) HIZ needs to be disabled.
1208 */
1209 if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) &&
1210 !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) {
1211 ret = bq24190_write_mask(bdi, BQ24190_REG_ISC,
1212 BQ24190_REG_ISC_EN_HIZ_MASK,
1213 BQ24190_REG_ISC_EN_HIZ_SHIFT,
1214 0);
1215 if (ret < 0)
1216 dev_err(bdi->dev, "Can't access ISC reg: %d\n",
1217 ret);
1218 }
1219
1220 if ((bdi->ss_reg & battery_mask_ss) != (ss_reg & battery_mask_ss))
1221 alert_battery = true;
1222 if ((bdi->ss_reg & ~battery_mask_ss) != (ss_reg & ~battery_mask_ss))
1223 alert_charger = true;
1224 bdi->ss_reg = ss_reg;
1225 }
1226
Liam Breck4b7dac02017-01-18 09:26:52 -08001227 if (alert_charger)
1228 power_supply_changed(bdi->charger);
1229 if (alert_battery)
1230 power_supply_changed(bdi->battery);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001231
1232out:
1233 pm_runtime_put_sync(bdi->dev);
1234
1235 dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
1236
1237 return IRQ_HANDLED;
1238}
1239
1240static int bq24190_hw_init(struct bq24190_dev_info *bdi)
1241{
1242 u8 v;
1243 int ret;
1244
1245 pm_runtime_get_sync(bdi->dev);
1246
1247 /* First check that the device really is what its supposed to be */
1248 ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS,
1249 BQ24190_REG_VPRS_PN_MASK,
1250 BQ24190_REG_VPRS_PN_SHIFT,
1251 &v);
1252 if (ret < 0)
1253 goto out;
1254
1255 if (v != bdi->model) {
1256 ret = -ENODEV;
1257 goto out;
1258 }
1259
1260 ret = bq24190_register_reset(bdi);
1261 if (ret < 0)
1262 goto out;
1263
1264 ret = bq24190_set_mode_host(bdi);
Liam Breck4b7dac02017-01-18 09:26:52 -08001265 if (ret < 0)
1266 goto out;
1267
1268 ret = bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001269out:
1270 pm_runtime_put_sync(bdi->dev);
1271 return ret;
1272}
1273
1274#ifdef CONFIG_OF
1275static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
1276{
1277 bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
1278 if (bdi->irq <= 0)
1279 return -1;
1280
1281 return 0;
1282}
1283#else
1284static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
1285{
1286 return -1;
1287}
1288#endif
1289
1290static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
1291 struct bq24190_platform_data *pdata)
1292{
1293 int ret;
1294
1295 if (!gpio_is_valid(pdata->gpio_int))
1296 return -1;
1297
1298 ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
1299 if (ret < 0)
1300 return -1;
1301
1302 ret = gpio_direction_input(pdata->gpio_int);
1303 if (ret < 0)
1304 goto out;
1305
1306 bdi->irq = gpio_to_irq(pdata->gpio_int);
1307 if (!bdi->irq)
1308 goto out;
1309
1310 bdi->gpio_int = pdata->gpio_int;
1311 return 0;
1312
1313out:
1314 gpio_free(pdata->gpio_int);
1315 return -1;
1316}
1317
1318static int bq24190_probe(struct i2c_client *client,
1319 const struct i2c_device_id *id)
1320{
1321 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1322 struct device *dev = &client->dev;
1323 struct bq24190_platform_data *pdata = client->dev.platform_data;
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001324 struct power_supply_config charger_cfg = {}, battery_cfg = {};
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001325 struct bq24190_dev_info *bdi;
1326 int ret;
1327
1328 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1329 dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
1330 return -ENODEV;
1331 }
1332
1333 bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
1334 if (!bdi) {
1335 dev_err(dev, "Can't alloc bdi struct\n");
1336 return -ENOMEM;
1337 }
1338
1339 bdi->client = client;
1340 bdi->dev = dev;
1341 bdi->model = id->driver_data;
1342 strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
1343 mutex_init(&bdi->f_reg_lock);
Liam Breck4b7dac02017-01-18 09:26:52 -08001344 bdi->f_reg = 0;
1345 bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001346
1347 i2c_set_clientdata(client, bdi);
1348
1349 if (dev->of_node)
1350 ret = bq24190_setup_dt(bdi);
1351 else
1352 ret = bq24190_setup_pdata(bdi, pdata);
1353
1354 if (ret) {
1355 dev_err(dev, "Can't get irq info\n");
1356 return -EINVAL;
1357 }
1358
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001359 pm_runtime_enable(dev);
1360 pm_runtime_resume(dev);
1361
1362 ret = bq24190_hw_init(bdi);
1363 if (ret < 0) {
1364 dev_err(dev, "Hardware init failed\n");
Liam Breck63e1acc2017-01-18 09:26:50 -08001365 goto out1;
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001366 }
1367
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001368 charger_cfg.drv_data = bdi;
1369 charger_cfg.supplied_to = bq24190_charger_supplied_to;
1370 charger_cfg.num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to),
1371 bdi->charger = power_supply_register(dev, &bq24190_charger_desc,
1372 &charger_cfg);
1373 if (IS_ERR(bdi->charger)) {
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001374 dev_err(dev, "Can't register charger\n");
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001375 ret = PTR_ERR(bdi->charger);
Liam Breck63e1acc2017-01-18 09:26:50 -08001376 goto out1;
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001377 }
1378
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001379 battery_cfg.drv_data = bdi;
1380 bdi->battery = power_supply_register(dev, &bq24190_battery_desc,
1381 &battery_cfg);
1382 if (IS_ERR(bdi->battery)) {
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001383 dev_err(dev, "Can't register battery\n");
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001384 ret = PTR_ERR(bdi->battery);
Liam Breck63e1acc2017-01-18 09:26:50 -08001385 goto out2;
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001386 }
1387
1388 ret = bq24190_sysfs_create_group(bdi);
1389 if (ret) {
1390 dev_err(dev, "Can't create sysfs entries\n");
Liam Breck63e1acc2017-01-18 09:26:50 -08001391 goto out3;
1392 }
1393
1394 ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
1395 bq24190_irq_handler_thread,
1396 IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
1397 "bq24190-charger", bdi);
1398 if (ret < 0) {
1399 dev_err(dev, "Can't set up irq handler\n");
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001400 goto out4;
1401 }
1402
1403 return 0;
1404
1405out4:
Liam Breck63e1acc2017-01-18 09:26:50 -08001406 bq24190_sysfs_remove_group(bdi);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001407out3:
Liam Breck63e1acc2017-01-18 09:26:50 -08001408 power_supply_unregister(bdi->battery);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001409out2:
Liam Breck63e1acc2017-01-18 09:26:50 -08001410 power_supply_unregister(bdi->charger);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001411out1:
Liam Breck63e1acc2017-01-18 09:26:50 -08001412 pm_runtime_disable(dev);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001413 if (bdi->gpio_int)
1414 gpio_free(bdi->gpio_int);
1415
1416 return ret;
1417}
1418
1419static int bq24190_remove(struct i2c_client *client)
1420{
1421 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1422
1423 pm_runtime_get_sync(bdi->dev);
1424 bq24190_register_reset(bdi);
1425 pm_runtime_put_sync(bdi->dev);
1426
1427 bq24190_sysfs_remove_group(bdi);
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001428 power_supply_unregister(bdi->battery);
1429 power_supply_unregister(bdi->charger);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001430 pm_runtime_disable(bdi->dev);
1431
1432 if (bdi->gpio_int)
1433 gpio_free(bdi->gpio_int);
1434
1435 return 0;
1436}
1437
1438#ifdef CONFIG_PM_SLEEP
1439static int bq24190_pm_suspend(struct device *dev)
1440{
1441 struct i2c_client *client = to_i2c_client(dev);
1442 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1443
1444 pm_runtime_get_sync(bdi->dev);
1445 bq24190_register_reset(bdi);
1446 pm_runtime_put_sync(bdi->dev);
1447
1448 return 0;
1449}
1450
1451static int bq24190_pm_resume(struct device *dev)
1452{
1453 struct i2c_client *client = to_i2c_client(dev);
1454 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1455
Liam Breck4b7dac02017-01-18 09:26:52 -08001456 bdi->f_reg = 0;
1457 bdi->ss_reg = BQ24190_REG_SS_VBUS_STAT_MASK; /* impossible state */
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001458
1459 pm_runtime_get_sync(bdi->dev);
1460 bq24190_register_reset(bdi);
Liam Breck20e448f2017-01-18 09:26:49 -08001461 bq24190_set_mode_host(bdi);
Liam Breck4b7dac02017-01-18 09:26:52 -08001462 bq24190_read(bdi, BQ24190_REG_SS, &bdi->ss_reg);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001463 pm_runtime_put_sync(bdi->dev);
1464
1465 /* Things may have changed while suspended so alert upper layer */
Krzysztof Kozlowski297d7162015-03-12 08:44:11 +01001466 power_supply_changed(bdi->charger);
1467 power_supply_changed(bdi->battery);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001468
1469 return 0;
1470}
1471#endif
1472
1473static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume);
1474
1475/*
1476 * Only support the bq24190 right now. The bq24192, bq24192i, and bq24193
1477 * are similar but not identical so the driver needs to be extended to
1478 * support them.
1479 */
1480static const struct i2c_device_id bq24190_i2c_ids[] = {
1481 { "bq24190", BQ24190_REG_VPRS_PN_24190 },
1482 { },
1483};
Javier Martinez Canillas63369b22015-07-30 18:18:33 +02001484MODULE_DEVICE_TABLE(i2c, bq24190_i2c_ids);
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001485
1486#ifdef CONFIG_OF
1487static const struct of_device_id bq24190_of_match[] = {
1488 { .compatible = "ti,bq24190", },
1489 { },
1490};
1491MODULE_DEVICE_TABLE(of, bq24190_of_match);
1492#else
1493static const struct of_device_id bq24190_of_match[] = {
1494 { },
1495};
1496#endif
1497
1498static struct i2c_driver bq24190_driver = {
1499 .probe = bq24190_probe,
1500 .remove = bq24190_remove,
1501 .id_table = bq24190_i2c_ids,
1502 .driver = {
1503 .name = "bq24190-charger",
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001504 .pm = &bq24190_pm_ops,
1505 .of_match_table = of_match_ptr(bq24190_of_match),
1506 },
1507};
1508module_i2c_driver(bq24190_driver);
1509
1510MODULE_LICENSE("GPL");
1511MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
Mark A. Greerd7bf3532013-08-23 19:21:03 -07001512MODULE_DESCRIPTION("TI BQ24190 Charger Driver");