Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  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			0x50
 18#define OSC_CTRL_OSC_FREQ_SHIFT		28
 19#define OSC_CTRL_PLL_REF_DIV_SHIFT	26
 20#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	else
 42		*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}