diff --git a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt
index 6824b31..2727ca16 100644
--- a/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt
+++ b/Documentation/devicetree/bindings/arm/bcm/raspberrypi,bcm2835-firmware.txt
@@ -5,10 +5,25 @@ Required properties:
 - compatible:		Should be "raspberrypi,bcm2835-firmware"
 - mboxes:		Phandle to the firmware device's Mailbox.
 			  (See: ../mailbox/mailbox.txt for more information)
+- #power-domain-cells:	Should be <1>, we providing multiple power domains.
+
+The valid defines for power domain are:
+
+ RPI_POWER_DOMAIN_SDCARD, RPI_POWER_DOMAIN_UART0, RPI_POWER_DOMAIN_UART1,
+ RPI_POWER_DOMAIN_USB, RPI_POWER_DOMAIN_I2C0, RPI_POWER_DOMAIN_I2C1,
+ RPI_POWER_DOMAIN_I2C2, RPI_POWER_DOMAIN_SPI, RPI_POWER_DOMAIN_CCP2TX,
+ RPI_POWER_DOMAIN_DSI
 
 Example:
 
 firmware {
 	compatible = "raspberrypi,bcm2835-firmware";
 	mboxes = <&mailbox>;
+	#power-domain-cells = <1>;
+};
+
+Example for using power domain:
+
+&usb {
+       power-domains = <&firmware RPI_POWER_DOMAIN_USB>;
 };
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
index ab5474e..7f19352 100644
--- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -1,3 +1,4 @@
+#include <dt-bindings/arm/raspberrypi-firmware-power.h>
 #include "bcm2835.dtsi"
 
 / {
@@ -19,6 +20,7 @@
 		firmware: firmware {
 			compatible = "raspberrypi,bcm2835-firmware";
 			mboxes = <&mailbox>;
+			#power-domain-cells = <1>;
 		};
 	};
 };
@@ -56,3 +58,7 @@
 	status = "okay";
 	bus-width = <4>;
 };
+
+&usb {
+	power-domains = <&firmware RPI_POWER_DOMAIN_USB>;
+};
diff --git a/arch/arm/boot/dts/bcm2835.dtsi b/arch/arm/boot/dts/bcm2835.dtsi
index 301c73f..3c899b3 100644
--- a/arch/arm/boot/dts/bcm2835.dtsi
+++ b/arch/arm/boot/dts/bcm2835.dtsi
@@ -149,7 +149,7 @@
 			status = "disabled";
 		};
 
