[RFC 1/8] RFC: CLK: OMAP: Add basic infrastructure for OMAP clocks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds basic infrastructure support for registering clocks
under common clock framework. This patch is done in preparation for
moving clock data from arch/arm/mach-omap2/ folder under /drivers/clk/omap.

Signed-off-by: Tero Kristo <t-kristo@xxxxxx>
Cc: Mike Turquette <mturquette@xxxxxxxxxx>
---
 drivers/clk/omap/clk.c   |  220 ++++++++++++++++
 drivers/clk/omap/clock.h |  645 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 865 insertions(+), 0 deletions(-)
 create mode 100644 drivers/clk/omap/clk.c
 create mode 100644 drivers/clk/omap/clock.h

diff --git a/drivers/clk/omap/clk.c b/drivers/clk/omap/clk.c
new file mode 100644
index 0000000..246f70d
--- /dev/null
+++ b/drivers/clk/omap/clk.c
@@ -0,0 +1,209 @@
+/*
+ * OMAP clock support
+ *
+ * Copyright (c) 2013, Texas Instruments.  All rights reserved.
+ *
+ * Tero Kristo (t-kristo@xxxxxx)
+ *
+ * Highly based on drivers/clk/tegra/clk.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk/omap.h>
+#include <linux/clk-provider.h>
+
+#include "clock.h"
+
+static void __iomem **clk_base;
+
+static struct clk_ops dummy_ck_ops __initdata = {};
+
+static struct clk_hw_omap dummy_ck_hw __initdata = {
+};
+
+struct omap_init_clk omap_dummy_ck __initdata = {
+        .name = "dummy_clk",
+        .ops = &dummy_ck_ops,
+        .clk_register = omap_clk_register,
+        .hw = &dummy_ck_hw,
+};
+
+static struct clksel *omap_clk_init_clksel(struct omap_init_clk *c)
+{
+	struct clksel *sel;
+	struct clksel_init *init;
+	int sz, i;
+
+	init = c->hw->clksel.init;
+
+	if (!init)
+		return NULL;
+
+	if (init->clksel)
+		return init->clksel;
+
+	/* Check size for clksel array */
+	sz = 0;
+	while (init[sz].parent_name) {
+		sz++;
+	}
+
+	sel = kzalloc(sizeof(struct clksel) * (sz + 1), GFP_KERNEL);
+
+	for (i = 0; i < sz; i++) {
+		sel[i].parent = clk_get(NULL, init[i].parent_name);
+		sel[i].rates = init[i].rates;
+	}
+
+	init->clksel = sel;
+
+	return sel;
+}
+
+static inline void __iomem *omap_clk_reg_to_ptr(struct clk_reginfo *reg)
+{
+	void __iomem *base;
+
+	base = clk_base[reg->module];
+	return base + reg->offset;
+}
+
+static struct dpll_data *omap_clk_init_dpll_data(struct omap_init_clk *c)
+{
+	struct dpll_data *init = c->hw->dpll_data;
+	struct dpll_data *dd;
+
+	if (!init)
+		return NULL;
+
+	dd = kmalloc(sizeof(struct dpll_data), GFP_KERNEL);
+
+	memcpy(dd, init, sizeof(struct dpll_data));
+
+	dd->clk_bypass.clk = clk_get(NULL, init->clk_bypass.name);
+	dd->clk_ref.clk = clk_get(NULL, init->clk_ref.name);
+	dd->mult_div1_reg.ptr =
+		omap_clk_reg_to_ptr(&init->mult_div1_reg.reginfo);
+	dd->control_reg.ptr =
+		omap_clk_reg_to_ptr(&init->control_reg.reginfo);
+	dd->autoidle_reg.ptr =
+		omap_clk_reg_to_ptr(&init->autoidle_reg.reginfo);
+	dd->idlest_reg.ptr =
+		omap_clk_reg_to_ptr(&init->idlest_reg.reginfo);
+
+	return dd;
+}
+
+struct clk *omap_clk_register(struct omap_init_clk *c)
+{
+	struct clk_init_data init;
+	struct clk_hw_omap *hw;
+
+	init.name = c->name;
+	init.ops = c->ops;
+	init.parent_names = c->parent_names;
+	init.num_parents = c->num_parents;
+	init.flags = 0;
+
+	hw = kzalloc(sizeof(struct clk_hw_omap), GFP_KERNEL);
+
+	memcpy(hw, c->hw, sizeof(struct clk_hw_omap));
+
+	hw->hw.init = &init;
+
+	hw->clksel.ptr = omap_clk_init_clksel(c);
+
+	hw->dpll_data = omap_clk_init_dpll_data(c);
+
+	if (c->hw->clksel_reg.reginfo.module)
+		hw->clksel_reg.ptr =
+			omap_clk_reg_to_ptr(&c->hw->clksel_reg.reginfo);
+
+	if (c->hw->enable_reg.reginfo.module)
+		hw->enable_reg.ptr =
+			omap_clk_reg_to_ptr(&c->hw->enable_reg.reginfo);
+
+	return clk_register(NULL, &hw->hw);
+}
+
+struct clk *omap_clk_register_fixed_rate(struct omap_init_clk *c)
+{
+	return  clk_register_fixed_rate(NULL, c->name, c->parent_name,
+					c->clk_flags, c->rate);
+}
+
+struct clk *omap_clk_register_mux(struct omap_init_clk *c)
+{
+	return clk_register_mux(NULL, c->name, c->parent_names, c->num_parents,
+				c->clk_flags, omap_clk_reg_to_ptr(&c->reginfo),
+				c->shift, c->width, c->clk_sub_flags, c->lock);
+}
+
+struct clk *omap_clk_register_gate(struct omap_init_clk *c)
+{
+	return clk_register_gate(NULL, c->name, c->parent_name, c->clk_flags,
+				omap_clk_reg_to_ptr(&c->reginfo), c->shift,
+				c->clk_sub_flags, c->lock);
+}
+
+struct clk *omap_clk_register_divider(struct omap_init_clk *c)
+{
+	return clk_register_divider_table(NULL, c->name, c->parent_name,
+					  c->clk_flags,
+					  omap_clk_reg_to_ptr(&c->reginfo),
+					  c->shift, c->width,
+					  c->clk_sub_flags, c->table, c->lock);
+}
+
+struct clk *omap_clk_register_fixed_factor(struct omap_init_clk *c)
+{
+	return clk_register_fixed_factor(NULL, c->name, c->parent_name,
+					 c->clk_flags, c->mult, c->div);
+}
+
+int omap_clk_register_clks(struct omap_clk *clks, int size, u32 cpu_clkflg,
+			   void __iomem **base)
+{
+	struct omap_clk *c;
+	struct clk *clk;
+
+	clk_base = base;
+
+	for (c = clks; c < clks + size; c++) {
+		if (!(c->cpu & cpu_clkflg))
+			continue;
+
+		clk = NULL;
+
+		if (c->clk->clk) {
+			clk = c->clk->clk;
+			clk_register_clkdev(clk, c->con_id, c->dev_id);
+			continue;
+		}
+
+		/* Register clk based on type */
+		clk = c->clk->clk_register(c->clk);
+
+		c->clk->clk = clk;
+
+		if (IS_ERR_OR_NULL(clk))
+			pr_err("%s: failed to register clk %s, type=%d\n",
+				__func__, c->clk->name, c->clk->type);
+		else if (!clk_register_clkdev(clk, c->con_id, c->dev_id))
+			omap2_init_clk_hw_omap_clocks(clk);
+	}
+
+	return 0;
+}
diff --git a/drivers/clk/omap/clock.h b/drivers/clk/omap/clock.h
new file mode 100644
index 0000000..80d7369
--- /dev/null
+++ b/drivers/clk/omap/clock.h
@@ -0,0 +1,645 @@
+/*
+ *  OMAP clock support header
+ *
+ *  Copyright (C) 2005-2009 Texas Instruments, Inc.
+ *  Copyright (C) 2004-2011 Nokia Corporation
+ *
+ *  Contacts:
+ *  Richard Woodruff <r-woodruff2@xxxxxx>
+ *  Paul Walmsley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __ARCH_ARM_MACH_OMAP2_CLOCK_H
+#define __ARCH_ARM_MACH_OMAP2_CLOCK_H
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+
+#include <linux/of.h>
+
+struct omap_init_clk;
+
+struct clk_reginfo {
+	u16				module;
+	u16				offset;
+};
+
+struct omap_init_clk {
+	struct clk			*clk;
+	//const char			*dev_id;
+	const char			*name;
+	const char			**parent_names;
+	const char			*parent_name;
+	int				num_parents;
+	u32				clk_flags;
+	u8				clk_sub_flags;
+	u32				rate;
+	struct clk_reginfo		reginfo;
+	u8				shift;
+	u8				width;
+	u16				mult;
+	u16				div;
+	u8				type;
+	struct clk_hw_omap		*hw;
+	const struct clk_ops		*ops;
+	spinlock_t			*lock;
+	const struct clk_div_table	*table;
+	struct clk*			(*clk_register)(struct omap_init_clk*);
+};
+
+struct omap_clk {
+	u16				cpu;
+	const char			*dev_id;
+	const char			*con_id;
+	struct omap_init_clk		*clk;
+};
+
+#define CLK(dev, con, ck, cp)		\
+	{				\
+		.cpu = cp,		\
+		.dev_id = dev,		\
+		.con_id = con,		\
+		.clk = ck,		\
+	}	
+
+/* Platform flags for the clkdev-OMAP integration code */
+#define CK_242X		(1 << 0)
+#define CK_243X		(1 << 1)	/* 243x, 253x */
+#define CK_3430ES1	(1 << 2)	/* 34xxES1 only */
+#define CK_3430ES2PLUS	(1 << 3)	/* 34xxES2, ES3, non-Sitara 35xx only */
+#define CK_AM35XX	(1 << 4)	/* Sitara AM35xx */
+#define CK_36XX		(1 << 5)	/* 36xx/37xx-specific clocks */
+#define CK_443X		(1 << 6)
+#define CK_TI816X	(1 << 7)
+#define CK_446X		(1 << 8)
+#define CK_AM33XX	(1 << 9)	/* AM33xx specific clocks */
+#define CK_54XX		(1 << 10)	/* OMAP54xx specific clocks */
+
+
+#define CK_34XX		(CK_3430ES1 | CK_3430ES2PLUS)
+#define CK_3XXX		(CK_34XX | CK_AM35XX | CK_36XX)
+
+struct clockdomain;
+#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw)
+
+#define OMAP_CLK_FIXED_RATE(_name, _flags, _rate, _ignore)	\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.clk_flags = _flags,				\
+		.rate = _rate,					\
+		.clk_register = omap_clk_register_fixed_rate,	\
+	};
+
+#define OMAP_CLK_GATE(_name, _parent_name, _ignore, _flags,	\
+		      _reg, _shift, _gate_flags, _lock)		\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.parent_name = _parent_name,			\
+		.clk_flags = _flags,				\
+		.reginfo = { _reg },				\
+		.shift = _shift,				\
+		.clk_sub_flags = _gate_flags,			\
+		.clk_register = omap_clk_register_gate,		\
+		.lock = _lock,					\
+	};
+
+#define OMAP_CLK_MUX(_name, _parents, _ignore, _flags, _reg,	\
+		     _shift, _width, _mux_flags, _lock)		\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.parent_names = _parents,			\
+		.num_parents = ARRAY_SIZE(_parents),		\
+		.clk_flags = _flags,				\
+		.reginfo = { _reg },				\
+		.shift = _shift,				\
+		.width = _width,				\
+		.clk_sub_flags = _mux_flags,			\
+		.clk_register = omap_clk_register_mux,		\
+		.lock = _lock,					\
+	};
+
+#define OMAP_CLK(_name, _parents, _ops)				\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.parent_names = _parents,			\
+		.num_parents = ARRAY_SIZE(_parents),		\
+		.hw = &_name##_hw,				\
+		.ops = &_ops,					\
+		.clk_register = omap_clk_register,		\
+	};
+
+#define OMAP_CLK_DIVIDER(_name, _parent_name, _ignore, _flags,	\
+			 _reg, _shift, _width, _div_flags,	\
+			 _lock)					\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.parent_name = _parent_name,			\
+		.clk_flags = _flags,				\
+		.reginfo = { _reg },				\
+		.shift = _shift,				\
+		.width = _width,				\
+		.clk_sub_flags = _div_flags,			\
+		.table = NULL,					\
+		.clk_register = omap_clk_register_divider,	\
+		.lock = _lock,					\
+	};
+
+#define OMAP_CLK_DIVIDER_TABLE(_name, _parent_name, _ignore,	\
+			       _flags, _reg, _shift, _width,	\
+			       _div_flags, _table, _lock)	\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.parent_name = _parent_name,			\
+		.clk_flags = _flags,				\
+		.reginfo = { _reg },				\
+		.shift = _shift,				\
+		.width = _width,				\
+		.clk_sub_flags = _div_flags,			\
+		.table = _table,				\
+		.clk_register = omap_clk_register_divider,	\
+		.lock = _lock,					\
+	};
+
+#define OMAP_CLK_FIXED_FACTOR(_name, _parent_name, _ignore,	\
+			      _flags, _mult, _div)		\
+	static struct omap_init_clk _name __initdata = {	\
+		.name = #_name,					\
+		.parent_name = _parent_name,			\
+		.clk_flags = _flags,				\
+		.mult = _mult,					\
+		.div = _div,					\
+		.clk_register = omap_clk_register_fixed_factor,	\
+	};
+
+#define DEFINE_STRUCT_CLK_HW_OMAP(_name, _clkdm_name)		\
+	static struct clk_hw_omap _name##_hw __initdata = {	\
+		.clkdm_name = _clkdm_name,			\
+	};
+
+#define DEFINE_CLK_OMAP_MUX(_name, _clkdm_name, _clksel,	\
+			    _reg, _clksel_mask,	_parent_names,	\
+			    _ops)				\
+	static struct clk_hw_omap _name##_hw __initdata = {	\
+		.clksel		= { .init = _clksel },		\
+		.clksel_reg	= { .reginfo = { _reg } },	\
+		.clksel_mask	= _clksel_mask,			\
+		.clkdm_name	= _clkdm_name,			\
+	};							\
+	OMAP_CLK(_name, _parent_names, _ops);
+
+#define DEFINE_CLK_OMAP_MUX_GATE(_name, _clkdm_name, _clksel,	\
+				 _clksel_reg, _clksel_mask,	\
+				 _enable_reg, _enable_bit,	\
+				 _hwops, _parent_names, _ops)	\
+	static struct clk_hw_omap _name##_hw __initdata = {	\
+		.ops		= _hwops,			\
+		.enable_reg	= { .reginfo = { _enable_reg }},\
+		.enable_bit	= _enable_bit,			\
+		.clksel		= { .init = _clksel },		\
+		.clksel_reg	= { .reginfo = { _clksel_reg }},\
+		.clksel_mask	= _clksel_mask,			\
+		.clkdm_name	= _clkdm_name,			\
+	};							\
+	OMAP_CLK(_name, _parent_names, _ops);
+
+#define DEFINE_CLK_OMAP_HSDIVIDER63(_name, _parent_name,	\
+				_parent_ptr, _flags,		\
+				_clksel_module, _clksel_offset,	\
+				_clksel_mask)	\
+								\
+	_DEFINE_CLK_OMAP_HSDIVIDER(_name, _parent_name,		\
+				_parent_ptr, _flags,		\
+				_clksel_module, _clksel_offset,	\
+				_clksel_mask, 63)
+
+#define DEFINE_CLK_OMAP_HSDIVIDER(_name, _parent_name,		\
+				_parent_ptr, _flags,		\
+				_clksel_reg, _clksel_mask)	\
+								\
+	_DEFINE_CLK_OMAP_HSDIVIDER(_name, _parent_name,		\
+				_parent_ptr, _flags,		\
+				_clksel_reg, _clksel_mask, 31)
+
+#define _DEFINE_CLK_OMAP_HSDIVIDER(_name, _parent_name,		\
+				_ignore, _flags,		\
+				_module, _offset,		\
+				_clksel_mask, mdiv)		\
+	static struct clksel_init _name##_div[] __initdata = {	\
+		{						\
+			.rates = div##mdiv##_1to##mdiv##_rates,	\
+			.parent_name = _parent_name,		\
+		},						\
+		{ .parent_name = NULL },			\
+	};							\
+	static const char *_name##_parent_names[] __initdata = {\
+		_parent_name,					\
+	};							\
+	static struct clk_hw_omap _name##_hw __initdata = {	\
+		.clksel		= { .init = _name##_div },	\
+		.clksel_reg	= {				\
+			.reginfo = {				\
+				.module = _module,		\
+				.offset = _offset },		\
+			},					\
+		.clksel_mask	= _clksel_mask,			\
+		.ops		= &clkhwops_omap4_dpllmx,	\
+	};							\
+	OMAP_CLK(_name, _name##_parent_names, omap_hsdivider_ops);
+
+/* struct clksel_rate.flags possibilities */
+#define RATE_IN_242X		(1 << 0)
+#define RATE_IN_243X		(1 << 1)
+#define RATE_IN_3430ES1		(1 << 2)	/* 3430ES1 rates only */
+#define RATE_IN_3430ES2PLUS	(1 << 3)	/* 3430 ES >= 2 rates only */
+#define RATE_IN_36XX		(1 << 4)
+#define RATE_IN_4430		(1 << 5)
+#define RATE_IN_TI816X		(1 << 6)
+#define RATE_IN_4460		(1 << 7)
+#define RATE_IN_AM33XX		(1 << 8)
+#define RATE_IN_TI814X		(1 << 9)
+#define RATE_IN_54XX		(1 << 10)
+
+#define RATE_IN_24XX		(RATE_IN_242X | RATE_IN_243X)
+#define RATE_IN_34XX		(RATE_IN_3430ES1 | RATE_IN_3430ES2PLUS)
+#define RATE_IN_3XXX		(RATE_IN_34XX | RATE_IN_36XX)
+#define RATE_IN_44XX		(RATE_IN_4430 | RATE_IN_4460)
+
+/* RATE_IN_3430ES2PLUS_36XX includes 34xx/35xx with ES >=2, and all 36xx/37xx */
+#define RATE_IN_3430ES2PLUS_36XX	(RATE_IN_3430ES2PLUS | RATE_IN_36XX)
+
+
+/**
+ * struct clksel_rate - register bitfield values corresponding to clk divisors
+ * @val: register bitfield value (shifted to bit 0)
+ * @div: clock divisor corresponding to @val
+ * @flags: (see "struct clksel_rate.flags possibilities" above)
+ *
+ * @val should match the value of a read from struct clk.clksel_reg
+ * AND'ed with struct clk.clksel_mask, shifted right to bit 0.
+ *
+ * @div is the divisor that should be applied to the parent clock's rate
+ * to produce the current clock's rate.
+ */
+struct clksel_rate {
+	u32			val;
+	u8			div;
+	u16			flags;
+};
+
+/**
+ * struct clksel - available parent clocks, and a pointer to their divisors
+ * @parent: struct clk * to a possible parent clock
+ * @rates: available divisors for this parent clock
+ *
+ * A struct clksel is always associated with one or more struct clks
+ * and one or more struct clksel_rates.
+ */
+struct clksel {
+	struct clk			*parent;
+	const struct clksel_rate	*rates;
+};
+
+struct clksel_init {
+	struct clksel			*clksel;
+	const struct clksel_rate	*rates;
+	const char			*parent_name;
+};
+
+/**
+ * struct dpll_data - DPLL registers and integration data
+ * @mult_div1_reg: register containing the DPLL M and N bitfields
+ * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg
+ * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg
+ * @clk_bypass: struct clk pointer to the clock's bypass clock input
+ * @clk_ref: struct clk pointer to the clock's reference clock input
+ * @control_reg: register containing the DPLL mode bitfield
+ * @enable_mask: mask of the DPLL mode bitfield in @control_reg
+ * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
+ * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
+ * @last_rounded_m4xen: cache of the last M4X result of
+ *			omap4_dpll_regm4xen_round_rate()
+ * @last_rounded_lpmode: cache of the last lpmode result of
+ *			 omap4_dpll_lpmode_recalc()
+ * @max_multiplier: maximum valid non-bypass multiplier value (actual)
+ * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
+ * @min_divider: minimum valid non-bypass divider value (actual)
+ * @max_divider: maximum valid non-bypass divider value (actual)
+ * @modes: possible values of @enable_mask
+ * @autoidle_reg: register containing the DPLL autoidle mode bitfield
+ * @idlest_reg: register containing the DPLL idle status bitfield
+ * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg
+ * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg
+ * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg
+ * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg
+ * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg
+ * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg
+ * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs
+ * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs
+ * @flags: DPLL type/features (see below)
+ *
+ * Possible values for @flags:
+ * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs)
+ *
+ * @freqsel_mask is only used on the OMAP34xx family and AM35xx.
+ *
+ * XXX Some DPLLs have multiple bypass inputs, so it's not technically
+ * correct to only have one @clk_bypass pointer.
+ *
+ * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m,
+ * @last_rounded_n) should be separated from the runtime-fixed fields
+ * and placed into a different structure, so that the runtime-fixed data
+ * can be placed into read-only space.
+ */
+struct dpll_data {
+	union {
+		void __iomem		*ptr;
+		struct clk_reginfo	reginfo;
+	} mult_div1_reg;
+	u32			mult_mask;
+	u32			div1_mask;
+	union {
+		struct clk	*clk;
+		const char	*name;
+	} clk_bypass;
+	union {
+		struct clk	*clk;
+		const char	*name;
+	} clk_ref;
+	union {
+		void __iomem		*ptr;
+		struct clk_reginfo	reginfo;
+	} control_reg;
+	u32			enable_mask;
+	unsigned long		last_rounded_rate;
+	u16			last_rounded_m;
+	u8			last_rounded_m4xen;
+	u8			last_rounded_lpmode;
+	u16			max_multiplier;
+	u8			last_rounded_n;
+	u8			min_divider;
+	u16			max_divider;
+	u8			modes;
+	union {
+		void __iomem	*ptr;
+		struct clk_reginfo	reginfo;
+	} autoidle_reg;
+	union {
+		void __iomem	*ptr;
+		struct clk_reginfo	reginfo;
+	} idlest_reg;
+	u32			autoidle_mask;
+	u32			freqsel_mask;
+	u32			idlest_mask;
+	u32			dco_mask;
+	u32			sddiv_mask;
+	u32			lpmode_mask;
+	u32			m4xen_mask;
+	u8			auto_recal_bit;
+	u8			recal_en_bit;
+	u8			recal_st_bit;
+	u8			flags;
+};
+
+/*
+ * struct clk.flags possibilities
+ *
+ * XXX document the rest of the clock flags here
+ *
+ * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL
+ *     bits share the same register.  This flag allows the
+ *     omap4_dpllmx*() code to determine which GATE_CTRL bit field
+ *     should be used.  This is a temporary solution - a better approach
+ *     would be to associate clock type-specific data with the clock,
+ *     similar to the struct dpll_data approach.
+ */
+#define ENABLE_REG_32BIT	(1 << 0)	/* Use 32-bit access */
+#define CLOCK_IDLE_CONTROL	(1 << 1)
+#define CLOCK_NO_IDLE_PARENT	(1 << 2)
+#define ENABLE_ON_INIT		(1 << 3)	/* Enable upon framework init */
+#define INVERT_ENABLE		(1 << 4)	/* 0 enables, 1 disables */
+#define CLOCK_CLKOUTX2		(1 << 5)
+
+/**
+ * struct clk_hw_omap - OMAP struct clk
+ * @node: list_head connecting this clock into the full clock list
+ * @enable_reg: register to write to enable the clock (see @enable_bit)
+ * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
+ * @flags: see "struct clk.flags possibilities" above
+ * @clksel_reg: for clksel clks, register va containing src/divisor select
+ * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector
+ * @clksel: for clksel clks, pointer to struct clksel for this clock
+ * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock
+ * @clkdm_name: clockdomain name that this clock is contained in
+ * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime
+ * @rate_offset: bitshift for rate selection bitfield (OMAP1 only)
+ * @src_offset: bitshift for source selection bitfield (OMAP1 only)
+ *
+ * XXX @rate_offset, @src_offset should probably be removed and OMAP1
+ * clock code converted to use clksel.
+ *
+ */
+
+struct clk_hw_omap_ops;
+
+struct clk_hw_omap {
+	struct clk_hw		hw;
+	struct list_head	node;
+	unsigned long		fixed_rate;
+	u8			fixed_div;
+	union {
+		void __iomem		*ptr;
+		struct clk_reginfo	reginfo;
+	} enable_reg;
+	u8			enable_bit;
+	u8			flags;
+	union {
+		void __iomem		*ptr;
+		struct clk_reginfo	reginfo;
+	} clksel_reg;
+	u32			clksel_mask;
+	union {
+		struct clksel		*ptr;
+		struct clksel_init	*init;
+	} clksel;
+	struct dpll_data	*dpll_data;
+	const char		*clkdm_name;
+	struct clockdomain	*clkdm;
+	const struct clk_hw_omap_ops	*ops;
+};
+
+struct clk_hw_omap_ops {
+	void			(*find_idlest)(struct clk_hw_omap *oclk,
+					void __iomem **idlest_reg,
+					u8 *idlest_bit, u8 *idlest_val);
+	void			(*find_companion)(struct clk_hw_omap *oclk,
+					void __iomem **other_reg,
+					u8 *other_bit);
+	void			(*allow_idle)(struct clk_hw_omap *oclk);
+	void			(*deny_idle)(struct clk_hw_omap *oclk);
+};
+
+unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw,
+					unsigned long parent_rate);
+
+/* CM_CLKSEL2_PLL.CORE_CLK_SRC bits (2XXX) */
+#define CORE_CLK_SRC_32K		0x0
+#define CORE_CLK_SRC_DPLL		0x1
+#define CORE_CLK_SRC_DPLL_X2		0x2
+
+/* OMAP2xxx CM_CLKEN_PLL.EN_DPLL bits - for omap2_get_dpll_rate() */
+#define OMAP2XXX_EN_DPLL_LPBYPASS		0x1
+#define OMAP2XXX_EN_DPLL_FRBYPASS		0x2
+#define OMAP2XXX_EN_DPLL_LOCKED			0x3
+
+/* OMAP3xxx CM_CLKEN_PLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */
+#define OMAP3XXX_EN_DPLL_LPBYPASS		0x5
+#define OMAP3XXX_EN_DPLL_FRBYPASS		0x6
+#define OMAP3XXX_EN_DPLL_LOCKED			0x7
+
+/* OMAP4xxx CM_CLKMODE_DPLL*.EN_*_DPLL bits - for omap2_get_dpll_rate() */
+#define OMAP4XXX_EN_DPLL_MNBYPASS		0x4
+#define OMAP4XXX_EN_DPLL_LPBYPASS		0x5
+#define OMAP4XXX_EN_DPLL_FRBYPASS		0x6
+#define OMAP4XXX_EN_DPLL_LOCKED			0x7
+
+/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */
+#define DPLL_LOW_POWER_STOP	0x1
+#define DPLL_LOW_POWER_BYPASS	0x5
+#define DPLL_LOCKED		0x7
+
+/* DPLL Type and DCO Selection Flags */
+#define DPLL_J_TYPE		0x1
+
+long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
+			unsigned long *parent_rate);
+unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
+int omap3_noncore_dpll_enable(struct clk_hw *hw);
+void omap3_noncore_dpll_disable(struct clk_hw *hw);
+int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate);
+u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
+void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
+void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
+unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
+				    unsigned long parent_rate);
+int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk);
+void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk);
+void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk);
+unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
+				unsigned long parent_rate);
+long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
+				    unsigned long target_rate,
+				    unsigned long *parent_rate);
+
+void omap2_init_clk_clkdm(struct clk_hw *clk);
+void __init omap2_clk_disable_clkdm_control(void);
+
+/* clkt_clksel.c public functions */
+u32 omap2_clksel_round_rate_div(struct clk_hw_omap *clk,
+				unsigned long target_rate,
+				u32 *new_div);
+u8 omap2_clksel_find_parent_index(struct clk_hw *hw);
+unsigned long omap2_clksel_recalc(struct clk_hw *hw, unsigned long parent_rate);
+long omap2_clksel_round_rate(struct clk_hw *hw, unsigned long target_rate,
+				unsigned long *parent_rate);
+int omap2_clksel_set_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long parent_rate);
+int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val);
+
+/* clkt_iclk.c public functions */
+extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk);
+extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk);
+
+u8 omap2_init_dpll_parent(struct clk_hw *hw);
+unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
+
+int omap2_dflt_clk_enable(struct clk_hw *hw);
+void omap2_dflt_clk_disable(struct clk_hw *hw);
+int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
+void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
+				   void __iomem **other_reg,
+				   u8 *other_bit);
+void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
+				void __iomem **idlest_reg,
+				u8 *idlest_bit, u8 *idlest_val);
+void omap2_init_clk_hw_omap_clocks(struct clk *clk);
+int omap2_clk_enable_autoidle_all(void);
+int omap2_clk_disable_autoidle_all(void);
+void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
+int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name);
+void omap2_clk_print_new_rates(const char *hfclkin_ck_name,
+			       const char *core_ck_name,
+			       const char *mpu_ck_name);
+
+extern u16 cpu_mask;
+
+extern const struct clkops clkops_omap2_dflt_wait;
+extern const struct clkops clkops_dummy;
+extern const struct clkops clkops_omap2_dflt;
+
+extern struct clk_functions omap2_clk_functions;
+
+extern const struct clksel_rate gpt_32k_rates[];
+extern const struct clksel_rate gpt_sys_rates[];
+extern const struct clksel_rate gfx_l3_rates[];
+extern const struct clksel_rate dsp_ick_rates[];
+
+extern struct omap_init_clk omap_dummy_ck;
+
+extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
+extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
+extern const struct clk_hw_omap_ops clkhwops_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;
+extern const struct clk_hw_omap_ops clkhwops_iclk;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait;
+extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
+extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait;
+extern const struct clk_hw_omap_ops clkhwops_apll54;
+extern const struct clk_hw_omap_ops clkhwops_apll96;
+extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll;
+extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait;
+
+/* clksel_rate blocks shared between OMAP44xx and AM33xx */
+extern const struct clksel_rate div_1_0_rates[];
+extern const struct clksel_rate div3_1to4_rates[];
+extern const struct clksel_rate div_1_1_rates[];
+extern const struct clksel_rate div_1_2_rates[];
+extern const struct clksel_rate div_1_3_rates[];
+extern const struct clksel_rate div_1_4_rates[];
+extern const struct clksel_rate div31_1to31_rates[];
+extern const struct clksel_rate div63_1to63_rates[];
+
+extern int am33xx_clk_init(void);
+
+extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
+extern void omap2_clkops_disable_clkdm(struct clk_hw *hw);
+
+#ifdef CONFIG_ARCH_OMAP4
+extern void omap4xxx_clocks_init(struct device_node *np);
+#else
+static inline void omap4xxx_clocks_init(struct device_node *np) {}
+#endif /* CONFIG_ARCH_OMAP4 */
+
+extern int omap_clk_register_clks(struct omap_clk *clks, int size,
+				  u32 cpu_clkflg, void __iomem **base);
+
+extern struct clk *omap_clk_register(struct omap_init_clk *c);
+extern struct clk *omap_clk_register_fixed_rate(struct omap_init_clk *c);
+extern struct clk *omap_clk_register_mux(struct omap_init_clk *c);
+extern struct clk *omap_clk_register_gate(struct omap_init_clk *c);
+extern struct clk *omap_clk_register_divider(struct omap_init_clk *c);
+extern struct clk *omap_clk_register_fixed_factor(struct omap_init_clk *c);
+
+#endif
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Arm (vger)]     [ARM Kernel]     [ARM MSM]     [Linux Tegra]     [Linux WPAN Networking]     [Linux Wireless Networking]     [Maemo Users]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Trails]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux