diff --git a/drivers/gpu/arm/mali/Kconfig b/drivers/gpu/arm/mali/Kconfig
index 416c231..41634f9 100644
--- a/drivers/gpu/arm/mali/Kconfig
+++ b/drivers/gpu/arm/mali/Kconfig
@@ -39,6 +39,13 @@ config USING_GPU_UTILIZATION
         ---help---
                 This enables GPU utilization information.
 
+config USING_GPU_DEVFREQ
+	bool "GPU devfreq"
+        depends on MALI400MP && USING_GPU_UTILIZATION
+        default n
+        ---help---
+                This enables GPU devfreq.
+
 config USING_MALI_RUN_TIME_PM
         bool "Using Run time Power Management"
         depends on MALI400MP
diff --git a/drivers/gpu/arm/mali/Makefile b/drivers/gpu/arm/mali/Makefile
index 525a23e..6c854b1 100755
--- a/drivers/gpu/arm/mali/Makefile
+++ b/drivers/gpu/arm/mali/Makefile
@@ -45,6 +45,10 @@ ifeq ($(CONFIG_USING_GPU_UTILIZATION),y)
 USING_GPU_UTILIZATION =1
 endif
 
+ifeq ($(CONFIG_USING_GPU_DEVFREQ),y)
+USING_GPU_DEVFREQ =1
+endif
+
 ifeq ($(CONFIG_USING_MALI_RUN_TIME_PM),y)
 USING_MALI_RUN_TIME_PM =1
 endif
@@ -64,6 +68,7 @@ USING_UMP ?= 0
 USING_OS_MEMORY ?= 0
 USING_PMM ?= 0
 USING_GPU_UTILIZATION ?= 0
+USING_GPU_DEVFREQ ?= 0
 USING_MALI_RUN_TIME_PM ?= 0
 USING_MALI_PMM_TESTSUITE ?= 0
 OS_MEMORY_KERNEL_BUFFER_SIZE_IN_MB ?= 6
@@ -105,6 +110,7 @@ endif
 
 DEFINES += -DUSING_MALI_PMM=$(USING_PMM)
 DEFINES += -DMALI_GPU_UTILIZATION=$(USING_GPU_UTILIZATION)
+DEFINES += -DMALI_GPU_DEVFREQ=$(USING_GPU_DEVFREQ)
 
 ifeq ($(CONFIG_DEBUG_BUILD),y)
 DEFINES += -DDEBUG
@@ -201,9 +207,14 @@ mali-y += \
 endif
 
 ifeq ($(USING_GPU_UTILIZATION),1)
+ifeq ($(USING_GPU_DEVFREQ),1)
+mali-y += \
+	linux/mali_kernel_devfreq.o
+else
 mali-y += \
 	common/mali_kernel_utilization.o
 endif
+endif
 
 ifneq ($(call submodule_enabled, $M, MALI400PP),0)
 	# Mali-400 PP in use
