Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2020 ROHM Semiconductors
0003 
0004 #include <linux/errno.h>
0005 #include <linux/mfd/rohm-generic.h>
0006 #include <linux/module.h>
0007 #include <linux/of.h>
0008 #include <linux/regmap.h>
0009 #include <linux/regulator/driver.h>
0010 
0011 static int set_dvs_level(const struct regulator_desc *desc,
0012              struct device_node *np, struct regmap *regmap,
0013              char *prop, unsigned int reg, unsigned int mask,
0014              unsigned int omask, unsigned int oreg)
0015 {
0016     int ret, i;
0017     uint32_t uv;
0018 
0019     ret = of_property_read_u32(np, prop, &uv);
0020     if (ret) {
0021         if (ret != -EINVAL)
0022             return ret;
0023         return 0;
0024     }
0025     /* If voltage is set to 0 => disable */
0026     if (uv == 0) {
0027         if (omask)
0028             return regmap_update_bits(regmap, oreg, omask, 0);
0029     }
0030     /* Some setups don't allow setting own voltage but do allow enabling */
0031     if (!mask) {
0032         if (omask)
0033             return regmap_update_bits(regmap, oreg, omask, omask);
0034 
0035         return -EINVAL;
0036     }
0037     for (i = 0; i < desc->n_voltages; i++) {
0038         /* NOTE to next hacker - Does not support pickable ranges */
0039         if (desc->linear_range_selectors)
0040             return -EINVAL;
0041         if (desc->n_linear_ranges)
0042             ret = regulator_desc_list_voltage_linear_range(desc, i);
0043         else
0044             ret = regulator_desc_list_voltage_linear(desc, i);
0045         if (ret < 0)
0046             continue;
0047         if (ret == uv) {
0048             i <<= ffs(desc->vsel_mask) - 1;
0049             ret = regmap_update_bits(regmap, reg, mask, i);
0050             if (omask && !ret)
0051                 ret = regmap_update_bits(regmap, oreg, omask,
0052                              omask);
0053             break;
0054         }
0055     }
0056     return ret;
0057 }
0058 
0059 int rohm_regulator_set_dvs_levels(const struct rohm_dvs_config *dvs,
0060               struct device_node *np,
0061               const struct regulator_desc *desc,
0062               struct regmap *regmap)
0063 {
0064     int i, ret = 0;
0065     char *prop;
0066     unsigned int reg, mask, omask, oreg = desc->enable_reg;
0067 
0068     for (i = 0; i < ROHM_DVS_LEVEL_VALID_AMOUNT && !ret; i++) {
0069         int bit;
0070 
0071         bit = BIT(i);
0072         if (dvs->level_map & bit) {
0073             switch (bit) {
0074             case ROHM_DVS_LEVEL_RUN:
0075                 prop = "rohm,dvs-run-voltage";
0076                 reg = dvs->run_reg;
0077                 mask = dvs->run_mask;
0078                 omask = dvs->run_on_mask;
0079                 break;
0080             case ROHM_DVS_LEVEL_IDLE:
0081                 prop = "rohm,dvs-idle-voltage";
0082                 reg = dvs->idle_reg;
0083                 mask = dvs->idle_mask;
0084                 omask = dvs->idle_on_mask;
0085                 break;
0086             case ROHM_DVS_LEVEL_SUSPEND:
0087                 prop = "rohm,dvs-suspend-voltage";
0088                 reg = dvs->suspend_reg;
0089                 mask = dvs->suspend_mask;
0090                 omask = dvs->suspend_on_mask;
0091                 break;
0092             case ROHM_DVS_LEVEL_LPSR:
0093                 prop = "rohm,dvs-lpsr-voltage";
0094                 reg = dvs->lpsr_reg;
0095                 mask = dvs->lpsr_mask;
0096                 omask = dvs->lpsr_on_mask;
0097                 break;
0098             case ROHM_DVS_LEVEL_SNVS:
0099                 prop = "rohm,dvs-snvs-voltage";
0100                 reg = dvs->snvs_reg;
0101                 mask = dvs->snvs_mask;
0102                 omask = dvs->snvs_on_mask;
0103                 break;
0104             default:
0105                 return -EINVAL;
0106             }
0107             ret = set_dvs_level(desc, np, regmap, prop, reg, mask,
0108                         omask, oreg);
0109         }
0110     }
0111     return ret;
0112 }
0113 EXPORT_SYMBOL(rohm_regulator_set_dvs_levels);
0114 
0115 /*
0116  * Few ROHM PMIC ICs have constrains on voltage changing:
0117  * BD71837 - only buck 1-4 voltages can be changed when they are enabled.
0118  * Other bucks and all LDOs must be disabled when voltage is changed.
0119  * BD96801 - LDO voltage levels can be changed when LDOs are disabled.
0120  */
0121 int rohm_regulator_set_voltage_sel_restricted(struct regulator_dev *rdev,
0122                           unsigned int sel)
0123 {
0124     if (rdev->desc->ops->is_enabled(rdev))
0125         return -EBUSY;
0126 
0127     return regulator_set_voltage_sel_regmap(rdev, sel);
0128 }
0129 EXPORT_SYMBOL_GPL(rohm_regulator_set_voltage_sel_restricted);
0130 
0131 MODULE_LICENSE("GPL v2");
0132 MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>");
0133 MODULE_DESCRIPTION("Generic helpers for ROHM PMIC regulator drivers");