Linux-libre 3.10.48-gnu
[librecmc/linux-libre.git] / drivers / clk / versatile / clk-impd1.c
1 /*
2  * Clock driver for the ARM Integrator/IM-PD1 board
3  * Copyright (C) 2012 Linus Walleij
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9 #include <linux/clk-provider.h>
10 #include <linux/clk.h>
11 #include <linux/clkdev.h>
12 #include <linux/err.h>
13 #include <linux/io.h>
14 #include <linux/platform_data/clk-integrator.h>
15
16 #include <mach/impd1.h>
17
18 #include "clk-icst.h"
19
20 struct impd1_clk {
21         struct clk *vcoclk;
22         struct clk *uartclk;
23         struct clk_lookup *clks[3];
24 };
25
26 static struct impd1_clk impd1_clks[4];
27
28 /*
29  * There are two VCO's on the IM-PD1 but only one is used by the
30  * kernel, that is why we are only implementing the control of
31  * IMPD1_OSC1 here.
32  */
33
34 static const struct icst_params impd1_vco_params = {
35         .ref            = 24000000,     /* 24 MHz */
36         .vco_max        = ICST525_VCO_MAX_3V,
37         .vco_min        = ICST525_VCO_MIN,
38         .vd_min         = 12,
39         .vd_max         = 519,
40         .rd_min         = 3,
41         .rd_max         = 120,
42         .s2div          = icst525_s2div,
43         .idx2s          = icst525_idx2s,
44 };
45
46 static const struct clk_icst_desc impd1_icst1_desc = {
47         .params = &impd1_vco_params,
48         .vco_offset = IMPD1_OSC1,
49         .lock_offset = IMPD1_LOCK,
50 };
51
52 /**
53  * integrator_impd1_clk_init() - set up the integrator clock tree
54  * @base: base address of the logic module (LM)
55  * @id: the ID of this LM
56  */
57 void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
58 {
59         struct impd1_clk *imc;
60         struct clk *clk;
61         int i;
62
63         if (id > 3) {
64                 pr_crit("no more than 4 LMs can be attached\n");
65                 return;
66         }
67         imc = &impd1_clks[id];
68
69         clk = icst_clk_register(NULL, &impd1_icst1_desc, base);
70         imc->vcoclk = clk;
71         imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
72
73         /* UART reference clock */
74         clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
75                                 14745600);
76         imc->uartclk = clk;
77         imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
78         imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
79
80         for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
81                 clkdev_add(imc->clks[i]);
82 }
83
84 void integrator_impd1_clk_exit(unsigned int id)
85 {
86         int i;
87         struct impd1_clk *imc;
88
89         if (id > 3)
90                 return;
91         imc = &impd1_clks[id];
92
93         for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
94                 clkdev_drop(imc->clks[i]);
95         clk_unregister(imc->uartclk);
96         clk_unregister(imc->vcoclk);
97 }