17b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* 27b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * r8a7779 Core CPG Clocks 37b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 47b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * Copyright (C) 2013, 2014 Horms Solutions Ltd. 57b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 67b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * Contact: Simon Horman <horms@verge.net.au> 77b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 87b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * This program is free software; you can redistribute it and/or modify 97b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * it under the terms of the GNU General Public License as published by 107b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * the Free Software Foundation; version 2 of the License. 117b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */ 127b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 137b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/clk-provider.h> 147b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/clkdev.h> 157b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/clk/shmobile.h> 167b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/init.h> 177b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/kernel.h> 187b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/of.h> 197b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/of_address.h> 207b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <linux/spinlock.h> 217b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 227b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#include <dt-bindings/clock/r8a7779-clock.h> 237b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 247b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#define CPG_NUM_CLOCKS (R8A7779_CLK_OUT + 1) 257b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 267b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstruct r8a7779_cpg { 277b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman struct clk_onecell_data data; 287b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman spinlock_t lock; 297b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman void __iomem *reg; 307b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman}; 317b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 327b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* ----------------------------------------------------------------------------- 337b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * CPG Clock Data 347b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */ 357b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 367b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* 377b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * MD1 = 1 MD1 = 0 387b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * (PLLA = 1500) (PLLA = 1600) 397b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * (MHz) (MHz) 407b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *------------------------------------------------+-------------------- 417b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkz 1000 (2/3) 800 (1/2) 427b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkzs 250 (1/6) 200 (1/8) 437b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clki 750 (1/2) 800 (1/2) 447b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks 250 (1/6) 200 (1/8) 457b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks1 125 (1/12) 100 (1/16) 467b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks3 187.5 (1/8) 200 (1/8) 477b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clks4 93.7 (1/16) 100 (1/16) 487b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkp 62.5 (1/24) 50 (1/32) 497b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkg 62.5 (1/24) 66.6 (1/24) 507b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * clkb, CLKOUT 517b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * (MD2 = 0) 62.5 (1/24) 66.6 (1/24) 527b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * (MD2 = 1) 41.6 (1/36) 50 (1/32) 537b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */ 547b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 557b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#define CPG_CLK_CONFIG_INDEX(md) (((md) & (BIT(2)|BIT(1))) >> 1) 567b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 577b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstruct cpg_clk_config { 587b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int z_mult; 597b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int z_div; 607b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int zs_and_s_div; 617b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int s1_div; 627b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int p_div; 637b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int b_and_out_div; 647b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman}; 657b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 667b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic const struct cpg_clk_config cpg_clk_configs[4] __initconst = { 677b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman { 1, 2, 8, 16, 32, 24 }, 687b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman { 2, 3, 6, 12, 24, 24 }, 697b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman { 1, 2, 8, 16, 32, 32 }, 707b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman { 2, 3, 6, 12, 24, 36 }, 717b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman}; 727b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 737b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* 747b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * MD PLLA Ratio 757b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 12 11 767b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman *------------------------ 777b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 0 0 x42 787b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 0 1 x48 797b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 1 0 x56 807b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * 1 1 x64 817b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */ 827b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 837b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman#define CPG_PLLA_MULT_INDEX(md) (((md) & (BIT(12)|BIT(11))) >> 11) 847b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 857b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic const unsigned int cpg_plla_mult[4] __initconst = { 42, 48, 56, 64 }; 867b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 877b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman/* ----------------------------------------------------------------------------- 887b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * Initialization 897b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */ 907b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 917b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic u32 cpg_mode __initdata; 927b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 937b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic struct clk * __init 947b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanr8a7779_cpg_register_clock(struct device_node *np, struct r8a7779_cpg *cpg, 957b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman const struct cpg_clk_config *config, 967b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int plla_mult, const char *name) 977b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman{ 987b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman const char *parent_name = "plla"; 997b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int mult = 1; 1007b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int div = 1; 1017b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1027b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman if (!strcmp(name, "plla")) { 1037b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman parent_name = of_clk_get_parent_name(np, 0); 1047b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman mult = plla_mult; 1057b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } else if (!strcmp(name, "z")) { 1067b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman div = config->z_div; 1077b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman mult = config->z_mult; 1087b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } else if (!strcmp(name, "zs") || !strcmp(name, "s")) { 1097b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman div = config->zs_and_s_div; 1107b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } else if (!strcmp(name, "s1")) { 1117b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman div = config->s1_div; 1127b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } else if (!strcmp(name, "p")) { 1137b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman div = config->p_div; 1147b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } else if (!strcmp(name, "b") || !strcmp(name, "out")) { 1157b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman div = config->b_and_out_div; 1167b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } else { 1177b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman return ERR_PTR(-EINVAL); 1187b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } 1197b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1207b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman return clk_register_fixed_factor(NULL, name, parent_name, 0, mult, div); 1217b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman} 1227b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1237b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanstatic void __init r8a7779_cpg_clocks_init(struct device_node *np) 1247b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman{ 1257b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman const struct cpg_clk_config *config; 1267b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman struct r8a7779_cpg *cpg; 1277b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman struct clk **clks; 1287b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman unsigned int i, plla_mult; 1297b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman int num_clks; 1307b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1317b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman num_clks = of_property_count_strings(np, "clock-output-names"); 1327b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman if (num_clks < 0) { 1337b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman pr_err("%s: failed to count clocks\n", __func__); 1347b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman return; 1357b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } 1367b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1377b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); 1387b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman clks = kzalloc(CPG_NUM_CLOCKS * sizeof(*clks), GFP_KERNEL); 1397b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman if (cpg == NULL || clks == NULL) { 1407b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman /* We're leaking memory on purpose, there's no point in cleaning 1417b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman * up as the system won't boot anyway. 1427b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman */ 1437b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman return; 1447b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } 1457b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1467b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman spin_lock_init(&cpg->lock); 1477b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1487b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman cpg->data.clks = clks; 1497b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman cpg->data.clk_num = num_clks; 1507b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1517b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman config = &cpg_clk_configs[CPG_CLK_CONFIG_INDEX(cpg_mode)]; 1527b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman plla_mult = cpg_plla_mult[CPG_PLLA_MULT_INDEX(cpg_mode)]; 1537b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1547b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman for (i = 0; i < num_clks; ++i) { 1557b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman const char *name; 1567b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman struct clk *clk; 1577b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1587b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman of_property_read_string_index(np, "clock-output-names", i, 1597b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman &name); 1607b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1617b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman clk = r8a7779_cpg_register_clock(np, cpg, config, 1627b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman plla_mult, name); 1637b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman if (IS_ERR(clk)) 1647b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman pr_err("%s: failed to register %s %s clock (%ld)\n", 1657b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman __func__, np->name, name, PTR_ERR(clk)); 1667b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman else 1677b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman cpg->data.clks[i] = clk; 1687b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman } 1697b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1707b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); 1717b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman} 1727b42a997bfb93c6ae0709f34ec8e2860757804b5Simon HormanCLK_OF_DECLARE(r8a7779_cpg_clks, "renesas,r8a7779-cpg-clocks", 1737b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman r8a7779_cpg_clocks_init); 1747b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1757b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Hormanvoid __init r8a7779_clocks_init(u32 mode) 1767b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman{ 1777b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman cpg_mode = mode; 1787b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman 1797b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman of_clk_init(NULL); 1807b42a997bfb93c6ae0709f34ec8e2860757804b5Simon Horman} 181