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