diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 7494565..64bff8dc 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE)	+= cpufreq_powersave.o
 obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE)	+= cpufreq_userspace.o
 obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND)	+= cpufreq_ondemand.o
 obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)	+= cpufreq_conservative.o
+obj-$(CONFIG_CPU_FREQ_GOV_LAB)		+= cpufreq_lab.o
 obj-$(CONFIG_CPU_FREQ_GOV_COMMON)		+= cpufreq_governor.o
 
 obj-$(CONFIG_GENERIC_CPUFREQ_CPU0)	+= cpufreq-cpu0.o
diff --git a/drivers/cpufreq/cpufreq_lab.c b/drivers/cpufreq/cpufreq_lab.c
new file mode 100644
index 0000000..153c06b
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_lab.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com
+ *		Jonghwa Lee <jonghw3.lee@samusng.com>
+ *		Lukasz Majewski <l.majewski@samsung.com>
+ *
+ * LAB (Legacy Application Boost) cpufreq governor
+ *
+ * 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/cpufreq.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/kernel_stat.h>
+#include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/percpu-defs.h>
+#include <linux/sysfs.h>
+#include <linux/tick.h>
+#include <linux/types.h>
+#include <linux/cpuidle.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "cpufreq_governor.h"
+
+#define MAX_HIST		5
+
+#define LB_BOOST_ENABLE        ~0UL
+#define LB_MIN_FREQ            ~1UL
+#define LB_ONDEMAND             0
+
+/*
+ * Pre-calculated summation of weight, 0.5
+ * 1
+ * 1 + 0.5^1 = 1.5
+ * 1 + 0.5^1 + 0.5^2 = 1.75
+ * 1 + 0.5^1 + 0.5^2 + 0.5^3 = 1.87
+ * 1 + 0.5^1 + 0.5^2 + 0.5^3 + 0.5^4 = 1.93
+ */
+static int history_weight_sum[] = { 100, 150, 175, 187, 193 };
+
+static unsigned int *idle_avg;
+static unsigned int *idle_hist;
+static int idle_cpus, lb_threshold = 90;
+static unsigned int *lb_ctrl_table, lb_load;
+static int lb_ctrl_table_size, lb_num_of_states;
+static bool boost_init_state;
+
+static DECLARE_BITMAP(boost_hist, MAX_HIST);
+DECLARE_PER_CPU(struct od_cpu_dbs_info_s, od_cpu_dbs_info);
+
+struct cpufreq_governor cpufreq_gov_lab;
+
+
+static struct lb_wq_boost_data {
+	bool state;
+	struct work_struct work;
+} lb_boost_data;
+
+/*
+ * Calculate average of idle time with weighting 50% less to older one.
+ * With weight, average can be affected by current phase more rapidly than
+ * normal average. And it also has tolerance for temporary fluctuation of
+ * idle time as normal average has.
+ *
+ * Weigted average = sum(ai * wi) / sum(wi)
+ */
+static inline int cpu_idle_calc_avg(unsigned int *p, int size)
+{
+	int i, sum;
+
+	for (i = 0, sum = 0; i < size; p++, i++) {
+		sum += *p;
+		*p >>= 1;
+	}
+	sum *= 100;
+
+	return (int) (sum / history_weight_sum[size - 1]);
+}
+
+static unsigned int lb_chose_freq(unsigned int load, int idle_cpus)
+{
+	unsigned int p, q = 100 / lb_num_of_states;
+	int idx;
+
+	for (idx = 0, p = q; idx < lb_num_of_states; idx++, p += q)
+		if (load <= p)
+			break;
+
+	return *(lb_ctrl_table + (lb_num_of_states * idle_cpus) + idx);
+}
+
+static void lb_cpufreq_boost_work(struct work_struct *work)
+{
+	struct lb_wq_boost_data *d = container_of(work,
+						  struct lb_wq_boost_data,
+						  work);
+	cpufreq_boost_trigger_state(d->state);
+}
+
+static struct common_dbs_data lb_dbs_cdata;
+/*
+ * LAB governor policy adjustement
+ */
+static void lb_check_cpu(int cpu, unsigned int load)
+{
+	struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu);
+	struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy;
+	unsigned int freq = 0, op;
+	static int cnt;
+	int i, idx, bs;
+
+	idle_cpus = 0;
+	lb_load = load;
+	idx = cnt++ % MAX_HIST;
+
+	for_each_possible_cpu(i) {
+		struct od_cpu_dbs_info_s *dbs_cpu_info =
+			&per_cpu(od_cpu_dbs_info, i);
+
+		idle_hist[i * MAX_HIST + idx] = dbs_cpu_info->idle_time;
+		idle_avg[i] = cpu_idle_calc_avg(&idle_hist[i * MAX_HIST],
+					cnt < MAX_HIST ? cnt : MAX_HIST);
+
+		if (idle_avg[i] > lb_threshold)
+			idle_cpus++;
+	}
+
+	if (idle_cpus < 0 || idle_cpus > num_possible_cpus()) {
+		pr_warn("%s: idle_cpus: %d out of range\n", __func__,
+			idle_cpus);
+		return;
+	}
+
+	if (!lb_ctrl_table)
+		return;
+
+	op = lb_chose_freq(load, idle_cpus);
+	if (op == LB_BOOST_ENABLE)
+		set_bit(idx, boost_hist);
+	else
+		clear_bit(idx, boost_hist);
+
+	bs = cpufreq_boost_enabled();
+	/*
+	 * - To disable boost -
+	 *
+	 * Operation different than LB_BOOST_ENABLE is
+	 * required for at least MAX_HIST previous operations
+	 */
+	if (bs && bitmap_empty(boost_hist, MAX_HIST)) {
+		lb_boost_data.state = false;
+		schedule_work_on(cpu, &lb_boost_data.work);
+	}
+
+	/*
+	 * - To enable boost -
+	 *
+	 * Only (MAX_HIST - 1) bits are required. This allows entering
+	 * BOOST mode earlier, since we skip one "round" of LAB operation
+	 * before work is executed.
+	 */
+	if (!bs &&
+	    (bitmap_weight(boost_hist, MAX_HIST) == (MAX_HIST - 1))) {
+		lb_boost_data.state = true;
+		schedule_work_on(cpu, &lb_boost_data.work);
+	}
+
+	switch (op) {
+	case LB_BOOST_ENABLE:
+		freq = policy->max;
+		break;
+
+	case LB_MIN_FREQ:
+		freq = policy->min;
+		break;
+
+	case LB_ONDEMAND:
+		od_check_cpu(cpu, load);
+		return;
+
+	default:
+		freq = op;
+	}
+
+	if (policy->cur == freq)
+		return;
+
+	__cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
+}
+
+static ssize_t show_load(struct kobject *kobj,
+			 struct attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", lb_load);
+}
+define_one_global_ro(load);
+
+static ssize_t show_idle_cpus_num(struct kobject *kobj,
+				  struct attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", idle_cpus);
+}
+define_one_global_ro(idle_cpus_num);
+
+static ssize_t show_idle_avg_cpus_val(struct kobject *kobj,
+				      struct attribute *attr, char *buf)
+{
+	char off;
+	int i;
+
+	for (i = 0, off = 0; i < num_possible_cpus(); i++)
+		off += sprintf(buf + off, "%u ", idle_avg[i]);
+
+	*(buf + off - 1) = '\n';
+
+	return off;
+}
+define_one_global_ro(idle_avg_cpus_val);
+
+static ssize_t show_idle_threshold(struct kobject *kobj,
+				   struct attribute *attr, char *buf)
+{
+	return sprintf(buf, "%u\n", lb_threshold);
+}
+
+static ssize_t store_idle_threshold(struct kobject *a, struct attribute *b,
+				    const char *buf, size_t count)
+{
+	unsigned int val;
+	int ret;
+
+	ret = sscanf(buf, "%u", &val);
+	if (ret != 1)
+		return -EINVAL;
+
+	if (val < 0 || val > 100) {
+		pr_err("%s: Only value in a range 0 to 100 accepted\n",
+		       __func__);
+		return -EINVAL;
+	}
+
+	lb_threshold = val;
+	return count;
+}
+define_one_global_rw(idle_threshold);
+
+ssize_t store_sampling_rate(struct kobject *a, struct attribute *b,
+				   const char *buf, size_t count)
+{
+	struct dbs_data *dbs_data = lb_dbs_cdata.gdbs_data;
+	unsigned int input;
+	int ret;
+	ret = sscanf(buf, "%u", &input);
+	if (ret != 1)
+		return -EINVAL;
+
+	update_sampling_rate(dbs_data, input);
+	return count;
+}
+
+static ssize_t show_sampling_rate(struct kobject *kobj, struct attribute *attr,
+				  char *buf)
+{
+	struct od_dbs_tuners *tuners = lb_dbs_cdata.gdbs_data->tuners;
+
+	return sprintf(buf, "%u\n", tuners->sampling_rate);
+}
+define_one_global_rw(sampling_rate);
+
+static ssize_t show_sampling_rate_min(struct kobject *kobj,
+				      struct attribute *attr, char *buf)
+{
+	struct dbs_data *dbs_data = lb_dbs_cdata.gdbs_data;
+
+	return sprintf(buf, "%u\n", dbs_data->min_sampling_rate);
+}
+define_one_global_ro(sampling_rate_min);
+
+static struct attribute *dbs_attributes_gov_sys[] = {
+	&sampling_rate_min.attr,
+	&idle_avg_cpus_val.attr,
+	&idle_threshold.attr,
+	&idle_cpus_num.attr,
+	&sampling_rate.attr,
+	&load.attr,
+	NULL
+};
+
+static struct attribute_group lb_attr_group_gov_sys = {
+	.attrs = dbs_attributes_gov_sys,
+	.name = "lab",
+};
+
+static int lb_ctrl_table_of_init(struct device_node *dn,
+				 unsigned int **ctrl_tab, int size)
+{
+	struct property *pp;
+	int len;
+
+	pp = of_find_property(dn, "lab-ctrl-freq", &len);
+	if (!pp) {
+		pr_err("%s: Property: 'lab-ctrl-freq'  not found\n", __func__);
+		return -ENODEV;
+	}
+
+	if (len != (size * sizeof(**ctrl_tab))) {
+		pr_err("%s: Wrong 'lab-ctrl-freq' size\n", __func__);
+		return -EINVAL;
+	}
+
+	*ctrl_tab = kzalloc(len, GFP_KERNEL);
+	if (!*ctrl_tab) {
+		pr_err("%s: Not enough memory for LAB control structure\n",
+		       __func__);
+		return -ENOMEM;
+	}
+
+	if (of_property_read_u32_array(dn, pp->name, *ctrl_tab, size)) {
+		pr_err("Property: %s cannot be read!\n", pp->name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int lb_of_init(void)
+{
+	struct device_node *dn;
+	struct property *pp;
+	int ret;
+
+	dn = of_find_node_by_path("/cpus/cpu@0");
+	if (!dn) {
+		pr_err("%s: Node: '/cpus/cpu@0/' not found\n", __func__);
+		return -ENODEV;
+	}
+
+	pp = of_find_property(dn, "lab-num-of-states", NULL);
+	if (!pp) {
+		pr_err("%s: Property: 'lab-num-of-states'  not found\n",
+		       __func__);
+		ret = -ENODEV;
+		goto dn_err;
+	}
+	lb_num_of_states = be32_to_cpup(pp->value);
+
+	lb_ctrl_table_size = lb_num_of_states * (num_possible_cpus() + 1);
+	ret = lb_ctrl_table_of_init(dn, &lb_ctrl_table, lb_ctrl_table_size);
+	if (ret) {
+		kfree(lb_ctrl_table);
+		lb_ctrl_table = NULL;
+		pr_err("%s: Cannot parse LAB control structure from OF\n",
+		       __func__);
+		return ret;
+	}
+
+dn_err:
+	of_node_put(dn);
+	return ret;
+}
+
+static int lb_init(struct dbs_data *dbs_data)
+{
+	int ret;
+
+	idle_avg = kzalloc(num_possible_cpus() * sizeof(*idle_avg), GFP_KERNEL);
+	if (!idle_avg) {
+		pr_err("%s: Not enough memory", __func__);
+		return -ENOMEM;
+	}
+
+	idle_hist = kzalloc(num_possible_cpus() * MAX_HIST * sizeof(*idle_hist),
+			    GFP_KERNEL);
+	if (!idle_hist) {
+		pr_err("%s: Not enough memory", __func__);
+		ret = -ENOMEM;
+		goto err_idle_avg;
+	}
+
+	ret = lb_of_init();
+	if (ret)
+		goto err_idle_hist;
+
+	boost_init_state = cpufreq_boost_enabled();
+	if (boost_init_state)
+		cpufreq_boost_trigger_state(false);
+
+	od_init(dbs_data);
+
+	INIT_WORK(&lb_boost_data.work, lb_cpufreq_boost_work);
+
+	return 0;
+
+err_idle_hist:
+	kfree(idle_hist);
+err_idle_avg:
+	kfree(idle_avg);
+
+	return ret;
+}
+
+void lb_exit(struct dbs_data *dbs_data)
+{
+	od_exit(dbs_data);
+
+	kfree(lb_ctrl_table);
+	lb_ctrl_table = NULL;
+
+	cpufreq_boost_trigger_state(boost_init_state);
+
+	kfree(idle_avg);
+	kfree(idle_hist);
+}
+
+define_get_cpu_dbs_routines(od_cpu_dbs_info);
+
+static struct common_dbs_data lb_dbs_cdata = {
+	.governor = GOV_LAB,
+	.attr_group_gov_sys = &lb_attr_group_gov_sys,
+	.get_cpu_cdbs = get_cpu_cdbs,
+	.get_cpu_dbs_info_s = get_cpu_dbs_info_s,
+	.gov_dbs_timer = od_dbs_timer,
+	.gov_check_cpu = lb_check_cpu,
+	.gov_ops = &od_ops,
+	.init = lb_init,
+	.exit = lb_exit,
+};
+
+static int lb_cpufreq_governor_dbs(struct cpufreq_policy *policy,
+		unsigned int event)
+{
+	return cpufreq_governor_dbs(policy, &lb_dbs_cdata, event);
+}
+
+struct cpufreq_governor cpufreq_gov_lab = {
+	.name			= "lab",
+	.governor		= lb_cpufreq_governor_dbs,
+	.max_transition_latency = TRANSITION_LATENCY_LIMIT,
+	.owner			= THIS_MODULE,
+};
+
+static int __init cpufreq_gov_dbs_init(void)
+{
+	return cpufreq_register_governor(&cpufreq_gov_lab);
+}
+
+#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_LAB
+fs_initcall(cpufreq_gov_dbs_init);
+#else
+module_init(cpufreq_gov_dbs_init);
+#endif
