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

This commit is contained in:
qctecmdr 2020-09-14 17:26:15 -07:00 • committed by Gerrit - the friendly Code Review server
commit 65d212e2e0
9 changed files with 245 additions and 106 deletions

View file

@ -10,6 +10,7 @@
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.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 = {
.halt_reg = 0xc094,
.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_CSIPHY5_CLK] = &cam_cc_csiphy5_clk.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_CLK] = &cam_cc_icp_clk.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,
};
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,
.clks = 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)
{
struct regmap *regmap;
struct clk *clk;
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);
if (IS_ERR(regmap)) {
dev_err(&pdev->dev, "Failed to map cam CC registers\n");
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_pll1, regmap, &cam_cc_pll1_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)
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);
if (ret) {
dev_err(&pdev->dev, "Failed to register CAM CC clocks\n");
return ret;
}
pm_runtime_put_sync(&pdev->dev);
dev_info(&pdev->dev, "Registered CAM CC clocks\n");
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);
}
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 = {
.probe = cam_cc_lahaina_probe,
.driver = {
.name = "lahaina-cam_cc",
.of_match_table = cam_cc_lahaina_match_table,
.sync_state = cam_cc_lahaina_sync_state,
.pm = &cam_cc_lahaina_pm_ops,
},
};

View file

@ -266,12 +266,22 @@ static u32 get_mux_divs(struct clk_hw *mux)
static int clk_debug_measure_get(void *data, u64 *val)
{
struct clk_regmap *rclk = NULL;
struct clk_debug_mux *mux;
struct clk_hw *hw = data;
struct clk_hw *parent;
int ret = 0;
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);
ret = clk_find_and_set_parent(measure, hw);
@ -306,6 +316,8 @@ static int clk_debug_measure_get(void *data, u64 *val)
}
exit:
mutex_unlock(&clk_debug_lock);
if (rclk)
clk_runtime_put_regmap(rclk);
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)) {
rclk = to_clk_regmap(hw);
if (clk_runtime_get_regmap(rclk))
return;
if (rclk->ops && rclk->ops->list_registers)
rclk->ops->list_registers(f, hw);
clk_runtime_put_regmap(rclk);
}
}

View file

@ -7,6 +7,7 @@
#include <linux/clk-provider.h>
#include <linux/regmap.h>
#include <linux/export.h>
#include <linux/pm_runtime.h>
#include "clk-regmap.h"
@ -270,6 +271,8 @@ int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk)
{
int ret;
rclk->dev = dev;
if (dev && dev_get_regmap(dev, NULL))
rclk->regmap = dev_get_regmap(dev, NULL);
else if (dev && dev->parent)
@ -282,3 +285,24 @@ int devm_clk_register_regmap(struct device *dev, struct clk_regmap *rclk)
return ret;
}
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);

View file

@ -50,6 +50,7 @@ struct clk_regmap {
struct clk_vdd_class_data vdd_data;
struct clk_regmap_ops *ops;
struct list_head list_node;
struct device *dev;
};
#define to_clk_regmap(_hw) container_of(_hw, struct clk_regmap, hw)
@ -71,4 +72,7 @@ struct clk_register_data {
u32 offset;
};
int clk_runtime_get_regmap(struct clk_regmap *rclk);
void clk_runtime_put_regmap(struct clk_regmap *rclk);
#endif

View file

@ -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");

View file

@ -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

View file

