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

clk: at91: add generated clock driver

Add a new type of clocks that can be provided to a peripheral.
In addition to the peripheral clock, this new clock that can use several
input clocks as parents can generate divided rates.
This would allow a peripheral to have finer grained clocks for generating
a baud rate, clocking an asynchronous part or having more
options in frequency.

Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
[sboyd@codeaurora.org: Transition to new clk_hw provider APIs]
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>

authored by

Nicolas Ferre and committed by
Stephen Boyd
df70aeef a5752e57

+361
+35
Documentation/devicetree/bindings/clock/at91-clock.txt
··· 77 77 "atmel,sama5d4-clk-h32mx": 78 78 at91 h32mx clock 79 79 80 + "atmel,sama5d2-clk-generated": 81 + at91 generated clock 82 + 80 83 Required properties for SCKC node: 81 84 - reg : defines the IO memory reserved for the SCKC. 82 85 - #size-cells : shall be 0 (reg is used to encode clk id). ··· 463 460 #clock-cells = <0>; 464 461 compatible = "atmel,sama5d4-clk-h32mx"; 465 462 clocks = <&mck>; 463 + }; 464 + 465 + Required properties for generated clocks: 466 + - #size-cells : shall be 0 (reg is used to encode clk id). 467 + - #address-cells : shall be 1 (reg is used to encode clk id). 468 + - clocks : shall be the generated clock source phandles. 469 + e.g. clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; 470 + - name: device tree node describing a specific generated clock. 471 + * #clock-cells : from common clock binding; shall be set to 0. 472 + * reg: peripheral id. See Atmel's datasheets to get a full 473 + list of peripheral ids. 474 + * atmel,clk-output-range : minimum and maximum clock frequency 475 + (two u32 fields). 476 + 477 + For example: 478 + gck { 479 + compatible = "atmel,sama5d2-clk-generated"; 480 + #address-cells = <1>; 481 + #size-cells = <0>; 482 + clocks = <&clk32k>, <&main>, <&plladiv>, <&utmi>, <&mck>, <&audio_pll_pmc>; 483 + 484 + tcb0_gclk: tcb0_gclk { 485 + #clock-cells = <0>; 486 + reg = <35>; 487 + atmel,clk-output-range = <0 83000000>; 488 + }; 489 + 490 + pwm_gclk: pwm_gclk { 491 + #clock-cells = <0>; 492 + reg = <38>; 493 + atmel,clk-output-range = <0 83000000>; 494 + }; 466 495 };
+3
arch/arm/mach-at91/Kconfig
··· 102 102 config HAVE_AT91_H32MX 103 103 bool 104 104 105 + config HAVE_AT91_GENERATED_CLK 106 + bool 107 + 105 108 config SOC_SAM_V4_V5 106 109 bool 107 110
+1
drivers/clk/at91/Makefile
··· 10 10 obj-$(CONFIG_HAVE_AT91_USB_CLK) += clk-usb.o 11 11 obj-$(CONFIG_HAVE_AT91_SMD) += clk-smd.o 12 12 obj-$(CONFIG_HAVE_AT91_H32MX) += clk-h32mx.o 13 + obj-$(CONFIG_HAVE_AT91_GENERATED_CLK) += clk-generated.o
+306
drivers/clk/at91/clk-generated.c
··· 1 + /* 2 + * Copyright (C) 2015 Atmel Corporation, 3 + * Nicolas Ferre <nicolas.ferre@atmel.com> 4 + * 5 + * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON. 6 + * 7 + * This program is free software; you can redistribute it and/or modify 8 + * it under the terms of the GNU General Public License as published by 9 + * the Free Software Foundation; either version 2 of the License, or 10 + * (at your option) any later version. 11 + * 12 + */ 13 + 14 + #include <linux/clk-provider.h> 15 + #include <linux/clkdev.h> 16 + #include <linux/clk/at91_pmc.h> 17 + #include <linux/of.h> 18 + #include <linux/of_address.h> 19 + #include <linux/io.h> 20 + 21 + #include "pmc.h" 22 + 23 + #define PERIPHERAL_MAX 64 24 + #define PERIPHERAL_ID_MIN 2 25 + 26 + #define GENERATED_SOURCE_MAX 6 27 + #define GENERATED_MAX_DIV 255 28 + 29 + struct clk_generated { 30 + struct clk_hw hw; 31 + struct at91_pmc *pmc; 32 + struct clk_range range; 33 + u32 id; 34 + u32 gckdiv; 35 + u8 parent_id; 36 + }; 37 + 38 + #define to_clk_generated(hw) \ 39 + container_of(hw, struct clk_generated, hw) 40 + 41 + static int clk_generated_enable(struct clk_hw *hw) 42 + { 43 + struct clk_generated *gck = to_clk_generated(hw); 44 + struct at91_pmc *pmc = gck->pmc; 45 + u32 tmp; 46 + 47 + pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n", 48 + __func__, gck->gckdiv, gck->parent_id); 49 + 50 + pmc_lock(pmc); 51 + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); 52 + tmp = pmc_read(pmc, AT91_PMC_PCR) & 53 + ~(AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK); 54 + pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_GCKCSS(gck->parent_id) 55 + | AT91_PMC_PCR_CMD 56 + | AT91_PMC_PCR_GCKDIV(gck->gckdiv) 57 + | AT91_PMC_PCR_GCKEN); 58 + pmc_unlock(pmc); 59 + return 0; 60 + } 61 + 62 + static void clk_generated_disable(struct clk_hw *hw) 63 + { 64 + struct clk_generated *gck = to_clk_generated(hw); 65 + struct at91_pmc *pmc = gck->pmc; 66 + u32 tmp; 67 + 68 + pmc_lock(pmc); 69 + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); 70 + tmp = pmc_read(pmc, AT91_PMC_PCR) & ~AT91_PMC_PCR_GCKEN; 71 + pmc_write(pmc, AT91_PMC_PCR, tmp | AT91_PMC_PCR_CMD); 72 + pmc_unlock(pmc); 73 + } 74 + 75 + static int clk_generated_is_enabled(struct clk_hw *hw) 76 + { 77 + struct clk_generated *gck = to_clk_generated(hw); 78 + struct at91_pmc *pmc = gck->pmc; 79 + int ret; 80 + 81 + pmc_lock(pmc); 82 + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); 83 + ret = !!(pmc_read(pmc, AT91_PMC_PCR) & AT91_PMC_PCR_GCKEN); 84 + pmc_unlock(pmc); 85 + 86 + return ret; 87 + } 88 + 89 + static unsigned long 90 + clk_generated_recalc_rate(struct clk_hw *hw, 91 + unsigned long parent_rate) 92 + { 93 + struct clk_generated *gck = to_clk_generated(hw); 94 + 95 + return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1); 96 + } 97 + 98 + static int clk_generated_determine_rate(struct clk_hw *hw, 99 + struct clk_rate_request *req) 100 + { 101 + struct clk_generated *gck = to_clk_generated(hw); 102 + struct clk_hw *parent = NULL; 103 + long best_rate = -EINVAL; 104 + unsigned long tmp_rate, min_rate; 105 + int best_diff = -1; 106 + int tmp_diff; 107 + int i; 108 + 109 + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { 110 + u32 div; 111 + unsigned long parent_rate; 112 + 113 + parent = clk_hw_get_parent_by_index(hw, i); 114 + if (!parent) 115 + continue; 116 + 117 + parent_rate = clk_hw_get_rate(parent); 118 + min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1); 119 + if (!parent_rate || 120 + (gck->range.max && min_rate > gck->range.max)) 121 + continue; 122 + 123 + for (div = 1; div < GENERATED_MAX_DIV + 2; div++) { 124 + tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div); 125 + tmp_diff = abs(req->rate - tmp_rate); 126 + 127 + if (best_diff < 0 || best_diff > tmp_diff) { 128 + best_rate = tmp_rate; 129 + best_diff = tmp_diff; 130 + req->best_parent_rate = parent_rate; 131 + req->best_parent_hw = parent; 132 + } 133 + 134 + if (!best_diff || tmp_rate < req->rate) 135 + break; 136 + } 137 + 138 + if (!best_diff) 139 + break; 140 + } 141 + 142 + pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", 143 + __func__, best_rate, 144 + __clk_get_name((req->best_parent_hw)->clk), 145 + req->best_parent_rate); 146 + 147 + if (best_rate < 0) 148 + return best_rate; 149 + 150 + req->rate = best_rate; 151 + return 0; 152 + } 153 + 154 + /* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */ 155 + static int clk_generated_set_parent(struct clk_hw *hw, u8 index) 156 + { 157 + struct clk_generated *gck = to_clk_generated(hw); 158 + 159 + if (index >= clk_hw_get_num_parents(hw)) 160 + return -EINVAL; 161 + 162 + gck->parent_id = index; 163 + return 0; 164 + } 165 + 166 + static u8 clk_generated_get_parent(struct clk_hw *hw) 167 + { 168 + struct clk_generated *gck = to_clk_generated(hw); 169 + 170 + return gck->parent_id; 171 + } 172 + 173 + /* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */ 174 + static int clk_generated_set_rate(struct clk_hw *hw, 175 + unsigned long rate, 176 + unsigned long parent_rate) 177 + { 178 + struct clk_generated *gck = to_clk_generated(hw); 179 + u32 div; 180 + 181 + if (!rate) 182 + return -EINVAL; 183 + 184 + if (gck->range.max && rate > gck->range.max) 185 + return -EINVAL; 186 + 187 + div = DIV_ROUND_CLOSEST(parent_rate, rate); 188 + if (div > GENERATED_MAX_DIV + 1 || !div) 189 + return -EINVAL; 190 + 191 + gck->gckdiv = div - 1; 192 + return 0; 193 + } 194 + 195 + static const struct clk_ops generated_ops = { 196 + .enable = clk_generated_enable, 197 + .disable = clk_generated_disable, 198 + .is_enabled = clk_generated_is_enabled, 199 + .recalc_rate = clk_generated_recalc_rate, 200 + .determine_rate = clk_generated_determine_rate, 201 + .get_parent = clk_generated_get_parent, 202 + .set_parent = clk_generated_set_parent, 203 + .set_rate = clk_generated_set_rate, 204 + }; 205 + 206 + /** 207 + * clk_generated_startup - Initialize a given clock to its default parent and 208 + * divisor parameter. 209 + * 210 + * @gck: Generated clock to set the startup parameters for. 211 + * 212 + * Take parameters from the hardware and update local clock configuration 213 + * accordingly. 214 + */ 215 + static void clk_generated_startup(struct clk_generated *gck) 216 + { 217 + struct at91_pmc *pmc = gck->pmc; 218 + u32 tmp; 219 + 220 + pmc_lock(pmc); 221 + pmc_write(pmc, AT91_PMC_PCR, (gck->id & AT91_PMC_PCR_PID_MASK)); 222 + tmp = pmc_read(pmc, AT91_PMC_PCR); 223 + pmc_unlock(pmc); 224 + 225 + gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK) 226 + >> AT91_PMC_PCR_GCKCSS_OFFSET; 227 + gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK) 228 + >> AT91_PMC_PCR_GCKDIV_OFFSET; 229 + } 230 + 231 + static struct clk * __init 232 + at91_clk_register_generated(struct at91_pmc *pmc, const char *name, 233 + const char **parent_names, u8 num_parents, 234 + u8 id, const struct clk_range *range) 235 + { 236 + struct clk_generated *gck; 237 + struct clk *clk = NULL; 238 + struct clk_init_data init; 239 + 240 + gck = kzalloc(sizeof(*gck), GFP_KERNEL); 241 + if (!gck) 242 + return ERR_PTR(-ENOMEM); 243 + 244 + init.name = name; 245 + init.ops = &generated_ops; 246 + init.parent_names = parent_names; 247 + init.num_parents = num_parents; 248 + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; 249 + 250 + gck->id = id; 251 + gck->hw.init = &init; 252 + gck->pmc = pmc; 253 + gck->range = *range; 254 + 255 + clk = clk_register(NULL, &gck->hw); 256 + if (IS_ERR(clk)) 257 + kfree(gck); 258 + else 259 + clk_generated_startup(gck); 260 + 261 + return clk; 262 + } 263 + 264 + void __init of_sama5d2_clk_generated_setup(struct device_node *np, 265 + struct at91_pmc *pmc) 266 + { 267 + int num; 268 + u32 id; 269 + const char *name; 270 + struct clk *clk; 271 + int num_parents; 272 + const char *parent_names[GENERATED_SOURCE_MAX]; 273 + struct device_node *gcknp; 274 + struct clk_range range = CLK_RANGE(0, 0); 275 + 276 + num_parents = of_clk_get_parent_count(np); 277 + if (num_parents <= 0 || num_parents > GENERATED_SOURCE_MAX) 278 + return; 279 + 280 + of_clk_parent_fill(np, parent_names, num_parents); 281 + 282 + num = of_get_child_count(np); 283 + if (!num || num > PERIPHERAL_MAX) 284 + return; 285 + 286 + for_each_child_of_node(np, gcknp) { 287 + if (of_property_read_u32(gcknp, "reg", &id)) 288 + continue; 289 + 290 + if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX) 291 + continue; 292 + 293 + if (of_property_read_string(np, "clock-output-names", &name)) 294 + name = gcknp->name; 295 + 296 + of_at91_get_clk_range(gcknp, "atmel,clk-output-range", 297 + &range); 298 + 299 + clk = at91_clk_register_generated(pmc, name, parent_names, 300 + num_parents, id, &range); 301 + if (IS_ERR(clk)) 302 + continue; 303 + 304 + of_clk_add_provider(gcknp, of_clk_src_simple_get, clk); 305 + } 306 + }
+6
drivers/clk/at91/pmc.c
··· 377 377 .data = of_sama5d4_clk_h32mx_setup, 378 378 }, 379 379 #endif 380 + #if defined(CONFIG_HAVE_AT91_GENERATED_CLK) 381 + { 382 + .compatible = "atmel,sama5d2-clk-generated", 383 + .data = of_sama5d2_clk_generated_setup, 384 + }, 385 + #endif 380 386 { /*sentinel*/ } 381 387 }; 382 388
+3
drivers/clk/at91/pmc.h
··· 118 118 void of_sama5d4_clk_h32mx_setup(struct device_node *np, 119 119 struct at91_pmc *pmc); 120 120 121 + void of_sama5d2_clk_generated_setup(struct device_node *np, 122 + struct at91_pmc *pmc); 123 + 121 124 #endif /* __PMC_H_ */
+7
include/linux/clk/at91_pmc.h
··· 184 184 185 185 #define AT91_PMC_PCR 0x10c /* Peripheral Control Register [some SAM9 and SAMA5] */ 186 186 #define AT91_PMC_PCR_PID_MASK 0x3f 187 + #define AT91_PMC_PCR_GCKCSS_OFFSET 8 188 + #define AT91_PMC_PCR_GCKCSS_MASK (0x7 << AT91_PMC_PCR_GCKCSS_OFFSET) 189 + #define AT91_PMC_PCR_GCKCSS(n) ((n) << AT91_PMC_PCR_GCKCSS_OFFSET) /* GCK Clock Source Selection */ 187 190 #define AT91_PMC_PCR_CMD (0x1 << 12) /* Command (read=0, write=1) */ 188 191 #define AT91_PMC_PCR_DIV_OFFSET 16 189 192 #define AT91_PMC_PCR_DIV_MASK (0x3 << AT91_PMC_PCR_DIV_OFFSET) 190 193 #define AT91_PMC_PCR_DIV(n) ((n) << AT91_PMC_PCR_DIV_OFFSET) /* Divisor Value */ 194 + #define AT91_PMC_PCR_GCKDIV_OFFSET 20 195 + #define AT91_PMC_PCR_GCKDIV_MASK (0xff << AT91_PMC_PCR_GCKDIV_OFFSET) 196 + #define AT91_PMC_PCR_GCKDIV(n) ((n) << AT91_PMC_PCR_GCKDIV_OFFSET) /* Generated Clock Divisor Value */ 191 197 #define AT91_PMC_PCR_EN (0x1 << 28) /* Enable */ 198 + #define AT91_PMC_PCR_GCKEN (0x1 << 29) /* GCK Enable */ 192 199 193 200 #endif