diff --git a/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c
new file mode 100644
index 0000000..1213e7b
--- /dev/null
+++ b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#include <linux/devfreq.h>
+#include <linux/platform_device.h>
+#include "mali_kernel_devfreq.h"
+#include "mali_osk.h"
+#include "mali_platform.h"
+#include "mali_linux_pm.h"
+
+#define MALI_GPU_UTILIZATION_PERIOD	500
+
+static _mali_osk_lock_t *time_data_lock;
+
+static _mali_osk_atomic_t num_running_cores;
+
+static u64 period_start_time = 0;
+static u64 work_start_time = 0;
+static u64 accumulated_work_time = 0;
+static mali_bool timer_running = MALI_FALSE;
+
+static struct devfreq *mali_devfreq;
+
+static int mali_get_dev_status(struct device *dev,
+				struct devfreq_dev_status *stat)
+{
+	u64 time_now;
+	u64 time_period;
+
+	_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+	if (accumulated_work_time == 0 && work_start_time == 0)
+	{
+		/* No work done for this period, report zero usage */
+		stat->total_time = 0;
+		stat->busy_time = 0;
+		stat->current_frequency = get_mali_platform_cur_freq();
+
+		_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+		return 0;
+	}
+
+	time_now = _mali_osk_time_get_ns();
+	time_period = time_now - period_start_time;
+
+	/* If we are currently busy, update working period up to now */
+	if (work_start_time != 0)
+	{
+		accumulated_work_time += (time_now - work_start_time);
+		work_start_time = time_now;
+	}
+
+	stat->total_time = time_period;
+	stat->busy_time = accumulated_work_time;
+	stat->current_frequency = get_mali_platform_cur_freq();
+
+	accumulated_work_time = 0;
+	/* start a new period */
+	period_start_time = time_now;
+	_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+	return 0;
+}
+
+static int mali_set_target_freq(struct device *dev,
+				unsigned long *freq,
+				u32 flags)
+{
+	mali_gpu_utilization_handler(*freq);
+	return 0;
+}
+
+static int mali_get_cur_freq(struct device *dev, unsigned long *freq)
+{
+	*freq = get_mali_platform_cur_freq();
+	return 0;
+}
+
+static struct devfreq_dev_profile mali_devfreq_profile = {
+	.polling_ms = MALI_GPU_UTILIZATION_PERIOD,
+	.initial_freq = 0,
+	.target = mali_set_target_freq,
+	.get_dev_status = mali_get_dev_status,
+	.get_cur_freq = mali_get_cur_freq,
+};
+
+_mali_osk_errcode_t mali_utilization_init(void)
+{
+	/* Register mali devfreq with ondemand governor */
+	mali_devfreq = devfreq_add_device(&mali_gpu_device.dev,
+					&mali_devfreq_profile,
+					&devfreq_simple_ondemand,
+					NULL);
+	if (NULL == mali_devfreq)
+	{
+		return _MALI_OSK_ERR_FAULT;
+	}
+
+	time_data_lock = _mali_osk_lock_init( 0, 0, 0 );
+	if (NULL == time_data_lock)
+	{
+		return _MALI_OSK_ERR_FAULT;
+	}
+
+	_mali_osk_atomic_init(&num_running_cores, 0);
+
+	return _MALI_OSK_ERR_OK;
+}
+
+void mali_utilization_suspend(void)
+{
+	if (timer_running == MALI_TRUE)
+	{
+		devfreq_suspend_device(mali_devfreq);
+		_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+		timer_running = MALI_FALSE;
+		work_start_time = 0;
+		period_start_time = 0;
+		accumulated_work_time = 0;
+		_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+	}
+}
+
+void mali_utilization_resume(void)
+{
+	devfreq_resume_device(mali_devfreq);
+}
+
+void mali_utilization_term(void)
+{
+	devfreq_remove_device(mali_devfreq);
+	mali_devfreq = NULL;
+
+	timer_running = MALI_FALSE;
+
+	_mali_osk_atomic_term(&num_running_cores);
+
+	_mali_osk_lock_term(time_data_lock);
+}
+
+void mali_utilization_core_start(void)
+{
+	if (_mali_osk_atomic_inc_return(&num_running_cores) == 1)
+	{
+		/*
+		 * We went from zero cores working, to one core working,
+		 * we now consider the entire GPU for being busy
+		 */
+		_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+		work_start_time = _mali_osk_time_get_ns();
+
+		if (timer_running != MALI_TRUE)
+		{
+			timer_running = MALI_TRUE;
+			period_start_time = work_start_time;
+		}
+
+		_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+	}
+}
+
+void mali_utilization_core_end(void)
+{
+	if (_mali_osk_atomic_dec_return(&num_running_cores) == 0)
+	{
+		/*
+		 * No more cores are working, so accumulate the time we was busy.
+		 */
+		u64 time_now;
+
+		_mali_osk_lock_wait(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+
+		time_now = _mali_osk_time_get_ns();
+		accumulated_work_time += (time_now - work_start_time);
+		work_start_time = 0;
+
+		_mali_osk_lock_signal(time_data_lock, _MALI_OSK_LOCKMODE_RW);
+	}
+}
diff --git a/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h
new file mode 100644
index 0000000..e0a76dc
--- /dev/null
+++ b/drivers/gpu/arm/mali/linux/mali_kernel_devfreq.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010-2011 ARM Limited. All rights reserved.
+ *
+ * This program is free software and is provided to you under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
+ *
+ * A copy of the licence is included with the program, and can also be obtained from Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __MALI_KERNEL_DEVFREQ_H__
+#define __MALI_KERNEL_DEVFREQ_H__
+
+#include "mali_osk.h"
+
+/**
+ * Initialize/start the Mali GPU utilization metrics reporting.
+ *
+ * @return _MALI_OSK_ERR_OK on success, otherwise failure.
+ */
+_mali_osk_errcode_t mali_utilization_init(void);
+
+/**
+ * Terminate the Mali GPU utilization metrics reporting
+ */
+void mali_utilization_term(void);
+
+/**
+ * Should be called when a job is about to execute a job
+ */
+void mali_utilization_core_start(void);
+
+/**
+ * Should be called to suspend the utilization monitoring during
+ * system suspend or device pm-runtime suspend
+ */
+void mali_utilization_suspend(void);
+
+/**
+ * Should be called to resume the utilization monitoring during
+ * system resume or device pm-runtime resume
+ */
+void mali_utilization_resume(void);
+
+/**
+ * Should be called when a job has completed executing a job
+ */
+void mali_utilization_core_end(void);
+
+
+#endif /* __MALI_KERNEL_DEVFREQ_H__ */
diff --git a/drivers/gpu/arm/mali/linux/mali_kernel_pm.c b/drivers/gpu/arm/mali/linux/mali_kernel_pm.c
index 0c03678..958164e 100644
--- a/drivers/gpu/arm/mali/linux/mali_kernel_pm.c
+++ b/drivers/gpu/arm/mali/linux/mali_kernel_pm.c
@@ -40,6 +40,10 @@
 #include "mali_kernel_utilization.h"
 #endif /* MALI_GPU_UTILIZATION */
 
+#if MALI_GPU_DEVFREQ
+#include "mali_kernel_devfreq.h"
+#endif /* MALI_GPU_DEVFREQ */
+
 #if MALI_POWER_MGMT_TEST_SUITE
 #ifdef CONFIG_PM
 #include "mali_linux_pm_testsuite.h"
@@ -418,6 +422,9 @@ static int mali_pm_os_resume_on_hibernation(struct device *dev)
  */
 static int mali_device_runtime_suspend(struct device *dev)
 {
+#if MALI_GPU_DEVFREQ
+	mali_utilization_suspend();
+#endif /* MALI_GPU_DEVFREQ */
 	MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time suspended \n" ));
 	return 0;
 }
@@ -426,6 +433,9 @@ static int mali_device_runtime_suspend(struct device *dev)
  */
 static int mali_device_runtime_resume(struct device *dev)
 {
+#if MALI_GPU_DEVFREQ
+	mali_utilization_resume();
+#endif /* MALI_GPU_DEVFREQ */
 	MALI_DEBUG_PRINT(4, ("PMMDEBUG: Mali device Run time Resumed \n" ));
 	return 0;
 }
diff --git a/drivers/gpu/arm/mali/platform/default/mali_platform.c b/drivers/gpu/arm/mali/platform/default/mali_platform.c
index d966f25..8247856 100644
--- a/drivers/gpu/arm/mali/platform/default/mali_platform.c
+++ b/drivers/gpu/arm/mali/platform/default/mali_platform.c
@@ -40,4 +40,7 @@ void set_mali_parent_power_domain(void* dev)
 {
 }
 
-
+unsigned long get_mali_platform_cur_freq(void)
+{
+    return 0;
+}
diff --git a/drivers/gpu/arm/mali/platform/mali_platform.h b/drivers/gpu/arm/mali/platform/mali_platform.h
index 078bcef..f1bb2b5 100644
--- a/drivers/gpu/arm/mali/platform/mali_platform.h
+++ b/drivers/gpu/arm/mali/platform/mali_platform.h
@@ -93,6 +93,14 @@ void mali_gpu_utilization_handler(u32 utilization);
  */
 void set_mali_parent_power_domain(void* dev);
 
+/** @brief Get MALI current running frequency
+ *
+ * This function gets the current running frequency of MALI
+ *
+ * @return frequency in Hz
+ */
+unsigned long get_mali_platform_cur_freq(void);
+
 #ifdef __cplusplus
 }
 #endif
