diff mbox

[v2,04/15] clk: sunxi-ng: Add fixed factor clock support

Message ID 20160607204154.31967-5-maxime.ripard@free-electrons.com (mailing list archive)
State Superseded, archived
Headers show

Commit Message

Maxime Ripard June 7, 2016, 8:41 p.m. UTC
Some clocks in the Allwinner SoCs clock units are direct, fixed,
multipliers or dividers from their parent.

Add support for such clocks.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
---
 drivers/clk/sunxi-ng/Makefile           |  2 ++
 drivers/clk/sunxi-ng/ccu_fixed_factor.c | 50 +++++++++++++++++++++++++++++++++
 drivers/clk/sunxi-ng/ccu_fixed_factor.h | 50 +++++++++++++++++++++++++++++++++
 3 files changed, 102 insertions(+)
 create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.c
 create mode 100644 drivers/clk/sunxi-ng/ccu_fixed_factor.h

Comments

Stephen Boyd June 21, 2016, 1:15 a.m. UTC | #1
On 06/07, Maxime Ripard wrote:
> +
> +#include <linux/clk-provider.h>
> +
> +#include "ccu_common.h"
> +
> +struct ccu_fixed_factor {
> +	u16			div;
> +	u16			mult;
> +
> +	struct ccu_common	common;

Does this use the common structure although we have no usage for
the members of struct ccu_common except struct clk_hw? I suppose
this is done so registering a bunch of clks is easy?
Maxime Ripard June 21, 2016, 9:24 a.m. UTC | #2
Hi Stephen,

On Mon, Jun 20, 2016 at 06:15:37PM -0700, Stephen Boyd wrote:
> On 06/07, Maxime Ripard wrote:
> > +
> > +#include <linux/clk-provider.h>
> > +
> > +#include "ccu_common.h"
> > +
> > +struct ccu_fixed_factor {
> > +	u16			div;
> > +	u16			mult;
> > +
> > +	struct ccu_common	common;
> 
> Does this use the common structure although we have no usage for
> the members of struct ccu_common except struct clk_hw? I suppose
> this is done so registering a bunch of clks is easy?

Yes, when we discussed this with Mike back at the ELC, he said that he
really liked the approach you had the qualcomm clocks where you have a
single array with all the clocks, so I tried to follow that as much as
possible.

Even though it doesn't really make much sense here, indeed.

Maxime
diff mbox

Patch

diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile
index 4585443b3771..c59cf2ea509b 100644
--- a/drivers/clk/sunxi-ng/Makefile
+++ b/drivers/clk/sunxi-ng/Makefile
@@ -2,3 +2,5 @@  obj-y += ccu_common.o
 obj-y += ccu_reset.o
 
 obj-y += ccu_frac.o
+
+obj-y += ccu_fixed_factor.o
diff --git a/drivers/clk/sunxi-ng/ccu_fixed_factor.c b/drivers/clk/sunxi-ng/ccu_fixed_factor.c
new file mode 100644
index 000000000000..0498dc5340ea
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_fixed_factor.c
@@ -0,0 +1,50 @@ 
+/*
+ * Copyright (C) 2016 Maxime Ripard
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ */
+
+#include <linux/clk-provider.h>
+
+#include "ccu_fixed_factor.h"
+
+static unsigned long ccu_fixed_factor_recalc_rate(struct clk_hw *hw,
+						  unsigned long parent_rate)
+{
+	struct ccu_fixed_factor *fix = hw_to_ccu_fixed_factor(hw);
+
+	return parent_rate / fix->div * fix->mult;
+}
+
+static long ccu_fixed_factor_round_rate(struct clk_hw *hw,
+					unsigned long rate,
+					unsigned long *parent_rate)
+{
+	struct ccu_fixed_factor *fix = hw_to_ccu_fixed_factor(hw);
+
+	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
+		unsigned long best_parent;
+
+		best_parent = (rate / fix->mult) * fix->div;
+		*parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+						 best_parent);
+	}
+
+	return *parent_rate / fix->div * fix->mult;
+}
+
+static int ccu_fixed_factor_set_rate(struct clk_hw *hw, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	return 0;
+}
+
+const struct clk_ops ccu_fixed_factor_ops = {
+	.recalc_rate	= ccu_fixed_factor_recalc_rate,
+	.round_rate	= ccu_fixed_factor_round_rate,
+	.set_rate	= ccu_fixed_factor_set_rate,
+};
diff --git a/drivers/clk/sunxi-ng/ccu_fixed_factor.h b/drivers/clk/sunxi-ng/ccu_fixed_factor.h
new file mode 100644
index 000000000000..4e53dbc9d10b
--- /dev/null
+++ b/drivers/clk/sunxi-ng/ccu_fixed_factor.h
@@ -0,0 +1,50 @@ 
+/*
+ * Copyright (c) 2016 Maxime Ripard. 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 _CCU_FIXED_FACTOR_H_
+#define _CCU_FIXED_FACTOR_H_
+
+#include <linux/clk-provider.h>
+
+#include "ccu_common.h"
+
+struct ccu_fixed_factor {
+	u16			div;
+	u16			mult;
+
+	struct ccu_common	common;
+};
+
+#define SUNXI_CCU_FIXED_FACTOR(_struct, _name, _parent,			\
+			       _div, _mult, _flags)			\
+	struct ccu_fixed_factor _struct = {				\
+		.div	= _div,						\
+		.mult	= _mult,					\
+		.common	= {						\
+			.hw.init	= SUNXI_HW_INIT(_name,		\
+							_parent,	\
+							&ccu_fixed_factor_ops, \
+							_flags),	\
+		},							\
+	}
+
+static inline struct ccu_fixed_factor *hw_to_ccu_fixed_factor(struct clk_hw *hw)
+{
+	struct ccu_common *common = hw_to_ccu_common(hw);
+
+	return container_of(common, struct ccu_fixed_factor, common);
+}
+
+extern const struct clk_ops ccu_fixed_factor_ops;
+
+#endif /* _CCU_FIXED_FACTOR_H_ */