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_omap_mux *mux = to_clk_omap_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_omap_mux *mux = to_clk_omap_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        ti_clk_latch(&mux->reg, mux->latch);
  90
  91        return 0;
  92}
  93
  94/**
  95 * clk_mux_save_context - Save the parent selcted in the mux
  96 * @hw: pointer  struct clk_hw
  97 *
  98 * Save the parent mux value.
  99 */
 100static int clk_mux_save_context(struct clk_hw *hw)
 101{
 102        struct clk_omap_mux *mux = to_clk_omap_mux(hw);
 103
 104        mux->saved_parent = ti_clk_mux_get_parent(hw);
 105        return 0;
 106}
 107
 108/**
 109 * clk_mux_restore_context - Restore the parent in the mux
 110 * @hw: pointer  struct clk_hw
 111 *
 112 * Restore the saved parent mux value.
 113 */
 114static void clk_mux_restore_context(struct clk_hw *hw)
 115{
 116        struct clk_omap_mux *mux = to_clk_omap_mux(hw);
 117
 118        ti_clk_mux_set_parent(hw, mux->saved_parent);
 119}
 120
 121const struct clk_ops ti_clk_mux_ops = {
 122        .get_parent = ti_clk_mux_get_parent,
 123        .set_parent = ti_clk_mux_set_parent,
 124        .determine_rate = __clk_mux_determine_rate,
 125        .save_context = clk_mux_save_context,
 126        .restore_context = clk_mux_restore_context,
 127};
 128
 129static struct clk *_register_mux(struct device *dev, const char *name,
 130                                 const char * const *parent_names,
 131                                 u8 num_parents, unsigned long flags,
 132                                 struct clk_omap_reg *reg, u8 shift, u32 mask,
 133                                 s8 latch, u8 clk_mux_flags, u32 *table)
 134{
 135        struct clk_omap_mux *mux;
 136        struct clk *clk;
 137        struct clk_init_data init;
 138
 139        /* allocate the mux */
 140        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 141        if (!mux)
 142                return ERR_PTR(-ENOMEM);
 143
 144        init.name = name;
 145        init.ops = &ti_clk_mux_ops;
 146        init.flags = flags;
 147        init.parent_names = parent_names;
 148        init.num_parents = num_parents;
 149
 150        /* struct clk_mux assignments */
 151        memcpy(&mux->reg, reg, sizeof(*reg));
 152        mux->shift = shift;
 153        mux->mask = mask;
 154        mux->latch = latch;
 155        mux->flags = clk_mux_flags;
 156        mux->table = table;
 157        mux->hw.init = &init;
 158
 159        clk = ti_clk_register(dev, &mux->hw, name);
 160
 161        if (IS_ERR(clk))
 162                kfree(mux);
 163
 164        return clk;
 165}
 166
 167/**
 168 * of_mux_clk_setup - Setup function for simple mux rate clock
 169 * @node: DT node for the clock
 170 *
 171 * Sets up a basic clock multiplexer.
 172 */
 173static void of_mux_clk_setup(struct device_node *node)
 174{
 175        struct clk *clk;
 176        struct clk_omap_reg reg;
 177        unsigned int num_parents;
 178        const char **parent_names;
 179        u8 clk_mux_flags = 0;
 180        u32 mask = 0;
 181        u32 shift = 0;
 182        s32 latch = -EINVAL;
 183        u32 flags = CLK_SET_RATE_NO_REPARENT;
 184
 185        num_parents = of_clk_get_parent_count(node);
 186        if (num_parents < 2) {
 187                pr_err("mux-clock %pOFn must have parents\n", node);
 188                return;
 189        }
 190        parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
 191        if (!parent_names)
 192                goto cleanup;
 193
 194        of_clk_parent_fill(node, parent_names, num_parents);
 195
 196        if (ti_clk_get_reg_addr(node, 0, &reg))
 197                goto cleanup;
 198
 199        of_property_read_u32(node, "ti,bit-shift", &shift);
 200
 201        of_property_read_u32(node, "ti,latch-bit", &latch);
 202
 203        if (of_property_read_bool(node, "ti,index-starts-at-one"))
 204                clk_mux_flags |= CLK_MUX_INDEX_ONE;
 205
 206        if (of_property_read_bool(node, "ti,set-rate-parent"))
 207                flags |= CLK_SET_RATE_PARENT;
 208
 209        /* Generate bit-mask based on parent info */
 210        mask = num_parents;
 211        if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
 212                mask--;
 213
 214        mask = (1 << fls(mask)) - 1;
 215
 216        clk = _register_mux(NULL, node->name, parent_names, num_parents,
 217                            flags, &reg, shift, mask, latch, clk_mux_flags,
 218                            NULL);
 219
 220        if (!IS_ERR(clk))
 221                of_clk_add_provider(node, of_clk_src_simple_get, clk);
 222
 223cleanup:
 224        kfree(parent_names);
 225}
 226CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
 227
 228struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
 229{
 230        struct clk_omap_mux *mux;
 231        int num_parents;
 232
 233        if (!setup)
 234                return NULL;
 235
 236        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 237        if (!mux)
 238                return ERR_PTR(-ENOMEM);
 239
 240        mux->shift = setup->bit_shift;
 241        mux->latch = -EINVAL;
 242
 243        mux->reg.index = setup->module;
 244        mux->reg.offset = setup->reg;
 245
 246        if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
 247                mux->flags |= CLK_MUX_INDEX_ONE;
 248
 249        num_parents = setup->num_parents;
 250
 251        mux->mask = num_parents - 1;
 252        mux->mask = (1 << fls(mux->mask)) - 1;
 253
 254        return &mux->hw;
 255}
 256
 257static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
 258{
 259        struct clk_omap_mux *mux;
 260        unsigned int num_parents;
 261        u32 val;
 262
 263        mux = kzalloc(sizeof(*mux), GFP_KERNEL);
 264        if (!mux)
 265                return;
 266
 267        if (ti_clk_get_reg_addr(node, 0, &mux->reg))
 268                goto cleanup;
 269
 270        if (!of_property_read_u32(node, "ti,bit-shift", &val))
 271                mux->shift = val;
 272
 273        if (of_property_read_bool(node, "ti,index-starts-at-one"))
 274                mux->flags |= CLK_MUX_INDEX_ONE;
 275
 276        num_parents = of_clk_get_parent_count(node);
 277
 278        if (num_parents < 2) {
 279                pr_err("%pOFn must have parents\n", node);
 280                goto cleanup;
 281        }
 282
 283        mux->mask = num_parents - 1;
 284        mux->mask = (1 << fls(mux->mask)) - 1;
 285
 286        if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
 287                return;
 288
 289cleanup:
 290        kfree(mux);
 291}
 292CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
 293               of_ti_composite_mux_clk_setup);
 294