xref: /linux/drivers/clk/tegra/clk-device.c (revision b1bc04a2ac5b15e0b681228376664671fc2f2017)
1*b1bc04a2SDmitry Osipenko // SPDX-License-Identifier: GPL-2.0-only
2*b1bc04a2SDmitry Osipenko 
3*b1bc04a2SDmitry Osipenko #include <linux/clk.h>
4*b1bc04a2SDmitry Osipenko #include <linux/clk-provider.h>
5*b1bc04a2SDmitry Osipenko #include <linux/mutex.h>
6*b1bc04a2SDmitry Osipenko #include <linux/of_device.h>
7*b1bc04a2SDmitry Osipenko #include <linux/platform_device.h>
8*b1bc04a2SDmitry Osipenko #include <linux/pm_domain.h>
9*b1bc04a2SDmitry Osipenko #include <linux/pm_opp.h>
10*b1bc04a2SDmitry Osipenko #include <linux/pm_runtime.h>
11*b1bc04a2SDmitry Osipenko #include <linux/slab.h>
12*b1bc04a2SDmitry Osipenko 
13*b1bc04a2SDmitry Osipenko #include <soc/tegra/common.h>
14*b1bc04a2SDmitry Osipenko 
15*b1bc04a2SDmitry Osipenko #include "clk.h"
16*b1bc04a2SDmitry Osipenko 
17*b1bc04a2SDmitry Osipenko /*
18*b1bc04a2SDmitry Osipenko  * This driver manages performance state of the core power domain for the
19*b1bc04a2SDmitry Osipenko  * independent PLLs and system clocks.  We created a virtual clock device
20*b1bc04a2SDmitry Osipenko  * for such clocks, see tegra_clk_dev_register().
21*b1bc04a2SDmitry Osipenko  */
22*b1bc04a2SDmitry Osipenko 
23*b1bc04a2SDmitry Osipenko struct tegra_clk_device {
24*b1bc04a2SDmitry Osipenko 	struct notifier_block clk_nb;
25*b1bc04a2SDmitry Osipenko 	struct device *dev;
26*b1bc04a2SDmitry Osipenko 	struct clk_hw *hw;
27*b1bc04a2SDmitry Osipenko 	struct mutex lock;
28*b1bc04a2SDmitry Osipenko };
29*b1bc04a2SDmitry Osipenko 
30*b1bc04a2SDmitry Osipenko static int tegra_clock_set_pd_state(struct tegra_clk_device *clk_dev,
31*b1bc04a2SDmitry Osipenko 				    unsigned long rate)
32*b1bc04a2SDmitry Osipenko {
33*b1bc04a2SDmitry Osipenko 	struct device *dev = clk_dev->dev;
34*b1bc04a2SDmitry Osipenko 	struct dev_pm_opp *opp;
35*b1bc04a2SDmitry Osipenko 	unsigned int pstate;
36*b1bc04a2SDmitry Osipenko 
37*b1bc04a2SDmitry Osipenko 	opp = dev_pm_opp_find_freq_ceil(dev, &rate);
38*b1bc04a2SDmitry Osipenko 	if (opp == ERR_PTR(-ERANGE)) {
39*b1bc04a2SDmitry Osipenko 		/*
40*b1bc04a2SDmitry Osipenko 		 * Some clocks may be unused by a particular board and they
41*b1bc04a2SDmitry Osipenko 		 * may have uninitiated clock rate that is overly high.  In
42*b1bc04a2SDmitry Osipenko 		 * this case clock is expected to be disabled, but still we
43*b1bc04a2SDmitry Osipenko 		 * need to set up performance state of the power domain and
44*b1bc04a2SDmitry Osipenko 		 * not error out clk initialization.  A typical example is
45*b1bc04a2SDmitry Osipenko 		 * a PCIe clock on Android tablets.
46*b1bc04a2SDmitry Osipenko 		 */
47*b1bc04a2SDmitry Osipenko 		dev_dbg(dev, "failed to find ceil OPP for %luHz\n", rate);
48*b1bc04a2SDmitry Osipenko 		opp = dev_pm_opp_find_freq_floor(dev, &rate);
49*b1bc04a2SDmitry Osipenko 	}
50*b1bc04a2SDmitry Osipenko 
51*b1bc04a2SDmitry Osipenko 	if (IS_ERR(opp)) {
52*b1bc04a2SDmitry Osipenko 		dev_err(dev, "failed to find OPP for %luHz: %pe\n", rate, opp);
53*b1bc04a2SDmitry Osipenko 		return PTR_ERR(opp);
54*b1bc04a2SDmitry Osipenko 	}
55*b1bc04a2SDmitry Osipenko 
56*b1bc04a2SDmitry Osipenko 	pstate = dev_pm_opp_get_required_pstate(opp, 0);
57*b1bc04a2SDmitry Osipenko 	dev_pm_opp_put(opp);
58*b1bc04a2SDmitry Osipenko 
59*b1bc04a2SDmitry Osipenko 	return dev_pm_genpd_set_performance_state(dev, pstate);
60*b1bc04a2SDmitry Osipenko }
61*b1bc04a2SDmitry Osipenko 
62*b1bc04a2SDmitry Osipenko static int tegra_clock_change_notify(struct notifier_block *nb,
63*b1bc04a2SDmitry Osipenko 				     unsigned long msg, void *data)
64*b1bc04a2SDmitry Osipenko {
65*b1bc04a2SDmitry Osipenko 	struct clk_notifier_data *cnd = data;
66*b1bc04a2SDmitry Osipenko 	struct tegra_clk_device *clk_dev;
67*b1bc04a2SDmitry Osipenko 	int err = 0;
68*b1bc04a2SDmitry Osipenko 
69*b1bc04a2SDmitry Osipenko 	clk_dev = container_of(nb, struct tegra_clk_device, clk_nb);
70*b1bc04a2SDmitry Osipenko 
71*b1bc04a2SDmitry Osipenko 	mutex_lock(&clk_dev->lock);
72*b1bc04a2SDmitry Osipenko 	switch (msg) {
73*b1bc04a2SDmitry Osipenko 	case PRE_RATE_CHANGE:
74*b1bc04a2SDmitry Osipenko 		if (cnd->new_rate > cnd->old_rate)
75*b1bc04a2SDmitry Osipenko 			err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
76*b1bc04a2SDmitry Osipenko 		break;
77*b1bc04a2SDmitry Osipenko 
78*b1bc04a2SDmitry Osipenko 	case ABORT_RATE_CHANGE:
79*b1bc04a2SDmitry Osipenko 		err = tegra_clock_set_pd_state(clk_dev, cnd->old_rate);
80*b1bc04a2SDmitry Osipenko 		break;
81*b1bc04a2SDmitry Osipenko 
82*b1bc04a2SDmitry Osipenko 	case POST_RATE_CHANGE:
83*b1bc04a2SDmitry Osipenko 		if (cnd->new_rate < cnd->old_rate)
84*b1bc04a2SDmitry Osipenko 			err = tegra_clock_set_pd_state(clk_dev, cnd->new_rate);
85*b1bc04a2SDmitry Osipenko 		break;
86*b1bc04a2SDmitry Osipenko 
87*b1bc04a2SDmitry Osipenko 	default:
88*b1bc04a2SDmitry Osipenko 		break;
89*b1bc04a2SDmitry Osipenko 	}
90*b1bc04a2SDmitry Osipenko 	mutex_unlock(&clk_dev->lock);
91*b1bc04a2SDmitry Osipenko 
92*b1bc04a2SDmitry Osipenko 	return notifier_from_errno(err);
93*b1bc04a2SDmitry Osipenko }
94*b1bc04a2SDmitry Osipenko 
95*b1bc04a2SDmitry Osipenko static int tegra_clock_sync_pd_state(struct tegra_clk_device *clk_dev)
96*b1bc04a2SDmitry Osipenko {
97*b1bc04a2SDmitry Osipenko 	unsigned long rate;
98*b1bc04a2SDmitry Osipenko 	int ret;
99*b1bc04a2SDmitry Osipenko 
100*b1bc04a2SDmitry Osipenko 	mutex_lock(&clk_dev->lock);
101*b1bc04a2SDmitry Osipenko 
102*b1bc04a2SDmitry Osipenko 	rate = clk_hw_get_rate(clk_dev->hw);
103*b1bc04a2SDmitry Osipenko 	ret = tegra_clock_set_pd_state(clk_dev, rate);
104*b1bc04a2SDmitry Osipenko 
105*b1bc04a2SDmitry Osipenko 	mutex_unlock(&clk_dev->lock);
106*b1bc04a2SDmitry Osipenko 
107*b1bc04a2SDmitry Osipenko 	return ret;
108*b1bc04a2SDmitry Osipenko }
109*b1bc04a2SDmitry Osipenko 
110*b1bc04a2SDmitry Osipenko static int tegra_clock_probe(struct platform_device *pdev)
111*b1bc04a2SDmitry Osipenko {
112*b1bc04a2SDmitry Osipenko 	struct tegra_core_opp_params opp_params = {};
113*b1bc04a2SDmitry Osipenko 	struct tegra_clk_device *clk_dev;
114*b1bc04a2SDmitry Osipenko 	struct device *dev = &pdev->dev;
115*b1bc04a2SDmitry Osipenko 	struct clk *clk;
116*b1bc04a2SDmitry Osipenko 	int err;
117*b1bc04a2SDmitry Osipenko 
118*b1bc04a2SDmitry Osipenko 	if (!dev->pm_domain)
119*b1bc04a2SDmitry Osipenko 		return -EINVAL;
120*b1bc04a2SDmitry Osipenko 
121*b1bc04a2SDmitry Osipenko 	clk_dev = devm_kzalloc(dev, sizeof(*clk_dev), GFP_KERNEL);
122*b1bc04a2SDmitry Osipenko 	if (!clk_dev)
123*b1bc04a2SDmitry Osipenko 		return -ENOMEM;
124*b1bc04a2SDmitry Osipenko 
125*b1bc04a2SDmitry Osipenko 	clk = devm_clk_get(dev, NULL);
126*b1bc04a2SDmitry Osipenko 	if (IS_ERR(clk))
127*b1bc04a2SDmitry Osipenko 		return PTR_ERR(clk);
128*b1bc04a2SDmitry Osipenko 
129*b1bc04a2SDmitry Osipenko 	clk_dev->dev = dev;
130*b1bc04a2SDmitry Osipenko 	clk_dev->hw = __clk_get_hw(clk);
131*b1bc04a2SDmitry Osipenko 	clk_dev->clk_nb.notifier_call = tegra_clock_change_notify;
132*b1bc04a2SDmitry Osipenko 	mutex_init(&clk_dev->lock);
133*b1bc04a2SDmitry Osipenko 
134*b1bc04a2SDmitry Osipenko 	platform_set_drvdata(pdev, clk_dev);
135*b1bc04a2SDmitry Osipenko 
136*b1bc04a2SDmitry Osipenko 	/*
137*b1bc04a2SDmitry Osipenko 	 * Runtime PM was already enabled for this device by the parent clk
138*b1bc04a2SDmitry Osipenko 	 * driver and power domain state should be synced under clk_dev lock,
139*b1bc04a2SDmitry Osipenko 	 * hence we don't use the common OPP helper that initializes OPP
140*b1bc04a2SDmitry Osipenko 	 * state. For some clocks common OPP helper may fail to find ceil
141*b1bc04a2SDmitry Osipenko 	 * rate, it's handled by this driver.
142*b1bc04a2SDmitry Osipenko 	 */
143*b1bc04a2SDmitry Osipenko 	err = devm_tegra_core_dev_init_opp_table(dev, &opp_params);
144*b1bc04a2SDmitry Osipenko 	if (err)
145*b1bc04a2SDmitry Osipenko 		return err;
146*b1bc04a2SDmitry Osipenko 
147*b1bc04a2SDmitry Osipenko 	err = clk_notifier_register(clk, &clk_dev->clk_nb);
148*b1bc04a2SDmitry Osipenko 	if (err) {
149*b1bc04a2SDmitry Osipenko 		dev_err(dev, "failed to register clk notifier: %d\n", err);
150*b1bc04a2SDmitry Osipenko 		return err;
151*b1bc04a2SDmitry Osipenko 	}
152*b1bc04a2SDmitry Osipenko 
153*b1bc04a2SDmitry Osipenko 	/*
154*b1bc04a2SDmitry Osipenko 	 * The driver is attaching to a potentially active/resumed clock, hence
155*b1bc04a2SDmitry Osipenko 	 * we need to sync the power domain performance state in a accordance to
156*b1bc04a2SDmitry Osipenko 	 * the clock rate if clock is resumed.
157*b1bc04a2SDmitry Osipenko 	 */
158*b1bc04a2SDmitry Osipenko 	err = tegra_clock_sync_pd_state(clk_dev);
159*b1bc04a2SDmitry Osipenko 	if (err)
160*b1bc04a2SDmitry Osipenko 		goto unreg_clk;
161*b1bc04a2SDmitry Osipenko 
162*b1bc04a2SDmitry Osipenko 	return 0;
163*b1bc04a2SDmitry Osipenko 
164*b1bc04a2SDmitry Osipenko unreg_clk:
165*b1bc04a2SDmitry Osipenko 	clk_notifier_unregister(clk, &clk_dev->clk_nb);
166*b1bc04a2SDmitry Osipenko 
167*b1bc04a2SDmitry Osipenko 	return err;
168*b1bc04a2SDmitry Osipenko }
169*b1bc04a2SDmitry Osipenko 
170*b1bc04a2SDmitry Osipenko /*
171*b1bc04a2SDmitry Osipenko  * Tegra GENPD driver enables clocks during NOIRQ phase. It can't be done
172*b1bc04a2SDmitry Osipenko  * for clocks served by this driver because runtime PM is unavailable in
173*b1bc04a2SDmitry Osipenko  * NOIRQ phase. We will keep clocks resumed during suspend to mitigate this
174*b1bc04a2SDmitry Osipenko  * problem. In practice this makes no difference from a power management
175*b1bc04a2SDmitry Osipenko  * perspective since voltage is kept at a nominal level during suspend anyways.
176*b1bc04a2SDmitry Osipenko  */
177*b1bc04a2SDmitry Osipenko static const struct dev_pm_ops tegra_clock_pm = {
178*b1bc04a2SDmitry Osipenko 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_resume_and_get, pm_runtime_put)
179*b1bc04a2SDmitry Osipenko };
180*b1bc04a2SDmitry Osipenko 
181*b1bc04a2SDmitry Osipenko static const struct of_device_id tegra_clock_match[] = {
182*b1bc04a2SDmitry Osipenko 	{ .compatible = "nvidia,tegra20-sclk" },
183*b1bc04a2SDmitry Osipenko 	{ .compatible = "nvidia,tegra30-sclk" },
184*b1bc04a2SDmitry Osipenko 	{ .compatible = "nvidia,tegra30-pllc" },
185*b1bc04a2SDmitry Osipenko 	{ .compatible = "nvidia,tegra30-plle" },
186*b1bc04a2SDmitry Osipenko 	{ .compatible = "nvidia,tegra30-pllm" },
187*b1bc04a2SDmitry Osipenko 	{ }
188*b1bc04a2SDmitry Osipenko };
189*b1bc04a2SDmitry Osipenko 
190*b1bc04a2SDmitry Osipenko static struct platform_driver tegra_clock_driver = {
191*b1bc04a2SDmitry Osipenko 	.driver = {
192*b1bc04a2SDmitry Osipenko 		.name = "tegra-clock",
193*b1bc04a2SDmitry Osipenko 		.of_match_table = tegra_clock_match,
194*b1bc04a2SDmitry Osipenko 		.pm = &tegra_clock_pm,
195*b1bc04a2SDmitry Osipenko 		.suppress_bind_attrs = true,
196*b1bc04a2SDmitry Osipenko 	},
197*b1bc04a2SDmitry Osipenko 	.probe = tegra_clock_probe,
198*b1bc04a2SDmitry Osipenko };
199*b1bc04a2SDmitry Osipenko builtin_platform_driver(tegra_clock_driver);
200