linux/drivers/clk/ti/mux.c
<<
>>
Prefs
   1/*
   2 * TI Multiplexer Clock
   3 *
   4 * Copyright (C) 2013 Texas Instruments, Inc.
   5 *
   6 * Tero Kristo <t-kristo@ti.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  13 * kind, whether express or implied; without even the implied warranty
  14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 */
  17
  18#include <linux/clk-provider.h>
  19#include <linux/slab.h>
  20#include <linux/err.h>
  21#include <linux/of.h>
  22#include <linux/of_address.h>
  23#include <linux/clk/ti.h>
  24#include "clock.h"
  25
  26#undef pr_fmt
  27#define pr_fmt(fmt) "%s: " fmt, __func__
  28
  29static u8 ti_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
  37         * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges
  38         * from 0x1 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 = ti_clk_ll_ops->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 ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
  67{
  68        struct clk_mux *mux = to_clk_mux(hw);
  69        u32 val;
  70
  71        if (mux->table) {
  72                index = mux->table[index];
  73        } else {
  74                if (mux->flags & CLK_MUX_INDEX_BIT)
  75                        index = (1 << ffs(index));
  76
  77                if (mux->flags & CLK_MUX_INDEX_ONE)
  78                        index++;
  79        }
  80
  81        if (mux->flags & CLK_MUX_HIWORD_MASK) {
  82                val = mux->mask << (mux->shift + 16);
  83        } else {
  84                val = ti_clk_ll_ops->clk_readl(mux->reg);
  85                val &= ~(mux->mask << mux->shift);
  86        }
  87        val |= index << mux->shift;
  88        ti_clk_ll_ops->clk_writel(val, mux->reg);
  89
  90        return 0;
  91}
  92
  93const struct clk_ops ti_clk_mux_ops = {
  94        .get_parent = ti_clk_mux_get_parent,
  95        .set_parent = ti_clk_mux_set_parent,
  96        .determine_rate = __clk_mux_determine_rate,
  97};
  98
  99static struct clk *_register_mux(struct device *dev, const char *name,
 100                                 const char **parent_names, u8 num_parents,
 101                                 unsigned long flags, void __iomem *reg,
 102                                 u8 shift, u32 mask, u8 clk_mux_flags,
 103                                 u32 *table)
 104{
 105        struct clk_mux *mux;
 106        struct clk *clk;
 107        struct clk_init_data init;
 108
 109        /* allocate the mux */
 110        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 111        if (!mux) {
 112                pr_err("%s: could not allocate mux clk\n", __func__);
 113                return ERR_PTR(-ENOMEM);
 114        }
 115
 116        init.name = name;
 117        init.ops = &ti_clk_mux_ops;
 118        init.flags = flags | CLK_IS_BASIC;
 119        init.parent_names = parent_names;
 120        init.num_parents = num_parents;
 121
 122        /* struct clk_mux assignments */
 123        mux->reg = reg;
 124        mux->shift = shift;
 125        mux->mask = mask;
 126        mux->flags = clk_mux_flags;
 127        mux->table = table;
 128        mux->hw.init = &init;
 129
 130        clk = clk_register(dev, &mux->hw);
 131
 132        if (IS_ERR(clk))
 133                kfree(mux);
 134
 135        return clk;
 136}
 137
 138struct clk *ti_clk_register_mux(struct ti_clk *setup)
 139{
 140        struct ti_clk_mux *mux;
 141        u32 flags;
 142        u8 mux_flags = 0;
 143        struct clk_omap_reg *reg_setup;
 144        u32 reg;
 145        u32 mask;
 146
 147        reg_setup = (struct clk_omap_reg *)&reg;
 148
 149        mux = setup->data;
 150        flags = CLK_SET_RATE_NO_REPARENT;
 151
 152        mask = mux->num_parents;
 153        if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
 154                mask--;
 155
 156        mask = (1 << fls(mask)) - 1;
 157        reg_setup->index = mux->module;
 158        reg_setup->offset = mux->reg;
 159
 160        if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
 161                mux_flags |= CLK_MUX_INDEX_ONE;
 162
 163        if (mux->flags & CLKF_SET_RATE_PARENT)
 164                flags |= CLK_SET_RATE_PARENT;
 165
 166        return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
 167                             flags, (void __iomem *)reg, mux->bit_shift, mask,
 168                             mux_flags, NULL);
 169}
 170
 171/**
 172 * of_mux_clk_setup - Setup function for simple mux rate clock
 173 * @node: DT node for the clock
 174 *
 175 * Sets up a basic clock multiplexer.
 176 */
 177static void of_mux_clk_setup(struct device_node *node)
 178{
 179        struct clk *clk;
 180        void __iomem *reg;
 181        unsigned int num_parents;
 182        const char **parent_names;
 183        u8 clk_mux_flags = 0;
 184        u32 mask = 0;
 185        u32 shift = 0;
 186        u32 flags = CLK_SET_RATE_NO_REPARENT;
 187
 188        num_parents = of_clk_get_parent_count(node);
 189        if (num_parents < 2) {
 190                pr_err("mux-clock %s must have parents\n", node->name);
 191                return;
 192        }
 193        parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
 194        if (!parent_names)
 195                goto cleanup;
 196
 197        of_clk_parent_fill(node, parent_names, num_parents);
 198
 199        reg = ti_clk_get_reg_addr(node, 0);
 200
 201        if (IS_ERR(reg))
 202                goto cleanup;
 203
 204        of_property_read_u32(node, "ti,bit-shift", &shift);
 205
 206        if (of_property_read_bool(node, "ti,index-starts-at-one"))
 207                clk_mux_flags |= CLK_MUX_INDEX_ONE;
 208
 209        if (of_property_read_bool(node, "ti,set-rate-parent"))
 210                flags |= CLK_SET_RATE_PARENT;
 211
 212        /* Generate bit-mask based on parent info */
 213        mask = num_parents;
 214        if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
 215                mask--;
 216
 217        mask = (1 << fls(mask)) - 1;
 218
 219        clk = _register_mux(NULL, node->name, parent_names, num_parents,
 220                            flags, reg, shift, mask, clk_mux_flags, NULL);
 221
 222        if (!IS_ERR(clk))
 223                of_clk_add_provider(node, of_clk_src_simple_get, clk);
 224
 225cleanup:
 226        kfree(parent_names);
 227}
 228CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
 229
 230struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
 231{
 232        struct clk_mux *mux;
 233        struct clk_omap_reg *reg;
 234        int num_parents;
 235
 236        if (!setup)
 237                return NULL;
 238
 239        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 240        if (!mux)
 241                return ERR_PTR(-ENOMEM);
 242
 243        reg = (struct clk_omap_reg *)&mux->reg;
 244
 245        mux->shift = setup->bit_shift;
 246
 247        reg->index = setup->module;
 248        reg->offset = setup->reg;
 249
 250        if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
 251                mux->flags |= CLK_MUX_INDEX_ONE;
 252
 253        num_parents = setup->num_parents;
 254
 255        mux->mask = num_parents - 1;
 256        mux->mask = (1 << fls(mux->mask)) - 1;
 257
 258        return &mux->hw;
 259}
 260
 261static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
 262{
 263        struct clk_mux *mux;
 264        unsigned int num_parents;
 265        u32 val;
 266
 267        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 268        if (!mux)
 269                return;
 270
 271        mux->reg = ti_clk_get_reg_addr(node, 0);
 272
 273        if (IS_ERR(mux->reg))
 274                goto cleanup;
 275
 276        if (!of_property_read_u32(node, "ti,bit-shift", &val))
 277                mux->shift = val;
 278
 279        if (of_property_read_bool(node, "ti,index-starts-at-one"))
 280                mux->flags |= CLK_MUX_INDEX_ONE;
 281
 282        num_parents = of_clk_get_parent_count(node);
 283
 284        if (num_parents < 2) {
 285                pr_err("%s must have parents\n", node->name);
 286                goto cleanup;
 287        }
 288
 289        mux->mask = num_parents - 1;
 290        mux->mask = (1 << fls(mux->mask)) - 1;
 291
 292        if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
 293                return;
 294
 295cleanup:
 296        kfree(mux);
 297}
 298CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
 299               of_ti_composite_mux_clk_setup);
 300