linux/drivers/clk/at91/clk-programmable.c
<<
>>
Prefs
   1/*
   2 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * (at your option) any later version.
   8 *
   9 */
  10
  11#include <linux/clk-provider.h>
  12#include <linux/clkdev.h>
  13#include <linux/clk/at91_pmc.h>
  14#include <linux/of.h>
  15#include <linux/mfd/syscon.h>
  16#include <linux/regmap.h>
  17
  18#include "pmc.h"
  19
  20#define PROG_SOURCE_MAX         5
  21#define PROG_ID_MAX             7
  22
  23#define PROG_STATUS_MASK(id)    (1 << ((id) + 8))
  24#define PROG_PRES_MASK          0x7
  25#define PROG_PRES(layout, pckr) ((pckr >> layout->pres_shift) & PROG_PRES_MASK)
  26#define PROG_MAX_RM9200_CSS     3
  27
  28struct clk_programmable_layout {
  29        u8 pres_shift;
  30        u8 css_mask;
  31        u8 have_slck_mck;
  32};
  33
  34struct clk_programmable {
  35        struct clk_hw hw;
  36        struct regmap *regmap;
  37        u8 id;
  38        const struct clk_programmable_layout *layout;
  39};
  40
  41#define to_clk_programmable(hw) container_of(hw, struct clk_programmable, hw)
  42
  43static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
  44                                                  unsigned long parent_rate)
  45{
  46        struct clk_programmable *prog = to_clk_programmable(hw);
  47        unsigned int pckr;
  48
  49        regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
  50
  51        return parent_rate >> PROG_PRES(prog->layout, pckr);
  52}
  53
  54static int clk_programmable_determine_rate(struct clk_hw *hw,
  55                                           struct clk_rate_request *req)
  56{
  57        struct clk_hw *parent;
  58        long best_rate = -EINVAL;
  59        unsigned long parent_rate;
  60        unsigned long tmp_rate;
  61        int shift;
  62        int i;
  63
  64        for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
  65                parent = clk_hw_get_parent_by_index(hw, i);
  66                if (!parent)
  67                        continue;
  68
  69                parent_rate = clk_hw_get_rate(parent);
  70                for (shift = 0; shift < PROG_PRES_MASK; shift++) {
  71                        tmp_rate = parent_rate >> shift;
  72                        if (tmp_rate <= req->rate)
  73                                break;
  74                }
  75
  76                if (tmp_rate > req->rate)
  77                        continue;
  78
  79                if (best_rate < 0 ||
  80                    (req->rate - tmp_rate) < (req->rate - best_rate)) {
  81                        best_rate = tmp_rate;
  82                        req->best_parent_rate = parent_rate;
  83                        req->best_parent_hw = parent;
  84                }
  85
  86                if (!best_rate)
  87                        break;
  88        }
  89
  90        if (best_rate < 0)
  91                return best_rate;
  92
  93        req->rate = best_rate;
  94        return 0;
  95}
  96
  97static int clk_programmable_set_parent(struct clk_hw *hw, u8 index)
  98{
  99        struct clk_programmable *prog = to_clk_programmable(hw);
 100        const struct clk_programmable_layout *layout = prog->layout;
 101        unsigned int mask = layout->css_mask;
 102        unsigned int pckr = index;
 103
 104        if (layout->have_slck_mck)
 105                mask |= AT91_PMC_CSSMCK_MCK;
 106
 107        if (index > layout->css_mask) {
 108                if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
 109                        return -EINVAL;
 110
 111                pckr |= AT91_PMC_CSSMCK_MCK;
 112        }
 113
 114        regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id), mask, pckr);
 115
 116        return 0;
 117}
 118
 119static u8 clk_programmable_get_parent(struct clk_hw *hw)
 120{
 121        struct clk_programmable *prog = to_clk_programmable(hw);
 122        const struct clk_programmable_layout *layout = prog->layout;
 123        unsigned int pckr;
 124        u8 ret;
 125
 126        regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
 127
 128        ret = pckr & layout->css_mask;
 129
 130        if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
 131                ret = PROG_MAX_RM9200_CSS + 1;
 132
 133        return ret;
 134}
 135
 136static int clk_programmable_set_rate(struct clk_hw *hw, unsigned long rate,
 137                                     unsigned long parent_rate)
 138{
 139        struct clk_programmable *prog = to_clk_programmable(hw);
 140        const struct clk_programmable_layout *layout = prog->layout;
 141        unsigned long div = parent_rate / rate;
 142        unsigned int pckr;
 143        int shift = 0;
 144
 145        regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
 146
 147        if (!div)
 148                return -EINVAL;
 149
 150        shift = fls(div) - 1;
 151
 152        if (div != (1 << shift))
 153                return -EINVAL;
 154
 155        if (shift >= PROG_PRES_MASK)
 156                return -EINVAL;
 157
 158        regmap_update_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
 159                           PROG_PRES_MASK << layout->pres_shift,
 160                           shift << layout->pres_shift);
 161
 162        return 0;
 163}
 164
 165static const struct clk_ops programmable_ops = {
 166        .recalc_rate = clk_programmable_recalc_rate,
 167        .determine_rate = clk_programmable_determine_rate,
 168        .get_parent = clk_programmable_get_parent,
 169        .set_parent = clk_programmable_set_parent,
 170        .set_rate = clk_programmable_set_rate,
 171};
 172
 173static struct clk_hw * __init
 174at91_clk_register_programmable(struct regmap *regmap,
 175                               const char *name, const char **parent_names,
 176                               u8 num_parents, u8 id,
 177                               const struct clk_programmable_layout *layout)
 178{
 179        struct clk_programmable *prog;
 180        struct clk_hw *hw;
 181        struct clk_init_data init;
 182        int ret;
 183
 184        if (id > PROG_ID_MAX)
 185                return ERR_PTR(-EINVAL);
 186
 187        prog = kzalloc(sizeof(*prog), GFP_KERNEL);
 188        if (!prog)
 189                return ERR_PTR(-ENOMEM);
 190
 191        init.name = name;
 192        init.ops = &programmable_ops;
 193        init.parent_names = parent_names;
 194        init.num_parents = num_parents;
 195        init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
 196
 197        prog->id = id;
 198        prog->layout = layout;
 199        prog->hw.init = &init;
 200        prog->regmap = regmap;
 201
 202        hw = &prog->hw;
 203        ret = clk_hw_register(NULL, &prog->hw);
 204        if (ret) {
 205                kfree(prog);
 206                hw = ERR_PTR(ret);
 207        }
 208
 209        return hw;
 210}
 211
 212static const struct clk_programmable_layout at91rm9200_programmable_layout = {
 213        .pres_shift = 2,
 214        .css_mask = 0x3,
 215        .have_slck_mck = 0,
 216};
 217
 218static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
 219        .pres_shift = 2,
 220        .css_mask = 0x3,
 221        .have_slck_mck = 1,
 222};
 223
 224static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
 225        .pres_shift = 4,
 226        .css_mask = 0x7,
 227        .have_slck_mck = 0,
 228};
 229
 230static void __init
 231of_at91_clk_prog_setup(struct device_node *np,
 232                       const struct clk_programmable_layout *layout)
 233{
 234        int num;
 235        u32 id;
 236        struct clk_hw *hw;
 237        unsigned int num_parents;
 238        const char *parent_names[PROG_SOURCE_MAX];
 239        const char *name;
 240        struct device_node *progclknp;
 241        struct regmap *regmap;
 242
 243        num_parents = of_clk_get_parent_count(np);
 244        if (num_parents == 0 || num_parents > PROG_SOURCE_MAX)
 245                return;
 246
 247        of_clk_parent_fill(np, parent_names, num_parents);
 248
 249        num = of_get_child_count(np);
 250        if (!num || num > (PROG_ID_MAX + 1))
 251                return;
 252
 253        regmap = syscon_node_to_regmap(of_get_parent(np));
 254        if (IS_ERR(regmap))
 255                return;
 256
 257        for_each_child_of_node(np, progclknp) {
 258                if (of_property_read_u32(progclknp, "reg", &id))
 259                        continue;
 260
 261                if (of_property_read_string(np, "clock-output-names", &name))
 262                        name = progclknp->name;
 263
 264                hw = at91_clk_register_programmable(regmap, name,
 265                                                     parent_names, num_parents,
 266                                                     id, layout);
 267                if (IS_ERR(hw))
 268                        continue;
 269
 270                of_clk_add_hw_provider(progclknp, of_clk_hw_simple_get, hw);
 271        }
 272}
 273
 274
 275static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
 276{
 277        of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
 278}
 279CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
 280               of_at91rm9200_clk_prog_setup);
 281
 282static void __init of_at91sam9g45_clk_prog_setup(struct device_node *np)
 283{
 284        of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
 285}
 286CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
 287               of_at91sam9g45_clk_prog_setup);
 288
 289static void __init of_at91sam9x5_clk_prog_setup(struct device_node *np)
 290{
 291        of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
 292}
 293CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
 294               of_at91sam9x5_clk_prog_setup);
 295