xref: /openbmc/linux/drivers/clk/clk-gpio.c (revision a96cbb14)
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