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> 19496747e7SDmitry Osipenko 20*029f7e24SDmitry Osipenko #include <soc/tegra/pmc.h> 21*029f7e24SDmitry Osipenko 22496747e7SDmitry Osipenko struct tegra_regulator_coupler { 23496747e7SDmitry Osipenko struct regulator_coupler coupler; 24496747e7SDmitry Osipenko struct regulator_dev *core_rdev; 25496747e7SDmitry Osipenko struct regulator_dev *cpu_rdev; 26496747e7SDmitry Osipenko struct regulator_dev *rtc_rdev; 2703978d42SDmitry Osipenko struct notifier_block reboot_notifier; 2803978d42SDmitry Osipenko int core_min_uV, cpu_min_uV; 2903978d42SDmitry Osipenko bool sys_reboot_mode_req; 3003978d42SDmitry Osipenko bool sys_reboot_mode; 31496747e7SDmitry Osipenko }; 32496747e7SDmitry Osipenko 33496747e7SDmitry Osipenko static inline struct tegra_regulator_coupler * 34496747e7SDmitry Osipenko to_tegra_coupler(struct regulator_coupler *coupler) 35496747e7SDmitry Osipenko { 36496747e7SDmitry Osipenko return container_of(coupler, struct tegra_regulator_coupler, coupler); 37496747e7SDmitry Osipenko } 38496747e7SDmitry Osipenko 39496747e7SDmitry Osipenko static int tegra20_core_limit(struct tegra_regulator_coupler *tegra, 40496747e7SDmitry Osipenko struct regulator_dev *core_rdev) 41496747e7SDmitry Osipenko { 42496747e7SDmitry Osipenko int core_min_uV = 0; 43496747e7SDmitry Osipenko int core_max_uV; 44496747e7SDmitry Osipenko int core_cur_uV; 45496747e7SDmitry Osipenko int err; 46496747e7SDmitry Osipenko 47*029f7e24SDmitry Osipenko /* 48*029f7e24SDmitry Osipenko * Tegra20 SoC has critical DVFS-capable devices that are 49*029f7e24SDmitry Osipenko * permanently-active or active at a boot time, like EMC 50*029f7e24SDmitry Osipenko * (DRAM controller) or Display controller for example. 51*029f7e24SDmitry Osipenko * 52*029f7e24SDmitry Osipenko * The voltage of a CORE SoC power domain shall not be dropped below 53*029f7e24SDmitry Osipenko * a minimum level, which is determined by device's clock rate. 54*029f7e24SDmitry Osipenko * This means that we can't fully allow CORE voltage scaling until 55*029f7e24SDmitry Osipenko * the state of all DVFS-critical CORE devices is synced. 56*029f7e24SDmitry Osipenko */ 57*029f7e24SDmitry Osipenko if (tegra_pmc_core_domain_state_synced() && !tegra->sys_reboot_mode) { 58*029f7e24SDmitry Osipenko pr_info_once("voltage state synced\n"); 59*029f7e24SDmitry Osipenko return 0; 60*029f7e24SDmitry Osipenko } 61*029f7e24SDmitry Osipenko 62496747e7SDmitry Osipenko if (tegra->core_min_uV > 0) 63496747e7SDmitry Osipenko return tegra->core_min_uV; 64496747e7SDmitry Osipenko 65496747e7SDmitry Osipenko core_cur_uV = regulator_get_voltage_rdev(core_rdev); 66496747e7SDmitry Osipenko if (core_cur_uV < 0) 67496747e7SDmitry Osipenko return core_cur_uV; 68496747e7SDmitry Osipenko 69496747e7SDmitry Osipenko core_max_uV = max(core_cur_uV, 1200000); 70496747e7SDmitry Osipenko 71496747e7SDmitry Osipenko err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV); 72496747e7SDmitry Osipenko if (err) 73496747e7SDmitry Osipenko return err; 74496747e7SDmitry Osipenko 75496747e7SDmitry Osipenko /* 76496747e7SDmitry Osipenko * Limit minimum CORE voltage to a value left from bootloader or, 77496747e7SDmitry Osipenko * if it's unreasonably low value, to the most common 1.2v or to 78496747e7SDmitry Osipenko * whatever maximum value defined via board's device-tree. 79496747e7SDmitry Osipenko */ 80496747e7SDmitry Osipenko tegra->core_min_uV = core_max_uV; 81496747e7SDmitry Osipenko 82*029f7e24SDmitry Osipenko pr_info("core voltage initialized to %duV\n", tegra->core_min_uV); 83496747e7SDmitry Osipenko 84496747e7SDmitry Osipenko return tegra->core_min_uV; 85496747e7SDmitry Osipenko } 86496747e7SDmitry Osipenko 87496747e7SDmitry Osipenko static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev, 88496747e7SDmitry Osipenko struct regulator_dev *rtc_rdev) 89496747e7SDmitry Osipenko { 90496747e7SDmitry Osipenko struct coupling_desc *c_desc = &core_rdev->coupling_desc; 91496747e7SDmitry Osipenko struct regulator_dev *rdev; 92496747e7SDmitry Osipenko int max_spread; 93496747e7SDmitry Osipenko unsigned int i; 94496747e7SDmitry Osipenko 95496747e7SDmitry Osipenko for (i = 1; i < c_desc->n_coupled; i++) { 96496747e7SDmitry Osipenko max_spread = core_rdev->constraints->max_spread[i - 1]; 97496747e7SDmitry Osipenko rdev = c_desc->coupled_rdevs[i]; 98496747e7SDmitry Osipenko 99496747e7SDmitry Osipenko if (rdev == rtc_rdev && max_spread) 100496747e7SDmitry Osipenko return max_spread; 101496747e7SDmitry Osipenko } 102496747e7SDmitry Osipenko 103496747e7SDmitry Osipenko pr_err_once("rtc-core max-spread is undefined in device-tree\n"); 104496747e7SDmitry Osipenko 105496747e7SDmitry Osipenko return 150000; 106496747e7SDmitry Osipenko } 107496747e7SDmitry Osipenko 108496747e7SDmitry Osipenko static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra, 109496747e7SDmitry Osipenko struct regulator_dev *core_rdev, 110496747e7SDmitry Osipenko struct regulator_dev *rtc_rdev, 111496747e7SDmitry Osipenko int cpu_uV, int cpu_min_uV) 112496747e7SDmitry Osipenko { 113496747e7SDmitry Osipenko int core_min_uV, core_max_uV = INT_MAX; 114496747e7SDmitry Osipenko int rtc_min_uV, rtc_max_uV = INT_MAX; 115496747e7SDmitry Osipenko int core_target_uV; 116496747e7SDmitry Osipenko int rtc_target_uV; 117496747e7SDmitry Osipenko int max_spread; 118496747e7SDmitry Osipenko int core_uV; 119496747e7SDmitry Osipenko int rtc_uV; 120496747e7SDmitry Osipenko int err; 121496747e7SDmitry Osipenko 122496747e7SDmitry Osipenko /* 123496747e7SDmitry Osipenko * RTC and CORE voltages should be no more than 170mV from each other, 124496747e7SDmitry Osipenko * CPU should be below RTC and CORE by at least 120mV. This applies 125496747e7SDmitry Osipenko * to all Tegra20 SoC's. 126496747e7SDmitry Osipenko */ 127496747e7SDmitry Osipenko max_spread = tegra20_core_rtc_max_spread(core_rdev, rtc_rdev); 128496747e7SDmitry Osipenko 129496747e7SDmitry Osipenko /* 130496747e7SDmitry Osipenko * The core voltage scaling is currently not hooked up in drivers, 131496747e7SDmitry Osipenko * hence we will limit the minimum core voltage to a reasonable value. 132496747e7SDmitry Osipenko * This should be good enough for the time being. 133496747e7SDmitry Osipenko */ 134496747e7SDmitry Osipenko core_min_uV = tegra20_core_limit(tegra, core_rdev); 135496747e7SDmitry Osipenko if (core_min_uV < 0) 136496747e7SDmitry Osipenko return core_min_uV; 137496747e7SDmitry Osipenko 138496747e7SDmitry Osipenko err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV); 139496747e7SDmitry Osipenko if (err) 140496747e7SDmitry Osipenko return err; 141496747e7SDmitry Osipenko 142496747e7SDmitry Osipenko err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV, 143496747e7SDmitry Osipenko PM_SUSPEND_ON); 144496747e7SDmitry Osipenko if (err) 145496747e7SDmitry Osipenko return err; 146496747e7SDmitry Osipenko 147496747e7SDmitry Osipenko core_uV = regulator_get_voltage_rdev(core_rdev); 148496747e7SDmitry Osipenko if (core_uV < 0) 149496747e7SDmitry Osipenko return core_uV; 150496747e7SDmitry Osipenko 151496747e7SDmitry Osipenko core_min_uV = max(cpu_min_uV + 125000, core_min_uV); 152496747e7SDmitry Osipenko if (core_min_uV > core_max_uV) 153496747e7SDmitry Osipenko return -EINVAL; 154496747e7SDmitry Osipenko 155496747e7SDmitry Osipenko if (cpu_uV + 120000 > core_uV) 156496747e7SDmitry Osipenko pr_err("core-cpu voltage constraint violated: %d %d\n", 157496747e7SDmitry Osipenko core_uV, cpu_uV + 120000); 158496747e7SDmitry Osipenko 159496747e7SDmitry Osipenko rtc_uV = regulator_get_voltage_rdev(rtc_rdev); 160496747e7SDmitry Osipenko if (rtc_uV < 0) 161496747e7SDmitry Osipenko return rtc_uV; 162496747e7SDmitry Osipenko 163496747e7SDmitry Osipenko if (cpu_uV + 120000 > rtc_uV) 164496747e7SDmitry Osipenko pr_err("rtc-cpu voltage constraint violated: %d %d\n", 165496747e7SDmitry Osipenko rtc_uV, cpu_uV + 120000); 166496747e7SDmitry Osipenko 167496747e7SDmitry Osipenko if (abs(core_uV - rtc_uV) > 170000) 168496747e7SDmitry Osipenko pr_err("core-rtc voltage constraint violated: %d %d\n", 169496747e7SDmitry Osipenko core_uV, rtc_uV); 170496747e7SDmitry Osipenko 171496747e7SDmitry Osipenko rtc_min_uV = max(cpu_min_uV + 125000, core_min_uV - max_spread); 172496747e7SDmitry Osipenko 173496747e7SDmitry Osipenko err = regulator_check_voltage(rtc_rdev, &rtc_min_uV, &rtc_max_uV); 174496747e7SDmitry Osipenko if (err) 175496747e7SDmitry Osipenko return err; 176496747e7SDmitry Osipenko 177496747e7SDmitry Osipenko while (core_uV != core_min_uV || rtc_uV != rtc_min_uV) { 178496747e7SDmitry Osipenko if (core_uV < core_min_uV) { 179496747e7SDmitry Osipenko core_target_uV = min(core_uV + max_spread, core_min_uV); 180496747e7SDmitry Osipenko core_target_uV = min(rtc_uV + max_spread, core_target_uV); 181496747e7SDmitry Osipenko } else { 182496747e7SDmitry Osipenko core_target_uV = max(core_uV - max_spread, core_min_uV); 183496747e7SDmitry Osipenko core_target_uV = max(rtc_uV - max_spread, core_target_uV); 184496747e7SDmitry Osipenko } 185496747e7SDmitry Osipenko 18645f019a6SDmitry Osipenko if (core_uV == core_target_uV) 18745f019a6SDmitry Osipenko goto update_rtc; 18845f019a6SDmitry Osipenko 189496747e7SDmitry Osipenko err = regulator_set_voltage_rdev(core_rdev, 190496747e7SDmitry Osipenko core_target_uV, 191496747e7SDmitry Osipenko core_max_uV, 192496747e7SDmitry Osipenko PM_SUSPEND_ON); 193496747e7SDmitry Osipenko if (err) 194496747e7SDmitry Osipenko return err; 195496747e7SDmitry Osipenko 196496747e7SDmitry Osipenko core_uV = core_target_uV; 19745f019a6SDmitry Osipenko update_rtc: 198496747e7SDmitry Osipenko if (rtc_uV < rtc_min_uV) { 199496747e7SDmitry Osipenko rtc_target_uV = min(rtc_uV + max_spread, rtc_min_uV); 200496747e7SDmitry Osipenko rtc_target_uV = min(core_uV + max_spread, rtc_target_uV); 201496747e7SDmitry Osipenko } else { 202496747e7SDmitry Osipenko rtc_target_uV = max(rtc_uV - max_spread, rtc_min_uV); 203496747e7SDmitry Osipenko rtc_target_uV = max(core_uV - max_spread, rtc_target_uV); 204496747e7SDmitry Osipenko } 205496747e7SDmitry Osipenko 20645f019a6SDmitry Osipenko if (rtc_uV == rtc_target_uV) 20745f019a6SDmitry Osipenko continue; 20845f019a6SDmitry Osipenko 209496747e7SDmitry Osipenko err = regulator_set_voltage_rdev(rtc_rdev, 210496747e7SDmitry Osipenko rtc_target_uV, 211496747e7SDmitry Osipenko rtc_max_uV, 212496747e7SDmitry Osipenko PM_SUSPEND_ON); 213496747e7SDmitry Osipenko if (err) 214496747e7SDmitry Osipenko return err; 215496747e7SDmitry Osipenko 216496747e7SDmitry Osipenko rtc_uV = rtc_target_uV; 217496747e7SDmitry Osipenko } 218496747e7SDmitry Osipenko 219496747e7SDmitry Osipenko return 0; 220496747e7SDmitry Osipenko } 221496747e7SDmitry Osipenko 222496747e7SDmitry Osipenko static int tegra20_core_voltage_update(struct tegra_regulator_coupler *tegra, 223496747e7SDmitry Osipenko struct regulator_dev *cpu_rdev, 224496747e7SDmitry Osipenko struct regulator_dev *core_rdev, 225496747e7SDmitry Osipenko struct regulator_dev *rtc_rdev) 226496747e7SDmitry Osipenko { 227496747e7SDmitry Osipenko int cpu_uV; 228496747e7SDmitry Osipenko 229496747e7SDmitry Osipenko cpu_uV = regulator_get_voltage_rdev(cpu_rdev); 230496747e7SDmitry Osipenko if (cpu_uV < 0) 231496747e7SDmitry Osipenko return cpu_uV; 232496747e7SDmitry Osipenko 233496747e7SDmitry Osipenko return tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, 234496747e7SDmitry Osipenko cpu_uV, cpu_uV); 235496747e7SDmitry Osipenko } 236496747e7SDmitry Osipenko 237496747e7SDmitry Osipenko static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra, 238496747e7SDmitry Osipenko struct regulator_dev *cpu_rdev, 239496747e7SDmitry Osipenko struct regulator_dev *core_rdev, 240496747e7SDmitry Osipenko struct regulator_dev *rtc_rdev) 241496747e7SDmitry Osipenko { 242496747e7SDmitry Osipenko int cpu_min_uV_consumers = 0; 243496747e7SDmitry Osipenko int cpu_max_uV = INT_MAX; 244496747e7SDmitry Osipenko int cpu_min_uV = 0; 245496747e7SDmitry Osipenko int cpu_uV; 246496747e7SDmitry Osipenko int err; 247496747e7SDmitry Osipenko 248496747e7SDmitry Osipenko err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV); 249496747e7SDmitry Osipenko if (err) 250496747e7SDmitry Osipenko return err; 251496747e7SDmitry Osipenko 252496747e7SDmitry Osipenko err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV, 253496747e7SDmitry Osipenko PM_SUSPEND_ON); 254496747e7SDmitry Osipenko if (err) 255496747e7SDmitry Osipenko return err; 256496747e7SDmitry Osipenko 257496747e7SDmitry Osipenko err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers, 258496747e7SDmitry Osipenko &cpu_max_uV, PM_SUSPEND_ON); 259496747e7SDmitry Osipenko if (err) 260496747e7SDmitry Osipenko return err; 261496747e7SDmitry Osipenko 262496747e7SDmitry Osipenko cpu_uV = regulator_get_voltage_rdev(cpu_rdev); 263496747e7SDmitry Osipenko if (cpu_uV < 0) 264496747e7SDmitry Osipenko return cpu_uV; 265496747e7SDmitry Osipenko 26603978d42SDmitry Osipenko /* store boot voltage level */ 26703978d42SDmitry Osipenko if (!tegra->cpu_min_uV) 26803978d42SDmitry Osipenko tegra->cpu_min_uV = cpu_uV; 26903978d42SDmitry Osipenko 270496747e7SDmitry Osipenko /* 271496747e7SDmitry Osipenko * CPU's regulator may not have any consumers, hence the voltage 272496747e7SDmitry Osipenko * must not be changed in that case because CPU simply won't 273496747e7SDmitry Osipenko * survive the voltage drop if it's running on a higher frequency. 274496747e7SDmitry Osipenko */ 275496747e7SDmitry Osipenko if (!cpu_min_uV_consumers) 276496747e7SDmitry Osipenko cpu_min_uV = cpu_uV; 277496747e7SDmitry Osipenko 27803978d42SDmitry Osipenko /* restore boot voltage level */ 27903978d42SDmitry Osipenko if (tegra->sys_reboot_mode) 28003978d42SDmitry Osipenko cpu_min_uV = max(cpu_min_uV, tegra->cpu_min_uV); 28103978d42SDmitry Osipenko 282496747e7SDmitry Osipenko if (cpu_min_uV > cpu_uV) { 283496747e7SDmitry Osipenko err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, 284496747e7SDmitry Osipenko cpu_uV, cpu_min_uV); 285496747e7SDmitry Osipenko if (err) 286496747e7SDmitry Osipenko return err; 287496747e7SDmitry Osipenko 288496747e7SDmitry Osipenko err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV, 289496747e7SDmitry Osipenko cpu_max_uV, PM_SUSPEND_ON); 290496747e7SDmitry Osipenko if (err) 291496747e7SDmitry Osipenko return err; 292496747e7SDmitry Osipenko } else if (cpu_min_uV < cpu_uV) { 293496747e7SDmitry Osipenko err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV, 294496747e7SDmitry Osipenko cpu_max_uV, PM_SUSPEND_ON); 295496747e7SDmitry Osipenko if (err) 296496747e7SDmitry Osipenko return err; 297496747e7SDmitry Osipenko 298496747e7SDmitry Osipenko err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev, 299496747e7SDmitry Osipenko cpu_uV, cpu_min_uV); 300496747e7SDmitry Osipenko if (err) 301496747e7SDmitry Osipenko return err; 302496747e7SDmitry Osipenko } 303496747e7SDmitry Osipenko 304496747e7SDmitry Osipenko return 0; 305496747e7SDmitry Osipenko } 306496747e7SDmitry Osipenko 307496747e7SDmitry Osipenko static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler, 308496747e7SDmitry Osipenko struct regulator_dev *rdev, 309496747e7SDmitry Osipenko suspend_state_t state) 310496747e7SDmitry Osipenko { 311496747e7SDmitry Osipenko struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); 312496747e7SDmitry Osipenko struct regulator_dev *core_rdev = tegra->core_rdev; 313496747e7SDmitry Osipenko struct regulator_dev *cpu_rdev = tegra->cpu_rdev; 314496747e7SDmitry Osipenko struct regulator_dev *rtc_rdev = tegra->rtc_rdev; 315496747e7SDmitry Osipenko 316496747e7SDmitry Osipenko if ((core_rdev != rdev && cpu_rdev != rdev && rtc_rdev != rdev) || 317496747e7SDmitry Osipenko state != PM_SUSPEND_ON) { 318496747e7SDmitry Osipenko pr_err("regulators are not coupled properly\n"); 319496747e7SDmitry Osipenko return -EINVAL; 320496747e7SDmitry Osipenko } 321496747e7SDmitry Osipenko 32203978d42SDmitry Osipenko tegra->sys_reboot_mode = READ_ONCE(tegra->sys_reboot_mode_req); 32303978d42SDmitry Osipenko 324496747e7SDmitry Osipenko if (rdev == cpu_rdev) 325496747e7SDmitry Osipenko return tegra20_cpu_voltage_update(tegra, cpu_rdev, 326496747e7SDmitry Osipenko core_rdev, rtc_rdev); 327496747e7SDmitry Osipenko 328496747e7SDmitry Osipenko if (rdev == core_rdev) 329496747e7SDmitry Osipenko return tegra20_core_voltage_update(tegra, cpu_rdev, 330496747e7SDmitry Osipenko core_rdev, rtc_rdev); 331496747e7SDmitry Osipenko 332496747e7SDmitry Osipenko pr_err("changing %s voltage not permitted\n", rdev_get_name(rtc_rdev)); 333496747e7SDmitry Osipenko 334496747e7SDmitry Osipenko return -EPERM; 335496747e7SDmitry Osipenko } 336496747e7SDmitry Osipenko 33703978d42SDmitry Osipenko static int tegra20_regulator_prepare_reboot(struct tegra_regulator_coupler *tegra, 33803978d42SDmitry Osipenko bool sys_reboot_mode) 33903978d42SDmitry Osipenko { 34003978d42SDmitry Osipenko int err; 34103978d42SDmitry Osipenko 34203978d42SDmitry Osipenko if (!tegra->core_rdev || !tegra->rtc_rdev || !tegra->cpu_rdev) 34303978d42SDmitry Osipenko return 0; 34403978d42SDmitry Osipenko 34503978d42SDmitry Osipenko WRITE_ONCE(tegra->sys_reboot_mode_req, true); 34603978d42SDmitry Osipenko 34703978d42SDmitry Osipenko /* 34803978d42SDmitry Osipenko * Some devices use CPU soft-reboot method and in this case we 34903978d42SDmitry Osipenko * should ensure that voltages are sane for the reboot by restoring 35003978d42SDmitry Osipenko * the minimum boot levels. 35103978d42SDmitry Osipenko */ 35203978d42SDmitry Osipenko err = regulator_sync_voltage_rdev(tegra->cpu_rdev); 35303978d42SDmitry Osipenko if (err) 35403978d42SDmitry Osipenko return err; 35503978d42SDmitry Osipenko 35603978d42SDmitry Osipenko err = regulator_sync_voltage_rdev(tegra->core_rdev); 35703978d42SDmitry Osipenko if (err) 35803978d42SDmitry Osipenko return err; 35903978d42SDmitry Osipenko 36003978d42SDmitry Osipenko WRITE_ONCE(tegra->sys_reboot_mode_req, sys_reboot_mode); 36103978d42SDmitry Osipenko 36203978d42SDmitry Osipenko return 0; 36303978d42SDmitry Osipenko } 36403978d42SDmitry Osipenko 36503978d42SDmitry Osipenko static int tegra20_regulator_reboot(struct notifier_block *notifier, 36603978d42SDmitry Osipenko unsigned long event, void *cmd) 36703978d42SDmitry Osipenko { 36803978d42SDmitry Osipenko struct tegra_regulator_coupler *tegra; 36903978d42SDmitry Osipenko int ret; 37003978d42SDmitry Osipenko 37103978d42SDmitry Osipenko if (event != SYS_RESTART) 37203978d42SDmitry Osipenko return NOTIFY_DONE; 37303978d42SDmitry Osipenko 37403978d42SDmitry Osipenko tegra = container_of(notifier, struct tegra_regulator_coupler, 37503978d42SDmitry Osipenko reboot_notifier); 37603978d42SDmitry Osipenko 37703978d42SDmitry Osipenko ret = tegra20_regulator_prepare_reboot(tegra, true); 37803978d42SDmitry Osipenko 37903978d42SDmitry Osipenko return notifier_from_errno(ret); 38003978d42SDmitry Osipenko } 38103978d42SDmitry Osipenko 382496747e7SDmitry Osipenko static int tegra20_regulator_attach(struct regulator_coupler *coupler, 383496747e7SDmitry Osipenko struct regulator_dev *rdev) 384496747e7SDmitry Osipenko { 385496747e7SDmitry Osipenko struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); 386496747e7SDmitry Osipenko struct device_node *np = rdev->dev.of_node; 387496747e7SDmitry Osipenko 388496747e7SDmitry Osipenko if (of_property_read_bool(np, "nvidia,tegra-core-regulator") && 389496747e7SDmitry Osipenko !tegra->core_rdev) { 390496747e7SDmitry Osipenko tegra->core_rdev = rdev; 391496747e7SDmitry Osipenko return 0; 392496747e7SDmitry Osipenko } 393496747e7SDmitry Osipenko 394496747e7SDmitry Osipenko if (of_property_read_bool(np, "nvidia,tegra-rtc-regulator") && 395496747e7SDmitry Osipenko !tegra->rtc_rdev) { 396496747e7SDmitry Osipenko tegra->rtc_rdev = rdev; 397496747e7SDmitry Osipenko return 0; 398496747e7SDmitry Osipenko } 399496747e7SDmitry Osipenko 400496747e7SDmitry Osipenko if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") && 401496747e7SDmitry Osipenko !tegra->cpu_rdev) { 402496747e7SDmitry Osipenko tegra->cpu_rdev = rdev; 403496747e7SDmitry Osipenko return 0; 404496747e7SDmitry Osipenko } 405496747e7SDmitry Osipenko 406496747e7SDmitry Osipenko return -EINVAL; 407496747e7SDmitry Osipenko } 408496747e7SDmitry Osipenko 409496747e7SDmitry Osipenko static int tegra20_regulator_detach(struct regulator_coupler *coupler, 410496747e7SDmitry Osipenko struct regulator_dev *rdev) 411496747e7SDmitry Osipenko { 412496747e7SDmitry Osipenko struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler); 413496747e7SDmitry Osipenko 41403978d42SDmitry Osipenko /* 41503978d42SDmitry Osipenko * We don't expect regulators to be decoupled during reboot, 41603978d42SDmitry Osipenko * this may race with the reboot handler and shouldn't ever 41703978d42SDmitry Osipenko * happen in practice. 41803978d42SDmitry Osipenko */ 41903978d42SDmitry Osipenko if (WARN_ON_ONCE(system_state > SYSTEM_RUNNING)) 42003978d42SDmitry Osipenko return -EPERM; 42103978d42SDmitry Osipenko 422496747e7SDmitry Osipenko if (tegra->core_rdev == rdev) { 423496747e7SDmitry Osipenko tegra->core_rdev = NULL; 424496747e7SDmitry Osipenko return 0; 425496747e7SDmitry Osipenko } 426496747e7SDmitry Osipenko 427496747e7SDmitry Osipenko if (tegra->rtc_rdev == rdev) { 428496747e7SDmitry Osipenko tegra->rtc_rdev = NULL; 429496747e7SDmitry Osipenko return 0; 430496747e7SDmitry Osipenko } 431496747e7SDmitry Osipenko 432496747e7SDmitry Osipenko if (tegra->cpu_rdev == rdev) { 433496747e7SDmitry Osipenko tegra->cpu_rdev = NULL; 434496747e7SDmitry Osipenko return 0; 435496747e7SDmitry Osipenko } 436496747e7SDmitry Osipenko 437496747e7SDmitry Osipenko return -EINVAL; 438496747e7SDmitry Osipenko } 439496747e7SDmitry Osipenko 440496747e7SDmitry Osipenko static struct tegra_regulator_coupler tegra20_coupler = { 441496747e7SDmitry Osipenko .coupler = { 442496747e7SDmitry Osipenko .attach_regulator = tegra20_regulator_attach, 443496747e7SDmitry Osipenko .detach_regulator = tegra20_regulator_detach, 444496747e7SDmitry Osipenko .balance_voltage = tegra20_regulator_balance_voltage, 445496747e7SDmitry Osipenko }, 44603978d42SDmitry Osipenko .reboot_notifier.notifier_call = tegra20_regulator_reboot, 447496747e7SDmitry Osipenko }; 448496747e7SDmitry Osipenko 449496747e7SDmitry Osipenko static int __init tegra_regulator_coupler_init(void) 450496747e7SDmitry Osipenko { 45103978d42SDmitry Osipenko int err; 45203978d42SDmitry Osipenko 453496747e7SDmitry Osipenko if (!of_machine_is_compatible("nvidia,tegra20")) 454496747e7SDmitry Osipenko return 0; 455496747e7SDmitry Osipenko 45603978d42SDmitry Osipenko err = register_reboot_notifier(&tegra20_coupler.reboot_notifier); 45703978d42SDmitry Osipenko WARN_ON(err); 45803978d42SDmitry Osipenko 459496747e7SDmitry Osipenko return regulator_coupler_register(&tegra20_coupler.coupler); 460496747e7SDmitry Osipenko } 461496747e7SDmitry Osipenko arch_initcall(tegra_regulator_coupler_init); 462