diff --git a/drivers/hid/hid-nintendo-wiiu.c b/drivers/hid/hid-nintendo-wiiu.c
index 813abb104275..b18fa403eb42 100644
--- a/drivers/hid/hid-nintendo-wiiu.c
+++ b/drivers/hid/hid-nintendo-wiiu.c
@@ -17,6 +17,11 @@
 #include <linux/input.h>
 #include <linux/minmax.h>
 #include <linux/module.h>
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+#include <linux/fixp-arith.h>
+#include <linux/power_supply.h>
+#include <linux/spinlock.h>
+#endif
 #include "hid-ids.h"
 #include "hid-nintendo.h"
 
@@ -72,6 +77,13 @@
 #define MAGNET_MIN	-(1 << 15)
 #define MAGNET_MAX	((1 << 15) - 1)
 
+/* ADC constants for the battery */
+#define BATTERY_CHARGING_BIT	BIT(6)
+#define BATTERY_MIN	142
+#define BATTERY_MAX	178
+#define VOLTAGE_MIN	3270000
+#define VOLTAGE_MAX	4100000
+
 /*
  * The device is setup with multiple input devices:
  * - A joypad with the buttons and sticks.
@@ -85,6 +97,14 @@ struct drc {
 	struct input_dev *joy_input_dev;
 	struct input_dev *touch_input_dev;
 	struct input_dev *accel_input_dev;
+
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+	struct power_supply *battery;
+	struct power_supply_desc battery_desc;
+	spinlock_t battery_lock;
+	u8 battery_energy;
+	int battery_status;
+#endif
 };
 
 /*
@@ -101,6 +121,9 @@ int wiiu_hid_event(struct hid_device *hdev, struct hid_report *report,
 	struct drc *drc = hid_get_drvdata(hdev);
 	int i, x, y, z, pressure, base;
 	u32 buttons;
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+	unsigned long flags;
+#endif
 
 	if (len != 128)
 		return -EINVAL;
@@ -219,6 +242,19 @@ int wiiu_hid_event(struct hid_device *hdev, struct hid_report *report,
 	input_report_abs(drc->accel_input_dev, ABS_WHEEL, (int16_t)z);
 	input_sync(drc->accel_input_dev);
 
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+	/* battery */
+	spin_lock_irqsave(&drc->battery_lock, flags);
+	drc->battery_energy = data[5];
+	if (drc->battery_energy == BATTERY_MAX)
+		drc->battery_status = POWER_SUPPLY_STATUS_FULL;
+	else if (data[4] & BATTERY_CHARGING_BIT)
+		drc->battery_status = POWER_SUPPLY_STATUS_CHARGING;
+	else
+		drc->battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
+	spin_unlock_irqrestore(&drc->battery_lock, flags);
+#endif
+
 	/* let hidraw and hiddev handle the report */
 	return 0;
 }
@@ -368,6 +404,98 @@ static bool drc_setup_accel(struct drc *drc,
 	return true;
 }
 
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+static enum power_supply_property drc_battery_props[] = {
+	POWER_SUPPLY_PROP_STATUS,
+	POWER_SUPPLY_PROP_PRESENT,
+	POWER_SUPPLY_PROP_VOLTAGE_MAX,
+	POWER_SUPPLY_PROP_VOLTAGE_MIN,
+	POWER_SUPPLY_PROP_VOLTAGE_NOW,
+	POWER_SUPPLY_PROP_CAPACITY,
+	POWER_SUPPLY_PROP_SCOPE,
+};
+
+static int drc_battery_get_property(struct power_supply *psy,
+				    enum power_supply_property psp,
+				    union power_supply_propval *val)
+{
+	struct drc *drc = power_supply_get_drvdata(psy);
+	unsigned long flags;
+	int ret = 0;
+	u8 battery_energy;
+	int battery_status;
+
+	spin_lock_irqsave(&drc->battery_lock, flags);
+	battery_energy = drc->battery_energy;
+	battery_status = drc->battery_status;
+	spin_unlock_irqrestore(&drc->battery_lock, flags);
+
+	switch (psp) {
+	case POWER_SUPPLY_PROP_STATUS:
+		val->intval = battery_status;
+		break;
+	case POWER_SUPPLY_PROP_PRESENT:
+		val->intval = 1;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+		val->intval = VOLTAGE_MAX;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_MIN:
+		val->intval = VOLTAGE_MIN;
+		break;
+	case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+		val->intval = fixp_linear_interpolate(BATTERY_MIN, VOLTAGE_MIN,
+						      BATTERY_MAX, VOLTAGE_MAX,
+						      battery_energy);
+		break;
+	case POWER_SUPPLY_PROP_CAPACITY:
+		val->intval = fixp_linear_interpolate(BATTERY_MIN, 0,
+						      BATTERY_MAX, 100,
+						      battery_energy);
+		break;
+	case POWER_SUPPLY_PROP_SCOPE:
+		val->intval = POWER_SUPPLY_SCOPE_DEVICE;
+		break;
+	default:
+		ret = -EINVAL;
+		break;
+	}
+	return ret;
+}
+
+static int drc_setup_battery(struct drc *drc,
+			     struct hid_device *hdev)
+{
+	struct power_supply_config psy_cfg = { .drv_data = drc, };
+	static atomic_t drc_num = ATOMIC_INIT(0);
+	int ret;
+
+	spin_lock_init(&drc->battery_lock);
+
+	drc->battery_desc.properties = drc_battery_props;
+	drc->battery_desc.num_properties = ARRAY_SIZE(drc_battery_props);
+	drc->battery_desc.get_property = drc_battery_get_property;
+	drc->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
+	drc->battery_desc.use_for_apm = 0;
+
+	drc->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+						"wiiu-drc-%i-battery", atomic_fetch_inc(&drc_num));
+	if (!drc->battery_desc.name)
+		return -ENOMEM;
+
+	drc->battery = devm_power_supply_register(&hdev->dev, &drc->battery_desc, &psy_cfg);
+	if (IS_ERR(drc->battery)) {
+		ret = PTR_ERR(drc->battery);
+		hid_err(hdev, "Unable to register battery device\n");
+		return ret;
+	}
+
+	power_supply_powers(drc->battery, &hdev->dev);
+
+	return 0;
+}
+#endif
+
 int wiiu_hid_probe(struct hid_device *hdev,
 		   const struct hid_device_id *id)
 {
@@ -396,6 +524,14 @@ int wiiu_hid_probe(struct hid_device *hdev,
 		return -ENOMEM;
 	}
 
+#ifdef CONFIG_HID_BATTERY_STRENGTH
+	ret = drc_setup_battery(drc, hdev);
+	if (ret) {
+		hid_err(hdev, "could not allocate battery interface\n");
+		return ret;
+	}
+#endif
+
 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW | HID_CONNECT_DRIVER);
 	if (ret) {
 		hid_err(hdev, "hw start failed\n");
