xref: /linux/drivers/soc/tegra/regulators-tegra20.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1496747e7SDmitry Osipenko // SPDX-License-Identifier: GPL-2.0+
2496747e7SDmitry Osipenko /*
3496747e7SDmitry Osipenko  * Voltage regulators coupler for NVIDIA Tegra20
4496747e7SDmitry Osipenko  * Copyright (C) 2019 GRATE-DRIVER project
5496747e7SDmitry Osipenko  *
6496747e7SDmitry Osipenko  * Voltage constraints borrowed from downstream kernel sources
7496747e7SDmitry Osipenko  * Copyright (C) 2010-2011 NVIDIA Corporation
8496747e7SDmitry Osipenko  */
9496747e7SDmitry Osipenko 
10496747e7SDmitry Osipenko #define pr_fmt(fmt)	"tegra voltage-coupler: " fmt
11496747e7SDmitry Osipenko 
12496747e7SDmitry Osipenko #include <linux/init.h>
13496747e7SDmitry Osipenko #include <linux/kernel.h>
14496747e7SDmitry Osipenko #include <linux/of.h>
1503978d42SDmitry Osipenko #include <linux/reboot.h>
16496747e7SDmitry Osipenko #include <linux/regulator/coupler.h>
17496747e7SDmitry Osipenko #include <linux/regulator/driver.h>
18496747e7SDmitry Osipenko #include <linux/regulator/machine.h>
19*80ef351cSDmitry Osipenko #include <linux/suspend.h>
20496747e7SDmitry Osipenko 
21*80ef351cSDmitry Osipenko #include <soc/tegra/fuse.h>
22029f7e24SDmitry Osipenko #include <soc/tegra/pmc.h>
23029f7e24SDmitry Osipenko 
24496747e7SDmitry Osipenko struct tegra_regulator_coupler {
25496747e7SDmitry Osipenko 	struct regulator_coupler coupler;
26496747e7SDmitry Osipenko 	struct regulator_dev *core_rdev;
27496747e7SDmitry Osipenko 	struct regulator_dev *cpu_rdev;
28496747e7SDmitry Osipenko 	struct regulator_dev *rtc_rdev;
2903978d42SDmitry Osipenko 	struct notifier_block reboot_notifier;
30*80ef351cSDmitry Osipenko 	struct notifier_block suspend_notifier;
3103978d42SDmitry Osipenko 	int core_min_uV, cpu_min_uV;
3203978d42SDmitry Osipenko 	bool sys_reboot_mode_req;
3303978d42SDmitry Osipenko 	bool sys_reboot_mode;
34*80ef351cSDmitry Osipenko 	bool sys_suspend_mode_req;
35*80ef351cSDmitry Osipenko 	bool sys_suspend_mode;
36496747e7SDmitry Osipenko };
37496747e7SDmitry Osipenko 
38496747e7SDmitry Osipenko static inline struct tegra_regulator_coupler *
to_tegra_coupler(struct regulator_coupler * coupler)39496747e7SDmitry Osipenko to_tegra_coupler(struct regulator_coupler *coupler)
40496747e7SDmitry Osipenko {
41496747e7SDmitry Osipenko 	return container_of(coupler, struct tegra_regulator_coupler, coupler);
42496747e7SDmitry Osipenko }
43496747e7SDmitry Osipenko 
tegra20_core_limit(struct tegra_regulator_coupler * tegra,struct regulator_dev * core_rdev)44496747e7SDmitry Osipenko static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
45496747e7SDmitry Osipenko 			      struct regulator_dev *core_rdev)
46496747e7SDmitry Osipenko {
47496747e7SDmitry Osipenko 	int core_min_uV = 0;
48496747e7SDmitry Osipenko 	int core_max_uV;
49496747e7SDmitry Osipenko 	int core_cur_uV;
50496747e7SDmitry Osipenko 	int err;
51496747e7SDmitry Osipenko 
52029f7e24SDmitry Osipenko 	/*
53029f7e24SDmitry Osipenko 	 * Tegra20 SoC has critical DVFS-capable devices that are
54029f7e24SDmitry Osipenko 	 * permanently-active or active at a boot time, like EMC
55029f7e24SDmitry Osipenko 	 * (DRAM controller) or Display controller for example.
56029f7e24SDmitry Osipenko 	 *
57029f7e24SDmitry Osipenko 	 * The voltage of a CORE SoC power domain shall not be dropped below
58029f7e24SDmitry Osipenko 	 * a minimum level, which is determined by device's clock rate.
59029f7e24SDmitry Osipenko 	 * This means that we can't fully allow CORE voltage scaling until
60029f7e24SDmitry Osipenko 	 * the state of all DVFS-critical CORE devices is synced.
61029f7e24SDmitry Osipenko 	 */
62029f7e24SDmitry Osipenko 	if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) {
63029f7e24SDmitry Osipenko 		pr_info_once("voltage state synced\n");
64029f7e24SDmitry Osipenko 		return 0;
65029f7e24SDmitry Osipenko 	}
66029f7e24SDmitry Osipenko 
67496747e7SDmitry Osipenko 	if (tegra->core_min_uV > 0)
68496747e7SDmitry Osipenko 		return tegra->core_min_uV;
69496747e7SDmitry Osipenko 
70496747e7SDmitry Osipenko 	core_cur_uV = regulator_get_voltage_rdev(core_rdev);
71496747e7SDmitry Osipenko 	if (core_cur_uV < 0)
72496747e7SDmitry Osipenko 		return core_cur_uV;
73496747e7SDmitry Osipenko 
74496747e7SDmitry Osipenko 	core_max_uV = max(core_cur_uV, 1200000);
75496747e7SDmitry Osipenko 
76496747e7SDmitry Osipenko 	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
77496747e7SDmitry Osipenko 	if (err)
78496747e7SDmitry Osipenko 		return err;
79496747e7SDmitry Osipenko 
80496747e7SDmitry Osipenko 	/*
81496747e7SDmitry Osipenko 	 * Limit minimum CORE voltage to a value left from bootloader or,
82496747e7SDmitry Osipenko 	 * if it's unreasonably low value, to the most common 1.2v or to
83496747e7SDmitry Osipenko 	 * whatever maximum value defined via board's device-tree.
84496747e7SDmitry Osipenko 	 */
85496747e7SDmitry Osipenko 	tegra->core_min_uV = core_max_uV;
86496747e7SDmitry Osipenko 
87029f7e24SDmitry Osipenko 	pr_info("core voltage initialized to %duV\n", tegra->core_min_uV);
88496747e7SDmitry Osipenko 
89496747e7SDmitry Osipenko 	return tegra->core_min_uV;
90496747e7SDmitry Osipenko }
91496747e7SDmitry Osipenko 
tegra20_core_rtc_max_spread(struct regulator_dev * core_rdev,struct regulator_dev * rtc_rdev)92496747e7SDmitry Osipenko static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev,
93496747e7SDmitry Osipenko 				       struct regulator_dev *rtc_rdev)
94496747e7SDmitry Osipenko {
95496747e7SDmitry Osipenko 	struct coupling_desc *c_desc = &core_rdev->coupling_desc;
96496747e7SDmitry Osipenko 	struct regulator_dev *rdev;
97496747e7SDmitry Osipenko 	int max_spread;
98496747e7SDmitry Osipenko 	unsigned int i;
99496747e7SDmitry Osipenko 
100496747e7SDmitry Osipenko 	for (i = 1; i < c_desc->n_coupled; i++) {
101496747e7SDmitry Osipenko 		max_spread = core_rdev->constraints->max_spread[i - 1];
102496747e7SDmitry Osipenko 		rdev = c_desc->coupled_rdevs[i];
103496747e7SDmitry Osipenko 
104496747e7SDmitry Osipenko 		if (rdev == rtc_rdev && max_spread)
105496747e7SDmitry Osipenko 			return max_spread;
106496747e7SDmitry Osipenko 	}
107496747e7SDmitry Osipenko 
108496747e7SDmitry Osipenko 	pr_err_once("rtc-core max-spread is undefined in device-tree\n");
109496747e7SDmitry Osipenko 
110496747e7SDmitry Osipenko 	return 150000;
111496747e7SDmitry Osipenko }
112496747e7SDmitry Osipenko 
tegra20_cpu_nominal_uV(void)113*80ef351cSDmitry Osipenko static int tegra20_cpu_nominal_uV(void)
114*80ef351cSDmitry Osipenko {
115*80ef351cSDmitry Osipenko 	switch (tegra_sku_info.soc_speedo_id) {
116*80ef351cSDmitry Osipenko 	case 0:
117*80ef351cSDmitry Osipenko 		return 1100000;
118*80ef351cSDmitry Osipenko 	case 1:
119*80ef351cSDmitry Osipenko 		return 1025000;
120*80ef351cSDmitry Osipenko 	default:
121*80ef351cSDmitry Osipenko 		return 1125000;
122*80ef351cSDmitry Osipenko 	}
123*80ef351cSDmitry Osipenko }
124*80ef351cSDmitry Osipenko 
tegra20_core_nominal_uV(void)125*80ef351cSDmitry Osipenko static int tegra20_core_nominal_uV(void)
126*80ef351cSDmitry Osipenko {
127*80ef351cSDmitry Osipenko 	switch (tegra_sku_info.soc_speedo_id) {
128*80ef351cSDmitry Osipenko 	default:
129*80ef351cSDmitry Osipenko 		return 1225000;
130*80ef351cSDmitry Osipenko 	case 2:
131*80ef351cSDmitry Osipenko 		return 1300000;
132*80ef351cSDmitry Osipenko 	}
133*80ef351cSDmitry Osipenko }
134*80ef351cSDmitry Osipenko 
tegra20_core_rtc_update(struct tegra_regulator_coupler * tegra,struct regulator_dev * core_rdev,struct regulator_dev * rtc_rdev,int cpu_uV,int cpu_min_uV)135496747e7SDmitry Osipenko static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
136496747e7SDmitry Osipenko 				   struct regulator_dev *core_rdev,
137496747e7SDmitry Osipenko 				   struct regulator_dev *rtc_rdev,
138496747e7SDmitry Osipenko 				   int cpu_uV, int cpu_min_uV)
139496747e7SDmitry Osipenko {
140496747e7SDmitry Osipenko 	int core_min_uV, core_max_uV = INT_MAX;
141496747e7SDmitry Osipenko 	int rtc_min_uV, rtc_max_uV = INT_MAX;
142496747e7SDmitry Osipenko 	int core_target_uV;
143496747e7SDmitry Osipenko 	int rtc_target_uV;
144496747e7SDmitry Osipenko 	int max_spread;
145496747e7SDmitry Osipenko 	int core_uV;
146496747e7SDmitry Osipenko 	int rtc_uV;
147496747e7SDmitry Osipenko 	int err;
148496747e7SDmitry Osipenko 
149496747e7SDmitry Osipenko 	/*
150496747e7SDmitry Osipenko 	 * RTC and CORE voltages should be no more than 170mV from each other,
151496747e7SDmitry Osipenko 	 * CPU should be below RTC and CORE by at least 120mV. This applies
152496747e7SDmitry Osipenko 	 * to all Tegra20 SoC's.
153496747e7SDmitry Osipenko 	 */
154496747e7SDmitry Osipenko 	max_spread = tegra20_core_rtc_max_spread(core_rdev, rtc_rdev);
155496747e7SDmitry Osipenko 
156496747e7SDmitry Osipenko 	/*
157496747e7SDmitry Osipenko 	 * The core voltage scaling is currently not hooked up in drivers,
158496747e7SDmitry Osipenko 	 * hence we will limit the minimum core voltage to a reasonable value.
159496747e7SDmitry Osipenko 	 * This should be good enough for the time being.
160496747e7SDmitry Osipenko 	 */
161496747e7SDmitry Osipenko 	core_min_uV = tegra20_core_limit(tegra, core_rdev);
162496747e7SDmitry Osipenko 	if (core_min_uV < 0)
163496747e7SDmitry Osipenko 		return core_min_uV;
164496747e7SDmitry Osipenko 
165496747e7SDmitry Osipenko 	err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
166496747e7SDmitry Osipenko 	if (err)
167496747e7SDmitry Osipenko 		return err;
168496747e7SDmitry Osipenko 
169496747e7SDmitry Osipenko 	err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
170496747e7SDmitry Osipenko 					PM_SUSPEND_ON);
171496747e7SDmitry Osipenko 	if (err)
172496747e7SDmitry Osipenko 		return err;
173496747e7SDmitry Osipenko 
174*80ef351cSDmitry Osipenko 	/* prepare voltage level for suspend */
175*80ef351cSDmitry Osipenko 	if (tegra->sys_suspend_mode)
176*80ef351cSDmitry Osipenko 		core_min_uV = clamp(tegra20_core_nominal_uV(),
177*80ef351cSDmitry Osipenko 				    core_min_uV, core_max_uV);
178*80ef351cSDmitry Osipenko 
179496747e7SDmitry Osipenko 	core_uV = regulator_get_voltage_rdev(core_rdev);
180496747e7SDmitry Osipenko 	if (core_uV < 0)
181496747e7SDmitry Osipenko 		return core_uV;
182496747e7SDmitry Osipenko 
183496747e7SDmitry Osipenko 	core_min_uV = max(cpu_min_uV + 125000, core_min_uV);
184496747e7SDmitry Osipenko 	if (core_min_uV > core_max_uV)
185496747e7SDmitry Osipenko 		return -EINVAL;
186496747e7SDmitry Osipenko 
187496747e7SDmitry Osipenko 	if (cpu_uV + 120000 > core_uV)
188496747e7SDmitry Osipenko 		pr_err("core-cpu voltage constraint violated: %d %d\n",
189496747e7SDmitry Osipenko 		       core_uV, cpu_uV + 120000);
190496747e7SDmitry Osipenko 
191496747e7SDmitry Osipenko 	rtc_uV = regulator_get_voltage_rdev(rtc_rdev);
192496747e7SDmitry Osipenko 	if (rtc_uV < 0)
193496747e7SDmitry Osipenko 		return rtc_uV;
194496747e7SDmitry Osipenko 
195496747e7SDmitry Osipenko 	if (cpu_uV + 120000 > rtc_uV)
196496747e7SDmitry Osipenko 		pr_err("rtc-cpu voltage constraint violated: %d %d\n",
197496747e7SDmitry Osipenko 		       rtc_uV, cpu_uV + 120000);
198496747e7SDmitry Osipenko 
199496747e7SDmitry Osipenko 	if (abs(core_uV - rtc_uV) > 170000)
200496747e7SDmitry Osipenko 		pr_err("core-rtc voltage constraint violated: %d %d\n",
201496747e7SDmitry Osipenko 		       core_uV, rtc_uV);
202496747e7SDmitry Osipenko 
203496747e7SDmitry Osipenko 	rtc_min_uV = max(cpu_min_uV + 125000, core_min_uV - max_spread);
204496747e7SDmitry Osipenko 
205496747e7SDmitry Osipenko 	err = regulator_check_voltage(rtc_rdev, &rtc_min_uV, &rtc_max_uV);
206496747e7SDmitry Osipenko 	if (err)
207496747e7SDmitry Osipenko 		return err;
208496747e7SDmitry Osipenko 
209496747e7SDmitry Osipenko 	while (core_uV != core_min_uV || rtc_uV != rtc_min_uV) {
210496747e7SDmitry Osipenko 		if (core_uV < core_min_uV) {
211496747e7SDmitry Osipenko 			core_target_uV = min(core_uV + max_spread, core_min_uV);
212496747e7SDmitry Osipenko 			core_target_uV = min(rtc_uV + max_spread, core_target_uV);
213496747e7SDmitry Osipenko 		} else {
214496747e7SDmitry Osipenko 			core_target_uV = max(core_uV - max_spread, core_min_uV);
215496747e7SDmitry Osipenko 			core_target_uV = max(rtc_uV - max_spread, core_target_uV);
216496747e7SDmitry Osipenko 		}
217496747e7SDmitry Osipenko 
21845f019a6SDmitry Osipenko 		if (core_uV == core_target_uV)
21945f019a6SDmitry Osipenko 			goto update_rtc;
22045f019a6SDmitry Osipenko 
221496747e7SDmitry Osipenko 		err = regulator_set_voltage_rdev(core_rdev,
222496747e7SDmitry Osipenko 						 core_target_uV,
223496747e7SDmitry Osipenko 						 core_max_uV,
224496747e7SDmitry Osipenko 						 PM_SUSPEND_ON);
225496747e7SDmitry Osipenko 		if (err)
226496747e7SDmitry Osipenko 			return err;
227496747e7SDmitry Osipenko 
228496747e7SDmitry Osipenko 		core_uV = core_target_uV;
22945f019a6SDmitry Osipenko update_rtc:
230496747e7SDmitry Osipenko 		if (rtc_uV < rtc_min_uV) {
231496747e7SDmitry Osipenko 			rtc_target_uV = min(rtc_uV + max_spread, rtc_min_uV);
232496747e7SDmitry Osipenko 			rtc_target_uV = min(core_uV + max_spread, rtc_target_uV);
233496747e7SDmitry Osipenko 		} else {
234496747e7SDmitry Osipenko 			rtc_target_uV = max(rtc_uV - max_spread, rtc_min_uV);
235496747e7SDmitry Osipenko 			rtc_target_uV = max(core_uV - max_spread, rtc_target_uV);
236496747e7SDmitry Osipenko 		}
237496747e7SDmitry Osipenko 
23845f019a6SDmitry Osipenko 		if (rtc_uV == rtc_target_uV)
23945f019a6SDmitry Osipenko 			continue;
24045f019a6SDmitry Osipenko 
241496747e7SDmitry Osipenko 		err = regulator_set_voltage_rdev(rtc_rdev,
242496747e7SDmitry Osipenko 						 rtc_target_uV,
243496747e7SDmitry Osipenko 						 rtc_max_uV,
244496747e7SDmitry Osipenko 						 PM_SUSPEND_ON);
245496747e7SDmitry Osipenko 		if (err)
246496747e7SDmitry Osipenko 			return err;
247496747e7SDmitry Osipenko 
248496747e7SDmitry Osipenko 		rtc_uV = rtc_target_uV;
249496747e7SDmitry Osipenko 	}
250496747e7SDmitry Osipenko 
251496747e7SDmitry Osipenko 	return 0;
252496747e7SDmitry Osipenko }
253496747e7SDmitry Osipenko 
tegra20_core_voltage_update(struct tegra_regulator_coupler * tegra,struct regulator_dev * cpu_rdev,struct regulator_dev * core_rdev,struct regulator_dev * rtc_rdev)254496747e7SDmitry Osipenko static int tegra20_core_voltage_update(struct tegra_regulator_coupler *tegra,
255496747e7SDmitry Osipenko 				       struct regulator_dev *cpu_rdev,
256496747e7SDmitry Osipenko 				       struct regulator_dev *core_rdev,
257496747e7SDmitry Osipenko 				       struct regulator_dev *rtc_rdev)
258496747e7SDmitry Osipenko {
259496747e7SDmitry Osipenko 	int cpu_uV;
260496747e7SDmitry Osipenko 
261496747e7SDmitry Osipenko 	cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
262496747e7SDmitry Osipenko 	if (cpu_uV < 0)
263496747e7SDmitry Osipenko 		return cpu_uV;
264496747e7SDmitry Osipenko 
265496747e7SDmitry Osipenko 	return tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
266496747e7SDmitry Osipenko 				       cpu_uV, cpu_uV);
267496747e7SDmitry Osipenko }
268496747e7SDmitry Osipenko 
tegra20_cpu_voltage_update(struct tegra_regulator_coupler * tegra,struct regulator_dev * cpu_rdev,struct regulator_dev * core_rdev,struct regulator_dev * rtc_rdev)269496747e7SDmitry Osipenko static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
270496747e7SDmitry Osipenko 				      struct regulator_dev *cpu_rdev,
271496747e7SDmitry Osipenko 				      struct regulator_dev *core_rdev,
272496747e7SDmitry Osipenko 				      struct regulator_dev *rtc_rdev)
273496747e7SDmitry Osipenko {
274496747e7SDmitry Osipenko 	int cpu_min_uV_consumers = 0;
275496747e7SDmitry Osipenko 	int cpu_max_uV = INT_MAX;
276496747e7SDmitry Osipenko 	int cpu_min_uV = 0;
277496747e7SDmitry Osipenko 	int cpu_uV;
278496747e7SDmitry Osipenko 	int err;
279496747e7SDmitry Osipenko 
280496747e7SDmitry Osipenko 	err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
281496747e7SDmitry Osipenko 	if (err)
282496747e7SDmitry Osipenko 		return err;
283496747e7SDmitry Osipenko 
284496747e7SDmitry Osipenko 	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
285496747e7SDmitry Osipenko 					PM_SUSPEND_ON);
286496747e7SDmitry Osipenko 	if (err)
287496747e7SDmitry Osipenko 		return err;
288496747e7SDmitry Osipenko 
289496747e7SDmitry Osipenko 	err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
290496747e7SDmitry Osipenko 					&cpu_max_uV, PM_SUSPEND_ON);
291496747e7SDmitry Osipenko 	if (err)
292496747e7SDmitry Osipenko 		return err;
293496747e7SDmitry Osipenko 
294496747e7SDmitry Osipenko 	cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
295496747e7SDmitry Osipenko 	if (cpu_uV < 0)
296496747e7SDmitry Osipenko 		return cpu_uV;
297496747e7SDmitry Osipenko 
29803978d42SDmitry Osipenko 	/* store boot voltage level */
29903978d42SDmitry Osipenko 	if (!tegra->cpu_min_uV)
30003978d42SDmitry Osipenko 		tegra->cpu_min_uV = cpu_uV;
30103978d42SDmitry Osipenko 
302496747e7SDmitry Osipenko 	/*
303496747e7SDmitry Osipenko 	 * CPU's regulator may not have any consumers, hence the voltage
304496747e7SDmitry Osipenko 	 * must not be changed in that case because CPU simply won't
305496747e7SDmitry Osipenko 	 * survive the voltage drop if it's running on a higher frequency.
306496747e7SDmitry Osipenko 	 */
307496747e7SDmitry Osipenko 	if (!cpu_min_uV_consumers)
308496747e7SDmitry Osipenko 		cpu_min_uV = cpu_uV;
309496747e7SDmitry Osipenko 
31003978d42SDmitry Osipenko 	/* restore boot voltage level */
31103978d42SDmitry Osipenko 	if (tegra->sys_reboot_mode)
31203978d42SDmitry Osipenko 		cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV);
31303978d42SDmitry Osipenko 
314*80ef351cSDmitry Osipenko 	/* prepare voltage level for suspend */
315*80ef351cSDmitry Osipenko 	if (tegra->sys_suspend_mode)
316*80ef351cSDmitry Osipenko 		cpu_min_uV = clamp(tegra20_cpu_nominal_uV(),
317*80ef351cSDmitry Osipenko 				   cpu_min_uV, cpu_max_uV);
318*80ef351cSDmitry Osipenko 
319496747e7SDmitry Osipenko 	if (cpu_min_uV > cpu_uV) {
320496747e7SDmitry Osipenko 		err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
321496747e7SDmitry Osipenko 					      cpu_uV, cpu_min_uV);
322496747e7SDmitry Osipenko 		if (err)
323496747e7SDmitry Osipenko 			return err;
324496747e7SDmitry Osipenko 
325496747e7SDmitry Osipenko 		err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
326496747e7SDmitry Osipenko 						 cpu_max_uV, PM_SUSPEND_ON);
327496747e7SDmitry Osipenko 		if (err)
328496747e7SDmitry Osipenko 			return err;
329496747e7SDmitry Osipenko 	} else if (cpu_min_uV < cpu_uV)  {
330496747e7SDmitry Osipenko 		err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
331496747e7SDmitry Osipenko 						 cpu_max_uV, PM_SUSPEND_ON);
332496747e7SDmitry Osipenko 		if (err)
333496747e7SDmitry Osipenko 			return err;
334496747e7SDmitry Osipenko 
335496747e7SDmitry Osipenko 		err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
336496747e7SDmitry Osipenko 					      cpu_uV, cpu_min_uV);
337496747e7SDmitry Osipenko 		if (err)
338496747e7SDmitry Osipenko 			return err;
339496747e7SDmitry Osipenko 	}
340496747e7SDmitry Osipenko 
341496747e7SDmitry Osipenko 	return 0;
342496747e7SDmitry Osipenko }
343496747e7SDmitry Osipenko 
tegra20_regulator_balance_voltage(struct regulator_coupler * coupler,struct regulator_dev * rdev,suspend_state_t state)344496747e7SDmitry Osipenko static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
345496747e7SDmitry Osipenko 					     struct regulator_dev *rdev,
346496747e7SDmitry Osipenko 					     suspend_state_t state)
347496747e7SDmitry Osipenko {
348496747e7SDmitry Osipenko 	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
349496747e7SDmitry Osipenko 	struct regulator_dev *core_rdev = tegra->core_rdev;
350496747e7SDmitry Osipenko 	struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
351496747e7SDmitry Osipenko 	struct regulator_dev *rtc_rdev = tegra->rtc_rdev;
352496747e7SDmitry Osipenko 
353496747e7SDmitry Osipenko 	if ((core_rdev != rdev && cpu_rdev != rdev && rtc_rdev != rdev) ||
354496747e7SDmitry Osipenko 	    state != PM_SUSPEND_ON) {
355496747e7SDmitry Osipenko 		pr_err("regulators are not coupled properly\n");
356496747e7SDmitry Osipenko 		return -EINVAL;
357496747e7SDmitry Osipenko 	}
358496747e7SDmitry Osipenko 
35903978d42SDmitry Osipenko 	tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req);
360*80ef351cSDmitry Osipenko 	tegra->sys_suspend_mode = READ_ONCE(tegra->sys_suspend_mode_req);
36103978d42SDmitry Osipenko 
362496747e7SDmitry Osipenko 	if (rdev == cpu_rdev)
363496747e7SDmitry Osipenko 		return tegra20_cpu_voltage_update(tegra, cpu_rdev,
364496747e7SDmitry Osipenko 						  core_rdev, rtc_rdev);
365496747e7SDmitry Osipenko 
366496747e7SDmitry Osipenko 	if (rdev == core_rdev)
367496747e7SDmitry Osipenko 		return tegra20_core_voltage_update(tegra, cpu_rdev,
368496747e7SDmitry Osipenko 						   core_rdev, rtc_rdev);
369496747e7SDmitry Osipenko 
370496747e7SDmitry Osipenko 	pr_err("changing %s voltage not permitted\n", rdev_get_name(rtc_rdev));
371496747e7SDmitry Osipenko 
372496747e7SDmitry Osipenko 	return -EPERM;
373496747e7SDmitry Osipenko }
374496747e7SDmitry Osipenko 
tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler * tegra,bool sys_suspend_mode)375*80ef351cSDmitry Osipenko static int tegra20_regulator_prepare_suspend(struct tegra_regulator_coupler *tegra,
376*80ef351cSDmitry Osipenko 					     bool sys_suspend_mode)
377*80ef351cSDmitry Osipenko {
378*80ef351cSDmitry Osipenko 	int err;
379*80ef351cSDmitry Osipenko 
380*80ef351cSDmitry Osipenko 	if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev)
381*80ef351cSDmitry Osipenko 		return 0;
382*80ef351cSDmitry Osipenko 
383*80ef351cSDmitry Osipenko 	/*
384*80ef351cSDmitry Osipenko 	 * All power domains are enabled early during resume from suspend
385*80ef351cSDmitry Osipenko 	 * by GENPD core.  Domains like VENC may require a higher voltage
386*80ef351cSDmitry Osipenko 	 * when enabled during resume from suspend.  This also prepares
387*80ef351cSDmitry Osipenko 	 * hardware for resuming from LP0.
388*80ef351cSDmitry Osipenko 	 */
389*80ef351cSDmitry Osipenko 
390*80ef351cSDmitry Osipenko 	WRITE_ONCE(tegra->sys_suspend_mode_req, sys_suspend_mode);
391*80ef351cSDmitry Osipenko 
392*80ef351cSDmitry Osipenko 	err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
393*80ef351cSDmitry Osipenko 	if (err)
394*80ef351cSDmitry Osipenko 		return err;
395*80ef351cSDmitry Osipenko 
396*80ef351cSDmitry Osipenko 	err = regulator_sync_voltage_rdev(tegra->core_rdev);
397*80ef351cSDmitry Osipenko 	if (err)
398*80ef351cSDmitry Osipenko 		return err;
399*80ef351cSDmitry Osipenko 
400*80ef351cSDmitry Osipenko 	return 0;
401*80ef351cSDmitry Osipenko }
402*80ef351cSDmitry Osipenko 
tegra20_regulator_suspend(struct notifier_block * notifier,unsigned long mode,void * arg)403*80ef351cSDmitry Osipenko static int tegra20_regulator_suspend(struct notifier_block *notifier,
404*80ef351cSDmitry Osipenko 				     unsigned long mode, void *arg)
405*80ef351cSDmitry Osipenko {
406*80ef351cSDmitry Osipenko 	struct tegra_regulator_coupler *tegra;
407*80ef351cSDmitry Osipenko 	int ret = 0;
408*80ef351cSDmitry Osipenko 
409*80ef351cSDmitry Osipenko 	tegra = container_of(notifier, struct tegra_regulator_coupler,
410*80ef351cSDmitry Osipenko 			     suspend_notifier);
411*80ef351cSDmitry Osipenko 
412*80ef351cSDmitry Osipenko 	switch (mode) {
413*80ef351cSDmitry Osipenko 	case PM_HIBERNATION_PREPARE:
414*80ef351cSDmitry Osipenko 	case PM_RESTORE_PREPARE:
415*80ef351cSDmitry Osipenko 	case PM_SUSPEND_PREPARE:
416*80ef351cSDmitry Osipenko 		ret = tegra20_regulator_prepare_suspend(tegra, true);
417*80ef351cSDmitry Osipenko 		break;
418*80ef351cSDmitry Osipenko 
419*80ef351cSDmitry Osipenko 	case PM_POST_HIBERNATION:
420*80ef351cSDmitry Osipenko 	case PM_POST_RESTORE:
421*80ef351cSDmitry Osipenko 	case PM_POST_SUSPEND:
422*80ef351cSDmitry Osipenko 		ret = tegra20_regulator_prepare_suspend(tegra, false);
423*80ef351cSDmitry Osipenko 		break;
424*80ef351cSDmitry Osipenko 	}
425*80ef351cSDmitry Osipenko 
426*80ef351cSDmitry Osipenko 	if (ret)
427*80ef351cSDmitry Osipenko 		pr_err("failed to prepare regulators: %d\n", ret);
428*80ef351cSDmitry Osipenko 
429*80ef351cSDmitry Osipenko 	return notifier_from_errno(ret);
430*80ef351cSDmitry Osipenko }
431*80ef351cSDmitry Osipenko 
tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler * tegra,bool sys_reboot_mode)43203978d42SDmitry Osipenko static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra,
43303978d42SDmitry Osipenko 					    bool sys_reboot_mode)
43403978d42SDmitry Osipenko {
43503978d42SDmitry Osipenko 	int err;
43603978d42SDmitry Osipenko 
43703978d42SDmitry Osipenko 	if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev)
43803978d42SDmitry Osipenko 		return 0;
43903978d42SDmitry Osipenko 
44003978d42SDmitry Osipenko 	WRITE_ONCE(tegra->sys_reboot_mode_req, true);
44103978d42SDmitry Osipenko 
44203978d42SDmitry Osipenko 	/*
44303978d42SDmitry Osipenko 	 * Some devices use CPU soft-reboot method and in this case we
44403978d42SDmitry Osipenko 	 * should ensure that voltages are sane for the reboot by restoring
44503978d42SDmitry Osipenko 	 * the minimum boot levels.
44603978d42SDmitry Osipenko 	 */
44703978d42SDmitry Osipenko 	err = regulator_sync_voltage_rdev(tegra->cpu_rdev);
44803978d42SDmitry Osipenko 	if (err)
44903978d42SDmitry Osipenko 		return err;
45003978d42SDmitry Osipenko 
45103978d42SDmitry Osipenko 	err = regulator_sync_voltage_rdev(tegra->core_rdev);
45203978d42SDmitry Osipenko 	if (err)
45303978d42SDmitry Osipenko 		return err;
45403978d42SDmitry Osipenko 
45503978d42SDmitry Osipenko 	WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode);
45603978d42SDmitry Osipenko 
45703978d42SDmitry Osipenko 	return 0;
45803978d42SDmitry Osipenko }
45903978d42SDmitry Osipenko 
tegra20_regulator_reboot(struct notifier_block * notifier,unsigned long event,void * cmd)46003978d42SDmitry Osipenko static int tegra20_regulator_reboot(struct notifier_block *notifier,
46103978d42SDmitry Osipenko 				    unsigned long event, void *cmd)
46203978d42SDmitry Osipenko {
46303978d42SDmitry Osipenko 	struct tegra_regulator_coupler *tegra;
46403978d42SDmitry Osipenko 	int ret;
46503978d42SDmitry Osipenko 
46603978d42SDmitry Osipenko 	if (event != SYS_RESTART)
46703978d42SDmitry Osipenko 		return NOTIFY_DONE;
46803978d42SDmitry Osipenko 
46903978d42SDmitry Osipenko 	tegra = container_of(notifier, struct tegra_regulator_coupler,
47003978d42SDmitry Osipenko 			     reboot_notifier);
47103978d42SDmitry Osipenko 
47203978d42SDmitry Osipenko 	ret = tegra20_regulator_prepare_reboot(tegra, true);
47303978d42SDmitry Osipenko 
47403978d42SDmitry Osipenko 	return notifier_from_errno(ret);
47503978d42SDmitry Osipenko }
47603978d42SDmitry Osipenko 
tegra20_regulator_attach(struct regulator_coupler * coupler,struct regulator_dev * rdev)477496747e7SDmitry Osipenko static int tegra20_regulator_attach(struct regulator_coupler *coupler,
478496747e7SDmitry Osipenko 				    struct regulator_dev *rdev)
479496747e7SDmitry Osipenko {
480496747e7SDmitry Osipenko 	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
481496747e7SDmitry Osipenko 	struct device_node *np = rdev->dev.of_node;
482496747e7SDmitry Osipenko 
483496747e7SDmitry Osipenko 	if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
484496747e7SDmitry Osipenko 	    !tegra->core_rdev) {
485496747e7SDmitry Osipenko 		tegra->core_rdev = rdev;
486496747e7SDmitry Osipenko 		return 0;
487496747e7SDmitry Osipenko 	}
488496747e7SDmitry Osipenko 
489496747e7SDmitry Osipenko 	if (of_property_read_bool(np, "nvidia,tegra-rtc-regulator") &&
490496747e7SDmitry Osipenko 	    !tegra->rtc_rdev) {
491496747e7SDmitry Osipenko 		tegra->rtc_rdev = rdev;
492496747e7SDmitry Osipenko 		return 0;
493496747e7SDmitry Osipenko 	}
494496747e7SDmitry Osipenko 
495496747e7SDmitry Osipenko 	if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
496496747e7SDmitry Osipenko 	    !tegra->cpu_rdev) {
497496747e7SDmitry Osipenko 		tegra->cpu_rdev = rdev;
498496747e7SDmitry Osipenko 		return 0;
499496747e7SDmitry Osipenko 	}
500496747e7SDmitry Osipenko 
501496747e7SDmitry Osipenko 	return -EINVAL;
502496747e7SDmitry Osipenko }
503496747e7SDmitry Osipenko 
tegra20_regulator_detach(struct regulator_coupler * coupler,struct regulator_dev * rdev)504496747e7SDmitry Osipenko static int tegra20_regulator_detach(struct regulator_coupler *coupler,
505496747e7SDmitry Osipenko 				    struct regulator_dev *rdev)
506496747e7SDmitry Osipenko {
507496747e7SDmitry Osipenko 	struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
508496747e7SDmitry Osipenko 
50903978d42SDmitry Osipenko 	/*
51003978d42SDmitry Osipenko 	 * We don't expect regulators to be decoupled during reboot,
51103978d42SDmitry Osipenko 	 * this may race with the reboot handler and shouldn't ever
51203978d42SDmitry Osipenko 	 * happen in practice.
51303978d42SDmitry Osipenko 	 */
51403978d42SDmitry Osipenko 	if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING))
51503978d42SDmitry Osipenko 		return -EPERM;
51603978d42SDmitry Osipenko 
517496747e7SDmitry Osipenko 	if (tegra->core_rdev == rdev) {
518496747e7SDmitry Osipenko 		tegra->core_rdev = NULL;
519496747e7SDmitry Osipenko 		return 0;
520496747e7SDmitry Osipenko 	}
521496747e7SDmitry Osipenko 
522496747e7SDmitry Osipenko 	if (tegra->rtc_rdev == rdev) {
523496747e7SDmitry Osipenko 		tegra->rtc_rdev = NULL;
524496747e7SDmitry Osipenko 		return 0;
525496747e7SDmitry Osipenko 	}
526496747e7SDmitry Osipenko 
527496747e7SDmitry Osipenko 	if (tegra->cpu_rdev == rdev) {
528496747e7SDmitry Osipenko 		tegra->cpu_rdev = NULL;
529496747e7SDmitry Osipenko 		return 0;
530496747e7SDmitry Osipenko 	}
531496747e7SDmitry Osipenko 
532496747e7SDmitry Osipenko 	return -EINVAL;
533496747e7SDmitry Osipenko }
534496747e7SDmitry Osipenko 
535496747e7SDmitry Osipenko static struct tegra_regulator_coupler tegra20_coupler = {
536496747e7SDmitry Osipenko 	.coupler = {
537496747e7SDmitry Osipenko 		.attach_regulator = tegra20_regulator_attach,
538496747e7SDmitry Osipenko 		.detach_regulator = tegra20_regulator_detach,
539496747e7SDmitry Osipenko 		.balance_voltage = tegra20_regulator_balance_voltage,
540496747e7SDmitry Osipenko 	},
54103978d42SDmitry Osipenko 	.reboot_notifier.notifier_call = tegra20_regulator_reboot,
542*80ef351cSDmitry Osipenko 	.suspend_notifier.notifier_call = tegra20_regulator_suspend,
543496747e7SDmitry Osipenko };
544496747e7SDmitry Osipenko 
tegra_regulator_coupler_init(void)545496747e7SDmitry Osipenko static int __init tegra_regulator_coupler_init(void)
546496747e7SDmitry Osipenko {
54703978d42SDmitry Osipenko 	int err;
54803978d42SDmitry Osipenko 
549496747e7SDmitry Osipenko 	if (!of_machine_is_compatible("nvidia,tegra20"))
550496747e7SDmitry Osipenko 		return 0;
551496747e7SDmitry Osipenko 
55203978d42SDmitry Osipenko 	err = register_reboot_notifier(&tegra20_coupler.reboot_notifier);
55303978d42SDmitry Osipenko 	WARN_ON(err);
55403978d42SDmitry Osipenko 
555*80ef351cSDmitry Osipenko 	err = register_pm_notifier(&tegra20_coupler.suspend_notifier);
556*80ef351cSDmitry Osipenko 	WARN_ON(err);
557*80ef351cSDmitry Osipenko 
558496747e7SDmitry Osipenko 	return regulator_coupler_register(&tegra20_coupler.coupler);
559496747e7SDmitry Osipenko }
560496747e7SDmitry Osipenko arch_initcall(tegra_regulator_coupler_init);
561