Linux Audio

Check our new training course

Buildroot integration, development and maintenance

Need a Buildroot system for your embedded project?
Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 */
  4
  5#define pr_fmt(fmt) "imx:clk-gpr-mux: " fmt
  6
  7#include <linux/module.h>
  8
  9#include <linux/clk-provider.h>
 10#include <linux/errno.h>
 11#include <linux/export.h>
 12#include <linux/io.h>
 13#include <linux/slab.h>
 14#include <linux/regmap.h>
 15#include <linux/mfd/syscon.h>
 16
 17#include "clk.h"
 18
 19struct imx_clk_gpr {
 20	struct clk_hw hw;
 21	struct regmap *regmap;
 22	u32 mask;
 23	u32 reg;
 24	const u32 *mux_table;
 25};
 26
 27static struct imx_clk_gpr *to_imx_clk_gpr(struct clk_hw *hw)
 28{
 29	return container_of(hw, struct imx_clk_gpr, hw);
 30}
 31
 32static u8 imx_clk_gpr_mux_get_parent(struct clk_hw *hw)
 33{
 34	struct imx_clk_gpr *priv = to_imx_clk_gpr(hw);
 35	unsigned int val;
 36	int ret;
 37
 38	ret = regmap_read(priv->regmap, priv->reg, &val);
 39	if (ret)
 40		goto get_parent_err;
 41
 42	val &= priv->mask;
 43
 44	ret = clk_mux_val_to_index(hw, priv->mux_table, 0, val);
 45	if (ret < 0)
 46		goto get_parent_err;
 47
 48	return ret;
 49
 50get_parent_err:
 51	pr_err("%s: failed to get parent (%pe)\n",
 52	       clk_hw_get_name(hw), ERR_PTR(ret));
 53
 54	/* return some realistic non negative value. Potentially we could
 55	 * give index to some dummy error parent.
 56	 */
 57	return 0;
 58}
 59
 60static int imx_clk_gpr_mux_set_parent(struct clk_hw *hw, u8 index)
 61{
 62	struct imx_clk_gpr *priv = to_imx_clk_gpr(hw);
 63	unsigned int val = clk_mux_index_to_val(priv->mux_table, 0, index);
 64
 65	return regmap_update_bits(priv->regmap, priv->reg, priv->mask, val);
 66}
 67
 68static const struct clk_ops imx_clk_gpr_mux_ops = {
 69	.get_parent = imx_clk_gpr_mux_get_parent,
 70	.set_parent = imx_clk_gpr_mux_set_parent,
 71	.determine_rate = __clk_mux_determine_rate,
 72};
 73
 74struct clk_hw *imx_clk_gpr_mux(const char *name, const char *compatible,
 75			       u32 reg, const char **parent_names,
 76			       u8 num_parents, const u32 *mux_table, u32 mask)
 77{
 78	struct clk_init_data init  = { };
 79	struct imx_clk_gpr *priv;
 80	struct regmap *regmap;
 81	struct clk_hw *hw;
 82	int ret;
 83
 84	regmap = syscon_regmap_lookup_by_compatible(compatible);
 85	if (IS_ERR(regmap)) {
 86		pr_err("failed to find %s regmap\n", compatible);
 87		return ERR_CAST(regmap);
 88	}
 89
 90	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
 91	if (!priv)
 92		return ERR_PTR(-ENOMEM);
 93
 94	init.name = name;
 95	init.ops = &imx_clk_gpr_mux_ops;
 96	init.parent_names = parent_names;
 97	init.num_parents = num_parents;
 98	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
 99
100	priv->hw.init = &init;
101	priv->regmap = regmap;
102	priv->mux_table = mux_table;
103	priv->reg = reg;
104	priv->mask = mask;
105
106	hw = &priv->hw;
107	ret = clk_hw_register(NULL, &priv->hw);
108	if (ret) {
109		kfree(priv);
110		hw = ERR_PTR(ret);
111	}
112
113	return hw;
114}