18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * SuperH clock framework 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2005 - 2010 Paul Mundt 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This clock framework is derived from the OMAP version by: 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2004 - 2008 Nokia Corporation 98c2ecf20Sopenharmony_ci * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 148c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 158c2ecf20Sopenharmony_ci * for more details. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "clock: " fmt 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/init.h> 218c2ecf20Sopenharmony_ci#include <linux/module.h> 228c2ecf20Sopenharmony_ci#include <linux/mutex.h> 238c2ecf20Sopenharmony_ci#include <linux/list.h> 248c2ecf20Sopenharmony_ci#include <linux/syscore_ops.h> 258c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 268c2ecf20Sopenharmony_ci#include <linux/err.h> 278c2ecf20Sopenharmony_ci#include <linux/io.h> 288c2ecf20Sopenharmony_ci#include <linux/cpufreq.h> 298c2ecf20Sopenharmony_ci#include <linux/clk.h> 308c2ecf20Sopenharmony_ci#include <linux/sh_clk.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic LIST_HEAD(clock_list); 338c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(clock_lock); 348c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(clock_list_sem); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* clock disable operations are not passed on to hardware during boot */ 378c2ecf20Sopenharmony_cistatic int allow_disable; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_civoid clk_rate_table_build(struct clk *clk, 408c2ecf20Sopenharmony_ci struct cpufreq_frequency_table *freq_table, 418c2ecf20Sopenharmony_ci int nr_freqs, 428c2ecf20Sopenharmony_ci struct clk_div_mult_table *src_table, 438c2ecf20Sopenharmony_ci unsigned long *bitmap) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci unsigned long mult, div; 468c2ecf20Sopenharmony_ci unsigned long freq; 478c2ecf20Sopenharmony_ci int i; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci clk->nr_freqs = nr_freqs; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci for (i = 0; i < nr_freqs; i++) { 528c2ecf20Sopenharmony_ci div = 1; 538c2ecf20Sopenharmony_ci mult = 1; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci if (src_table->divisors && i < src_table->nr_divisors) 568c2ecf20Sopenharmony_ci div = src_table->divisors[i]; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (src_table->multipliers && i < src_table->nr_multipliers) 598c2ecf20Sopenharmony_ci mult = src_table->multipliers[i]; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci if (!div || !mult || (bitmap && !test_bit(i, bitmap))) 628c2ecf20Sopenharmony_ci freq = CPUFREQ_ENTRY_INVALID; 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci freq = clk->parent->rate * mult / div; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci freq_table[i].driver_data = i; 678c2ecf20Sopenharmony_ci freq_table[i].frequency = freq; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Termination entry */ 718c2ecf20Sopenharmony_ci freq_table[i].driver_data = i; 728c2ecf20Sopenharmony_ci freq_table[i].frequency = CPUFREQ_TABLE_END; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistruct clk_rate_round_data; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistruct clk_rate_round_data { 788c2ecf20Sopenharmony_ci unsigned long rate; 798c2ecf20Sopenharmony_ci unsigned int min, max; 808c2ecf20Sopenharmony_ci long (*func)(unsigned int, struct clk_rate_round_data *); 818c2ecf20Sopenharmony_ci void *arg; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define for_each_frequency(pos, r, freq) \ 858c2ecf20Sopenharmony_ci for (pos = r->min, freq = r->func(pos, r); \ 868c2ecf20Sopenharmony_ci pos <= r->max; pos++, freq = r->func(pos, r)) \ 878c2ecf20Sopenharmony_ci if (unlikely(freq == 0)) \ 888c2ecf20Sopenharmony_ci ; \ 898c2ecf20Sopenharmony_ci else 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic long clk_rate_round_helper(struct clk_rate_round_data *rounder) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci unsigned long rate_error, rate_error_prev = ~0UL; 948c2ecf20Sopenharmony_ci unsigned long highest, lowest, freq; 958c2ecf20Sopenharmony_ci long rate_best_fit = -ENOENT; 968c2ecf20Sopenharmony_ci int i; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci highest = 0; 998c2ecf20Sopenharmony_ci lowest = ~0UL; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for_each_frequency(i, rounder, freq) { 1028c2ecf20Sopenharmony_ci if (freq > highest) 1038c2ecf20Sopenharmony_ci highest = freq; 1048c2ecf20Sopenharmony_ci if (freq < lowest) 1058c2ecf20Sopenharmony_ci lowest = freq; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci rate_error = abs(freq - rounder->rate); 1088c2ecf20Sopenharmony_ci if (rate_error < rate_error_prev) { 1098c2ecf20Sopenharmony_ci rate_best_fit = freq; 1108c2ecf20Sopenharmony_ci rate_error_prev = rate_error; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (rate_error == 0) 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci if (rounder->rate >= highest) 1188c2ecf20Sopenharmony_ci rate_best_fit = highest; 1198c2ecf20Sopenharmony_ci if (rounder->rate <= lowest) 1208c2ecf20Sopenharmony_ci rate_best_fit = lowest; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci return rate_best_fit; 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic long clk_rate_table_iter(unsigned int pos, 1268c2ecf20Sopenharmony_ci struct clk_rate_round_data *rounder) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct cpufreq_frequency_table *freq_table = rounder->arg; 1298c2ecf20Sopenharmony_ci unsigned long freq = freq_table[pos].frequency; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (freq == CPUFREQ_ENTRY_INVALID) 1328c2ecf20Sopenharmony_ci freq = 0; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return freq; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cilong clk_rate_table_round(struct clk *clk, 1388c2ecf20Sopenharmony_ci struct cpufreq_frequency_table *freq_table, 1398c2ecf20Sopenharmony_ci unsigned long rate) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct clk_rate_round_data table_round = { 1428c2ecf20Sopenharmony_ci .min = 0, 1438c2ecf20Sopenharmony_ci .max = clk->nr_freqs - 1, 1448c2ecf20Sopenharmony_ci .func = clk_rate_table_iter, 1458c2ecf20Sopenharmony_ci .arg = freq_table, 1468c2ecf20Sopenharmony_ci .rate = rate, 1478c2ecf20Sopenharmony_ci }; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (clk->nr_freqs < 1) 1508c2ecf20Sopenharmony_ci return -ENOSYS; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return clk_rate_round_helper(&table_round); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic long clk_rate_div_range_iter(unsigned int pos, 1568c2ecf20Sopenharmony_ci struct clk_rate_round_data *rounder) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci return clk_get_rate(rounder->arg) / pos; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cilong clk_rate_div_range_round(struct clk *clk, unsigned int div_min, 1628c2ecf20Sopenharmony_ci unsigned int div_max, unsigned long rate) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct clk_rate_round_data div_range_round = { 1658c2ecf20Sopenharmony_ci .min = div_min, 1668c2ecf20Sopenharmony_ci .max = div_max, 1678c2ecf20Sopenharmony_ci .func = clk_rate_div_range_iter, 1688c2ecf20Sopenharmony_ci .arg = clk_get_parent(clk), 1698c2ecf20Sopenharmony_ci .rate = rate, 1708c2ecf20Sopenharmony_ci }; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci return clk_rate_round_helper(&div_range_round); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic long clk_rate_mult_range_iter(unsigned int pos, 1768c2ecf20Sopenharmony_ci struct clk_rate_round_data *rounder) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return clk_get_rate(rounder->arg) * pos; 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cilong clk_rate_mult_range_round(struct clk *clk, unsigned int mult_min, 1828c2ecf20Sopenharmony_ci unsigned int mult_max, unsigned long rate) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct clk_rate_round_data mult_range_round = { 1858c2ecf20Sopenharmony_ci .min = mult_min, 1868c2ecf20Sopenharmony_ci .max = mult_max, 1878c2ecf20Sopenharmony_ci .func = clk_rate_mult_range_iter, 1888c2ecf20Sopenharmony_ci .arg = clk_get_parent(clk), 1898c2ecf20Sopenharmony_ci .rate = rate, 1908c2ecf20Sopenharmony_ci }; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci return clk_rate_round_helper(&mult_range_round); 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ciint clk_rate_table_find(struct clk *clk, 1968c2ecf20Sopenharmony_ci struct cpufreq_frequency_table *freq_table, 1978c2ecf20Sopenharmony_ci unsigned long rate) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci struct cpufreq_frequency_table *pos; 2008c2ecf20Sopenharmony_ci int idx; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci cpufreq_for_each_valid_entry_idx(pos, freq_table, idx) 2038c2ecf20Sopenharmony_ci if (pos->frequency == rate) 2048c2ecf20Sopenharmony_ci return idx; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return -ENOENT; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci/* Used for clocks that always have same value as the parent clock */ 2108c2ecf20Sopenharmony_ciunsigned long followparent_recalc(struct clk *clk) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci return clk->parent ? clk->parent->rate : 0; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciint clk_reparent(struct clk *child, struct clk *parent) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci list_del_init(&child->sibling); 2188c2ecf20Sopenharmony_ci if (parent) 2198c2ecf20Sopenharmony_ci list_add(&child->sibling, &parent->children); 2208c2ecf20Sopenharmony_ci child->parent = parent; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* Propagate rate to children */ 2268c2ecf20Sopenharmony_civoid propagate_rate(struct clk *tclk) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct clk *clkp; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci list_for_each_entry(clkp, &tclk->children, sibling) { 2318c2ecf20Sopenharmony_ci if (clkp->ops && clkp->ops->recalc) 2328c2ecf20Sopenharmony_ci clkp->rate = clkp->ops->recalc(clkp); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci propagate_rate(clkp); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic void __clk_disable(struct clk *clk) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci if (WARN(!clk->usecount, "Trying to disable clock %p with 0 usecount\n", 2418c2ecf20Sopenharmony_ci clk)) 2428c2ecf20Sopenharmony_ci return; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci if (!(--clk->usecount)) { 2458c2ecf20Sopenharmony_ci if (likely(allow_disable && clk->ops && clk->ops->disable)) 2468c2ecf20Sopenharmony_ci clk->ops->disable(clk); 2478c2ecf20Sopenharmony_ci if (likely(clk->parent)) 2488c2ecf20Sopenharmony_ci __clk_disable(clk->parent); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_civoid clk_disable(struct clk *clk) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci unsigned long flags; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!clk) 2578c2ecf20Sopenharmony_ci return; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci spin_lock_irqsave(&clock_lock, flags); 2608c2ecf20Sopenharmony_ci __clk_disable(clk); 2618c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clock_lock, flags); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_disable); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int __clk_enable(struct clk *clk) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci int ret = 0; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (clk->usecount++ == 0) { 2708c2ecf20Sopenharmony_ci if (clk->parent) { 2718c2ecf20Sopenharmony_ci ret = __clk_enable(clk->parent); 2728c2ecf20Sopenharmony_ci if (unlikely(ret)) 2738c2ecf20Sopenharmony_ci goto err; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (clk->ops && clk->ops->enable) { 2778c2ecf20Sopenharmony_ci ret = clk->ops->enable(clk); 2788c2ecf20Sopenharmony_ci if (ret) { 2798c2ecf20Sopenharmony_ci if (clk->parent) 2808c2ecf20Sopenharmony_ci __clk_disable(clk->parent); 2818c2ecf20Sopenharmony_ci goto err; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_cierr: 2888c2ecf20Sopenharmony_ci clk->usecount--; 2898c2ecf20Sopenharmony_ci return ret; 2908c2ecf20Sopenharmony_ci} 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ciint clk_enable(struct clk *clk) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci unsigned long flags; 2958c2ecf20Sopenharmony_ci int ret; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci if (!clk) 2988c2ecf20Sopenharmony_ci return -EINVAL; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci spin_lock_irqsave(&clock_lock, flags); 3018c2ecf20Sopenharmony_ci ret = __clk_enable(clk); 3028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clock_lock, flags); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_enable); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_cistatic LIST_HEAD(root_clks); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/** 3118c2ecf20Sopenharmony_ci * recalculate_root_clocks - recalculate and propagate all root clocks 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Recalculates all root clocks (clocks with no parent), which if the 3148c2ecf20Sopenharmony_ci * clock's .recalc is set correctly, should also propagate their rates. 3158c2ecf20Sopenharmony_ci * Called at init. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_civoid recalculate_root_clocks(void) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct clk *clkp; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci list_for_each_entry(clkp, &root_clks, sibling) { 3228c2ecf20Sopenharmony_ci if (clkp->ops && clkp->ops->recalc) 3238c2ecf20Sopenharmony_ci clkp->rate = clkp->ops->recalc(clkp); 3248c2ecf20Sopenharmony_ci propagate_rate(clkp); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_cistatic struct clk_mapping dummy_mapping; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic struct clk *lookup_root_clock(struct clk *clk) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci while (clk->parent) 3338c2ecf20Sopenharmony_ci clk = clk->parent; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return clk; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int clk_establish_mapping(struct clk *clk) 3398c2ecf20Sopenharmony_ci{ 3408c2ecf20Sopenharmony_ci struct clk_mapping *mapping = clk->mapping; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* 3438c2ecf20Sopenharmony_ci * Propagate mappings. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci if (!mapping) { 3468c2ecf20Sopenharmony_ci struct clk *clkp; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * dummy mapping for root clocks with no specified ranges 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_ci if (!clk->parent) { 3528c2ecf20Sopenharmony_ci clk->mapping = &dummy_mapping; 3538c2ecf20Sopenharmony_ci goto out; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* 3578c2ecf20Sopenharmony_ci * If we're on a child clock and it provides no mapping of its 3588c2ecf20Sopenharmony_ci * own, inherit the mapping from its root clock. 3598c2ecf20Sopenharmony_ci */ 3608c2ecf20Sopenharmony_ci clkp = lookup_root_clock(clk); 3618c2ecf20Sopenharmony_ci mapping = clkp->mapping; 3628c2ecf20Sopenharmony_ci BUG_ON(!mapping); 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* 3668c2ecf20Sopenharmony_ci * Establish initial mapping. 3678c2ecf20Sopenharmony_ci */ 3688c2ecf20Sopenharmony_ci if (!mapping->base && mapping->phys) { 3698c2ecf20Sopenharmony_ci kref_init(&mapping->ref); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci mapping->base = ioremap(mapping->phys, mapping->len); 3728c2ecf20Sopenharmony_ci if (unlikely(!mapping->base)) 3738c2ecf20Sopenharmony_ci return -ENXIO; 3748c2ecf20Sopenharmony_ci } else if (mapping->base) { 3758c2ecf20Sopenharmony_ci /* 3768c2ecf20Sopenharmony_ci * Bump the refcount for an existing mapping 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci kref_get(&mapping->ref); 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci clk->mapping = mapping; 3828c2ecf20Sopenharmony_ciout: 3838c2ecf20Sopenharmony_ci clk->mapped_reg = clk->mapping->base; 3848c2ecf20Sopenharmony_ci clk->mapped_reg += (phys_addr_t)clk->enable_reg - clk->mapping->phys; 3858c2ecf20Sopenharmony_ci return 0; 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic void clk_destroy_mapping(struct kref *kref) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct clk_mapping *mapping; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci mapping = container_of(kref, struct clk_mapping, ref); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci iounmap(mapping->base); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic void clk_teardown_mapping(struct clk *clk) 3988c2ecf20Sopenharmony_ci{ 3998c2ecf20Sopenharmony_ci struct clk_mapping *mapping = clk->mapping; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* Nothing to do */ 4028c2ecf20Sopenharmony_ci if (mapping == &dummy_mapping) 4038c2ecf20Sopenharmony_ci goto out; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci kref_put(&mapping->ref, clk_destroy_mapping); 4068c2ecf20Sopenharmony_ci clk->mapping = NULL; 4078c2ecf20Sopenharmony_ciout: 4088c2ecf20Sopenharmony_ci clk->mapped_reg = NULL; 4098c2ecf20Sopenharmony_ci} 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ciint clk_register(struct clk *clk) 4128c2ecf20Sopenharmony_ci{ 4138c2ecf20Sopenharmony_ci int ret; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(clk)) 4168c2ecf20Sopenharmony_ci return -EINVAL; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* 4198c2ecf20Sopenharmony_ci * trap out already registered clocks 4208c2ecf20Sopenharmony_ci */ 4218c2ecf20Sopenharmony_ci if (clk->node.next || clk->node.prev) 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci mutex_lock(&clock_list_sem); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&clk->children); 4278c2ecf20Sopenharmony_ci clk->usecount = 0; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ret = clk_establish_mapping(clk); 4308c2ecf20Sopenharmony_ci if (unlikely(ret)) 4318c2ecf20Sopenharmony_ci goto out_unlock; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci if (clk->parent) 4348c2ecf20Sopenharmony_ci list_add(&clk->sibling, &clk->parent->children); 4358c2ecf20Sopenharmony_ci else 4368c2ecf20Sopenharmony_ci list_add(&clk->sibling, &root_clks); 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci list_add(&clk->node, &clock_list); 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci#ifdef CONFIG_SH_CLK_CPG_LEGACY 4418c2ecf20Sopenharmony_ci if (clk->ops && clk->ops->init) 4428c2ecf20Sopenharmony_ci clk->ops->init(clk); 4438c2ecf20Sopenharmony_ci#endif 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciout_unlock: 4468c2ecf20Sopenharmony_ci mutex_unlock(&clock_list_sem); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci return ret; 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_register); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_civoid clk_unregister(struct clk *clk) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci mutex_lock(&clock_list_sem); 4558c2ecf20Sopenharmony_ci list_del(&clk->sibling); 4568c2ecf20Sopenharmony_ci list_del(&clk->node); 4578c2ecf20Sopenharmony_ci clk_teardown_mapping(clk); 4588c2ecf20Sopenharmony_ci mutex_unlock(&clock_list_sem); 4598c2ecf20Sopenharmony_ci} 4608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_unregister); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_civoid clk_enable_init_clocks(void) 4638c2ecf20Sopenharmony_ci{ 4648c2ecf20Sopenharmony_ci struct clk *clkp; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci list_for_each_entry(clkp, &clock_list, node) 4678c2ecf20Sopenharmony_ci if (clkp->flags & CLK_ENABLE_ON_INIT) 4688c2ecf20Sopenharmony_ci clk_enable(clkp); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ciunsigned long clk_get_rate(struct clk *clk) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci if (!clk) 4748c2ecf20Sopenharmony_ci return 0; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return clk->rate; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_get_rate); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ciint clk_set_rate(struct clk *clk, unsigned long rate) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 4838c2ecf20Sopenharmony_ci unsigned long flags; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci if (!clk) 4868c2ecf20Sopenharmony_ci return 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci spin_lock_irqsave(&clock_lock, flags); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (likely(clk->ops && clk->ops->set_rate)) { 4918c2ecf20Sopenharmony_ci ret = clk->ops->set_rate(clk, rate); 4928c2ecf20Sopenharmony_ci if (ret != 0) 4938c2ecf20Sopenharmony_ci goto out_unlock; 4948c2ecf20Sopenharmony_ci } else { 4958c2ecf20Sopenharmony_ci clk->rate = rate; 4968c2ecf20Sopenharmony_ci ret = 0; 4978c2ecf20Sopenharmony_ci } 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci if (clk->ops && clk->ops->recalc) 5008c2ecf20Sopenharmony_ci clk->rate = clk->ops->recalc(clk); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci propagate_rate(clk); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ciout_unlock: 5058c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clock_lock, flags); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return ret; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_set_rate); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ciint clk_set_parent(struct clk *clk, struct clk *parent) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci unsigned long flags; 5148c2ecf20Sopenharmony_ci int ret = -EINVAL; 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (!parent || !clk) 5178c2ecf20Sopenharmony_ci return ret; 5188c2ecf20Sopenharmony_ci if (clk->parent == parent) 5198c2ecf20Sopenharmony_ci return 0; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci spin_lock_irqsave(&clock_lock, flags); 5228c2ecf20Sopenharmony_ci if (clk->usecount == 0) { 5238c2ecf20Sopenharmony_ci if (clk->ops->set_parent) 5248c2ecf20Sopenharmony_ci ret = clk->ops->set_parent(clk, parent); 5258c2ecf20Sopenharmony_ci else 5268c2ecf20Sopenharmony_ci ret = clk_reparent(clk, parent); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci if (ret == 0) { 5298c2ecf20Sopenharmony_ci if (clk->ops->recalc) 5308c2ecf20Sopenharmony_ci clk->rate = clk->ops->recalc(clk); 5318c2ecf20Sopenharmony_ci pr_debug("set parent of %p to %p (new rate %ld)\n", 5328c2ecf20Sopenharmony_ci clk, clk->parent, clk->rate); 5338c2ecf20Sopenharmony_ci propagate_rate(clk); 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci } else 5368c2ecf20Sopenharmony_ci ret = -EBUSY; 5378c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clock_lock, flags); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return ret; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_set_parent); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistruct clk *clk_get_parent(struct clk *clk) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci if (!clk) 5468c2ecf20Sopenharmony_ci return NULL; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return clk->parent; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_get_parent); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_cilong clk_round_rate(struct clk *clk, unsigned long rate) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci if (!clk) 5558c2ecf20Sopenharmony_ci return 0; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (likely(clk->ops && clk->ops->round_rate)) { 5588c2ecf20Sopenharmony_ci unsigned long flags, rounded; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci spin_lock_irqsave(&clock_lock, flags); 5618c2ecf20Sopenharmony_ci rounded = clk->ops->round_rate(clk, rate); 5628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clock_lock, flags); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci return rounded; 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci return clk_get_rate(clk); 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_round_rate); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5728c2ecf20Sopenharmony_cistatic void clks_core_resume(void) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct clk *clkp; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci list_for_each_entry(clkp, &clock_list, node) { 5778c2ecf20Sopenharmony_ci if (likely(clkp->usecount && clkp->ops)) { 5788c2ecf20Sopenharmony_ci unsigned long rate = clkp->rate; 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci if (likely(clkp->ops->set_parent)) 5818c2ecf20Sopenharmony_ci clkp->ops->set_parent(clkp, 5828c2ecf20Sopenharmony_ci clkp->parent); 5838c2ecf20Sopenharmony_ci if (likely(clkp->ops->set_rate)) 5848c2ecf20Sopenharmony_ci clkp->ops->set_rate(clkp, rate); 5858c2ecf20Sopenharmony_ci else if (likely(clkp->ops->recalc)) 5868c2ecf20Sopenharmony_ci clkp->rate = clkp->ops->recalc(clkp); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci} 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_cistatic struct syscore_ops clks_syscore_ops = { 5928c2ecf20Sopenharmony_ci .resume = clks_core_resume, 5938c2ecf20Sopenharmony_ci}; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic int __init clk_syscore_init(void) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci register_syscore_ops(&clks_syscore_ops); 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci return 0; 6008c2ecf20Sopenharmony_ci} 6018c2ecf20Sopenharmony_cisubsys_initcall(clk_syscore_init); 6028c2ecf20Sopenharmony_ci#endif 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_cistatic int __init clk_late_init(void) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci unsigned long flags; 6078c2ecf20Sopenharmony_ci struct clk *clk; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci /* disable all clocks with zero use count */ 6108c2ecf20Sopenharmony_ci mutex_lock(&clock_list_sem); 6118c2ecf20Sopenharmony_ci spin_lock_irqsave(&clock_lock, flags); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci list_for_each_entry(clk, &clock_list, node) 6148c2ecf20Sopenharmony_ci if (!clk->usecount && clk->ops && clk->ops->disable) 6158c2ecf20Sopenharmony_ci clk->ops->disable(clk); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci /* from now on allow clock disable operations */ 6188c2ecf20Sopenharmony_ci allow_disable = 1; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&clock_lock, flags); 6218c2ecf20Sopenharmony_ci mutex_unlock(&clock_list_sem); 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_cilate_initcall(clk_late_init); 625