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