| Linus Walleij | 70ee657 | 2012-11-20 22:39:49 +0100 | [diff] [blame] | 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 | } |