1 /* 2 * Clock driver for the ARM Integrator/IM-PD1 board 3 * Copyright (C) 2012 Linus Walleij 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 #include <linux/clk-provider.h> 10 #include <linux/clk.h> 11 #include <linux/clkdev.h> 12 #include <linux/err.h> 13 #include <linux/io.h> 14 #include <linux/platform_data/clk-integrator.h> 15 16 #include <mach/impd1.h> 17 18 #include "clk-icst.h" 19 20 struct impd1_clk { 21 struct clk *vcoclk; 22 struct clk *uartclk; 23 struct clk_lookup *clks[3]; 24 }; 25 26 static struct impd1_clk impd1_clks[4]; 27 28 /* 29 * There are two VCO's on the IM-PD1 but only one is used by the 30 * kernel, that is why we are only implementing the control of 31 * IMPD1_OSC1 here. 32 */ 33 34 static const struct icst_params impd1_vco_params = { 35 .ref = 24000000, /* 24 MHz */ 36 .vco_max = ICST525_VCO_MAX_3V, 37 .vco_min = ICST525_VCO_MIN, 38 .vd_min = 12, 39 .vd_max = 519, 40 .rd_min = 3, 41 .rd_max = 120, 42 .s2div = icst525_s2div, 43 .idx2s = icst525_idx2s, 44 }; 45 46 static const struct clk_icst_desc impd1_icst1_desc = { 47 .params = &impd1_vco_params, 48 .vco_offset = IMPD1_OSC1, 49 .lock_offset = IMPD1_LOCK, 50 }; 51 52 /** 53 * integrator_impd1_clk_init() - set up the integrator clock tree 54 * @base: base address of the logic module (LM) 55 * @id: the ID of this LM 56 */ 57 void integrator_impd1_clk_init(void __iomem *base, unsigned int id) 58 { 59 struct impd1_clk *imc; 60 struct clk *clk; 61 int i; 62 63 if (id > 3) { 64 pr_crit("no more than 4 LMs can be attached\n"); 65 return; 66 } 67 imc = &impd1_clks[id]; 68 69 clk = icst_clk_register(NULL, &impd1_icst1_desc, base); 70 imc->vcoclk = clk; 71 imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id); 72 73 /* UART reference clock */ 74 clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT, 75 14745600); 76 imc->uartclk = clk; 77 imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id); 78 imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id); 79 80 for (i = 0; i < ARRAY_SIZE(imc->clks); i++) 81 clkdev_add(imc->clks[i]); 82 } 83 84 void integrator_impd1_clk_exit(unsigned int id) 85 { 86 int i; 87 struct impd1_clk *imc; 88 89 if (id > 3) 90 return; 91 imc = &impd1_clks[id]; 92 93 for (i = 0; i < ARRAY_SIZE(imc->clks); i++) 94 clkdev_drop(imc->clks[i]); 95 clk_unregister(imc->uartclk); 96 clk_unregister(imc->vcoclk); 97 } 98