162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * drivers/clk/clk-axm5516.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Provides clock implementations for three different types of clock devices on
662306a36Sopenharmony_ci * the Axxia device: PLL clock, a clock divider and a clock mux.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Copyright (C) 2014 LSI Corporation
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/slab.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/of.h>
1562306a36Sopenharmony_ci#include <linux/of_address.h>
1662306a36Sopenharmony_ci#include <linux/clk-provider.h>
1762306a36Sopenharmony_ci#include <linux/regmap.h>
1862306a36Sopenharmony_ci#include <dt-bindings/clock/lsi,axm5516-clks.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/**
2262306a36Sopenharmony_ci * struct axxia_clk - Common struct to all Axxia clocks.
2362306a36Sopenharmony_ci * @hw: clk_hw for the common clk framework
2462306a36Sopenharmony_ci * @regmap: Regmap for the clock control registers
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_cistruct axxia_clk {
2762306a36Sopenharmony_ci	struct clk_hw hw;
2862306a36Sopenharmony_ci	struct regmap *regmap;
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci#define to_axxia_clk(_hw) container_of(_hw, struct axxia_clk, hw)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/**
3362306a36Sopenharmony_ci * struct axxia_pllclk - Axxia PLL generated clock.
3462306a36Sopenharmony_ci * @aclk: Common struct
3562306a36Sopenharmony_ci * @reg: Offset into regmap for PLL control register
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_cistruct axxia_pllclk {
3862306a36Sopenharmony_ci	struct axxia_clk aclk;
3962306a36Sopenharmony_ci	u32 reg;
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci#define to_axxia_pllclk(_aclk) container_of(_aclk, struct axxia_pllclk, aclk)
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/**
4462306a36Sopenharmony_ci * axxia_pllclk_recalc - Calculate the PLL generated clock rate given the
4562306a36Sopenharmony_ci * parent clock rate.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistatic unsigned long
4862306a36Sopenharmony_ciaxxia_pllclk_recalc(struct clk_hw *hw, unsigned long parent_rate)
4962306a36Sopenharmony_ci{
5062306a36Sopenharmony_ci	struct axxia_clk *aclk = to_axxia_clk(hw);
5162306a36Sopenharmony_ci	struct axxia_pllclk *pll = to_axxia_pllclk(aclk);
5262306a36Sopenharmony_ci	unsigned long rate, fbdiv, refdiv, postdiv;
5362306a36Sopenharmony_ci	u32 control;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	regmap_read(aclk->regmap, pll->reg, &control);
5662306a36Sopenharmony_ci	postdiv = ((control >> 0) & 0xf) + 1;
5762306a36Sopenharmony_ci	fbdiv   = ((control >> 4) & 0xfff) + 3;
5862306a36Sopenharmony_ci	refdiv  = ((control >> 16) & 0x1f) + 1;
5962306a36Sopenharmony_ci	rate = (parent_rate / (refdiv * postdiv)) * fbdiv;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	return rate;
6262306a36Sopenharmony_ci}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic const struct clk_ops axxia_pllclk_ops = {
6562306a36Sopenharmony_ci	.recalc_rate = axxia_pllclk_recalc,
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/**
6962306a36Sopenharmony_ci * struct axxia_divclk - Axxia clock divider
7062306a36Sopenharmony_ci * @aclk: Common struct
7162306a36Sopenharmony_ci * @reg: Offset into regmap for PLL control register
7262306a36Sopenharmony_ci * @shift: Bit position for divider value
7362306a36Sopenharmony_ci * @width: Number of bits in divider value
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_cistruct axxia_divclk {
7662306a36Sopenharmony_ci	struct axxia_clk aclk;
7762306a36Sopenharmony_ci	u32 reg;
7862306a36Sopenharmony_ci	u32 shift;
7962306a36Sopenharmony_ci	u32 width;
8062306a36Sopenharmony_ci};
8162306a36Sopenharmony_ci#define to_axxia_divclk(_aclk) container_of(_aclk, struct axxia_divclk, aclk)
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci/**
8462306a36Sopenharmony_ci * axxia_divclk_recalc_rate - Calculate clock divider output rage
8562306a36Sopenharmony_ci */
8662306a36Sopenharmony_cistatic unsigned long
8762306a36Sopenharmony_ciaxxia_divclk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct axxia_clk *aclk = to_axxia_clk(hw);
9062306a36Sopenharmony_ci	struct axxia_divclk *divclk = to_axxia_divclk(aclk);
9162306a36Sopenharmony_ci	u32 ctrl, div;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	regmap_read(aclk->regmap, divclk->reg, &ctrl);
9462306a36Sopenharmony_ci	div = 1 + ((ctrl >> divclk->shift) & ((1 << divclk->width)-1));
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return parent_rate / div;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cistatic const struct clk_ops axxia_divclk_ops = {
10062306a36Sopenharmony_ci	.recalc_rate = axxia_divclk_recalc_rate,
10162306a36Sopenharmony_ci};
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/**
10462306a36Sopenharmony_ci * struct axxia_clkmux - Axxia clock mux
10562306a36Sopenharmony_ci * @aclk: Common struct
10662306a36Sopenharmony_ci * @reg: Offset into regmap for PLL control register
10762306a36Sopenharmony_ci * @shift: Bit position for selection value
10862306a36Sopenharmony_ci * @width: Number of bits in selection value
10962306a36Sopenharmony_ci */
11062306a36Sopenharmony_cistruct axxia_clkmux {
11162306a36Sopenharmony_ci	struct axxia_clk aclk;
11262306a36Sopenharmony_ci	u32 reg;
11362306a36Sopenharmony_ci	u32 shift;
11462306a36Sopenharmony_ci	u32 width;
11562306a36Sopenharmony_ci};
11662306a36Sopenharmony_ci#define to_axxia_clkmux(_aclk) container_of(_aclk, struct axxia_clkmux, aclk)
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/**
11962306a36Sopenharmony_ci * axxia_clkmux_get_parent - Return the index of selected parent clock
12062306a36Sopenharmony_ci */
12162306a36Sopenharmony_cistatic u8 axxia_clkmux_get_parent(struct clk_hw *hw)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct axxia_clk *aclk = to_axxia_clk(hw);
12462306a36Sopenharmony_ci	struct axxia_clkmux *mux = to_axxia_clkmux(aclk);
12562306a36Sopenharmony_ci	u32 ctrl, parent;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	regmap_read(aclk->regmap, mux->reg, &ctrl);
12862306a36Sopenharmony_ci	parent = (ctrl >> mux->shift) & ((1 << mux->width) - 1);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	return (u8) parent;
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic const struct clk_ops axxia_clkmux_ops = {
13462306a36Sopenharmony_ci	.get_parent = axxia_clkmux_get_parent,
13562306a36Sopenharmony_ci};
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/*
13962306a36Sopenharmony_ci * PLLs
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_cistatic struct axxia_pllclk clk_fab_pll = {
14362306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
14462306a36Sopenharmony_ci		.name = "clk_fab_pll",
14562306a36Sopenharmony_ci		.parent_names = (const char *[]){
14662306a36Sopenharmony_ci			"clk_ref0"
14762306a36Sopenharmony_ci		},
14862306a36Sopenharmony_ci		.num_parents = 1,
14962306a36Sopenharmony_ci		.ops = &axxia_pllclk_ops,
15062306a36Sopenharmony_ci	},
15162306a36Sopenharmony_ci	.reg   = 0x01800,
15262306a36Sopenharmony_ci};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic struct axxia_pllclk clk_cpu_pll = {
15562306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
15662306a36Sopenharmony_ci		.name = "clk_cpu_pll",
15762306a36Sopenharmony_ci		.parent_names = (const char *[]){
15862306a36Sopenharmony_ci			"clk_ref0"
15962306a36Sopenharmony_ci		},
16062306a36Sopenharmony_ci		.num_parents = 1,
16162306a36Sopenharmony_ci		.ops = &axxia_pllclk_ops,
16262306a36Sopenharmony_ci	},
16362306a36Sopenharmony_ci	.reg   = 0x02000,
16462306a36Sopenharmony_ci};
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_cistatic struct axxia_pllclk clk_sys_pll = {
16762306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
16862306a36Sopenharmony_ci		.name = "clk_sys_pll",
16962306a36Sopenharmony_ci		.parent_names = (const char *[]){
17062306a36Sopenharmony_ci			"clk_ref0"
17162306a36Sopenharmony_ci		},
17262306a36Sopenharmony_ci		.num_parents = 1,
17362306a36Sopenharmony_ci		.ops = &axxia_pllclk_ops,
17462306a36Sopenharmony_ci	},
17562306a36Sopenharmony_ci	.reg   = 0x02800,
17662306a36Sopenharmony_ci};
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_cistatic struct axxia_pllclk clk_sm0_pll = {
17962306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
18062306a36Sopenharmony_ci		.name = "clk_sm0_pll",
18162306a36Sopenharmony_ci		.parent_names = (const char *[]){
18262306a36Sopenharmony_ci			"clk_ref2"
18362306a36Sopenharmony_ci		},
18462306a36Sopenharmony_ci		.num_parents = 1,
18562306a36Sopenharmony_ci		.ops = &axxia_pllclk_ops,
18662306a36Sopenharmony_ci	},
18762306a36Sopenharmony_ci	.reg   = 0x03000,
18862306a36Sopenharmony_ci};
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_cistatic struct axxia_pllclk clk_sm1_pll = {
19162306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
19262306a36Sopenharmony_ci		.name = "clk_sm1_pll",
19362306a36Sopenharmony_ci		.parent_names = (const char *[]){
19462306a36Sopenharmony_ci			"clk_ref1"
19562306a36Sopenharmony_ci		},
19662306a36Sopenharmony_ci		.num_parents = 1,
19762306a36Sopenharmony_ci		.ops = &axxia_pllclk_ops,
19862306a36Sopenharmony_ci	},
19962306a36Sopenharmony_ci	.reg   = 0x03800,
20062306a36Sopenharmony_ci};
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/*
20362306a36Sopenharmony_ci * Clock dividers
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_cistatic struct axxia_divclk clk_cpu0_div = {
20762306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
20862306a36Sopenharmony_ci		.name = "clk_cpu0_div",
20962306a36Sopenharmony_ci		.parent_names = (const char *[]){
21062306a36Sopenharmony_ci			"clk_cpu_pll"
21162306a36Sopenharmony_ci		},
21262306a36Sopenharmony_ci		.num_parents = 1,
21362306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
21462306a36Sopenharmony_ci	},
21562306a36Sopenharmony_ci	.reg   = 0x10008,
21662306a36Sopenharmony_ci	.shift = 0,
21762306a36Sopenharmony_ci	.width = 4,
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic struct axxia_divclk clk_cpu1_div = {
22162306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
22262306a36Sopenharmony_ci		.name = "clk_cpu1_div",
22362306a36Sopenharmony_ci		.parent_names = (const char *[]){
22462306a36Sopenharmony_ci			"clk_cpu_pll"
22562306a36Sopenharmony_ci		},
22662306a36Sopenharmony_ci		.num_parents = 1,
22762306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
22862306a36Sopenharmony_ci	},
22962306a36Sopenharmony_ci	.reg   = 0x10008,
23062306a36Sopenharmony_ci	.shift = 4,
23162306a36Sopenharmony_ci	.width = 4,
23262306a36Sopenharmony_ci};
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_cistatic struct axxia_divclk clk_cpu2_div = {
23562306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
23662306a36Sopenharmony_ci		.name = "clk_cpu2_div",
23762306a36Sopenharmony_ci		.parent_names = (const char *[]){
23862306a36Sopenharmony_ci			"clk_cpu_pll"
23962306a36Sopenharmony_ci		},
24062306a36Sopenharmony_ci		.num_parents = 1,
24162306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
24262306a36Sopenharmony_ci	},
24362306a36Sopenharmony_ci	.reg   = 0x10008,
24462306a36Sopenharmony_ci	.shift = 8,
24562306a36Sopenharmony_ci	.width = 4,
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic struct axxia_divclk clk_cpu3_div = {
24962306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
25062306a36Sopenharmony_ci		.name = "clk_cpu3_div",
25162306a36Sopenharmony_ci		.parent_names = (const char *[]){
25262306a36Sopenharmony_ci			"clk_cpu_pll"
25362306a36Sopenharmony_ci		},
25462306a36Sopenharmony_ci		.num_parents = 1,
25562306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
25662306a36Sopenharmony_ci	},
25762306a36Sopenharmony_ci	.reg   = 0x10008,
25862306a36Sopenharmony_ci	.shift = 12,
25962306a36Sopenharmony_ci	.width = 4,
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic struct axxia_divclk clk_nrcp_div = {
26362306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
26462306a36Sopenharmony_ci		.name = "clk_nrcp_div",
26562306a36Sopenharmony_ci		.parent_names = (const char *[]){
26662306a36Sopenharmony_ci			"clk_sys_pll"
26762306a36Sopenharmony_ci		},
26862306a36Sopenharmony_ci		.num_parents = 1,
26962306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
27062306a36Sopenharmony_ci	},
27162306a36Sopenharmony_ci	.reg   = 0x1000c,
27262306a36Sopenharmony_ci	.shift = 0,
27362306a36Sopenharmony_ci	.width = 4,
27462306a36Sopenharmony_ci};
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_cistatic struct axxia_divclk clk_sys_div = {
27762306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
27862306a36Sopenharmony_ci		.name = "clk_sys_div",
27962306a36Sopenharmony_ci		.parent_names = (const char *[]){
28062306a36Sopenharmony_ci			"clk_sys_pll"
28162306a36Sopenharmony_ci		},
28262306a36Sopenharmony_ci		.num_parents = 1,
28362306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
28462306a36Sopenharmony_ci	},
28562306a36Sopenharmony_ci	.reg   = 0x1000c,
28662306a36Sopenharmony_ci	.shift = 4,
28762306a36Sopenharmony_ci	.width = 4,
28862306a36Sopenharmony_ci};
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_cistatic struct axxia_divclk clk_fab_div = {
29162306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
29262306a36Sopenharmony_ci		.name = "clk_fab_div",
29362306a36Sopenharmony_ci		.parent_names = (const char *[]){
29462306a36Sopenharmony_ci			"clk_fab_pll"
29562306a36Sopenharmony_ci		},
29662306a36Sopenharmony_ci		.num_parents = 1,
29762306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
29862306a36Sopenharmony_ci	},
29962306a36Sopenharmony_ci	.reg   = 0x1000c,
30062306a36Sopenharmony_ci	.shift = 8,
30162306a36Sopenharmony_ci	.width = 4,
30262306a36Sopenharmony_ci};
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_cistatic struct axxia_divclk clk_per_div = {
30562306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
30662306a36Sopenharmony_ci		.name = "clk_per_div",
30762306a36Sopenharmony_ci		.parent_names = (const char *[]){
30862306a36Sopenharmony_ci			"clk_sm1_pll"
30962306a36Sopenharmony_ci		},
31062306a36Sopenharmony_ci		.num_parents = 1,
31162306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
31262306a36Sopenharmony_ci	},
31362306a36Sopenharmony_ci	.reg   = 0x1000c,
31462306a36Sopenharmony_ci	.shift = 12,
31562306a36Sopenharmony_ci	.width = 4,
31662306a36Sopenharmony_ci};
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic struct axxia_divclk clk_mmc_div = {
31962306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
32062306a36Sopenharmony_ci		.name = "clk_mmc_div",
32162306a36Sopenharmony_ci		.parent_names = (const char *[]){
32262306a36Sopenharmony_ci			"clk_sm1_pll"
32362306a36Sopenharmony_ci		},
32462306a36Sopenharmony_ci		.num_parents = 1,
32562306a36Sopenharmony_ci		.ops = &axxia_divclk_ops,
32662306a36Sopenharmony_ci	},
32762306a36Sopenharmony_ci	.reg   = 0x1000c,
32862306a36Sopenharmony_ci	.shift = 16,
32962306a36Sopenharmony_ci	.width = 4,
33062306a36Sopenharmony_ci};
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci/*
33362306a36Sopenharmony_ci * Clock MUXes
33462306a36Sopenharmony_ci */
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_cistatic struct axxia_clkmux clk_cpu0_mux = {
33762306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
33862306a36Sopenharmony_ci		.name = "clk_cpu0",
33962306a36Sopenharmony_ci		.parent_names = (const char *[]){
34062306a36Sopenharmony_ci			"clk_ref0",
34162306a36Sopenharmony_ci			"clk_cpu_pll",
34262306a36Sopenharmony_ci			"clk_cpu0_div",
34362306a36Sopenharmony_ci			"clk_cpu0_div"
34462306a36Sopenharmony_ci		},
34562306a36Sopenharmony_ci		.num_parents = 4,
34662306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
34762306a36Sopenharmony_ci	},
34862306a36Sopenharmony_ci	.reg   = 0x10000,
34962306a36Sopenharmony_ci	.shift = 0,
35062306a36Sopenharmony_ci	.width = 2,
35162306a36Sopenharmony_ci};
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic struct axxia_clkmux clk_cpu1_mux = {
35462306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
35562306a36Sopenharmony_ci		.name = "clk_cpu1",
35662306a36Sopenharmony_ci		.parent_names = (const char *[]){
35762306a36Sopenharmony_ci			"clk_ref0",
35862306a36Sopenharmony_ci			"clk_cpu_pll",
35962306a36Sopenharmony_ci			"clk_cpu1_div",
36062306a36Sopenharmony_ci			"clk_cpu1_div"
36162306a36Sopenharmony_ci		},
36262306a36Sopenharmony_ci		.num_parents = 4,
36362306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
36462306a36Sopenharmony_ci	},
36562306a36Sopenharmony_ci	.reg   = 0x10000,
36662306a36Sopenharmony_ci	.shift = 2,
36762306a36Sopenharmony_ci	.width = 2,
36862306a36Sopenharmony_ci};
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_cistatic struct axxia_clkmux clk_cpu2_mux = {
37162306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
37262306a36Sopenharmony_ci		.name = "clk_cpu2",
37362306a36Sopenharmony_ci		.parent_names = (const char *[]){
37462306a36Sopenharmony_ci			"clk_ref0",
37562306a36Sopenharmony_ci			"clk_cpu_pll",
37662306a36Sopenharmony_ci			"clk_cpu2_div",
37762306a36Sopenharmony_ci			"clk_cpu2_div"
37862306a36Sopenharmony_ci		},
37962306a36Sopenharmony_ci		.num_parents = 4,
38062306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
38162306a36Sopenharmony_ci	},
38262306a36Sopenharmony_ci	.reg   = 0x10000,
38362306a36Sopenharmony_ci	.shift = 4,
38462306a36Sopenharmony_ci	.width = 2,
38562306a36Sopenharmony_ci};
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic struct axxia_clkmux clk_cpu3_mux = {
38862306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
38962306a36Sopenharmony_ci		.name = "clk_cpu3",
39062306a36Sopenharmony_ci		.parent_names = (const char *[]){
39162306a36Sopenharmony_ci			"clk_ref0",
39262306a36Sopenharmony_ci			"clk_cpu_pll",
39362306a36Sopenharmony_ci			"clk_cpu3_div",
39462306a36Sopenharmony_ci			"clk_cpu3_div"
39562306a36Sopenharmony_ci		},
39662306a36Sopenharmony_ci		.num_parents = 4,
39762306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
39862306a36Sopenharmony_ci	},
39962306a36Sopenharmony_ci	.reg   = 0x10000,
40062306a36Sopenharmony_ci	.shift = 6,
40162306a36Sopenharmony_ci	.width = 2,
40262306a36Sopenharmony_ci};
40362306a36Sopenharmony_ci
40462306a36Sopenharmony_cistatic struct axxia_clkmux clk_nrcp_mux = {
40562306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
40662306a36Sopenharmony_ci		.name = "clk_nrcp",
40762306a36Sopenharmony_ci		.parent_names = (const char *[]){
40862306a36Sopenharmony_ci			"clk_ref0",
40962306a36Sopenharmony_ci			"clk_sys_pll",
41062306a36Sopenharmony_ci			"clk_nrcp_div",
41162306a36Sopenharmony_ci			"clk_nrcp_div"
41262306a36Sopenharmony_ci		},
41362306a36Sopenharmony_ci		.num_parents = 4,
41462306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
41562306a36Sopenharmony_ci	},
41662306a36Sopenharmony_ci	.reg   = 0x10004,
41762306a36Sopenharmony_ci	.shift = 0,
41862306a36Sopenharmony_ci	.width = 2,
41962306a36Sopenharmony_ci};
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_cistatic struct axxia_clkmux clk_sys_mux = {
42262306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
42362306a36Sopenharmony_ci		.name = "clk_sys",
42462306a36Sopenharmony_ci		.parent_names = (const char *[]){
42562306a36Sopenharmony_ci			"clk_ref0",
42662306a36Sopenharmony_ci			"clk_sys_pll",
42762306a36Sopenharmony_ci			"clk_sys_div",
42862306a36Sopenharmony_ci			"clk_sys_div"
42962306a36Sopenharmony_ci		},
43062306a36Sopenharmony_ci		.num_parents = 4,
43162306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
43262306a36Sopenharmony_ci	},
43362306a36Sopenharmony_ci	.reg   = 0x10004,
43462306a36Sopenharmony_ci	.shift = 2,
43562306a36Sopenharmony_ci	.width = 2,
43662306a36Sopenharmony_ci};
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic struct axxia_clkmux clk_fab_mux = {
43962306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
44062306a36Sopenharmony_ci		.name = "clk_fab",
44162306a36Sopenharmony_ci		.parent_names = (const char *[]){
44262306a36Sopenharmony_ci			"clk_ref0",
44362306a36Sopenharmony_ci			"clk_fab_pll",
44462306a36Sopenharmony_ci			"clk_fab_div",
44562306a36Sopenharmony_ci			"clk_fab_div"
44662306a36Sopenharmony_ci		},
44762306a36Sopenharmony_ci		.num_parents = 4,
44862306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
44962306a36Sopenharmony_ci	},
45062306a36Sopenharmony_ci	.reg   = 0x10004,
45162306a36Sopenharmony_ci	.shift = 4,
45262306a36Sopenharmony_ci	.width = 2,
45362306a36Sopenharmony_ci};
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic struct axxia_clkmux clk_per_mux = {
45662306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
45762306a36Sopenharmony_ci		.name = "clk_per",
45862306a36Sopenharmony_ci		.parent_names = (const char *[]){
45962306a36Sopenharmony_ci			"clk_ref1",
46062306a36Sopenharmony_ci			"clk_per_div"
46162306a36Sopenharmony_ci		},
46262306a36Sopenharmony_ci		.num_parents = 2,
46362306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
46462306a36Sopenharmony_ci	},
46562306a36Sopenharmony_ci	.reg   = 0x10004,
46662306a36Sopenharmony_ci	.shift = 6,
46762306a36Sopenharmony_ci	.width = 1,
46862306a36Sopenharmony_ci};
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic struct axxia_clkmux clk_mmc_mux = {
47162306a36Sopenharmony_ci	.aclk.hw.init = &(struct clk_init_data){
47262306a36Sopenharmony_ci		.name = "clk_mmc",
47362306a36Sopenharmony_ci		.parent_names = (const char *[]){
47462306a36Sopenharmony_ci			"clk_ref1",
47562306a36Sopenharmony_ci			"clk_mmc_div"
47662306a36Sopenharmony_ci		},
47762306a36Sopenharmony_ci		.num_parents = 2,
47862306a36Sopenharmony_ci		.ops = &axxia_clkmux_ops,
47962306a36Sopenharmony_ci	},
48062306a36Sopenharmony_ci	.reg   = 0x10004,
48162306a36Sopenharmony_ci	.shift = 9,
48262306a36Sopenharmony_ci	.width = 1,
48362306a36Sopenharmony_ci};
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci/* Table of all supported clocks indexed by the clock identifiers from the
48662306a36Sopenharmony_ci * device tree binding
48762306a36Sopenharmony_ci */
48862306a36Sopenharmony_cistatic struct axxia_clk *axmclk_clocks[] = {
48962306a36Sopenharmony_ci	[AXXIA_CLK_FAB_PLL]  = &clk_fab_pll.aclk,
49062306a36Sopenharmony_ci	[AXXIA_CLK_CPU_PLL]  = &clk_cpu_pll.aclk,
49162306a36Sopenharmony_ci	[AXXIA_CLK_SYS_PLL]  = &clk_sys_pll.aclk,
49262306a36Sopenharmony_ci	[AXXIA_CLK_SM0_PLL]  = &clk_sm0_pll.aclk,
49362306a36Sopenharmony_ci	[AXXIA_CLK_SM1_PLL]  = &clk_sm1_pll.aclk,
49462306a36Sopenharmony_ci	[AXXIA_CLK_FAB_DIV]  = &clk_fab_div.aclk,
49562306a36Sopenharmony_ci	[AXXIA_CLK_SYS_DIV]  = &clk_sys_div.aclk,
49662306a36Sopenharmony_ci	[AXXIA_CLK_NRCP_DIV] = &clk_nrcp_div.aclk,
49762306a36Sopenharmony_ci	[AXXIA_CLK_CPU0_DIV] = &clk_cpu0_div.aclk,
49862306a36Sopenharmony_ci	[AXXIA_CLK_CPU1_DIV] = &clk_cpu1_div.aclk,
49962306a36Sopenharmony_ci	[AXXIA_CLK_CPU2_DIV] = &clk_cpu2_div.aclk,
50062306a36Sopenharmony_ci	[AXXIA_CLK_CPU3_DIV] = &clk_cpu3_div.aclk,
50162306a36Sopenharmony_ci	[AXXIA_CLK_PER_DIV]  = &clk_per_div.aclk,
50262306a36Sopenharmony_ci	[AXXIA_CLK_MMC_DIV]  = &clk_mmc_div.aclk,
50362306a36Sopenharmony_ci	[AXXIA_CLK_FAB]      = &clk_fab_mux.aclk,
50462306a36Sopenharmony_ci	[AXXIA_CLK_SYS]      = &clk_sys_mux.aclk,
50562306a36Sopenharmony_ci	[AXXIA_CLK_NRCP]     = &clk_nrcp_mux.aclk,
50662306a36Sopenharmony_ci	[AXXIA_CLK_CPU0]     = &clk_cpu0_mux.aclk,
50762306a36Sopenharmony_ci	[AXXIA_CLK_CPU1]     = &clk_cpu1_mux.aclk,
50862306a36Sopenharmony_ci	[AXXIA_CLK_CPU2]     = &clk_cpu2_mux.aclk,
50962306a36Sopenharmony_ci	[AXXIA_CLK_CPU3]     = &clk_cpu3_mux.aclk,
51062306a36Sopenharmony_ci	[AXXIA_CLK_PER]      = &clk_per_mux.aclk,
51162306a36Sopenharmony_ci	[AXXIA_CLK_MMC]      = &clk_mmc_mux.aclk,
51262306a36Sopenharmony_ci};
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_cistatic struct clk_hw *
51562306a36Sopenharmony_ciof_clk_axmclk_get(struct of_phandle_args *clkspec, void *unused)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	unsigned int idx = clkspec->args[0];
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (idx >= ARRAY_SIZE(axmclk_clocks)) {
52062306a36Sopenharmony_ci		pr_err("%s: invalid index %u\n", __func__, idx);
52162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	return &axmclk_clocks[idx]->hw;
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic const struct regmap_config axmclk_regmap_config = {
52862306a36Sopenharmony_ci	.reg_bits	= 32,
52962306a36Sopenharmony_ci	.reg_stride	= 4,
53062306a36Sopenharmony_ci	.val_bits	= 32,
53162306a36Sopenharmony_ci	.max_register	= 0x1fffc,
53262306a36Sopenharmony_ci	.fast_io	= true,
53362306a36Sopenharmony_ci};
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_cistatic const struct of_device_id axmclk_match_table[] = {
53662306a36Sopenharmony_ci	{ .compatible = "lsi,axm5516-clks" },
53762306a36Sopenharmony_ci	{ }
53862306a36Sopenharmony_ci};
53962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, axmclk_match_table);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic int axmclk_probe(struct platform_device *pdev)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	void __iomem *base;
54462306a36Sopenharmony_ci	int i, ret;
54562306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
54662306a36Sopenharmony_ci	struct regmap *regmap;
54762306a36Sopenharmony_ci	size_t num_clks;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	base = devm_platform_ioremap_resource(pdev, 0);
55062306a36Sopenharmony_ci	if (IS_ERR(base))
55162306a36Sopenharmony_ci		return PTR_ERR(base);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	regmap = devm_regmap_init_mmio(dev, base, &axmclk_regmap_config);
55462306a36Sopenharmony_ci	if (IS_ERR(regmap))
55562306a36Sopenharmony_ci		return PTR_ERR(regmap);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	num_clks = ARRAY_SIZE(axmclk_clocks);
55862306a36Sopenharmony_ci	pr_info("axmclk: supporting %zu clocks\n", num_clks);
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* Update each entry with the allocated regmap and register the clock
56162306a36Sopenharmony_ci	 * with the common clock framework
56262306a36Sopenharmony_ci	 */
56362306a36Sopenharmony_ci	for (i = 0; i < num_clks; i++) {
56462306a36Sopenharmony_ci		axmclk_clocks[i]->regmap = regmap;
56562306a36Sopenharmony_ci		ret = devm_clk_hw_register(dev, &axmclk_clocks[i]->hw);
56662306a36Sopenharmony_ci		if (ret)
56762306a36Sopenharmony_ci			return ret;
56862306a36Sopenharmony_ci	}
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	return devm_of_clk_add_hw_provider(dev, of_clk_axmclk_get, NULL);
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_cistatic struct platform_driver axmclk_driver = {
57462306a36Sopenharmony_ci	.probe		= axmclk_probe,
57562306a36Sopenharmony_ci	.driver		= {
57662306a36Sopenharmony_ci		.name	= "clk-axm5516",
57762306a36Sopenharmony_ci		.of_match_table = axmclk_match_table,
57862306a36Sopenharmony_ci	},
57962306a36Sopenharmony_ci};
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic int __init axmclk_init(void)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	return platform_driver_register(&axmclk_driver);
58462306a36Sopenharmony_ci}
58562306a36Sopenharmony_cicore_initcall(axmclk_init);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_cistatic void __exit axmclk_exit(void)
58862306a36Sopenharmony_ci{
58962306a36Sopenharmony_ci	platform_driver_unregister(&axmclk_driver);
59062306a36Sopenharmony_ci}
59162306a36Sopenharmony_cimodule_exit(axmclk_exit);
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ciMODULE_DESCRIPTION("AXM5516 clock driver");
59462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
59562306a36Sopenharmony_ciMODULE_ALIAS("platform:clk-axm5516");
596