linux/drivers/clk/tegra/clk-tegra-pmc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (c) 2012, 2013, NVIDIA CORPORATION.  All rights reserved.
   4 */
   5
   6#include <linux/io.h>
   7#include <linux/clk-provider.h>
   8#include <linux/clkdev.h>
   9#include <linux/of.h>
  10#include <linux/of_address.h>
  11#include <linux/delay.h>
  12#include <linux/export.h>
  13#include <linux/clk/tegra.h>
  14
  15#include "clk.h"
  16#include "clk-id.h"
  17
  18#define PMC_CLK_OUT_CNTRL 0x1a8
  19#define PMC_DPD_PADS_ORIDE 0x1c
  20#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
  21#define PMC_CTRL 0
  22#define PMC_CTRL_BLINK_ENB 7
  23#define PMC_BLINK_TIMER 0x40
  24
  25struct pmc_clk_init_data {
  26        char *mux_name;
  27        char *gate_name;
  28        const char **parents;
  29        int num_parents;
  30        int mux_id;
  31        int gate_id;
  32        char *dev_name;
  33        u8 mux_shift;
  34        u8 gate_shift;
  35};
  36
  37#define PMC_CLK(_num, _mux_shift, _gate_shift)\
  38        {\
  39                .mux_name = "clk_out_" #_num "_mux",\
  40                .gate_name = "clk_out_" #_num,\
  41                .parents = clk_out ##_num ##_parents,\
  42                .num_parents = ARRAY_SIZE(clk_out ##_num ##_parents),\
  43                .mux_id = tegra_clk_clk_out_ ##_num ##_mux,\
  44                .gate_id = tegra_clk_clk_out_ ##_num,\
  45                .dev_name = "extern" #_num,\
  46                .mux_shift = _mux_shift,\
  47                .gate_shift = _gate_shift,\
  48        }
  49
  50static DEFINE_SPINLOCK(clk_out_lock);
  51
  52static const char *clk_out1_parents[] = { "clk_m", "clk_m_div2",
  53        "clk_m_div4", "extern1",
  54};
  55
  56static const char *clk_out2_parents[] = { "clk_m", "clk_m_div2",
  57        "clk_m_div4", "extern2",
  58};
  59
  60static const char *clk_out3_parents[] = { "clk_m", "clk_m_div2",
  61        "clk_m_div4", "extern3",
  62};
  63
  64static struct pmc_clk_init_data pmc_clks[] = {
  65        PMC_CLK(1, 6, 2),
  66        PMC_CLK(2, 14, 10),
  67        PMC_CLK(3, 22, 18),
  68};
  69
  70void __init tegra_pmc_clk_init(void __iomem *pmc_base,
  71                                struct tegra_clk *tegra_clks)
  72{
  73        struct clk *clk;
  74        struct clk **dt_clk;
  75        int i;
  76
  77        for (i = 0; i < ARRAY_SIZE(pmc_clks); i++) {
  78                struct pmc_clk_init_data *data;
  79
  80                data = pmc_clks + i;
  81
  82                dt_clk = tegra_lookup_dt_id(data->mux_id, tegra_clks);
  83                if (!dt_clk)
  84                        continue;
  85
  86                clk = clk_register_mux(NULL, data->mux_name, data->parents,
  87                                data->num_parents,
  88                                CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
  89                                pmc_base + PMC_CLK_OUT_CNTRL, data->mux_shift,
  90                                3, 0, &clk_out_lock);
  91                *dt_clk = clk;
  92
  93
  94                dt_clk = tegra_lookup_dt_id(data->gate_id, tegra_clks);
  95                if (!dt_clk)
  96                        continue;
  97
  98                clk = clk_register_gate(NULL, data->gate_name, data->mux_name,
  99                                        CLK_SET_RATE_PARENT,
 100                                        pmc_base + PMC_CLK_OUT_CNTRL,
 101                                        data->gate_shift, 0, &clk_out_lock);
 102                *dt_clk = clk;
 103                clk_register_clkdev(clk, data->dev_name, data->gate_name);
 104        }
 105
 106        /* blink */
 107        writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
 108        clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
 109                                pmc_base + PMC_DPD_PADS_ORIDE,
 110                                PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
 111
 112        dt_clk = tegra_lookup_dt_id(tegra_clk_blink, tegra_clks);
 113        if (!dt_clk)
 114                return;
 115
 116        clk = clk_register_gate(NULL, "blink", "blink_override", 0,
 117                                pmc_base + PMC_CTRL,
 118                                PMC_CTRL_BLINK_ENB, 0, NULL);
 119        clk_register_clkdev(clk, "blink", NULL);
 120        *dt_clk = clk;
 121}
 122
 123