aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/power/bq24190_charger.c
diff options
context:
space:
mode:
authorMark A. Greer <mgreer@animalcreek.com>2013-08-23 22:21:03 -0400
committerAnton Vorontsov <anton@enomsg.org>2013-08-27 21:17:54 -0400
commitd7bf353fd0aa3e12060ce64c8a7b4aaf4336145c (patch)
tree2c2464a7b173e3f8b387cd618b3f235dc31c8e77 /drivers/power/bq24190_charger.c
parented5243f8ab2470e988dce0e416eaaddb4d7d2ccc (diff)
bq24190_charger: Add support for TI BQ24190 Battery Charger
Add driver support for the Texas Instruments BQ24190 battery charger. Some of the information provided by the device is about the charger and other information is about the battery so create two power_supply objects (one for each) and provide the appropriate information for each one. The device has many fields that go beyond what is reasonable to report or modify using the existing 'POWER_SUPPLY_PROP_*' properties so the driver exports the register fields via sysfs. They are prefixed by 'f_' (for 'field') to make it easier to distinguish between a register field and a "normal" sysfs file exported by the power_supply infrastructure. Signed-off-by: Mark A. Greer <mgreer@animalcreek.com> Signed-off-by: Anton Vorontsov <anton@enomsg.org>
Diffstat (limited to 'drivers/power/bq24190_charger.c')
-rw-r--r--drivers/power/bq24190_charger.c1546
1 files changed, 1546 insertions, 0 deletions
diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c
new file mode 100644
index 000000000000..2b0f0e0b58a2
--- /dev/null
+++ b/drivers/power/bq24190_charger.c
@@ -0,0 +1,1546 @@
1/*
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
147 * it in the appropriate health/status routine. Each routine has its own
148 * flag indicating whether it should use the value stored by the last run
149 * of the interrupt handler or do an actual reg read. That way each routine
150 * can report back whatever fault may have occured.
151 */
152struct bq24190_dev_info {
153 struct i2c_client *client;
154 struct device *dev;
155 struct power_supply charger;
156 struct power_supply battery;
157 char model_name[I2C_NAME_SIZE];
158 kernel_ulong_t model;
159 unsigned int gpio_int;
160 unsigned int irq;
161 struct mutex f_reg_lock;
162 bool first_time;
163 bool charger_health_valid;
164 bool battery_health_valid;
165 bool battery_status_valid;
166 u8 f_reg;
167 u8 ss_reg;
168 u8 watchdog;
169};
170
171/*
172 * The tables below provide a 2-way mapping for the value that goes in
173 * the register field and the real-world value that it represents.
174 * The index of the array is the value that goes in the register; the
175 * number at that index in the array is the real-world value that it
176 * represents.
177 */
178/* REG02[7:2] (ICHG) in uAh */
179static const int bq24190_ccc_ichg_values[] = {
180 512000, 576000, 640000, 704000, 768000, 832000, 896000, 960000,
181 1024000, 1088000, 1152000, 1216000, 1280000, 1344000, 1408000, 1472000,
182 1536000, 1600000, 1664000, 1728000, 1792000, 1856000, 1920000, 1984000,
183 2048000, 2112000, 2176000, 2240000, 2304000, 2368000, 2432000, 2496000,
184 2560000, 2624000, 2688000, 2752000, 2816000, 2880000, 2944000, 3008000,
185 3072000, 3136000, 3200000, 3264000, 3328000, 3392000, 3456000, 3520000,
186 3584000, 3648000, 3712000, 3776000, 3840000, 3904000, 3968000, 4032000,
187 4096000, 4160000, 4224000, 4288000, 4352000, 4416000, 4480000, 4544000
188};
189
190/* REG04[7:2] (VREG) in uV */
191static const int bq24190_cvc_vreg_values[] = {
192 3504000, 3520000, 3536000, 3552000, 3568000, 3584000, 3600000, 3616000,
193 3632000, 3648000, 3664000, 3680000, 3696000, 3712000, 3728000, 3744000,
194 3760000, 3776000, 3792000, 3808000, 3824000, 3840000, 3856000, 3872000,
195 3888000, 3904000, 3920000, 3936000, 3952000, 3968000, 3984000, 4000000,
196 4016000, 4032000, 4048000, 4064000, 4080000, 4096000, 4112000, 4128000,
197 4144000, 4160000, 4176000, 4192000, 4208000, 4224000, 4240000, 4256000,
198 4272000, 4288000, 4304000, 4320000, 4336000, 4352000, 4368000, 4384000,
199 4400000
200};
201
202/* REG06[1:0] (TREG) in tenths of degrees Celcius */
203static const int bq24190_ictrc_treg_values[] = {
204 600, 800, 1000, 1200
205};
206
207/*
208 * Return the index in 'tbl' of greatest value that is less than or equal to
209 * 'val'. The index range returned is 0 to 'tbl_size' - 1. Assumes that
210 * the values in 'tbl' are sorted from smallest to largest and 'tbl_size'
211 * is less than 2^8.
212 */
213static u8 bq24190_find_idx(const int tbl[], int tbl_size, int v)
214{
215 int i;
216
217 for (i = 1; i < tbl_size; i++)
218 if (v < tbl[i])
219 break;
220
221 return i - 1;
222}
223
224/* Basic driver I/O routines */
225
226static int bq24190_read(struct bq24190_dev_info *bdi, u8 reg, u8 *data)
227{
228 int ret;
229
230 ret = i2c_smbus_read_byte_data(bdi->client, reg);
231 if (ret < 0)
232 return ret;
233
234 *data = ret;
235 return 0;
236}
237
238static int bq24190_write(struct bq24190_dev_info *bdi, u8 reg, u8 data)
239{
240 return i2c_smbus_write_byte_data(bdi->client, reg, data);
241}
242
243static int bq24190_read_mask(struct bq24190_dev_info *bdi, u8 reg,
244 u8 mask, u8 shift, u8 *data)
245{
246 u8 v;
247 int ret;
248
249 ret = bq24190_read(bdi, reg, &v);
250 if (ret < 0)
251 return ret;
252
253 v &= mask;
254 v >>= shift;
255 *data = v;
256
257 return 0;
258}
259
260static int bq24190_write_mask(struct bq24190_dev_info *bdi, u8 reg,
261 u8 mask, u8 shift, u8 data)
262{
263 u8 v;
264 int ret;
265
266 ret = bq24190_read(bdi, reg, &v);
267 if (ret < 0)
268 return ret;
269
270 v &= ~mask;
271 v |= ((data << shift) & mask);
272
273 return bq24190_write(bdi, reg, v);
274}
275
276static int bq24190_get_field_val(struct bq24190_dev_info *bdi,
277 u8 reg, u8 mask, u8 shift,
278 const int tbl[], int tbl_size,
279 int *val)
280{
281 u8 v;
282 int ret;
283
284 ret = bq24190_read_mask(bdi, reg, mask, shift, &v);
285 if (ret < 0)
286 return ret;
287
288 v = (v >= tbl_size) ? (tbl_size - 1) : v;
289 *val = tbl[v];
290
291 return 0;
292}
293
294static int bq24190_set_field_val(struct bq24190_dev_info *bdi,
295 u8 reg, u8 mask, u8 shift,
296 const int tbl[], int tbl_size,
297 int val)
298{
299 u8 idx;
300
301 idx = bq24190_find_idx(tbl, tbl_size, val);
302
303 return bq24190_write_mask(bdi, reg, mask, shift, idx);
304}
305
306#ifdef CONFIG_SYSFS
307/*
308 * There are a numerous options that are configurable on the bq24190
309 * that go well beyond what the power_supply properties provide access to.
310 * Provide sysfs access to them so they can be examined and possibly modified
311 * on the fly. They will be provided for the charger power_supply object only
312 * and will be prefixed by 'f_' to make them easier to recognize.
313 */
314
315#define BQ24190_SYSFS_FIELD(_name, r, f, m, store) \
316{ \
317 .attr = __ATTR(f_##_name, m, bq24190_sysfs_show, store), \
318 .reg = BQ24190_REG_##r, \
319 .mask = BQ24190_REG_##r##_##f##_MASK, \
320 .shift = BQ24190_REG_##r##_##f##_SHIFT, \
321}
322
323#define BQ24190_SYSFS_FIELD_RW(_name, r, f) \
324 BQ24190_SYSFS_FIELD(_name, r, f, S_IWUSR | S_IRUGO, \
325 bq24190_sysfs_store)
326
327#define BQ24190_SYSFS_FIELD_RO(_name, r, f) \
328 BQ24190_SYSFS_FIELD(_name, r, f, S_IRUGO, NULL)
329
330static ssize_t bq24190_sysfs_show(struct device *dev,
331 struct device_attribute *attr, char *buf);
332static ssize_t bq24190_sysfs_store(struct device *dev,
333 struct device_attribute *attr, const char *buf, size_t count);
334
335struct bq24190_sysfs_field_info {
336 struct device_attribute attr;
337 u8 reg;
338 u8 mask;
339 u8 shift;
340};
341
342static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
343 /* sysfs name reg field in reg */
344 BQ24190_SYSFS_FIELD_RW(en_hiz, ISC, EN_HIZ),
345 BQ24190_SYSFS_FIELD_RW(vindpm, ISC, VINDPM),
346 BQ24190_SYSFS_FIELD_RW(iinlim, ISC, IINLIM),
347 BQ24190_SYSFS_FIELD_RW(chg_config, POC, CHG_CONFIG),
348 BQ24190_SYSFS_FIELD_RW(sys_min, POC, SYS_MIN),
349 BQ24190_SYSFS_FIELD_RW(boost_lim, POC, BOOST_LIM),
350 BQ24190_SYSFS_FIELD_RW(ichg, CCC, ICHG),
351 BQ24190_SYSFS_FIELD_RW(force_20_pct, CCC, FORCE_20PCT),
352 BQ24190_SYSFS_FIELD_RW(iprechg, PCTCC, IPRECHG),
353 BQ24190_SYSFS_FIELD_RW(iterm, PCTCC, ITERM),
354 BQ24190_SYSFS_FIELD_RW(vreg, CVC, VREG),
355 BQ24190_SYSFS_FIELD_RW(batlowv, CVC, BATLOWV),
356 BQ24190_SYSFS_FIELD_RW(vrechg, CVC, VRECHG),
357 BQ24190_SYSFS_FIELD_RW(en_term, CTTC, EN_TERM),
358 BQ24190_SYSFS_FIELD_RW(term_stat, CTTC, TERM_STAT),
359 BQ24190_SYSFS_FIELD_RO(watchdog, CTTC, WATCHDOG),
360 BQ24190_SYSFS_FIELD_RW(en_timer, CTTC, EN_TIMER),
361 BQ24190_SYSFS_FIELD_RW(chg_timer, CTTC, CHG_TIMER),
362 BQ24190_SYSFS_FIELD_RW(jeta_iset, CTTC, JEITA_ISET),
363 BQ24190_SYSFS_FIELD_RW(bat_comp, ICTRC, BAT_COMP),
364 BQ24190_SYSFS_FIELD_RW(vclamp, ICTRC, VCLAMP),
365 BQ24190_SYSFS_FIELD_RW(treg, ICTRC, TREG),
366 BQ24190_SYSFS_FIELD_RW(dpdm_en, MOC, DPDM_EN),
367 BQ24190_SYSFS_FIELD_RW(tmr2x_en, MOC, TMR2X_EN),
368 BQ24190_SYSFS_FIELD_RW(batfet_disable, MOC, BATFET_DISABLE),
369 BQ24190_SYSFS_FIELD_RW(jeita_vset, MOC, JEITA_VSET),
370 BQ24190_SYSFS_FIELD_RO(int_mask, MOC, INT_MASK),
371 BQ24190_SYSFS_FIELD_RO(vbus_stat, SS, VBUS_STAT),
372 BQ24190_SYSFS_FIELD_RO(chrg_stat, SS, CHRG_STAT),
373 BQ24190_SYSFS_FIELD_RO(dpm_stat, SS, DPM_STAT),
374 BQ24190_SYSFS_FIELD_RO(pg_stat, SS, PG_STAT),
375 BQ24190_SYSFS_FIELD_RO(therm_stat, SS, THERM_STAT),
376 BQ24190_SYSFS_FIELD_RO(vsys_stat, SS, VSYS_STAT),
377 BQ24190_SYSFS_FIELD_RO(watchdog_fault, F, WATCHDOG_FAULT),
378 BQ24190_SYSFS_FIELD_RO(boost_fault, F, BOOST_FAULT),
379 BQ24190_SYSFS_FIELD_RO(chrg_fault, F, CHRG_FAULT),
380 BQ24190_SYSFS_FIELD_RO(bat_fault, F, BAT_FAULT),
381 BQ24190_SYSFS_FIELD_RO(ntc_fault, F, NTC_FAULT),
382 BQ24190_SYSFS_FIELD_RO(pn, VPRS, PN),
383 BQ24190_SYSFS_FIELD_RO(ts_profile, VPRS, TS_PROFILE),
384 BQ24190_SYSFS_FIELD_RO(dev_reg, VPRS, DEV_REG),
385};
386
387static struct attribute *
388 bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
389
390static const struct attribute_group bq24190_sysfs_attr_group = {
391 .attrs = bq24190_sysfs_attrs,
392};
393
394static void bq24190_sysfs_init_attrs(void)
395{
396 int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
397
398 for (i = 0; i < limit; i++)
399 bq24190_sysfs_attrs[i] = &bq24190_sysfs_field_tbl[i].attr.attr;
400
401 bq24190_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
402}
403
404static struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup(
405 const char *name)
406{
407 int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
408
409 for (i = 0; i < limit; i++)
410 if (!strcmp(name, bq24190_sysfs_field_tbl[i].attr.attr.name))
411 break;
412
413 if (i >= limit)
414 return NULL;
415
416 return &bq24190_sysfs_field_tbl[i];
417}
418
419static ssize_t bq24190_sysfs_show(struct device *dev,
420 struct device_attribute *attr, char *buf)
421{
422 struct power_supply *psy = dev_get_drvdata(dev);
423 struct bq24190_dev_info *bdi =
424 container_of(psy, struct bq24190_dev_info, charger);
425 struct bq24190_sysfs_field_info *info;
426 int ret;
427 u8 v;
428
429 info = bq24190_sysfs_field_lookup(attr->attr.name);
430 if (!info)
431 return -EINVAL;
432
433 ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
434 if (ret)
435 return ret;
436
437 return scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
438}
439
440static ssize_t bq24190_sysfs_store(struct device *dev,
441 struct device_attribute *attr, const char *buf, size_t count)
442{
443 struct power_supply *psy = dev_get_drvdata(dev);
444 struct bq24190_dev_info *bdi =
445 container_of(psy, struct bq24190_dev_info, charger);
446 struct bq24190_sysfs_field_info *info;
447 int ret;
448 u8 v;
449
450 info = bq24190_sysfs_field_lookup(attr->attr.name);
451 if (!info)
452 return -EINVAL;
453
454 ret = kstrtou8(buf, 0, &v);
455 if (ret < 0)
456 return ret;
457
458 ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
459 if (ret)
460 return ret;
461
462 return count;
463}
464
465static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
466{
467 bq24190_sysfs_init_attrs();
468
469 return sysfs_create_group(&bdi->charger.dev->kobj,
470 &bq24190_sysfs_attr_group);
471}
472
473static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
474{
475 sysfs_remove_group(&bdi->charger.dev->kobj, &bq24190_sysfs_attr_group);
476}
477#else
478static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
479{
480 return 0;
481}
482
483static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
484#endif
485
486/*
487 * According to the "Host Mode and default Mode" section of the
488 * manual, a write to any register causes the bq24190 to switch
489 * from default mode to host mode. It will switch back to default
490 * mode after a WDT timeout unless the WDT is turned off as well.
491 * So, by simply turning off the WDT, we accomplish both with the
492 * same write.
493 */
494static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
495{
496 int ret;
497 u8 v;
498
499 ret = bq24190_read(bdi, BQ24190_REG_CTTC, &v);
500 if (ret < 0)
501 return ret;
502
503 bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >>
504 BQ24190_REG_CTTC_WATCHDOG_SHIFT);
505 v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
506
507 return bq24190_write(bdi, BQ24190_REG_CTTC, v);
508}
509
510static int bq24190_register_reset(struct bq24190_dev_info *bdi)
511{
512 int ret, limit = 100;
513 u8 v;
514
515 /* Reset the registers */
516 ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
517 BQ24190_REG_POC_RESET_MASK,
518 BQ24190_REG_POC_RESET_SHIFT,
519 0x1);
520 if (ret < 0)
521 return ret;
522
523 /* Reset bit will be cleared by hardware so poll until it is */
524 do {
525 ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
526 BQ24190_REG_POC_RESET_MASK,
527 BQ24190_REG_POC_RESET_SHIFT,
528 &v);
529 if (ret < 0)
530 return ret;
531
532 if (!v)
533 break;
534
535 udelay(10);
536 } while (--limit);
537
538 if (!limit)
539 return -EIO;
540
541 return 0;
542}
543
544/* Charger power supply property routines */
545
546static int bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi,
547 union power_supply_propval *val)
548{
549 u8 v;
550 int type, ret;
551
552 ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
553 BQ24190_REG_POC_CHG_CONFIG_MASK,
554 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
555 &v);
556 if (ret < 0)
557 return ret;
558
559 /* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */
560 if (!v) {
561 type = POWER_SUPPLY_CHARGE_TYPE_NONE;
562 } else {
563 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
564 BQ24190_REG_CCC_FORCE_20PCT_MASK,
565 BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
566 &v);
567 if (ret < 0)
568 return ret;
569
570 type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE :
571 POWER_SUPPLY_CHARGE_TYPE_FAST;
572 }
573
574 val->intval = type;
575
576 return 0;
577}
578
579static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
580 const union power_supply_propval *val)
581{
582 u8 chg_config, force_20pct, en_term;
583 int ret;
584
585 /*
586 * According to the "Termination when REG02[0] = 1" section of
587 * the bq24190 manual, the trickle charge could be less than the
588 * termination current so it recommends turning off the termination
589 * function.
590 *
591 * Note: AFAICT from the datasheet, the user will have to manually
592 * turn off the charging when in 20% mode. If its not turned off,
593 * there could be battery damage. So, use this mode at your own risk.
594 */
595 switch (val->intval) {
596 case POWER_SUPPLY_CHARGE_TYPE_NONE:
597 chg_config = 0x0;
598 break;
599 case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
600 chg_config = 0x1;
601 force_20pct = 0x1;
602 en_term = 0x0;
603 break;
604 case POWER_SUPPLY_CHARGE_TYPE_FAST:
605 chg_config = 0x1;
606 force_20pct = 0x0;
607 en_term = 0x1;
608 break;
609 default:
610 return -EINVAL;
611 }
612
613 if (chg_config) { /* Enabling the charger */
614 ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
615 BQ24190_REG_CCC_FORCE_20PCT_MASK,
616 BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
617 force_20pct);
618 if (ret < 0)
619 return ret;
620
621 ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC,
622 BQ24190_REG_CTTC_EN_TERM_MASK,
623 BQ24190_REG_CTTC_EN_TERM_SHIFT,
624 en_term);
625 if (ret < 0)
626 return ret;
627 }
628
629 return bq24190_write_mask(bdi, BQ24190_REG_POC,
630 BQ24190_REG_POC_CHG_CONFIG_MASK,
631 BQ24190_REG_POC_CHG_CONFIG_SHIFT, chg_config);
632}
633
634static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
635 union power_supply_propval *val)
636{
637 u8 v;
638 int health, ret;
639
640 mutex_lock(&bdi->f_reg_lock);
641
642 if (bdi->charger_health_valid) {
643 v = bdi->f_reg;
644 bdi->charger_health_valid = false;
645 mutex_unlock(&bdi->f_reg_lock);
646 } else {
647 mutex_unlock(&bdi->f_reg_lock);
648
649 ret = bq24190_read(bdi, BQ24190_REG_F, &v);
650 if (ret < 0)
651 return ret;
652 }
653
654 if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
655 /*
656 * This could be over-current or over-voltage but there's
657 * no way to tell which. Return 'OVERVOLTAGE' since there
658 * isn't an 'OVERCURRENT' value defined that we can return
659 * even if it was over-current.
660 */
661 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
662 } else {
663 v &= BQ24190_REG_F_CHRG_FAULT_MASK;
664 v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
665
666 switch (v) {
667 case 0x0: /* Normal */
668 health = POWER_SUPPLY_HEALTH_GOOD;
669 break;
670 case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
671 /*
672 * This could be over-voltage or under-voltage
673 * and there's no way to tell which. Instead
674 * of looking foolish and returning 'OVERVOLTAGE'
675 * when its really under-voltage, just return
676 * 'UNSPEC_FAILURE'.
677 */
678 health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
679 break;
680 case 0x2: /* Thermal Shutdown */
681 health = POWER_SUPPLY_HEALTH_OVERHEAT;
682 break;
683 case 0x3: /* Charge Safety Timer Expiration */
684 health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
685 break;
686 default:
687 health = POWER_SUPPLY_HEALTH_UNKNOWN;
688 }
689 }
690
691 val->intval = health;
692
693 return 0;
694}
695
696static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
697 union power_supply_propval *val)
698{
699 u8 v;
700 int ret;
701
702 ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
703 BQ24190_REG_SS_PG_STAT_MASK,
704 BQ24190_REG_SS_PG_STAT_SHIFT, &v);
705 if (ret < 0)
706 return ret;
707
708 val->intval = v;
709 return 0;
710}
711
712static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
713 union power_supply_propval *val)
714{
715 u8 v;
716 int curr, ret;
717
718 ret = bq24190_get_field_val(bdi, BQ24190_REG_CCC,
719 BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
720 bq24190_ccc_ichg_values,
721 ARRAY_SIZE(bq24190_ccc_ichg_values), &curr);
722 if (ret < 0)
723 return ret;
724
725 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
726 BQ24190_REG_CCC_FORCE_20PCT_MASK,
727 BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
728 if (ret < 0)
729 return ret;
730
731 /* If FORCE_20PCT is enabled, then current is 20% of ICHG value */
732 if (v)
733 curr /= 5;
734
735 val->intval = curr;
736 return 0;
737}
738
739static int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi,
740 union power_supply_propval *val)
741{
742 int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
743
744 val->intval = bq24190_ccc_ichg_values[idx];
745 return 0;
746}
747
748static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
749 const union power_supply_propval *val)
750{
751 u8 v;
752 int ret, curr = val->intval;
753
754 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
755 BQ24190_REG_CCC_FORCE_20PCT_MASK,
756 BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
757 if (ret < 0)
758 return ret;
759
760 /* If FORCE_20PCT is enabled, have to multiply value passed in by 5 */
761 if (v)
762 curr *= 5;
763
764 return bq24190_set_field_val(bdi, BQ24190_REG_CCC,
765 BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
766 bq24190_ccc_ichg_values,
767 ARRAY_SIZE(bq24190_ccc_ichg_values), curr);
768}
769
770static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
771 union power_supply_propval *val)
772{
773 int voltage, ret;
774
775 ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC,
776 BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
777 bq24190_cvc_vreg_values,
778 ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage);
779 if (ret < 0)
780 return ret;
781
782 val->intval = voltage;
783 return 0;
784}
785
786static int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi,
787 union power_supply_propval *val)
788{
789 int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
790
791 val->intval = bq24190_cvc_vreg_values[idx];
792 return 0;
793}
794
795static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
796 const union power_supply_propval *val)
797{
798 return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
799 BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
800 bq24190_cvc_vreg_values,
801 ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
802}
803
804static int bq24190_charger_get_property(struct power_supply *psy,
805 enum power_supply_property psp, union power_supply_propval *val)
806{
807 struct bq24190_dev_info *bdi =
808 container_of(psy, struct bq24190_dev_info, charger);
809 int ret;
810
811 dev_dbg(bdi->dev, "prop: %d\n", psp);
812
813 pm_runtime_get_sync(bdi->dev);
814
815 switch (psp) {
816 case POWER_SUPPLY_PROP_CHARGE_TYPE:
817 ret = bq24190_charger_get_charge_type(bdi, val);
818 break;
819 case POWER_SUPPLY_PROP_HEALTH:
820 ret = bq24190_charger_get_health(bdi, val);
821 break;
822 case POWER_SUPPLY_PROP_ONLINE:
823 ret = bq24190_charger_get_online(bdi, val);
824 break;
825 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
826 ret = bq24190_charger_get_current(bdi, val);
827 break;
828 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
829 ret = bq24190_charger_get_current_max(bdi, val);
830 break;
831 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
832 ret = bq24190_charger_get_voltage(bdi, val);
833 break;
834 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
835 ret = bq24190_charger_get_voltage_max(bdi, val);
836 break;
837 case POWER_SUPPLY_PROP_SCOPE:
838 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
839 ret = 0;
840 break;
841 case POWER_SUPPLY_PROP_MODEL_NAME:
842 val->strval = bdi->model_name;
843 ret = 0;
844 break;
845 case POWER_SUPPLY_PROP_MANUFACTURER:
846 val->strval = BQ24190_MANUFACTURER;
847 ret = 0;
848 break;
849 default:
850 ret = -ENODATA;
851 }
852
853 pm_runtime_put_sync(bdi->dev);
854 return ret;
855}
856
857static int bq24190_charger_set_property(struct power_supply *psy,
858 enum power_supply_property psp,
859 const union power_supply_propval *val)
860{
861 struct bq24190_dev_info *bdi =
862 container_of(psy, struct bq24190_dev_info, charger);
863 int ret;
864
865 dev_dbg(bdi->dev, "prop: %d\n", psp);
866
867 pm_runtime_get_sync(bdi->dev);
868
869 switch (psp) {
870 case POWER_SUPPLY_PROP_CHARGE_TYPE:
871 ret = bq24190_charger_set_charge_type(bdi, val);
872 break;
873 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
874 ret = bq24190_charger_set_current(bdi, val);
875 break;
876 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
877 ret = bq24190_charger_set_voltage(bdi, val);
878 break;
879 default:
880 ret = -EINVAL;
881 }
882
883 pm_runtime_put_sync(bdi->dev);
884 return ret;
885}
886
887static int bq24190_charger_property_is_writeable(struct power_supply *psy,
888 enum power_supply_property psp)
889{
890 int ret;
891
892 switch (psp) {
893 case POWER_SUPPLY_PROP_CHARGE_TYPE:
894 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
895 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
896 ret = 1;
897 break;
898 default:
899 ret = 0;
900 }
901
902 return ret;
903}
904
905static enum power_supply_property bq24190_charger_properties[] = {
906 POWER_SUPPLY_PROP_TYPE,
907 POWER_SUPPLY_PROP_HEALTH,
908 POWER_SUPPLY_PROP_ONLINE,
909 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
910 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
911 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
912 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
913 POWER_SUPPLY_PROP_SCOPE,
914 POWER_SUPPLY_PROP_MODEL_NAME,
915 POWER_SUPPLY_PROP_MANUFACTURER,
916};
917
918static char *bq24190_charger_supplied_to[] = {
919 "main-battery",
920};
921
922static void bq24190_charger_init(struct power_supply *charger)
923{
924 charger->name = "bq24190-charger";
925 charger->type = POWER_SUPPLY_TYPE_USB;
926 charger->properties = bq24190_charger_properties;
927 charger->num_properties = ARRAY_SIZE(bq24190_charger_properties);
928 charger->supplied_to = bq24190_charger_supplied_to;
929 charger->num_supplies = ARRAY_SIZE(bq24190_charger_supplied_to);
930 charger->get_property = bq24190_charger_get_property;
931 charger->set_property = bq24190_charger_set_property;
932 charger->property_is_writeable = bq24190_charger_property_is_writeable;
933}
934
935/* Battery power supply property routines */
936
937static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
938 union power_supply_propval *val)
939{
940 u8 ss_reg, chrg_fault;
941 int status, ret;
942
943 mutex_lock(&bdi->f_reg_lock);
944
945 if (bdi->battery_status_valid) {
946 chrg_fault = bdi->f_reg;
947 bdi->battery_status_valid = false;
948 mutex_unlock(&bdi->f_reg_lock);
949 } else {
950 mutex_unlock(&bdi->f_reg_lock);
951
952 ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
953 if (ret < 0)
954 return ret;
955 }
956
957 chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
958 chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
959
960 ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
961 if (ret < 0)
962 return ret;
963
964 /*
965 * The battery must be discharging when any of these are true:
966 * - there is no good power source;
967 * - there is a charge fault.
968 * Could also be discharging when in "supplement mode" but
969 * there is no way to tell when its in that mode.
970 */
971 if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) {
972 status = POWER_SUPPLY_STATUS_DISCHARGING;
973 } else {
974 ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK;
975 ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT;
976
977 switch (ss_reg) {
978 case 0x0: /* Not Charging */
979 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
980 break;
981 case 0x1: /* Pre-charge */
982 case 0x2: /* Fast Charging */
983 status = POWER_SUPPLY_STATUS_CHARGING;
984 break;
985 case 0x3: /* Charge Termination Done */
986 status = POWER_SUPPLY_STATUS_FULL;
987 break;
988 default:
989 ret = -EIO;
990 }
991 }
992
993 if (!ret)
994 val->intval = status;
995
996 return ret;
997}
998
999static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
1000 union power_supply_propval *val)
1001{
1002 u8 v;
1003 int health, ret;
1004
1005 mutex_lock(&bdi->f_reg_lock);
1006
1007 if (bdi->battery_health_valid) {
1008 v = bdi->f_reg;
1009 bdi->battery_health_valid = false;
1010 mutex_unlock(&bdi->f_reg_lock);
1011 } else {
1012 mutex_unlock(&bdi->f_reg_lock);
1013
1014 ret = bq24190_read(bdi, BQ24190_REG_F, &v);
1015 if (ret < 0)
1016 return ret;
1017 }
1018
1019 if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
1020 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1021 } else {
1022 v &= BQ24190_REG_F_NTC_FAULT_MASK;
1023 v >>= BQ24190_REG_F_NTC_FAULT_SHIFT;
1024
1025 switch (v) {
1026 case 0x0: /* Normal */
1027 health = POWER_SUPPLY_HEALTH_GOOD;
1028 break;
1029 case 0x1: /* TS1 Cold */
1030 case 0x3: /* TS2 Cold */
1031 case 0x5: /* Both Cold */
1032 health = POWER_SUPPLY_HEALTH_COLD;
1033 break;
1034 case 0x2: /* TS1 Hot */
1035 case 0x4: /* TS2 Hot */
1036 case 0x6: /* Both Hot */
1037 health = POWER_SUPPLY_HEALTH_OVERHEAT;
1038 break;
1039 default:
1040 health = POWER_SUPPLY_HEALTH_UNKNOWN;
1041 }
1042 }
1043
1044 val->intval = health;
1045 return 0;
1046}
1047
1048static int bq24190_battery_get_online(struct bq24190_dev_info *bdi,
1049 union power_supply_propval *val)
1050{
1051 u8 batfet_disable;
1052 int ret;
1053
1054 ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
1055 BQ24190_REG_MOC_BATFET_DISABLE_MASK,
1056 BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
1057 if (ret < 0)
1058 return ret;
1059
1060 val->intval = !batfet_disable;
1061 return 0;
1062}
1063
1064static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
1065 const union power_supply_propval *val)
1066{
1067 return bq24190_write_mask(bdi, BQ24190_REG_MOC,
1068 BQ24190_REG_MOC_BATFET_DISABLE_MASK,
1069 BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, !val->intval);
1070}
1071
1072static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
1073 union power_supply_propval *val)
1074{
1075 int temp, ret;
1076
1077 ret = bq24190_get_field_val(bdi, BQ24190_REG_ICTRC,
1078 BQ24190_REG_ICTRC_TREG_MASK,
1079 BQ24190_REG_ICTRC_TREG_SHIFT,
1080 bq24190_ictrc_treg_values,
1081 ARRAY_SIZE(bq24190_ictrc_treg_values), &temp);
1082 if (ret < 0)
1083 return ret;
1084
1085 val->intval = temp;
1086 return 0;
1087}
1088
1089static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
1090 const union power_supply_propval *val)
1091{
1092 return bq24190_set_field_val(bdi, BQ24190_REG_ICTRC,
1093 BQ24190_REG_ICTRC_TREG_MASK,
1094 BQ24190_REG_ICTRC_TREG_SHIFT,
1095 bq24190_ictrc_treg_values,
1096 ARRAY_SIZE(bq24190_ictrc_treg_values), val->intval);
1097}
1098
1099static int bq24190_battery_get_property(struct power_supply *psy,
1100 enum power_supply_property psp, union power_supply_propval *val)
1101{
1102 struct bq24190_dev_info *bdi =
1103 container_of(psy, struct bq24190_dev_info, battery);
1104 int ret;
1105
1106 dev_dbg(bdi->dev, "prop: %d\n", psp);
1107
1108 pm_runtime_get_sync(bdi->dev);
1109
1110 switch (psp) {
1111 case POWER_SUPPLY_PROP_STATUS:
1112 ret = bq24190_battery_get_status(bdi, val);
1113 break;
1114 case POWER_SUPPLY_PROP_HEALTH:
1115 ret = bq24190_battery_get_health(bdi, val);
1116 break;
1117 case POWER_SUPPLY_PROP_ONLINE:
1118 ret = bq24190_battery_get_online(bdi, val);
1119 break;
1120 case POWER_SUPPLY_PROP_TECHNOLOGY:
1121 /* Could be Li-on or Li-polymer but no way to tell which */
1122 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
1123 ret = 0;
1124 break;
1125 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1126 ret = bq24190_battery_get_temp_alert_max(bdi, val);
1127 break;
1128 case POWER_SUPPLY_PROP_SCOPE:
1129 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1130 ret = 0;
1131 break;
1132 default:
1133 ret = -ENODATA;
1134 }
1135
1136 pm_runtime_put_sync(bdi->dev);
1137 return ret;
1138}
1139
1140static int bq24190_battery_set_property(struct power_supply *psy,
1141 enum power_supply_property psp,
1142 const union power_supply_propval *val)
1143{
1144 struct bq24190_dev_info *bdi =
1145 container_of(psy, struct bq24190_dev_info, battery);
1146 int ret;
1147
1148 dev_dbg(bdi->dev, "prop: %d\n", psp);
1149
1150 pm_runtime_put_sync(bdi->dev);
1151
1152 switch (psp) {
1153 case POWER_SUPPLY_PROP_ONLINE:
1154 ret = bq24190_battery_set_online(bdi, val);
1155 break;
1156 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1157 ret = bq24190_battery_set_temp_alert_max(bdi, val);
1158 break;
1159 default:
1160 ret = -EINVAL;
1161 }
1162
1163 pm_runtime_put_sync(bdi->dev);
1164 return ret;
1165}
1166
1167static int bq24190_battery_property_is_writeable(struct power_supply *psy,
1168 enum power_supply_property psp)
1169{
1170 int ret;
1171
1172 switch (psp) {
1173 case POWER_SUPPLY_PROP_ONLINE:
1174 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1175 ret = 1;
1176 break;
1177 default:
1178 ret = 0;
1179 }
1180
1181 return ret;
1182}
1183
1184static enum power_supply_property bq24190_battery_properties[] = {
1185 POWER_SUPPLY_PROP_STATUS,
1186 POWER_SUPPLY_PROP_HEALTH,
1187 POWER_SUPPLY_PROP_ONLINE,
1188 POWER_SUPPLY_PROP_TECHNOLOGY,
1189 POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
1190 POWER_SUPPLY_PROP_SCOPE,
1191};
1192
1193static void bq24190_battery_init(struct power_supply *battery)
1194{
1195 battery->name = "bq24190-battery";
1196 battery->type = POWER_SUPPLY_TYPE_BATTERY;
1197 battery->properties = bq24190_battery_properties;
1198 battery->num_properties = ARRAY_SIZE(bq24190_battery_properties);
1199 battery->get_property = bq24190_battery_get_property;
1200 battery->set_property = bq24190_battery_set_property;
1201 battery->property_is_writeable = bq24190_battery_property_is_writeable;
1202}
1203
1204static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
1205{
1206 struct bq24190_dev_info *bdi = data;
1207 bool alert_userspace = false;
1208 u8 ss_reg, f_reg;
1209 int ret;
1210
1211 pm_runtime_get_sync(bdi->dev);
1212
1213 ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
1214 if (ret < 0) {
1215 dev_err(bdi->dev, "Can't read SS reg: %d\n", ret);
1216 goto out;
1217 }
1218
1219 if (ss_reg != bdi->ss_reg) {
1220 /*
1221 * The device is in host mode so when PG_STAT goes from 1->0
1222 * (i.e., power removed) HIZ needs to be disabled.
1223 */
1224 if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) &&
1225 !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) {
1226 ret = bq24190_write_mask(bdi, BQ24190_REG_ISC,
1227 BQ24190_REG_ISC_EN_HIZ_MASK,
1228 BQ24190_REG_ISC_EN_HIZ_SHIFT,
1229 0);
1230 if (ret < 0)
1231 dev_err(bdi->dev, "Can't access ISC reg: %d\n",
1232 ret);
1233 }
1234
1235 bdi->ss_reg = ss_reg;
1236 alert_userspace = true;
1237 }
1238
1239 mutex_lock(&bdi->f_reg_lock);
1240
1241 ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
1242 if (ret < 0) {
1243 mutex_unlock(&bdi->f_reg_lock);
1244 dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
1245 goto out;
1246 }
1247
1248 if (f_reg != bdi->f_reg) {
1249 bdi->f_reg = f_reg;
1250 bdi->charger_health_valid = true;
1251 bdi->battery_health_valid = true;
1252 bdi->battery_status_valid = true;
1253
1254 alert_userspace = true;
1255 }
1256
1257 mutex_unlock(&bdi->f_reg_lock);
1258
1259 /*
1260 * Sometimes bq24190 gives a steady trickle of interrupts even
1261 * though the watchdog timer is turned off and neither the STATUS
1262 * nor FAULT registers have changed. Weed out these sprurious
1263 * interrupts so userspace isn't alerted for no reason.
1264 * In addition, the chip always generates an interrupt after
1265 * register reset so we should ignore that one (the very first
1266 * interrupt received).
1267 */
1268 if (alert_userspace && !bdi->first_time) {
1269 power_supply_changed(&bdi->charger);
1270 power_supply_changed(&bdi->battery);
1271 bdi->first_time = false;
1272 }
1273
1274out:
1275 pm_runtime_put_sync(bdi->dev);
1276
1277 dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
1278
1279 return IRQ_HANDLED;
1280}
1281
1282static int bq24190_hw_init(struct bq24190_dev_info *bdi)
1283{
1284 u8 v;
1285 int ret;
1286
1287 pm_runtime_get_sync(bdi->dev);
1288
1289 /* First check that the device really is what its supposed to be */
1290 ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS,
1291 BQ24190_REG_VPRS_PN_MASK,
1292 BQ24190_REG_VPRS_PN_SHIFT,
1293 &v);
1294 if (ret < 0)
1295 goto out;
1296
1297 if (v != bdi->model) {
1298 ret = -ENODEV;
1299 goto out;
1300 }
1301
1302 ret = bq24190_register_reset(bdi);
1303 if (ret < 0)
1304 goto out;
1305
1306 ret = bq24190_set_mode_host(bdi);
1307out:
1308 pm_runtime_put_sync(bdi->dev);
1309 return ret;
1310}
1311
1312#ifdef CONFIG_OF
1313static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
1314{
1315 bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
1316 if (bdi->irq <= 0)
1317 return -1;
1318
1319 return 0;
1320}
1321#else
1322static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
1323{
1324 return -1;
1325}
1326#endif
1327
1328static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
1329 struct bq24190_platform_data *pdata)
1330{
1331 int ret;
1332
1333 if (!gpio_is_valid(pdata->gpio_int))
1334 return -1;
1335
1336 ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
1337 if (ret < 0)
1338 return -1;
1339
1340 ret = gpio_direction_input(pdata->gpio_int);
1341 if (ret < 0)
1342 goto out;
1343
1344 bdi->irq = gpio_to_irq(pdata->gpio_int);
1345 if (!bdi->irq)
1346 goto out;
1347
1348 bdi->gpio_int = pdata->gpio_int;
1349 return 0;
1350
1351out:
1352 gpio_free(pdata->gpio_int);
1353 return -1;
1354}
1355
1356static int bq24190_probe(struct i2c_client *client,
1357 const struct i2c_device_id *id)
1358{
1359 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1360 struct device *dev = &client->dev;
1361 struct bq24190_platform_data *pdata = client->dev.platform_data;
1362 struct bq24190_dev_info *bdi;
1363 int ret;
1364
1365 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1366 dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
1367 return -ENODEV;
1368 }
1369
1370 bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
1371 if (!bdi) {
1372 dev_err(dev, "Can't alloc bdi struct\n");
1373 return -ENOMEM;
1374 }
1375
1376 bdi->client = client;
1377 bdi->dev = dev;
1378 bdi->model = id->driver_data;
1379 strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
1380 mutex_init(&bdi->f_reg_lock);
1381 bdi->first_time = true;
1382 bdi->charger_health_valid = false;
1383 bdi->battery_health_valid = false;
1384 bdi->battery_status_valid = false;
1385
1386 i2c_set_clientdata(client, bdi);
1387
1388 if (dev->of_node)
1389 ret = bq24190_setup_dt(bdi);
1390 else
1391 ret = bq24190_setup_pdata(bdi, pdata);
1392
1393 if (ret) {
1394 dev_err(dev, "Can't get irq info\n");
1395 return -EINVAL;
1396 }
1397
1398 ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
1399 bq24190_irq_handler_thread,
1400 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1401 "bq24190-charger", bdi);
1402 if (ret < 0) {
1403 dev_err(dev, "Can't set up irq handler\n");
1404 goto out1;
1405 }
1406
1407 pm_runtime_enable(dev);
1408 pm_runtime_resume(dev);
1409
1410 ret = bq24190_hw_init(bdi);
1411 if (ret < 0) {
1412 dev_err(dev, "Hardware init failed\n");
1413 goto out2;
1414 }
1415
1416 bq24190_charger_init(&bdi->charger);
1417
1418 ret = power_supply_register(dev, &bdi->charger);
1419 if (ret) {
1420 dev_err(dev, "Can't register charger\n");
1421 goto out2;
1422 }
1423
1424 bq24190_battery_init(&bdi->battery);
1425
1426 ret = power_supply_register(dev, &bdi->battery);
1427 if (ret) {
1428 dev_err(dev, "Can't register battery\n");
1429 goto out3;
1430 }
1431
1432 ret = bq24190_sysfs_create_group(bdi);
1433 if (ret) {
1434 dev_err(dev, "Can't create sysfs entries\n");
1435 goto out4;
1436 }
1437
1438 return 0;
1439
1440out4:
1441 power_supply_unregister(&bdi->battery);
1442out3:
1443 power_supply_unregister(&bdi->charger);
1444out2:
1445 pm_runtime_disable(dev);
1446out1:
1447 if (bdi->gpio_int)
1448 gpio_free(bdi->gpio_int);
1449
1450 return ret;
1451}
1452
1453static int bq24190_remove(struct i2c_client *client)
1454{
1455 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1456
1457 pm_runtime_get_sync(bdi->dev);
1458 bq24190_register_reset(bdi);
1459 pm_runtime_put_sync(bdi->dev);
1460
1461 bq24190_sysfs_remove_group(bdi);
1462 power_supply_unregister(&bdi->battery);
1463 power_supply_unregister(&bdi->charger);
1464 pm_runtime_disable(bdi->dev);
1465
1466 if (bdi->gpio_int)
1467 gpio_free(bdi->gpio_int);
1468
1469 return 0;
1470}
1471
1472#ifdef CONFIG_PM_SLEEP
1473static int bq24190_pm_suspend(struct device *dev)
1474{
1475 struct i2c_client *client = to_i2c_client(dev);
1476 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1477
1478 pm_runtime_get_sync(bdi->dev);
1479 bq24190_register_reset(bdi);
1480 pm_runtime_put_sync(bdi->dev);
1481
1482 return 0;
1483}
1484
1485static int bq24190_pm_resume(struct device *dev)
1486{
1487 struct i2c_client *client = to_i2c_client(dev);
1488 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1489
1490 bdi->charger_health_valid = false;
1491 bdi->battery_health_valid = false;
1492 bdi->battery_status_valid = false;
1493
1494 pm_runtime_get_sync(bdi->dev);
1495 bq24190_register_reset(bdi);
1496 pm_runtime_put_sync(bdi->dev);
1497
1498 /* Things may have changed while suspended so alert upper layer */
1499 power_supply_changed(&bdi->charger);
1500 power_supply_changed(&bdi->battery);
1501
1502 return 0;
1503}
1504#endif
1505
1506static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume);
1507
1508/*
1509 * Only support the bq24190 right now. The bq24192, bq24192i, and bq24193
1510 * are similar but not identical so the driver needs to be extended to
1511 * support them.
1512 */
1513static const struct i2c_device_id bq24190_i2c_ids[] = {
1514 { "bq24190", BQ24190_REG_VPRS_PN_24190 },
1515 { },
1516};
1517
1518#ifdef CONFIG_OF
1519static const struct of_device_id bq24190_of_match[] = {
1520 { .compatible = "ti,bq24190", },
1521 { },
1522};
1523MODULE_DEVICE_TABLE(of, bq24190_of_match);
1524#else
1525static const struct of_device_id bq24190_of_match[] = {
1526 { },
1527};
1528#endif
1529
1530static struct i2c_driver bq24190_driver = {
1531 .probe = bq24190_probe,
1532 .remove = bq24190_remove,
1533 .id_table = bq24190_i2c_ids,
1534 .driver = {
1535 .name = "bq24190-charger",
1536 .owner = THIS_MODULE,
1537 .pm = &bq24190_pm_ops,
1538 .of_match_table = of_match_ptr(bq24190_of_match),
1539 },
1540};
1541module_i2c_driver(bq24190_driver);
1542
1543MODULE_LICENSE("GPL");
1544MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
1545MODULE_ALIAS("i2c:bq24190-charger");
1546MODULE_DESCRIPTION("TI BQ24190 Charger Driver");