2015-01-20 05:05:33 +03:00
/*
* Copyright ( c ) 2014 , The Linux Foundation . All rights reserved .
*
* This software is licensed under the terms of the GNU General Public
* License version 2 , as published by the Free Software Foundation , and
* may be copied , distributed , and modified under those terms .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*/
# include <linux/kernel.h>
# include <linux/bitops.h>
# include <linux/err.h>
# include <linux/platform_device.h>
# include <linux/module.h>
# include <linux/of.h>
# include <linux/of_device.h>
# include <linux/clk-provider.h>
# include <linux/regmap.h>
# include <dt-bindings/clock/qcom,lcc-ipq806x.h>
# include "common.h"
# include "clk-regmap.h"
# include "clk-pll.h"
# include "clk-rcg.h"
# include "clk-branch.h"
# include "clk-regmap-divider.h"
# include "clk-regmap-mux.h"
static struct clk_pll pll4 = {
. l_reg = 0x4 ,
. m_reg = 0x8 ,
. n_reg = 0xc ,
. config_reg = 0x14 ,
. mode_reg = 0x0 ,
. status_reg = 0x18 ,
. status_bit = 16 ,
. clkr . hw . init = & ( struct clk_init_data ) {
. name = " pll4 " ,
. parent_names = ( const char * [ ] ) { " pxo " } ,
. num_parents = 1 ,
. ops = & clk_pll_ops ,
} ,
} ;
static const struct pll_config pll4_config = {
. l = 0xf ,
. m = 0x91 ,
. n = 0xc7 ,
. vco_val = 0x0 ,
. vco_mask = BIT ( 17 ) | BIT ( 16 ) ,
. pre_div_val = 0x0 ,
. pre_div_mask = BIT ( 19 ) ,
. post_div_val = 0x0 ,
. post_div_mask = BIT ( 21 ) | BIT ( 20 ) ,
. mn_ena_mask = BIT ( 22 ) ,
. main_output_mask = BIT ( 23 ) ,
} ;
2015-03-20 19:30:26 +03:00
enum {
P_PXO ,
P_PLL4 ,
} ;
2015-01-20 05:05:33 +03:00
2015-03-20 19:30:26 +03:00
static const struct parent_map lcc_pxo_pll4_map [ ] = {
{ P_PXO , 0 } ,
{ P_PLL4 , 2 }
2015-01-20 05:05:33 +03:00
} ;
2015-07-06 16:51:30 +03:00
static const char * const lcc_pxo_pll4 [ ] = {
2015-01-20 05:05:33 +03:00
" pxo " ,
" pll4_vote " ,
} ;
static struct freq_tbl clk_tbl_aif_mi2s [ ] = {
{ 1024000 , P_PLL4 , 4 , 1 , 96 } ,
{ 1411200 , P_PLL4 , 4 , 2 , 139 } ,
{ 1536000 , P_PLL4 , 4 , 1 , 64 } ,
{ 2048000 , P_PLL4 , 4 , 1 , 48 } ,
{ 2116800 , P_PLL4 , 4 , 2 , 93 } ,
{ 2304000 , P_PLL4 , 4 , 2 , 85 } ,
{ 2822400 , P_PLL4 , 4 , 6 , 209 } ,
{ 3072000 , P_PLL4 , 4 , 1 , 32 } ,
{ 3175200 , P_PLL4 , 4 , 1 , 31 } ,
{ 4096000 , P_PLL4 , 4 , 1 , 24 } ,
{ 4233600 , P_PLL4 , 4 , 9 , 209 } ,
{ 4608000 , P_PLL4 , 4 , 3 , 64 } ,
{ 5644800 , P_PLL4 , 4 , 12 , 209 } ,
{ 6144000 , P_PLL4 , 4 , 1 , 16 } ,
{ 6350400 , P_PLL4 , 4 , 2 , 31 } ,
{ 8192000 , P_PLL4 , 4 , 1 , 12 } ,
{ 8467200 , P_PLL4 , 4 , 18 , 209 } ,
{ 9216000 , P_PLL4 , 4 , 3 , 32 } ,
{ 11289600 , P_PLL4 , 4 , 24 , 209 } ,
{ 12288000 , P_PLL4 , 4 , 1 , 8 } ,
{ 12700800 , P_PLL4 , 4 , 27 , 209 } ,
{ 13824000 , P_PLL4 , 4 , 9 , 64 } ,
{ 16384000 , P_PLL4 , 4 , 1 , 6 } ,
{ 16934400 , P_PLL4 , 4 , 41 , 238 } ,
{ 18432000 , P_PLL4 , 4 , 3 , 16 } ,
{ 22579200 , P_PLL4 , 2 , 24 , 209 } ,
{ 24576000 , P_PLL4 , 4 , 1 , 4 } ,
{ 27648000 , P_PLL4 , 4 , 9 , 32 } ,
{ 33868800 , P_PLL4 , 4 , 41 , 119 } ,
{ 36864000 , P_PLL4 , 4 , 3 , 8 } ,
{ 45158400 , P_PLL4 , 1 , 24 , 209 } ,
{ 49152000 , P_PLL4 , 4 , 1 , 2 } ,
{ 50803200 , P_PLL4 , 1 , 27 , 209 } ,
{ }
} ;
static struct clk_rcg mi2s_osr_src = {
. ns_reg = 0x48 ,
. md_reg = 0x4c ,
. mn = {
. mnctr_en_bit = 8 ,
. mnctr_reset_bit = 7 ,
. mnctr_mode_shift = 5 ,
. n_val_shift = 24 ,
. m_val_shift = 8 ,
. width = 8 ,
} ,
. p = {
. pre_div_shift = 3 ,
. pre_div_width = 2 ,
} ,
. s = {
. src_sel_shift = 0 ,
. parent_map = lcc_pxo_pll4_map ,
} ,
. freq_tbl = clk_tbl_aif_mi2s ,
. clkr = {
. enable_reg = 0x48 ,
. enable_mask = BIT ( 9 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " mi2s_osr_src " ,
. parent_names = lcc_pxo_pll4 ,
. num_parents = 2 ,
. ops = & clk_rcg_ops ,
. flags = CLK_SET_RATE_GATE ,
} ,
} ,
} ;
2015-07-06 16:51:30 +03:00
static const char * const lcc_mi2s_parents [ ] = {
2015-01-20 05:05:33 +03:00
" mi2s_osr_src " ,
} ;
static struct clk_branch mi2s_osr_clk = {
. halt_reg = 0x50 ,
. halt_bit = 1 ,
. halt_check = BRANCH_HALT_ENABLE ,
. clkr = {
. enable_reg = 0x48 ,
. enable_mask = BIT ( 17 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " mi2s_osr_clk " ,
. parent_names = lcc_mi2s_parents ,
. num_parents = 1 ,
. ops = & clk_branch_ops ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ,
} ;
static struct clk_regmap_div mi2s_div_clk = {
. reg = 0x48 ,
. shift = 10 ,
. width = 4 ,
. clkr = {
. hw . init = & ( struct clk_init_data ) {
. name = " mi2s_div_clk " ,
. parent_names = lcc_mi2s_parents ,
. num_parents = 1 ,
. ops = & clk_regmap_div_ops ,
} ,
} ,
} ;
static struct clk_branch mi2s_bit_div_clk = {
. halt_reg = 0x50 ,
. halt_bit = 0 ,
. halt_check = BRANCH_HALT_ENABLE ,
. clkr = {
. enable_reg = 0x48 ,
. enable_mask = BIT ( 15 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " mi2s_bit_div_clk " ,
. parent_names = ( const char * [ ] ) { " mi2s_div_clk " } ,
. num_parents = 1 ,
. ops = & clk_branch_ops ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ,
} ;
static struct clk_regmap_mux mi2s_bit_clk = {
. reg = 0x48 ,
. shift = 14 ,
. width = 1 ,
. clkr = {
. hw . init = & ( struct clk_init_data ) {
. name = " mi2s_bit_clk " ,
. parent_names = ( const char * [ ] ) {
" mi2s_bit_div_clk " ,
" mi2s_codec_clk " ,
} ,
. num_parents = 2 ,
. ops = & clk_regmap_mux_closest_ops ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ,
} ;
static struct freq_tbl clk_tbl_pcm [ ] = {
{ 64000 , P_PLL4 , 4 , 1 , 1536 } ,
{ 128000 , P_PLL4 , 4 , 1 , 768 } ,
{ 256000 , P_PLL4 , 4 , 1 , 384 } ,
{ 512000 , P_PLL4 , 4 , 1 , 192 } ,
{ 1024000 , P_PLL4 , 4 , 1 , 96 } ,
{ 2048000 , P_PLL4 , 4 , 1 , 48 } ,
{ } ,
} ;
static struct clk_rcg pcm_src = {
. ns_reg = 0x54 ,
. md_reg = 0x58 ,
. mn = {
. mnctr_en_bit = 8 ,
. mnctr_reset_bit = 7 ,
. mnctr_mode_shift = 5 ,
. n_val_shift = 16 ,
. m_val_shift = 16 ,
. width = 16 ,
} ,
. p = {
. pre_div_shift = 3 ,
. pre_div_width = 2 ,
} ,
. s = {
. src_sel_shift = 0 ,
. parent_map = lcc_pxo_pll4_map ,
} ,
. freq_tbl = clk_tbl_pcm ,
. clkr = {
. enable_reg = 0x54 ,
. enable_mask = BIT ( 9 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " pcm_src " ,
. parent_names = lcc_pxo_pll4 ,
. num_parents = 2 ,
. ops = & clk_rcg_ops ,
. flags = CLK_SET_RATE_GATE ,
} ,
} ,
} ;
static struct clk_branch pcm_clk_out = {
. halt_reg = 0x5c ,
. halt_bit = 0 ,
. halt_check = BRANCH_HALT_ENABLE ,
. clkr = {
. enable_reg = 0x54 ,
. enable_mask = BIT ( 11 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " pcm_clk_out " ,
. parent_names = ( const char * [ ] ) { " pcm_src " } ,
. num_parents = 1 ,
. ops = & clk_branch_ops ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ,
} ;
static struct clk_regmap_mux pcm_clk = {
. reg = 0x54 ,
. shift = 10 ,
. width = 1 ,
. clkr = {
. hw . init = & ( struct clk_init_data ) {
. name = " pcm_clk " ,
. parent_names = ( const char * [ ] ) {
" pcm_clk_out " ,
" pcm_codec_clk " ,
} ,
. num_parents = 2 ,
. ops = & clk_regmap_mux_closest_ops ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ,
} ;
static struct freq_tbl clk_tbl_aif_osr [ ] = {
2015-02-27 06:34:35 +03:00
{ 2822400 , P_PLL4 , 1 , 147 , 20480 } ,
{ 4096000 , P_PLL4 , 1 , 1 , 96 } ,
{ 5644800 , P_PLL4 , 1 , 147 , 10240 } ,
{ 6144000 , P_PLL4 , 1 , 1 , 64 } ,
{ 11289600 , P_PLL4 , 1 , 147 , 5120 } ,
{ 12288000 , P_PLL4 , 1 , 1 , 32 } ,
{ 22579200 , P_PLL4 , 1 , 147 , 2560 } ,
{ 24576000 , P_PLL4 , 1 , 1 , 16 } ,
2015-01-20 05:05:33 +03:00
{ } ,
} ;
static struct clk_rcg spdif_src = {
. ns_reg = 0xcc ,
. md_reg = 0xd0 ,
. mn = {
. mnctr_en_bit = 8 ,
. mnctr_reset_bit = 7 ,
. mnctr_mode_shift = 5 ,
. n_val_shift = 16 ,
. m_val_shift = 16 ,
. width = 8 ,
} ,
. p = {
. pre_div_shift = 3 ,
. pre_div_width = 2 ,
} ,
. s = {
. src_sel_shift = 0 ,
. parent_map = lcc_pxo_pll4_map ,
} ,
. freq_tbl = clk_tbl_aif_osr ,
. clkr = {
. enable_reg = 0xcc ,
. enable_mask = BIT ( 9 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " spdif_src " ,
. parent_names = lcc_pxo_pll4 ,
. num_parents = 2 ,
. ops = & clk_rcg_ops ,
. flags = CLK_SET_RATE_GATE ,
} ,
} ,
} ;
2015-07-06 16:51:30 +03:00
static const char * const lcc_spdif_parents [ ] = {
2015-01-20 05:05:33 +03:00
" spdif_src " ,
} ;
static struct clk_branch spdif_clk = {
. halt_reg = 0xd4 ,
. halt_bit = 1 ,
. halt_check = BRANCH_HALT_ENABLE ,
. clkr = {
. enable_reg = 0xcc ,
. enable_mask = BIT ( 12 ) ,
. hw . init = & ( struct clk_init_data ) {
. name = " spdif_clk " ,
. parent_names = lcc_spdif_parents ,
. num_parents = 1 ,
. ops = & clk_branch_ops ,
. flags = CLK_SET_RATE_PARENT ,
} ,
} ,
} ;
static struct freq_tbl clk_tbl_ahbix [ ] = {
2015-02-27 06:34:35 +03:00
{ 131072000 , P_PLL4 , 1 , 1 , 3 } ,
2015-01-20 05:05:33 +03:00
{ } ,
} ;
static struct clk_rcg ahbix_clk = {
. ns_reg = 0x38 ,
. md_reg = 0x3c ,
. mn = {
. mnctr_en_bit = 8 ,
. mnctr_reset_bit = 7 ,
. mnctr_mode_shift = 5 ,
. n_val_shift = 24 ,
. m_val_shift = 8 ,
. width = 8 ,
} ,
. p = {
. pre_div_shift = 3 ,
. pre_div_width = 2 ,
} ,
. s = {
. src_sel_shift = 0 ,
. parent_map = lcc_pxo_pll4_map ,
} ,
. freq_tbl = clk_tbl_ahbix ,
. clkr = {
. enable_reg = 0x38 ,
2015-03-07 02:41:53 +03:00
. enable_mask = BIT ( 11 ) ,
2015-01-20 05:05:33 +03:00
. hw . init = & ( struct clk_init_data ) {
. name = " ahbix " ,
. parent_names = lcc_pxo_pll4 ,
. num_parents = 2 ,
2015-03-07 02:41:53 +03:00
. ops = & clk_rcg_lcc_ops ,
2015-01-20 05:05:33 +03:00
} ,
} ,
} ;
static struct clk_regmap * lcc_ipq806x_clks [ ] = {
[ PLL4 ] = & pll4 . clkr ,
[ MI2S_OSR_SRC ] = & mi2s_osr_src . clkr ,
[ MI2S_OSR_CLK ] = & mi2s_osr_clk . clkr ,
[ MI2S_DIV_CLK ] = & mi2s_div_clk . clkr ,
[ MI2S_BIT_DIV_CLK ] = & mi2s_bit_div_clk . clkr ,
[ MI2S_BIT_CLK ] = & mi2s_bit_clk . clkr ,
[ PCM_SRC ] = & pcm_src . clkr ,
[ PCM_CLK_OUT ] = & pcm_clk_out . clkr ,
[ PCM_CLK ] = & pcm_clk . clkr ,
[ SPDIF_SRC ] = & spdif_src . clkr ,
[ SPDIF_CLK ] = & spdif_clk . clkr ,
[ AHBIX_CLK ] = & ahbix_clk . clkr ,
} ;
static const struct regmap_config lcc_ipq806x_regmap_config = {
. reg_bits = 32 ,
. reg_stride = 4 ,
. val_bits = 32 ,
. max_register = 0xfc ,
. fast_io = true ,
} ;
static const struct qcom_cc_desc lcc_ipq806x_desc = {
. config = & lcc_ipq806x_regmap_config ,
. clks = lcc_ipq806x_clks ,
. num_clks = ARRAY_SIZE ( lcc_ipq806x_clks ) ,
} ;
static const struct of_device_id lcc_ipq806x_match_table [ ] = {
{ . compatible = " qcom,lcc-ipq8064 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , lcc_ipq806x_match_table ) ;
static int lcc_ipq806x_probe ( struct platform_device * pdev )
{
u32 val ;
struct regmap * regmap ;
regmap = qcom_cc_map ( pdev , & lcc_ipq806x_desc ) ;
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
/* Configure the rate of PLL4 if the bootloader hasn't already */
2016-09-10 06:47:30 +03:00
regmap_read ( regmap , 0x0 , & val ) ;
2015-01-20 05:05:33 +03:00
if ( ! val )
clk_pll_configure_sr ( & pll4 , regmap , & pll4_config , true ) ;
/* Enable PLL4 source on the LPASS Primary PLL Mux */
regmap_write ( regmap , 0xc4 , 0x1 ) ;
return qcom_cc_really_probe ( pdev , & lcc_ipq806x_desc , regmap ) ;
}
static struct platform_driver lcc_ipq806x_driver = {
. probe = lcc_ipq806x_probe ,
. driver = {
. name = " lcc-ipq806x " ,
. of_match_table = lcc_ipq806x_match_table ,
} ,
} ;
module_platform_driver ( lcc_ipq806x_driver ) ;
MODULE_DESCRIPTION ( " QCOM LCC IPQ806x Driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_ALIAS ( " platform:lcc-ipq806x " ) ;