summaryrefslogtreecommitdiffstats
path: root/drivers/clk/tegra/clk-pll-out.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2013-02-05 12:13:10 -0800
committerOlof Johansson <olof@lixom.net>2013-02-05 12:13:10 -0800
commitbda6f8e6cdcdb55db9b2961b6a7c9d0d97da4765 (patch)
treecec7c71c5120538352157fa1d2826efe881a7b0c /drivers/clk/tegra/clk-pll-out.c
parentc35a0bfacb61f5c56e0e64f309d36c59c7fe8da3 (diff)
parentef3ffe5a0458606c488def757bb7f6dd013c2db5 (diff)
downloadtalos-op-linux-bda6f8e6cdcdb55db9b2961b6a7c9d0d97da4765.tar.gz
talos-op-linux-bda6f8e6cdcdb55db9b2961b6a7c9d0d97da4765.zip
Merge tag 'tegra-for-3.9-soc-ccf' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra into next/soc
From Stephen Warren: ARM: tegra: Common Clock Framework rework Tegra already supports the common clock framework, but had issues: 1) The clock driver was located in arch/arm/mach-tegra/ rather than drivers/clk/. 2) A single "Tegra clock" type was implemented, rather than separate clock types for PLL, mux, divider, ... type in HW. 3) Clock lookups by device drivers were still driven by device name and connection ID, rather than through device tree. This pull request solves all three issues. This required some DT changes to add clocks properties, and driver changes to request clocks more "correctly". Finally, this rework allows all AUXDATA to be removed from Tegra board files, and various duplicate clock lookup entries to be removed from the driver. This pull request is based on the previous pull request, with tag tegra-for-3.9-cleanup. * tag 'tegra-for-3.9-soc-ccf' of git://git.kernel.org/pub/scm/linux/kernel/git/swarren/linux-tegra: (31 commits) clk: tegra30: remove unused TEGRA_CLK_DUPLICATE()s clk: tegra20: remove unused TEGRA_CLK_DUPLICATE()s ARM: tegra30: remove auxdata ARM: tegra20: remove auxdata ASoC: tegra: remove auxdata staging: nvec: remove use of clk_get_sys ARM: tegra: paz00: add clock information to DT ARM: tegra: add clock properties to Tegra30 DT ARM: tegra: add clock properties to Tegra20 DT spi: tegra: do not use clock name to get clock ARM: tegra: remove legacy clock code ARM: tegra: migrate to new clock code clk: tegra: add clock support for Tegra30 clk: tegra: add clock support for Tegra20 clk: tegra: add Tegra specific clocks ARM: tegra: define Tegra30 CAR binding ARM: tegra: define Tegra20 CAR binding ARM: tegra: move tegra_cpu_car.h to linux/clk/tegra.h ARM: tegra: add function to read chipid ARM: tegra: fix compile error when disable CPU_IDLE ... Signed-off-by: Olof Johansson <olof@lixom.net> Conflicts: arch/arm/mach-tegra/board-dt-tegra20.c arch/arm/mach-tegra/board-dt-tegra30.c arch/arm/mach-tegra/common.c arch/arm/mach-tegra/platsmp.c drivers/clocksource/Makefile
Diffstat (limited to 'drivers/clk/tegra/clk-pll-out.c')
-rw-r--r--drivers/clk/tegra/clk-pll-out.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/clk/tegra/clk-pll-out.c b/drivers/clk/tegra/clk-pll-out.c
new file mode 100644
index 000000000000..3598987a451d
--- /dev/null
+++ b/drivers/clk/tegra/clk-pll-out.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
+ *
+ * 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/kernel.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/clk-provider.h>
+#include <linux/clk.h>
+
+#include "clk.h"
+
+#define pll_out_enb(p) (BIT(p->enb_bit_idx))
+#define pll_out_rst(p) (BIT(p->rst_bit_idx))
+
+static int clk_pll_out_is_enabled(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+ u32 val = readl_relaxed(pll_out->reg);
+ int state;
+
+ state = (val & pll_out_enb(pll_out)) ? 1 : 0;
+ if (!(val & (pll_out_rst(pll_out))))
+ state = 0;
+ return state;
+}
+
+static int clk_pll_out_enable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll_out->lock)
+ spin_lock_irqsave(pll_out->lock, flags);
+
+ val = readl_relaxed(pll_out->reg);
+
+ val |= (pll_out_enb(pll_out) | pll_out_rst(pll_out));
+
+ writel_relaxed(val, pll_out->reg);
+ udelay(2);
+
+ if (pll_out->lock)
+ spin_unlock_irqrestore(pll_out->lock, flags);
+
+ return 0;
+}
+
+static void clk_pll_out_disable(struct clk_hw *hw)
+{
+ struct tegra_clk_pll_out *pll_out = to_clk_pll_out(hw);
+ unsigned long flags = 0;
+ u32 val;
+
+ if (pll_out->lock)
+ spin_lock_irqsave(pll_out->lock, flags);
+
+ val = readl_relaxed(pll_out->reg);
+
+ val &= ~(pll_out_enb(pll_out) | pll_out_rst(pll_out));
+
+ writel_relaxed(val, pll_out->reg);
+ udelay(2);
+
+ if (pll_out->lock)
+ spin_unlock_irqrestore(pll_out->lock, flags);
+}
+
+const struct clk_ops tegra_clk_pll_out_ops = {
+ .is_enabled = clk_pll_out_is_enabled,
+ .enable = clk_pll_out_enable,
+ .disable = clk_pll_out_disable,
+};
+
+struct clk *tegra_clk_register_pll_out(const char *name,
+ const char *parent_name, void __iomem *reg, u8 enb_bit_idx,
+ u8 rst_bit_idx, unsigned long flags, u8 pll_out_flags,
+ spinlock_t *lock)
+{
+ struct tegra_clk_pll_out *pll_out;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ pll_out = kzalloc(sizeof(*pll_out), GFP_KERNEL);
+ if (!pll_out)
+ return ERR_PTR(-ENOMEM);
+
+ init.name = name;
+ init.ops = &tegra_clk_pll_out_ops;
+ init.parent_names = (parent_name ? &parent_name : NULL);
+ init.num_parents = (parent_name ? 1 : 0);
+ init.flags = flags;
+
+ pll_out->reg = reg;
+ pll_out->enb_bit_idx = enb_bit_idx;
+ pll_out->rst_bit_idx = rst_bit_idx;
+ pll_out->flags = pll_out_flags;
+ pll_out->lock = lock;
+
+ /* Data in .init is copied by clk_register(), so stack variable OK */
+ pll_out->hw.init = &init;
+
+ clk = clk_register(NULL, &pll_out->hw);
+ if (IS_ERR(clk))
+ kfree(pll_out);
+
+ return clk;
+}
OpenPOWER on IntegriCloud