Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * TI Multiplexer Clock
0004  *
0005  * Copyright (C) 2013 Texas Instruments, Inc.
0006  *
0007  * Tero Kristo <t-kristo@ti.com>
0008  */
0009 
0010 #include <linux/clk-provider.h>
0011 #include <linux/slab.h>
0012 #include <linux/err.h>
0013 #include <linux/of.h>
0014 #include <linux/of_address.h>
0015 #include <linux/clk/ti.h>
0016 #include "clock.h"
0017 
0018 #undef pr_fmt
0019 #define pr_fmt(fmt) "%s: " fmt, __func__
0020 
0021 static u8 ti_clk_mux_get_parent(struct clk_hw *hw)
0022 {
0023     struct clk_omap_mux *mux = to_clk_omap_mux(hw);
0024     int num_parents = clk_hw_get_num_parents(hw);
0025     u32 val;
0026 
0027     /*
0028      * FIXME need a mux-specific flag to determine if val is bitwise or
0029      * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges
0030      * from 0x1 to 0x7 (index starts at one)
0031      * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
0032      * val = 0x4 really means "bit 2, index starts at bit 0"
0033      */
0034     val = ti_clk_ll_ops->clk_readl(&mux->reg) >> mux->shift;
0035     val &= mux->mask;
0036 
0037     if (mux->table) {
0038         int i;
0039 
0040         for (i = 0; i < num_parents; i++)
0041             if (mux->table[i] == val)
0042                 return i;
0043         return -EINVAL;
0044     }
0045 
0046     if (val && (mux->flags & CLK_MUX_INDEX_BIT))
0047         val = ffs(val) - 1;
0048 
0049     if (val && (mux->flags & CLK_MUX_INDEX_ONE))
0050         val--;
0051 
0052     if (val >= num_parents)
0053         return -EINVAL;
0054 
0055     return val;
0056 }
0057 
0058 static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
0059 {
0060     struct clk_omap_mux *mux = to_clk_omap_mux(hw);
0061     u32 val;
0062 
0063     if (mux->table) {
0064         index = mux->table[index];
0065     } else {
0066         if (mux->flags & CLK_MUX_INDEX_BIT)
0067             index = (1 << ffs(index));
0068 
0069         if (mux->flags & CLK_MUX_INDEX_ONE)
0070             index++;
0071     }
0072 
0073     if (mux->flags & CLK_MUX_HIWORD_MASK) {
0074         val = mux->mask << (mux->shift + 16);
0075     } else {
0076         val = ti_clk_ll_ops->clk_readl(&mux->reg);
0077         val &= ~(mux->mask << mux->shift);
0078     }
0079     val |= index << mux->shift;
0080     ti_clk_ll_ops->clk_writel(val, &mux->reg);
0081     ti_clk_latch(&mux->reg, mux->latch);
0082 
0083     return 0;
0084 }
0085 
0086 /**
0087  * clk_mux_save_context - Save the parent selcted in the mux
0088  * @hw: pointer  struct clk_hw
0089  *
0090  * Save the parent mux value.
0091  */
0092 static int clk_mux_save_context(struct clk_hw *hw)
0093 {
0094     struct clk_omap_mux *mux = to_clk_omap_mux(hw);
0095 
0096     mux->saved_parent = ti_clk_mux_get_parent(hw);
0097     return 0;
0098 }
0099 
0100 /**
0101  * clk_mux_restore_context - Restore the parent in the mux
0102  * @hw: pointer  struct clk_hw
0103  *
0104  * Restore the saved parent mux value.
0105  */
0106 static void clk_mux_restore_context(struct clk_hw *hw)
0107 {
0108     struct clk_omap_mux *mux = to_clk_omap_mux(hw);
0109 
0110     ti_clk_mux_set_parent(hw, mux->saved_parent);
0111 }
0112 
0113 const struct clk_ops ti_clk_mux_ops = {
0114     .get_parent = ti_clk_mux_get_parent,
0115     .set_parent = ti_clk_mux_set_parent,
0116     .determine_rate = __clk_mux_determine_rate,
0117     .save_context = clk_mux_save_context,
0118     .restore_context = clk_mux_restore_context,
0119 };
0120 
0121 static struct clk *_register_mux(struct device *dev, const char *name,
0122                  const char * const *parent_names,
0123                  u8 num_parents, unsigned long flags,
0124                  struct clk_omap_reg *reg, u8 shift, u32 mask,
0125                  s8 latch, u8 clk_mux_flags, u32 *table)
0126 {
0127     struct clk_omap_mux *mux;
0128     struct clk *clk;
0129     struct clk_init_data init;
0130 
0131     /* allocate the mux */
0132     mux = kzalloc(sizeof(*mux), GFP_KERNEL);
0133     if (!mux)
0134         return ERR_PTR(-ENOMEM);
0135 
0136     init.name = name;
0137     init.ops = &ti_clk_mux_ops;
0138     init.flags = flags;
0139     init.parent_names = parent_names;
0140     init.num_parents = num_parents;
0141 
0142     /* struct clk_mux assignments */
0143     memcpy(&mux->reg, reg, sizeof(*reg));
0144     mux->shift = shift;
0145     mux->mask = mask;
0146     mux->latch = latch;
0147     mux->flags = clk_mux_flags;
0148     mux->table = table;
0149     mux->hw.init = &init;
0150 
0151     clk = ti_clk_register(dev, &mux->hw, name);
0152 
0153     if (IS_ERR(clk))
0154         kfree(mux);
0155 
0156     return clk;
0157 }
0158 
0159 /**
0160  * of_mux_clk_setup - Setup function for simple mux rate clock
0161  * @node: DT node for the clock
0162  *
0163  * Sets up a basic clock multiplexer.
0164  */
0165 static void of_mux_clk_setup(struct device_node *node)
0166 {
0167     struct clk *clk;
0168     struct clk_omap_reg reg;
0169     unsigned int num_parents;
0170     const char **parent_names;
0171     const char *name;
0172     u8 clk_mux_flags = 0;
0173     u32 mask = 0;
0174     u32 shift = 0;
0175     s32 latch = -EINVAL;
0176     u32 flags = CLK_SET_RATE_NO_REPARENT;
0177 
0178     num_parents = of_clk_get_parent_count(node);
0179     if (num_parents < 2) {
0180         pr_err("mux-clock %pOFn must have parents\n", node);
0181         return;
0182     }
0183     parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
0184     if (!parent_names)
0185         goto cleanup;
0186 
0187     of_clk_parent_fill(node, parent_names, num_parents);
0188 
0189     if (ti_clk_get_reg_addr(node, 0, &reg))
0190         goto cleanup;
0191 
0192     of_property_read_u32(node, "ti,bit-shift", &shift);
0193 
0194     of_property_read_u32(node, "ti,latch-bit", &latch);
0195 
0196     if (of_property_read_bool(node, "ti,index-starts-at-one"))
0197         clk_mux_flags |= CLK_MUX_INDEX_ONE;
0198 
0199     if (of_property_read_bool(node, "ti,set-rate-parent"))
0200         flags |= CLK_SET_RATE_PARENT;
0201 
0202     /* Generate bit-mask based on parent info */
0203     mask = num_parents;
0204     if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
0205         mask--;
0206 
0207     mask = (1 << fls(mask)) - 1;
0208 
0209     name = ti_dt_clk_name(node);
0210     clk = _register_mux(NULL, name, parent_names, num_parents,
0211                 flags, &reg, shift, mask, latch, clk_mux_flags,
0212                 NULL);
0213 
0214     if (!IS_ERR(clk))
0215         of_clk_add_provider(node, of_clk_src_simple_get, clk);
0216 
0217 cleanup:
0218     kfree(parent_names);
0219 }
0220 CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
0221 
0222 struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
0223 {
0224     struct clk_omap_mux *mux;
0225     int num_parents;
0226 
0227     if (!setup)
0228         return NULL;
0229 
0230     mux = kzalloc(sizeof(*mux), GFP_KERNEL);
0231     if (!mux)
0232         return ERR_PTR(-ENOMEM);
0233 
0234     mux->shift = setup->bit_shift;
0235     mux->latch = -EINVAL;
0236 
0237     mux->reg.index = setup->module;
0238     mux->reg.offset = setup->reg;
0239 
0240     if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
0241         mux->flags |= CLK_MUX_INDEX_ONE;
0242 
0243     num_parents = setup->num_parents;
0244 
0245     mux->mask = num_parents - 1;
0246     mux->mask = (1 << fls(mux->mask)) - 1;
0247 
0248     return &mux->hw;
0249 }
0250 
0251 static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
0252 {
0253     struct clk_omap_mux *mux;
0254     unsigned int num_parents;
0255     u32 val;
0256 
0257     mux = kzalloc(sizeof(*mux), GFP_KERNEL);
0258     if (!mux)
0259         return;
0260 
0261     if (ti_clk_get_reg_addr(node, 0, &mux->reg))
0262         goto cleanup;
0263 
0264     if (!of_property_read_u32(node, "ti,bit-shift", &val))
0265         mux->shift = val;
0266 
0267     if (of_property_read_bool(node, "ti,index-starts-at-one"))
0268         mux->flags |= CLK_MUX_INDEX_ONE;
0269 
0270     num_parents = of_clk_get_parent_count(node);
0271 
0272     if (num_parents < 2) {
0273         pr_err("%pOFn must have parents\n", node);
0274         goto cleanup;
0275     }
0276 
0277     mux->mask = num_parents - 1;
0278     mux->mask = (1 << fls(mux->mask)) - 1;
0279 
0280     if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
0281         return;
0282 
0283 cleanup:
0284     kfree(mux);
0285 }
0286 CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
0287            of_ti_composite_mux_clk_setup);