1e1bd55e5SStephen Boyd // SPDX-License-Identifier: GPL-2.0
2bb68a4f1SSergej Sawazki /*
35f1d8970SAlexander A. Klimov * Copyright (C) 2013 - 2014 Texas Instruments Incorporated - https://www.ti.com
4bb68a4f1SSergej Sawazki *
5bb68a4f1SSergej Sawazki * Authors:
6bb68a4f1SSergej Sawazki * Jyri Sarha <jsarha@ti.com>
7bb68a4f1SSergej Sawazki * Sergej Sawazki <ce3a@gmx.de>
8bb68a4f1SSergej Sawazki *
9bb68a4f1SSergej Sawazki * Gpio controlled clock implementation
10bb68a4f1SSergej Sawazki */
11bb68a4f1SSergej Sawazki
12bb68a4f1SSergej Sawazki #include <linux/clk-provider.h>
13bb68a4f1SSergej Sawazki #include <linux/export.h>
14bb68a4f1SSergej Sawazki #include <linux/slab.h>
15bb68a4f1SSergej Sawazki #include <linux/gpio/consumer.h>
16bb68a4f1SSergej Sawazki #include <linux/err.h>
17bb68a4f1SSergej Sawazki #include <linux/device.h>
18*a96cbb14SRob Herring #include <linux/of.h>
1914b04f28SStephen Boyd #include <linux/platform_device.h>
20bb68a4f1SSergej Sawazki
21bb68a4f1SSergej Sawazki /**
22bb68a4f1SSergej Sawazki * DOC: basic gpio gated clock which can be enabled and disabled
23bb68a4f1SSergej Sawazki * with gpio output
24bb68a4f1SSergej Sawazki * Traits of this clock:
25bb68a4f1SSergej Sawazki * prepare - clk_(un)prepare only ensures parent is (un)prepared
26bb68a4f1SSergej Sawazki * enable - clk_enable and clk_disable are functional & control gpio
27bb68a4f1SSergej Sawazki * rate - inherits rate from parent. No clk_set_rate support
28bb68a4f1SSergej Sawazki * parent - fixed parent. No clk_set_parent support
29bb68a4f1SSergej Sawazki */
30bb68a4f1SSergej Sawazki
319a9b5a4aSStephen Boyd /**
329a9b5a4aSStephen Boyd * struct clk_gpio - gpio gated clock
339a9b5a4aSStephen Boyd *
349a9b5a4aSStephen Boyd * @hw: handle between common and hardware-specific interfaces
359a9b5a4aSStephen Boyd * @gpiod: gpio descriptor
369a9b5a4aSStephen Boyd *
379a9b5a4aSStephen Boyd * Clock with a gpio control for enabling and disabling the parent clock
389a9b5a4aSStephen Boyd * or switching between two parents by asserting or deasserting the gpio.
399a9b5a4aSStephen Boyd *
409a9b5a4aSStephen Boyd * Implements .enable, .disable and .is_enabled or
419a9b5a4aSStephen Boyd * .get_parent, .set_parent and .determine_rate depending on which clk_ops
429a9b5a4aSStephen Boyd * is used.
439a9b5a4aSStephen Boyd */
449a9b5a4aSStephen Boyd struct clk_gpio {
459a9b5a4aSStephen Boyd struct clk_hw hw;
469a9b5a4aSStephen Boyd struct gpio_desc *gpiod;
479a9b5a4aSStephen Boyd };
489a9b5a4aSStephen Boyd
499a9b5a4aSStephen Boyd #define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw)
509a9b5a4aSStephen Boyd
clk_gpio_gate_enable(struct clk_hw * hw)51bb68a4f1SSergej Sawazki static int clk_gpio_gate_enable(struct clk_hw *hw)
52bb68a4f1SSergej Sawazki {
53bb68a4f1SSergej Sawazki struct clk_gpio *clk = to_clk_gpio(hw);
54bb68a4f1SSergej Sawazki
55bb68a4f1SSergej Sawazki gpiod_set_value(clk->gpiod, 1);
56bb68a4f1SSergej Sawazki
57bb68a4f1SSergej Sawazki return 0;
58bb68a4f1SSergej Sawazki }
59bb68a4f1SSergej Sawazki
clk_gpio_gate_disable(struct clk_hw * hw)60bb68a4f1SSergej Sawazki static void clk_gpio_gate_disable(struct clk_hw *hw)
61bb68a4f1SSergej Sawazki {
62bb68a4f1SSergej Sawazki struct clk_gpio *clk = to_clk_gpio(hw);
63bb68a4f1SSergej Sawazki
64bb68a4f1SSergej Sawazki gpiod_set_value(clk->gpiod, 0);
65bb68a4f1SSergej Sawazki }
66bb68a4f1SSergej Sawazki
clk_gpio_gate_is_enabled(struct clk_hw * hw)67bb68a4f1SSergej Sawazki static int clk_gpio_gate_is_enabled(struct clk_hw *hw)
68bb68a4f1SSergej Sawazki {
69bb68a4f1SSergej Sawazki struct clk_gpio *clk = to_clk_gpio(hw);
70bb68a4f1SSergej Sawazki
71bb68a4f1SSergej Sawazki return gpiod_get_value(clk->gpiod);
72bb68a4f1SSergej Sawazki }
73bb68a4f1SSergej Sawazki
749a9b5a4aSStephen Boyd static const struct clk_ops clk_gpio_gate_ops = {
75bb68a4f1SSergej Sawazki .enable = clk_gpio_gate_enable,
76bb68a4f1SSergej Sawazki .disable = clk_gpio_gate_disable,
77bb68a4f1SSergej Sawazki .is_enabled = clk_gpio_gate_is_enabled,
78bb68a4f1SSergej Sawazki };
79bb68a4f1SSergej Sawazki
clk_sleeping_gpio_gate_prepare(struct clk_hw * hw)80c0189feeSThomas Petazzoni static int clk_sleeping_gpio_gate_prepare(struct clk_hw *hw)
81c0189feeSThomas Petazzoni {
82c0189feeSThomas Petazzoni struct clk_gpio *clk = to_clk_gpio(hw);
83c0189feeSThomas Petazzoni
84c0189feeSThomas Petazzoni gpiod_set_value_cansleep(clk->gpiod, 1);
85c0189feeSThomas Petazzoni
86c0189feeSThomas Petazzoni return 0;
87c0189feeSThomas Petazzoni }
88c0189feeSThomas Petazzoni
clk_sleeping_gpio_gate_unprepare(struct clk_hw * hw)89c0189feeSThomas Petazzoni static void clk_sleeping_gpio_gate_unprepare(struct clk_hw *hw)
90c0189feeSThomas Petazzoni {
91c0189feeSThomas Petazzoni struct clk_gpio *clk = to_clk_gpio(hw);
92c0189feeSThomas Petazzoni
93c0189feeSThomas Petazzoni gpiod_set_value_cansleep(clk->gpiod, 0);
94c0189feeSThomas Petazzoni }
95c0189feeSThomas Petazzoni
clk_sleeping_gpio_gate_is_prepared(struct clk_hw * hw)96c0189feeSThomas Petazzoni static int clk_sleeping_gpio_gate_is_prepared(struct clk_hw *hw)
97c0189feeSThomas Petazzoni {
98c0189feeSThomas Petazzoni struct clk_gpio *clk = to_clk_gpio(hw);
99c0189feeSThomas Petazzoni
100c0189feeSThomas Petazzoni return gpiod_get_value_cansleep(clk->gpiod);
101c0189feeSThomas Petazzoni }
102c0189feeSThomas Petazzoni
103c0189feeSThomas Petazzoni static const struct clk_ops clk_sleeping_gpio_gate_ops = {
104c0189feeSThomas Petazzoni .prepare = clk_sleeping_gpio_gate_prepare,
105c0189feeSThomas Petazzoni .unprepare = clk_sleeping_gpio_gate_unprepare,
106c0189feeSThomas Petazzoni .is_prepared = clk_sleeping_gpio_gate_is_prepared,
107c0189feeSThomas Petazzoni };
108c0189feeSThomas Petazzoni
109bb68a4f1SSergej Sawazki /**
110bb68a4f1SSergej Sawazki * DOC: basic clock multiplexer which can be controlled with a gpio output
111bb68a4f1SSergej Sawazki * Traits of this clock:
112bb68a4f1SSergej Sawazki * prepare - clk_prepare only ensures that parents are prepared
113bb68a4f1SSergej Sawazki * rate - rate is only affected by parent switching. No clk_set_rate support
114bb68a4f1SSergej Sawazki * parent - parent is adjustable through clk_set_parent
115bb68a4f1SSergej Sawazki */
116bb68a4f1SSergej Sawazki
clk_gpio_mux_get_parent(struct clk_hw * hw)117bb68a4f1SSergej Sawazki static u8 clk_gpio_mux_get_parent(struct clk_hw *hw)
118bb68a4f1SSergej Sawazki {
119bb68a4f1SSergej Sawazki struct clk_gpio *clk = to_clk_gpio(hw);
120bb68a4f1SSergej Sawazki
1212e838e7fSMike Looijmans return gpiod_get_value_cansleep(clk->gpiod);
122bb68a4f1SSergej Sawazki }
123bb68a4f1SSergej Sawazki
clk_gpio_mux_set_parent(struct clk_hw * hw,u8 index)124bb68a4f1SSergej Sawazki static int clk_gpio_mux_set_parent(struct clk_hw *hw, u8 index)
125bb68a4f1SSergej Sawazki {
126bb68a4f1SSergej Sawazki struct clk_gpio *clk = to_clk_gpio(hw);
127bb68a4f1SSergej Sawazki
1282e838e7fSMike Looijmans gpiod_set_value_cansleep(clk->gpiod, index);
129bb68a4f1SSergej Sawazki
130bb68a4f1SSergej Sawazki return 0;
131bb68a4f1SSergej Sawazki }
132bb68a4f1SSergej Sawazki
1339a9b5a4aSStephen Boyd static const struct clk_ops clk_gpio_mux_ops = {
134bb68a4f1SSergej Sawazki .get_parent = clk_gpio_mux_get_parent,
135bb68a4f1SSergej Sawazki .set_parent = clk_gpio_mux_set_parent,
136bb68a4f1SSergej Sawazki .determine_rate = __clk_mux_determine_rate,
137bb68a4f1SSergej Sawazki };
138bb68a4f1SSergej Sawazki
clk_register_gpio(struct device * dev,u8 num_parents,struct gpio_desc * gpiod,const struct clk_ops * clk_gpio_ops)1399a9b5a4aSStephen Boyd static struct clk_hw *clk_register_gpio(struct device *dev, u8 num_parents,
1409a9b5a4aSStephen Boyd struct gpio_desc *gpiod,
1419a9b5a4aSStephen Boyd const struct clk_ops *clk_gpio_ops)
142bb68a4f1SSergej Sawazki {
143bb68a4f1SSergej Sawazki struct clk_gpio *clk_gpio;
144b120743aSStephen Boyd struct clk_hw *hw;
145bb68a4f1SSergej Sawazki struct clk_init_data init = {};
146bb68a4f1SSergej Sawazki int err;
1479a9b5a4aSStephen Boyd const struct clk_parent_data gpio_parent_data[] = {
1489a9b5a4aSStephen Boyd { .index = 0 },
1499a9b5a4aSStephen Boyd { .index = 1 },
1509a9b5a4aSStephen Boyd };
151bb68a4f1SSergej Sawazki
152bb68a4f1SSergej Sawazki clk_gpio = devm_kzalloc(dev, sizeof(*clk_gpio), GFP_KERNEL);
153bb68a4f1SSergej Sawazki if (!clk_gpio)
154bb68a4f1SSergej Sawazki return ERR_PTR(-ENOMEM);
155bb68a4f1SSergej Sawazki
1569a9b5a4aSStephen Boyd init.name = dev->of_node->name;
157bb68a4f1SSergej Sawazki init.ops = clk_gpio_ops;
1589a9b5a4aSStephen Boyd init.parent_data = gpio_parent_data;
159bb68a4f1SSergej Sawazki init.num_parents = num_parents;
1609a9b5a4aSStephen Boyd init.flags = CLK_SET_RATE_PARENT;
161bb68a4f1SSergej Sawazki
162908a543aSLinus Walleij clk_gpio->gpiod = gpiod;
163bb68a4f1SSergej Sawazki clk_gpio->hw.init = &init;
164bb68a4f1SSergej Sawazki
165b120743aSStephen Boyd hw = &clk_gpio->hw;
166b120743aSStephen Boyd err = devm_clk_hw_register(dev, hw);
1679a9b5a4aSStephen Boyd if (err)
168b120743aSStephen Boyd return ERR_PTR(err);
1699a9b5a4aSStephen Boyd
1709a9b5a4aSStephen Boyd return hw;
171bb68a4f1SSergej Sawazki }
172bb68a4f1SSergej Sawazki
clk_hw_register_gpio_gate(struct device * dev,int num_parents,struct gpio_desc * gpiod)1739a9b5a4aSStephen Boyd static struct clk_hw *clk_hw_register_gpio_gate(struct device *dev,
1749a9b5a4aSStephen Boyd int num_parents,
1759a9b5a4aSStephen Boyd struct gpio_desc *gpiod)
176bb68a4f1SSergej Sawazki {
177c0189feeSThomas Petazzoni const struct clk_ops *ops;
178c0189feeSThomas Petazzoni
179c0189feeSThomas Petazzoni if (gpiod_cansleep(gpiod))
180c0189feeSThomas Petazzoni ops = &clk_sleeping_gpio_gate_ops;
181c0189feeSThomas Petazzoni else
182c0189feeSThomas Petazzoni ops = &clk_gpio_gate_ops;
183c0189feeSThomas Petazzoni
1849a9b5a4aSStephen Boyd return clk_register_gpio(dev, num_parents, gpiod, ops);
185bb68a4f1SSergej Sawazki }
186b120743aSStephen Boyd
clk_hw_register_gpio_mux(struct device * dev,struct gpio_desc * gpiod)1879a9b5a4aSStephen Boyd static struct clk_hw *clk_hw_register_gpio_mux(struct device *dev,
1889a9b5a4aSStephen Boyd struct gpio_desc *gpiod)
189b120743aSStephen Boyd {
1909a9b5a4aSStephen Boyd return clk_register_gpio(dev, 2, gpiod, &clk_gpio_mux_ops);
191b120743aSStephen Boyd }
192bb68a4f1SSergej Sawazki
gpio_clk_driver_probe(struct platform_device * pdev)19314b04f28SStephen Boyd static int gpio_clk_driver_probe(struct platform_device *pdev)
194bb68a4f1SSergej Sawazki {
1959a9b5a4aSStephen Boyd struct device *dev = &pdev->dev;
1969a9b5a4aSStephen Boyd struct device_node *node = dev->of_node;
1979a9b5a4aSStephen Boyd const char *gpio_name;
1980985df89SStephen Boyd unsigned int num_parents;
199908a543aSLinus Walleij struct gpio_desc *gpiod;
2009a9b5a4aSStephen Boyd struct clk_hw *hw;
201908a543aSLinus Walleij bool is_mux;
202908a543aSLinus Walleij int ret;
203bb68a4f1SSergej Sawazki
20414b04f28SStephen Boyd is_mux = of_device_is_compatible(node, "gpio-mux-clock");
205bb68a4f1SSergej Sawazki
2069a9b5a4aSStephen Boyd num_parents = of_clk_get_parent_count(node);
2079a9b5a4aSStephen Boyd if (is_mux && num_parents != 2) {
2089a9b5a4aSStephen Boyd dev_err(dev, "mux-clock must have 2 parents\n");
2099a9b5a4aSStephen Boyd return -EINVAL;
2109a9b5a4aSStephen Boyd }
2119a9b5a4aSStephen Boyd
212908a543aSLinus Walleij gpio_name = is_mux ? "select" : "enable";
2139a9b5a4aSStephen Boyd gpiod = devm_gpiod_get(dev, gpio_name, GPIOD_OUT_LOW);
214908a543aSLinus Walleij if (IS_ERR(gpiod)) {
215908a543aSLinus Walleij ret = PTR_ERR(gpiod);
216908a543aSLinus Walleij if (ret == -EPROBE_DEFER)
217e665f029SRob Herring pr_debug("%pOFn: %s: GPIOs not yet available, retry later\n",
218e665f029SRob Herring node, __func__);
21914b04f28SStephen Boyd else
220e665f029SRob Herring pr_err("%pOFn: %s: Can't get '%s' named GPIO property\n",
221e665f029SRob Herring node, __func__,
22214b04f28SStephen Boyd gpio_name);
223908a543aSLinus Walleij return ret;
224bb68a4f1SSergej Sawazki }
225bb68a4f1SSergej Sawazki
22614b04f28SStephen Boyd if (is_mux)
2279a9b5a4aSStephen Boyd hw = clk_hw_register_gpio_mux(dev, gpiod);
22814b04f28SStephen Boyd else
2299a9b5a4aSStephen Boyd hw = clk_hw_register_gpio_gate(dev, num_parents, gpiod);
2309a9b5a4aSStephen Boyd if (IS_ERR(hw))
2319a9b5a4aSStephen Boyd return PTR_ERR(hw);
23214b04f28SStephen Boyd
2339a9b5a4aSStephen Boyd return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
234bb68a4f1SSergej Sawazki }
23514b04f28SStephen Boyd
23614b04f28SStephen Boyd static const struct of_device_id gpio_clk_match_table[] = {
23714b04f28SStephen Boyd { .compatible = "gpio-mux-clock" },
23814b04f28SStephen Boyd { .compatible = "gpio-gate-clock" },
23914b04f28SStephen Boyd { }
24014b04f28SStephen Boyd };
24114b04f28SStephen Boyd
24214b04f28SStephen Boyd static struct platform_driver gpio_clk_driver = {
24314b04f28SStephen Boyd .probe = gpio_clk_driver_probe,
24414b04f28SStephen Boyd .driver = {
24514b04f28SStephen Boyd .name = "gpio-clk",
24614b04f28SStephen Boyd .of_match_table = gpio_clk_match_table,
24714b04f28SStephen Boyd },
24814b04f28SStephen Boyd };
24914b04f28SStephen Boyd builtin_platform_driver(gpio_clk_driver);
250