root/drivers/clk/renesas/clk-r8a73a4.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. r8a73a4_cpg_register_clock
  2. r8a73a4_cpg_clocks_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * r8a73a4 Core CPG Clocks
   4  *
   5  * Copyright (C) 2014  Ulrich Hecht
   6  */
   7 
   8 #include <linux/clk-provider.h>
   9 #include <linux/clk/renesas.h>
  10 #include <linux/init.h>
  11 #include <linux/io.h>
  12 #include <linux/kernel.h>
  13 #include <linux/slab.h>
  14 #include <linux/of.h>
  15 #include <linux/of_address.h>
  16 #include <linux/spinlock.h>
  17 
  18 struct r8a73a4_cpg {
  19         struct clk_onecell_data data;
  20         spinlock_t lock;
  21         void __iomem *reg;
  22 };
  23 
  24 #define CPG_CKSCR       0xc0
  25 #define CPG_FRQCRA      0x00
  26 #define CPG_FRQCRB      0x04
  27 #define CPG_FRQCRC      0xe0
  28 #define CPG_PLL0CR      0xd8
  29 #define CPG_PLL1CR      0x28
  30 #define CPG_PLL2CR      0x2c
  31 #define CPG_PLL2HCR     0xe4
  32 #define CPG_PLL2SCR     0xf4
  33 
  34 #define CLK_ENABLE_ON_INIT BIT(0)
  35 
  36 struct div4_clk {
  37         const char *name;
  38         unsigned int reg;
  39         unsigned int shift;
  40 };
  41 
  42 static struct div4_clk div4_clks[] = {
  43         { "i",  CPG_FRQCRA, 20 },
  44         { "m3", CPG_FRQCRA, 12 },
  45         { "b",  CPG_FRQCRA,  8 },
  46         { "m1", CPG_FRQCRA,  4 },
  47         { "m2", CPG_FRQCRA,  0 },
  48         { "zx", CPG_FRQCRB, 12 },
  49         { "zs", CPG_FRQCRB,  8 },
  50         { "hp", CPG_FRQCRB,  4 },
  51         { NULL, 0, 0 },
  52 };
  53 
  54 static const struct clk_div_table div4_div_table[] = {
  55         { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
  56         { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
  57         { 12, 10 }, { 0, 0 }
  58 };
  59 
  60 static struct clk * __init
  61 r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
  62                              const char *name)
  63 {
  64         const struct clk_div_table *table = NULL;
  65         const char *parent_name;
  66         unsigned int shift, reg;
  67         unsigned int mult = 1;
  68         unsigned int div = 1;
  69 
  70 
  71         if (!strcmp(name, "main")) {
  72                 u32 ckscr = readl(cpg->reg + CPG_CKSCR);
  73 
  74                 switch ((ckscr >> 28) & 3) {
  75                 case 0: /* extal1 */
  76                         parent_name = of_clk_get_parent_name(np, 0);
  77                         break;
  78                 case 1: /* extal1 / 2 */
  79                         parent_name = of_clk_get_parent_name(np, 0);
  80                         div = 2;
  81                         break;
  82                 case 2: /* extal2 */
  83                         parent_name = of_clk_get_parent_name(np, 1);
  84                         break;
  85                 case 3: /* extal2 / 2 */
  86                         parent_name = of_clk_get_parent_name(np, 1);
  87                         div = 2;
  88                         break;
  89                 }
  90         } else if (!strcmp(name, "pll0")) {
  91                 /* PLL0/1 are configurable multiplier clocks. Register them as
  92                  * fixed factor clocks for now as there's no generic multiplier
  93                  * clock implementation and we currently have no need to change
  94                  * the multiplier value.
  95                  */
  96                 u32 value = readl(cpg->reg + CPG_PLL0CR);
  97 
  98                 parent_name = "main";
  99                 mult = ((value >> 24) & 0x7f) + 1;
 100                 if (value & BIT(20))
 101                         div = 2;
 102         } else if (!strcmp(name, "pll1")) {
 103                 u32 value = readl(cpg->reg + CPG_PLL1CR);
 104 
 105                 parent_name = "main";
 106                 /* XXX: enable bit? */
 107                 mult = ((value >> 24) & 0x7f) + 1;
 108                 if (value & BIT(7))
 109                         div = 2;
 110         } else if (!strncmp(name, "pll2", 4)) {
 111                 u32 value, cr;
 112 
 113                 switch (name[4]) {
 114                 case 0:
 115                         cr = CPG_PLL2CR;
 116                         break;
 117                 case 's':
 118                         cr = CPG_PLL2SCR;
 119                         break;
 120                 case 'h':
 121                         cr = CPG_PLL2HCR;
 122                         break;
 123                 default:
 124                         return ERR_PTR(-EINVAL);
 125                 }
 126                 value = readl(cpg->reg + cr);
 127                 switch ((value >> 5) & 7) {
 128                 case 0:
 129                         parent_name = "main";
 130                         div = 2;
 131                         break;
 132                 case 1:
 133                         parent_name = "extal2";
 134                         div = 2;
 135                         break;
 136                 case 3:
 137                         parent_name = "extal2";
 138                         div = 4;
 139                         break;
 140                 case 4:
 141                         parent_name = "main";
 142                         break;
 143                 case 5:
 144                         parent_name = "extal2";
 145                         break;
 146                 default:
 147                         pr_warn("%s: unexpected parent of %s\n", __func__,
 148                                 name);
 149                         return ERR_PTR(-EINVAL);
 150                 }
 151                 /* XXX: enable bit? */
 152                 mult = ((value >> 24) & 0x7f) + 1;
 153         } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
 154                 u32 shift = 8;
 155 
 156                 parent_name = "pll0";
 157                 if (name[1] == '2') {
 158                         div = 2;
 159                         shift = 0;
 160                 }
 161                 div *= 32;
 162                 mult = 0x20 - ((readl(cpg->reg + CPG_FRQCRC) >> shift) & 0x1f);
 163         } else {
 164                 struct div4_clk *c;
 165 
 166                 for (c = div4_clks; c->name; c++) {
 167                         if (!strcmp(name, c->name))
 168                                 break;
 169                 }
 170                 if (!c->name)
 171                         return ERR_PTR(-EINVAL);
 172 
 173                 parent_name = "pll1";
 174                 table = div4_div_table;
 175                 reg = c->reg;
 176                 shift = c->shift;
 177         }
 178 
 179         if (!table) {
 180                 return clk_register_fixed_factor(NULL, name, parent_name, 0,
 181                                                  mult, div);
 182         } else {
 183                 return clk_register_divider_table(NULL, name, parent_name, 0,
 184                                                   cpg->reg + reg, shift, 4, 0,
 185                                                   table, &cpg->lock);
 186         }
 187 }
 188 
 189 static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
 190 {
 191         struct r8a73a4_cpg *cpg;
 192         struct clk **clks;
 193         unsigned int i;
 194         int num_clks;
 195 
 196         num_clks = of_property_count_strings(np, "clock-output-names");
 197         if (num_clks < 0) {
 198                 pr_err("%s: failed to count clocks\n", __func__);
 199                 return;
 200         }
 201 
 202         cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
 203         clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
 204         if (cpg == NULL || clks == NULL) {
 205                 /* We're leaking memory on purpose, there's no point in cleaning
 206                  * up as the system won't boot anyway.
 207                  */
 208                 return;
 209         }
 210 
 211         spin_lock_init(&cpg->lock);
 212 
 213         cpg->data.clks = clks;
 214         cpg->data.clk_num = num_clks;
 215 
 216         cpg->reg = of_iomap(np, 0);
 217         if (WARN_ON(cpg->reg == NULL))
 218                 return;
 219 
 220         for (i = 0; i < num_clks; ++i) {
 221                 const char *name;
 222                 struct clk *clk;
 223 
 224                 of_property_read_string_index(np, "clock-output-names", i,
 225                                               &name);
 226 
 227                 clk = r8a73a4_cpg_register_clock(np, cpg, name);
 228                 if (IS_ERR(clk))
 229                         pr_err("%s: failed to register %pOFn %s clock (%ld)\n",
 230                                __func__, np, name, PTR_ERR(clk));
 231                 else
 232                         cpg->data.clks[i] = clk;
 233         }
 234 
 235         of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
 236 }
 237 CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
 238                r8a73a4_cpg_clocks_init);

/* [<][>][^][v][top][bottom][index][help] */