diff options
author | Mike Turquette <mturquette@linaro.org> | 2014-09-30 15:49:42 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-09-30 15:49:42 -0400 |
commit | 38bf3a79785f50ecad01e0ea60bf779507032984 (patch) | |
tree | e97036f8b9accbc1a5fae496a4fab1b33f4e0b8a /drivers/clk | |
parent | 44b4aa97bea84fa8ac179155f147e3483cc7a6e0 (diff) | |
parent | 9ff25d7b58d8a4374886843ed3ed21f1ef17bf16 (diff) |
Merge branch 'clk-pxa27x' into clk-next
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/pxa/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/pxa/clk-pxa.c | 97 | ||||
-rw-r--r-- | drivers/clk/pxa/clk-pxa.h | 107 | ||||
-rw-r--r-- | drivers/clk/pxa/clk-pxa27x.c | 370 |
5 files changed, 577 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index 92a7f6c02394..8f3c04a91511 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -51,6 +51,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ | |||
51 | endif | 51 | endif |
52 | obj-$(CONFIG_PLAT_ORION) += mvebu/ | 52 | obj-$(CONFIG_PLAT_ORION) += mvebu/ |
53 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 53 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
54 | obj-$(CONFIG_ARCH_PXA) += pxa/ | ||
54 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ | 55 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ |
55 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 56 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
56 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ | 57 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ |
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile new file mode 100644 index 000000000000..4ff2abcd500b --- /dev/null +++ b/drivers/clk/pxa/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | obj-y += clk-pxa.o | ||
2 | obj-$(CONFIG_PXA27x) += clk-pxa27x.o | ||
diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c new file mode 100644 index 000000000000..ef3c05389c0a --- /dev/null +++ b/drivers/clk/pxa/clk-pxa.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Marvell PXA family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/clk-provider.h> | ||
15 | #include <linux/clkdev.h> | ||
16 | #include <linux/of.h> | ||
17 | |||
18 | #include <dt-bindings/clock/pxa-clock.h> | ||
19 | #include "clk-pxa.h" | ||
20 | |||
21 | DEFINE_SPINLOCK(lock); | ||
22 | |||
23 | static struct clk *pxa_clocks[CLK_MAX]; | ||
24 | static struct clk_onecell_data onecell_data = { | ||
25 | .clks = pxa_clocks, | ||
26 | .clk_num = CLK_MAX, | ||
27 | }; | ||
28 | |||
29 | #define to_pxa_clk(_hw) container_of(_hw, struct pxa_clk_cken, hw) | ||
30 | |||
31 | static unsigned long cken_recalc_rate(struct clk_hw *hw, | ||
32 | unsigned long parent_rate) | ||
33 | { | ||
34 | struct pxa_clk_cken *pclk = to_pxa_clk(hw); | ||
35 | struct clk_fixed_factor *fix; | ||
36 | |||
37 | if (!pclk->is_in_low_power || pclk->is_in_low_power()) | ||
38 | fix = &pclk->lp; | ||
39 | else | ||
40 | fix = &pclk->hp; | ||
41 | fix->hw.clk = hw->clk; | ||
42 | return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate); | ||
43 | } | ||
44 | |||
45 | static struct clk_ops cken_rate_ops = { | ||
46 | .recalc_rate = cken_recalc_rate, | ||
47 | }; | ||
48 | |||
49 | static u8 cken_get_parent(struct clk_hw *hw) | ||
50 | { | ||
51 | struct pxa_clk_cken *pclk = to_pxa_clk(hw); | ||
52 | |||
53 | if (!pclk->is_in_low_power) | ||
54 | return 0; | ||
55 | return pclk->is_in_low_power() ? 0 : 1; | ||
56 | } | ||
57 | |||
58 | static struct clk_ops cken_mux_ops = { | ||
59 | .get_parent = cken_get_parent, | ||
60 | .set_parent = dummy_clk_set_parent, | ||
61 | }; | ||
62 | |||
63 | void __init clkdev_pxa_register(int ckid, const char *con_id, | ||
64 | const char *dev_id, struct clk *clk) | ||
65 | { | ||
66 | if (!IS_ERR(clk) && (ckid != CLK_NONE)) | ||
67 | pxa_clocks[ckid] = clk; | ||
68 | if (!IS_ERR(clk)) | ||
69 | clk_register_clkdev(clk, con_id, dev_id); | ||
70 | } | ||
71 | |||
72 | int __init clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks) | ||
73 | { | ||
74 | int i; | ||
75 | struct pxa_clk_cken *pclk; | ||
76 | struct clk *clk; | ||
77 | |||
78 | for (i = 0; i < nb_clks; i++) { | ||
79 | pclk = clks + i; | ||
80 | pclk->gate.lock = &lock; | ||
81 | clk = clk_register_composite(NULL, pclk->name, | ||
82 | pclk->parent_names, 2, | ||
83 | &pclk->hw, &cken_mux_ops, | ||
84 | &pclk->hw, &cken_rate_ops, | ||
85 | &pclk->gate.hw, &clk_gate_ops, | ||
86 | pclk->flags); | ||
87 | clkdev_pxa_register(pclk->ckid, pclk->con_id, pclk->dev_id, | ||
88 | clk); | ||
89 | } | ||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static void __init pxa_dt_clocks_init(struct device_node *np) | ||
94 | { | ||
95 | of_clk_add_provider(np, of_clk_src_onecell_get, &onecell_data); | ||
96 | } | ||
97 | CLK_OF_DECLARE(pxa_clks, "marvell,pxa-clocks", pxa_dt_clocks_init); | ||
diff --git a/drivers/clk/pxa/clk-pxa.h b/drivers/clk/pxa/clk-pxa.h new file mode 100644 index 000000000000..5fe219d06b49 --- /dev/null +++ b/drivers/clk/pxa/clk-pxa.h | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Marvell PXA family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Common clock code for PXA clocks ("CKEN" type clocks + DT) | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #ifndef _CLK_PXA_ | ||
14 | #define _CLK_PXA_ | ||
15 | |||
16 | #define PARENTS(name) \ | ||
17 | static const char *name ## _parents[] __initconst | ||
18 | #define MUX_RO_RATE_RO_OPS(name, clk_name) \ | ||
19 | static struct clk_hw name ## _mux_hw; \ | ||
20 | static struct clk_hw name ## _rate_hw; \ | ||
21 | static struct clk_ops name ## _mux_ops = { \ | ||
22 | .get_parent = name ## _get_parent, \ | ||
23 | .set_parent = dummy_clk_set_parent, \ | ||
24 | }; \ | ||
25 | static struct clk_ops name ## _rate_ops = { \ | ||
26 | .recalc_rate = name ## _get_rate, \ | ||
27 | }; \ | ||
28 | static struct clk *clk_register_ ## name(void) \ | ||
29 | { \ | ||
30 | return clk_register_composite(NULL, clk_name, \ | ||
31 | name ## _parents, \ | ||
32 | ARRAY_SIZE(name ## _parents), \ | ||
33 | &name ## _mux_hw, &name ## _mux_ops, \ | ||
34 | &name ## _rate_hw, &name ## _rate_ops, \ | ||
35 | NULL, NULL, CLK_GET_RATE_NOCACHE); \ | ||
36 | } | ||
37 | |||
38 | #define RATE_RO_OPS(name, clk_name) \ | ||
39 | static struct clk_hw name ## _rate_hw; \ | ||
40 | static struct clk_ops name ## _rate_ops = { \ | ||
41 | .recalc_rate = name ## _get_rate, \ | ||
42 | }; \ | ||
43 | static struct clk *clk_register_ ## name(void) \ | ||
44 | { \ | ||
45 | return clk_register_composite(NULL, clk_name, \ | ||
46 | name ## _parents, \ | ||
47 | ARRAY_SIZE(name ## _parents), \ | ||
48 | NULL, NULL, \ | ||
49 | &name ## _rate_hw, &name ## _rate_ops, \ | ||
50 | NULL, NULL, CLK_GET_RATE_NOCACHE); \ | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * CKEN clock type | ||
55 | * This clock takes it source from 2 possible parents : | ||
56 | * - a low power parent | ||
57 | * - a normal parent | ||
58 | * | ||
59 | * +------------+ +-----------+ | ||
60 | * | Low Power | --- | x mult_lp | | ||
61 | * | Clock | | / div_lp |\ | ||
62 | * +------------+ +-----------+ \+-----+ +-----------+ | ||
63 | * | Mux |---| CKEN gate | | ||
64 | * +------------+ +-----------+ /+-----+ +-----------+ | ||
65 | * | High Power | | x mult_hp |/ | ||
66 | * | Clock | --- | / div_hp | | ||
67 | * +------------+ +-----------+ | ||
68 | */ | ||
69 | struct pxa_clk_cken { | ||
70 | struct clk_hw hw; | ||
71 | int ckid; | ||
72 | const char *name; | ||
73 | const char *dev_id; | ||
74 | const char *con_id; | ||
75 | const char **parent_names; | ||
76 | struct clk_fixed_factor lp; | ||
77 | struct clk_fixed_factor hp; | ||
78 | struct clk_gate gate; | ||
79 | bool (*is_in_low_power)(void); | ||
80 | const unsigned long flags; | ||
81 | }; | ||
82 | |||
83 | #define PXA_CKEN(_dev_id, _con_id, _name, parents, _mult_lp, _div_lp, \ | ||
84 | _mult_hp, _div_hp, is_lp, _cken_reg, _cken_bit, flag) \ | ||
85 | { .ckid = CLK_ ## _name, .name = #_name, \ | ||
86 | .dev_id = _dev_id, .con_id = _con_id, .parent_names = parents,\ | ||
87 | .lp = { .mult = _mult_lp, .div = _div_lp }, \ | ||
88 | .hp = { .mult = _mult_hp, .div = _div_hp }, \ | ||
89 | .is_in_low_power = is_lp, \ | ||
90 | .gate = { .reg = (void __iomem *)_cken_reg, .bit_idx = _cken_bit }, \ | ||
91 | .flags = flag, \ | ||
92 | } | ||
93 | #define PXA_CKEN_1RATE(dev_id, con_id, name, parents, cken_reg, \ | ||
94 | cken_bit, flag) \ | ||
95 | PXA_CKEN(dev_id, con_id, name, parents, 1, 1, 1, 1, \ | ||
96 | NULL, cken_reg, cken_bit, flag) | ||
97 | |||
98 | static int dummy_clk_set_parent(struct clk_hw *hw, u8 index) | ||
99 | { | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | extern void clkdev_pxa_register(int ckid, const char *con_id, | ||
104 | const char *dev_id, struct clk *clk); | ||
105 | extern int clk_pxa_cken_init(struct pxa_clk_cken *clks, int nb_clks); | ||
106 | |||
107 | #endif | ||
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c new file mode 100644 index 000000000000..b345cc791e5d --- /dev/null +++ b/drivers/clk/pxa/clk-pxa27x.c | |||
@@ -0,0 +1,370 @@ | |||
1 | /* | ||
2 | * Marvell PXA27x family clocks | ||
3 | * | ||
4 | * Copyright (C) 2014 Robert Jarzmik | ||
5 | * | ||
6 | * Heavily inspired from former arch/arm/mach-pxa/clock.c. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/clk-provider.h> | ||
14 | #include <mach/pxa2xx-regs.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/clk.h> | ||
17 | #include <linux/clkdev.h> | ||
18 | #include <linux/of.h> | ||
19 | |||
20 | #include <dt-bindings/clock/pxa-clock.h> | ||
21 | #include "clk-pxa.h" | ||
22 | |||
23 | #define KHz 1000 | ||
24 | #define MHz (1000 * 1000) | ||
25 | |||
26 | enum { | ||
27 | PXA_CORE_13Mhz = 0, | ||
28 | PXA_CORE_RUN, | ||
29 | PXA_CORE_TURBO, | ||
30 | }; | ||
31 | |||
32 | enum { | ||
33 | PXA_BUS_13Mhz = 0, | ||
34 | PXA_BUS_RUN, | ||
35 | }; | ||
36 | |||
37 | enum { | ||
38 | PXA_LCD_13Mhz = 0, | ||
39 | PXA_LCD_RUN, | ||
40 | }; | ||
41 | |||
42 | enum { | ||
43 | PXA_MEM_13Mhz = 0, | ||
44 | PXA_MEM_SYSTEM_BUS, | ||
45 | PXA_MEM_RUN, | ||
46 | }; | ||
47 | |||
48 | static const char * const get_freq_khz[] = { | ||
49 | "core", "run", "cpll", "memory", | ||
50 | "system_bus" | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * Get the clock frequency as reflected by CCSR and the turbo flag. | ||
55 | * We assume these values have been applied via a fcs. | ||
56 | * If info is not 0 we also display the current settings. | ||
57 | */ | ||
58 | unsigned int pxa27x_get_clk_frequency_khz(int info) | ||
59 | { | ||
60 | struct clk *clk; | ||
61 | unsigned long clks[5]; | ||
62 | int i; | ||
63 | |||
64 | for (i = 0; i < 5; i++) { | ||
65 | clk = clk_get(NULL, get_freq_khz[i]); | ||
66 | if (IS_ERR(clk)) { | ||
67 | clks[i] = 0; | ||
68 | } else { | ||
69 | clks[i] = clk_get_rate(clk); | ||
70 | clk_put(clk); | ||
71 | } | ||
72 | } | ||
73 | if (info) { | ||
74 | pr_info("Run Mode clock: %ld.%02ldMHz\n", | ||
75 | clks[1] / 1000000, (clks[1] % 1000000) / 10000); | ||
76 | pr_info("Turbo Mode clock: %ld.%02ldMHz\n", | ||
77 | clks[2] / 1000000, (clks[2] % 1000000) / 10000); | ||
78 | pr_info("Memory clock: %ld.%02ldMHz\n", | ||
79 | clks[3] / 1000000, (clks[3] % 1000000) / 10000); | ||
80 | pr_info("System bus clock: %ld.%02ldMHz\n", | ||
81 | clks[4] / 1000000, (clks[4] % 1000000) / 10000); | ||
82 | } | ||
83 | return (unsigned int)clks[0]; | ||
84 | } | ||
85 | |||
86 | bool pxa27x_is_ppll_disabled(void) | ||
87 | { | ||
88 | unsigned long ccsr = CCSR; | ||
89 | |||
90 | return ccsr & (1 << CCCR_PPDIS_BIT); | ||
91 | } | ||
92 | |||
93 | #define PXA27X_CKEN(dev_id, con_id, parents, mult_hp, div_hp, \ | ||
94 | bit, is_lp, flags) \ | ||
95 | PXA_CKEN(dev_id, con_id, bit, parents, 1, 1, mult_hp, div_hp, \ | ||
96 | is_lp, &CKEN, CKEN_ ## bit, flags) | ||
97 | #define PXA27X_PBUS_CKEN(dev_id, con_id, bit, mult_hp, div_hp, delay) \ | ||
98 | PXA27X_CKEN(dev_id, con_id, pxa27x_pbus_parents, mult_hp, \ | ||
99 | div_hp, bit, pxa27x_is_ppll_disabled, 0) | ||
100 | |||
101 | PARENTS(pxa27x_pbus) = { "osc_13mhz", "ppll_312mhz" }; | ||
102 | PARENTS(pxa27x_sbus) = { "system_bus", "system_bus" }; | ||
103 | PARENTS(pxa27x_32Mhz_bus) = { "osc_32_768khz", "osc_32_768khz" }; | ||
104 | PARENTS(pxa27x_lcd_bus) = { "lcd_base", "lcd_base" }; | ||
105 | PARENTS(pxa27x_membus) = { "lcd_base", "lcd_base" }; | ||
106 | |||
107 | #define PXA27X_CKEN_1RATE(dev_id, con_id, bit, parents, delay) \ | ||
108 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
109 | &CKEN, CKEN_ ## bit, 0) | ||
110 | #define PXA27X_CKEN_1RATE_AO(dev_id, con_id, bit, parents, delay) \ | ||
111 | PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \ | ||
112 | &CKEN, CKEN_ ## bit, CLK_IGNORE_UNUSED) | ||
113 | |||
114 | static struct pxa_clk_cken pxa27x_clocks[] = { | ||
115 | PXA27X_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 2, 42, 1), | ||
116 | PXA27X_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 2, 42, 1), | ||
117 | PXA27X_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 2, 42, 1), | ||
118 | PXA27X_PBUS_CKEN("pxa2xx-i2s", NULL, I2S, 2, 51, 0), | ||
119 | PXA27X_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 19, 0), | ||
120 | PXA27X_PBUS_CKEN("pxa27x-udc", NULL, USB, 2, 13, 5), | ||
121 | PXA27X_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC, 2, 32, 0), | ||
122 | PXA27X_PBUS_CKEN("pxa2xx-ir", "FICPCLK", FICP, 2, 13, 0), | ||
123 | PXA27X_PBUS_CKEN("pxa27x-ohci", NULL, USBHOST, 2, 13, 0), | ||
124 | PXA27X_PBUS_CKEN("pxa2xx-i2c.1", NULL, PWRI2C, 1, 24, 0), | ||
125 | PXA27X_PBUS_CKEN("pxa27x-ssp.0", NULL, SSP1, 1, 24, 0), | ||
126 | PXA27X_PBUS_CKEN("pxa27x-ssp.1", NULL, SSP2, 1, 24, 0), | ||
127 | PXA27X_PBUS_CKEN("pxa27x-ssp.2", NULL, SSP3, 1, 24, 0), | ||
128 | PXA27X_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 24, 0), | ||
129 | PXA27X_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 24, 0), | ||
130 | PXA27X_PBUS_CKEN(NULL, "MSLCLK", MSL, 2, 13, 0), | ||
131 | PXA27X_PBUS_CKEN(NULL, "USIMCLK", USIM, 2, 13, 0), | ||
132 | PXA27X_PBUS_CKEN(NULL, "MSTKCLK", MEMSTK, 2, 32, 0), | ||
133 | PXA27X_PBUS_CKEN(NULL, "AC97CLK", AC97, 1, 1, 0), | ||
134 | PXA27X_PBUS_CKEN(NULL, "AC97CONFCLK", AC97CONF, 1, 1, 0), | ||
135 | PXA27X_PBUS_CKEN(NULL, "OSTIMER0", OSTIMER, 1, 96, 0), | ||
136 | |||
137 | PXA27X_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD, | ||
138 | pxa27x_32Mhz_bus_parents, 0), | ||
139 | PXA27X_CKEN_1RATE(NULL, "IMCLK", IM, pxa27x_sbus_parents, 0), | ||
140 | PXA27X_CKEN_1RATE("pxa2xx-fb", NULL, LCD, pxa27x_lcd_bus_parents, 0), | ||
141 | PXA27X_CKEN_1RATE("pxa27x-camera.0", NULL, CAMERA, | ||
142 | pxa27x_lcd_bus_parents, 0), | ||
143 | PXA27X_CKEN_1RATE_AO("pxa2xx-pcmcia", NULL, MEMC, | ||
144 | pxa27x_membus_parents, 0), | ||
145 | |||
146 | }; | ||
147 | |||
148 | static unsigned long clk_pxa27x_cpll_get_rate(struct clk_hw *hw, | ||
149 | unsigned long parent_rate) | ||
150 | { | ||
151 | unsigned long clkcfg; | ||
152 | unsigned int t, ht; | ||
153 | unsigned int l, L, n2, N; | ||
154 | unsigned long ccsr = CCSR; | ||
155 | |||
156 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
157 | t = clkcfg & (1 << 0); | ||
158 | ht = clkcfg & (1 << 2); | ||
159 | |||
160 | l = ccsr & CCSR_L_MASK; | ||
161 | n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
162 | L = l * parent_rate; | ||
163 | N = (L * n2) / 2; | ||
164 | |||
165 | return t ? N : L; | ||
166 | } | ||
167 | PARENTS(clk_pxa27x_cpll) = { "osc_13mhz" }; | ||
168 | RATE_RO_OPS(clk_pxa27x_cpll, "cpll"); | ||
169 | |||
170 | static unsigned long clk_pxa27x_lcd_base_get_rate(struct clk_hw *hw, | ||
171 | unsigned long parent_rate) | ||
172 | { | ||
173 | unsigned int l, osc_forced; | ||
174 | unsigned long ccsr = CCSR; | ||
175 | unsigned long cccr = CCCR; | ||
176 | |||
177 | l = ccsr & CCSR_L_MASK; | ||
178 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
179 | if (osc_forced) { | ||
180 | if (cccr & (1 << CCCR_LCD_26_BIT)) | ||
181 | return parent_rate * 2; | ||
182 | else | ||
183 | return parent_rate; | ||
184 | } | ||
185 | |||
186 | if (l <= 7) | ||
187 | return parent_rate; | ||
188 | if (l <= 16) | ||
189 | return parent_rate / 2; | ||
190 | return parent_rate / 4; | ||
191 | } | ||
192 | |||
193 | static u8 clk_pxa27x_lcd_base_get_parent(struct clk_hw *hw) | ||
194 | { | ||
195 | unsigned int osc_forced; | ||
196 | unsigned long ccsr = CCSR; | ||
197 | |||
198 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
199 | if (osc_forced) | ||
200 | return PXA_LCD_13Mhz; | ||
201 | else | ||
202 | return PXA_LCD_RUN; | ||
203 | } | ||
204 | |||
205 | PARENTS(clk_pxa27x_lcd_base) = { "osc_13mhz", "run" }; | ||
206 | MUX_RO_RATE_RO_OPS(clk_pxa27x_lcd_base, "lcd_base"); | ||
207 | |||
208 | static void __init pxa27x_register_plls(void) | ||
209 | { | ||
210 | clk_register_fixed_rate(NULL, "osc_13mhz", NULL, | ||
211 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
212 | 13 * MHz); | ||
213 | clk_register_fixed_rate(NULL, "osc_32_768khz", NULL, | ||
214 | CLK_GET_RATE_NOCACHE | CLK_IS_ROOT, | ||
215 | 32768 * KHz); | ||
216 | clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0); | ||
217 | clk_register_fixed_factor(NULL, "ppll_312mhz", "osc_13mhz", 0, 24, 1); | ||
218 | } | ||
219 | |||
220 | static unsigned long clk_pxa27x_core_get_rate(struct clk_hw *hw, | ||
221 | unsigned long parent_rate) | ||
222 | { | ||
223 | unsigned long clkcfg; | ||
224 | unsigned int t, ht, b, osc_forced; | ||
225 | unsigned long ccsr = CCSR; | ||
226 | |||
227 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
228 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
229 | t = clkcfg & (1 << 0); | ||
230 | ht = clkcfg & (1 << 2); | ||
231 | b = clkcfg & (1 << 3); | ||
232 | |||
233 | if (osc_forced) | ||
234 | return parent_rate; | ||
235 | if (ht) | ||
236 | return parent_rate / 2; | ||
237 | else | ||
238 | return parent_rate; | ||
239 | } | ||
240 | |||
241 | static u8 clk_pxa27x_core_get_parent(struct clk_hw *hw) | ||
242 | { | ||
243 | unsigned long clkcfg; | ||
244 | unsigned int t, ht, b, osc_forced; | ||
245 | unsigned long ccsr = CCSR; | ||
246 | |||
247 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
248 | if (osc_forced) | ||
249 | return PXA_CORE_13Mhz; | ||
250 | |||
251 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
252 | t = clkcfg & (1 << 0); | ||
253 | ht = clkcfg & (1 << 2); | ||
254 | b = clkcfg & (1 << 3); | ||
255 | |||
256 | if (ht || t) | ||
257 | return PXA_CORE_TURBO; | ||
258 | return PXA_CORE_RUN; | ||
259 | } | ||
260 | PARENTS(clk_pxa27x_core) = { "osc_13mhz", "run", "cpll" }; | ||
261 | MUX_RO_RATE_RO_OPS(clk_pxa27x_core, "core"); | ||
262 | |||
263 | static unsigned long clk_pxa27x_run_get_rate(struct clk_hw *hw, | ||
264 | unsigned long parent_rate) | ||
265 | { | ||
266 | unsigned long ccsr = CCSR; | ||
267 | unsigned int n2 = (ccsr & CCSR_N2_MASK) >> CCSR_N2_SHIFT; | ||
268 | |||
269 | return (parent_rate / n2) * 2; | ||
270 | } | ||
271 | PARENTS(clk_pxa27x_run) = { "cpll" }; | ||
272 | RATE_RO_OPS(clk_pxa27x_run, "run"); | ||
273 | |||
274 | static void __init pxa27x_register_core(void) | ||
275 | { | ||
276 | clk_register_clk_pxa27x_cpll(); | ||
277 | clk_register_clk_pxa27x_run(); | ||
278 | |||
279 | clkdev_pxa_register(CLK_CORE, "core", NULL, | ||
280 | clk_register_clk_pxa27x_core()); | ||
281 | } | ||
282 | |||
283 | static unsigned long clk_pxa27x_system_bus_get_rate(struct clk_hw *hw, | ||
284 | unsigned long parent_rate) | ||
285 | { | ||
286 | unsigned long clkcfg; | ||
287 | unsigned int b, osc_forced; | ||
288 | unsigned long ccsr = CCSR; | ||
289 | |||
290 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
291 | asm("mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg)); | ||
292 | b = clkcfg & (1 << 3); | ||
293 | |||
294 | if (osc_forced) | ||
295 | return parent_rate; | ||
296 | if (b) | ||
297 | return parent_rate / 2; | ||
298 | else | ||
299 | return parent_rate; | ||
300 | } | ||
301 | |||
302 | static u8 clk_pxa27x_system_bus_get_parent(struct clk_hw *hw) | ||
303 | { | ||
304 | unsigned int osc_forced; | ||
305 | unsigned long ccsr = CCSR; | ||
306 | |||
307 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
308 | if (osc_forced) | ||
309 | return PXA_BUS_13Mhz; | ||
310 | else | ||
311 | return PXA_BUS_RUN; | ||
312 | } | ||
313 | |||
314 | PARENTS(clk_pxa27x_system_bus) = { "osc_13mhz", "run" }; | ||
315 | MUX_RO_RATE_RO_OPS(clk_pxa27x_system_bus, "system_bus"); | ||
316 | |||
317 | static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw, | ||
318 | unsigned long parent_rate) | ||
319 | { | ||
320 | unsigned int a, l, osc_forced; | ||
321 | unsigned long cccr = CCCR; | ||
322 | unsigned long ccsr = CCSR; | ||
323 | |||
324 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
325 | a = cccr & CCCR_A_BIT; | ||
326 | l = ccsr & CCSR_L_MASK; | ||
327 | |||
328 | if (osc_forced || a) | ||
329 | return parent_rate; | ||
330 | if (l <= 10) | ||
331 | return parent_rate; | ||
332 | if (l <= 20) | ||
333 | return parent_rate / 2; | ||
334 | return parent_rate / 4; | ||
335 | } | ||
336 | |||
337 | static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw) | ||
338 | { | ||
339 | unsigned int osc_forced, a; | ||
340 | unsigned long cccr = CCCR; | ||
341 | unsigned long ccsr = CCSR; | ||
342 | |||
343 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | ||
344 | a = cccr & CCCR_A_BIT; | ||
345 | if (osc_forced) | ||
346 | return PXA_MEM_13Mhz; | ||
347 | if (a) | ||
348 | return PXA_MEM_SYSTEM_BUS; | ||
349 | else | ||
350 | return PXA_MEM_RUN; | ||
351 | } | ||
352 | |||
353 | PARENTS(clk_pxa27x_memory) = { "osc_13mhz", "system_bus", "run" }; | ||
354 | MUX_RO_RATE_RO_OPS(clk_pxa27x_memory, "memory"); | ||
355 | |||
356 | static void __init pxa27x_base_clocks_init(void) | ||
357 | { | ||
358 | pxa27x_register_plls(); | ||
359 | pxa27x_register_core(); | ||
360 | clk_register_clk_pxa27x_system_bus(); | ||
361 | clk_register_clk_pxa27x_memory(); | ||
362 | clk_register_clk_pxa27x_lcd_base(); | ||
363 | } | ||
364 | |||
365 | static int __init pxa27x_clocks_init(void) | ||
366 | { | ||
367 | pxa27x_base_clocks_init(); | ||
368 | return clk_pxa_cken_init(pxa27x_clocks, ARRAY_SIZE(pxa27x_clocks)); | ||
369 | } | ||
370 | postcore_initcall(pxa27x_clocks_init); | ||