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

clk: make ICST driver handle the VCO registers

It turns out that all platforms using the ICST VCO are really
just touching two registers, and in the same way as well: one
register with the VCO configuration as such, and one lock register
that makes it possible to write to the VCO.

Factor this register read/write into the ICST driver so we can
reuse it in the IM-PD1 driver.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Mike Turquette <mturquette@linaro.org>

authored by

Linus Walleij and committed by
Mike Turquette
7a9ad671 401301cc

+81 -95
+51 -9
drivers/clk/versatile/clk-icst.c
··· 17 17 #include <linux/clkdev.h> 18 18 #include <linux/err.h> 19 19 #include <linux/clk-provider.h> 20 + #include <linux/io.h> 20 21 21 22 #include "clk-icst.h" 22 23 23 24 /** 24 25 * struct clk_icst - ICST VCO clock wrapper 25 26 * @hw: corresponding clock hardware entry 27 + * @vcoreg: VCO register address 28 + * @lockreg: VCO lock register address 26 29 * @params: parameters for this ICST instance 27 30 * @rate: current rate 28 - * @setvco: function to commit ICST settings to hardware 29 31 */ 30 32 struct clk_icst { 31 33 struct clk_hw hw; 34 + void __iomem *vcoreg; 35 + void __iomem *lockreg; 32 36 const struct icst_params *params; 33 37 unsigned long rate; 34 - struct icst_vco (*getvco)(void); 35 - void (*setvco)(struct icst_vco); 36 38 }; 37 39 38 40 #define to_icst(_hw) container_of(_hw, struct clk_icst, hw) 41 + 42 + /** 43 + * vco_get() - get ICST VCO settings from a certain register 44 + * @vcoreg: register containing the VCO settings 45 + */ 46 + static struct icst_vco vco_get(void __iomem *vcoreg) 47 + { 48 + u32 val; 49 + struct icst_vco vco; 50 + 51 + val = readl(vcoreg); 52 + vco.v = val & 0x1ff; 53 + vco.r = (val >> 9) & 0x7f; 54 + vco.s = (val >> 16) & 03; 55 + return vco; 56 + } 57 + 58 + /** 59 + * vco_set() - commit changes to an ICST VCO 60 + * @locreg: register to poke to unlock the VCO for writing 61 + * @vcoreg: register containing the VCO settings 62 + * @vco: ICST VCO parameters to commit 63 + */ 64 + static void vco_set(void __iomem *lockreg, 65 + void __iomem *vcoreg, 66 + struct icst_vco vco) 67 + { 68 + u32 val; 69 + 70 + val = readl(vcoreg) & ~0x7ffff; 71 + val |= vco.v | (vco.r << 9) | (vco.s << 16); 72 + 73 + /* This magic unlocks the VCO so it can be controlled */ 74 + writel(0xa05f, lockreg); 75 + writel(val, vcoreg); 76 + /* This locks the VCO again */ 77 + writel(0, lockreg); 78 + } 79 + 39 80 40 81 static unsigned long icst_recalc_rate(struct clk_hw *hw, 41 82 unsigned long parent_rate) ··· 84 43 struct clk_icst *icst = to_icst(hw); 85 44 struct icst_vco vco; 86 45 87 - vco = icst->getvco(); 46 + vco = vco_get(icst->vcoreg); 88 47 icst->rate = icst_hz(icst->params, vco); 89 48 return icst->rate; 90 49 } ··· 107 66 108 67 vco = icst_hz_to_vco(icst->params, rate); 109 68 icst->rate = icst_hz(icst->params, vco); 110 - icst->setvco(vco); 69 + vco_set(icst->vcoreg, icst->lockreg, vco); 111 70 return 0; 112 71 } 113 72 ··· 117 76 .set_rate = icst_set_rate, 118 77 }; 119 78 120 - struct clk * __init icst_clk_register(struct device *dev, 121 - const struct clk_icst_desc *desc) 79 + struct clk *icst_clk_register(struct device *dev, 80 + const struct clk_icst_desc *desc, 81 + void __iomem *base) 122 82 { 123 83 struct clk *clk; 124 84 struct clk_icst *icst; ··· 137 95 init.num_parents = 0; 138 96 icst->hw.init = &init; 139 97 icst->params = desc->params; 140 - icst->getvco = desc->getvco; 141 - icst->setvco = desc->setvco; 98 + icst->vcoreg = base + desc->vco_offset; 99 + icst->lockreg = base + desc->lock_offset; 142 100 143 101 clk = clk_register(dev, &icst->hw); 144 102 if (IS_ERR(clk))
+11 -3
drivers/clk/versatile/clk-icst.h
··· 1 1 #include <asm/hardware/icst.h> 2 2 3 + /** 4 + * struct clk_icst_desc - descriptor for the ICST VCO 5 + * @params: ICST parameters 6 + * @vco_offset: offset to the ICST VCO from the provided memory base 7 + * @lock_offset: offset to the ICST VCO locking register from the provided 8 + * memory base 9 + */ 3 10 struct clk_icst_desc { 4 11 const struct icst_params *params; 5 - struct icst_vco (*getvco)(void); 6 - void (*setvco)(struct icst_vco); 12 + u32 vco_offset; 13 + u32 lock_offset; 7 14 }; 8 15 9 16 struct clk *icst_clk_register(struct device *dev, 10 - const struct clk_icst_desc *desc); 17 + const struct clk_icst_desc *desc, 18 + void __iomem *base);
+5 -40
drivers/clk/versatile/clk-integrator.c
··· 10 10 #include <linux/clk.h> 11 11 #include <linux/clkdev.h> 12 12 #include <linux/err.h> 13 - #include <linux/io.h> 13 + #include <linux/platform_data/clk-integrator.h> 14 14 15 15 #include <mach/hardware.h> 16 16 #include <mach/platform.h> ··· 22 22 * Inspired by portions of: 23 23 * plat-versatile/clock.c and plat-versatile/include/plat/clock.h 24 24 */ 25 - #define CM_LOCK (__io_address(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET) 26 - #define CM_AUXOSC (__io_address(INTEGRATOR_HDR_BASE)+0x1c) 27 - 28 - /** 29 - * cp_auxvco_get() - get ICST VCO settings for the Integrator/CP 30 - * @vco: ICST VCO parameters to update with hardware status 31 - */ 32 - static struct icst_vco cp_auxvco_get(void) 33 - { 34 - u32 val; 35 - struct icst_vco vco; 36 - 37 - val = readl(CM_AUXOSC); 38 - vco.v = val & 0x1ff; 39 - vco.r = (val >> 9) & 0x7f; 40 - vco.s = (val >> 16) & 03; 41 - return vco; 42 - } 43 - 44 - /** 45 - * cp_auxvco_set() - commit changes to Integrator/CP ICST VCO 46 - * @vco: ICST VCO parameters to commit 47 - */ 48 - static void cp_auxvco_set(struct icst_vco vco) 49 - { 50 - u32 val; 51 - 52 - val = readl(CM_AUXOSC) & ~0x7ffff; 53 - val |= vco.v | (vco.r << 9) | (vco.s << 16); 54 - 55 - /* This magic unlocks the CM VCO so it can be controlled */ 56 - writel(0xa05f, CM_LOCK); 57 - writel(val, CM_AUXOSC); 58 - /* This locks the CM again */ 59 - writel(0, CM_LOCK); 60 - } 61 25 62 26 static const struct icst_params cp_auxvco_params = { 63 27 .ref = 24000000, ··· 37 73 38 74 static const struct clk_icst_desc __initdata cp_icst_desc = { 39 75 .params = &cp_auxvco_params, 40 - .getvco = cp_auxvco_get, 41 - .setvco = cp_auxvco_set, 76 + .vco_offset = 0x1c, 77 + .lock_offset = INTEGRATOR_HDR_LOCK_OFFSET, 42 78 }; 43 79 44 80 /* ··· 78 114 clk_register_clkdev(clk, NULL, "sp804"); 79 115 80 116 /* ICST VCO clock used on the Integrator/CP CLCD */ 81 - clk = icst_clk_register(NULL, &cp_icst_desc); 117 + clk = icst_clk_register(NULL, &cp_icst_desc, 118 + __io_address(INTEGRATOR_HDR_BASE)); 82 119 clk_register_clkdev(clk, NULL, "clcd"); 83 120 }
+14 -43
drivers/clk/versatile/clk-realview.c
··· 21 21 * Implementation of the ARM RealView clock trees. 22 22 */ 23 23 24 - static void __iomem *sys_lock; 25 - static void __iomem *sys_vcoreg; 26 - 27 - /** 28 - * realview_oscvco_get() - get ICST OSC settings for the RealView 29 - */ 30 - static struct icst_vco realview_oscvco_get(void) 31 - { 32 - u32 val; 33 - struct icst_vco vco; 34 - 35 - val = readl(sys_vcoreg); 36 - vco.v = val & 0x1ff; 37 - vco.r = (val >> 9) & 0x7f; 38 - vco.s = (val >> 16) & 03; 39 - return vco; 40 - } 41 - 42 - static void realview_oscvco_set(struct icst_vco vco) 43 - { 44 - u32 val; 45 - 46 - val = readl(sys_vcoreg) & ~0x7ffff; 47 - val |= vco.v | (vco.r << 9) | (vco.s << 16); 48 - 49 - /* This magic unlocks the CM VCO so it can be controlled */ 50 - writel(0xa05f, sys_lock); 51 - writel(val, sys_vcoreg); 52 - /* This locks the CM again */ 53 - writel(0, sys_lock); 54 - } 55 - 56 24 static const struct icst_params realview_oscvco_params = { 57 25 .ref = 24000000, 58 26 .vco_max = ICST307_VCO_MAX, ··· 33 65 .idx2s = icst307_idx2s, 34 66 }; 35 67 36 - static const struct clk_icst_desc __initdata realview_icst_desc = { 68 + static const struct clk_icst_desc __initdata realview_osc0_desc = { 37 69 .params = &realview_oscvco_params, 38 - .getvco = realview_oscvco_get, 39 - .setvco = realview_oscvco_set, 70 + .vco_offset = REALVIEW_SYS_OSC0_OFFSET, 71 + .lock_offset = REALVIEW_SYS_LOCK_OFFSET, 72 + }; 73 + 74 + static const struct clk_icst_desc __initdata realview_osc4_desc = { 75 + .params = &realview_oscvco_params, 76 + .vco_offset = REALVIEW_SYS_OSC4_OFFSET, 77 + .lock_offset = REALVIEW_SYS_LOCK_OFFSET, 40 78 }; 41 79 42 80 /* ··· 51 77 void __init realview_clk_init(void __iomem *sysbase, bool is_pb1176) 52 78 { 53 79 struct clk *clk; 54 - 55 - sys_lock = sysbase + REALVIEW_SYS_LOCK_OFFSET; 56 - if (is_pb1176) 57 - sys_vcoreg = sysbase + REALVIEW_SYS_OSC0_OFFSET; 58 - else 59 - sys_vcoreg = sysbase + REALVIEW_SYS_OSC4_OFFSET; 60 - 61 80 62 81 /* APB clock dummy */ 63 82 clk = clk_register_fixed_rate(NULL, "apb_pclk", NULL, CLK_IS_ROOT, 0); ··· 83 116 clk_register_clkdev(clk, NULL, "sp804"); 84 117 85 118 /* ICST VCO clock */ 86 - clk = icst_clk_register(NULL, &realview_icst_desc); 119 + if (is_pb1176) 120 + clk = icst_clk_register(NULL, &realview_osc0_desc, sysbase); 121 + else 122 + clk = icst_clk_register(NULL, &realview_osc4_desc, sysbase); 123 + 87 124 clk_register_clkdev(clk, NULL, "dev:clcd"); 88 125 clk_register_clkdev(clk, NULL, "issp:clcd"); 89 126 }