aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2014-09-05 08:21:34 -0400
committerMike Turquette <mturquette@linaro.org>2014-09-26 19:51:42 -0400
commitc873d14d30b838a516a94967242322d4b73e79e7 (patch)
tree2f9768c73c55c7667b93bca59eefb6dfd5af1f81 /drivers
parentdb0bcc33a8aabab462c996baeac619f21616d938 (diff)
clk: add gpio gated clock
The added gpio-gate-clock is a basic clock that can be enabled and disabled trough a gpio output. The DT binding document for the clock is also added. For EPROBE_DEFER handling the registering of the clock has to be delayed until of_clk_get() call time. Signed-off-by: Jyri Sarha <jsarha@ti.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-gpio-gate.c204
2 files changed, 205 insertions, 0 deletions
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 27c542ba9e73..92a7f6c02394 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o
9obj-$(CONFIG_COMMON_CLK) += clk-mux.o 9obj-$(CONFIG_COMMON_CLK) += clk-mux.o
10obj-$(CONFIG_COMMON_CLK) += clk-composite.o 10obj-$(CONFIG_COMMON_CLK) += clk-composite.o
11obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o 11obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
12obj-$(CONFIG_COMMON_CLK) += clk-gpio-gate.o
12ifeq ($(CONFIG_OF), y) 13ifeq ($(CONFIG_OF), y)
13obj-$(CONFIG_COMMON_CLK) += clk-conf.o 14obj-$(CONFIG_COMMON_CLK) += clk-conf.o
14endif 15endif
diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c
new file mode 100644
index 000000000000..9dde88533684
--- /dev/null
+++ b/drivers/clk/clk-gpio-gate.c
@@ -0,0 +1,204 @@
1/*
2 * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - http://www.ti.com
3 * Author: Jyri Sarha <jsarha@ti.com>
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 * Gpio gated clock implementation
10 */
11
12#include <linux/clk-provider.h>
13#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/gpio.h>
16#include <linux/of_gpio.h>
17#include <linux/err.h>
18#include <linux/device.h>
19
20/**
21 * DOC: basic gpio gated clock which can be enabled and disabled
22 * with gpio output
23 * Traits of this clock:
24 * prepare - clk_(un)prepare only ensures parent is (un)prepared
25 * enable - clk_enable and clk_disable are functional & control gpio
26 * rate - inherits rate from parent. No clk_set_rate support
27 * parent - fixed parent. No clk_set_parent support
28 */
29
30#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
31
32static int clk_gpio_gate_enable(struct clk_hw *hw)
33{
34 struct clk_gpio *clk = to_clk_gpio(hw);
35
36 gpiod_set_value(clk->gpiod, 1);
37
38 return 0;
39}
40
41static void clk_gpio_gate_disable(struct clk_hw *hw)
42{
43 struct clk_gpio *clk = to_clk_gpio(hw);
44
45 gpiod_set_value(clk->gpiod, 0);
46}
47
48static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
49{
50 struct clk_gpio *clk = to_clk_gpio(hw);
51
52 return gpiod_get_value(clk->gpiod);
53}
54
55const struct clk_ops clk_gpio_gate_ops = {
56 .enable = clk_gpio_gate_enable,
57 .disable = clk_gpio_gate_disable,
58 .is_enabled = clk_gpio_gate_is_enabled,
59};
60EXPORT_SYMBOL_GPL(clk_gpio_gate_ops);
61
62/**
63 * clk_register_gpio - register a gpip clock with the clock framework
64 * @dev: device that is registering this clock
65 * @name: name of this clock
66 * @parent_name: name of this clock's parent
67 * @gpiod: gpio descriptor to gate this clock
68 */
69struct clk *clk_register_gpio_gate(struct device *dev, const char *name,
70 const char *parent_name, struct gpio_desc *gpiod,
71 unsigned long flags)
72{
73 struct clk_gpio *clk_gpio = NULL;
74 struct clk *clk = ERR_PTR(-EINVAL);
75 struct clk_init_data init = { NULL };
76 unsigned long gpio_flags;
77 int err;
78
79 if (gpiod_is_active_low(gpiod))
80 gpio_flags = GPIOF_OUT_INIT_HIGH;
81 else
82 gpio_flags = GPIOF_OUT_INIT_LOW;
83
84 if (dev)
85 err = devm_gpio_request_one(dev, desc_to_gpio(gpiod),
86 gpio_flags, name);
87 else
88 err = gpio_request_one(desc_to_gpio(gpiod), gpio_flags, name);
89
90 if (err) {
91 pr_err("%s: %s: Error requesting clock control gpio %u\n",
92 __func__, name, desc_to_gpio(gpiod));
93 return ERR_PTR(err);
94 }
95
96 if (dev)
97 clk_gpio = devm_kzalloc(dev, sizeof(struct clk_gpio),
98 GFP_KERNEL);
99 else
100 clk_gpio = kzalloc(sizeof(struct clk_gpio), GFP_KERNEL);
101
102 if (!clk_gpio) {
103 clk = ERR_PTR(-ENOMEM);
104 goto clk_register_gpio_gate_err;
105 }
106
107 init.name = name;
108 init.ops = &clk_gpio_gate_ops;
109 init.flags = flags | CLK_IS_BASIC;
110 init.parent_names = (parent_name ? &parent_name : NULL);
111 init.num_parents = (parent_name ? 1 : 0);
112
113 clk_gpio->gpiod = gpiod;
114 clk_gpio->hw.init = &init;
115
116 clk = clk_register(dev, &clk_gpio->hw);
117
118 if (!IS_ERR(clk))
119 return clk;
120
121 if (!dev)
122 kfree(clk_gpio);
123
124clk_register_gpio_gate_err:
125 gpiod_put(gpiod);
126
127 return clk;
128}
129EXPORT_SYMBOL_GPL(clk_register_gpio_gate);
130
131#ifdef CONFIG_OF
132/**
133 * The clk_register_gpio_gate has to be delayed, because the EPROBE_DEFER
134 * can not be handled properly at of_clk_init() call time.
135 */
136
137struct clk_gpio_gate_delayed_register_data {
138 struct device_node *node;
139 struct mutex lock;
140 struct clk *clk;
141};
142
143static struct clk *of_clk_gpio_gate_delayed_register_get(
144 struct of_phandle_args *clkspec,
145 void *_data)
146{
147 struct clk_gpio_gate_delayed_register_data *data = _data;
148 struct clk *clk;
149 const char *clk_name = data->node->name;
150 const char *parent_name;
151 struct gpio_desc *gpiod;
152 int gpio;
153
154 mutex_lock(&data->lock);
155
156 if (data->clk) {
157 mutex_unlock(&data->lock);
158 return data->clk;
159 }
160
161 gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, NULL);
162 if (gpio < 0) {
163 mutex_unlock(&data->lock);
164 if (gpio != -EPROBE_DEFER)
165 pr_err("%s: %s: Can't get 'enable-gpios' DT property\n",
166 __func__, clk_name);
167 return ERR_PTR(gpio);
168 }
169 gpiod = gpio_to_desc(gpio);
170
171 parent_name = of_clk_get_parent_name(data->node, 0);
172
173 clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpiod, 0);
174 if (IS_ERR(clk)) {
175 mutex_unlock(&data->lock);
176 return clk;
177 }
178
179 data->clk = clk;
180 mutex_unlock(&data->lock);
181
182 return clk;
183}
184
185/**
186 * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock
187 */
188void __init of_gpio_gate_clk_setup(struct device_node *node)
189{
190 struct clk_gpio_gate_delayed_register_data *data;
191
192 data = kzalloc(sizeof(struct clk_gpio_gate_delayed_register_data),
193 GFP_KERNEL);
194 if (!data)
195 return;
196
197 data->node = node;
198 mutex_init(&data->lock);
199
200 of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data);
201}
202EXPORT_SYMBOL_GPL(of_gpio_gate_clk_setup);
203CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
204#endif