119 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.4 */5 6#include <linux/io.h>7#include <linux/clk-provider.h>8#include <linux/of.h>9#include <linux/of_address.h>10#include <linux/delay.h>11#include <linux/export.h>12#include <linux/clk/tegra.h>13 14#include "clk.h"15#include "clk-id.h"16 17#define OSC_CTRL 0x5018#define OSC_CTRL_OSC_FREQ_SHIFT 2819#define OSC_CTRL_PLL_REF_DIV_SHIFT 2620#define OSC_CTRL_MASK (0x3f2 | \21 (0xf << OSC_CTRL_OSC_FREQ_SHIFT))22 23static u32 osc_ctrl_ctx;24 25int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,26 unsigned long *input_freqs, unsigned int num,27 unsigned int clk_m_div, unsigned long *osc_freq,28 unsigned long *pll_ref_freq)29{30 struct clk *clk, *osc;31 struct clk **dt_clk;32 u32 val, pll_ref_div;33 unsigned osc_idx;34 35 val = readl_relaxed(clk_base + OSC_CTRL);36 osc_ctrl_ctx = val & OSC_CTRL_MASK;37 osc_idx = val >> OSC_CTRL_OSC_FREQ_SHIFT;38 39 if (osc_idx < num)40 *osc_freq = input_freqs[osc_idx];41 else42 *osc_freq = 0;43 44 if (!*osc_freq) {45 WARN_ON(1);46 return -EINVAL;47 }48 49 dt_clk = tegra_lookup_dt_id(tegra_clk_osc, clks);50 if (!dt_clk)51 return 0;52 53 osc = clk_register_fixed_rate(NULL, "osc", NULL, 0, *osc_freq);54 *dt_clk = osc;55 56 /* osc_div2 */57 dt_clk = tegra_lookup_dt_id(tegra_clk_osc_div2, clks);58 if (dt_clk) {59 clk = clk_register_fixed_factor(NULL, "osc_div2", "osc",60 0, 1, 2);61 *dt_clk = clk;62 }63 64 /* osc_div4 */65 dt_clk = tegra_lookup_dt_id(tegra_clk_osc_div4, clks);66 if (dt_clk) {67 clk = clk_register_fixed_factor(NULL, "osc_div4", "osc",68 0, 1, 4);69 *dt_clk = clk;70 }71 72 dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, clks);73 if (!dt_clk)74 return 0;75 76 clk = clk_register_fixed_factor(NULL, "clk_m", "osc",77 0, 1, clk_m_div);78 *dt_clk = clk;79 80 /* pll_ref */81 val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;82 pll_ref_div = 1 << val;83 dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, clks);84 if (!dt_clk)85 return 0;86 87 clk = clk_register_fixed_factor(NULL, "pll_ref", "osc",88 0, 1, pll_ref_div);89 *dt_clk = clk;90 91 if (pll_ref_freq)92 *pll_ref_freq = *osc_freq / pll_ref_div;93 94 return 0;95}96 97void __init tegra_fixed_clk_init(struct tegra_clk *tegra_clks)98{99 struct clk *clk;100 struct clk **dt_clk;101 102 /* clk_32k */103 dt_clk = tegra_lookup_dt_id(tegra_clk_clk_32k, tegra_clks);104 if (dt_clk) {105 clk = clk_register_fixed_rate(NULL, "clk_32k", NULL, 0, 32768);106 *dt_clk = clk;107 }108}109 110void tegra_clk_osc_resume(void __iomem *clk_base)111{112 u32 val;113 114 val = readl_relaxed(clk_base + OSC_CTRL) & ~OSC_CTRL_MASK;115 val |= osc_ctrl_ctx;116 writel_relaxed(val, clk_base + OSC_CTRL);117 fence_udelay(2, clk_base);118}119