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

Commit ff74cb09 authored by Deepak Katragadda's avatar Deepak Katragadda
Browse files

clk: qcom: clk-dummy: Add a dummy clock provider



Add a dummy clock provider that registers a simple callback that
in turn always returns the dummy clock for any clk_get call.

In addition, consumers of the dummy clock provider would require
support for dummy resets, which would make a dummy assert/deassert
of the reset signals.

Change-Id: I08fcb174fd0e0c49f8069e106b48597bcdfe847d
Signed-off-by: default avatarTaniya Das <tdas@codeaurora.org>
Signed-off-by: default avatarDeepak Katragadda <dkatraga@codeaurora.org>
parent 40f58568
Loading
Loading
Loading
Loading
+26 −0
Original line number Original line 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>;
	};
+1 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@ clk-qcom-y += clk-regmap-divider.o
clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += clk-regmap-mux-div.o
clk-qcom-y += clk-regmap-mux-div.o
clk-qcom-y += reset.o
clk-qcom-y += reset.o
clk-qcom-y += clk-dummy.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o
clk-qcom-$(CONFIG_QCOM_GDSC) += gdsc.o


# Keep alphabetically sorted by config
# Keep alphabetically sorted by config
+138 −0
Original line number Original line 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);
+11 −11
Original line number Original line Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
/*
 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014, 2018, 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.
 */
 */
#ifndef __QCOM_CLK_COMMON_H__
#ifndef __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__
#define __QCOM_CLK_COMMON_H__


#include <linux/reset-controller.h>

struct platform_device;
struct platform_device;
struct regmap_config;
struct regmap_config;
struct clk_regmap;
struct clk_regmap;
@@ -48,6 +42,12 @@ struct parent_map {
	u8 cfg;
	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,
extern const struct freq_tbl *qcom_find_freq(const struct freq_tbl *f,
					     unsigned long rate);
					     unsigned long rate);
extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
extern const struct freq_tbl *qcom_find_freq_floor(const struct freq_tbl *f,
@@ -68,5 +68,5 @@ extern int qcom_cc_really_probe(struct platform_device *pdev,
				struct regmap *regmap);
				struct regmap *regmap);
extern int qcom_cc_probe(struct platform_device *pdev,
extern int qcom_cc_probe(struct platform_device *pdev,
			 const struct qcom_cc_desc *desc);
			 const struct qcom_cc_desc *desc);

extern const struct clk_ops clk_dummy_ops;
#endif
#endif