xref: /openbmc/linux/drivers/clk/clk-stm32f4.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
19952f691SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2358bdf89SDaniel Thompson /*
3358bdf89SDaniel Thompson  * Author: Daniel Thompson <daniel.thompson@linaro.org>
4358bdf89SDaniel Thompson  *
5358bdf89SDaniel Thompson  * Inspired by clk-asm9260.c .
6358bdf89SDaniel Thompson  */
7358bdf89SDaniel Thompson 
8358bdf89SDaniel Thompson #include <linux/clk-provider.h>
9358bdf89SDaniel Thompson #include <linux/err.h>
10358bdf89SDaniel Thompson #include <linux/io.h>
11861adc44SGabriel Fernandez #include <linux/iopoll.h>
12861adc44SGabriel Fernandez #include <linux/ioport.h>
13358bdf89SDaniel Thompson #include <linux/slab.h>
14358bdf89SDaniel Thompson #include <linux/spinlock.h>
15358bdf89SDaniel Thompson #include <linux/of.h>
16358bdf89SDaniel Thompson #include <linux/of_address.h>
17861adc44SGabriel Fernandez #include <linux/regmap.h>
18861adc44SGabriel Fernandez #include <linux/mfd/syscon.h>
19358bdf89SDaniel Thompson 
2083135ad3SGabriel Fernandez /*
2183135ad3SGabriel Fernandez  * Include list of clocks wich are not derived from system clock (SYSCLOCK)
2283135ad3SGabriel Fernandez  * The index of these clocks is the secondary index of DT bindings
2383135ad3SGabriel Fernandez  *
2483135ad3SGabriel Fernandez  */
2583135ad3SGabriel Fernandez #include <dt-bindings/clock/stm32fx-clock.h>
2683135ad3SGabriel Fernandez 
2783135ad3SGabriel Fernandez #define STM32F4_RCC_CR			0x00
28358bdf89SDaniel Thompson #define STM32F4_RCC_PLLCFGR		0x04
29358bdf89SDaniel Thompson #define STM32F4_RCC_CFGR		0x08
30358bdf89SDaniel Thompson #define STM32F4_RCC_AHB1ENR		0x30
31358bdf89SDaniel Thompson #define STM32F4_RCC_AHB2ENR		0x34
32358bdf89SDaniel Thompson #define STM32F4_RCC_AHB3ENR		0x38
33358bdf89SDaniel Thompson #define STM32F4_RCC_APB1ENR		0x40
34358bdf89SDaniel Thompson #define STM32F4_RCC_APB2ENR		0x44
35861adc44SGabriel Fernandez #define STM32F4_RCC_BDCR		0x70
36861adc44SGabriel Fernandez #define STM32F4_RCC_CSR			0x74
3783135ad3SGabriel Fernandez #define STM32F4_RCC_PLLI2SCFGR		0x84
3883135ad3SGabriel Fernandez #define STM32F4_RCC_PLLSAICFGR		0x88
39517633efSGabriel Fernandez #define STM32F4_RCC_DCKCFGR		0x8c
4088c9b70bSGabriel Fernandez #define STM32F7_RCC_DCKCFGR2		0x90
41517633efSGabriel Fernandez 
42517633efSGabriel Fernandez #define NONE -1
43517633efSGabriel Fernandez #define NO_IDX  NONE
44daf2d117SGabriel Fernandez #define NO_MUX  NONE
45daf2d117SGabriel Fernandez #define NO_GATE NONE
46358bdf89SDaniel Thompson 
47358bdf89SDaniel Thompson struct stm32f4_gate_data {
48358bdf89SDaniel Thompson 	u8	offset;
49358bdf89SDaniel Thompson 	u8	bit_idx;
50358bdf89SDaniel Thompson 	const char *name;
51358bdf89SDaniel Thompson 	const char *parent_name;
52358bdf89SDaniel Thompson 	unsigned long flags;
53358bdf89SDaniel Thompson };
54358bdf89SDaniel Thompson 
55a064a07fSGabriel Fernandez static const struct stm32f4_gate_data stm32f429_gates[] __initconst = {
56358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
57358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
58358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
59358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
60358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
61358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
62358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
63358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
64358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
65358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
66358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
67358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
68358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
69358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 20,	"ccmdatam",	"ahb_div" },
70358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
71358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
72358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
73358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
74358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
75358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
76358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
77358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
78358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
79358bdf89SDaniel Thompson 
80358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
81358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
82358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
83358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48" },
84358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48" },
85358bdf89SDaniel Thompson 
86358bdf89SDaniel Thompson 	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
87358bdf89SDaniel Thompson 		CLK_IGNORE_UNUSED },
88358bdf89SDaniel Thompson 
89358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
90358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
91358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
92358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
93358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
94358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
95358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
96358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
97358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
98358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
99358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
100358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
101358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 17,	"uart2",	"apb1_div" },
102358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 18,	"uart3",	"apb1_div" },
103358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 19,	"uart4",	"apb1_div" },
104358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 20,	"uart5",	"apb1_div" },
105358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 21,	"i2c1",		"apb1_div" },
106358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 22,	"i2c2",		"apb1_div" },
107358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 23,	"i2c3",		"apb1_div" },
108358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
109358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
110358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
111358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
112358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 30,	"uart7",	"apb1_div" },
113358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB1ENR, 31,	"uart8",	"apb1_div" },
114358bdf89SDaniel Thompson 
115358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
116358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
117358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR,  4,	"usart1",	"apb2_div" },
118358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR,  5,	"usart6",	"apb2_div" },
119358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
120358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
121358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
122358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 11,	"sdio",		"pll48" },
123358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
124358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
125358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
126358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
127358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
128358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
129358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
130358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
131358bdf89SDaniel Thompson 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
132358bdf89SDaniel Thompson };
133358bdf89SDaniel Thompson 
134a064a07fSGabriel Fernandez static const struct stm32f4_gate_data stm32f469_gates[] __initconst = {
135a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
136a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
137a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
138a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
139a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
140a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
141a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
142a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
143a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
144a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
145a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
146a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
147a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
148a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 20,	"ccmdatam",	"ahb_div" },
149a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
150a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
151a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
152a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
153a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
154a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
155a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
156a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
157a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
158a064a07fSGabriel Fernandez 
159a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
160a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
161a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
162a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48" },
163a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48" },
164a064a07fSGabriel Fernandez 
165a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
166a064a07fSGabriel Fernandez 		CLK_IGNORE_UNUSED },
167a064a07fSGabriel Fernandez 	{ STM32F4_RCC_AHB3ENR,  1,	"qspi",		"ahb_div",
168a064a07fSGabriel Fernandez 		CLK_IGNORE_UNUSED },
169a064a07fSGabriel Fernandez 
170a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
171a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
172a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
173a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
174a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
175a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
176a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
177a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
178a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
179a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
180a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
181a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
182a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 17,	"uart2",	"apb1_div" },
183a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 18,	"uart3",	"apb1_div" },
184a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 19,	"uart4",	"apb1_div" },
185a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 20,	"uart5",	"apb1_div" },
186a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 21,	"i2c1",		"apb1_div" },
187a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 22,	"i2c2",		"apb1_div" },
188a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 23,	"i2c3",		"apb1_div" },
189a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
190a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
191a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
192a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
193a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 30,	"uart7",	"apb1_div" },
194a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 31,	"uart8",	"apb1_div" },
195a064a07fSGabriel Fernandez 
196a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
197a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
198a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  4,	"usart1",	"apb2_div" },
199a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  5,	"usart6",	"apb2_div" },
200a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
201a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
202a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
203844ca23fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 11,	"sdio",		"sdmux" },
204a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
205a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
206a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
207a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
208a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
209a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
210a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
211a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
212a064a07fSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
213a064a07fSGabriel Fernandez };
214a064a07fSGabriel Fernandez 
21588c9b70bSGabriel Fernandez static const struct stm32f4_gate_data stm32f746_gates[] __initconst = {
21688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
21788c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
21888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
21988c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
22088c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
22188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
22288c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
22388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
22488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
22588c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
22688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
22788c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
22888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
22988c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 20,	"dtcmram",	"ahb_div" },
23088c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
23188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
23288c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
23388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
23488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
23588c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
23688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
23788c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
23888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
23988c9b70bSGabriel Fernandez 
24088c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
24188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
24288c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
24388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48"   },
24488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48"   },
24588c9b70bSGabriel Fernandez 
24688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
24788c9b70bSGabriel Fernandez 		CLK_IGNORE_UNUSED },
24888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_AHB3ENR,  1,	"qspi",		"ahb_div",
24988c9b70bSGabriel Fernandez 		CLK_IGNORE_UNUSED },
25088c9b70bSGabriel Fernandez 
25188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
25288c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
25388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
25488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
25588c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
25688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
25788c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
25888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
25988c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
26088c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
26188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
26288c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
26388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 16,	"spdifrx",	"apb1_div" },
26488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
26588c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
26688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 27,	"cec",		"apb1_div" },
26788c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
26888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
26988c9b70bSGabriel Fernandez 
27088c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
27188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
272f9acf105SPatrice Chotard 	{ STM32F4_RCC_APB2ENR,  7,	"sdmmc2",	"sdmux"    },
27388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
27488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
27588c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
27688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 11,	"sdmmc",	"sdmux"    },
27788c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
27888c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
27988c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
28088c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
28188c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
28288c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
28388c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
28488c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
28588c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
28688c9b70bSGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 23,	"sai2",		"apb2_div" },
28788c9b70bSGabriel Fernandez };
28888c9b70bSGabriel Fernandez 
289936289f0SGabriel Fernandez static const struct stm32f4_gate_data stm32f769_gates[] __initconst = {
290936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  0,	"gpioa",	"ahb_div" },
291936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  1,	"gpiob",	"ahb_div" },
292936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  2,	"gpioc",	"ahb_div" },
293936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  3,	"gpiod",	"ahb_div" },
294936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  4,	"gpioe",	"ahb_div" },
295936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  5,	"gpiof",	"ahb_div" },
296936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  6,	"gpiog",	"ahb_div" },
297936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  7,	"gpioh",	"ahb_div" },
298936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  8,	"gpioi",	"ahb_div" },
299936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR,  9,	"gpioj",	"ahb_div" },
300936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 10,	"gpiok",	"ahb_div" },
301936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 12,	"crc",		"ahb_div" },
302936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 18,	"bkpsra",	"ahb_div" },
303936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 20,	"dtcmram",	"ahb_div" },
304936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 21,	"dma1",		"ahb_div" },
305936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 22,	"dma2",		"ahb_div" },
306936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 23,	"dma2d",	"ahb_div" },
307936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 25,	"ethmac",	"ahb_div" },
308936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 26,	"ethmactx",	"ahb_div" },
309936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 27,	"ethmacrx",	"ahb_div" },
310936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 28,	"ethmacptp",	"ahb_div" },
311936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 29,	"otghs",	"ahb_div" },
312936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB1ENR, 30,	"otghsulpi",	"ahb_div" },
313936289f0SGabriel Fernandez 
314936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  0,	"dcmi",		"ahb_div" },
315936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  1,	"jpeg",		"ahb_div" },
316936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  4,	"cryp",		"ahb_div" },
317936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  5,	"hash",		"ahb_div" },
318936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  6,	"rng",		"pll48"   },
319936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB2ENR,  7,	"otgfs",	"pll48"   },
320936289f0SGabriel Fernandez 
321936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB3ENR,  0,	"fmc",		"ahb_div",
322936289f0SGabriel Fernandez 		CLK_IGNORE_UNUSED },
323936289f0SGabriel Fernandez 	{ STM32F4_RCC_AHB3ENR,  1,	"qspi",		"ahb_div",
324936289f0SGabriel Fernandez 		CLK_IGNORE_UNUSED },
325936289f0SGabriel Fernandez 
326936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  0,	"tim2",		"apb1_mul" },
327936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  1,	"tim3",		"apb1_mul" },
328936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  2,	"tim4",		"apb1_mul" },
329936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  3,	"tim5",		"apb1_mul" },
330936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  4,	"tim6",		"apb1_mul" },
331936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  5,	"tim7",		"apb1_mul" },
332936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  6,	"tim12",	"apb1_mul" },
333936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  7,	"tim13",	"apb1_mul" },
334936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR,  8,	"tim14",	"apb1_mul" },
335936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 10,	"rtcapb",	"apb1_mul" },
336936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 11,	"wwdg",		"apb1_div" },
337936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 13,	"can3",		"apb1_div" },
338936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 14,	"spi2",		"apb1_div" },
339936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 15,	"spi3",		"apb1_div" },
340936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 16,	"spdifrx",	"apb1_div" },
341936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 25,	"can1",		"apb1_div" },
342936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 26,	"can2",		"apb1_div" },
343936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 27,	"cec",		"apb1_div" },
344936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 28,	"pwr",		"apb1_div" },
345936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB1ENR, 29,	"dac",		"apb1_div" },
346936289f0SGabriel Fernandez 
347936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  0,	"tim1",		"apb2_mul" },
348936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  1,	"tim8",		"apb2_mul" },
349936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  7,	"sdmmc2",	"sdmux2" },
350936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  8,	"adc1",		"apb2_div" },
351936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR,  9,	"adc2",		"apb2_div" },
352936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 10,	"adc3",		"apb2_div" },
353936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 11,	"sdmmc1",	"sdmux1" },
354936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 12,	"spi1",		"apb2_div" },
355936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 13,	"spi4",		"apb2_div" },
356936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 14,	"syscfg",	"apb2_div" },
357936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 16,	"tim9",		"apb2_mul" },
358936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 17,	"tim10",	"apb2_mul" },
359936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 18,	"tim11",	"apb2_mul" },
360936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 20,	"spi5",		"apb2_div" },
361936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 21,	"spi6",		"apb2_div" },
362936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 22,	"sai1",		"apb2_div" },
363936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 23,	"sai2",		"apb2_div" },
364936289f0SGabriel Fernandez 	{ STM32F4_RCC_APB2ENR, 30,	"mdio",		"apb2_div" },
365936289f0SGabriel Fernandez };
366936289f0SGabriel Fernandez 
367358bdf89SDaniel Thompson /*
368358bdf89SDaniel Thompson  * This bitmask tells us which bit offsets (0..192) on STM32F4[23]xxx
369358bdf89SDaniel Thompson  * have gate bits associated with them. Its combined hweight is 71.
370358bdf89SDaniel Thompson  */
371a064a07fSGabriel Fernandez #define MAX_GATE_MAP 3
372a064a07fSGabriel Fernandez 
373a064a07fSGabriel Fernandez static const u64 stm32f42xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
374358bdf89SDaniel Thompson 						       0x0000000000000001ull,
375358bdf89SDaniel Thompson 						       0x04777f33f6fec9ffull };
376358bdf89SDaniel Thompson 
377a064a07fSGabriel Fernandez static const u64 stm32f46xx_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
378a064a07fSGabriel Fernandez 						       0x0000000000000003ull,
379a064a07fSGabriel Fernandez 						       0x0c777f33f6fec9ffull };
380a064a07fSGabriel Fernandez 
38188c9b70bSGabriel Fernandez static const u64 stm32f746_gate_map[MAX_GATE_MAP] = { 0x000000f17ef417ffull,
38288c9b70bSGabriel Fernandez 						      0x0000000000000003ull,
383f9acf105SPatrice Chotard 						      0x04f77f833e01c9ffull };
38488c9b70bSGabriel Fernandez 
385936289f0SGabriel Fernandez static const u64 stm32f769_gate_map[MAX_GATE_MAP] = { 0x000000f37ef417ffull,
386936289f0SGabriel Fernandez 						      0x0000000000000003ull,
387936289f0SGabriel Fernandez 						      0x44F77F833E01EDFFull };
388936289f0SGabriel Fernandez 
389a064a07fSGabriel Fernandez static const u64 *stm32f4_gate_map;
390a064a07fSGabriel Fernandez 
391a064a07fSGabriel Fernandez static struct clk_hw **clks;
392a064a07fSGabriel Fernandez 
393358bdf89SDaniel Thompson static DEFINE_SPINLOCK(stm32f4_clk_lock);
394358bdf89SDaniel Thompson static void __iomem *base;
395358bdf89SDaniel Thompson 
396861adc44SGabriel Fernandez static struct regmap *pdrm;
397861adc44SGabriel Fernandez 
39888c9b70bSGabriel Fernandez static int stm32fx_end_primary_clk;
39988c9b70bSGabriel Fernandez 
400358bdf89SDaniel Thompson /*
401358bdf89SDaniel Thompson  * "Multiplier" device for APBx clocks.
402358bdf89SDaniel Thompson  *
403358bdf89SDaniel Thompson  * The APBx dividers are power-of-two dividers and, if *not* running in 1:1
404358bdf89SDaniel Thompson  * mode, they also tap out the one of the low order state bits to run the
405358bdf89SDaniel Thompson  * timers. ST datasheets represent this feature as a (conditional) clock
406358bdf89SDaniel Thompson  * multiplier.
407358bdf89SDaniel Thompson  */
408358bdf89SDaniel Thompson struct clk_apb_mul {
409358bdf89SDaniel Thompson 	struct clk_hw hw;
410358bdf89SDaniel Thompson 	u8 bit_idx;
411358bdf89SDaniel Thompson };
412358bdf89SDaniel Thompson 
413358bdf89SDaniel Thompson #define to_clk_apb_mul(_hw) container_of(_hw, struct clk_apb_mul, hw)
414358bdf89SDaniel Thompson 
clk_apb_mul_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)415358bdf89SDaniel Thompson static unsigned long clk_apb_mul_recalc_rate(struct clk_hw *hw,
416358bdf89SDaniel Thompson 					     unsigned long parent_rate)
417358bdf89SDaniel Thompson {
418358bdf89SDaniel Thompson 	struct clk_apb_mul *am = to_clk_apb_mul(hw);
419358bdf89SDaniel Thompson 
420358bdf89SDaniel Thompson 	if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
421358bdf89SDaniel Thompson 		return parent_rate * 2;
422358bdf89SDaniel Thompson 
423358bdf89SDaniel Thompson 	return parent_rate;
424358bdf89SDaniel Thompson }
425358bdf89SDaniel Thompson 
clk_apb_mul_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)426358bdf89SDaniel Thompson static long clk_apb_mul_round_rate(struct clk_hw *hw, unsigned long rate,
427358bdf89SDaniel Thompson 				   unsigned long *prate)
428358bdf89SDaniel Thompson {
429358bdf89SDaniel Thompson 	struct clk_apb_mul *am = to_clk_apb_mul(hw);
430358bdf89SDaniel Thompson 	unsigned long mult = 1;
431358bdf89SDaniel Thompson 
432358bdf89SDaniel Thompson 	if (readl(base + STM32F4_RCC_CFGR) & BIT(am->bit_idx))
433358bdf89SDaniel Thompson 		mult = 2;
434358bdf89SDaniel Thompson 
43598d8a60eSStephen Boyd 	if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) {
436358bdf89SDaniel Thompson 		unsigned long best_parent = rate / mult;
437358bdf89SDaniel Thompson 
43817ae4b40SStephen Boyd 		*prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent);
439358bdf89SDaniel Thompson 	}
440358bdf89SDaniel Thompson 
441358bdf89SDaniel Thompson 	return *prate * mult;
442358bdf89SDaniel Thompson }
443358bdf89SDaniel Thompson 
clk_apb_mul_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)444358bdf89SDaniel Thompson static int clk_apb_mul_set_rate(struct clk_hw *hw, unsigned long rate,
445358bdf89SDaniel Thompson 				unsigned long parent_rate)
446358bdf89SDaniel Thompson {
447358bdf89SDaniel Thompson 	/*
448358bdf89SDaniel Thompson 	 * We must report success but we can do so unconditionally because
449358bdf89SDaniel Thompson 	 * clk_apb_mul_round_rate returns values that ensure this call is a
450358bdf89SDaniel Thompson 	 * nop.
451358bdf89SDaniel Thompson 	 */
452358bdf89SDaniel Thompson 
453358bdf89SDaniel Thompson 	return 0;
454358bdf89SDaniel Thompson }
455358bdf89SDaniel Thompson 
456358bdf89SDaniel Thompson static const struct clk_ops clk_apb_mul_factor_ops = {
457358bdf89SDaniel Thompson 	.round_rate = clk_apb_mul_round_rate,
458358bdf89SDaniel Thompson 	.set_rate = clk_apb_mul_set_rate,
459358bdf89SDaniel Thompson 	.recalc_rate = clk_apb_mul_recalc_rate,
460358bdf89SDaniel Thompson };
461358bdf89SDaniel Thompson 
clk_register_apb_mul(struct device * dev,const char * name,const char * parent_name,unsigned long flags,u8 bit_idx)462358bdf89SDaniel Thompson static struct clk *clk_register_apb_mul(struct device *dev, const char *name,
463358bdf89SDaniel Thompson 					const char *parent_name,
464358bdf89SDaniel Thompson 					unsigned long flags, u8 bit_idx)
465358bdf89SDaniel Thompson {
466358bdf89SDaniel Thompson 	struct clk_apb_mul *am;
467358bdf89SDaniel Thompson 	struct clk_init_data init;
468358bdf89SDaniel Thompson 	struct clk *clk;
469358bdf89SDaniel Thompson 
470358bdf89SDaniel Thompson 	am = kzalloc(sizeof(*am), GFP_KERNEL);
471358bdf89SDaniel Thompson 	if (!am)
472358bdf89SDaniel Thompson 		return ERR_PTR(-ENOMEM);
473358bdf89SDaniel Thompson 
474358bdf89SDaniel Thompson 	am->bit_idx = bit_idx;
475358bdf89SDaniel Thompson 	am->hw.init = &init;
476358bdf89SDaniel Thompson 
477358bdf89SDaniel Thompson 	init.name = name;
478358bdf89SDaniel Thompson 	init.ops = &clk_apb_mul_factor_ops;
479358bdf89SDaniel Thompson 	init.flags = flags;
480358bdf89SDaniel Thompson 	init.parent_names = &parent_name;
481358bdf89SDaniel Thompson 	init.num_parents = 1;
482358bdf89SDaniel Thompson 
483358bdf89SDaniel Thompson 	clk = clk_register(dev, &am->hw);
484358bdf89SDaniel Thompson 
485358bdf89SDaniel Thompson 	if (IS_ERR(clk))
486358bdf89SDaniel Thompson 		kfree(am);
487358bdf89SDaniel Thompson 
488358bdf89SDaniel Thompson 	return clk;
489358bdf89SDaniel Thompson }
490358bdf89SDaniel Thompson 
49183135ad3SGabriel Fernandez enum {
49283135ad3SGabriel Fernandez 	PLL,
49383135ad3SGabriel Fernandez 	PLL_I2S,
49483135ad3SGabriel Fernandez 	PLL_SAI,
49583135ad3SGabriel Fernandez };
49683135ad3SGabriel Fernandez 
49783135ad3SGabriel Fernandez static const struct clk_div_table pll_divp_table[] = {
49883135ad3SGabriel Fernandez 	{ 0, 2 }, { 1, 4 }, { 2, 6 }, { 3, 8 }, { 0 }
49983135ad3SGabriel Fernandez };
50083135ad3SGabriel Fernandez 
501ef189104SGabriel Fernandez static const struct clk_div_table pll_divq_table[] = {
502ef189104SGabriel Fernandez 	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 },
503ef189104SGabriel Fernandez 	{ 8, 8 }, { 9, 9 }, { 10, 10 }, { 11, 11 }, { 12, 12 }, { 13, 13 },
504ef189104SGabriel Fernandez 	{ 14, 14 }, { 15, 15 },
505ef189104SGabriel Fernandez 	{ 0 }
506ef189104SGabriel Fernandez };
507ef189104SGabriel Fernandez 
50883135ad3SGabriel Fernandez static const struct clk_div_table pll_divr_table[] = {
50983135ad3SGabriel Fernandez 	{ 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 }, { 7, 7 }, { 0 }
51083135ad3SGabriel Fernandez };
51183135ad3SGabriel Fernandez 
51283135ad3SGabriel Fernandez struct stm32f4_pll {
51383135ad3SGabriel Fernandez 	spinlock_t *lock;
51483135ad3SGabriel Fernandez 	struct	clk_gate gate;
51583135ad3SGabriel Fernandez 	u8 offset;
51683135ad3SGabriel Fernandez 	u8 bit_rdy_idx;
51783135ad3SGabriel Fernandez 	u8 status;
51883135ad3SGabriel Fernandez 	u8 n_start;
51983135ad3SGabriel Fernandez };
52083135ad3SGabriel Fernandez 
52183135ad3SGabriel Fernandez #define to_stm32f4_pll(_gate) container_of(_gate, struct stm32f4_pll, gate)
52283135ad3SGabriel Fernandez 
523517633efSGabriel Fernandez struct stm32f4_pll_post_div_data {
524517633efSGabriel Fernandez 	int idx;
52524b5b197SDario Binacchi 	int pll_idx;
526517633efSGabriel Fernandez 	const char *name;
527517633efSGabriel Fernandez 	const char *parent;
528517633efSGabriel Fernandez 	u8 flag;
529517633efSGabriel Fernandez 	u8 offset;
530517633efSGabriel Fernandez 	u8 shift;
531517633efSGabriel Fernandez 	u8 width;
532517633efSGabriel Fernandez 	u8 flag_div;
533517633efSGabriel Fernandez 	const struct clk_div_table *div_table;
534517633efSGabriel Fernandez };
535517633efSGabriel Fernandez 
53683135ad3SGabriel Fernandez struct stm32f4_vco_data {
53783135ad3SGabriel Fernandez 	const char *vco_name;
53883135ad3SGabriel Fernandez 	u8 offset;
53983135ad3SGabriel Fernandez 	u8 bit_idx;
54083135ad3SGabriel Fernandez 	u8 bit_rdy_idx;
54183135ad3SGabriel Fernandez };
54283135ad3SGabriel Fernandez 
54383135ad3SGabriel Fernandez static const struct stm32f4_vco_data  vco_data[] = {
54483135ad3SGabriel Fernandez 	{ "vco",     STM32F4_RCC_PLLCFGR,    24, 25 },
54583135ad3SGabriel Fernandez 	{ "vco-i2s", STM32F4_RCC_PLLI2SCFGR, 26, 27 },
54683135ad3SGabriel Fernandez 	{ "vco-sai", STM32F4_RCC_PLLSAICFGR, 28, 29 },
54783135ad3SGabriel Fernandez };
54883135ad3SGabriel Fernandez 
549517633efSGabriel Fernandez 
550517633efSGabriel Fernandez static const struct clk_div_table post_divr_table[] = {
551517633efSGabriel Fernandez 	{ 0, 2 }, { 1, 4 }, { 2, 8 }, { 3, 16 }, { 0 }
552517633efSGabriel Fernandez };
553517633efSGabriel Fernandez 
554517633efSGabriel Fernandez #define MAX_POST_DIV 3
555517633efSGabriel Fernandez static const struct stm32f4_pll_post_div_data  post_div_data[MAX_POST_DIV] = {
55624b5b197SDario Binacchi 	{ CLK_I2SQ_PDIV, PLL_VCO_I2S, "plli2s-q-div", "plli2s-q",
557517633efSGabriel Fernandez 		CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 0, 5, 0, NULL},
558517633efSGabriel Fernandez 
55924b5b197SDario Binacchi 	{ CLK_SAIQ_PDIV, PLL_VCO_SAI, "pllsai-q-div", "pllsai-q",
560517633efSGabriel Fernandez 		CLK_SET_RATE_PARENT, STM32F4_RCC_DCKCFGR, 8, 5, 0, NULL },
561517633efSGabriel Fernandez 
56224b5b197SDario Binacchi 	{ NO_IDX, PLL_VCO_SAI, "pllsai-r-div", "pllsai-r", CLK_SET_RATE_PARENT,
563517633efSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 16, 2, 0, post_divr_table },
564517633efSGabriel Fernandez };
565517633efSGabriel Fernandez 
56683135ad3SGabriel Fernandez struct stm32f4_div_data {
56783135ad3SGabriel Fernandez 	u8 shift;
56883135ad3SGabriel Fernandez 	u8 width;
56983135ad3SGabriel Fernandez 	u8 flag_div;
57083135ad3SGabriel Fernandez 	const struct clk_div_table *div_table;
57183135ad3SGabriel Fernandez };
57283135ad3SGabriel Fernandez 
57383135ad3SGabriel Fernandez #define MAX_PLL_DIV 3
57483135ad3SGabriel Fernandez static const struct stm32f4_div_data  div_data[MAX_PLL_DIV] = {
57583135ad3SGabriel Fernandez 	{ 16, 2, 0, pll_divp_table },
576ef189104SGabriel Fernandez 	{ 24, 4, 0, pll_divq_table },
57783135ad3SGabriel Fernandez 	{ 28, 3, 0, pll_divr_table },
57883135ad3SGabriel Fernandez };
57983135ad3SGabriel Fernandez 
58083135ad3SGabriel Fernandez struct stm32f4_pll_data {
58183135ad3SGabriel Fernandez 	u8 pll_num;
58283135ad3SGabriel Fernandez 	u8 n_start;
58383135ad3SGabriel Fernandez 	const char *div_name[MAX_PLL_DIV];
58483135ad3SGabriel Fernandez };
58583135ad3SGabriel Fernandez 
58683135ad3SGabriel Fernandez static const struct stm32f4_pll_data stm32f429_pll[MAX_PLL_DIV] = {
58783135ad3SGabriel Fernandez 	{ PLL,	   192, { "pll", "pll48",    NULL	} },
58883135ad3SGabriel Fernandez 	{ PLL_I2S, 192, { NULL,  "plli2s-q", "plli2s-r" } },
58983135ad3SGabriel Fernandez 	{ PLL_SAI,  49, { NULL,  "pllsai-q", "pllsai-r" } },
59083135ad3SGabriel Fernandez };
59183135ad3SGabriel Fernandez 
59283135ad3SGabriel Fernandez static const struct stm32f4_pll_data stm32f469_pll[MAX_PLL_DIV] = {
5932f05b6b9SGabriel Fernandez 	{ PLL,	   50, { "pll",	     "pll-q",    "pll-r"    } },
59483135ad3SGabriel Fernandez 	{ PLL_I2S, 50, { "plli2s-p", "plli2s-q", "plli2s-r" } },
59583135ad3SGabriel Fernandez 	{ PLL_SAI, 50, { "pllsai-p", "pllsai-q", "pllsai-r" } },
59683135ad3SGabriel Fernandez };
59783135ad3SGabriel Fernandez 
stm32f4_pll_is_enabled(struct clk_hw * hw)59883135ad3SGabriel Fernandez static int stm32f4_pll_is_enabled(struct clk_hw *hw)
599358bdf89SDaniel Thompson {
60083135ad3SGabriel Fernandez 	return clk_gate_ops.is_enabled(hw);
60183135ad3SGabriel Fernandez }
602358bdf89SDaniel Thompson 
603ac03d8b3SGabriel Fernandez #define PLL_TIMEOUT 10000
604ac03d8b3SGabriel Fernandez 
stm32f4_pll_enable(struct clk_hw * hw)60583135ad3SGabriel Fernandez static int stm32f4_pll_enable(struct clk_hw *hw)
60683135ad3SGabriel Fernandez {
60783135ad3SGabriel Fernandez 	struct clk_gate *gate = to_clk_gate(hw);
60883135ad3SGabriel Fernandez 	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
609ac03d8b3SGabriel Fernandez 	int bit_status;
610ac03d8b3SGabriel Fernandez 	unsigned int timeout = PLL_TIMEOUT;
611358bdf89SDaniel Thompson 
612ac03d8b3SGabriel Fernandez 	if (clk_gate_ops.is_enabled(hw))
613ac03d8b3SGabriel Fernandez 		return 0;
61483135ad3SGabriel Fernandez 
615ac03d8b3SGabriel Fernandez 	clk_gate_ops.enable(hw);
61683135ad3SGabriel Fernandez 
617ac03d8b3SGabriel Fernandez 	do {
618ac03d8b3SGabriel Fernandez 		bit_status = !(readl(gate->reg) & BIT(pll->bit_rdy_idx));
619ac03d8b3SGabriel Fernandez 
620ac03d8b3SGabriel Fernandez 	} while (bit_status && --timeout);
621ac03d8b3SGabriel Fernandez 
622ac03d8b3SGabriel Fernandez 	return bit_status;
62383135ad3SGabriel Fernandez }
62483135ad3SGabriel Fernandez 
stm32f4_pll_disable(struct clk_hw * hw)62583135ad3SGabriel Fernandez static void stm32f4_pll_disable(struct clk_hw *hw)
62683135ad3SGabriel Fernandez {
62783135ad3SGabriel Fernandez 	clk_gate_ops.disable(hw);
62883135ad3SGabriel Fernandez }
62983135ad3SGabriel Fernandez 
stm32f4_pll_recalc(struct clk_hw * hw,unsigned long parent_rate)63083135ad3SGabriel Fernandez static unsigned long stm32f4_pll_recalc(struct clk_hw *hw,
63183135ad3SGabriel Fernandez 		unsigned long parent_rate)
63283135ad3SGabriel Fernandez {
63383135ad3SGabriel Fernandez 	struct clk_gate *gate = to_clk_gate(hw);
63483135ad3SGabriel Fernandez 	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
63583135ad3SGabriel Fernandez 	unsigned long n;
63683135ad3SGabriel Fernandez 
63783135ad3SGabriel Fernandez 	n = (readl(base + pll->offset) >> 6) & 0x1ff;
63883135ad3SGabriel Fernandez 
63983135ad3SGabriel Fernandez 	return parent_rate * n;
64083135ad3SGabriel Fernandez }
64183135ad3SGabriel Fernandez 
stm32f4_pll_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)64283135ad3SGabriel Fernandez static long stm32f4_pll_round_rate(struct clk_hw *hw, unsigned long rate,
64383135ad3SGabriel Fernandez 		unsigned long *prate)
64483135ad3SGabriel Fernandez {
64583135ad3SGabriel Fernandez 	struct clk_gate *gate = to_clk_gate(hw);
64683135ad3SGabriel Fernandez 	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
64783135ad3SGabriel Fernandez 	unsigned long n;
64883135ad3SGabriel Fernandez 
64983135ad3SGabriel Fernandez 	n = rate / *prate;
65083135ad3SGabriel Fernandez 
65183135ad3SGabriel Fernandez 	if (n < pll->n_start)
65283135ad3SGabriel Fernandez 		n = pll->n_start;
65383135ad3SGabriel Fernandez 	else if (n > 432)
65483135ad3SGabriel Fernandez 		n = 432;
65583135ad3SGabriel Fernandez 
65683135ad3SGabriel Fernandez 	return *prate * n;
65783135ad3SGabriel Fernandez }
65883135ad3SGabriel Fernandez 
stm32f4_pll_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)65983135ad3SGabriel Fernandez static int stm32f4_pll_set_rate(struct clk_hw *hw, unsigned long rate,
66083135ad3SGabriel Fernandez 				unsigned long parent_rate)
66183135ad3SGabriel Fernandez {
66283135ad3SGabriel Fernandez 	struct clk_gate *gate = to_clk_gate(hw);
66383135ad3SGabriel Fernandez 	struct stm32f4_pll *pll = to_stm32f4_pll(gate);
66483135ad3SGabriel Fernandez 
66583135ad3SGabriel Fernandez 	unsigned long n;
66683135ad3SGabriel Fernandez 	unsigned long val;
66783135ad3SGabriel Fernandez 	int pll_state;
66883135ad3SGabriel Fernandez 
66983135ad3SGabriel Fernandez 	pll_state = stm32f4_pll_is_enabled(hw);
67083135ad3SGabriel Fernandez 
67183135ad3SGabriel Fernandez 	if (pll_state)
67283135ad3SGabriel Fernandez 		stm32f4_pll_disable(hw);
67383135ad3SGabriel Fernandez 
67483135ad3SGabriel Fernandez 	n = rate  / parent_rate;
67583135ad3SGabriel Fernandez 
67683135ad3SGabriel Fernandez 	val = readl(base + pll->offset) & ~(0x1ff << 6);
67783135ad3SGabriel Fernandez 
67883135ad3SGabriel Fernandez 	writel(val | ((n & 0x1ff) <<  6), base + pll->offset);
67983135ad3SGabriel Fernandez 
68083135ad3SGabriel Fernandez 	if (pll_state)
68183135ad3SGabriel Fernandez 		stm32f4_pll_enable(hw);
68283135ad3SGabriel Fernandez 
68383135ad3SGabriel Fernandez 	return 0;
68483135ad3SGabriel Fernandez }
68583135ad3SGabriel Fernandez 
68683135ad3SGabriel Fernandez static const struct clk_ops stm32f4_pll_gate_ops = {
68783135ad3SGabriel Fernandez 	.enable		= stm32f4_pll_enable,
68883135ad3SGabriel Fernandez 	.disable	= stm32f4_pll_disable,
68983135ad3SGabriel Fernandez 	.is_enabled	= stm32f4_pll_is_enabled,
69083135ad3SGabriel Fernandez 	.recalc_rate	= stm32f4_pll_recalc,
69183135ad3SGabriel Fernandez 	.round_rate	= stm32f4_pll_round_rate,
69283135ad3SGabriel Fernandez 	.set_rate	= stm32f4_pll_set_rate,
69383135ad3SGabriel Fernandez };
69483135ad3SGabriel Fernandez 
69583135ad3SGabriel Fernandez struct stm32f4_pll_div {
69683135ad3SGabriel Fernandez 	struct clk_divider div;
69783135ad3SGabriel Fernandez 	struct clk_hw *hw_pll;
69883135ad3SGabriel Fernandez };
69983135ad3SGabriel Fernandez 
70083135ad3SGabriel Fernandez #define to_pll_div_clk(_div) container_of(_div, struct stm32f4_pll_div, div)
70183135ad3SGabriel Fernandez 
stm32f4_pll_div_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)70283135ad3SGabriel Fernandez static unsigned long stm32f4_pll_div_recalc_rate(struct clk_hw *hw,
70383135ad3SGabriel Fernandez 		unsigned long parent_rate)
70483135ad3SGabriel Fernandez {
70583135ad3SGabriel Fernandez 	return clk_divider_ops.recalc_rate(hw, parent_rate);
70683135ad3SGabriel Fernandez }
70783135ad3SGabriel Fernandez 
stm32f4_pll_div_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)708*d1e40bc9SMartin Blumenstingl static int stm32f4_pll_div_determine_rate(struct clk_hw *hw,
709*d1e40bc9SMartin Blumenstingl 					  struct clk_rate_request *req)
71083135ad3SGabriel Fernandez {
711*d1e40bc9SMartin Blumenstingl 	return clk_divider_ops.determine_rate(hw, req);
71283135ad3SGabriel Fernandez }
71383135ad3SGabriel Fernandez 
stm32f4_pll_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)71483135ad3SGabriel Fernandez static int stm32f4_pll_div_set_rate(struct clk_hw *hw, unsigned long rate,
71583135ad3SGabriel Fernandez 				unsigned long parent_rate)
71683135ad3SGabriel Fernandez {
71783135ad3SGabriel Fernandez 	int pll_state, ret;
71883135ad3SGabriel Fernandez 
71983135ad3SGabriel Fernandez 	struct clk_divider *div = to_clk_divider(hw);
72083135ad3SGabriel Fernandez 	struct stm32f4_pll_div *pll_div = to_pll_div_clk(div);
72183135ad3SGabriel Fernandez 
72283135ad3SGabriel Fernandez 	pll_state = stm32f4_pll_is_enabled(pll_div->hw_pll);
72383135ad3SGabriel Fernandez 
72483135ad3SGabriel Fernandez 	if (pll_state)
72583135ad3SGabriel Fernandez 		stm32f4_pll_disable(pll_div->hw_pll);
72683135ad3SGabriel Fernandez 
72783135ad3SGabriel Fernandez 	ret = clk_divider_ops.set_rate(hw, rate, parent_rate);
72883135ad3SGabriel Fernandez 
72983135ad3SGabriel Fernandez 	if (pll_state)
73083135ad3SGabriel Fernandez 		stm32f4_pll_enable(pll_div->hw_pll);
73183135ad3SGabriel Fernandez 
73283135ad3SGabriel Fernandez 	return ret;
73383135ad3SGabriel Fernandez }
73483135ad3SGabriel Fernandez 
73583135ad3SGabriel Fernandez static const struct clk_ops stm32f4_pll_div_ops = {
73683135ad3SGabriel Fernandez 	.recalc_rate = stm32f4_pll_div_recalc_rate,
737*d1e40bc9SMartin Blumenstingl 	.determine_rate = stm32f4_pll_div_determine_rate,
73883135ad3SGabriel Fernandez 	.set_rate = stm32f4_pll_div_set_rate,
73983135ad3SGabriel Fernandez };
74083135ad3SGabriel Fernandez 
clk_register_pll_div(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,struct clk_hw * pll_hw,spinlock_t * lock)74183135ad3SGabriel Fernandez static struct clk_hw *clk_register_pll_div(const char *name,
74283135ad3SGabriel Fernandez 		const char *parent_name, unsigned long flags,
74383135ad3SGabriel Fernandez 		void __iomem *reg, u8 shift, u8 width,
74483135ad3SGabriel Fernandez 		u8 clk_divider_flags, const struct clk_div_table *table,
74583135ad3SGabriel Fernandez 		struct clk_hw *pll_hw, spinlock_t *lock)
74683135ad3SGabriel Fernandez {
74783135ad3SGabriel Fernandez 	struct stm32f4_pll_div *pll_div;
74883135ad3SGabriel Fernandez 	struct clk_hw *hw;
74983135ad3SGabriel Fernandez 	struct clk_init_data init;
75083135ad3SGabriel Fernandez 	int ret;
75183135ad3SGabriel Fernandez 
75283135ad3SGabriel Fernandez 	/* allocate the divider */
75383135ad3SGabriel Fernandez 	pll_div = kzalloc(sizeof(*pll_div), GFP_KERNEL);
75483135ad3SGabriel Fernandez 	if (!pll_div)
75583135ad3SGabriel Fernandez 		return ERR_PTR(-ENOMEM);
75683135ad3SGabriel Fernandez 
75783135ad3SGabriel Fernandez 	init.name = name;
75883135ad3SGabriel Fernandez 	init.ops = &stm32f4_pll_div_ops;
75983135ad3SGabriel Fernandez 	init.flags = flags;
76083135ad3SGabriel Fernandez 	init.parent_names = (parent_name ? &parent_name : NULL);
76183135ad3SGabriel Fernandez 	init.num_parents = (parent_name ? 1 : 0);
76283135ad3SGabriel Fernandez 
76383135ad3SGabriel Fernandez 	/* struct clk_divider assignments */
76483135ad3SGabriel Fernandez 	pll_div->div.reg = reg;
76583135ad3SGabriel Fernandez 	pll_div->div.shift = shift;
76683135ad3SGabriel Fernandez 	pll_div->div.width = width;
76783135ad3SGabriel Fernandez 	pll_div->div.flags = clk_divider_flags;
76883135ad3SGabriel Fernandez 	pll_div->div.lock = lock;
76983135ad3SGabriel Fernandez 	pll_div->div.table = table;
77083135ad3SGabriel Fernandez 	pll_div->div.hw.init = &init;
77183135ad3SGabriel Fernandez 
77283135ad3SGabriel Fernandez 	pll_div->hw_pll = pll_hw;
77383135ad3SGabriel Fernandez 
77483135ad3SGabriel Fernandez 	/* register the clock */
77583135ad3SGabriel Fernandez 	hw = &pll_div->div.hw;
77683135ad3SGabriel Fernandez 	ret = clk_hw_register(NULL, hw);
77783135ad3SGabriel Fernandez 	if (ret) {
77883135ad3SGabriel Fernandez 		kfree(pll_div);
77983135ad3SGabriel Fernandez 		hw = ERR_PTR(ret);
78083135ad3SGabriel Fernandez 	}
78183135ad3SGabriel Fernandez 
78283135ad3SGabriel Fernandez 	return hw;
78383135ad3SGabriel Fernandez }
78483135ad3SGabriel Fernandez 
stm32f4_rcc_register_pll(const char * pllsrc,const struct stm32f4_pll_data * data,spinlock_t * lock)78583135ad3SGabriel Fernandez static struct clk_hw *stm32f4_rcc_register_pll(const char *pllsrc,
78683135ad3SGabriel Fernandez 		const struct stm32f4_pll_data *data,  spinlock_t *lock)
78783135ad3SGabriel Fernandez {
78883135ad3SGabriel Fernandez 	struct stm32f4_pll *pll;
78983135ad3SGabriel Fernandez 	struct clk_init_data init = { NULL };
79083135ad3SGabriel Fernandez 	void __iomem *reg;
79183135ad3SGabriel Fernandez 	struct clk_hw *pll_hw;
79283135ad3SGabriel Fernandez 	int ret;
79383135ad3SGabriel Fernandez 	int i;
79483135ad3SGabriel Fernandez 	const struct stm32f4_vco_data *vco;
79583135ad3SGabriel Fernandez 
79683135ad3SGabriel Fernandez 
79783135ad3SGabriel Fernandez 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
79883135ad3SGabriel Fernandez 	if (!pll)
79983135ad3SGabriel Fernandez 		return ERR_PTR(-ENOMEM);
80083135ad3SGabriel Fernandez 
80183135ad3SGabriel Fernandez 	vco = &vco_data[data->pll_num];
80283135ad3SGabriel Fernandez 
80383135ad3SGabriel Fernandez 	init.name = vco->vco_name;
80483135ad3SGabriel Fernandez 	init.ops = &stm32f4_pll_gate_ops;
80583135ad3SGabriel Fernandez 	init.flags = CLK_SET_RATE_GATE;
80683135ad3SGabriel Fernandez 	init.parent_names = &pllsrc;
80783135ad3SGabriel Fernandez 	init.num_parents = 1;
80883135ad3SGabriel Fernandez 
80983135ad3SGabriel Fernandez 	pll->gate.lock = lock;
81083135ad3SGabriel Fernandez 	pll->gate.reg = base + STM32F4_RCC_CR;
81183135ad3SGabriel Fernandez 	pll->gate.bit_idx = vco->bit_idx;
81283135ad3SGabriel Fernandez 	pll->gate.hw.init = &init;
81383135ad3SGabriel Fernandez 
81483135ad3SGabriel Fernandez 	pll->offset = vco->offset;
81583135ad3SGabriel Fernandez 	pll->n_start = data->n_start;
81683135ad3SGabriel Fernandez 	pll->bit_rdy_idx = vco->bit_rdy_idx;
81783135ad3SGabriel Fernandez 	pll->status = (readl(base + STM32F4_RCC_CR) >> vco->bit_idx) & 0x1;
81883135ad3SGabriel Fernandez 
81983135ad3SGabriel Fernandez 	reg = base + pll->offset;
82083135ad3SGabriel Fernandez 
82183135ad3SGabriel Fernandez 	pll_hw = &pll->gate.hw;
82283135ad3SGabriel Fernandez 	ret = clk_hw_register(NULL, pll_hw);
82383135ad3SGabriel Fernandez 	if (ret) {
82483135ad3SGabriel Fernandez 		kfree(pll);
82583135ad3SGabriel Fernandez 		return ERR_PTR(ret);
82683135ad3SGabriel Fernandez 	}
82783135ad3SGabriel Fernandez 
82883135ad3SGabriel Fernandez 	for (i = 0; i < MAX_PLL_DIV; i++)
82983135ad3SGabriel Fernandez 		if (data->div_name[i])
83083135ad3SGabriel Fernandez 			clk_register_pll_div(data->div_name[i],
83183135ad3SGabriel Fernandez 					vco->vco_name,
83283135ad3SGabriel Fernandez 					0,
83383135ad3SGabriel Fernandez 					reg,
83483135ad3SGabriel Fernandez 					div_data[i].shift,
83583135ad3SGabriel Fernandez 					div_data[i].width,
83683135ad3SGabriel Fernandez 					div_data[i].flag_div,
83783135ad3SGabriel Fernandez 					div_data[i].div_table,
83883135ad3SGabriel Fernandez 					pll_hw,
83983135ad3SGabriel Fernandez 					lock);
84083135ad3SGabriel Fernandez 	return pll_hw;
841358bdf89SDaniel Thompson }
842358bdf89SDaniel Thompson 
843358bdf89SDaniel Thompson /*
844358bdf89SDaniel Thompson  * Converts the primary and secondary indices (as they appear in DT) to an
845358bdf89SDaniel Thompson  * offset into our struct clock array.
846358bdf89SDaniel Thompson  */
stm32f4_rcc_lookup_clk_idx(u8 primary,u8 secondary)847358bdf89SDaniel Thompson static int stm32f4_rcc_lookup_clk_idx(u8 primary, u8 secondary)
848358bdf89SDaniel Thompson {
849a064a07fSGabriel Fernandez 	u64 table[MAX_GATE_MAP];
850358bdf89SDaniel Thompson 
851358bdf89SDaniel Thompson 	if (primary == 1) {
85288c9b70bSGabriel Fernandez 		if (WARN_ON(secondary >= stm32fx_end_primary_clk))
853358bdf89SDaniel Thompson 			return -EINVAL;
854358bdf89SDaniel Thompson 		return secondary;
855358bdf89SDaniel Thompson 	}
856358bdf89SDaniel Thompson 
857a064a07fSGabriel Fernandez 	memcpy(table, stm32f4_gate_map, sizeof(table));
858358bdf89SDaniel Thompson 
859358bdf89SDaniel Thompson 	/* only bits set in table can be used as indices */
86015ab3827SDaniel Thompson 	if (WARN_ON(secondary >= BITS_PER_BYTE * sizeof(table) ||
861358bdf89SDaniel Thompson 		    0 == (table[BIT_ULL_WORD(secondary)] &
862358bdf89SDaniel Thompson 			  BIT_ULL_MASK(secondary))))
863358bdf89SDaniel Thompson 		return -EINVAL;
864358bdf89SDaniel Thompson 
865358bdf89SDaniel Thompson 	/* mask out bits above our current index */
866358bdf89SDaniel Thompson 	table[BIT_ULL_WORD(secondary)] &=
867358bdf89SDaniel Thompson 	    GENMASK_ULL(secondary % BITS_PER_LONG_LONG, 0);
868358bdf89SDaniel Thompson 
86988c9b70bSGabriel Fernandez 	return stm32fx_end_primary_clk - 1 + hweight64(table[0]) +
870358bdf89SDaniel Thompson 	       (BIT_ULL_WORD(secondary) >= 1 ? hweight64(table[1]) : 0) +
871358bdf89SDaniel Thompson 	       (BIT_ULL_WORD(secondary) >= 2 ? hweight64(table[2]) : 0);
872358bdf89SDaniel Thompson }
873358bdf89SDaniel Thompson 
8744e950d1eSStephen Boyd static struct clk_hw *
stm32f4_rcc_lookup_clk(struct of_phandle_args * clkspec,void * data)875358bdf89SDaniel Thompson stm32f4_rcc_lookup_clk(struct of_phandle_args *clkspec, void *data)
876358bdf89SDaniel Thompson {
877358bdf89SDaniel Thompson 	int i = stm32f4_rcc_lookup_clk_idx(clkspec->args[0], clkspec->args[1]);
878358bdf89SDaniel Thompson 
879358bdf89SDaniel Thompson 	if (i < 0)
880358bdf89SDaniel Thompson 		return ERR_PTR(-EINVAL);
881358bdf89SDaniel Thompson 
882358bdf89SDaniel Thompson 	return clks[i];
883358bdf89SDaniel Thompson }
884358bdf89SDaniel Thompson 
885861adc44SGabriel Fernandez #define to_rgclk(_rgate) container_of(_rgate, struct stm32_rgate, gate)
886861adc44SGabriel Fernandez 
disable_power_domain_write_protection(void)887861adc44SGabriel Fernandez static inline void disable_power_domain_write_protection(void)
888861adc44SGabriel Fernandez {
889861adc44SGabriel Fernandez 	if (pdrm)
890861adc44SGabriel Fernandez 		regmap_update_bits(pdrm, 0x00, (1 << 8), (1 << 8));
891861adc44SGabriel Fernandez }
892861adc44SGabriel Fernandez 
enable_power_domain_write_protection(void)893861adc44SGabriel Fernandez static inline void enable_power_domain_write_protection(void)
894861adc44SGabriel Fernandez {
895861adc44SGabriel Fernandez 	if (pdrm)
896861adc44SGabriel Fernandez 		regmap_update_bits(pdrm, 0x00, (1 << 8), (0 << 8));
897861adc44SGabriel Fernandez }
898861adc44SGabriel Fernandez 
sofware_reset_backup_domain(void)8994261a881SGabriel Fernandez static inline void sofware_reset_backup_domain(void)
9004261a881SGabriel Fernandez {
9014261a881SGabriel Fernandez 	unsigned long val;
9024261a881SGabriel Fernandez 
9034261a881SGabriel Fernandez 	val = readl(base + STM32F4_RCC_BDCR);
9044261a881SGabriel Fernandez 	writel(val | BIT(16), base + STM32F4_RCC_BDCR);
9054261a881SGabriel Fernandez 	writel(val & ~BIT(16), base + STM32F4_RCC_BDCR);
9064261a881SGabriel Fernandez }
9074261a881SGabriel Fernandez 
908861adc44SGabriel Fernandez struct stm32_rgate {
909861adc44SGabriel Fernandez 	struct	clk_gate gate;
910861adc44SGabriel Fernandez 	u8	bit_rdy_idx;
911861adc44SGabriel Fernandez };
912861adc44SGabriel Fernandez 
913ac03d8b3SGabriel Fernandez #define RGATE_TIMEOUT 50000
914861adc44SGabriel Fernandez 
rgclk_enable(struct clk_hw * hw)915861adc44SGabriel Fernandez static int rgclk_enable(struct clk_hw *hw)
916861adc44SGabriel Fernandez {
917861adc44SGabriel Fernandez 	struct clk_gate *gate = to_clk_gate(hw);
918861adc44SGabriel Fernandez 	struct stm32_rgate *rgate = to_rgclk(gate);
919ac03d8b3SGabriel Fernandez 	int bit_status;
920ac03d8b3SGabriel Fernandez 	unsigned int timeout = RGATE_TIMEOUT;
921ac03d8b3SGabriel Fernandez 
922ac03d8b3SGabriel Fernandez 	if (clk_gate_ops.is_enabled(hw))
923ac03d8b3SGabriel Fernandez 		return 0;
924861adc44SGabriel Fernandez 
925861adc44SGabriel Fernandez 	disable_power_domain_write_protection();
926861adc44SGabriel Fernandez 
927861adc44SGabriel Fernandez 	clk_gate_ops.enable(hw);
928861adc44SGabriel Fernandez 
929ac03d8b3SGabriel Fernandez 	do {
930ac03d8b3SGabriel Fernandez 		bit_status = !(readl(gate->reg) & BIT(rgate->bit_rdy_idx));
931ac03d8b3SGabriel Fernandez 		if (bit_status)
932ac03d8b3SGabriel Fernandez 			udelay(100);
933ac03d8b3SGabriel Fernandez 
934ac03d8b3SGabriel Fernandez 	} while (bit_status && --timeout);
935861adc44SGabriel Fernandez 
936861adc44SGabriel Fernandez 	enable_power_domain_write_protection();
937ac03d8b3SGabriel Fernandez 
938ac03d8b3SGabriel Fernandez 	return bit_status;
939861adc44SGabriel Fernandez }
940861adc44SGabriel Fernandez 
rgclk_disable(struct clk_hw * hw)941861adc44SGabriel Fernandez static void rgclk_disable(struct clk_hw *hw)
942861adc44SGabriel Fernandez {
943861adc44SGabriel Fernandez 	clk_gate_ops.disable(hw);
944861adc44SGabriel Fernandez }
945861adc44SGabriel Fernandez 
rgclk_is_enabled(struct clk_hw * hw)946861adc44SGabriel Fernandez static int rgclk_is_enabled(struct clk_hw *hw)
947861adc44SGabriel Fernandez {
948861adc44SGabriel Fernandez 	return clk_gate_ops.is_enabled(hw);
949861adc44SGabriel Fernandez }
950861adc44SGabriel Fernandez 
951861adc44SGabriel Fernandez static const struct clk_ops rgclk_ops = {
952861adc44SGabriel Fernandez 	.enable = rgclk_enable,
953861adc44SGabriel Fernandez 	.disable = rgclk_disable,
954861adc44SGabriel Fernandez 	.is_enabled = rgclk_is_enabled,
955861adc44SGabriel Fernandez };
956861adc44SGabriel Fernandez 
clk_register_rgate(struct device * dev,const char * name,const char * parent_name,unsigned long flags,void __iomem * reg,u8 bit_idx,u8 bit_rdy_idx,u8 clk_gate_flags,spinlock_t * lock)957861adc44SGabriel Fernandez static struct clk_hw *clk_register_rgate(struct device *dev, const char *name,
958861adc44SGabriel Fernandez 		const char *parent_name, unsigned long flags,
959861adc44SGabriel Fernandez 		void __iomem *reg, u8 bit_idx, u8 bit_rdy_idx,
960861adc44SGabriel Fernandez 		u8 clk_gate_flags, spinlock_t *lock)
961861adc44SGabriel Fernandez {
962861adc44SGabriel Fernandez 	struct stm32_rgate *rgate;
963861adc44SGabriel Fernandez 	struct clk_init_data init = { NULL };
964861adc44SGabriel Fernandez 	struct clk_hw *hw;
965861adc44SGabriel Fernandez 	int ret;
966861adc44SGabriel Fernandez 
967861adc44SGabriel Fernandez 	rgate = kzalloc(sizeof(*rgate), GFP_KERNEL);
968861adc44SGabriel Fernandez 	if (!rgate)
969861adc44SGabriel Fernandez 		return ERR_PTR(-ENOMEM);
970861adc44SGabriel Fernandez 
971861adc44SGabriel Fernandez 	init.name = name;
972861adc44SGabriel Fernandez 	init.ops = &rgclk_ops;
973861adc44SGabriel Fernandez 	init.flags = flags;
974861adc44SGabriel Fernandez 	init.parent_names = &parent_name;
975861adc44SGabriel Fernandez 	init.num_parents = 1;
976861adc44SGabriel Fernandez 
977861adc44SGabriel Fernandez 	rgate->bit_rdy_idx = bit_rdy_idx;
978861adc44SGabriel Fernandez 
979861adc44SGabriel Fernandez 	rgate->gate.lock = lock;
980861adc44SGabriel Fernandez 	rgate->gate.reg = reg;
981861adc44SGabriel Fernandez 	rgate->gate.bit_idx = bit_idx;
982861adc44SGabriel Fernandez 	rgate->gate.hw.init = &init;
983861adc44SGabriel Fernandez 
984861adc44SGabriel Fernandez 	hw = &rgate->gate.hw;
985861adc44SGabriel Fernandez 	ret = clk_hw_register(dev, hw);
986861adc44SGabriel Fernandez 	if (ret) {
987861adc44SGabriel Fernandez 		kfree(rgate);
988861adc44SGabriel Fernandez 		hw = ERR_PTR(ret);
989861adc44SGabriel Fernandez 	}
990861adc44SGabriel Fernandez 
991861adc44SGabriel Fernandez 	return hw;
992861adc44SGabriel Fernandez }
993861adc44SGabriel Fernandez 
cclk_gate_enable(struct clk_hw * hw)9944261a881SGabriel Fernandez static int cclk_gate_enable(struct clk_hw *hw)
9954261a881SGabriel Fernandez {
9964261a881SGabriel Fernandez 	int ret;
9974261a881SGabriel Fernandez 
9984261a881SGabriel Fernandez 	disable_power_domain_write_protection();
9994261a881SGabriel Fernandez 
10004261a881SGabriel Fernandez 	ret = clk_gate_ops.enable(hw);
10014261a881SGabriel Fernandez 
10024261a881SGabriel Fernandez 	enable_power_domain_write_protection();
10034261a881SGabriel Fernandez 
10044261a881SGabriel Fernandez 	return ret;
10054261a881SGabriel Fernandez }
10064261a881SGabriel Fernandez 
cclk_gate_disable(struct clk_hw * hw)10074261a881SGabriel Fernandez static void cclk_gate_disable(struct clk_hw *hw)
10084261a881SGabriel Fernandez {
10094261a881SGabriel Fernandez 	disable_power_domain_write_protection();
10104261a881SGabriel Fernandez 
10114261a881SGabriel Fernandez 	clk_gate_ops.disable(hw);
10124261a881SGabriel Fernandez 
10134261a881SGabriel Fernandez 	enable_power_domain_write_protection();
10144261a881SGabriel Fernandez }
10154261a881SGabriel Fernandez 
cclk_gate_is_enabled(struct clk_hw * hw)10164261a881SGabriel Fernandez static int cclk_gate_is_enabled(struct clk_hw *hw)
10174261a881SGabriel Fernandez {
10184261a881SGabriel Fernandez 	return clk_gate_ops.is_enabled(hw);
10194261a881SGabriel Fernandez }
10204261a881SGabriel Fernandez 
10214261a881SGabriel Fernandez static const struct clk_ops cclk_gate_ops = {
10224261a881SGabriel Fernandez 	.enable		= cclk_gate_enable,
10234261a881SGabriel Fernandez 	.disable	= cclk_gate_disable,
10244261a881SGabriel Fernandez 	.is_enabled	= cclk_gate_is_enabled,
10254261a881SGabriel Fernandez };
10264261a881SGabriel Fernandez 
cclk_mux_get_parent(struct clk_hw * hw)10274261a881SGabriel Fernandez static u8 cclk_mux_get_parent(struct clk_hw *hw)
10284261a881SGabriel Fernandez {
10294261a881SGabriel Fernandez 	return clk_mux_ops.get_parent(hw);
10304261a881SGabriel Fernandez }
10314261a881SGabriel Fernandez 
cclk_mux_set_parent(struct clk_hw * hw,u8 index)10324261a881SGabriel Fernandez static int cclk_mux_set_parent(struct clk_hw *hw, u8 index)
10334261a881SGabriel Fernandez {
10344261a881SGabriel Fernandez 	int ret;
10354261a881SGabriel Fernandez 
10364261a881SGabriel Fernandez 	disable_power_domain_write_protection();
10374261a881SGabriel Fernandez 
10384261a881SGabriel Fernandez 	sofware_reset_backup_domain();
10394261a881SGabriel Fernandez 
10404261a881SGabriel Fernandez 	ret = clk_mux_ops.set_parent(hw, index);
10414261a881SGabriel Fernandez 
10424261a881SGabriel Fernandez 	enable_power_domain_write_protection();
10434261a881SGabriel Fernandez 
10444261a881SGabriel Fernandez 	return ret;
10454261a881SGabriel Fernandez }
10464261a881SGabriel Fernandez 
10474261a881SGabriel Fernandez static const struct clk_ops cclk_mux_ops = {
10484261a881SGabriel Fernandez 	.determine_rate = clk_hw_determine_rate_no_reparent,
10494261a881SGabriel Fernandez 	.get_parent = cclk_mux_get_parent,
10504261a881SGabriel Fernandez 	.set_parent = cclk_mux_set_parent,
10514261a881SGabriel Fernandez };
10524261a881SGabriel Fernandez 
stm32_register_cclk(struct device * dev,const char * name,const char * const * parent_names,int num_parents,void __iomem * reg,u8 bit_idx,u8 shift,unsigned long flags,spinlock_t * lock)10534261a881SGabriel Fernandez static struct clk_hw *stm32_register_cclk(struct device *dev, const char *name,
10544261a881SGabriel Fernandez 		const char * const *parent_names, int num_parents,
10554261a881SGabriel Fernandez 		void __iomem *reg, u8 bit_idx, u8 shift, unsigned long flags,
10564261a881SGabriel Fernandez 		spinlock_t *lock)
10574261a881SGabriel Fernandez {
10584261a881SGabriel Fernandez 	struct clk_hw *hw;
10594261a881SGabriel Fernandez 	struct clk_gate *gate;
10604261a881SGabriel Fernandez 	struct clk_mux *mux;
10614261a881SGabriel Fernandez 
10624261a881SGabriel Fernandez 	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
10634261a881SGabriel Fernandez 	if (!gate) {
10644261a881SGabriel Fernandez 		hw = ERR_PTR(-EINVAL);
10654261a881SGabriel Fernandez 		goto fail;
10664261a881SGabriel Fernandez 	}
10674261a881SGabriel Fernandez 
10684261a881SGabriel Fernandez 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
10694261a881SGabriel Fernandez 	if (!mux) {
10704261a881SGabriel Fernandez 		kfree(gate);
10714261a881SGabriel Fernandez 		hw = ERR_PTR(-EINVAL);
10724261a881SGabriel Fernandez 		goto fail;
10734261a881SGabriel Fernandez 	}
10744261a881SGabriel Fernandez 
10754261a881SGabriel Fernandez 	gate->reg = reg;
10764261a881SGabriel Fernandez 	gate->bit_idx = bit_idx;
10774261a881SGabriel Fernandez 	gate->flags = 0;
10784261a881SGabriel Fernandez 	gate->lock = lock;
10794261a881SGabriel Fernandez 
10804261a881SGabriel Fernandez 	mux->reg = reg;
10814261a881SGabriel Fernandez 	mux->shift = shift;
10824261a881SGabriel Fernandez 	mux->mask = 3;
10834261a881SGabriel Fernandez 	mux->flags = 0;
10844261a881SGabriel Fernandez 
10854261a881SGabriel Fernandez 	hw = clk_hw_register_composite(dev, name, parent_names, num_parents,
10864261a881SGabriel Fernandez 			&mux->hw, &cclk_mux_ops,
10874261a881SGabriel Fernandez 			NULL, NULL,
10884261a881SGabriel Fernandez 			&gate->hw, &cclk_gate_ops,
10894261a881SGabriel Fernandez 			flags);
10904261a881SGabriel Fernandez 
10914261a881SGabriel Fernandez 	if (IS_ERR(hw)) {
10924261a881SGabriel Fernandez 		kfree(gate);
10934261a881SGabriel Fernandez 		kfree(mux);
10944261a881SGabriel Fernandez 	}
10954261a881SGabriel Fernandez 
10964261a881SGabriel Fernandez fail:
10974261a881SGabriel Fernandez 	return hw;
10984261a881SGabriel Fernandez }
1099358bdf89SDaniel Thompson 
1100358bdf89SDaniel Thompson static const char *sys_parents[] __initdata =   { "hsi", NULL, "pll" };
1101358bdf89SDaniel Thompson 
1102358bdf89SDaniel Thompson static const struct clk_div_table ahb_div_table[] = {
1103358bdf89SDaniel Thompson 	{ 0x0,   1 }, { 0x1,   1 }, { 0x2,   1 }, { 0x3,   1 },
1104358bdf89SDaniel Thompson 	{ 0x4,   1 }, { 0x5,   1 }, { 0x6,   1 }, { 0x7,   1 },
1105358bdf89SDaniel Thompson 	{ 0x8,   2 }, { 0x9,   4 }, { 0xa,   8 }, { 0xb,  16 },
1106358bdf89SDaniel Thompson 	{ 0xc,  64 }, { 0xd, 128 }, { 0xe, 256 }, { 0xf, 512 },
1107358bdf89SDaniel Thompson 	{ 0 },
1108358bdf89SDaniel Thompson };
1109358bdf89SDaniel Thompson 
1110358bdf89SDaniel Thompson static const struct clk_div_table apb_div_table[] = {
1111358bdf89SDaniel Thompson 	{ 0,  1 }, { 0,  1 }, { 0,  1 }, { 0,  1 },
1112358bdf89SDaniel Thompson 	{ 4,  2 }, { 5,  4 }, { 6,  8 }, { 7, 16 },
1113358bdf89SDaniel Thompson 	{ 0 },
1114358bdf89SDaniel Thompson };
11154261a881SGabriel Fernandez 
11164261a881SGabriel Fernandez static const char *rtc_parents[4] = {
11174261a881SGabriel Fernandez 	"no-clock", "lse", "lsi", "hse-rtc"
11184261a881SGabriel Fernandez };
1119936289f0SGabriel Fernandez 
1120936289f0SGabriel Fernandez static const char *pll_src = "pll-src";
1121936289f0SGabriel Fernandez 
1122936289f0SGabriel Fernandez static const char *pllsrc_parent[2] = { "hsi", NULL };
11232f05b6b9SGabriel Fernandez 
11242f05b6b9SGabriel Fernandez static const char *dsi_parent[2] = { NULL, "pll-r" };
1125daf2d117SGabriel Fernandez 
1126daf2d117SGabriel Fernandez static const char *lcd_parent[1] = { "pllsai-r-div" };
112712696bacSGabriel Fernandez 
112812696bacSGabriel Fernandez static const char *i2s_parents[2] = { "plli2s-r", NULL };
112962710c12SGabriel Fernandez 
113062710c12SGabriel Fernandez static const char *sai_parents[4] = { "pllsai-q-div", "plli2s-q-div", NULL,
113162710c12SGabriel Fernandez 	"no-clock" };
1132844ca23fSGabriel Fernandez 
1133844ca23fSGabriel Fernandez static const char *pll48_parents[2] = { "pll-q", "pllsai-p" };
1134844ca23fSGabriel Fernandez 
1135844ca23fSGabriel Fernandez static const char *sdmux_parents[2] = { "pll48", "sys" };
113688c9b70bSGabriel Fernandez 
113788c9b70bSGabriel Fernandez static const char *hdmi_parents[2] = { "lse", "hsi_div488" };
113888c9b70bSGabriel Fernandez 
113988c9b70bSGabriel Fernandez static const char *spdif_parent[1] = { "plli2s-p" };
114088c9b70bSGabriel Fernandez 
114188c9b70bSGabriel Fernandez static const char *lptim_parent[4] = { "apb1_mul", "lsi", "hsi", "lse" };
114288c9b70bSGabriel Fernandez 
114388c9b70bSGabriel Fernandez static const char *uart_parents1[4] = { "apb2_div", "sys", "hsi", "lse" };
114488c9b70bSGabriel Fernandez static const char *uart_parents2[4] = { "apb1_div", "sys", "hsi", "lse" };
114588c9b70bSGabriel Fernandez 
114688c9b70bSGabriel Fernandez static const char *i2c_parents[4] = { "apb1_div", "sys", "hsi", "no-clock" };
1147936289f0SGabriel Fernandez 
1148936289f0SGabriel Fernandez static const char * const dfsdm1_src[] = { "apb2_div", "sys" };
1149936289f0SGabriel Fernandez static const char * const adsfdm1_parent[] = { "sai1_clk", "sai2_clk" };
1150daf2d117SGabriel Fernandez 
1151daf2d117SGabriel Fernandez struct stm32_aux_clk {
1152daf2d117SGabriel Fernandez 	int idx;
1153daf2d117SGabriel Fernandez 	const char *name;
1154daf2d117SGabriel Fernandez 	const char * const *parent_names;
1155daf2d117SGabriel Fernandez 	int num_parents;
1156daf2d117SGabriel Fernandez 	int offset_mux;
1157daf2d117SGabriel Fernandez 	u8 shift;
1158daf2d117SGabriel Fernandez 	u8 mask;
1159daf2d117SGabriel Fernandez 	int offset_gate;
1160daf2d117SGabriel Fernandez 	u8 bit_idx;
1161daf2d117SGabriel Fernandez 	unsigned long flags;
1162daf2d117SGabriel Fernandez };
1163a064a07fSGabriel Fernandez 
1164a064a07fSGabriel Fernandez struct stm32f4_clk_data {
1165a064a07fSGabriel Fernandez 	const struct stm32f4_gate_data *gates_data;
1166a064a07fSGabriel Fernandez 	const u64 *gates_map;
116783135ad3SGabriel Fernandez 	int gates_num;
1168daf2d117SGabriel Fernandez 	const struct stm32f4_pll_data *pll_data;
1169daf2d117SGabriel Fernandez 	const struct stm32_aux_clk *aux_clk;
117088c9b70bSGabriel Fernandez 	int aux_clk_num;
1171daf2d117SGabriel Fernandez 	int end_primary;
1172daf2d117SGabriel Fernandez };
1173daf2d117SGabriel Fernandez 
1174daf2d117SGabriel Fernandez static const struct stm32_aux_clk stm32f429_aux_clk[] = {
1175daf2d117SGabriel Fernandez 	{
1176daf2d117SGabriel Fernandez 		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
1177daf2d117SGabriel Fernandez 		NO_MUX, 0, 0,
1178daf2d117SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 26,
1179daf2d117SGabriel Fernandez 		CLK_SET_RATE_PARENT
118012696bacSGabriel Fernandez 	},
118112696bacSGabriel Fernandez 	{
118212696bacSGabriel Fernandez 		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
118312696bacSGabriel Fernandez 		STM32F4_RCC_CFGR, 23, 1,
118412696bacSGabriel Fernandez 		NO_GATE, 0,
118512696bacSGabriel Fernandez 		CLK_SET_RATE_PARENT
118662710c12SGabriel Fernandez 	},
118762710c12SGabriel Fernandez 	{
118862710c12SGabriel Fernandez 		CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
118962710c12SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 20, 3,
119062710c12SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 22,
119162710c12SGabriel Fernandez 		CLK_SET_RATE_PARENT
119262710c12SGabriel Fernandez 	},
119362710c12SGabriel Fernandez 	{
119462710c12SGabriel Fernandez 		CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
119562710c12SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 22, 3,
119662710c12SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 22,
119762710c12SGabriel Fernandez 		CLK_SET_RATE_PARENT
1198a064a07fSGabriel Fernandez 	},
1199a064a07fSGabriel Fernandez };
1200844ca23fSGabriel Fernandez 
1201844ca23fSGabriel Fernandez static const struct stm32_aux_clk stm32f469_aux_clk[] = {
1202844ca23fSGabriel Fernandez 	{
1203844ca23fSGabriel Fernandez 		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
1204844ca23fSGabriel Fernandez 		NO_MUX, 0, 0,
1205844ca23fSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 26,
1206844ca23fSGabriel Fernandez 		CLK_SET_RATE_PARENT
1207844ca23fSGabriel Fernandez 	},
1208844ca23fSGabriel Fernandez 	{
1209844ca23fSGabriel Fernandez 		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
1210844ca23fSGabriel Fernandez 		STM32F4_RCC_CFGR, 23, 1,
1211844ca23fSGabriel Fernandez 		NO_GATE, 0,
1212844ca23fSGabriel Fernandez 		CLK_SET_RATE_PARENT
1213844ca23fSGabriel Fernandez 	},
1214844ca23fSGabriel Fernandez 	{
1215844ca23fSGabriel Fernandez 		CLK_SAI1, "sai1-a", sai_parents, ARRAY_SIZE(sai_parents),
1216844ca23fSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 20, 3,
1217844ca23fSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 22,
1218844ca23fSGabriel Fernandez 		CLK_SET_RATE_PARENT
1219844ca23fSGabriel Fernandez 	},
1220844ca23fSGabriel Fernandez 	{
1221844ca23fSGabriel Fernandez 		CLK_SAI2, "sai1-b", sai_parents, ARRAY_SIZE(sai_parents),
1222844ca23fSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 22, 3,
1223844ca23fSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 22,
1224844ca23fSGabriel Fernandez 		CLK_SET_RATE_PARENT
1225844ca23fSGabriel Fernandez 	},
1226844ca23fSGabriel Fernandez 	{
1227844ca23fSGabriel Fernandez 		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
1228844ca23fSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 27, 1,
1229844ca23fSGabriel Fernandez 		NO_GATE, 0,
1230844ca23fSGabriel Fernandez 		0
1231844ca23fSGabriel Fernandez 	},
1232844ca23fSGabriel Fernandez 	{
1233844ca23fSGabriel Fernandez 		NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
1234844ca23fSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 28, 1,
1235844ca23fSGabriel Fernandez 		NO_GATE, 0,
1236844ca23fSGabriel Fernandez 		0
12372f05b6b9SGabriel Fernandez 	},
12382f05b6b9SGabriel Fernandez 	{
12392f05b6b9SGabriel Fernandez 		CLK_F469_DSI, "dsi", dsi_parent, ARRAY_SIZE(dsi_parent),
12402f05b6b9SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 29, 1,
12412f05b6b9SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 27,
12422f05b6b9SGabriel Fernandez 		CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT
1243a064a07fSGabriel Fernandez 	},
1244a064a07fSGabriel Fernandez };
124588c9b70bSGabriel Fernandez 
124688c9b70bSGabriel Fernandez static const struct stm32_aux_clk stm32f746_aux_clk[] = {
124788c9b70bSGabriel Fernandez 	{
124888c9b70bSGabriel Fernandez 		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
124988c9b70bSGabriel Fernandez 		NO_MUX, 0, 0,
125088c9b70bSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 26,
125188c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT
125288c9b70bSGabriel Fernandez 	},
125388c9b70bSGabriel Fernandez 	{
125488c9b70bSGabriel Fernandez 		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
125588c9b70bSGabriel Fernandez 		STM32F4_RCC_CFGR, 23, 1,
125688c9b70bSGabriel Fernandez 		NO_GATE, 0,
125788c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT
125888c9b70bSGabriel Fernandez 	},
125988c9b70bSGabriel Fernandez 	{
126088c9b70bSGabriel Fernandez 		CLK_SAI1, "sai1_clk", sai_parents, ARRAY_SIZE(sai_parents),
126188c9b70bSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 20, 3,
126288c9b70bSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 22,
126388c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT
126488c9b70bSGabriel Fernandez 	},
126588c9b70bSGabriel Fernandez 	{
126688c9b70bSGabriel Fernandez 		CLK_SAI2, "sai2_clk", sai_parents, ARRAY_SIZE(sai_parents),
126788c9b70bSGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 22, 3,
126888c9b70bSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 23,
126988c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT
127088c9b70bSGabriel Fernandez 	},
127188c9b70bSGabriel Fernandez 	{
127288c9b70bSGabriel Fernandez 		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
127388c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 27, 1,
127488c9b70bSGabriel Fernandez 		NO_GATE, 0,
127588c9b70bSGabriel Fernandez 		0
127688c9b70bSGabriel Fernandez 	},
127788c9b70bSGabriel Fernandez 	{
127888c9b70bSGabriel Fernandez 		NO_IDX, "sdmux", sdmux_parents, ARRAY_SIZE(sdmux_parents),
127988c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 28, 1,
128088c9b70bSGabriel Fernandez 		NO_GATE, 0,
128188c9b70bSGabriel Fernandez 		0
128288c9b70bSGabriel Fernandez 	},
128388c9b70bSGabriel Fernandez 	{
128488c9b70bSGabriel Fernandez 		CLK_HDMI_CEC, "hdmi-cec",
128588c9b70bSGabriel Fernandez 		hdmi_parents, ARRAY_SIZE(hdmi_parents),
128688c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 26, 1,
128788c9b70bSGabriel Fernandez 		NO_GATE, 0,
128888c9b70bSGabriel Fernandez 		0
128988c9b70bSGabriel Fernandez 	},
129088c9b70bSGabriel Fernandez 	{
129188c9b70bSGabriel Fernandez 		CLK_SPDIF, "spdif-rx",
129288c9b70bSGabriel Fernandez 		spdif_parent, ARRAY_SIZE(spdif_parent),
129388c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 22, 3,
129488c9b70bSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 23,
129588c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT
129688c9b70bSGabriel Fernandez 	},
129788c9b70bSGabriel Fernandez 	{
129888c9b70bSGabriel Fernandez 		CLK_USART1, "usart1",
129988c9b70bSGabriel Fernandez 		uart_parents1, ARRAY_SIZE(uart_parents1),
130088c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 0, 3,
130188c9b70bSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 4,
130288c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
130388c9b70bSGabriel Fernandez 	},
130488c9b70bSGabriel Fernandez 	{
130588c9b70bSGabriel Fernandez 		CLK_USART2, "usart2",
130688c9b70bSGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
130788c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 2, 3,
130888c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 17,
130988c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
131088c9b70bSGabriel Fernandez 	},
131188c9b70bSGabriel Fernandez 	{
131288c9b70bSGabriel Fernandez 		CLK_USART3, "usart3",
131388c9b70bSGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
131488c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 4, 3,
131588c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 18,
131688c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
131788c9b70bSGabriel Fernandez 	},
131888c9b70bSGabriel Fernandez 	{
131988c9b70bSGabriel Fernandez 		CLK_UART4, "uart4",
132088c9b70bSGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
132188c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 6, 3,
132288c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 19,
132388c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
132488c9b70bSGabriel Fernandez 	},
132588c9b70bSGabriel Fernandez 	{
132688c9b70bSGabriel Fernandez 		CLK_UART5, "uart5",
132788c9b70bSGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
132888c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 8, 3,
132988c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 20,
133088c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
133188c9b70bSGabriel Fernandez 	},
133288c9b70bSGabriel Fernandez 	{
133388c9b70bSGabriel Fernandez 		CLK_USART6, "usart6",
133488c9b70bSGabriel Fernandez 		uart_parents1, ARRAY_SIZE(uart_parents1),
133588c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 10, 3,
133688c9b70bSGabriel Fernandez 		STM32F4_RCC_APB2ENR, 5,
133788c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
133888c9b70bSGabriel Fernandez 	},
133988c9b70bSGabriel Fernandez 
134088c9b70bSGabriel Fernandez 	{
134188c9b70bSGabriel Fernandez 		CLK_UART7, "uart7",
134288c9b70bSGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
134388c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 12, 3,
134488c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 30,
134588c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
134688c9b70bSGabriel Fernandez 	},
134788c9b70bSGabriel Fernandez 	{
134888c9b70bSGabriel Fernandez 		CLK_UART8, "uart8",
134988c9b70bSGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
135088c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 14, 3,
135188c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 31,
135288c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
135388c9b70bSGabriel Fernandez 	},
135488c9b70bSGabriel Fernandez 	{
135588c9b70bSGabriel Fernandez 		CLK_I2C1, "i2c1",
135688c9b70bSGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
135788c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 16, 3,
135888c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 21,
135988c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
136088c9b70bSGabriel Fernandez 	},
136188c9b70bSGabriel Fernandez 	{
136288c9b70bSGabriel Fernandez 		CLK_I2C2, "i2c2",
136388c9b70bSGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
136488c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 18, 3,
136588c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 22,
136688c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
136788c9b70bSGabriel Fernandez 	},
136888c9b70bSGabriel Fernandez 	{
136988c9b70bSGabriel Fernandez 		CLK_I2C3, "i2c3",
137088c9b70bSGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
137188c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 20, 3,
137288c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 23,
137388c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
137488c9b70bSGabriel Fernandez 	},
137588c9b70bSGabriel Fernandez 	{
137688c9b70bSGabriel Fernandez 		CLK_I2C4, "i2c4",
137788c9b70bSGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
137888c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 22, 3,
137988c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 24,
138088c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT,
138188c9b70bSGabriel Fernandez 	},
138288c9b70bSGabriel Fernandez 
138388c9b70bSGabriel Fernandez 	{
138488c9b70bSGabriel Fernandez 		CLK_LPTIMER, "lptim1",
138588c9b70bSGabriel Fernandez 		lptim_parent, ARRAY_SIZE(lptim_parent),
138688c9b70bSGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 24, 3,
138788c9b70bSGabriel Fernandez 		STM32F4_RCC_APB1ENR, 9,
138888c9b70bSGabriel Fernandez 		CLK_SET_RATE_PARENT
138988c9b70bSGabriel Fernandez 	},
139088c9b70bSGabriel Fernandez };
1391936289f0SGabriel Fernandez 
1392936289f0SGabriel Fernandez static const struct stm32_aux_clk stm32f769_aux_clk[] = {
1393936289f0SGabriel Fernandez 	{
1394936289f0SGabriel Fernandez 		CLK_LCD, "lcd-tft", lcd_parent, ARRAY_SIZE(lcd_parent),
1395936289f0SGabriel Fernandez 		NO_MUX, 0, 0,
1396936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 26,
1397936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1398936289f0SGabriel Fernandez 	},
1399936289f0SGabriel Fernandez 	{
1400936289f0SGabriel Fernandez 		CLK_I2S, "i2s", i2s_parents, ARRAY_SIZE(i2s_parents),
1401936289f0SGabriel Fernandez 		STM32F4_RCC_CFGR, 23, 1,
1402936289f0SGabriel Fernandez 		NO_GATE, 0,
1403936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1404936289f0SGabriel Fernandez 	},
1405936289f0SGabriel Fernandez 	{
1406936289f0SGabriel Fernandez 		CLK_SAI1, "sai1_clk", sai_parents, ARRAY_SIZE(sai_parents),
1407936289f0SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 20, 3,
1408936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 22,
1409936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1410936289f0SGabriel Fernandez 	},
1411936289f0SGabriel Fernandez 	{
1412936289f0SGabriel Fernandez 		CLK_SAI2, "sai2_clk", sai_parents, ARRAY_SIZE(sai_parents),
1413936289f0SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 22, 3,
1414936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 23,
1415936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1416936289f0SGabriel Fernandez 	},
1417936289f0SGabriel Fernandez 	{
1418936289f0SGabriel Fernandez 		NO_IDX, "pll48", pll48_parents, ARRAY_SIZE(pll48_parents),
1419936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 27, 1,
1420936289f0SGabriel Fernandez 		NO_GATE, 0,
1421936289f0SGabriel Fernandez 		0
1422936289f0SGabriel Fernandez 	},
1423936289f0SGabriel Fernandez 	{
1424936289f0SGabriel Fernandez 		NO_IDX, "sdmux1", sdmux_parents, ARRAY_SIZE(sdmux_parents),
1425936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 28, 1,
1426936289f0SGabriel Fernandez 		NO_GATE, 0,
1427936289f0SGabriel Fernandez 		0
1428936289f0SGabriel Fernandez 	},
1429936289f0SGabriel Fernandez 	{
1430936289f0SGabriel Fernandez 		NO_IDX, "sdmux2", sdmux_parents, ARRAY_SIZE(sdmux_parents),
1431936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 29, 1,
1432936289f0SGabriel Fernandez 		NO_GATE, 0,
1433936289f0SGabriel Fernandez 		0
1434936289f0SGabriel Fernandez 	},
1435936289f0SGabriel Fernandez 	{
1436936289f0SGabriel Fernandez 		CLK_HDMI_CEC, "hdmi-cec",
1437936289f0SGabriel Fernandez 		hdmi_parents, ARRAY_SIZE(hdmi_parents),
1438936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 26, 1,
1439936289f0SGabriel Fernandez 		NO_GATE, 0,
1440936289f0SGabriel Fernandez 		0
1441936289f0SGabriel Fernandez 	},
1442936289f0SGabriel Fernandez 	{
1443936289f0SGabriel Fernandez 		CLK_SPDIF, "spdif-rx",
1444936289f0SGabriel Fernandez 		spdif_parent, ARRAY_SIZE(spdif_parent),
1445936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 22, 3,
1446936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 23,
1447936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1448936289f0SGabriel Fernandez 	},
1449936289f0SGabriel Fernandez 	{
1450936289f0SGabriel Fernandez 		CLK_USART1, "usart1",
1451936289f0SGabriel Fernandez 		uart_parents1, ARRAY_SIZE(uart_parents1),
1452936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 0, 3,
1453936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 4,
1454936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1455936289f0SGabriel Fernandez 	},
1456936289f0SGabriel Fernandez 	{
1457936289f0SGabriel Fernandez 		CLK_USART2, "usart2",
1458936289f0SGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
1459936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 2, 3,
1460936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 17,
1461936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1462936289f0SGabriel Fernandez 	},
1463936289f0SGabriel Fernandez 	{
1464936289f0SGabriel Fernandez 		CLK_USART3, "usart3",
1465936289f0SGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
1466936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 4, 3,
1467936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 18,
1468936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1469936289f0SGabriel Fernandez 	},
1470936289f0SGabriel Fernandez 	{
1471936289f0SGabriel Fernandez 		CLK_UART4, "uart4",
1472936289f0SGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
1473936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 6, 3,
1474936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 19,
1475936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1476936289f0SGabriel Fernandez 	},
1477936289f0SGabriel Fernandez 	{
1478936289f0SGabriel Fernandez 		CLK_UART5, "uart5",
1479936289f0SGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
1480936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 8, 3,
1481936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 20,
1482936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1483936289f0SGabriel Fernandez 	},
1484936289f0SGabriel Fernandez 	{
1485936289f0SGabriel Fernandez 		CLK_USART6, "usart6",
1486936289f0SGabriel Fernandez 		uart_parents1, ARRAY_SIZE(uart_parents1),
1487936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 10, 3,
1488936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 5,
1489936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1490936289f0SGabriel Fernandez 	},
1491936289f0SGabriel Fernandez 	{
1492936289f0SGabriel Fernandez 		CLK_UART7, "uart7",
1493936289f0SGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
1494936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 12, 3,
1495936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 30,
1496936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1497936289f0SGabriel Fernandez 	},
1498936289f0SGabriel Fernandez 	{
1499936289f0SGabriel Fernandez 		CLK_UART8, "uart8",
1500936289f0SGabriel Fernandez 		uart_parents2, ARRAY_SIZE(uart_parents1),
1501936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 14, 3,
1502936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 31,
1503936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1504936289f0SGabriel Fernandez 	},
1505936289f0SGabriel Fernandez 	{
1506936289f0SGabriel Fernandez 		CLK_I2C1, "i2c1",
1507936289f0SGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
1508936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 16, 3,
1509936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 21,
1510936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1511936289f0SGabriel Fernandez 	},
1512936289f0SGabriel Fernandez 	{
1513936289f0SGabriel Fernandez 		CLK_I2C2, "i2c2",
1514936289f0SGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
1515936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 18, 3,
1516936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 22,
1517936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1518936289f0SGabriel Fernandez 	},
1519936289f0SGabriel Fernandez 	{
1520936289f0SGabriel Fernandez 		CLK_I2C3, "i2c3",
1521936289f0SGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
1522936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 20, 3,
1523936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 23,
1524936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1525936289f0SGabriel Fernandez 	},
1526936289f0SGabriel Fernandez 	{
1527936289f0SGabriel Fernandez 		CLK_I2C4, "i2c4",
1528936289f0SGabriel Fernandez 		i2c_parents, ARRAY_SIZE(i2c_parents),
1529936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 22, 3,
1530936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 24,
1531936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT,
1532936289f0SGabriel Fernandez 	},
1533936289f0SGabriel Fernandez 	{
1534936289f0SGabriel Fernandez 		CLK_LPTIMER, "lptim1",
1535936289f0SGabriel Fernandez 		lptim_parent, ARRAY_SIZE(lptim_parent),
1536936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 24, 3,
1537936289f0SGabriel Fernandez 		STM32F4_RCC_APB1ENR, 9,
1538936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1539936289f0SGabriel Fernandez 	},
1540936289f0SGabriel Fernandez 	{
1541936289f0SGabriel Fernandez 		CLK_F769_DSI, "dsi",
1542936289f0SGabriel Fernandez 		dsi_parent, ARRAY_SIZE(dsi_parent),
1543936289f0SGabriel Fernandez 		STM32F7_RCC_DCKCFGR2, 0, 1,
1544936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 27,
1545936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1546936289f0SGabriel Fernandez 	},
1547936289f0SGabriel Fernandez 	{
1548936289f0SGabriel Fernandez 		CLK_DFSDM1, "dfsdm1",
1549936289f0SGabriel Fernandez 		dfsdm1_src, ARRAY_SIZE(dfsdm1_src),
1550936289f0SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 25, 1,
1551936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 29,
1552936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1553936289f0SGabriel Fernandez 	},
1554936289f0SGabriel Fernandez 	{
1555936289f0SGabriel Fernandez 		CLK_ADFSDM1, "adfsdm1",
1556936289f0SGabriel Fernandez 		adsfdm1_parent, ARRAY_SIZE(adsfdm1_parent),
1557936289f0SGabriel Fernandez 		STM32F4_RCC_DCKCFGR, 26, 1,
1558936289f0SGabriel Fernandez 		STM32F4_RCC_APB2ENR, 29,
1559936289f0SGabriel Fernandez 		CLK_SET_RATE_PARENT
1560936289f0SGabriel Fernandez 	},
1561936289f0SGabriel Fernandez };
1562a064a07fSGabriel Fernandez 
156388c9b70bSGabriel Fernandez static const struct stm32f4_clk_data stm32f429_clk_data = {
1564a064a07fSGabriel Fernandez 	.end_primary	= END_PRIMARY_CLK,
1565a064a07fSGabriel Fernandez 	.gates_data	= stm32f429_gates,
1566a064a07fSGabriel Fernandez 	.gates_map	= stm32f42xx_gate_map,
156783135ad3SGabriel Fernandez 	.gates_num	= ARRAY_SIZE(stm32f429_gates),
1568daf2d117SGabriel Fernandez 	.pll_data	= stm32f429_pll,
1569daf2d117SGabriel Fernandez 	.aux_clk	= stm32f429_aux_clk,
1570a064a07fSGabriel Fernandez 	.aux_clk_num	= ARRAY_SIZE(stm32f429_aux_clk),
1571a064a07fSGabriel Fernandez };
1572a064a07fSGabriel Fernandez 
157388c9b70bSGabriel Fernandez static const struct stm32f4_clk_data stm32f469_clk_data = {
1574a064a07fSGabriel Fernandez 	.end_primary	= END_PRIMARY_CLK,
1575a064a07fSGabriel Fernandez 	.gates_data	= stm32f469_gates,
1576a064a07fSGabriel Fernandez 	.gates_map	= stm32f46xx_gate_map,
157783135ad3SGabriel Fernandez 	.gates_num	= ARRAY_SIZE(stm32f469_gates),
1578844ca23fSGabriel Fernandez 	.pll_data	= stm32f469_pll,
1579844ca23fSGabriel Fernandez 	.aux_clk	= stm32f469_aux_clk,
1580a064a07fSGabriel Fernandez 	.aux_clk_num	= ARRAY_SIZE(stm32f469_aux_clk),
1581a064a07fSGabriel Fernandez };
158288c9b70bSGabriel Fernandez 
158388c9b70bSGabriel Fernandez static const struct stm32f4_clk_data stm32f746_clk_data = {
158488c9b70bSGabriel Fernandez 	.end_primary	= END_PRIMARY_CLK_F7,
158588c9b70bSGabriel Fernandez 	.gates_data	= stm32f746_gates,
158688c9b70bSGabriel Fernandez 	.gates_map	= stm32f746_gate_map,
158788c9b70bSGabriel Fernandez 	.gates_num	= ARRAY_SIZE(stm32f746_gates),
158888c9b70bSGabriel Fernandez 	.pll_data	= stm32f469_pll,
158988c9b70bSGabriel Fernandez 	.aux_clk	= stm32f746_aux_clk,
159088c9b70bSGabriel Fernandez 	.aux_clk_num	= ARRAY_SIZE(stm32f746_aux_clk),
159188c9b70bSGabriel Fernandez };
1592936289f0SGabriel Fernandez 
1593936289f0SGabriel Fernandez static const struct stm32f4_clk_data stm32f769_clk_data = {
1594936289f0SGabriel Fernandez 	.end_primary	= END_PRIMARY_CLK_F7,
1595936289f0SGabriel Fernandez 	.gates_data	= stm32f769_gates,
1596936289f0SGabriel Fernandez 	.gates_map	= stm32f769_gate_map,
1597936289f0SGabriel Fernandez 	.gates_num	= ARRAY_SIZE(stm32f769_gates),
1598936289f0SGabriel Fernandez 	.pll_data	= stm32f469_pll,
1599936289f0SGabriel Fernandez 	.aux_clk	= stm32f769_aux_clk,
1600936289f0SGabriel Fernandez 	.aux_clk_num	= ARRAY_SIZE(stm32f769_aux_clk),
1601936289f0SGabriel Fernandez };
1602a064a07fSGabriel Fernandez 
1603a064a07fSGabriel Fernandez static const struct of_device_id stm32f4_of_match[] = {
1604a064a07fSGabriel Fernandez 	{
1605a064a07fSGabriel Fernandez 		.compatible = "st,stm32f42xx-rcc",
1606a064a07fSGabriel Fernandez 		.data = &stm32f429_clk_data
1607a064a07fSGabriel Fernandez 	},
1608a064a07fSGabriel Fernandez 	{
1609a064a07fSGabriel Fernandez 		.compatible = "st,stm32f469-rcc",
1610a064a07fSGabriel Fernandez 		.data = &stm32f469_clk_data
161188c9b70bSGabriel Fernandez 	},
161288c9b70bSGabriel Fernandez 	{
161388c9b70bSGabriel Fernandez 		.compatible = "st,stm32f746-rcc",
161488c9b70bSGabriel Fernandez 		.data = &stm32f746_clk_data
1615936289f0SGabriel Fernandez 	},
1616936289f0SGabriel Fernandez 	{
1617936289f0SGabriel Fernandez 		.compatible = "st,stm32f769-rcc",
1618936289f0SGabriel Fernandez 		.data = &stm32f769_clk_data
1619a064a07fSGabriel Fernandez 	},
1620a064a07fSGabriel Fernandez 	{}
1621a064a07fSGabriel Fernandez };
1622daf2d117SGabriel Fernandez 
stm32_register_aux_clk(const char * name,const char * const * parent_names,int num_parents,int offset_mux,u8 shift,u8 mask,int offset_gate,u8 bit_idx,unsigned long flags,spinlock_t * lock)1623daf2d117SGabriel Fernandez static struct clk_hw *stm32_register_aux_clk(const char *name,
1624daf2d117SGabriel Fernandez 		const char * const *parent_names, int num_parents,
1625daf2d117SGabriel Fernandez 		int offset_mux, u8 shift, u8 mask,
1626daf2d117SGabriel Fernandez 		int offset_gate, u8 bit_idx,
1627daf2d117SGabriel Fernandez 		unsigned long flags, spinlock_t *lock)
1628daf2d117SGabriel Fernandez {
162989d5dcc4SArnd Bergmann 	struct clk_hw *hw;
1630daf2d117SGabriel Fernandez 	struct clk_gate *gate = NULL;
1631daf2d117SGabriel Fernandez 	struct clk_mux *mux = NULL;
1632daf2d117SGabriel Fernandez 	struct clk_hw *mux_hw = NULL, *gate_hw = NULL;
1633daf2d117SGabriel Fernandez 	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL;
1634daf2d117SGabriel Fernandez 
1635daf2d117SGabriel Fernandez 	if (offset_gate != NO_GATE) {
1636daf2d117SGabriel Fernandez 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
1637daf2d117SGabriel Fernandez 		if (!gate) {
1638daf2d117SGabriel Fernandez 			hw = ERR_PTR(-EINVAL);
1639daf2d117SGabriel Fernandez 			goto fail;
1640daf2d117SGabriel Fernandez 		}
1641daf2d117SGabriel Fernandez 
1642daf2d117SGabriel Fernandez 		gate->reg = base + offset_gate;
1643daf2d117SGabriel Fernandez 		gate->bit_idx = bit_idx;
1644daf2d117SGabriel Fernandez 		gate->flags = 0;
1645daf2d117SGabriel Fernandez 		gate->lock = lock;
1646daf2d117SGabriel Fernandez 		gate_hw = &gate->hw;
1647daf2d117SGabriel Fernandez 		gate_ops = &clk_gate_ops;
1648daf2d117SGabriel Fernandez 	}
1649daf2d117SGabriel Fernandez 
1650daf2d117SGabriel Fernandez 	if (offset_mux != NO_MUX) {
1651daf2d117SGabriel Fernandez 		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
1652daf2d117SGabriel Fernandez 		if (!mux) {
1653daf2d117SGabriel Fernandez 			hw = ERR_PTR(-EINVAL);
1654daf2d117SGabriel Fernandez 			goto fail;
1655daf2d117SGabriel Fernandez 		}
1656daf2d117SGabriel Fernandez 
1657daf2d117SGabriel Fernandez 		mux->reg = base + offset_mux;
1658daf2d117SGabriel Fernandez 		mux->shift = shift;
1659daf2d117SGabriel Fernandez 		mux->mask = mask;
1660daf2d117SGabriel Fernandez 		mux->flags = 0;
1661daf2d117SGabriel Fernandez 		mux_hw = &mux->hw;
1662daf2d117SGabriel Fernandez 		mux_ops = &clk_mux_ops;
1663daf2d117SGabriel Fernandez 	}
166489d5dcc4SArnd Bergmann 
166589d5dcc4SArnd Bergmann 	if (mux_hw == NULL && gate_hw == NULL) {
166689d5dcc4SArnd Bergmann 		hw = ERR_PTR(-EINVAL);
166789d5dcc4SArnd Bergmann 		goto fail;
1668daf2d117SGabriel Fernandez 	}
1669daf2d117SGabriel Fernandez 
1670daf2d117SGabriel Fernandez 	hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
1671daf2d117SGabriel Fernandez 			mux_hw, mux_ops,
1672daf2d117SGabriel Fernandez 			NULL, NULL,
1673daf2d117SGabriel Fernandez 			gate_hw, gate_ops,
1674daf2d117SGabriel Fernandez 			flags);
167589d5dcc4SArnd Bergmann 
1676daf2d117SGabriel Fernandez fail:
1677daf2d117SGabriel Fernandez 	if (IS_ERR(hw)) {
1678daf2d117SGabriel Fernandez 		kfree(gate);
1679daf2d117SGabriel Fernandez 		kfree(mux);
168089d5dcc4SArnd Bergmann 	}
1681daf2d117SGabriel Fernandez 
1682daf2d117SGabriel Fernandez 	return hw;
1683daf2d117SGabriel Fernandez }
1684358bdf89SDaniel Thompson 
stm32f4_rcc_init(struct device_node * np)1685358bdf89SDaniel Thompson static void __init stm32f4_rcc_init(struct device_node *np)
168612696bacSGabriel Fernandez {
1687358bdf89SDaniel Thompson 	const char *hse_clk, *i2s_in_clk;
1688a064a07fSGabriel Fernandez 	int n;
1689a064a07fSGabriel Fernandez 	const struct of_device_id *match;
169083135ad3SGabriel Fernandez 	const struct stm32f4_clk_data *data;
1691936289f0SGabriel Fernandez 	unsigned long pllm;
1692358bdf89SDaniel Thompson 	struct clk_hw *pll_src_hw;
1693358bdf89SDaniel Thompson 
1694358bdf89SDaniel Thompson 	base = of_iomap(np, 0);
1695e665f029SRob Herring 	if (!base) {
1696358bdf89SDaniel Thompson 		pr_err("%pOFn: unable to map resource\n", np);
1697358bdf89SDaniel Thompson 		return;
1698358bdf89SDaniel Thompson 	}
1699861adc44SGabriel Fernandez 
1700861adc44SGabriel Fernandez 	pdrm = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
1701861adc44SGabriel Fernandez 	if (IS_ERR(pdrm)) {
1702861adc44SGabriel Fernandez 		pdrm = NULL;
1703861adc44SGabriel Fernandez 		pr_warn("%s: Unable to get syscfg\n", __func__);
1704861adc44SGabriel Fernandez 	}
1705a064a07fSGabriel Fernandez 
1706a064a07fSGabriel Fernandez 	match = of_match_node(stm32f4_of_match, np);
1707a064a07fSGabriel Fernandez 	if (WARN_ON(!match))
1708a064a07fSGabriel Fernandez 		return;
1709a064a07fSGabriel Fernandez 
1710a064a07fSGabriel Fernandez 	data = match->data;
171188c9b70bSGabriel Fernandez 
171288c9b70bSGabriel Fernandez 	stm32fx_end_primary_clk = data->end_primary;
171388c9b70bSGabriel Fernandez 
1714a064a07fSGabriel Fernandez 	clks = kmalloc_array(data->gates_num + stm32fx_end_primary_clk,
1715a064a07fSGabriel Fernandez 			sizeof(*clks), GFP_KERNEL);
1716a064a07fSGabriel Fernandez 	if (!clks)
1717a064a07fSGabriel Fernandez 		goto fail;
1718a064a07fSGabriel Fernandez 
1719a064a07fSGabriel Fernandez 	stm32f4_gate_map = data->gates_map;
1720358bdf89SDaniel Thompson 
17212f05b6b9SGabriel Fernandez 	hse_clk = of_clk_get_parent_name(np, 0);
1722936289f0SGabriel Fernandez 	dsi_parent[0] = hse_clk;
1723358bdf89SDaniel Thompson 	pllsrc_parent[1] = hse_clk;
172412696bacSGabriel Fernandez 
172512696bacSGabriel Fernandez 	i2s_in_clk = of_clk_get_parent_name(np, 1);
172612696bacSGabriel Fernandez 
172762710c12SGabriel Fernandez 	i2s_parents[1] = i2s_in_clk;
172812696bacSGabriel Fernandez 	sai_parents[2] = i2s_in_clk;
1729936289f0SGabriel Fernandez 
1730936289f0SGabriel Fernandez 	if (of_device_is_compatible(np, "st,stm32f769-rcc")) {
1731936289f0SGabriel Fernandez 		clk_hw_register_gate(NULL, "dfsdm1_apb", "apb2_div", 0,
1732936289f0SGabriel Fernandez 				     base + STM32F4_RCC_APB2ENR, 29,
1733936289f0SGabriel Fernandez 				     CLK_IGNORE_UNUSED, &stm32f4_clk_lock);
1734936289f0SGabriel Fernandez 		dsi_parent[0] = pll_src;
1735936289f0SGabriel Fernandez 		sai_parents[3] = pll_src;
1736936289f0SGabriel Fernandez 	}
173788c9b70bSGabriel Fernandez 
173888c9b70bSGabriel Fernandez 	clks[CLK_HSI] = clk_hw_register_fixed_rate_with_accuracy(NULL, "hsi",
173988c9b70bSGabriel Fernandez 			NULL, 0, 16000000, 160000);
1740936289f0SGabriel Fernandez 
1741936289f0SGabriel Fernandez 	pll_src_hw = clk_hw_register_mux(NULL, pll_src, pllsrc_parent,
1742936289f0SGabriel Fernandez 					 ARRAY_SIZE(pllsrc_parent), 0,
1743936289f0SGabriel Fernandez 					 base + STM32F4_RCC_PLLCFGR, 22, 1, 0,
174483135ad3SGabriel Fernandez 					 &stm32f4_clk_lock);
1745936289f0SGabriel Fernandez 
1746936289f0SGabriel Fernandez 	pllm = readl(base + STM32F4_RCC_PLLCFGR) & 0x3f;
1747936289f0SGabriel Fernandez 
174883135ad3SGabriel Fernandez 	clk_hw_register_fixed_factor(NULL, "vco_in", pll_src,
174983135ad3SGabriel Fernandez 				     0, 1, pllm);
175083135ad3SGabriel Fernandez 
175183135ad3SGabriel Fernandez 	stm32f4_rcc_register_pll("vco_in", &data->pll_data[0],
175283135ad3SGabriel Fernandez 			&stm32f4_clk_lock);
175383135ad3SGabriel Fernandez 
175483135ad3SGabriel Fernandez 	clks[PLL_VCO_I2S] = stm32f4_rcc_register_pll("vco_in",
175583135ad3SGabriel Fernandez 			&data->pll_data[1], &stm32f4_clk_lock);
175683135ad3SGabriel Fernandez 
175783135ad3SGabriel Fernandez 	clks[PLL_VCO_SAI] = stm32f4_rcc_register_pll("vco_in",
1758358bdf89SDaniel Thompson 			&data->pll_data[2], &stm32f4_clk_lock);
1759517633efSGabriel Fernandez 
1760517633efSGabriel Fernandez 	for (n = 0; n < MAX_POST_DIV; n++) {
1761517633efSGabriel Fernandez 		const struct stm32f4_pll_post_div_data *post_div;
1762517633efSGabriel Fernandez 		struct clk_hw *hw;
1763517633efSGabriel Fernandez 
1764517633efSGabriel Fernandez 		post_div = &post_div_data[n];
1765517633efSGabriel Fernandez 
1766517633efSGabriel Fernandez 		hw = clk_register_pll_div(post_div->name,
1767517633efSGabriel Fernandez 				post_div->parent,
1768517633efSGabriel Fernandez 				post_div->flag,
1769517633efSGabriel Fernandez 				base + post_div->offset,
1770517633efSGabriel Fernandez 				post_div->shift,
1771517633efSGabriel Fernandez 				post_div->width,
1772517633efSGabriel Fernandez 				post_div->flag_div,
177324b5b197SDario Binacchi 				post_div->div_table,
1774517633efSGabriel Fernandez 				clks[post_div->pll_idx],
1775517633efSGabriel Fernandez 				&stm32f4_clk_lock);
1776517633efSGabriel Fernandez 
1777517633efSGabriel Fernandez 		if (post_div->idx != NO_IDX)
1778517633efSGabriel Fernandez 			clks[post_div->idx] = hw;
1779358bdf89SDaniel Thompson 	}
1780358bdf89SDaniel Thompson 
178188c9b70bSGabriel Fernandez 	sys_parents[1] = hse_clk;
178288c9b70bSGabriel Fernandez 
1783358bdf89SDaniel Thompson 	clks[CLK_SYSCLK] = clk_hw_register_mux_table(
1784358bdf89SDaniel Thompson 	    NULL, "sys", sys_parents, ARRAY_SIZE(sys_parents), 0,
1785358bdf89SDaniel Thompson 	    base + STM32F4_RCC_CFGR, 0, 3, 0, NULL, &stm32f4_clk_lock);
1786358bdf89SDaniel Thompson 
1787358bdf89SDaniel Thompson 	clk_register_divider_table(NULL, "ahb_div", "sys",
1788358bdf89SDaniel Thompson 				   CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
1789358bdf89SDaniel Thompson 				   4, 4, 0, ahb_div_table, &stm32f4_clk_lock);
1790358bdf89SDaniel Thompson 
1791358bdf89SDaniel Thompson 	clk_register_divider_table(NULL, "apb1_div", "ahb_div",
1792358bdf89SDaniel Thompson 				   CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
1793358bdf89SDaniel Thompson 				   10, 3, 0, apb_div_table, &stm32f4_clk_lock);
1794358bdf89SDaniel Thompson 	clk_register_apb_mul(NULL, "apb1_mul", "apb1_div",
1795358bdf89SDaniel Thompson 			     CLK_SET_RATE_PARENT, 12);
1796358bdf89SDaniel Thompson 
1797358bdf89SDaniel Thompson 	clk_register_divider_table(NULL, "apb2_div", "ahb_div",
1798358bdf89SDaniel Thompson 				   CLK_SET_RATE_PARENT, base + STM32F4_RCC_CFGR,
1799358bdf89SDaniel Thompson 				   13, 3, 0, apb_div_table, &stm32f4_clk_lock);
1800358bdf89SDaniel Thompson 	clk_register_apb_mul(NULL, "apb2_mul", "apb2_div",
1801358bdf89SDaniel Thompson 			     CLK_SET_RATE_PARENT, 15);
18024e950d1eSStephen Boyd 
1803358bdf89SDaniel Thompson 	clks[SYSTICK] = clk_hw_register_fixed_factor(NULL, "systick", "ahb_div",
18044e950d1eSStephen Boyd 						  0, 1, 8);
1805358bdf89SDaniel Thompson 	clks[FCLK] = clk_hw_register_fixed_factor(NULL, "fclk", "ahb_div",
1806358bdf89SDaniel Thompson 					       0, 1, 1);
1807a064a07fSGabriel Fernandez 
1808a064a07fSGabriel Fernandez 	for (n = 0; n < data->gates_num; n++) {
1809a064a07fSGabriel Fernandez 		const struct stm32f4_gate_data *gd;
1810a064a07fSGabriel Fernandez 		unsigned int secondary;
1811a064a07fSGabriel Fernandez 		int idx;
1812a064a07fSGabriel Fernandez 
1813a064a07fSGabriel Fernandez 		gd = &data->gates_data[n];
1814a064a07fSGabriel Fernandez 		secondary = 8 * (gd->offset - STM32F4_RCC_AHB1ENR) +
1815a064a07fSGabriel Fernandez 			gd->bit_idx;
1816358bdf89SDaniel Thompson 		idx = stm32f4_rcc_lookup_clk_idx(0, secondary);
1817358bdf89SDaniel Thompson 
1818358bdf89SDaniel Thompson 		if (idx < 0)
1819358bdf89SDaniel Thompson 			goto fail;
18204e950d1eSStephen Boyd 
1821358bdf89SDaniel Thompson 		clks[idx] = clk_hw_register_gate(
1822358bdf89SDaniel Thompson 		    NULL, gd->name, gd->parent_name, gd->flags,
1823358bdf89SDaniel Thompson 		    base + gd->offset, gd->bit_idx, 0, &stm32f4_clk_lock);
1824334e125bSChristophe JAILLET 
182516673931SRob Herring 		if (IS_ERR(clks[idx])) {
182616673931SRob Herring 			pr_err("%pOF: Unable to register leaf clock %s\n",
1827358bdf89SDaniel Thompson 			       np, gd->name);
1828358bdf89SDaniel Thompson 			goto fail;
1829358bdf89SDaniel Thompson 		}
1830358bdf89SDaniel Thompson 	}
1831861adc44SGabriel Fernandez 
1832ac03d8b3SGabriel Fernandez 	clks[CLK_LSI] = clk_register_rgate(NULL, "lsi", "clk-lsi", 0,
1833861adc44SGabriel Fernandez 			base + STM32F4_RCC_CSR, 0, 1, 0, &stm32f4_clk_lock);
1834861adc44SGabriel Fernandez 
1835861adc44SGabriel Fernandez 	if (IS_ERR(clks[CLK_LSI])) {
1836861adc44SGabriel Fernandez 		pr_err("Unable to register lsi clock\n");
1837861adc44SGabriel Fernandez 		goto fail;
1838861adc44SGabriel Fernandez 	}
1839861adc44SGabriel Fernandez 
1840ac03d8b3SGabriel Fernandez 	clks[CLK_LSE] = clk_register_rgate(NULL, "lse", "clk-lse", 0,
1841861adc44SGabriel Fernandez 			base + STM32F4_RCC_BDCR, 0, 1, 0, &stm32f4_clk_lock);
1842861adc44SGabriel Fernandez 
1843861adc44SGabriel Fernandez 	if (IS_ERR(clks[CLK_LSE])) {
1844861adc44SGabriel Fernandez 		pr_err("Unable to register lse clock\n");
1845861adc44SGabriel Fernandez 		goto fail;
1846861adc44SGabriel Fernandez 	}
18474261a881SGabriel Fernandez 
18484261a881SGabriel Fernandez 	clks[CLK_HSE_RTC] = clk_hw_register_divider(NULL, "hse-rtc", "clk-hse",
18494261a881SGabriel Fernandez 			0, base + STM32F4_RCC_CFGR, 16, 5, 0,
18504261a881SGabriel Fernandez 			&stm32f4_clk_lock);
18514261a881SGabriel Fernandez 
18524261a881SGabriel Fernandez 	if (IS_ERR(clks[CLK_HSE_RTC])) {
18534261a881SGabriel Fernandez 		pr_err("Unable to register hse-rtc clock\n");
18544261a881SGabriel Fernandez 		goto fail;
18554261a881SGabriel Fernandez 	}
18564261a881SGabriel Fernandez 
18574261a881SGabriel Fernandez 	clks[CLK_RTC] = stm32_register_cclk(NULL, "rtc", rtc_parents, 4,
18584261a881SGabriel Fernandez 			base + STM32F4_RCC_BDCR, 15, 8, 0, &stm32f4_clk_lock);
18594261a881SGabriel Fernandez 
18604261a881SGabriel Fernandez 	if (IS_ERR(clks[CLK_RTC])) {
18614261a881SGabriel Fernandez 		pr_err("Unable to register rtc clock\n");
18624261a881SGabriel Fernandez 		goto fail;
18634261a881SGabriel Fernandez 	}
1864daf2d117SGabriel Fernandez 
1865daf2d117SGabriel Fernandez 	for (n = 0; n < data->aux_clk_num; n++) {
1866daf2d117SGabriel Fernandez 		const struct stm32_aux_clk *aux_clk;
1867daf2d117SGabriel Fernandez 		struct clk_hw *hw;
1868daf2d117SGabriel Fernandez 
1869daf2d117SGabriel Fernandez 		aux_clk = &data->aux_clk[n];
1870daf2d117SGabriel Fernandez 
1871daf2d117SGabriel Fernandez 		hw = stm32_register_aux_clk(aux_clk->name,
1872daf2d117SGabriel Fernandez 				aux_clk->parent_names, aux_clk->num_parents,
1873daf2d117SGabriel Fernandez 				aux_clk->offset_mux, aux_clk->shift,
1874daf2d117SGabriel Fernandez 				aux_clk->mask, aux_clk->offset_gate,
1875daf2d117SGabriel Fernandez 				aux_clk->bit_idx, aux_clk->flags,
1876daf2d117SGabriel Fernandez 				&stm32f4_clk_lock);
1877daf2d117SGabriel Fernandez 
1878daf2d117SGabriel Fernandez 		if (IS_ERR(hw)) {
1879daf2d117SGabriel Fernandez 			pr_warn("Unable to register %s clk\n", aux_clk->name);
1880daf2d117SGabriel Fernandez 			continue;
1881daf2d117SGabriel Fernandez 		}
1882daf2d117SGabriel Fernandez 
1883daf2d117SGabriel Fernandez 		if (aux_clk->idx != NO_IDX)
1884daf2d117SGabriel Fernandez 			clks[aux_clk->idx] = hw;
1885daf2d117SGabriel Fernandez 	}
1886936289f0SGabriel Fernandez 
188788c9b70bSGabriel Fernandez 	if (of_device_is_compatible(np, "st,stm32f746-rcc")) {
188888c9b70bSGabriel Fernandez 
188988c9b70bSGabriel Fernandez 		clk_hw_register_fixed_factor(NULL, "hsi_div488", "hsi", 0,
189088c9b70bSGabriel Fernandez 				1, 488);
1891936289f0SGabriel Fernandez 
1892936289f0SGabriel Fernandez 		clks[CLK_PLL_SRC] = pll_src_hw;
1893936289f0SGabriel Fernandez 	}
18944e950d1eSStephen Boyd 
1895936289f0SGabriel Fernandez 	of_clk_add_hw_provider(np, stm32f4_rcc_lookup_clk, NULL);
1896358bdf89SDaniel Thompson 
1897358bdf89SDaniel Thompson 	return;
1898a064a07fSGabriel Fernandez fail:
1899358bdf89SDaniel Thompson 	kfree(clks);
1900358bdf89SDaniel Thompson 	iounmap(base);
19013868f132SGabriel Fernandez }
19023868f132SGabriel Fernandez CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init);
190388c9b70bSGabriel Fernandez CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init);
1904936289f0SGabriel Fernandez CLK_OF_DECLARE_DRIVER(stm32f746_rcc, "st,stm32f746-rcc", stm32f4_rcc_init);
1905 CLK_OF_DECLARE_DRIVER(stm32f769_rcc, "st,stm32f769-rcc", stm32f4_rcc_init);
1906