linux/drivers/clk/mvebu/clk-gating-ctrl.c
<<
>>
Prefs
   1/*
   2 * Marvell MVEBU clock gating control.
   3 *
   4 * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
   5 * Andrew Lunn <andrew@lunn.ch>
   6 *
   7 * This file is licensed under the terms of the GNU General Public
   8 * License version 2. This program is licensed "as is" without any
   9 * warranty of any kind, whether express or implied.
  10 */
  11#include <linux/kernel.h>
  12#include <linux/bitops.h>
  13#include <linux/io.h>
  14#include <linux/clk.h>
  15#include <linux/clkdev.h>
  16#include <linux/clk-provider.h>
  17#include <linux/clk/mvebu.h>
  18#include <linux/of.h>
  19#include <linux/of_address.h>
  20
  21struct mvebu_gating_ctrl {
  22        spinlock_t lock;
  23        struct clk **gates;
  24        int num_gates;
  25};
  26
  27struct mvebu_soc_descr {
  28        const char *name;
  29        const char *parent;
  30        int bit_idx;
  31};
  32
  33#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
  34
  35static struct clk *mvebu_clk_gating_get_src(
  36        struct of_phandle_args *clkspec, void *data)
  37{
  38        struct mvebu_gating_ctrl *ctrl = (struct mvebu_gating_ctrl *)data;
  39        int n;
  40
  41        if (clkspec->args_count < 1)
  42                return ERR_PTR(-EINVAL);
  43
  44        for (n = 0; n < ctrl->num_gates; n++) {
  45                struct clk_gate *gate =
  46                        to_clk_gate(__clk_get_hw(ctrl->gates[n]));
  47                if (clkspec->args[0] == gate->bit_idx)
  48                        return ctrl->gates[n];
  49        }
  50        return ERR_PTR(-ENODEV);
  51}
  52
  53static void __init mvebu_clk_gating_setup(
  54        struct device_node *np, const struct mvebu_soc_descr *descr)
  55{
  56        struct mvebu_gating_ctrl *ctrl;
  57        struct clk *clk;
  58        void __iomem *base;
  59        const char *default_parent = NULL;
  60        int n;
  61
  62        base = of_iomap(np, 0);
  63
  64        clk = of_clk_get(np, 0);
  65        if (!IS_ERR(clk)) {
  66                default_parent = __clk_get_name(clk);
  67                clk_put(clk);
  68        }
  69
  70        ctrl = kzalloc(sizeof(struct mvebu_gating_ctrl), GFP_KERNEL);
  71        if (WARN_ON(!ctrl))
  72                return;
  73
  74        spin_lock_init(&ctrl->lock);
  75
  76        /*
  77         * Count, allocate, and register clock gates
  78         */
  79        for (n = 0; descr[n].name;)
  80                n++;
  81
  82        ctrl->num_gates = n;
  83        ctrl->gates = kzalloc(ctrl->num_gates * sizeof(struct clk *),
  84                              GFP_KERNEL);
  85        if (WARN_ON(!ctrl->gates)) {
  86                kfree(ctrl);
  87                return;
  88        }
  89
  90        for (n = 0; n < ctrl->num_gates; n++) {
  91                u8 flags = 0;
  92                const char *parent =
  93                        (descr[n].parent) ? descr[n].parent : default_parent;
  94
  95                /*
  96                 * On Armada 370, the DDR clock is a special case: it
  97                 * isn't taken by any driver, but should anyway be
  98                 * kept enabled, so we mark it as IGNORE_UNUSED for
  99                 * now.
 100                 */
 101                if (!strcmp(descr[n].name, "ddr"))
 102                        flags |= CLK_IGNORE_UNUSED;
 103
 104                ctrl->gates[n] = clk_register_gate(NULL, descr[n].name, parent,
 105                                   flags, base, descr[n].bit_idx, 0, &ctrl->lock);
 106                WARN_ON(IS_ERR(ctrl->gates[n]));
 107        }
 108        of_clk_add_provider(np, mvebu_clk_gating_get_src, ctrl);
 109}
 110
 111/*
 112 * SoC specific clock gating control
 113 */
 114
 115#ifdef CONFIG_MACH_ARMADA_370
 116static const struct mvebu_soc_descr __initconst armada_370_gating_descr[] = {
 117        { "audio", NULL, 0 },
 118        { "pex0_en", NULL, 1 },
 119        { "pex1_en", NULL,  2 },
 120        { "ge1", NULL, 3 },
 121        { "ge0", NULL, 4 },
 122        { "pex0", NULL, 5 },
 123        { "pex1", NULL, 9 },
 124        { "sata0", NULL, 15 },
 125        { "sdio", NULL, 17 },
 126        { "tdm", NULL, 25 },
 127        { "ddr", NULL, 28 },
 128        { "sata1", NULL, 30 },
 129        { }
 130};
 131#endif
 132
 133#ifdef CONFIG_MACH_ARMADA_XP
 134static const struct mvebu_soc_descr __initconst armada_xp_gating_descr[] = {
 135        { "audio", NULL, 0 },
 136        { "ge3", NULL, 1 },
 137        { "ge2", NULL,  2 },
 138        { "ge1", NULL, 3 },
 139        { "ge0", NULL, 4 },
 140        { "pex0", NULL, 5 },
 141        { "pex1", NULL, 6 },
 142        { "pex2", NULL, 7 },
 143        { "pex3", NULL, 8 },
 144        { "bp", NULL, 13 },
 145        { "sata0lnk", NULL, 14 },
 146        { "sata0", "sata0lnk", 15 },
 147        { "lcd", NULL, 16 },
 148        { "sdio", NULL, 17 },
 149        { "usb0", NULL, 18 },
 150        { "usb1", NULL, 19 },
 151        { "usb2", NULL, 20 },
 152        { "xor0", NULL, 22 },
 153        { "crypto", NULL, 23 },
 154        { "tdm", NULL, 25 },
 155        { "xor1", NULL, 28 },
 156        { "sata1lnk", NULL, 29 },
 157        { "sata1", "sata1lnk", 30 },
 158        { }
 159};
 160#endif
 161
 162#ifdef CONFIG_ARCH_DOVE
 163static const struct mvebu_soc_descr __initconst dove_gating_descr[] = {
 164        { "usb0", NULL, 0 },
 165        { "usb1", NULL, 1 },
 166        { "ge", "gephy", 2 },
 167        { "sata", NULL, 3 },
 168        { "pex0", NULL, 4 },
 169        { "pex1", NULL, 5 },
 170        { "sdio0", NULL, 8 },
 171        { "sdio1", NULL, 9 },
 172        { "nand", NULL, 10 },
 173        { "camera", NULL, 11 },
 174        { "i2s0", NULL, 12 },
 175        { "i2s1", NULL, 13 },
 176        { "crypto", NULL, 15 },
 177        { "ac97", NULL, 21 },
 178        { "pdma", NULL, 22 },
 179        { "xor0", NULL, 23 },
 180        { "xor1", NULL, 24 },
 181        { "gephy", NULL, 30 },
 182        { }
 183};
 184#endif
 185
 186#ifdef CONFIG_ARCH_KIRKWOOD
 187static const struct mvebu_soc_descr __initconst kirkwood_gating_descr[] = {
 188        { "ge0", NULL, 0 },
 189        { "pex0", NULL, 2 },
 190        { "usb0", NULL, 3 },
 191        { "sdio", NULL, 4 },
 192        { "tsu", NULL, 5 },
 193        { "runit", NULL, 7 },
 194        { "xor0", NULL, 8 },
 195        { "audio", NULL, 9 },
 196        { "powersave", "cpuclk", 11 },
 197        { "sata0", NULL, 14 },
 198        { "sata1", NULL, 15 },
 199        { "xor1", NULL, 16 },
 200        { "crypto", NULL, 17 },
 201        { "pex1", NULL, 18 },
 202        { "ge1", NULL, 19 },
 203        { "tdm", NULL, 20 },
 204        { }
 205};
 206#endif
 207
 208static const __initdata struct of_device_id clk_gating_match[] = {
 209#ifdef CONFIG_MACH_ARMADA_370
 210        {
 211                .compatible = "marvell,armada-370-gating-clock",
 212                .data = armada_370_gating_descr,
 213        },
 214#endif
 215
 216#ifdef CONFIG_MACH_ARMADA_XP
 217        {
 218                .compatible = "marvell,armada-xp-gating-clock",
 219                .data = armada_xp_gating_descr,
 220        },
 221#endif
 222
 223#ifdef CONFIG_ARCH_DOVE
 224        {
 225                .compatible = "marvell,dove-gating-clock",
 226                .data = dove_gating_descr,
 227        },
 228#endif
 229
 230#ifdef CONFIG_ARCH_KIRKWOOD
 231        {
 232                .compatible = "marvell,kirkwood-gating-clock",
 233                .data = kirkwood_gating_descr,
 234        },
 235#endif
 236
 237        { }
 238};
 239
 240void __init mvebu_gating_clk_init(void)
 241{
 242        struct device_node *np;
 243
 244        for_each_matching_node(np, clk_gating_match) {
 245                const struct of_device_id *match =
 246                        of_match_node(clk_gating_match, np);
 247                mvebu_clk_gating_setup(np,
 248                       (const struct mvebu_soc_descr *)match->data);
 249        }
 250}
 251
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.