diff options
-rw-r--r-- | arch/arm/mach-integrator/impd1.c | 69 | ||||
-rw-r--r-- | drivers/clk/versatile/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/versatile/clk-impd1.c | 97 | ||||
-rw-r--r-- | include/linux/platform_data/clk-integrator.h | 2 |
4 files changed, 103 insertions, 66 deletions
diff --git a/arch/arm/mach-integrator/impd1.c b/arch/arm/mach-integrator/impd1.c index e428f3ab15c7..b3d86d7081a0 100644 --- a/arch/arm/mach-integrator/impd1.c +++ b/arch/arm/mach-integrator/impd1.c | |||
@@ -21,10 +21,9 @@ | |||
21 | #include <linux/amba/bus.h> | 21 | #include <linux/amba/bus.h> |
22 | #include <linux/amba/clcd.h> | 22 | #include <linux/amba/clcd.h> |
23 | #include <linux/io.h> | 23 | #include <linux/io.h> |
24 | #include <linux/platform_data/clk-integrator.h> | ||
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | #include <linux/clkdev.h> | ||
26 | 26 | ||
27 | #include <asm/hardware/icst.h> | ||
28 | #include <mach/lm.h> | 27 | #include <mach/lm.h> |
29 | #include <mach/impd1.h> | 28 | #include <mach/impd1.h> |
30 | #include <asm/sizes.h> | 29 | #include <asm/sizes.h> |
@@ -36,45 +35,6 @@ MODULE_PARM_DESC(lmid, "logic module stack position"); | |||
36 | 35 | ||
37 | struct impd1_module { | 36 | struct impd1_module { |
38 | void __iomem *base; | 37 | void __iomem *base; |
39 | struct clk vcos[2]; | ||
40 | struct clk_lookup *clks[3]; | ||
41 | }; | ||
42 | |||
43 | static const struct icst_params impd1_vco_params = { | ||
44 | .ref = 24000000, /* 24 MHz */ | ||
45 | .vco_max = ICST525_VCO_MAX_3V, | ||
46 | .vco_min = ICST525_VCO_MIN, | ||
47 | .vd_min = 12, | ||
48 | .vd_max = 519, | ||
49 | .rd_min = 3, | ||
50 | .rd_max = 120, | ||
51 | .s2div = icst525_s2div, | ||
52 | .idx2s = icst525_idx2s, | ||
53 | }; | ||
54 | |||
55 | static void impd1_setvco(struct clk *clk, struct icst_vco vco) | ||
56 | { | ||
57 | struct impd1_module *impd1 = clk->data; | ||
58 | u32 val = vco.v | (vco.r << 9) | (vco.s << 16); | ||
59 | |||
60 | writel(0xa05f, impd1->base + IMPD1_LOCK); | ||
61 | writel(val, clk->vcoreg); | ||
62 | writel(0, impd1->base + IMPD1_LOCK); | ||
63 | |||
64 | #ifdef DEBUG | ||
65 | vco.v = val & 0x1ff; | ||
66 | vco.r = (val >> 9) & 0x7f; | ||
67 | vco.s = (val >> 16) & 7; | ||
68 | |||
69 | pr_debug("IM-PD1: VCO%d clock is %ld Hz\n", | ||
70 | vconr, icst525_hz(&impd1_vco_params, vco)); | ||
71 | #endif | ||
72 | } | ||
73 | |||
74 | static const struct clk_ops impd1_clk_ops = { | ||
75 | .round = icst_clk_round, | ||
76 | .set = icst_clk_set, | ||
77 | .setvco = impd1_setvco, | ||
78 | }; | 38 | }; |
79 | 39 | ||
80 | void impd1_tweak_control(struct device *dev, u32 mask, u32 val) | 40 | void impd1_tweak_control(struct device *dev, u32 mask, u32 val) |
@@ -344,10 +304,6 @@ static struct impd1_device impd1_devs[] = { | |||
344 | } | 304 | } |
345 | }; | 305 | }; |
346 | 306 | ||
347 | static struct clk fixed_14745600 = { | ||
348 | .rate = 14745600, | ||
349 | }; | ||
350 | |||
351 | static int impd1_probe(struct lm_device *dev) | 307 | static int impd1_probe(struct lm_device *dev) |
352 | { | 308 | { |
353 | struct impd1_module *impd1; | 309 | struct impd1_module *impd1; |
@@ -376,23 +332,7 @@ static int impd1_probe(struct lm_device *dev) | |||
376 | printk("IM-PD1 found at 0x%08lx\n", | 332 | printk("IM-PD1 found at 0x%08lx\n", |
377 | (unsigned long)dev->resource.start); | 333 | (unsigned long)dev->resource.start); |
378 | 334 | ||
379 | for (i = 0; i < ARRAY_SIZE(impd1->vcos); i++) { | 335 | integrator_impd1_clk_init(impd1->base, dev->id); |
380 | impd1->vcos[i].ops = &impd1_clk_ops, | ||
381 | impd1->vcos[i].owner = THIS_MODULE, | ||
382 | impd1->vcos[i].params = &impd1_vco_params, | ||
383 | impd1->vcos[i].data = impd1; | ||
384 | } | ||
385 | impd1->vcos[0].vcoreg = impd1->base + IMPD1_OSC1; | ||
386 | impd1->vcos[1].vcoreg = impd1->base + IMPD1_OSC2; | ||
387 | |||
388 | impd1->clks[0] = clkdev_alloc(&impd1->vcos[0], NULL, "lm%x:01000", | ||
389 | dev->id); | ||
390 | impd1->clks[1] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00100", | ||
391 | dev->id); | ||
392 | impd1->clks[2] = clkdev_alloc(&fixed_14745600, NULL, "lm%x:00200", | ||
393 | dev->id); | ||
394 | for (i = 0; i < ARRAY_SIZE(impd1->clks); i++) | ||
395 | clkdev_add(impd1->clks[i]); | ||
396 | 336 | ||
397 | for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { | 337 | for (i = 0; i < ARRAY_SIZE(impd1_devs); i++) { |
398 | struct impd1_device *idev = impd1_devs + i; | 338 | struct impd1_device *idev = impd1_devs + i; |
@@ -431,12 +371,9 @@ static int impd1_remove_one(struct device *dev, void *data) | |||
431 | static void impd1_remove(struct lm_device *dev) | 371 | static void impd1_remove(struct lm_device *dev) |
432 | { | 372 | { |
433 | struct impd1_module *impd1 = lm_get_drvdata(dev); | 373 | struct impd1_module *impd1 = lm_get_drvdata(dev); |
434 | int i; | ||
435 | 374 | ||
436 | device_for_each_child(&dev->dev, NULL, impd1_remove_one); | 375 | device_for_each_child(&dev->dev, NULL, impd1_remove_one); |
437 | 376 | integrator_impd1_clk_exit(dev->id); | |
438 | for (i = 0; i < ARRAY_SIZE(impd1->clks); i++) | ||
439 | clkdev_drop(impd1->clks[i]); | ||
440 | 377 | ||
441 | lm_set_drvdata(dev, NULL); | 378 | lm_set_drvdata(dev, NULL); |
442 | 379 | ||
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile index c776053e5bb4..ec3b88fe3e6d 100644 --- a/drivers/clk/versatile/Makefile +++ b/drivers/clk/versatile/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | # Makefile for Versatile-specific clocks | 1 | # Makefile for Versatile-specific clocks |
2 | obj-$(CONFIG_ICST) += clk-icst.o | 2 | obj-$(CONFIG_ICST) += clk-icst.o |
3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o | 3 | obj-$(CONFIG_ARCH_INTEGRATOR) += clk-integrator.o |
4 | obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o | ||
4 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o | 5 | obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o |
5 | obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o | 6 | obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o |
6 | obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o | 7 | obj-$(CONFIG_VEXPRESS_CONFIG) += clk-vexpress-osc.o |
diff --git a/drivers/clk/versatile/clk-impd1.c b/drivers/clk/versatile/clk-impd1.c new file mode 100644 index 000000000000..369139af2a3b --- /dev/null +++ b/drivers/clk/versatile/clk-impd1.c | |||
@@ -0,0 +1,97 @@ | |||
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 | } | ||
diff --git a/include/linux/platform_data/clk-integrator.h b/include/linux/platform_data/clk-integrator.h index 83fe9c283bb8..280edac9d0a5 100644 --- a/include/linux/platform_data/clk-integrator.h +++ b/include/linux/platform_data/clk-integrator.h | |||
@@ -1 +1,3 @@ | |||
1 | void integrator_clk_init(bool is_cp); | 1 | void integrator_clk_init(bool is_cp); |
2 | void integrator_impd1_clk_init(void __iomem *base, unsigned int id); | ||
3 | void integrator_impd1_clk_exit(unsigned int id); | ||