Merge branches 'tz1090_8250_tolerance', 'tz1090_clk_specified', 'tz1090_clks' (early part), 'tz1090_metag' (early part) and 'img_wdt_fixes' into tmp
$ git merge tz1090_8250_tolerance tz1090_clk_specified tz1090_clks~2 tz1090_metag~ img_wdt_fixes
diff --git a/Documentation/devicetree/bindings/clock/img,tz1090-hep-cr.txt b/Documentation/devicetree/bindings/clock/img,tz1090-hep-cr.txt
new file mode 100644
index 0000000..79a3f7a
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/img,tz1090-hep-cr.txt
@@ -0,0 +1,53 @@
+Binding for TZ1090 High end peripheral clocks.
+
+This binding uses the common clock binding[1]. It represents the clocks
+controlled from the high end peripheral registers of the TZ1090:
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : Shall be "img,tz1090-hep-cr", "syscon".
+- #clock-cells : From common clock binding; shall be set to 1.
+- reg : Base address for clock registers in high end peripheral
+ register region.
+- clocks : Clock specifiers for each input clock.
+- clock-names : Labels for each input clock specified in clocks.
+ Can contain the following entries:
+ "sys" : Main system clock.
+ "sys_x2_undeleted" : System clock before division and
+ deletion.
+
+Optional properties:
+- clock-indices : From common clock binding. Allows clock-output-names to
+ be sparse.
+- clock-output-names : From common clock binding. May be used to name specific
+ output clocks so that other clock providers can find
+ the clocks by name before the provider has been
+ instantiated. Can contain:
+ "sys_2d", "ddr_en", "sys_pdp"
+
+Clock Specifier Definition:
+- <1st-cell>: Output clock number. Use constants from
+ <dt-bindings/clock/tz1090-hep.h>.
+
+Examples:
+ hep_cr: hep_cr {
+ compatible = "img,tz1090-hep-cr", "syscon";
+ #clock-cells = <1>;
+ reg = <0x02008c00 0x08>;
+ /* input clocks */
+ clocks = <&top_clks CLK_TOP_SYS>,
+ <&top_clks CLK_TOP_SYS_X2_UNDELETED>;
+ clock-names = "sys",
+ "sys_x2_undeleted";
+ /* output clocks for other clock providers */
+ clock-indices = <CLK_HEP_DDR_EN>;
+ clock-output-names = "ddr_en";
+ };
+
+ pdp {
+ ...
+ clocks = <&hep_cr CLK_HEP_PDP>;
+ clock-names = "pdp";
+ ...
+ };
diff --git a/Documentation/devicetree/bindings/clock/img,tz1090-pdc-cr.txt b/Documentation/devicetree/bindings/clock/img,tz1090-pdc-cr.txt
new file mode 100644
index 0000000..37d36d2
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/img,tz1090-pdc-cr.txt
@@ -0,0 +1,59 @@
+Binding for TZ1090 PDC clocks.
+
+This binding uses the common clock binding[1]. It represents the clocks
+required to generate the 32KHz PDC clock used by the devices in the low power
+domain:
+
+ ___________
+xtal1 ___| xtal1_div |____________________________
+ |___________| | ________ xtal1_div
+ `--o| rtc_sw \____________
+xtal3 ----------------------|________/ 32khz
+
+xtal1_div = xtal1 / (reg[26:16] + 1)
+xtal3 = reg[30] ? xtal3 : xtal1_div
+
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : Shall be "img,tz1090-pdc-cr", "syscon".
+- #clock-cells : From common clock binding; shall be set to 1.
+- reg : Base address for registers controlling PDC clocks.
+- clocks : Clock specifiers for each input clock.
+- clock-names : Labels for each input clock specified in clocks.
+ Can contain the following entries:
+ "xtal1" : XTAL1 oscillator.
+ "xtal3" : XTAL3 32KHz oscillator.
+
+Optional properties:
+- clock-indices : From common clock binding. Allows clock-output-names to
+ be sparse.
+- clock-output-names : From common clock binding. May be used to name specific
+ output clocks so that other clock providers can find
+ the clocks by name before the provider has been
+ instantiated. Can contain:
+ "32khz" : 32khz PDC clock.
+
+Clock Specifier Definition:
+- <1st-cell>: Output clock number. Use constants from
+ <dt-bindings/clock/tz1090-pdc.h>.
+
+Examples:
+ pdc_cr: pdc_cr {
+ compatible = "img,tz1090-pdc-cr", "syscon";
+ #clock-cells = <1>;
+ reg = <0x02006500 0x4>; /* SOC_GPIO_CONTROL0 */
+ clocks = <&xtal1>,
+ <&xtal3>;
+ clock-names = "xtal1",
+ "xtal3";
+ };
+
+ ir {
+ ...
+ clocks = <&pdc_cr CLK_PDC_32KHZ>,
+ <&top_cr CLK_TOP_PDC>;
+ clock-names = "core", "sys";
+ ...
+ };
diff --git a/Documentation/devicetree/bindings/clock/img,tz1090-perip-cr.txt b/Documentation/devicetree/bindings/clock/img,tz1090-perip-cr.txt
new file mode 100644
index 0000000..f9c293d
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/img,tz1090-perip-cr.txt
@@ -0,0 +1,49 @@
+Binding for TZ1090 Peripheral register clocks.
+
+This binding uses the common clock binding[1]. It represents the clocks
+controlled from the peripheral registers of the TZ1090:
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : Shall be "img,tz1090-perip-cr", "syscon".
+- #clock-cells : From common clock binding; shall be set to 1.
+- reg : Base address for clock registers in peripheral register
+ region.
+- clocks : Clock specifiers for each input clock.
+- clock-names : Labels for each input clock specified in clocks.
+ Can contain the following entries:
+ "sys" : Main system clock.
+
+Optional properties:
+- clock-indices : From common clock binding. Allows clock-output-names to
+ be sparse.
+- clock-output-names : From common clock binding. May be used to name specific
+ output clocks so that other clock providers can find
+ the clocks by name before the provider has been
+ instantiated. Can contain:
+ "sys_scb0", "sys_scb1", "sys_scb2", "sys_sdio",
+ "sys_uart0", "sys_uart1", "sys_spim", "sys_spis",
+ "sys_spim1", "sys_i2sout", "sys_i2sin", "sys_lcd",
+ "sys_sdhost", "sys_usb"
+
+Clock Specifier Definition:
+- <1st-cell>: Output clock number. Use constants from
+ <dt-bindings/clock/tz1090-perip.h>.
+
+Examples:
+ perip_cr: perip_cr {
+ compatible = "img,tz1090-perip-cr", "syscon";
+ #clock-cells = <1>;
+ reg = <0x02004000 0x18>;
+ clocks = <&top_cr CLK_TOP_SYS>;
+ clock-names = "sys";
+ };
+
+ i2c {
+ ...
+ clocks = <&top_cr CLK_TOP_SCB>,
+ <&perip_cr CLK_PERIP_SCB0>;
+ clock-names = "scb", "sys";
+ ...
+ };
diff --git a/Documentation/devicetree/bindings/clock/img,tz1090-top-cr.txt b/Documentation/devicetree/bindings/clock/img,tz1090-top-cr.txt
new file mode 100644
index 0000000..6c4f0b7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/img,tz1090-top-cr.txt
@@ -0,0 +1,68 @@
+Binding for TZ1090 Top level register clocks.
+
+This binding uses the common clock binding[1]. It represents the clocks
+controlled from the top level registers of the TZ1090, and encompasses most of
+the complexity of the TZ1090 clock tree:
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : Shall be "img,tz1090-top-cr", "syscon".
+- #clock-cells : From common clock binding; shall be set to 1.
+- reg : Base address for clock registers in top level register
+ region.
+- clocks : Clock specifiers for each input clock.
+- clock-names : Labels for each input clock specified in clocks.
+ Can contain the following entries:
+ "xtal1" : XTAL1 oscillator.
+ "xtal3" : XTAL2 oscillator.
+ "ext_adc_dac" : External ADC/DAC clock input.
+ "ddr_en" : Output of HEP DDR clock gate.
+ "afe_progdiv1",
+ "afe_progdiv3",
+ "afe_rxsync",
+ "afe_txsync",
+ "iqadc_sync" : Output clocks from AFE block.
+
+Optional properties:
+- clock-indices : From common clock binding. Allows clock-output-names to
+ be sparse.
+- clock-output-names : From common clock binding. May be used to name specific
+ output clocks so that other clock providers can find
+ the clocks by name before the provider has been
+ instantiated. Can contain:
+ "sys", "sys_x2_undeleted" "scb", "ext_stc0", "ext_stc1",
+ "if1", "if0", "sys_ucc1", "sys_mtx", "meta", "ucc0",
+ "ucc1_del", "sys_undeleted", "afe", "adcpll_div", "uart",
+ "pdm", "spi0", "spi1", "i2sm", "usb_phy", "sdhost",
+ "ring_osc", "i2s", "meta_trace", "pixel", "out0", "out1",
+ "ddr", "sys_pll", "sys_pdc"
+
+Clock Specifier Definition:
+- <1st-cell>: Output clock number. Use constants from
+ <dt-bindings/clock/tz1090-top.h>.
+
+Examples:
+ top_cr: top_cr {
+ compatible = "img,tz1090-top-cr", "syscon";
+ #clock-cells = <1>;
+ reg = <0x02005900 0xb0>;
+ /* input clocks */
+ clocks = <&xtal1>, <&xtal2>, <&ext_adc_dac>,
+ <&hep_cr CLK_HEP_DDR_EN>;
+ clock-names = "xtal1", "xtal2", "ext_adc_dac",
+ "ddr_en";
+ /* output clocks for other clock providers */
+ clock-indices = <CLK_TOP_SYS>,
+ <CLK_TOP_SYS_X2_UNDELETED>;
+ clock-output-names = "sys",
+ "sys_x2_undeleted";
+ };
+
+ ir {
+ ...
+ clocks = <&pdc_cr CLK_PDC_32KHZ>,
+ <&top_cr CLK_TOP_PDC>;
+ clock-names = "core", "sys";
+ ...
+ };
diff --git a/Documentation/devicetree/bindings/clock/specified-clock.txt b/Documentation/devicetree/bindings/clock/specified-clock.txt
new file mode 100644
index 0000000..7135adda
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/specified-clock.txt
@@ -0,0 +1,62 @@
+Binding for discoverable-fixed-rate clock sources.
+
+This binding uses the common clock binding[1].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "specified-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- bit-mask : Mask of bits in the field specifying the frequency.
+- table : array of integer pairs defining register field values and
+ corresponding clock frequencies in Hz.
+
+Optional properties:
+- reg : Base address of configuration register specifying the frequency.
+- syscon-reg : Phandle to syscon node and offset of syscon register.
+- bit-shift : Number of bits to shift the masked register value.
+ Defaults to (ffs(bit-mask) - 1) if absent.
+- clock-accuracy : accuracy of clock in ppb (parts per billion).
+ Should be a single cell.
+- clock-output-names : From common clock binding.
+
+NOTE: One of reg or syscon-reg must be provided.
+
+Examples:
+ clock {
+ compatible = "specified-clock";
+ #clock-cells = <0>;
+ reg = <0x02004004 0x4>; /* CR_PERIP_RESET_CFG */
+ bit-mask = <0x00000f00>; /* FXTAL */
+ table = /* FXTAL Frequency */
+ <0 16384000>,
+ <1 19200000>,
+ <2 24000000>,
+ <3 24576000>,
+ <4 26000000>,
+ <5 36000000>,
+ <6 36864000>,
+ <7 38400000>,
+ <8 40000000>;
+ clock-accuracy = <100>;
+ clock-output-names = "xtal1";
+ };
+
+ clock {
+ compatible = "specified-clock";
+ #clock-cells = <0>;
+ syscon-reg = <&perip_cr 0x4>; /* CR_PERIP_RESET_CFG */
+ bit-mask = <0x00000f00>; /* FXTAL */
+ table = /* FXTAL Frequency */
+ <0 16384000>,
+ <1 19200000>,
+ <2 24000000>,
+ <3 24576000>,
+ <4 26000000>,
+ <5 36000000>,
+ <6 36864000>,
+ <7 38400000>,
+ <8 40000000>;
+ clock-accuracy = <100>;
+ clock-output-names = "xtal1";
+ };
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d478ceb..7262958 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -65,6 +65,7 @@
obj-$(CONFIG_ARCH_STI) += st/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_TEGRA) += tegra/
+obj-$(CONFIG_SOC_TZ1090) += tz1090/
obj-$(CONFIG_ARCH_OMAP2PLUS) += ti/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index 0fc56ab..c76241b 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -9,12 +9,16 @@
* Fixed rate clock implementation
*/
+#include <linux/bitops.h>
#include <linux/clk-provider.h>
+#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/regmap.h>
#include <linux/io.h>
#include <linux/err.h>
#include <linux/of.h>
+#include <linux/of_address.h>
/*
* DOC: basic fixed-rate clock that cannot gate
@@ -134,4 +138,90 @@
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
+
+/**
+ * of_specified_clk_read() - Read the register specifying the clock rate.
+ * @node: Device tree node.
+ * @reg_val: Output pointer to write register value.
+ *
+ * Returns: 0 on success, -errno on failure.
+ */
+static int of_specified_clk_read(struct device_node *node, u32 *reg_val)
+{
+ void __iomem *reg;
+ struct regmap *syscon;
+ int ret;
+ u32 offset;
+
+ /* First try iomapping and reading the configuration register */
+ reg = of_iomap(node, 0);
+ if (reg) {
+ *reg_val = readl(reg);
+ iounmap(reg);
+ return 0;
+ }
+
+ /* Next look for a syscon phandle */
+ syscon = syscon_regmap_lookup_by_phandle(node, "syscon-reg");
+ if (IS_ERR(syscon))
+ return PTR_ERR(syscon);
+
+ /* Get the register offset from the second element */
+ ret = of_property_read_u32_index(node, "syscon-reg", 1, &offset);
+ if (ret)
+ return ret;
+
+ /* Read the register value */
+ return regmap_read(syscon, offset, reg_val);
+}
+
+/**
+ * of_specified_clk_setup() - Setup function for discoverable fixed rate clock.
+ * @node: Device tree node.
+ */
+void of_specified_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ u32 shift, mask, rate, reg_val, val;
+ u32 accuracy = 0;
+ struct property *prop;
+ const __be32 *p;
+
+ /* Read the register value specifying the clock rate */
+ if (of_specified_clk_read(node, ®_val))
+ return;
+
+ /* Apply bit-mask */
+ if (of_property_read_u32(node, "bit-mask", &mask))
+ return;
+ reg_val &= mask;
+ /* Apply bit-shift */
+ if (of_property_read_u32(node, "bit-shift", &shift))
+ shift = ffs(mask) - 1;
+ reg_val >>= shift;
+
+ /* Look through the mapping for a matching frequency */
+ of_property_for_each_u32(node, "table", prop, p, val) {
+ p = of_prop_next_u32(prop, p, &rate);
+ if (!p)
+ break;
+ if (val == reg_val)
+ goto found_rate;
+ }
+ /* No match found */
+ return;
+found_rate:
+ of_property_read_u32(node, "clock-accuracy", &accuracy);
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ clk = clk_register_fixed_rate_with_accuracy(NULL, clk_name, NULL,
+ CLK_IS_ROOT, rate,
+ accuracy);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+}
+EXPORT_SYMBOL_GPL(of_specified_clk_setup);
+CLK_OF_DECLARE(specified_clk, "specified-clock", of_specified_clk_setup);
#endif
diff --git a/drivers/clk/tz1090/Makefile b/drivers/clk/tz1090/Makefile
new file mode 100644
index 0000000..1df6b8a
--- /dev/null
+++ b/drivers/clk/tz1090/Makefile
@@ -0,0 +1,13 @@
+# Makefile for TZ1090-specific clocks
+obj-y += clk.o
+
+obj-y += clk-tz1090-deleter.o
+obj-y += clk-tz1090-divider.o
+obj-y += clk-tz1090-gate-bank.o
+obj-y += clk-tz1090-mux-bank.o
+obj-y += clk-tz1090-pll.o
+
+obj-y += clk-tz1090-hep.o
+obj-y += clk-tz1090-pdc.o
+obj-y += clk-tz1090-perip.o
+obj-y += clk-tz1090-top.o
diff --git a/drivers/clk/tz1090/clk-tz1090-deleter.c b/drivers/clk/tz1090/clk-tz1090-deleter.c
new file mode 100644
index 0000000..9ec604d
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-deleter.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * Clock deleter in TZ1090
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+/**
+ * struct tz1090_clk_deleter_priv - Clock deleter
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: delete register
+ * @period: cycle period
+ * @mask: bit mask of delete field
+ * @shift: start bit of delete field
+ *
+ * Deleter in TZ1090, allowing up to period-1 out of each period cycles to be
+ * deleted.
+ */
+struct tz1090_clk_deleter_priv {
+ struct clk_hw hw;
+ void __iomem *reg;
+ u32 period;
+ u32 mask;
+ u8 shift;
+};
+
+#define to_tz1090_clk_deleter(_hw) \
+ container_of(_hw, struct tz1090_clk_deleter_priv, hw)
+
+static unsigned long tz1090_clk_deleter_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tz1090_clk_deleter_priv *deleter = to_tz1090_clk_deleter(hw);
+ u32 delete;
+ u64 rate;
+
+ delete = (readl(deleter->reg) & deleter->mask) >> deleter->shift;
+ rate = (u64)parent_rate * (deleter->period - delete);
+ do_div(rate, deleter->period);
+ return rate;
+}
+
+static const struct clk_ops tz1090_clk_deleter_ops = {
+ .recalc_rate = tz1090_clk_deleter_recalc_rate,
+};
+
+/**
+ * __register_deleter() - register a clock deleter
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @reg: register address to adjust deleter
+ * @period: delete cycle period
+ * @mask: mask of delete field
+ * @shift: start bit of delete field
+ *
+ * Register a TZ1090 clock deleter with the clock framework.
+ */
+static struct clk *__init __register_deleter(const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *reg,
+ u32 period,
+ u32 mask,
+ u8 shift)
+{
+ struct tz1090_clk_deleter_priv *deleter;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the deleter */
+ deleter = kzalloc(sizeof(struct tz1090_clk_deleter_priv), GFP_KERNEL);
+ if (!deleter)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tz1090_clk_deleter_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct tz1090_clk_deleter_priv assignments */
+ deleter->reg = reg;
+ deleter->period = period;
+ deleter->mask = mask;
+ deleter->shift = shift;
+ deleter->hw.init = &init;
+
+ /* register the clock */
+ clk = clk_register(NULL, &deleter->hw);
+
+ if (IS_ERR(clk))
+ kfree(deleter);
+
+ return clk;
+}
+
+/**
+ * tz1090_clk_register_deleters() - Register set of deleters with a provider.
+ * @p: TZ1090 clock provider.
+ * @deleters: Array of deleter descriptions.
+ * @count Number of deleters described in the array.
+ */
+void __init tz1090_clk_register_deleters(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_deleter *deleters,
+ unsigned int count)
+{
+ const struct tz1090_clk_deleter *del;
+ struct clk *clk;
+ unsigned int i;
+
+ for (del = deleters, i = 0; i < count; ++del, ++i) {
+ clk = __register_deleter(tz1090_clk_xlate(p, del->name),
+ tz1090_clk_xlate(p, del->parent), 0,
+ p->base + del->reg, 1024, 0x3ff, 0);
+ p->clk_data.clks[del->id] = clk;
+ }
+}
diff --git a/drivers/clk/tz1090/clk-tz1090-divider.c b/drivers/clk/tz1090/clk-tz1090-divider.c
new file mode 100644
index 0000000..22db67d
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-divider.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 Divider Clock.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <asm/global_lock.h>
+
+#include "clk.h"
+
+/**
+ * struct tz1090_clk_div_priv - tz1090 divider clock
+ *
+ * @div: the parent class
+ * @ops: pointer to clk_ops of parent class
+ *
+ * Divider clock whose field shares a register with other fields which may be
+ * used by multiple threads/cores and other drivers.
+ */
+struct tz1090_clk_div_priv {
+ struct clk_divider div;
+ const struct clk_ops *ops;
+};
+
+static inline struct tz1090_clk_div_priv *to_tz1090_clk_div(struct clk_hw *hw)
+{
+ struct clk_divider *div = container_of(hw, struct clk_divider, hw);
+
+ return container_of(div, struct tz1090_clk_div_priv, div);
+}
+
+static unsigned long tz1090_clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct tz1090_clk_div_priv *div = to_tz1090_clk_div(hw);
+
+ return div->ops->recalc_rate(&div->div.hw, parent_rate);
+}
+
+static long tz1090_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct tz1090_clk_div_priv *div = to_tz1090_clk_div(hw);
+
+ return div->ops->round_rate(&div->div.hw, rate, prate);
+}
+
+/* Acquire exclusive lock since other cores may access the same register */
+static int tz1090_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tz1090_clk_div_priv *div = to_tz1090_clk_div(hw);
+ int ret;
+ unsigned long flags;
+
+ __global_lock2(flags);
+ ret = div->ops->set_rate(&div->div.hw, rate, parent_rate);
+ __global_unlock2(flags);
+
+ return ret;
+}
+
+static const struct clk_ops tz1090_clk_div_ops = {
+ .recalc_rate = tz1090_clk_divider_recalc_rate,
+ .round_rate = tz1090_clk_divider_round_rate,
+ .set_rate = tz1090_clk_divider_set_rate,
+};
+
+static struct clk *__init __register_divider(const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *reg, u8 shift,
+ u8 width, u8 clk_divider_flags)
+{
+ struct tz1090_clk_div_priv *div;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the divider */
+ div = kzalloc(sizeof(struct tz1090_clk_div_priv), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tz1090_clk_div_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct clk_divider assignments */
+ div->div.reg = reg;
+ div->div.shift = shift;
+ div->div.width = width;
+ div->div.flags = clk_divider_flags;
+ div->div.hw.init = &init;
+
+ /* struct tz1090_clk_div_priv assignments */
+ div->ops = &clk_divider_ops;
+
+ /* register the clock */
+ clk = clk_register(NULL, &div->div.hw);
+
+ if (IS_ERR(clk))
+ kfree(div);
+
+ return clk;
+}
+
+/**
+ * tz1090_clk_register_dividers() - Register set of dividers with a provider.
+ * @p: TZ1090 clock provider.
+ * @dividers: Array of divider descriptions.
+ * @count Number of dividers described in the array.
+ */
+void __init tz1090_clk_register_dividers(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_divider *dividers,
+ unsigned int count)
+{
+ const struct tz1090_clk_divider *div;
+ struct clk *clk;
+ unsigned int i;
+
+ for (div = dividers, i = 0; i < count; ++div, ++i) {
+ /*
+ * Dividers in registers shared between OSes must protect the
+ * register with a global lock. Others with dedicated registers
+ * can just use a normal divider.
+ */
+ if (div->shared)
+ clk = __register_divider(tz1090_clk_xlate(p, div->name),
+ tz1090_clk_xlate(p, div->parent),
+ div->flags, p->base + div->reg,
+ div->shift, div->width, div->div_flags);
+ else
+ clk = clk_register_divider(NULL,
+ tz1090_clk_xlate(p, div->name),
+ tz1090_clk_xlate(p, div->parent),
+ div->flags, p->base + div->reg,
+ div->shift, div->width, div->div_flags,
+ NULL);
+ p->clk_data.clks[div->id] = clk;
+ }
+}
diff --git a/drivers/clk/tz1090/clk-tz1090-gate-bank.c b/drivers/clk/tz1090/clk-tz1090-gate-bank.c
new file mode 100644
index 0000000..5834afd
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-gate-bank.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 Clock gate bank
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/global_lock.h>
+
+#include "clk.h"
+
+/**
+ * struct tz1090_clk_gate_priv - tz1090 gating clock
+ *
+ * @mux: the parent class
+ * @ops: pointer to clk_ops of parent class
+ *
+ * Clock which can gate its output. Extends basic mux by using a global
+ * exclusive lock when read-modify-writing the mux field so that multiple
+ * threads/cores can use different fields in the same register.
+ */
+struct tz1090_clk_gate_priv {
+ struct clk_gate gate;
+ const struct clk_ops *ops;
+};
+
+static inline struct tz1090_clk_gate_priv *to_tz1090_clk_gate(struct clk_hw *hw)
+{
+ struct clk_gate *gate = container_of(hw, struct clk_gate, hw);
+
+ return container_of(gate, struct tz1090_clk_gate_priv, gate);
+}
+
+/* Acquire exclusive lock since other cores may access the same register */
+static int tz1090_clk_gate_enable(struct clk_hw *hw)
+{
+ struct tz1090_clk_gate_priv *gate = to_tz1090_clk_gate(hw);
+ int ret;
+ unsigned long flags;
+
+ __global_lock2(flags);
+ ret = gate->ops->enable(&gate->gate.hw);
+ __global_unlock2(flags);
+
+ return ret;
+}
+
+/* Acquire exclusive lock since other cores may access the same register */
+static void tz1090_clk_gate_disable(struct clk_hw *hw)
+{
+ struct tz1090_clk_gate_priv *gate = to_tz1090_clk_gate(hw);
+ unsigned long flags;
+
+ __global_lock2(flags);
+ gate->ops->disable(&gate->gate.hw);
+ __global_unlock2(flags);
+}
+
+static int tz1090_clk_gate_is_enabled(struct clk_hw *hw)
+{
+ struct tz1090_clk_gate_priv *gate = to_tz1090_clk_gate(hw);
+
+ return gate->ops->is_enabled(&gate->gate.hw);
+}
+
+static const struct clk_ops tz1090_clk_gate_ops = {
+ .enable = tz1090_clk_gate_enable,
+ .disable = tz1090_clk_gate_disable,
+ .is_enabled = tz1090_clk_gate_is_enabled,
+};
+
+/**
+ * __register_gate() - register a TZ1090 gate clock with clock framework.
+ * @name: name of this clock
+ * @parent_name: name of this clock's parent
+ * @flags: framework-specific flags for this clock
+ * @reg: register address to control gating of this clock
+ * @bit_idx: which bit in the register controls gating of this clock
+ * @clk_gate_flags: gate-specific flags for this clock
+ */
+static struct clk *__init __register_gate(const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *reg,
+ u8 bit_idx,
+ u8 clk_gate_flags)
+{
+ struct tz1090_clk_gate_priv *gate;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the gate */
+ gate = kzalloc(sizeof(struct tz1090_clk_gate_priv), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tz1090_clk_gate_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct clk_gate assignments */
+ gate->gate.reg = reg;
+ gate->gate.bit_idx = bit_idx;
+ gate->gate.flags = clk_gate_flags;
+ gate->gate.hw.init = &init;
+
+ /* struct tz1090_clk_gate_priv assignments */
+ gate->ops = &clk_gate_ops;
+
+ clk = clk_register(NULL, &gate->gate.hw);
+
+ if (IS_ERR(clk))
+ kfree(gate);
+
+ return clk;
+}
+
+/**
+ * tz1090_clk_register_gate_bank() - Register bank of gates with a provider.
+ * @p: TZ1090 clock provider.
+ * @bank: Data describing gate bank.
+ */
+void __init tz1090_clk_register_gate_bank(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_gate_bank *bank)
+{
+ const struct tz1090_clk_gate *gate;
+ struct clk *clk;
+ unsigned int id = bank->id_base;
+
+ for (gate = bank->gates; gate->name; ++gate, ++id) {
+ clk = __register_gate(tz1090_clk_xlate(p, gate->name),
+ tz1090_clk_xlate(p, gate->parent),
+ CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT,
+ p->base + bank->reg_base, gate->shift, 0);
+ p->clk_data.clks[id] = clk;
+ }
+}
diff --git a/drivers/clk/tz1090/clk-tz1090-hep.c b/drivers/clk/tz1090/clk-tz1090-hep.c
new file mode 100644
index 0000000..0aa8dc1
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-hep.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 High End Peripheral (HEP) Clocks
+ */
+
+#include <dt-bindings/clock/tz1090-hep.h>
+
+#include "clk.h"
+
+/* Register offsets into high end peripheral memory region */
+#define HEP_CLK_EN 0x04
+
+/*
+ * CR_HEP_CLK_EN
+ * =============
+ *
+ * sys -+--[ 2d_en ]--- 0 sys_2d
+ * sys_x2_undeleted -|--[ ddr_en ]--- 1 ddr_en
+ * sys `--[ pdp_pdi_en ]--- 2 sys_pdp
+ */
+GATE_BANK(tz1090_hep_clken, 0, HEP_CLK_EN,
+ /* bit in out */
+ GATE( 0, "@sys", "sys_2d")
+ GATE( 1, "@sys_x2_undeleted", "ddr_en")
+ GATE( 2, "@sys", "sys_pdp")
+ /* bits 3..31 unused */
+);
+
+static void __init tz1090_hep_cr_init(struct device_node *np)
+{
+ struct tz1090_clk_provider *p;
+
+ p = tz1090_clk_alloc_provider(np, CLK_HEP_MAX);
+ if (!p)
+ return;
+
+ tz1090_clk_register_gate_bank(p, &tz1090_hep_clken);
+
+ tz1090_clk_register_provider(p);
+}
+CLK_OF_DECLARE(tz1090_hep_cr, "img,tz1090-hep-cr", tz1090_hep_cr_init);
diff --git a/drivers/clk/tz1090/clk-tz1090-mux-bank.c b/drivers/clk/tz1090/clk-tz1090-mux-bank.c
new file mode 100644
index 0000000..bdfb243
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-mux-bank.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 Clock mux bank
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <asm/global_lock.h>
+
+#include "clk.h"
+
+/**
+ * struct tz1090_clk_mux_priv - tz1090 multiplexer clock
+ *
+ * @mux: the parent class
+ * @ops: pointer to clk_ops of parent class
+ *
+ * Clock with multiple selectable parents. Extends basic mux by using a global
+ * exclusive lock when read-modify-writing the mux field so that multiple
+ * threads/cores can use different fields in the same register.
+ */
+struct tz1090_clk_mux_priv {
+ struct clk_mux mux;
+ const struct clk_ops *ops;
+};
+
+static inline struct tz1090_clk_mux_priv *to_tz1090_clk_mux(struct clk_hw *hw)
+{
+ struct clk_mux *mux = container_of(hw, struct clk_mux, hw);
+
+ return container_of(mux, struct tz1090_clk_mux_priv, mux);
+}
+
+static u8 tz1090_clk_mux_get_parent(struct clk_hw *hw)
+{
+ struct tz1090_clk_mux_priv *mux = to_tz1090_clk_mux(hw);
+
+ return mux->ops->get_parent(&mux->mux.hw);
+}
+
+/* Acquire exclusive lock since other cores may access the same register */
+static int tz1090_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct tz1090_clk_mux_priv *mux = to_tz1090_clk_mux(hw);
+ int ret;
+ unsigned long flags;
+
+ __global_lock2(flags);
+ ret = mux->ops->set_parent(&mux->mux.hw, index);
+ __global_unlock2(flags);
+
+ return ret;
+}
+
+static long tz1090_clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *prate,
+ struct clk_hw **best_parent)
+{
+ struct tz1090_clk_mux_priv *mux = to_tz1090_clk_mux(hw);
+
+ return mux->ops->determine_rate(&mux->mux.hw, rate, min_rate, max_rate,
+ prate, best_parent);
+}
+
+static const struct clk_ops tz1090_clk_mux_ops = {
+ .get_parent = tz1090_clk_mux_get_parent,
+ .set_parent = tz1090_clk_mux_set_parent,
+ .determine_rate = tz1090_clk_mux_determine_rate,
+};
+
+static struct clk *__init __register_mux(const char *name,
+ const char **parent_names,
+ unsigned long flags, void __iomem *reg,
+ u8 shift, u8 clk_mux_flags)
+{
+ struct tz1090_clk_mux_priv *mux;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the mux */
+ mux = kzalloc(sizeof(struct tz1090_clk_mux_priv), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tz1090_clk_mux_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_names;
+ init.num_parents = 2;
+
+ /* struct clk_mux assignments */
+ mux->mux.reg = reg;
+ mux->mux.shift = shift;
+ mux->mux.mask = 0x1;
+ mux->mux.flags = clk_mux_flags;
+ mux->mux.hw.init = &init;
+
+ /* struct tz1090_clk_mux_priv assignments */
+ if (clk_mux_flags & CLK_MUX_READ_ONLY)
+ mux->ops = &clk_mux_ro_ops;
+ else
+ mux->ops = &clk_mux_ops;
+
+ clk = clk_register(NULL, &mux->mux.hw);
+
+ if (IS_ERR(clk))
+ kfree(mux);
+
+ return clk;
+}
+
+/**
+ * tz1090_clk_register_mux_bank() - Register bank of muxes with a provider.
+ * @p: TZ1090 clock provider.
+ * @bank: Data describing mux bank.
+ */
+void __init tz1090_clk_register_mux_bank(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_mux_bank *bank)
+{
+ const struct tz1090_clk_mux *mux;
+ struct clk *clk;
+ unsigned int id = bank->id_base;
+ const char *parents[2];
+ unsigned long flags;
+ u32 val;
+
+ for (mux = bank->muxes; mux->name; ++mux, ++id) {
+ if (mux->default_parent >= 0) {
+ __global_lock2(flags);
+ val = ioread32(p->base + bank->reg_base);
+ if (mux->default_parent)
+ val |= BIT(mux->shift);
+ else
+ val &= ~BIT(mux->shift);
+ iowrite32(val, p->base + bank->reg_base);
+ __global_unlock2(flags);
+ }
+
+ parents[0] = tz1090_clk_xlate(p, mux->parents[0]);
+ parents[1] = tz1090_clk_xlate(p, mux->parents[1]);
+ clk = __register_mux(tz1090_clk_xlate(p, mux->name), parents,
+ CLK_SET_RATE_PARENT,
+ p->base + bank->reg_base, mux->shift,
+ mux->mux_flags);
+ p->clk_data.clks[id] = clk;
+ }
+}
diff --git a/drivers/clk/tz1090/clk-tz1090-pdc.c b/drivers/clk/tz1090/clk-tz1090-pdc.c
new file mode 100644
index 0000000..89789b4
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-pdc.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 PDC Clocks.
+ */
+
+#include <dt-bindings/clock/tz1090-pdc.h>
+
+#include "clk.h"
+
+/* Register offsets into PDC SoC region */
+#define PDC_SOC0 0x00
+
+/*
+ * SOC_GPIO_CONTROL 0
+ * ==================
+ * ___________
+ * xtal1 ___| xtal1_div |____________________________
+ * |___________| | ________ xtal1_div
+ * `--o| rtc_sw \____________
+ * xtal3 ----------------------|________/ 32khz
+ */
+
+static const struct tz1090_clk_divider tz1090_pdc_dividers[] __initconst = {
+ /* id in out reg width shift */
+ DIV_SHARED(CLK_PDC_XTAL1_DIV, "@xtal1", "xtal1_div", PDC_SOC0, 11, 16),
+};
+
+MUX_BANK(tz1090_pdc_mux, CLK_PDC_32KHZ, PDC_SOC0,
+ /* bit in[0] in[1] out */
+ MUX(30, "xtal1_div", "@xtal3", "32khz")
+);
+
+static void __init tz1090_pdc_cr_init(struct device_node *np)
+{
+ struct tz1090_clk_provider *p;
+
+ p = tz1090_clk_alloc_provider(np, CLK_PDC_MAX);
+ if (!p)
+ return;
+
+ tz1090_clk_register_dividers(p, tz1090_pdc_dividers,
+ ARRAY_SIZE(tz1090_pdc_dividers));
+ tz1090_clk_register_mux_bank(p, &tz1090_pdc_mux);
+
+ tz1090_clk_register_provider(p);
+}
+CLK_OF_DECLARE(tz1090_pdc_cr, "img,tz1090-pdc-cr", tz1090_pdc_cr_init);
diff --git a/drivers/clk/tz1090/clk-tz1090-perip.c b/drivers/clk/tz1090/clk-tz1090-perip.c
new file mode 100644
index 0000000..ba7b2db
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-perip.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 Peripheral Clocks
+ */
+
+#include <dt-bindings/clock/tz1090-perip.h>
+
+#include "clk.h"
+
+/* Register offsets into peripheral memory region */
+#define PERIP_SRST 0x00
+#define PERIP_CLKEN 0x10
+#define PERIP_CLKSTATUS 0x14
+
+/*
+ * CR_PERIP_CLKEN
+ * ==============
+ *
+ * sys ---[CR_PERIP_*_SYS_CLK_EN]--- sys_*
+ */
+GATE_BANK(tz1090_perip_clken, 0, PERIP_CLKEN,
+ /* bit in out */
+ GATE( 0, "@sys", "sys_scb0")
+ GATE( 1, "@sys", "sys_scb1")
+ GATE( 2, "@sys", "sys_scb2")
+ GATE( 3, "@sys", "sys_sdio")
+ GATE( 4, "@sys", "sys_uart0")
+ GATE( 5, "@sys", "sys_uart1")
+ GATE( 6, "@sys", "sys_spim")
+ GATE( 7, "@sys", "sys_spis")
+ GATE( 8, "@sys", "sys_spim1")
+ GATE( 9, "@sys", "sys_i2sout")
+ GATE(10, "@sys", "sys_i2sin")
+ GATE(11, "@sys", "sys_lcd")
+ GATE(12, "@sys", "sys_sdhost")
+ GATE(13, "@sys", "sys_usb")
+ /* bits 14..31 unused */
+);
+
+static void __init tz1090_perip_cr_init(struct device_node *np)
+{
+ struct tz1090_clk_provider *p;
+
+ p = tz1090_clk_alloc_provider(np, CLK_PERIP_MAX);
+ if (!p)
+ return;
+
+ tz1090_clk_register_gate_bank(p, &tz1090_perip_clken);
+
+ tz1090_clk_register_provider(p);
+}
+CLK_OF_DECLARE(tz1090_perip_cr, "img,tz1090-perip-cr", tz1090_perip_cr_init);
diff --git a/drivers/clk/tz1090/clk-tz1090-pll.c b/drivers/clk/tz1090/clk-tz1090-pll.c
new file mode 100644
index 0000000..ca8260b
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-pll.c
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
+ * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
+ * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * True Circuits PLL in TZ1090 SoC.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+/* Register definitions */
+
+#define PLL_CTL0 0
+#define PLL_CTL0_BWADJ_M 0xfff
+#define PLL_CTL0_BWADJ_S 20
+#define PLL_CTL0_CLKF_M 0x1fff
+#define PLL_CTL0_CLKF_S 4
+#define PLL_CTL0_CLKOD_M 0x7
+#define PLL_CTL0_CLKOD_S 0
+#define PLL_CTL1 4
+#define PLL_CTL1_RESET_B BIT(28)
+#define PLL_CTL1_FASTEN_B BIT(27)
+#define PLL_CTL1_ENSAT_B BIT(26)
+#define PLL_CTL1_BYPASS_B BIT(25)
+#define PLL_CTL1_PWRDN_B BIT(24)
+#define PLL_CTL1_CLKR_M 0x3f
+#define PLL_CTL1_CLKR_S 0
+
+/**
+ * struct tz1090_clk_pll_priv - PLL in TZ1090
+ *
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: first of two registers
+ *
+ * PLL in TZ1090.
+ */
+struct tz1090_clk_pll_priv {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+#define to_tz1090_clk_pll(_hw) container_of(_hw, struct tz1090_clk_pll_priv, hw)
+
+static unsigned long tz1090_clk_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long f_in)
+{
+ struct tz1090_clk_pll_priv *pll = to_tz1090_clk_pll(hw);
+ u32 ctl0, ctl1;
+ unsigned int clk_f; /* feedback divide */
+ unsigned int clk_od; /* output divide */
+ unsigned int clk_r; /* reference divide */
+ unsigned long f_out;
+
+ ctl0 = readl(pll->reg + PLL_CTL0);
+ ctl1 = readl(pll->reg + PLL_CTL1);
+
+ /* Bypass? */
+ if (ctl1 & PLL_CTL1_BYPASS_B)
+ return f_in;
+
+ /* Get divider values */
+ clk_f = 1 + ((ctl0 >> PLL_CTL0_CLKF_S) & PLL_CTL0_CLKF_M);
+ clk_od = 1 + ((ctl0 >> PLL_CTL0_CLKOD_S) & PLL_CTL0_CLKOD_M);
+ clk_r = 1 + ((ctl1 >> PLL_CTL1_CLKR_S) & PLL_CTL1_CLKR_M);
+
+ /*
+ * formula:
+ * f_out = (f_in / clk_r) * (clk_f / 2) / clk_od
+ * = (f_in * clk_f) / (2 * clk_r * clk_od)
+ */
+ f_out = div_u64((u64)f_in * clk_f,
+ 2 * clk_r * clk_od);
+ return f_out;
+}
+
+/* finds best pll parameters and returns rate on success (or 0) */
+static int tz1090_clk_pll_bestvals(struct clk_hw *hw, unsigned long parent_rate,
+ unsigned long rate, unsigned long *clkf,
+ unsigned long *clkr, unsigned long *clkod)
+{
+ unsigned long odmin, odmax;
+ unsigned long bestf = 1, bestr = 1, bestod = 1;
+ unsigned long rod2, cur, best = 0;
+ unsigned long f, r, od;
+
+ /* 120MHz/freq < od < 600MHz/freq */
+ odmin = 120000000/rate + 1;
+ odmax = 600000000/rate;
+
+ if (odmin < 1)
+ odmin = 1;
+ if (odmax > PLL_CTL0_CLKOD_M + 1)
+ odmax = PLL_CTL0_CLKOD_M + 1;
+
+ /*
+ * Search through valid combinations of od and r, starting with lower
+ * output divider values to get a lower intermediate frequency.
+ */
+ for (od = odmin; od <= odmax; ++od) {
+ for (r = 1; r <= PLL_CTL1_CLKR_M + 1; ++r) {
+ /*
+ * Calculate best f for given r and od, rounding down
+ * So for f, freq <= rate
+ * And for f+1, freq > rate
+ * We have to do rate+1 because rate may have itself
+ * been rounded down.
+ */
+ rod2 = 2 * r * od;
+ f = div_u64((u64)(rate + 1) * rod2, parent_rate);
+ if (f < 1)
+ continue;
+ if (f > PLL_CTL0_CLKF_M + 1)
+ f = PLL_CTL0_CLKF_M + 1;
+
+ /* Calculate final rate and see if it's the best */
+ cur = div_u64((u64)parent_rate * f, rod2);
+ if (cur > best) {
+ bestf = f;
+ bestr = r;
+ bestod = od;
+ best = cur;
+ /* Can't improve on a perfect match */
+ if (cur == rate)
+ goto done;
+ }
+ }
+ }
+ if (!best)
+ return 0;
+done:
+ pr_debug("tz1090_clk_pll: final %lu/%lu * %lu/2/%lu=%lu (req=%lu, err=%ld)\n",
+ parent_rate, bestr, bestf, bestod, best, rate, best - rate);
+
+ *clkf = bestf;
+ *clkr = bestr;
+ *clkod = bestod;
+ return best;
+}
+
+static long tz1090_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ unsigned long clkf, clkr, clkod;
+ unsigned long parent_rate = *prate;
+
+ return tz1090_clk_pll_bestvals(hw, parent_rate, rate, &clkf, &clkr,
+ &clkod);
+}
+
+static int tz1090_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct tz1090_clk_pll_priv *pll = to_tz1090_clk_pll(hw);
+ unsigned long clkf, clkr, clkod, bwadj;
+ u32 ctl0, ctl1;
+
+ if (!tz1090_clk_pll_bestvals(hw, parent_rate, rate,
+ &clkf, &clkr, &clkod))
+ return -EINVAL;
+
+ /* offset the values ready to go in the PLL registers */
+ --clkr;
+ --clkf;
+ --clkod;
+ bwadj = clkf / 2;
+
+ /* bypass, reset and configure PLL */
+ ctl0 = (bwadj << PLL_CTL0_BWADJ_S) |
+ (clkf << PLL_CTL0_CLKF_S) |
+ (clkod << PLL_CTL0_CLKOD_S);
+ ctl1 = PLL_CTL1_RESET_B |
+ PLL_CTL1_ENSAT_B |
+ PLL_CTL1_BYPASS_B |
+ (clkr << PLL_CTL1_CLKR_S);
+ writel(ctl1, pll->reg + PLL_CTL1);
+ writel(ctl0, pll->reg + PLL_CTL0);
+
+ /* allow 5us after clkf before deasserting reset */
+ udelay(5);
+
+ /* take PLL out of reset and enable fasten */
+ ctl1 &= ~PLL_CTL1_RESET_B;
+ ctl1 |= PLL_CTL1_FASTEN_B;
+ writel(ctl1, pll->reg + PLL_CTL1);
+
+ /* count at least 500 divided ref clks to allow time to lock */
+ msleep(1 + 500*1000*(clkr+1)/parent_rate);
+
+ /* take PLL out of fasten / bypass */
+ ctl1 &= ~PLL_CTL1_FASTEN_B;
+ ctl1 &= ~PLL_CTL1_BYPASS_B;
+ writel(ctl1, pll->reg + PLL_CTL1);
+
+ return 0;
+}
+
+static const struct clk_ops tz1090_clk_pll_ops = {
+ .recalc_rate = tz1090_clk_pll_recalc_rate,
+ .round_rate = tz1090_clk_pll_round_rate,
+ .set_rate = tz1090_clk_pll_set_rate,
+};
+
+/**
+ * __register_pll() - register a PLL with the clock framework
+ * @name: name of this clock
+ * @parent_name: name of clock's parent
+ * @flags: framework-specific flags
+ * @reg: register address to adjust PLL
+ *
+ * Register a TZ1090 PLL clock to the clock framework.
+ */
+static struct clk *__init __register_pll(const char *name,
+ const char *parent_name,
+ unsigned long flags,
+ void __iomem *reg)
+{
+ struct tz1090_clk_pll_priv *pll;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ /* allocate the pll */
+ pll = kzalloc(sizeof(struct tz1090_clk_pll_priv), GFP_KERNEL);
+ if (!pll)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tz1090_clk_pll_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+
+ /* struct tz1090_clk_pll_priv assignments */
+ pll->reg = reg;
+ pll->hw.init = &init;
+
+ /* register the clock */
+ clk = clk_register(NULL, &pll->hw);
+
+ if (IS_ERR(clk))
+ kfree(pll);
+
+ return clk;
+}
+
+/**
+ * tz1090_clk_register_plls() - Register set of PLLs with a provider.
+ * @p: TZ1090 clock provider.
+ * @plls: Array of PLL descriptions.
+ * @count Number of PLLs described in the array.
+ */
+void __init tz1090_clk_register_plls(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_pll *plls,
+ unsigned int count)
+{
+ const struct tz1090_clk_pll *pll;
+ struct clk *clk;
+ unsigned int i;
+
+ for (pll = plls, i = 0; i < count; ++pll, ++i) {
+ clk = __register_pll(tz1090_clk_xlate(p, pll->name),
+ tz1090_clk_xlate(p, pll->parent), 0,
+ p->base + pll->reg_base);
+ p->clk_data.clks[pll->id] = clk;
+ }
+}
diff --git a/drivers/clk/tz1090/clk-tz1090-top.c b/drivers/clk/tz1090/clk-tz1090-top.c
new file mode 100644
index 0000000..724c925
--- /dev/null
+++ b/drivers/clk/tz1090/clk-tz1090-top.c
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 TOP Clocks
+ */
+
+#include <dt-bindings/clock/tz1090-top.h>
+
+#include "clk.h"
+
+/* Register offsets into top level memory region */
+#define TOP_CLKEN 0x00
+#define TOP_CLKSTATUS 0x04
+#define TOP_CLKSWITCH 0x08
+#define TOP_CLKENAB 0x0c
+#define TOP_CLKDELETE 0x10
+#define TOP_SYSCLK_DIV 0x14
+#define TOP_META_CLKDIV 0x18
+#define TOP_META_CLKDELETE 0x1c
+#define TOP_AFE_DIV 0x20
+#define TOP_ADCPLL_DIV 0x24
+#define TOP_UARTCLK_DIV 0x28
+#define TOP_PDMCK_CTL 0x30
+#define TOP_SPICLK_DIV 0x34
+#define TOP_SPI1CLK_DIV 0x38
+#define TOP_I2SCLK_DIV 0x3c
+#define TOP_USB_PLLDIV 0x40
+#define TOP_SDHOSTCLK_DIV 0x44
+#define TOP_RING_OP_DIV 0x48
+#define TOP_SYSPLL_CTL0 0x50
+#define TOP_ADCPLL_CTL0 0x58
+#define TOP_META_CLK 0x80
+#define TOP_CLKSWITCH2 0x88
+#define TOP_CLKENAB2 0x8c
+#define TOP_I2S_DIV2 0x90
+#define TOP_META_TRACE_CLK_DIV 0x94
+#define TOP_PIXEL_CLK_DIV 0x98
+#define TOP_CLKOUT0_DIV 0x9c
+#define TOP_CLKOUT1_DIV 0xa0
+#define TOP_UCC0_CLKDELETE 0xa4
+#define TOP_UCC1_CLKDELETE 0xa8
+#define TOP_DDR_CLKDIV 0xac
+
+/*
+ * CR_TOP_CLKSWITCH
+ * ================
+ * ___________ _________ _____________
+ * xtal1 ------o| sys_sw \______| sys_pll |_| sys_clk_div |__
+ * xtal2 -------|___________/ 0 |_________| |_____________| |
+ * __________________________________________________|
+ * | ___________
+ * xtal1 ----|-o|sysclk1_sw \____________________________
+ * sys_clk_div `--|___________/ 1 sys_clk_x2_undeleted
+ * xtal1 ------o|clkout0_sw0\______
+ * afe_progdiv1 -------|___________/ 2 |
+ * sys_undeleted ------o|clkout0_sw1\____ |
+ * if0_sw -------|___________/ 3 | | CR_TOP_CLKENAB
+ * ,-;==================='-' ==============
+ * | | ___________ ___________
+ * clkout0_sw0 | `-o|clkout0_sw2\____ _| out0_inv \_____
+ * xtal2 --|----|___________/ 4 | | |___________/ 4
+ * | ___________________| |__________________
+ * | | ___________ ___________ |
+ * clkout0_sw2 | `-o|clkout0_sw3\__________| out0_en \____|
+ * clkout0_sw1 `----|___________/ 5 |___________/ 5
+ * xtal1 ------o|clkout1_sw0\______ .
+ * xtal2 -------|___________/ 6 | .
+ * sys_undeleted ------o|clkout1_sw1\____ | .
+ * if1_sw -------|___________/ 7 | | .
+ * ,-;==================='-' .
+ * | | ___________ ___________
+ * adcpll_clk --|-|-o|clkout1_sw2\____ _| out1_inv \_____
+ * clkout1_sw1 `-|--|___________/ 8 | | |___________/ 8
+ * _|___________________| |__________________
+ * | | ___________ ___________ |
+ * clkout1_sw0 | `-o|clkout1_sw3\__________| out1_en \____|
+ * clkout1_sw2 `----|___________/ 9 |___________/ 9
+ * xtal1 ------o| i2s_sw2 \______ .
+ * sys_undeleted -------|___________/ 10 | .
+ * xtal2 ------o| i2s_sw0 \____ | .
+ * adcpll_clk -------|___________/ 11 | | .
+ * ,-;==================='-' .
+ * | | ___________ ___________
+ * i2s_sw2 | `-o| i2s_sw1 \__________| i2s_en \_____
+ * i2s_sw0 `----|___________/ 12 |___________/ 12
+ * xtal1 ------o| scb_sw \__________| scb_en \_____
+ * sys_undeleted -------|___________/ 13 |___________/ 13
+ * xtal1 ------o| uart_sw \__________| uart_en \_____
+ * sys_undeleted -------|___________/ 14 |___________/ 14
+ * xtal1 ------o|ext_stc0_sw\__________|ext_stc0_en\_____
+ * xtal2 -------|___________/ 16 |___________/ 16
+ * xtal1 ------o|ext_stc1_sw\__________|ext_stc1_en\_____
+ * xtal2 -------|___________/ 17 |___________/ 17
+ * adcpll_clk ------o| usb_sw0 \____ .
+ * afe_progdiv3 -------|___________/ 18 | .
+ * ___________________| .
+ * | ___________ ___________
+ * usb_sw3 ,-|-o| usb_sw1 \__________| usb_en \_____
+ * usb_sw0 | `--|___________/ 19 |___________/ 19
+ * xtal1 --|---o| afe_sw0 \________________
+ * afe_sw1 ,-|----|___________/ 20 . | _____________
+ * `-`=====================:-. . |___| afe_clk_div |________
+ * ___________ | | . |_____________| afe_clk
+ * adcpll_en ,---o| afe_sw1 \____| | .
+ * xtal2 --|----|___________/ 21 | . ________
+ * xtal1 --|---o|adcpll_sw0 \______|_____________| adcpll |_____________
+ * xtal2 --|----|___________/ 22 | . |________| adcpll_clk
+ * xtal1 --|---o|adcpll_sw1 \____ | .
+ * xtal2 --|----|___________/ 23 | | .
+ * | ___________________| | .
+ * | | ___________ | . ________________
+ * adcpll_en +-|-o|adcpll_sw2 \______|_____________| adcpll_clk_div |_____
+ * adcpll_sw1 | `--|___________/ 24 | . |________________|
+ * |_______________________|_____________________
+ * ___________ | ___________ |
+ * sys_undeleted -------|adcpll_sw3 \______|___| adcpll_en \_____|
+ * adcpll_clk -------|___________/ 25 | |___________/ 25
+ * xtal1 -------| usb_sw2 \____ |
+ * xtal2 -------|___________/ 28 | |
+ * ___________________| |
+ * | ___________ |
+ * usb_sw2 `--| usb_sw3 \______|
+ * sys_undeleted -------|___________/ 29
+ */
+MUX_BANK(tz1090_top_clkswitch, CLK_TOP_CLKSWITCH_BASE, TOP_CLKSWITCH,
+ /* bit in[0] in[1] out */
+ MUX( 0, "@xtal1", "@xtal2", "sys_sw")
+ MUX( 1, "@xtal1", "sys_div", "sys_x2_undeleted")
+ MUX( 2, "@xtal1", "@afe_progdiv1", "out0_sw0")
+ MUX( 3, "sys_undeleted", "if0_sw", "out0_sw1")
+ MUX( 4, "out0_sw0", "@xtal2", "out0_sw2")
+ MUX( 5, "out0_sw2", "out0_sw1", "out0_sw3")
+ MUX( 6, "@xtal1", "@xtal2", "out1_sw0")
+ MUX( 7, "sys_undeleted", "if1_sw", "out1_sw1")
+ MUX( 8, "adcpll", "out1_sw1", "out1_sw2")
+ MUX( 9, "out1_sw0", "out1_sw2", "out1_sw3")
+ MUX(10, "@xtal1", "sys_undeleted", "i2s_sw2")
+ MUX(11, "@xtal2", "adcpll", "i2s_sw0")
+ MUX(12, "i2s_sw2", "i2s_sw0", "i2s_sw1")
+ /*
+ * SCB clock must be derived from system clock to workaround clock
+ * domain crossing problems in SCB automatic mode.
+ */
+ MUX_FIXED(13, "@xtal1", "sys_undeleted", "scb_sw", 1)
+ MUX(14, "@xtal1", "sys_undeleted", "uart_sw")
+ /* bit 15 unused */
+ MUX(16, "@xtal1", "@xtal2", "ext_stc0_sw")
+ MUX(17, "@xtal1", "@xtal2", "ext_stc1_sw")
+ MUX(18, "adcpll", "@afe_progdiv3", "usb_sw0")
+ MUX(19, "usb_sw3", "usb_sw0", "usb_sw1")
+ MUX(20, "@xtal1", "afe_sw1", "afe_sw0")
+ MUX(21, "adcpll_en", "@xtal2", "afe_sw1")
+ MUX(22, "@xtal1", "@xtal2", "adcpll_sw0")
+ MUX(23, "@xtal1", "@xtal2", "adcpll_sw1")
+ MUX(24, "adcpll_en", "adcpll_sw1", "adcpll_sw2")
+ MUX(25, "sys_undeleted", "adcpll", "adcpll_sw3")
+ /* bits 26..27 unused */
+ MUX(28, "@xtal1", "@xtal2", "usb_sw2")
+ MUX(29, "usb_sw2", "sys_undeleted", "usb_sw3")
+ /* bits 30..31 unused */
+);
+
+GATE_BANK(tz1090_top_clkenab, CLK_TOP_CLKENAB_BASE, TOP_CLKENAB,
+ /* bit in out */
+ /* bits 0..4 unused */
+ GATE( 5, "out0_sw3", "out0_en")
+ /* bits 6..8 unused */
+ GATE( 9, "out1_sw3", "out1_en")
+ /* bits 10..11 unused */
+ GATE(12, "i2s_sw1", "i2s_en")
+ GATE(13, "scb_sw", "scb")
+ GATE(14, "uart_sw", "uart_en")
+ /* bit 15 unused */
+ GATE(16, "ext_stc0_sw", "ext_stc0")
+ GATE(17, "ext_stc1_sw", "ext_stc1")
+ /* bit 18 unused */
+ GATE(19, "usb_sw1", "usb_en")
+ /* bits 20..24 unused */
+ GATE(25, "adcpll_sw3", "adcpll_en")
+ /* bits 26..31 unused */
+);
+
+/*
+ * CR_TOP_CLKSWITCH2
+ * =================
+ * ___________
+ * xtal1 ------o| pixel_sw0 \______
+ * pixel_sw3 ,----|___________/ 0 |
+ * sys_undeleted --+---o| pixel_sw1 \____ |
+ * pixel_sw4 | ,--|___________/ 1 | |
+ * `-`===================|=|=:-. CR_TOP_CLKENAB2
+ * ,-;==================='-' | | ===============
+ * | | ___________ | | __________
+ * pixel_sw0 | `-o| pixel_sw2 \________|_|___| pixel_en \_____
+ * pixel_sw1 `----|___________/ 2 | | |__________/ 2
+ * adcpll_clk ------o| pixel_sw3 \________| | .
+ * afe_progdiv3 -------|___________/ 3 | .
+ * usb_phy_clk ------o| pixel_sw4 \__________| .
+ * xtal2 -------|___________/ 4 __________
+ * iqadc_sync ------o| if1_sw \______________| if1_en \_____
+ * ext_adc_dac --+----|___________/ 5 |__________/ 5
+ * afe_rxsync --|---o| if0_sw \______________| if0_en \_____
+ * ext_adc_dac |`---|___________/ 6 _____|__________/ 6
+ * |.________________________| ext_adc_dac_en \_____
+ * | ___________ |________________/ 7
+ * afe_txsync --|---o| dac0_sw \______________| dac0_en \_____
+ * ext_adc_dac `----|___________/ 8 |__________/ 8
+ * ucc1_clk_del ------o| ucc1_sw \______________| ucc1_en \_____
+ * ucc0_clk_del --+----|___________/ 9 |__________/ 9
+ * ucc0_clk_del `---o| ucc0_sw \______________| ucc0_en \_____
+ * sys_clk -------|___________/ 10 |__________/ 10
+ */
+MUX_BANK(tz1090_top_clkswitch2, CLK_TOP_CLKSWITCH2_BASE, TOP_CLKSWITCH2,
+ /* bit in[0] in[1] out */
+ MUX( 0, "@xtal1", "pixel_sw3", "pixel_sw0")
+ MUX( 1, "sys_undeleted", "pixel_sw4", "pixel_sw1")
+ MUX( 2, "pixel_sw0", "pixel_sw1", "pixel_sw2")
+ MUX( 3, "adcpll", "@afe_progdiv3", "pixel_sw3")
+ MUX( 4, "usb_phy", "@xtal2", "pixel_sw4")
+ MUX( 5, "@iqadc_sync", "@ext_adc_dac", "if1_sw")
+ MUX( 6, "@afe_rxsync", "@ext_adc_dac", "if0_sw")
+ /* bit 7 unused */
+ MUX( 8, "@afe_txsync", "@ext_adc_dac", "dac0_sw")
+ MUX( 9, "ucc1_del", "ucc0", "ucc1_sw")
+ MUX(10, "ucc0", "sys", "ucc0_sw")
+ /* bits 11..31 unused */
+);
+
+GATE_BANK(tz1090_top_clkenab2, CLK_TOP_CLKENAB2_BASE, TOP_CLKENAB2,
+ /* bit in out */
+ /* bits 0..1 unused */
+ GATE( 2, "pixel_sw2", "pixel_en")
+ /* bits 3..4 unused */
+ GATE( 5, "if1_sw", "if1")
+ GATE( 6, "if0_sw", "if0")
+ GATE( 7, "@ext_adc_dac", "ext_adc_dac_en")
+ GATE( 8, "dac0_sw", "dac0")
+ GATE( 9, "ucc1_sw", "sys_ucc1")
+ GATE(10, "ucc0_sw", "sys_mtx")
+ /* bits 11..31 unused */
+);
+
+/*
+ * Deleters
+ * ========
+ *
+ * sys_undeleted ---[ clkdelete ]--- sys_clk
+ * sys_x2_undeleted ---[ meta_clkdelete ]--- meta_core_clk
+ * sys_undeleted ---[ clkdelete ]--- ucc0_clk_del
+ * sys_undeleted ---[ clkdelete ]--- ucc1_clk_del
+ */
+
+static const struct tz1090_clk_deleter tz1090_top_deleters[] __initconst = {
+ DEL(CLK_TOP_SYS, "sys_undeleted", "sys", TOP_CLKDELETE),
+ DEL(CLK_TOP_META, "sys_x2_undeleted", "meta", TOP_META_CLKDELETE),
+ DEL(CLK_TOP_UCC0, "sys_undeleted", "ucc0", TOP_UCC0_CLKDELETE),
+ DEL(CLK_TOP_UCC1_DEL, "sys_undeleted", "ucc1_del", TOP_UCC1_CLKDELETE),
+};
+
+/*
+ * Dividers
+ * ========
+ *
+ * sys_pll ---[ sys_clk_div ]--- sys_div
+ * sys_x2_undeleted ---[ meta_clk_div ]--- sys_undeleted
+ * afe_sw0 ---[ afe_clk_div ]--- afe_clk
+ * adcpll_sw2 ---[ adcpll_clk_div ]--- adcpll_div
+ * uart_en ---[ uart_clk_div ]--- uart_clk
+ * sys_undeleted ---[ pdm_clk_div ]--- pdm_clk
+ * sys_undeleted ---[ spi0_clk_div ]--- spi0_clk
+ * sys_undeleted ---[ spi1_clk_div ]--- spi1_clk
+ * i2s_en ---[ i2sm_clk_div ]--- i2sm
+ * usb_en ---[ usbpll_clk_div ]--- usb_phy_clk
+ * sys_undeleted ---[ sdhost_clk_div ]--- sdhost_clk
+ * sys_undeleted ---[ ring_osc_clk_div ]--- ring_osc_clk
+ * i2sm_clk ---[ i2s_clk_div2 ]--- i2s_clk
+ * sys_undeleted ---[ meta_trace_clk_div ]--- meta_trace_clk
+ * pixel_en ---[ pixel_clk_div ]--- pixel_clk
+ * clkout0_en ---[ clkout0_clk_div ]--- clkout0
+ * clkout1_en ---[ clkout1_clk_div ]--- clkout1
+ * ddr_en ---[ ddr_clk_div ]--- ddr_clk
+ */
+
+static const struct tz1090_clk_divider tz1090_top_dividers[] __initconst = {
+ DIV(CLK_TOP_SYS_DIV, "sys_pll", "sys_div", TOP_SYSCLK_DIV, 8),
+ /*
+ * CLK_DIVIDER_READ_ONLY: sys_undeleted is set up by the bootloader
+ * along with sys_pll, and has a whole bunch of derivative peripheral
+ * clocks. It would be really bad for it to change on the fly.
+ */
+ DIV_FLAGS(CLK_TOP_SYS_UNDELETED, "sys_x2_undeleted", "sys_undeleted", TOP_META_CLKDIV, 2,
+ 0, CLK_DIVIDER_READ_ONLY),
+ DIV(CLK_TOP_AFE, "afe_sw0", "afe", TOP_AFE_DIV, 8),
+ DIV(CLK_TOP_ADCPLL_DIV, "adcpll_sw2", "adcpll_div", TOP_ADCPLL_DIV, 8),
+ /*
+ * CLK_SET_RATE_PARENT: UART clock changes must propagate up to uart_sw,
+ * which muxes between XTAL1 and sys_undeleted, in order to get enough
+ * precision.
+ */
+ DIV_FLAGS(CLK_TOP_UART, "uart_en", "uart", TOP_UARTCLK_DIV, 8,
+ CLK_SET_RATE_PARENT, CLK_DIVIDER_ROUND_CLOSEST),
+ DIV(CLK_TOP_PDM, "sys_undeleted", "pdm", TOP_PDMCK_CTL, 3),
+ DIV(CLK_TOP_SPI0, "sys_undeleted", "spi0", TOP_SPICLK_DIV, 8),
+ DIV(CLK_TOP_SPI1, "sys_undeleted", "spi1", TOP_SPI1CLK_DIV, 8),
+ DIV(CLK_TOP_I2SM, "i2s_en", "i2sm", TOP_I2SCLK_DIV, 8),
+ DIV(CLK_TOP_USB_PHY, "usb_en", "usb_phy", TOP_USB_PLLDIV, 8),
+ DIV(CLK_TOP_SDHOST, "sys_undeleted", "sdhost", TOP_SDHOSTCLK_DIV, 8),
+ DIV(CLK_TOP_RING_OSC, "sys_undeleted", "ring_osc", TOP_RING_OP_DIV, 4),
+ DIV(CLK_TOP_I2S, "i2sm", "i2s", TOP_I2S_DIV2, 8),
+ DIV(CLK_TOP_META_TRACE, "sys_undeleted", "meta_trace", TOP_META_TRACE_CLK_DIV, 8),
+ DIV(CLK_TOP_PIXEL, "pixel_en", "pixel", TOP_PIXEL_CLK_DIV, 8),
+ DIV(CLK_TOP_OUT0, "out0_en", "out0", TOP_CLKOUT0_DIV, 8),
+ DIV(CLK_TOP_OUT1, "out1_en", "out1", TOP_CLKOUT1_DIV, 8),
+ DIV(CLK_TOP_DDR, "@ddr_en", "ddr", TOP_DDR_CLKDIV, 8),
+};
+
+/*
+ * PLLs
+ * ====
+ *
+ * sys_sw ---[ sys_pll ]---
+ * adcpll_sw0 ---[ adcpll ]---
+ */
+
+static const struct tz1090_clk_pll tz1090_top_plls[] __initconst = {
+ PLL(CLK_TOP_SYSPLL, "sys_sw", "sys_pll", TOP_SYSPLL_CTL0),
+ PLL(CLK_TOP_ADCPLL, "adcpll_sw0", "adcpll", TOP_ADCPLL_CTL0),
+};
+
+/*
+ * CR_TOP_CLKEN
+ * ============
+ *
+ * sys ----[ pdc_sys_en ]--- 0 sys_pdc
+ */
+GATE_BANK(tz1090_top_clken, CLK_TOP_CLKEN_BASE, TOP_CLKEN,
+ /* bit in out */
+ GATE( 0, "sys", "sys_pdc")
+ /* bits 1..31 unused */
+);
+
+static void __init tz1090_top_cr_init(struct device_node *np)
+{
+ struct tz1090_clk_provider *p;
+
+ p = tz1090_clk_alloc_provider(np, CLK_TOP_MAX);
+ if (!p)
+ return;
+
+ tz1090_clk_register_mux_bank(p, &tz1090_top_clkswitch);
+ tz1090_clk_register_mux_bank(p, &tz1090_top_clkswitch2);
+ tz1090_clk_register_gate_bank(p, &tz1090_top_clkenab);
+ tz1090_clk_register_gate_bank(p, &tz1090_top_clkenab2);
+ tz1090_clk_register_gate_bank(p, &tz1090_top_clken);
+ tz1090_clk_register_deleters(p, tz1090_top_deleters,
+ ARRAY_SIZE(tz1090_top_deleters));
+ tz1090_clk_register_dividers(p, tz1090_top_dividers,
+ ARRAY_SIZE(tz1090_top_dividers));
+ tz1090_clk_register_plls(p, tz1090_top_plls,
+ ARRAY_SIZE(tz1090_top_plls));
+
+ tz1090_clk_register_provider(p);
+}
+CLK_OF_DECLARE(tz1090_top_cr, "img,tz1090-top-cr", tz1090_top_cr_init);
diff --git a/drivers/clk/tz1090/clk.c b/drivers/clk/tz1090/clk.c
new file mode 100644
index 0000000..5f4e8f28
--- /dev/null
+++ b/drivers/clk/tz1090/clk.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 Clocks
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include "clk.h"
+
+struct tz1090_clk_provider *tz1090_clk_alloc_provider(struct device_node *node,
+ unsigned int num_clks)
+{
+ struct tz1090_clk_provider *p;
+
+ p = kzalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return p;
+
+ p->clk_data.clks = kcalloc(num_clks, sizeof(struct clk *), GFP_KERNEL);
+ if (!p->clk_data.clks)
+ goto free_provider;
+ p->clk_data.clk_num = num_clks;
+ p->node = node;
+ p->base = of_iomap(node, 0);
+ if (!p->base) {
+ pr_err("%s: Failed to map clock provider registers\n",
+ node->full_name);
+ goto free_clks;
+ }
+
+ return p;
+
+free_clks:
+ kfree(p->clk_data.clks);
+free_provider:
+ kfree(p);
+ return NULL;
+}
+
+const char *tz1090_clk_xlate(struct tz1090_clk_provider *p,
+ const char *clk_name)
+{
+ /*
+ * If clock name begins with @, the rest refers to an external clock.
+ *
+ * Look for the index of the parent clock with a matching label in
+ * clock-names. If found, find the name of the specified parent clock.
+ *
+ * If not found, we leave it unchanged. The @ at the beginning should
+ * ensure it doesn't accidentally match a real clock.
+ */
+ if (*clk_name == '@') {
+ const char *clk_label = clk_name + 1;
+ int idx = of_property_match_string(p->node, "clock-names",
+ clk_label);
+ if (idx >= 0) {
+ clk_name = of_clk_get_parent_name(p->node, idx);
+ pr_debug("%s: Parent clock '%s' found as '%s'\n",
+ p->node->full_name, clk_label, clk_name);
+ } else {
+ pr_err("%s: No parent clock '%s' found\n",
+ p->node->full_name, clk_label);
+ }
+ }
+
+ return clk_name;
+}
+
+void tz1090_clk_register_provider(struct tz1090_clk_provider *p)
+{
+ unsigned int i;
+
+ for (i = 0; i < p->clk_data.clk_num; i++)
+ if (IS_ERR(p->clk_data.clks[i]))
+ pr_warn("%s: Failed to register clock %d: %ld\n",
+ p->node->full_name, i,
+ PTR_ERR(p->clk_data.clks[i]));
+
+ of_clk_add_provider(p->node, of_clk_src_onecell_get, &p->clk_data);
+}
diff --git a/drivers/clk/tz1090/clk.h b/drivers/clk/tz1090/clk.h
new file mode 100644
index 0000000..1d430a4
--- /dev/null
+++ b/drivers/clk/tz1090/clk.h
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2014 Imagination Technologies Ltd.
+ *
+ * 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.
+ *
+ * TZ1090 Clocks
+ */
+
+#ifndef CLK_TZ1090_CLK_H
+#define CLK_TZ1090_CLK_H
+
+#include <linux/clk-provider.h>
+#include <linux/init.h>
+
+/* Generic TZ1090 clock provider */
+
+/**
+ * struct tz1090_clk_provider - Clock provider data.
+ * @node: Device tree node for the clock provider.
+ * @base: IO remapped base address.
+ * @clk_data: Standard onecell clock data including list of clocks.
+ */
+struct tz1090_clk_provider {
+ struct device_node *node;
+ void __iomem *base;
+ struct clk_onecell_data clk_data;
+};
+
+struct tz1090_clk_provider *tz1090_clk_alloc_provider(struct device_node *node,
+ unsigned int num_clks);
+const char *tz1090_clk_xlate(struct tz1090_clk_provider *p,
+ const char *clk_name);
+void tz1090_clk_register_provider(struct tz1090_clk_provider *p);
+
+
+/* Clock gate banks */
+
+/**
+ * struct tz1090_clk_gate - Describes an individual gate in a bank.
+ * @shift: Shift of bit controlling gate within the bank control register.
+ * @name: Name of gated clock to provide.
+ * @parent: Name of parent/source clock.
+ */
+struct tz1090_clk_gate {
+ unsigned int shift;
+ const char *name;
+ const char *parent;
+};
+
+/**
+ * struct tz1090_clk_gate_bank - Describes a gate bank.
+ * @id_base: Base id of bank in provider.
+ * Individual gates get the id id_base + index in gates array.
+ * @reg_base: Offset of gate bank register in the MMIO region.
+ * @gates: Pointer to array of gates in the bank, terminated by one with a
+ * NULL name field.
+ */
+struct tz1090_clk_gate_bank {
+ unsigned int id_base;
+ unsigned long reg_base;
+ const struct tz1090_clk_gate *gates;
+};
+
+#define GATE(_shift, _parent, _name) \
+ { \
+ .shift = (_shift), \
+ .name = (_name), \
+ .parent = (_parent), \
+ },
+
+#define GATE_BANK(_name, _id, _reg, _gates) \
+ static const struct tz1090_clk_gate_bank _name __initconst = { \
+ .id_base = (_id), \
+ .reg_base = (_reg), \
+ .gates = (const struct tz1090_clk_gate[]) { \
+ _gates \
+ { .name = NULL } \
+ }, \
+ }
+
+void tz1090_clk_register_gate_bank(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_gate_bank *bank);
+
+
+/* Clock mux banks */
+
+/**
+ * struct tz1090_clk_mux - Describes an individual mux in a bank.
+ * @shift: Shift of bit controlling mux within the bank control register.
+ * @name: Name of muxed clock to provide.
+ * @parents: Name of two parent/source clocks for when the bit is 0 and 1.
+ * @default_parent: Default parent to set the mux to.
+ * @mux_flags: Mux flags.
+ */
+struct tz1090_clk_mux {
+ unsigned int shift;
+ const char *name;
+ const char *parents[2];
+ s8 default_parent;
+ u8 mux_flags;
+};
+
+/**
+ * struct tz1090_clk_mux_bank - Describes a mux bank.
+ * @id_base: Base id of bank in provider.
+ * Individual muxes get the id id_base + index in muxes array.
+ * @reg_base: Offset of mux bank register in the MMIO region.
+ * @muxes: Pointer to array of muxes in the bank, terminated by one with a
+ * NULL name field.
+ */
+struct tz1090_clk_mux_bank {
+ unsigned int id_base;
+ unsigned long reg_base;
+ const struct tz1090_clk_mux *muxes;
+};
+
+#define MUX(_shift, _parent0, _parent1, _name) \
+ { \
+ .shift = (_shift), \
+ .name = (_name), \
+ .parents = { \
+ _parent0, \
+ _parent1 \
+ }, \
+ .default_parent = -1, \
+ .mux_flags = 0, \
+ },
+
+#define MUX_FIXED(_shift, _parent0, _parent1, _name, _default) \
+ { \
+ .shift = (_shift), \
+ .name = (_name), \
+ .parents = { \
+ _parent0, \
+ _parent1 \
+ }, \
+ .default_parent = (_default), \
+ .mux_flags = CLK_MUX_READ_ONLY, \
+ },
+
+#define MUX_BANK(_name, _id, _reg, _muxes) \
+ static const struct tz1090_clk_mux_bank _name __initconst = { \
+ .id_base = (_id), \
+ .reg_base = (_reg), \
+ .muxes = (const struct tz1090_clk_mux[]) { \
+ _muxes \
+ { .name = NULL } \
+ }, \
+ }
+
+void tz1090_clk_register_mux_bank(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_mux_bank *bank);
+
+
+/* Deleters */
+
+/**
+ * struct tz1090_clk_deleter - Describes a clock deleter.
+ * @id: Id of output clock in provider.
+ * @reg: Offset of deleter register in the MMIO region.
+ * @name: Name of deleted clock to provide.
+ * @parent: Name of parent/source clocks.
+ *
+ * The deleter is assumed to have a period of 1024.
+ */
+struct tz1090_clk_deleter {
+ unsigned int id;
+ unsigned long reg;
+ const char *name;
+ const char *parent;
+};
+
+#define DEL(_id, _parent, _name, _reg) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .name = (_name), \
+ .parent = (_parent), \
+ }
+
+void tz1090_clk_register_deleters(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_deleter *deleters,
+ unsigned int count);
+
+
+/* Dividers */
+
+/**
+ * struct tz1090_clk_divider - Describes a clock divider.
+ * @id: Id of output clock in provider.
+ * @reg: Offset of divider register in the MMIO region.
+ * @flags: Clock flags.
+ * @div_flags: Divider flags.
+ * @shift: Shift of field controlling divider.
+ * @width: Width of field controlling divider.
+ * @shared: 1 if register is shared with other important fields and requires
+ * global locking.
+ * @name: Name of divided clock to provide.
+ * @parent: Name of parent/source clocks.
+ */
+struct tz1090_clk_divider {
+ unsigned int id;
+ unsigned long reg;
+ unsigned long flags;
+ u8 div_flags;
+ u8 shift;
+ u8 width;
+ u8 shared;
+ const char *name;
+ const char *parent;
+};
+
+#define DIV(_id, _parent, _name, _reg, _width) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .width = (_width), \
+ .name = (_name), \
+ .parent = (_parent), \
+ }
+
+#define DIV_FLAGS(_id, _parent, _name, _reg, _width, _flags, _divflags) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .flags = (_flags), \
+ .div_flags = (_divflags), \
+ .width = (_width), \
+ .name = (_name), \
+ .parent = (_parent), \
+ }
+
+#define DIV_SHARED(_id, _parent, _name, _reg, _width, _shift) \
+ { \
+ .id = (_id), \
+ .reg = (_reg), \
+ .shift = (_shift), \
+ .width = (_width), \
+ .shared = 1, \
+ .name = (_name), \
+ .parent = (_parent), \
+ }
+
+void tz1090_clk_register_dividers(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_divider *dividers,
+ unsigned int count);
+
+
+/* PLLs */
+
+struct tz1090_clk_pll {
+ unsigned int id;
+ unsigned long reg_base;
+ const char *name;
+ const char *parent;
+};
+
+#define PLL(_id, _parent, _name, _reg) \
+ { \
+ .id = (_id), \
+ .reg_base = (_reg), \
+ .name = (_name), \
+ .parent = (_parent), \
+ }
+
+void tz1090_clk_register_plls(struct tz1090_clk_provider *p,
+ const struct tz1090_clk_pll *plls,
+ unsigned int count);
+
+#endif
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index deae122..105d4a9 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -2536,16 +2536,18 @@
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
unsigned long flags;
- unsigned int baud, quot, frac = 0;
+ unsigned int baud, quot, frac = 0, uartclk_hi;
cval = serial8250_compute_lcr(up, termios->c_cflag);
/*
- * Ask the core to calculate the divisor for us.
+ * Ask the core to calculate the divisor for us, but tolerate some
+ * variance (e.g. if the uartclk is only slightly under 1.8432MHz).
*/
+ uartclk_hi = port->uartclk + port->uartclk / 128;
baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 0xffff,
- port->uartclk / 16);
+ uartclk_hi / 16);
quot = serial8250_get_divisor(up, baud, &frac);
/*
@@ -3269,15 +3271,16 @@
/* check scratch reg to see if port powered off during system sleep */
if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
struct ktermios termios;
- unsigned int baud, quot, frac = 0;
+ unsigned int baud, quot, frac = 0, uartclk_hi;
termios.c_cflag = port->cons->cflag;
if (port->state->port.tty && termios.c_cflag == 0)
termios.c_cflag = port->state->port.tty->termios.c_cflag;
+ uartclk_hi = port->uartclk + port->uartclk / 128;
baud = uart_get_baud_rate(port, &termios, NULL,
port->uartclk / 16 / 0xffff,
- port->uartclk / 16);
+ uartclk_hi / 16);
quot = serial8250_get_divisor(up, baud, &frac);
serial8250_set_divisor(port, baud, quot, frac);
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
index c8def68..0deaa4f 100644
--- a/drivers/watchdog/imgpdc_wdt.c
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -42,10 +42,10 @@
#define PDC_WDT_MIN_TIMEOUT 1
#define PDC_WDT_DEF_TIMEOUT 64
-static int heartbeat;
+static int heartbeat = PDC_WDT_DEF_TIMEOUT;
module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
- "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds "
+ "(default=" __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
@@ -191,6 +191,7 @@
pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
pdc_wdt->wdt_dev.parent = &pdev->dev;
+ watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
if (ret < 0) {
@@ -232,7 +233,6 @@
watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
platform_set_drvdata(pdev, pdc_wdt);
- watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
ret = watchdog_register_device(&pdc_wdt->wdt_dev);
if (ret)
diff --git a/include/dt-bindings/clock/tz1090-hep.h b/include/dt-bindings/clock/tz1090-hep.h
new file mode 100644
index 0000000..44398ef
--- /dev/null
+++ b/include/dt-bindings/clock/tz1090-hep.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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 _DT_BINDINGS_CLK_TZ1090_HEP_H
+#define _DT_BINDINGS_CLK_TZ1090_HEP_H
+
+/* CR_HEP_CLK_EN - High End Peripheral clocks */
+#define CLK_HEP_2D 0
+#define CLK_HEP_DDR_EN 1
+#define CLK_HEP_PDP 2
+
+#define CLK_HEP_MAX 3
+
+#endif
diff --git a/include/dt-bindings/clock/tz1090-pdc.h b/include/dt-bindings/clock/tz1090-pdc.h
new file mode 100644
index 0000000..fa9a11c
--- /dev/null
+++ b/include/dt-bindings/clock/tz1090-pdc.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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 _DT_BINDINGS_CLK_TZ1090_PDC_H
+#define _DT_BINDINGS_CLK_TZ1090_PDC_H
+
+/* Powerdown Controller clocks */
+#define CLK_PDC_XTAL1_DIV 0
+#define CLK_PDC_32KHZ 1
+
+#define CLK_PDC_MAX 2
+
+#endif
diff --git a/include/dt-bindings/clock/tz1090-perip.h b/include/dt-bindings/clock/tz1090-perip.h
new file mode 100644
index 0000000..b2990ea
--- /dev/null
+++ b/include/dt-bindings/clock/tz1090-perip.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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 _DT_BINDINGS_CLK_TZ1090_PERIP_H
+#define _DT_BINDINGS_CLK_TZ1090_PERIP_H
+
+/* CR_PERIP_CLKEN - Peripheral system clocks */
+#define CLK_PERIP_SCB0 0
+#define CLK_PERIP_SCB1 1
+#define CLK_PERIP_SCB2 2
+#define CLK_PERIP_SDIO 3
+#define CLK_PERIP_UART0 4
+#define CLK_PERIP_UART1 5
+#define CLK_PERIP_SPIM 6
+#define CLK_PERIP_SPIS 7
+#define CLK_PERIP_SPIM1 8
+#define CLK_PERIP_I2SOUT 9
+#define CLK_PERIP_I2SIN 10
+#define CLK_PERIP_LCD 11
+#define CLK_PERIP_SDHOST 12
+#define CLK_PERIP_USB 13
+
+#define CLK_PERIP_MAX 14
+
+#endif
diff --git a/include/dt-bindings/clock/tz1090-top.h b/include/dt-bindings/clock/tz1090-top.h
new file mode 100644
index 0000000..effb06a
--- /dev/null
+++ b/include/dt-bindings/clock/tz1090-top.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2013-2014 Imagination Technologies Ltd.
+ *
+ * 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 _DT_BINDINGS_CLK_TZ1090_TOP_H
+#define _DT_BINDINGS_CLK_TZ1090_TOP_H
+
+/* Ranges of top level clock numbers */
+#define CLK_TOP_CLKSWITCH_BASE 0
+#define CLK_TOP_CLKENAB_BASE (CLK_TOP_CLKSWITCH_BASE + 27)
+#define CLK_TOP_CLKSWITCH2_BASE (CLK_TOP_CLKENAB_BASE + 9)
+#define CLK_TOP_CLKENAB2_BASE (CLK_TOP_CLKSWITCH2_BASE + 10)
+#define CLK_TOP_DEL_BASE (CLK_TOP_CLKENAB2_BASE + 7)
+#define CLK_TOP_DIV_BASE (CLK_TOP_DEL_BASE + 4)
+#define CLK_TOP_PLL_BASE (CLK_TOP_DIV_BASE + 18)
+#define CLK_TOP_CLKEN_BASE (CLK_TOP_PLL_BASE + 2)
+#define CLK_TOP_MAX (CLK_TOP_CLKEN_BASE + 1)
+
+
+/* CR_TOP_CLKSWITCH clocks */
+#define CLK_TOP_SYS_SW (CLK_TOP_CLKSWITCH_BASE + 0)
+#define CLK_TOP_SYS_X2_UNDELETED (CLK_TOP_CLKSWITCH_BASE + 1)
+#define CLK_TOP_OUT0_SW0 (CLK_TOP_CLKSWITCH_BASE + 2)
+#define CLK_TOP_OUT0_SW1 (CLK_TOP_CLKSWITCH_BASE + 3)
+#define CLK_TOP_OUT0_SW2 (CLK_TOP_CLKSWITCH_BASE + 4)
+#define CLK_TOP_OUT0_SW3 (CLK_TOP_CLKSWITCH_BASE + 5)
+#define CLK_TOP_OUT1_SW0 (CLK_TOP_CLKSWITCH_BASE + 6)
+#define CLK_TOP_OUT1_SW1 (CLK_TOP_CLKSWITCH_BASE + 7)
+#define CLK_TOP_OUT1_SW2 (CLK_TOP_CLKSWITCH_BASE + 8)
+#define CLK_TOP_OUT1_SW3 (CLK_TOP_CLKSWITCH_BASE + 9)
+#define CLK_TOP_I2S_SW2 (CLK_TOP_CLKSWITCH_BASE + 10)
+#define CLK_TOP_I2S_SW0 (CLK_TOP_CLKSWITCH_BASE + 11)
+#define CLK_TOP_I2S_SW1 (CLK_TOP_CLKSWITCH_BASE + 12)
+#define CLK_TOP_SCB_SW (CLK_TOP_CLKSWITCH_BASE + 13)
+#define CLK_TOP_UART_SW (CLK_TOP_CLKSWITCH_BASE + 14)
+#define CLK_TOP_EXT_STC0_SW (CLK_TOP_CLKSWITCH_BASE + 15)
+#define CLK_TOP_EXT_STC1_SW (CLK_TOP_CLKSWITCH_BASE + 16)
+#define CLK_TOP_USB_SW0 (CLK_TOP_CLKSWITCH_BASE + 17)
+#define CLK_TOP_USB_SW1 (CLK_TOP_CLKSWITCH_BASE + 18)
+#define CLK_TOP_AFE_SW0 (CLK_TOP_CLKSWITCH_BASE + 19)
+#define CLK_TOP_AFE_SW1 (CLK_TOP_CLKSWITCH_BASE + 20)
+#define CLK_TOP_ADCPLL_SW0 (CLK_TOP_CLKSWITCH_BASE + 21)
+#define CLK_TOP_ADCPLL_SW1 (CLK_TOP_CLKSWITCH_BASE + 22)
+#define CLK_TOP_ADCPLL_SW2 (CLK_TOP_CLKSWITCH_BASE + 23)
+#define CLK_TOP_ADCPLL_SW3 (CLK_TOP_CLKSWITCH_BASE + 24)
+#define CLK_TOP_USB_SW2 (CLK_TOP_CLKSWITCH_BASE + 25)
+#define CLK_TOP_USB_SW3 (CLK_TOP_CLKSWITCH_BASE + 26)
+
+/* CR_TOP_CLKENAB clocks */
+#define CLK_TOP_OUT0_EN (CLK_TOP_CLKENAB_BASE + 0)
+#define CLK_TOP_OUT1_EN (CLK_TOP_CLKENAB_BASE + 1)
+#define CLK_TOP_I2S_EN (CLK_TOP_CLKENAB_BASE + 2)
+#define CLK_TOP_SCB (CLK_TOP_CLKENAB_BASE + 3)
+#define CLK_TOP_UART_EN (CLK_TOP_CLKENAB_BASE + 4)
+#define CLK_TOP_EXT_STC0 (CLK_TOP_CLKENAB_BASE + 5)
+#define CLK_TOP_EXT_STC1 (CLK_TOP_CLKENAB_BASE + 6)
+#define CLK_TOP_USB_EN (CLK_TOP_CLKENAB_BASE + 7)
+#define CLK_TOP_ADCPLL_EN (CLK_TOP_CLKENAB_BASE + 8)
+
+/* CR_TOP_CLKSWITCH2 clocks */
+#define CLK_TOP_PIXEL_SW0 (CLK_TOP_CLKSWITCH2_BASE + 0)
+#define CLK_TOP_PIXEL_SW1 (CLK_TOP_CLKSWITCH2_BASE + 1)
+#define CLK_TOP_PIXEL_SW2 (CLK_TOP_CLKSWITCH2_BASE + 2)
+#define CLK_TOP_PIXEL_SW3 (CLK_TOP_CLKSWITCH2_BASE + 3)
+#define CLK_TOP_PIXEL_SW4 (CLK_TOP_CLKSWITCH2_BASE + 4)
+#define CLK_TOP_IF1_SW (CLK_TOP_CLKSWITCH2_BASE + 5)
+#define CLK_TOP_IF0_SW (CLK_TOP_CLKSWITCH2_BASE + 6)
+#define CLK_TOP_DAC0_SW (CLK_TOP_CLKSWITCH2_BASE + 7)
+#define CLK_TOP_UCC1_SW (CLK_TOP_CLKSWITCH2_BASE + 8)
+#define CLK_TOP_UCC0_SW (CLK_TOP_CLKSWITCH2_BASE + 9)
+
+/* CR_TOP_CLKENAB2 clocks */
+#define CLK_TOP_PIXEL_EN (CLK_TOP_CLKENAB2_BASE + 0)
+#define CLK_TOP_IF1 (CLK_TOP_CLKENAB2_BASE + 1)
+#define CLK_TOP_IF0 (CLK_TOP_CLKENAB2_BASE + 2)
+#define CLK_TOP_EXT_ADC_EN (CLK_TOP_CLKENAB2_BASE + 3)
+#define CLK_TOP_DAC0 (CLK_TOP_CLKENAB2_BASE + 4)
+#define CLK_TOP_SYS_UCC1 (CLK_TOP_CLKENAB2_BASE + 5)
+#define CLK_TOP_SYS_MTX (CLK_TOP_CLKENAB2_BASE + 6)
+
+/* Clock deleters */
+#define CLK_TOP_SYS (CLK_TOP_DEL_BASE + 0)
+#define CLK_TOP_META (CLK_TOP_DEL_BASE + 1)
+#define CLK_TOP_UCC0 (CLK_TOP_DEL_BASE + 2)
+#define CLK_TOP_UCC1_DEL (CLK_TOP_DEL_BASE + 3)
+
+/* Clock dividers */
+#define CLK_TOP_SYS_DIV (CLK_TOP_DIV_BASE + 0)
+#define CLK_TOP_SYS_UNDELETED (CLK_TOP_DIV_BASE + 1)
+#define CLK_TOP_AFE (CLK_TOP_DIV_BASE + 2)
+#define CLK_TOP_ADCPLL_DIV (CLK_TOP_DIV_BASE + 3)
+#define CLK_TOP_UART (CLK_TOP_DIV_BASE + 4)
+#define CLK_TOP_PDM (CLK_TOP_DIV_BASE + 5)
+#define CLK_TOP_SPI0 (CLK_TOP_DIV_BASE + 6)
+#define CLK_TOP_SPI1 (CLK_TOP_DIV_BASE + 7)
+#define CLK_TOP_I2SM (CLK_TOP_DIV_BASE + 8)
+#define CLK_TOP_USB_PHY (CLK_TOP_DIV_BASE + 9)
+#define CLK_TOP_SDHOST (CLK_TOP_DIV_BASE + 10)
+#define CLK_TOP_RING_OSC (CLK_TOP_DIV_BASE + 11)
+#define CLK_TOP_I2S (CLK_TOP_DIV_BASE + 12)
+#define CLK_TOP_META_TRACE (CLK_TOP_DIV_BASE + 13)
+#define CLK_TOP_PIXEL (CLK_TOP_DIV_BASE + 14)
+#define CLK_TOP_OUT0 (CLK_TOP_DIV_BASE + 15)
+#define CLK_TOP_OUT1 (CLK_TOP_DIV_BASE + 16)
+#define CLK_TOP_DDR (CLK_TOP_DIV_BASE + 17)
+
+/* PLL clocks */
+#define CLK_TOP_SYSPLL (CLK_TOP_PLL_BASE + 0)
+#define CLK_TOP_ADCPLL (CLK_TOP_PLL_BASE + 1)
+
+/* CR_TOP_CLKEN clocks */
+#define CLK_TOP_PDC (CLK_TOP_CLKEN_BASE + 0)
+
+#endif
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 5591ea7..80e54bf 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -265,6 +265,7 @@
unsigned long fixed_rate, unsigned long fixed_accuracy);
void of_fixed_clk_setup(struct device_node *np);
+void of_specified_clk_setup(struct device_node *np);
/**
* struct clk_gate - gating clock