18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Clock and PLL control for C64x+ devices
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2010, 2011 Texas Instruments.
68c2ecf20Sopenharmony_ci * Contributed by: Mark Salter <msalter@redhat.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Copied heavily from arm/mach-davinci/clock.c, so:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Copyright (C) 2006-2007 Texas Instruments.
118c2ecf20Sopenharmony_ci * Copyright (C) 2008-2009 Deep Root Systems, LLC
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/clkdev.h>
168c2ecf20Sopenharmony_ci#include <linux/clk.h>
178c2ecf20Sopenharmony_ci#include <linux/io.h>
188c2ecf20Sopenharmony_ci#include <linux/err.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include <asm/clock.h>
218c2ecf20Sopenharmony_ci#include <asm/soc.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic LIST_HEAD(clocks);
248c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(clocks_mutex);
258c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(clockfw_lock);
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic void __clk_enable(struct clk *clk)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	if (clk->parent)
308c2ecf20Sopenharmony_ci		__clk_enable(clk->parent);
318c2ecf20Sopenharmony_ci	clk->usecount++;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistatic void __clk_disable(struct clk *clk)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	if (WARN_ON(clk->usecount == 0))
378c2ecf20Sopenharmony_ci		return;
388c2ecf20Sopenharmony_ci	--clk->usecount;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	if (clk->parent)
418c2ecf20Sopenharmony_ci		__clk_disable(clk->parent);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint clk_enable(struct clk *clk)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	unsigned long flags;
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
498c2ecf20Sopenharmony_ci		return -EINVAL;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	spin_lock_irqsave(&clockfw_lock, flags);
528c2ecf20Sopenharmony_ci	__clk_enable(clk);
538c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&clockfw_lock, flags);
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	return 0;
568c2ecf20Sopenharmony_ci}
578c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_enable);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_civoid clk_disable(struct clk *clk)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	unsigned long flags;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
648c2ecf20Sopenharmony_ci		return;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	spin_lock_irqsave(&clockfw_lock, flags);
678c2ecf20Sopenharmony_ci	__clk_disable(clk);
688c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&clockfw_lock, flags);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_disable);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ciunsigned long clk_get_rate(struct clk *clk)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
758c2ecf20Sopenharmony_ci		return -EINVAL;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return clk->rate;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_get_rate);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cilong clk_round_rate(struct clk *clk, unsigned long rate)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
848c2ecf20Sopenharmony_ci		return -EINVAL;
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (clk->round_rate)
878c2ecf20Sopenharmony_ci		return clk->round_rate(clk, rate);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	return clk->rate;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_round_rate);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci/* Propagate rate to children */
948c2ecf20Sopenharmony_cistatic void propagate_rate(struct clk *root)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	struct clk *clk;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	list_for_each_entry(clk, &root->children, childnode) {
998c2ecf20Sopenharmony_ci		if (clk->recalc)
1008c2ecf20Sopenharmony_ci			clk->rate = clk->recalc(clk);
1018c2ecf20Sopenharmony_ci		propagate_rate(clk);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ciint clk_set_rate(struct clk *clk, unsigned long rate)
1068c2ecf20Sopenharmony_ci{
1078c2ecf20Sopenharmony_ci	unsigned long flags;
1088c2ecf20Sopenharmony_ci	int ret = -EINVAL;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
1118c2ecf20Sopenharmony_ci		return ret;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	if (clk->set_rate)
1148c2ecf20Sopenharmony_ci		ret = clk->set_rate(clk, rate);
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	spin_lock_irqsave(&clockfw_lock, flags);
1178c2ecf20Sopenharmony_ci	if (ret == 0) {
1188c2ecf20Sopenharmony_ci		if (clk->recalc)
1198c2ecf20Sopenharmony_ci			clk->rate = clk->recalc(clk);
1208c2ecf20Sopenharmony_ci		propagate_rate(clk);
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&clockfw_lock, flags);
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	return ret;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_set_rate);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ciint clk_set_parent(struct clk *clk, struct clk *parent)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	unsigned long flags;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
1338c2ecf20Sopenharmony_ci		return -EINVAL;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	/* Cannot change parent on enabled clock */
1368c2ecf20Sopenharmony_ci	if (WARN_ON(clk->usecount))
1378c2ecf20Sopenharmony_ci		return -EINVAL;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	mutex_lock(&clocks_mutex);
1408c2ecf20Sopenharmony_ci	clk->parent = parent;
1418c2ecf20Sopenharmony_ci	list_del_init(&clk->childnode);
1428c2ecf20Sopenharmony_ci	list_add(&clk->childnode, &clk->parent->children);
1438c2ecf20Sopenharmony_ci	mutex_unlock(&clocks_mutex);
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	spin_lock_irqsave(&clockfw_lock, flags);
1468c2ecf20Sopenharmony_ci	if (clk->recalc)
1478c2ecf20Sopenharmony_ci		clk->rate = clk->recalc(clk);
1488c2ecf20Sopenharmony_ci	propagate_rate(clk);
1498c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&clockfw_lock, flags);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_set_parent);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ciint clk_register(struct clk *clk)
1568c2ecf20Sopenharmony_ci{
1578c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
1588c2ecf20Sopenharmony_ci		return -EINVAL;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (WARN(clk->parent && !clk->parent->rate,
1618c2ecf20Sopenharmony_ci		 "CLK: %s parent %s has no rate!\n",
1628c2ecf20Sopenharmony_ci		 clk->name, clk->parent->name))
1638c2ecf20Sopenharmony_ci		return -EINVAL;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	mutex_lock(&clocks_mutex);
1668c2ecf20Sopenharmony_ci	list_add_tail(&clk->node, &clocks);
1678c2ecf20Sopenharmony_ci	if (clk->parent)
1688c2ecf20Sopenharmony_ci		list_add_tail(&clk->childnode, &clk->parent->children);
1698c2ecf20Sopenharmony_ci	mutex_unlock(&clocks_mutex);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/* If rate is already set, use it */
1728c2ecf20Sopenharmony_ci	if (clk->rate)
1738c2ecf20Sopenharmony_ci		return 0;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	/* Else, see if there is a way to calculate it */
1768c2ecf20Sopenharmony_ci	if (clk->recalc)
1778c2ecf20Sopenharmony_ci		clk->rate = clk->recalc(clk);
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	/* Otherwise, default to parent rate */
1808c2ecf20Sopenharmony_ci	else if (clk->parent)
1818c2ecf20Sopenharmony_ci		clk->rate = clk->parent->rate;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return 0;
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_register);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_civoid clk_unregister(struct clk *clk)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	if (clk == NULL || IS_ERR(clk))
1908c2ecf20Sopenharmony_ci		return;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	mutex_lock(&clocks_mutex);
1938c2ecf20Sopenharmony_ci	list_del(&clk->node);
1948c2ecf20Sopenharmony_ci	list_del(&clk->childnode);
1958c2ecf20Sopenharmony_ci	mutex_unlock(&clocks_mutex);
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL(clk_unregister);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_cistatic u32 pll_read(struct pll_data *pll, int reg)
2018c2ecf20Sopenharmony_ci{
2028c2ecf20Sopenharmony_ci	return soc_readl(pll->base + reg);
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_cistatic unsigned long clk_sysclk_recalc(struct clk *clk)
2068c2ecf20Sopenharmony_ci{
2078c2ecf20Sopenharmony_ci	u32 v, plldiv = 0;
2088c2ecf20Sopenharmony_ci	struct pll_data *pll;
2098c2ecf20Sopenharmony_ci	unsigned long rate = clk->rate;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (WARN_ON(!clk->parent))
2128c2ecf20Sopenharmony_ci		return rate;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	rate = clk->parent->rate;
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	/* the parent must be a PLL */
2178c2ecf20Sopenharmony_ci	if (WARN_ON(!clk->parent->pll_data))
2188c2ecf20Sopenharmony_ci		return rate;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	pll = clk->parent->pll_data;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	/* If pre-PLL, source clock is before the multiplier and divider(s) */
2238c2ecf20Sopenharmony_ci	if (clk->flags & PRE_PLL)
2248c2ecf20Sopenharmony_ci		rate = pll->input_rate;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (!clk->div) {
2278c2ecf20Sopenharmony_ci		pr_debug("%s: (no divider) rate = %lu KHz\n",
2288c2ecf20Sopenharmony_ci			 clk->name, rate / 1000);
2298c2ecf20Sopenharmony_ci		return rate;
2308c2ecf20Sopenharmony_ci	}
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	if (clk->flags & FIXED_DIV_PLL) {
2338c2ecf20Sopenharmony_ci		rate /= clk->div;
2348c2ecf20Sopenharmony_ci		pr_debug("%s: (fixed divide by %d) rate = %lu KHz\n",
2358c2ecf20Sopenharmony_ci			 clk->name, clk->div, rate / 1000);
2368c2ecf20Sopenharmony_ci		return rate;
2378c2ecf20Sopenharmony_ci	}
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	v = pll_read(pll, clk->div);
2408c2ecf20Sopenharmony_ci	if (v & PLLDIV_EN)
2418c2ecf20Sopenharmony_ci		plldiv = (v & PLLDIV_RATIO_MASK) + 1;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	if (plldiv == 0)
2448c2ecf20Sopenharmony_ci		plldiv = 1;
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	rate /= plldiv;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	pr_debug("%s: (divide by %d) rate = %lu KHz\n",
2498c2ecf20Sopenharmony_ci		 clk->name, plldiv, rate / 1000);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return rate;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic unsigned long clk_leafclk_recalc(struct clk *clk)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	if (WARN_ON(!clk->parent))
2578c2ecf20Sopenharmony_ci		return clk->rate;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	pr_debug("%s: (parent %s) rate = %lu KHz\n",
2608c2ecf20Sopenharmony_ci		 clk->name, clk->parent->name,	clk->parent->rate / 1000);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return clk->parent->rate;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic unsigned long clk_pllclk_recalc(struct clk *clk)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	u32 ctrl, mult = 0, prediv = 0, postdiv = 0;
2688c2ecf20Sopenharmony_ci	u8 bypass;
2698c2ecf20Sopenharmony_ci	struct pll_data *pll = clk->pll_data;
2708c2ecf20Sopenharmony_ci	unsigned long rate = clk->rate;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	if (clk->flags & FIXED_RATE_PLL)
2738c2ecf20Sopenharmony_ci		return rate;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	ctrl = pll_read(pll, PLLCTL);
2768c2ecf20Sopenharmony_ci	rate = pll->input_rate = clk->parent->rate;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (ctrl & PLLCTL_PLLEN)
2798c2ecf20Sopenharmony_ci		bypass = 0;
2808c2ecf20Sopenharmony_ci	else
2818c2ecf20Sopenharmony_ci		bypass = 1;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci	if (pll->flags & PLL_HAS_MUL) {
2848c2ecf20Sopenharmony_ci		mult = pll_read(pll, PLLM);
2858c2ecf20Sopenharmony_ci		mult = (mult & PLLM_PLLM_MASK) + 1;
2868c2ecf20Sopenharmony_ci	}
2878c2ecf20Sopenharmony_ci	if (pll->flags & PLL_HAS_PRE) {
2888c2ecf20Sopenharmony_ci		prediv = pll_read(pll, PLLPRE);
2898c2ecf20Sopenharmony_ci		if (prediv & PLLDIV_EN)
2908c2ecf20Sopenharmony_ci			prediv = (prediv & PLLDIV_RATIO_MASK) + 1;
2918c2ecf20Sopenharmony_ci		else
2928c2ecf20Sopenharmony_ci			prediv = 0;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci	if (pll->flags & PLL_HAS_POST) {
2958c2ecf20Sopenharmony_ci		postdiv = pll_read(pll, PLLPOST);
2968c2ecf20Sopenharmony_ci		if (postdiv & PLLDIV_EN)
2978c2ecf20Sopenharmony_ci			postdiv = (postdiv & PLLDIV_RATIO_MASK) + 1;
2988c2ecf20Sopenharmony_ci		else
2998c2ecf20Sopenharmony_ci			postdiv = 1;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	if (!bypass) {
3038c2ecf20Sopenharmony_ci		if (prediv)
3048c2ecf20Sopenharmony_ci			rate /= prediv;
3058c2ecf20Sopenharmony_ci		if (mult)
3068c2ecf20Sopenharmony_ci			rate *= mult;
3078c2ecf20Sopenharmony_ci		if (postdiv)
3088c2ecf20Sopenharmony_ci			rate /= postdiv;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci		pr_debug("PLL%d: input = %luMHz, pre[%d] mul[%d] post[%d] "
3118c2ecf20Sopenharmony_ci			 "--> %luMHz output.\n",
3128c2ecf20Sopenharmony_ci			 pll->num, clk->parent->rate / 1000000,
3138c2ecf20Sopenharmony_ci			 prediv, mult, postdiv, rate / 1000000);
3148c2ecf20Sopenharmony_ci	} else
3158c2ecf20Sopenharmony_ci		pr_debug("PLL%d: input = %luMHz, bypass mode.\n",
3168c2ecf20Sopenharmony_ci			 pll->num, clk->parent->rate / 1000000);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return rate;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic void __init __init_clk(struct clk *clk)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&clk->node);
3258c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&clk->children);
3268c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&clk->childnode);
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	if (!clk->recalc) {
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci		/* Check if clock is a PLL */
3318c2ecf20Sopenharmony_ci		if (clk->pll_data)
3328c2ecf20Sopenharmony_ci			clk->recalc = clk_pllclk_recalc;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		/* Else, if it is a PLL-derived clock */
3358c2ecf20Sopenharmony_ci		else if (clk->flags & CLK_PLL)
3368c2ecf20Sopenharmony_ci			clk->recalc = clk_sysclk_recalc;
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci		/* Otherwise, it is a leaf clock (PSC clock) */
3398c2ecf20Sopenharmony_ci		else if (clk->parent)
3408c2ecf20Sopenharmony_ci			clk->recalc = clk_leafclk_recalc;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_civoid __init c6x_clks_init(struct clk_lookup *clocks)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct clk_lookup *c;
3478c2ecf20Sopenharmony_ci	struct clk *clk;
3488c2ecf20Sopenharmony_ci	size_t num_clocks = 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	for (c = clocks; c->clk; c++) {
3518c2ecf20Sopenharmony_ci		clk = c->clk;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci		__init_clk(clk);
3548c2ecf20Sopenharmony_ci		clk_register(clk);
3558c2ecf20Sopenharmony_ci		num_clocks++;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci		/* Turn on clocks that Linux doesn't otherwise manage */
3588c2ecf20Sopenharmony_ci		if (clk->flags & ALWAYS_ENABLED)
3598c2ecf20Sopenharmony_ci			clk_enable(clk);
3608c2ecf20Sopenharmony_ci	}
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	clkdev_add_table(clocks, num_clocks);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
3688c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci#define CLKNAME_MAX	10		/* longest clock name */
3718c2ecf20Sopenharmony_ci#define NEST_DELTA	2
3728c2ecf20Sopenharmony_ci#define NEST_MAX	4
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic void
3758c2ecf20Sopenharmony_cidump_clock(struct seq_file *s, unsigned nest, struct clk *parent)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	char		*state;
3788c2ecf20Sopenharmony_ci	char		buf[CLKNAME_MAX + NEST_DELTA * NEST_MAX];
3798c2ecf20Sopenharmony_ci	struct clk	*clk;
3808c2ecf20Sopenharmony_ci	unsigned	i;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	if (parent->flags & CLK_PLL)
3838c2ecf20Sopenharmony_ci		state = "pll";
3848c2ecf20Sopenharmony_ci	else
3858c2ecf20Sopenharmony_ci		state = "";
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	/* <nest spaces> name <pad to end> */
3888c2ecf20Sopenharmony_ci	memset(buf, ' ', sizeof(buf) - 1);
3898c2ecf20Sopenharmony_ci	buf[sizeof(buf) - 1] = 0;
3908c2ecf20Sopenharmony_ci	i = strlen(parent->name);
3918c2ecf20Sopenharmony_ci	memcpy(buf + nest, parent->name,
3928c2ecf20Sopenharmony_ci	       min(i, (unsigned)(sizeof(buf) - 1 - nest)));
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	seq_printf(s, "%s users=%2d %-3s %9ld Hz\n",
3958c2ecf20Sopenharmony_ci		   buf, parent->usecount, state, clk_get_rate(parent));
3968c2ecf20Sopenharmony_ci	/* REVISIT show device associations too */
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	/* cost is now small, but not linear... */
3998c2ecf20Sopenharmony_ci	list_for_each_entry(clk, &parent->children, childnode) {
4008c2ecf20Sopenharmony_ci		dump_clock(s, nest + NEST_DELTA, clk);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic int c6x_ck_show(struct seq_file *m, void *v)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct clk *clk;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	/*
4098c2ecf20Sopenharmony_ci	 * Show clock tree; We trust nonzero usecounts equate to PSC enables...
4108c2ecf20Sopenharmony_ci	 */
4118c2ecf20Sopenharmony_ci	mutex_lock(&clocks_mutex);
4128c2ecf20Sopenharmony_ci	list_for_each_entry(clk, &clocks, node)
4138c2ecf20Sopenharmony_ci		if (!clk->parent)
4148c2ecf20Sopenharmony_ci			dump_clock(m, 0, clk);
4158c2ecf20Sopenharmony_ci	mutex_unlock(&clocks_mutex);
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	return 0;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_cistatic int c6x_ck_open(struct inode *inode, struct file *file)
4218c2ecf20Sopenharmony_ci{
4228c2ecf20Sopenharmony_ci	return single_open(file, c6x_ck_show, NULL);
4238c2ecf20Sopenharmony_ci}
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_cistatic const struct file_operations c6x_ck_operations = {
4268c2ecf20Sopenharmony_ci	.open		= c6x_ck_open,
4278c2ecf20Sopenharmony_ci	.read		= seq_read,
4288c2ecf20Sopenharmony_ci	.llseek		= seq_lseek,
4298c2ecf20Sopenharmony_ci	.release	= single_release,
4308c2ecf20Sopenharmony_ci};
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_cistatic int __init c6x_clk_debugfs_init(void)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	debugfs_create_file("c6x_clocks", S_IFREG | S_IRUGO, NULL, NULL,
4358c2ecf20Sopenharmony_ci			    &c6x_ck_operations);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	return 0;
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_cidevice_initcall(c6x_clk_debugfs_init);
4408c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */
441