130 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * r8a7778 Core CPG Clocks4 *5 * Copyright (C) 2014 Ulrich Hecht6 */7 8#include <linux/clk-provider.h>9#include <linux/clk/renesas.h>10#include <linux/of_address.h>11#include <linux/slab.h>12#include <linux/soc/renesas/rcar-rst.h>13 14/* PLL multipliers per bits 11, 12, and 18 of MODEMR */15static const struct {16 unsigned long plla_mult;17 unsigned long pllb_mult;18} r8a7778_rates[] __initconst = {19 [0] = { 21, 21 },20 [1] = { 24, 24 },21 [2] = { 28, 28 },22 [3] = { 32, 32 },23 [5] = { 24, 21 },24 [6] = { 28, 21 },25 [7] = { 32, 24 },26};27 28/* Clock dividers per bits 1 and 2 of MODEMR */29static const struct {30 const char *name;31 unsigned int div[4];32} r8a7778_divs[6] __initconst = {33 { "b", { 12, 12, 16, 18 } },34 { "out", { 12, 12, 16, 18 } },35 { "p", { 16, 12, 16, 12 } },36 { "s", { 4, 3, 4, 3 } },37 { "s1", { 8, 6, 8, 6 } },38};39 40static u32 cpg_mode_rates __initdata;41static u32 cpg_mode_divs __initdata;42 43static struct clk * __init44r8a7778_cpg_register_clock(struct device_node *np, const char *name)45{46 if (!strcmp(name, "plla")) {47 return clk_register_fixed_factor(NULL, "plla",48 of_clk_get_parent_name(np, 0), 0,49 r8a7778_rates[cpg_mode_rates].plla_mult, 1);50 } else if (!strcmp(name, "pllb")) {51 return clk_register_fixed_factor(NULL, "pllb",52 of_clk_get_parent_name(np, 0), 0,53 r8a7778_rates[cpg_mode_rates].pllb_mult, 1);54 } else {55 unsigned int i;56 57 for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) {58 if (!strcmp(name, r8a7778_divs[i].name)) {59 return clk_register_fixed_factor(NULL,60 r8a7778_divs[i].name,61 "plla", 0, 1,62 r8a7778_divs[i].div[cpg_mode_divs]);63 }64 }65 }66 67 return ERR_PTR(-EINVAL);68}69 70 71static void __init r8a7778_cpg_clocks_init(struct device_node *np)72{73 struct clk_onecell_data *data;74 struct clk **clks;75 unsigned int i;76 int num_clks;77 u32 mode;78 79 if (rcar_rst_read_mode_pins(&mode))80 return;81 82 BUG_ON(!(mode & BIT(19)));83 84 cpg_mode_rates = (!!(mode & BIT(18)) << 2) |85 (!!(mode & BIT(12)) << 1) |86 (!!(mode & BIT(11)));87 cpg_mode_divs = (!!(mode & BIT(2)) << 1) |88 (!!(mode & BIT(1)));89 90 num_clks = of_property_count_strings(np, "clock-output-names");91 if (num_clks < 0) {92 pr_err("%s: failed to count clocks\n", __func__);93 return;94 }95 96 data = kzalloc(sizeof(*data), GFP_KERNEL);97 clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);98 if (data == NULL || clks == NULL) {99 /* We're leaking memory on purpose, there's no point in cleaning100 * up as the system won't boot anyway.101 */102 return;103 }104 105 data->clks = clks;106 data->clk_num = num_clks;107 108 for (i = 0; i < num_clks; ++i) {109 const char *name;110 struct clk *clk;111 112 of_property_read_string_index(np, "clock-output-names", i,113 &name);114 115 clk = r8a7778_cpg_register_clock(np, name);116 if (IS_ERR(clk))117 pr_err("%s: failed to register %pOFn %s clock (%ld)\n",118 __func__, np, name, PTR_ERR(clk));119 else120 data->clks[i] = clk;121 }122 123 of_clk_add_provider(np, of_clk_src_onecell_get, data);124 125 cpg_mstp_add_clk_domain(np);126}127 128CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks",129 r8a7778_cpg_clocks_init);130