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