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
diff --git a/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt b/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt
new file mode 100644
index 0000000..ce44ad3
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/msm-poweroff.txt
@@ -0,0 +1,17 @@
+MSM Restart Driver
+
+A power supply hold (ps-hold) bit is set to power the msm chipsets.
+Clearing that bit allows us to restart/poweroff. The difference
+between poweroff and restart is determined by unique power manager IC
+settings.
+
+Required Properties:
+-compatible: "qcom,pshold"
+-reg: Specifies the physical address of the ps-hold register
+
+Example:
+
+	restart@fc4ab000 {
+		compatible = "qcom,pshold";
+		reg = <0xfc4ab000 0x4>;
+	};
diff --git a/MAINTAINERS b/MAINTAINERS
index 38a37f7..d721af1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7624,6 +7624,14 @@
 F:	Documentation/security/Smack.txt
 F:	security/smack/
 
+SMARTREFLEX DRIVERS FOR ADAPTIVE VOLTAGE SCALING (AVS)
+M:	Kevin Hilman <khilman@kernel.org>
+M:	Nishanth Menon <nm@ti.com>
+S:	Maintained
+F:	drivers/power/avs/smartreflex.c
+F:	include/linux/power/smartreflex.h
+L:	linux-pm@vger.kernel.org
+
 SMC91x ETHERNET DRIVER
 M:	Nicolas Pitre <nico@fluxnic.net>
 S:	Odd Fixes
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 7b8979c..bb49ab6 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -216,6 +216,13 @@
 	help
 	  Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery
 
+config BATTERY_TWL4030_MADC
+	tristate "TWL4030 MADC battery driver"
+	depends on TWL4030_MADC
+	help
+	  Say Y here to enable this dumb driver for batteries managed
+	  through the TWL4030 MADC.
+
 config CHARGER_88PM860X
 	tristate "Marvell 88PM860x Charger driver"
 	depends on MFD_88PM860X && BATTERY_88PM860X
@@ -334,6 +341,12 @@
 	  You'll need this driver to charge batteries on e.g. Nokia
 	  RX-51/N900.
 
+config CHARGER_BQ24190
+	tristate "TI BQ24190 battery charger driver"
+	depends on I2C && GPIOLIB
+	help
+	  Say Y to enable support for the TI BQ24190 battery charger.
+
 config CHARGER_SMB347
 	tristate "Summit Microelectronics SMB347 Battery Charger"
 	depends on I2C
@@ -357,7 +370,7 @@
 
 config BATTERY_GOLDFISH
 	tristate "Goldfish battery driver"
-	depends on GENERIC_HARDIRQS
+	depends on GENERIC_HARDIRQS && (GOLDFISH || COMPILE_TEST)
 	help
 	  Say Y to enable support for the battery and AC power in the
 	  Goldfish emulator.
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index 653bf6c..a4b7417 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_BATTERY_MAX17042)	+= max17042_battery.o
 obj-$(CONFIG_BATTERY_Z2)	+= z2_battery.o
 obj-$(CONFIG_BATTERY_S3C_ADC)	+= s3c_adc_battery.o
+obj-$(CONFIG_BATTERY_TWL4030_MADC)	+= twl4030_madc_battery.o
 obj-$(CONFIG_CHARGER_88PM860X)	+= 88pm860x_charger.o
 obj-$(CONFIG_CHARGER_PCF50633)	+= pcf50633-charger.o
 obj-$(CONFIG_BATTERY_JZ4740)	+= jz4740-battery.o
@@ -50,6 +51,7 @@
 obj-$(CONFIG_CHARGER_MAX8997)	+= max8997_charger.o
 obj-$(CONFIG_CHARGER_MAX8998)	+= max8998_charger.o
 obj-$(CONFIG_CHARGER_BQ2415X)	+= bq2415x_charger.o
+obj-$(CONFIG_CHARGER_BQ24190)	+= bq24190_charger.o
 obj-$(CONFIG_POWER_AVS)		+= avs/
 obj-$(CONFIG_CHARGER_SMB347)	+= smb347-charger.o
 obj-$(CONFIG_CHARGER_TPS65090)	+= tps65090-charger.o
diff --git a/drivers/power/ab8500_charger.c b/drivers/power/ab8500_charger.c
index f098fda..a4c4a10 100644
--- a/drivers/power/ab8500_charger.c
+++ b/drivers/power/ab8500_charger.c
@@ -774,6 +774,7 @@
 		di->max_usb_in_curr.usb_type_max = USB_CH_IP_CUR_LVL_0P5;
 		dev_dbg(di->dev, "USB Type - 0x%02x MaxCurr: %d", link_status,
 				di->max_usb_in_curr.usb_type_max);
+		break;
 	case USB_STAT_NOT_VALID_LINK:
 		dev_err(di->dev, "USB Type invalid - try charging anyway\n");
 		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 0000000..ad3ff8f
