xref: /openbmc/linux/drivers/clk/at91/pmc.c (revision af719c18)
1 /*
2  *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  */
10 
11 #include <linux/clk-provider.h>
12 #include <linux/clkdev.h>
13 #include <linux/clk/at91_pmc.h>
14 #include <linux/of.h>
15 #include <linux/mfd/syscon.h>
16 #include <linux/regmap.h>
17 
18 #include <asm/proc-fns.h>
19 
20 #include "pmc.h"
21 
22 struct at91_pmc_caps {
23 	u32 available_irqs;
24 };
25 
26 struct at91_pmc {
27 	struct regmap *regmap;
28 	const struct at91_pmc_caps *caps;
29 };
30 
31 int of_at91_get_clk_range(struct device_node *np, const char *propname,
32 			  struct clk_range *range)
33 {
34 	u32 min, max;
35 	int ret;
36 
37 	ret = of_property_read_u32_index(np, propname, 0, &min);
38 	if (ret)
39 		return ret;
40 
41 	ret = of_property_read_u32_index(np, propname, 1, &max);
42 	if (ret)
43 		return ret;
44 
45 	if (range) {
46 		range->min = min;
47 		range->max = max;
48 	}
49 
50 	return 0;
51 }
52 EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
53 
54 static const struct at91_pmc_caps at91rm9200_caps = {
55 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
56 			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
57 			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
58 			  AT91_PMC_PCK3RDY,
59 };
60 
61 static const struct at91_pmc_caps at91sam9260_caps = {
62 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
63 			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
64 			  AT91_PMC_PCK1RDY,
65 };
66 
67 static const struct at91_pmc_caps at91sam9g45_caps = {
68 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
69 			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
70 			  AT91_PMC_PCK1RDY,
71 };
72 
73 static const struct at91_pmc_caps at91sam9n12_caps = {
74 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_LOCKB |
75 			  AT91_PMC_MCKRDY | AT91_PMC_PCK0RDY |
76 			  AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
77 			  AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
78 };
79 
80 static const struct at91_pmc_caps at91sam9x5_caps = {
81 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
82 			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
83 			  AT91_PMC_PCK1RDY | AT91_PMC_MOSCSELS |
84 			  AT91_PMC_MOSCRCS | AT91_PMC_CFDEV,
85 };
86 
87 static const struct at91_pmc_caps sama5d2_caps = {
88 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
89 			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
90 			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
91 			  AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
92 			  AT91_PMC_CFDEV | AT91_PMC_GCKRDY,
93 };
94 
95 static const struct at91_pmc_caps sama5d3_caps = {
96 	.available_irqs = AT91_PMC_MOSCS | AT91_PMC_LOCKA | AT91_PMC_MCKRDY |
97 			  AT91_PMC_LOCKU | AT91_PMC_PCK0RDY |
98 			  AT91_PMC_PCK1RDY | AT91_PMC_PCK2RDY |
99 			  AT91_PMC_MOSCSELS | AT91_PMC_MOSCRCS |
100 			  AT91_PMC_CFDEV,
101 };
102 
103 static void __init of_at91_pmc_setup(struct device_node *np,
104 				     const struct at91_pmc_caps *caps)
105 {
106 	struct at91_pmc *pmc;
107 	struct regmap *regmap;
108 
109 	regmap = syscon_node_to_regmap(np);
110 	if (IS_ERR(regmap))
111 		panic("Could not retrieve syscon regmap");
112 
113 	pmc = kzalloc(sizeof(*pmc), GFP_KERNEL);
114 	if (!pmc)
115 		return;
116 
117 	pmc->regmap = regmap;
118 	pmc->caps = caps;
119 
120 	regmap_write(pmc->regmap, AT91_PMC_IDR, 0xffffffff);
121 
122 }
123 
124 static void __init of_at91rm9200_pmc_setup(struct device_node *np)
125 {
126 	of_at91_pmc_setup(np, &at91rm9200_caps);
127 }
128 CLK_OF_DECLARE(at91rm9200_clk_pmc, "atmel,at91rm9200-pmc",
129 	       of_at91rm9200_pmc_setup);
130 
131 static void __init of_at91sam9260_pmc_setup(struct device_node *np)
132 {
133 	of_at91_pmc_setup(np, &at91sam9260_caps);
134 }
135 CLK_OF_DECLARE(at91sam9260_clk_pmc, "atmel,at91sam9260-pmc",
136 	       of_at91sam9260_pmc_setup);
137 
138 static void __init of_at91sam9g45_pmc_setup(struct device_node *np)
139 {
140 	of_at91_pmc_setup(np, &at91sam9g45_caps);
141 }
142 CLK_OF_DECLARE(at91sam9g45_clk_pmc, "atmel,at91sam9g45-pmc",
143 	       of_at91sam9g45_pmc_setup);
144 
145 static void __init of_at91sam9n12_pmc_setup(struct device_node *np)
146 {
147 	of_at91_pmc_setup(np, &at91sam9n12_caps);
148 }
149 CLK_OF_DECLARE(at91sam9n12_clk_pmc, "atmel,at91sam9n12-pmc",
150 	       of_at91sam9n12_pmc_setup);
151 
152 static void __init of_at91sam9x5_pmc_setup(struct device_node *np)
153 {
154 	of_at91_pmc_setup(np, &at91sam9x5_caps);
155 }
156 CLK_OF_DECLARE(at91sam9x5_clk_pmc, "atmel,at91sam9x5-pmc",
157 	       of_at91sam9x5_pmc_setup);
158 
159 static void __init of_sama5d2_pmc_setup(struct device_node *np)
160 {
161 	of_at91_pmc_setup(np, &sama5d2_caps);
162 }
163 CLK_OF_DECLARE(sama5d2_clk_pmc, "atmel,sama5d2-pmc",
164 	       of_sama5d2_pmc_setup);
165 
166 static void __init of_sama5d3_pmc_setup(struct device_node *np)
167 {
168 	of_at91_pmc_setup(np, &sama5d3_caps);
169 }
170 CLK_OF_DECLARE(sama5d3_clk_pmc, "atmel,sama5d3-pmc",
171 	       of_sama5d3_pmc_setup);
172