linux/drivers/clk/mmp/clk-apbc.c
<<
>>
Prefs
   1/*
   2 * mmp APB clock operation source file
   3 *
   4 * Copyright (C) 2012 Marvell
   5 * Chao Xie <xiechao.mail@gmail.com>
   6 *
   7 * This file is licensed under the terms of the GNU General Public
   8 * License version 2. This program is licensed "as is" without any
   9 * warranty of any kind, whether express or implied.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/io.h>
  14#include <linux/err.h>
  15#include <linux/delay.h>
  16#include <linux/slab.h>
  17
  18#include "clk.h"
  19
  20/* Common APB clock register bit definitions */
  21#define APBC_APBCLK     (1 << 0)  /* APB Bus Clock Enable */
  22#define APBC_FNCLK      (1 << 1)  /* Functional Clock Enable */
  23#define APBC_RST        (1 << 2)  /* Reset Generation */
  24#define APBC_POWER      (1 << 7)  /* Reset Generation */
  25
  26#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
  27struct clk_apbc {
  28        struct clk_hw           hw;
  29        void __iomem            *base;
  30        unsigned int            delay;
  31        unsigned int            flags;
  32        spinlock_t              *lock;
  33};
  34
  35static int clk_apbc_prepare(struct clk_hw *hw)
  36{
  37        struct clk_apbc *apbc = to_clk_apbc(hw);
  38        unsigned int data;
  39        unsigned long flags = 0;
  40
  41        /*
  42         * It may share same register as MUX clock,
  43         * and it will impact FNCLK enable. Spinlock is needed
  44         */
  45        if (apbc->lock)
  46                spin_lock_irqsave(apbc->lock, flags);
  47
  48        data = readl_relaxed(apbc->base);
  49        if (apbc->flags & APBC_POWER_CTRL)
  50                data |= APBC_POWER;
  51        data |= APBC_FNCLK;
  52        writel_relaxed(data, apbc->base);
  53
  54        if (apbc->lock)
  55                spin_unlock_irqrestore(apbc->lock, flags);
  56
  57        udelay(apbc->delay);
  58
  59        if (apbc->lock)
  60                spin_lock_irqsave(apbc->lock, flags);
  61
  62        data = readl_relaxed(apbc->base);
  63        data |= APBC_APBCLK;
  64        writel_relaxed(data, apbc->base);
  65
  66        if (apbc->lock)
  67                spin_unlock_irqrestore(apbc->lock, flags);
  68
  69        udelay(apbc->delay);
  70
  71        if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
  72                if (apbc->lock)
  73                        spin_lock_irqsave(apbc->lock, flags);
  74
  75                data = readl_relaxed(apbc->base);
  76                data &= ~APBC_RST;
  77                writel_relaxed(data, apbc->base);
  78
  79                if (apbc->lock)
  80                        spin_unlock_irqrestore(apbc->lock, flags);
  81        }
  82
  83        return 0;
  84}
  85
  86static void clk_apbc_unprepare(struct clk_hw *hw)
  87{
  88        struct clk_apbc *apbc = to_clk_apbc(hw);
  89        unsigned long data;
  90        unsigned long flags = 0;
  91
  92        if (apbc->lock)
  93                spin_lock_irqsave(apbc->lock, flags);
  94
  95        data = readl_relaxed(apbc->base);
  96        if (apbc->flags & APBC_POWER_CTRL)
  97                data &= ~APBC_POWER;
  98        data &= ~APBC_FNCLK;
  99        writel_relaxed(data, apbc->base);
 100
 101        if (apbc->lock)
 102                spin_unlock_irqrestore(apbc->lock, flags);
 103
 104        udelay(10);
 105
 106        if (apbc->lock)
 107                spin_lock_irqsave(apbc->lock, flags);
 108
 109        data = readl_relaxed(apbc->base);
 110        data &= ~APBC_APBCLK;
 111        writel_relaxed(data, apbc->base);
 112
 113        if (apbc->lock)
 114                spin_unlock_irqrestore(apbc->lock, flags);
 115}
 116
 117static const struct clk_ops clk_apbc_ops = {
 118        .prepare = clk_apbc_prepare,
 119        .unprepare = clk_apbc_unprepare,
 120};
 121
 122struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
 123                void __iomem *base, unsigned int delay,
 124                unsigned int apbc_flags, spinlock_t *lock)
 125{
 126        struct clk_apbc *apbc;
 127        struct clk *clk;
 128        struct clk_init_data init;
 129
 130        apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
 131        if (!apbc)
 132                return NULL;
 133
 134        init.name = name;
 135        init.ops = &clk_apbc_ops;
 136        init.flags = CLK_SET_RATE_PARENT;
 137        init.parent_names = (parent_name ? &parent_name : NULL);
 138        init.num_parents = (parent_name ? 1 : 0);
 139
 140        apbc->base = base;
 141        apbc->delay = delay;
 142        apbc->flags = apbc_flags;
 143        apbc->lock = lock;
 144        apbc->hw.init = &init;
 145
 146        clk = clk_register(NULL, &apbc->hw);
 147        if (IS_ERR(clk))
 148                kfree(apbc);
 149
 150        return clk;
 151}
 152