clk: sunxi: Move mod0 clock to a file of its own
[linux-2.6-block.git] / drivers / clk / sunxi / clk-mod0.c
CommitLineData
992a56e4
MR
1/*
2 * Copyright 2013 Emilio López
3 *
4 * Emilio López <emilio@elopez.com.ar>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/clk-provider.h>
18#include <linux/clkdev.h>
19
20#include "clk-factors.h"
21
22/**
23 * sun4i_get_mod0_factors() - calculates m, n factors for MOD0-style clocks
24 * MOD0 rate is calculated as follows
25 * rate = (parent_rate >> p) / (m + 1);
26 */
27
28static void sun4i_a10_get_mod0_factors(u32 *freq, u32 parent_rate,
29 u8 *n, u8 *k, u8 *m, u8 *p)
30{
31 u8 div, calcm, calcp;
32
33 /* These clocks can only divide, so we will never be able to achieve
34 * frequencies higher than the parent frequency */
35 if (*freq > parent_rate)
36 *freq = parent_rate;
37
38 div = DIV_ROUND_UP(parent_rate, *freq);
39
40 if (div < 16)
41 calcp = 0;
42 else if (div / 2 < 16)
43 calcp = 1;
44 else if (div / 4 < 16)
45 calcp = 2;
46 else
47 calcp = 3;
48
49 calcm = DIV_ROUND_UP(div, 1 << calcp);
50
51 *freq = (parent_rate >> calcp) / calcm;
52
53 /* we were called to round the frequency, we can now return */
54 if (n == NULL)
55 return;
56
57 *m = calcm - 1;
58 *p = calcp;
59}
60
61/* user manual says "n" but it's really "p" */
62static struct clk_factors_config sun4i_a10_mod0_config = {
63 .mshift = 0,
64 .mwidth = 4,
65 .pshift = 16,
66 .pwidth = 2,
67};
68
69static const struct factors_data sun4i_a10_mod0_data __initconst = {
70 .enable = 31,
71 .mux = 24,
72 .table = &sun4i_a10_mod0_config,
73 .getter = sun4i_a10_get_mod0_factors,
74};
75
76static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
77
78static void __init sun4i_a10_mod0_setup(struct device_node *node)
79{
80 sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
81}
82CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);