linux/drivers/clk/clk-mux.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
   3 * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
   4 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License version 2 as
   8 * published by the Free Software Foundation.
   9 *
  10 * Simple multiplexer clock implementation
  11 */
  12
  13#include <linux/clk-provider.h>
  14#include <linux/module.h>
  15#include <linux/slab.h>
  16#include <linux/io.h>
  17#include <linux/err.h>
  18
  19/*
  20 * DOC: basic adjustable multiplexer clock that cannot gate
  21 *
  22 * Traits of this clock:
  23 * prepare - clk_prepare only ensures that parents are prepared
  24 * enable - clk_enable only ensures that parents are enabled
  25 * rate - rate is only affected by parent switching.  No clk_set_rate support
  26 * parent - parent is adjustable through clk_set_parent
  27 */
  28
  29static u8 clk_mux_get_parent(struct clk_hw *hw)
  30{
  31        struct clk_mux *mux = to_clk_mux(hw);
  32        int num_parents = clk_hw_get_num_parents(hw);
  33        u32 val;
  34
  35        /*
  36         * FIXME need a mux-specific flag to determine if val is bitwise or numeric
  37         * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
  38         * to 0x7 (index starts at one)
  39         * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
  40         * val = 0x4 really means "bit 2, index starts at bit 0"
  41         */
  42        val = clk_readl(mux->reg) >> mux->shift;
  43        val &= mux->mask;
  44
  45        if (mux->table) {
  46                int i;
  47
  48                for (i = 0; i < num_parents; i++)
  49                        if (mux->table[i] == val)
  50                                return i;
  51                return -EINVAL;
  52        }
  53
  54        if (val && (mux->flags & CLK_MUX_INDEX_BIT))
  55                val = ffs(val) - 1;
  56
  57        if (val && (mux->flags & CLK_MUX_INDEX_ONE))
  58                val--;
  59
  60        if (val >= num_parents)
  61                return -EINVAL;
  62
  63        return val;
  64}
  65
  66static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
  67{
  68        struct clk_mux *mux = to_clk_mux(hw);
  69        u32 val;
  70        unsigned long flags = 0;
  71
  72        if (mux->table) {
  73                index = mux->table[index];
  74        } else {
  75                if (mux->flags & CLK_MUX_INDEX_BIT)
  76                        index = 1 << index;
  77
  78                if (mux->flags & CLK_MUX_INDEX_ONE)
  79                        index++;
  80        }
  81
  82        if (mux->lock)
  83                spin_lock_irqsave(mux->lock, flags);
  84        else
  85                __acquire(mux->lock);
  86
  87        if (mux->flags & CLK_MUX_HIWORD_MASK) {
  88                val = mux->mask << (mux->shift + 16);
  89        } else {
  90                val = clk_readl(mux->reg);
  91                val &= ~(mux->mask << mux->shift);
  92        }
  93        val |= index << mux->shift;
  94        clk_writel(val, mux->reg);
  95
  96        if (mux->lock)
  97                spin_unlock_irqrestore(mux->lock, flags);
  98        else
  99                __release(mux->lock);
 100
 101        return 0;
 102}
 103
 104const struct clk_ops clk_mux_ops = {
 105        .get_parent = clk_mux_get_parent,
 106        .set_parent = clk_mux_set_parent,
 107        .determine_rate = __clk_mux_determine_rate,
 108};
 109EXPORT_SYMBOL_GPL(clk_mux_ops);
 110
 111const struct clk_ops clk_mux_ro_ops = {
 112        .get_parent = clk_mux_get_parent,
 113};
 114EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
 115
 116struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name,
 117                const char * const *parent_names, u8 num_parents,
 118                unsigned long flags,
 119                void __iomem *reg, u8 shift, u32 mask,
 120                u8 clk_mux_flags, u32 *table, spinlock_t *lock)
 121{
 122        struct clk_mux *mux;
 123        struct clk_hw *hw;
 124        struct clk_init_data init;
 125        u8 width = 0;
 126        int ret;
 127
 128        if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
 129                width = fls(mask) - ffs(mask) + 1;
 130                if (width + shift > 16) {
 131                        pr_err("mux value exceeds LOWORD field\n");
 132                        return ERR_PTR(-EINVAL);
 133                }
 134        }
 135
 136        /* allocate the mux */
 137        mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
 138        if (!mux) {
 139                pr_err("%s: could not allocate mux clk\n", __func__);
 140                return ERR_PTR(-ENOMEM);
 141        }
 142
 143        init.name = name;
 144        if (clk_mux_flags & CLK_MUX_READ_ONLY)
 145                init.ops = &clk_mux_ro_ops;
 146        else
 147                init.ops = &clk_mux_ops;
 148        init.flags = flags | CLK_IS_BASIC;
 149        init.parent_names = parent_names;
 150        init.num_parents = num_parents;
 151
 152        /* struct clk_mux assignments */
 153        mux->reg = reg;
 154        mux->shift = shift;
 155        mux->mask = mask;
 156        mux->flags = clk_mux_flags;
 157        mux->lock = lock;
 158        mux->table = table;
 159        mux->hw.init = &init;
 160
 161        hw = &mux->hw;
 162        ret = clk_hw_register(dev, hw);
 163        if (ret) {
 164                kfree(mux);
 165                hw = ERR_PTR(ret);
 166        }
 167
 168        return hw;
 169}
 170EXPORT_SYMBOL_GPL(clk_hw_register_mux_table);
 171
 172struct clk *clk_register_mux_table(struct device *dev, const char *name,
 173                const char * const *parent_names, u8 num_parents,
 174                unsigned long flags,
 175                void __iomem *reg, u8 shift, u32 mask,
 176                u8 clk_mux_flags, u32 *table, spinlock_t *lock)
 177{
 178        struct clk_hw *hw;
 179
 180        hw = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
 181                                       flags, reg, shift, mask, clk_mux_flags,
 182                                       table, lock);
 183        if (IS_ERR(hw))
 184                return ERR_CAST(hw);
 185        return hw->clk;
 186}
 187EXPORT_SYMBOL_GPL(clk_register_mux_table);
 188
 189struct clk *clk_register_mux(struct device *dev, const char *name,
 190                const char * const *parent_names, u8 num_parents,
 191                unsigned long flags,
 192                void __iomem *reg, u8 shift, u8 width,
 193                u8 clk_mux_flags, spinlock_t *lock)
 194{
 195        u32 mask = BIT(width) - 1;
 196
 197        return clk_register_mux_table(dev, name, parent_names, num_parents,
 198                                      flags, reg, shift, mask, clk_mux_flags,
 199                                      NULL, lock);
 200}
 201EXPORT_SYMBOL_GPL(clk_register_mux);
 202
 203struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name,
 204                const char * const *parent_names, u8 num_parents,
 205                unsigned long flags,
 206                void __iomem *reg, u8 shift, u8 width,
 207                u8 clk_mux_flags, spinlock_t *lock)
 208{
 209        u32 mask = BIT(width) - 1;
 210
 211        return clk_hw_register_mux_table(dev, name, parent_names, num_parents,
 212                                      flags, reg, shift, mask, clk_mux_flags,
 213                                      NULL, lock);
 214}
 215EXPORT_SYMBOL_GPL(clk_hw_register_mux);
 216
 217void clk_unregister_mux(struct clk *clk)
 218{
 219        struct clk_mux *mux;
 220        struct clk_hw *hw;
 221
 222        hw = __clk_get_hw(clk);
 223        if (!hw)
 224                return;
 225
 226        mux = to_clk_mux(hw);
 227
 228        clk_unregister(clk);
 229        kfree(mux);
 230}
 231EXPORT_SYMBOL_GPL(clk_unregister_mux);
 232
 233void clk_hw_unregister_mux(struct clk_hw *hw)
 234{
 235        struct clk_mux *mux;
 236
 237        mux = to_clk_mux(hw);
 238
 239        clk_hw_unregister(hw);
 240        kfree(mux);
 241}
 242EXPORT_SYMBOL_GPL(clk_hw_unregister_mux);
 243