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