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