170ee6577SLinus Walleij /*
270ee6577SLinus Walleij  * Clock driver for the ARM Integrator/IM-PD1 board
370ee6577SLinus Walleij  * Copyright (C) 2012 Linus Walleij
470ee6577SLinus Walleij  *
570ee6577SLinus Walleij  * This program is free software; you can redistribute it and/or modify
670ee6577SLinus Walleij  * it under the terms of the GNU General Public License version 2 as
770ee6577SLinus Walleij  * published by the Free Software Foundation.
870ee6577SLinus Walleij  */
970ee6577SLinus Walleij #include <linux/clk-provider.h>
1070ee6577SLinus Walleij #include <linux/clk.h>
1170ee6577SLinus Walleij #include <linux/clkdev.h>
1270ee6577SLinus Walleij #include <linux/err.h>
1370ee6577SLinus Walleij #include <linux/io.h>
1470ee6577SLinus Walleij #include <linux/platform_data/clk-integrator.h>
1570ee6577SLinus Walleij 
1670ee6577SLinus Walleij #include <mach/impd1.h>
1770ee6577SLinus Walleij 
1870ee6577SLinus Walleij #include "clk-icst.h"
1970ee6577SLinus Walleij 
2070ee6577SLinus Walleij struct impd1_clk {
2170ee6577SLinus Walleij 	struct clk *vcoclk;
2270ee6577SLinus Walleij 	struct clk *uartclk;
2370ee6577SLinus Walleij 	struct clk_lookup *clks[3];
2470ee6577SLinus Walleij };
2570ee6577SLinus Walleij 
2670ee6577SLinus Walleij static struct impd1_clk impd1_clks[4];
2770ee6577SLinus Walleij 
2870ee6577SLinus Walleij /*
2970ee6577SLinus Walleij  * There are two VCO's on the IM-PD1 but only one is used by the
3070ee6577SLinus Walleij  * kernel, that is why we are only implementing the control of
3170ee6577SLinus Walleij  * IMPD1_OSC1 here.
3270ee6577SLinus Walleij  */
3370ee6577SLinus Walleij 
3470ee6577SLinus Walleij static const struct icst_params impd1_vco_params = {
3570ee6577SLinus Walleij 	.ref		= 24000000,	/* 24 MHz */
3670ee6577SLinus Walleij 	.vco_max	= ICST525_VCO_MAX_3V,
3770ee6577SLinus Walleij 	.vco_min	= ICST525_VCO_MIN,
3870ee6577SLinus Walleij 	.vd_min		= 12,
3970ee6577SLinus Walleij 	.vd_max		= 519,
4070ee6577SLinus Walleij 	.rd_min		= 3,
4170ee6577SLinus Walleij 	.rd_max		= 120,
4270ee6577SLinus Walleij 	.s2div		= icst525_s2div,
4370ee6577SLinus Walleij 	.idx2s		= icst525_idx2s,
4470ee6577SLinus Walleij };
4570ee6577SLinus Walleij 
4670ee6577SLinus Walleij static const struct clk_icst_desc impd1_icst1_desc = {
4770ee6577SLinus Walleij 	.params = &impd1_vco_params,
4870ee6577SLinus Walleij 	.vco_offset = IMPD1_OSC1,
4970ee6577SLinus Walleij 	.lock_offset = IMPD1_LOCK,
5070ee6577SLinus Walleij };
5170ee6577SLinus Walleij 
5270ee6577SLinus Walleij /**
5370ee6577SLinus Walleij  * integrator_impd1_clk_init() - set up the integrator clock tree
5470ee6577SLinus Walleij  * @base: base address of the logic module (LM)
5570ee6577SLinus Walleij  * @id: the ID of this LM
5670ee6577SLinus Walleij  */
5770ee6577SLinus Walleij void integrator_impd1_clk_init(void __iomem *base, unsigned int id)
5870ee6577SLinus Walleij {
5970ee6577SLinus Walleij 	struct impd1_clk *imc;
6070ee6577SLinus Walleij 	struct clk *clk;
6170ee6577SLinus Walleij 	int i;
6270ee6577SLinus Walleij 
6370ee6577SLinus Walleij 	if (id > 3) {
6470ee6577SLinus Walleij 		pr_crit("no more than 4 LMs can be attached\n");
6570ee6577SLinus Walleij 		return;
6670ee6577SLinus Walleij 	}
6770ee6577SLinus Walleij 	imc = &impd1_clks[id];
6870ee6577SLinus Walleij 
6970ee6577SLinus Walleij 	clk = icst_clk_register(NULL, &impd1_icst1_desc, base);
7070ee6577SLinus Walleij 	imc->vcoclk = clk;
7170ee6577SLinus Walleij 	imc->clks[0] = clkdev_alloc(clk, NULL, "lm%x:01000", id);
7270ee6577SLinus Walleij 
7370ee6577SLinus Walleij 	/* UART reference clock */
7470ee6577SLinus Walleij 	clk = clk_register_fixed_rate(NULL, "uartclk", NULL, CLK_IS_ROOT,
7570ee6577SLinus Walleij 				14745600);
7670ee6577SLinus Walleij 	imc->uartclk = clk;
7770ee6577SLinus Walleij 	imc->clks[1] = clkdev_alloc(clk, NULL, "lm%x:00100", id);
7870ee6577SLinus Walleij 	imc->clks[2] = clkdev_alloc(clk, NULL, "lm%x:00200", id);
7970ee6577SLinus Walleij 
8070ee6577SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
8170ee6577SLinus Walleij 		clkdev_add(imc->clks[i]);
8270ee6577SLinus Walleij }
8370ee6577SLinus Walleij 
8470ee6577SLinus Walleij void integrator_impd1_clk_exit(unsigned int id)
8570ee6577SLinus Walleij {
8670ee6577SLinus Walleij 	int i;
8770ee6577SLinus Walleij 	struct impd1_clk *imc;
8870ee6577SLinus Walleij 
8970ee6577SLinus Walleij 	if (id > 3)
9070ee6577SLinus Walleij 		return;
9170ee6577SLinus Walleij 	imc = &impd1_clks[id];
9270ee6577SLinus Walleij 
9370ee6577SLinus Walleij 	for (i = 0; i < ARRAY_SIZE(imc->clks); i++)
9470ee6577SLinus Walleij 		clkdev_drop(imc->clks[i]);
9570ee6577SLinus Walleij 	clk_unregister(imc->uartclk);
9670ee6577SLinus Walleij 	clk_unregister(imc->vcoclk);
9770ee6577SLinus Walleij }
98