@ -10,6 +10,7 @@
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <dt-bindings/clock/qcom,dispcc-lahaina.h>
@ -1422,24 +1423,6 @@ static struct clk_branch disp_cc_sleep_clk = {
},
};
static struct clk_branch disp_cc_xo_clk = {
.halt_reg = 0x605c,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0x605c,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "disp_cc_xo_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &disp_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_regmap *disp_cc_lahaina_clocks[] = {
[DISP_CC_MDSS_AHB_CLK] = &disp_cc_mdss_ahb_clk.clkr,
[DISP_CC_MDSS_AHB_CLK_SRC] = &disp_cc_mdss_ahb_clk_src.clkr,
@ -1502,7 +1485,6 @@ static struct clk_regmap *disp_cc_lahaina_clocks[] = {
[DISP_CC_PLL1] = &disp_cc_pll1.clkr,
[DISP_CC_SLEEP_CLK] = &disp_cc_sleep_clk.clkr,
[DISP_CC_SLEEP_CLK_SRC] = &disp_cc_sleep_clk_src.clkr,
[DISP_CC_XO_CLK] = &disp_cc_xo_clk.clkr,
[DISP_CC_XO_CLK_SRC] = &disp_cc_xo_clk_src.clkr,
};
@ -1519,7 +1501,7 @@ static const struct regmap_config disp_cc_lahaina_regmap_config = {
.fast_io = true,
};
static const struct qcom_cc_desc disp_cc_lahaina_desc = {
static struct qcom_cc_desc disp_cc_lahaina_desc = {
.config = &disp_cc_lahaina_regmap_config,
.clks = disp_cc_lahaina_clocks,
.num_clks = ARRAY_SIZE(disp_cc_lahaina_clocks),
@ -1538,20 +1520,19 @@ MODULE_DEVICE_TABLE(of, disp_cc_lahaina_match_table);
static int disp_cc_lahaina_probe(struct platform_device *pdev)
{
struct regmap *regmap;
struct clk *clk;
int ret;
regmap = qcom_cc_map(pdev, &disp_cc_lahaina_desc);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
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);
ret = qcom_cc_runtime_init(pdev, &disp_cc_lahaina_desc);
if (ret)
return ret;
ret = pm_runtime_get_sync(&pdev->dev);
if (ret)
return ret;
clk_lucid_5lpe_pll_configure(&disp_cc_pll0, regmap,
&disp_cc_pll0_config);
@ -1561,12 +1542,19 @@ static int disp_cc_lahaina_probe(struct platform_device *pdev)
/* Enable clock gating for MDP clocks */
regmap_update_bits(regmap, DISP_CC_MISC_CMD, 0x10, 0x10);
/*
* Keep clocks always enabled:
* disp_cc_xo_clk
*/
regmap_update_bits(regmap, 0x605c, BIT(0), BIT(0));
ret = qcom_cc_really_probe(pdev, &disp_cc_lahaina_desc, regmap);
if (ret) {
dev_err(&pdev->dev, "Failed to register DISP CC clocks\n");
return ret;
}
pm_runtime_put_sync(&pdev->dev);
dev_info(&pdev->dev, "Registered DISP CC clocks\n");
return ret;
@ -1577,12 +1565,17 @@ static void disp_cc_lahaina_sync_state(struct device *dev)
qcom_cc_sync_state(dev, &disp_cc_lahaina_desc);
}
static const struct dev_pm_ops disp_cc_lahaina_pm_ops = {
SET_RUNTIME_PM_OPS(qcom_cc_runtime_suspend, qcom_cc_runtime_resume, NULL)
};
static struct platform_driver disp_cc_lahaina_driver = {
.probe = disp_cc_lahaina_probe,
.driver = {
.name = "disp_cc-lahaina",
.of_match_table = disp_cc_lahaina_match_table,
.sync_state = disp_cc_lahaina_sync_state,
.pm = &disp_cc_lahaina_pm_ops,
},
};

View file

@ -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)) {

View file

@ -10,6 +10,7 @@
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/regmap.h>
#include <linux/pm_runtime.h>
#include <dt-bindings/clock/qcom,videocc-lahaina.h>
@ -361,26 +362,6 @@ static struct clk_regmap_div video_cc_mvs1c_div2_div_clk_src = {
},
};
static struct clk_branch video_cc_ahb_clk = {
.halt_reg = 0xe58,
.halt_check = BRANCH_HALT_VOTED,
.hwcg_reg = 0xe58,
.hwcg_bit = 1,
.clkr = {
.enable_reg = 0xe58,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "video_cc_ahb_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &video_cc_ahb_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_branch video_cc_mvs0_clk = {
.halt_reg = 0xd34,
.halt_check = BRANCH_HALT_VOTED,
@ -495,26 +476,7 @@ static struct clk_branch video_cc_sleep_clk = {
},
};
static struct clk_branch video_cc_xo_clk = {
.halt_reg = 0xeec,
.halt_check = BRANCH_HALT,
.clkr = {
.enable_reg = 0xeec,
.enable_mask = BIT(0),
.hw.init = &(struct clk_init_data){
.name = "video_cc_xo_clk",
.parent_data = &(const struct clk_parent_data){
.hw = &video_cc_xo_clk_src.clkr.hw,
},
.num_parents = 1,
.flags = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
.ops = &clk_branch2_ops,
},
},
};
static struct clk_regmap *video_cc_lahaina_clocks[] = {
[VIDEO_CC_AHB_CLK] = &video_cc_ahb_clk.clkr,
[VIDEO_CC_AHB_CLK_SRC] = &video_cc_ahb_clk_src.clkr,
[VIDEO_CC_MVS0_CLK] = &video_cc_mvs0_clk.clkr,
[VIDEO_CC_MVS0_CLK_SRC] = &video_cc_mvs0_clk_src.clkr,
@ -531,7 +493,6 @@ static struct clk_regmap *video_cc_lahaina_clocks[] = {
&video_cc_mvs1c_div2_div_clk_src.clkr,
[VIDEO_CC_SLEEP_CLK] = &video_cc_sleep_clk.clkr,
[VIDEO_CC_SLEEP_CLK_SRC] = &video_cc_sleep_clk_src.clkr,
[VIDEO_CC_XO_CLK] = &video_cc_xo_clk.clkr,
[VIDEO_CC_XO_CLK_SRC] = &video_cc_xo_clk_src.clkr,
[VIDEO_PLL0] = &video_pll0.clkr,
[VIDEO_PLL1] = &video_pll1.clkr,
@ -555,7 +516,7 @@ static const struct regmap_config video_cc_lahaina_regmap_config = {
.fast_io = true,
};
static const struct qcom_cc_desc video_cc_lahaina_desc = {
static struct qcom_cc_desc video_cc_lahaina_desc = {
.config = &video_cc_lahaina_regmap_config,
.clks = video_cc_lahaina_clocks,
.num_clks = ARRAY_SIZE(video_cc_lahaina_clocks),
@ -574,30 +535,38 @@ MODULE_DEVICE_TABLE(of, video_cc_lahaina_match_table);
static int video_cc_lahaina_probe(struct platform_device *pdev)
{
struct regmap *regmap;
struct clk *clk;
int ret;
regmap = qcom_cc_map(pdev, &video_cc_lahaina_desc);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
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);
ret = qcom_cc_runtime_init(pdev, &video_cc_lahaina_desc);
if (ret)
return ret;
ret = pm_runtime_get_sync(&pdev->dev);
if (ret)
return ret;
clk_lucid_5lpe_pll_configure(&video_pll0, regmap, &video_pll0_config);
clk_lucid_5lpe_pll_configure(&video_pll1, regmap, &video_pll1_config);
/*
* Keep clocks always enabled:
* video_cc_ahb_clk
* video_cc_xo_clk
*/
regmap_update_bits(regmap, 0xe58, BIT(0), BIT(0));
regmap_update_bits(regmap, 0xeec, BIT(0), BIT(0));
ret = qcom_cc_really_probe(pdev, &video_cc_lahaina_desc, regmap);
if (ret) {
dev_err(&pdev->dev, "Failed to register VIDEO CC clocks\n");
return ret;
}
pm_runtime_put_sync(&pdev->dev);
dev_info(&pdev->dev, "Registered VIDEO CC clocks\n");
return ret;
@ -608,12 +577,17 @@ static void video_cc_lahaina_sync_state(struct device *dev)
qcom_cc_sync_state(dev, &video_cc_lahaina_desc);
}
static const struct dev_pm_ops video_cc_lahaina_pm_ops = {
SET_RUNTIME_PM_OPS(qcom_cc_runtime_suspend, qcom_cc_runtime_resume, NULL)
};
static struct platform_driver video_cc_lahaina_driver = {
.probe = video_cc_lahaina_probe,
.driver = {
.name = "video_cc-lahaina",
.of_match_table = video_cc_lahaina_match_table,
.sync_state = video_cc_lahaina_sync_state,
.pm = &video_cc_lahaina_pm_ops,
},
};