Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 70335921 authored by Mike Tipton's avatar Mike Tipton
Browse files

clk: qcom: Add common runtime_pm support



Add common runtime_pm initialization and callback functions to allow
clock providers to vote clocks, interconnects, and regulators in
runtime_suspend and runtime_resume.

Change-Id: I97588feae47016b8375849c5926495c1d73f792d
Signed-off-by: default avatarMike Tipton <mdtipton@codeaurora.org>
parent 2ac873fb
Loading
Loading
Loading
Loading
+123 −0
Original line number Diff line number Diff line
@@ -12,6 +12,10 @@
#include <linux/reset-controller.h>
#include <linux/of.h>
#include <linux/clk/qcom.h>
#include <linux/clk.h>
#include <linux/interconnect.h>
#include <linux/pm_clock.h>
#include <linux/pm_runtime.h>

#include "common.h"
#include "clk-opp.h"
@@ -394,4 +398,123 @@ int qcom_clk_get_voltage(struct clk *clk, unsigned long rate)
}
EXPORT_SYMBOL(qcom_clk_get_voltage);

int qcom_cc_runtime_init(struct platform_device *pdev,
			 struct qcom_cc_desc *desc)
{
	struct device *dev = &pdev->dev;
	struct clk *clk;
	int ret;

	clk = clk_get_optional(dev, "iface");
	if (IS_ERR(clk)) {
		if (PTR_ERR(clk) != -EPROBE_DEFER)
			dev_err(dev, "unable to get iface clock\n");
		return PTR_ERR(clk);
	}
	clk_put(clk);

	ret = clk_regulator_init(dev, desc);
	if (ret)
		return ret;

	desc->path = of_icc_get(dev, NULL);
	if (IS_ERR(desc->path)) {
		if (PTR_ERR(desc->path) != -EPROBE_DEFER)
			dev_err(dev, "error getting path\n");
		return PTR_ERR(desc->path);
	}

	platform_set_drvdata(pdev, desc);
	pm_runtime_enable(dev);

	ret = pm_clk_create(dev);
	if (ret)
		goto disable_pm_runtime;

	ret = pm_clk_add(dev, "iface");
	if (ret < 0) {
		dev_err(dev, "failed to acquire iface clock\n");
		goto destroy_pm_clk;
	}

	return 0;

destroy_pm_clk:
	pm_clk_destroy(dev);

disable_pm_runtime:
	pm_runtime_disable(dev);
	icc_put(desc->path);

	return ret;
}
EXPORT_SYMBOL(qcom_cc_runtime_init);

int qcom_cc_runtime_resume(struct device *dev)
{
	struct qcom_cc_desc *desc = dev_get_drvdata(dev);
	struct clk_vdd_class_data vdd_data = {0};
	int ret;
	int i;

	for (i = 0; i < desc->num_clk_regulators; i++) {
		vdd_data.vdd_class = desc->clk_regulators[i];
		if (!vdd_data.vdd_class)
			continue;

		ret = clk_vote_vdd_level(&vdd_data, 1);
		if (ret) {
			dev_warn(dev, "%s: failed to vote voltage\n", __func__);
			return ret;
		}
	}

	if (desc->path) {
		ret = icc_set_bw(desc->path, 0, 1);
		if (ret) {
			dev_warn(dev, "%s: failed to vote bw\n", __func__);
			return ret;
		}
	}

	ret = pm_clk_resume(dev);
	if (ret)
		dev_warn(dev, "%s: failed to enable clocks\n", __func__);

	return ret;
}
EXPORT_SYMBOL(qcom_cc_runtime_resume);

int qcom_cc_runtime_suspend(struct device *dev)
{
	struct qcom_cc_desc *desc = dev_get_drvdata(dev);
	struct clk_vdd_class_data vdd_data = {0};
	int ret;
	int i;

	ret = pm_clk_suspend(dev);
	if (ret)
		dev_warn(dev, "%s: failed to disable clocks\n", __func__);

	if (desc->path) {
		ret = icc_set_bw(desc->path, 0, 0);
		if (ret)
			dev_warn(dev, "%s: failed to unvote bw\n", __func__);
	}

	for (i = 0; i < desc->num_clk_regulators; i++) {
		vdd_data.vdd_class = desc->clk_regulators[i];
		if (!vdd_data.vdd_class)
			continue;

		ret = clk_unvote_vdd_level(&vdd_data, 1);
		if (ret)
			dev_warn(dev, "%s: failed to unvote voltage\n",
				 __func__);
	}

	return 0;
}
EXPORT_SYMBOL(qcom_cc_runtime_suspend);

MODULE_LICENSE("GPL v2");
+7 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ struct qcom_cc_desc {
	size_t num_clk_hws;
	struct clk_vdd_class **clk_regulators;
	size_t num_clk_regulators;
	struct icc_path *path;
};

/**
@@ -77,4 +78,10 @@ extern int qcom_cc_probe_by_index(struct platform_device *pdev, int index,
				  const struct qcom_cc_desc *desc);
extern const struct clk_ops clk_dummy_ops;
void qcom_cc_sync_state(struct device *dev, const struct qcom_cc_desc *desc);

int qcom_cc_runtime_init(struct platform_device *pdev,
			 struct qcom_cc_desc *desc);
int qcom_cc_runtime_suspend(struct device *dev);
int qcom_cc_runtime_resume(struct device *dev);

#endif
+3 −0
Original line number Diff line number Diff line
@@ -197,6 +197,9 @@ int clk_regulator_init(struct device *dev, const struct qcom_cc_desc *desc)
		vdd_class = desc->clk_regulators[i];

		for (cnt = 0; cnt < vdd_class->num_regulators; cnt++) {
			if (vdd_class->regulator[cnt])
				continue;

			name = vdd_class->regulator_names[cnt];
			regulator = devm_regulator_get(dev, name);
			if (IS_ERR(regulator)) {