diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index fc2ea336ef4b..3575cbdcd29e 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -74,6 +74,11 @@ config DEVFREQ_GOV_PASSIVE
 	  through sysfs entries. The passive governor recommends that
 	  devfreq device uses the OPP table to get the frequency/voltage.
 
+config DEVFREQ_GOV_BUSFREQ
+	tristate "Busfreq"
+	help
+	  Sets the frequency that compatible drivers request it to set.
+
 comment "DEVFREQ Drivers"
 
 config ARM_EXYNOS_BUS_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 61d0edee16f7..657b0b6d92c4 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE)	+= governor_performance.o
 obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE)	+= governor_powersave.o
 obj-$(CONFIG_DEVFREQ_GOV_USERSPACE)	+= governor_userspace.o
 obj-$(CONFIG_DEVFREQ_GOV_PASSIVE)	+= governor_passive.o
+obj-$(CONFIG_DEVFREQ_GOV_BUSFREQ)	+= governor_busfreq.o
 
 # DEVFREQ Drivers
 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ)	+= exynos-bus.o
diff --git a/drivers/devfreq/governor_busfreq.c b/drivers/devfreq/governor_busfreq.c
new file mode 100644
index 000000000000..e12d64e9a09b
--- /dev/null
+++ b/drivers/devfreq/governor_busfreq.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  linux/drivers/devfreq/governor_busfreq.c
+ *
+ *  Copyright (C) 2020 Purism SPC
+ */
+
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/devfreq.h>
+#include <linux/pm.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include "governor.h"
+
+struct busfreq_data {
+	unsigned long user_frequency;
+	bool valid;
+	struct devfreq *df;
+	unsigned int high_count;
+};
+
+static struct busfreq_data *bfdata = NULL;
+
+static int devfreq_busfreq_func(struct devfreq *df, unsigned long *freq)
+{
+	if (bfdata->valid)
+		*freq = bfdata->user_frequency;
+	else
+		*freq = df->previous_freq; /* No user freq specified yet */
+
+	return 0;
+}
+
+int devfreq_busfreq_request(unsigned long freq)
+{
+	struct devfreq *devfreq;
+	int err = 0;
+
+	if (!bfdata) {
+		pr_info("%s: governor not available\n", __func__);
+		return -ENODEV;
+	}
+
+	if (freq != DEVFREQ_BUSFREQ_HIGH) {
+		pr_err("%s: undefined frequency\n", __func__);
+		return -EINVAL;
+	}
+
+	if (freq == DEVFREQ_BUSFREQ_HIGH)
+		bfdata->high_count++;
+
+	devfreq = bfdata->df;
+
+	mutex_lock(&devfreq->lock);
+
+	bfdata->user_frequency = freq;
+	bfdata->valid = true;
+	err = update_devfreq(devfreq); /* calls our get_target_freq */
+	if (err)
+		dev_err(&devfreq->dev, "update_devfreq failed: %d\n", err);
+
+	mutex_unlock(&devfreq->lock);
+
+	return err;
+}
+EXPORT_SYMBOL(devfreq_busfreq_request);
+
+void devfreq_busfreq_release(unsigned long freq)
+{
+	struct devfreq *devfreq;
+	int err = 0;
+
+	if (!bfdata) {
+		pr_info("%s: governor not available\n", __func__);
+		return;
+	}
+
+	if (freq != DEVFREQ_BUSFREQ_HIGH) {
+		pr_err("%s: undefined frequency\n", __func__);
+		return;
+	}
+
+	if (freq == DEVFREQ_BUSFREQ_HIGH && bfdata->high_count > 0)
+		bfdata->high_count--;
+
+	if (bfdata->high_count)
+		return;
+
+	devfreq = bfdata->df;
+
+	mutex_lock(&devfreq->lock);
+
+	bfdata->user_frequency = DEVFREQ_BUSFREQ_LOW;
+	bfdata->valid = true;
+	err = update_devfreq(devfreq); /* calls our get_target_freq */
+	if (err)
+		dev_err(&devfreq->dev, "update_devfreq failed: %d\n", err);
+
+	mutex_unlock(&devfreq->lock);
+}
+EXPORT_SYMBOL(devfreq_busfreq_release);
+
+static int busfreq_init(struct devfreq *devfreq)
+{
+	int err = 0;
+
+	bfdata = kzalloc(sizeof(struct busfreq_data),
+		      GFP_KERNEL);
+	if (!bfdata) {
+		err = -ENOMEM;
+		goto out;
+	}
+	bfdata->valid = false;
+	devfreq->data = bfdata;
+	bfdata->df = devfreq;
+
+out:
+	return err;
+}
+
+static void busfreq_exit(struct devfreq *devfreq)
+{
+	if (bfdata)
+		kfree(bfdata);
+
+	devfreq->data = NULL;
+}
+
+static int devfreq_busfreq_handler(struct devfreq *devfreq,
+				   unsigned int event, void *data)
+{
+	int ret = 0;
+
+	switch (event) {
+	case DEVFREQ_GOV_START:
+		ret = busfreq_init(devfreq);
+		break;
+	case DEVFREQ_GOV_STOP:
+		busfreq_exit(devfreq);
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static struct devfreq_governor devfreq_busfreq = {
+	.name = "busfreq",
+	.get_target_freq = devfreq_busfreq_func,
+	.event_handler = devfreq_busfreq_handler,
+};
+
+static int __init devfreq_busfreq_init(void)
+{
+	return devfreq_add_governor(&devfreq_busfreq);
+}
+subsys_initcall(devfreq_busfreq_init);
+
+static void __exit devfreq_busfreq_exit(void)
+{
+	int ret;
+
+	ret = devfreq_remove_governor(&devfreq_busfreq);
+	if (ret)
+		pr_err("%s: failed remove governor %d\n", __func__, ret);
+
+	return;
+}
+module_exit(devfreq_busfreq_exit);
+MODULE_LICENSE("GPL");
diff --git a/include/linux/devfreq.h b/include/linux/devfreq.h
index 678391c1bb0f..df1bf6928d87 100644
--- a/include/linux/devfreq.h
+++ b/include/linux/devfreq.h
@@ -23,6 +23,7 @@
 #define DEVFREQ_GOV_POWERSAVE		"powersave"
 #define DEVFREQ_GOV_USERSPACE		"userspace"
 #define DEVFREQ_GOV_PASSIVE		"passive"
+#define DEVFREQ_GOV_BUSFREQ		"busfreq"
 
 /* DEVFREQ notifier interface */
 #define DEVFREQ_TRANSITION_NOTIFIER	(0)
@@ -310,6 +311,27 @@ struct devfreq_passive_data {
 };
 #endif
 
+/*
+ * "powersave" by default
+ * giving drivers the option to require "performance"
+ */
+#define DEVFREQ_BUSFREQ_HIGH			ULONG_MAX
+#define DEVFREQ_BUSFREQ_LOW			0
+#if IS_ENABLED(CONFIG_DEVFREQ_GOV_BUSFREQ)
+extern int devfreq_busfreq_request(unsigned long freq);
+extern void devfreq_busfreq_release(unsigned long freq);
+#else
+static inline int devfreq_busfreq_request(unsigned long freq)
+{
+	return -ENOSYS;
+}
+
+static inline void devfreq_busfreq_release(unsigned long freq)
+{
+	return;
+}
+#endif
+
 #else /* !CONFIG_PM_DEVFREQ */
 static inline struct devfreq *devfreq_add_device(struct device *dev,
 					  struct devfreq_dev_profile *profile,
