diff --git a/Documentation/thermal/cpu-cooling-api.txt b/Documentation/thermal/cpu-cooling-api.txt
index fca24c9..2f94f68 100644
--- a/Documentation/thermal/cpu-cooling-api.txt
+++ b/Documentation/thermal/cpu-cooling-api.txt
@@ -30,3 +30,20 @@ the user. The registration APIs returns the cooling device pointer.
     This interface function unregisters the "thermal-cpufreq-%x" cooling device.
 
     cdev: Cooling device pointer which has to be unregistered.
+
+1.2 cpu hotplug registration/unregistration APIs
+1.2.1 struct thermal_cooling_device *cpuhp_cooling_register(
+	struct cpumask *cpus, const char *ext)
+
+    This function creates and registers a cpu hotplug cooling device with
+    the name "cpu-hotplug-%s".
+
+    cpus: cpumask of cpu cores participating in cooling.
+    ext: instance-specific name of device
+
+1.2.2 void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+
+    This function unregisters and frees the cpu hotplug cooling device cdev.
+
+    cdev: Pointer to cooling device to unregister.
+
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 52b6ed7..3509100 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -79,6 +79,16 @@ config CPU_THERMAL
 
 	  If you want this support, you should say Y here.
 
+config CPU_THERMAL_HOTPLUG
+	bool "Generic CPU hotplug cooling"
+	depends on HOTPLUG_CPU
+	help
+	  Shutdown CPUs to prevent the device from overheating. This feature
+	  uses generic CPU hot-unplug capabilities to control device
+	  temperature. When the temperature increases over a trip point, a
+	  random subset of CPUs is shut down to reach the desired cooling
+	  state.
+
 config THERMAL_EMULATION
 	bool "Thermal emulation mode support"
 	help
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 5ee0db0..0bd08be 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -12,6 +12,7 @@ thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE)	+= user_space.o
 
 # cpufreq cooling
 thermal_sys-$(CONFIG_CPU_THERMAL)	+= cpu_cooling.o
+thermal_sys-$(CONFIG_CPU_THERMAL_HOTPLUG)	+= cpu_hotplug.o
 
 # platform thermal drivers
 obj-$(CONFIG_SPEAR_THERMAL)	+= spear_thermal.o
