blob: 6d8b8e1a080ab0c695e694bcfff63b442f0e0bbf [file] [log] [blame]
Linus Walleij70ee6572012-11-20 22:39:49 +01001/*
2 * Clock driver for the ARM Integrator/IM-PD1 board
Linus Walleij8e048b92013-11-22 16:25:09 +01003 * Copyright (C) 2012-2013 Linus Walleij
Linus Walleij70ee6572012-11-20 22:39:49 +01004 *
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
20struct impd1_clk {
Linus Walleij8e048b92013-11-22 16:25:09 +010021 char *vco1name;
22 struct clk *vco1clk;
23 char *vco2name;
24 struct clk *vco2clk;
25 struct clk *mmciclk;
26 char *uartname;
Linus Walleij70ee6572012-11-20 22:39:49 +010027 struct clk *uartclk;
Linus Walleij8e048b92013-11-22 16:25:09 +010028 char *spiname;
29 struct clk *spiclk;
30 char *scname;
31 struct clk *scclk;
32 struct clk_lookup *clks[6];
Linus Walleij70ee6572012-11-20 22:39:49 +010033};
34
Linus Walleij8e048b92013-11-22 16:25:09 +010035/* One entry for each connected IM-PD1 LM */
Linus Walleij70ee6572012-11-20 22:39:49 +010036static struct impd1_clk impd1_clks[4];
37
38/*
Linus Walleij8e048b92013-11-22 16:25:09 +010039 * There are two VCO's on the IM-PD1
Linus Walleij70ee6572012-11-20 22:39:49 +010040 */
41
Linus Walleij8e048b92013-11-22 16:25:09 +010042static const struct icst_params impd1_vco1_params = {
Linus Walleij70ee6572012-11-20 22:39:49 +010043 .ref = 24000000, /* 24 MHz */
44 .vco_max = ICST525_VCO_MAX_3V,
45 .vco_min = ICST525_VCO_MIN,
46 .vd_min = 12,
47 .vd_max = 519,
48 .rd_min = 3,
49 .rd_max = 120,
50 .s2div = icst525_s2div,
51 .idx2s = icst525_idx2s,
52};
53
54static const struct clk_icst_desc impd1_icst1_desc = {
Linus Walleij8e048b92013-11-22 16:25:09 +010055 .params = &impd1_vco1_params,
Linus Walleij70ee6572012-11-20 22:39:49 +010056 .vco_offset = IMPD1_OSC1,
57 .lock_offset = IMPD1_LOCK,
58};
59
Linus Walleij8e048b92013-11-22 16:25:09 +010060static const struct icst_params impd1_vco2_params = {
61 .ref = 24000000, /* 24 MHz */
62 .vco_max = ICST525_VCO_MAX_3V,
63 .vco_min = ICST525_VCO_MIN,
64 .vd_min = 12,
65 .vd_max = 519,
66 .rd_min = 3,
67 .rd_max = 120,
68 .s2div = icst525_s2div,
69 .idx2s = icst525_idx2s,
70};
71
72static const struct clk_icst_desc impd1_icst2_desc = {
73 .params = &impd1_vco2_params,
74 .vco_offset = IMPD1_OSC2,
75 .lock_offset = IMPD1_LOCK,
76};
77
Linus Walleij70ee6572012-11-20 22:39:49 +010078/**
79 * integrator_impd1_clk_init() - set up the integrator clock tree
80 * @base: base address of the logic module (LM)
81 * @id: the ID of this LM
82 */
83void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
84{
85 struct impd1_clk *imc;
86 struct clk *clk;
87 int i;
88
89 if (id > 3) {
90 pr_crit("no more than 4 LMs can be attached\n");
91 return;
92 }
93 imc = &impd1_clks[id];
94
Linus Walleij8e048b92013-11-22 16:25:09 +010095 imc->vco1name = kasprintf(GFP_KERNEL, "lm%x-vco1", id);
Linus Walleijbf6edb42014-01-20 21:31:41 +010096 clk = icst_clk_register(NULL, &impd1_icst1_desc, imc->vco1name, NULL,
97 base);
Linus Walleijae6e6942013-11-22 11:30:05 +010098 imc->vco1clk = clk;
Linus Walleij70ee6572012-11-20 22:39:49 +010099 imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
100
Linus Walleij8e048b92013-11-22 16:25:09 +0100101 /* VCO2 is also called "CLK2" */
102 imc->vco2name = kasprintf(GFP_KERNEL, "lm%x-vco2", id);
Linus Walleijbf6edb42014-01-20 21:31:41 +0100103 clk = icst_clk_register(NULL, &impd1_icst2_desc, imc->vco2name, NULL,
104 base);
Linus Walleij8e048b92013-11-22 16:25:09 +0100105 imc->vco2clk = clk;
106
107 /* MMCI uses CLK2 right off */
108 imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00700", id);
109
110 /* UART reference clock divides CLK2 by a fixed factor 4 */
111 imc->uartname = kasprintf(GFP_KERNEL, "lm%x-uartclk", id);
112 clk = clk_register_fixed_factor(NULL, imc->uartname, imc->vco2name,
113 CLK_IGNORE_UNUSED, 1, 4);
Linus Walleij70ee6572012-11-20 22:39:49 +0100114 imc->uartclk = clk;
Linus Walleij8e048b92013-11-22 16:25:09 +0100115 imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
116 imc->clks[3] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
117
118 /* SPI PL022 clock divides CLK2 by a fixed factor 64 */
119 imc->spiname = kasprintf(GFP_KERNEL, "lm%x-spiclk", id);
120 clk = clk_register_fixed_factor(NULL, imc->spiname, imc->vco2name,
121 CLK_IGNORE_UNUSED, 1, 64);
122 imc->clks[4] = clkdev_alloc(clk, NULL, "lm%x:00300", id);
123
124 /* Smart Card clock divides CLK2 by a fixed factor 4 */
125 imc->scname = kasprintf(GFP_KERNEL, "lm%x-scclk", id);
126 clk = clk_register_fixed_factor(NULL, imc->scname, imc->vco2name,
127 CLK_IGNORE_UNUSED, 1, 4);
128 imc->scclk = clk;
129 imc->clks[5] = clkdev_alloc(clk, NULL, "lm%x:00600", id);
Linus Walleij70ee6572012-11-20 22:39:49 +0100130
131 for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
132 clkdev_add(imc->clks[i]);
133}
134
135void integrator_impd1_clk_exit(unsigned int id)
136{
137 int i;
138 struct impd1_clk *imc;
139
140 if (id > 3)
141 return;
142 imc = &impd1_clks[id];
143
144 for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
145 clkdev_drop(imc->clks[i]);
Linus Walleij8e048b92013-11-22 16:25:09 +0100146 clk_unregister(imc->spiclk);
Linus Walleij70ee6572012-11-20 22:39:49 +0100147 clk_unregister(imc->uartclk);
Linus Walleij8e048b92013-11-22 16:25:09 +0100148 clk_unregister(imc->vco2clk);
149 clk_unregister(imc->vco1clk);
150 kfree(imc->scname);
151 kfree(imc->spiname);
152 kfree(imc->uartname);
153 kfree(imc->vco2name);
154 kfree(imc->vco1name);
Linus Walleij70ee6572012-11-20 22:39:49 +0100155}