linux/drivers/clk/ux500/clk-prcmu.c
<<
>>
Prefs
   1/*
   2 * PRCMU clock implementation for ux500 platform.
   3 *
   4 * Copyright (C) 2012 ST-Ericsson SA
   5 * Author: Ulf Hansson <ulf.hansson@linaro.org>
   6 *
   7 * License terms: GNU General Public License (GPL) version 2
   8 */
   9
  10#include <linux/clk-provider.h>
  11#include <linux/clk-private.h>
  12#include <linux/mfd/dbx500-prcmu.h>
  13#include <linux/slab.h>
  14#include <linux/io.h>
  15#include <linux/err.h>
  16#include "clk.h"
  17
  18#define to_clk_prcmu(_hw) container_of(_hw, struct clk_prcmu, hw)
  19
  20struct clk_prcmu {
  21        struct clk_hw hw;
  22        u8 cg_sel;
  23        int is_prepared;
  24        int is_enabled;
  25        int opp_requested;
  26};
  27
  28/* PRCMU clock operations. */
  29
  30static int clk_prcmu_prepare(struct clk_hw *hw)
  31{
  32        int ret;
  33        struct clk_prcmu *clk = to_clk_prcmu(hw);
  34
  35        ret = prcmu_request_clock(clk->cg_sel, true);
  36        if (!ret)
  37                clk->is_prepared = 1;
  38
  39        return ret;;
  40}
  41
  42static void clk_prcmu_unprepare(struct clk_hw *hw)
  43{
  44        struct clk_prcmu *clk = to_clk_prcmu(hw);
  45        if (prcmu_request_clock(clk->cg_sel, false))
  46                pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
  47                        __clk_get_name(hw->clk));
  48        else
  49                clk->is_prepared = 0;
  50}
  51
  52static int clk_prcmu_is_prepared(struct clk_hw *hw)
  53{
  54        struct clk_prcmu *clk = to_clk_prcmu(hw);
  55        return clk->is_prepared;
  56}
  57
  58static int clk_prcmu_enable(struct clk_hw *hw)
  59{
  60        struct clk_prcmu *clk = to_clk_prcmu(hw);
  61        clk->is_enabled = 1;
  62        return 0;
  63}
  64
  65static void clk_prcmu_disable(struct clk_hw *hw)
  66{
  67        struct clk_prcmu *clk = to_clk_prcmu(hw);
  68        clk->is_enabled = 0;
  69}
  70
  71static int clk_prcmu_is_enabled(struct clk_hw *hw)
  72{
  73        struct clk_prcmu *clk = to_clk_prcmu(hw);
  74        return clk->is_enabled;
  75}
  76
  77static unsigned long clk_prcmu_recalc_rate(struct clk_hw *hw,
  78                                           unsigned long parent_rate)
  79{
  80        struct clk_prcmu *clk = to_clk_prcmu(hw);
  81        return prcmu_clock_rate(clk->cg_sel);
  82}
  83
  84static long clk_prcmu_round_rate(struct clk_hw *hw, unsigned long rate,
  85                                 unsigned long *parent_rate)
  86{
  87        struct clk_prcmu *clk = to_clk_prcmu(hw);
  88        return prcmu_round_clock_rate(clk->cg_sel, rate);
  89}
  90
  91static int clk_prcmu_set_rate(struct clk_hw *hw, unsigned long rate,
  92                              unsigned long parent_rate)
  93{
  94        struct clk_prcmu *clk = to_clk_prcmu(hw);
  95        return prcmu_set_clock_rate(clk->cg_sel, rate);
  96}
  97
  98static int clk_prcmu_opp_prepare(struct clk_hw *hw)
  99{
 100        int err;
 101        struct clk_prcmu *clk = to_clk_prcmu(hw);
 102
 103        if (!clk->opp_requested) {
 104                err = prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP,
 105                                                (char *)__clk_get_name(hw->clk),
 106                                                100);
 107                if (err) {
 108                        pr_err("clk_prcmu: %s fail req APE OPP for %s.\n",
 109                                __func__, __clk_get_name(hw->clk));
 110                        return err;
 111                }
 112                clk->opp_requested = 1;
 113        }
 114
 115        err = prcmu_request_clock(clk->cg_sel, true);
 116        if (err) {
 117                prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
 118                                        (char *)__clk_get_name(hw->clk));
 119                clk->opp_requested = 0;
 120                return err;
 121        }
 122
 123        clk->is_prepared = 1;
 124        return 0;
 125}
 126
 127static void clk_prcmu_opp_unprepare(struct clk_hw *hw)
 128{
 129        struct clk_prcmu *clk = to_clk_prcmu(hw);
 130
 131        if (prcmu_request_clock(clk->cg_sel, false)) {
 132                pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 133                        __clk_get_name(hw->clk));
 134                return;
 135        }
 136
 137        if (clk->opp_requested) {
 138                prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP,
 139                                        (char *)__clk_get_name(hw->clk));
 140                clk->opp_requested = 0;
 141        }
 142
 143        clk->is_prepared = 0;
 144}
 145
 146static int clk_prcmu_opp_volt_prepare(struct clk_hw *hw)
 147{
 148        int err;
 149        struct clk_prcmu *clk = to_clk_prcmu(hw);
 150
 151        if (!clk->opp_requested) {
 152                err = prcmu_request_ape_opp_100_voltage(true);
 153                if (err) {
 154                        pr_err("clk_prcmu: %s fail req APE OPP VOLT for %s.\n",
 155                                __func__, __clk_get_name(hw->clk));
 156                        return err;
 157                }
 158                clk->opp_requested = 1;
 159        }
 160
 161        err = prcmu_request_clock(clk->cg_sel, true);
 162        if (err) {
 163                prcmu_request_ape_opp_100_voltage(false);
 164                clk->opp_requested = 0;
 165                return err;
 166        }
 167
 168        clk->is_prepared = 1;
 169        return 0;
 170}
 171
 172static void clk_prcmu_opp_volt_unprepare(struct clk_hw *hw)
 173{
 174        struct clk_prcmu *clk = to_clk_prcmu(hw);
 175
 176        if (prcmu_request_clock(clk->cg_sel, false)) {
 177                pr_err("clk_prcmu: %s failed to disable %s.\n", __func__,
 178                        __clk_get_name(hw->clk));
 179                return;
 180        }
 181
 182        if (clk->opp_requested) {
 183                prcmu_request_ape_opp_100_voltage(false);
 184                clk->opp_requested = 0;
 185        }
 186
 187        clk->is_prepared = 0;
 188}
 189
 190static struct clk_ops clk_prcmu_scalable_ops = {
 191        .prepare = clk_prcmu_prepare,
 192        .unprepare = clk_prcmu_unprepare,
 193        .is_prepared = clk_prcmu_is_prepared,
 194        .enable = clk_prcmu_enable,
 195        .disable = clk_prcmu_disable,
 196        .is_enabled = clk_prcmu_is_enabled,
 197        .recalc_rate = clk_prcmu_recalc_rate,
 198        .round_rate = clk_prcmu_round_rate,
 199        .set_rate = clk_prcmu_set_rate,
 200};
 201
 202static struct clk_ops clk_prcmu_gate_ops = {
 203        .prepare = clk_prcmu_prepare,
 204        .unprepare = clk_prcmu_unprepare,
 205        .is_prepared = clk_prcmu_is_prepared,
 206        .enable = clk_prcmu_enable,
 207        .disable = clk_prcmu_disable,
 208        .is_enabled = clk_prcmu_is_enabled,
 209        .recalc_rate = clk_prcmu_recalc_rate,
 210};
 211
 212static struct clk_ops clk_prcmu_scalable_rate_ops = {
 213        .is_enabled = clk_prcmu_is_enabled,
 214        .recalc_rate = clk_prcmu_recalc_rate,
 215        .round_rate = clk_prcmu_round_rate,
 216        .set_rate = clk_prcmu_set_rate,
 217};
 218
 219static struct clk_ops clk_prcmu_rate_ops = {
 220        .is_enabled = clk_prcmu_is_enabled,
 221        .recalc_rate = clk_prcmu_recalc_rate,
 222};
 223
 224static struct clk_ops clk_prcmu_opp_gate_ops = {
 225        .prepare = clk_prcmu_opp_prepare,
 226        .unprepare = clk_prcmu_opp_unprepare,
 227        .is_prepared = clk_prcmu_is_prepared,
 228        .enable = clk_prcmu_enable,
 229        .disable = clk_prcmu_disable,
 230        .is_enabled = clk_prcmu_is_enabled,
 231        .recalc_rate = clk_prcmu_recalc_rate,
 232};
 233
 234static struct clk_ops clk_prcmu_opp_volt_scalable_ops = {
 235        .prepare = clk_prcmu_opp_volt_prepare,
 236        .unprepare = clk_prcmu_opp_volt_unprepare,
 237        .is_prepared = clk_prcmu_is_prepared,
 238        .enable = clk_prcmu_enable,
 239        .disable = clk_prcmu_disable,
 240        .is_enabled = clk_prcmu_is_enabled,
 241        .recalc_rate = clk_prcmu_recalc_rate,
 242        .round_rate = clk_prcmu_round_rate,
 243        .set_rate = clk_prcmu_set_rate,
 244};
 245
 246static struct clk *clk_reg_prcmu(const char *name,
 247                                 const char *parent_name,
 248                                 u8 cg_sel,
 249                                 unsigned long rate,
 250                                 unsigned long flags,
 251                                 struct clk_ops *clk_prcmu_ops)
 252{
 253        struct clk_prcmu *clk;
 254        struct clk_init_data clk_prcmu_init;
 255        struct clk *clk_reg;
 256
 257        if (!name) {
 258                pr_err("clk_prcmu: %s invalid arguments passed\n", __func__);
 259                return ERR_PTR(-EINVAL);
 260        }
 261
 262        clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL);
 263        if (!clk) {
 264                pr_err("clk_prcmu: %s could not allocate clk\n", __func__);
 265                return ERR_PTR(-ENOMEM);
 266        }
 267
 268        clk->cg_sel = cg_sel;
 269        clk->is_prepared = 1;
 270        clk->is_enabled = 1;
 271        clk->opp_requested = 0;
 272        /* "rate" can be used for changing the initial frequency */
 273        if (rate)
 274                prcmu_set_clock_rate(cg_sel, rate);
 275
 276        clk_prcmu_init.name = name;
 277        clk_prcmu_init.ops = clk_prcmu_ops;
 278        clk_prcmu_init.flags = flags;
 279        clk_prcmu_init.parent_names = (parent_name ? &parent_name : NULL);
 280        clk_prcmu_init.num_parents = (parent_name ? 1 : 0);
 281        clk->hw.init = &clk_prcmu_init;
 282
 283        clk_reg = clk_register(NULL, &clk->hw);
 284        if (IS_ERR_OR_NULL(clk_reg))
 285                goto free_clk;
 286
 287        return clk_reg;
 288
 289free_clk:
 290        kfree(clk);
 291        pr_err("clk_prcmu: %s failed to register clk\n", __func__);
 292        return ERR_PTR(-ENOMEM);
 293}
 294
 295struct clk *clk_reg_prcmu_scalable(const char *name,
 296                                   const char *parent_name,
 297                                   u8 cg_sel,
 298                                   unsigned long rate,
 299                                   unsigned long flags)
 300{
 301        return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
 302                        &clk_prcmu_scalable_ops);
 303}
 304
 305struct clk *clk_reg_prcmu_gate(const char *name,
 306                               const char *parent_name,
 307                               u8 cg_sel,
 308                               unsigned long flags)
 309{
 310        return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
 311                        &clk_prcmu_gate_ops);
 312}
 313
 314struct clk *clk_reg_prcmu_scalable_rate(const char *name,
 315                                        const char *parent_name,
 316                                        u8 cg_sel,
 317                                        unsigned long rate,
 318                                        unsigned long flags)
 319{
 320        return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
 321                        &clk_prcmu_scalable_rate_ops);
 322}
 323
 324struct clk *clk_reg_prcmu_rate(const char *name,
 325                               const char *parent_name,
 326                               u8 cg_sel,
 327                               unsigned long flags)
 328{
 329        return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
 330                        &clk_prcmu_rate_ops);
 331}
 332
 333struct clk *clk_reg_prcmu_opp_gate(const char *name,
 334                                   const char *parent_name,
 335                                   u8 cg_sel,
 336                                   unsigned long flags)
 337{
 338        return clk_reg_prcmu(name, parent_name, cg_sel, 0, flags,
 339                        &clk_prcmu_opp_gate_ops);
 340}
 341
 342struct clk *clk_reg_prcmu_opp_volt_scalable(const char *name,
 343                                            const char *parent_name,
 344                                            u8 cg_sel,
 345                                            unsigned long rate,
 346                                            unsigned long flags)
 347{
 348        return clk_reg_prcmu(name, parent_name, cg_sel, rate, flags,
 349                        &clk_prcmu_opp_volt_scalable_ops);
 350}
 351