diff options
| -rw-r--r-- | Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt | 25 | ||||
| -rw-r--r-- | drivers/clk/shmobile/Makefile | 1 | ||||
| -rw-r--r-- | drivers/clk/shmobile/clk-r8a7778.c | 143 | ||||
| -rw-r--r-- | include/linux/clk/shmobile.h | 1 |
4 files changed, 170 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt b/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt new file mode 100644 index 000000000000..2f3747fdcf1c --- /dev/null +++ b/Documentation/devicetree/bindings/clock/renesas,r8a7778-cpg-clocks.txt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | * Renesas R8A7778 Clock Pulse Generator (CPG) | ||
| 2 | |||
| 3 | The CPG generates core clocks for the R8A7778. It includes two PLLs and | ||
| 4 | several fixed ratio dividers | ||
| 5 | |||
| 6 | Required Properties: | ||
| 7 | |||
| 8 | - compatible: Must be "renesas,r8a7778-cpg-clocks" | ||
| 9 | - reg: Base address and length of the memory resource used by the CPG | ||
| 10 | - #clock-cells: Must be 1 | ||
| 11 | - clock-output-names: The names of the clocks. Supported clocks are | ||
| 12 | "plla", "pllb", "b", "out", "p", "s", and "s1". | ||
| 13 | |||
| 14 | |||
| 15 | Example | ||
| 16 | ------- | ||
| 17 | |||
| 18 | cpg_clocks: cpg_clocks@ffc80000 { | ||
| 19 | compatible = "renesas,r8a7778-cpg-clocks"; | ||
| 20 | reg = <0xffc80000 0x80>; | ||
| 21 | #clock-cells = <1>; | ||
| 22 | clocks = <&extal_clk>; | ||
| 23 | clock-output-names = "plla", "pllb", "b", | ||
| 24 | "out", "p", "s", "s1"; | ||
| 25 | }; | ||
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile index 0689d7fb2666..97c71c885e4f 100644 --- a/drivers/clk/shmobile/Makefile +++ b/drivers/clk/shmobile/Makefile | |||
| @@ -2,6 +2,7 @@ obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o | |||
| 2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o | 2 | obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o |
| 3 | obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o | 3 | obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o |
| 4 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o | 4 | obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o |
| 5 | obj-$(CONFIG_ARCH_R8A7778) += clk-r8a7778.o | ||
| 5 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o | 6 | obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o |
| 6 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o | 7 | obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o |
| 7 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o | 8 | obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o |
diff --git a/drivers/clk/shmobile/clk-r8a7778.c b/drivers/clk/shmobile/clk-r8a7778.c new file mode 100644 index 000000000000..cb33b57274bf --- /dev/null +++ b/drivers/clk/shmobile/clk-r8a7778.c | |||
| @@ -0,0 +1,143 @@ | |||
| 1 | /* | ||
| 2 | * r8a7778 Core CPG Clocks | ||
| 3 | * | ||
| 4 | * Copyright (C) 2014 Ulrich Hecht | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; version 2 of the License. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/clk-provider.h> | ||
| 12 | #include <linux/clkdev.h> | ||
| 13 | #include <linux/clk/shmobile.h> | ||
| 14 | #include <linux/of_address.h> | ||
| 15 | |||
| 16 | struct r8a7778_cpg { | ||
| 17 | struct clk_onecell_data data; | ||
| 18 | spinlock_t lock; | ||
| 19 | void __iomem *reg; | ||
| 20 | }; | ||
| 21 | |||
| 22 | /* PLL multipliers per bits 11, 12, and 18 of MODEMR */ | ||
| 23 | struct { | ||
| 24 | unsigned long plla_mult; | ||
| 25 | unsigned long pllb_mult; | ||
| 26 | } r8a7778_rates[] __initdata = { | ||
| 27 | [0] = { 21, 21 }, | ||
| 28 | [1] = { 24, 24 }, | ||
| 29 | [2] = { 28, 28 }, | ||
| 30 | [3] = { 32, 32 }, | ||
| 31 | [5] = { 24, 21 }, | ||
| 32 | [6] = { 28, 21 }, | ||
| 33 | [7] = { 32, 24 }, | ||
| 34 | }; | ||
| 35 | |||
| 36 | /* Clock dividers per bits 1 and 2 of MODEMR */ | ||
| 37 | struct { | ||
| 38 | const char *name; | ||
| 39 | unsigned int div[4]; | ||
| 40 | } r8a7778_divs[6] __initdata = { | ||
| 41 | { "b", { 12, 12, 16, 18 } }, | ||
| 42 | { "out", { 12, 12, 16, 18 } }, | ||
| 43 | { "p", { 16, 12, 16, 12 } }, | ||
| 44 | { "s", { 4, 3, 4, 3 } }, | ||
| 45 | { "s1", { 8, 6, 8, 6 } }, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static u32 cpg_mode_rates __initdata; | ||
| 49 | static u32 cpg_mode_divs __initdata; | ||
| 50 | |||
| 51 | static struct clk * __init | ||
| 52 | r8a7778_cpg_register_clock(struct device_node *np, struct r8a7778_cpg *cpg, | ||
| 53 | const char *name) | ||
| 54 | { | ||
| 55 | if (!strcmp(name, "plla")) { | ||
| 56 | return clk_register_fixed_factor(NULL, "plla", | ||
| 57 | of_clk_get_parent_name(np, 0), 0, | ||
| 58 | r8a7778_rates[cpg_mode_rates].plla_mult, 1); | ||
| 59 | } else if (!strcmp(name, "pllb")) { | ||
| 60 | return clk_register_fixed_factor(NULL, "pllb", | ||
| 61 | of_clk_get_parent_name(np, 0), 0, | ||
| 62 | r8a7778_rates[cpg_mode_rates].pllb_mult, 1); | ||
| 63 | } else { | ||
| 64 | unsigned int i; | ||
| 65 | |||
| 66 | for (i = 0; i < ARRAY_SIZE(r8a7778_divs); i++) { | ||
| 67 | if (!strcmp(name, r8a7778_divs[i].name)) { | ||
| 68 | return clk_register_fixed_factor(NULL, | ||
| 69 | r8a7778_divs[i].name, | ||
| 70 | "plla", 0, 1, | ||
| 71 | r8a7778_divs[i].div[cpg_mode_divs]); | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | return ERR_PTR(-EINVAL); | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | static void __init r8a7778_cpg_clocks_init(struct device_node *np) | ||
| 81 | { | ||
| 82 | struct r8a7778_cpg *cpg; | ||
| 83 | struct clk **clks; | ||
| 84 | unsigned int i; | ||
| 85 | int num_clks; | ||
| 86 | |||
| 87 | num_clks = of_property_count_strings(np, "clock-output-names"); | ||
| 88 | if (num_clks < 0) { | ||
| 89 | pr_err("%s: failed to count clocks\n", __func__); | ||
| 90 | return; | ||
| 91 | } | ||
| 92 | |||
| 93 | cpg = kzalloc(sizeof(*cpg), GFP_KERNEL); | ||
| 94 | clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL); | ||
| 95 | if (cpg == NULL || clks == NULL) { | ||
| 96 | /* We're leaking memory on purpose, there's no point in cleaning | ||
| 97 | * up as the system won't boot anyway. | ||
| 98 | */ | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | |||
| 102 | spin_lock_init(&cpg->lock); | ||
| 103 | |||
| 104 | cpg->data.clks = clks; | ||
| 105 | cpg->data.clk_num = num_clks; | ||
| 106 | |||
| 107 | cpg->reg = of_iomap(np, 0); | ||
| 108 | if (WARN_ON(cpg->reg == NULL)) | ||
| 109 | return; | ||
| 110 | |||
| 111 | for (i = 0; i < num_clks; ++i) { | ||
| 112 | const char *name; | ||
| 113 | struct clk *clk; | ||
| 114 | |||
| 115 | of_property_read_string_index(np, "clock-output-names", i, | ||
| 116 | &name); | ||
| 117 | |||
| 118 | clk = r8a7778_cpg_register_clock(np, cpg, name); | ||
| 119 | if (IS_ERR(clk)) | ||
| 120 | pr_err("%s: failed to register %s %s clock (%ld)\n", | ||
| 121 | __func__, np->name, name, PTR_ERR(clk)); | ||
| 122 | else | ||
| 123 | cpg->data.clks[i] = clk; | ||
| 124 | } | ||
| 125 | |||
| 126 | of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data); | ||
| 127 | } | ||
| 128 | |||
| 129 | CLK_OF_DECLARE(r8a7778_cpg_clks, "renesas,r8a7778-cpg-clocks", | ||
| 130 | r8a7778_cpg_clocks_init); | ||
| 131 | |||
| 132 | void __init r8a7778_clocks_init(u32 mode) | ||
| 133 | { | ||
| 134 | BUG_ON(!(mode & BIT(19))); | ||
| 135 | |||
| 136 | cpg_mode_rates = (!!(mode & BIT(18)) << 2) | | ||
| 137 | (!!(mode & BIT(12)) << 1) | | ||
| 138 | (!!(mode & BIT(11))); | ||
| 139 | cpg_mode_divs = (!!(mode & BIT(2)) << 1) | | ||
| 140 | (!!(mode & BIT(1))); | ||
| 141 | |||
| 142 | of_clk_init(NULL); | ||
| 143 | } | ||
diff --git a/include/linux/clk/shmobile.h b/include/linux/clk/shmobile.h index 9f8a14041dd5..63a8159c4e64 100644 --- a/include/linux/clk/shmobile.h +++ b/include/linux/clk/shmobile.h | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
| 18 | 18 | ||
| 19 | void r8a7778_clocks_init(u32 mode); | ||
| 19 | void r8a7779_clocks_init(u32 mode); | 20 | void r8a7779_clocks_init(u32 mode); |
| 20 | void rcar_gen2_clocks_init(u32 mode); | 21 | void rcar_gen2_clocks_init(u32 mode); |
| 21 | 22 | ||
