diff options
author | Tero Kristo <t-kristo@ti.com> | 2013-06-18 09:27:57 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-17 15:34:59 -0500 |
commit | b1a07b478b63f0a8f971b3a82ce34a67a9324547 (patch) | |
tree | dc5d86884961efff9caaa25c277eac3b0d3c58df /drivers/clk | |
parent | f38b0dd63f0d0cca753bf0997eefdfb23dcc9518 (diff) |
CLK: TI: add autoidle support
TI clk driver now routes some of the basic clocks through own
registration routine to allow autoidle support. This routine just
checks a couple of device node properties and adds autoidle support
if required, and just passes the registration forward to basic clocks.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/ti/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/ti/autoidle.c | 133 |
2 files changed, 134 insertions, 1 deletions
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 3dbb78dc9fca..7fa1a48df4f3 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | ifneq ($(CONFIG_OF),) | 1 | ifneq ($(CONFIG_OF),) |
2 | obj-y += clk.o | 2 | obj-y += clk.o autoidle.o |
3 | clk-common = dpll.o | 3 | clk-common = dpll.o |
4 | endif | 4 | endif |
diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c new file mode 100644 index 000000000000..8912ff80af34 --- /dev/null +++ b/drivers/clk/ti/autoidle.c | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * TI clock autoidle support | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments, Inc. | ||
5 | * | ||
6 | * Tero Kristo <t-kristo@ti.com> | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
13 | * kind, whether express or implied; without even the implied warranty | ||
14 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/clk-provider.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/of.h> | ||
22 | #include <linux/of_address.h> | ||
23 | #include <linux/clk/ti.h> | ||
24 | |||
25 | struct clk_ti_autoidle { | ||
26 | void __iomem *reg; | ||
27 | u8 shift; | ||
28 | u8 flags; | ||
29 | const char *name; | ||
30 | struct list_head node; | ||
31 | }; | ||
32 | |||
33 | #define AUTOIDLE_LOW 0x1 | ||
34 | |||
35 | static LIST_HEAD(autoidle_clks); | ||
36 | |||
37 | static void ti_allow_autoidle(struct clk_ti_autoidle *clk) | ||
38 | { | ||
39 | u32 val; | ||
40 | |||
41 | val = ti_clk_ll_ops->clk_readl(clk->reg); | ||
42 | |||
43 | if (clk->flags & AUTOIDLE_LOW) | ||
44 | val &= ~(1 << clk->shift); | ||
45 | else | ||
46 | val |= (1 << clk->shift); | ||
47 | |||
48 | ti_clk_ll_ops->clk_writel(val, clk->reg); | ||
49 | } | ||
50 | |||
51 | static void ti_deny_autoidle(struct clk_ti_autoidle *clk) | ||
52 | { | ||
53 | u32 val; | ||
54 | |||
55 | val = ti_clk_ll_ops->clk_readl(clk->reg); | ||
56 | |||
57 | if (clk->flags & AUTOIDLE_LOW) | ||
58 | val |= (1 << clk->shift); | ||
59 | else | ||
60 | val &= ~(1 << clk->shift); | ||
61 | |||
62 | ti_clk_ll_ops->clk_writel(val, clk->reg); | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks | ||
67 | * | ||
68 | * Enables hardware autoidle for all registered DT clocks, which have | ||
69 | * the feature. | ||
70 | */ | ||
71 | void of_ti_clk_allow_autoidle_all(void) | ||
72 | { | ||
73 | struct clk_ti_autoidle *c; | ||
74 | |||
75 | list_for_each_entry(c, &autoidle_clks, node) | ||
76 | ti_allow_autoidle(c); | ||
77 | } | ||
78 | |||
79 | /** | ||
80 | * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks | ||
81 | * | ||
82 | * Disables hardware autoidle for all registered DT clocks, which have | ||
83 | * the feature. | ||
84 | */ | ||
85 | void of_ti_clk_deny_autoidle_all(void) | ||
86 | { | ||
87 | struct clk_ti_autoidle *c; | ||
88 | |||
89 | list_for_each_entry(c, &autoidle_clks, node) | ||
90 | ti_deny_autoidle(c); | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock | ||
95 | * @node: pointer to the clock device node | ||
96 | * | ||
97 | * Checks if a clock has hardware autoidle support or not (check | ||
98 | * for presence of 'ti,autoidle-shift' property in the device tree | ||
99 | * node) and sets up the hardware autoidle feature for the clock | ||
100 | * if available. If autoidle is available, the clock is also added | ||
101 | * to the autoidle list for later processing. Returns 0 on success, | ||
102 | * negative error value on failure. | ||
103 | */ | ||
104 | int __init of_ti_clk_autoidle_setup(struct device_node *node) | ||
105 | { | ||
106 | u32 shift; | ||
107 | struct clk_ti_autoidle *clk; | ||
108 | |||
109 | /* Check if this clock has autoidle support or not */ | ||
110 | if (of_property_read_u32(node, "ti,autoidle-shift", &shift)) | ||
111 | return 0; | ||
112 | |||
113 | clk = kzalloc(sizeof(*clk), GFP_KERNEL); | ||
114 | |||
115 | if (!clk) | ||
116 | return -ENOMEM; | ||
117 | |||
118 | clk->shift = shift; | ||
119 | clk->name = node->name; | ||
120 | clk->reg = ti_clk_get_reg_addr(node, 0); | ||
121 | |||
122 | if (!clk->reg) { | ||
123 | kfree(clk); | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | |||
127 | if (of_property_read_bool(node, "ti,invert-autoidle-bit")) | ||
128 | clk->flags |= AUTOIDLE_LOW; | ||
129 | |||
130 | list_add(&clk->node, &autoidle_clks); | ||
131 | |||
132 | return 0; | ||
133 | } | ||