-		usb@7e980000 {
+		usb: usb@7e980000 {
 			compatible = "brcm,bcm2835-usb";
 			reg = <0x7e980000 0x10000>;
 			interrupts = <1 9>;
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 7181126..8981599 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -150,6 +150,8 @@ config QCOM_SCM_64
 config RASPBERRYPI_FIRMWARE
 	tristate "Raspberry Pi Firmware Driver"
 	depends on BCM2835_MBOX
+	select PM_GENERIC_DOMAINS if PM
+	select PM_GENERIC_DOMAINS_OF if PM
 	help
 	  This option enables support for communicating with the firmware on the
 	  Raspberry Pi.
diff --git a/drivers/firmware/raspberrypi.c b/drivers/firmware/raspberrypi.c
index dd506cd3..e8db75e 100644
--- a/drivers/firmware/raspberrypi.c
+++ b/drivers/firmware/raspberrypi.c
@@ -14,6 +14,8 @@
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <dt-bindings/arm/raspberrypi-firmware-power.h>
 #include <soc/bcm2835/raspberrypi-firmware.h>
 
 #define MBOX_MSG(chan, data28)		(((data28) & ~0xf) | ((chan) & 0xf))
@@ -21,7 +23,19 @@
 #define MBOX_DATA28(msg)		((msg) & ~0xf)
 #define MBOX_CHAN_PROPERTY		8
 
+#define RPI_POWER_DOMAIN(_domain, _name)			\
+	[_domain] =						\
+	{							\
+		.domain = _domain,				\
+		.base = {					\
+			.name = _name,				\
+			.power_off = raspberrypi_domain_off,	\
+			.power_on = raspberrypi_domain_on,	\
+		},						\
+	}
+
 struct rpi_firmware {
+	struct genpd_onecell_data genpd_xlate;
 	struct mbox_client cl;
 	struct mbox_chan *chan; /* The property channel. */
 	struct completion c;
@@ -30,6 +44,17 @@ struct rpi_firmware {
 
 static DEFINE_MUTEX(transaction_lock);
 
+struct raspberrypi_power_domain {
+	struct rpi_firmware *fw;
+	u32 domain;
+	struct generic_pm_domain base;
+};
+
+struct rpi_power_domain_packet {
+	u32 domain;
+	u32 on;
+} __packet;
+
 static void response_callback(struct mbox_client *cl, void *msg)
 {
 	struct rpi_firmware *fw = container_of(cl, struct rpi_firmware, cl);
@@ -183,10 +208,84 @@ rpi_firmware_print_firmware_revision(struct rpi_firmware *fw)
 	}
 }
 
+/*
+ * Asks the firmware to enable or disable power on a specific power
+ * domain.
+ */
+static int raspberrypi_firmware_set_power(struct rpi_firmware *fw,
+					  u32 domain, bool on)
+{
+	struct rpi_power_domain_packet packet;
+	int ret;
+
+	packet.domain = domain;
+	packet.on = on;
+	ret = rpi_firmware_property(fw, RPI_FIRMWARE_SET_POWER_STATE, &packet,
+				    sizeof(packet));
+	if (!ret && !packet.on)
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Asks the firmware to if power is on for a specific power domain. */
+static int raspberrypi_firmware_power_is_on(struct rpi_firmware *fw,
+					    u32 domain)
+{
+	struct rpi_power_domain_packet packet;
+	int ret;
+
+	packet.domain = domain;
+	ret = rpi_firmware_property(fw, RPI_FIRMWARE_GET_POWER_STATE, &packet,
+				    sizeof(packet));
+	if (ret < 0)
+		return ret;
+
+	return packet.on & BIT(0);
+}
+
+static int raspberrypi_domain_off(struct generic_pm_domain *domain)
+{
+	struct raspberrypi_power_domain *raspberrpi_domain =
+		container_of(domain, struct raspberrypi_power_domain, base);
+
+	return raspberrypi_firmware_set_power(raspberrpi_domain->fw,
+					      raspberrpi_domain->domain, false);
+}
+
+static int raspberrypi_domain_on(struct generic_pm_domain *domain)
+{
+	struct raspberrypi_power_domain *raspberrpi_domain =
+		container_of(domain, struct raspberrypi_power_domain, base);
+
+	return raspberrypi_firmware_set_power(raspberrpi_domain->fw,
+					      raspberrpi_domain->domain, true);
+}
+
+/*
+ * IMPORTANT: be sure this array has no entries which are not specified
+ * between others by RPI_POWER_DOMAIN, otherwise mapping between
+ * generic_pm_domain array doesn't work anymore.
+ */
+static struct raspberrypi_power_domain rpi_power_domains[] = {
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_SDCARD, "SDCARD"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_UART0, "UART0"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_UART1, "UART1"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_USB, "USB"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_I2C0, "I2C0"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_I2C1, "I2C1"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_I2C2, "I2C2"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_SPI, "SPI"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_CCP2TX, "CCP2TX"),
+	RPI_POWER_DOMAIN(RPI_POWER_DOMAIN_DSI, "DSI"),
+};
+
 static int rpi_firmware_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct rpi_firmware *fw;
+	struct generic_pm_domain **power_domains;
+	int i, ret, num_domains = ARRAY_SIZE(rpi_power_domains);
 
 	fw = devm_kzalloc(dev, sizeof(*fw), GFP_KERNEL);
 	if (!fw)
@@ -196,6 +295,11 @@ static int rpi_firmware_probe(struct platform_device *pdev)
 	fw->cl.rx_callback = response_callback;
 	fw->cl.tx_block = true;
 
+	power_domains = devm_kzalloc(dev, sizeof(*power_domains) * num_domains,
+				     GFP_KERNEL);
+	if (!power_domains)
+		return -ENOMEM;
+
 	fw->chan = mbox_request_channel(&fw->cl, 0);
 	if (IS_ERR(fw->chan)) {
 		int ret = PTR_ERR(fw->chan);
@@ -208,15 +312,44 @@ static int rpi_firmware_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, fw);
 
+	fw->genpd_xlate.domains = power_domains;
+	fw->genpd_xlate.num_domains = num_domains;
+
+	for (i = 0; i < num_domains; i++) {
+		bool is_off;
+
+		rpi_power_domains[i].fw = fw;
+		power_domains[i] = &rpi_power_domains[i].base;
+
+		/* get the initial state */
+		ret = raspberrypi_firmware_power_is_on(fw, i);
+		if (ret < 0)
+			goto mbox;
+
+		/* pm_genpd_init needs is_off, invert the logic here */
+		is_off = !ret;
+		pm_genpd_init(power_domains[i], NULL, is_off);
+	}
+
+	ret = of_genpd_add_provider_onecell(dev->of_node, &fw->genpd_xlate);
+	if (ret < 0)
+		goto mbox;
+
 	rpi_firmware_print_firmware_revision(fw);
 
 	return 0;
+
+mbox:
+	mbox_free_channel(fw->chan);
+	return ret;
 }
 
 static int rpi_firmware_remove(struct platform_device *pdev)
 {
 	struct rpi_firmware *fw = platform_get_drvdata(pdev);
+	struct device *dev = &pdev->dev;
 
+	of_genpd_del_provider(dev->of_node);
 	mbox_free_channel(fw->chan);
 
 	return 0;
diff --git a/include/dt-bindings/arm/raspberrypi-firmware-power.h b/include/dt-bindings/arm/raspberrypi-firmware-power.h
new file mode 100644
index 0000000..c363a1f
--- /dev/null
+++ b/include/dt-bindings/arm/raspberrypi-firmware-power.h
@@ -0,0 +1,23 @@
+/*
+ *  Copyright © 2015 Broadcom
+ *
+ * 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 _DT_BINDINGS_ARM_BCM2835_MBOX_POWER_H
+#define _DT_BINDINGS_ARM_BCM2835_MBOX_POWER_H
+
+#define RPI_POWER_DOMAIN_SDCARD	0
+#define RPI_POWER_DOMAIN_UART0	1
+#define RPI_POWER_DOMAIN_UART1	2
+#define RPI_POWER_DOMAIN_USB	3
+#define RPI_POWER_DOMAIN_I2C0	4
+#define RPI_POWER_DOMAIN_I2C1	5
+#define RPI_POWER_DOMAIN_I2C2	6
+#define RPI_POWER_DOMAIN_SPI	7
+#define RPI_POWER_DOMAIN_CCP2TX	8
+#define RPI_POWER_DOMAIN_DSI	9
+
+#endif /* _DT_BINDINGS_ARM_BCM2835_MBOX_POWER_H */
