1de4f30fdSPeter De Schrijver /* 2de4f30fdSPeter De Schrijver * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. 3de4f30fdSPeter De Schrijver * 4de4f30fdSPeter De Schrijver * This program is free software; you can redistribute it and/or modify it 5de4f30fdSPeter De Schrijver * under the terms and conditions of the GNU General Public License, 6de4f30fdSPeter De Schrijver * version 2, as published by the Free Software Foundation. 7de4f30fdSPeter De Schrijver * 8de4f30fdSPeter De Schrijver * This program is distributed in the hope it will be useful, but WITHOUT 9de4f30fdSPeter De Schrijver * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10de4f30fdSPeter De Schrijver * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11de4f30fdSPeter De Schrijver * more details. 12de4f30fdSPeter De Schrijver * 13de4f30fdSPeter De Schrijver * You should have received a copy of the GNU General Public License 14de4f30fdSPeter De Schrijver * along with this program. If not, see <http://www.gnu.org/licenses/>. 15de4f30fdSPeter De Schrijver */ 16de4f30fdSPeter De Schrijver 17de4f30fdSPeter De Schrijver #include <linux/io.h> 18de4f30fdSPeter De Schrijver #include <linux/clk-provider.h> 19de4f30fdSPeter De Schrijver #include <linux/of.h> 20de4f30fdSPeter De Schrijver #include <linux/of_address.h> 21de4f30fdSPeter De Schrijver #include <linux/delay.h> 22de4f30fdSPeter De Schrijver #include <linux/export.h> 23de4f30fdSPeter De Schrijver #include <linux/clk/tegra.h> 24de4f30fdSPeter De Schrijver 25de4f30fdSPeter De Schrijver #include "clk.h" 26de4f30fdSPeter De Schrijver #include "clk-id.h" 27de4f30fdSPeter De Schrijver 28de4f30fdSPeter De Schrijver #define OSC_CTRL 0x50 29de4f30fdSPeter De Schrijver #define OSC_CTRL_OSC_FREQ_SHIFT 28 30de4f30fdSPeter De Schrijver #define OSC_CTRL_PLL_REF_DIV_SHIFT 26 31de4f30fdSPeter De Schrijver 3263cc5a4dSThierry Reding int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks, 3363cc5a4dSThierry Reding unsigned long *input_freqs, unsigned int num, 3463cc5a4dSThierry Reding unsigned int clk_m_div, unsigned long *osc_freq, 35de4f30fdSPeter De Schrijver unsigned long *pll_ref_freq) 36de4f30fdSPeter De Schrijver { 3763cc5a4dSThierry Reding struct clk *clk, *osc; 38de4f30fdSPeter De Schrijver struct clk **dt_clk; 39de4f30fdSPeter De Schrijver u32 val, pll_ref_div; 40de4f30fdSPeter De Schrijver unsigned osc_idx; 41de4f30fdSPeter De Schrijver 42de4f30fdSPeter De Schrijver val = readl_relaxed(clk_base + OSC_CTRL); 43de4f30fdSPeter De Schrijver osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT; 44de4f30fdSPeter De Schrijver 45de4f30fdSPeter De Schrijver if (osc_idx < num) 46de4f30fdSPeter De Schrijver *osc_freq = input_freqs[osc_idx]; 47de4f30fdSPeter De Schrijver else 48de4f30fdSPeter De Schrijver *osc_freq = 0; 49de4f30fdSPeter De Schrijver 50de4f30fdSPeter De Schrijver if (!*osc_freq) { 51de4f30fdSPeter De Schrijver WARN_ON(1); 52de4f30fdSPeter De Schrijver return -EINVAL; 53de4f30fdSPeter De Schrijver } 54de4f30fdSPeter De Schrijver 55*f6da46a3SStephen Boyd osc = clk_register_fixed_rate(NULL, "osc", NULL, 0, *osc_freq); 5663cc5a4dSThierry Reding 5763cc5a4dSThierry Reding dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, clks); 58de4f30fdSPeter De Schrijver if (!dt_clk) 59de4f30fdSPeter De Schrijver return 0; 60de4f30fdSPeter De Schrijver 6163cc5a4dSThierry Reding clk = clk_register_fixed_factor(NULL, "clk_m", "osc", 6263cc5a4dSThierry Reding 0, 1, clk_m_div); 63de4f30fdSPeter De Schrijver *dt_clk = clk; 64de4f30fdSPeter De Schrijver 65de4f30fdSPeter De Schrijver /* pll_ref */ 66de4f30fdSPeter De Schrijver val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; 67de4f30fdSPeter De Schrijver pll_ref_div = 1 << val; 6863cc5a4dSThierry Reding dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, clks); 69de4f30fdSPeter De Schrijver if (!dt_clk) 70de4f30fdSPeter De Schrijver return 0; 71de4f30fdSPeter De Schrijver 7263cc5a4dSThierry Reding clk = clk_register_fixed_factor(NULL, "pll_ref", "osc", 73de4f30fdSPeter De Schrijver 0, 1, pll_ref_div); 74de4f30fdSPeter De Schrijver *dt_clk = clk; 75de4f30fdSPeter De Schrijver 76de4f30fdSPeter De Schrijver if (pll_ref_freq) 77de4f30fdSPeter De Schrijver *pll_ref_freq = *osc_freq / pll_ref_div; 78de4f30fdSPeter De Schrijver 79de4f30fdSPeter De Schrijver return 0; 80de4f30fdSPeter De Schrijver } 81de4f30fdSPeter De Schrijver 82de4f30fdSPeter De Schrijver void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks) 83de4f30fdSPeter De Schrijver { 84de4f30fdSPeter De Schrijver struct clk *clk; 85de4f30fdSPeter De Schrijver struct clk **dt_clk; 86de4f30fdSPeter De Schrijver 87de4f30fdSPeter De Schrijver /* clk_32k */ 88de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks); 89de4f30fdSPeter De Schrijver if (dt_clk) { 90*f6da46a3SStephen Boyd clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, 0, 32768); 91de4f30fdSPeter De Schrijver *dt_clk = clk; 92de4f30fdSPeter De Schrijver } 93de4f30fdSPeter De Schrijver 94de4f30fdSPeter De Schrijver /* clk_m_div2 */ 95de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div2, tegra_clks); 96de4f30fdSPeter De Schrijver if (dt_clk) { 97de4f30fdSPeter De Schrijver clk = clk_register_fixed_factor(NULL, "clk_m_div2", "clk_m", 98de4f30fdSPeter De Schrijver CLK_SET_RATE_PARENT, 1, 2); 99de4f30fdSPeter De Schrijver *dt_clk = clk; 100de4f30fdSPeter De Schrijver } 101de4f30fdSPeter De Schrijver 102de4f30fdSPeter De Schrijver /* clk_m_div4 */ 103de4f30fdSPeter De Schrijver dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m_div4, tegra_clks); 104de4f30fdSPeter De Schrijver if (dt_clk) { 105de4f30fdSPeter De Schrijver clk = clk_register_fixed_factor(NULL, "clk_m_div4", "clk_m", 106de4f30fdSPeter De Schrijver CLK_SET_RATE_PARENT, 1, 4); 107de4f30fdSPeter De Schrijver *dt_clk = clk; 108de4f30fdSPeter De Schrijver } 109de4f30fdSPeter De Schrijver } 110de4f30fdSPeter De Schrijver 111