···11+/*22+ * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.33+ *44+ * This program is free software; you can redistribute it and/or modify it55+ * under the terms and conditions of the GNU General Public License,66+ * version 2, as published by the Free Software Foundation.77+ *88+ * This program is distributed in the hope it will be useful, but WITHOUT99+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1010+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1111+ * more details.1212+ *1313+ * You should have received a copy of the GNU General Public License1414+ * along with this program. If not, see <http://www.gnu.org/licenses/>.1515+ */1616+1717+#include <linux/io.h>1818+#include <linux/clk.h>1919+#include <linux/clk-provider.h>2020+#include <linux/of.h>2121+#include <linux/of_address.h>2222+#include <linux/delay.h>2323+#include <linux/export.h>2424+#include <linux/clk/tegra.h>2525+2626+#include "clk.h"2727+#include "clk-id.h"2828+2929+#define OSC_CTRL 0x503030+#define OSC_CTRL_OSC_FREQ_SHIFT 283131+#define OSC_CTRL_PLL_REF_DIV_SHIFT 263232+3333+int __init tegra_osc_clk_init(void __iomem *clk_base,3434+ struct tegra_clk *tegra_clks,3535+ unsigned long *input_freqs, int num,3636+ unsigned long *osc_freq,3737+ unsigned long *pll_ref_freq)3838+{3939+ struct clk *clk;4040+ struct clk **dt_clk;4141+ u32 val, pll_ref_div;4242+ unsigned osc_idx;4343+4444+ val = readl_relaxed(clk_base + OSC_CTRL);4545+ osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;4646+4747+ if (osc_idx < num)4848+ *osc_freq = input_freqs[osc_idx];4949+ else5050+ *osc_freq = 0;5151+5252+ if (!*osc_freq) {5353+ WARN_ON(1);5454+ return -EINVAL;5555+ }5656+5757+ dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, tegra_clks);5858+ if (!dt_clk)5959+ return 0;6060+6161+ clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT,6262+ *osc_freq);6363+ *dt_clk = clk;6464+6565+ /* pll_ref */6666+ val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;6767+ pll_ref_div = 1 << val;6868+ dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, tegra_clks);6969+ if (!dt_clk)7070+ return 0;7171+7272+ clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m",7373+ 0, 1, pll_ref_div);7474+ *dt_clk = clk;7575+7676+ if (pll_ref_freq)7777+ *pll_ref_freq = *osc_freq / pll_ref_div;7878+7979+ return 0;8080+}8181+8282+void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks)8383+{8484+ struct clk *clk;8585+ struct clk **dt_clk;8686+8787+ /* clk_32k */8888+ dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks);8989+ if (dt_clk) {9090+ clk = clk_register_fixed_rate(NULL, "clk_32k", NULL,9191+ CLK_IS_ROOT, 32768);9292+ *dt_clk = clk;9393+ }9494+9595+ /* clk_m_div2 */9696+ dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks);9797+ if (dt_clk) {9898+ clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m",9999+ CLK_SET_RATE_PARENT, 1, 2);100100+ *dt_clk = clk;101101+ }102102+103103+ /* clk_m_div4 */104104+ dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks);105105+ if (dt_clk) {106106+ clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m",107107+ CLK_SET_RATE_PARENT, 1, 4);108108+ *dt_clk = clk;109109+ }110110+}111111+
+132
drivers/clk/tegra/clk-tegra-pmc.c
···11+/*22+ * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.33+ *44+ * This program is free software; you can redistribute it and/or modify it55+ * under the terms and conditions of the GNU General Public License,66+ * version 2, as published by the Free Software Foundation.77+ *88+ * This program is distributed in the hope it will be useful, but WITHOUT99+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1010+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1111+ * more details.1212+ *1313+ * You should have received a copy of the GNU General Public License1414+ * along with this program. If not, see <http://www.gnu.org/licenses/>.1515+ */1616+1717+#include <linux/io.h>1818+#include <linux/clk.h>1919+#include <linux/clk-provider.h>2020+#include <linux/clkdev.h>2121+#include <linux/of.h>2222+#include <linux/of_address.h>2323+#include <linux/delay.h>2424+#include <linux/export.h>2525+#include <linux/clk/tegra.h>2626+2727+#include "clk.h"2828+#include "clk-id.h"2929+3030+#define PMC_CLK_OUT_CNTRL 0x1a83131+#define PMC_DPD_PADS_ORIDE 0x1c3232+#define PMC_DPD_PADS_ORIDE_BLINK_ENB 203333+#define PMC_CTRL 03434+#define PMC_CTRL_BLINK_ENB 73535+#define PMC_BLINK_TIMER 0x403636+3737+struct pmc_clk_init_data {3838+ char *mux_name;3939+ char *gate_name;4040+ const char **parents;4141+ int num_parents;4242+ int mux_id;4343+ int gate_id;4444+ char *dev_name;4545+ u8 mux_shift;4646+ u8 gate_shift;4747+};4848+4949+#define PMC_CLK(_num, _mux_shift, _gate_shift)\5050+ {\5151+ .mux_name = "clk_out_" #_num "_mux",\5252+ .gate_name = "clk_out_" #_num,\5353+ .parents = clk_out ##_num ##_parents,\5454+ .num_parents = ARRAY_SIZE(clk_out ##_num ##_parents),\5555+ .mux_id = tegra_clk_clk_out_ ##_num ##_mux,\5656+ .gate_id = tegra_clk_clk_out_ ##_num,\5757+ .dev_name = "extern" #_num,\5858+ .mux_shift = _mux_shift,\5959+ .gate_shift = _gate_shift,\6060+ }6161+6262+static DEFINE_SPINLOCK(clk_out_lock);6363+6464+static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",6565+ "clk_m_div4", "extern1",6666+};6767+6868+static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",6969+ "clk_m_div4", "extern2",7070+};7171+7272+static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",7373+ "clk_m_div4", "extern3",7474+};7575+7676+static struct pmc_clk_init_data pmc_clks[] = {7777+ PMC_CLK(1, 6, 2),7878+ PMC_CLK(2, 14, 10),7979+ PMC_CLK(3, 22, 18),8080+};8181+8282+void __init tegra_pmc_clk_init(void __iomem *pmc_base,8383+ struct tegra_clk *tegra_clks)8484+{8585+ struct clk *clk;8686+ struct clk **dt_clk;8787+ int i;8888+8989+ for (i = 0; i < ARRAY_SIZE(pmc_clks); i++) {9090+ struct pmc_clk_init_data *data;9191+9292+ data = pmc_clks + i;9393+9494+ dt_clk = tegra_lookup_dt_id(data->mux_id, tegra_clks);9595+ if (!dt_clk)9696+ continue;9797+9898+ clk = clk_register_mux(NULL, data->mux_name, data->parents,9999+ data->num_parents, CLK_SET_RATE_NO_REPARENT,100100+ pmc_base + PMC_CLK_OUT_CNTRL, data->mux_shift,101101+ 3, 0, &clk_out_lock);102102+ *dt_clk = clk;103103+104104+105105+ dt_clk = tegra_lookup_dt_id(data->gate_id, tegra_clks);106106+ if (!dt_clk)107107+ continue;108108+109109+ clk = clk_register_gate(NULL, data->gate_name, data->mux_name,110110+ 0, pmc_base + PMC_CLK_OUT_CNTRL,111111+ data->gate_shift, 0, &clk_out_lock);112112+ *dt_clk = clk;113113+ clk_register_clkdev(clk, data->dev_name, data->gate_name);114114+ }115115+116116+ /* blink */117117+ writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);118118+ clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,119119+ pmc_base + PMC_DPD_PADS_ORIDE,120120+ PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);121121+122122+ dt_clk = tegra_lookup_dt_id(tegra_clk_blink, tegra_clks);123123+ if (!dt_clk)124124+ return;125125+126126+ clk = clk_register_gate(NULL, "blink", "blink_override", 0,127127+ pmc_base + PMC_CTRL,128128+ PMC_CTRL_BLINK_ENB, 0, NULL);129129+ clk_register_clkdev(clk, "blink", NULL);130130+ *dt_clk = clk;131131+}132132+