162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * R-Car Gen3 Clock Pulse Generator Library 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015-2018 Glider bvba 662306a36Sopenharmony_ci * Copyright (C) 2019 Renesas Electronics Corp. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Based on clk-rcar-gen3.c 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Copyright (C) 2015 Renesas Electronics Corp. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/clk.h> 1462306a36Sopenharmony_ci#include <linux/clk-provider.h> 1562306a36Sopenharmony_ci#include <linux/device.h> 1662306a36Sopenharmony_ci#include <linux/err.h> 1762306a36Sopenharmony_ci#include <linux/init.h> 1862306a36Sopenharmony_ci#include <linux/io.h> 1962306a36Sopenharmony_ci#include <linux/pm.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <linux/sys_soc.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "rcar-cpg-lib.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cispinlock_t cpg_lock; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_civoid cpg_reg_modify(void __iomem *reg, u32 clear, u32 set) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci unsigned long flags; 3062306a36Sopenharmony_ci u32 val; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci spin_lock_irqsave(&cpg_lock, flags); 3362306a36Sopenharmony_ci val = readl(reg); 3462306a36Sopenharmony_ci val &= ~clear; 3562306a36Sopenharmony_ci val |= set; 3662306a36Sopenharmony_ci writel(val, reg); 3762306a36Sopenharmony_ci spin_unlock_irqrestore(&cpg_lock, flags); 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int cpg_simple_notifier_call(struct notifier_block *nb, 4162306a36Sopenharmony_ci unsigned long action, void *data) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci struct cpg_simple_notifier *csn = 4462306a36Sopenharmony_ci container_of(nb, struct cpg_simple_notifier, nb); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci switch (action) { 4762306a36Sopenharmony_ci case PM_EVENT_SUSPEND: 4862306a36Sopenharmony_ci csn->saved = readl(csn->reg); 4962306a36Sopenharmony_ci return NOTIFY_OK; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci case PM_EVENT_RESUME: 5262306a36Sopenharmony_ci writel(csn->saved, csn->reg); 5362306a36Sopenharmony_ci return NOTIFY_OK; 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci return NOTIFY_DONE; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_civoid cpg_simple_notifier_register(struct raw_notifier_head *notifiers, 5962306a36Sopenharmony_ci struct cpg_simple_notifier *csn) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci csn->nb.notifier_call = cpg_simple_notifier_call; 6262306a36Sopenharmony_ci raw_notifier_chain_register(notifiers, &csn->nb); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * SDn Clock 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define SDnSRCFC_SHIFT 2 7062306a36Sopenharmony_ci#define STPnHCK BIT(9 - SDnSRCFC_SHIFT) 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic const struct clk_div_table cpg_sdh_div_table[] = { 7362306a36Sopenharmony_ci /* 7462306a36Sopenharmony_ci * These values are recommended by the datasheet. Because they come 7562306a36Sopenharmony_ci * first, Linux will only use these. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci { 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 }, 7862306a36Sopenharmony_ci { STPnHCK | 4, 16 }, 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * These values are not recommended because STPnHCK is wrong. But they 8162306a36Sopenharmony_ci * have been seen because of broken firmware. So, we support reading 8262306a36Sopenharmony_ci * them but Linux will sanitize them when initializing through 8362306a36Sopenharmony_ci * recalc_rate. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci { STPnHCK | 0, 1 }, { STPnHCK | 1, 2 }, { 2, 4 }, { 3, 8 }, { 4, 16 }, 8662306a36Sopenharmony_ci /* Sentinel */ 8762306a36Sopenharmony_ci { 0, 0 } 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistruct clk * __init cpg_sdh_clk_register(const char *name, 9162306a36Sopenharmony_ci void __iomem *sdnckcr, const char *parent_name, 9262306a36Sopenharmony_ci struct raw_notifier_head *notifiers) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct cpg_simple_notifier *csn; 9562306a36Sopenharmony_ci struct clk *clk; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci csn = kzalloc(sizeof(*csn), GFP_KERNEL); 9862306a36Sopenharmony_ci if (!csn) 9962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci csn->reg = sdnckcr; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci clk = clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr, 10462306a36Sopenharmony_ci SDnSRCFC_SHIFT, 8, 0, cpg_sdh_div_table, 10562306a36Sopenharmony_ci &cpg_lock); 10662306a36Sopenharmony_ci if (IS_ERR(clk)) { 10762306a36Sopenharmony_ci kfree(csn); 10862306a36Sopenharmony_ci return clk; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci cpg_simple_notifier_register(notifiers, csn); 11262306a36Sopenharmony_ci return clk; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic const struct clk_div_table cpg_sd_div_table[] = { 11662306a36Sopenharmony_ci { 0, 2 }, { 1, 4 }, { 0, 0 }, 11762306a36Sopenharmony_ci}; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistruct clk * __init cpg_sd_clk_register(const char *name, 12062306a36Sopenharmony_ci void __iomem *sdnckcr, const char *parent_name) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci return clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr, 12362306a36Sopenharmony_ci 0, 2, 0, cpg_sd_div_table, &cpg_lock); 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistruct rpc_clock { 12762306a36Sopenharmony_ci struct clk_divider div; 12862306a36Sopenharmony_ci struct clk_gate gate; 12962306a36Sopenharmony_ci /* 13062306a36Sopenharmony_ci * One notifier covers both RPC and RPCD2 clocks as they are both 13162306a36Sopenharmony_ci * controlled by the same RPCCKCR register... 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_ci struct cpg_simple_notifier csn; 13462306a36Sopenharmony_ci}; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic const struct clk_div_table cpg_rpc_div_table[] = { 13762306a36Sopenharmony_ci { 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 }, 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistruct clk * __init cpg_rpc_clk_register(const char *name, 14162306a36Sopenharmony_ci void __iomem *rpcckcr, const char *parent_name, 14262306a36Sopenharmony_ci struct raw_notifier_head *notifiers) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci struct rpc_clock *rpc; 14562306a36Sopenharmony_ci struct clk *clk; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci rpc = kzalloc(sizeof(*rpc), GFP_KERNEL); 14862306a36Sopenharmony_ci if (!rpc) 14962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci rpc->div.reg = rpcckcr; 15262306a36Sopenharmony_ci rpc->div.width = 3; 15362306a36Sopenharmony_ci rpc->div.table = cpg_rpc_div_table; 15462306a36Sopenharmony_ci rpc->div.lock = &cpg_lock; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci rpc->gate.reg = rpcckcr; 15762306a36Sopenharmony_ci rpc->gate.bit_idx = 8; 15862306a36Sopenharmony_ci rpc->gate.flags = CLK_GATE_SET_TO_DISABLE; 15962306a36Sopenharmony_ci rpc->gate.lock = &cpg_lock; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci rpc->csn.reg = rpcckcr; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, 16462306a36Sopenharmony_ci &rpc->div.hw, &clk_divider_ops, 16562306a36Sopenharmony_ci &rpc->gate.hw, &clk_gate_ops, 16662306a36Sopenharmony_ci CLK_SET_RATE_PARENT); 16762306a36Sopenharmony_ci if (IS_ERR(clk)) { 16862306a36Sopenharmony_ci kfree(rpc); 16962306a36Sopenharmony_ci return clk; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci cpg_simple_notifier_register(notifiers, &rpc->csn); 17362306a36Sopenharmony_ci return clk; 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistruct rpcd2_clock { 17762306a36Sopenharmony_ci struct clk_fixed_factor fixed; 17862306a36Sopenharmony_ci struct clk_gate gate; 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistruct clk * __init cpg_rpcd2_clk_register(const char *name, 18262306a36Sopenharmony_ci void __iomem *rpcckcr, 18362306a36Sopenharmony_ci const char *parent_name) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct rpcd2_clock *rpcd2; 18662306a36Sopenharmony_ci struct clk *clk; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci rpcd2 = kzalloc(sizeof(*rpcd2), GFP_KERNEL); 18962306a36Sopenharmony_ci if (!rpcd2) 19062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci rpcd2->fixed.mult = 1; 19362306a36Sopenharmony_ci rpcd2->fixed.div = 2; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci rpcd2->gate.reg = rpcckcr; 19662306a36Sopenharmony_ci rpcd2->gate.bit_idx = 9; 19762306a36Sopenharmony_ci rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE; 19862306a36Sopenharmony_ci rpcd2->gate.lock = &cpg_lock; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL, 20162306a36Sopenharmony_ci &rpcd2->fixed.hw, &clk_fixed_factor_ops, 20262306a36Sopenharmony_ci &rpcd2->gate.hw, &clk_gate_ops, 20362306a36Sopenharmony_ci CLK_SET_RATE_PARENT); 20462306a36Sopenharmony_ci if (IS_ERR(clk)) 20562306a36Sopenharmony_ci kfree(rpcd2); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return clk; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 210