xref: /linux/drivers/clk/ti/mux.c (revision 4a5917cd504c7afd5e9de7166eb710687a9b026f)
15a729246SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
26a369c58STero Kristo /*
36a369c58STero Kristo  * TI Multiplexer Clock
46a369c58STero Kristo  *
56a369c58STero Kristo  * Copyright (C) 2013 Texas Instruments, Inc.
66a369c58STero Kristo  *
76a369c58STero Kristo  * Tero Kristo <t-kristo@ti.com>
86a369c58STero Kristo  */
96a369c58STero Kristo 
106a369c58STero Kristo #include <linux/clk-provider.h>
116a369c58STero Kristo #include <linux/slab.h>
126a369c58STero Kristo #include <linux/err.h>
136a369c58STero Kristo #include <linux/of.h>
146a369c58STero Kristo #include <linux/of_address.h>
156a369c58STero Kristo #include <linux/clk/ti.h>
167c18a65cSTero Kristo #include "clock.h"
176a369c58STero Kristo 
186a369c58STero Kristo #undef pr_fmt
196a369c58STero Kristo #define pr_fmt(fmt) "%s: " fmt, __func__
206a369c58STero Kristo 
216a369c58STero Kristo static u8 ti_clk_mux_get_parent(struct clk_hw *hw)
226a369c58STero Kristo {
23d83bc5b6STero Kristo 	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
24497295afSStephen Boyd 	int num_parents = clk_hw_get_num_parents(hw);
256a369c58STero Kristo 	u32 val;
266a369c58STero Kristo 
276a369c58STero Kristo 	/*
286a369c58STero Kristo 	 * FIXME need a mux-specific flag to determine if val is bitwise or
296a369c58STero Kristo 	 * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges
306a369c58STero Kristo 	 * from 0x1 to 0x7 (index starts at one)
316a369c58STero Kristo 	 * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
326a369c58STero Kristo 	 * val = 0x4 really means "bit 2, index starts at bit 0"
336a369c58STero Kristo 	 */
346c0afb50STero Kristo 	val = ti_clk_ll_ops->clk_readl(&mux->reg) >> mux->shift;
356a369c58STero Kristo 	val &= mux->mask;
366a369c58STero Kristo 
376a369c58STero Kristo 	if (mux->table) {
386a369c58STero Kristo 		int i;
396a369c58STero Kristo 
406a369c58STero Kristo 		for (i = 0; i < num_parents; i++)
416a369c58STero Kristo 			if (mux->table[i] == val)
426a369c58STero Kristo 				return i;
436a369c58STero Kristo 		return -EINVAL;
446a369c58STero Kristo 	}
456a369c58STero Kristo 
466a369c58STero Kristo 	if (val && (mux->flags & CLK_MUX_INDEX_BIT))
476a369c58STero Kristo 		val = ffs(val) - 1;
486a369c58STero Kristo 
496a369c58STero Kristo 	if (val && (mux->flags & CLK_MUX_INDEX_ONE))
506a369c58STero Kristo 		val--;
516a369c58STero Kristo 
526a369c58STero Kristo 	if (val >= num_parents)
536a369c58STero Kristo 		return -EINVAL;
546a369c58STero Kristo 
556a369c58STero Kristo 	return val;
566a369c58STero Kristo }
576a369c58STero Kristo 
586a369c58STero Kristo static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
596a369c58STero Kristo {
60d83bc5b6STero Kristo 	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
616a369c58STero Kristo 	u32 val;
626a369c58STero Kristo 
636a369c58STero Kristo 	if (mux->table) {
646a369c58STero Kristo 		index = mux->table[index];
656a369c58STero Kristo 	} else {
666a369c58STero Kristo 		if (mux->flags & CLK_MUX_INDEX_BIT)
676a369c58STero Kristo 			index = (1 << ffs(index));
686a369c58STero Kristo 
696a369c58STero Kristo 		if (mux->flags & CLK_MUX_INDEX_ONE)
706a369c58STero Kristo 			index++;
716a369c58STero Kristo 	}
726a369c58STero Kristo 
736a369c58STero Kristo 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
746a369c58STero Kristo 		val = mux->mask << (mux->shift + 16);
756a369c58STero Kristo 	} else {
766c0afb50STero Kristo 		val = ti_clk_ll_ops->clk_readl(&mux->reg);
776a369c58STero Kristo 		val &= ~(mux->mask << mux->shift);
786a369c58STero Kristo 	}
796a369c58STero Kristo 	val |= index << mux->shift;
806c0afb50STero Kristo 	ti_clk_ll_ops->clk_writel(val, &mux->reg);
81ee2fc3c5STero Kristo 	ti_clk_latch(&mux->reg, mux->latch);
826a369c58STero Kristo 
836a369c58STero Kristo 	return 0;
846a369c58STero Kristo }
856a369c58STero Kristo 
86d6e7bbc1SRuss Dill /**
87d6e7bbc1SRuss Dill  * clk_mux_save_context - Save the parent selcted in the mux
88d6e7bbc1SRuss Dill  * @hw: pointer  struct clk_hw
89d6e7bbc1SRuss Dill  *
90d6e7bbc1SRuss Dill  * Save the parent mux value.
91d6e7bbc1SRuss Dill  */
92d6e7bbc1SRuss Dill static int clk_mux_save_context(struct clk_hw *hw)
93d6e7bbc1SRuss Dill {
94d6e7bbc1SRuss Dill 	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
95d6e7bbc1SRuss Dill 
96d6e7bbc1SRuss Dill 	mux->saved_parent = ti_clk_mux_get_parent(hw);
97d6e7bbc1SRuss Dill 	return 0;
98d6e7bbc1SRuss Dill }
99d6e7bbc1SRuss Dill 
100d6e7bbc1SRuss Dill /**
101d6e7bbc1SRuss Dill  * clk_mux_restore_context - Restore the parent in the mux
102d6e7bbc1SRuss Dill  * @hw: pointer  struct clk_hw
103d6e7bbc1SRuss Dill  *
104d6e7bbc1SRuss Dill  * Restore the saved parent mux value.
105d6e7bbc1SRuss Dill  */
106d6e7bbc1SRuss Dill static void clk_mux_restore_context(struct clk_hw *hw)
107d6e7bbc1SRuss Dill {
108d6e7bbc1SRuss Dill 	struct clk_omap_mux *mux = to_clk_omap_mux(hw);
109d6e7bbc1SRuss Dill 
110d6e7bbc1SRuss Dill 	ti_clk_mux_set_parent(hw, mux->saved_parent);
111d6e7bbc1SRuss Dill }
112d6e7bbc1SRuss Dill 
1136a369c58STero Kristo const struct clk_ops ti_clk_mux_ops = {
1146a369c58STero Kristo 	.get_parent = ti_clk_mux_get_parent,
1156a369c58STero Kristo 	.set_parent = ti_clk_mux_set_parent,
1166a369c58STero Kristo 	.determine_rate = __clk_mux_determine_rate,
117d6e7bbc1SRuss Dill 	.save_context = clk_mux_save_context,
118d6e7bbc1SRuss Dill 	.restore_context = clk_mux_restore_context,
1196a369c58STero Kristo };
1206a369c58STero Kristo 
1213400d546SDario Binacchi static struct clk *_register_mux(struct device_node *node, const char *name,
122ce382d47STero Kristo 				 const char * const *parent_names,
123ce382d47STero Kristo 				 u8 num_parents, unsigned long flags,
1246c0afb50STero Kristo 				 struct clk_omap_reg *reg, u8 shift, u32 mask,
125ee2fc3c5STero Kristo 				 s8 latch, u8 clk_mux_flags, u32 *table)
1266a369c58STero Kristo {
127d83bc5b6STero Kristo 	struct clk_omap_mux *mux;
1286a369c58STero Kristo 	struct clk *clk;
1296a369c58STero Kristo 	struct clk_init_data init;
1306a369c58STero Kristo 
1316a369c58STero Kristo 	/* allocate the mux */
1326a369c58STero Kristo 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
133f80c8a29SMarkus Elfring 	if (!mux)
1346a369c58STero Kristo 		return ERR_PTR(-ENOMEM);
1356a369c58STero Kristo 
1366a369c58STero Kristo 	init.name = name;
1376a369c58STero Kristo 	init.ops = &ti_clk_mux_ops;
1388aa09cf3STero Kristo 	init.flags = flags;
1396a369c58STero Kristo 	init.parent_names = parent_names;
1406a369c58STero Kristo 	init.num_parents = num_parents;
1416a369c58STero Kristo 
1426a369c58STero Kristo 	/* struct clk_mux assignments */
1436c0afb50STero Kristo 	memcpy(&mux->reg, reg, sizeof(*reg));
1446a369c58STero Kristo 	mux->shift = shift;
1456a369c58STero Kristo 	mux->mask = mask;
146ee2fc3c5STero Kristo 	mux->latch = latch;
1476a369c58STero Kristo 	mux->flags = clk_mux_flags;
1486a369c58STero Kristo 	mux->table = table;
1496a369c58STero Kristo 	mux->hw.init = &init;
1506a369c58STero Kristo 
1513400d546SDario Binacchi 	clk = of_ti_clk_register(node, &mux->hw, name);
1526a369c58STero Kristo 
1536a369c58STero Kristo 	if (IS_ERR(clk))
1546a369c58STero Kristo 		kfree(mux);
1556a369c58STero Kristo 
1566a369c58STero Kristo 	return clk;
1576a369c58STero Kristo }
1586a369c58STero Kristo 
1596a369c58STero Kristo /**
1606a369c58STero Kristo  * of_mux_clk_setup - Setup function for simple mux rate clock
1616a369c58STero Kristo  * @node: DT node for the clock
1626a369c58STero Kristo  *
1636a369c58STero Kristo  * Sets up a basic clock multiplexer.
1646a369c58STero Kristo  */
1656a369c58STero Kristo static void of_mux_clk_setup(struct device_node *node)
1666a369c58STero Kristo {
1676a369c58STero Kristo 	struct clk *clk;
1686c0afb50STero Kristo 	struct clk_omap_reg reg;
169921bacfaSStephen Boyd 	unsigned int num_parents;
1706a369c58STero Kristo 	const char **parent_names;
171ed06099cSTony Lindgren 	const char *name;
1726a369c58STero Kristo 	u8 clk_mux_flags = 0;
1736a369c58STero Kristo 	u32 mask = 0;
1746a369c58STero Kristo 	u32 shift = 0;
175ee2fc3c5STero Kristo 	s32 latch = -EINVAL;
1767d5fc85dSTomi Valkeinen 	u32 flags = CLK_SET_RATE_NO_REPARENT;
1776a369c58STero Kristo 
1786a369c58STero Kristo 	num_parents = of_clk_get_parent_count(node);
1796a369c58STero Kristo 	if (num_parents < 2) {
180e665f029SRob Herring 		pr_err("mux-clock %pOFn must have parents\n", node);
1816a369c58STero Kristo 		return;
1826a369c58STero Kristo 	}
1836a369c58STero Kristo 	parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
1846a369c58STero Kristo 	if (!parent_names)
1856a369c58STero Kristo 		goto cleanup;
1866a369c58STero Kristo 
1879da9e761SDinh Nguyen 	of_clk_parent_fill(node, parent_names, num_parents);
1886a369c58STero Kristo 
1896c0afb50STero Kristo 	if (ti_clk_get_reg_addr(node, 0, &reg))
1906a369c58STero Kristo 		goto cleanup;
1916a369c58STero Kristo 
192*4a5917cdSTony Lindgren 	shift = reg.bit;
1936a369c58STero Kristo 
194ee2fc3c5STero Kristo 	of_property_read_u32(node, "ti,latch-bit", &latch);
195ee2fc3c5STero Kristo 
1966a369c58STero Kristo 	if (of_property_read_bool(node, "ti,index-starts-at-one"))
1976a369c58STero Kristo 		clk_mux_flags |= CLK_MUX_INDEX_ONE;
1986a369c58STero Kristo 
1996a369c58STero Kristo 	if (of_property_read_bool(node, "ti,set-rate-parent"))
2006a369c58STero Kristo 		flags |= CLK_SET_RATE_PARENT;
2016a369c58STero Kristo 
2026a369c58STero Kristo 	/* Generate bit-mask based on parent info */
2036a369c58STero Kristo 	mask = num_parents;
2046a369c58STero Kristo 	if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
2056a369c58STero Kristo 		mask--;
2066a369c58STero Kristo 
2076a369c58STero Kristo 	mask = (1 << fls(mask)) - 1;
2086a369c58STero Kristo 
209ed06099cSTony Lindgren 	name = ti_dt_clk_name(node);
2103400d546SDario Binacchi 	clk = _register_mux(node, name, parent_names, num_parents,
211ee2fc3c5STero Kristo 			    flags, &reg, shift, mask, latch, clk_mux_flags,
212ee2fc3c5STero Kristo 			    NULL);
2136a369c58STero Kristo 
2146a369c58STero Kristo 	if (!IS_ERR(clk))
2156a369c58STero Kristo 		of_clk_add_provider(node, of_clk_src_simple_get, clk);
2166a369c58STero Kristo 
2176a369c58STero Kristo cleanup:
2186a369c58STero Kristo 	kfree(parent_names);
2196a369c58STero Kristo }
2206a369c58STero Kristo CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
2216a369c58STero Kristo 
2227c18a65cSTero Kristo struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
2237c18a65cSTero Kristo {
224d83bc5b6STero Kristo 	struct clk_omap_mux *mux;
2257c18a65cSTero Kristo 	int num_parents;
2267c18a65cSTero Kristo 
2277c18a65cSTero Kristo 	if (!setup)
2287c18a65cSTero Kristo 		return NULL;
2297c18a65cSTero Kristo 
2307c18a65cSTero Kristo 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
2317c18a65cSTero Kristo 	if (!mux)
2327c18a65cSTero Kristo 		return ERR_PTR(-ENOMEM);
2337c18a65cSTero Kristo 
2347c18a65cSTero Kristo 	mux->shift = setup->bit_shift;
235ee2fc3c5STero Kristo 	mux->latch = -EINVAL;
2367c18a65cSTero Kristo 
2376c0afb50STero Kristo 	mux->reg.index = setup->module;
2386c0afb50STero Kristo 	mux->reg.offset = setup->reg;
2397c18a65cSTero Kristo 
2407c18a65cSTero Kristo 	if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
2417c18a65cSTero Kristo 		mux->flags |= CLK_MUX_INDEX_ONE;
2427c18a65cSTero Kristo 
2437c18a65cSTero Kristo 	num_parents = setup->num_parents;
2447c18a65cSTero Kristo 
2457c18a65cSTero Kristo 	mux->mask = num_parents - 1;
2467c18a65cSTero Kristo 	mux->mask = (1 << fls(mux->mask)) - 1;
2477c18a65cSTero Kristo 
2487c18a65cSTero Kristo 	return &mux->hw;
2497c18a65cSTero Kristo }
2507c18a65cSTero Kristo 
2516a369c58STero Kristo static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
2526a369c58STero Kristo {
253d83bc5b6STero Kristo 	struct clk_omap_mux *mux;
254921bacfaSStephen Boyd 	unsigned int num_parents;
2556a369c58STero Kristo 
2566a369c58STero Kristo 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
2576a369c58STero Kristo 	if (!mux)
2586a369c58STero Kristo 		return;
2596a369c58STero Kristo 
2606c0afb50STero Kristo 	if (ti_clk_get_reg_addr(node, 0, &mux->reg))
2616a369c58STero Kristo 		goto cleanup;
2626a369c58STero Kristo 
263*4a5917cdSTony Lindgren 	mux->shift = mux->reg.bit;
2646a369c58STero Kristo 
2656a369c58STero Kristo 	if (of_property_read_bool(node, "ti,index-starts-at-one"))
2666a369c58STero Kristo 		mux->flags |= CLK_MUX_INDEX_ONE;
2676a369c58STero Kristo 
2686a369c58STero Kristo 	num_parents = of_clk_get_parent_count(node);
2696a369c58STero Kristo 
2706a369c58STero Kristo 	if (num_parents < 2) {
271e665f029SRob Herring 		pr_err("%pOFn must have parents\n", node);
2726a369c58STero Kristo 		goto cleanup;
2736a369c58STero Kristo 	}
2746a369c58STero Kristo 
2756a369c58STero Kristo 	mux->mask = num_parents - 1;
2766a369c58STero Kristo 	mux->mask = (1 << fls(mux->mask)) - 1;
2776a369c58STero Kristo 
2786a369c58STero Kristo 	if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
2796a369c58STero Kristo 		return;
2806a369c58STero Kristo 
2816a369c58STero Kristo cleanup:
2826a369c58STero Kristo 	kfree(mux);
2836a369c58STero Kristo }
2846a369c58STero Kristo CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
2856a369c58STero Kristo 	       of_ti_composite_mux_clk_setup);
286