aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTero Kristo <t-kristo@ti.com>2013-06-18 09:27:57 -0400
committerMike Turquette <mturquette@linaro.org>2014-01-17 15:34:59 -0500
commitb1a07b478b63f0a8f971b3a82ce34a67a9324547 (patch)
treedc5d86884961efff9caaa25c277eac3b0d3c58df
parentf38b0dd63f0d0cca753bf0997eefdfb23dcc9518 (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>
-rw-r--r--Documentation/devicetree/bindings/clock/ti/autoidle.txt39
-rw-r--r--arch/arm/mach-omap2/clock.c6
-rw-r--r--drivers/clk/ti/Makefile2
-rw-r--r--drivers/clk/ti/autoidle.c133
-rw-r--r--include/linux/clk/ti.h9
5 files changed, 188 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/clock/ti/autoidle.txt b/Documentation/devicetree/bindings/clock/ti/autoidle.txt
new file mode 100644
index 000000000000..7c735dde9fe9
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/ti/autoidle.txt
@@ -0,0 +1,39 @@
1Binding for Texas Instruments autoidle clock.
2
3Binding status: Unstable - ABI compatibility may be broken in the future
4
5This binding uses the common clock binding[1]. It assumes a register mapped
6clock which can be put to idle automatically by hardware based on the usage
7and a configuration bit setting. Autoidle clock is never an individual
8clock, it is always a derivative of some basic clock like a gate, divider,
9or fixed-factor.
10
11[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
12
13Required properties:
14- reg : offset for the register controlling the autoidle
15- ti,autoidle-shift : bit shift of the autoidle enable bit
16- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0
17
18Examples:
19 dpll_core_m4_ck: dpll_core_m4_ck {
20 #clock-cells = <0>;
21 compatible = "ti,divider-clock";
22 clocks = <&dpll_core_x2_ck>;
23 ti,max-div = <31>;
24 ti,autoidle-shift = <8>;
25 reg = <0x2d38>;
26 ti,index-starts-at-one;
27 ti,invert-autoidle-bit;
28 };
29
30 dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck {
31 #clock-cells = <0>;
32 compatible = "ti,fixed-factor-clock";
33 clocks = <&dpll_usb_ck>;
34 ti,clock-div = <1>;
35 ti,autoidle-shift = <8>;
36 reg = <0x01b4>;
37 ti,clock-mult = <1>;
38 ti,invert-autoidle-bit;
39 };
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index c7c5d31e9082..238be3f1ddce 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -520,6 +520,9 @@ int omap2_clk_enable_autoidle_all(void)
520 list_for_each_entry(c, &clk_hw_omap_clocks, node) 520 list_for_each_entry(c, &clk_hw_omap_clocks, node)
521 if (c->ops && c->ops->allow_idle) 521 if (c->ops && c->ops->allow_idle)
522 c->ops->allow_idle(c); 522 c->ops->allow_idle(c);
523
524 of_ti_clk_allow_autoidle_all();
525
523 return 0; 526 return 0;
524} 527}
525 528
@@ -539,6 +542,9 @@ int omap2_clk_disable_autoidle_all(void)
539 list_for_each_entry(c, &clk_hw_omap_clocks, node) 542 list_for_each_entry(c, &clk_hw_omap_clocks, node)
540 if (c->ops && c->ops->deny_idle) 543 if (c->ops && c->ops->deny_idle)
541 c->ops->deny_idle(c); 544 c->ops->deny_idle(c);
545
546 of_ti_clk_deny_autoidle_all();
547
542 return 0; 548 return 0;
543} 549}
544 550
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 @@
1ifneq ($(CONFIG_OF),) 1ifneq ($(CONFIG_OF),)
2obj-y += clk.o 2obj-y += clk.o autoidle.o
3clk-common = dpll.o 3clk-common = dpll.o
4endif 4endif
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
25struct 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
35static LIST_HEAD(autoidle_clks);
36
37static 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
51static 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 */
71void 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 */
85void 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 */
104int __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}
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index 3f9de3973582..ca38ee3620b1 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -242,6 +242,15 @@ void ti_dt_clocks_register(struct ti_dt_clk *oclks);
242void ti_dt_clk_init_provider(struct device_node *np, int index); 242void ti_dt_clk_init_provider(struct device_node *np, int index);
243int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, 243int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
244 ti_of_clk_init_cb_t func); 244 ti_of_clk_init_cb_t func);
245int of_ti_clk_autoidle_setup(struct device_node *node);
246
247#ifdef CONFIG_OF
248void of_ti_clk_allow_autoidle_all(void);
249void of_ti_clk_deny_autoidle_all(void);
250#else
251static inline void of_ti_clk_allow_autoidle_all(void) { }
252static inline void of_ti_clk_deny_autoidle_all(void) { }
253#endif
245 254
246extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; 255extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
247extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; 256extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;