linux/drivers/regulator/rohm-regulator.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2// Copyright (C) 2020 ROHM Semiconductors
   3
   4#include <linux/errno.h>
   5#include <linux/mfd/rohm-generic.h>
   6#include <linux/module.h>
   7#include <linux/of.h>
   8#include <linux/regmap.h>
   9#include <linux/regulator/driver.h>
  10
  11static int set_dvs_level(const struct regulator_desc *desc,
  12                         struct device_node *np, struct regmap *regmap,
  13                         char *prop, unsigned int reg, unsigned int mask,
  14                         unsigned int omask, unsigned int oreg)
  15{
  16        int ret, i;
  17        uint32_t uv;
  18
  19        ret = of_property_read_u32(np, prop, &uv);
  20        if (ret) {
  21                if (ret != -EINVAL)
  22                        return ret;
  23                return 0;
  24        }
  25        /* If voltage is set to 0 => disable */
  26        if (uv == 0) {
  27                if (omask)
  28                        return regmap_update_bits(regmap, oreg, omask, 0);
  29        }
  30        /* Some setups don't allow setting own voltage but do allow enabling */
  31        if (!mask) {
  32                if (omask)
  33                        return regmap_update_bits(regmap, oreg, omask, omask);
  34
  35                return -EINVAL;
  36        }
  37        for (i = 0; i < desc->n_voltages; i++) {
  38                /* NOTE to next hacker - Does not support pickable ranges */
  39                if (desc->linear_range_selectors)
  40                        return -EINVAL;
  41                if (desc->n_linear_ranges)
  42                        ret = regulator_desc_list_voltage_linear_range(desc, i);
  43                else
  44                        ret = regulator_desc_list_voltage_linear(desc, i);
  45                if (ret < 0)
  46                        continue;
  47                if (ret == uv) {
  48                        i <<= ffs(desc->vsel_mask) - 1;
  49                        ret = regmap_update_bits(regmap, reg, mask, i);
  50                        if (omask && !ret)
  51                                ret = regmap_update_bits(regmap, oreg, omask,
  52                                                         omask);
  53                        break;
  54                }
  55        }
  56        return ret;
  57}
  58
  59int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
  60                          struct device_node *np,
  61                          const struct regulator_desc *desc,
  62                          struct regmap *regmap)
  63{
  64        int i, ret = 0;
  65        char *prop;
  66        unsigned int reg, mask, omask, oreg = desc->enable_reg;
  67
  68        for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) {
  69                int bit;
  70
  71                bit = BIT(i);
  72                if (dvs->level_map & bit) {
  73                        switch (bit) {
  74                        case ROHM_DVS_LEVEL_RUN:
  75                                prop = "rohm,dvs-run-voltage";
  76                                reg = dvs->run_reg;
  77                                mask = dvs->run_mask;
  78                                omask = dvs->run_on_mask;
  79                                break;
  80                        case ROHM_DVS_LEVEL_IDLE:
  81                                prop = "rohm,dvs-idle-voltage";
  82                                reg = dvs->idle_reg;
  83                                mask = dvs->idle_mask;
  84                                omask = dvs->idle_on_mask;
  85                                break;
  86                        case ROHM_DVS_LEVEL_SUSPEND:
  87                                prop = "rohm,dvs-suspend-voltage";
  88                                reg = dvs->suspend_reg;
  89                                mask = dvs->suspend_mask;
  90                                omask = dvs->suspend_on_mask;
  91                                break;
  92                        case ROHM_DVS_LEVEL_LPSR:
  93                                prop = "rohm,dvs-lpsr-voltage";
  94                                reg = dvs->lpsr_reg;
  95                                mask = dvs->lpsr_mask;
  96                                omask = dvs->lpsr_on_mask;
  97                                break;
  98                        case ROHM_DVS_LEVEL_SNVS:
  99                                prop = "rohm,dvs-snvs-voltage";
 100                                reg = dvs->snvs_reg;
 101                                mask = dvs->snvs_mask;
 102                                omask = dvs->snvs_on_mask;
 103                                break;
 104                        default:
 105                                return -EINVAL;
 106                        }
 107                        ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
 108                                            omask, oreg);
 109                }
 110        }
 111        return ret;
 112}
 113EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
 114
 115MODULE_LICENSE("GPL v2");
 116MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
 117MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");
 118