18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * TI Divider Clock
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * Copyright (C) 2013 Texas Instruments, Inc.
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Tero Kristo <t-kristo@ti.com>
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
98c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as
108c2ecf20Sopenharmony_ci * published by the Free Software Foundation.
118c2ecf20Sopenharmony_ci *
128c2ecf20Sopenharmony_ci * This program is distributed "as is" WITHOUT ANY WARRANTY of any
138c2ecf20Sopenharmony_ci * kind, whether express or implied; without even the implied warranty
148c2ecf20Sopenharmony_ci * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
158c2ecf20Sopenharmony_ci * GNU General Public License for more details.
168c2ecf20Sopenharmony_ci */
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/err.h>
218c2ecf20Sopenharmony_ci#include <linux/of.h>
228c2ecf20Sopenharmony_ci#include <linux/of_address.h>
238c2ecf20Sopenharmony_ci#include <linux/clk/ti.h>
248c2ecf20Sopenharmony_ci#include "clock.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#undef pr_fmt
278c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "%s: " fmt, __func__
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistatic unsigned int _get_table_div(const struct clk_div_table *table,
308c2ecf20Sopenharmony_ci				   unsigned int val)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	const struct clk_div_table *clkt;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
358c2ecf20Sopenharmony_ci		if (clkt->val == val)
368c2ecf20Sopenharmony_ci			return clkt->div;
378c2ecf20Sopenharmony_ci	return 0;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic void _setup_mask(struct clk_omap_divider *divider)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	u16 mask;
438c2ecf20Sopenharmony_ci	u32 max_val;
448c2ecf20Sopenharmony_ci	const struct clk_div_table *clkt;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (divider->table) {
478c2ecf20Sopenharmony_ci		max_val = 0;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci		for (clkt = divider->table; clkt->div; clkt++)
508c2ecf20Sopenharmony_ci			if (clkt->val > max_val)
518c2ecf20Sopenharmony_ci				max_val = clkt->val;
528c2ecf20Sopenharmony_ci	} else {
538c2ecf20Sopenharmony_ci		max_val = divider->max;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci		if (!(divider->flags & CLK_DIVIDER_ONE_BASED) &&
568c2ecf20Sopenharmony_ci		    !(divider->flags & CLK_DIVIDER_POWER_OF_TWO))
578c2ecf20Sopenharmony_ci			max_val--;
588c2ecf20Sopenharmony_ci	}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
618c2ecf20Sopenharmony_ci		mask = fls(max_val) - 1;
628c2ecf20Sopenharmony_ci	else
638c2ecf20Sopenharmony_ci		mask = max_val;
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	divider->mask = (1 << fls(mask)) - 1;
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistatic unsigned int _get_div(struct clk_omap_divider *divider, unsigned int val)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_ONE_BASED)
718c2ecf20Sopenharmony_ci		return val;
728c2ecf20Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
738c2ecf20Sopenharmony_ci		return 1 << val;
748c2ecf20Sopenharmony_ci	if (divider->table)
758c2ecf20Sopenharmony_ci		return _get_table_div(divider->table, val);
768c2ecf20Sopenharmony_ci	return val + 1;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cistatic unsigned int _get_table_val(const struct clk_div_table *table,
808c2ecf20Sopenharmony_ci				   unsigned int div)
818c2ecf20Sopenharmony_ci{
828c2ecf20Sopenharmony_ci	const struct clk_div_table *clkt;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
858c2ecf20Sopenharmony_ci		if (clkt->div == div)
868c2ecf20Sopenharmony_ci			return clkt->val;
878c2ecf20Sopenharmony_ci	return 0;
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_cistatic unsigned int _get_val(struct clk_omap_divider *divider, u8 div)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_ONE_BASED)
938c2ecf20Sopenharmony_ci		return div;
948c2ecf20Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
958c2ecf20Sopenharmony_ci		return __ffs(div);
968c2ecf20Sopenharmony_ci	if (divider->table)
978c2ecf20Sopenharmony_ci		return  _get_table_val(divider->table, div);
988c2ecf20Sopenharmony_ci	return div - 1;
998c2ecf20Sopenharmony_ci}
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cistatic unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,
1028c2ecf20Sopenharmony_ci						unsigned long parent_rate)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
1058c2ecf20Sopenharmony_ci	unsigned int div, val;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
1088c2ecf20Sopenharmony_ci	val &= divider->mask;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	div = _get_div(divider, val);
1118c2ecf20Sopenharmony_ci	if (!div) {
1128c2ecf20Sopenharmony_ci		WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
1138c2ecf20Sopenharmony_ci		     "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
1148c2ecf20Sopenharmony_ci		     clk_hw_get_name(hw));
1158c2ecf20Sopenharmony_ci		return parent_rate;
1168c2ecf20Sopenharmony_ci	}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(parent_rate, div);
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/*
1228c2ecf20Sopenharmony_ci * The reverse of DIV_ROUND_UP: The maximum number which
1238c2ecf20Sopenharmony_ci * divided by m is r
1248c2ecf20Sopenharmony_ci */
1258c2ecf20Sopenharmony_ci#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic bool _is_valid_table_div(const struct clk_div_table *table,
1288c2ecf20Sopenharmony_ci				unsigned int div)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	const struct clk_div_table *clkt;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++)
1338c2ecf20Sopenharmony_ci		if (clkt->div == div)
1348c2ecf20Sopenharmony_ci			return true;
1358c2ecf20Sopenharmony_ci	return false;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic bool _is_valid_div(struct clk_omap_divider *divider, unsigned int div)
1398c2ecf20Sopenharmony_ci{
1408c2ecf20Sopenharmony_ci	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
1418c2ecf20Sopenharmony_ci		return is_power_of_2(div);
1428c2ecf20Sopenharmony_ci	if (divider->table)
1438c2ecf20Sopenharmony_ci		return _is_valid_table_div(divider->table, div);
1448c2ecf20Sopenharmony_ci	return true;
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic int _div_round_up(const struct clk_div_table *table,
1488c2ecf20Sopenharmony_ci			 unsigned long parent_rate, unsigned long rate)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	const struct clk_div_table *clkt;
1518c2ecf20Sopenharmony_ci	int up = INT_MAX;
1528c2ecf20Sopenharmony_ci	int div = DIV_ROUND_UP_ULL((u64)parent_rate, rate);
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci	for (clkt = table; clkt->div; clkt++) {
1558c2ecf20Sopenharmony_ci		if (clkt->div == div)
1568c2ecf20Sopenharmony_ci			return clkt->div;
1578c2ecf20Sopenharmony_ci		else if (clkt->div < div)
1588c2ecf20Sopenharmony_ci			continue;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		if ((clkt->div - div) < (up - div))
1618c2ecf20Sopenharmony_ci			up = clkt->div;
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	return up;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int _div_round(const struct clk_div_table *table,
1688c2ecf20Sopenharmony_ci		      unsigned long parent_rate, unsigned long rate)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	if (!table)
1718c2ecf20Sopenharmony_ci		return DIV_ROUND_UP(parent_rate, rate);
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return _div_round_up(table, parent_rate, rate);
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
1778c2ecf20Sopenharmony_ci				  unsigned long *best_parent_rate)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
1808c2ecf20Sopenharmony_ci	int i, bestdiv = 0;
1818c2ecf20Sopenharmony_ci	unsigned long parent_rate, best = 0, now, maxdiv;
1828c2ecf20Sopenharmony_ci	unsigned long parent_rate_saved = *best_parent_rate;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	if (!rate)
1858c2ecf20Sopenharmony_ci		rate = 1;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	maxdiv = divider->max;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
1908c2ecf20Sopenharmony_ci		parent_rate = *best_parent_rate;
1918c2ecf20Sopenharmony_ci		bestdiv = _div_round(divider->table, parent_rate, rate);
1928c2ecf20Sopenharmony_ci		bestdiv = bestdiv == 0 ? 1 : bestdiv;
1938c2ecf20Sopenharmony_ci		bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
1948c2ecf20Sopenharmony_ci		return bestdiv;
1958c2ecf20Sopenharmony_ci	}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	/*
1988c2ecf20Sopenharmony_ci	 * The maximum divider we can use without overflowing
1998c2ecf20Sopenharmony_ci	 * unsigned long in rate * i below
2008c2ecf20Sopenharmony_ci	 */
2018c2ecf20Sopenharmony_ci	maxdiv = min(ULONG_MAX / rate, maxdiv);
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	for (i = 1; i <= maxdiv; i++) {
2048c2ecf20Sopenharmony_ci		if (!_is_valid_div(divider, i))
2058c2ecf20Sopenharmony_ci			continue;
2068c2ecf20Sopenharmony_ci		if (rate * i == parent_rate_saved) {
2078c2ecf20Sopenharmony_ci			/*
2088c2ecf20Sopenharmony_ci			 * It's the most ideal case if the requested rate can be
2098c2ecf20Sopenharmony_ci			 * divided from parent clock without needing to change
2108c2ecf20Sopenharmony_ci			 * parent rate, so return the divider immediately.
2118c2ecf20Sopenharmony_ci			 */
2128c2ecf20Sopenharmony_ci			*best_parent_rate = parent_rate_saved;
2138c2ecf20Sopenharmony_ci			return i;
2148c2ecf20Sopenharmony_ci		}
2158c2ecf20Sopenharmony_ci		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
2168c2ecf20Sopenharmony_ci				MULT_ROUND_UP(rate, i));
2178c2ecf20Sopenharmony_ci		now = DIV_ROUND_UP(parent_rate, i);
2188c2ecf20Sopenharmony_ci		if (now <= rate && now > best) {
2198c2ecf20Sopenharmony_ci			bestdiv = i;
2208c2ecf20Sopenharmony_ci			best = now;
2218c2ecf20Sopenharmony_ci			*best_parent_rate = parent_rate;
2228c2ecf20Sopenharmony_ci		}
2238c2ecf20Sopenharmony_ci	}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	if (!bestdiv) {
2268c2ecf20Sopenharmony_ci		bestdiv = divider->max;
2278c2ecf20Sopenharmony_ci		*best_parent_rate =
2288c2ecf20Sopenharmony_ci			clk_hw_round_rate(clk_hw_get_parent(hw), 1);
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return bestdiv;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
2358c2ecf20Sopenharmony_ci				      unsigned long *prate)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	int div;
2388c2ecf20Sopenharmony_ci	div = ti_clk_divider_bestdiv(hw, rate, prate);
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(*prate, div);
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
2448c2ecf20Sopenharmony_ci				   unsigned long parent_rate)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct clk_omap_divider *divider;
2478c2ecf20Sopenharmony_ci	unsigned int div, value;
2488c2ecf20Sopenharmony_ci	u32 val;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (!hw || !rate)
2518c2ecf20Sopenharmony_ci		return -EINVAL;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	divider = to_clk_omap_divider(hw);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	div = DIV_ROUND_UP(parent_rate, rate);
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	if (div > divider->max)
2588c2ecf20Sopenharmony_ci		div = divider->max;
2598c2ecf20Sopenharmony_ci	if (div < divider->min)
2608c2ecf20Sopenharmony_ci		div = divider->min;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	value = _get_val(divider, div);
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	val = ti_clk_ll_ops->clk_readl(&divider->reg);
2658c2ecf20Sopenharmony_ci	val &= ~(divider->mask << divider->shift);
2668c2ecf20Sopenharmony_ci	val |= value << divider->shift;
2678c2ecf20Sopenharmony_ci	ti_clk_ll_ops->clk_writel(val, &divider->reg);
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	ti_clk_latch(&divider->reg, divider->latch);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	return 0;
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci/**
2758c2ecf20Sopenharmony_ci * clk_divider_save_context - Save the divider value
2768c2ecf20Sopenharmony_ci * @hw: pointer  struct clk_hw
2778c2ecf20Sopenharmony_ci *
2788c2ecf20Sopenharmony_ci * Save the divider value
2798c2ecf20Sopenharmony_ci */
2808c2ecf20Sopenharmony_cistatic int clk_divider_save_context(struct clk_hw *hw)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
2838c2ecf20Sopenharmony_ci	u32 val;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	val = ti_clk_ll_ops->clk_readl(&divider->reg) >> divider->shift;
2868c2ecf20Sopenharmony_ci	divider->context = val & divider->mask;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	return 0;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci/**
2928c2ecf20Sopenharmony_ci * clk_divider_restore_context - restore the saved the divider value
2938c2ecf20Sopenharmony_ci * @hw: pointer  struct clk_hw
2948c2ecf20Sopenharmony_ci *
2958c2ecf20Sopenharmony_ci * Restore the saved the divider value
2968c2ecf20Sopenharmony_ci */
2978c2ecf20Sopenharmony_cistatic void clk_divider_restore_context(struct clk_hw *hw)
2988c2ecf20Sopenharmony_ci{
2998c2ecf20Sopenharmony_ci	struct clk_omap_divider *divider = to_clk_omap_divider(hw);
3008c2ecf20Sopenharmony_ci	u32 val;
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	val = ti_clk_ll_ops->clk_readl(&divider->reg);
3038c2ecf20Sopenharmony_ci	val &= ~(divider->mask << divider->shift);
3048c2ecf20Sopenharmony_ci	val |= divider->context << divider->shift;
3058c2ecf20Sopenharmony_ci	ti_clk_ll_ops->clk_writel(val, &divider->reg);
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ciconst struct clk_ops ti_clk_divider_ops = {
3098c2ecf20Sopenharmony_ci	.recalc_rate = ti_clk_divider_recalc_rate,
3108c2ecf20Sopenharmony_ci	.round_rate = ti_clk_divider_round_rate,
3118c2ecf20Sopenharmony_ci	.set_rate = ti_clk_divider_set_rate,
3128c2ecf20Sopenharmony_ci	.save_context = clk_divider_save_context,
3138c2ecf20Sopenharmony_ci	.restore_context = clk_divider_restore_context,
3148c2ecf20Sopenharmony_ci};
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic struct clk *_register_divider(struct device_node *node,
3178c2ecf20Sopenharmony_ci				     u32 flags,
3188c2ecf20Sopenharmony_ci				     struct clk_omap_divider *div)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	struct clk_init_data init;
3218c2ecf20Sopenharmony_ci	const char *parent_name;
3228c2ecf20Sopenharmony_ci	const char *name;
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	parent_name = of_clk_get_parent_name(node, 0);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	name = ti_dt_clk_name(node);
3278c2ecf20Sopenharmony_ci	init.name = name;
3288c2ecf20Sopenharmony_ci	init.ops = &ti_clk_divider_ops;
3298c2ecf20Sopenharmony_ci	init.flags = flags;
3308c2ecf20Sopenharmony_ci	init.parent_names = (parent_name ? &parent_name : NULL);
3318c2ecf20Sopenharmony_ci	init.num_parents = (parent_name ? 1 : 0);
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	div->hw.init = &init;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	/* register the clock */
3368c2ecf20Sopenharmony_ci	return of_ti_clk_register(node, &div->hw, name);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ciint ti_clk_parse_divider_data(int *div_table, int num_dividers, int max_div,
3408c2ecf20Sopenharmony_ci			      u8 flags, struct clk_omap_divider *divider)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	int valid_div = 0;
3438c2ecf20Sopenharmony_ci	int i;
3448c2ecf20Sopenharmony_ci	struct clk_div_table *tmp;
3458c2ecf20Sopenharmony_ci	u16 min_div = 0;
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ci	if (!div_table) {
3488c2ecf20Sopenharmony_ci		divider->min = 1;
3498c2ecf20Sopenharmony_ci		divider->max = max_div;
3508c2ecf20Sopenharmony_ci		_setup_mask(divider);
3518c2ecf20Sopenharmony_ci		return 0;
3528c2ecf20Sopenharmony_ci	}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	i = 0;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	while (!num_dividers || i < num_dividers) {
3578c2ecf20Sopenharmony_ci		if (div_table[i] == -1)
3588c2ecf20Sopenharmony_ci			break;
3598c2ecf20Sopenharmony_ci		if (div_table[i])
3608c2ecf20Sopenharmony_ci			valid_div++;
3618c2ecf20Sopenharmony_ci		i++;
3628c2ecf20Sopenharmony_ci	}
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	num_dividers = i;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	tmp = kcalloc(valid_div + 1, sizeof(*tmp), GFP_KERNEL);
3678c2ecf20Sopenharmony_ci	if (!tmp)
3688c2ecf20Sopenharmony_ci		return -ENOMEM;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	valid_div = 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	for (i = 0; i < num_dividers; i++)
3738c2ecf20Sopenharmony_ci		if (div_table[i] > 0) {
3748c2ecf20Sopenharmony_ci			tmp[valid_div].div = div_table[i];
3758c2ecf20Sopenharmony_ci			tmp[valid_div].val = i;
3768c2ecf20Sopenharmony_ci			valid_div++;
3778c2ecf20Sopenharmony_ci			if (div_table[i] > max_div)
3788c2ecf20Sopenharmony_ci				max_div = div_table[i];
3798c2ecf20Sopenharmony_ci			if (!min_div || div_table[i] < min_div)
3808c2ecf20Sopenharmony_ci				min_div = div_table[i];
3818c2ecf20Sopenharmony_ci		}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	divider->min = min_div;
3848c2ecf20Sopenharmony_ci	divider->max = max_div;
3858c2ecf20Sopenharmony_ci	divider->table = tmp;
3868c2ecf20Sopenharmony_ci	_setup_mask(divider);
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	return 0;
3898c2ecf20Sopenharmony_ci}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_cistatic int __init ti_clk_get_div_table(struct device_node *node,
3928c2ecf20Sopenharmony_ci				       struct clk_omap_divider *div)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	struct clk_div_table *table;
3958c2ecf20Sopenharmony_ci	const __be32 *divspec;
3968c2ecf20Sopenharmony_ci	u32 val;
3978c2ecf20Sopenharmony_ci	u32 num_div;
3988c2ecf20Sopenharmony_ci	u32 valid_div;
3998c2ecf20Sopenharmony_ci	int i;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	divspec = of_get_property(node, "ti,dividers", &num_div);
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	if (!divspec)
4048c2ecf20Sopenharmony_ci		return 0;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	num_div /= 4;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	valid_div = 0;
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* Determine required size for divider table */
4118c2ecf20Sopenharmony_ci	for (i = 0; i < num_div; i++) {
4128c2ecf20Sopenharmony_ci		of_property_read_u32_index(node, "ti,dividers", i, &val);
4138c2ecf20Sopenharmony_ci		if (val)
4148c2ecf20Sopenharmony_ci			valid_div++;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	if (!valid_div) {
4188c2ecf20Sopenharmony_ci		pr_err("no valid dividers for %pOFn table\n", node);
4198c2ecf20Sopenharmony_ci		return -EINVAL;
4208c2ecf20Sopenharmony_ci	}
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	table = kcalloc(valid_div + 1, sizeof(*table), GFP_KERNEL);
4238c2ecf20Sopenharmony_ci	if (!table)
4248c2ecf20Sopenharmony_ci		return -ENOMEM;
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	valid_div = 0;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	for (i = 0; i < num_div; i++) {
4298c2ecf20Sopenharmony_ci		of_property_read_u32_index(node, "ti,dividers", i, &val);
4308c2ecf20Sopenharmony_ci		if (val) {
4318c2ecf20Sopenharmony_ci			table[valid_div].div = val;
4328c2ecf20Sopenharmony_ci			table[valid_div].val = i;
4338c2ecf20Sopenharmony_ci			valid_div++;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci	}
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	div->table = table;
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	return 0;
4408c2ecf20Sopenharmony_ci}
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_cistatic int _populate_divider_min_max(struct device_node *node,
4438c2ecf20Sopenharmony_ci				     struct clk_omap_divider *divider)
4448c2ecf20Sopenharmony_ci{
4458c2ecf20Sopenharmony_ci	u32 min_div = 0;
4468c2ecf20Sopenharmony_ci	u32 max_div = 0;
4478c2ecf20Sopenharmony_ci	u32 val;
4488c2ecf20Sopenharmony_ci	const struct clk_div_table *clkt;
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	if (!divider->table) {
4518c2ecf20Sopenharmony_ci		/* Clk divider table not provided, determine min/max divs */
4528c2ecf20Sopenharmony_ci		if (of_property_read_u32(node, "ti,min-div", &min_div))
4538c2ecf20Sopenharmony_ci			min_div = 1;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci		if (of_property_read_u32(node, "ti,max-div", &max_div)) {
4568c2ecf20Sopenharmony_ci			pr_err("no max-div for %pOFn!\n", node);
4578c2ecf20Sopenharmony_ci			return -EINVAL;
4588c2ecf20Sopenharmony_ci		}
4598c2ecf20Sopenharmony_ci	} else {
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci		for (clkt = divider->table; clkt->div; clkt++) {
4628c2ecf20Sopenharmony_ci			val = clkt->div;
4638c2ecf20Sopenharmony_ci			if (val > max_div)
4648c2ecf20Sopenharmony_ci				max_div = val;
4658c2ecf20Sopenharmony_ci			if (!min_div || val < min_div)
4668c2ecf20Sopenharmony_ci				min_div = val;
4678c2ecf20Sopenharmony_ci		}
4688c2ecf20Sopenharmony_ci	}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	divider->min = min_div;
4718c2ecf20Sopenharmony_ci	divider->max = max_div;
4728c2ecf20Sopenharmony_ci	_setup_mask(divider);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	return 0;
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistatic int __init ti_clk_divider_populate(struct device_node *node,
4788c2ecf20Sopenharmony_ci					  struct clk_omap_divider *div,
4798c2ecf20Sopenharmony_ci					  u32 *flags)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	u32 val;
4828c2ecf20Sopenharmony_ci	int ret;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	ret = ti_clk_get_reg_addr(node, 0, &div->reg);
4858c2ecf20Sopenharmony_ci	if (ret)
4868c2ecf20Sopenharmony_ci		return ret;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	if (!of_property_read_u32(node, "ti,bit-shift", &val))
4898c2ecf20Sopenharmony_ci		div->shift = val;
4908c2ecf20Sopenharmony_ci	else
4918c2ecf20Sopenharmony_ci		div->shift = 0;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (!of_property_read_u32(node, "ti,latch-bit", &val))
4948c2ecf20Sopenharmony_ci		div->latch = val;
4958c2ecf20Sopenharmony_ci	else
4968c2ecf20Sopenharmony_ci		div->latch = -EINVAL;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	*flags = 0;
4998c2ecf20Sopenharmony_ci	div->flags = 0;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (of_property_read_bool(node, "ti,index-starts-at-one"))
5028c2ecf20Sopenharmony_ci		div->flags |= CLK_DIVIDER_ONE_BASED;
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	if (of_property_read_bool(node, "ti,index-power-of-two"))
5058c2ecf20Sopenharmony_ci		div->flags |= CLK_DIVIDER_POWER_OF_TWO;
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci	if (of_property_read_bool(node, "ti,set-rate-parent"))
5088c2ecf20Sopenharmony_ci		*flags |= CLK_SET_RATE_PARENT;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	ret = ti_clk_get_div_table(node, div);
5118c2ecf20Sopenharmony_ci	if (ret)
5128c2ecf20Sopenharmony_ci		return ret;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	return _populate_divider_min_max(node, div);
5158c2ecf20Sopenharmony_ci}
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci/**
5188c2ecf20Sopenharmony_ci * of_ti_divider_clk_setup - Setup function for simple div rate clock
5198c2ecf20Sopenharmony_ci * @node: device node for this clock
5208c2ecf20Sopenharmony_ci *
5218c2ecf20Sopenharmony_ci * Sets up a basic divider clock.
5228c2ecf20Sopenharmony_ci */
5238c2ecf20Sopenharmony_cistatic void __init of_ti_divider_clk_setup(struct device_node *node)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct clk *clk;
5268c2ecf20Sopenharmony_ci	u32 flags = 0;
5278c2ecf20Sopenharmony_ci	struct clk_omap_divider *div;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	div = kzalloc(sizeof(*div), GFP_KERNEL);
5308c2ecf20Sopenharmony_ci	if (!div)
5318c2ecf20Sopenharmony_ci		return;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	if (ti_clk_divider_populate(node, div, &flags))
5348c2ecf20Sopenharmony_ci		goto cleanup;
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_ci	clk = _register_divider(node, flags, div);
5378c2ecf20Sopenharmony_ci	if (!IS_ERR(clk)) {
5388c2ecf20Sopenharmony_ci		of_clk_add_provider(node, of_clk_src_simple_get, clk);
5398c2ecf20Sopenharmony_ci		of_ti_clk_autoidle_setup(node);
5408c2ecf20Sopenharmony_ci		return;
5418c2ecf20Sopenharmony_ci	}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cicleanup:
5448c2ecf20Sopenharmony_ci	kfree(div->table);
5458c2ecf20Sopenharmony_ci	kfree(div);
5468c2ecf20Sopenharmony_ci}
5478c2ecf20Sopenharmony_ciCLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_cistatic void __init of_ti_composite_divider_clk_setup(struct device_node *node)
5508c2ecf20Sopenharmony_ci{
5518c2ecf20Sopenharmony_ci	struct clk_omap_divider *div;
5528c2ecf20Sopenharmony_ci	u32 tmp;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	div = kzalloc(sizeof(*div), GFP_KERNEL);
5558c2ecf20Sopenharmony_ci	if (!div)
5568c2ecf20Sopenharmony_ci		return;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	if (ti_clk_divider_populate(node, div, &tmp))
5598c2ecf20Sopenharmony_ci		goto cleanup;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER))
5628c2ecf20Sopenharmony_ci		return;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cicleanup:
5658c2ecf20Sopenharmony_ci	kfree(div->table);
5668c2ecf20Sopenharmony_ci	kfree(div);
5678c2ecf20Sopenharmony_ci}
5688c2ecf20Sopenharmony_ciCLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock",
5698c2ecf20Sopenharmony_ci	       of_ti_composite_divider_clk_setup);
570