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

Commit 65d212e2 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "clk: qcom: lahaina: Add runtime_pm support"

parents 26ef6f32 5004b214
Loading
Loading
Loading
Loading
+22 −29
Original line number Original line Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/of_device.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>


#include <dt-bindings/clock/qcom,camcc-lahaina.h>
#include <dt-bindings/clock/qcom,camcc-lahaina.h>


@@ -1931,24 +1932,6 @@ static struct clk_branch cam_cc_csiphy5_clk = {
	},
	},
};
};


static struct clk_branch cam_cc_gdsc_clk = {
	.halt_reg = 0xc148,
	.halt_check = BRANCH_HALT,
	.clkr = {
		.enable_reg = 0xc148,
		.enable_mask = BIT(0),
		.hw.init = &(struct clk_init_data){
			.name = "cam_cc_gdsc_clk",
			.parent_data = &(const struct clk_parent_data){
				.hw = &cam_cc_xo_clk_src.clkr.hw,
			},
			.num_parents = 1,
			.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
			.ops = &clk_branch2_ops,
		},
	},
};

static struct clk_branch cam_cc_icp_ahb_clk = {
static struct clk_branch cam_cc_icp_ahb_clk = {
	.halt_reg = 0xc094,
	.halt_reg = 0xc094,
	.halt_check = BRANCH_HALT,
	.halt_check = BRANCH_HALT,
@@ -2866,7 +2849,6 @@ static struct clk_regmap *cam_cc_lahaina_clocks[] = {
	[CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr,
	[CAM_CC_CSIPHY4_CLK] = &cam_cc_csiphy4_clk.clkr,
	[CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr,
	[CAM_CC_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.clkr,
	[CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
	[CAM_CC_FAST_AHB_CLK_SRC] = &cam_cc_fast_ahb_clk_src.clkr,
	[CAM_CC_GDSC_CLK] = &cam_cc_gdsc_clk.clkr,
	[CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr,
	[CAM_CC_ICP_AHB_CLK] = &cam_cc_icp_ahb_clk.clkr,
	[CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr,
	[CAM_CC_ICP_CLK] = &cam_cc_icp_clk.clkr,
	[CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr,
	[CAM_CC_ICP_CLK_SRC] = &cam_cc_icp_clk_src.clkr,
@@ -2972,7 +2954,7 @@ static const struct regmap_config cam_cc_lahaina_regmap_config = {
	.fast_io = true,
	.fast_io = true,
};
};


static const struct qcom_cc_desc cam_cc_lahaina_desc = {
static struct qcom_cc_desc cam_cc_lahaina_desc = {
	.config = &cam_cc_lahaina_regmap_config,
	.config = &cam_cc_lahaina_regmap_config,
	.clks = cam_cc_lahaina_clocks,
	.clks = cam_cc_lahaina_clocks,
	.num_clks = ARRAY_SIZE(cam_cc_lahaina_clocks),
	.num_clks = ARRAY_SIZE(cam_cc_lahaina_clocks),
@@ -3014,23 +2996,22 @@ static int cam_cc_lahaina_fixup(struct platform_device *pdev,
static int cam_cc_lahaina_probe(struct platform_device *pdev)
static int cam_cc_lahaina_probe(struct platform_device *pdev)
{
{
	struct regmap *regmap;
	struct regmap *regmap;
	struct clk *clk;
	int ret;
	int ret;


	clk = devm_clk_get(&pdev->dev, "cfg_ahb_clk");
	if (IS_ERR(clk)) {
		if (PTR_ERR(clk) != -EPROBE_DEFER)
			dev_err(&pdev->dev, "Unable to get ahb clock handle\n");
		return PTR_ERR(clk);
	}
	devm_clk_put(&pdev->dev, clk);

	regmap = qcom_cc_map(pdev, &cam_cc_lahaina_desc);
	regmap = qcom_cc_map(pdev, &cam_cc_lahaina_desc);
	if (IS_ERR(regmap)) {
	if (IS_ERR(regmap)) {
		dev_err(&pdev->dev, "Failed to map cam CC registers\n");
		dev_err(&pdev->dev, "Failed to map cam CC registers\n");
		return PTR_ERR(regmap);
		return PTR_ERR(regmap);
	}
	}


	ret = qcom_cc_runtime_init(pdev, &cam_cc_lahaina_desc);
	if (ret)
		return ret;

	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret)
		return ret;

	clk_lucid_5lpe_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config);
	clk_lucid_5lpe_pll_configure(&cam_cc_pll0, regmap, &cam_cc_pll0_config);
	clk_lucid_5lpe_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config);
	clk_lucid_5lpe_pll_configure(&cam_cc_pll1, regmap, &cam_cc_pll1_config);
	clk_zonda_5lpe_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config);
	clk_zonda_5lpe_pll_configure(&cam_cc_pll2, regmap, &cam_cc_pll2_config);
@@ -3043,12 +3024,19 @@ static int cam_cc_lahaina_probe(struct platform_device *pdev)
	if (ret)
	if (ret)
		return ret;
		return ret;


	/*
	 * Keep clocks always enabled:
	 *	cam_cc_gdsc_clk
	 */
	regmap_update_bits(regmap, 0xc148, BIT(0), BIT(0));

	ret = qcom_cc_really_probe(pdev, &cam_cc_lahaina_desc, regmap);
	ret = qcom_cc_really_probe(pdev, &cam_cc_lahaina_desc, regmap);
	if (ret) {
	if (ret) {
		dev_err(&pdev->dev, "Failed to register CAM CC clocks\n");
		dev_err(&pdev->dev, "Failed to register CAM CC clocks\n");
		return ret;
		return ret;
	}
	}


	pm_runtime_put_sync(&pdev->dev);
	dev_info(&pdev->dev, "Registered CAM CC clocks\n");
	dev_info(&pdev->dev, "Registered CAM CC clocks\n");


	return ret;
	return ret;
@@ -3059,12 +3047,17 @@ static void cam_cc_lahaina_sync_state(struct device *dev)
	qcom_cc_sync_state(dev, &cam_cc_lahaina_desc);
	qcom_cc_sync_state(dev, &cam_cc_lahaina_desc);
}
}


static const struct dev_pm_ops cam_cc_lahaina_pm_ops = {
	SET_RUNTIME_PM_OPS(qcom_cc_runtime_suspend, qcom_cc_runtime_resume, NULL)
};

static struct platform_driver cam_cc_lahaina_driver = {
static struct platform_driver cam_cc_lahaina_driver = {
	.probe = cam_cc_lahaina_probe,
	.probe = cam_cc_lahaina_probe,
	.driver = {
	.driver = {
		.name = "lahaina-cam_cc",
		.name = "lahaina-cam_cc",
		.of_match_table = cam_cc_lahaina_match_table,
		.of_match_table = cam_cc_lahaina_match_table,
		.sync_state = cam_cc_lahaina_sync_state,
		.sync_state = cam_cc_lahaina_sync_state,
		.pm = &cam_cc_lahaina_pm_ops,
	},
	},
};
};


+18 −0
Original line number Original line Diff line number Diff line
@@ -266,12 +266,22 @@ static u32 get_mux_divs(struct clk_hw *mux)


static int clk_debug_measure_get(void *data, u64 *val)
static int clk_debug_measure_get(void *data, u64 *val)
{
{
	struct clk_regmap *rclk = NULL;
	struct clk_debug_mux *mux;
	struct clk_debug_mux *mux;
	struct clk_hw *hw = data;
	struct clk_hw *hw = data;
	struct clk_hw *parent;
	struct clk_hw *parent;
	int ret = 0;
	int ret = 0;
	u32 regval;
	u32 regval;


	if (clk_is_regmap_clk(hw))
		rclk = to_clk_regmap(hw);

	if (rclk) {
		ret = clk_runtime_get_regmap(rclk);
		if (ret)
			return ret;
	}

	mutex_lock(&clk_debug_lock);
	mutex_lock(&clk_debug_lock);


	ret = clk_find_and_set_parent(measure, hw);
	ret = clk_find_and_set_parent(measure, hw);
@@ -306,6 +316,8 @@ static int clk_debug_measure_get(void *data, u64 *val)
	}
	}
exit:
exit:
	mutex_unlock(&clk_debug_lock);
	mutex_unlock(&clk_debug_lock);
	if (rclk)
		clk_runtime_put_regmap(rclk);
	return ret;
	return ret;
}
}


@@ -501,8 +513,14 @@ static void clk_debug_print_hw(struct clk_hw *hw, struct seq_file *f)


	if (clk_is_regmap_clk(hw)) {
	if (clk_is_regmap_clk(hw)) {
		rclk = to_clk_regmap(hw);
		rclk = to_clk_regmap(hw);

		if (clk_runtime_get_regmap(rclk))
			return;

		if (rclk->ops && rclk->ops->list_registers)
		if (rclk->ops && rclk->ops->list_registers)
			rclk->ops->list_registers(f, hw);
			rclk->ops->list_registers(f, hw);

		clk_runtime_put_regmap(rclk);
	}
	}
}
}


+24 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/clk-provider.h>
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/regmap.h>
#include <linux/export.h>
#include <linux/export.h>
#include <linux/pm_runtime.h>


#include "clk-regmap.h"
#include "clk-regmap.h"


@@ -270,6 +271,8 @@ int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk)
{
{
	int ret;
	int ret;


	rclk->dev = dev;

	if (dev && dev_get_regmap(dev, NULL))
	if (dev && dev_get_regmap(dev, NULL))
		rclk->regmap = dev_get_regmap(dev, NULL);
		rclk->regmap = dev_get_regmap(dev, NULL);
	else if (dev && dev->parent)
	else if (dev && dev->parent)
@@ -282,3 +285,24 @@ int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk)
	return ret;
	return ret;
}
}
EXPORT_SYMBOL_GPL(devm_clk_register_regmap);
EXPORT_SYMBOL_GPL(devm_clk_register_regmap);

int clk_runtime_get_regmap(struct clk_regmap *rclk)
{
	int ret;

	if (pm_runtime_enabled(rclk->dev)) {
		ret = pm_runtime_get_sync(rclk->dev);
		if (ret < 0)
			return ret;
	}

	return 0;
}
EXPORT_SYMBOL(clk_runtime_get_regmap);

void clk_runtime_put_regmap(struct clk_regmap *rclk)
{
	if (pm_runtime_enabled(rclk->dev))
		pm_runtime_put_sync(rclk->dev);
}
EXPORT_SYMBOL(clk_runtime_put_regmap);
+4 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ struct clk_regmap {
	struct clk_vdd_class_data vdd_data;
	struct clk_vdd_class_data vdd_data;
	struct clk_regmap_ops *ops;
	struct clk_regmap_ops *ops;
	struct list_head list_node;
	struct list_head list_node;
	struct device *dev;
};
};
#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw)
#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw)


@@ -71,4 +72,7 @@ struct clk_register_data {
	u32 offset;
	u32 offset;
};
};


int clk_runtime_get_regmap(struct clk_regmap *rclk);
void clk_runtime_put_regmap(struct clk_regmap *rclk);

#endif
#endif
+123 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,10 @@
#include <linux/reset-controller.h>
#include <linux/reset-controller.h>
#include <linux/of.h>
#include <linux/of.h>
#include <linux/clk/qcom.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 "common.h"
#include "clk-opp.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);
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");
MODULE_LICENSE("GPL v2");
Loading