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

clk: Add CLPS711X clk driver

This adds the clock driver for Cirrus Logic CLPS711X series SoCs
using common clock infrastructure.
Designed primarily for migration CLPS711X subarch for multiplatform & DT,
for this as the "OF" and "non-OF" calls implemented.

Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Alexander Shiyan and committed by
Mike Turquette
631c5347 eee40bb4

+220
+1
drivers/clk/Makefile
··· 18 18 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o 19 19 obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o 20 20 obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o 21 + obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o 21 22 obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o 22 23 obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o 23 24 obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
+192
drivers/clk/clk-clps711x.c
··· 1 + /* 2 + * Cirrus Logic CLPS711X CLK driver 3 + * 4 + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> 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; either version 2 of the License, or 9 + * (at your option) any later version. 10 + */ 11 + 12 + #include <linux/clk.h> 13 + #include <linux/clk-provider.h> 14 + #include <linux/clkdev.h> 15 + #include <linux/io.h> 16 + #include <linux/ioport.h> 17 + #include <linux/of_address.h> 18 + #include <linux/slab.h> 19 + #include <linux/mfd/syscon/clps711x.h> 20 + 21 + #include <dt-bindings/clock/clps711x-clock.h> 22 + 23 + #define CLPS711X_SYSCON1 (0x0100) 24 + #define CLPS711X_SYSCON2 (0x1100) 25 + #define CLPS711X_SYSFLG2 (CLPS711X_SYSCON2 + SYSFLG_OFFSET) 26 + #define CLPS711X_PLLR (0xa5a8) 27 + 28 + #define CLPS711X_EXT_FREQ (13000000) 29 + #define CLPS711X_OSC_FREQ (3686400) 30 + 31 + static const struct clk_div_table spi_div_table[] = { 32 + { .val = 0, .div = 32, }, 33 + { .val = 1, .div = 8, }, 34 + { .val = 2, .div = 2, }, 35 + { .val = 3, .div = 1, }, 36 + }; 37 + 38 + static const struct clk_div_table timer_div_table[] = { 39 + { .val = 0, .div = 256, }, 40 + { .val = 1, .div = 1, }, 41 + }; 42 + 43 + struct clps711x_clk { 44 + struct clk_onecell_data clk_data; 45 + spinlock_t lock; 46 + struct clk *clks[CLPS711X_CLK_MAX]; 47 + }; 48 + 49 + static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base, 50 + u32 fref) 51 + { 52 + u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi; 53 + struct clps711x_clk *clps711x_clk; 54 + unsigned i; 55 + 56 + if (!base) 57 + return ERR_PTR(-ENOMEM); 58 + 59 + clps711x_clk = kzalloc(sizeof(*clps711x_clk), GFP_KERNEL); 60 + if (!clps711x_clk) 61 + return ERR_PTR(-ENOMEM); 62 + 63 + spin_lock_init(&clps711x_clk->lock); 64 + 65 + /* Read PLL multiplier value and sanity check */ 66 + tmp = readl(base + CLPS711X_PLLR) >> 24; 67 + if (((tmp >= 10) && (tmp <= 50)) || !fref) 68 + f_pll = DIV_ROUND_UP(CLPS711X_OSC_FREQ * tmp, 2); 69 + else 70 + f_pll = fref; 71 + 72 + tmp = readl(base + CLPS711X_SYSFLG2); 73 + if (tmp & SYSFLG2_CKMODE) { 74 + f_cpu = CLPS711X_EXT_FREQ; 75 + f_bus = CLPS711X_EXT_FREQ; 76 + f_spi = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 96); 77 + f_pll = 0; 78 + f_pwm = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 128); 79 + } else { 80 + f_cpu = f_pll; 81 + if (f_cpu > 36864000) 82 + f_bus = DIV_ROUND_UP(f_cpu, 2); 83 + else 84 + f_bus = 36864000 / 2; 85 + f_spi = DIV_ROUND_CLOSEST(f_cpu, 576); 86 + f_pwm = DIV_ROUND_CLOSEST(f_cpu, 768); 87 + } 88 + 89 + if (tmp & SYSFLG2_CKMODE) { 90 + if (readl(base + CLPS711X_SYSCON2) & SYSCON2_OSTB) 91 + f_tim = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 26); 92 + else 93 + f_tim = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 24); 94 + } else 95 + f_tim = DIV_ROUND_CLOSEST(f_cpu, 144); 96 + 97 + tmp = readl(base + CLPS711X_SYSCON1); 98 + /* Timer1 in free running mode. 99 + * Counter will wrap around to 0xffff when it underflows 100 + * and will continue to count down. 101 + */ 102 + tmp &= ~(SYSCON1_TC1M | SYSCON1_TC1S); 103 + /* Timer2 in prescale mode. 104 + * Value writen is automatically re-loaded when 105 + * the counter underflows. 106 + */ 107 + tmp |= SYSCON1_TC2M | SYSCON1_TC2S; 108 + writel(tmp, base + CLPS711X_SYSCON1); 109 + 110 + clps711x_clk->clks[CLPS711X_CLK_DUMMY] = 111 + clk_register_fixed_rate(NULL, "dummy", NULL, CLK_IS_ROOT, 0); 112 + clps711x_clk->clks[CLPS711X_CLK_CPU] = 113 + clk_register_fixed_rate(NULL, "cpu", NULL, CLK_IS_ROOT, f_cpu); 114 + clps711x_clk->clks[CLPS711X_CLK_BUS] = 115 + clk_register_fixed_rate(NULL, "bus", NULL, CLK_IS_ROOT, f_bus); 116 + clps711x_clk->clks[CLPS711X_CLK_PLL] = 117 + clk_register_fixed_rate(NULL, "pll", NULL, CLK_IS_ROOT, f_pll); 118 + clps711x_clk->clks[CLPS711X_CLK_TIMERREF] = 119 + clk_register_fixed_rate(NULL, "timer_ref", NULL, CLK_IS_ROOT, 120 + f_tim); 121 + clps711x_clk->clks[CLPS711X_CLK_TIMER1] = 122 + clk_register_divider_table(NULL, "timer1", "timer_ref", 0, 123 + base + CLPS711X_SYSCON1, 5, 1, 0, 124 + timer_div_table, &clps711x_clk->lock); 125 + clps711x_clk->clks[CLPS711X_CLK_TIMER2] = 126 + clk_register_divider_table(NULL, "timer2", "timer_ref", 0, 127 + base + CLPS711X_SYSCON1, 7, 1, 0, 128 + timer_div_table, &clps711x_clk->lock); 129 + clps711x_clk->clks[CLPS711X_CLK_PWM] = 130 + clk_register_fixed_rate(NULL, "pwm", NULL, CLK_IS_ROOT, f_pwm); 131 + clps711x_clk->clks[CLPS711X_CLK_SPIREF] = 132 + clk_register_fixed_rate(NULL, "spi_ref", NULL, CLK_IS_ROOT, 133 + f_spi); 134 + clps711x_clk->clks[CLPS711X_CLK_SPI] = 135 + clk_register_divider_table(NULL, "spi", "spi_ref", 0, 136 + base + CLPS711X_SYSCON1, 16, 2, 0, 137 + spi_div_table, &clps711x_clk->lock); 138 + clps711x_clk->clks[CLPS711X_CLK_UART] = 139 + clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10); 140 + clps711x_clk->clks[CLPS711X_CLK_TICK] = 141 + clk_register_fixed_rate(NULL, "tick", NULL, CLK_IS_ROOT, 64); 142 + 143 + for (i = 0; i < CLPS711X_CLK_MAX; i++) 144 + if (IS_ERR(clps711x_clk->clks[i])) 145 + pr_err("clk %i: register failed with %ld\n", 146 + i, PTR_ERR(clps711x_clk->clks[i])); 147 + 148 + return clps711x_clk; 149 + } 150 + 151 + void __init clps711x_clk_init(void __iomem *base) 152 + { 153 + struct clps711x_clk *clps711x_clk; 154 + 155 + clps711x_clk = _clps711x_clk_init(base, 73728000); 156 + 157 + BUG_ON(IS_ERR(clps711x_clk)); 158 + 159 + /* Clocksource */ 160 + clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER1], 161 + NULL, "clps711x-timer.0"); 162 + clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER2], 163 + NULL, "clps711x-timer.1"); 164 + 165 + /* Drivers */ 166 + clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_PWM], 167 + NULL, "clps711x-pwm"); 168 + clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART], 169 + NULL, "clps711x-uart.0"); 170 + clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART], 171 + NULL, "clps711x-uart.1"); 172 + } 173 + 174 + #ifdef CONFIG_OF 175 + static void __init clps711x_clk_init_dt(struct device_node *np) 176 + { 177 + void __iomem *base = of_iomap(np, 0); 178 + struct clps711x_clk *clps711x_clk; 179 + u32 fref = 0; 180 + 181 + WARN_ON(of_property_read_u32(np, "startup-frequency", &fref)); 182 + 183 + clps711x_clk = _clps711x_clk_init(base, fref); 184 + BUG_ON(IS_ERR(clps711x_clk)); 185 + 186 + clps711x_clk->clk_data.clks = clps711x_clk->clks; 187 + clps711x_clk->clk_data.clk_num = CLPS711X_CLK_MAX; 188 + of_clk_add_provider(np, of_clk_src_onecell_get, 189 + &clps711x_clk->clk_data); 190 + } 191 + CLK_OF_DECLARE(clps711x, "cirrus,clps711x-clk", clps711x_clk_init_dt); 192 + #endif
+27
include/dt-bindings/clock/clps711x-clock.h
··· 1 + /* 2 + * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru> 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + */ 9 + 10 + #ifndef __DT_BINDINGS_CLOCK_CLPS711X_H 11 + #define __DT_BINDINGS_CLOCK_CLPS711X_H 12 + 13 + #define CLPS711X_CLK_DUMMY 0 14 + #define CLPS711X_CLK_CPU 1 15 + #define CLPS711X_CLK_BUS 2 16 + #define CLPS711X_CLK_PLL 3 17 + #define CLPS711X_CLK_TIMERREF 4 18 + #define CLPS711X_CLK_TIMER1 5 19 + #define CLPS711X_CLK_TIMER2 6 20 + #define CLPS711X_CLK_PWM 7 21 + #define CLPS711X_CLK_SPIREF 8 22 + #define CLPS711X_CLK_SPI 9 23 + #define CLPS711X_CLK_UART 10 24 + #define CLPS711X_CLK_TICK 11 25 + #define CLPS711X_CLK_MAX 12 26 + 27 + #endif