clk-divider.c 9.9 KB
Newer Older
M
Mike Turquette 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * 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>
J
James Hogan 已提交
19
#include <linux/log2.h>
M
Mike Turquette 已提交
20 21 22 23 24 25 26

/*
 * 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
27
 * rate - rate is adjustable.  clk->rate = DIV_ROUND_UP(parent->rate / divisor)
M
Mike Turquette 已提交
28 29 30 31 32
 * parent - fixed parent.  No clk_set_parent support
 */

#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)

J
James Hogan 已提交
33
#define div_mask(d)	((1 << ((d)->width)) - 1)
34

35 36 37 38 39 40 41 42 43 44 45
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;
}

46 47 48 49 50 51
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);
52 53
	if (divider->table)
		return _get_table_maxdiv(divider->table);
54 55 56
	return div_mask(divider) + 1;
}

57 58 59 60 61 62 63 64 65 66 67
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;
}

68 69 70 71 72 73
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;
74 75
	if (divider->table)
		return _get_table_div(divider->table, val);
76 77 78
	return val + 1;
}

79 80 81 82 83 84 85 86 87 88 89
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;
}

90
static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
91 92 93 94 95
{
	if (divider->flags & CLK_DIVIDER_ONE_BASED)
		return div;
	if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
		return __ffs(div);
96 97
	if (divider->table)
		return  _get_table_val(divider->table, div);
98 99
	return div - 1;
}
M
Mike Turquette 已提交
100 101 102 103 104

static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
		unsigned long parent_rate)
{
	struct clk_divider *divider = to_clk_divider(hw);
105
	unsigned int div, val;
M
Mike Turquette 已提交
106

107
	val = clk_readl(divider->reg) >> divider->shift;
108
	val &= div_mask(divider);
M
Mike Turquette 已提交
109

110 111
	div = _get_div(divider, val);
	if (!div) {
112 113 114
		WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
			__clk_get_name(hw->clk));
115 116
		return parent_rate;
	}
M
Mike Turquette 已提交
117

118
	return DIV_ROUND_UP(parent_rate, div);
M
Mike Turquette 已提交
119 120 121 122 123 124 125 126
}

