diff options
author | Robert Jarzmik <robert.jarzmik@free.fr> | 2014-07-30 16:50:59 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-09-30 15:31:30 -0400 |
commit | bda003036684b9779fca2b3d457621eaff9bcd0a (patch) | |
tree | ab1b69b8d74b6baa63c0dd021fbbf562f36c56e2 /drivers/clk | |
parent | 7d1311b93e58ed55f3a31cc8f94c4b8fe988a2b9 (diff) |
clk: add pxa clocks infrastructure
Add a the common code used by all PXA variants.
This is the first step in the transition from architecture defined
clocks (in arch/arm/mach-pxa) towards clock framework. The goal is to
have the same features (and not all the features) of the existing
clocks, and enable the transition of PXA to device-tree.
All PXA rely on a "CKEN" type clock, which :
- has a gate (bit in CKEN register)
- is generated from a PLL, generally divided
- has an alternate low power clock
Each variant will specialize the CKEN clock :
- pxa25x have no low power clock
- pxa27x in low power use always the 13 MHz ring oscillator
- pxa3xx in low power have specific dividers for each clock
The device-tree provides a list of CLK_* (ex: CLK_USB or CLK_I2C) to get
a handle on the clock. While pxa-clock.h will describe all the clocks of
all the variants, each variant will only use a subset of it.
Signed-off-by: Robert Jarzmik <robert.jarzmik@free.fr>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/pxa/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/pxa/clk-pxa.c | 97 | ||||
-rw-r--r-- | drivers/clk/pxa/clk-pxa.h | 107 |
4 files changed, 206 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index f537a0b1f798..7891e4edaa07 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile | |||
@@ -48,6 +48,7 @@ obj-$(CONFIG_ARCH_MMP) += mmp/ | |||
48 | endif | 48 | endif |
49 | obj-$(CONFIG_PLAT_ORION) += mvebu/ | 49 | obj-$(CONFIG_PLAT_ORION) += mvebu/ |
50 | obj-$(CONFIG_ARCH_MXS) += mxs/ | 50 | obj-$(CONFIG_ARCH_MXS) += mxs/ |
51 | obj-$(CONFIG_ARCH_PXA) += pxa/ | ||
51 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ | 52 | obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ |
52 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ | 53 | obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ |
53 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ | 54 | obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ |
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile new file mode 100644 index 000000000000..cb2bd8ff53da --- /dev/null +++ b/drivers/clk/pxa/Makefile | |||
@@ -0,0 +1 @@ | |||
obj-y += clk-pxa.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 | ||