diff --git a/drivers/thermal/cpu_hotplug.c b/drivers/thermal/cpu_hotplug.c
new file mode 100644
index 0000000..8c3021e
--- /dev/null
+++ b/drivers/thermal/cpu_hotplug.c
@@ -0,0 +1,362 @@
+/*
+ *  drivers/thermal/cpu_hotplug.c
+ *
+ *  Copyright (C) 2013  Broadcom Corporation Ltd.
+ *  Copyright (C) 2013  Zoran Markovic <zoran.markovic@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *  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; version 2 of the License.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/thermal.h>
+#include <linux/workqueue.h>
+#include <linux/cpu.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/cpuhp_cooling.h>
+
+/**
+ * struct cpuhotplug_cooling_device - cpu hotplug cooling device data
+ * @cpus: cpu mask representing cpus that can be hot-unplugged for cooling
+ * @cdev: pointer to generic cooling device
+ */
+struct cpuhotplug_cooling_device {
+	unsigned int target;
+	struct cpumask cpus;
+	struct thermal_cooling_device *cdev;
+	struct list_head list;
+};
+
+/**
+ * cpuhotplug_list - list of all cpu hotplug cooling devices. Traversed
+ * by cpu hotplug notifier to check constraints on booting cpus. Locked
+ * by cpuhotplug_cooling_lock mutex.
+ */
+static LIST_HEAD(cpuhotplug_list);
+static DEFINE_MUTEX(cpuhotplug_cooling_lock);
+
+/**
+ * boot_cpu - return index of boot CPU; same criteria as in
+ * disable_nonboot_cpus()
+ */
+static inline int boot_cpu(void)
+{
+	int cpu;
+	get_online_cpus();
+	cpu = cpumask_first(cpu_online_mask);
+	put_online_cpus();
+	return cpu;
+}
+
+/**
+ * random_online_cpu - pick any online hot-unpluggable cpu
+ * @d: pointer to cpuhotplug_cooling_device containing hot-pluggable cpu mask
+ */
+static inline int random_online_cpu(struct cpuhotplug_cooling_device *d)
+{
+	int cpu;
+
+	get_online_cpus();
+	cpu = any_online_cpu(d->cpus);
+	put_online_cpus();
+
+	return cpu;
+}
+
+/**
+ * _num_offline_cpus - number of hot-pluggable cpus currently offline
+ * @d: pointer to cpuhotplug_cooling_device containing hot-pluggable cpu mask
+ */
+static inline int _num_offline_cpus(struct cpuhotplug_cooling_device *d)
+{
+	struct cpumask offline;
+
+	cpumask_andnot(&offline, &(d->cpus), cpu_online_mask);
+	return cpumask_weight(&offline);
+}
+
+/**
+ * num_offline_cpus - same as _num_offline_cpus, but safe from background
+ * hotplug events.
+ * @d: pointer to cpuhotplug_cooling_device containing hot-pluggable cpu mask
+ */
+static inline int num_offline_cpus(struct cpuhotplug_cooling_device *d)
+{
+	int num;
+
+	get_online_cpus();
+	num = _num_offline_cpus(d);
+	put_online_cpus();
+
+	return num;
+}
+
+/**
+ * cpuhotplug_get_max_state - get maximum cooling state of device
+ * @cdev: pointer to generic cooling device
+ * @state: returned maximum cooling state
+ *
+ * Thermal framework callback to get the maximum cooling state of cpu
+ * hotplug cooling device.
+ *
+ * Return: always 0.
+ */
+static int cpuhotplug_get_max_state(struct thermal_cooling_device *cdev,
+				    unsigned long *state)
+{
+	struct cpuhotplug_cooling_device *d = cdev->devdata;
+
+	/* defined as number of CPUs in hot-pluggable mask: this is invariant */
+	*state = cpumask_weight(&(d->cpus));
+
+	return 0;
+}
+
+/**
+ * cpuhotplug_get_cur_state - get current cooling state of device
+ * @cdev: pointer to generic cooling device
+ * @state: current cooling state
+ *
+ * Thermal framework callback to get the current cooling state of cpu
+ * hotplug cooling device.
+ *
+ * Return: always 0.
+ */
+static int cpuhotplug_get_cur_state(struct thermal_cooling_device *cdev,
+				    unsigned long *state)
+{
+	struct cpuhotplug_cooling_device *d = cdev->devdata;
+
+	*state = d->target;
+
+	return 0;
+}
+
+/**
+ * cpuhotplug_get_cur_state - set cooling state of device
+ * @cdev: pointer to generic cooling device
+ * @state: cooling state
+ *
+ * Thermal framework callback to set/change cooling state of cpu hotplug
+ * cooling device.
+ *
+ * Return: 0 on success, or error code otherwise
+ */
+static int cpuhotplug_set_cur_state(struct thermal_cooling_device *cdev,
+				    unsigned long state)
+{
+	struct cpuhotplug_cooling_device *d = cdev->devdata;
+	unsigned long cstate;
+	unsigned int cpu;
+	int err = 0;
+
+	if (state > cpumask_weight(&(d->cpus)))
+		return -EINVAL; /* out of allowed range */
+
+	/*
+	 * Set target state here; hot-unplug CPUs if we are too hot, but
+	 * don't attempt to hot-plug CPUs if we're cold. Starting CPUs
+	 * should be left to CPUOffline governor.
+	 *
+	 * There is a chance that CPU hotplug driver is racing with this
+	 * code. Rather than trying to make the procedure atomic, iterate
+	 * until we reach the desired state, or signal error if the state
+	 * cannot be reached.
+	 *
+	 * Neither CPU hotplug nor this code is expected to run too often.
+	 */
+	d->target = state;
+
+	/* compare desired cooling state to current cooling state */
+	while ((cstate = num_offline_cpus(d)) < state && !err) {
+		/* cstate < cstate: we're too hot, unplug any cpu */
+		cpu = random_online_cpu(d);
+		if (cpu < nr_cpu_ids)
+			err = work_on_cpu(boot_cpu(),
+					  (long(*)(void *))cpu_down,
+					  (void *)cpu);
+			/* on error, message would come from cpu_down() */
+		else {
+			pr_warn("cpuhotplug: CPUs already down\n");
+			err = -EAGAIN;
+		}
+	}
+
+	return err;
+}
+
+/* cpu hotplug cooling device ops */
+static struct thermal_cooling_device_ops const cpuhotplug_cooling_ops = {
+	.get_max_state = cpuhotplug_get_max_state,
+	.get_cur_state = cpuhotplug_get_cur_state,
+	.set_cur_state = cpuhotplug_set_cur_state,
+};
+
+/**
+ * _cpu_startup_allowed - traverse list of hotplug cooling devices to
+ * check if startup of cpu violates thermal constraints
+ */
+static inline int _cpu_startup_allowed(int cpu)
+{
+	struct cpuhotplug_cooling_device *d;
+	int ret = 1;
+
+	/*
+	 * Prevent starting CPU if it violates any cooling
+	 * device's constraint. Called from hotplug notifier, so
+	 * cpu_up()/cpu_down() already holds a lock on hotplug
+	 * events.
+	 */
+	mutex_lock(&cpuhotplug_cooling_lock);
+	list_for_each_entry(d, &cpuhotplug_list, list) {
+		if (cpumask_test_cpu(cpu, &(d->cpus)) &&
+		    d->target >= _num_offline_cpus(d)) {
+			pr_warn("%s: CPU%d startup prevented\n",
+				dev_name(&(d->cdev->device)), cpu);
+			ret = 0;
+			break;
+		}
+	}
+	mutex_unlock(&cpuhotplug_cooling_lock);
+	return ret;
+}
+
+/**
+ * cpuhotplug_thermal_notifier - notifier callback for CPU hotplug events.
+ * @nb: struct notifier_block
+ * @event: cpu hotplug event for which callback is invoked.
+ * @data: context data, in this particular case CPU index.
+ *
+ * Callback intercepting CPU hotplug events. Compares CPU hotplug action
+ * with current thermal state and allows/denies accordingly.
+ *
+ * Return: 0 (allow) or error (deny).
+ */
+static int cpuhotplug_thermal_notifier(struct notifier_block *nb,
+				       unsigned long event, void *data)
+{
+	int cpu = (int)data;
+
+	switch (event) {
+	case CPU_UP_PREPARE:
+	case CPU_UP_PREPARE_FROZEN:
+		/* _cpu_up() only cares about result from CPU_UP_PREPAREs */
+		if (!_cpu_startup_allowed(cpu))
+			return notifier_from_errno(-EAGAIN);
+		break;
+	default:
+		/* allow all other actions */
+		break;
+	}
+	return 0;
+}
+
+static struct notifier_block cpuhotplug_thermal_notifier_block = {
+	.notifier_call = cpuhotplug_thermal_notifier,
+};
+
+/**
+ * cpuhotplug_cooling_register - create cpu hotplug cooling device
+ * @cpus: cpumask of cpu cores participating in cooling
+ * @ext: instance-specific name of device
+ *
+ * Creates and registers a cpu hotplug cooling device with the name
+ * "cpu-hotplug-<ext>".
+ *
+ * Return: valid pointer to cpuhotplug_cooling_device struct on success,
+ * corresponding ERR_PTR() on failure.
+ */
+struct thermal_cooling_device *
+cpuhotplug_cooling_register(const struct cpumask *cpus, const char *ext)
+{
+	struct thermal_cooling_device *cdev;
+	struct cpuhotplug_cooling_device *cpuhotplug_cdev;
+	struct cpumask test;
+	char name[THERMAL_NAME_LENGTH];
+	int err;
+
+	/* test if we passed in a good cpumask */
+	cpu_maps_update_begin();
+	cpumask_and(&test, cpus, cpu_possible_mask);
+	cpu_maps_update_done();
+
+	if (cpumask_test_cpu(boot_cpu(), &test)) {
+		pr_warn("cannot hot-plug boot CPU%d\n", boot_cpu());
+		cpumask_clear_cpu(boot_cpu(), &test);
+	}
+	if (cpumask_empty(&test)) {
+		pr_err("CPUs unavailable for hot-plug cooling\n");
+		err = -EINVAL;
+		goto out;
+	}
+
+	cpuhotplug_cdev = kzalloc(sizeof(struct cpuhotplug_cooling_device),
+			     GFP_KERNEL);
+	if (!cpuhotplug_cdev) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	cpumask_copy(&cpuhotplug_cdev->cpus, &test);
+
+	snprintf(name, sizeof(name), "cpu-hotplug-%s", ext);
+
+	cpuhotplug_cdev->target = 0;
+	cdev = thermal_cooling_device_register(name, cpuhotplug_cdev,
+					       &cpuhotplug_cooling_ops);
+	if (!cdev) {
+		pr_err("%s: cooling device registration failed.\n", name);
+		err = -EINVAL;
+		goto out_free;
+	}
+	cpuhotplug_cdev->cdev = cdev;
+
+	mutex_lock(&cpuhotplug_cooling_lock);
+	if (list_empty(&cpuhotplug_list))
+		register_cpu_notifier(&cpuhotplug_thermal_notifier_block);
+	list_add(&(cpuhotplug_cdev->list), &cpuhotplug_list);
+	mutex_unlock(&cpuhotplug_cooling_lock);
+
+	return cdev;
+
+out_free:
+	kfree(cpuhotplug_cdev);
+out:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(cpuhotplug_cooling_register);
+
+/**
+ * cpuhotplug_cooling_unregister - remove cpu hotplug cooling device
+ * @cdev: cooling device to remove
+ *
+ * Unregisters and frees the cpu hotplug cooling device.
+ */
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+	struct cpuhotplug_cooling_device *cpuhotplug_cdev = cdev->devdata;
+
+	mutex_lock(&cpuhotplug_cooling_lock);
+	list_del(&(cpuhotplug_cdev->list));
+	if (list_empty(&cpuhotplug_list))
+		unregister_cpu_notifier(&cpuhotplug_thermal_notifier_block);
+	mutex_unlock(&cpuhotplug_cooling_lock);
+
+	thermal_cooling_device_unregister(cpuhotplug_cdev->cdev);
+	kfree(cpuhotplug_cdev);
+}
+EXPORT_SYMBOL_GPL(cpuhotplug_cooling_unregister);
+
diff --git a/include/linux/cpuhp_cooling.h b/include/linux/cpuhp_cooling.h
new file mode 100644
index 0000000..ace1d5b
--- /dev/null
+++ b/include/linux/cpuhp_cooling.h
@@ -0,0 +1,57 @@
+/*
+ *  linux/include/linux/cpuhp_cooling.h
+ *
+ *  Copyright (C) 2013	Broadcom Corporation Ltd.
+ *  Copyright (C) 2013	Zoran Markovic <zoran.markovic@linaro.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *  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; version 2 of the License.
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#ifndef __CPUHP_COOLING_H__
+#define __CPUHP_COOLING_H__
+
+#include <linux/thermal.h>
+#include <linux/cpumask.h>
+
+#ifdef CONFIG_CPU_THERMAL_HOTPLUG
+/**
+ * cpuhotplug_cooling_register - create cpu hotplug cooling device.
+ * @cpus: cpumask of hot-pluggable cpus
+ * @ext: instance-specific device name
+ */
+struct thermal_cooling_device *
+cpuhotplug_cooling_register(const struct cpumask *cpus, const char *ext);
+
+/**
+ * cpuhotplug_cooling_unregister - remove cpu hoptlug cooling device.
+ * @cdev: thermal cooling device pointer.
+ */
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev);
+#else /* !CONFIG_CPU_THERMAL_HOTPLUG */
+static inline struct thermal_cooling_device *
+cpuhotplug_cooling_register(const struct cpumask *cpus, const char *ext)
+{
+	return NULL;
+}
+static inline
+void cpuhotplug_cooling_unregister(struct thermal_cooling_device *cdev)
+{
+	return;
+}
+#endif	/* CONFIG_CPU_THERMAL_HOTPLUG */
+
+#endif /* __CPU_COOLING_H__ */