/*
 * 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)

127 128 129 130 131 132 133 134 135 136 137 138 139 140
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)
J
James Hogan 已提交
141
		return is_power_of_2(div);
142 143 144 145 146
	if (divider->table)
		return _is_valid_table_div(divider->table, div);
	return true;
}

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
static int _round_up_table(const struct clk_div_table *table, int div)
{
	const struct clk_div_table *clkt;
	int up = _get_table_maxdiv(table);

	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;
}

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;
}

M
Mike Turquette 已提交
178 179 180 181 182 183
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;
184
	unsigned long parent_rate_saved = *best_parent_rate;
M
Mike Turquette 已提交
185 186 187 188

	if (!rate)
		rate = 1;

189
	maxdiv = _get_maxdiv(divider);
M
Mike Turquette 已提交
190

191 192
	if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
		parent_rate = *best_parent_rate;
193
		bestdiv = _div_round_up(divider, parent_rate, rate);
M
Mike Turquette 已提交
194 195 196 197 198 199 200 201 202 203 204 205
		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);

	for (i = 1; i <= maxdiv; i++) {
206
		if (!_is_valid_div(divider, i))
207
			continue;
208 209 210 211 212 213 214 215 216
		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;
		}
M
Mike Turquette 已提交
217 218
		parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
				MULT_ROUND_UP(rate, i));
219
		now = DIV_ROUND_UP(parent_rate, i);
M
Mike Turquette 已提交
220 221 222 223 224 225 226 227
		if (now <= rate && now > best) {
			bestdiv = i;
			best = now;
			*best_parent_rate = parent_rate;
		}
	}

	if (!bestdiv) {
228
		bestdiv = _get_maxdiv(divider);
M
Mike Turquette 已提交
229 230 231 232 233 234 235 236 237 238 239 240
		*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);

241
	return DIV_ROUND_UP(*prate, div);
M
Mike Turquette 已提交
242 243
}

S
Shawn Guo 已提交
244 245
static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
				unsigned long parent_rate)
M
Mike Turquette 已提交
246 247
{
	struct clk_divider *divider = to_clk_divider(hw);
248
	unsigned int div, value;
M
Mike Turquette 已提交
249 250 251
	unsigned long flags = 0;
	u32 val;

252
	div = DIV_ROUND_UP(parent_rate, rate);
253 254 255 256

	if (!_is_valid_div(divider, div))
		return -EINVAL;

257
	value = _get_val(divider, div);
M
Mike Turquette 已提交
258

259 260
	if (value > div_mask(divider))
		value = div_mask(divider);
M
Mike Turquette 已提交
261 262 263 264

	if (divider->lock)
		spin_lock_irqsave(divider->lock, flags);

265 266 267
	if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
		val = div_mask(divider) << (divider->shift + 16);
	} else {
268
		val = clk_readl(divider->reg);
269 270
		val &= ~(div_mask(divider) << divider->shift);
	}
271
	val |= value << divider->shift;
272
	clk_writel(val, divider->reg);
M
Mike Turquette 已提交
273 274 275 276 277 278 279

	if (divider->lock)
		spin_unlock_irqrestore(divider->lock, flags);

	return 0;
}

280
const struct clk_ops clk_divider_ops = {
M
Mike Turquette 已提交
281 282 283 284 285 286
	.recalc_rate = clk_divider_recalc_rate,
	.round_rate = clk_divider_round_rate,
	.set_rate = clk_divider_set_rate,
};
EXPORT_SYMBOL_GPL(clk_divider_ops);

287
static struct clk *_register_divider(struct device *dev, const char *name,
M
Mike Turquette 已提交
288 289
		const char *parent_name, unsigned long flags,
		void __iomem *reg, u8 shift, u8 width,
290 291
		u8 clk_divider_flags, const struct clk_div_table *table,
		spinlock_t *lock)
M
Mike Turquette 已提交
292 293 294
{
	struct clk_divider *div;
	struct clk *clk;
295
	struct clk_init_data init;
M
Mike Turquette 已提交
296

297 298 299 300 301 302 303
	if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
		if (width + shift > 16) {
			pr_warn("divider value exceeds LOWORD field\n");
			return ERR_PTR(-EINVAL);
		}
	}

304
	/* allocate the divider */
M
Mike Turquette 已提交
305 306 307
	div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
	if (!div) {
		pr_err("%s: could not allocate divider clk\n", __func__);
308
		return ERR_PTR(-ENOMEM);
M
Mike Turquette 已提交
309 310
	}

311 312
	init.name = name;
	init.ops = &clk_divider_ops;
313
	init.flags = flags | CLK_IS_BASIC;
314 315 316
	init.parent_names = (parent_name ? &parent_name: NULL);
	init.num_parents = (parent_name ? 1 : 0);

M
Mike Turquette 已提交
317 318 319 320 321 322
	/* struct clk_divider assignments */
	div->reg = reg;
	div->shift = shift;
	div->width = width;
	div->flags = clk_divider_flags;
	div->lock = lock;
323
	div->hw.init = &init;
324
	div->table = table;
M
Mike Turquette 已提交
325

326
	/* register the clock */
327
	clk = clk_register(dev, &div->hw);
M
Mike Turquette 已提交
328

329 330
	if (IS_ERR(clk))
		kfree(div);
M
Mike Turquette 已提交
331

332
	return clk;
M
Mike Turquette 已提交
333
}
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354

/**
 * 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);
}
355
EXPORT_SYMBOL_GPL(clk_register_divider);
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379

/**
 * 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);
}
380
EXPORT_SYMBOL_GPL(clk_register_divider_table);