Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: at91: sama7g5: add clock support for sama7g5

Add clock support for SAMA7G5.

Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Link: https://lore.kernel.org/r/1595403506-8209-19-git-send-email-claudiu.beznea@microchip.com
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Claudiu Beznea and committed by
Stephen Boyd
cb783bbb ef396df9

+1060
+1
drivers/clk/at91/Makefile
··· 23 23 obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o 24 24 obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o 25 25 obj-$(CONFIG_SOC_SAMA5D2) += sama5d2.o 26 + obj-$(CONFIG_SOC_SAMA7G5) += sama7g5.o
+1059
drivers/clk/at91/sama7g5.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * SAMA7G5 PMC code. 4 + * 5 + * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries 6 + * 7 + * Author: Claudiu Beznea <claudiu.beznea@microchip.com> 8 + * 9 + */ 10 + #include <linux/clk.h> 11 + #include <linux/clk-provider.h> 12 + #include <linux/mfd/syscon.h> 13 + #include <linux/slab.h> 14 + 15 + #include <dt-bindings/clock/at91.h> 16 + 17 + #include "pmc.h" 18 + 19 + #define SAMA7G5_INIT_TABLE(_table, _count) \ 20 + do { \ 21 + u8 _i; \ 22 + for (_i = 0; _i < (_count); _i++) \ 23 + (_table)[_i] = _i; \ 24 + } while (0) 25 + 26 + #define SAMA7G5_FILL_TABLE(_to, _from, _count) \ 27 + do { \ 28 + u8 _i; \ 29 + for (_i = 0; _i < (_count); _i++) { \ 30 + (_to)[_i] = (_from)[_i]; \ 31 + } \ 32 + } while (0) 33 + 34 + static DEFINE_SPINLOCK(pmc_pll_lock); 35 + static DEFINE_SPINLOCK(pmc_mckX_lock); 36 + 37 + /** 38 + * PLL clocks identifiers 39 + * @PLL_ID_CPU: CPU PLL identifier 40 + * @PLL_ID_SYS: System PLL identifier 41 + * @PLL_ID_DDR: DDR PLL identifier 42 + * @PLL_ID_IMG: Image subsystem PLL identifier 43 + * @PLL_ID_BAUD: Baud PLL identifier 44 + * @PLL_ID_AUDIO: Audio PLL identifier 45 + * @PLL_ID_ETH: Ethernet PLL identifier 46 + */ 47 + enum pll_ids { 48 + PLL_ID_CPU, 49 + PLL_ID_SYS, 50 + PLL_ID_DDR, 51 + PLL_ID_IMG, 52 + PLL_ID_BAUD, 53 + PLL_ID_AUDIO, 54 + PLL_ID_ETH, 55 + PLL_ID_MAX, 56 + }; 57 + 58 + /** 59 + * PLL type identifiers 60 + * @PLL_TYPE_FRAC: fractional PLL identifier 61 + * @PLL_TYPE_DIV: divider PLL identifier 62 + */ 63 + enum pll_type { 64 + PLL_TYPE_FRAC, 65 + PLL_TYPE_DIV, 66 + }; 67 + 68 + /* Layout for fractional PLLs. */ 69 + static const struct clk_pll_layout pll_layout_frac = { 70 + .mul_mask = GENMASK(31, 24), 71 + .frac_mask = GENMASK(21, 0), 72 + .mul_shift = 24, 73 + .frac_shift = 0, 74 + }; 75 + 76 + /* Layout for DIVPMC dividers. */ 77 + static const struct clk_pll_layout pll_layout_divpmc = { 78 + .div_mask = GENMASK(7, 0), 79 + .endiv_mask = BIT(29), 80 + .div_shift = 0, 81 + .endiv_shift = 29, 82 + }; 83 + 84 + /* Layout for DIVIO dividers. */ 85 + static const struct clk_pll_layout pll_layout_divio = { 86 + .div_mask = GENMASK(19, 12), 87 + .endiv_mask = BIT(30), 88 + .div_shift = 12, 89 + .endiv_shift = 30, 90 + }; 91 + 92 + /** 93 + * PLL clocks description 94 + * @n: clock name 95 + * @p: clock parent 96 + * @l: clock layout 97 + * @t: clock type 98 + * @f: true if clock is critical and cannot be disabled 99 + * @eid: export index in sama7g5->chws[] array 100 + */ 101 + static const struct { 102 + const char *n; 103 + const char *p; 104 + const struct clk_pll_layout *l; 105 + u8 t; 106 + u8 c; 107 + u8 eid; 108 + } sama7g5_plls[][PLL_ID_MAX] = { 109 + [PLL_ID_CPU] = { 110 + { .n = "cpupll_fracck", 111 + .p = "mainck", 112 + .l = &pll_layout_frac, 113 + .t = PLL_TYPE_FRAC, 114 + .c = 1, }, 115 + 116 + { .n = "cpupll_divpmcck", 117 + .p = "cpupll_fracck", 118 + .l = &pll_layout_divpmc, 119 + .t = PLL_TYPE_DIV, 120 + .c = 1, }, 121 + }, 122 + 123 + [PLL_ID_SYS] = { 124 + { .n = "syspll_fracck", 125 + .p = "mainck", 126 + .l = &pll_layout_frac, 127 + .t = PLL_TYPE_FRAC, 128 + .c = 1, }, 129 + 130 + { .n = "syspll_divpmcck", 131 + .p = "syspll_fracck", 132 + .l = &pll_layout_divpmc, 133 + .t = PLL_TYPE_DIV, 134 + .c = 1, }, 135 + }, 136 + 137 + [PLL_ID_DDR] = { 138 + { .n = "ddrpll_fracck", 139 + .p = "mainck", 140 + .l = &pll_layout_frac, 141 + .t = PLL_TYPE_FRAC, 142 + .c = 1, }, 143 + 144 + { .n = "ddrpll_divpmcck", 145 + .p = "ddrpll_fracck", 146 + .l = &pll_layout_divpmc, 147 + .t = PLL_TYPE_DIV, 148 + .c = 1, }, 149 + }, 150 + 151 + [PLL_ID_IMG] = { 152 + { .n = "imgpll_fracck", 153 + .p = "mainck", 154 + .l = &pll_layout_frac, 155 + .t = PLL_TYPE_FRAC, }, 156 + 157 + { .n = "imgpll_divpmcck", 158 + .p = "imgpll_fracck", 159 + .l = &pll_layout_divpmc, 160 + .t = PLL_TYPE_DIV, }, 161 + }, 162 + 163 + [PLL_ID_BAUD] = { 164 + { .n = "baudpll_fracck", 165 + .p = "mainck", 166 + .l = &pll_layout_frac, 167 + .t = PLL_TYPE_FRAC, }, 168 + 169 + { .n = "baudpll_divpmcck", 170 + .p = "baudpll_fracck", 171 + .l = &pll_layout_divpmc, 172 + .t = PLL_TYPE_DIV, }, 173 + }, 174 + 175 + [PLL_ID_AUDIO] = { 176 + { .n = "audiopll_fracck", 177 + .p = "main_xtal", 178 + .l = &pll_layout_frac, 179 + .t = PLL_TYPE_FRAC, }, 180 + 181 + { .n = "audiopll_divpmcck", 182 + .p = "audiopll_fracck", 183 + .l = &pll_layout_divpmc, 184 + .t = PLL_TYPE_DIV, 185 + .eid = PMC_I2S0_MUX, }, 186 + 187 + { .n = "audiopll_diviock", 188 + .p = "audiopll_fracck", 189 + .l = &pll_layout_divio, 190 + .t = PLL_TYPE_DIV, 191 + .eid = PMC_I2S1_MUX, }, 192 + }, 193 + 194 + [PLL_ID_ETH] = { 195 + { .n = "ethpll_fracck", 196 + .p = "main_xtal", 197 + .l = &pll_layout_frac, 198 + .t = PLL_TYPE_FRAC, }, 199 + 200 + { .n = "ethpll_divpmcck", 201 + .p = "ethpll_fracck", 202 + .l = &pll_layout_divpmc, 203 + .t = PLL_TYPE_DIV, }, 204 + }, 205 + }; 206 + 207 + /** 208 + * Master clock (MCK[1..4]) description 209 + * @n: clock name 210 + * @ep: extra parents names array 211 + * @ep_chg_chg_id: index in parents array that specifies the changeable 212 + * parent 213 + * @ep_count: extra parents count 214 + * @ep_mux_table: mux table for extra parents 215 + * @id: clock id 216 + * @c: true if clock is critical and cannot be disabled 217 + */ 218 + static const struct { 219 + const char *n; 220 + const char *ep[4]; 221 + int ep_chg_id; 222 + u8 ep_count; 223 + u8 ep_mux_table[4]; 224 + u8 id; 225 + u8 c; 226 + } sama7g5_mckx[] = { 227 + { .n = "mck1", 228 + .id = 1, 229 + .ep = { "syspll_divpmcck", }, 230 + .ep_mux_table = { 5, }, 231 + .ep_count = 1, 232 + .ep_chg_id = INT_MIN, 233 + .c = 1, }, 234 + 235 + { .n = "mck2", 236 + .id = 2, 237 + .ep = { "ddrpll_divpmcck", }, 238 + .ep_mux_table = { 6, }, 239 + .ep_count = 1, 240 + .ep_chg_id = INT_MIN, 241 + .c = 1, }, 242 + 243 + { .n = "mck3", 244 + .id = 3, 245 + .ep = { "syspll_divpmcck", "ddrpll_divpmcck", "imgpll_divpmcck", }, 246 + .ep_mux_table = { 5, 6, 7, }, 247 + .ep_count = 3, 248 + .ep_chg_id = 6, }, 249 + 250 + { .n = "mck4", 251 + .id = 4, 252 + .ep = { "syspll_divpmcck", }, 253 + .ep_mux_table = { 5, }, 254 + .ep_count = 1, 255 + .ep_chg_id = INT_MIN, 256 + .c = 1, }, 257 + }; 258 + 259 + /** 260 + * System clock description 261 + * @n: clock name 262 + * @p: clock parent name 263 + * @id: clock id 264 + */ 265 + static const struct { 266 + const char *n; 267 + const char *p; 268 + u8 id; 269 + } sama7g5_systemck[] = { 270 + { .n = "pck0", .p = "prog0", .id = 8, }, 271 + { .n = "pck1", .p = "prog1", .id = 9, }, 272 + { .n = "pck2", .p = "prog2", .id = 10, }, 273 + { .n = "pck3", .p = "prog3", .id = 11, }, 274 + { .n = "pck4", .p = "prog4", .id = 12, }, 275 + { .n = "pck5", .p = "prog5", .id = 13, }, 276 + { .n = "pck6", .p = "prog6", .id = 14, }, 277 + { .n = "pck7", .p = "prog7", .id = 15, }, 278 + }; 279 + 280 + /* Mux table for programmable clocks. */ 281 + static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, }; 282 + 283 + /** 284 + * Peripheral clock description 285 + * @n: clock name 286 + * @p: clock parent name 287 + * @r: clock range values 288 + * @id: clock id 289 + * @chgp: index in parent array of the changeable parent 290 + */ 291 + static const struct { 292 + const char *n; 293 + const char *p; 294 + struct clk_range r; 295 + u8 chgp; 296 + u8 id; 297 + } sama7g5_periphck[] = { 298 + { .n = "pioA_clk", .p = "mck0", .id = 11, }, 299 + { .n = "sfr_clk", .p = "mck1", .id = 19, }, 300 + { .n = "hsmc_clk", .p = "mck1", .id = 21, }, 301 + { .n = "xdmac0_clk", .p = "mck1", .id = 22, }, 302 + { .n = "xdmac1_clk", .p = "mck1", .id = 23, }, 303 + { .n = "xdmac2_clk", .p = "mck1", .id = 24, }, 304 + { .n = "acc_clk", .p = "mck1", .id = 25, }, 305 + { .n = "aes_clk", .p = "mck1", .id = 27, }, 306 + { .n = "tzaesbasc_clk", .p = "mck1", .id = 28, }, 307 + { .n = "asrc_clk", .p = "mck1", .id = 30, .r = { .max = 200000000, }, }, 308 + { .n = "cpkcc_clk", .p = "mck0", .id = 32, }, 309 + { .n = "csi_clk", .p = "mck3", .id = 33, .r = { .max = 266000000, }, .chgp = 1, }, 310 + { .n = "csi2dc_clk", .p = "mck3", .id = 34, .r = { .max = 266000000, }, .chgp = 1, }, 311 + { .n = "eic_clk", .p = "mck1", .id = 37, }, 312 + { .n = "flex0_clk", .p = "mck1", .id = 38, }, 313 + { .n = "flex1_clk", .p = "mck1", .id = 39, }, 314 + { .n = "flex2_clk", .p = "mck1", .id = 40, }, 315 + { .n = "flex3_clk", .p = "mck1", .id = 41, }, 316 + { .n = "flex4_clk", .p = "mck1", .id = 42, }, 317 + { .n = "flex5_clk", .p = "mck1", .id = 43, }, 318 + { .n = "flex6_clk", .p = "mck1", .id = 44, }, 319 + { .n = "flex7_clk", .p = "mck1", .id = 45, }, 320 + { .n = "flex8_clk", .p = "mck1", .id = 46, }, 321 + { .n = "flex9_clk", .p = "mck1", .id = 47, }, 322 + { .n = "flex10_clk", .p = "mck1", .id = 48, }, 323 + { .n = "flex11_clk", .p = "mck1", .id = 49, }, 324 + { .n = "gmac0_clk", .p = "mck1", .id = 51, }, 325 + { .n = "gmac1_clk", .p = "mck1", .id = 52, }, 326 + { .n = "icm_clk", .p = "mck1", .id = 55, }, 327 + { .n = "isc_clk", .p = "mck3", .id = 56, .r = { .max = 266000000, }, .chgp = 1, }, 328 + { .n = "i2smcc0_clk", .p = "mck1", .id = 57, .r = { .max = 200000000, }, }, 329 + { .n = "i2smcc1_clk", .p = "mck1", .id = 58, .r = { .max = 200000000, }, }, 330 + { .n = "matrix_clk", .p = "mck1", .id = 60, }, 331 + { .n = "mcan0_clk", .p = "mck1", .id = 61, .r = { .max = 200000000, }, }, 332 + { .n = "mcan1_clk", .p = "mck1", .id = 62, .r = { .max = 200000000, }, }, 333 + { .n = "mcan2_clk", .p = "mck1", .id = 63, .r = { .max = 200000000, }, }, 334 + { .n = "mcan3_clk", .p = "mck1", .id = 64, .r = { .max = 200000000, }, }, 335 + { .n = "mcan4_clk", .p = "mck1", .id = 65, .r = { .max = 200000000, }, }, 336 + { .n = "mcan5_clk", .p = "mck1", .id = 66, .r = { .max = 200000000, }, }, 337 + { .n = "pdmc0_clk", .p = "mck1", .id = 68, .r = { .max = 200000000, }, }, 338 + { .n = "pdmc1_clk", .p = "mck1", .id = 69, .r = { .max = 200000000, }, }, 339 + { .n = "pit64b0_clk", .p = "mck1", .id = 70, }, 340 + { .n = "pit64b1_clk", .p = "mck1", .id = 71, }, 341 + { .n = "pit64b2_clk", .p = "mck1", .id = 72, }, 342 + { .n = "pit64b3_clk", .p = "mck1", .id = 73, }, 343 + { .n = "pit64b4_clk", .p = "mck1", .id = 74, }, 344 + { .n = "pit64b5_clk", .p = "mck1", .id = 75, }, 345 + { .n = "pwm_clk", .p = "mck1", .id = 77, }, 346 + { .n = "qspi0_clk", .p = "mck1", .id = 78, }, 347 + { .n = "qspi1_clk", .p = "mck1", .id = 79, }, 348 + { .n = "sdmmc0_clk", .p = "mck1", .id = 80, }, 349 + { .n = "sdmmc1_clk", .p = "mck1", .id = 81, }, 350 + { .n = "sdmmc2_clk", .p = "mck1", .id = 82, }, 351 + { .n = "sha_clk", .p = "mck1", .id = 83, }, 352 + { .n = "spdifrx_clk", .p = "mck1", .id = 84, .r = { .max = 200000000, }, }, 353 + { .n = "spdiftx_clk", .p = "mck1", .id = 85, .r = { .max = 200000000, }, }, 354 + { .n = "ssc0_clk", .p = "mck1", .id = 86, .r = { .max = 200000000, }, }, 355 + { .n = "ssc1_clk", .p = "mck1", .id = 87, .r = { .max = 200000000, }, }, 356 + { .n = "tcb0_ch0_clk", .p = "mck1", .id = 88, .r = { .max = 200000000, }, }, 357 + { .n = "tcb0_ch1_clk", .p = "mck1", .id = 89, .r = { .max = 200000000, }, }, 358 + { .n = "tcb0_ch2_clk", .p = "mck1", .id = 90, .r = { .max = 200000000, }, }, 359 + { .n = "tcb1_ch0_clk", .p = "mck1", .id = 91, .r = { .max = 200000000, }, }, 360 + { .n = "tcb1_ch1_clk", .p = "mck1", .id = 92, .r = { .max = 200000000, }, }, 361 + { .n = "tcb1_ch2_clk", .p = "mck1", .id = 93, .r = { .max = 200000000, }, }, 362 + { .n = "tcpca_clk", .p = "mck1", .id = 94, }, 363 + { .n = "tcpcb_clk", .p = "mck1", .id = 95, }, 364 + { .n = "tdes_clk", .p = "mck1", .id = 96, }, 365 + { .n = "trng_clk", .p = "mck1", .id = 97, }, 366 + { .n = "udphsa_clk", .p = "mck1", .id = 104, }, 367 + { .n = "udphsb_clk", .p = "mck1", .id = 105, }, 368 + { .n = "uhphs_clk", .p = "mck1", .id = 106, }, 369 + }; 370 + 371 + /** 372 + * Generic clock description 373 + * @n: clock name 374 + * @pp: PLL parents 375 + * @pp_mux_table: PLL parents mux table 376 + * @r: clock output range 377 + * @pp_chg_id: id in parrent array of changeable PLL parent 378 + * @pp_count: PLL parents count 379 + * @id: clock id 380 + */ 381 + static const struct { 382 + const char *n; 383 + const char *pp[8]; 384 + const char pp_mux_table[8]; 385 + struct clk_range r; 386 + int pp_chg_id; 387 + u8 pp_count; 388 + u8 id; 389 + } sama7g5_gck[] = { 390 + { .n = "adc_gclk", 391 + .id = 26, 392 + .r = { .max = 100000000, }, 393 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "audiopll_divpmcck", }, 394 + .pp_mux_table = { 5, 7, 9, }, 395 + .pp_count = 3, 396 + .pp_chg_id = INT_MIN, }, 397 + 398 + { .n = "asrc_gclk", 399 + .id = 30, 400 + .r = { .max = 200000000 }, 401 + .pp = { "audiopll_divpmcck", }, 402 + .pp_mux_table = { 9, }, 403 + .pp_count = 1, 404 + .pp_chg_id = 4, }, 405 + 406 + { .n = "csi_gclk", 407 + .id = 33, 408 + .r = { .max = 27000000 }, 409 + .pp = { "ddrpll_divpmcck", "imgpll_divpmcck", }, 410 + .pp_mux_table = { 6, 7, }, 411 + .pp_count = 2, 412 + .pp_chg_id = INT_MIN, }, 413 + 414 + { .n = "flex0_gclk", 415 + .id = 38, 416 + .r = { .max = 200000000 }, 417 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 418 + .pp_mux_table = { 5, 8, }, 419 + .pp_count = 2, 420 + .pp_chg_id = INT_MIN, }, 421 + 422 + { .n = "flex1_gclk", 423 + .id = 39, 424 + .r = { .max = 200000000 }, 425 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 426 + .pp_mux_table = { 5, 8, }, 427 + .pp_count = 2, 428 + .pp_chg_id = INT_MIN, }, 429 + 430 + { .n = "flex2_gclk", 431 + .id = 40, 432 + .r = { .max = 200000000 }, 433 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 434 + .pp_mux_table = { 5, 8, }, 435 + .pp_count = 2, 436 + .pp_chg_id = INT_MIN, }, 437 + 438 + { .n = "flex3_gclk", 439 + .id = 41, 440 + .r = { .max = 200000000 }, 441 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 442 + .pp_mux_table = { 5, 8, }, 443 + .pp_count = 2, 444 + .pp_chg_id = INT_MIN, }, 445 + 446 + { .n = "flex4_gclk", 447 + .id = 42, 448 + .r = { .max = 200000000 }, 449 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 450 + .pp_mux_table = { 5, 8, }, 451 + .pp_count = 2, 452 + .pp_chg_id = INT_MIN, }, 453 + 454 + { .n = "flex5_gclk", 455 + .id = 43, 456 + .r = { .max = 200000000 }, 457 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 458 + .pp_mux_table = { 5, 8, }, 459 + .pp_count = 2, 460 + .pp_chg_id = INT_MIN, }, 461 + 462 + { .n = "flex6_gclk", 463 + .id = 44, 464 + .r = { .max = 200000000 }, 465 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 466 + .pp_mux_table = { 5, 8, }, 467 + .pp_count = 2, 468 + .pp_chg_id = INT_MIN, }, 469 + 470 + { .n = "flex7_gclk", 471 + .id = 45, 472 + .r = { .max = 200000000 }, 473 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 474 + .pp_mux_table = { 5, 8, }, 475 + .pp_count = 2, 476 + .pp_chg_id = INT_MIN, }, 477 + 478 + { .n = "flex8_gclk", 479 + .id = 46, 480 + .r = { .max = 200000000 }, 481 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 482 + .pp_mux_table = { 5, 8, }, 483 + .pp_count = 2, 484 + .pp_chg_id = INT_MIN, }, 485 + 486 + { .n = "flex9_gclk", 487 + .id = 47, 488 + .r = { .max = 200000000 }, 489 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 490 + .pp_mux_table = { 5, 8, }, 491 + .pp_count = 2, 492 + .pp_chg_id = INT_MIN, }, 493 + 494 + { .n = "flex10_gclk", 495 + .id = 48, 496 + .r = { .max = 200000000 }, 497 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 498 + .pp_mux_table = { 5, 8, }, 499 + .pp_count = 2, 500 + .pp_chg_id = INT_MIN, }, 501 + 502 + { .n = "flex11_gclk", 503 + .id = 49, 504 + .r = { .max = 200000000 }, 505 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 506 + .pp_mux_table = { 5, 8, }, 507 + .pp_count = 2, 508 + .pp_chg_id = INT_MIN, }, 509 + 510 + { .n = "gmac0_gclk", 511 + .id = 51, 512 + .r = { .max = 125000000 }, 513 + .pp = { "ethpll_divpmcck", }, 514 + .pp_mux_table = { 10, }, 515 + .pp_count = 1, 516 + .pp_chg_id = 4, }, 517 + 518 + { .n = "gmac1_gclk", 519 + .id = 52, 520 + .r = { .max = 50000000 }, 521 + .pp = { "ethpll_divpmcck", }, 522 + .pp_mux_table = { 10, }, 523 + .pp_count = 1, 524 + .pp_chg_id = INT_MIN, }, 525 + 526 + { .n = "gmac0_tsu_gclk", 527 + .id = 53, 528 + .r = { .max = 300000000 }, 529 + .pp = { "audiopll_divpmcck", "ethpll_divpmcck", }, 530 + .pp_mux_table = { 9, 10, }, 531 + .pp_count = 2, 532 + .pp_chg_id = INT_MIN, }, 533 + 534 + { .n = "gmac1_tsu_gclk", 535 + .id = 54, 536 + .r = { .max = 300000000 }, 537 + .pp = { "audiopll_divpmcck", "ethpll_divpmcck", }, 538 + .pp_mux_table = { 9, 10, }, 539 + .pp_count = 2, 540 + .pp_chg_id = INT_MIN, }, 541 + 542 + { .n = "i2smcc0_gclk", 543 + .id = 57, 544 + .r = { .max = 100000000 }, 545 + .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, 546 + .pp_mux_table = { 5, 9, }, 547 + .pp_count = 2, 548 + .pp_chg_id = 5, }, 549 + 550 + { .n = "i2smcc1_gclk", 551 + .id = 58, 552 + .r = { .max = 100000000 }, 553 + .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, 554 + .pp_mux_table = { 5, 9, }, 555 + .pp_count = 2, 556 + .pp_chg_id = 5, }, 557 + 558 + { .n = "mcan0_gclk", 559 + .id = 61, 560 + .r = { .max = 200000000 }, 561 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 562 + .pp_mux_table = { 5, 8, }, 563 + .pp_count = 2, 564 + .pp_chg_id = INT_MIN, }, 565 + 566 + { .n = "mcan1_gclk", 567 + .id = 62, 568 + .r = { .max = 200000000 }, 569 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 570 + .pp_mux_table = { 5, 8, }, 571 + .pp_count = 2, 572 + .pp_chg_id = INT_MIN, }, 573 + 574 + { .n = "mcan2_gclk", 575 + .id = 63, 576 + .r = { .max = 200000000 }, 577 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 578 + .pp_mux_table = { 5, 8, }, 579 + .pp_count = 2, 580 + .pp_chg_id = INT_MIN, }, 581 + 582 + { .n = "mcan3_gclk", 583 + .id = 64, 584 + .r = { .max = 200000000 }, 585 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 586 + .pp_mux_table = { 5, 8, }, 587 + .pp_count = 2, 588 + .pp_chg_id = INT_MIN, }, 589 + 590 + { .n = "mcan4_gclk", 591 + .id = 65, 592 + .r = { .max = 200000000 }, 593 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 594 + .pp_mux_table = { 5, 8, }, 595 + .pp_count = 2, 596 + .pp_chg_id = INT_MIN, }, 597 + 598 + { .n = "mcan5_gclk", 599 + .id = 66, 600 + .r = { .max = 200000000 }, 601 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 602 + .pp_mux_table = { 5, 8, }, 603 + .pp_count = 2, 604 + .pp_chg_id = INT_MIN, }, 605 + 606 + { .n = "pdmc0_gclk", 607 + .id = 68, 608 + .r = { .max = 50000000 }, 609 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 610 + .pp_mux_table = { 5, 8, }, 611 + .pp_count = 2, 612 + .pp_chg_id = INT_MIN, }, 613 + 614 + { .n = "pdmc1_gclk", 615 + .id = 69, 616 + .r = { .max = 50000000, }, 617 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 618 + .pp_mux_table = { 5, 8, }, 619 + .pp_count = 2, 620 + .pp_chg_id = INT_MIN, }, 621 + 622 + { .n = "pit64b0_gclk", 623 + .id = 70, 624 + .r = { .max = 200000000 }, 625 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 626 + "audiopll_divpmcck", "ethpll_divpmcck", }, 627 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 628 + .pp_count = 5, 629 + .pp_chg_id = INT_MIN, }, 630 + 631 + { .n = "pit64b1_gclk", 632 + .id = 71, 633 + .r = { .max = 200000000 }, 634 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 635 + "audiopll_divpmcck", "ethpll_divpmcck", }, 636 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 637 + .pp_count = 5, 638 + .pp_chg_id = INT_MIN, }, 639 + 640 + { .n = "pit64b2_gclk", 641 + .id = 72, 642 + .r = { .max = 200000000 }, 643 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 644 + "audiopll_divpmcck", "ethpll_divpmcck", }, 645 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 646 + .pp_count = 5, 647 + .pp_chg_id = INT_MIN, }, 648 + 649 + { .n = "pit64b3_gclk", 650 + .id = 73, 651 + .r = { .max = 200000000 }, 652 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 653 + "audiopll_divpmcck", "ethpll_divpmcck", }, 654 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 655 + .pp_count = 5, 656 + .pp_chg_id = INT_MIN, }, 657 + 658 + { .n = "pit64b4_gclk", 659 + .id = 74, 660 + .r = { .max = 200000000 }, 661 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 662 + "audiopll_divpmcck", "ethpll_divpmcck", }, 663 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 664 + .pp_count = 5, 665 + .pp_chg_id = INT_MIN, }, 666 + 667 + { .n = "pit64b5_gclk", 668 + .id = 75, 669 + .r = { .max = 200000000 }, 670 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 671 + "audiopll_divpmcck", "ethpll_divpmcck", }, 672 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 673 + .pp_count = 5, 674 + .pp_chg_id = INT_MIN, }, 675 + 676 + { .n = "qspi0_gclk", 677 + .id = 78, 678 + .r = { .max = 200000000 }, 679 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 680 + .pp_mux_table = { 5, 8, }, 681 + .pp_count = 2, 682 + .pp_chg_id = INT_MIN, }, 683 + 684 + { .n = "qspi1_gclk", 685 + .id = 79, 686 + .r = { .max = 200000000 }, 687 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 688 + .pp_mux_table = { 5, 8, }, 689 + .pp_count = 2, 690 + .pp_chg_id = INT_MIN, }, 691 + 692 + { .n = "sdmmc0_gclk", 693 + .id = 80, 694 + .r = { .max = 208000000 }, 695 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 696 + .pp_mux_table = { 5, 8, }, 697 + .pp_count = 2, 698 + .pp_chg_id = 5, }, 699 + 700 + { .n = "sdmmc1_gclk", 701 + .id = 81, 702 + .r = { .max = 208000000 }, 703 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 704 + .pp_mux_table = { 5, 8, }, 705 + .pp_count = 2, 706 + .pp_chg_id = 5, }, 707 + 708 + { .n = "sdmmc2_gclk", 709 + .id = 82, 710 + .r = { .max = 208000000 }, 711 + .pp = { "syspll_divpmcck", "baudpll_divpmcck", }, 712 + .pp_mux_table = { 5, 8, }, 713 + .pp_count = 2, 714 + .pp_chg_id = 5, }, 715 + 716 + { .n = "spdifrx_gclk", 717 + .id = 84, 718 + .r = { .max = 150000000 }, 719 + .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, 720 + .pp_mux_table = { 5, 9, }, 721 + .pp_count = 2, 722 + .pp_chg_id = 5, }, 723 + 724 + { .n = "spdiftx_gclk", 725 + .id = 85, 726 + .r = { .max = 25000000 }, 727 + .pp = { "syspll_divpmcck", "audiopll_divpmcck", }, 728 + .pp_mux_table = { 5, 9, }, 729 + .pp_count = 2, 730 + .pp_chg_id = 5, }, 731 + 732 + { .n = "tcb0_ch0_gclk", 733 + .id = 88, 734 + .r = { .max = 200000000 }, 735 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 736 + "audiopll_divpmcck", "ethpll_divpmcck", }, 737 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 738 + .pp_count = 5, 739 + .pp_chg_id = INT_MIN, }, 740 + 741 + { .n = "tcb1_ch0_gclk", 742 + .id = 91, 743 + .r = { .max = 200000000 }, 744 + .pp = { "syspll_divpmcck", "imgpll_divpmcck", "baudpll_divpmcck", 745 + "audiopll_divpmcck", "ethpll_divpmcck", }, 746 + .pp_mux_table = { 5, 7, 8, 9, 10, }, 747 + .pp_count = 5, 748 + .pp_chg_id = INT_MIN, }, 749 + 750 + { .n = "tcpca_gclk", 751 + .id = 94, 752 + .r = { .max = 32768, }, 753 + .pp_chg_id = INT_MIN, }, 754 + 755 + { .n = "tcpcb_gclk", 756 + .id = 95, 757 + .r = { .max = 32768, }, 758 + .pp_chg_id = INT_MIN, }, 759 + }; 760 + 761 + /* PLL output range. */ 762 + static const struct clk_range pll_outputs[] = { 763 + { .min = 2343750, .max = 1200000000 }, 764 + }; 765 + 766 + /* PLL characteristics. */ 767 + static const struct clk_pll_characteristics pll_characteristics = { 768 + .input = { .min = 12000000, .max = 50000000 }, 769 + .num_output = ARRAY_SIZE(pll_outputs), 770 + .output = pll_outputs, 771 + }; 772 + 773 + /* MCK0 characteristics. */ 774 + static const struct clk_master_characteristics mck0_characteristics = { 775 + .output = { .min = 140000000, .max = 200000000 }, 776 + .divisors = { 1, 2, 4, 3 }, 777 + .have_div3_pres = 1, 778 + }; 779 + 780 + /* MCK0 layout. */ 781 + static const struct clk_master_layout mck0_layout = { 782 + .mask = 0x373, 783 + .pres_shift = 4, 784 + .offset = 0x28, 785 + }; 786 + 787 + /* Programmable clock layout. */ 788 + static const struct clk_programmable_layout programmable_layout = { 789 + .pres_mask = 0xff, 790 + .pres_shift = 8, 791 + .css_mask = 0x1f, 792 + .have_slck_mck = 0, 793 + .is_pres_direct = 1, 794 + }; 795 + 796 + /* Peripheral clock layout. */ 797 + static const struct clk_pcr_layout sama7g5_pcr_layout = { 798 + .offset = 0x88, 799 + .cmd = BIT(31), 800 + .gckcss_mask = GENMASK(12, 8), 801 + .pid_mask = GENMASK(6, 0), 802 + }; 803 + 804 + static void __init sama7g5_pmc_setup(struct device_node *np) 805 + { 806 + const char *td_slck_name, *md_slck_name, *mainxtal_name; 807 + struct pmc_data *sama7g5_pmc; 808 + const char *parent_names[10]; 809 + void **alloc_mem = NULL; 810 + int alloc_mem_size = 0; 811 + struct regmap *regmap; 812 + struct clk_hw *hw; 813 + bool bypass; 814 + int i, j; 815 + 816 + i = of_property_match_string(np, "clock-names", "td_slck"); 817 + if (i < 0) 818 + return; 819 + 820 + td_slck_name = of_clk_get_parent_name(np, i); 821 + 822 + i = of_property_match_string(np, "clock-names", "md_slck"); 823 + if (i < 0) 824 + return; 825 + 826 + md_slck_name = of_clk_get_parent_name(np, i); 827 + 828 + i = of_property_match_string(np, "clock-names", "main_xtal"); 829 + if (i < 0) 830 + return; 831 + 832 + mainxtal_name = of_clk_get_parent_name(np, i); 833 + 834 + regmap = device_node_to_regmap(np); 835 + if (IS_ERR(regmap)) 836 + return; 837 + 838 + sama7g5_pmc = pmc_data_allocate(PMC_I2S1_MUX + 1, 839 + nck(sama7g5_systemck), 840 + nck(sama7g5_periphck), 841 + nck(sama7g5_gck)); 842 + if (!sama7g5_pmc) 843 + return; 844 + 845 + alloc_mem = kmalloc(sizeof(void *) * 846 + (ARRAY_SIZE(sama7g5_mckx) + ARRAY_SIZE(sama7g5_gck)), 847 + GFP_KERNEL); 848 + if (!alloc_mem) 849 + goto err_free; 850 + 851 + hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000, 852 + 50000000); 853 + if (IS_ERR(hw)) 854 + goto err_free; 855 + 856 + bypass = of_property_read_bool(np, "atmel,osc-bypass"); 857 + 858 + hw = at91_clk_register_main_osc(regmap, "main_osc", mainxtal_name, 859 + bypass); 860 + if (IS_ERR(hw)) 861 + goto err_free; 862 + 863 + parent_names[0] = "main_rc_osc"; 864 + parent_names[1] = "main_osc"; 865 + hw = at91_clk_register_sam9x5_main(regmap, "mainck", parent_names, 2); 866 + if (IS_ERR(hw)) 867 + goto err_free; 868 + 869 + sama7g5_pmc->chws[PMC_MAIN] = hw; 870 + 871 + for (i = 0; i < PLL_ID_MAX; i++) { 872 + for (j = 0; j < 3; j++) { 873 + struct clk_hw *parent_hw; 874 + 875 + if (!sama7g5_plls[i][j].n) 876 + continue; 877 + 878 + switch (sama7g5_plls[i][j].t) { 879 + case PLL_TYPE_FRAC: 880 + if (!strcmp(sama7g5_plls[i][j].p, "mainck")) 881 + parent_hw = sama7g5_pmc->chws[PMC_MAIN]; 882 + else 883 + parent_hw = __clk_get_hw(of_clk_get_by_name(np, 884 + sama7g5_plls[i][j].p)); 885 + 886 + hw = sam9x60_clk_register_frac_pll(regmap, 887 + &pmc_pll_lock, sama7g5_plls[i][j].n, 888 + sama7g5_plls[i][j].p, parent_hw, i, 889 + &pll_characteristics, 890 + sama7g5_plls[i][j].l, 891 + sama7g5_plls[i][j].c); 892 + break; 893 + 894 + case PLL_TYPE_DIV: 895 + hw = sam9x60_clk_register_div_pll(regmap, 896 + &pmc_pll_lock, sama7g5_plls[i][j].n, 897 + sama7g5_plls[i][j].p, i, 898 + &pll_characteristics, 899 + sama7g5_plls[i][j].l, 900 + sama7g5_plls[i][j].c); 901 + break; 902 + 903 + default: 904 + continue; 905 + } 906 + 907 + if (IS_ERR(hw)) 908 + goto err_free; 909 + 910 + if (sama7g5_plls[i][j].eid) 911 + sama7g5_pmc->chws[sama7g5_plls[i][j].eid] = hw; 912 + } 913 + } 914 + 915 + parent_names[0] = md_slck_name; 916 + parent_names[1] = "mainck"; 917 + parent_names[2] = "cpupll_divpmcck"; 918 + parent_names[3] = "syspll_divpmcck"; 919 + hw = at91_clk_register_master(regmap, "mck0", 4, parent_names, 920 + &mck0_layout, &mck0_characteristics); 921 + if (IS_ERR(hw)) 922 + goto err_free; 923 + 924 + sama7g5_pmc->chws[PMC_MCK] = hw; 925 + 926 + parent_names[0] = md_slck_name; 927 + parent_names[1] = td_slck_name; 928 + parent_names[2] = "mainck"; 929 + parent_names[3] = "mck0"; 930 + for (i = 0; i < ARRAY_SIZE(sama7g5_mckx); i++) { 931 + u8 num_parents = 4 + sama7g5_mckx[i].ep_count; 932 + u32 *mux_table; 933 + 934 + mux_table = kmalloc_array(num_parents, sizeof(*mux_table), 935 + GFP_KERNEL); 936 + if (!mux_table) 937 + goto err_free; 938 + 939 + SAMA7G5_INIT_TABLE(mux_table, 4); 940 + SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_mckx[i].ep_mux_table, 941 + sama7g5_mckx[i].ep_count); 942 + SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_mckx[i].ep, 943 + sama7g5_mckx[i].ep_count); 944 + 945 + hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n, 946 + num_parents, parent_names, mux_table, 947 + &pmc_mckX_lock, sama7g5_mckx[i].id, 948 + sama7g5_mckx[i].c, 949 + sama7g5_mckx[i].ep_chg_id); 950 + if (IS_ERR(hw)) 951 + goto err_free; 952 + 953 + alloc_mem[alloc_mem_size++] = mux_table; 954 + } 955 + 956 + hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", "main_xtal"); 957 + if (IS_ERR(hw)) 958 + goto err_free; 959 + 960 + sama7g5_pmc->chws[PMC_UTMI] = hw; 961 + 962 + parent_names[0] = md_slck_name; 963 + parent_names[1] = td_slck_name; 964 + parent_names[2] = "mainck"; 965 + parent_names[3] = "mck0"; 966 + parent_names[4] = "syspll_divpmcck"; 967 + parent_names[5] = "ddrpll_divpmcck"; 968 + parent_names[6] = "imgpll_divpmcck"; 969 + parent_names[7] = "baudpll_divpmcck"; 970 + parent_names[8] = "audiopll_divpmcck"; 971 + parent_names[9] = "ethpll_divpmcck"; 972 + for (i = 0; i < 8; i++) { 973 + char name[6]; 974 + 975 + snprintf(name, sizeof(name), "prog%d", i); 976 + 977 + hw = at91_clk_register_programmable(regmap, name, parent_names, 978 + 10, i, 979 + &programmable_layout, 980 + sama7g5_prog_mux_table); 981 + if (IS_ERR(hw)) 982 + goto err_free; 983 + } 984 + 985 + for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) { 986 + hw = at91_clk_register_system(regmap, sama7g5_systemck[i].n, 987 + sama7g5_systemck[i].p, 988 + sama7g5_systemck[i].id); 989 + if (IS_ERR(hw)) 990 + goto err_free; 991 + 992 + sama7g5_pmc->shws[sama7g5_systemck[i].id] = hw; 993 + } 994 + 995 + for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) { 996 + hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock, 997 + &sama7g5_pcr_layout, 998 + sama7g5_periphck[i].n, 999 + sama7g5_periphck[i].p, 1000 + sama7g5_periphck[i].id, 1001 + &sama7g5_periphck[i].r, 1002 + sama7g5_periphck[i].chgp ? 0 : 1003 + INT_MIN); 1004 + if (IS_ERR(hw)) 1005 + goto err_free; 1006 + 1007 + sama7g5_pmc->phws[sama7g5_periphck[i].id] = hw; 1008 + } 1009 + 1010 + parent_names[0] = md_slck_name; 1011 + parent_names[1] = td_slck_name; 1012 + parent_names[2] = "mainck"; 1013 + parent_names[3] = "mck0"; 1014 + for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) { 1015 + u8 num_parents = 4 + sama7g5_gck[i].pp_count; 1016 + u32 *mux_table; 1017 + 1018 + mux_table = kmalloc_array(num_parents, sizeof(*mux_table), 1019 + GFP_KERNEL); 1020 + if (!mux_table) 1021 + goto err_free; 1022 + 1023 + SAMA7G5_INIT_TABLE(mux_table, 4); 1024 + SAMA7G5_FILL_TABLE(&mux_table[4], sama7g5_gck[i].pp_mux_table, 1025 + sama7g5_gck[i].pp_count); 1026 + SAMA7G5_FILL_TABLE(&parent_names[4], sama7g5_gck[i].pp, 1027 + sama7g5_gck[i].pp_count); 1028 + 1029 + hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, 1030 + &sama7g5_pcr_layout, 1031 + sama7g5_gck[i].n, 1032 + parent_names, mux_table, 1033 + num_parents, 1034 + sama7g5_gck[i].id, 1035 + &sama7g5_gck[i].r, 1036 + sama7g5_gck[i].pp_chg_id); 1037 + if (IS_ERR(hw)) 1038 + goto err_free; 1039 + 1040 + sama7g5_pmc->ghws[sama7g5_gck[i].id] = hw; 1041 + alloc_mem[alloc_mem_size++] = mux_table; 1042 + } 1043 + 1044 + of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama7g5_pmc); 1045 + 1046 + return; 1047 + 1048 + err_free: 1049 + if (alloc_mem) { 1050 + for (i = 0; i < alloc_mem_size; i++) 1051 + kfree(alloc_mem[i]); 1052 + kfree(alloc_mem); 1053 + } 1054 + 1055 + pmc_data_free(sama7g5_pmc); 1056 + } 1057 + 1058 + /* Some clks are used for a clocksource */ 1059 + CLK_OF_DECLARE(sama7g5_pmc, "microchip,sama7g5-pmc", sama7g5_pmc_setup);