--- /dev/null
+++ b/drivers/power/bq24190_charger.c
@@ -0,0 +1,1549 @@
+/*
+ * Driver for the TI bq24190 battery charger.
+ *
+ * Author: Mark A. Greer <mgreer@animalcreek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/power_supply.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+
+#include <linux/power/bq24190_charger.h>
+
+
+#define	BQ24190_MANUFACTURER	"Texas Instruments"
+
+#define BQ24190_REG_ISC		0x00 /* Input Source Control */
+#define BQ24190_REG_ISC_EN_HIZ_MASK		BIT(7)
+#define BQ24190_REG_ISC_EN_HIZ_SHIFT		7
+#define BQ24190_REG_ISC_VINDPM_MASK		(BIT(6) | BIT(5) | BIT(4) | \
+						 BIT(3))
+#define BQ24190_REG_ISC_VINDPM_SHIFT		3
+#define BQ24190_REG_ISC_IINLIM_MASK		(BIT(2) | BIT(1) | BIT(0))
+#define BQ24190_REG_ISC_IINLIM_SHIFT		0
+
+#define BQ24190_REG_POC		0x01 /* Power-On Configuration */
+#define BQ24190_REG_POC_RESET_MASK		BIT(7)
+#define BQ24190_REG_POC_RESET_SHIFT		7
+#define BQ24190_REG_POC_WDT_RESET_MASK		BIT(6)
+#define BQ24190_REG_POC_WDT_RESET_SHIFT		6
+#define BQ24190_REG_POC_CHG_CONFIG_MASK		(BIT(5) | BIT(4))
+#define BQ24190_REG_POC_CHG_CONFIG_SHIFT	4
+#define BQ24190_REG_POC_SYS_MIN_MASK		(BIT(3) | BIT(2) | BIT(1))
+#define BQ24190_REG_POC_SYS_MIN_SHIFT		1
+#define BQ24190_REG_POC_BOOST_LIM_MASK		BIT(0)
+#define BQ24190_REG_POC_BOOST_LIM_SHIFT		0
+
+#define BQ24190_REG_CCC		0x02 /* Charge Current Control */
+#define BQ24190_REG_CCC_ICHG_MASK		(BIT(7) | BIT(6) | BIT(5) | \
+						 BIT(4) | BIT(3) | BIT(2))
+#define BQ24190_REG_CCC_ICHG_SHIFT		2
+#define BQ24190_REG_CCC_FORCE_20PCT_MASK	BIT(0)
+#define BQ24190_REG_CCC_FORCE_20PCT_SHIFT	0
+
+#define BQ24190_REG_PCTCC	0x03 /* Pre-charge/Termination Current Cntl */
+#define BQ24190_REG_PCTCC_IPRECHG_MASK		(BIT(7) | BIT(6) | BIT(5) | \
+						 BIT(4))
+#define BQ24190_REG_PCTCC_IPRECHG_SHIFT		4
+#define BQ24190_REG_PCTCC_ITERM_MASK		(BIT(3) | BIT(2) | BIT(1) | \
+						 BIT(0))
+#define BQ24190_REG_PCTCC_ITERM_SHIFT		0
+
+#define BQ24190_REG_CVC		0x04 /* Charge Voltage Control */
+#define BQ24190_REG_CVC_VREG_MASK		(BIT(7) | BIT(6) | BIT(5) | \
+						 BIT(4) | BIT(3) | BIT(2))
+#define BQ24190_REG_CVC_VREG_SHIFT		2
+#define BQ24190_REG_CVC_BATLOWV_MASK		BIT(1)
+#define BQ24190_REG_CVC_BATLOWV_SHIFT		1
+#define BQ24190_REG_CVC_VRECHG_MASK		BIT(0)
+#define BQ24190_REG_CVC_VRECHG_SHIFT		0
+
+#define BQ24190_REG_CTTC	0x05 /* Charge Term/Timer Control */
+#define BQ24190_REG_CTTC_EN_TERM_MASK		BIT(7)
+#define BQ24190_REG_CTTC_EN_TERM_SHIFT		7
+#define BQ24190_REG_CTTC_TERM_STAT_MASK		BIT(6)
+#define BQ24190_REG_CTTC_TERM_STAT_SHIFT	6
+#define BQ24190_REG_CTTC_WATCHDOG_MASK		(BIT(5) | BIT(4))
+#define BQ24190_REG_CTTC_WATCHDOG_SHIFT		4
+#define BQ24190_REG_CTTC_EN_TIMER_MASK		BIT(3)
+#define BQ24190_REG_CTTC_EN_TIMER_SHIFT		3
+#define BQ24190_REG_CTTC_CHG_TIMER_MASK		(BIT(2) | BIT(1))
+#define BQ24190_REG_CTTC_CHG_TIMER_SHIFT	1
+#define BQ24190_REG_CTTC_JEITA_ISET_MASK	BIT(0)
+#define BQ24190_REG_CTTC_JEITA_ISET_SHIFT	0
+
+#define BQ24190_REG_ICTRC	0x06 /* IR Comp/Thermal Regulation Control */
+#define BQ24190_REG_ICTRC_BAT_COMP_MASK		(BIT(7) | BIT(6) | BIT(5))
+#define BQ24190_REG_ICTRC_BAT_COMP_SHIFT	5
+#define BQ24190_REG_ICTRC_VCLAMP_MASK		(BIT(4) | BIT(3) | BIT(2))
+#define BQ24190_REG_ICTRC_VCLAMP_SHIFT		2
+#define BQ24190_REG_ICTRC_TREG_MASK		(BIT(1) | BIT(0))
+#define BQ24190_REG_ICTRC_TREG_SHIFT		0
+
+#define BQ24190_REG_MOC		0x07 /* Misc. Operation Control */
+#define BQ24190_REG_MOC_DPDM_EN_MASK		BIT(7)
+#define BQ24190_REG_MOC_DPDM_EN_SHIFT		7
+#define BQ24190_REG_MOC_TMR2X_EN_MASK		BIT(6)
+#define BQ24190_REG_MOC_TMR2X_EN_SHIFT		6
+#define BQ24190_REG_MOC_BATFET_DISABLE_MASK	BIT(5)
+#define BQ24190_REG_MOC_BATFET_DISABLE_SHIFT	5
+#define BQ24190_REG_MOC_JEITA_VSET_MASK		BIT(4)
+#define BQ24190_REG_MOC_JEITA_VSET_SHIFT	4
+#define BQ24190_REG_MOC_INT_MASK_MASK		(BIT(1) | BIT(0))
+#define BQ24190_REG_MOC_INT_MASK_SHIFT		0
+
+#define BQ24190_REG_SS		0x08 /* System Status */
+#define BQ24190_REG_SS_VBUS_STAT_MASK		(BIT(7) | BIT(6))
+#define BQ24190_REG_SS_VBUS_STAT_SHIFT		6
+#define BQ24190_REG_SS_CHRG_STAT_MASK		(BIT(5) | BIT(4))
+#define BQ24190_REG_SS_CHRG_STAT_SHIFT		4
+#define BQ24190_REG_SS_DPM_STAT_MASK		BIT(3)
+#define BQ24190_REG_SS_DPM_STAT_SHIFT		3
+#define BQ24190_REG_SS_PG_STAT_MASK		BIT(2)
+#define BQ24190_REG_SS_PG_STAT_SHIFT		2
+#define BQ24190_REG_SS_THERM_STAT_MASK		BIT(1)
+#define BQ24190_REG_SS_THERM_STAT_SHIFT		1
+#define BQ24190_REG_SS_VSYS_STAT_MASK		BIT(0)
+#define BQ24190_REG_SS_VSYS_STAT_SHIFT		0
+
+#define BQ24190_REG_F		0x09 /* Fault */
+#define BQ24190_REG_F_WATCHDOG_FAULT_MASK	BIT(7)
+#define BQ24190_REG_F_WATCHDOG_FAULT_SHIFT	7
+#define BQ24190_REG_F_BOOST_FAULT_MASK		BIT(6)
+#define BQ24190_REG_F_BOOST_FAULT_SHIFT		6
+#define BQ24190_REG_F_CHRG_FAULT_MASK		(BIT(5) | BIT(4))
+#define BQ24190_REG_F_CHRG_FAULT_SHIFT		4
+#define BQ24190_REG_F_BAT_FAULT_MASK		BIT(3)
+#define BQ24190_REG_F_BAT_FAULT_SHIFT		3
+#define BQ24190_REG_F_NTC_FAULT_MASK		(BIT(2) | BIT(1) | BIT(0))
+#define BQ24190_REG_F_NTC_FAULT_SHIFT		0
+
+#define BQ24190_REG_VPRS	0x0A /* Vendor/Part/Revision Status */
+#define BQ24190_REG_VPRS_PN_MASK		(BIT(5) | BIT(4) | BIT(3))
+#define BQ24190_REG_VPRS_PN_SHIFT		3
+#define BQ24190_REG_VPRS_PN_24190			0x4
+#define BQ24190_REG_VPRS_PN_24192			0x5 /* Also 24193 */
+#define BQ24190_REG_VPRS_PN_24192I			0x3
+#define BQ24190_REG_VPRS_TS_PROFILE_MASK	BIT(2)
+#define BQ24190_REG_VPRS_TS_PROFILE_SHIFT	2
+#define BQ24190_REG_VPRS_DEV_REG_MASK		(BIT(1) | BIT(0))
+#define BQ24190_REG_VPRS_DEV_REG_SHIFT		0
+
+/*
+ * The FAULT register is latched by the bq24190 (except for NTC_FAULT)
+ * so the first read after a fault returns the latched value and subsequent
+ * reads return the current value.  In order to return the fault status
+ * to the user, have the interrupt handler save the reg's value and retrieve
+ * it in the appropriate health/status routine.  Each routine has its own
+ * flag indicating whether it should use the value stored by the last run
+ * of the interrupt handler or do an actual reg read.  That way each routine
+ * can report back whatever fault may have occured.
+ */
+struct bq24190_dev_info {
+	struct i2c_client		*client;
+	struct device			*dev;
+	struct power_supply		charger;
+	struct power_supply		battery;
+	char				model_name[I2C_NAME_SIZE];
+	kernel_ulong_t			model;
+	unsigned int			gpio_int;
+	unsigned int			irq;
+	struct mutex			f_reg_lock;
+	bool				first_time;
+	bool				charger_health_valid;
+	bool				battery_health_valid;
+	bool				battery_status_valid;
+	u8				f_reg;
+	u8				ss_reg;
+	u8				watchdog;
+};
+
+/*
+ * The tables below provide a 2-way mapping for the value that goes in
+ * the register field and the real-world value that it represents.
+ * The index of the array is the value that goes in the register; the
+ * number at that index in the array is the real-world value that it
+ * represents.
+ */
+/* REG02[7:2] (ICHG) in uAh */
+static const int bq24190_ccc_ichg_values[] = {
+	 512000,  576000,  640000,  704000,  768000,  832000,  896000,  960000,
+	1024000, 1088000, 1152000, 1216000, 1280000, 1344000, 1408000, 1472000,
+	1536000, 1600000, 1664000, 1728000, 1792000, 1856000, 1920000, 1984000,
+	2048000, 2112000, 2176000, 2240000, 2304000, 2368000, 2432000, 2496000,
+	2560000, 2624000, 2688000, 2752000, 2816000, 2880000, 2944000, 3008000,
+	3072000, 3136000, 3200000, 3264000, 3328000, 3392000, 3456000, 3520000,
+	3584000, 3648000, 3712000, 3776000, 3840000, 3904000, 3968000, 4032000,
+	4096000, 4160000, 4224000, 4288000, 4352000, 4416000, 4480000, 4544000
+};
+
+/* REG04[7:2] (VREG) in uV */
+static const int bq24190_cvc_vreg_values[] = {
+	3504000, 3520000, 3536000, 3552000, 3568000, 3584000, 3600000, 3616000,
+	3632000, 3648000, 3664000, 3680000, 3696000, 3712000, 3728000, 3744000,
+	3760000, 3776000, 3792000, 3808000, 3824000, 3840000, 3856000, 3872000,
+	3888000, 3904000, 3920000, 3936000, 3952000, 3968000, 3984000, 4000000,
+	4016000, 4032000, 4048000, 4064000, 4080000, 4096000, 4112000, 4128000,
+	4144000, 4160000, 4176000, 4192000, 4208000, 4224000, 4240000, 4256000,
+	4272000, 4288000, 4304000, 4320000, 4336000, 4352000, 4368000, 4384000,
+	4400000
+};
+
+/* REG06[1:0] (TREG) in tenths of degrees Celcius */
+static const int bq24190_ictrc_treg_values[] = {
+	600, 800, 1000, 1200
+};
+
+/*
+ * Return the index in 'tbl' of greatest value that is less than or equal to
+ * 'val'.  The index range returned is 0 to 'tbl_size' - 1.  Assumes that
+ * the values in 'tbl' are sorted from smallest to largest and 'tbl_size'
+ * is less than 2^8.
+ */
+static u8 bq24190_find_idx(const int tbl[], int tbl_size, int v)
+{
+	int i;
+
+	for (i = 1; i < tbl_size; i++)
+		if (v < tbl[i])
+			break;
+
+	return i - 1;
+}
+
+/* Basic driver I/O routines */
+
+static int bq24190_read(struct bq24190_dev_info *bdi, u8 reg, u8 *data)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(bdi->client, reg);
+	if (ret < 0)
+		return ret;
+
+	*data = ret;
+	return 0;
+}
+
+static int bq24190_write(struct bq24190_dev_info *bdi, u8 reg, u8 data)
+{
+	return i2c_smbus_write_byte_data(bdi->client, reg, data);
+}
+
+static int bq24190_read_mask(struct bq24190_dev_info *bdi, u8 reg,
+		u8 mask, u8 shift, u8 *data)
+{
+	u8 v;
+	int ret;
+
+	ret = bq24190_read(bdi, reg, &v);
+	if (ret < 0)
+		return ret;
+
+	v &= mask;
+	v >>= shift;
+	*data = v;
+
+	return 0;
+}
+
+static int bq24190_write_mask(struct bq24190_dev_info *bdi, u8 reg,
+		u8 mask, u8 shift, u8 data)
+{
+	u8 v;
+	int ret;
+
+	ret = bq24190_read(bdi, reg, &v);
+	if (ret < 0)
+		return ret;
+
+	v &= ~mask;
+	v |= ((data << shift) & mask);
+
+	return bq24190_write(bdi, reg, v);
+}
+
+static int bq24190_get_field_val(struct bq24190_dev_info *bdi,
+		u8 reg, u8 mask, u8 shift,
+		const int tbl[], int tbl_size,
+		int *val)
+{
+	u8 v;
+	int ret;
+
+	ret = bq24190_read_mask(bdi, reg, mask, shift, &v);
+	if (ret < 0)
+		return ret;
+
+	v = (v >= tbl_size) ? (tbl_size - 1) : v;
+	*val = tbl[v];
+
+	return 0;
+}
+
+static int bq24190_set_field_val(struct bq24190_dev_info *bdi,
+		u8 reg, u8 mask, u8 shift,
+		const int tbl[], int tbl_size,
+		int val)
+{
+	u8 idx;
+
+	idx = bq24190_find_idx(tbl, tbl_size, val);
+
+	return bq24190_write_mask(bdi, reg, mask, shift, idx);
+}
+
+#ifdef CONFIG_SYSFS
+/*
+ * There are a numerous options that are configurable on the bq24190
+ * that go well beyond what the power_supply properties provide access to.
+ * Provide sysfs access to them so they can be examined and possibly modified
+ * on the fly.  They will be provided for the charger power_supply object only
+ * and will be prefixed by 'f_' to make them easier to recognize.
+ */
+
+#define BQ24190_SYSFS_FIELD(_name, r, f, m, store)			\
+{									\
+	.attr	= __ATTR(f_##_name, m, bq24190_sysfs_show, store),	\
+	.reg	= BQ24190_REG_##r,					\
+	.mask	= BQ24190_REG_##r##_##f##_MASK,				\
+	.shift	= BQ24190_REG_##r##_##f##_SHIFT,			\
+}
+
+#define BQ24190_SYSFS_FIELD_RW(_name, r, f)				\
+		BQ24190_SYSFS_FIELD(_name, r, f, S_IWUSR | S_IRUGO,	\
+				bq24190_sysfs_store)
+
+#define BQ24190_SYSFS_FIELD_RO(_name, r, f)				\
+		BQ24190_SYSFS_FIELD(_name, r, f, S_IRUGO, NULL)
+
+static ssize_t bq24190_sysfs_show(struct device *dev,
+		struct device_attribute *attr, char *buf);
+static ssize_t bq24190_sysfs_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count);
+
+struct bq24190_sysfs_field_info {
+	struct device_attribute	attr;
+	u8	reg;
+	u8	mask;
+	u8	shift;
+};
+
+/* On i386 ptrace-abi.h defines SS that breaks the macro calls below. */
+#undef SS
+
+static struct bq24190_sysfs_field_info bq24190_sysfs_field_tbl[] = {
+			/*	sysfs name	reg	field in reg */
+	BQ24190_SYSFS_FIELD_RW(en_hiz,		ISC,	EN_HIZ),
+	BQ24190_SYSFS_FIELD_RW(vindpm,		ISC,	VINDPM),
+	BQ24190_SYSFS_FIELD_RW(iinlim,		ISC,	IINLIM),
+	BQ24190_SYSFS_FIELD_RW(chg_config,	POC,	CHG_CONFIG),
+	BQ24190_SYSFS_FIELD_RW(sys_min,		POC,	SYS_MIN),
+	BQ24190_SYSFS_FIELD_RW(boost_lim,	POC,	BOOST_LIM),
+	BQ24190_SYSFS_FIELD_RW(ichg,		CCC,	ICHG),
+	BQ24190_SYSFS_FIELD_RW(force_20_pct,	CCC,	FORCE_20PCT),
+	BQ24190_SYSFS_FIELD_RW(iprechg,		PCTCC,	IPRECHG),
+	BQ24190_SYSFS_FIELD_RW(iterm,		PCTCC,	ITERM),
+	BQ24190_SYSFS_FIELD_RW(vreg,		CVC,	VREG),
+	BQ24190_SYSFS_FIELD_RW(batlowv,		CVC,	BATLOWV),
+	BQ24190_SYSFS_FIELD_RW(vrechg,		CVC,	VRECHG),
+	BQ24190_SYSFS_FIELD_RW(en_term,		CTTC,	EN_TERM),
+	BQ24190_SYSFS_FIELD_RW(term_stat,	CTTC,	TERM_STAT),
+	BQ24190_SYSFS_FIELD_RO(watchdog,	CTTC,	WATCHDOG),
+	BQ24190_SYSFS_FIELD_RW(en_timer,	CTTC,	EN_TIMER),
+	BQ24190_SYSFS_FIELD_RW(chg_timer,	CTTC,	CHG_TIMER),
+	BQ24190_SYSFS_FIELD_RW(jeta_iset,	CTTC,	JEITA_ISET),
+	BQ24190_SYSFS_FIELD_RW(bat_comp,	ICTRC,	BAT_COMP),
+	BQ24190_SYSFS_FIELD_RW(vclamp,		ICTRC,	VCLAMP),
+	BQ24190_SYSFS_FIELD_RW(treg,		ICTRC,	TREG),
+	BQ24190_SYSFS_FIELD_RW(dpdm_en,		MOC,	DPDM_EN),
+	BQ24190_SYSFS_FIELD_RW(tmr2x_en,	MOC,	TMR2X_EN),
+	BQ24190_SYSFS_FIELD_RW(batfet_disable,	MOC,	BATFET_DISABLE),
+	BQ24190_SYSFS_FIELD_RW(jeita_vset,	MOC,	JEITA_VSET),
+	BQ24190_SYSFS_FIELD_RO(int_mask,	MOC,	INT_MASK),
+	BQ24190_SYSFS_FIELD_RO(vbus_stat,	SS,	VBUS_STAT),
+	BQ24190_SYSFS_FIELD_RO(chrg_stat,	SS,	CHRG_STAT),
+	BQ24190_SYSFS_FIELD_RO(dpm_stat,	SS,	DPM_STAT),
+	BQ24190_SYSFS_FIELD_RO(pg_stat,		SS,	PG_STAT),
+	BQ24190_SYSFS_FIELD_RO(therm_stat,	SS,	THERM_STAT),
+	BQ24190_SYSFS_FIELD_RO(vsys_stat,	SS,	VSYS_STAT),
+	BQ24190_SYSFS_FIELD_RO(watchdog_fault,	F,	WATCHDOG_FAULT),
+	BQ24190_SYSFS_FIELD_RO(boost_fault,	F,	BOOST_FAULT),
+	BQ24190_SYSFS_FIELD_RO(chrg_fault,	F,	CHRG_FAULT),
+	BQ24190_SYSFS_FIELD_RO(bat_fault,	F,	BAT_FAULT),
+	BQ24190_SYSFS_FIELD_RO(ntc_fault,	F,	NTC_FAULT),
+	BQ24190_SYSFS_FIELD_RO(pn,		VPRS,	PN),
+	BQ24190_SYSFS_FIELD_RO(ts_profile,	VPRS,	TS_PROFILE),
+	BQ24190_SYSFS_FIELD_RO(dev_reg,		VPRS,	DEV_REG),
+};
+
+static struct attribute *
+	bq24190_sysfs_attrs[ARRAY_SIZE(bq24190_sysfs_field_tbl) + 1];
+
+static const struct attribute_group bq24190_sysfs_attr_group = {
+	.attrs = bq24190_sysfs_attrs,
+};
+
+static void bq24190_sysfs_init_attrs(void)
+{
+	int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
+
+	for (i = 0; i < limit; i++)
+		bq24190_sysfs_attrs[i] = &bq24190_sysfs_field_tbl[i].attr.attr;
+
+	bq24190_sysfs_attrs[limit] = NULL; /* Has additional entry for this */
+}
+
+static struct bq24190_sysfs_field_info *bq24190_sysfs_field_lookup(
+		const char *name)
+{
+	int i, limit = ARRAY_SIZE(bq24190_sysfs_field_tbl);
+
+	for (i = 0; i < limit; i++)
+		if (!strcmp(name, bq24190_sysfs_field_tbl[i].attr.attr.name))
+			break;
+
+	if (i >= limit)
+		return NULL;
+
+	return &bq24190_sysfs_field_tbl[i];
+}
+
+static ssize_t bq24190_sysfs_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct power_supply *psy = dev_get_drvdata(dev);
+	struct bq24190_dev_info *bdi =
+			container_of(psy, struct bq24190_dev_info, charger);
+	struct bq24190_sysfs_field_info *info;
+	int ret;
+	u8 v;
+
+	info = bq24190_sysfs_field_lookup(attr->attr.name);
+	if (!info)
+		return -EINVAL;
+
+	ret = bq24190_read_mask(bdi, info->reg, info->mask, info->shift, &v);
+	if (ret)
+		return ret;
+
+	return scnprintf(buf, PAGE_SIZE, "%hhx\n", v);
+}
+
+static ssize_t bq24190_sysfs_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct power_supply *psy = dev_get_drvdata(dev);
+	struct bq24190_dev_info *bdi =
+			container_of(psy, struct bq24190_dev_info, charger);
+	struct bq24190_sysfs_field_info *info;
+	int ret;
+	u8 v;
+
+	info = bq24190_sysfs_field_lookup(attr->attr.name);
+	if (!info)
+		return -EINVAL;
+
+	ret = kstrtou8(buf, 0, &v);
+	if (ret < 0)
+		return ret;
+
+	ret = bq24190_write_mask(bdi, info->reg, info->mask, info->shift, v);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
+{
+	bq24190_sysfs_init_attrs();
+
+	return sysfs_create_group(&bdi->charger.dev->kobj,
+			&bq24190_sysfs_attr_group);
+}
+
+static void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi)
+{
+	sysfs_remove_group(&bdi->charger.dev->kobj, &bq24190_sysfs_attr_group);
+}
+#else
+static int bq24190_sysfs_create_group(struct bq24190_dev_info *bdi)
+{
+	return 0;
+}
+
+static inline void bq24190_sysfs_remove_group(struct bq24190_dev_info *bdi) {}
+#endif
+
+/*
+ * According to the "Host Mode and default Mode" section of the
+ * manual, a write to any register causes the bq24190 to switch
+ * from default mode to host mode.  It will switch back to default
+ * mode after a WDT timeout unless the WDT is turned off as well.
+ * So, by simply turning off the WDT, we accomplish both with the
+ * same write.
+ */
+static int bq24190_set_mode_host(struct bq24190_dev_info *bdi)
+{
+	int ret;
+	u8 v;
+
+	ret = bq24190_read(bdi, BQ24190_REG_CTTC, &v);
+	if (ret < 0)
+		return ret;
+
+	bdi->watchdog = ((v & BQ24190_REG_CTTC_WATCHDOG_MASK) >>
+					BQ24190_REG_CTTC_WATCHDOG_SHIFT);
+	v &= ~BQ24190_REG_CTTC_WATCHDOG_MASK;
+
+	return bq24190_write(bdi, BQ24190_REG_CTTC, v);
+}
+
+static int bq24190_register_reset(struct bq24190_dev_info *bdi)
+{
+	int ret, limit = 100;
+	u8 v;
+
+	/* Reset the registers */
+	ret = bq24190_write_mask(bdi, BQ24190_REG_POC,
+			BQ24190_REG_POC_RESET_MASK,
+			BQ24190_REG_POC_RESET_SHIFT,
+			0x1);
+	if (ret < 0)
+		return ret;
+
+	/* Reset bit will be cleared by hardware so poll until it is */
+	do {
+		ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
+				BQ24190_REG_POC_RESET_MASK,
+				BQ24190_REG_POC_RESET_SHIFT,
+				&v);
+		if (ret < 0)
+			return ret;
+
+		if (!v)
+			break;
+
+		udelay(10);
+	} while (--limit);
+
+	if (!limit)
+		return -EIO;
+
+	return 0;
+}
+
+/* Charger power supply property routines */
+
+static int bq24190_charger_get_charge_type(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 v;
+	int type, ret;
+
+	ret = bq24190_read_mask(bdi, BQ24190_REG_POC,
+			BQ24190_REG_POC_CHG_CONFIG_MASK,
+			BQ24190_REG_POC_CHG_CONFIG_SHIFT,
+			&v);
+	if (ret < 0)
+		return ret;
+
+	/* If POC[CHG_CONFIG] (REG01[5:4]) == 0, charge is disabled */
+	if (!v) {
+		type = POWER_SUPPLY_CHARGE_TYPE_NONE;
+	} else {
+		ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+				BQ24190_REG_CCC_FORCE_20PCT_MASK,
+				BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
+				&v);
+		if (ret < 0)
+			return ret;
+
+		type = (v) ? POWER_SUPPLY_CHARGE_TYPE_TRICKLE :
+			     POWER_SUPPLY_CHARGE_TYPE_FAST;
+	}
+
+	val->intval = type;
+
+	return 0;
+}
+
+static int bq24190_charger_set_charge_type(struct bq24190_dev_info *bdi,
+		const union power_supply_propval *val)
+{
+	u8 chg_config, force_20pct, en_term;
+	int ret;
+
+	/*
+	 * According to the "Termination when REG02[0] = 1" section of
+	 * the bq24190 manual, the trickle charge could be less than the
+	 * termination current so it recommends turning off the termination
+	 * function.
+	 *
+	 * Note: AFAICT from the datasheet, the user will have to manually
+	 * turn off the charging when in 20% mode.  If its not turned off,
+	 * there could be battery damage.  So, use this mode at your own risk.
+	 */
+	switch (val->intval) {
+	case POWER_SUPPLY_CHARGE_TYPE_NONE:
+		chg_config = 0x0;
+		break;
+	case POWER_SUPPLY_CHARGE_TYPE_TRICKLE:
+		chg_config = 0x1;
+		force_20pct = 0x1;
+		en_term = 0x0;
+		break;
+	case POWER_SUPPLY_CHARGE_TYPE_FAST:
+		chg_config = 0x1;
+		force_20pct = 0x0;
+		en_term = 0x1;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (chg_config) { /* Enabling the charger */
+		ret = bq24190_write_mask(bdi, BQ24190_REG_CCC,
+				BQ24190_REG_CCC_FORCE_20PCT_MASK,
+				BQ24190_REG_CCC_FORCE_20PCT_SHIFT,
+				force_20pct);
+		if (ret < 0)
+			return ret;
+
+		ret = bq24190_write_mask(bdi, BQ24190_REG_CTTC,
+				BQ24190_REG_CTTC_EN_TERM_MASK,
+				BQ24190_REG_CTTC_EN_TERM_SHIFT,
+				en_term);
+		if (ret < 0)
+			return ret;
+	}
+
+	return bq24190_write_mask(bdi, BQ24190_REG_POC,
+			BQ24190_REG_POC_CHG_CONFIG_MASK,
+			BQ24190_REG_POC_CHG_CONFIG_SHIFT, chg_config);
+}
+
+static int bq24190_charger_get_health(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 v;
+	int health, ret;
+
+	mutex_lock(&bdi->f_reg_lock);
+
+	if (bdi->charger_health_valid) {
+		v = bdi->f_reg;
+		bdi->charger_health_valid = false;
+		mutex_unlock(&bdi->f_reg_lock);
+	} else {
+		mutex_unlock(&bdi->f_reg_lock);
+
+		ret = bq24190_read(bdi, BQ24190_REG_F, &v);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (v & BQ24190_REG_F_BOOST_FAULT_MASK) {
+		/*
+		 * This could be over-current or over-voltage but there's
+		 * no way to tell which.  Return 'OVERVOLTAGE' since there
+		 * isn't an 'OVERCURRENT' value defined that we can return
+		 * even if it was over-current.
+		 */
+		health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	} else {
+		v &= BQ24190_REG_F_CHRG_FAULT_MASK;
+		v >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
+
+		switch (v) {
+		case 0x0: /* Normal */
+			health = POWER_SUPPLY_HEALTH_GOOD;
+			break;
+		case 0x1: /* Input Fault (VBUS OVP or VBAT<VBUS<3.8V) */
+			/*
+			 * This could be over-voltage or under-voltage
+			 * and there's no way to tell which.  Instead
+			 * of looking foolish and returning 'OVERVOLTAGE'
+			 * when its really under-voltage, just return
+			 * 'UNSPEC_FAILURE'.
+			 */
+			health = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+			break;
+		case 0x2: /* Thermal Shutdown */
+			health = POWER_SUPPLY_HEALTH_OVERHEAT;
+			break;
+		case 0x3: /* Charge Safety Timer Expiration */
+			health = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+			break;
+		default:
+			health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		}
+	}
+
+	val->intval = health;
+
+	return 0;
+}
+
+static int bq24190_charger_get_online(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 v;
+	int ret;
+
+	ret = bq24190_read_mask(bdi, BQ24190_REG_SS,
+			BQ24190_REG_SS_PG_STAT_MASK,
+			BQ24190_REG_SS_PG_STAT_SHIFT, &v);
+	if (ret < 0)
+		return ret;
+
+	val->intval = v;
+	return 0;
+}
+
+static int bq24190_charger_get_current(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 v;
+	int curr, ret;
+
+	ret = bq24190_get_field_val(bdi, BQ24190_REG_CCC,
+			BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
+			bq24190_ccc_ichg_values,
+			ARRAY_SIZE(bq24190_ccc_ichg_values), &curr);
+	if (ret < 0)
+		return ret;
+
+	ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+			BQ24190_REG_CCC_FORCE_20PCT_MASK,
+			BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
+	if (ret < 0)
+		return ret;
+
+	/* If FORCE_20PCT is enabled, then current is 20% of ICHG value */
+	if (v)
+		curr /= 5;
+
+	val->intval = curr;
+	return 0;
+}
+
+static int bq24190_charger_get_current_max(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	int idx = ARRAY_SIZE(bq24190_ccc_ichg_values) - 1;
+
+	val->intval = bq24190_ccc_ichg_values[idx];
+	return 0;
+}
+
+static int bq24190_charger_set_current(struct bq24190_dev_info *bdi,
+		const union power_supply_propval *val)
+{
+	u8 v;
+	int ret, curr = val->intval;
+
+	ret = bq24190_read_mask(bdi, BQ24190_REG_CCC,
+			BQ24190_REG_CCC_FORCE_20PCT_MASK,
+			BQ24190_REG_CCC_FORCE_20PCT_SHIFT, &v);
+	if (ret < 0)
+		return ret;
+
+	/* If FORCE_20PCT is enabled, have to multiply value passed in by 5 */
+	if (v)
+		curr *= 5;
+
+	return bq24190_set_field_val(bdi, BQ24190_REG_CCC,
+			BQ24190_REG_CCC_ICHG_MASK, BQ24190_REG_CCC_ICHG_SHIFT,
+			bq24190_ccc_ichg_values,
+			ARRAY_SIZE(bq24190_ccc_ichg_values), curr);
+}
+
+static int bq24190_charger_get_voltage(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	int voltage, ret;
+
+	ret = bq24190_get_field_val(bdi, BQ24190_REG_CVC,
+			BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
+			bq24190_cvc_vreg_values,
+			ARRAY_SIZE(bq24190_cvc_vreg_values), &voltage);
+	if (ret < 0)
+		return ret;
+
+	val->intval = voltage;
+	return 0;
+}
+
+static int bq24190_charger_get_voltage_max(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	int idx = ARRAY_SIZE(bq24190_cvc_vreg_values) - 1;
+
+	val->intval = bq24190_cvc_vreg_values[idx];
+	return 0;
+}
+
+static int bq24190_charger_set_voltage(struct bq24190_dev_info *bdi,
+		const union power_supply_propval *val)
+{
+	return bq24190_set_field_val(bdi, BQ24190_REG_CVC,
+			BQ24190_REG_CVC_VREG_MASK, BQ24190_REG_CVC_VREG_SHIFT,
+			bq24190_cvc_vreg_values,
+			ARRAY_SIZE(bq24190_cvc_vreg_values), val->intval);
+}
+
+static int bq24190_charger_get_property(struct power_supply *psy,
+		enum power_supply_property psp, union power_supply_propval *val)
+{
+	struct bq24190_dev_info *bdi =
+			container_of(psy, struct bq24190_dev_info, charger);
+	int ret;
+
+	dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+	pm_runtime_get_sync(bdi->dev);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = bq24190_charger_get_charge_type(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = bq24190_charger_get_health(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = bq24190_charger_get_online(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = bq24190_charger_get_current(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX:
+		ret = bq24190_charger_get_current_max(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = bq24190_charger_get_voltage(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX:
+		ret = bq24190_charger_get_voltage_max(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_SCOPE:
+		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
+		ret = 0;
+		break;
+	case POWER_SUPPLY_PROP_MODEL_NAME:
+		val->strval = bdi->model_name;
+		ret = 0;
+		break;
+	case POWER_SUPPLY_PROP_MANUFACTURER:
+		val->strval = BQ24190_MANUFACTURER;
+		ret = 0;
+		break;
+	default:
+		ret = -ENODATA;
+	}
+
+	pm_runtime_put_sync(bdi->dev);
+	return ret;
+}
+
+static int bq24190_charger_set_property(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct bq24190_dev_info *bdi =
+			container_of(psy, struct bq24190_dev_info, charger);
+	int ret;
+
+	dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+	pm_runtime_get_sync(bdi->dev);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+		ret = bq24190_charger_set_charge_type(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+		ret = bq24190_charger_set_current(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = bq24190_charger_set_voltage(bdi, val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	pm_runtime_put_sync(bdi->dev);
+	return ret;
+}
+
+static int bq24190_charger_property_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_CHARGE_TYPE:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT:
+	case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE:
+		ret = 1;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static enum power_supply_property bq24190_charger_properties[] = {
+	POWER_SUPPLY_PROP_TYPE,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE,
+	POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_SCOPE,
+	POWER_SUPPLY_PROP_MODEL_NAME,
+	POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static char *bq24190_charger_supplied_to[] = {
+	"main-battery",
+};
+
+static void bq24190_charger_init(struct power_supply *charger)
+{
+	charger->name = "bq24190-charger";
+	charger->type = POWER_SUPPLY_TYPE_USB;
+	charger->properties = bq24190_charger_properties;
+	charger->num_properties = ARRAY_SIZE(bq24190_charger_properties);
+	charger->supplied_to = bq24190_charger_supplied_to;
+	charger->num_supplies = ARRAY_SIZE(bq24190_charger_supplied_to);
+	charger->get_property = bq24190_charger_get_property;
+	charger->set_property = bq24190_charger_set_property;
+	charger->property_is_writeable = bq24190_charger_property_is_writeable;
+}
+
+/* Battery power supply property routines */
+
+static int bq24190_battery_get_status(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 ss_reg, chrg_fault;
+	int status, ret;
+
+	mutex_lock(&bdi->f_reg_lock);
+
+	if (bdi->battery_status_valid) {
+		chrg_fault = bdi->f_reg;
+		bdi->battery_status_valid = false;
+		mutex_unlock(&bdi->f_reg_lock);
+	} else {
+		mutex_unlock(&bdi->f_reg_lock);
+
+		ret = bq24190_read(bdi, BQ24190_REG_F, &chrg_fault);
+		if (ret < 0)
+			return ret;
+	}
+
+	chrg_fault &= BQ24190_REG_F_CHRG_FAULT_MASK;
+	chrg_fault >>= BQ24190_REG_F_CHRG_FAULT_SHIFT;
+
+	ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * The battery must be discharging when any of these are true:
+	 * - there is no good power source;
+	 * - there is a charge fault.
+	 * Could also be discharging when in "supplement mode" but
+	 * there is no way to tell when its in that mode.
+	 */
+	if (!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK) || chrg_fault) {
+		status = POWER_SUPPLY_STATUS_DISCHARGING;
+	} else {
+		ss_reg &= BQ24190_REG_SS_CHRG_STAT_MASK;
+		ss_reg >>= BQ24190_REG_SS_CHRG_STAT_SHIFT;
+
+		switch (ss_reg) {
+		case 0x0: /* Not Charging */
+			status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+			break;
+		case 0x1: /* Pre-charge */
+		case 0x2: /* Fast Charging */
+			status = POWER_SUPPLY_STATUS_CHARGING;
+			break;
+		case 0x3: /* Charge Termination Done */
+			status = POWER_SUPPLY_STATUS_FULL;
+			break;
+		default:
+			ret = -EIO;
+		}
+	}
+
+	if (!ret)
+		val->intval = status;
+
+	return ret;
+}
+
+static int bq24190_battery_get_health(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 v;
+	int health, ret;
+
+	mutex_lock(&bdi->f_reg_lock);
+
+	if (bdi->battery_health_valid) {
+		v = bdi->f_reg;
+		bdi->battery_health_valid = false;
+		mutex_unlock(&bdi->f_reg_lock);
+	} else {
+		mutex_unlock(&bdi->f_reg_lock);
+
+		ret = bq24190_read(bdi, BQ24190_REG_F, &v);
+		if (ret < 0)
+			return ret;
+	}
+
+	if (v & BQ24190_REG_F_BAT_FAULT_MASK) {
+		health = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+	} else {
+		v &= BQ24190_REG_F_NTC_FAULT_MASK;
+		v >>= BQ24190_REG_F_NTC_FAULT_SHIFT;
+
+		switch (v) {
+		case 0x0: /* Normal */
+			health = POWER_SUPPLY_HEALTH_GOOD;
+			break;
+		case 0x1: /* TS1 Cold */
+		case 0x3: /* TS2 Cold */
+		case 0x5: /* Both Cold */
+			health = POWER_SUPPLY_HEALTH_COLD;
+			break;
+		case 0x2: /* TS1 Hot */
+		case 0x4: /* TS2 Hot */
+		case 0x6: /* Both Hot */
+			health = POWER_SUPPLY_HEALTH_OVERHEAT;
+			break;
+		default:
+			health = POWER_SUPPLY_HEALTH_UNKNOWN;
+		}
+	}
+
+	val->intval = health;
+	return 0;
+}
+
+static int bq24190_battery_get_online(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	u8 batfet_disable;
+	int ret;
+
+	ret = bq24190_read_mask(bdi, BQ24190_REG_MOC,
+			BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+			BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, &batfet_disable);
+	if (ret < 0)
+		return ret;
+
+	val->intval = !batfet_disable;
+	return 0;
+}
+
+static int bq24190_battery_set_online(struct bq24190_dev_info *bdi,
+		const union power_supply_propval *val)
+{
+	return bq24190_write_mask(bdi, BQ24190_REG_MOC,
+			BQ24190_REG_MOC_BATFET_DISABLE_MASK,
+			BQ24190_REG_MOC_BATFET_DISABLE_SHIFT, !val->intval);
+}
+
+static int bq24190_battery_get_temp_alert_max(struct bq24190_dev_info *bdi,
+		union power_supply_propval *val)
+{
+	int temp, ret;
+
+	ret = bq24190_get_field_val(bdi, BQ24190_REG_ICTRC,
+			BQ24190_REG_ICTRC_TREG_MASK,
+			BQ24190_REG_ICTRC_TREG_SHIFT,
+			bq24190_ictrc_treg_values,
+			ARRAY_SIZE(bq24190_ictrc_treg_values), &temp);
+	if (ret < 0)
+		return ret;
+
+	val->intval = temp;
+	return 0;
+}
+
+static int bq24190_battery_set_temp_alert_max(struct bq24190_dev_info *bdi,
+		const union power_supply_propval *val)
+{
+	return bq24190_set_field_val(bdi, BQ24190_REG_ICTRC,
+			BQ24190_REG_ICTRC_TREG_MASK,
+			BQ24190_REG_ICTRC_TREG_SHIFT,
+			bq24190_ictrc_treg_values,
+			ARRAY_SIZE(bq24190_ictrc_treg_values), val->intval);
+}
+
+static int bq24190_battery_get_property(struct power_supply *psy,
+		enum power_supply_property psp, union power_supply_propval *val)
+{
+	struct bq24190_dev_info *bdi =
+			container_of(psy, struct bq24190_dev_info, battery);
+	int ret;
+
+	dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+	pm_runtime_get_sync(bdi->dev);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		ret = bq24190_battery_get_status(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_HEALTH:
+		ret = bq24190_battery_get_health(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = bq24190_battery_get_online(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		/* Could be Li-on or Li-polymer but no way to tell which */
+		val->intval = POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
+		ret = 0;
+		break;
+	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+		ret = bq24190_battery_get_temp_alert_max(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_SCOPE:
+		val->intval = POWER_SUPPLY_SCOPE_SYSTEM;
+		ret = 0;
+		break;
+	default:
+		ret = -ENODATA;
+	}
+
+	pm_runtime_put_sync(bdi->dev);
+	return ret;
+}
+
+static int bq24190_battery_set_property(struct power_supply *psy,
+		enum power_supply_property psp,
+		const union power_supply_propval *val)
+{
+	struct bq24190_dev_info *bdi =
+			container_of(psy, struct bq24190_dev_info, battery);
+	int ret;
+
+	dev_dbg(bdi->dev, "prop: %d\n", psp);
+
+	pm_runtime_put_sync(bdi->dev);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		ret = bq24190_battery_set_online(bdi, val);
+		break;
+	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+		ret = bq24190_battery_set_temp_alert_max(bdi, val);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	pm_runtime_put_sync(bdi->dev);
+	return ret;
+}
+
+static int bq24190_battery_property_is_writeable(struct power_supply *psy,
+		enum power_supply_property psp)
+{
+	int ret;
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+	case POWER_SUPPLY_PROP_TEMP_ALERT_MAX:
+		ret = 1;
+		break;
+	default:
+		ret = 0;
+	}
+
+	return ret;
+}
+
+static enum power_supply_property bq24190_battery_properties[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_HEALTH,
+	POWER_SUPPLY_PROP_ONLINE,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_TEMP_ALERT_MAX,
+	POWER_SUPPLY_PROP_SCOPE,
+};
+
+static void bq24190_battery_init(struct power_supply *battery)
+{
+	battery->name = "bq24190-battery";
+	battery->type = POWER_SUPPLY_TYPE_BATTERY;
+	battery->properties = bq24190_battery_properties;
+	battery->num_properties = ARRAY_SIZE(bq24190_battery_properties);
+	battery->get_property = bq24190_battery_get_property;
+	battery->set_property = bq24190_battery_set_property;
+	battery->property_is_writeable = bq24190_battery_property_is_writeable;
+}
+
+static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
+{
+	struct bq24190_dev_info *bdi = data;
+	bool alert_userspace = false;
+	u8 ss_reg, f_reg;
+	int ret;
+
+	pm_runtime_get_sync(bdi->dev);
+
+	ret = bq24190_read(bdi, BQ24190_REG_SS, &ss_reg);
+	if (ret < 0) {
+		dev_err(bdi->dev, "Can't read SS reg: %d\n", ret);
+		goto out;
+	}
+
+	if (ss_reg != bdi->ss_reg) {
+		/*
+		 * The device is in host mode so when PG_STAT goes from 1->0
+		 * (i.e., power removed) HIZ needs to be disabled.
+		 */
+		if ((bdi->ss_reg & BQ24190_REG_SS_PG_STAT_MASK) &&
+				!(ss_reg & BQ24190_REG_SS_PG_STAT_MASK)) {
+			ret = bq24190_write_mask(bdi, BQ24190_REG_ISC,
+					BQ24190_REG_ISC_EN_HIZ_MASK,
+					BQ24190_REG_ISC_EN_HIZ_SHIFT,
+					0);
+			if (ret < 0)
+				dev_err(bdi->dev, "Can't access ISC reg: %d\n",
+					ret);
+		}
+
+		bdi->ss_reg = ss_reg;
+		alert_userspace = true;
+	}
+
+	mutex_lock(&bdi->f_reg_lock);
+
+	ret = bq24190_read(bdi, BQ24190_REG_F, &f_reg);
+	if (ret < 0) {
+		mutex_unlock(&bdi->f_reg_lock);
+		dev_err(bdi->dev, "Can't read F reg: %d\n", ret);
+		goto out;
+	}
+
+	if (f_reg != bdi->f_reg) {
+		bdi->f_reg = f_reg;
+		bdi->charger_health_valid = true;
+		bdi->battery_health_valid = true;
+		bdi->battery_status_valid = true;
+
+		alert_userspace = true;
+	}
+
+	mutex_unlock(&bdi->f_reg_lock);
+
+	/*
+	 * Sometimes bq24190 gives a steady trickle of interrupts even
+	 * though the watchdog timer is turned off and neither the STATUS
+	 * nor FAULT registers have changed.  Weed out these sprurious
+	 * interrupts so userspace isn't alerted for no reason.
+	 * In addition, the chip always generates an interrupt after
+	 * register reset so we should ignore that one (the very first
+	 * interrupt received).
+	 */
+	if (alert_userspace && !bdi->first_time) {
+		power_supply_changed(&bdi->charger);
+		power_supply_changed(&bdi->battery);
+		bdi->first_time = false;
+	}
+
+out:
+	pm_runtime_put_sync(bdi->dev);
+
+	dev_dbg(bdi->dev, "ss_reg: 0x%02x, f_reg: 0x%02x\n", ss_reg, f_reg);
+
+	return IRQ_HANDLED;
+}
+
+static int bq24190_hw_init(struct bq24190_dev_info *bdi)
+{
+	u8 v;
+	int ret;
+
+	pm_runtime_get_sync(bdi->dev);
+
+	/* First check that the device really is what its supposed to be */
+	ret = bq24190_read_mask(bdi, BQ24190_REG_VPRS,
+			BQ24190_REG_VPRS_PN_MASK,
+			BQ24190_REG_VPRS_PN_SHIFT,
+			&v);
+	if (ret < 0)
+		goto out;
+
+	if (v != bdi->model) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	ret = bq24190_register_reset(bdi);
+	if (ret < 0)
+		goto out;
+
+	ret = bq24190_set_mode_host(bdi);
+out:
+	pm_runtime_put_sync(bdi->dev);
+	return ret;
+}
+
+#ifdef CONFIG_OF
+static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
+{
+	bdi->irq = irq_of_parse_and_map(bdi->dev->of_node, 0);
+	if (bdi->irq <= 0)
+		return -1;
+
+	return 0;
+}
+#else
+static int bq24190_setup_dt(struct bq24190_dev_info *bdi)
+{
+	return -1;
+}
+#endif
+
+static int bq24190_setup_pdata(struct bq24190_dev_info *bdi,
+		struct bq24190_platform_data *pdata)
+{
+	int ret;
+
+	if (!gpio_is_valid(pdata->gpio_int))
+		return -1;
+
+	ret = gpio_request(pdata->gpio_int, dev_name(bdi->dev));
+	if (ret < 0)
+		return -1;
+
+	ret = gpio_direction_input(pdata->gpio_int);
+	if (ret < 0)
+		goto out;
+
+	bdi->irq = gpio_to_irq(pdata->gpio_int);
+	if (!bdi->irq)
+		goto out;
+
+	bdi->gpio_int = pdata->gpio_int;
+	return 0;
+
+out:
+	gpio_free(pdata->gpio_int);
+	return -1;
+}
+
+static int bq24190_probe(struct i2c_client *client,
+		const struct i2c_device_id *id)
+{
+	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+	struct device *dev = &client->dev;
+	struct bq24190_platform_data *pdata = client->dev.platform_data;
+	struct bq24190_dev_info *bdi;
+	int ret;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+		dev_err(dev, "No support for SMBUS_BYTE_DATA\n");
+		return -ENODEV;
+	}
+
+	bdi = devm_kzalloc(dev, sizeof(*bdi), GFP_KERNEL);
+	if (!bdi) {
+		dev_err(dev, "Can't alloc bdi struct\n");
+		return -ENOMEM;
+	}
+
+	bdi->client = client;
+	bdi->dev = dev;
+	bdi->model = id->driver_data;
+	strncpy(bdi->model_name, id->name, I2C_NAME_SIZE);
+	mutex_init(&bdi->f_reg_lock);
+	bdi->first_time = true;
+	bdi->charger_health_valid = false;
+	bdi->battery_health_valid = false;
+	bdi->battery_status_valid = false;
+
+	i2c_set_clientdata(client, bdi);
+
+	if (dev->of_node)
+		ret = bq24190_setup_dt(bdi);
+	else
+		ret = bq24190_setup_pdata(bdi, pdata);
+
+	if (ret) {
+		dev_err(dev, "Can't get irq info\n");
+		return -EINVAL;
+	}
+
+	ret = devm_request_threaded_irq(dev, bdi->irq, NULL,
+			bq24190_irq_handler_thread,
+			IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+			"bq24190-charger", bdi);
+	if (ret < 0) {
+		dev_err(dev, "Can't set up irq handler\n");
+		goto out1;
+	}
+
+	pm_runtime_enable(dev);
+	pm_runtime_resume(dev);
+
+	ret = bq24190_hw_init(bdi);
+	if (ret < 0) {
+		dev_err(dev, "Hardware init failed\n");
+		goto out2;
+	}
+
+	bq24190_charger_init(&bdi->charger);
+
+	ret = power_supply_register(dev, &bdi->charger);
+	if (ret) {
+		dev_err(dev, "Can't register charger\n");
+		goto out2;
+	}
+
+	bq24190_battery_init(&bdi->battery);
+
+	ret = power_supply_register(dev, &bdi->battery);
+	if (ret) {
+		dev_err(dev, "Can't register battery\n");
+		goto out3;
+	}
+
+	ret = bq24190_sysfs_create_group(bdi);
+	if (ret) {
+		dev_err(dev, "Can't create sysfs entries\n");
+		goto out4;
+	}
+
+	return 0;
+
+out4:
+	power_supply_unregister(&bdi->battery);
+out3:
+	power_supply_unregister(&bdi->charger);
+out2:
+	pm_runtime_disable(dev);
+out1:
+	if (bdi->gpio_int)
+		gpio_free(bdi->gpio_int);
+
+	return ret;
+}
+
+static int bq24190_remove(struct i2c_client *client)
+{
+	struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+
+	pm_runtime_get_sync(bdi->dev);
+	bq24190_register_reset(bdi);
+	pm_runtime_put_sync(bdi->dev);
+
+	bq24190_sysfs_remove_group(bdi);
+	power_supply_unregister(&bdi->battery);
+	power_supply_unregister(&bdi->charger);
+	pm_runtime_disable(bdi->dev);
+
+	if (bdi->gpio_int)
+		gpio_free(bdi->gpio_int);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int bq24190_pm_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+
+	pm_runtime_get_sync(bdi->dev);
+	bq24190_register_reset(bdi);
+	pm_runtime_put_sync(bdi->dev);
+
+	return 0;
+}
+
+static int bq24190_pm_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct bq24190_dev_info *bdi = i2c_get_clientdata(client);
+
+	bdi->charger_health_valid = false;
+	bdi->battery_health_valid = false;
+	bdi->battery_status_valid = false;
+
+	pm_runtime_get_sync(bdi->dev);
+	bq24190_register_reset(bdi);
+	pm_runtime_put_sync(bdi->dev);
+
+	/* Things may have changed while suspended so alert upper layer */
+	power_supply_changed(&bdi->charger);
+	power_supply_changed(&bdi->battery);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(bq24190_pm_ops, bq24190_pm_suspend, bq24190_pm_resume);
+
+/*
+ * Only support the bq24190 right now.  The bq24192, bq24192i, and bq24193
+ * are similar but not identical so the driver needs to be extended to
+ * support them.
+ */
+static const struct i2c_device_id bq24190_i2c_ids[] = {
+	{ "bq24190", BQ24190_REG_VPRS_PN_24190 },
+	{ },
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id bq24190_of_match[] = {
+	{ .compatible = "ti,bq24190", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, bq24190_of_match);
+#else
+static const struct of_device_id bq24190_of_match[] = {
+	{ },
+};
+#endif
+
+static struct i2c_driver bq24190_driver = {
+	.probe		= bq24190_probe,
+	.remove		= bq24190_remove,
+	.id_table	= bq24190_i2c_ids,
+	.driver = {
+		.name		= "bq24190-charger",
+		.owner		= THIS_MODULE,
+		.pm		= &bq24190_pm_ops,
+		.of_match_table	= of_match_ptr(bq24190_of_match),
+	},
+};
+module_i2c_driver(bq24190_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mark A. Greer <mgreer@animalcreek.com>");
+MODULE_ALIAS("i2c:bq24190-charger");
+MODULE_DESCRIPTION("TI BQ24190 Charger Driver");
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index c58d0e3..d02ae02 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -287,7 +287,7 @@
 };
 
 #ifdef CONFIG_PM
-static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
+static int collie_bat_suspend(struct ucb1x00_dev *dev)
 {
 	/* flush all pending status updates */
 	flush_work(&bat_work);
diff --git a/drivers/power/max8925_power.c b/drivers/power/max8925_power.c
index 0ee1e14..b4513f2 100644
--- a/drivers/power/max8925_power.c
+++ b/drivers/power/max8925_power.c
@@ -458,6 +458,7 @@
 	of_property_read_u32(np, "fast-charge", &fast_charge);
 	of_property_read_u32(np, "no-insert-detect", &no_insert_detect);
 	of_property_read_u32(np, "no-temp-support", &no_temp_support);
+	of_node_put(np);
 
 	pdata->batt_detect = batt_detect;
 	pdata->fast_charge = fast_charge;
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 3b2d5df..00e6672 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -67,23 +67,42 @@
 
 static void power_supply_changed_work(struct work_struct *work)
 {
+	unsigned long flags;
 	struct power_supply *psy = container_of(work, struct power_supply,
 						changed_work);
 
 	dev_dbg(psy->dev, "%s\n", __func__);
 
-	class_for_each_device(power_supply_class, NULL, psy,
-			      __power_supply_changed_work);
-
-	power_supply_update_leds(psy);
-
-	kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
+	spin_lock_irqsave(&psy->changed_lock, flags);
+	if (psy->changed) {
+		psy->changed = false;
+		spin_unlock_irqrestore(&psy->changed_lock, flags);
+		class_for_each_device(power_supply_class, NULL, psy,
+				      __power_supply_changed_work);
+		power_supply_update_leds(psy);
+		kobject_uevent(&psy->dev->kobj, KOBJ_CHANGE);
+		spin_lock_irqsave(&psy->changed_lock, flags);
+	}
+	/*
+	 * Dependent power supplies (e.g. battery) may have changed state
+	 * as a result of this event, so poll again and hold the
+	 * wakeup_source until all events are processed.
+	 */
+	if (!psy->changed)
+		pm_relax(psy->dev);
+	spin_unlock_irqrestore(&psy->changed_lock, flags);
 }
 
 void power_supply_changed(struct power_supply *psy)
 {
+	unsigned long flags;
+
 	dev_dbg(psy->dev, "%s\n", __func__);
 
+	spin_lock_irqsave(&psy->changed_lock, flags);
+	psy->changed = true;
+	pm_stay_awake(psy->dev);
+	spin_unlock_irqrestore(&psy->changed_lock, flags);
 	schedule_work(&psy->changed_work);
 }
 EXPORT_SYMBOL_GPL(power_supply_changed);
@@ -500,6 +519,11 @@
 		goto check_supplies_failed;
 	}
 
+	spin_lock_init(&psy->changed_lock);
+	rc = device_init_wakeup(dev, true);
+	if (rc)
+		goto wakeup_init_failed;
+
 	rc = kobject_set_name(&dev->kobj, "%s", psy->name);
 	if (rc)
 		goto kobject_set_name_failed;
@@ -529,6 +553,7 @@
 register_cooler_failed:
 	psy_unregister_thermal(psy);
 register_thermal_failed:
+wakeup_init_failed:
 	device_del(dev);
 kobject_set_name_failed:
 device_add_failed:
@@ -546,6 +571,7 @@
 	power_supply_remove_triggers(psy);
 	psy_unregister_cooler(psy);
 	psy_unregister_thermal(psy);
+	device_init_wakeup(psy->dev, false);
 	device_unregister(psy->dev);
 }
 EXPORT_SYMBOL_GPL(power_supply_unregister);
diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
index 29178f7..44420d1 100644
--- a/drivers/power/power_supply_sysfs.c
+++ b/drivers/power/power_supply_sysfs.c
@@ -118,7 +118,7 @@
 	long long_val;
 
 	/* TODO: support other types than int */
-	ret = strict_strtol(buf, 10, &long_val);
+	ret = kstrtol(buf, 10, &long_val);
 	if (ret < 0)
 		return ret;
 
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index ee039dc..9b3ea53 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -14,6 +14,12 @@
 	  If your board needs a GPIO high/low to power down, say Y and
 	  create a binding in your devicetree.
 
+config POWER_RESET_MSM
+	bool "Qualcomm MSM power-off driver"
+	depends on POWER_RESET && ARCH_MSM
+	help
+	  Power off and restart support for Qualcomm boards.
+
 config POWER_RESET_QNAP
 	bool "QNAP power-off driver"
 	depends on OF_GPIO && POWER_RESET && PLAT_ORION
@@ -34,7 +40,14 @@
 config POWER_RESET_VEXPRESS
 	bool "ARM Versatile Express power-off and reset driver"
 	depends on ARM || ARM64
-	depends on POWER_RESET
+	depends on POWER_RESET && VEXPRESS_CONFIG
 	help
 	  Power off and reset support for the ARM Ltd. Versatile
 	  Express boards.
+
+config POWER_RESET_XGENE
+	bool "APM SoC X-Gene reset driver"
+	depends on ARM64
+	depends on POWER_RESET
+	help
+	  Reboot support for the APM SoC X-Gene Eval boards.
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 372807f..3e6ed88 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -1,4 +1,6 @@
 obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
+obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
 obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
+obj-$(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 0000000..774f9a3
--- /dev/null
+++ b/drivers/power/reset/msm-poweroff.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/reboot.h>
+
+#include <asm/system_misc.h>
+
+static void __iomem *msm_ps_hold;
+
+static void do_msm_restart(enum reboot_mode reboot_mode, const char *cmd)
+{
+	writel(0, msm_ps_hold);
+	mdelay(10000);
+}
+
+static void do_msm_poweroff(void)
+{
+	/* TODO: Add poweroff capability */
+	do_msm_restart(REBOOT_HARD, NULL);
+}
+
+static int msm_restart_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *mem;
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	msm_ps_hold = devm_ioremap_resource(dev, mem);
+	if (IS_ERR(msm_ps_hold))
+		return PTR_ERR(msm_ps_hold);
+
+	pm_power_off = do_msm_poweroff;
+	arm_pm_restart = do_msm_restart;
+	return 0;
+}
+
+static const struct of_device_id of_msm_restart_match[] = {
+	{ .compatible = "qcom,pshold", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_msm_restart_match);
+
+static struct platform_driver msm_restart_driver = {
+	.probe = msm_restart_probe,
+	.driver = {
+		.name = "msm-restart",
+		.of_match_table = of_match_ptr(of_msm_restart_match),
+	},
+};
+
+static int __init msm_restart_init(void)
+{
+	return platform_driver_register(&msm_restart_driver);
+}
+device_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 0000000..ecd55f8
--- /dev/null
+++ b/drivers/power/reset/xgene-reboot.c
@@ -0,0 +1,103 @@
+/*
+ * AppliedMicro X-Gene SoC Reboot Driver
+ *
+ * Copyright (c) 2013, Applied Micro Circuits Corporation
+ * Author: Feng Kan <fkan@apm.com>
+ * Author: Loc Ho <lho@apm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * This driver provides system reboot functionality for APM X-Gene SoC.
+ * For system shutdown, this is board specify. If a board designer
+ * implements GPIO shutdown, use the gpio-poweroff.c driver.
+ */
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <asm/system_misc.h>
+
+struct xgene_reboot_context {
+	struct platform_device *pdev;
+	void *csr;
+	u32 mask;
+};
+
+static struct xgene_reboot_context *xgene_restart_ctx;
+
+static void xgene_restart(char str, const char *cmd)
+{
+	struct xgene_reboot_context *ctx = xgene_restart_ctx;
+	unsigned long timeout;
+
+	/* Issue the reboot */
+	if (ctx)
+		writel(ctx->mask, ctx->csr);
+
+	timeout = jiffies + HZ;
+	while (time_before(jiffies, timeout))
+		cpu_relax();
+
+	dev_emerg(&ctx->pdev->dev, "Unable to restart system\n");
+}
+
+static int xgene_reboot_probe(struct platform_device *pdev)
+{
+	struct xgene_reboot_context *ctx;
+
+	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+	if (!ctx) {
+		dev_err(&pdev->dev, "out of memory for context\n");
+		return -ENODEV;
+	}
+
+	ctx->csr = of_iomap(pdev->dev.of_node, 0);
+	if (!ctx->csr) {
+		devm_kfree(&pdev->dev, ctx);
+		dev_err(&pdev->dev, "can not map resource\n");
+		return -ENODEV;
+	}
+
+	if (of_property_read_u32(pdev->dev.of_node, "mask", &ctx->mask))
+		ctx->mask = 0xFFFFFFFF;
+
+	ctx->pdev = pdev;
+	arm_pm_restart = xgene_restart;
+	xgene_restart_ctx = ctx;
+
+	return 0;
+}
+
+static struct of_device_id xgene_reboot_of_match[] = {
+	{ .compatible = "apm,xgene-reboot" },
+	{}
+};
+
+static struct platform_driver xgene_reboot_driver = {
+	.probe = xgene_reboot_probe,
+	.driver = {
+		.name = "xgene-reboot",
+		.of_match_table = xgene_reboot_of_match,
+	},
+};
+
+static int __init xgene_reboot_init(void)
+{
+	return platform_driver_register(&xgene_reboot_driver);
+}
+device_initcall(xgene_reboot_init);
diff --git a/drivers/power/rx51_battery.c b/drivers/power/rx51_battery.c
index 8a6288d..1bc5857 100644
--- a/drivers/power/rx51_battery.c
+++ b/drivers/power/rx51_battery.c
@@ -25,6 +25,10 @@
 #include <linux/slab.h>
 #include <linux/i2c/twl4030-madc.h>
 
+/* RX51 specific channels */
+#define TWL4030_MADC_BTEMP_RX51	TWL4030_MADC_ADCIN0
+#define TWL4030_MADC_BCI_RX51	TWL4030_MADC_ADCIN4
+
 struct rx51_device_info {
 	struct device *dev;
 	struct power_supply bat;
@@ -37,7 +41,7 @@
 {
 	struct twl4030_madc_request req;
 
-	req.channels = 1 << channel;
+	req.channels = channel;
 	req.do_avg = 1;
 	req.method = TWL4030_MADC_SW1;
 	req.func_cb = NULL;
@@ -47,7 +51,7 @@
 	if (twl4030_madc_conversion(&req) <= 0)
 		return -ENODATA;
 
-	return req.rbuf[channel];
+	return req.rbuf[ffs(channel) - 1];
 }
 
 /*
@@ -56,7 +60,7 @@
  */
 static int rx51_battery_read_voltage(struct rx51_device_info *di)
 {
-	int voltage = rx51_battery_read_adc(12);
+	int voltage = rx51_battery_read_adc(TWL4030_MADC_VBAT);
 
 	if (voltage < 0)
 		return voltage;
@@ -108,7 +112,7 @@
 {
 	int min = 0;
 	int max = ARRAY_SIZE(rx51_temp_table2) - 1;
-	int raw = rx51_battery_read_adc(0);
+	int raw = rx51_battery_read_adc(TWL4030_MADC_BTEMP_RX51);
 
 	/* Zero and negative values are undefined */
 	if (raw <= 0)
@@ -142,7 +146,7 @@
  */
 static int rx51_battery_read_capacity(struct rx51_device_info *di)
 {
-	int capacity = rx51_battery_read_adc(4);
+	int capacity = rx51_battery_read_adc(TWL4030_MADC_BCI_RX51);
 
 	if (capacity < 0)
 		return capacity;
diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
index 0224de5..f4d80df 100644
--- a/drivers/power/tosa_battery.c
+++ b/drivers/power/tosa_battery.c
@@ -150,7 +150,7 @@
 
 static irqreturn_t tosa_bat_gpio_isr(int irq, void *data)
 {
-	pr_info("tosa_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
+	pr_info("tosa_bat_gpio irq\n");
 	schedule_work(&bat_work);
 	return IRQ_HANDLED;
 }
diff --git a/drivers/power/twl4030_charger.c b/drivers/power/twl4030_charger.c
index be98e70..d98abe9 100644
--- a/drivers/power/twl4030_charger.c
+++ b/drivers/power/twl4030_charger.c
@@ -189,7 +189,12 @@
 
 		/* Need to keep regulator on */
 		if (!bci->usb_enabled) {
-			regulator_enable(bci->usb_reg);
+			ret = regulator_enable(bci->usb_reg);
+			if (ret) {
+				dev_err(bci->dev,
+					"Failed to enable regulator\n");
+				return ret;
+			}
 			bci->usb_enabled = 1;
 		}
 
diff --git a/drivers/power/twl4030_madc_battery.c b/drivers/power/twl4030_madc_battery.c
new file mode 100644
index 0000000..7ef445a
--- /dev/null
+++ b/drivers/power/twl4030_madc_battery.c
@@ -0,0 +1,245 @@
+/*
+ * Dumb driver for LiIon batteries using TWL4030 madc.
+ *
+ * Copyright 2013 Golden Delicious Computers
+ * Lukas Märdian <lukas@goldelico.com>
+ *
+ * Based on dumb driver for gta01 battery
+ * Copyright 2009 Openmoko, Inc
+ * Balaji Rao <balajirrao@openmoko.org>
+ */
+
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+#include <linux/sort.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/power/twl4030_madc_battery.h>
+
+struct twl4030_madc_battery {
+	struct power_supply psy;
+	struct twl4030_madc_bat_platform_data *pdata;
+};
+
+static enum power_supply_property twl4030_madc_bat_props[] = {
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_TECHNOLOGY,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CURRENT_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_CHARGE_FULL,
+	POWER_SUPPLY_PROP_CHARGE_NOW,
+	POWER_SUPPLY_PROP_TEMP,
+	POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW,
+};
+
+static int madc_read(int index)
+{
+	struct twl4030_madc_request req;
+	int val;
+
+	req.channels = index;
+	req.method = TWL4030_MADC_SW2;
+	req.type = TWL4030_MADC_WAIT;
+	req.do_avg = 0;
+	req.raw = false;
+	req.func_cb = NULL;
+
+	val = twl4030_madc_conversion(&req);
+	if (val < 0)
+		return val;
+
+	return req.rbuf[ffs(index) - 1];
+}
+
+static int twl4030_madc_bat_get_charging_status(void)
+{
+	return (madc_read(TWL4030_MADC_ICHG) > 0) ? 1 : 0;
+}
+
+static int twl4030_madc_bat_get_voltage(void)
+{
+	return madc_read(TWL4030_MADC_VBAT);
+}
+
+static int twl4030_madc_bat_get_current(void)
+{
+	return madc_read(TWL4030_MADC_ICHG) * 1000;
+}
+
+static int twl4030_madc_bat_get_temp(void)
+{
+	return madc_read(TWL4030_MADC_BTEMP) * 10;
+}
+
+static int twl4030_madc_bat_voltscale(struct twl4030_madc_battery *bat,
+					int volt)
+{
+	struct twl4030_madc_bat_calibration *calibration;
+	int i, res = 0;
+
+	/* choose charging curve */
+	if (twl4030_madc_bat_get_charging_status())
+		calibration = bat->pdata->charging;
+	else
+		calibration = bat->pdata->discharging;
+
+	if (volt > calibration[0].voltage) {
+		res = calibration[0].level;
+	} else {
+		for (i = 0; calibration[i+1].voltage >= 0; i++) {
+			if (volt <= calibration[i].voltage &&
+					volt >= calibration[i+1].voltage) {
+				/* interval found - interpolate within range */
+				res = calibration[i].level -
+					((calibration[i].voltage - volt) *
+					(calibration[i].level -
+					calibration[i+1].level)) /
+					(calibration[i].voltage -
+					calibration[i+1].voltage);
+				break;
+			}
+		}
+	}
+	return res;
+}
+
+static int twl4030_madc_bat_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	struct twl4030_madc_battery *bat = container_of(psy,
+					struct twl4030_madc_battery, psy);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		if (twl4030_madc_bat_voltscale(bat,
+				twl4030_madc_bat_get_voltage()) > 95)
+			val->intval = POWER_SUPPLY_STATUS_FULL;
+		else {
+			if (twl4030_madc_bat_get_charging_status())
+				val->intval = POWER_SUPPLY_STATUS_CHARGING;
+			else
+				val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
+		}
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = twl4030_madc_bat_get_voltage() * 1000;
+		break;
+	case POWER_SUPPLY_PROP_TECHNOLOGY:
+		val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
+		break;
+	case POWER_SUPPLY_PROP_CURRENT_NOW:
+		val->intval = twl4030_madc_bat_get_current();
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		/* assume battery is always present */
+		val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_NOW: {
+			int percent = twl4030_madc_bat_voltscale(bat,
+					twl4030_madc_bat_get_voltage());
+			val->intval = (percent * bat->pdata->capacity) / 100;
+			break;
+		}
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = twl4030_madc_bat_voltscale(bat,
+					twl4030_madc_bat_get_voltage());
+		break;
+	case POWER_SUPPLY_PROP_CHARGE_FULL:
+		val->intval = bat->pdata->capacity;
+		break;
+	case POWER_SUPPLY_PROP_TEMP:
+		val->intval = twl4030_madc_bat_get_temp();
+		break;
+	case POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW: {
+			int percent = twl4030_madc_bat_voltscale(bat,
+					twl4030_madc_bat_get_voltage());
+			/* in mAh */
+			int chg = (percent * (bat->pdata->capacity/1000))/100;
+
+			/* assume discharge with 400 mA (ca. 1.5W) */
+			val->intval = (3600l * chg) / 400;
+			break;
+		}
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void twl4030_madc_bat_ext_changed(struct power_supply *psy)
+{
+	struct twl4030_madc_battery *bat = container_of(psy,
+					struct twl4030_madc_battery, psy);
+
+	power_supply_changed(&bat->psy);
+}
+
+static int twl4030_cmp(const void *a, const void *b)
+{
+	return ((struct twl4030_madc_bat_calibration *)b)->voltage -
+		((struct twl4030_madc_bat_calibration *)a)->voltage;
+}
+
+static int twl4030_madc_battery_probe(struct platform_device *pdev)
+{
+	struct twl4030_madc_battery *twl4030_madc_bat;
+	struct twl4030_madc_bat_platform_data *pdata = pdev->dev.platform_data;
+
+	twl4030_madc_bat = kzalloc(sizeof(*twl4030_madc_bat), GFP_KERNEL);
+	if (!twl4030_madc_bat)
+		return -ENOMEM;
+
+	twl4030_madc_bat->psy.name = "twl4030_battery";
+	twl4030_madc_bat->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+	twl4030_madc_bat->psy.properties = twl4030_madc_bat_props;
+	twl4030_madc_bat->psy.num_properties =
+					ARRAY_SIZE(twl4030_madc_bat_props);
+	twl4030_madc_bat->psy.get_property = twl4030_madc_bat_get_property;
+	twl4030_madc_bat->psy.external_power_changed =
+					twl4030_madc_bat_ext_changed;
+
+	/* sort charging and discharging calibration data */
+	sort(pdata->charging, pdata->charging_size,
+		sizeof(struct twl4030_madc_bat_calibration),
+		twl4030_cmp, NULL);
+	sort(pdata->discharging, pdata->discharging_size,
+		sizeof(struct twl4030_madc_bat_calibration),
+		twl4030_cmp, NULL);
+
+	twl4030_madc_bat->pdata = pdata;
+	platform_set_drvdata(pdev, twl4030_madc_bat);
+	power_supply_register(&pdev->dev, &twl4030_madc_bat->psy);
+
+	return 0;
+}
+
+static int twl4030_madc_battery_remove(struct platform_device *pdev)
+{
+	struct twl4030_madc_battery *bat = platform_get_drvdata(pdev);
+
+	power_supply_unregister(&bat->psy);
+	kfree(bat);
+
+	return 0;
+}
+
+static struct platform_driver twl4030_madc_battery_driver = {
+	.driver = {
+		.name = "twl4030_madc_battery",
+	},
+	.probe  = twl4030_madc_battery_probe,
+	.remove = twl4030_madc_battery_remove,
+};
+module_platform_driver(twl4030_madc_battery_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lukas Märdian <lukas@goldelico.com>");
+MODULE_DESCRIPTION("twl4030_madc battery driver");
diff --git a/include/linux/power/bq24190_charger.h b/include/linux/power/bq24190_charger.h
new file mode 100644
index 0000000..9f02837
--- /dev/null
+++ b/include/linux/power/bq24190_charger.h
@@ -0,0 +1,16 @@
+/*
+ * Platform data for the TI bq24190 battery charger driver.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _BQ24190_CHARGER_H_
+#define _BQ24190_CHARGER_H_
+
+struct bq24190_platform_data {
+	unsigned int	gpio_int;	/* GPIO pin that's connected to INT# */
+};
+
+#endif
diff --git a/include/linux/power/twl4030_madc_battery.h b/include/linux/power/twl4030_madc_battery.h
new file mode 100644
index 0000000..23110dc
--- /dev/null
+++ b/include/linux/power/twl4030_madc_battery.h
@@ -0,0 +1,39 @@
+/*
+ * Dumb driver for LiIon batteries using TWL4030 madc.
+ *
+ * Copyright 2013 Golden Delicious Computers
+ * Nikolaus Schaller <hns@goldelico.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation;  either version 2 of the License, or (at your
+ *  option) any later version.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __TWL4030_MADC_BATTERY_H
+#define __TWL4030_MADC_BATTERY_H
+
+/*
+ * Usually we can assume 100% @ 4.15V and 0% @ 3.3V but curves differ for
+ * charging and discharging!
+ */
+
+struct twl4030_madc_bat_calibration {
+	short voltage;	/* in mV - specify -1 for end of list */
+	short level;	/* in percent (0 .. 100%) */
+};
+
+struct twl4030_madc_bat_platform_data {
+	unsigned int capacity;	/* total capacity in uAh */
+	struct twl4030_madc_bat_calibration *charging;
+	int charging_size;
+	struct twl4030_madc_bat_calibration *discharging;
+	int discharging_size;
+};
+
+#endif
diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
index 804b906..5c26006 100644
--- a/include/linux/power_supply.h
+++ b/include/linux/power_supply.h
@@ -15,6 +15,7 @@
 
 #include <linux/workqueue.h>
 #include <linux/leds.h>
+#include <linux/spinlock.h>
 
 struct device;
 
@@ -194,6 +195,8 @@
 	/* private */
 	struct device *dev;
 	struct work_struct changed_work;
+	spinlock_t changed_lock;
+	bool changed;
 #ifdef CONFIG_THERMAL
 	struct thermal_zone_device *tzd;
 	struct thermal_cooling_device *tcd;