18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 78c2ecf20Sopenharmony_ci#include <linux/clkdev.h> 88c2ecf20Sopenharmony_ci#include <linux/clk/at91_pmc.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 118c2ecf20Sopenharmony_ci#include <linux/regmap.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "pmc.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define SLOW_CLOCK_FREQ 32768 168c2ecf20Sopenharmony_ci#define MAINF_DIV 16 178c2ecf20Sopenharmony_ci#define MAINFRDY_TIMEOUT (((MAINF_DIV + 1) * USEC_PER_SEC) / \ 188c2ecf20Sopenharmony_ci SLOW_CLOCK_FREQ) 198c2ecf20Sopenharmony_ci#define MAINF_LOOP_MIN_WAIT (USEC_PER_SEC / SLOW_CLOCK_FREQ) 208c2ecf20Sopenharmony_ci#define MAINF_LOOP_MAX_WAIT MAINFRDY_TIMEOUT 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define MOR_KEY_MASK (0xff << 16) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define clk_main_parent_select(s) (((s) & \ 258c2ecf20Sopenharmony_ci (AT91_PMC_MOSCEN | \ 268c2ecf20Sopenharmony_ci AT91_PMC_OSCBYPASS)) ? 1 : 0) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct clk_main_osc { 298c2ecf20Sopenharmony_ci struct clk_hw hw; 308c2ecf20Sopenharmony_ci struct regmap *regmap; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#define to_clk_main_osc(hw) container_of(hw, struct clk_main_osc, hw) 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistruct clk_main_rc_osc { 368c2ecf20Sopenharmony_ci struct clk_hw hw; 378c2ecf20Sopenharmony_ci struct regmap *regmap; 388c2ecf20Sopenharmony_ci unsigned long frequency; 398c2ecf20Sopenharmony_ci unsigned long accuracy; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci#define to_clk_main_rc_osc(hw) container_of(hw, struct clk_main_rc_osc, hw) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistruct clk_rm9200_main { 458c2ecf20Sopenharmony_ci struct clk_hw hw; 468c2ecf20Sopenharmony_ci struct regmap *regmap; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define to_clk_rm9200_main(hw) container_of(hw, struct clk_rm9200_main, hw) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct clk_sam9x5_main { 528c2ecf20Sopenharmony_ci struct clk_hw hw; 538c2ecf20Sopenharmony_ci struct regmap *regmap; 548c2ecf20Sopenharmony_ci u8 parent; 558c2ecf20Sopenharmony_ci}; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define to_clk_sam9x5_main(hw) container_of(hw, struct clk_sam9x5_main, hw) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic inline bool clk_main_osc_ready(struct regmap *regmap) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci unsigned int status; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return status & AT91_PMC_MOSCS; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int clk_main_osc_prepare(struct clk_hw *hw) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct clk_main_osc *osc = to_clk_main_osc(hw); 718c2ecf20Sopenharmony_ci struct regmap *regmap = osc->regmap; 728c2ecf20Sopenharmony_ci u32 tmp; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &tmp); 758c2ecf20Sopenharmony_ci tmp &= ~MOR_KEY_MASK; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (tmp & AT91_PMC_OSCBYPASS) 788c2ecf20Sopenharmony_ci return 0; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (!(tmp & AT91_PMC_MOSCEN)) { 818c2ecf20Sopenharmony_ci tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY; 828c2ecf20Sopenharmony_ci regmap_write(regmap, AT91_CKGR_MOR, tmp); 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci while (!clk_main_osc_ready(regmap)) 868c2ecf20Sopenharmony_ci cpu_relax(); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci return 0; 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic void clk_main_osc_unprepare(struct clk_hw *hw) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct clk_main_osc *osc = to_clk_main_osc(hw); 948c2ecf20Sopenharmony_ci struct regmap *regmap = osc->regmap; 958c2ecf20Sopenharmony_ci u32 tmp; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &tmp); 988c2ecf20Sopenharmony_ci if (tmp & AT91_PMC_OSCBYPASS) 998c2ecf20Sopenharmony_ci return; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci if (!(tmp & AT91_PMC_MOSCEN)) 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN); 1058c2ecf20Sopenharmony_ci regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY); 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int clk_main_osc_is_prepared(struct clk_hw *hw) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci struct clk_main_osc *osc = to_clk_main_osc(hw); 1118c2ecf20Sopenharmony_ci struct regmap *regmap = osc->regmap; 1128c2ecf20Sopenharmony_ci u32 tmp, status; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &tmp); 1158c2ecf20Sopenharmony_ci if (tmp & AT91_PMC_OSCBYPASS) 1168c2ecf20Sopenharmony_ci return 1; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return (status & AT91_PMC_MOSCS) && clk_main_parent_select(tmp); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic const struct clk_ops main_osc_ops = { 1248c2ecf20Sopenharmony_ci .prepare = clk_main_osc_prepare, 1258c2ecf20Sopenharmony_ci .unprepare = clk_main_osc_unprepare, 1268c2ecf20Sopenharmony_ci .is_prepared = clk_main_osc_is_prepared, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistruct clk_hw * __init 1308c2ecf20Sopenharmony_ciat91_clk_register_main_osc(struct regmap *regmap, 1318c2ecf20Sopenharmony_ci const char *name, 1328c2ecf20Sopenharmony_ci const char *parent_name, 1338c2ecf20Sopenharmony_ci bool bypass) 1348c2ecf20Sopenharmony_ci{ 1358c2ecf20Sopenharmony_ci struct clk_main_osc *osc; 1368c2ecf20Sopenharmony_ci struct clk_init_data init; 1378c2ecf20Sopenharmony_ci struct clk_hw *hw; 1388c2ecf20Sopenharmony_ci int ret; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (!name || !parent_name) 1418c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci osc = kzalloc(sizeof(*osc), GFP_KERNEL); 1448c2ecf20Sopenharmony_ci if (!osc) 1458c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci init.name = name; 1488c2ecf20Sopenharmony_ci init.ops = &main_osc_ops; 1498c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 1508c2ecf20Sopenharmony_ci init.num_parents = 1; 1518c2ecf20Sopenharmony_ci init.flags = CLK_IGNORE_UNUSED; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci osc->hw.init = &init; 1548c2ecf20Sopenharmony_ci osc->regmap = regmap; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (bypass) 1578c2ecf20Sopenharmony_ci regmap_update_bits(regmap, 1588c2ecf20Sopenharmony_ci AT91_CKGR_MOR, MOR_KEY_MASK | 1598c2ecf20Sopenharmony_ci AT91_PMC_OSCBYPASS, 1608c2ecf20Sopenharmony_ci AT91_PMC_OSCBYPASS | AT91_PMC_KEY); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci hw = &osc->hw; 1638c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, &osc->hw); 1648c2ecf20Sopenharmony_ci if (ret) { 1658c2ecf20Sopenharmony_ci kfree(osc); 1668c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return hw; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic bool clk_main_rc_osc_ready(struct regmap *regmap) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci unsigned int status; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci return !!(status & AT91_PMC_MOSCRCS); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic int clk_main_rc_osc_prepare(struct clk_hw *hw) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); 1848c2ecf20Sopenharmony_ci struct regmap *regmap = osc->regmap; 1858c2ecf20Sopenharmony_ci unsigned int mor; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &mor); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!(mor & AT91_PMC_MOSCRCEN)) 1908c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_CKGR_MOR, 1918c2ecf20Sopenharmony_ci MOR_KEY_MASK | AT91_PMC_MOSCRCEN, 1928c2ecf20Sopenharmony_ci AT91_PMC_MOSCRCEN | AT91_PMC_KEY); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci while (!clk_main_rc_osc_ready(regmap)) 1958c2ecf20Sopenharmony_ci cpu_relax(); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return 0; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void clk_main_rc_osc_unprepare(struct clk_hw *hw) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); 2038c2ecf20Sopenharmony_ci struct regmap *regmap = osc->regmap; 2048c2ecf20Sopenharmony_ci unsigned int mor; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &mor); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (!(mor & AT91_PMC_MOSCRCEN)) 2098c2ecf20Sopenharmony_ci return; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_CKGR_MOR, 2128c2ecf20Sopenharmony_ci MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY); 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic int clk_main_rc_osc_is_prepared(struct clk_hw *hw) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); 2188c2ecf20Sopenharmony_ci struct regmap *regmap = osc->regmap; 2198c2ecf20Sopenharmony_ci unsigned int mor, status; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &mor); 2228c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic unsigned long clk_main_rc_osc_recalc_rate(struct clk_hw *hw, 2288c2ecf20Sopenharmony_ci unsigned long parent_rate) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci return osc->frequency; 2338c2ecf20Sopenharmony_ci} 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic unsigned long clk_main_rc_osc_recalc_accuracy(struct clk_hw *hw, 2368c2ecf20Sopenharmony_ci unsigned long parent_acc) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct clk_main_rc_osc *osc = to_clk_main_rc_osc(hw); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return osc->accuracy; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic const struct clk_ops main_rc_osc_ops = { 2448c2ecf20Sopenharmony_ci .prepare = clk_main_rc_osc_prepare, 2458c2ecf20Sopenharmony_ci .unprepare = clk_main_rc_osc_unprepare, 2468c2ecf20Sopenharmony_ci .is_prepared = clk_main_rc_osc_is_prepared, 2478c2ecf20Sopenharmony_ci .recalc_rate = clk_main_rc_osc_recalc_rate, 2488c2ecf20Sopenharmony_ci .recalc_accuracy = clk_main_rc_osc_recalc_accuracy, 2498c2ecf20Sopenharmony_ci}; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_cistruct clk_hw * __init 2528c2ecf20Sopenharmony_ciat91_clk_register_main_rc_osc(struct regmap *regmap, 2538c2ecf20Sopenharmony_ci const char *name, 2548c2ecf20Sopenharmony_ci u32 frequency, u32 accuracy) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct clk_main_rc_osc *osc; 2578c2ecf20Sopenharmony_ci struct clk_init_data init; 2588c2ecf20Sopenharmony_ci struct clk_hw *hw; 2598c2ecf20Sopenharmony_ci int ret; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (!name || !frequency) 2628c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci osc = kzalloc(sizeof(*osc), GFP_KERNEL); 2658c2ecf20Sopenharmony_ci if (!osc) 2668c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci init.name = name; 2698c2ecf20Sopenharmony_ci init.ops = &main_rc_osc_ops; 2708c2ecf20Sopenharmony_ci init.parent_names = NULL; 2718c2ecf20Sopenharmony_ci init.num_parents = 0; 2728c2ecf20Sopenharmony_ci init.flags = CLK_IGNORE_UNUSED; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci osc->hw.init = &init; 2758c2ecf20Sopenharmony_ci osc->regmap = regmap; 2768c2ecf20Sopenharmony_ci osc->frequency = frequency; 2778c2ecf20Sopenharmony_ci osc->accuracy = accuracy; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci hw = &osc->hw; 2808c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, hw); 2818c2ecf20Sopenharmony_ci if (ret) { 2828c2ecf20Sopenharmony_ci kfree(osc); 2838c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return hw; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int clk_main_probe_frequency(struct regmap *regmap) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci unsigned long prep_time, timeout; 2928c2ecf20Sopenharmony_ci unsigned int mcfr; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci timeout = jiffies + usecs_to_jiffies(MAINFRDY_TIMEOUT); 2958c2ecf20Sopenharmony_ci do { 2968c2ecf20Sopenharmony_ci prep_time = jiffies; 2978c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MCFR, &mcfr); 2988c2ecf20Sopenharmony_ci if (mcfr & AT91_PMC_MAINRDY) 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci if (system_state < SYSTEM_RUNNING) 3018c2ecf20Sopenharmony_ci udelay(MAINF_LOOP_MIN_WAIT); 3028c2ecf20Sopenharmony_ci else 3038c2ecf20Sopenharmony_ci usleep_range(MAINF_LOOP_MIN_WAIT, MAINF_LOOP_MAX_WAIT); 3048c2ecf20Sopenharmony_ci } while (time_before(prep_time, timeout)); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return -ETIMEDOUT; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic unsigned long clk_main_recalc_rate(struct regmap *regmap, 3108c2ecf20Sopenharmony_ci unsigned long parent_rate) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci unsigned int mcfr; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (parent_rate) 3158c2ecf20Sopenharmony_ci return parent_rate; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci pr_warn("Main crystal frequency not set, using approximate value\n"); 3188c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MCFR, &mcfr); 3198c2ecf20Sopenharmony_ci if (!(mcfr & AT91_PMC_MAINRDY)) 3208c2ecf20Sopenharmony_ci return 0; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV; 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic int clk_rm9200_main_prepare(struct clk_hw *hw) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci return clk_main_probe_frequency(clkmain->regmap); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_cistatic int clk_rm9200_main_is_prepared(struct clk_hw *hw) 3338c2ecf20Sopenharmony_ci{ 3348c2ecf20Sopenharmony_ci struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); 3358c2ecf20Sopenharmony_ci unsigned int status; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci return !!(status & AT91_PMC_MAINRDY); 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic unsigned long clk_rm9200_main_recalc_rate(struct clk_hw *hw, 3438c2ecf20Sopenharmony_ci unsigned long parent_rate) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct clk_rm9200_main *clkmain = to_clk_rm9200_main(hw); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci return clk_main_recalc_rate(clkmain->regmap, parent_rate); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_cistatic const struct clk_ops rm9200_main_ops = { 3518c2ecf20Sopenharmony_ci .prepare = clk_rm9200_main_prepare, 3528c2ecf20Sopenharmony_ci .is_prepared = clk_rm9200_main_is_prepared, 3538c2ecf20Sopenharmony_ci .recalc_rate = clk_rm9200_main_recalc_rate, 3548c2ecf20Sopenharmony_ci}; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistruct clk_hw * __init 3578c2ecf20Sopenharmony_ciat91_clk_register_rm9200_main(struct regmap *regmap, 3588c2ecf20Sopenharmony_ci const char *name, 3598c2ecf20Sopenharmony_ci const char *parent_name) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct clk_rm9200_main *clkmain; 3628c2ecf20Sopenharmony_ci struct clk_init_data init; 3638c2ecf20Sopenharmony_ci struct clk_hw *hw; 3648c2ecf20Sopenharmony_ci int ret; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci if (!name) 3678c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci if (!parent_name) 3708c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); 3738c2ecf20Sopenharmony_ci if (!clkmain) 3748c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci init.name = name; 3778c2ecf20Sopenharmony_ci init.ops = &rm9200_main_ops; 3788c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 3798c2ecf20Sopenharmony_ci init.num_parents = 1; 3808c2ecf20Sopenharmony_ci init.flags = 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci clkmain->hw.init = &init; 3838c2ecf20Sopenharmony_ci clkmain->regmap = regmap; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci hw = &clkmain->hw; 3868c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, &clkmain->hw); 3878c2ecf20Sopenharmony_ci if (ret) { 3888c2ecf20Sopenharmony_ci kfree(clkmain); 3898c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci return hw; 3938c2ecf20Sopenharmony_ci} 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_cistatic inline bool clk_sam9x5_main_ready(struct regmap *regmap) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci unsigned int status; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_PMC_SR, &status); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci return !!(status & AT91_PMC_MOSCSELS); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic int clk_sam9x5_main_prepare(struct clk_hw *hw) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); 4078c2ecf20Sopenharmony_ci struct regmap *regmap = clkmain->regmap; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci while (!clk_sam9x5_main_ready(regmap)) 4108c2ecf20Sopenharmony_ci cpu_relax(); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci return clk_main_probe_frequency(regmap); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic int clk_sam9x5_main_is_prepared(struct clk_hw *hw) 4168c2ecf20Sopenharmony_ci{ 4178c2ecf20Sopenharmony_ci struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return clk_sam9x5_main_ready(clkmain->regmap); 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic unsigned long clk_sam9x5_main_recalc_rate(struct clk_hw *hw, 4238c2ecf20Sopenharmony_ci unsigned long parent_rate) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return clk_main_recalc_rate(clkmain->regmap, parent_rate); 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int clk_sam9x5_main_set_parent(struct clk_hw *hw, u8 index) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); 4338c2ecf20Sopenharmony_ci struct regmap *regmap = clkmain->regmap; 4348c2ecf20Sopenharmony_ci unsigned int tmp; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci if (index > 1) 4378c2ecf20Sopenharmony_ci return -EINVAL; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci regmap_read(regmap, AT91_CKGR_MOR, &tmp); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci if (index && !(tmp & AT91_PMC_MOSCSEL)) 4428c2ecf20Sopenharmony_ci tmp = AT91_PMC_MOSCSEL; 4438c2ecf20Sopenharmony_ci else if (!index && (tmp & AT91_PMC_MOSCSEL)) 4448c2ecf20Sopenharmony_ci tmp = 0; 4458c2ecf20Sopenharmony_ci else 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci regmap_update_bits(regmap, AT91_CKGR_MOR, 4498c2ecf20Sopenharmony_ci AT91_PMC_MOSCSEL | MOR_KEY_MASK, 4508c2ecf20Sopenharmony_ci tmp | AT91_PMC_KEY); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci while (!clk_sam9x5_main_ready(regmap)) 4538c2ecf20Sopenharmony_ci cpu_relax(); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic u8 clk_sam9x5_main_get_parent(struct clk_hw *hw) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(hw); 4618c2ecf20Sopenharmony_ci unsigned int status; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return clk_main_parent_select(status); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic const struct clk_ops sam9x5_main_ops = { 4698c2ecf20Sopenharmony_ci .prepare = clk_sam9x5_main_prepare, 4708c2ecf20Sopenharmony_ci .is_prepared = clk_sam9x5_main_is_prepared, 4718c2ecf20Sopenharmony_ci .recalc_rate = clk_sam9x5_main_recalc_rate, 4728c2ecf20Sopenharmony_ci .set_parent = clk_sam9x5_main_set_parent, 4738c2ecf20Sopenharmony_ci .get_parent = clk_sam9x5_main_get_parent, 4748c2ecf20Sopenharmony_ci}; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistruct clk_hw * __init 4778c2ecf20Sopenharmony_ciat91_clk_register_sam9x5_main(struct regmap *regmap, 4788c2ecf20Sopenharmony_ci const char *name, 4798c2ecf20Sopenharmony_ci const char **parent_names, 4808c2ecf20Sopenharmony_ci int num_parents) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct clk_sam9x5_main *clkmain; 4838c2ecf20Sopenharmony_ci struct clk_init_data init; 4848c2ecf20Sopenharmony_ci unsigned int status; 4858c2ecf20Sopenharmony_ci struct clk_hw *hw; 4868c2ecf20Sopenharmony_ci int ret; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (!name) 4898c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci if (!parent_names || !num_parents) 4928c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci clkmain = kzalloc(sizeof(*clkmain), GFP_KERNEL); 4958c2ecf20Sopenharmony_ci if (!clkmain) 4968c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci init.name = name; 4998c2ecf20Sopenharmony_ci init.ops = &sam9x5_main_ops; 5008c2ecf20Sopenharmony_ci init.parent_names = parent_names; 5018c2ecf20Sopenharmony_ci init.num_parents = num_parents; 5028c2ecf20Sopenharmony_ci init.flags = CLK_SET_PARENT_GATE; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci clkmain->hw.init = &init; 5058c2ecf20Sopenharmony_ci clkmain->regmap = regmap; 5068c2ecf20Sopenharmony_ci regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status); 5078c2ecf20Sopenharmony_ci clkmain->parent = clk_main_parent_select(status); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci hw = &clkmain->hw; 5108c2ecf20Sopenharmony_ci ret = clk_hw_register(NULL, &clkmain->hw); 5118c2ecf20Sopenharmony_ci if (ret) { 5128c2ecf20Sopenharmony_ci kfree(clkmain); 5138c2ecf20Sopenharmony_ci hw = ERR_PTR(ret); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci return hw; 5178c2ecf20Sopenharmony_ci} 518