linux/drivers/clk/renesas/clk-r8a73a4.c
<<
>>
Prefs
   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
  18struct 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
  36struct div4_clk {
  37        const char *name;
  38        unsigned int reg;
  39        unsigned int shift;
  40};
  41
  42static 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
  54static 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
  60static struct clk * __init
  61r8a73a4_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
 189static 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}
 237CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
 238               r8a73a4_cpg_clocks_init);
 239