Loading Documentation/devicetree/bindings/clock/qcom,dummycc.txt 0 → 100644 +26 −0 Original line number Diff line number Diff line Qualcomm Technologies, Inc. Dummy Clock Controller Binding Qualcomm Technologies, Inc. dummy clock controller devices provide clock API support for driver development during pre-silicon stage. The clock driver always returns a dummy clock that has no effect on hardware. Required properties: - compatible: Must be "qcom,dummycc" - #clock-cells: Must be <1>. This will allow the common clock device tree framework to recognize _this_ device node as a clock provider. Optional properties: - clock-output-names: Name of the clock or the clock type. - #reset-cells: Must be <1>. This will allow the common reset device tree framework to recognize _this_ device node as a reset controller provider. Example: clock_gcc: qcom,gcc { compatible = "qcom,dummycc"; clock-output-names = "gcc_clocks"; #clock-cells = <1>; #reset-cells = <1>; }; drivers/clk/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o clk-qcom-y += clk-regmap-mux-div.o clk-qcom-y += reset.o clk-qcom-y += clk-dummy.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o # Keep alphabetically sorted by config Loading drivers/clk/qcom/clk-dummy.c 0 → 100644 +138 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018, The Linux Foundation. All rights reserved. */ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include "common.h" #define to_clk_dummy(_hw) container_of(_hw, struct clk_dummy, hw) #define RESET_MAX 100 static int dummy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_dummy *dummy = to_clk_dummy(hw); dummy->rrate = rate; pr_debug("%s: rate %lu\n", __func__, rate); return 0; } static long dummy_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { return rate; } static unsigned long dummy_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_dummy *dummy = to_clk_dummy(hw); pr_debug("%s: returning a clock rate of %lu\n", __func__, dummy->rrate); return dummy->rrate; } const struct clk_ops clk_dummy_ops = { .set_rate = dummy_clk_set_rate, .round_rate = dummy_clk_round_rate, .recalc_rate = dummy_clk_recalc_rate, }; EXPORT_SYMBOL(clk_dummy_ops); static int dummy_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { return 0; } static int dummy_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { return 0; } static struct reset_control_ops dummy_reset_ops = { .assert = dummy_reset_assert, .deassert = dummy_reset_deassert, }; /** * clk_register_dummy - register dummy clock with the * clock framework * @dev: device that is registering this clock * @name: name of this clock * @flags: framework-specific flags * @node: device node */ static struct clk *clk_register_dummy(struct device *dev, const char *name, unsigned long flags, struct device_node *node) { struct clk_dummy *dummy; struct clk *clk; struct clk_init_data init = {}; /* allocate dummy clock */ dummy = kzalloc(sizeof(*dummy), GFP_KERNEL); if (!dummy) return ERR_PTR(-ENOMEM); init.name = name; init.ops = &clk_dummy_ops; init.flags = flags | CLK_IS_BASIC; init.num_parents = 0; dummy->hw.init = &init; /* register the clock */ clk = clk_register(dev, &dummy->hw); if (IS_ERR(clk)) { kfree(dummy); return clk; } dummy->reset.of_node = node; dummy->reset.ops = &dummy_reset_ops; dummy->reset.nr_resets = RESET_MAX; if (reset_controller_register(&dummy->reset)) pr_err("Failed to register reset controller for %s\n", name); else pr_info("Successfully registered dummy reset controller for %s\n", name); return clk; } /** * of_dummy_clk_setup() - Setup function for simple fixed rate clock */ static void of_dummy_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = "dummy_clk"; of_property_read_string(node, "clock-output-names", &clk_name); clk = clk_register_dummy(NULL, clk_name, 0, node); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); } else { pr_err("Failed to register dummy clock controller for %s\n", clk_name); return; } pr_info("Successfully registered dummy clock controller for %s\n", clk_name); } CLK_OF_DECLARE(dummy_clk, "qcom,dummycc", of_dummy_clk_setup); drivers/clk/qcom/common.h +11 −11 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_COMMON_H__ #define __QCOM_CLK_COMMON_H__ #include <linux/reset-controller.h> struct platform_device; struct regmap_config; struct clk_regmap; Loading Loading @@ -48,6 +42,12 @@ struct parent_map { u8 cfg; }; struct clk_dummy { struct clk_hw hw; struct reset_controller_dev reset; unsigned long rrate; }; extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate); extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f, Loading @@ -68,5 +68,5 @@ extern int qcom_cc_really_probe(struct platform_device *pdev, struct regmap *regmap); extern int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc); extern const struct clk_ops clk_dummy_ops; #endif Loading
Documentation/devicetree/bindings/clock/qcom,dummycc.txt 0 → 100644 +26 −0 Original line number Diff line number Diff line Qualcomm Technologies, Inc. Dummy Clock Controller Binding Qualcomm Technologies, Inc. dummy clock controller devices provide clock API support for driver development during pre-silicon stage. The clock driver always returns a dummy clock that has no effect on hardware. Required properties: - compatible: Must be "qcom,dummycc" - #clock-cells: Must be <1>. This will allow the common clock device tree framework to recognize _this_ device node as a clock provider. Optional properties: - clock-output-names: Name of the clock or the clock type. - #reset-cells: Must be <1>. This will allow the common reset device tree framework to recognize _this_ device node as a reset controller provider. Example: clock_gcc: qcom,gcc { compatible = "qcom,dummycc"; clock-output-names = "gcc_clocks"; #clock-cells = <1>; #reset-cells = <1>; };
drivers/clk/qcom/Makefile +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ clk-qcom-y += clk-regmap-divider.o clk-qcom-y += clk-regmap-mux.o clk-qcom-y += clk-regmap-mux-div.o clk-qcom-y += reset.o clk-qcom-y += clk-dummy.o clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o # Keep alphabetically sorted by config Loading
drivers/clk/qcom/clk-dummy.c 0 → 100644 +138 −0 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018, The Linux Foundation. All rights reserved. */ #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> #include "common.h" #define to_clk_dummy(_hw) container_of(_hw, struct clk_dummy, hw) #define RESET_MAX 100 static int dummy_clk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { struct clk_dummy *dummy = to_clk_dummy(hw); dummy->rrate = rate; pr_debug("%s: rate %lu\n", __func__, rate); return 0; } static long dummy_clk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *parent_rate) { return rate; } static unsigned long dummy_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct clk_dummy *dummy = to_clk_dummy(hw); pr_debug("%s: returning a clock rate of %lu\n", __func__, dummy->rrate); return dummy->rrate; } const struct clk_ops clk_dummy_ops = { .set_rate = dummy_clk_set_rate, .round_rate = dummy_clk_round_rate, .recalc_rate = dummy_clk_recalc_rate, }; EXPORT_SYMBOL(clk_dummy_ops); static int dummy_reset_assert(struct reset_controller_dev *rcdev, unsigned long id) { return 0; } static int dummy_reset_deassert(struct reset_controller_dev *rcdev, unsigned long id) { return 0; } static struct reset_control_ops dummy_reset_ops = { .assert = dummy_reset_assert, .deassert = dummy_reset_deassert, }; /** * clk_register_dummy - register dummy clock with the * clock framework * @dev: device that is registering this clock * @name: name of this clock * @flags: framework-specific flags * @node: device node */ static struct clk *clk_register_dummy(struct device *dev, const char *name, unsigned long flags, struct device_node *node) { struct clk_dummy *dummy; struct clk *clk; struct clk_init_data init = {}; /* allocate dummy clock */ dummy = kzalloc(sizeof(*dummy), GFP_KERNEL); if (!dummy) return ERR_PTR(-ENOMEM); init.name = name; init.ops = &clk_dummy_ops; init.flags = flags | CLK_IS_BASIC; init.num_parents = 0; dummy->hw.init = &init; /* register the clock */ clk = clk_register(dev, &dummy->hw); if (IS_ERR(clk)) { kfree(dummy); return clk; } dummy->reset.of_node = node; dummy->reset.ops = &dummy_reset_ops; dummy->reset.nr_resets = RESET_MAX; if (reset_controller_register(&dummy->reset)) pr_err("Failed to register reset controller for %s\n", name); else pr_info("Successfully registered dummy reset controller for %s\n", name); return clk; } /** * of_dummy_clk_setup() - Setup function for simple fixed rate clock */ static void of_dummy_clk_setup(struct device_node *node) { struct clk *clk; const char *clk_name = "dummy_clk"; of_property_read_string(node, "clock-output-names", &clk_name); clk = clk_register_dummy(NULL, clk_name, 0, node); if (!IS_ERR(clk)) { of_clk_add_provider(node, of_clk_src_simple_get, clk); } else { pr_err("Failed to register dummy clock controller for %s\n", clk_name); return; } pr_info("Successfully registered dummy clock controller for %s\n", clk_name); } CLK_OF_DECLARE(dummy_clk, "qcom,dummycc", of_dummy_clk_setup);
drivers/clk/qcom/common.h +11 −11 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014, The Linux Foundation. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * Copyright (c) 2014, 2018, The Linux Foundation. All rights reserved. */ #ifndef __QCOM_CLK_COMMON_H__ #define __QCOM_CLK_COMMON_H__ #include <linux/reset-controller.h> struct platform_device; struct regmap_config; struct clk_regmap; Loading Loading @@ -48,6 +42,12 @@ struct parent_map { u8 cfg; }; struct clk_dummy { struct clk_hw hw; struct reset_controller_dev reset; unsigned long rrate; }; extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f, unsigned long rate); extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f, Loading @@ -68,5 +68,5 @@ extern int qcom_cc_really_probe(struct platform_device *pdev, struct regmap *regmap); extern int qcom_cc_probe(struct platform_device *pdev, const struct qcom_cc_desc *desc); extern const struct clk_ops clk_dummy_ops; #endif