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