linux/drivers/soc/tegra/regulators-tegra20.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Voltage regulators coupler for NVIDIA Tegra20
   4 * Copyright (C) 2019 GRATE-DRIVER project
   5 *
   6 * Voltage constraints borrowed from downstream kernel sources
   7 * Copyright (C) 2010-2011 NVIDIA Corporation
   8 */
   9
  10#define pr_fmt(fmt)     "tegra voltage-coupler: " fmt
  11
  12#include <linux/init.h>
  13#include <linux/kernel.h>
  14#include <linux/of.h>
  15#include <linux/regulator/coupler.h>
  16#include <linux/regulator/driver.h>
  17#include <linux/regulator/machine.h>
  18
  19struct tegra_regulator_coupler {
  20        struct regulator_coupler coupler;
  21        struct regulator_dev *core_rdev;
  22        struct regulator_dev *cpu_rdev;
  23        struct regulator_dev *rtc_rdev;
  24        int core_min_uV;
  25};
  26
  27static inline struct tegra_regulator_coupler *
  28to_tegra_coupler(struct regulator_coupler *coupler)
  29{
  30        return container_of(coupler, struct tegra_regulator_coupler, coupler);
  31}
  32
  33static int tegra20_core_limit(struct tegra_regulator_coupler *tegra,
  34                              struct regulator_dev *core_rdev)
  35{
  36        int core_min_uV = 0;
  37        int core_max_uV;
  38        int core_cur_uV;
  39        int err;
  40
  41        if (tegra->core_min_uV > 0)
  42                return tegra->core_min_uV;
  43
  44        core_cur_uV = regulator_get_voltage_rdev(core_rdev);
  45        if (core_cur_uV < 0)
  46                return core_cur_uV;
  47
  48        core_max_uV = max(core_cur_uV, 1200000);
  49
  50        err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
  51        if (err)
  52                return err;
  53
  54        /*
  55         * Limit minimum CORE voltage to a value left from bootloader or,
  56         * if it's unreasonably low value, to the most common 1.2v or to
  57         * whatever maximum value defined via board's device-tree.
  58         */
  59        tegra->core_min_uV = core_max_uV;
  60
  61        pr_info("core minimum voltage limited to %duV\n", tegra->core_min_uV);
  62
  63        return tegra->core_min_uV;
  64}
  65
  66static int tegra20_core_rtc_max_spread(struct regulator_dev *core_rdev,
  67                                       struct regulator_dev *rtc_rdev)
  68{
  69        struct coupling_desc *c_desc = &core_rdev->coupling_desc;
  70        struct regulator_dev *rdev;
  71        int max_spread;
  72        unsigned int i;
  73
  74        for (i = 1; i < c_desc->n_coupled; i++) {
  75                max_spread = core_rdev->constraints->max_spread[i - 1];
  76                rdev = c_desc->coupled_rdevs[i];
  77
  78                if (rdev == rtc_rdev && max_spread)
  79                        return max_spread;
  80        }
  81
  82        pr_err_once("rtc-core max-spread is undefined in device-tree\n");
  83
  84        return 150000;
  85}
  86
  87static int tegra20_core_rtc_update(struct tegra_regulator_coupler *tegra,
  88                                   struct regulator_dev *core_rdev,
  89                                   struct regulator_dev *rtc_rdev,
  90                                   int cpu_uV, int cpu_min_uV)
  91{
  92        int core_min_uV, core_max_uV = INT_MAX;
  93        int rtc_min_uV, rtc_max_uV = INT_MAX;
  94        int core_target_uV;
  95        int rtc_target_uV;
  96        int max_spread;
  97        int core_uV;
  98        int rtc_uV;
  99        int err;
 100
 101        /*
 102         * RTC and CORE voltages should be no more than 170mV from each other,
 103         * CPU should be below RTC and CORE by at least 120mV. This applies
 104         * to all Tegra20 SoC's.
 105         */
 106        max_spread = tegra20_core_rtc_max_spread(core_rdev, rtc_rdev);
 107
 108        /*
 109         * The core voltage scaling is currently not hooked up in drivers,
 110         * hence we will limit the minimum core voltage to a reasonable value.
 111         * This should be good enough for the time being.
 112         */
 113        core_min_uV = tegra20_core_limit(tegra, core_rdev);
 114        if (core_min_uV < 0)
 115                return core_min_uV;
 116
 117        err = regulator_check_voltage(core_rdev, &core_min_uV, &core_max_uV);
 118        if (err)
 119                return err;
 120
 121        err = regulator_check_consumers(core_rdev, &core_min_uV, &core_max_uV,
 122                                        PM_SUSPEND_ON);
 123        if (err)
 124                return err;
 125
 126        core_uV = regulator_get_voltage_rdev(core_rdev);
 127        if (core_uV < 0)
 128                return core_uV;
 129
 130        core_min_uV = max(cpu_min_uV + 125000, core_min_uV);
 131        if (core_min_uV > core_max_uV)
 132                return -EINVAL;
 133
 134        if (cpu_uV + 120000 > core_uV)
 135                pr_err("core-cpu voltage constraint violated: %d %d\n",
 136                       core_uV, cpu_uV + 120000);
 137
 138        rtc_uV = regulator_get_voltage_rdev(rtc_rdev);
 139        if (rtc_uV < 0)
 140                return rtc_uV;
 141
 142        if (cpu_uV + 120000 > rtc_uV)
 143                pr_err("rtc-cpu voltage constraint violated: %d %d\n",
 144                       rtc_uV, cpu_uV + 120000);
 145
 146        if (abs(core_uV - rtc_uV) > 170000)
 147                pr_err("core-rtc voltage constraint violated: %d %d\n",
 148                       core_uV, rtc_uV);
 149
 150        rtc_min_uV = max(cpu_min_uV + 125000, core_min_uV - max_spread);
 151
 152        err = regulator_check_voltage(rtc_rdev, &rtc_min_uV, &rtc_max_uV);
 153        if (err)
 154                return err;
 155
 156        while (core_uV != core_min_uV || rtc_uV != rtc_min_uV) {
 157                if (core_uV < core_min_uV) {
 158                        core_target_uV = min(core_uV + max_spread, core_min_uV);
 159                        core_target_uV = min(rtc_uV + max_spread, core_target_uV);
 160                } else {
 161                        core_target_uV = max(core_uV - max_spread, core_min_uV);
 162                        core_target_uV = max(rtc_uV - max_spread, core_target_uV);
 163                }
 164
 165                if (core_uV == core_target_uV)
 166                        goto update_rtc;
 167
 168                err = regulator_set_voltage_rdev(core_rdev,
 169                                                 core_target_uV,
 170                                                 core_max_uV,
 171                                                 PM_SUSPEND_ON);
 172                if (err)
 173                        return err;
 174
 175                core_uV = core_target_uV;
 176update_rtc:
 177                if (rtc_uV < rtc_min_uV) {
 178                        rtc_target_uV = min(rtc_uV + max_spread, rtc_min_uV);
 179                        rtc_target_uV = min(core_uV + max_spread, rtc_target_uV);
 180                } else {
 181                        rtc_target_uV = max(rtc_uV - max_spread, rtc_min_uV);
 182                        rtc_target_uV = max(core_uV - max_spread, rtc_target_uV);
 183                }
 184
 185                if (rtc_uV == rtc_target_uV)
 186                        continue;
 187
 188                err = regulator_set_voltage_rdev(rtc_rdev,
 189                                                 rtc_target_uV,
 190                                                 rtc_max_uV,
 191                                                 PM_SUSPEND_ON);
 192                if (err)
 193                        return err;
 194
 195                rtc_uV = rtc_target_uV;
 196        }
 197
 198        return 0;
 199}
 200
 201static int tegra20_core_voltage_update(struct tegra_regulator_coupler *tegra,
 202                                       struct regulator_dev *cpu_rdev,
 203                                       struct regulator_dev *core_rdev,
 204                                       struct regulator_dev *rtc_rdev)
 205{
 206        int cpu_uV;
 207
 208        cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
 209        if (cpu_uV < 0)
 210                return cpu_uV;
 211
 212        return tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
 213                                       cpu_uV, cpu_uV);
 214}
 215
 216static int tegra20_cpu_voltage_update(struct tegra_regulator_coupler *tegra,
 217                                      struct regulator_dev *cpu_rdev,
 218                                      struct regulator_dev *core_rdev,
 219                                      struct regulator_dev *rtc_rdev)
 220{
 221        int cpu_min_uV_consumers = 0;
 222        int cpu_max_uV = INT_MAX;
 223        int cpu_min_uV = 0;
 224        int cpu_uV;
 225        int err;
 226
 227        err = regulator_check_voltage(cpu_rdev, &cpu_min_uV, &cpu_max_uV);
 228        if (err)
 229                return err;
 230
 231        err = regulator_check_consumers(cpu_rdev, &cpu_min_uV, &cpu_max_uV,
 232                                        PM_SUSPEND_ON);
 233        if (err)
 234                return err;
 235
 236        err = regulator_check_consumers(cpu_rdev, &cpu_min_uV_consumers,
 237                                        &cpu_max_uV, PM_SUSPEND_ON);
 238        if (err)
 239                return err;
 240
 241        cpu_uV = regulator_get_voltage_rdev(cpu_rdev);
 242        if (cpu_uV < 0)
 243                return cpu_uV;
 244
 245        /*
 246         * CPU's regulator may not have any consumers, hence the voltage
 247         * must not be changed in that case because CPU simply won't
 248         * survive the voltage drop if it's running on a higher frequency.
 249         */
 250        if (!cpu_min_uV_consumers)
 251                cpu_min_uV = cpu_uV;
 252
 253        if (cpu_min_uV > cpu_uV) {
 254                err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
 255                                              cpu_uV, cpu_min_uV);
 256                if (err)
 257                        return err;
 258
 259                err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
 260                                                 cpu_max_uV, PM_SUSPEND_ON);
 261                if (err)
 262                        return err;
 263        } else if (cpu_min_uV < cpu_uV)  {
 264                err = regulator_set_voltage_rdev(cpu_rdev, cpu_min_uV,
 265                                                 cpu_max_uV, PM_SUSPEND_ON);
 266                if (err)
 267                        return err;
 268
 269                err = tegra20_core_rtc_update(tegra, core_rdev, rtc_rdev,
 270                                              cpu_uV, cpu_min_uV);
 271                if (err)
 272                        return err;
 273        }
 274
 275        return 0;
 276}
 277
 278static int tegra20_regulator_balance_voltage(struct regulator_coupler *coupler,
 279                                             struct regulator_dev *rdev,
 280                                             suspend_state_t state)
 281{
 282        struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
 283        struct regulator_dev *core_rdev = tegra->core_rdev;
 284        struct regulator_dev *cpu_rdev = tegra->cpu_rdev;
 285        struct regulator_dev *rtc_rdev = tegra->rtc_rdev;
 286
 287        if ((core_rdev != rdev && cpu_rdev != rdev && rtc_rdev != rdev) ||
 288            state != PM_SUSPEND_ON) {
 289                pr_err("regulators are not coupled properly\n");
 290                return -EINVAL;
 291        }
 292
 293        if (rdev == cpu_rdev)
 294                return tegra20_cpu_voltage_update(tegra, cpu_rdev,
 295                                                  core_rdev, rtc_rdev);
 296
 297        if (rdev == core_rdev)
 298                return tegra20_core_voltage_update(tegra, cpu_rdev,
 299                                                   core_rdev, rtc_rdev);
 300
 301        pr_err("changing %s voltage not permitted\n", rdev_get_name(rtc_rdev));
 302
 303        return -EPERM;
 304}
 305
 306static int tegra20_regulator_attach(struct regulator_coupler *coupler,
 307                                    struct regulator_dev *rdev)
 308{
 309        struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
 310        struct device_node *np = rdev->dev.of_node;
 311
 312        if (of_property_read_bool(np, "nvidia,tegra-core-regulator") &&
 313            !tegra->core_rdev) {
 314                tegra->core_rdev = rdev;
 315                return 0;
 316        }
 317
 318        if (of_property_read_bool(np, "nvidia,tegra-rtc-regulator") &&
 319            !tegra->rtc_rdev) {
 320                tegra->rtc_rdev = rdev;
 321                return 0;
 322        }
 323
 324        if (of_property_read_bool(np, "nvidia,tegra-cpu-regulator") &&
 325            !tegra->cpu_rdev) {
 326                tegra->cpu_rdev = rdev;
 327                return 0;
 328        }
 329
 330        return -EINVAL;
 331}
 332
 333static int tegra20_regulator_detach(struct regulator_coupler *coupler,
 334                                    struct regulator_dev *rdev)
 335{
 336        struct tegra_regulator_coupler *tegra = to_tegra_coupler(coupler);
 337
 338        if (tegra->core_rdev == rdev) {
 339                tegra->core_rdev = NULL;
 340                return 0;
 341        }
 342
 343        if (tegra->rtc_rdev == rdev) {
 344                tegra->rtc_rdev = NULL;
 345                return 0;
 346        }
 347
 348        if (tegra->cpu_rdev == rdev) {
 349                tegra->cpu_rdev = NULL;
 350                return 0;
 351        }
 352
 353        return -EINVAL;
 354}
 355
 356static struct tegra_regulator_coupler tegra20_coupler = {
 357        .coupler = {
 358                .attach_regulator = tegra20_regulator_attach,
 359                .detach_regulator = tegra20_regulator_detach,
 360                .balance_voltage = tegra20_regulator_balance_voltage,
 361        },
 362};
 363
 364static int __init tegra_regulator_coupler_init(void)
 365{
 366        if (!of_machine_is_compatible("nvidia,tegra20"))
 367                return 0;
 368
 369        return regulator_coupler_register(&tegra20_coupler.coupler);
 370}
 371arch_initcall(tegra_regulator_coupler_init);
 372