162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/module.h>
662306a36Sopenharmony_ci#include <linux/clk-provider.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci * DOC: basic fixed multiplier and divider clock that cannot gate
1462306a36Sopenharmony_ci *
1562306a36Sopenharmony_ci * Traits of this clock:
1662306a36Sopenharmony_ci * prepare - clk_prepare only ensures that parents are prepared
1762306a36Sopenharmony_ci * enable - clk_enable only ensures that parents are enabled
1862306a36Sopenharmony_ci * rate - rate is fixed.  clk->rate = parent->rate / div * mult
1962306a36Sopenharmony_ci * parent - fixed parent.  No clk_set_parent support
2062306a36Sopenharmony_ci */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
2362306a36Sopenharmony_ci		unsigned long parent_rate)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
2662306a36Sopenharmony_ci	unsigned long long int rate;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	rate = (unsigned long long int)parent_rate * fix->mult;
2962306a36Sopenharmony_ci	do_div(rate, fix->div);
3062306a36Sopenharmony_ci	return (unsigned long)rate;
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_cistatic long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
3462306a36Sopenharmony_ci				unsigned long *prate)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
3962306a36Sopenharmony_ci		unsigned long best_parent;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci		best_parent = (rate / fix->mult) * fix->div;
4262306a36Sopenharmony_ci		*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
4362306a36Sopenharmony_ci	}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	return (*prate / fix->div) * fix->mult;
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
4962306a36Sopenharmony_ci				unsigned long parent_rate)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	/*
5262306a36Sopenharmony_ci	 * We must report success but we can do so unconditionally because
5362306a36Sopenharmony_ci	 * clk_factor_round_rate returns values that ensure this call is a
5462306a36Sopenharmony_ci	 * nop.
5562306a36Sopenharmony_ci	 */
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return 0;
5862306a36Sopenharmony_ci}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ciconst struct clk_ops clk_fixed_factor_ops = {
6162306a36Sopenharmony_ci	.round_rate = clk_factor_round_rate,
6262306a36Sopenharmony_ci	.set_rate = clk_factor_set_rate,
6362306a36Sopenharmony_ci	.recalc_rate = clk_factor_recalc_rate,
6462306a36Sopenharmony_ci};
6562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_fixed_factor_ops);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void devm_clk_hw_register_fixed_factor_release(struct device *dev, void *res)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	struct clk_fixed_factor *fix = res;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	/*
7262306a36Sopenharmony_ci	 * We can not use clk_hw_unregister_fixed_factor, since it will kfree()
7362306a36Sopenharmony_ci	 * the hw, resulting in double free. Just unregister the hw and let
7462306a36Sopenharmony_ci	 * devres code kfree() it.
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci	clk_hw_unregister(&fix->hw);
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic struct clk_hw *
8062306a36Sopenharmony_ci__clk_hw_register_fixed_factor(struct device *dev, struct device_node *np,
8162306a36Sopenharmony_ci		const char *name, const char *parent_name,
8262306a36Sopenharmony_ci		const struct clk_hw *parent_hw, int index,
8362306a36Sopenharmony_ci		unsigned long flags, unsigned int mult, unsigned int div,
8462306a36Sopenharmony_ci		bool devm)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct clk_fixed_factor *fix;
8762306a36Sopenharmony_ci	struct clk_init_data init = { };
8862306a36Sopenharmony_ci	struct clk_parent_data pdata = { .index = index };
8962306a36Sopenharmony_ci	struct clk_hw *hw;
9062306a36Sopenharmony_ci	int ret;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* You can't use devm without a dev */
9362306a36Sopenharmony_ci	if (devm && !dev)
9462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (devm)
9762306a36Sopenharmony_ci		fix = devres_alloc(devm_clk_hw_register_fixed_factor_release,
9862306a36Sopenharmony_ci				sizeof(*fix), GFP_KERNEL);
9962306a36Sopenharmony_ci	else
10062306a36Sopenharmony_ci		fix = kmalloc(sizeof(*fix), GFP_KERNEL);
10162306a36Sopenharmony_ci	if (!fix)
10262306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* struct clk_fixed_factor assignments */
10562306a36Sopenharmony_ci	fix->mult = mult;
10662306a36Sopenharmony_ci	fix->div = div;
10762306a36Sopenharmony_ci	fix->hw.init = &init;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	init.name = name;
11062306a36Sopenharmony_ci	init.ops = &clk_fixed_factor_ops;
11162306a36Sopenharmony_ci	init.flags = flags;
11262306a36Sopenharmony_ci	if (parent_name)
11362306a36Sopenharmony_ci		init.parent_names = &parent_name;
11462306a36Sopenharmony_ci	else if (parent_hw)
11562306a36Sopenharmony_ci		init.parent_hws = &parent_hw;
11662306a36Sopenharmony_ci	else
11762306a36Sopenharmony_ci		init.parent_data = &pdata;
11862306a36Sopenharmony_ci	init.num_parents = 1;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	hw = &fix->hw;
12162306a36Sopenharmony_ci	if (dev)
12262306a36Sopenharmony_ci		ret = clk_hw_register(dev, hw);
12362306a36Sopenharmony_ci	else
12462306a36Sopenharmony_ci		ret = of_clk_hw_register(np, hw);
12562306a36Sopenharmony_ci	if (ret) {
12662306a36Sopenharmony_ci		if (devm)
12762306a36Sopenharmony_ci			devres_free(fix);
12862306a36Sopenharmony_ci		else
12962306a36Sopenharmony_ci			kfree(fix);
13062306a36Sopenharmony_ci		hw = ERR_PTR(ret);
13162306a36Sopenharmony_ci	} else if (devm)
13262306a36Sopenharmony_ci		devres_add(dev, fix);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return hw;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/**
13862306a36Sopenharmony_ci * devm_clk_hw_register_fixed_factor_index - Register a fixed factor clock with
13962306a36Sopenharmony_ci * parent from DT index
14062306a36Sopenharmony_ci * @dev: device that is registering this clock
14162306a36Sopenharmony_ci * @name: name of this clock
14262306a36Sopenharmony_ci * @index: index of phandle in @dev 'clocks' property
14362306a36Sopenharmony_ci * @flags: fixed factor flags
14462306a36Sopenharmony_ci * @mult: multiplier
14562306a36Sopenharmony_ci * @div: divider
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * Return: Pointer to fixed factor clk_hw structure that was registered or
14862306a36Sopenharmony_ci * an error pointer.
14962306a36Sopenharmony_ci */
15062306a36Sopenharmony_cistruct clk_hw *devm_clk_hw_register_fixed_factor_index(struct device *dev,
15162306a36Sopenharmony_ci		const char *name, unsigned int index, unsigned long flags,
15262306a36Sopenharmony_ci		unsigned int mult, unsigned int div)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, NULL, index,
15562306a36Sopenharmony_ci					      flags, mult, div, true);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_index);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/**
16062306a36Sopenharmony_ci * devm_clk_hw_register_fixed_factor_parent_hw - Register a fixed factor clock with
16162306a36Sopenharmony_ci * pointer to parent clock
16262306a36Sopenharmony_ci * @dev: device that is registering this clock
16362306a36Sopenharmony_ci * @name: name of this clock
16462306a36Sopenharmony_ci * @parent_hw: pointer to parent clk
16562306a36Sopenharmony_ci * @flags: fixed factor flags
16662306a36Sopenharmony_ci * @mult: multiplier
16762306a36Sopenharmony_ci * @div: divider
16862306a36Sopenharmony_ci *
16962306a36Sopenharmony_ci * Return: Pointer to fixed factor clk_hw structure that was registered or
17062306a36Sopenharmony_ci * an error pointer.
17162306a36Sopenharmony_ci */
17262306a36Sopenharmony_cistruct clk_hw *devm_clk_hw_register_fixed_factor_parent_hw(struct device *dev,
17362306a36Sopenharmony_ci		const char *name, const struct clk_hw *parent_hw,
17462306a36Sopenharmony_ci		unsigned long flags, unsigned int mult, unsigned int div)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	return __clk_hw_register_fixed_factor(dev, NULL, name, NULL, parent_hw,
17762306a36Sopenharmony_ci					      -1, flags, mult, div, true);
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor_parent_hw);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistruct clk_hw *clk_hw_register_fixed_factor_parent_hw(struct device *dev,
18262306a36Sopenharmony_ci		const char *name, const struct clk_hw *parent_hw,
18362306a36Sopenharmony_ci		unsigned long flags, unsigned int mult, unsigned int div)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	return __clk_hw_register_fixed_factor(dev, NULL, name, NULL,
18662306a36Sopenharmony_ci					      parent_hw, -1, flags, mult, div,
18762306a36Sopenharmony_ci					      false);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor_parent_hw);
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_cistruct clk_hw *clk_hw_register_fixed_factor(struct device *dev,
19262306a36Sopenharmony_ci		const char *name, const char *parent_name, unsigned long flags,
19362306a36Sopenharmony_ci		unsigned int mult, unsigned int div)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1,
19662306a36Sopenharmony_ci					      flags, mult, div, false);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_hw_register_fixed_factor);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistruct clk *clk_register_fixed_factor(struct device *dev, const char *name,
20162306a36Sopenharmony_ci		const char *parent_name, unsigned long flags,
20262306a36Sopenharmony_ci		unsigned int mult, unsigned int div)
20362306a36Sopenharmony_ci{
20462306a36Sopenharmony_ci	struct clk_hw *hw;
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	hw = clk_hw_register_fixed_factor(dev, name, parent_name, flags, mult,
20762306a36Sopenharmony_ci					  div);
20862306a36Sopenharmony_ci	if (IS_ERR(hw))
20962306a36Sopenharmony_ci		return ERR_CAST(hw);
21062306a36Sopenharmony_ci	return hw->clk;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_register_fixed_factor);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_civoid clk_unregister_fixed_factor(struct clk *clk)
21562306a36Sopenharmony_ci{
21662306a36Sopenharmony_ci	struct clk_hw *hw;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	hw = __clk_get_hw(clk);
21962306a36Sopenharmony_ci	if (!hw)
22062306a36Sopenharmony_ci		return;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	clk_unregister(clk);
22362306a36Sopenharmony_ci	kfree(to_clk_fixed_factor(hw));
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_unregister_fixed_factor);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_civoid clk_hw_unregister_fixed_factor(struct clk_hw *hw)
22862306a36Sopenharmony_ci{
22962306a36Sopenharmony_ci	struct clk_fixed_factor *fix;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	fix = to_clk_fixed_factor(hw);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	clk_hw_unregister(hw);
23462306a36Sopenharmony_ci	kfree(fix);
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_hw_unregister_fixed_factor);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistruct clk_hw *devm_clk_hw_register_fixed_factor(struct device *dev,
23962306a36Sopenharmony_ci		const char *name, const char *parent_name, unsigned long flags,
24062306a36Sopenharmony_ci		unsigned int mult, unsigned int div)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	return __clk_hw_register_fixed_factor(dev, NULL, name, parent_name, NULL, -1,
24362306a36Sopenharmony_ci			flags, mult, div, true);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(devm_clk_hw_register_fixed_factor);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci#ifdef CONFIG_OF
24862306a36Sopenharmony_cistatic struct clk_hw *_of_fixed_factor_clk_setup(struct device_node *node)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct clk_hw *hw;
25162306a36Sopenharmony_ci	const char *clk_name = node->name;
25262306a36Sopenharmony_ci	u32 div, mult;
25362306a36Sopenharmony_ci	int ret;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	if (of_property_read_u32(node, "clock-div", &div)) {
25662306a36Sopenharmony_ci		pr_err("%s Fixed factor clock <%pOFn> must have a clock-div property\n",
25762306a36Sopenharmony_ci			__func__, node);
25862306a36Sopenharmony_ci		return ERR_PTR(-EIO);
25962306a36Sopenharmony_ci	}
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	if (of_property_read_u32(node, "clock-mult", &mult)) {
26262306a36Sopenharmony_ci		pr_err("%s Fixed factor clock <%pOFn> must have a clock-mult property\n",
26362306a36Sopenharmony_ci			__func__, node);
26462306a36Sopenharmony_ci		return ERR_PTR(-EIO);
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	of_property_read_string(node, "clock-output-names", &clk_name);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	hw = __clk_hw_register_fixed_factor(NULL, node, clk_name, NULL, NULL, 0,
27062306a36Sopenharmony_ci					    0, mult, div, false);
27162306a36Sopenharmony_ci	if (IS_ERR(hw)) {
27262306a36Sopenharmony_ci		/*
27362306a36Sopenharmony_ci		 * Clear OF_POPULATED flag so that clock registration can be
27462306a36Sopenharmony_ci		 * attempted again from probe function.
27562306a36Sopenharmony_ci		 */
27662306a36Sopenharmony_ci		of_node_clear_flag(node, OF_POPULATED);
27762306a36Sopenharmony_ci		return ERR_CAST(hw);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = of_clk_add_hw_provider(node, of_clk_hw_simple_get, hw);
28162306a36Sopenharmony_ci	if (ret) {
28262306a36Sopenharmony_ci		clk_hw_unregister_fixed_factor(hw);
28362306a36Sopenharmony_ci		return ERR_PTR(ret);
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return hw;
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/**
29062306a36Sopenharmony_ci * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
29162306a36Sopenharmony_ci * @node:	device node for the clock
29262306a36Sopenharmony_ci */
29362306a36Sopenharmony_civoid __init of_fixed_factor_clk_setup(struct device_node *node)
29462306a36Sopenharmony_ci{
29562306a36Sopenharmony_ci	_of_fixed_factor_clk_setup(node);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ciCLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
29862306a36Sopenharmony_ci		of_fixed_factor_clk_setup);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cistatic void of_fixed_factor_clk_remove(struct platform_device *pdev)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	struct clk_hw *clk = platform_get_drvdata(pdev);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	of_clk_del_provider(pdev->dev.of_node);
30562306a36Sopenharmony_ci	clk_hw_unregister_fixed_factor(clk);
30662306a36Sopenharmony_ci}
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_cistatic int of_fixed_factor_clk_probe(struct platform_device *pdev)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct clk_hw *clk;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * This function is not executed when of_fixed_factor_clk_setup
31462306a36Sopenharmony_ci	 * succeeded.
31562306a36Sopenharmony_ci	 */
31662306a36Sopenharmony_ci	clk = _of_fixed_factor_clk_setup(pdev->dev.of_node);
31762306a36Sopenharmony_ci	if (IS_ERR(clk))
31862306a36Sopenharmony_ci		return PTR_ERR(clk);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	platform_set_drvdata(pdev, clk);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic const struct of_device_id of_fixed_factor_clk_ids[] = {
32662306a36Sopenharmony_ci	{ .compatible = "fixed-factor-clock" },
32762306a36Sopenharmony_ci	{ }
32862306a36Sopenharmony_ci};
32962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, of_fixed_factor_clk_ids);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_cistatic struct platform_driver of_fixed_factor_clk_driver = {
33262306a36Sopenharmony_ci	.driver = {
33362306a36Sopenharmony_ci		.name = "of_fixed_factor_clk",
33462306a36Sopenharmony_ci		.of_match_table = of_fixed_factor_clk_ids,
33562306a36Sopenharmony_ci	},
33662306a36Sopenharmony_ci	.probe = of_fixed_factor_clk_probe,
33762306a36Sopenharmony_ci	.remove_new = of_fixed_factor_clk_remove,
33862306a36Sopenharmony_ci};
33962306a36Sopenharmony_cibuiltin_platform_driver(of_fixed_factor_clk_driver);
34062306a36Sopenharmony_ci#endif
341