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