linux/drivers/clk/qcom/lcc-ipq806x.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2014, The Linux Foundation. All rights reserved.
   3 *
   4 * This software is licensed under the terms of the GNU General Public
   5 * License version 2, as published by the Free Software Foundation, and
   6 * may be copied, distributed, and modified under those terms.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 */
  13
  14#include <linux/kernel.h>
  15#include <linux/bitops.h>
  16#include <linux/err.h>
  17#include <linux/platform_device.h>
  18#include <linux/module.h>
  19#include <linux/of.h>
  20#include <linux/of_device.h>
  21#include <linux/clk-provider.h>
  22#include <linux/regmap.h>
  23
  24#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
  25
  26#include "common.h"
  27#include "clk-regmap.h"
  28#include "clk-pll.h"
  29#include "clk-rcg.h"
  30#include "clk-branch.h"
  31#include "clk-regmap-divider.h"
  32#include "clk-regmap-mux.h"
  33
  34static struct clk_pll pll4 = {
  35        .l_reg = 0x4,
  36        .m_reg = 0x8,
  37        .n_reg = 0xc,
  38        .config_reg = 0x14,
  39        .mode_reg = 0x0,
  40        .status_reg = 0x18,
  41        .status_bit = 16,
  42        .clkr.hw.init = &(struct clk_init_data){
  43                .name = "pll4",
  44                .parent_names = (const char *[]){ "pxo" },
  45                .num_parents = 1,
  46                .ops = &clk_pll_ops,
  47        },
  48};
  49
  50static const struct pll_config pll4_config = {
  51        .l = 0xf,
  52        .m = 0x91,
  53        .n = 0xc7,
  54        .vco_val = 0x0,
  55        .vco_mask = BIT(17) | BIT(16),
  56        .pre_div_val = 0x0,
  57        .pre_div_mask = BIT(19),
  58        .post_div_val = 0x0,
  59        .post_div_mask = BIT(21) | BIT(20),
  60        .mn_ena_mask = BIT(22),
  61        .main_output_mask = BIT(23),
  62};
  63
  64enum {
  65        P_PXO,
  66        P_PLL4,
  67};
  68
  69static const struct parent_map lcc_pxo_pll4_map[] = {
  70        { P_PXO, 0 },
  71        { P_PLL4, 2 }
  72};
  73
  74static const char * const lcc_pxo_pll4[] = {
  75        "pxo",
  76        "pll4_vote",
  77};
  78
  79static struct freq_tbl clk_tbl_aif_mi2s[] = {
  80        {  1024000, P_PLL4, 4,  1,  96 },
  81        {  1411200, P_PLL4, 4,  2, 139 },
  82        {  1536000, P_PLL4, 4,  1,  64 },
  83        {  2048000, P_PLL4, 4,  1,  48 },
  84        {  2116800, P_PLL4, 4,  2,  93 },
  85        {  2304000, P_PLL4, 4,  2,  85 },
  86        {  2822400, P_PLL4, 4,  6, 209 },
  87        {  3072000, P_PLL4, 4,  1,  32 },
  88        {  3175200, P_PLL4, 4,  1,  31 },
  89        {  4096000, P_PLL4, 4,  1,  24 },
  90        {  4233600, P_PLL4, 4,  9, 209 },
  91        {  4608000, P_PLL4, 4,  3,  64 },
  92        {  5644800, P_PLL4, 4, 12, 209 },
  93        {  6144000, P_PLL4, 4,  1,  16 },
  94        {  6350400, P_PLL4, 4,  2,  31 },
  95        {  8192000, P_PLL4, 4,  1,  12 },
  96        {  8467200, P_PLL4, 4, 18, 209 },
  97        {  9216000, P_PLL4, 4,  3,  32 },
  98        { 11289600, P_PLL4, 4, 24, 209 },
  99        { 12288000, P_PLL4, 4,  1,   8 },
 100        { 12700800, P_PLL4, 4, 27, 209 },
 101        { 13824000, P_PLL4, 4,  9,  64 },
 102        { 16384000, P_PLL4, 4,  1,   6 },
 103        { 16934400, P_PLL4, 4, 41, 238 },
 104        { 18432000, P_PLL4, 4,  3,  16 },
 105        { 22579200, P_PLL4, 2, 24, 209 },
 106        { 24576000, P_PLL4, 4,  1,   4 },
 107        { 27648000, P_PLL4, 4,  9,  32 },
 108        { 33868800, P_PLL4, 4, 41, 119 },
 109        { 36864000, P_PLL4, 4,  3,   8 },
 110        { 45158400, P_PLL4, 1, 24, 209 },
 111        { 49152000, P_PLL4, 4,  1,   2 },
 112        { 50803200, P_PLL4, 1, 27, 209 },
 113        { }
 114};
 115
 116static struct clk_rcg mi2s_osr_src = {
 117        .ns_reg = 0x48,
 118        .md_reg = 0x4c,
 119        .mn = {
 120                .mnctr_en_bit = 8,
 121                .mnctr_reset_bit = 7,
 122                .mnctr_mode_shift = 5,
 123                .n_val_shift = 24,
 124                .m_val_shift = 8,
 125                .width = 8,
 126        },
 127        .p = {
 128                .pre_div_shift = 3,
 129                .pre_div_width = 2,
 130        },
 131        .s = {
 132                .src_sel_shift = 0,
 133                .parent_map = lcc_pxo_pll4_map,
 134        },
 135        .freq_tbl = clk_tbl_aif_mi2s,
 136        .clkr = {
 137                .enable_reg = 0x48,
 138                .enable_mask = BIT(9),
 139                .hw.init = &(struct clk_init_data){
 140                        .name = "mi2s_osr_src",
 141                        .parent_names = lcc_pxo_pll4,
 142                        .num_parents = 2,
 143                        .ops = &clk_rcg_ops,
 144                        .flags = CLK_SET_RATE_GATE,
 145                },
 146        },
 147};
 148
 149static const char * const lcc_mi2s_parents[] = {
 150        "mi2s_osr_src",
 151};
 152
 153static struct clk_branch mi2s_osr_clk = {
 154        .halt_reg = 0x50,
 155        .halt_bit = 1,
 156        .halt_check = BRANCH_HALT_ENABLE,
 157        .clkr = {
 158                .enable_reg = 0x48,
 159                .enable_mask = BIT(17),
 160                .hw.init = &(struct clk_init_data){
 161                        .name = "mi2s_osr_clk",
 162                        .parent_names = lcc_mi2s_parents,
 163                        .num_parents = 1,
 164                        .ops = &clk_branch_ops,
 165                        .flags = CLK_SET_RATE_PARENT,
 166                },
 167        },
 168};
 169
 170static struct clk_regmap_div mi2s_div_clk = {
 171        .reg = 0x48,
 172        .shift = 10,
 173        .width = 4,
 174        .clkr = {
 175                .hw.init = &(struct clk_init_data){
 176                        .name = "mi2s_div_clk",
 177                        .parent_names = lcc_mi2s_parents,
 178                        .num_parents = 1,
 179                        .ops = &clk_regmap_div_ops,
 180                },
 181        },
 182};
 183
 184static struct clk_branch mi2s_bit_div_clk = {
 185        .halt_reg = 0x50,
 186        .halt_bit = 0,
 187        .halt_check = BRANCH_HALT_ENABLE,
 188        .clkr = {
 189                .enable_reg = 0x48,
 190                .enable_mask = BIT(15),
 191                .hw.init = &(struct clk_init_data){
 192                        .name = "mi2s_bit_div_clk",
 193                        .parent_names = (const char *[]){ "mi2s_div_clk" },
 194                        .num_parents = 1,
 195                        .ops = &clk_branch_ops,
 196                        .flags = CLK_SET_RATE_PARENT,
 197                },
 198        },
 199};
 200
 201
 202static struct clk_regmap_mux mi2s_bit_clk = {
 203        .reg = 0x48,
 204        .shift = 14,
 205        .width = 1,
 206        .clkr = {
 207                .hw.init = &(struct clk_init_data){
 208                        .name = "mi2s_bit_clk",
 209                        .parent_names = (const char *[]){
 210                                "mi2s_bit_div_clk",
 211                                "mi2s_codec_clk",
 212                        },
 213                        .num_parents = 2,
 214                        .ops = &clk_regmap_mux_closest_ops,
 215                        .flags = CLK_SET_RATE_PARENT,
 216                },
 217        },
 218};
 219
 220static struct freq_tbl clk_tbl_pcm[] = {
 221        {   64000, P_PLL4, 4, 1, 1536 },
 222        {  128000, P_PLL4, 4, 1,  768 },
 223        {  256000, P_PLL4, 4, 1,  384 },
 224        {  512000, P_PLL4, 4, 1,  192 },
 225        { 1024000, P_PLL4, 4, 1,   96 },
 226        { 2048000, P_PLL4, 4, 1,   48 },
 227        { },
 228};
 229
 230static struct clk_rcg pcm_src = {
 231        .ns_reg = 0x54,
 232        .md_reg = 0x58,
 233        .mn = {
 234                .mnctr_en_bit = 8,
 235                .mnctr_reset_bit = 7,
 236                .mnctr_mode_shift = 5,
 237                .n_val_shift = 16,
 238                .m_val_shift = 16,
 239                .width = 16,
 240        },
 241        .p = {
 242                .pre_div_shift = 3,
 243                .pre_div_width = 2,
 244        },
 245        .s = {
 246                .src_sel_shift = 0,
 247                .parent_map = lcc_pxo_pll4_map,
 248        },
 249        .freq_tbl = clk_tbl_pcm,
 250        .clkr = {
 251                .enable_reg = 0x54,
 252                .enable_mask = BIT(9),
 253                .hw.init = &(struct clk_init_data){
 254                        .name = "pcm_src",
 255                        .parent_names = lcc_pxo_pll4,
 256                        .num_parents = 2,
 257                        .ops = &clk_rcg_ops,
 258                        .flags = CLK_SET_RATE_GATE,
 259                },
 260        },
 261};
 262
 263static struct clk_branch pcm_clk_out = {
 264        .halt_reg = 0x5c,
 265        .halt_bit = 0,
 266        .halt_check = BRANCH_HALT_ENABLE,
 267        .clkr = {
 268                .enable_reg = 0x54,
 269                .enable_mask = BIT(11),
 270                .hw.init = &(struct clk_init_data){
 271                        .name = "pcm_clk_out",
 272                        .parent_names = (const char *[]){ "pcm_src" },
 273                        .num_parents = 1,
 274                        .ops = &clk_branch_ops,
 275                        .flags = CLK_SET_RATE_PARENT,
 276                },
 277        },
 278};
 279
 280static struct clk_regmap_mux pcm_clk = {
 281        .reg = 0x54,
 282        .shift = 10,
 283        .width = 1,
 284        .clkr = {
 285                .hw.init = &(struct clk_init_data){
 286                        .name = "pcm_clk",
 287                        .parent_names = (const char *[]){
 288                                "pcm_clk_out",
 289                                "pcm_codec_clk",
 290                        },
 291                        .num_parents = 2,
 292                        .ops = &clk_regmap_mux_closest_ops,
 293                        .flags = CLK_SET_RATE_PARENT,
 294                },
 295        },
 296};
 297
 298static struct freq_tbl clk_tbl_aif_osr[] = {
 299        {  2822400, P_PLL4, 1, 147, 20480 },
 300        {  4096000, P_PLL4, 1,   1,    96 },
 301        {  5644800, P_PLL4, 1, 147, 10240 },
 302        {  6144000, P_PLL4, 1,   1,    64 },
 303        { 11289600, P_PLL4, 1, 147,  5120 },
 304        { 12288000, P_PLL4, 1,   1,    32 },
 305        { 22579200, P_PLL4, 1, 147,  2560 },
 306        { 24576000, P_PLL4, 1,   1,    16 },
 307        { },
 308};
 309
 310static struct clk_rcg spdif_src = {
 311        .ns_reg = 0xcc,
 312        .md_reg = 0xd0,
 313        .mn = {
 314                .mnctr_en_bit = 8,
 315                .mnctr_reset_bit = 7,
 316                .mnctr_mode_shift = 5,
 317                .n_val_shift = 16,
 318                .m_val_shift = 16,
 319                .width = 8,
 320        },
 321        .p = {
 322                .pre_div_shift = 3,
 323                .pre_div_width = 2,
 324        },
 325        .s = {
 326                .src_sel_shift = 0,
 327                .parent_map = lcc_pxo_pll4_map,
 328        },
 329        .freq_tbl = clk_tbl_aif_osr,
 330        .clkr = {
 331                .enable_reg = 0xcc,
 332                .enable_mask = BIT(9),
 333                .hw.init = &(struct clk_init_data){
 334                        .name = "spdif_src",
 335                        .parent_names = lcc_pxo_pll4,
 336                        .num_parents = 2,
 337                        .ops = &clk_rcg_ops,
 338                        .flags = CLK_SET_RATE_GATE,
 339                },
 340        },
 341};
 342
 343static const char * const lcc_spdif_parents[] = {
 344        "spdif_src",
 345};
 346
 347static struct clk_branch spdif_clk = {
 348        .halt_reg = 0xd4,
 349        .halt_bit = 1,
 350        .halt_check = BRANCH_HALT_ENABLE,
 351        .clkr = {
 352                .enable_reg = 0xcc,
 353                .enable_mask = BIT(12),
 354                .hw.init = &(struct clk_init_data){
 355                        .name = "spdif_clk",
 356                        .parent_names = lcc_spdif_parents,
 357                        .num_parents = 1,
 358                        .ops = &clk_branch_ops,
 359                        .flags = CLK_SET_RATE_PARENT,
 360                },
 361        },
 362};
 363
 364static struct freq_tbl clk_tbl_ahbix[] = {
 365        { 131072000, P_PLL4, 1, 1, 3 },
 366        { },
 367};
 368
 369static struct clk_rcg ahbix_clk = {
 370        .ns_reg = 0x38,
 371        .md_reg = 0x3c,
 372        .mn = {
 373                .mnctr_en_bit = 8,
 374                .mnctr_reset_bit = 7,
 375                .mnctr_mode_shift = 5,
 376                .n_val_shift = 24,
 377                .m_val_shift = 8,
 378                .width = 8,
 379        },
 380        .p = {
 381                .pre_div_shift = 3,
 382                .pre_div_width = 2,
 383        },
 384        .s = {
 385                .src_sel_shift = 0,
 386                .parent_map = lcc_pxo_pll4_map,
 387        },
 388        .freq_tbl = clk_tbl_ahbix,
 389        .clkr = {
 390                .enable_reg = 0x38,
 391                .enable_mask = BIT(11),
 392                .hw.init = &(struct clk_init_data){
 393                        .name = "ahbix",
 394                        .parent_names = lcc_pxo_pll4,
 395                        .num_parents = 2,
 396                        .ops = &clk_rcg_lcc_ops,
 397                },
 398        },
 399};
 400
 401static struct clk_regmap *lcc_ipq806x_clks[] = {
 402        [PLL4] = &pll4.clkr,
 403        [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
 404        [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
 405        [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
 406        [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
 407        [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
 408        [PCM_SRC] = &pcm_src.clkr,
 409        [PCM_CLK_OUT] = &pcm_clk_out.clkr,
 410        [PCM_CLK] = &pcm_clk.clkr,
 411        [SPDIF_SRC] = &spdif_src.clkr,
 412        [SPDIF_CLK] = &spdif_clk.clkr,
 413        [AHBIX_CLK] = &ahbix_clk.clkr,
 414};
 415
 416static const struct regmap_config lcc_ipq806x_regmap_config = {
 417        .reg_bits       = 32,
 418        .reg_stride     = 4,
 419        .val_bits       = 32,
 420        .max_register   = 0xfc,
 421        .fast_io        = true,
 422};
 423
 424static const struct qcom_cc_desc lcc_ipq806x_desc = {
 425        .config = &lcc_ipq806x_regmap_config,
 426        .clks = lcc_ipq806x_clks,
 427        .num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
 428};
 429
 430static const struct of_device_id lcc_ipq806x_match_table[] = {
 431        { .compatible = "qcom,lcc-ipq8064" },
 432        { }
 433};
 434MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
 435
 436static int lcc_ipq806x_probe(struct platform_device *pdev)
 437{
 438        u32 val;
 439        struct regmap *regmap;
 440
 441        regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
 442        if (IS_ERR(regmap))
 443                return PTR_ERR(regmap);
 444
 445        /* Configure the rate of PLL4 if the bootloader hasn't already */
 446        val = regmap_read(regmap, 0x0, &val);
 447        if (!val)
 448                clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
 449        /* Enable PLL4 source on the LPASS Primary PLL Mux */
 450        regmap_write(regmap, 0xc4, 0x1);
 451
 452        return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
 453}
 454
 455static struct platform_driver lcc_ipq806x_driver = {
 456        .probe          = lcc_ipq806x_probe,
 457        .driver         = {
 458                .name   = "lcc-ipq806x",
 459                .of_match_table = lcc_ipq806x_match_table,
 460        },
 461};
 462module_platform_driver(lcc_ipq806x_driver);
 463
 464MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
 465MODULE_LICENSE("GPL v2");
 466MODULE_ALIAS("platform:lcc-ipq806x");
 467