linux/drivers/clk/ux500/clk-prcc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * PRCC 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/slab.h>
  11#include <linux/io.h>
  12#include <linux/err.h>
  13#include <linux/types.h>
  14
  15#include "clk.h"
  16
  17#define PRCC_PCKEN                      0x000
  18#define PRCC_PCKDIS                     0x004
  19#define PRCC_KCKEN                      0x008
  20#define PRCC_KCKDIS                     0x00C
  21#define PRCC_PCKSR                      0x010
  22#define PRCC_KCKSR                      0x014
  23
  24#define to_clk_prcc(_hw) container_of(_hw, struct clk_prcc, hw)
  25
  26struct clk_prcc {
  27        struct clk_hw hw;
  28        void __iomem *base;
  29        u32 cg_sel;
  30        int is_enabled;
  31};
  32
  33/* PRCC clock operations. */
  34
  35static int clk_prcc_pclk_enable(struct clk_hw *hw)
  36{
  37        struct clk_prcc *clk = to_clk_prcc(hw);
  38
  39        writel(clk->cg_sel, (clk->base + PRCC_PCKEN));
  40        while (!(readl(clk->base + PRCC_PCKSR) & clk->cg_sel))
  41                cpu_relax();
  42
  43        clk->is_enabled = 1;
  44        return 0;
  45}
  46
  47static void clk_prcc_pclk_disable(struct clk_hw *hw)
  48{
  49        struct clk_prcc *clk = to_clk_prcc(hw);
  50
  51        writel(clk->cg_sel, (clk->base + PRCC_PCKDIS));
  52        clk->is_enabled = 0;
  53}
  54
  55static int clk_prcc_kclk_enable(struct clk_hw *hw)
  56{
  57        struct clk_prcc *clk = to_clk_prcc(hw);
  58
  59        writel(clk->cg_sel, (clk->base + PRCC_KCKEN));
  60        while (!(readl(clk->base + PRCC_KCKSR) & clk->cg_sel))
  61                cpu_relax();
  62
  63        clk->is_enabled = 1;
  64        return 0;
  65}
  66
  67static void clk_prcc_kclk_disable(struct clk_hw *hw)
  68{
  69        struct clk_prcc *clk = to_clk_prcc(hw);
  70
  71        writel(clk->cg_sel, (clk->base + PRCC_KCKDIS));
  72        clk->is_enabled = 0;
  73}
  74
  75static int clk_prcc_is_enabled(struct clk_hw *hw)
  76{
  77        struct clk_prcc *clk = to_clk_prcc(hw);
  78        return clk->is_enabled;
  79}
  80
  81static const struct clk_ops clk_prcc_pclk_ops = {
  82        .enable = clk_prcc_pclk_enable,
  83        .disable = clk_prcc_pclk_disable,
  84        .is_enabled = clk_prcc_is_enabled,
  85};
  86
  87static const struct clk_ops clk_prcc_kclk_ops = {
  88        .enable = clk_prcc_kclk_enable,
  89        .disable = clk_prcc_kclk_disable,
  90        .is_enabled = clk_prcc_is_enabled,
  91};
  92
  93static struct clk *clk_reg_prcc(const char *name,
  94                                const char *parent_name,
  95                                resource_size_t phy_base,
  96                                u32 cg_sel,
  97                                unsigned long flags,
  98                                const struct clk_ops *clk_prcc_ops)
  99{
 100        struct clk_prcc *clk;
 101        struct clk_init_data clk_prcc_init;
 102        struct clk *clk_reg;
 103
 104        if (!name) {
 105                pr_err("clk_prcc: %s invalid arguments passed\n", __func__);
 106                return ERR_PTR(-EINVAL);
 107        }
 108
 109        clk = kzalloc(sizeof(*clk), GFP_KERNEL);
 110        if (!clk)
 111                return ERR_PTR(-ENOMEM);
 112
 113        clk->base = ioremap(phy_base, SZ_4K);
 114        if (!clk->base)
 115                goto free_clk;
 116
 117        clk->cg_sel = cg_sel;
 118        clk->is_enabled = 1;
 119
 120        clk_prcc_init.name = name;
 121        clk_prcc_init.ops = clk_prcc_ops;
 122        clk_prcc_init.flags = flags;
 123        clk_prcc_init.parent_names = (parent_name ? &parent_name : NULL);
 124        clk_prcc_init.num_parents = (parent_name ? 1 : 0);
 125        clk->hw.init = &clk_prcc_init;
 126
 127        clk_reg = clk_register(NULL, &clk->hw);
 128        if (IS_ERR_OR_NULL(clk_reg))
 129                goto unmap_clk;
 130
 131        return clk_reg;
 132
 133unmap_clk:
 134        iounmap(clk->base);
 135free_clk:
 136        kfree(clk);
 137        pr_err("clk_prcc: %s failed to register clk\n", __func__);
 138        return ERR_PTR(-ENOMEM);
 139}
 140
 141struct clk *clk_reg_prcc_pclk(const char *name,
 142                              const char *parent_name,
 143                              resource_size_t phy_base,
 144                              u32 cg_sel,
 145                              unsigned long flags)
 146{
 147        return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
 148                        &clk_prcc_pclk_ops);
 149}
 150
 151struct clk *clk_reg_prcc_kclk(const char *name,
 152                              const char *parent_name,
 153                              resource_size_t phy_base,
 154                              u32 cg_sel,
 155                              unsigned long flags)
 156{
 157        return clk_reg_prcc(name, parent_name, phy_base, cg_sel, flags,
 158                        &clk_prcc_kclk_ops);
 159}
 160