summaryrefslogtreecommitdiffstats
path: root/drivers/power
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 01:58:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-09-11 01:58:14 -0400
commita22a0fdba4191473581f86c9dd5361cf581521d3 (patch)
treeef5d3992f791641d6c8c16cee781f214fecbb105 /drivers/power
parentbf83e61464803d386d0ec3fc92e5449d7963a409 (diff)
parentdb15e6312efd537e2deb2cbad110c23f98704a3c (diff)
Merge tag 'for-v3.12' of git://git.infradead.org/battery-2.6
Pull battery/power supply driver updates from Anton Vorontsov: "New drivers: - APM X-Gene system reboot driver by Feng Kan and Loc Ho (APM). - Qualcomm MSM reboot/poweroff driver by Abhimanyu Kapur (Codeaurora). - Texas Instruments BQ24190 charger driver by Mark A. Greer (Animal Creek Technologies). - Texas Instruments TWL4030 MADC battery driver by Lukas Märdian and Marek Belisko (Golden Delicious Computers). The driver is used on Freerunner GTA04 phones. Highlighted fixes and improvements: - Suspend/wakeup logic improvements: power supply objects will block system suspend until all power supply events are processed. Thanks to Zoran Markovic (Linaro), Arve Hjonnevag and Todd Poynor (Google)" * tag 'for-v3.12' of git://git.infradead.org/battery-2.6: rx51_battery: Fix channel number when reading adc value power: Add twl4030_madc battery driver. bq24190_charger: Workaround SS definition problem on i386 builds power_supply: Prevent suspend until power supply events are processed vexpress-poweroff: Should depend on the required infrastructure twl4030-charger: Fix compiler warning with regulator_enable() rx51_battery: Replace hardcoded channels values. bq24190_charger: Add support for TI BQ24190 Battery Charger ab8500-charger: We print an unintended error message max8925_power: Fix missing of_node_put power_supply: Replace strict_strtol() with kstrtol() power: Add APM X-Gene system reboot driver power_supply: tosa_battery: Get rid of irq_to_gpio usage power supply: collie_battery: Convert to use dev_pm_ops power_supply: Make goldfish_battery depend on GOLDFISH || COMPILE_TEST power: reset: Add msm restart support MAINTAINERS: drivers/power: add entry for SmartReflex AVS drivers
Diffstat (limited to 'drivers/power')
-rw-r--r--drivers/power/Kconfig15
-rw-r--r--drivers/power/Makefile2
-rw-r--r--drivers/power/ab8500_charger.c1
-rw-r--r--drivers/power/bq24190_charger.c1549
-rw-r--r--drivers/power/collie_battery.c2
-rw-r--r--drivers/power/max8925_power.c1
-rw-r--r--drivers/power/power_supply_core.c38
-rw-r--r--drivers/power/power_supply_sysfs.c2
-rw-r--r--drivers/power/reset/Kconfig15
-rw-r--r--drivers/power/reset/Makefile2
-rw-r--r--drivers/power/reset/msm-poweroff.c73
-rw-r--r--drivers/power/reset/xgene-reboot.c103
-rw-r--r--drivers/power/rx51_battery.c14
-rw-r--r--drivers/power/tosa_battery.c2
-rw-r--r--drivers/power/twl4030_charger.c7
-rw-r--r--drivers/power/twl4030_madc_battery.c245
16 files changed, 2054 insertions, 17 deletions
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 7b8979c63f48..bb49ab684f9a 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -216,6 +216,13 @@ config BATTERY_S3C_ADC
216 help 216 help
217 Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery 217 Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
218 218
219config BATTERY_TWL4030_MADC
220 tristate "TWL4030 MADC battery driver"
221 depends on TWL4030_MADC
222 help
223 Say Y here to enable this dumb driver for batteries managed
224 through the TWL4030 MADC.
225
219config CHARGER_88PM860X 226config CHARGER_88PM860X
220 tristate "Marvell 88PM860x Charger driver" 227 tristate "Marvell 88PM860x Charger driver"
221 depends on MFD_88PM860X && BATTERY_88PM860X 228 depends on MFD_88PM860X && BATTERY_88PM860X
@@ -334,6 +341,12 @@ config CHARGER_BQ2415X
334 You'll need this driver to charge batteries on e.g. Nokia 341 You'll need this driver to charge batteries on e.g. Nokia
335 RX-51/N900. 342 RX-51/N900.
336 343
344config CHARGER_BQ24190
345 tristate "TI BQ24190 battery charger driver"
346 depends on I2C && GPIOLIB
347 help
348 Say Y to enable support for the TI BQ24190 battery charger.
349
337config CHARGER_SMB347 350config CHARGER_SMB347
338 tristate "Summit Microelectronics SMB347 Battery Charger" 351 tristate "Summit Microelectronics SMB347 Battery Charger"
339 depends on I2C 352 depends on I2C
@@ -357,7 +370,7 @@ config AB8500_BM
357 370
358config BATTERY_GOLDFISH 371config BATTERY_GOLDFISH
359 tristate "Goldfish battery driver" 372 tristate "Goldfish battery driver"
360 depends on GENERIC_HARDIRQS 373 depends on GENERIC_HARDIRQS && (GOLDFISH || COMPILE_TEST)
361 help 374 help
362 Say Y to enable support for the battery and AC power in the 375 Say Y to enable support for the battery and AC power in the
363 Goldfish emulator. 376 Goldfish emulator.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 653bf6ceff30..a4b74177706f 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
34obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o 34obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
35obj-$(CONFIG_BATTERY_Z2) += z2_battery.o 35obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
36obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o 36obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
37obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
37obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o 38obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
38obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o 39obj-$(CONFIG_CHARGER_PCF50633) += pcf50633-charger.o
39obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o 40obj-$(CONFIG_BATTERY_JZ4740) += jz4740-battery.o
@@ -50,6 +51,7 @@ obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
50obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o 51obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
51obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o 52obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
52obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o 53obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
54obj-$(CONFIG_CHARGER_BQ24190) += bq24190_charger.o
53obj-$(CONFIG_POWER_AVS) += avs/ 55obj-$(CONFIG_POWER_AVS) += avs/
54obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o 56obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o
55obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o 57obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index f098fdafee9f..a4c4a10b3a41 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -774,6 +774,7 @@ static int ab8500_charger_max_usb_curr(struct ab8500_charger *di,
774 di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 774 di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
775 dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status, 775 dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
776 di->max_usb_in_curr.usb_type_max); 776 di->max_usb_in_curr.usb_type_max);
777 break;
777 case USB_STAT_NOT_VALID_LINK: 778 case USB_STAT_NOT_VALID_LINK:
778 dev_err(di->dev, "USB Type invalid - try charging anyway\n"); 779 dev_err(di->dev, "USB Type invalid - try charging anyway\n");
779 di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5; 780 di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c
new file mode 100644
index 000000000000..ad3ff8fbfbbb
--- /dev/null
+++ b/drivers/power/bq24190_charger.c
@@ -0,0 +1,1549 @@
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
342/* On i386 ptrace-abi.h defines SS that breaks the macro calls below. */
343#undef SS
344
345static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
346 /* sysfs name reg field in reg */
347 BQ24190_SYSFS_FIELD_RW(en_hiz, ISC, EN_HIZ),
348 BQ24190_SYSFS_FIELD_RW(vindpm, ISC, VINDPM),
349 BQ24190_SYSFS_FIELD_RW(iinlim, ISC, IINLIM),
350 BQ24190_SYSFS_FIELD_RW(chg_config, POC, CHG_CONFIG),
351 BQ24190_SYSFS_FIELD_RW(sys_min, POC, SYS_MIN),
352 BQ24190_SYSFS_FIELD_RW(boost_lim, POC, BOOST_LIM),
353 BQ24190_SYSFS_FIELD_RW(ichg, CCC, ICHG),
354 BQ24190_SYSFS_FIELD_RW(force_20_pct, CCC, FORCE_20PCT),
355 BQ24190_SYSFS_FIELD_RW(iprechg, PCTCC, IPRECHG),
356 BQ24190_SYSFS_FIELD_RW(iterm, PCTCC, ITERM),
357 BQ24190_SYSFS_FIELD_RW(vreg, CVC, VREG),
358 BQ24190_SYSFS_FIELD_RW(batlowv, CVC, BATLOWV),
359 BQ24190_SYSFS_FIELD_RW(vrechg, CVC, VRECHG),
360 BQ24190_SYSFS_FIELD_RW(en_term, CTTC, EN_TERM),
361 BQ24190_SYSFS_FIELD_RW(term_stat, CTTC, TERM_STAT),
362 BQ24190_SYSFS_FIELD_RO(watchdog, CTTC, WATCHDOG),
363 BQ24190_SYSFS_FIELD_RW(en_timer, CTTC, EN_TIMER),
364 BQ24190_SYSFS_FIELD_RW(chg_timer, CTTC, CHG_TIMER),
365 BQ24190_SYSFS_FIELD_RW(jeta_iset, CTTC, JEITA_ISET),
366 BQ24190_SYSFS_FIELD_RW(bat_comp, ICTRC, BAT_COMP),
367 BQ24190_SYSFS_FIELD_RW(vclamp, ICTRC, VCLAMP),
368 BQ24190_SYSFS_FIELD_RW(treg, ICTRC, TREG),
369 BQ24190_SYSFS_FIELD_RW(dpdm_en, MOC, DPDM_EN),
370 BQ24190_SYSFS_FIELD_RW(tmr2x_en, MOC, TMR2X_EN),
371 BQ24190_SYSFS_FIELD_RW(batfet_disable, MOC, BATFET_DISABLE),
372 BQ24190_SYSFS_FIELD_RW(jeita_vset, MOC, JEITA_VSET),
373 BQ24190_SYSFS_FIELD_RO(int_mask, MOC, INT_MASK),
374 BQ24190_SYSFS_FIELD_RO(vbus_stat, SS, VBUS_STAT),
375 BQ24190_SYSFS_FIELD_RO(chrg_stat, SS, CHRG_STAT),
376 BQ24190_SYSFS_FIELD_RO(dpm_stat, SS, DPM_STAT),
377 BQ24190_SYSFS_FIELD_RO(pg_stat, SS, PG_STAT),
378 BQ24190_SYSFS_FIELD_RO(therm_stat, SS, THERM_STAT),
379 BQ24190_SYSFS_FIELD_RO(vsys_stat, SS, VSYS_STAT),
380 BQ24190_SYSFS_FIELD_RO(watchdog_fault, F, WATCHDOG_FAULT),
381 BQ24190_SYSFS_FIELD_RO(boost_fault, F, BOOST_FAULT),
382 BQ24190_SYSFS_FIELD_RO(chrg_fault, F, CHRG_FAULT),
383 BQ24190_SYSFS_FIELD_RO(bat_fault, F, BAT_FAULT),
384 BQ24190_SYSFS_FIELD_RO(ntc_fault, F, NTC_FAULT),
385 BQ24190_SYSFS_FIELD_RO(pn, VPRS, PN),
386 BQ24190_SYSFS_FIELD_RO(ts_profile, VPRS, TS_PROFILE),
387 BQ24190_SYSFS_FIELD_RO(dev_reg, VPRS, DEV_REG),
388};
389
390static struct attribute *
391 bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
392
393static const struct attribute_group bq24190_sysfs_attr_group = {
394 .attrs = bq24190_sysfs_attrs,
395};
396
397static void bq24190_sysfs_init_attrs(void)
398{
399 int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
400
401 for (i = 0; i < limit; i++)
402 bq24190_sysfs_attrs[i] = &bq24190_sysfs_field_tbl[i].attr.attr;
403
404 bq24190_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
405}
406
407static struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup(
408 const char *name)
409{
410 int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
411
412 for (i = 0; i < limit; i++)
413 if (!strcmp(name, bq24190_sysfs_field_tbl[i].attr.attr.name))
414 break;
415
416 if (i >= limit)
417 return NULL;
418
419 return &bq24190_sysfs_field_tbl[i];
420}
421
422static ssize_t bq24190_sysfs_show(struct device *dev,
423 struct device_attribute *attr, char *buf)
424{
425 struct power_supply *psy = dev_get_drvdata(dev);
426 struct bq24190_dev_info *bdi =
427 container_of(psy, struct bq24190_dev_info, charger);
428 struct bq24190_sysfs_field_info *info;
429 int ret;
430 u8 v;
431
432 info = bq24190_sysfs_field_lookup(attr->attr.name);
433 if (!info)
434 return -EINVAL;
435
436 ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
437 if (ret)
438 return ret;
439
440 return scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
441}
442
443static ssize_t bq24190_sysfs_store(struct device *dev,
444 struct device_attribute *attr, const char *buf, size_t count)
445{
446 struct power_supply *psy = dev_get_drvdata(dev);
447 struct bq24190_dev_info *bdi =
448 container_of(psy, struct bq24190_dev_info, charger);
449 struct bq24190_sysfs_field_info *info;
450 int ret;
451 u8 v;
452
453 info = bq24190_sysfs_field_lookup(attr->attr.name);
454 if (!info)
455 return -EINVAL;
456
457 ret = kstrtou8(buf, 0, &v);
458 if (ret < 0)
459 return ret;
460
461 ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
462 if (ret)
463 return ret;
464
465 return count;
466}
467
468static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
469{
470 bq24190_sysfs_init_attrs();
471
472 return sysfs_create_group(&bdi->charger.dev->kobj,
473 &bq24190_sysfs_attr_group);
474}
475
476static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
477{
478 sysfs_remove_group(&bdi->charger.dev->kobj, &bq24190_sysfs_attr_group);
479}
480#else
481static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
482{
483 return 0;
484}
485
486static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
487#endif
488
489/*
490 * According to the "Host Mode and default Mode" section of the
491 * manual, a write to any register causes the bq24190 to switch
492 * from default mode to host mode. It will switch back to default
493 * mode after a WDT timeout unless the WDT is turned off as well.
494 * So, by simply turning off the WDT, we accomplish both with the
495 * same write.
496 */
497static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
498{
499 int ret;
500 u8 v;
501
502 ret = bq24190_read(bdi, BQ24190_REG_CTTC, &v);
503 if (ret < 0)
504 return ret;
505
506 bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >>
507 BQ24190_REG_CTTC_WATCHDOG_SHIFT);
508 v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
509
510 return bq24190_write(bdi, BQ24190_REG_CTTC, v);
511}
512
513static int bq24190_register_reset(struct bq24190_dev_info *bdi)
514{
515 int ret, limit = 100;
516 u8 v;
517
518 /* Reset the registers */
519 ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
520 BQ24190_REG_POC_RESET_MASK,
521 BQ24190_REG_POC_RESET_SHIFT,
522 0x1);
523 if (ret < 0)
524 return ret;
525
526 /* Reset bit will be cleared by hardware so poll until it is */
527 do {
528 ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
529 BQ24190_REG_POC_RESET_MASK,
530 BQ24190_REG_POC_RESET_SHIFT,
531 &v);
532 if (ret < 0)
533 return ret;
534
535 if (!v)
536 break;
537
538 udelay(10);
539 } while (--limit);
540
541 if (!limit)
542 return -EIO;
543
544 return 0;
545}
546
547/* Charger power supply property routines */
548
549static int bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi,
550 union power_supply_propval *val)
551{
552 u8 v;
553 int type, ret;
554
555 ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
556 BQ24190_REG_POC_CHG_CONFIG_MASK,
557 BQ24190_REG_POC_CHG_CONFIG_SHIFT,
558 &v);
559 if (ret < 0)
560 return ret;
561
562 /* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */
563 if (!v) {
564 type = POWER_SUPPLY_CHARGE_TYPE_NONE;
565 } else {
566 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
567 BQ24190_REG_CCC_FORCE_20PCT_MASK,
568 BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
569 &v);
570 if (ret < 0)
571 return ret;
572
573 type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE :
574 POWER_SUPPLY_CHARGE_TYPE_FAST;
575 }
576
577 val->intval = type;
578
579 return 0;
580}
581
582static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
583 const union power_supply_propval *val)
584{
585 u8 chg_config, force_20pct, en_term;
586 int ret;
587
588 /*
589 * According to the "Termination when REG02[0] = 1" section of
590 * the bq24190 manual, the trickle charge could be less than the
591 * termination current so it recommends turning off the termination
592 * function.
593 *
594 * Note: AFAICT from the datasheet, the user will have to manually
595 * turn off the charging when in 20% mode. If its not turned off,
596 * there could be battery damage. So, use this mode at your own risk.
597 */
598 switch (val->intval) {
599 case POWER_SUPPLY_CHARGE_TYPE_NONE:
600 chg_config = 0x0;
601 break;
602 case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
603 chg_config = 0x1;
604 force_20pct = 0x1;
605 en_term = 0x0;
606 break;
607 case POWER_SUPPLY_CHARGE_TYPE_FAST:
608 chg_config = 0x1;
609 force_20pct = 0x0;
610 en_term = 0x1;
611 break;
612 default:
613 return -EINVAL;
614 }
615
616 if (chg_config) { /* Enabling the charger */
617 ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
618 BQ24190_REG_CCC_FORCE_20PCT_MASK,
619 BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
620 force_20pct);
621 if (ret < 0)
622 return ret;
623
624 ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC,
625 BQ24190_REG_CTTC_EN_TERM_MASK,
626 BQ24190_REG_CTTC_EN_TERM_SHIFT,
627 en_term);
628 if (ret < 0)
629 return ret;
630 }
631
632 return bq24190_write_mask(bdi, BQ24190_REG_POC,
633 BQ24190_REG_POC_CHG_CONFIG_MASK,
634 BQ24190_REG_POC_CHG_CONFIG_SHIFT, chg_config);
635}
636
637static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
638 union power_supply_propval *val)
639{
640 u8 v;
641 int health, ret;
642
643 mutex_lock(&bdi->f_reg_lock);
644
645 if (bdi->charger_health_valid) {
646 v = bdi->f_reg;
647 bdi->charger_health_valid = false;
648 mutex_unlock(&bdi->f_reg_lock);
649 } else {
650 mutex_unlock(&bdi->f_reg_lock);
651
652 ret = bq24190_read(bdi, BQ24190_REG_F, &v);
653 if (ret < 0)
654 return ret;
655 }
656
657 if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
658 /*
659 * This could be over-current or over-voltage but there's
660 * no way to tell which. Return 'OVERVOLTAGE' since there
661 * isn't an 'OVERCURRENT' value defined that we can return
662 * even if it was over-current.
663 */
664 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
665 } else {
666 v &= BQ24190_REG_F_CHRG_FAULT_MASK;
667 v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
668
669 switch (v) {
670 case 0x0: /* Normal */
671 health = POWER_SUPPLY_HEALTH_GOOD;
672 break;
673 case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
674 /*
675 * This could be over-voltage or under-voltage
676 * and there's no way to tell which. Instead
677 * of looking foolish and returning 'OVERVOLTAGE'
678 * when its really under-voltage, just return
679 * 'UNSPEC_FAILURE'.
680 */
681 health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
682 break;
683 case 0x2: /* Thermal Shutdown */
684 health = POWER_SUPPLY_HEALTH_OVERHEAT;
685 break;
686 case 0x3: /* Charge Safety Timer Expiration */
687 health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
688 break;
689 default:
690 health = POWER_SUPPLY_HEALTH_UNKNOWN;
691 }
692 }
693
694 val->intval = health;
695
696 return 0;
697}
698
699static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
700 union power_supply_propval *val)
701{
702 u8 v;
703 int ret;
704
705 ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
706 BQ24190_REG_SS_PG_STAT_MASK,
707 BQ24190_REG_SS_PG_STAT_SHIFT, &v);
708 if (ret < 0)
709 return ret;
710
711 val->intval = v;
712 return 0;
713}
714
715static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
716 union power_supply_propval *val)
717{
718 u8 v;
719 int curr, ret;
720
721 ret = bq24190_get_field_val(bdi, BQ24190_REG_CCC,
722 BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
723 bq24190_ccc_ichg_values,
724 ARRAY_SIZE(bq24190_ccc_ichg_values), &curr);
725 if (ret < 0)
726 return ret;
727
728 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
729 BQ24190_REG_CCC_FORCE_20PCT_MASK,
730 BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
731 if (ret < 0)
732 return ret;
733
734 /* If FORCE_20PCT is enabled, then current is 20% of ICHG value */
735 if (v)
736 curr /= 5;
737
738 val->intval = curr;
739 return 0;
740}
741
742static int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi,
743 union power_supply_propval *val)
744{
745 int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
746
747 val->intval = bq24190_ccc_ichg_values[idx];
748 return 0;
749}
750
751static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
752 const union power_supply_propval *val)
753{
754 u8 v;
755 int ret, curr = val->intval;
756
757 ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
758 BQ24190_REG_CCC_FORCE_20PCT_MASK,
759 BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
760 if (ret < 0)
761 return ret;
762
763 /* If FORCE_20PCT is enabled, have to multiply value passed in by 5 */
764 if (v)
765 curr *= 5;
766
767 return bq24190_set_field_val(bdi, BQ24190_REG_CCC,
768 BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
769 bq24190_ccc_ichg_values,
770 ARRAY_SIZE(bq24190_ccc_ichg_values), curr);
771}
772
773static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
774 union power_supply_propval *val)
775{
776 int voltage, ret;
777
778 ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC,
779 BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
780 bq24190_cvc_vreg_values,
781 ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage);
782 if (ret < 0)
783 return ret;
784
785 val->intval = voltage;
786 return 0;
787}
788
789static int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi,
790 union power_supply_propval *val)
791{
792 int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
793
794 val->intval = bq24190_cvc_vreg_values[idx];
795 return 0;
796}
797
798static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
799 const union power_supply_propval *val)
800{
801 return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
802 BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
803 bq24190_cvc_vreg_values,
804 ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
805}
806
807static int bq24190_charger_get_property(struct power_supply *psy,
808 enum power_supply_property psp, union power_supply_propval *val)
809{
810 struct bq24190_dev_info *bdi =
811 container_of(psy, struct bq24190_dev_info, charger);
812 int ret;
813
814 dev_dbg(bdi->dev, "prop: %d\n", psp);
815
816 pm_runtime_get_sync(bdi->dev);
817
818 switch (psp) {
819 case POWER_SUPPLY_PROP_CHARGE_TYPE:
820 ret = bq24190_charger_get_charge_type(bdi, val);
821 break;
822 case POWER_SUPPLY_PROP_HEALTH:
823 ret = bq24190_charger_get_health(bdi, val);
824 break;
825 case POWER_SUPPLY_PROP_ONLINE:
826 ret = bq24190_charger_get_online(bdi, val);
827 break;
828 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
829 ret = bq24190_charger_get_current(bdi, val);
830 break;
831 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
832 ret = bq24190_charger_get_current_max(bdi, val);
833 break;
834 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
835 ret = bq24190_charger_get_voltage(bdi, val);
836 break;
837 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
838 ret = bq24190_charger_get_voltage_max(bdi, val);
839 break;
840 case POWER_SUPPLY_PROP_SCOPE:
841 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
842 ret = 0;
843 break;
844 case POWER_SUPPLY_PROP_MODEL_NAME:
845 val->strval = bdi->model_name;
846 ret = 0;
847 break;
848 case POWER_SUPPLY_PROP_MANUFACTURER:
849 val->strval = BQ24190_MANUFACTURER;
850 ret = 0;
851 break;
852 default:
853 ret = -ENODATA;
854 }
855
856 pm_runtime_put_sync(bdi->dev);
857 return ret;
858}
859
860static int bq24190_charger_set_property(struct power_supply *psy,
861 enum power_supply_property psp,
862 const union power_supply_propval *val)
863{
864 struct bq24190_dev_info *bdi =
865 container_of(psy, struct bq24190_dev_info, charger);
866 int ret;
867
868 dev_dbg(bdi->dev, "prop: %d\n", psp);
869
870 pm_runtime_get_sync(bdi->dev);
871
872 switch (psp) {
873 case POWER_SUPPLY_PROP_CHARGE_TYPE:
874 ret = bq24190_charger_set_charge_type(bdi, val);
875 break;
876 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
877 ret = bq24190_charger_set_current(bdi, val);
878 break;
879 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
880 ret = bq24190_charger_set_voltage(bdi, val);
881 break;
882 default:
883 ret = -EINVAL;
884 }
885
886 pm_runtime_put_sync(bdi->dev);
887 return ret;
888}
889
890static int bq24190_charger_property_is_writeable(struct power_supply *psy,
891 enum power_supply_property psp)
892{
893 int ret;
894
895 switch (psp) {
896 case POWER_SUPPLY_PROP_CHARGE_TYPE:
897 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
898 case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
899 ret = 1;
900 break;
901 default:
902 ret = 0;
903 }
904
905 return ret;
906}
907
908static enum power_supply_property bq24190_charger_properties[] = {
909 POWER_SUPPLY_PROP_TYPE,
910 POWER_SUPPLY_PROP_HEALTH,
911 POWER_SUPPLY_PROP_ONLINE,
912 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
913 POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
914 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
915 POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
916 POWER_SUPPLY_PROP_SCOPE,
917 POWER_SUPPLY_PROP_MODEL_NAME,
918 POWER_SUPPLY_PROP_MANUFACTURER,
919};
920
921static char *bq24190_charger_supplied_to[] = {
922 "main-battery",
923};
924
925static void bq24190_charger_init(struct power_supply *charger)
926{
927 charger->name = "bq24190-charger";
928 charger->type = POWER_SUPPLY_TYPE_USB;
929 charger->properties = bq24190_charger_properties;
930 charger->num_properties = ARRAY_SIZE(bq24190_charger_properties);
931 charger->supplied_to = bq24190_charger_supplied_to;
932 charger->num_supplies = ARRAY_SIZE(bq24190_charger_supplied_to);
933 charger->get_property = bq24190_charger_get_property;
934 charger->set_property = bq24190_charger_set_property;
935 charger->property_is_writeable = bq24190_charger_property_is_writeable;
936}
937
938/* Battery power supply property routines */
939
940static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
941 union power_supply_propval *val)
942{
943 u8 ss_reg, chrg_fault;
944 int status, ret;
945
946 mutex_lock(&bdi->f_reg_lock);
947
948 if (bdi->battery_status_valid) {
949 chrg_fault = bdi->f_reg;
950 bdi->battery_status_valid = false;
951 mutex_unlock(&bdi->f_reg_lock);
952 } else {
953 mutex_unlock(&bdi->f_reg_lock);
954
955 ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
956 if (ret < 0)
957 return ret;
958 }
959
960 chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
961 chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
962
963 ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
964 if (ret < 0)
965 return ret;
966
967 /*
968 * The battery must be discharging when any of these are true:
969 * - there is no good power source;
970 * - there is a charge fault.
971 * Could also be discharging when in "supplement mode" but
972 * there is no way to tell when its in that mode.
973 */
974 if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) {
975 status = POWER_SUPPLY_STATUS_DISCHARGING;
976 } else {
977 ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK;
978 ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT;
979
980 switch (ss_reg) {
981 case 0x0: /* Not Charging */
982 status = POWER_SUPPLY_STATUS_NOT_CHARGING;
983 break;
984 case 0x1: /* Pre-charge */
985 case 0x2: /* Fast Charging */
986 status = POWER_SUPPLY_STATUS_CHARGING;
987 break;
988 case 0x3: /* Charge Termination Done */
989 status = POWER_SUPPLY_STATUS_FULL;
990 break;
991 default:
992 ret = -EIO;
993 }
994 }
995
996 if (!ret)
997 val->intval = status;
998
999 return ret;
1000}
1001
1002static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
1003 union power_supply_propval *val)
1004{
1005 u8 v;
1006 int health, ret;
1007
1008 mutex_lock(&bdi->f_reg_lock);
1009
1010 if (bdi->battery_health_valid) {
1011 v = bdi->f_reg;
1012 bdi->battery_health_valid = false;
1013 mutex_unlock(&bdi->f_reg_lock);
1014 } else {
1015 mutex_unlock(&bdi->f_reg_lock);
1016
1017 ret = bq24190_read(bdi, BQ24190_REG_F, &v);
1018 if (ret < 0)
1019 return ret;
1020 }
1021
1022 if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
1023 health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
1024 } else {
1025 v &= BQ24190_REG_F_NTC_FAULT_MASK;
1026 v >>= BQ24190_REG_F_NTC_FAULT_SHIFT;
1027
1028 switch (v) {
1029 case 0x0: /* Normal */
1030 health = POWER_SUPPLY_HEALTH_GOOD;
1031 break;
1032 case 0x1: /* TS1 Cold */
1033 case 0x3: /* TS2 Cold */
1034 case 0x5: /* Both Cold */
1035 health = POWER_SUPPLY_HEALTH_COLD;
1036 break;
1037 case 0x2: /* TS1 Hot */
1038 case 0x4: /* TS2 Hot */
1039 case 0x6: /* Both Hot */
1040 health = POWER_SUPPLY_HEALTH_OVERHEAT;
1041 break;
1042 default:
1043 health = POWER_SUPPLY_HEALTH_UNKNOWN;
1044 }
1045 }
1046
1047 val->intval = health;
1048 return 0;
1049}
1050
1051static int bq24190_battery_get_online(struct bq24190_dev_info *bdi,
1052 union power_supply_propval *val)
1053{
1054 u8 batfet_disable;
1055 int ret;
1056
1057 ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
1058 BQ24190_REG_MOC_BATFET_DISABLE_MASK,
1059 BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
1060 if (ret < 0)
1061 return ret;
1062
1063 val->intval = !batfet_disable;
1064 return 0;
1065}
1066
1067static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
1068 const union power_supply_propval *val)
1069{
1070 return bq24190_write_mask(bdi, BQ24190_REG_MOC,
1071 BQ24190_REG_MOC_BATFET_DISABLE_MASK,
1072 BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, !val->intval);
1073}
1074
1075static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
1076 union power_supply_propval *val)
1077{
1078 int temp, ret;
1079
1080 ret = bq24190_get_field_val(bdi, BQ24190_REG_ICTRC,
1081 BQ24190_REG_ICTRC_TREG_MASK,
1082 BQ24190_REG_ICTRC_TREG_SHIFT,
1083 bq24190_ictrc_treg_values,
1084 ARRAY_SIZE(bq24190_ictrc_treg_values), &temp);
1085 if (ret < 0)
1086 return ret;
1087
1088 val->intval = temp;
1089 return 0;
1090}
1091
1092static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
1093 const union power_supply_propval *val)
1094{
1095 return bq24190_set_field_val(bdi, BQ24190_REG_ICTRC,
1096 BQ24190_REG_ICTRC_TREG_MASK,
1097 BQ24190_REG_ICTRC_TREG_SHIFT,
1098 bq24190_ictrc_treg_values,
1099 ARRAY_SIZE(bq24190_ictrc_treg_values), val->intval);
1100}
1101
1102static int bq24190_battery_get_property(struct power_supply *psy,
1103 enum power_supply_property psp, union power_supply_propval *val)
1104{
1105 struct bq24190_dev_info *bdi =
1106 container_of(psy, struct bq24190_dev_info, battery);
1107 int ret;
1108
1109 dev_dbg(bdi->dev, "prop: %d\n", psp);
1110
1111 pm_runtime_get_sync(bdi->dev);
1112
1113 switch (psp) {
1114 case POWER_SUPPLY_PROP_STATUS:
1115 ret = bq24190_battery_get_status(bdi, val);
1116 break;
1117 case POWER_SUPPLY_PROP_HEALTH:
1118 ret = bq24190_battery_get_health(bdi, val);
1119 break;
1120 case POWER_SUPPLY_PROP_ONLINE:
1121 ret = bq24190_battery_get_online(bdi, val);
1122 break;
1123 case POWER_SUPPLY_PROP_TECHNOLOGY:
1124 /* Could be Li-on or Li-polymer but no way to tell which */
1125 val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
1126 ret = 0;
1127 break;
1128 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1129 ret = bq24190_battery_get_temp_alert_max(bdi, val);
1130 break;
1131 case POWER_SUPPLY_PROP_SCOPE:
1132 val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
1133 ret = 0;
1134 break;
1135 default:
1136 ret = -ENODATA;
1137 }
1138
1139 pm_runtime_put_sync(bdi->dev);
1140 return ret;
1141}
1142
1143static int bq24190_battery_set_property(struct power_supply *psy,
1144 enum power_supply_property psp,
1145 const union power_supply_propval *val)
1146{
1147 struct bq24190_dev_info *bdi =
1148 container_of(psy, struct bq24190_dev_info, battery);
1149 int ret;
1150
1151 dev_dbg(bdi->dev, "prop: %d\n", psp);
1152
1153 pm_runtime_put_sync(bdi->dev);
1154
1155 switch (psp) {
1156 case POWER_SUPPLY_PROP_ONLINE:
1157 ret = bq24190_battery_set_online(bdi, val);
1158 break;
1159 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1160 ret = bq24190_battery_set_temp_alert_max(bdi, val);
1161 break;
1162 default:
1163 ret = -EINVAL;
1164 }
1165
1166 pm_runtime_put_sync(bdi->dev);
1167 return ret;
1168}
1169
1170static int bq24190_battery_property_is_writeable(struct power_supply *psy,
1171 enum power_supply_property psp)
1172{
1173 int ret;
1174
1175 switch (psp) {
1176 case POWER_SUPPLY_PROP_ONLINE:
1177 case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
1178 ret = 1;
1179 break;
1180 default:
1181 ret = 0;
1182 }
1183
1184 return ret;
1185}
1186
1187static enum power_supply_property bq24190_battery_properties[] = {
1188 POWER_SUPPLY_PROP_STATUS,
1189 POWER_SUPPLY_PROP_HEALTH,
1190 POWER_SUPPLY_PROP_ONLINE,
1191 POWER_SUPPLY_PROP_TECHNOLOGY,
1192 POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
1193 POWER_SUPPLY_PROP_SCOPE,
1194};
1195
1196static void bq24190_battery_init(struct power_supply *battery)
1197{
1198 battery->name = "bq24190-battery";
1199 battery->type = POWER_SUPPLY_TYPE_BATTERY;
1200 battery->properties = bq24190_battery_properties;
1201 battery->num_properties = ARRAY_SIZE(bq24190_battery_properties);
1202 battery->get_property = bq24190_battery_get_property;
1203 battery->set_property = bq24190_battery_set_property;
1204 battery->property_is_writeable = bq24190_battery_property_is_writeable;
1205}
1206
1207static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
1208{
1209 struct bq24190_dev_info *bdi = data;
1210 bool alert_userspace = false;
1211 u8 ss_reg, f_reg;
1212 int ret;
1213
1214 pm_runtime_get_sync(bdi->dev);
1215
1216 ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
1217 if (ret < 0) {
1218 dev_err(bdi->dev, "Can't read SS reg: %d\n", ret);
1219 goto out;
1220 }
1221
1222 if (ss_reg != bdi->ss_reg) {
1223 /*
1224 * The device is in host mode so when PG_STAT goes from 1->0
1225 * (i.e., power removed) HIZ needs to be disabled.
1226 */
1227 if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) &&
1228 !(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) {
1229 ret = bq24190_write_mask(bdi, BQ24190_REG_ISC,
1230 BQ24190_REG_ISC_EN_HIZ_MASK,
1231 BQ24190_REG_ISC_EN_HIZ_SHIFT,
1232 0);
1233 if (ret < 0)
1234 dev_err(bdi->dev, "Can't access ISC reg: %d\n",
1235 ret);
1236 }
1237
1238 bdi->ss_reg = ss_reg;
1239 alert_userspace = true;
1240 }
1241
1242 mutex_lock(&bdi->f_reg_lock);
1243
1244 ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
1245 if (ret < 0) {
1246 mutex_unlock(&bdi->f_reg_lock);
1247 dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
1248 goto out;
1249 }
1250
1251 if (f_reg != bdi->f_reg) {
1252 bdi->f_reg = f_reg;
1253 bdi->charger_health_valid = true;
1254 bdi->battery_health_valid = true;
1255 bdi->battery_status_valid = true;
1256
1257 alert_userspace = true;
1258 }
1259
1260 mutex_unlock(&bdi->f_reg_lock);
1261
1262 /*
1263 * Sometimes bq24190 gives a steady trickle of interrupts even
1264 * though the watchdog timer is turned off and neither the STATUS
1265 * nor FAULT registers have changed. Weed out these sprurious
1266 * interrupts so userspace isn't alerted for no reason.
1267 * In addition, the chip always generates an interrupt after
1268 * register reset so we should ignore that one (the very first
1269 * interrupt received).
1270 */
1271 if (alert_userspace && !bdi->first_time) {
1272 power_supply_changed(&bdi->charger);
1273 power_supply_changed(&bdi->battery);
1274 bdi->first_time = false;
1275 }
1276
1277out:
1278 pm_runtime_put_sync(bdi->dev);
1279
1280 dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
1281
1282 return IRQ_HANDLED;
1283}
1284
1285static int bq24190_hw_init(struct bq24190_dev_info *bdi)
1286{
1287 u8 v;
1288 int ret;
1289
1290 pm_runtime_get_sync(bdi->dev);
1291
1292 /* First check that the device really is what its supposed to be */
1293 ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS,
1294 BQ24190_REG_VPRS_PN_MASK,
1295 BQ24190_REG_VPRS_PN_SHIFT,
1296 &v);
1297 if (ret < 0)
1298 goto out;
1299
1300 if (v != bdi->model) {
1301 ret = -ENODEV;
1302 goto out;
1303 }
1304
1305 ret = bq24190_register_reset(bdi);
1306 if (ret < 0)
1307 goto out;
1308
1309 ret = bq24190_set_mode_host(bdi);
1310out:
1311 pm_runtime_put_sync(bdi->dev);
1312 return ret;
1313}
1314
1315#ifdef CONFIG_OF
1316static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
1317{
1318 bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
1319 if (bdi->irq <= 0)
1320 return -1;
1321
1322 return 0;
1323}
1324#else
1325static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
1326{
1327 return -1;
1328}
1329#endif
1330
1331static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
1332 struct bq24190_platform_data *pdata)
1333{
1334 int ret;
1335
1336 if (!gpio_is_valid(pdata->gpio_int))
1337 return -1;
1338
1339 ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
1340 if (ret < 0)
1341 return -1;
1342
1343 ret = gpio_direction_input(pdata->gpio_int);
1344 if (ret < 0)
1345 goto out;
1346
1347 bdi->irq = gpio_to_irq(pdata->gpio_int);
1348 if (!bdi->irq)
1349 goto out;
1350
1351 bdi->gpio_int = pdata->gpio_int;
1352 return 0;
1353
1354out:
1355 gpio_free(pdata->gpio_int);
1356 return -1;
1357}
1358
1359static int bq24190_probe(struct i2c_client *client,
1360 const struct i2c_device_id *id)
1361{
1362 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
1363 struct device *dev = &client->dev;
1364 struct bq24190_platform_data *pdata = client->dev.platform_data;
1365 struct bq24190_dev_info *bdi;
1366 int ret;
1367
1368 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
1369 dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
1370 return -ENODEV;
1371 }
1372
1373 bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
1374 if (!bdi) {
1375 dev_err(dev, "Can't alloc bdi struct\n");
1376 return -ENOMEM;
1377 }
1378
1379 bdi->client = client;
1380 bdi->dev = dev;
1381 bdi->model = id->driver_data;
1382 strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
1383 mutex_init(&bdi->f_reg_lock);
1384 bdi->first_time = true;
1385 bdi->charger_health_valid = false;
1386 bdi->battery_health_valid = false;
1387 bdi->battery_status_valid = false;
1388
1389 i2c_set_clientdata(client, bdi);
1390
1391 if (dev->of_node)
1392 ret = bq24190_setup_dt(bdi);
1393 else
1394 ret = bq24190_setup_pdata(bdi, pdata);
1395
1396 if (ret) {
1397 dev_err(dev, "Can't get irq info\n");
1398 return -EINVAL;
1399 }
1400
1401 ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
1402 bq24190_irq_handler_thread,
1403 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1404 "bq24190-charger", bdi);
1405 if (ret < 0) {
1406 dev_err(dev, "Can't set up irq handler\n");
1407 goto out1;
1408 }
1409
1410 pm_runtime_enable(dev);
1411 pm_runtime_resume(dev);
1412
1413 ret = bq24190_hw_init(bdi);
1414 if (ret < 0) {
1415 dev_err(dev, "Hardware init failed\n");
1416 goto out2;
1417 }
1418
1419 bq24190_charger_init(&bdi->charger);
1420
1421 ret = power_supply_register(dev, &bdi->charger);
1422 if (ret) {
1423 dev_err(dev, "Can't register charger\n");
1424 goto out2;
1425 }
1426
1427 bq24190_battery_init(&bdi->battery);
1428
1429 ret = power_supply_register(dev, &bdi->battery);
1430 if (ret) {
1431 dev_err(dev, "Can't register battery\n");
1432 goto out3;
1433 }
1434
1435 ret = bq24190_sysfs_create_group(bdi);
1436 if (ret) {
1437 dev_err(dev, "Can't create sysfs entries\n");
1438 goto out4;
1439 }
1440
1441 return 0;
1442
1443out4:
1444 power_supply_unregister(&bdi->battery);
1445out3:
1446 power_supply_unregister(&bdi->charger);
1447out2:
1448 pm_runtime_disable(dev);
1449out1:
1450 if (bdi->gpio_int)
1451 gpio_free(bdi->gpio_int);
1452
1453 return ret;
1454}
1455
1456static int bq24190_remove(struct i2c_client *client)
1457{
1458 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1459
1460 pm_runtime_get_sync(bdi->dev);
1461 bq24190_register_reset(bdi);
1462 pm_runtime_put_sync(bdi->dev);
1463
1464 bq24190_sysfs_remove_group(bdi);
1465 power_supply_unregister(&bdi->battery);
1466 power_supply_unregister(&bdi->charger);
1467 pm_runtime_disable(bdi->dev);
1468
1469 if (bdi->gpio_int)
1470 gpio_free(bdi->gpio_int);
1471
1472 return 0;
1473}
1474
1475#ifdef CONFIG_PM_SLEEP
1476static int bq24190_pm_suspend(struct device *dev)
1477{
1478 struct i2c_client *client = to_i2c_client(dev);
1479 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1480
1481 pm_runtime_get_sync(bdi->dev);
1482 bq24190_register_reset(bdi);
1483 pm_runtime_put_sync(bdi->dev);
1484
1485 return 0;
1486}
1487
1488static int bq24190_pm_resume(struct device *dev)
1489{
1490 struct i2c_client *client = to_i2c_client(dev);
1491 struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
1492
1493 bdi->charger_health_valid = false;
1494 bdi->battery_health_valid = false;
1495 bdi->battery_status_valid = false;
1496
1497 pm_runtime_get_sync(bdi->dev);
1498 bq24190_register_reset(bdi);
1499 pm_runtime_put_sync(bdi->dev);
1500
1501 /* Things may have changed while suspended so alert upper layer */
1502 power_supply_changed(&bdi->charger);
1503 power_supply_changed(&bdi->battery);
1504
1505 return 0;
1506}
1507#endif
1508
1509static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume);
1510
1511/*
1512 * Only support the bq24190 right now. The bq24192, bq24192i, and bq24193
1513 * are similar but not identical so the driver needs to be extended to
1514 * support them.
1515 */
1516static const struct i2c_device_id bq24190_i2c_ids[] = {
1517 { "bq24190", BQ24190_REG_VPRS_PN_24190 },
1518 { },
1519};
1520
1521#ifdef CONFIG_OF
1522static const struct of_device_id bq24190_of_match[] = {
1523 { .compatible = "ti,bq24190", },
1524 { },
1525};
1526MODULE_DEVICE_TABLE(of, bq24190_of_match);
1527#else
1528static const struct of_device_id bq24190_of_match[] = {
1529 { },
1530};
1531#endif
1532
1533static struct i2c_driver bq24190_driver = {
1534 .probe = bq24190_probe,
1535 .remove = bq24190_remove,
1536 .id_table = bq24190_i2c_ids,
1537 .driver = {
1538 .name = "bq24190-charger",
1539 .owner = THIS_MODULE,
1540 .pm = &bq24190_pm_ops,
1541 .of_match_table = of_match_ptr(bq24190_of_match),
1542 },
1543};
1544module_i2c_driver(bq24190_driver);
1545
1546MODULE_LICENSE("GPL");
1547MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
1548MODULE_ALIAS("i2c:bq24190-charger");
1549MODULE_DESCRIPTION("TI BQ24190 Charger Driver");
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index c58d0e31bdef..d02ae02a7590 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -287,7 +287,7 @@ static struct gpio collie_batt_gpios[] = {
287}; 287};
288 288
289#ifdef CONFIG_PM 289#ifdef CONFIG_PM
290static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state) 290static int collie_bat_suspend(struct ucb1x00_dev *dev)
291{ 291{
292 /* flush all pending status updates */ 292 /* flush all pending status updates */
293 flush_work(&bat_work); 293 flush_work(&bat_work);
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c
index 0ee1e14f76e9..b4513f284bbc 100644
--- a/drivers/power/max8925_power.c
+++ b/drivers/power/max8925_power.c
@@ -458,6 +458,7 @@ max8925_power_dt_init(struct platform_device *pdev)
458 of_property_read_u32(np, "fast-charge", &fast_charge); 458 of_property_read_u32(np, "fast-charge", &fast_charge);
459 of_property_read_u32(np, "no-insert-detect", &no_insert_detect); 459 of_property_read_u32(np, "no-insert-detect", &no_insert_detect);
460 of_property_read_u32(np, "no-temp-support", &no_temp_support); 460 of_property_read_u32(np, "no-temp-support", &no_temp_support);
461 of_node_put(np);
461 462
462 pdata->batt_detect = batt_detect; 463 pdata->batt_detect = batt_detect;
463 pdata->fast_charge = fast_charge; 464 pdata->fast_charge = fast_charge;
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 3b2d5df45e7a..00e667296360 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -67,23 +67,42 @@ static int __power_supply_changed_work(struct device *dev, void *data)
67 67
68static void power_supply_changed_work(struct work_struct *work) 68static void power_supply_changed_work(struct work_struct *work)
69{ 69{
70 unsigned long flags;
70 struct power_supply *psy = container_of(work, struct power_supply, 71 struct power_supply *psy = container_of(work, struct power_supply,
71 changed_work); 72 changed_work);
72 73
73 dev_dbg(psy->dev, "%s\n", __func__); 74 dev_dbg(psy->dev, "%s\n", __func__);
74 75
75 class_for_each_device(power_supply_class, NULL, psy, 76 spin_lock_irqsave(&psy->changed_lock, flags);
76 __power_supply_changed_work); 77 if (psy->changed) {
77 78 psy->changed = false;
78 power_supply_update_leds(psy); 79 spin_unlock_irqrestore(&psy->changed_lock, flags);
79 80 class_for_each_device(power_supply_class, NULL, psy,
80 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE); 81 __power_supply_changed_work);
82 power_supply_update_leds(psy);
83 kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
84 spin_lock_irqsave(&psy->changed_lock, flags);
85 }
86 /*
87 * Dependent power supplies (e.g. battery) may have changed state
88 * as a result of this event, so poll again and hold the
89 * wakeup_source until all events are processed.
90 */
91 if (!psy->changed)
92 pm_relax(psy->dev);
93 spin_unlock_irqrestore(&psy->changed_lock, flags);
81} 94}
82 95
83void power_supply_changed(struct power_supply *psy) 96void power_supply_changed(struct power_supply *psy)
84{ 97{
98 unsigned long flags;
99
85 dev_dbg(psy->dev, "%s\n", __func__); 100 dev_dbg(psy->dev, "%s\n", __func__);
86 101
102 spin_lock_irqsave(&psy->changed_lock, flags);
103 psy->changed = true;
104 pm_stay_awake(psy->dev);
105 spin_unlock_irqrestore(&psy->changed_lock, flags);
87 schedule_work(&psy->changed_work); 106 schedule_work(&psy->changed_work);
88} 107}
89EXPORT_SYMBOL_GPL(power_supply_changed); 108EXPORT_SYMBOL_GPL(power_supply_changed);
@@ -500,6 +519,11 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
500 goto check_supplies_failed; 519 goto check_supplies_failed;
501 } 520 }
502 521
522 spin_lock_init(&psy->changed_lock);
523 rc = device_init_wakeup(dev, true);
524 if (rc)
525 goto wakeup_init_failed;
526
503 rc = kobject_set_name(&dev->kobj, "%s", psy->name); 527 rc = kobject_set_name(&dev->kobj, "%s", psy->name);
504 if (rc) 528 if (rc)
505 goto kobject_set_name_failed; 529 goto kobject_set_name_failed;
@@ -529,6 +553,7 @@ create_triggers_failed:
529register_cooler_failed: 553register_cooler_failed:
530 psy_unregister_thermal(psy); 554 psy_unregister_thermal(psy);
531register_thermal_failed: 555register_thermal_failed:
556wakeup_init_failed:
532 device_del(dev); 557 device_del(dev);
533kobject_set_name_failed: 558kobject_set_name_failed:
534device_add_failed: 559device_add_failed:
@@ -546,6 +571,7 @@ void power_supply_unregister(struct power_supply *psy)
546 power_supply_remove_triggers(psy); 571 power_supply_remove_triggers(psy);
547 psy_unregister_cooler(psy); 572 psy_unregister_cooler(psy);
548 psy_unregister_thermal(psy); 573 psy_unregister_thermal(psy);
574 device_init_wakeup(psy->dev, false);
549 device_unregister(psy->dev); 575 device_unregister(psy->dev);
550} 576}
551EXPORT_SYMBOL_GPL(power_supply_unregister); 577EXPORT_SYMBOL_GPL(power_supply_unregister);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 29178f78d73c..44420d1e9094 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -118,7 +118,7 @@ static ssize_t power_supply_store_property(struct device *dev,
118 long long_val; 118 long long_val;
119 119
120 /* TODO: support other types than int */ 120 /* TODO: support other types than int */
121 ret = strict_strtol(buf, 10, &long_val); 121 ret = kstrtol(buf, 10, &long_val);
122 if (ret < 0) 122 if (ret < 0)
123 return ret; 123 return ret;
124 124
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index ee039dcead04..9b3ea535b472 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -14,6 +14,12 @@ config POWER_RESET_GPIO
14 If your board needs a GPIO high/low to power down, say Y and 14 If your board needs a GPIO high/low to power down, say Y and
15 create a binding in your devicetree. 15 create a binding in your devicetree.
16 16
17config POWER_RESET_MSM
18 bool "Qualcomm MSM power-off driver"
19 depends on POWER_RESET && ARCH_MSM
20 help
21 Power off and restart support for Qualcomm boards.
22
17config POWER_RESET_QNAP 23config POWER_RESET_QNAP
18 bool "QNAP power-off driver" 24 bool "QNAP power-off driver"
19 depends on OF_GPIO && POWER_RESET && PLAT_ORION 25 depends on OF_GPIO && POWER_RESET && PLAT_ORION
@@ -34,7 +40,14 @@ config POWER_RESET_RESTART
34config POWER_RESET_VEXPRESS 40config POWER_RESET_VEXPRESS
35 bool "ARM Versatile Express power-off and reset driver" 41 bool "ARM Versatile Express power-off and reset driver"
36 depends on ARM || ARM64 42 depends on ARM || ARM64
37 depends on POWER_RESET 43 depends on POWER_RESET && VEXPRESS_CONFIG
38 help 44 help
39 Power off and reset support for the ARM Ltd. Versatile 45 Power off and reset support for the ARM Ltd. Versatile
40 Express boards. 46 Express boards.
47
48config POWER_RESET_XGENE
49 bool "APM SoC X-Gene reset driver"
50 depends on ARM64
51 depends on POWER_RESET
52 help
53 Reboot support for the APM SoC X-Gene Eval boards.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 372807fd83f7..3e6ed88725ac 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1,4 +1,6 @@
1obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o 1obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
2obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
2obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o 3obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
3obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o 4obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
4obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o 5obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
6obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c
new file mode 100644
index 000000000000..774f9a3b310d
--- /dev/null
+++ b/drivers/power/reset/msm-poweroff.c
@@ -0,0 +1,73 @@
1/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#include <linux/delay.h>
15#include <linux/err.h>
16#include <linux/init.h>
17#include <linux/kernel.h>
18#include <linux/io.h>
19#include <linux/of.h>
20#include <linux/platform_device.h>
21#include <linux/module.h>
22#include <linux/reboot.h>
23
24#include <asm/system_misc.h>
25
26static void __iomem *msm_ps_hold;
27
28static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
29{
30 writel(0, msm_ps_hold);
31 mdelay(10000);
32}
33
34static void do_msm_poweroff(void)
35{
36 /* TODO: Add poweroff capability */
37 do_msm_restart(REBOOT_HARD, NULL);
38}
39
40static int msm_restart_probe(struct platform_device *pdev)
41{
42 struct device *dev = &pdev->dev;
43 struct resource *mem;
44
45 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
46 msm_ps_hold = devm_ioremap_resource(dev, mem);
47 if (IS_ERR(msm_ps_hold))
48 return PTR_ERR(msm_ps_hold);
49
50 pm_power_off = do_msm_poweroff;
51 arm_pm_restart = do_msm_restart;
52 return 0;
53}
54
55static const struct of_device_id of_msm_restart_match[] = {
56 { .compatible = "qcom,pshold", },
57 {},
58};
59MODULE_DEVICE_TABLE(of, of_msm_restart_match);
60
61static struct platform_driver msm_restart_driver = {
62 .probe = msm_restart_probe,
63 .driver = {
64 .name = "msm-restart",
65 .of_match_table = of_match_ptr(of_msm_restart_match),
66 },
67};
68
69static int __init msm_restart_init(void)
70{
71 return platform_driver_register(&msm_restart_driver);
72}
73device_initcall(msm_restart_init);
diff --git a/drivers/power/reset/xgene-reboot.c b/drivers/power/reset/xgene-reboot.c
new file mode 100644
index 000000000000..ecd55f81b9d1
--- /dev/null
+++ b/drivers/power/reset/xgene-reboot.c
@@ -0,0 +1,103 @@
1/*
2 * AppliedMicro X-Gene SoC Reboot Driver
3 *
4 * Copyright (c) 2013, Applied Micro Circuits Corporation
5 * Author: Feng Kan <fkan@apm.com>
6 * Author: Loc Ho <lho@apm.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of
11 * the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21 * MA 02111-1307 USA
22 *
23 * This driver provides system reboot functionality for APM X-Gene SoC.
24 * For system shutdown, this is board specify. If a board designer
25 * implements GPIO shutdown, use the gpio-poweroff.c driver.
26 */
27#include <linux/io.h>
28#include <linux/of_device.h>
29#include <linux/of_address.h>
30#include <linux/platform_device.h>
31#include <linux/stat.h>
32#include <linux/slab.h>
33#include <asm/system_misc.h>
34
35struct xgene_reboot_context {
36 struct platform_device *pdev;
37 void *csr;
38 u32 mask;
39};
40
41static struct xgene_reboot_context *xgene_restart_ctx;
42
43static void xgene_restart(char str, const char *cmd)
44{
45 struct xgene_reboot_context *ctx = xgene_restart_ctx;
46 unsigned long timeout;
47
48 /* Issue the reboot */
49 if (ctx)
50 writel(ctx->mask, ctx->csr);
51
52 timeout = jiffies + HZ;
53 while (time_before(jiffies, timeout))
54 cpu_relax();
55
56 dev_emerg(&ctx->pdev->dev, "Unable to restart system\n");
57}
58
59static int xgene_reboot_probe(struct platform_device *pdev)
60{
61 struct xgene_reboot_context *ctx;
62
63 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
64 if (!ctx) {
65 dev_err(&pdev->dev, "out of memory for context\n");
66 return -ENODEV;
67 }
68
69 ctx->csr = of_iomap(pdev->dev.of_node, 0);
70 if (!ctx->csr) {
71 devm_kfree(&pdev->dev, ctx);
72 dev_err(&pdev->dev, "can not map resource\n");
73 return -ENODEV;
74 }
75
76 if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask))
77 ctx->mask = 0xFFFFFFFF;
78
79 ctx->pdev = pdev;
80 arm_pm_restart = xgene_restart;
81 xgene_restart_ctx = ctx;
82
83 return 0;
84}
85
86static struct of_device_id xgene_reboot_of_match[] = {
87 { .compatible = "apm,xgene-reboot" },
88 {}
89};
90
91static struct platform_driver xgene_reboot_driver = {
92 .probe = xgene_reboot_probe,
93 .driver = {
94 .name = "xgene-reboot",
95 .of_match_table = xgene_reboot_of_match,
96 },
97};
98
99static int __init xgene_reboot_init(void)
100{
101 return platform_driver_register(&xgene_reboot_driver);
102}
103device_initcall(xgene_reboot_init);
diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c
index 8a6288d87056..1bc5857b8bd5 100644
--- a/drivers/power/rx51_battery.c
+++ b/drivers/power/rx51_battery.c
@@ -25,6 +25,10 @@
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/i2c/twl4030-madc.h> 26#include <linux/i2c/twl4030-madc.h>
27 27
28/* RX51 specific channels */
29#define TWL4030_MADC_BTEMP_RX51 TWL4030_MADC_ADCIN0
30#define TWL4030_MADC_BCI_RX51 TWL4030_MADC_ADCIN4
31
28struct rx51_device_info { 32struct rx51_device_info {
29 struct device *dev; 33 struct device *dev;
30 struct power_supply bat; 34 struct power_supply bat;
@@ -37,7 +41,7 @@ static int rx51_battery_read_adc(int channel)
37{ 41{
38 struct twl4030_madc_request req; 42 struct twl4030_madc_request req;
39 43
40 req.channels = 1 << channel; 44 req.channels = channel;
41 req.do_avg = 1; 45 req.do_avg = 1;
42 req.method = TWL4030_MADC_SW1; 46 req.method = TWL4030_MADC_SW1;
43 req.func_cb = NULL; 47 req.func_cb = NULL;
@@ -47,7 +51,7 @@ static int rx51_battery_read_adc(int channel)
47 if (twl4030_madc_conversion(&req) <= 0) 51 if (twl4030_madc_conversion(&req) <= 0)
48 return -ENODATA; 52 return -ENODATA;
49 53
50 return req.rbuf[channel]; 54 return req.rbuf[ffs(channel) - 1];
51} 55}
52 56
53/* 57/*
@@ -56,7 +60,7 @@ static int rx51_battery_read_adc(int channel)
56 */ 60 */
57static int rx51_battery_read_voltage(struct rx51_device_info *di) 61static int rx51_battery_read_voltage(struct rx51_device_info *di)
58{ 62{
59 int voltage = rx51_battery_read_adc(12); 63 int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
60 64
61 if (voltage < 0) 65 if (voltage < 0)
62 return voltage; 66 return voltage;
@@ -108,7 +112,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
108{ 112{
109 int min = 0; 113 int min = 0;
110 int max = ARRAY_SIZE(rx51_temp_table2) - 1; 114 int max = ARRAY_SIZE(rx51_temp_table2) - 1;
111 int raw = rx51_battery_read_adc(0); 115 int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
112 116
113 /* Zero and negative values are undefined */ 117 /* Zero and negative values are undefined */
114 if (raw <= 0) 118 if (raw <= 0)
@@ -142,7 +146,7 @@ static int rx51_battery_read_temperature(struct rx51_device_info *di)
142 */ 146 */
143static int rx51_battery_read_capacity(struct rx51_device_info *di) 147static int rx51_battery_read_capacity(struct rx51_device_info *di)
144{ 148{
145 int capacity = rx51_battery_read_adc(4); 149 int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
146 150
147 if (capacity < 0) 151 if (capacity < 0)
148 return capacity; 152 return capacity;
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index 0224de50c540..f4d80df627c7 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -150,7 +150,7 @@ static void tosa_bat_external_power_changed(struct power_supply *psy)
150 150
151static irqreturn_t tosa_bat_gpio_isr(int irq, void *data) 151static irqreturn_t tosa_bat_gpio_isr(int irq, void *data)
152{ 152{
153 pr_info("tosa_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq))); 153 pr_info("tosa_bat_gpio irq\n");
154 schedule_work(&bat_work); 154 schedule_work(&bat_work);
155 return IRQ_HANDLED; 155 return IRQ_HANDLED;
156} 156}
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index be98e70380f9..d98abe911e37 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -189,7 +189,12 @@ static int twl4030_charger_enable_usb(struct twl4030_bci *bci, bool enable)
189 189
190 /* Need to keep regulator on */ 190 /* Need to keep regulator on */
191 if (!bci->usb_enabled) { 191 if (!bci->usb_enabled) {
192 regulator_enable(bci->usb_reg); 192 ret = regulator_enable(bci->usb_reg);
193 if (ret) {
194 dev_err(bci->dev,
195 "Failed to enable regulator\n");
196 return ret;
197 }
193 bci->usb_enabled = 1; 198 bci->usb_enabled = 1;
194 } 199 }
195 200
diff --git a/drivers/power/twl4030_madc_battery.c b/drivers/power/twl4030_madc_battery.c
new file mode 100644
index 000000000000..7ef445a6cfa6
--- /dev/null
+++ b/drivers/power/twl4030_madc_battery.c
@@ -0,0 +1,245 @@
1/*
2 * Dumb driver for LiIon batteries using TWL4030 madc.
3 *
4 * Copyright 2013 Golden Delicious Computers
5 * Lukas Märdian <lukas@goldelico.com>
6 *
7 * Based on dumb driver for gta01 battery
8 * Copyright 2009 Openmoko, Inc
9 * Balaji Rao <balajirrao@openmoko.org>
10 */
11
12#include <linux/module.h>
13#include <linux/param.h>
14#include <linux/delay.h>
15#include <linux/workqueue.h>
16#include <linux/platform_device.h>
17#include <linux/power_supply.h>
18#include <linux/slab.h>
19#include <linux/sort.h>
20#include <linux/i2c/twl4030-madc.h>
21#include <linux/power/twl4030_madc_battery.h>
22
23struct twl4030_madc_battery {
24 struct power_supply psy;
25 struct twl4030_madc_bat_platform_data *pdata;
26};
27
28static enum power_supply_property twl4030_madc_bat_props[] = {
29 POWER_SUPPLY_PROP_PRESENT,
30 POWER_SUPPLY_PROP_STATUS,
31 POWER_SUPPLY_PROP_TECHNOLOGY,
32 POWER_SUPPLY_PROP_VOLTAGE_NOW,
33 POWER_SUPPLY_PROP_CURRENT_NOW,
34 POWER_SUPPLY_PROP_CAPACITY,
35 POWER_SUPPLY_PROP_CHARGE_FULL,
36 POWER_SUPPLY_PROP_CHARGE_NOW,
37 POWER_SUPPLY_PROP_TEMP,
38 POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
39};
40
41static int madc_read(int index)
42{
43 struct twl4030_madc_request req;
44 int val;
45
46 req.channels = index;
47 req.method = TWL4030_MADC_SW2;
48 req.type = TWL4030_MADC_WAIT;
49 req.do_avg = 0;
50 req.raw = false;
51 req.func_cb = NULL;
52
53 val = twl4030_madc_conversion(&req);
54 if (val < 0)
55 return val;
56
57 return req.rbuf[ffs(index) - 1];
58}
59
60static int twl4030_madc_bat_get_charging_status(void)
61{
62 return (madc_read(TWL4030_MADC_ICHG) > 0) ? 1 : 0;
63}
64
65static int twl4030_madc_bat_get_voltage(void)
66{
67 return madc_read(TWL4030_MADC_VBAT);
68}
69
70static int twl4030_madc_bat_get_current(void)
71{
72 return madc_read(TWL4030_MADC_ICHG) * 1000;
73}
74
75static int twl4030_madc_bat_get_temp(void)
76{
77 return madc_read(TWL4030_MADC_BTEMP) * 10;
78}
79
80static int twl4030_madc_bat_voltscale(struct twl4030_madc_battery *bat,
81 int volt)
82{
83 struct twl4030_madc_bat_calibration *calibration;
84 int i, res = 0;
85
86 /* choose charging curve */
87 if (twl4030_madc_bat_get_charging_status())
88 calibration = bat->pdata->charging;
89 else
90 calibration = bat->pdata->discharging;
91
92 if (volt > calibration[0].voltage) {
93 res = calibration[0].level;
94 } else {
95 for (i = 0; calibration[i+1].voltage >= 0; i++) {
96 if (volt <= calibration[i].voltage &&
97 volt >= calibration[i+1].voltage) {
98 /* interval found - interpolate within range */
99 res = calibration[i].level -
100 ((calibration[i].voltage - volt) *
101 (calibration[i].level -
102 calibration[i+1].level)) /
103 (calibration[i].voltage -
104 calibration[i+1].voltage);
105 break;
106 }
107 }
108 }
109 return res;
110}
111
112static int twl4030_madc_bat_get_property(struct power_supply *psy,
113 enum power_supply_property psp,
114 union power_supply_propval *val)
115{
116 struct twl4030_madc_battery *bat = container_of(psy,
117 struct twl4030_madc_battery, psy);
118
119 switch (psp) {
120 case POWER_SUPPLY_PROP_STATUS:
121 if (twl4030_madc_bat_voltscale(bat,
122 twl4030_madc_bat_get_voltage()) > 95)
123 val->intval = POWER_SUPPLY_STATUS_FULL;
124 else {
125 if (twl4030_madc_bat_get_charging_status())
126 val->intval = POWER_SUPPLY_STATUS_CHARGING;
127 else
128 val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
129 }
130 break;
131 case POWER_SUPPLY_PROP_VOLTAGE_NOW:
132 val->intval = twl4030_madc_bat_get_voltage() * 1000;
133 break;
134 case POWER_SUPPLY_PROP_TECHNOLOGY:
135 val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
136 break;
137 case POWER_SUPPLY_PROP_CURRENT_NOW:
138 val->intval = twl4030_madc_bat_get_current();
139 break;
140 case POWER_SUPPLY_PROP_PRESENT:
141 /* assume battery is always present */
142 val->intval = 1;
143 break;
144 case POWER_SUPPLY_PROP_CHARGE_NOW: {
145 int percent = twl4030_madc_bat_voltscale(bat,
146 twl4030_madc_bat_get_voltage());
147 val->intval = (percent * bat->pdata->capacity) / 100;
148 break;
149 }
150 case POWER_SUPPLY_PROP_CAPACITY:
151 val->intval = twl4030_madc_bat_voltscale(bat,
152 twl4030_madc_bat_get_voltage());
153 break;
154 case POWER_SUPPLY_PROP_CHARGE_FULL:
155 val->intval = bat->pdata->capacity;
156 break;
157 case POWER_SUPPLY_PROP_TEMP:
158 val->intval = twl4030_madc_bat_get_temp();
159 break;
160 case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: {
161 int percent = twl4030_madc_bat_voltscale(bat,
162 twl4030_madc_bat_get_voltage());
163 /* in mAh */
164 int chg = (percent * (bat->pdata->capacity/1000))/100;
165
166 /* assume discharge with 400 mA (ca. 1.5W) */
167 val->intval = (3600l * chg) / 400;
168 break;
169 }
170 default:
171 return -EINVAL;
172 }
173
174 return 0;
175}
176
177static void twl4030_madc_bat_ext_changed(struct power_supply *psy)
178{
179 struct twl4030_madc_battery *bat = container_of(psy,
180 struct twl4030_madc_battery, psy);
181
182 power_supply_changed(&bat->psy);
183}
184
185static int twl4030_cmp(const void *a, const void *b)
186{
187 return ((struct twl4030_madc_bat_calibration *)b)->voltage -
188 ((struct twl4030_madc_bat_calibration *)a)->voltage;
189}
190
191static int twl4030_madc_battery_probe(struct platform_device *pdev)
192{
193 struct twl4030_madc_battery *twl4030_madc_bat;
194 struct twl4030_madc_bat_platform_data *pdata = pdev->dev.platform_data;
195
196 twl4030_madc_bat = kzalloc(sizeof(*twl4030_madc_bat), GFP_KERNEL);
197 if (!twl4030_madc_bat)
198 return -ENOMEM;
199
200 twl4030_madc_bat->psy.name = "twl4030_battery";
201 twl4030_madc_bat->psy.type = POWER_SUPPLY_TYPE_BATTERY;
202 twl4030_madc_bat->psy.properties = twl4030_madc_bat_props;
203 twl4030_madc_bat->psy.num_properties =
204 ARRAY_SIZE(twl4030_madc_bat_props);
205 twl4030_madc_bat->psy.get_property = twl4030_madc_bat_get_property;
206 twl4030_madc_bat->psy.external_power_changed =
207 twl4030_madc_bat_ext_changed;
208
209 /* sort charging and discharging calibration data */
210 sort(pdata->charging, pdata->charging_size,
211 sizeof(struct twl4030_madc_bat_calibration),
212 twl4030_cmp, NULL);
213 sort(pdata->discharging, pdata->discharging_size,
214 sizeof(struct twl4030_madc_bat_calibration),
215 twl4030_cmp, NULL);
216
217 twl4030_madc_bat->pdata = pdata;
218 platform_set_drvdata(pdev, twl4030_madc_bat);
219 power_supply_register(&pdev->dev, &twl4030_madc_bat->psy);
220
221 return 0;
222}
223
224static int twl4030_madc_battery_remove(struct platform_device *pdev)
225{
226 struct twl4030_madc_battery *bat = platform_get_drvdata(pdev);
227
228 power_supply_unregister(&bat->psy);
229 kfree(bat);
230
231 return 0;
232}
233
234static struct platform_driver twl4030_madc_battery_driver = {
235 .driver = {
236 .name = "twl4030_madc_battery",
237 },
238 .probe = twl4030_madc_battery_probe,
239 .remove = twl4030_madc_battery_remove,
240};
241module_platform_driver(twl4030_madc_battery_driver);
242
243MODULE_LICENSE("GPL");
244MODULE_AUTHOR("Lukas Märdian <lukas@goldelico.com>");
245MODULE_DESCRIPTION("twl4030_madc battery driver");