18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * R-Car Gen2 Clock Pulse Generator 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Cogent Embedded Inc. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bug.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/err.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "renesas-cpg-mssr.h" 198c2ecf20Sopenharmony_ci#include "rcar-gen2-cpg.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define CPG_FRQCRB 0x0004 228c2ecf20Sopenharmony_ci#define CPG_FRQCRB_KICK BIT(31) 238c2ecf20Sopenharmony_ci#define CPG_SDCKCR 0x0074 248c2ecf20Sopenharmony_ci#define CPG_PLL0CR 0x00d8 258c2ecf20Sopenharmony_ci#define CPG_PLL0CR_STC_SHIFT 24 268c2ecf20Sopenharmony_ci#define CPG_PLL0CR_STC_MASK (0x7f << CPG_PLL0CR_STC_SHIFT) 278c2ecf20Sopenharmony_ci#define CPG_FRQCRC 0x00e0 288c2ecf20Sopenharmony_ci#define CPG_FRQCRC_ZFC_SHIFT 8 298c2ecf20Sopenharmony_ci#define CPG_FRQCRC_ZFC_MASK (0x1f << CPG_FRQCRC_ZFC_SHIFT) 308c2ecf20Sopenharmony_ci#define CPG_ADSPCKCR 0x025c 318c2ecf20Sopenharmony_ci#define CPG_RCANCKCR 0x0270 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic spinlock_t cpg_lock; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* 368c2ecf20Sopenharmony_ci * Z Clock 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Traits of this clock: 398c2ecf20Sopenharmony_ci * prepare - clk_prepare only ensures that parents are prepared 408c2ecf20Sopenharmony_ci * enable - clk_enable only ensures that parents are enabled 418c2ecf20Sopenharmony_ci * rate - rate is adjustable. clk->rate = parent->rate * mult / 32 428c2ecf20Sopenharmony_ci * parent - fixed parent. No clk_set_parent support 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct cpg_z_clk { 468c2ecf20Sopenharmony_ci struct clk_hw hw; 478c2ecf20Sopenharmony_ci void __iomem *reg; 488c2ecf20Sopenharmony_ci void __iomem *kick_reg; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define to_z_clk(_hw) container_of(_hw, struct cpg_z_clk, hw) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic unsigned long cpg_z_clk_recalc_rate(struct clk_hw *hw, 548c2ecf20Sopenharmony_ci unsigned long parent_rate) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct cpg_z_clk *zclk = to_z_clk(hw); 578c2ecf20Sopenharmony_ci unsigned int mult; 588c2ecf20Sopenharmony_ci unsigned int val; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci val = (readl(zclk->reg) & CPG_FRQCRC_ZFC_MASK) >> CPG_FRQCRC_ZFC_SHIFT; 618c2ecf20Sopenharmony_ci mult = 32 - val; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci return div_u64((u64)parent_rate * mult, 32); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int cpg_z_clk_determine_rate(struct clk_hw *hw, 678c2ecf20Sopenharmony_ci struct clk_rate_request *req) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci unsigned long prate = req->best_parent_rate; 708c2ecf20Sopenharmony_ci unsigned int min_mult, max_mult, mult; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci min_mult = max(div64_ul(req->min_rate * 32ULL, prate), 1ULL); 738c2ecf20Sopenharmony_ci max_mult = min(div64_ul(req->max_rate * 32ULL, prate), 32ULL); 748c2ecf20Sopenharmony_ci if (max_mult < min_mult) 758c2ecf20Sopenharmony_ci return -EINVAL; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci mult = div64_ul(req->rate * 32ULL, prate); 788c2ecf20Sopenharmony_ci mult = clamp(mult, min_mult, max_mult); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci req->rate = div_u64((u64)prate * mult, 32); 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int cpg_z_clk_set_rate(struct clk_hw *hw, unsigned long rate, 858c2ecf20Sopenharmony_ci unsigned long parent_rate) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct cpg_z_clk *zclk = to_z_clk(hw); 888c2ecf20Sopenharmony_ci unsigned int mult; 898c2ecf20Sopenharmony_ci u32 val, kick; 908c2ecf20Sopenharmony_ci unsigned int i; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci mult = div64_ul(rate * 32ULL, parent_rate); 938c2ecf20Sopenharmony_ci mult = clamp(mult, 1U, 32U); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (readl(zclk->kick_reg) & CPG_FRQCRB_KICK) 968c2ecf20Sopenharmony_ci return -EBUSY; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci val = readl(zclk->reg); 998c2ecf20Sopenharmony_ci val &= ~CPG_FRQCRC_ZFC_MASK; 1008c2ecf20Sopenharmony_ci val |= (32 - mult) << CPG_FRQCRC_ZFC_SHIFT; 1018c2ecf20Sopenharmony_ci writel(val, zclk->reg); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * Set KICK bit in FRQCRB to update hardware setting and wait for 1058c2ecf20Sopenharmony_ci * clock change completion. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci kick = readl(zclk->kick_reg); 1088c2ecf20Sopenharmony_ci kick |= CPG_FRQCRB_KICK; 1098c2ecf20Sopenharmony_ci writel(kick, zclk->kick_reg); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * Note: There is no HW information about the worst case latency. 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * Using experimental measurements, it seems that no more than 1158c2ecf20Sopenharmony_ci * ~10 iterations are needed, independently of the CPU rate. 1168c2ecf20Sopenharmony_ci * Since this value might be dependent on external xtal rate, pll1 1178c2ecf20Sopenharmony_ci * rate or even the other emulation clocks rate, use 1000 as a 1188c2ecf20Sopenharmony_ci * "super" safe value. 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_ci for (i = 1000; i; i--) { 1218c2ecf20Sopenharmony_ci if (!(readl(zclk->kick_reg) & CPG_FRQCRB_KICK)) 1228c2ecf20Sopenharmony_ci return 0; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci cpu_relax(); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci return -ETIMEDOUT; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic const struct clk_ops cpg_z_clk_ops = { 1318c2ecf20Sopenharmony_ci .recalc_rate = cpg_z_clk_recalc_rate, 1328c2ecf20Sopenharmony_ci .determine_rate = cpg_z_clk_determine_rate, 1338c2ecf20Sopenharmony_ci .set_rate = cpg_z_clk_set_rate, 1348c2ecf20Sopenharmony_ci}; 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic struct clk * __init cpg_z_clk_register(const char *name, 1378c2ecf20Sopenharmony_ci const char *parent_name, 1388c2ecf20Sopenharmony_ci void __iomem *base) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct clk_init_data init; 1418c2ecf20Sopenharmony_ci struct cpg_z_clk *zclk; 1428c2ecf20Sopenharmony_ci struct clk *clk; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci zclk = kzalloc(sizeof(*zclk), GFP_KERNEL); 1458c2ecf20Sopenharmony_ci if (!zclk) 1468c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci init.name = name; 1498c2ecf20Sopenharmony_ci init.ops = &cpg_z_clk_ops; 1508c2ecf20Sopenharmony_ci init.flags = 0; 1518c2ecf20Sopenharmony_ci init.parent_names = &parent_name; 1528c2ecf20Sopenharmony_ci init.num_parents = 1; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci zclk->reg = base + CPG_FRQCRC; 1558c2ecf20Sopenharmony_ci zclk->kick_reg = base + CPG_FRQCRB; 1568c2ecf20Sopenharmony_ci zclk->hw.init = &init; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci clk = clk_register(NULL, &zclk->hw); 1598c2ecf20Sopenharmony_ci if (IS_ERR(clk)) 1608c2ecf20Sopenharmony_ci kfree(zclk); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return clk; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic struct clk * __init cpg_rcan_clk_register(const char *name, 1668c2ecf20Sopenharmony_ci const char *parent_name, 1678c2ecf20Sopenharmony_ci void __iomem *base) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct clk_fixed_factor *fixed; 1708c2ecf20Sopenharmony_ci struct clk_gate *gate; 1718c2ecf20Sopenharmony_ci struct clk *clk; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci fixed = kzalloc(sizeof(*fixed), GFP_KERNEL); 1748c2ecf20Sopenharmony_ci if (!fixed) 1758c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci fixed->mult = 1; 1788c2ecf20Sopenharmony_ci fixed->div = 6; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci gate = kzalloc(sizeof(*gate), GFP_KERNEL); 1818c2ecf20Sopenharmony_ci if (!gate) { 1828c2ecf20Sopenharmony_ci kfree(fixed); 1838c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1848c2ecf20Sopenharmony_ci } 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci gate->reg = base + CPG_RCANCKCR; 1878c2ecf20Sopenharmony_ci gate->bit_idx = 8; 1888c2ecf20Sopenharmony_ci gate->flags = CLK_GATE_SET_TO_DISABLE; 1898c2ecf20Sopenharmony_ci gate->lock = &cpg_lock; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, 1928c2ecf20Sopenharmony_ci &fixed->hw, &clk_fixed_factor_ops, 1938c2ecf20Sopenharmony_ci &gate->hw, &clk_gate_ops, 0); 1948c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 1958c2ecf20Sopenharmony_ci kfree(gate); 1968c2ecf20Sopenharmony_ci kfree(fixed); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return clk; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* ADSP divisors */ 2038c2ecf20Sopenharmony_cistatic const struct clk_div_table cpg_adsp_div_table[] = { 2048c2ecf20Sopenharmony_ci { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, 2058c2ecf20Sopenharmony_ci { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 }, 2068c2ecf20Sopenharmony_ci { 10, 36 }, { 11, 48 }, { 0, 0 }, 2078c2ecf20Sopenharmony_ci}; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic struct clk * __init cpg_adsp_clk_register(const char *name, 2108c2ecf20Sopenharmony_ci const char *parent_name, 2118c2ecf20Sopenharmony_ci void __iomem *base) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct clk_divider *div; 2148c2ecf20Sopenharmony_ci struct clk_gate *gate; 2158c2ecf20Sopenharmony_ci struct clk *clk; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci div = kzalloc(sizeof(*div), GFP_KERNEL); 2188c2ecf20Sopenharmony_ci if (!div) 2198c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci div->reg = base + CPG_ADSPCKCR; 2228c2ecf20Sopenharmony_ci div->width = 4; 2238c2ecf20Sopenharmony_ci div->table = cpg_adsp_div_table; 2248c2ecf20Sopenharmony_ci div->lock = &cpg_lock; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci gate = kzalloc(sizeof(*gate), GFP_KERNEL); 2278c2ecf20Sopenharmony_ci if (!gate) { 2288c2ecf20Sopenharmony_ci kfree(div); 2298c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci gate->reg = base + CPG_ADSPCKCR; 2338c2ecf20Sopenharmony_ci gate->bit_idx = 8; 2348c2ecf20Sopenharmony_ci gate->flags = CLK_GATE_SET_TO_DISABLE; 2358c2ecf20Sopenharmony_ci gate->lock = &cpg_lock; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, 2388c2ecf20Sopenharmony_ci &div->hw, &clk_divider_ops, 2398c2ecf20Sopenharmony_ci &gate->hw, &clk_gate_ops, 0); 2408c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 2418c2ecf20Sopenharmony_ci kfree(gate); 2428c2ecf20Sopenharmony_ci kfree(div); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci return clk; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci/* SDHI divisors */ 2498c2ecf20Sopenharmony_cistatic const struct clk_div_table cpg_sdh_div_table[] = { 2508c2ecf20Sopenharmony_ci { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, 2518c2ecf20Sopenharmony_ci { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, 2528c2ecf20Sopenharmony_ci { 8, 24 }, { 10, 36 }, { 11, 48 }, { 0, 0 }, 2538c2ecf20Sopenharmony_ci}; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic const struct clk_div_table cpg_sd01_div_table[] = { 2568c2ecf20Sopenharmony_ci { 4, 8 }, { 5, 12 }, { 6, 16 }, { 7, 18 }, 2578c2ecf20Sopenharmony_ci { 8, 24 }, { 10, 36 }, { 11, 48 }, { 12, 10 }, 2588c2ecf20Sopenharmony_ci { 0, 0 }, 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic const struct rcar_gen2_cpg_pll_config *cpg_pll_config __initdata; 2628c2ecf20Sopenharmony_cistatic unsigned int cpg_pll0_div __initdata; 2638c2ecf20Sopenharmony_cistatic u32 cpg_mode __initdata; 2648c2ecf20Sopenharmony_cistatic u32 cpg_quirks __initdata; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci#define SD_SKIP_FIRST BIT(0) /* Skip first clock in SD table */ 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_cistatic const struct soc_device_attribute cpg_quirks_match[] __initconst = { 2698c2ecf20Sopenharmony_ci { 2708c2ecf20Sopenharmony_ci .soc_id = "r8a77470", 2718c2ecf20Sopenharmony_ci .data = (void *)SD_SKIP_FIRST, 2728c2ecf20Sopenharmony_ci }, 2738c2ecf20Sopenharmony_ci { /* sentinel */ } 2748c2ecf20Sopenharmony_ci}; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistruct clk * __init rcar_gen2_cpg_clk_register(struct device *dev, 2778c2ecf20Sopenharmony_ci const struct cpg_core_clk *core, const struct cpg_mssr_info *info, 2788c2ecf20Sopenharmony_ci struct clk **clks, void __iomem *base, 2798c2ecf20Sopenharmony_ci struct raw_notifier_head *notifiers) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci const struct clk_div_table *table = NULL; 2828c2ecf20Sopenharmony_ci const struct clk *parent; 2838c2ecf20Sopenharmony_ci const char *parent_name; 2848c2ecf20Sopenharmony_ci unsigned int mult = 1; 2858c2ecf20Sopenharmony_ci unsigned int div = 1; 2868c2ecf20Sopenharmony_ci unsigned int shift; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci parent = clks[core->parent]; 2898c2ecf20Sopenharmony_ci if (IS_ERR(parent)) 2908c2ecf20Sopenharmony_ci return ERR_CAST(parent); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci parent_name = __clk_get_name(parent); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci switch (core->type) { 2958c2ecf20Sopenharmony_ci /* R-Car Gen2 */ 2968c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_MAIN: 2978c2ecf20Sopenharmony_ci div = cpg_pll_config->extal_div; 2988c2ecf20Sopenharmony_ci break; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_PLL0: 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * PLL0 is a configurable multiplier clock except on R-Car 3038c2ecf20Sopenharmony_ci * V2H/E2. Register the PLL0 clock as a fixed factor clock for 3048c2ecf20Sopenharmony_ci * now as there's no generic multiplier clock implementation and 3058c2ecf20Sopenharmony_ci * we currently have no need to change the multiplier value. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_ci mult = cpg_pll_config->pll0_mult; 3088c2ecf20Sopenharmony_ci div = cpg_pll0_div; 3098c2ecf20Sopenharmony_ci if (!mult) { 3108c2ecf20Sopenharmony_ci u32 pll0cr = readl(base + CPG_PLL0CR); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci mult = (((pll0cr & CPG_PLL0CR_STC_MASK) >> 3138c2ecf20Sopenharmony_ci CPG_PLL0CR_STC_SHIFT) + 1) * 2; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_PLL1: 3188c2ecf20Sopenharmony_ci mult = cpg_pll_config->pll1_mult / 2; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_PLL3: 3228c2ecf20Sopenharmony_ci mult = cpg_pll_config->pll3_mult; 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_Z: 3268c2ecf20Sopenharmony_ci return cpg_z_clk_register(core->name, parent_name, base); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_LB: 3298c2ecf20Sopenharmony_ci div = cpg_mode & BIT(18) ? 36 : 24; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_ADSP: 3338c2ecf20Sopenharmony_ci return cpg_adsp_clk_register(core->name, parent_name, base); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_SDH: 3368c2ecf20Sopenharmony_ci table = cpg_sdh_div_table; 3378c2ecf20Sopenharmony_ci shift = 8; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_SD0: 3418c2ecf20Sopenharmony_ci table = cpg_sd01_div_table; 3428c2ecf20Sopenharmony_ci if (cpg_quirks & SD_SKIP_FIRST) 3438c2ecf20Sopenharmony_ci table++; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci shift = 4; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_SD1: 3498c2ecf20Sopenharmony_ci table = cpg_sd01_div_table; 3508c2ecf20Sopenharmony_ci if (cpg_quirks & SD_SKIP_FIRST) 3518c2ecf20Sopenharmony_ci table++; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci shift = 0; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_QSPI: 3578c2ecf20Sopenharmony_ci div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) ? 3588c2ecf20Sopenharmony_ci 8 : 10; 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci case CLK_TYPE_GEN2_RCAN: 3628c2ecf20Sopenharmony_ci return cpg_rcan_clk_register(core->name, parent_name, base); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci default: 3658c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (!table) 3698c2ecf20Sopenharmony_ci return clk_register_fixed_factor(NULL, core->name, parent_name, 3708c2ecf20Sopenharmony_ci 0, mult, div); 3718c2ecf20Sopenharmony_ci else 3728c2ecf20Sopenharmony_ci return clk_register_divider_table(NULL, core->name, 3738c2ecf20Sopenharmony_ci parent_name, 0, 3748c2ecf20Sopenharmony_ci base + CPG_SDCKCR, shift, 4, 3758c2ecf20Sopenharmony_ci 0, table, &cpg_lock); 3768c2ecf20Sopenharmony_ci} 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ciint __init rcar_gen2_cpg_init(const struct rcar_gen2_cpg_pll_config *config, 3798c2ecf20Sopenharmony_ci unsigned int pll0_div, u32 mode) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci const struct soc_device_attribute *attr; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci cpg_pll_config = config; 3848c2ecf20Sopenharmony_ci cpg_pll0_div = pll0_div; 3858c2ecf20Sopenharmony_ci cpg_mode = mode; 3868c2ecf20Sopenharmony_ci attr = soc_device_match(cpg_quirks_match); 3878c2ecf20Sopenharmony_ci if (attr) 3888c2ecf20Sopenharmony_ci cpg_quirks = (uintptr_t)attr->data; 3898c2ecf20Sopenharmony_ci pr_debug("%s: mode = 0x%x quirks = 0x%x\n", __func__, mode, cpg_quirks); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci spin_lock_init(&cpg_lock); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci return 0; 3948c2ecf20Sopenharmony_ci} 395