162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014, The Linux Foundation. All rights reserved.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/kernel.h>
762306a36Sopenharmony_ci#include <linux/bitops.h>
862306a36Sopenharmony_ci#include <linux/err.h>
962306a36Sopenharmony_ci#include <linux/platform_device.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/of.h>
1262306a36Sopenharmony_ci#include <linux/clk-provider.h>
1362306a36Sopenharmony_ci#include <linux/regmap.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <dt-bindings/clock/qcom,lcc-msm8960.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "common.h"
1862306a36Sopenharmony_ci#include "clk-regmap.h"
1962306a36Sopenharmony_ci#include "clk-pll.h"
2062306a36Sopenharmony_ci#include "clk-rcg.h"
2162306a36Sopenharmony_ci#include "clk-branch.h"
2262306a36Sopenharmony_ci#include "clk-regmap-divider.h"
2362306a36Sopenharmony_ci#include "clk-regmap-mux.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistatic struct clk_parent_data pxo_parent_data = {
2662306a36Sopenharmony_ci	.fw_name = "pxo", .name = "pxo_board",
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic struct clk_pll pll4 = {
3062306a36Sopenharmony_ci	.l_reg = 0x4,
3162306a36Sopenharmony_ci	.m_reg = 0x8,
3262306a36Sopenharmony_ci	.n_reg = 0xc,
3362306a36Sopenharmony_ci	.config_reg = 0x14,
3462306a36Sopenharmony_ci	.mode_reg = 0x0,
3562306a36Sopenharmony_ci	.status_reg = 0x18,
3662306a36Sopenharmony_ci	.status_bit = 16,
3762306a36Sopenharmony_ci	.clkr.hw.init = &(struct clk_init_data){
3862306a36Sopenharmony_ci		.name = "pll4",
3962306a36Sopenharmony_ci		.parent_data = &pxo_parent_data,
4062306a36Sopenharmony_ci		.num_parents = 1,
4162306a36Sopenharmony_ci		.ops = &clk_pll_ops,
4262306a36Sopenharmony_ci	},
4362306a36Sopenharmony_ci};
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_cienum {
4662306a36Sopenharmony_ci	P_PXO,
4762306a36Sopenharmony_ci	P_PLL4,
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic const struct parent_map lcc_pxo_pll4_map[] = {
5162306a36Sopenharmony_ci	{ P_PXO, 0 },
5262306a36Sopenharmony_ci	{ P_PLL4, 2 }
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic struct clk_parent_data lcc_pxo_pll4[] = {
5662306a36Sopenharmony_ci	{ .fw_name = "pxo", .name = "pxo_board" },
5762306a36Sopenharmony_ci	{ .fw_name = "pll4_vote", .name = "pll4_vote" },
5862306a36Sopenharmony_ci};
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_cistatic struct freq_tbl clk_tbl_aif_osr_492[] = {
6162306a36Sopenharmony_ci	{   512000, P_PLL4, 4, 1, 240 },
6262306a36Sopenharmony_ci	{   768000, P_PLL4, 4, 1, 160 },
6362306a36Sopenharmony_ci	{  1024000, P_PLL4, 4, 1, 120 },
6462306a36Sopenharmony_ci	{  1536000, P_PLL4, 4, 1,  80 },
6562306a36Sopenharmony_ci	{  2048000, P_PLL4, 4, 1,  60 },
6662306a36Sopenharmony_ci	{  3072000, P_PLL4, 4, 1,  40 },
6762306a36Sopenharmony_ci	{  4096000, P_PLL4, 4, 1,  30 },
6862306a36Sopenharmony_ci	{  6144000, P_PLL4, 4, 1,  20 },
6962306a36Sopenharmony_ci	{  8192000, P_PLL4, 4, 1,  15 },
7062306a36Sopenharmony_ci	{ 12288000, P_PLL4, 4, 1,  10 },
7162306a36Sopenharmony_ci	{ 24576000, P_PLL4, 4, 1,   5 },
7262306a36Sopenharmony_ci	{ 27000000, P_PXO,  1, 0,   0 },
7362306a36Sopenharmony_ci	{ }
7462306a36Sopenharmony_ci};
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic struct freq_tbl clk_tbl_aif_osr_393[] = {
7762306a36Sopenharmony_ci	{   512000, P_PLL4, 4, 1, 192 },
7862306a36Sopenharmony_ci	{   768000, P_PLL4, 4, 1, 128 },
7962306a36Sopenharmony_ci	{  1024000, P_PLL4, 4, 1,  96 },
8062306a36Sopenharmony_ci	{  1536000, P_PLL4, 4, 1,  64 },
8162306a36Sopenharmony_ci	{  2048000, P_PLL4, 4, 1,  48 },
8262306a36Sopenharmony_ci	{  3072000, P_PLL4, 4, 1,  32 },
8362306a36Sopenharmony_ci	{  4096000, P_PLL4, 4, 1,  24 },
8462306a36Sopenharmony_ci	{  6144000, P_PLL4, 4, 1,  16 },
8562306a36Sopenharmony_ci	{  8192000, P_PLL4, 4, 1,  12 },
8662306a36Sopenharmony_ci	{ 12288000, P_PLL4, 4, 1,   8 },
8762306a36Sopenharmony_ci	{ 24576000, P_PLL4, 4, 1,   4 },
8862306a36Sopenharmony_ci	{ 27000000, P_PXO,  1, 0,   0 },
8962306a36Sopenharmony_ci	{ }
9062306a36Sopenharmony_ci};
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci#define CLK_AIF_OSR_SRC(prefix, _ns, _md)			\
9362306a36Sopenharmony_cistatic struct clk_rcg prefix##_osr_src = {			\
9462306a36Sopenharmony_ci	.ns_reg = _ns,						\
9562306a36Sopenharmony_ci	.md_reg = _md,						\
9662306a36Sopenharmony_ci	.mn = {							\
9762306a36Sopenharmony_ci		.mnctr_en_bit = 8,				\
9862306a36Sopenharmony_ci		.mnctr_reset_bit = 7,				\
9962306a36Sopenharmony_ci		.mnctr_mode_shift = 5,				\
10062306a36Sopenharmony_ci		.n_val_shift = 24,				\
10162306a36Sopenharmony_ci		.m_val_shift = 8,				\
10262306a36Sopenharmony_ci		.width = 8,					\
10362306a36Sopenharmony_ci	},							\
10462306a36Sopenharmony_ci	.p = {							\
10562306a36Sopenharmony_ci		.pre_div_shift = 3,				\
10662306a36Sopenharmony_ci		.pre_div_width = 2,				\
10762306a36Sopenharmony_ci	},							\
10862306a36Sopenharmony_ci	.s = {							\
10962306a36Sopenharmony_ci		.src_sel_shift = 0,				\
11062306a36Sopenharmony_ci		.parent_map = lcc_pxo_pll4_map,			\
11162306a36Sopenharmony_ci	},							\
11262306a36Sopenharmony_ci	.freq_tbl = clk_tbl_aif_osr_393,			\
11362306a36Sopenharmony_ci	.clkr = {						\
11462306a36Sopenharmony_ci		.enable_reg = _ns,				\
11562306a36Sopenharmony_ci		.enable_mask = BIT(9),				\
11662306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){		\
11762306a36Sopenharmony_ci			.name = #prefix "_osr_src",		\
11862306a36Sopenharmony_ci			.parent_data = lcc_pxo_pll4,		\
11962306a36Sopenharmony_ci			.num_parents = ARRAY_SIZE(lcc_pxo_pll4), \
12062306a36Sopenharmony_ci			.ops = &clk_rcg_ops,			\
12162306a36Sopenharmony_ci			.flags = CLK_SET_RATE_GATE,		\
12262306a36Sopenharmony_ci		},						\
12362306a36Sopenharmony_ci	},							\
12462306a36Sopenharmony_ci};								\
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci#define CLK_AIF_OSR_CLK(prefix, _ns, hr, en_bit)		\
12762306a36Sopenharmony_cistatic struct clk_branch prefix##_osr_clk = {			\
12862306a36Sopenharmony_ci	.halt_reg = hr,						\
12962306a36Sopenharmony_ci	.halt_bit = 1,						\
13062306a36Sopenharmony_ci	.halt_check = BRANCH_HALT_ENABLE,			\
13162306a36Sopenharmony_ci	.clkr = {						\
13262306a36Sopenharmony_ci		.enable_reg = _ns,				\
13362306a36Sopenharmony_ci		.enable_mask = BIT(en_bit),			\
13462306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){		\
13562306a36Sopenharmony_ci			.name = #prefix "_osr_clk",		\
13662306a36Sopenharmony_ci			.parent_hws = (const struct clk_hw*[]){	\
13762306a36Sopenharmony_ci				&prefix##_osr_src.clkr.hw,	\
13862306a36Sopenharmony_ci			},					\
13962306a36Sopenharmony_ci			.num_parents = 1,			\
14062306a36Sopenharmony_ci			.ops = &clk_branch_ops,			\
14162306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,		\
14262306a36Sopenharmony_ci		},						\
14362306a36Sopenharmony_ci	},							\
14462306a36Sopenharmony_ci};								\
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#define CLK_AIF_OSR_DIV_CLK(prefix, _ns, _width)		\
14762306a36Sopenharmony_cistatic struct clk_regmap_div prefix##_div_clk = {		\
14862306a36Sopenharmony_ci	.reg = _ns,						\
14962306a36Sopenharmony_ci	.shift = 10,						\
15062306a36Sopenharmony_ci	.width = _width,					\
15162306a36Sopenharmony_ci	.clkr = {						\
15262306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){		\
15362306a36Sopenharmony_ci			.name = #prefix "_div_clk",		\
15462306a36Sopenharmony_ci			.parent_hws = (const struct clk_hw*[]){	\
15562306a36Sopenharmony_ci				&prefix##_osr_src.clkr.hw,	\
15662306a36Sopenharmony_ci			},					\
15762306a36Sopenharmony_ci			.num_parents = 1,			\
15862306a36Sopenharmony_ci			.ops = &clk_regmap_div_ops,		\
15962306a36Sopenharmony_ci		},						\
16062306a36Sopenharmony_ci	},							\
16162306a36Sopenharmony_ci};								\
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci#define CLK_AIF_OSR_BIT_DIV_CLK(prefix, _ns, hr, en_bit)	\
16462306a36Sopenharmony_cistatic struct clk_branch prefix##_bit_div_clk = {		\
16562306a36Sopenharmony_ci	.halt_reg = hr,						\
16662306a36Sopenharmony_ci	.halt_bit = 0,						\
16762306a36Sopenharmony_ci	.halt_check = BRANCH_HALT_ENABLE,			\
16862306a36Sopenharmony_ci	.clkr = {						\
16962306a36Sopenharmony_ci		.enable_reg = _ns,				\
17062306a36Sopenharmony_ci		.enable_mask = BIT(en_bit),			\
17162306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){		\
17262306a36Sopenharmony_ci			.name = #prefix "_bit_div_clk",		\
17362306a36Sopenharmony_ci			.parent_hws = (const struct clk_hw*[]){	\
17462306a36Sopenharmony_ci				&prefix##_div_clk.clkr.hw,	\
17562306a36Sopenharmony_ci			},					\
17662306a36Sopenharmony_ci			.num_parents = 1,			\
17762306a36Sopenharmony_ci			.ops = &clk_branch_ops,			\
17862306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,		\
17962306a36Sopenharmony_ci		},						\
18062306a36Sopenharmony_ci	},							\
18162306a36Sopenharmony_ci};								\
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci#define CLK_AIF_OSR_BIT_CLK(prefix, _ns, _shift)		\
18462306a36Sopenharmony_cistatic struct clk_regmap_mux prefix##_bit_clk = {		\
18562306a36Sopenharmony_ci	.reg = _ns,						\
18662306a36Sopenharmony_ci	.shift = _shift,					\
18762306a36Sopenharmony_ci	.width = 1,						\
18862306a36Sopenharmony_ci	.clkr = {						\
18962306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){		\
19062306a36Sopenharmony_ci			.name = #prefix "_bit_clk",		\
19162306a36Sopenharmony_ci			.parent_data = (const struct clk_parent_data[]){ \
19262306a36Sopenharmony_ci				{ .hw = &prefix##_bit_div_clk.clkr.hw, }, \
19362306a36Sopenharmony_ci				{ .fw_name = #prefix "_codec_clk", \
19462306a36Sopenharmony_ci				  .name = #prefix "_codec_clk", }, \
19562306a36Sopenharmony_ci			},					\
19662306a36Sopenharmony_ci			.num_parents = 2,			\
19762306a36Sopenharmony_ci			.ops = &clk_regmap_mux_closest_ops,	\
19862306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,		\
19962306a36Sopenharmony_ci		},						\
20062306a36Sopenharmony_ci	},							\
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciCLK_AIF_OSR_SRC(mi2s, 0x48, 0x4c)
20462306a36Sopenharmony_ciCLK_AIF_OSR_CLK(mi2s, 0x48, 0x50, 17)
20562306a36Sopenharmony_ciCLK_AIF_OSR_DIV_CLK(mi2s, 0x48, 4)
20662306a36Sopenharmony_ciCLK_AIF_OSR_BIT_DIV_CLK(mi2s, 0x48, 0x50, 15)
20762306a36Sopenharmony_ciCLK_AIF_OSR_BIT_CLK(mi2s, 0x48, 14)
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr)			\
21062306a36Sopenharmony_ci	CLK_AIF_OSR_SRC(prefix, _ns, _md)			\
21162306a36Sopenharmony_ci	CLK_AIF_OSR_CLK(prefix, _ns, hr, 21)			\
21262306a36Sopenharmony_ci	CLK_AIF_OSR_DIV_CLK(prefix, _ns, 8)			\
21362306a36Sopenharmony_ci	CLK_AIF_OSR_BIT_DIV_CLK(prefix, _ns, hr, 19)		\
21462306a36Sopenharmony_ci	CLK_AIF_OSR_BIT_CLK(prefix, _ns, 18)
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciCLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
21762306a36Sopenharmony_ciCLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
21862306a36Sopenharmony_ciCLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
21962306a36Sopenharmony_ciCLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic struct freq_tbl clk_tbl_pcm_492[] = {
22262306a36Sopenharmony_ci	{   256000, P_PLL4, 4, 1, 480 },
22362306a36Sopenharmony_ci	{   512000, P_PLL4, 4, 1, 240 },
22462306a36Sopenharmony_ci	{   768000, P_PLL4, 4, 1, 160 },
22562306a36Sopenharmony_ci	{  1024000, P_PLL4, 4, 1, 120 },
22662306a36Sopenharmony_ci	{  1536000, P_PLL4, 4, 1,  80 },
22762306a36Sopenharmony_ci	{  2048000, P_PLL4, 4, 1,  60 },
22862306a36Sopenharmony_ci	{  3072000, P_PLL4, 4, 1,  40 },
22962306a36Sopenharmony_ci	{  4096000, P_PLL4, 4, 1,  30 },
23062306a36Sopenharmony_ci	{  6144000, P_PLL4, 4, 1,  20 },
23162306a36Sopenharmony_ci	{  8192000, P_PLL4, 4, 1,  15 },
23262306a36Sopenharmony_ci	{ 12288000, P_PLL4, 4, 1,  10 },
23362306a36Sopenharmony_ci	{ 24576000, P_PLL4, 4, 1,   5 },
23462306a36Sopenharmony_ci	{ 27000000, P_PXO,  1, 0,   0 },
23562306a36Sopenharmony_ci	{ }
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_cistatic struct freq_tbl clk_tbl_pcm_393[] = {
23962306a36Sopenharmony_ci	{   256000, P_PLL4, 4, 1, 384 },
24062306a36Sopenharmony_ci	{   512000, P_PLL4, 4, 1, 192 },
24162306a36Sopenharmony_ci	{   768000, P_PLL4, 4, 1, 128 },
24262306a36Sopenharmony_ci	{  1024000, P_PLL4, 4, 1,  96 },
24362306a36Sopenharmony_ci	{  1536000, P_PLL4, 4, 1,  64 },
24462306a36Sopenharmony_ci	{  2048000, P_PLL4, 4, 1,  48 },
24562306a36Sopenharmony_ci	{  3072000, P_PLL4, 4, 1,  32 },
24662306a36Sopenharmony_ci	{  4096000, P_PLL4, 4, 1,  24 },
24762306a36Sopenharmony_ci	{  6144000, P_PLL4, 4, 1,  16 },
24862306a36Sopenharmony_ci	{  8192000, P_PLL4, 4, 1,  12 },
24962306a36Sopenharmony_ci	{ 12288000, P_PLL4, 4, 1,   8 },
25062306a36Sopenharmony_ci	{ 24576000, P_PLL4, 4, 1,   4 },
25162306a36Sopenharmony_ci	{ 27000000, P_PXO,  1, 0,   0 },
25262306a36Sopenharmony_ci	{ }
25362306a36Sopenharmony_ci};
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic struct clk_rcg pcm_src = {
25662306a36Sopenharmony_ci	.ns_reg = 0x54,
25762306a36Sopenharmony_ci	.md_reg = 0x58,
25862306a36Sopenharmony_ci	.mn = {
25962306a36Sopenharmony_ci		.mnctr_en_bit = 8,
26062306a36Sopenharmony_ci		.mnctr_reset_bit = 7,
26162306a36Sopenharmony_ci		.mnctr_mode_shift = 5,
26262306a36Sopenharmony_ci		.n_val_shift = 16,
26362306a36Sopenharmony_ci		.m_val_shift = 16,
26462306a36Sopenharmony_ci		.width = 16,
26562306a36Sopenharmony_ci	},
26662306a36Sopenharmony_ci	.p = {
26762306a36Sopenharmony_ci		.pre_div_shift = 3,
26862306a36Sopenharmony_ci		.pre_div_width = 2,
26962306a36Sopenharmony_ci	},
27062306a36Sopenharmony_ci	.s = {
27162306a36Sopenharmony_ci		.src_sel_shift = 0,
27262306a36Sopenharmony_ci		.parent_map = lcc_pxo_pll4_map,
27362306a36Sopenharmony_ci	},
27462306a36Sopenharmony_ci	.freq_tbl = clk_tbl_pcm_393,
27562306a36Sopenharmony_ci	.clkr = {
27662306a36Sopenharmony_ci		.enable_reg = 0x54,
27762306a36Sopenharmony_ci		.enable_mask = BIT(9),
27862306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){
27962306a36Sopenharmony_ci			.name = "pcm_src",
28062306a36Sopenharmony_ci			.parent_data = lcc_pxo_pll4,
28162306a36Sopenharmony_ci			.num_parents = ARRAY_SIZE(lcc_pxo_pll4),
28262306a36Sopenharmony_ci			.ops = &clk_rcg_ops,
28362306a36Sopenharmony_ci			.flags = CLK_SET_RATE_GATE,
28462306a36Sopenharmony_ci		},
28562306a36Sopenharmony_ci	},
28662306a36Sopenharmony_ci};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic struct clk_branch pcm_clk_out = {
28962306a36Sopenharmony_ci	.halt_reg = 0x5c,
29062306a36Sopenharmony_ci	.halt_bit = 0,
29162306a36Sopenharmony_ci	.halt_check = BRANCH_HALT_ENABLE,
29262306a36Sopenharmony_ci	.clkr = {
29362306a36Sopenharmony_ci		.enable_reg = 0x54,
29462306a36Sopenharmony_ci		.enable_mask = BIT(11),
29562306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){
29662306a36Sopenharmony_ci			.name = "pcm_clk_out",
29762306a36Sopenharmony_ci			.parent_hws = (const struct clk_hw*[]){
29862306a36Sopenharmony_ci				&pcm_src.clkr.hw
29962306a36Sopenharmony_ci			},
30062306a36Sopenharmony_ci			.num_parents = 1,
30162306a36Sopenharmony_ci			.ops = &clk_branch_ops,
30262306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,
30362306a36Sopenharmony_ci		},
30462306a36Sopenharmony_ci	},
30562306a36Sopenharmony_ci};
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic struct clk_regmap_mux pcm_clk = {
30862306a36Sopenharmony_ci	.reg = 0x54,
30962306a36Sopenharmony_ci	.shift = 10,
31062306a36Sopenharmony_ci	.width = 1,
31162306a36Sopenharmony_ci	.clkr = {
31262306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){
31362306a36Sopenharmony_ci			.name = "pcm_clk",
31462306a36Sopenharmony_ci			.parent_data = (const struct clk_parent_data[]){
31562306a36Sopenharmony_ci				{ .hw = &pcm_clk_out.clkr.hw },
31662306a36Sopenharmony_ci				{ .fw_name = "pcm_codec_clk", .name = "pcm_codec_clk" },
31762306a36Sopenharmony_ci			},
31862306a36Sopenharmony_ci			.num_parents = 2,
31962306a36Sopenharmony_ci			.ops = &clk_regmap_mux_closest_ops,
32062306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,
32162306a36Sopenharmony_ci		},
32262306a36Sopenharmony_ci	},
32362306a36Sopenharmony_ci};
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_cistatic struct clk_rcg slimbus_src = {
32662306a36Sopenharmony_ci	.ns_reg = 0xcc,
32762306a36Sopenharmony_ci	.md_reg = 0xd0,
32862306a36Sopenharmony_ci	.mn = {
32962306a36Sopenharmony_ci		.mnctr_en_bit = 8,
33062306a36Sopenharmony_ci		.mnctr_reset_bit = 7,
33162306a36Sopenharmony_ci		.mnctr_mode_shift = 5,
33262306a36Sopenharmony_ci		.n_val_shift = 24,
33362306a36Sopenharmony_ci		.m_val_shift = 8,
33462306a36Sopenharmony_ci		.width = 8,
33562306a36Sopenharmony_ci	},
33662306a36Sopenharmony_ci	.p = {
33762306a36Sopenharmony_ci		.pre_div_shift = 3,
33862306a36Sopenharmony_ci		.pre_div_width = 2,
33962306a36Sopenharmony_ci	},
34062306a36Sopenharmony_ci	.s = {
34162306a36Sopenharmony_ci		.src_sel_shift = 0,
34262306a36Sopenharmony_ci		.parent_map = lcc_pxo_pll4_map,
34362306a36Sopenharmony_ci	},
34462306a36Sopenharmony_ci	.freq_tbl = clk_tbl_aif_osr_393,
34562306a36Sopenharmony_ci	.clkr = {
34662306a36Sopenharmony_ci		.enable_reg = 0xcc,
34762306a36Sopenharmony_ci		.enable_mask = BIT(9),
34862306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){
34962306a36Sopenharmony_ci			.name = "slimbus_src",
35062306a36Sopenharmony_ci			.parent_data = lcc_pxo_pll4,
35162306a36Sopenharmony_ci			.num_parents = ARRAY_SIZE(lcc_pxo_pll4),
35262306a36Sopenharmony_ci			.ops = &clk_rcg_ops,
35362306a36Sopenharmony_ci			.flags = CLK_SET_RATE_GATE,
35462306a36Sopenharmony_ci		},
35562306a36Sopenharmony_ci	},
35662306a36Sopenharmony_ci};
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic struct clk_branch audio_slimbus_clk = {
35962306a36Sopenharmony_ci	.halt_reg = 0xd4,
36062306a36Sopenharmony_ci	.halt_bit = 0,
36162306a36Sopenharmony_ci	.halt_check = BRANCH_HALT_ENABLE,
36262306a36Sopenharmony_ci	.clkr = {
36362306a36Sopenharmony_ci		.enable_reg = 0xcc,
36462306a36Sopenharmony_ci		.enable_mask = BIT(10),
36562306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){
36662306a36Sopenharmony_ci			.name = "audio_slimbus_clk",
36762306a36Sopenharmony_ci			.parent_hws = (const struct clk_hw*[]){
36862306a36Sopenharmony_ci				&slimbus_src.clkr.hw,
36962306a36Sopenharmony_ci			},
37062306a36Sopenharmony_ci			.num_parents = 1,
37162306a36Sopenharmony_ci			.ops = &clk_branch_ops,
37262306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,
37362306a36Sopenharmony_ci		},
37462306a36Sopenharmony_ci	},
37562306a36Sopenharmony_ci};
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_cistatic struct clk_branch sps_slimbus_clk = {
37862306a36Sopenharmony_ci	.halt_reg = 0xd4,
37962306a36Sopenharmony_ci	.halt_bit = 1,
38062306a36Sopenharmony_ci	.halt_check = BRANCH_HALT_ENABLE,
38162306a36Sopenharmony_ci	.clkr = {
38262306a36Sopenharmony_ci		.enable_reg = 0xcc,
38362306a36Sopenharmony_ci		.enable_mask = BIT(12),
38462306a36Sopenharmony_ci		.hw.init = &(struct clk_init_data){
38562306a36Sopenharmony_ci			.name = "sps_slimbus_clk",
38662306a36Sopenharmony_ci			.parent_hws = (const struct clk_hw*[]){
38762306a36Sopenharmony_ci				&slimbus_src.clkr.hw,
38862306a36Sopenharmony_ci			},
38962306a36Sopenharmony_ci			.num_parents = 1,
39062306a36Sopenharmony_ci			.ops = &clk_branch_ops,
39162306a36Sopenharmony_ci			.flags = CLK_SET_RATE_PARENT,
39262306a36Sopenharmony_ci		},
39362306a36Sopenharmony_ci	},
39462306a36Sopenharmony_ci};
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_cistatic struct clk_regmap *lcc_msm8960_clks[] = {
39762306a36Sopenharmony_ci	[PLL4] = &pll4.clkr,
39862306a36Sopenharmony_ci	[MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
39962306a36Sopenharmony_ci	[MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
40062306a36Sopenharmony_ci	[MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
40162306a36Sopenharmony_ci	[MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
40262306a36Sopenharmony_ci	[MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
40362306a36Sopenharmony_ci	[PCM_SRC] = &pcm_src.clkr,
40462306a36Sopenharmony_ci	[PCM_CLK_OUT] = &pcm_clk_out.clkr,
40562306a36Sopenharmony_ci	[PCM_CLK] = &pcm_clk.clkr,
40662306a36Sopenharmony_ci	[SLIMBUS_SRC] = &slimbus_src.clkr,
40762306a36Sopenharmony_ci	[AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
40862306a36Sopenharmony_ci	[SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
40962306a36Sopenharmony_ci	[CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
41062306a36Sopenharmony_ci	[CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
41162306a36Sopenharmony_ci	[CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
41262306a36Sopenharmony_ci	[CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
41362306a36Sopenharmony_ci	[CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
41462306a36Sopenharmony_ci	[SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
41562306a36Sopenharmony_ci	[SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
41662306a36Sopenharmony_ci	[SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
41762306a36Sopenharmony_ci	[SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
41862306a36Sopenharmony_ci	[SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
41962306a36Sopenharmony_ci	[CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
42062306a36Sopenharmony_ci	[CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
42162306a36Sopenharmony_ci	[CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
42262306a36Sopenharmony_ci	[CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
42362306a36Sopenharmony_ci	[CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
42462306a36Sopenharmony_ci	[SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
42562306a36Sopenharmony_ci	[SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
42662306a36Sopenharmony_ci	[SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
42762306a36Sopenharmony_ci	[SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
42862306a36Sopenharmony_ci	[SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
42962306a36Sopenharmony_ci};
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_cistatic const struct regmap_config lcc_msm8960_regmap_config = {
43262306a36Sopenharmony_ci	.reg_bits	= 32,
43362306a36Sopenharmony_ci	.reg_stride	= 4,
43462306a36Sopenharmony_ci	.val_bits	= 32,
43562306a36Sopenharmony_ci	.max_register	= 0xfc,
43662306a36Sopenharmony_ci	.fast_io	= true,
43762306a36Sopenharmony_ci};
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cistatic const struct qcom_cc_desc lcc_msm8960_desc = {
44062306a36Sopenharmony_ci	.config = &lcc_msm8960_regmap_config,
44162306a36Sopenharmony_ci	.clks = lcc_msm8960_clks,
44262306a36Sopenharmony_ci	.num_clks = ARRAY_SIZE(lcc_msm8960_clks),
44362306a36Sopenharmony_ci};
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic const struct of_device_id lcc_msm8960_match_table[] = {
44662306a36Sopenharmony_ci	{ .compatible = "qcom,lcc-msm8960" },
44762306a36Sopenharmony_ci	{ .compatible = "qcom,lcc-apq8064" },
44862306a36Sopenharmony_ci	{ .compatible = "qcom,lcc-mdm9615" },
44962306a36Sopenharmony_ci	{ }
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int lcc_msm8960_probe(struct platform_device *pdev)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	u32 val;
45662306a36Sopenharmony_ci	struct regmap *regmap;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/* patch for the cxo <-> pxo difference */
45962306a36Sopenharmony_ci	if (of_device_is_compatible(pdev->dev.of_node, "qcom,lcc-mdm9615")) {
46062306a36Sopenharmony_ci		pxo_parent_data.fw_name = "cxo";
46162306a36Sopenharmony_ci		pxo_parent_data.name = "cxo_board";
46262306a36Sopenharmony_ci		lcc_pxo_pll4[0].fw_name = "cxo";
46362306a36Sopenharmony_ci		lcc_pxo_pll4[0].name = "cxo_board";
46462306a36Sopenharmony_ci	}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
46762306a36Sopenharmony_ci	if (IS_ERR(regmap))
46862306a36Sopenharmony_ci		return PTR_ERR(regmap);
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	/* Use the correct frequency plan depending on speed of PLL4 */
47162306a36Sopenharmony_ci	regmap_read(regmap, 0x4, &val);
47262306a36Sopenharmony_ci	if (val == 0x12) {
47362306a36Sopenharmony_ci		slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
47462306a36Sopenharmony_ci		mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
47562306a36Sopenharmony_ci		codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
47662306a36Sopenharmony_ci		spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
47762306a36Sopenharmony_ci		codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
47862306a36Sopenharmony_ci		spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
47962306a36Sopenharmony_ci		pcm_src.freq_tbl = clk_tbl_pcm_492;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci	/* Enable PLL4 source on the LPASS Primary PLL Mux */
48262306a36Sopenharmony_ci	regmap_write(regmap, 0xc4, 0x1);
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
48562306a36Sopenharmony_ci}
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_cistatic struct platform_driver lcc_msm8960_driver = {
48862306a36Sopenharmony_ci	.probe		= lcc_msm8960_probe,
48962306a36Sopenharmony_ci	.driver		= {
49062306a36Sopenharmony_ci		.name	= "lcc-msm8960",
49162306a36Sopenharmony_ci		.of_match_table = lcc_msm8960_match_table,
49262306a36Sopenharmony_ci	},
49362306a36Sopenharmony_ci};
49462306a36Sopenharmony_cimodule_platform_driver(lcc_msm8960_driver);
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ciMODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
49762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
49862306a36Sopenharmony_ciMODULE_ALIAS("platform:lcc-msm8960");
499