Loading drivers/clk/qcom/camcc-lahaina.c +22 −29 Original line number Original line Diff line number Diff line Loading @@ -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> Loading Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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), Loading Loading @@ -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); Loading @@ -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; Loading @@ -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, }, }, }; }; Loading drivers/clk/qcom/clk-debug.c +18 −0 Original line number Original line Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } } Loading Loading @@ -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); } } } } Loading drivers/clk/qcom/clk-regmap.c +24 −0 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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) Loading @@ -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); drivers/clk/qcom/clk-regmap.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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) Loading @@ -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 drivers/clk/qcom/common.c +123 −0 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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
drivers/clk/qcom/camcc-lahaina.c +22 −29 Original line number Original line Diff line number Diff line Loading @@ -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> Loading Loading @@ -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, Loading Loading @@ -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, Loading Loading @@ -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), Loading Loading @@ -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); Loading @@ -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; Loading @@ -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, }, }, }; }; Loading
drivers/clk/qcom/clk-debug.c +18 −0 Original line number Original line Diff line number Diff line Loading @@ -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); Loading Loading @@ -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; } } Loading Loading @@ -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); } } } } Loading
drivers/clk/qcom/clk-regmap.c +24 −0 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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) Loading @@ -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);
drivers/clk/qcom/clk-regmap.h +4 −0 Original line number Original line Diff line number Diff line Loading @@ -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) Loading @@ -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
drivers/clk/qcom/common.c +123 −0 Original line number Original line Diff line number Diff line Loading @@ -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" Loading Loading @@ -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");