162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * TI clock support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2013 Texas Instruments, Inc.
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Tero Kristo <t-kristo@ti.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/clk-provider.h>
1262306a36Sopenharmony_ci#include <linux/clkdev.h>
1362306a36Sopenharmony_ci#include <linux/clk/ti.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/of_address.h>
1762306a36Sopenharmony_ci#include <linux/list.h>
1862306a36Sopenharmony_ci#include <linux/regmap.h>
1962306a36Sopenharmony_ci#include <linux/string_helpers.h>
2062306a36Sopenharmony_ci#include <linux/memblock.h>
2162306a36Sopenharmony_ci#include <linux/device.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#include "clock.h"
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#undef pr_fmt
2662306a36Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic LIST_HEAD(clk_hw_omap_clocks);
2962306a36Sopenharmony_cistruct ti_clk_ll_ops *ti_clk_ll_ops;
3062306a36Sopenharmony_cistatic struct device_node *clocks_node_ptr[CLK_MAX_MEMMAPS];
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cistruct ti_clk_features ti_clk_features;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistruct clk_iomap {
3562306a36Sopenharmony_ci	struct regmap *regmap;
3662306a36Sopenharmony_ci	void __iomem *mem;
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic struct clk_iomap *clk_memmaps[CLK_MAX_MEMMAPS];
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic void clk_memmap_writel(u32 val, const struct clk_omap_reg *reg)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	struct clk_iomap *io = clk_memmaps[reg->index];
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (reg->ptr)
4662306a36Sopenharmony_ci		writel_relaxed(val, reg->ptr);
4762306a36Sopenharmony_ci	else if (io->regmap)
4862306a36Sopenharmony_ci		regmap_write(io->regmap, reg->offset, val);
4962306a36Sopenharmony_ci	else
5062306a36Sopenharmony_ci		writel_relaxed(val, io->mem + reg->offset);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void _clk_rmw(u32 val, u32 mask, void __iomem *ptr)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	u32 v;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	v = readl_relaxed(ptr);
5862306a36Sopenharmony_ci	v &= ~mask;
5962306a36Sopenharmony_ci	v |= val;
6062306a36Sopenharmony_ci	writel_relaxed(v, ptr);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic void clk_memmap_rmw(u32 val, u32 mask, const struct clk_omap_reg *reg)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	struct clk_iomap *io = clk_memmaps[reg->index];
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	if (reg->ptr) {
6862306a36Sopenharmony_ci		_clk_rmw(val, mask, reg->ptr);
6962306a36Sopenharmony_ci	} else if (io->regmap) {
7062306a36Sopenharmony_ci		regmap_update_bits(io->regmap, reg->offset, mask, val);
7162306a36Sopenharmony_ci	} else {
7262306a36Sopenharmony_ci		_clk_rmw(val, mask, io->mem + reg->offset);
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic u32 clk_memmap_readl(const struct clk_omap_reg *reg)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	u32 val;
7962306a36Sopenharmony_ci	struct clk_iomap *io = clk_memmaps[reg->index];
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	if (reg->ptr)
8262306a36Sopenharmony_ci		val = readl_relaxed(reg->ptr);
8362306a36Sopenharmony_ci	else if (io->regmap)
8462306a36Sopenharmony_ci		regmap_read(io->regmap, reg->offset, &val);
8562306a36Sopenharmony_ci	else
8662306a36Sopenharmony_ci		val = readl_relaxed(io->mem + reg->offset);
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return val;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci/**
9262306a36Sopenharmony_ci * ti_clk_setup_ll_ops - setup low level clock operations
9362306a36Sopenharmony_ci * @ops: low level clock ops descriptor
9462306a36Sopenharmony_ci *
9562306a36Sopenharmony_ci * Sets up low level clock operations for TI clock driver. This is used
9662306a36Sopenharmony_ci * to provide various callbacks for the clock driver towards platform
9762306a36Sopenharmony_ci * specific code. Returns 0 on success, -EBUSY if ll_ops have been
9862306a36Sopenharmony_ci * registered already.
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_ciint ti_clk_setup_ll_ops(struct ti_clk_ll_ops *ops)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	if (ti_clk_ll_ops) {
10362306a36Sopenharmony_ci		pr_err("Attempt to register ll_ops multiple times.\n");
10462306a36Sopenharmony_ci		return -EBUSY;
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	ti_clk_ll_ops = ops;
10862306a36Sopenharmony_ci	ops->clk_readl = clk_memmap_readl;
10962306a36Sopenharmony_ci	ops->clk_writel = clk_memmap_writel;
11062306a36Sopenharmony_ci	ops->clk_rmw = clk_memmap_rmw;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return 0;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*
11662306a36Sopenharmony_ci * Eventually we could standardize to using '_' for clk-*.c files to follow the
11762306a36Sopenharmony_ci * TRM naming and leave out the tmp name here.
11862306a36Sopenharmony_ci */
11962306a36Sopenharmony_cistatic struct device_node *ti_find_clock_provider(struct device_node *from,
12062306a36Sopenharmony_ci						  const char *name)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct device_node *np;
12362306a36Sopenharmony_ci	bool found = false;
12462306a36Sopenharmony_ci	const char *n;
12562306a36Sopenharmony_ci	char *tmp;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci	tmp = kstrdup_and_replace(name, '-', '_', GFP_KERNEL);
12862306a36Sopenharmony_ci	if (!tmp)
12962306a36Sopenharmony_ci		return NULL;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* Node named "clock" with "clock-output-names" */
13262306a36Sopenharmony_ci	for_each_of_allnodes_from(from, np) {
13362306a36Sopenharmony_ci		if (of_property_read_string_index(np, "clock-output-names",
13462306a36Sopenharmony_ci						  0, &n))
13562306a36Sopenharmony_ci			continue;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		if (!strncmp(n, tmp, strlen(tmp))) {
13862306a36Sopenharmony_ci			of_node_get(np);
13962306a36Sopenharmony_ci			found = true;
14062306a36Sopenharmony_ci			break;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci	kfree(tmp);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	if (found) {
14662306a36Sopenharmony_ci		of_node_put(from);
14762306a36Sopenharmony_ci		return np;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	/* Fall back to using old node name base provider name */
15162306a36Sopenharmony_ci	return of_find_node_by_name(from, name);
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/**
15562306a36Sopenharmony_ci * ti_dt_clocks_register - register DT alias clocks during boot
15662306a36Sopenharmony_ci * @oclks: list of clocks to register
15762306a36Sopenharmony_ci *
15862306a36Sopenharmony_ci * Register alias or non-standard DT clock entries during boot. By
15962306a36Sopenharmony_ci * default, DT clocks are found based on their clock-output-names
16062306a36Sopenharmony_ci * property, or the clock node name for legacy cases. If any
16162306a36Sopenharmony_ci * additional con-id / dev-id -> clock mapping is required, use this
16262306a36Sopenharmony_ci * function to list these.
16362306a36Sopenharmony_ci */
16462306a36Sopenharmony_civoid __init ti_dt_clocks_register(struct ti_dt_clk oclks[])
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct ti_dt_clk *c;
16762306a36Sopenharmony_ci	struct device_node *node, *parent, *child;
16862306a36Sopenharmony_ci	struct clk *clk;
16962306a36Sopenharmony_ci	struct of_phandle_args clkspec;
17062306a36Sopenharmony_ci	char buf[64];
17162306a36Sopenharmony_ci	char *ptr;
17262306a36Sopenharmony_ci	char *tags[2];
17362306a36Sopenharmony_ci	int i;
17462306a36Sopenharmony_ci	int num_args;
17562306a36Sopenharmony_ci	int ret;
17662306a36Sopenharmony_ci	static bool clkctrl_nodes_missing;
17762306a36Sopenharmony_ci	static bool has_clkctrl_data;
17862306a36Sopenharmony_ci	static bool compat_mode;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	compat_mode = ti_clk_get_features()->flags & TI_CLK_CLKCTRL_COMPAT;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	for (c = oclks; c->node_name != NULL; c++) {
18362306a36Sopenharmony_ci		strcpy(buf, c->node_name);
18462306a36Sopenharmony_ci		ptr = buf;
18562306a36Sopenharmony_ci		for (i = 0; i < 2; i++)
18662306a36Sopenharmony_ci			tags[i] = NULL;
18762306a36Sopenharmony_ci		num_args = 0;
18862306a36Sopenharmony_ci		while (*ptr) {
18962306a36Sopenharmony_ci			if (*ptr == ':') {
19062306a36Sopenharmony_ci				if (num_args >= 2) {
19162306a36Sopenharmony_ci					pr_warn("Bad number of tags on %s\n",
19262306a36Sopenharmony_ci						c->node_name);
19362306a36Sopenharmony_ci					return;
19462306a36Sopenharmony_ci				}
19562306a36Sopenharmony_ci				tags[num_args++] = ptr + 1;
19662306a36Sopenharmony_ci				*ptr = 0;
19762306a36Sopenharmony_ci			}
19862306a36Sopenharmony_ci			ptr++;
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci		if (num_args && clkctrl_nodes_missing)
20262306a36Sopenharmony_ci			continue;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		node = ti_find_clock_provider(NULL, buf);
20562306a36Sopenharmony_ci		if (num_args && compat_mode) {
20662306a36Sopenharmony_ci			parent = node;
20762306a36Sopenharmony_ci			child = of_get_child_by_name(parent, "clock");
20862306a36Sopenharmony_ci			if (!child)
20962306a36Sopenharmony_ci				child = of_get_child_by_name(parent, "clk");
21062306a36Sopenharmony_ci			if (child) {
21162306a36Sopenharmony_ci				of_node_put(parent);
21262306a36Sopenharmony_ci				node = child;
21362306a36Sopenharmony_ci			}
21462306a36Sopenharmony_ci		}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci		clkspec.np = node;
21762306a36Sopenharmony_ci		clkspec.args_count = num_args;
21862306a36Sopenharmony_ci		for (i = 0; i < num_args; i++) {
21962306a36Sopenharmony_ci			ret = kstrtoint(tags[i], i ? 10 : 16, clkspec.args + i);
22062306a36Sopenharmony_ci			if (ret) {
22162306a36Sopenharmony_ci				pr_warn("Bad tag in %s at %d: %s\n",
22262306a36Sopenharmony_ci					c->node_name, i, tags[i]);
22362306a36Sopenharmony_ci				of_node_put(node);
22462306a36Sopenharmony_ci				return;
22562306a36Sopenharmony_ci			}
22662306a36Sopenharmony_ci		}
22762306a36Sopenharmony_ci		clk = of_clk_get_from_provider(&clkspec);
22862306a36Sopenharmony_ci		of_node_put(node);
22962306a36Sopenharmony_ci		if (!IS_ERR(clk)) {
23062306a36Sopenharmony_ci			c->lk.clk = clk;
23162306a36Sopenharmony_ci			clkdev_add(&c->lk);
23262306a36Sopenharmony_ci		} else {
23362306a36Sopenharmony_ci			if (num_args && !has_clkctrl_data) {
23462306a36Sopenharmony_ci				struct device_node *np;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci				np = of_find_compatible_node(NULL, NULL,
23762306a36Sopenharmony_ci							     "ti,clkctrl");
23862306a36Sopenharmony_ci				if (np) {
23962306a36Sopenharmony_ci					has_clkctrl_data = true;
24062306a36Sopenharmony_ci					of_node_put(np);
24162306a36Sopenharmony_ci				} else {
24262306a36Sopenharmony_ci					clkctrl_nodes_missing = true;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci					pr_warn("missing clkctrl nodes, please update your dts.\n");
24562306a36Sopenharmony_ci					continue;
24662306a36Sopenharmony_ci				}
24762306a36Sopenharmony_ci			}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci			pr_warn("failed to lookup clock node %s, ret=%ld\n",
25062306a36Sopenharmony_ci				c->node_name, PTR_ERR(clk));
25162306a36Sopenharmony_ci		}
25262306a36Sopenharmony_ci	}
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistruct clk_init_item {
25662306a36Sopenharmony_ci	struct device_node *node;
25762306a36Sopenharmony_ci	void *user;
25862306a36Sopenharmony_ci	ti_of_clk_init_cb_t func;
25962306a36Sopenharmony_ci	struct list_head link;
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic LIST_HEAD(retry_list);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/**
26562306a36Sopenharmony_ci * ti_clk_retry_init - retries a failed clock init at later phase
26662306a36Sopenharmony_ci * @node: device node for the clock
26762306a36Sopenharmony_ci * @user: user data pointer
26862306a36Sopenharmony_ci * @func: init function to be called for the clock
26962306a36Sopenharmony_ci *
27062306a36Sopenharmony_ci * Adds a failed clock init to the retry list. The retry list is parsed
27162306a36Sopenharmony_ci * once all the other clocks have been initialized.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_ciint __init ti_clk_retry_init(struct device_node *node, void *user,
27462306a36Sopenharmony_ci			     ti_of_clk_init_cb_t func)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct clk_init_item *retry;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	pr_debug("%pOFn: adding to retry list...\n", node);
27962306a36Sopenharmony_ci	retry = kzalloc(sizeof(*retry), GFP_KERNEL);
28062306a36Sopenharmony_ci	if (!retry)
28162306a36Sopenharmony_ci		return -ENOMEM;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	retry->node = node;
28462306a36Sopenharmony_ci	retry->func = func;
28562306a36Sopenharmony_ci	retry->user = user;
28662306a36Sopenharmony_ci	list_add(&retry->link, &retry_list);
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	return 0;
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci/**
29262306a36Sopenharmony_ci * ti_clk_get_reg_addr - get register address for a clock register
29362306a36Sopenharmony_ci * @node: device node for the clock
29462306a36Sopenharmony_ci * @index: register index from the clock node
29562306a36Sopenharmony_ci * @reg: pointer to target register struct
29662306a36Sopenharmony_ci *
29762306a36Sopenharmony_ci * Builds clock register address from device tree information, and returns
29862306a36Sopenharmony_ci * the data via the provided output pointer @reg. Returns 0 on success,
29962306a36Sopenharmony_ci * negative error value on failure.
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_ciint ti_clk_get_reg_addr(struct device_node *node, int index,
30262306a36Sopenharmony_ci			struct clk_omap_reg *reg)
30362306a36Sopenharmony_ci{
30462306a36Sopenharmony_ci	u32 val;
30562306a36Sopenharmony_ci	int i;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	for (i = 0; i < CLK_MAX_MEMMAPS; i++) {
30862306a36Sopenharmony_ci		if (clocks_node_ptr[i] == node->parent)
30962306a36Sopenharmony_ci			break;
31062306a36Sopenharmony_ci		if (clocks_node_ptr[i] == node->parent->parent)
31162306a36Sopenharmony_ci			break;
31262306a36Sopenharmony_ci	}
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (i == CLK_MAX_MEMMAPS) {
31562306a36Sopenharmony_ci		pr_err("clk-provider not found for %pOFn!\n", node);
31662306a36Sopenharmony_ci		return -ENOENT;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	reg->index = i;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	if (of_property_read_u32_index(node, "reg", index, &val)) {
32262306a36Sopenharmony_ci		if (of_property_read_u32_index(node->parent, "reg",
32362306a36Sopenharmony_ci					       index, &val)) {
32462306a36Sopenharmony_ci			pr_err("%pOFn or parent must have reg[%d]!\n",
32562306a36Sopenharmony_ci			       node, index);
32662306a36Sopenharmony_ci			return -EINVAL;
32762306a36Sopenharmony_ci		}
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	reg->offset = val;
33162306a36Sopenharmony_ci	reg->ptr = NULL;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_civoid ti_clk_latch(struct clk_omap_reg *reg, s8 shift)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci	u32 latch;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	if (shift < 0)
34162306a36Sopenharmony_ci		return;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	latch = 1 << shift;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	ti_clk_ll_ops->clk_rmw(latch, latch, reg);
34662306a36Sopenharmony_ci	ti_clk_ll_ops->clk_rmw(0, latch, reg);
34762306a36Sopenharmony_ci	ti_clk_ll_ops->clk_readl(reg); /* OCP barrier */
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci/**
35162306a36Sopenharmony_ci * omap2_clk_provider_init - init master clock provider
35262306a36Sopenharmony_ci * @parent: master node
35362306a36Sopenharmony_ci * @index: internal index for clk_reg_ops
35462306a36Sopenharmony_ci * @syscon: syscon regmap pointer for accessing clock registers
35562306a36Sopenharmony_ci * @mem: iomem pointer for the clock provider memory area, only used if
35662306a36Sopenharmony_ci *       syscon is not provided
35762306a36Sopenharmony_ci *
35862306a36Sopenharmony_ci * Initializes a master clock IP block. This basically sets up the
35962306a36Sopenharmony_ci * mapping from clocks node to the memory map index. All the clocks
36062306a36Sopenharmony_ci * are then initialized through the common of_clk_init call, and the
36162306a36Sopenharmony_ci * clocks will access their memory maps based on the node layout.
36262306a36Sopenharmony_ci * Returns 0 in success.
36362306a36Sopenharmony_ci */
36462306a36Sopenharmony_ciint __init omap2_clk_provider_init(struct device_node *parent, int index,
36562306a36Sopenharmony_ci				   struct regmap *syscon, void __iomem *mem)
36662306a36Sopenharmony_ci{
36762306a36Sopenharmony_ci	struct device_node *clocks;
36862306a36Sopenharmony_ci	struct clk_iomap *io;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	/* get clocks for this parent */
37162306a36Sopenharmony_ci	clocks = of_get_child_by_name(parent, "clocks");
37262306a36Sopenharmony_ci	if (!clocks) {
37362306a36Sopenharmony_ci		pr_err("%pOFn missing 'clocks' child node.\n", parent);
37462306a36Sopenharmony_ci		return -EINVAL;
37562306a36Sopenharmony_ci	}
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	/* add clocks node info */
37862306a36Sopenharmony_ci	clocks_node_ptr[index] = clocks;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	io = kzalloc(sizeof(*io), GFP_KERNEL);
38162306a36Sopenharmony_ci	if (!io)
38262306a36Sopenharmony_ci		return -ENOMEM;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	io->regmap = syscon;
38562306a36Sopenharmony_ci	io->mem = mem;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	clk_memmaps[index] = io;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	return 0;
39062306a36Sopenharmony_ci}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci/**
39362306a36Sopenharmony_ci * omap2_clk_legacy_provider_init - initialize a legacy clock provider
39462306a36Sopenharmony_ci * @index: index for the clock provider
39562306a36Sopenharmony_ci * @mem: iomem pointer for the clock provider memory area
39662306a36Sopenharmony_ci *
39762306a36Sopenharmony_ci * Initializes a legacy clock provider memory mapping.
39862306a36Sopenharmony_ci */
39962306a36Sopenharmony_civoid __init omap2_clk_legacy_provider_init(int index, void __iomem *mem)
40062306a36Sopenharmony_ci{
40162306a36Sopenharmony_ci	struct clk_iomap *io;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	io = memblock_alloc(sizeof(*io), SMP_CACHE_BYTES);
40462306a36Sopenharmony_ci	if (!io)
40562306a36Sopenharmony_ci		panic("%s: Failed to allocate %zu bytes\n", __func__,
40662306a36Sopenharmony_ci		      sizeof(*io));
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	io->mem = mem;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	clk_memmaps[index] = io;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci/**
41462306a36Sopenharmony_ci * ti_dt_clk_init_retry_clks - init clocks from the retry list
41562306a36Sopenharmony_ci *
41662306a36Sopenharmony_ci * Initializes any clocks that have failed to initialize before,
41762306a36Sopenharmony_ci * reasons being missing parent node(s) during earlier init. This
41862306a36Sopenharmony_ci * typically happens only for DPLLs which need to have both of their
41962306a36Sopenharmony_ci * parent clocks ready during init.
42062306a36Sopenharmony_ci */
42162306a36Sopenharmony_civoid ti_dt_clk_init_retry_clks(void)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	struct clk_init_item *retry;
42462306a36Sopenharmony_ci	struct clk_init_item *tmp;
42562306a36Sopenharmony_ci	int retries = 5;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	while (!list_empty(&retry_list) && retries) {
42862306a36Sopenharmony_ci		list_for_each_entry_safe(retry, tmp, &retry_list, link) {
42962306a36Sopenharmony_ci			pr_debug("retry-init: %pOFn\n", retry->node);
43062306a36Sopenharmony_ci			retry->func(retry->user, retry->node);
43162306a36Sopenharmony_ci			list_del(&retry->link);
43262306a36Sopenharmony_ci			kfree(retry);
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci		retries--;
43562306a36Sopenharmony_ci	}
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic const struct of_device_id simple_clk_match_table[] __initconst = {
43962306a36Sopenharmony_ci	{ .compatible = "fixed-clock" },
44062306a36Sopenharmony_ci	{ .compatible = "fixed-factor-clock" },
44162306a36Sopenharmony_ci	{ }
44262306a36Sopenharmony_ci};
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci/**
44562306a36Sopenharmony_ci * ti_dt_clk_name - init clock name from first output name or node name
44662306a36Sopenharmony_ci * @np: device node
44762306a36Sopenharmony_ci *
44862306a36Sopenharmony_ci * Use the first clock-output-name for the clock name if found. Fall back
44962306a36Sopenharmony_ci * to legacy naming based on node name.
45062306a36Sopenharmony_ci */
45162306a36Sopenharmony_ciconst char *ti_dt_clk_name(struct device_node *np)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	const char *name;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (!of_property_read_string_index(np, "clock-output-names", 0,
45662306a36Sopenharmony_ci					   &name))
45762306a36Sopenharmony_ci		return name;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	return np->name;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/**
46362306a36Sopenharmony_ci * ti_clk_add_aliases - setup clock aliases
46462306a36Sopenharmony_ci *
46562306a36Sopenharmony_ci * Sets up any missing clock aliases. No return value.
46662306a36Sopenharmony_ci */
46762306a36Sopenharmony_civoid __init ti_clk_add_aliases(void)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct device_node *np;
47062306a36Sopenharmony_ci	struct clk *clk;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	for_each_matching_node(np, simple_clk_match_table) {
47362306a36Sopenharmony_ci		struct of_phandle_args clkspec;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci		clkspec.np = np;
47662306a36Sopenharmony_ci		clk = of_clk_get_from_provider(&clkspec);
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci		ti_clk_add_alias(clk, ti_dt_clk_name(np));
47962306a36Sopenharmony_ci	}
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci/**
48362306a36Sopenharmony_ci * ti_clk_setup_features - setup clock features flags
48462306a36Sopenharmony_ci * @features: features definition to use
48562306a36Sopenharmony_ci *
48662306a36Sopenharmony_ci * Initializes the clock driver features flags based on platform
48762306a36Sopenharmony_ci * provided data. No return value.
48862306a36Sopenharmony_ci */
48962306a36Sopenharmony_civoid __init ti_clk_setup_features(struct ti_clk_features *features)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	memcpy(&ti_clk_features, features, sizeof(*features));
49262306a36Sopenharmony_ci}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci/**
49562306a36Sopenharmony_ci * ti_clk_get_features - get clock driver features flags
49662306a36Sopenharmony_ci *
49762306a36Sopenharmony_ci * Get TI clock driver features description. Returns a pointer
49862306a36Sopenharmony_ci * to the current feature setup.
49962306a36Sopenharmony_ci */
50062306a36Sopenharmony_ciconst struct ti_clk_features *ti_clk_get_features(void)
50162306a36Sopenharmony_ci{
50262306a36Sopenharmony_ci	return &ti_clk_features;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_ci/**
50662306a36Sopenharmony_ci * omap2_clk_enable_init_clocks - prepare & enable a list of clocks
50762306a36Sopenharmony_ci * @clk_names: ptr to an array of strings of clock names to enable
50862306a36Sopenharmony_ci * @num_clocks: number of clock names in @clk_names
50962306a36Sopenharmony_ci *
51062306a36Sopenharmony_ci * Prepare and enable a list of clocks, named by @clk_names.  No
51162306a36Sopenharmony_ci * return value. XXX Deprecated; only needed until these clocks are
51262306a36Sopenharmony_ci * properly claimed and enabled by the drivers or core code that uses
51362306a36Sopenharmony_ci * them.  XXX What code disables & calls clk_put on these clocks?
51462306a36Sopenharmony_ci */
51562306a36Sopenharmony_civoid omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks)
51662306a36Sopenharmony_ci{
51762306a36Sopenharmony_ci	struct clk *init_clk;
51862306a36Sopenharmony_ci	int i;
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	for (i = 0; i < num_clocks; i++) {
52162306a36Sopenharmony_ci		init_clk = clk_get(NULL, clk_names[i]);
52262306a36Sopenharmony_ci		if (WARN(IS_ERR(init_clk), "could not find init clock %s\n",
52362306a36Sopenharmony_ci			 clk_names[i]))
52462306a36Sopenharmony_ci			continue;
52562306a36Sopenharmony_ci		clk_prepare_enable(init_clk);
52662306a36Sopenharmony_ci	}
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci/**
53062306a36Sopenharmony_ci * ti_clk_add_alias - add a clock alias for a TI clock
53162306a36Sopenharmony_ci * @clk: clock handle to create alias for
53262306a36Sopenharmony_ci * @con: connection ID for this clock
53362306a36Sopenharmony_ci *
53462306a36Sopenharmony_ci * Creates a clock alias for a TI clock. Allocates the clock lookup entry
53562306a36Sopenharmony_ci * and assigns the data to it. Returns 0 if successful, negative error
53662306a36Sopenharmony_ci * value otherwise.
53762306a36Sopenharmony_ci */
53862306a36Sopenharmony_ciint ti_clk_add_alias(struct clk *clk, const char *con)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct clk_lookup *cl;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_ci	if (!clk)
54362306a36Sopenharmony_ci		return 0;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (IS_ERR(clk))
54662306a36Sopenharmony_ci		return PTR_ERR(clk);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	cl = kzalloc(sizeof(*cl), GFP_KERNEL);
54962306a36Sopenharmony_ci	if (!cl)
55062306a36Sopenharmony_ci		return -ENOMEM;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	cl->con_id = con;
55362306a36Sopenharmony_ci	cl->clk = clk;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	clkdev_add(cl);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	return 0;
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/**
56162306a36Sopenharmony_ci * of_ti_clk_register - register a TI clock to the common clock framework
56262306a36Sopenharmony_ci * @node: device node for this clock
56362306a36Sopenharmony_ci * @hw: hardware clock handle
56462306a36Sopenharmony_ci * @con: connection ID for this clock
56562306a36Sopenharmony_ci *
56662306a36Sopenharmony_ci * Registers a TI clock to the common clock framework, and adds a clock
56762306a36Sopenharmony_ci * alias for it. Returns a handle to the registered clock if successful,
56862306a36Sopenharmony_ci * ERR_PTR value in failure.
56962306a36Sopenharmony_ci */
57062306a36Sopenharmony_cistruct clk *of_ti_clk_register(struct device_node *node, struct clk_hw *hw,
57162306a36Sopenharmony_ci			       const char *con)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct clk *clk;
57462306a36Sopenharmony_ci	int ret;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	ret = of_clk_hw_register(node, hw);
57762306a36Sopenharmony_ci	if (ret)
57862306a36Sopenharmony_ci		return ERR_PTR(ret);
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	clk = hw->clk;
58162306a36Sopenharmony_ci	ret = ti_clk_add_alias(clk, con);
58262306a36Sopenharmony_ci	if (ret) {
58362306a36Sopenharmony_ci		clk_unregister(clk);
58462306a36Sopenharmony_ci		return ERR_PTR(ret);
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	return clk;
58862306a36Sopenharmony_ci}
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci/**
59162306a36Sopenharmony_ci * of_ti_clk_register_omap_hw - register a clk_hw_omap to the clock framework
59262306a36Sopenharmony_ci * @node: device node for this clock
59362306a36Sopenharmony_ci * @hw: hardware clock handle
59462306a36Sopenharmony_ci * @con: connection ID for this clock
59562306a36Sopenharmony_ci *
59662306a36Sopenharmony_ci * Registers a clk_hw_omap clock to the clock framewor, adds a clock alias
59762306a36Sopenharmony_ci * for it, and adds the list to the available clk_hw_omap type clocks.
59862306a36Sopenharmony_ci * Returns a handle to the registered clock if successful, ERR_PTR value
59962306a36Sopenharmony_ci * in failure.
60062306a36Sopenharmony_ci */
60162306a36Sopenharmony_cistruct clk *of_ti_clk_register_omap_hw(struct device_node *node,
60262306a36Sopenharmony_ci				       struct clk_hw *hw, const char *con)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	struct clk *clk;
60562306a36Sopenharmony_ci	struct clk_hw_omap *oclk;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	clk = of_ti_clk_register(node, hw, con);
60862306a36Sopenharmony_ci	if (IS_ERR(clk))
60962306a36Sopenharmony_ci		return clk;
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	oclk = to_clk_hw_omap(hw);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	list_add(&oclk->node, &clk_hw_omap_clocks);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	return clk;
61662306a36Sopenharmony_ci}
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci/**
61962306a36Sopenharmony_ci * omap2_clk_for_each - call function for each registered clk_hw_omap
62062306a36Sopenharmony_ci * @fn: pointer to a callback function
62162306a36Sopenharmony_ci *
62262306a36Sopenharmony_ci * Call @fn for each registered clk_hw_omap, passing @hw to each
62362306a36Sopenharmony_ci * function.  @fn must return 0 for success or any other value for
62462306a36Sopenharmony_ci * failure.  If @fn returns non-zero, the iteration across clocks
62562306a36Sopenharmony_ci * will stop and the non-zero return value will be passed to the
62662306a36Sopenharmony_ci * caller of omap2_clk_for_each().
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_ciint omap2_clk_for_each(int (*fn)(struct clk_hw_omap *hw))
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	int ret;
63162306a36Sopenharmony_ci	struct clk_hw_omap *hw;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	list_for_each_entry(hw, &clk_hw_omap_clocks, node) {
63462306a36Sopenharmony_ci		ret = (*fn)(hw);
63562306a36Sopenharmony_ci		if (ret)
63662306a36Sopenharmony_ci			break;
63762306a36Sopenharmony_ci	}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci	return ret;
64062306a36Sopenharmony_ci}
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci/**
64362306a36Sopenharmony_ci * omap2_clk_is_hw_omap - check if the provided clk_hw is OMAP clock
64462306a36Sopenharmony_ci * @hw: clk_hw to check if it is an omap clock or not
64562306a36Sopenharmony_ci *
64662306a36Sopenharmony_ci * Checks if the provided clk_hw is OMAP clock or not. Returns true if
64762306a36Sopenharmony_ci * it is, false otherwise.
64862306a36Sopenharmony_ci */
64962306a36Sopenharmony_cibool omap2_clk_is_hw_omap(struct clk_hw *hw)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	struct clk_hw_omap *oclk;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	list_for_each_entry(oclk, &clk_hw_omap_clocks, node) {
65462306a36Sopenharmony_ci		if (&oclk->hw == hw)
65562306a36Sopenharmony_ci			return true;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	return false;
65962306a36Sopenharmony_ci}
660