Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.5.6.
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * clkgen-mux.c: ST GEN-MUX Clock driver
  4 *
  5 * Copyright (C) 2014 STMicroelectronics (R&D) Limited
  6 *
  7 * Authors: Stephen Gallimore <stephen.gallimore@st.com>
  8 *	    Pankaj Dev <pankaj.dev@st.com>
  9 */
 10
 11#include <linux/slab.h>
 12#include <linux/io.h>
 13#include <linux/of_address.h>
 14#include <linux/clk.h>
 15#include <linux/clk-provider.h>
 16#include "clkgen.h"
 17
 18static const char ** __init clkgen_mux_get_parents(struct device_node *np,
 19						       int *num_parents)
 20{
 21	const char **parents;
 22	unsigned int nparents;
 23
 24	nparents = of_clk_get_parent_count(np);
 25	if (WARN_ON(!nparents))
 26		return ERR_PTR(-EINVAL);
 27
 28	parents = kcalloc(nparents, sizeof(const char *), GFP_KERNEL);
 29	if (!parents)
 30		return ERR_PTR(-ENOMEM);
 31
 32	*num_parents = of_clk_parent_fill(np, parents, nparents);
 33	return parents;
 34}
 35
 36struct clkgen_mux_data {
 37	u32 offset;
 38	u8 shift;
 39	u8 width;
 40	spinlock_t *lock;
 41	unsigned long clk_flags;
 42	u8 mux_flags;
 43};
 44
 45static struct clkgen_mux_data stih407_a9_mux_data = {
 46	.offset = 0x1a4,
 47	.shift = 0,
 48	.width = 2,
 49	.lock = &clkgen_a9_lock,
 50};
 51
 52static void __init st_of_clkgen_mux_setup(struct device_node *np,
 53		struct clkgen_mux_data *data)
 54{
 55	struct clk *clk;
 56	void __iomem *reg;
 57	const char **parents;
 58	int num_parents = 0;
 59	struct device_node *parent_np;
 60
 61	/*
 62	 * First check for reg property within the node to keep backward
 63	 * compatibility, then if reg doesn't exist look at the parent node
 64	 */
 65	reg = of_iomap(np, 0);
 66	if (!reg) {
 67		parent_np = of_get_parent(np);
 68		reg = of_iomap(parent_np, 0);
 69		of_node_put(parent_np);
 70		if (!reg) {
 71			pr_err("%s: Failed to get base address\n", __func__);
 72			return;
 73		}
 74	}
 75
 76	parents = clkgen_mux_get_parents(np, &num_parents);
 77	if (IS_ERR(parents)) {
 78		pr_err("%s: Failed to get parents (%ld)\n",
 79				__func__, PTR_ERR(parents));
 80		goto err_parents;
 81	}
 82
 83	clk = clk_register_mux(NULL, np->name, parents, num_parents,
 84				data->clk_flags | CLK_SET_RATE_PARENT,
 85				reg + data->offset,
 86				data->shift, data->width, data->mux_flags,
 87				data->lock);
 88	if (IS_ERR(clk))
 89		goto err;
 90
 91	pr_debug("%s: parent %s rate %u\n",
 92			__clk_get_name(clk),
 93			__clk_get_name(clk_get_parent(clk)),
 94			(unsigned int)clk_get_rate(clk));
 95
 96	kfree(parents);
 97	of_clk_add_provider(np, of_clk_src_simple_get, clk);
 98	return;
 99
100err:
101	kfree(parents);
102err_parents:
103	iounmap(reg);
104}
105
106static void __init st_of_clkgen_a9_mux_setup(struct device_node *np)
107{
108	st_of_clkgen_mux_setup(np, &stih407_a9_mux_data);
109}
110CLK_OF_DECLARE(clkgen_a9mux, "st,stih407-clkgen-a9-mux",
111		st_of_clkgen_a9_mux_setup);