linux/drivers/soc/samsung/exynos-regulator-coupler.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
   4 *            http://www.samsung.com/
   5 * Author: Marek Szyprowski <m.szyprowski@samsung.com>
   6 *
   7 * Simplified generic voltage coupler from regulator core.c
   8 * The main difference is that it keeps current regulator voltage
   9 * if consumers didn't apply their constraints yet.
  10 */
  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
  19static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
  20                                         int *current_uV,
  21                                         int *min_uV, int *max_uV,
  22                                         suspend_state_t state)
  23{
  24        struct coupling_desc *c_desc = &rdev->coupling_desc;
  25        struct regulator_dev **c_rdevs = c_desc->coupled_rdevs;
  26        struct regulation_constraints *constraints = rdev->constraints;
  27        int desired_min_uV = 0, desired_max_uV = INT_MAX;
  28        int max_current_uV = 0, min_current_uV = INT_MAX;
  29        int highest_min_uV = 0, target_uV, possible_uV;
  30        int i, ret, max_spread, n_coupled = c_desc->n_coupled;
  31        bool done;
  32
  33        *current_uV = -1;
  34
  35        /* Find highest min desired voltage */
  36        for (i = 0; i < n_coupled; i++) {
  37                int tmp_min = 0;
  38                int tmp_max = INT_MAX;
  39
  40                lockdep_assert_held_once(&c_rdevs[i]->mutex.base);
  41
  42                ret = regulator_check_consumers(c_rdevs[i],
  43                                                &tmp_min,
  44                                                &tmp_max, state);
  45                if (ret < 0)
  46                        return ret;
  47
  48                if (tmp_min == 0) {
  49                        ret = regulator_get_voltage_rdev(c_rdevs[i]);
  50                        if (ret < 0)
  51                                return ret;
  52                        tmp_min = ret;
  53                }
  54
  55                /* apply constraints */
  56                ret = regulator_check_voltage(c_rdevs[i], &tmp_min, &tmp_max);
  57                if (ret < 0)
  58                        return ret;
  59
  60                highest_min_uV = max(highest_min_uV, tmp_min);
  61
  62                if (i == 0) {
  63                        desired_min_uV = tmp_min;
  64                        desired_max_uV = tmp_max;
  65                }
  66        }
  67
  68        max_spread = constraints->max_spread[0];
  69
  70        /*
  71         * Let target_uV be equal to the desired one if possible.
  72         * If not, set it to minimum voltage, allowed by other coupled
  73         * regulators.
  74         */
  75        target_uV = max(desired_min_uV, highest_min_uV - max_spread);
  76
  77        /*
  78         * Find min and max voltages, which currently aren't violating
  79         * max_spread.
  80         */
  81        for (i = 1; i < n_coupled; i++) {
  82                int tmp_act;
  83
  84                tmp_act = regulator_get_voltage_rdev(c_rdevs[i]);
  85                if (tmp_act < 0)
  86                        return tmp_act;
  87
  88                min_current_uV = min(tmp_act, min_current_uV);
  89                max_current_uV = max(tmp_act, max_current_uV);
  90        }
  91
  92        /*
  93         * Correct target voltage, so as it currently isn't
  94         * violating max_spread
  95         */
  96        possible_uV = max(target_uV, max_current_uV - max_spread);
  97        possible_uV = min(possible_uV, min_current_uV + max_spread);
  98
  99        if (possible_uV > desired_max_uV)
 100                return -EINVAL;
 101
 102        done = (possible_uV == target_uV);
 103        desired_min_uV = possible_uV;
 104
 105        /* Set current_uV if wasn't done earlier in the code and if necessary */
 106        if (*current_uV == -1) {
 107                ret = regulator_get_voltage_rdev(rdev);
 108                if (ret < 0)
 109                        return ret;
 110                *current_uV = ret;
 111        }
 112
 113        *min_uV = desired_min_uV;
 114        *max_uV = desired_max_uV;
 115
 116        return done;
 117}
 118
 119static int exynos_coupler_balance_voltage(struct regulator_coupler *coupler,
 120                                          struct regulator_dev *rdev,
 121                                          suspend_state_t state)
 122{
 123        struct regulator_dev **c_rdevs;
 124        struct regulator_dev *best_rdev;
 125        struct coupling_desc *c_desc = &rdev->coupling_desc;
 126        int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
 127        unsigned int delta, best_delta;
 128        unsigned long c_rdev_done = 0;
 129        bool best_c_rdev_done;
 130
 131        c_rdevs = c_desc->coupled_rdevs;
 132        n_coupled = c_desc->n_coupled;
 133
 134        /*
 135         * Find the best possible voltage change on each loop. Leave the loop
 136         * if there isn't any possible change.
 137         */
 138        do {
 139                best_c_rdev_done = false;
 140                best_delta = 0;
 141                best_min_uV = 0;
 142                best_max_uV = 0;
 143                best_c_rdev = 0;
 144                best_rdev = NULL;
 145
 146                /*
 147                 * Find highest difference between optimal voltage
 148                 * and current voltage.
 149                 */
 150                for (i = 0; i < n_coupled; i++) {
 151                        /*
 152                         * optimal_uV is the best voltage that can be set for
 153                         * i-th regulator at the moment without violating
 154                         * max_spread constraint in order to balance
 155                         * the coupled voltages.
 156                         */
 157                        int optimal_uV = 0, optimal_max_uV = 0, current_uV = 0;
 158
 159                        if (test_bit(i, &c_rdev_done))
 160                                continue;
 161
 162                        ret = regulator_get_optimal_voltage(c_rdevs[i],
 163                                                            &current_uV,
 164                                                            &optimal_uV,
 165                                                            &optimal_max_uV,
 166                                                            state);
 167                        if (ret < 0)
 168                                goto out;
 169
 170                        delta = abs(optimal_uV - current_uV);
 171
 172                        if (delta && best_delta <= delta) {
 173                                best_c_rdev_done = ret;
 174                                best_delta = delta;
 175                                best_rdev = c_rdevs[i];
 176                                best_min_uV = optimal_uV;
 177                                best_max_uV = optimal_max_uV;
 178                                best_c_rdev = i;
 179                        }
 180                }
 181
 182                /* Nothing to change, return successfully */
 183                if (!best_rdev) {
 184                        ret = 0;
 185                        goto out;
 186                }
 187
 188                ret = regulator_set_voltage_rdev(best_rdev, best_min_uV,
 189                                                 best_max_uV, state);
 190
 191                if (ret < 0)
 192                        goto out;
 193
 194                if (best_c_rdev_done)
 195                        set_bit(best_c_rdev, &c_rdev_done);
 196
 197        } while (n_coupled > 1);
 198
 199out:
 200        return ret;
 201}
 202
 203static int exynos_coupler_attach(struct regulator_coupler *coupler,
 204                                 struct regulator_dev *rdev)
 205{
 206        return 0;
 207}
 208
 209static struct regulator_coupler exynos_coupler = {
 210        .attach_regulator = exynos_coupler_attach,
 211        .balance_voltage  = exynos_coupler_balance_voltage,
 212};
 213
 214static int __init exynos_coupler_init(void)
 215{
 216        if (!of_machine_is_compatible("samsung,exynos5800"))
 217                return 0;
 218
 219        return regulator_coupler_register(&exynos_coupler);
 220}
 221arch_initcall(exynos_coupler_init);
 222