summaryrefslogtreecommitdiffstats
path: root/drivers/clk/mvebu/clk-gating-ctrl.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-11-30 18:01:49 +0100
committerOlof Johansson <olof@lixom.net>2012-11-30 18:02:53 +0100
commit0c0029cb1806601430692d48c130a17302a18225 (patch)
tree2481cc582a77b3ce7651c3ab2478886941bea621 /drivers/clk/mvebu/clk-gating-ctrl.c
parentLinux 3.7-rc7 (diff)
parentMerge branch 'mvebu-misc-fixes' of git://github.com/MISL-EBU-System-SW/mainli... (diff)
downloadlinux-0c0029cb1806601430692d48c130a17302a18225.tar.xz
linux-0c0029cb1806601430692d48c130a17302a18225.zip
Merge tag 'mvebu_everything_for_3.8' of git://git.infradead.org/users/jcooper/linux into late/mvebu
From Jason Cooper. Unfortunately this is a combined branch with all mvebu code as one drop, something we normally try to avoid and instead slice vendor topics across our branches. Hopefully we can avoid doing this again for 3.9! mvebu everything for v3.8 - due to the complex interdependencies of the received pull requests I decided to keep this in one branch the way they recommended merging it - this was their first attempt at doing pull requests, we'll work on it with them - added SMP support for mvebu SoCs - added coherency fabric - added mdio and mvneta drivers - added mirabox board - added openblocks ax3-4 board - clock fixes and improvements - converted mv_xor driver to devicetree (extensive series in itself) * tag 'mvebu_everything_for_3.8' of git://git.infradead.org/users/jcooper/linux: (85 commits) dma: mv_xor: fix error handling path dma: mv_xor: fix error checking of irq_of_parse_and_map() dma: mv_xor: use request_irq() instead of devm_request_irq() dma: mv_xor: clear the window override control registers arm: mvebu: fix address decoding armada_cfg_base() function ARM: mvebu: update defconfig with I2C and RTC support ARM: mvebu: Add SATA support for OpenBlocks AX3-4 ARM: mvebu: Add support for the RTC in OpenBlocks AX3-4 ARM: mvebu: Add support for I2C on OpenBlocks AX3-4 ARM: mvebu: Add support for I2C controllers in Armada 370/XP arm: mvebu: Add hardware I/O Coherency support arm: plat-orion: Add coherency attribute when setup mbus target arm: dma mapping: Export a dma ops function arm_dma_set_mask arm: mvebu: Add SMP support for Armada XP arm: mm: Add support for PJ4B cpu and init routines arm: mvebu: Add IPI support via doorbells arm: mvebu: Add initial support for power managmement service unit arm: mvebu: Add support for coherency fabric in mach-mvebu arm: mvebu: update defconfig to include XOR driver arm: mvebu: update defconfig to include network driver ... Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/clk/mvebu/clk-gating-ctrl.c')
-rw-r--r--drivers/clk/mvebu/clk-gating-ctrl.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/drivers/clk/mvebu/clk-gating-ctrl.c b/drivers/clk/mvebu/clk-gating-ctrl.c
new file mode 100644
index 000000000000..c6d3c263b070
--- /dev/null
+++ b/drivers/clk/mvebu/clk-gating-ctrl.c
@@ -0,0 +1,249 @@
+/*
+ * Marvell MVEBU clock gating control.
+ *
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ * Andrew Lunn <andrew@lunn.ch>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/mvebu.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+struct mvebu_gating_ctrl {
+ spinlock_t lock;
+ struct clk **gates;
+ int num_gates;
+};
+
+struct mvebu_soc_descr {
+ const char *name;
+ const char *parent;
+ int bit_idx;
+};
+
+#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+
+static struct clk __init *mvebu_clk_gating_get_src(
+ struct of_phandle_args *clkspec, void *data)
+{
+ struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data;
+ int n;
+
+ if (clkspec->args_count < 1)
+ return ERR_PTR(-EINVAL);
+
+ for (n = 0; n < ctrl->num_gates; n++) {
+ struct clk_gate *gate =
+ to_clk_gate(__clk_get_hw(ctrl->gates[n]));
+ if (clkspec->args[0] == gate->bit_idx)
+ return ctrl->gates[n];
+ }
+ return ERR_PTR(-ENODEV);
+}
+
+static void __init mvebu_clk_gating_setup(
+ struct device_node *np, const struct mvebu_soc_descr *descr)
+{
+ struct mvebu_gating_ctrl *ctrl;
+ struct clk *clk;
+ void __iomem *base;
+ const char *default_parent = NULL;
+ int n;
+
+ base = of_iomap(np, 0);
+
+ clk = of_clk_get(np, 0);
+ if (!IS_ERR(clk)) {
+ default_parent = __clk_get_name(clk);
+ clk_put(clk);
+ }
+
+ ctrl = kzalloc(sizeof(struct mvebu_gating_ctrl), GFP_KERNEL);
+ if (WARN_ON(!ctrl))
+ return;
+
+ spin_lock_init(&ctrl->lock);
+
+ /*
+ * Count, allocate, and register clock gates
+ */
+ for (n = 0; descr[n].name;)
+ n++;
+
+ ctrl->num_gates = n;
+ ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *),
+ GFP_KERNEL);
+ if (WARN_ON(!ctrl->gates)) {
+ kfree(ctrl);
+ return;
+ }
+
+ for (n = 0; n < ctrl->num_gates; n++) {
+ u8 flags = 0;
+ const char *parent =
+ (descr[n].parent) ? descr[n].parent : default_parent;
+
+ /*
+ * On Armada 370, the DDR clock is a special case: it
+ * isn't taken by any driver, but should anyway be
+ * kept enabled, so we mark it as IGNORE_UNUSED for
+ * now.
+ */
+ if (!strcmp(descr[n].name, "ddr"))
+ flags |= CLK_IGNORE_UNUSED;
+
+ ctrl->gates[n] = clk_register_gate(NULL, descr[n].name, parent,
+ flags, base, descr[n].bit_idx, 0, &ctrl->lock);
+ WARN_ON(IS_ERR(ctrl->gates[n]));
+ }
+ of_clk_add_provider(np, mvebu_clk_gating_get_src, ctrl);
+}
+
+/*
+ * SoC specific clock gating control
+ */
+
+#ifdef CONFIG_MACH_ARMADA_370
+static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = {
+ { "audio", NULL, 0 },
+ { "pex0_en", NULL, 1 },
+ { "pex1_en", NULL, 2 },
+ { "ge1", NULL, 3 },
+ { "ge0", NULL, 4 },
+ { "pex0", NULL, 5 },
+ { "pex1", NULL, 9 },
+ { "sata0", NULL, 15 },
+ { "sdio", NULL, 17 },
+ { "tdm", NULL, 25 },
+ { "ddr", NULL, 28 },
+ { "sata1", NULL, 30 },
+ { }
+};
+#endif
+
+#ifdef CONFIG_MACH_ARMADA_XP
+static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = {
+ { "audio", NULL, 0 },
+ { "ge3", NULL, 1 },
+ { "ge2", NULL, 2 },
+ { "ge1", NULL, 3 },
+ { "ge0", NULL, 4 },
+ { "pex0", NULL, 5 },
+ { "pex1", NULL, 6 },
+ { "pex2", NULL, 7 },
+ { "pex3", NULL, 8 },
+ { "bp", NULL, 13 },
+ { "sata0lnk", NULL, 14 },
+ { "sata0", "sata0lnk", 15 },
+ { "lcd", NULL, 16 },
+ { "sdio", NULL, 17 },
+ { "usb0", NULL, 18 },
+ { "usb1", NULL, 19 },
+ { "usb2", NULL, 20 },
+ { "xor0", NULL, 22 },
+ { "crypto", NULL, 23 },
+ { "tdm", NULL, 25 },
+ { "xor1", NULL, 28 },
+ { "sata1lnk", NULL, 29 },
+ { "sata1", "sata1lnk", 30 },
+ { }
+};
+#endif
+
+#ifdef CONFIG_ARCH_DOVE
+static const struct mvebu_soc_descr __initconst dove_gating_descr[] = {
+ { "usb0", NULL, 0 },
+ { "usb1", NULL, 1 },
+ { "ge", "gephy", 2 },
+ { "sata", NULL, 3 },
+ { "pex0", NULL, 4 },
+ { "pex1", NULL, 5 },
+ { "sdio0", NULL, 8 },
+ { "sdio1", NULL, 9 },
+ { "nand", NULL, 10 },
+ { "camera", NULL, 11 },
+ { "i2s0", NULL, 12 },
+ { "i2s1", NULL, 13 },
+ { "crypto", NULL, 15 },
+ { "ac97", NULL, 21 },
+ { "pdma", NULL, 22 },
+ { "xor0", NULL, 23 },
+ { "xor1", NULL, 24 },
+ { "gephy", NULL, 30 },
+ { }
+};
+#endif
+
+#ifdef CONFIG_ARCH_KIRKWOOD
+static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = {
+ { "ge0", NULL, 0 },
+ { "pex0", NULL, 2 },
+ { "usb0", NULL, 3 },
+ { "sdio", NULL, 4 },
+ { "tsu", NULL, 5 },
+ { "runit", NULL, 7 },
+ { "xor0", NULL, 8 },
+ { "audio", NULL, 9 },
+ { "sata0", NULL, 14 },
+ { "sata1", NULL, 15 },
+ { "xor1", NULL, 16 },
+ { "crypto", NULL, 17 },
+ { "pex1", NULL, 18 },
+ { "ge1", NULL, 19 },
+ { "tdm", NULL, 20 },
+ { }
+};
+#endif
+
+static const __initdata struct of_device_id clk_gating_match[] = {
+#ifdef CONFIG_MACH_ARMADA_370
+ {
+ .compatible = "marvell,armada-370-gating-clock",
+ .data = armada_370_gating_descr,
+ },
+#endif
+
+#ifdef CONFIG_MACH_ARMADA_XP
+ {
+ .compatible = "marvell,armada-xp-gating-clock",
+ .data = armada_xp_gating_descr,
+ },
+#endif
+
+#ifdef CONFIG_ARCH_DOVE
+ {
+ .compatible = "marvell,dove-gating-clock",
+ .data = dove_gating_descr,
+ },
+#endif
+
+#ifdef CONFIG_ARCH_KIRKWOOD
+ {
+ .compatible = "marvell,kirkwood-gating-clock",
+ .data = kirkwood_gating_descr,
+ },
+#endif
+
+ { }
+};
+
+void __init mvebu_gating_clk_init(void)
+{
+ struct device_node *np;
+
+ for_each_matching_node(np, clk_gating_match) {
+ const struct of_device_id *match =
+ of_match_node(clk_gating_match, np);
+ mvebu_clk_gating_setup(np,
+ (const struct mvebu_soc_descr *)match->data);
+ }
+}