| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> | 
					
						
							|  |  |  |  * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org> | 
					
						
							|  |  |  |  * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or modify | 
					
						
							|  |  |  |  * it under the terms of the GNU General Public License version 2 as | 
					
						
							|  |  |  |  * published by the Free Software Foundation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Adjustable divider clock implementation | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/clk-provider.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/io.h>
 | 
					
						
							|  |  |  | #include <linux/err.h>
 | 
					
						
							|  |  |  | #include <linux/string.h>
 | 
					
						
							| 
									
										
										
										
											2013-01-15 10:28:05 +00:00
										 |  |  | #include <linux/log2.h>
 | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * DOC: basic adjustable divider clock that cannot gate | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Traits of this clock: | 
					
						
							|  |  |  |  * prepare - clk_prepare only ensures that parents are prepared | 
					
						
							|  |  |  |  * enable - clk_enable only ensures that parents are enabled | 
					
						
							| 
									
										
										
										
											2014-02-13 12:03:59 +02:00
										 |  |  |  * rate - rate is adjustable.  clk->rate = DIV_ROUND_UP(parent->rate / divisor) | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  |  * parent - fixed parent.  No clk_set_parent support | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-01-15 10:28:05 +00:00
										 |  |  | #define div_mask(d)	((1 << ((d)->width)) - 1)
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | static unsigned int _get_table_maxdiv(const struct clk_div_table *table) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int maxdiv = 0; | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) | 
					
						
							|  |  |  | 		if (clkt->div > maxdiv) | 
					
						
							|  |  |  | 			maxdiv = clkt->div; | 
					
						
							|  |  |  | 	return maxdiv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:07 +01:00
										 |  |  | static unsigned int _get_table_mindiv(const struct clk_div_table *table) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	unsigned int mindiv = UINT_MAX; | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) | 
					
						
							|  |  |  | 		if (clkt->div < mindiv) | 
					
						
							|  |  |  | 			mindiv = clkt->div; | 
					
						
							|  |  |  | 	return mindiv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | static unsigned int _get_maxdiv(struct clk_divider *divider) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_ONE_BASED) | 
					
						
							|  |  |  | 		return div_mask(divider); | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 
					
						
							|  |  |  | 		return 1 << div_mask(divider); | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 	if (divider->table) | 
					
						
							|  |  |  | 		return _get_table_maxdiv(divider->table); | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	return div_mask(divider) + 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | static unsigned int _get_table_div(const struct clk_div_table *table, | 
					
						
							|  |  |  | 							unsigned int val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) | 
					
						
							|  |  |  | 		if (clkt->val == val) | 
					
						
							|  |  |  | 			return clkt->div; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | static unsigned int _get_div(struct clk_divider *divider, unsigned int val) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_ONE_BASED) | 
					
						
							|  |  |  | 		return val; | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 
					
						
							|  |  |  | 		return 1 << val; | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 	if (divider->table) | 
					
						
							|  |  |  | 		return _get_table_div(divider->table, val); | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	return val + 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | static unsigned int _get_table_val(const struct clk_div_table *table, | 
					
						
							|  |  |  | 							unsigned int div) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) | 
					
						
							|  |  |  | 		if (clkt->div == div) | 
					
						
							|  |  |  | 			return clkt->val; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-16 10:41:38 +00:00
										 |  |  | static unsigned int _get_val(struct clk_divider *divider, unsigned int div) | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | { | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_ONE_BASED) | 
					
						
							|  |  |  | 		return div; | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 
					
						
							|  |  |  | 		return __ffs(div); | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 	if (divider->table) | 
					
						
							|  |  |  | 		return  _get_table_val(divider->table, div); | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	return div - 1; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | static unsigned long clk_divider_recalc_rate(struct clk_hw *hw, | 
					
						
							|  |  |  | 		unsigned long parent_rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct clk_divider *divider = to_clk_divider(hw); | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	unsigned int div, val; | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-22 14:14:40 +02:00
										 |  |  | 	val = clk_readl(divider->reg) >> divider->shift; | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	val &= div_mask(divider); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	div = _get_div(divider, val); | 
					
						
							|  |  |  | 	if (!div) { | 
					
						
							| 
									
										
										
										
											2013-04-02 15:36:56 -07:00
										 |  |  | 		WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO), | 
					
						
							|  |  |  | 			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n", | 
					
						
							|  |  |  | 			__clk_get_name(hw->clk)); | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 		return parent_rate; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 12:03:59 +02:00
										 |  |  | 	return DIV_ROUND_UP(parent_rate, div); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * The reverse of DIV_ROUND_UP: The maximum number which | 
					
						
							|  |  |  |  * divided by m is r | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | static bool _is_valid_table_div(const struct clk_div_table *table, | 
					
						
							|  |  |  | 							 unsigned int div) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) | 
					
						
							|  |  |  | 		if (clkt->div == div) | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool _is_valid_div(struct clk_divider *divider, unsigned int div) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 
					
						
							| 
									
										
										
										
											2013-01-15 10:28:05 +00:00
										 |  |  | 		return is_power_of_2(div); | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 	if (divider->table) | 
					
						
							|  |  |  | 		return _is_valid_table_div(divider->table, div); | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:06 +01:00
										 |  |  | static int _round_up_table(const struct clk_div_table *table, int div) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							| 
									
										
										
										
											2014-05-07 18:48:52 +02:00
										 |  |  | 	int up = INT_MAX; | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) { | 
					
						
							|  |  |  | 		if (clkt->div == div) | 
					
						
							|  |  |  | 			return clkt->div; | 
					
						
							|  |  |  | 		else if (clkt->div < div) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((clkt->div - div) < (up - div)) | 
					
						
							|  |  |  | 			up = clkt->div; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return up; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:07 +01:00
										 |  |  | static int _round_down_table(const struct clk_div_table *table, int div) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	const struct clk_div_table *clkt; | 
					
						
							|  |  |  | 	int down = _get_table_mindiv(table); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (clkt = table; clkt->div; clkt++) { | 
					
						
							|  |  |  | 		if (clkt->div == div) | 
					
						
							|  |  |  | 			return clkt->div; | 
					
						
							|  |  |  | 		else if (clkt->div > div) | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ((div - clkt->div) < (div - down)) | 
					
						
							|  |  |  | 			down = clkt->div; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return down; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:06 +01:00
										 |  |  | static int _div_round_up(struct clk_divider *divider, | 
					
						
							|  |  |  | 		unsigned long parent_rate, unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int div = DIV_ROUND_UP(parent_rate, rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 
					
						
							|  |  |  | 		div = __roundup_pow_of_two(div); | 
					
						
							|  |  |  | 	if (divider->table) | 
					
						
							|  |  |  | 		div = _round_up_table(divider->table, div); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return div; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:07 +01:00
										 |  |  | static int _div_round_closest(struct clk_divider *divider, | 
					
						
							|  |  |  | 		unsigned long parent_rate, unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int up, down, div; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) { | 
					
						
							|  |  |  | 		up = __roundup_pow_of_two(div); | 
					
						
							|  |  |  | 		down = __rounddown_pow_of_two(div); | 
					
						
							|  |  |  | 	} else if (divider->table) { | 
					
						
							|  |  |  | 		up = _round_up_table(divider->table, div); | 
					
						
							|  |  |  | 		down = _round_down_table(divider->table, div); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return (up - div) <= (div - down) ? up : down; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int _div_round(struct clk_divider *divider, unsigned long parent_rate, | 
					
						
							|  |  |  | 		unsigned long rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) | 
					
						
							|  |  |  | 		return _div_round_closest(divider, parent_rate, rate); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return _div_round_up(divider, parent_rate, rate); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool _is_best_div(struct clk_divider *divider, | 
					
						
							| 
									
										
										
										
											2014-05-07 18:24:10 +02:00
										 |  |  | 		unsigned long rate, unsigned long now, unsigned long best) | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:07 +01:00
										 |  |  | { | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST) | 
					
						
							|  |  |  | 		return abs(rate - now) < abs(rate - best); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return now <= rate && now > best; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:08 +01:00
										 |  |  | static int _next_div(struct clk_divider *divider, int div) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	div++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) | 
					
						
							|  |  |  | 		return __roundup_pow_of_two(div); | 
					
						
							|  |  |  | 	if (divider->table) | 
					
						
							|  |  |  | 		return _round_up_table(divider->table, div); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return div; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | 
					
						
							|  |  |  | 		unsigned long *best_parent_rate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct clk_divider *divider = to_clk_divider(hw); | 
					
						
							|  |  |  | 	int i, bestdiv = 0; | 
					
						
							|  |  |  | 	unsigned long parent_rate, best = 0, now, maxdiv; | 
					
						
							| 
									
										
										
										
											2013-06-02 22:20:55 +08:00
										 |  |  | 	unsigned long parent_rate_saved = *best_parent_rate; | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!rate) | 
					
						
							|  |  |  | 		rate = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	maxdiv = _get_maxdiv(divider); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-12 20:50:17 +08:00
										 |  |  | 	if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { | 
					
						
							|  |  |  | 		parent_rate = *best_parent_rate; | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:07 +01:00
										 |  |  | 		bestdiv = _div_round(divider, parent_rate, rate); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 		bestdiv = bestdiv == 0 ? 1 : bestdiv; | 
					
						
							|  |  |  | 		bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv; | 
					
						
							|  |  |  | 		return bestdiv; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * The maximum divider we can use without overflowing | 
					
						
							|  |  |  | 	 * unsigned long in rate * i below | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	maxdiv = min(ULONG_MAX / rate, maxdiv); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:08 +01:00
										 |  |  | 	for (i = 1; i <= maxdiv; i = _next_div(divider, i)) { | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 		if (!_is_valid_div(divider, i)) | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2013-06-02 22:20:55 +08:00
										 |  |  | 		if (rate * i == parent_rate_saved) { | 
					
						
							|  |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * It's the most ideal case if the requested rate can be | 
					
						
							|  |  |  | 			 * divided from parent clock without needing to change | 
					
						
							|  |  |  | 			 * parent rate, so return the divider immediately. | 
					
						
							|  |  |  | 			 */ | 
					
						
							|  |  |  | 			*best_parent_rate = parent_rate_saved; | 
					
						
							|  |  |  | 			return i; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), | 
					
						
							|  |  |  | 				MULT_ROUND_UP(rate, i)); | 
					
						
							| 
									
										
										
										
											2014-02-13 12:03:59 +02:00
										 |  |  | 		now = DIV_ROUND_UP(parent_rate, i); | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:07 +01:00
										 |  |  | 		if (_is_best_div(divider, rate, now, best)) { | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 			bestdiv = i; | 
					
						
							|  |  |  | 			best = now; | 
					
						
							|  |  |  | 			*best_parent_rate = parent_rate; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!bestdiv) { | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 		bestdiv = _get_maxdiv(divider); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 		*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return bestdiv; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate, | 
					
						
							|  |  |  | 				unsigned long *prate) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int div; | 
					
						
							|  |  |  | 	div = clk_divider_bestdiv(hw, rate, prate); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 12:03:59 +02:00
										 |  |  | 	return DIV_ROUND_UP(*prate, div); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-12 20:50:18 +08:00
										 |  |  | static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, | 
					
						
							|  |  |  | 				unsigned long parent_rate) | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct clk_divider *divider = to_clk_divider(hw); | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	unsigned int div, value; | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 	unsigned long flags = 0; | 
					
						
							|  |  |  | 	u32 val; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-13 12:03:59 +02:00
										 |  |  | 	div = DIV_ROUND_UP(parent_rate, rate); | 
					
						
							| 
									
										
										
										
											2014-01-29 17:24:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!_is_valid_div(divider, div)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	value = _get_val(divider, div); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	if (value > div_mask(divider)) | 
					
						
							|  |  |  | 		value = div_mask(divider); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (divider->lock) | 
					
						
							|  |  |  | 		spin_lock_irqsave(divider->lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:47:18 +08:00
										 |  |  | 	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) { | 
					
						
							|  |  |  | 		val = div_mask(divider) << (divider->shift + 16); | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-07-22 14:14:40 +02:00
										 |  |  | 		val = clk_readl(divider->reg); | 
					
						
							| 
									
										
										
										
											2013-06-08 22:47:18 +08:00
										 |  |  | 		val &= ~(div_mask(divider) << divider->shift); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-05-17 15:52:13 +05:30
										 |  |  | 	val |= value << divider->shift; | 
					
						
							| 
									
										
										
										
											2013-07-22 14:14:40 +02:00
										 |  |  | 	clk_writel(val, divider->reg); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (divider->lock) | 
					
						
							|  |  |  | 		spin_unlock_irqrestore(divider->lock, flags); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-27 15:23:22 +08:00
										 |  |  | const struct clk_ops clk_divider_ops = { | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 	.recalc_rate = clk_divider_recalc_rate, | 
					
						
							|  |  |  | 	.round_rate = clk_divider_round_rate, | 
					
						
							|  |  |  | 	.set_rate = clk_divider_set_rate, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(clk_divider_ops); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-05-23 18:32:15 +05:30
										 |  |  | const struct clk_ops clk_divider_ro_ops = { | 
					
						
							|  |  |  | 	.recalc_rate = clk_divider_recalc_rate, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | EXPORT_SYMBOL_GPL(clk_divider_ro_ops); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | static struct clk *_register_divider(struct device *dev, const char *name, | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 		const char *parent_name, unsigned long flags, | 
					
						
							|  |  |  | 		void __iomem *reg, u8 shift, u8 width, | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 		u8 clk_divider_flags, const struct clk_div_table *table, | 
					
						
							|  |  |  | 		spinlock_t *lock) | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct clk_divider *div; | 
					
						
							|  |  |  | 	struct clk *clk; | 
					
						
							| 
									
										
										
										
											2012-04-25 22:58:56 -07:00
										 |  |  | 	struct clk_init_data init; | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 22:47:18 +08:00
										 |  |  | 	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) { | 
					
						
							|  |  |  | 		if (width + shift > 16) { | 
					
						
							|  |  |  | 			pr_warn("divider value exceeds LOWORD field\n"); | 
					
						
							|  |  |  | 			return ERR_PTR(-EINVAL); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 17:51:03 -07:00
										 |  |  | 	/* allocate the divider */ | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 	div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); | 
					
						
							|  |  |  | 	if (!div) { | 
					
						
							|  |  |  | 		pr_err("%s: could not allocate divider clk\n", __func__); | 
					
						
							| 
									
										
										
										
											2012-03-26 17:51:03 -07:00
										 |  |  | 		return ERR_PTR(-ENOMEM); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-25 22:58:56 -07:00
										 |  |  | 	init.name = name; | 
					
						
							| 
									
										
										
										
											2014-05-23 18:32:15 +05:30
										 |  |  | 	if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) | 
					
						
							|  |  |  | 		init.ops = &clk_divider_ro_ops; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		init.ops = &clk_divider_ops; | 
					
						
							| 
									
										
										
										
											2012-06-01 14:02:47 +05:30
										 |  |  | 	init.flags = flags | CLK_IS_BASIC; | 
					
						
							| 
									
										
										
										
											2012-04-25 22:58:56 -07:00
										 |  |  | 	init.parent_names = (parent_name ? &parent_name: NULL); | 
					
						
							|  |  |  | 	init.num_parents = (parent_name ? 1 : 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 	/* struct clk_divider assignments */ | 
					
						
							|  |  |  | 	div->reg = reg; | 
					
						
							|  |  |  | 	div->shift = shift; | 
					
						
							|  |  |  | 	div->width = width; | 
					
						
							|  |  |  | 	div->flags = clk_divider_flags; | 
					
						
							|  |  |  | 	div->lock = lock; | 
					
						
							| 
									
										
										
										
											2012-04-25 22:58:56 -07:00
										 |  |  | 	div->hw.init = &init; | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 	div->table = table; | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 17:51:03 -07:00
										 |  |  | 	/* register the clock */ | 
					
						
							| 
									
										
										
										
											2012-04-25 22:58:56 -07:00
										 |  |  | 	clk = clk_register(dev, &div->hw); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 17:51:03 -07:00
										 |  |  | 	if (IS_ERR(clk)) | 
					
						
							|  |  |  | 		kfree(div); | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-26 17:51:03 -07:00
										 |  |  | 	return clk; | 
					
						
							| 
									
										
										
										
											2012-03-15 23:11:20 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * clk_register_divider - register a divider clock with the clock framework | 
					
						
							|  |  |  |  * @dev: device registering this clock | 
					
						
							|  |  |  |  * @name: name of this clock | 
					
						
							|  |  |  |  * @parent_name: name of clock's parent | 
					
						
							|  |  |  |  * @flags: framework-specific flags | 
					
						
							|  |  |  |  * @reg: register address to adjust divider | 
					
						
							|  |  |  |  * @shift: number of bits to shift the bitfield | 
					
						
							|  |  |  |  * @width: width of the bitfield | 
					
						
							|  |  |  |  * @clk_divider_flags: divider-specific flags for this clock | 
					
						
							|  |  |  |  * @lock: shared register lock for this clock | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct clk *clk_register_divider(struct device *dev, const char *name, | 
					
						
							|  |  |  | 		const char *parent_name, unsigned long flags, | 
					
						
							|  |  |  | 		void __iomem *reg, u8 shift, u8 width, | 
					
						
							|  |  |  | 		u8 clk_divider_flags, spinlock_t *lock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return _register_divider(dev, name, parent_name, flags, reg, shift, | 
					
						
							|  |  |  | 			width, clk_divider_flags, NULL, lock); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-02 13:14:07 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(clk_register_divider); | 
					
						
							| 
									
										
										
										
											2012-06-29 19:06:32 +05:30
										 |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * clk_register_divider_table - register a table based divider clock with | 
					
						
							|  |  |  |  * the clock framework | 
					
						
							|  |  |  |  * @dev: device registering this clock | 
					
						
							|  |  |  |  * @name: name of this clock | 
					
						
							|  |  |  |  * @parent_name: name of clock's parent | 
					
						
							|  |  |  |  * @flags: framework-specific flags | 
					
						
							|  |  |  |  * @reg: register address to adjust divider | 
					
						
							|  |  |  |  * @shift: number of bits to shift the bitfield | 
					
						
							|  |  |  |  * @width: width of the bitfield | 
					
						
							|  |  |  |  * @clk_divider_flags: divider-specific flags for this clock | 
					
						
							|  |  |  |  * @table: array of divider/value pairs ending with a div set to 0 | 
					
						
							|  |  |  |  * @lock: shared register lock for this clock | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct clk *clk_register_divider_table(struct device *dev, const char *name, | 
					
						
							|  |  |  | 		const char *parent_name, unsigned long flags, | 
					
						
							|  |  |  | 		void __iomem *reg, u8 shift, u8 width, | 
					
						
							|  |  |  | 		u8 clk_divider_flags, const struct clk_div_table *table, | 
					
						
							|  |  |  | 		spinlock_t *lock) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return _register_divider(dev, name, parent_name, flags, reg, shift, | 
					
						
							|  |  |  | 			width, clk_divider_flags, table, lock); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-08-02 13:14:07 -03:00
										 |  |  | EXPORT_SYMBOL_GPL(clk_register_divider_table); |