diff options
author | Linus Torvalds | 2019-09-16 13:58:43 -0700 |
---|---|---|
committer | Linus Torvalds | 2019-09-16 13:58:43 -0700 |
commit | c4d11ccb2b5cec6cdef7aeeb0017473d23031d96 (patch) | |
tree | 2cae7e62c8852d634b6e79eba865b3bfc7fae0c1 /drivers | |
parent | 0372fd1a70c4bc0731486851abe2048993f94a8d (diff) | |
parent | c4ad85026d4dd5a3f65c04b4564fe273e37e5b88 (diff) |
Merge tag 'regulator-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator
Pull regulator updates from Mark Brown:
"A small update for the regualtor API for this cycle, some small fixes
and a bunch of new devices but none of them very big.
The most stand out thing is the regulator-fixed-clock driver which is
for regulators where the enable control is done by using a clock
instead of a GPIO or register write, a novel hardware design that had
not previously come up.
Summary:
- Added a keyword pattern for regulator_get_optional() since usage of
that API generally needs extra review.
- Operating mode and suspend state support for act8865.
- New device support for Active Semiconductor ACT8600 chargers,
Mediatek MT6358, Qualcomm SM8150, regulator-fixed-clock, and
Synoptics SY20276, SY20278 and SY8824E"
* tag 'regulator-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator: (52 commits)
regulator: core: Fix error return for /sys access
regulator: da9211: fix obtaining "enable" GPIO
regulator: max77686: fix obtaining "maxim,ena" GPIO
regulator: uniphier: Add Pro5 USB3 VBUS support
dt-bindings: regulator: add regulator-fixed-clock binding
regulator: fixed: add possibility to enable by clock
regulator: s2mps11: Consistently use local variable
regulator: lp87565: Simplify lp87565_buck_set_ramp_delay
regulator: slg51000: use devm_gpiod_get_optional() in probe
regulator: lp8788-ldo: make array en_mask static const, makes object smaller
regulator: tps65132: Stop parsing DT when gpio is not found
regulator: Defer init completion for a while after late_initcall
regulator: add missing 'static inline' to a helper's stub
regulator: provide regulator_bulk_set_supply_names()
MAINTAINERS: Add keyword pattern on regulator_get_optional()
regulator: sy8824x: add prefixes to BUCK_EN and MODE macros
regulator: sy8824x: use c++style for the comment block near SPDX
regulator: mt6358: Add BROKEN dependency while waiting for MFD to merge
regulator: mt6358: Add support for MT6358 regulator
regulator: Add document for MT6358 regulator
...
Diffstat (limited to 'drivers')
24 files changed, 1480 insertions, 73 deletions
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index b57093d7c01f..3ee63531f6d5 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -83,6 +83,7 @@ config REGULATOR_88PM8607 config REGULATOR_ACT8865 tristate "Active-semi act8865 voltage regulator" depends on I2C + depends on POWER_SUPPLY select REGMAP_I2C help This driver controls a active-semi act8865 voltage output @@ -618,6 +619,15 @@ config REGULATOR_MT6323 This driver supports the control of different power rails of device through regulator interface. +config REGULATOR_MT6358 + tristate "MediaTek MT6358 PMIC" + depends on MFD_MT6397 && BROKEN + help + Say y here to select this option to enable the power regulator of + MediaTek MT6358 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6380 tristate "MediaTek MT6380 PMIC" depends on MTK_PMIC_WRAP @@ -906,6 +916,13 @@ config REGULATOR_SY8106A help This driver supports SY8106A single output regulator. +config REGULATOR_SY8824X + tristate "Silergy SY8824C/SY8824E regulator" + depends on I2C && (OF || COMPILE_TEST) + select REGMAP_I2C + help + This driver supports SY8824C single output regulator. + config REGULATOR_TPS51632 tristate "TI TPS51632 Power Regulator" depends on I2C diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index eef73b5a35a4..2210ba56f9bd 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -79,6 +79,7 @@ obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o obj-$(CONFIG_REGULATOR_MCP16502) += mcp16502.o obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6323) += mt6323-regulator.o +obj-$(CONFIG_REGULATOR_MT6358) += mt6358-regulator.o obj-$(CONFIG_REGULATOR_MT6380) += mt6380-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o @@ -111,6 +112,7 @@ obj-$(CONFIG_REGULATOR_STM32_PWR) += stm32-pwr.o obj-$(CONFIG_REGULATOR_STPMIC1) += stpmic1_regulator.o obj-$(CONFIG_REGULATOR_STW481X_VMMC) += stw481x-vmmc.o obj-$(CONFIG_REGULATOR_SY8106A) += sy8106a-regulator.o +obj-$(CONFIG_REGULATOR_SY8824X) += sy8824x.o obj-$(CONFIG_REGULATOR_TI_ABB) += ti-abb-regulator.o obj-$(CONFIG_REGULATOR_TPS6105X) += tps6105x-regulator.o obj-$(CONFIG_REGULATOR_TPS62360) += tps62360-regulator.o diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index cf72d7c6b8c9..0fa97f934df4 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -16,8 +16,10 @@ #include <linux/regulator/act8865.h> #include <linux/of.h> #include <linux/of_device.h> +#include <linux/power_supply.h> #include <linux/regulator/of_regulator.h> #include <linux/regmap.h> +#include <dt-bindings/regulator/active-semi,8865-regulator.h> /* * ACT8600 Global Register Map. @@ -89,35 +91,50 @@ */ #define ACT8865_SYS_MODE 0x00 #define ACT8865_SYS_CTRL 0x01 +#define ACT8865_SYS_UNLK_REGS 0x0b #define ACT8865_DCDC1_VSET1 0x20 #define ACT8865_DCDC1_VSET2 0x21 #define ACT8865_DCDC1_CTRL 0x22 +#define ACT8865_DCDC1_SUS 0x24 #define ACT8865_DCDC2_VSET1 0x30 #define ACT8865_DCDC2_VSET2 0x31 #define ACT8865_DCDC2_CTRL 0x32 +#define ACT8865_DCDC2_SUS 0x34 #define ACT8865_DCDC3_VSET1 0x40 #define ACT8865_DCDC3_VSET2 0x41 #define ACT8865_DCDC3_CTRL 0x42 +#define ACT8865_DCDC3_SUS 0x44 #define ACT8865_LDO1_VSET 0x50 #define ACT8865_LDO1_CTRL 0x51 +#define ACT8865_LDO1_SUS 0x52 #define ACT8865_LDO2_VSET 0x54 #define ACT8865_LDO2_CTRL 0x55 +#define ACT8865_LDO2_SUS 0x56 #define ACT8865_LDO3_VSET 0x60 #define ACT8865_LDO3_CTRL 0x61 +#define ACT8865_LDO3_SUS 0x62 #define ACT8865_LDO4_VSET 0x64 #define ACT8865_LDO4_CTRL 0x65 +#define ACT8865_LDO4_SUS 0x66 #define ACT8865_MSTROFF 0x20 /* * Field Definitions. */ #define ACT8865_ENA 0x80 /* ON - [7] */ +#define ACT8865_DIS 0x40 /* DIS - [6] */ + #define ACT8865_VSEL_MASK 0x3F /* VSET - [5:0] */ #define ACT8600_LDO10_ENA 0x40 /* ON - [6] */ #define ACT8600_SUDCDC_VSEL_MASK 0xFF /* SUDCDC VSET - [7:0] */ +#define ACT8600_APCH_CHG_ACIN BIT(7) +#define ACT8600_APCH_CHG_USB BIT(6) +#define ACT8600_APCH_CSTATE0 BIT(5) +#define ACT8600_APCH_CSTATE1 BIT(4) + /* * ACT8865 voltage number */ @@ -217,6 +234,171 @@ static const struct regulator_linear_range act8600_sudcdc_voltage_ranges[] = { REGULATOR_LINEAR_RANGE(41400000, 248, 255, 0), }; +static int act8865_set_suspend_state(struct regulator_dev *rdev, bool enable) +{ + struct regmap *regmap = rdev->regmap; + int id = rdev->desc->id, reg, val; + + switch (id) { + case ACT8865_ID_DCDC1: + reg = ACT8865_DCDC1_SUS; + val = 0xa8; + break; + case ACT8865_ID_DCDC2: + reg = ACT8865_DCDC2_SUS; + val = 0xa8; + break; + case ACT8865_ID_DCDC3: + reg = ACT8865_DCDC3_SUS; + val = 0xa8; + break; + case ACT8865_ID_LDO1: + reg = ACT8865_LDO1_SUS; + val = 0xe8; + break; + case ACT8865_ID_LDO2: + reg = ACT8865_LDO2_SUS; + val = 0xe8; + break; + case ACT8865_ID_LDO3: + reg = ACT8865_LDO3_SUS; + val = 0xe8; + break; + case ACT8865_ID_LDO4: + reg = ACT8865_LDO4_SUS; + val = 0xe8; + break; + default: + return -EINVAL; + } + + if (enable) + val |= BIT(4); + + /* + * Ask the PMIC to enable/disable this output when entering hibernate + * mode. + */ + return regmap_write(regmap, reg, val); +} + +static int act8865_set_suspend_enable(struct regulator_dev *rdev) +{ + return act8865_set_suspend_state(rdev, true); +} + +static int act8865_set_suspend_disable(struct regulator_dev *rdev) +{ + return act8865_set_suspend_state(rdev, false); +} + +static unsigned int act8865_of_map_mode(unsigned int mode) +{ + switch (mode) { + case ACT8865_REGULATOR_MODE_FIXED: + return REGULATOR_MODE_FAST; + case ACT8865_REGULATOR_MODE_NORMAL: + return REGULATOR_MODE_NORMAL; + case ACT8865_REGULATOR_MODE_LOWPOWER: + return REGULATOR_MODE_STANDBY; + default: + return REGULATOR_MODE_INVALID; + } +} + +static int act8865_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct regmap *regmap = rdev->regmap; + int id = rdev_get_id(rdev); + int reg, val = 0; + + switch (id) { + case ACT8865_ID_DCDC1: + reg = ACT8865_DCDC1_CTRL; + break; + case ACT8865_ID_DCDC2: + reg = ACT8865_DCDC2_CTRL; + break; + case ACT8865_ID_DCDC3: + reg = ACT8865_DCDC3_CTRL; + break; + case ACT8865_ID_LDO1: + reg = ACT8865_LDO1_CTRL; + break; + case ACT8865_ID_LDO2: + reg = ACT8865_LDO2_CTRL; + break; + case ACT8865_ID_LDO3: + reg = ACT8865_LDO3_CTRL; + break; + case ACT8865_ID_LDO4: + reg = ACT8865_LDO4_CTRL; + break; + default: + return -EINVAL; + } + + switch (mode) { + case REGULATOR_MODE_FAST: + case REGULATOR_MODE_NORMAL: + if (id <= ACT8865_ID_DCDC3) + val = BIT(5); + break; + case REGULATOR_MODE_STANDBY: + if (id > ACT8865_ID_DCDC3) + val = BIT(5); + break; + default: + return -EINVAL; + } + + return regmap_update_bits(regmap, reg, BIT(5), val); +} + +static unsigned int act8865_get_mode(struct regulator_dev *rdev) +{ + struct regmap *regmap = rdev->regmap; + int id = rdev_get_id(rdev); + int reg, ret, val = 0; + + switch (id) { + case ACT8865_ID_DCDC1: + reg = ACT8865_DCDC1_CTRL; + break; + case ACT8865_ID_DCDC2: + reg = ACT8865_DCDC2_CTRL; + break; + case ACT8865_ID_DCDC3: + reg = ACT8865_DCDC3_CTRL; + break; + case ACT8865_ID_LDO1: + reg = ACT8865_LDO1_CTRL; + break; + case ACT8865_ID_LDO2: + reg = ACT8865_LDO2_CTRL; + break; + case ACT8865_ID_LDO3: + reg = ACT8865_LDO3_CTRL; + break; + case ACT8865_ID_LDO4: + reg = ACT8865_LDO4_CTRL; + break; + default: + return -EINVAL; + } + + ret = regmap_read(regmap, reg, &val); + if (ret) + return ret; + + if (id <= ACT8865_ID_DCDC3 && (val & BIT(5))) + return REGULATOR_MODE_FAST; + else if (id > ACT8865_ID_DCDC3 && !(val & BIT(5))) + return REGULATOR_MODE_NORMAL; + else + return REGULATOR_MODE_STANDBY; +} + static const struct regulator_ops act8865_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, @@ -224,24 +406,44 @@ static const struct regulator_ops act8865_ops = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, + .set_mode = act8865_set_mode, + .get_mode = act8865_get_mode, .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = act8865_set_suspend_enable, + .set_suspend_disable = act8865_set_suspend_disable, }; static const struct regulator_ops act8865_ldo_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .set_mode = act8865_set_mode, + .get_mode = act8865_get_mode, + .is_enabled = regulator_is_enabled_regmap, + .set_suspend_enable = act8865_set_suspend_enable, + .set_suspend_disable = act8865_set_suspend_disable, + .set_pull_down = regulator_set_pull_down_regmap, +}; + +static const struct regulator_ops act8865_fixed_ldo_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, }; -#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \ +#define ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, _ops) \ [_family##_ID_##_id] = { \ .name = _name, \ .of_match = of_match_ptr(_name), \ + .of_map_mode = act8865_of_map_mode, \ .regulators_node = of_match_ptr("regulators"), \ .supply_name = _supply, \ .id = _family##_ID_##_id, \ .type = REGULATOR_VOLTAGE, \ - .ops = &act8865_ops, \ + .ops = _ops, \ .n_voltages = ACT8865_VOLTAGE_NUM, \ .linear_ranges = act8865_voltage_ranges, \ .n_linear_ranges = ARRAY_SIZE(act8865_voltage_ranges), \ @@ -249,9 +451,17 @@ static const struct regulator_ops act8865_ldo_ops = { .vsel_mask = ACT8865_VSEL_MASK, \ .enable_reg = _family##_##_id##_CTRL, \ .enable_mask = ACT8865_ENA, \ + .pull_down_reg = _family##_##_id##_CTRL, \ + .pull_down_mask = ACT8865_DIS, \ .owner = THIS_MODULE, \ } +#define ACT88xx_REG(_name, _family, _id, _vsel_reg, _supply) \ + ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ops) + +#define ACT88xx_LDO(_name, _family, _id, _vsel_reg, _supply) \ + ACT88xx_REG_(_name, _family, _id, _vsel_reg, _supply, &act8865_ldo_ops) + static const struct regulator_desc act8600_regulators[] = { ACT88xx_REG("DCDC1", ACT8600, DCDC1, VSET, "vp1"), ACT88xx_REG("DCDC2", ACT8600, DCDC2, VSET, "vp2"), @@ -281,7 +491,7 @@ static const struct regulator_desc act8600_regulators[] = { .of_match = of_match_ptr("LDO_REG9"), .regulators_node = of_match_ptr("regulators"), .id = ACT8600_ID_LDO9, - .ops = &act8865_ldo_ops, + .ops = &act8865_fixed_ldo_ops, .type = REGULATOR_VOLTAGE, .n_voltages = 1, .fixed_uV = 3300000, @@ -294,7 +504,7 @@ static const struct regulator_desc act8600_regulators[] = { .of_match = of_match_ptr("LDO_REG10"), .regulators_node = of_match_ptr("regulators"), .id = ACT8600_ID_LDO10, - .ops = &act8865_ldo_ops, + .ops = &act8865_fixed_ldo_ops, .type = REGULATOR_VOLTAGE, .n_voltages = 1, .fixed_uV = 1200000, @@ -323,20 +533,20 @@ static const struct regulator_desc act8865_regulators[] = { ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET1, "vp1"), ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET1, "vp2"), ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET1, "vp3"), - ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), - ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), - ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), - ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), + ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), + ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), + ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), + ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), }; static const struct regulator_desc act8865_alt_regulators[] = { ACT88xx_REG("DCDC_REG1", ACT8865, DCDC1, VSET2, "vp1"), ACT88xx_REG("DCDC_REG2", ACT8865, DCDC2, VSET2, "vp2"), ACT88xx_REG("DCDC_REG3", ACT8865, DCDC3, VSET2, "vp3"), - ACT88xx_REG("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), - ACT88xx_REG("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), - ACT88xx_REG("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), - ACT88xx_REG("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), + ACT88xx_LDO("LDO_REG1", ACT8865, LDO1, VSET, "inl45"), + ACT88xx_LDO("LDO_REG2", ACT8865, LDO2, VSET, "inl45"), + ACT88xx_LDO("LDO_REG3", ACT8865, LDO3, VSET, "inl67"), + ACT88xx_LDO("LDO_REG4", ACT8865, LDO4, VSET, "inl67"), }; #ifdef CONFIG_OF @@ -372,6 +582,75 @@ static void act8865_power_off(void) while (1); } +static int act8600_charger_get_status(struct regmap *map) +{ + unsigned int val; + int ret; + u8 state0, state1; + + ret = regmap_read(map, ACT8600_APCH_STAT, &val); + if (ret < 0) + return ret; + + state0 = val & ACT8600_APCH_CSTATE0; + state1 = val & ACT8600_APCH_CSTATE1; + + if (state0 && !state1) + return POWER_SUPPLY_STATUS_CHARGING; + if (!state0 && state1) + return POWER_SUPPLY_STATUS_NOT_CHARGING; + if (!state0 && !state1) + return POWER_SUPPLY_STATUS_DISCHARGING; + + return POWER_SUPPLY_STATUS_UNKNOWN; +} + +static int act8600_charger_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val) +{ + struct regmap *map = power_supply_get_drvdata(psy); + int ret; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + ret = act8600_charger_get_status(map); + if (ret < 0) + return ret; + + val->intval = ret; + break; + default: + return -EINVAL; + } + + return 0; +} + +static enum power_supply_property act8600_charger_properties[] = { + POWER_SUPPLY_PROP_STATUS, +}; + +static const struct power_supply_desc act8600_charger_desc = { + .name = "act8600-charger", + .type = POWER_SUPPLY_TYPE_BATTERY, + .properties = act8600_charger_properties, + .num_properties = ARRAY_SIZE(act8600_charger_properties), + .get_property = act8600_charger_get_property, +}; + +static int act8600_charger_probe(struct device *dev, struct regmap *regmap) +{ + struct power_supply *charger; + struct power_supply_config cfg = { + .drv_data = regmap, + .of_node = dev->of_node, + }; + + charger = devm_power_supply_register(dev, &act8600_charger_desc, &cfg); + + return PTR_ERR_OR_ZERO(charger); +} + static int act8865_pmic_probe(struct i2c_client *client, const struct i2c_device_id *i2c_id) { @@ -483,9 +762,20 @@ static int act8865_pmic_probe(struct i2c_client *client, } } + if (type == ACT8600) { + ret = act8600_charger_probe(dev, act8865->regmap); + if (ret < 0) { + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to probe charger"); + return ret; + } + } + i2c_set_clientdata(client, act8865); - return 0; + /* Unlock expert registers for ACT8865. */ + return type != ACT8865 ? 0 : regmap_write(act8865->regmap, + ACT8865_SYS_UNLK_REGS, 0xef); } static const struct i2c_device_id act8865_ids[] = { diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index e0c0cf462004..afe94470b67f 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -381,12 +381,16 @@ static struct device_node *of_get_child_regulator(struct device_node *parent, if (!regnode) { regnode = of_get_child_regulator(child, prop_name); if (regnode) - return regnode; + goto err_node_put; } else { - return regnode; + goto err_node_put; } } return NULL; + +err_node_put: + of_node_put(child); + return regnode; } /** @@ -564,13 +568,15 @@ static ssize_t regulator_uV_show(struct device *dev, struct device_attribute *attr, char *buf) { struct regulator_dev *rdev = dev_get_drvdata(dev); - ssize_t ret; + int uV; regulator_lock(rdev); - ret = sprintf(buf, "%d\n", regulator_get_voltage_rdev(rdev)); + uV = regulator_get_voltage_rdev(rdev); regulator_unlock(rdev); - return ret; + if (uV < 0) + return uV; + return sprintf(buf, "%d\n", uV); } static DEVICE_ATTR(microvolts, 0444, regulator_uV_show, NULL); @@ -5640,7 +5646,7 @@ static int __init regulator_init(void) /* init early to allow our consumers to complete system booting */ core_initcall(regulator_init); -static int __init regulator_late_cleanup(struct device *dev, void *data) +static int regulator_late_cleanup(struct device *dev, void *data) { struct regulator_dev *rdev = dev_to_rdev(dev); const struct regulator_ops *ops = rdev->desc->ops; @@ -5689,18 +5695,9 @@ unlock: return 0; } -static int __init regulator_init_complete(void) +static void regulator_init_complete_work_function(struct work_struct *work) { /* - * Since DT doesn't provide an idiomatic mechanism for - * enabling full constraints and since it's much more natural - * with DT to provide them just assume that a DT enabled - * system has full constraints. - */ - if (of_have_populated_dt()) - has_full_constraints = true; - - /* * Regulators may had failed to resolve their input supplies * when were registered, either because the input supply was * not registered yet or because its parent device was not @@ -5717,6 +5714,35 @@ static int __init regulator_init_complete(void) */ class_for_each_device(®ulator_class, NULL, NULL, regulator_late_cleanup); +} + +static DECLARE_DELAYED_WORK(regulator_init_complete_work, + regulator_init_complete_work_function); + +static int __init regulator_init_complete(void) +{ + /* + * Since DT doesn't provide an idiomatic mechanism for + * enabling full constraints and since it's much more natural + * with DT to provide them just assume that a DT enabled + * system has full constraints. + */ + if (of_have_populated_dt()) + has_full_constraints = true; + + /* + * We punt completion for an arbitrary amount of time since + * systems like distros will load many drivers from userspace + * so consumers might not always be ready yet, this is + * particularly an issue with laptops where this might bounce + * the display off then on. Ideally we'd get a notification + * from userspace when this happens but we don't so just wait + * a bit and hope we waited long enough. It'd be better if + * we'd only do this on systems that need it, and a kernel + * command line option might be useful. + */ + schedule_delayed_work(®ulator_init_complete_work, + msecs_to_jiffies(30000)); return 0; } diff --git a/drivers/regulator/da9062-regulator.c b/drivers/regulator/da9062-regulator.c index 2ffc64622451..56f3f72d7707 100644 --- a/drivers/regulator/da9062-regulator.c +++ b/drivers/regulator/da9062-regulator.c @@ -1032,10 +1032,8 @@ static int da9062_regulator_probe(struct platform_device *pdev) /* LDOs overcurrent event support */ irq = platform_get_irq_byname(pdev, "LDO_LIM"); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ.\n"); + if (irq < 0) return irq; - } regulators->irq_ldo_lim = irq; ret = devm_request_threaded_irq(&pdev->dev, irq, diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 02f816318fba..28b1b20f45bd 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -863,10 +863,8 @@ static int da9063_regulator_probe(struct platform_device *pdev) /* LDOs overcurrent event support */ irq = platform_get_irq_byname(pdev, "LDO_LIM"); - if (irq < 0) { - dev_err(&pdev->dev, "Failed to get IRQ.\n"); + if (irq < 0) return irq; - } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, da9063_ldo_lim_event, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index 0309823d2c72..bf80748f1ccc 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -285,7 +285,7 @@ static struct da9211_pdata *da9211_parse_regulators_dt( pdata->reg_node[n] = da9211_matches[i].of_node; pdata->gpiod_ren[n] = devm_gpiod_get_from_of_node(dev, da9211_matches[i].of_node, - "enable", + "enable-gpios", 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "da9211-enable"); diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c index 999547dde99d..d90a6fd8cbc7 100644 --- a/drivers/regulator/fixed.c +++ b/drivers/regulator/fixed.c @@ -23,14 +23,63 @@ #include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/regulator/of_regulator.h> #include <linux/regulator/machine.h> +#include <linux/clk.h> + struct fixed_voltage_data { struct regulator_desc desc; struct regulator_dev *dev; + + struct clk *enable_clock; + unsigned int clk_enable_counter; }; +struct fixed_dev_type { + bool has_enable_clock; +}; + +static const struct fixed_dev_type fixed_voltage_data = { + .has_enable_clock = false, +}; + +static const struct fixed_dev_type fixed_clkenable_data = { + .has_enable_clock = true, +}; + +static int reg_clock_enable(struct regulator_dev *rdev) +{ + struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); + int ret = 0; + + ret = clk_prepare_enable(priv->enable_clock); + if (ret) + return ret; + + priv->clk_enable_counter++; + + return ret; +} + +static int reg_clock_disable(struct regulator_dev *rdev) +{ + struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); + + clk_disable_unprepare(priv->enable_clock); + priv->clk_enable_counter--; + + return 0; +} + +static int reg_clock_is_enabled(struct regulator_dev *rdev) +{ + struct fixed_voltage_data *priv = rdev_get_drvdata(rdev); + + return priv->clk_enable_counter > 0; +} + /** * of_get_fixed_voltage_config - extract fixed_voltage_config structure info @@ -84,10 +133,19 @@ of_get_fixed_voltage_config(struct device *dev, static struct regulator_ops fixed_voltage_ops = { }; +static struct regulator_ops fixed_voltage_clkenabled_ops = { + .enable = reg_clock_enable, + .disable = reg_clock_disable, + .is_enabled = reg_clock_is_enabled, +}; + static int reg_fixed_voltage_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct fixed_voltage_config *config; struct fixed_voltage_data *drvdata; + const struct fixed_dev_type *drvtype = + of_match_device(dev->driver->of_match_table, dev)->data; struct regulator_config cfg = { }; enum gpiod_flags gflags; int ret; @@ -118,7 +176,18 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) } drvdata->desc.type = REGULATOR_VOLTAGE; drvdata->desc.owner = THIS_MODULE; - drvdata->desc.ops = &fixed_voltage_ops; + + if (drvtype->has_enable_clock) { + drvdata->desc.ops = &fixed_voltage_clkenabled_ops; + + drvdata->enable_clock = devm_clk_get(dev, NULL); + if (IS_ERR(drvdata->enable_clock)) { + dev_err(dev, "Cant get enable-clock from devicetree\n"); + return -ENOENT; + } + } else { + drvdata->desc.ops = &fixed_voltage_ops; + } drvdata->desc.enable_time = config->startup_delay; @@ -191,8 +260,16 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev) #if defined(CONFIG_OF) static const struct of_device_id fixed_of_match[] = { - { .compatible = "regulator-fixed", }, - {}, + { + .compatible = "regulator-fixed", + .data = &fixed_voltage_data, + }, + { + .compatible = "regulator-fixed-clock", + .data = &fixed_clkenable_data, + }, + { + }, }; MODULE_DEVICE_TABLE(of, fixed_of_match); #endif diff --git a/drivers/regulator/helpers.c b/drivers/regulator/helpers.c index 4986cc5064a1..ca3dc3f3bb29 100644 --- a/drivers/regulator/helpers.c +++ b/drivers/regulator/helpers.c @@ -860,3 +860,24 @@ int regulator_get_current_limit_regmap(struct regulator_dev *rdev) return -EINVAL; } EXPORT_SYMBOL_GPL(regulator_get_current_limit_regmap); + +/** + * regulator_bulk_set_supply_names - initialize the 'supply' fields in an array + * of regulator_bulk_data structs + * + * @consumers: array of regulator_bulk_data entries to initialize + * @supply_names: array of supply name strings + * @num_supplies: number of supply names to initialize + * + * Note: the 'consumers' array must be the size of 'num_supplies'. + */ +void regulator_bulk_set_supply_names(struct regulator_bulk_data *consumers, + const char *const *supply_names, + unsigned int num_supplies) +{ + unsigned int i; + + for (i = 0; i < num_supplies; i++) + consumers[i].supply = supply_names[i]; +} +EXPORT_SYMBOL_GPL(regulator_bulk_set_supply_names); diff --git a/drivers/regulator/lm363x-regulator.c b/drivers/regulator/lm363x-regulator.c index 5647e2f97ff8..4b9f618b07e9 100644 --- a/drivers/regulator/lm363x-regulator.c +++ b/drivers/regulator/lm363x-regulator.c @@ -30,13 +30,13 @@ /* LM3632 */ #define LM3632_BOOST_VSEL_MAX 0x26 -#define LM3632_LDO_VSEL_MAX 0x29 +#define LM3632_LDO_VSEL_MAX 0x28 #define LM3632_VBOOST_MIN 4500000 #define LM3632_VLDO_MIN 4000000 /* LM36274 */ #define LM36274_BOOST_VSEL_MAX 0x3f -#define LM36274_LDO_VSEL_MAX 0x34 +#define LM36274_LDO_VSEL_MAX 0x32 #define LM36274_VOLTAGE_MIN 4000000 /* Common */ @@ -226,7 +226,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = { .of_match = "vboost", .id = LM36274_BOOST, .ops = &lm363x_boost_voltage_table_ops, - .n_voltages = LM36274_BOOST_VSEL_MAX, + .n_voltages = LM36274_BOOST_VSEL_MAX + 1, .min_uV = LM36274_VOLTAGE_MIN, .uV_step = LM363X_STEP_50mV, .type = REGULATOR_VOLTAGE, @@ -239,7 +239,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = { .of_match = "vpos", .id = LM36274_LDO_POS, .ops = &lm363x_regulator_voltage_table_ops, - .n_voltages = LM36274_LDO_VSEL_MAX, + .n_voltages = LM36274_LDO_VSEL_MAX + 1, .min_uV = LM36274_VOLTAGE_MIN, .uV_step = LM363X_STEP_50mV, .type = REGULATOR_VOLTAGE, @@ -254,7 +254,7 @@ static const struct regulator_desc lm363x_regulator_desc[] = { .of_match = "vneg", .id = LM36274_LDO_NEG, .ops = &lm363x_regulator_voltage_table_ops, - .n_voltages = LM36274_LDO_VSEL_MAX, + .n_voltages = LM36274_LDO_VSEL_MAX + 1, .min_uV = LM36274_VOLTAGE_MIN, .uV_step = LM363X_STEP_50mV, .type = REGULATOR_VOLTAGE, diff --git a/drivers/regulator/lp87565-regulator.c b/drivers/regulator/lp87565-regulator.c index 0c440c5e2832..4ae12ac1f4c6 100644 --- a/drivers/regulator/lp87565-regulator.c +++ b/drivers/regulator/lp87565-regulator.c @@ -65,7 +65,6 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { int id = rdev_get_id(rdev); - struct lp87565 *lp87565 = rdev_get_drvdata(rdev); unsigned int reg; int ret; @@ -86,11 +85,11 @@ static int lp87565_buck_set_ramp_delay(struct regulator_dev *rdev, else reg = 0; - ret = regmap_update_bits(lp87565->regmap, regulators[id].ctrl2_reg, + ret = regmap_update_bits(rdev->regmap, regulators[id].ctrl2_reg, LP87565_BUCK_CTRL_2_SLEW_RATE, reg << __ffs(LP87565_BUCK_CTRL_2_SLEW_RATE)); if (ret) { - dev_err(lp87565->dev, "SLEW RATE write failed: %d\n", ret); + dev_err(&rdev->dev, "SLEW RATE write failed: %d\n", ret); return ret; } diff --git a/drivers/regulator/lp8788-ldo.c b/drivers/regulator/lp8788-ldo.c index 1b00f3638996..00e9bb92c326 100644 --- a/drivers/regulator/lp8788-ldo.c +++ b/drivers/regulator/lp8788-ldo.c @@ -464,7 +464,7 @@ static int lp8788_config_ldo_enable_mode(struct platform_device *pdev, { struct lp8788 *lp = ldo->lp; enum lp8788_ext_ldo_en_id enable_id; - u8 en_mask[] = { + static const u8 en_mask[] = { [EN_ALDO1] = LP8788_EN_SEL_ALDO1_M, [EN_ALDO234] = LP8788_EN_SEL_ALDO234_M, [EN_ALDO5] = LP8788_EN_SEL_ALDO5_M, diff --git a/drivers/regulator/max77686-regulator.c b/drivers/regulator/max77686-regulator.c index 8020eb57374a..c8e579e99316 100644 --- a/drivers/regulator/max77686-regulator.c +++ b/drivers/regulator/max77686-regulator.c @@ -257,7 +257,7 @@ static int max77686_of_parse_cb(struct device_node *np, case MAX77686_BUCK9: case MAX77686_LDO20 ... MAX77686_LDO22: config->ena_gpiod = gpiod_get_from_of_node(np, - "maxim,ena", + "maxim,ena-gpios", 0, GPIOD_OUT_HIGH | GPIOD_FLAGS_BIT_NONEXCLUSIVE, "max77686-regulator"); diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 4bca54446287..347043a5a9a7 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -485,7 +485,6 @@ static int max8660_probe(struct i2c_client *client, rdev = devm_regulator_register(&client->dev, &max8660_reg[id], &config); if (IS_ERR(rdev)) { - ret = PTR_ERR(rdev); dev_err(&client->dev, "failed to register %s\n", max8660_reg[id].name); return PTR_ERR(rdev); diff --git a/drivers/regulator/mt6358-regulator.c b/drivers/regulator/mt6358-regulator.c new file mode 100644 index 000000000000..ba42682e06f3 --- /dev/null +++ b/drivers/regulator/mt6358-regulator.c @@ -0,0 +1,549 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2019 MediaTek Inc. + +#include <linux/mfd/mt6358/registers.h> +#include <linux/mfd/mt6397/core.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/machine.h> +#include <linux/regulator/mt6358-regulator.h> +#include <linux/regulator/of_regulator.h> + +#define MT6358_BUCK_MODE_AUTO 0 +#define MT6358_BUCK_MODE_FORCE_PWM 1 + +/* + * MT6358 regulators' information + * + * @desc: standard fields of regulator description. + * @qi: Mask for query enable signal status of regulators + */ +struct mt6358_regulator_info { + struct regulator_desc desc; + u32 status_reg; + u32 qi; + const u32 *index_table; + unsigned int n_table; + u32 vsel_shift; + u32 da_vsel_reg; + u32 da_vsel_mask; + u32 da_vsel_shift; + u32 modeset_reg; + u32 modeset_mask; + u32 modeset_shift; +}; + +#define MT6358_BUCK(match, vreg, min, max, step, \ + volt_ranges, vosel_mask, _da_vsel_reg, _da_vsel_mask, \ + _da_vsel_shift, _modeset_reg, _modeset_shift) \ +[MT6358_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6358_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = MT6358_BUCK_##vreg##_ELR0, \ + .vsel_mask = vosel_mask, \ + .enable_reg = MT6358_BUCK_##vreg##_CON0, \ + .enable_mask = BIT(0), \ + .of_map_mode = mt6358_map_mode, \ + }, \ + .status_reg = MT6358_BUCK_##vreg##_DBG1, \ + .qi = BIT(0), \ + .da_vsel_reg = _da_vsel_reg, \ + .da_vsel_mask = _da_vsel_mask, \ + .da_vsel_shift = _da_vsel_shift, \ + .modeset_reg = _modeset_reg, \ + .modeset_mask = BIT(_modeset_shift), \ + .modeset_shift = _modeset_shift \ +} + +#define MT6358_LDO(match, vreg, ldo_volt_table, \ + ldo_index_table, enreg, enbit, vosel, \ + vosel_mask, vosel_shift) \ +[MT6358_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_table_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6358_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ARRAY_SIZE(ldo_volt_table), \ + .volt_table = ldo_volt_table, \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + }, \ + .status_reg = MT6358_LDO_##vreg##_CON1, \ + .qi = BIT(15), \ + .index_table = ldo_index_table, \ + .n_table = ARRAY_SIZE(ldo_index_table), \ + .vsel_shift = vosel_shift, \ +} + +#define MT6358_LDO1(match, vreg, min, max, step, \ + volt_ranges, _da_vsel_reg, _da_vsel_mask, \ + _da_vsel_shift, vosel, vosel_mask) \ +[MT6358_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_range_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6358_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = ((max) - (min)) / (step) + 1, \ + .linear_ranges = volt_ranges, \ + .n_linear_ranges = ARRAY_SIZE(volt_ranges), \ + .vsel_reg = vosel, \ + .vsel_mask = vosel_mask, \ + .enable_reg = MT6358_LDO_##vreg##_CON0, \ + .enable_mask = BIT(0), \ + }, \ + .da_vsel_reg = _da_vsel_reg, \ + .da_vsel_mask = _da_vsel_mask, \ + .da_vsel_shift = _da_vsel_shift, \ + .status_reg = MT6358_LDO_##vreg##_DBG1, \ + .qi = BIT(0), \ +} + +#define MT6358_REG_FIXED(match, vreg, \ + enreg, enbit, volt) \ +[MT6358_ID_##vreg] = { \ + .desc = { \ + .name = #vreg, \ + .of_match = of_match_ptr(match), \ + .ops = &mt6358_volt_fixed_ops, \ + .type = REGULATOR_VOLTAGE, \ + .id = MT6358_ID_##vreg, \ + .owner = THIS_MODULE, \ + .n_voltages = 1, \ + .enable_reg = enreg, \ + .enable_mask = BIT(enbit), \ + .min_uV = volt, \ + }, \ + .status_reg = MT6358_LDO_##vreg##_CON1, \ + .qi = BIT(15), \ +} + +static const struct regulator_linear_range buck_volt_range1[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 6250), +}; + +static const struct regulator_linear_range buck_volt_range2[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 0x7f, 12500), +}; + +static const struct regulator_linear_range buck_volt_range3[] = { + REGULATOR_LINEAR_RANGE(500000, 0, 0x3f, 50000), +}; + +static const struct regulator_linear_range buck_volt_range4[] = { + REGULATOR_LINEAR_RANGE(1000000, 0, 0x7f, 12500), +}; + +static const u32 vdram2_voltages[] = { + 600000, 1800000, +}; + +static const u32 vsim_voltages[] = { + 1700000, 1800000, 2700000, 3000000, 3100000, +}; + +static const u32 vibr_voltages[] = { + 1200000, 1300000, 1500000, 1800000, + 2000000, 2800000, 3000000, 3300000, +}; + +static const u32 vusb_voltages[] = { + 3000000, 3100000, +}; + +static const u32 vcamd_voltages[] = { + 900000, 1000000, 1100000, 1200000, + 1300000, 1500000, 1800000, +}; + +static const u32 vefuse_voltages[] = { + 1700000, 1800000, 1900000, +}; + +static const u32 vmch_vemc_voltages[] = { + 2900000, 3000000, 3300000, +}; + +static const u32 vcama_voltages[] = { + 1800000, 2500000, 2700000, + 2800000, 2900000, 3000000, +}; + +static const u32 vcn33_bt_wifi_voltages[] = { + 3300000, 3400000, 3500000, +}; + +static const u32 vmc_voltages[] = { + 1800000, 2900000, 3000000, 3300000, +}; + +static const u32 vldo28_voltages[] = { + 2800000, 3000000, +}; + +static const u32 vdram2_idx[] = { + 0, 12, +}; + +static const u32 vsim_idx[] = { + 3, 4, 8, 11, 12, +}; + +static const u32 vibr_idx[] = { + 0, 1, 2, 4, 5, 9, 11, 13, +}; + +static const u32 vusb_idx[] = { + 3, 4, +}; + +static const u32 vcamd_idx[] = { + 3, 4, 5, 6, 7, 9, 12, +}; + +static const u32 vefuse_idx[] = { + 11, 12, 13, +}; + +static const u32 vmch_vemc_idx[] = { + 2, 3, 5, +}; + +static const u32 vcama_idx[] = { + 0, 7, 9, 10, 11, 12, +}; + +static const u32 vcn33_bt_wifi_idx[] = { + 1, 2, 3, +}; + +static const u32 vmc_idx[] = { + 4, 10, 11, 13, +}; + +static const u32 vldo28_idx[] = { + 1, 3, +}; + +static unsigned int mt6358_map_mode(unsigned int mode) +{ + return mode == MT6358_BUCK_MODE_AUTO ? + REGULATOR_MODE_NORMAL : REGULATOR_MODE_FAST; +} + +static int mt6358_set_voltage_sel(struct regulator_dev *rdev, + unsigned int selector) +{ + int idx, ret; + const u32 *pvol; + struct mt6358_regulator_info *info = rdev_get_drvdata(rdev); + + pvol = info->index_table; + + idx = pvol[selector]; + ret = regmap_update_bits(rdev->regmap, info->desc.vsel_reg, + info->desc.vsel_mask, + idx << info->vsel_shift); + + return ret; +} + +static int mt6358_get_voltage_sel(struct regulator_dev *rdev) +{ + int idx, ret; + u32 selector; + struct mt6358_regulator_info *info = rdev_get_drvdata(rdev); + const u32 *pvol; + + ret = regmap_read(rdev->regmap, info->desc.vsel_reg, &selector); + if (ret != 0) { + dev_info(&rdev->dev, + "Failed to get mt6358 %s vsel reg: %d\n", + info->desc.name, ret); + return ret; + } + + selector = (selector & info->desc.vsel_mask) >> info->vsel_shift; + pvol = info->index_table; + for (idx = 0; idx < info->desc.n_voltages; idx++) { + if (pvol[idx] == selector) + return idx; + } + + return -EINVAL; +} + +static int mt6358_get_buck_voltage_sel(struct regulator_dev *rdev) +{ + int ret, regval; + struct mt6358_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->da_vsel_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to get mt6358 Buck %s vsel reg: %d\n", + info->desc.name, ret); + return ret; + } + + ret = (regval >> info->da_vsel_shift) & info->da_vsel_mask; + + return ret; +} + +static int mt6358_get_status(struct regulator_dev *rdev) +{ + int ret; + u32 regval; + struct mt6358_regulator_info *info = rdev_get_drvdata(rdev); + + ret = regmap_read(rdev->regmap, info->status_reg, ®val); + if (ret != 0) { + dev_info(&rdev->dev, "Failed to get enable reg: %d\n", ret); + return ret; + } + + return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF; +} + +static int mt6358_regulator_set_mode(struct regulator_dev *rdev, + unsigned int mode) +{ + struct mt6358_regulator_info *info = rdev_get_drvdata(rdev); + int val; + + switch (mode) { + case REGULATOR_MODE_FAST: + val = MT6358_BUCK_MODE_FORCE_PWM; + break; + case REGULATOR_MODE_NORMAL: + val = MT6358_BUCK_MODE_AUTO; + break; + default: + return -EINVAL; + } + + dev_dbg(&rdev->dev, "mt6358 buck set_mode %#x, %#x, %#x, %#x\n", + info->modeset_reg, info->modeset_mask, + info->modeset_shift, val); + + val <<= info->modeset_shift; + + return regmap_update_bits(rdev->regmap, info->modeset_reg, + info->modeset_mask, val); +} + +static unsigned int mt6358_regulator_get_mode(struct regulator_dev *rdev) +{ + struct mt6358_regulator_info *info = rdev_get_drvdata(rdev); + int ret, regval; + + ret = regmap_read(rdev->regmap, info->modeset_reg, ®val); + if (ret != 0) { + dev_err(&rdev->dev, + "Failed to get mt6358 buck mode: %d\n", ret); + return ret; + } + + switch ((regval & info->modeset_mask) >> info->modeset_shift) { + case MT6358_BUCK_MODE_AUTO: + return REGULATOR_MODE_NORMAL; + case MT6358_BUCK_MODE_FORCE_PWM: + return REGULATOR_MODE_FAST; + default: + return -EINVAL; + } +} + +static const struct regulator_ops mt6358_volt_range_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = mt6358_get_buck_voltage_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6358_get_status, + .set_mode = mt6358_regulator_set_mode, + .get_mode = mt6358_regulator_get_mode, +}; + +static const struct regulator_ops mt6358_volt_table_ops = { + .list_voltage = regulator_list_voltage_table, + .map_voltage = regulator_map_voltage_iterate, + .set_voltage_sel = mt6358_set_voltage_sel, + .get_voltage_sel = mt6358_get_voltage_sel, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6358_get_status, +}; + +static const struct regulator_ops mt6358_volt_fixed_ops = { + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .get_status = mt6358_get_status, +}; + +/* The array is indexed by id(MT6358_ID_XXX) */ +static struct mt6358_regulator_info mt6358_regulators[] = { + MT6358_BUCK("buck_vdram1", VDRAM1, 500000, 2087500, 12500, + buck_volt_range2, 0x7f, MT6358_BUCK_VDRAM1_DBG0, 0x7f, + 0, MT6358_VDRAM1_ANA_CON0, 8), + MT6358_BUCK("buck_vcore", VCORE, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VCORE_DBG0, 0x7f, + 0, MT6358_VCORE_VGPU_ANA_CON0, 1), + MT6358_BUCK("buck_vpa", VPA, 500000, 3650000, 50000, + buck_volt_range3, 0x3f, MT6358_BUCK_VPA_DBG0, 0x3f, 0, + MT6358_VPA_ANA_CON0, 3), + MT6358_BUCK("buck_vproc11", VPROC11, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VPROC11_DBG0, 0x7f, + 0, MT6358_VPROC_ANA_CON0, 1), + MT6358_BUCK("buck_vproc12", VPROC12, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VPROC12_DBG0, 0x7f, + 0, MT6358_VPROC_ANA_CON0, 2), + MT6358_BUCK("buck_vgpu", VGPU, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VGPU_ELR0, 0x7f, 0, + MT6358_VCORE_VGPU_ANA_CON0, 2), + MT6358_BUCK("buck_vs2", VS2, 500000, 2087500, 12500, + buck_volt_range2, 0x7f, MT6358_BUCK_VS2_DBG0, 0x7f, 0, + MT6358_VS2_ANA_CON0, 8), + MT6358_BUCK("buck_vmodem", VMODEM, 500000, 1293750, 6250, + buck_volt_range1, 0x7f, MT6358_BUCK_VMODEM_DBG0, 0x7f, + 0, MT6358_VMODEM_ANA_CON0, 8), + MT6358_BUCK("buck_vs1", VS1, 1000000, 2587500, 12500, + buck_volt_range4, 0x7f, MT6358_BUCK_VS1_DBG0, 0x7f, 0, + MT6358_VS1_ANA_CON0, 8), + MT6358_REG_FIXED("ldo_vrf12", VRF12, + MT6358_LDO_VRF12_CON0, 0, 1200000), + MT6358_REG_FIXED("ldo_vio18", VIO18, + MT6358_LDO_VIO18_CON0, 0, 1800000), + MT6358_REG_FIXED("ldo_vcamio", VCAMIO, + MT6358_LDO_VCAMIO_CON0, 0, 1800000), + MT6358_REG_FIXED("ldo_vcn18", VCN18, MT6358_LDO_VCN18_CON0, 0, 1800000), + MT6358_REG_FIXED("ldo_vfe28", VFE28, MT6358_LDO_VFE28_CON0, 0, 2800000), + MT6358_REG_FIXED("ldo_vcn28", VCN28, MT6358_LDO_VCN28_CON0, 0, 2800000), + MT6358_REG_FIXED("ldo_vxo22", VXO22, MT6358_LDO_VXO22_CON0, 0, 2200000), + MT6358_REG_FIXED("ldo_vaux18", VAUX18, + MT6358_LDO_VAUX18_CON0, 0, 1800000), + MT6358_REG_FIXED("ldo_vbif28", VBIF28, + MT6358_LDO_VBIF28_CON0, 0, 2800000), + MT6358_REG_FIXED("ldo_vio28", VIO28, MT6358_LDO_VIO28_CON0, 0, 2800000), + MT6358_REG_FIXED("ldo_va12", VA12, MT6358_LDO_VA12_CON0, 0, 1200000), + MT6358_REG_FIXED("ldo_vrf18", VRF18, MT6358_LDO_VRF18_CON0, 0, 1800000), + MT6358_REG_FIXED("ldo_vaud28", VAUD28, + MT6358_LDO_VAUD28_CON0, 0, 2800000), + MT6358_LDO("ldo_vdram2", VDRAM2, vdram2_voltages, vdram2_idx, + MT6358_LDO_VDRAM2_CON0, 0, MT6358_LDO_VDRAM2_ELR0, 0x10, 0), + MT6358_LDO("ldo_vsim1", VSIM1, vsim_voltages, vsim_idx, + MT6358_LDO_VSIM1_CON0, 0, MT6358_VSIM1_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vibr", VIBR, vibr_voltages, vibr_idx, + MT6358_LDO_VIBR_CON0, 0, MT6358_VIBR_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vusb", VUSB, vusb_voltages, vusb_idx, + MT6358_LDO_VUSB_CON0_0, 0, MT6358_VUSB_ANA_CON0, 0x700, 8), + MT6358_LDO("ldo_vcamd", VCAMD, vcamd_voltages, vcamd_idx, + MT6358_LDO_VCAMD_CON0, 0, MT6358_VCAMD_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vefuse", VEFUSE, vefuse_voltages, vefuse_idx, + MT6358_LDO_VEFUSE_CON0, 0, MT6358_VEFUSE_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vmch", VMCH, vmch_vemc_voltages, vmch_vemc_idx, + MT6358_LDO_VMCH_CON0, 0, MT6358_VMCH_ANA_CON0, 0x700, 8), + MT6358_LDO("ldo_vcama1", VCAMA1, vcama_voltages, vcama_idx, + MT6358_LDO_VCAMA1_CON0, 0, MT6358_VCAMA1_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vemc", VEMC, vmch_vemc_voltages, vmch_vemc_idx, + MT6358_LDO_VEMC_CON0, 0, MT6358_VEMC_ANA_CON0, 0x700, 8), + MT6358_LDO("ldo_vcn33_bt", VCN33_BT, vcn33_bt_wifi_voltages, + vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_0, + 0, MT6358_VCN33_ANA_CON0, 0x300, 8), + MT6358_LDO("ldo_vcn33_wifi", VCN33_WIFI, vcn33_bt_wifi_voltages, + vcn33_bt_wifi_idx, MT6358_LDO_VCN33_CON0_1, + 0, MT6358_VCN33_ANA_CON0, 0x300, 8), + MT6358_LDO("ldo_vcama2", VCAMA2, vcama_voltages, vcama_idx, + MT6358_LDO_VCAMA2_CON0, 0, MT6358_VCAMA2_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vmc", VMC, vmc_voltages, vmc_idx, + MT6358_LDO_VMC_CON0, 0, MT6358_VMC_ANA_CON0, 0xf00, 8), + MT6358_LDO("ldo_vldo28", VLDO28, vldo28_voltages, vldo28_idx, + MT6358_LDO_VLDO28_CON0_0, 0, + MT6358_VLDO28_ANA_CON0, 0x300, 8), + MT6358_LDO("ldo_vsim2", VSIM2, vsim_voltages, vsim_idx, + MT6358_LDO_VSIM2_CON0, 0, MT6358_VSIM2_ANA_CON0, 0xf00, 8), + MT6358_LDO1("ldo_vsram_proc11", VSRAM_PROC11, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_PROC11_DBG0, 0x7f, 8, + MT6358_LDO_VSRAM_CON0, 0x7f), + MT6358_LDO1("ldo_vsram_others", VSRAM_OTHERS, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_OTHERS_DBG0, 0x7f, 8, + MT6358_LDO_VSRAM_CON2, 0x7f), + MT6358_LDO1("ldo_vsram_gpu", VSRAM_GPU, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_GPU_DBG0, 0x7f, 8, + MT6358_LDO_VSRAM_CON3, 0x7f), + MT6358_LDO1("ldo_vsram_proc12", VSRAM_PROC12, 500000, 1293750, 6250, + buck_volt_range1, MT6358_LDO_VSRAM_PROC12_DBG0, 0x7f, 8, + MT6358_LDO_VSRAM_CON1, 0x7f), +}; + +static int mt6358_regulator_probe(struct platform_device *pdev) +{ + struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent); + struct regulator_config config = {}; + struct regulator_dev *rdev; + int i; + + for (i = 0; i < MT6358_MAX_REGULATOR; i++) { + config.dev = &pdev->dev; + config.driver_data = &mt6358_regulators[i]; + config.regmap = mt6397->regmap; + + rdev = devm_regulator_register(&pdev->dev, + &mt6358_regulators[i].desc, + &config); + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s\n", + mt6358_regulators[i].desc.name); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct platform_device_id mt6358_platform_ids[] = { + {"mt6358-regulator", 0}, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, mt6358_platform_ids); + +static struct platform_driver mt6358_regulator_driver = { + .driver = { + .name = "mt6358-regulator", + }, + .probe = mt6358_regulator_probe, + .id_table = mt6358_platform_ids, +}; + +module_platform_driver(mt6358_regulator_driver); + +MODULE_AUTHOR("Hsin-Hsiung Wang <hsin-hsiung.wang@mediatek.com>"); +MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6358 PMIC"); +MODULE_LICENSE("GPL"); diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c index b2c2d01d1637..db6c085da65e 100644 --- a/drivers/regulator/qcom-rpmh-regulator.c +++ b/drivers/regulator/qcom-rpmh-regulator.c @@ -50,6 +50,20 @@ enum rpmh_regulator_type { #define PMIC4_BOB_MODE_AUTO 2 #define PMIC4_BOB_MODE_PWM 3 +#define PMIC5_LDO_MODE_RETENTION 3 +#define PMIC5_LDO_MODE_LPM 4 +#define PMIC5_LDO_MODE_HPM 7 + +#define PMIC5_SMPS_MODE_RETENTION 3 +#define PMIC5_SMPS_MODE_PFM 4 +#define PMIC5_SMPS_MODE_AUTO 6 +#define PMIC5_SMPS_MODE_PWM 7 + +#define PMIC5_BOB_MODE_PASS 2 +#define PMIC5_BOB_MODE_PFM 4 +#define PMIC5_BOB_MODE_AUTO 6 +#define PMIC5_BOB_MODE_PWM 7 + /** * struct rpmh_vreg_hw_data - RPMh regulator hardware configurations * @regulator_type: RPMh accelerator type used to manage this @@ -488,6 +502,14 @@ static const int pmic_mode_map_pmic4_ldo[REGULATOR_MODE_STANDBY + 1] = { [REGULATOR_MODE_FAST] = -EINVAL, }; +static const int pmic_mode_map_pmic5_ldo[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = PMIC5_LDO_MODE_RETENTION, + [REGULATOR_MODE_IDLE] = PMIC5_LDO_MODE_LPM, + [REGULATOR_MODE_NORMAL] = PMIC5_LDO_MODE_HPM, + [REGULATOR_MODE_FAST] = -EINVAL, +}; + static unsigned int rpmh_regulator_pmic4_ldo_of_map_mode(unsigned int rpmh_mode) { unsigned int mode; @@ -518,6 +540,14 @@ static const int pmic_mode_map_pmic4_smps[REGULATOR_MODE_STANDBY + 1] = { [REGULATOR_MODE_FAST] = PMIC4_SMPS_MODE_PWM, }; +static const int pmic_mode_map_pmic5_smps[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = PMIC5_SMPS_MODE_RETENTION, + [REGULATOR_MODE_IDLE] = PMIC5_SMPS_MODE_PFM, + [REGULATOR_MODE_NORMAL] = PMIC5_SMPS_MODE_AUTO, + [REGULATOR_MODE_FAST] = PMIC5_SMPS_MODE_PWM, +}; + static unsigned int rpmh_regulator_pmic4_smps_of_map_mode(unsigned int rpmh_mode) { @@ -552,6 +582,14 @@ static const int pmic_mode_map_pmic4_bob[REGULATOR_MODE_STANDBY + 1] = { [REGULATOR_MODE_FAST] = PMIC4_BOB_MODE_PWM, }; +static const int pmic_mode_map_pmic5_bob[REGULATOR_MODE_STANDBY + 1] = { + [REGULATOR_MODE_INVALID] = -EINVAL, + [REGULATOR_MODE_STANDBY] = -EINVAL, + [REGULATOR_MODE_IDLE] = PMIC5_BOB_MODE_PFM, + [REGULATOR_MODE_NORMAL] = PMIC5_BOB_MODE_AUTO, + [REGULATOR_MODE_FAST] = PMIC5_BOB_MODE_PWM, +}; + static unsigned int rpmh_regulator_pmic4_bob_of_map_mode(unsigned int rpmh_mode) { unsigned int mode; @@ -637,6 +675,72 @@ static const struct rpmh_vreg_hw_data pmic4_lvs = { /* LVS hardware does not support voltage or mode configuration. */ }; +static const struct rpmh_vreg_hw_data pmic5_pldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 255, 8000), + .n_voltages = 256, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_pldo_lv = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(1504000, 0, 62, 8000), + .n_voltages = 63, + .hpm_min_load_uA = 10000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_nldo = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_drms_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 123, 8000), + .n_voltages = 124, + .hpm_min_load_uA = 30000, + .pmic_mode_map = pmic_mode_map_pmic5_ldo, + .of_map_mode = rpmh_regulator_pmic4_ldo_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_hfsmps510 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(320000, 0, 215, 8000), + .n_voltages = 216, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_ftsmps510 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 263, 4000), + .n_voltages = 264, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_hfsmps515 = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(2800000, 0, 4, 1600), + .n_voltages = 5, + .pmic_mode_map = pmic_mode_map_pmic5_smps, + .of_map_mode = rpmh_regulator_pmic4_smps_of_map_mode, +}; + +static const struct rpmh_vreg_hw_data pmic5_bob = { + .regulator_type = VRM, + .ops = &rpmh_regulator_vrm_bypass_ops, + .voltage_range = REGULATOR_LINEAR_RANGE(300000, 0, 135, 32000), + .n_voltages = 136, + .pmic_mode_map = pmic_mode_map_pmic5_bob, + .of_map_mode = rpmh_regulator_pmic4_bob_of_map_mode, +}; + #define RPMH_VREG(_name, _resource_name, _hw_data, _supply_name) \ { \ .name = _name, \ @@ -705,6 +809,75 @@ static const struct rpmh_vreg_init_data pm8005_vreg_data[] = { {}, }; +static const struct rpmh_vreg_init_data pm8150_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_hfsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_hfsmps510, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_ftsmps510, "vdd-s8"), + RPMH_VREG("smps9", "smp%s9", &pmic5_ftsmps510, "vdd-s9"), + RPMH_VREG("smps10", "smp%s10", &pmic5_ftsmps510, "vdd-s10"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_nldo, "vdd-l6-l9"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l2-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_nldo, "vdd-l1-l8-l11"), + RPMH_VREG("ldo12", "ldo%s12", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo13", "ldo%s13", &pmic5_pldo, "vdd-l13-l6-l17"), + RPMH_VREG("ldo14", "ldo%s14", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo15", "ldo%s15", &pmic5_pldo_lv, "vdd-l7-l12-l14-l15"), + RPMH_VREG("ldo16", "ldo%s16", &pmic5_pldo, "vdd-l13-l6-l17"), + RPMH_VREG("ldo17", "ldo%s17", &pmic5_pldo, "vdd-l13-l6-l17"), + RPMH_VREG("ldo18", "ldo%s18", &pmic5_nldo, "vdd-l3-l4-l5-l18"), + {}, +}; + +static const struct rpmh_vreg_init_data pm8150l_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_ftsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_ftsmps510, "vdd-s2"), + RPMH_VREG("smps3", "smp%s3", &pmic5_ftsmps510, "vdd-s3"), + RPMH_VREG("smps4", "smp%s4", &pmic5_ftsmps510, "vdd-s4"), + RPMH_VREG("smps5", "smp%s5", &pmic5_ftsmps510, "vdd-s5"), + RPMH_VREG("smps6", "smp%s6", &pmic5_ftsmps510, "vdd-s6"), + RPMH_VREG("smps7", "smp%s7", &pmic5_ftsmps510, "vdd-s7"), + RPMH_VREG("smps8", "smp%s8", &pmic5_hfsmps510, "vdd-s8"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_pldo_lv, "vdd-l1-l8"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l2-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l4-l5-l6"), + RPMH_VREG("ldo7", "ldo%s7", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("ldo8", "ldo%s8", &pmic5_pldo_lv, "vdd-l1-l8-l11"), + RPMH_VREG("ldo9", "ldo%s9", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo10", "ldo%s10", &pmic5_pldo, "vdd-l9-l10"), + RPMH_VREG("ldo11", "ldo%s11", &pmic5_pldo, "vdd-l7-l11"), + RPMH_VREG("bob", "bob%s1", &pmic5_bob, "vdd-bob"), + {}, +}; + +static const struct rpmh_vreg_init_data pm8009_vreg_data[] = { + RPMH_VREG("smps1", "smp%s1", &pmic5_hfsmps510, "vdd-s1"), + RPMH_VREG("smps2", "smp%s2", &pmic5_hfsmps515, "vdd-s2"), + RPMH_VREG("ldo1", "ldo%s1", &pmic5_nldo, "vdd-l1"), + RPMH_VREG("ldo2", "ldo%s2", &pmic5_nldo, "vdd-l2"), + RPMH_VREG("ldo3", "ldo%s3", &pmic5_nldo, "vdd-l3"), + RPMH_VREG("ldo4", "ldo%s4", &pmic5_nldo, "vdd-l4"), + RPMH_VREG("ldo5", "ldo%s5", &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo6", "ldo%s6", &pmic5_pldo, "vdd-l5-l6"), + RPMH_VREG("ldo7", "ldo%s6", &pmic5_pldo_lv, "vdd-l7"), + {}, +}; + static int rpmh_regulator_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -744,6 +917,22 @@ static int rpmh_regulator_probe(struct platform_device *pdev) static const struct of_device_id rpmh_regulator_match_table[] = { { + .compatible = "qcom,pm8005-rpmh-regulators", + .data = pm8005_vreg_data, + }, + { + .compatible = "qcom,pm8009-rpmh-regulators", + .data = pm8009_vreg_data, + }, + { + .compatible = "qcom,pm8150-rpmh-regulators", + .data = pm8150_vreg_data, + }, + { + .compatible = "qcom,pm8150l-rpmh-regulators", + .data = pm8150l_vreg_data, + }, + { .compatible = "qcom,pm8998-rpmh-regulators", .data = pm8998_vreg_data, }, @@ -751,10 +940,6 @@ static const struct of_device_id rpmh_regulator_match_table[] = { .compatible = "qcom,pmi8998-rpmh-regulators", .data = pmi8998_vreg_data, }, - { - .compatible = "qcom,pm8005-rpmh-regulators", - .data = pm8005_vreg_data, - }, {} }; MODULE_DEVICE_TABLE(of, rpmh_regulator_match_table); diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index e7af0c53d449..61bd5ef0806c 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -606,7 +606,7 @@ static unsigned int rk8xx_regulator_of_map_mode(unsigned int mode) case 2: return REGULATOR_MODE_NORMAL; default: - return -EINVAL; + return REGULATOR_MODE_INVALID; } } diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c index 054baaadfdfd..5bc00884cf51 100644 --- a/drivers/regulator/s2mps11.c +++ b/drivers/regulator/s2mps11.c @@ -1226,7 +1226,7 @@ common_reg: goto out; } - if (s2mps11->ext_control_gpiod[i]) { + if (config.ena_gpiod) { ret = s2mps14_pmic_enable_ext_control(s2mps11, regulator); if (ret < 0) { diff --git a/drivers/regulator/slg51000-regulator.c b/drivers/regulator/slg51000-regulator.c index 4d859fef55e6..a0565daecace 100644 --- a/drivers/regulator/slg51000-regulator.c +++ b/drivers/regulator/slg51000-regulator.c @@ -447,19 +447,20 @@ static int slg51000_i2c_probe(struct i2c_client *client, { struct device *dev = &client->dev; struct slg51000 *chip; - struct gpio_desc *cs_gpiod = NULL; + struct gpio_desc *cs_gpiod; int error, ret; chip = devm_kzalloc(dev, sizeof(struct slg51000), GFP_KERNEL); if (!chip) return -ENOMEM; - cs_gpiod = devm_gpiod_get_from_of_node(dev, dev->of_node, - "dlg,cs-gpios", 0, - GPIOD_OUT_HIGH - | GPIOD_FLAGS_BIT_NONEXCLUSIVE, - "slg51000-cs"); - if (!IS_ERR(cs_gpiod)) { + cs_gpiod = devm_gpiod_get_optional(dev, "dlg,cs", + GPIOD_OUT_HIGH | + GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(cs_gpiod)) + return PTR_ERR(cs_gpiod); + + if (cs_gpiod) { dev_info(dev, "Found chip selector property\n"); chip->cs_gpiod = cs_gpiod; } diff --git a/drivers/regulator/stm32-booster.c b/drivers/regulator/stm32-booster.c index 2a897666c650..03f162ffd144 100644 --- a/drivers/regulator/stm32-booster.c +++ b/drivers/regulator/stm32-booster.c @@ -20,7 +20,6 @@ #define STM32MP1_SYSCFG_EN_BOOSTER_MASK BIT(8) static const struct regulator_ops stm32h7_booster_ops = { - .list_voltage = regulator_list_voltage_linear, .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -31,7 +30,6 @@ static const struct regulator_desc stm32h7_booster_desc = { .supply_name = "vdda", .n_voltages = 1, .type = REGULATOR_VOLTAGE, - .min_uV = 3300000, .fixed_uV = 3300000, .ramp_delay = 66000, /* up to 50us to stabilize */ .ops = &stm32h7_booster_ops, @@ -53,7 +51,6 @@ static int stm32mp1_booster_disable(struct regulator_dev *rdev) } static const struct regulator_ops stm32mp1_booster_ops = { - .list_voltage = regulator_list_voltage_linear, .enable = stm32mp1_booster_enable, .disable = stm32mp1_booster_disable, .is_enabled = regulator_is_enabled_regmap, @@ -64,7 +61,6 @@ static const struct regulator_desc stm32mp1_booster_desc = { .supply_name = "vdda", .n_voltages = 1, .type = REGULATOR_VOLTAGE, - .min_uV = 3300000, .fixed_uV = 3300000, .ramp_delay = 66000, .ops = &stm32mp1_booster_ops, diff --git a/drivers/regulator/sy8824x.c b/drivers/regulator/sy8824x.c new file mode 100644 index 000000000000..92adb4f3ee19 --- /dev/null +++ b/drivers/regulator/sy8824x.c @@ -0,0 +1,232 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// SY8824C/SY8824E regulator driver +// +// Copyright (C) 2019 Synaptics Incorporated +// +// Author: Jisheng Zhang <jszhang@kernel.org> + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/regulator/driver.h> +#include <linux/regulator/of_regulator.h> + +#define SY8824C_BUCK_EN (1 << 7) +#define SY8824C_MODE (1 << 6) + +struct sy8824_config { + /* registers */ + unsigned int vol_reg; + unsigned int mode_reg; + unsigned int enable_reg; + /* Voltage range and step(linear) */ + unsigned int vsel_min; + unsigned int vsel_step; + unsigned int vsel_count; +}; + +struct sy8824_device_info { + struct device *dev; + struct regulator_desc desc; + struct regulator_init_data *regulator; + const struct sy8824_config *cfg; +}; + +static int sy8824_set_mode(struct regulator_dev *rdev, unsigned int mode) +{ + struct sy8824_device_info *di = rdev_get_drvdata(rdev); + const struct sy8824_config *cfg = di->cfg; + + switch (mode) { + case REGULATOR_MODE_FAST: + regmap_update_bits(rdev->regmap, cfg->mode_reg, + SY8824C_MODE, SY8824C_MODE); + break; + case REGULATOR_MODE_NORMAL: + regmap_update_bits(rdev->regmap, cfg->mode_reg, + SY8824C_MODE, 0); + break; + default: + return -EINVAL; + } + return 0; +} + +static unsigned int sy8824_get_mode(struct regulator_dev *rdev) +{ + struct sy8824_device_info *di = rdev_get_drvdata(rdev); + const struct sy8824_config *cfg = di->cfg; + u32 val; + int ret = 0; + + ret = regmap_read(rdev->regmap, cfg->mode_reg, &val); + if (ret < 0) + return ret; + if (val & SY8824C_MODE) + return REGULATOR_MODE_FAST; + else + return REGULATOR_MODE_NORMAL; +} + +static const struct regulator_ops sy8824_regulator_ops = { + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .map_voltage = regulator_map_voltage_linear, + .list_voltage = regulator_list_voltage_linear, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_mode = sy8824_set_mode, + .get_mode = sy8824_get_mode, +}; + +static int sy8824_regulator_register(struct sy8824_device_info *di, + struct regulator_config *config) +{ + struct regulator_desc *rdesc = &di->desc; + const struct sy8824_config *cfg = di->cfg; + struct regulator_dev *rdev; + + rdesc->name = "sy8824-reg"; + rdesc->supply_name = "vin"; + rdesc->ops = &sy8824_regulator_ops; + rdesc->type = REGULATOR_VOLTAGE; + rdesc->n_voltages = cfg->vsel_count; + rdesc->enable_reg = cfg->enable_reg; + rdesc->enable_mask = SY8824C_BUCK_EN; + rdesc->min_uV = cfg->vsel_min; + rdesc->uV_step = cfg->vsel_step; + rdesc->vsel_reg = cfg->vol_reg; + rdesc->vsel_mask = cfg->vsel_count - 1; + rdesc->owner = THIS_MODULE; + + rdev = devm_regulator_register(di->dev, &di->desc, config); + return PTR_ERR_OR_ZERO(rdev); +} + +static const struct regmap_config sy8824_regmap_config = { + .reg_bits = 8, + .val_bits = 8, +}; + +static int sy8824_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct device_node *np = dev->of_node; + struct sy8824_device_info *di; + struct regulator_config config = { }; + struct regmap *regmap; + int ret; + + di = devm_kzalloc(dev, sizeof(struct sy8824_device_info), GFP_KERNEL); + if (!di) + return -ENOMEM; + + di->regulator = of_get_regulator_init_data(dev, np, &di->desc); + if (!di->regulator) { + dev_err(dev, "Platform data not found!\n"); + return -EINVAL; + } + + di->dev = dev; + di->cfg = of_device_get_match_data(dev); + + regmap = devm_regmap_init_i2c(client, &sy8824_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "Failed to allocate regmap!\n"); + return PTR_ERR(regmap); + } + i2c_set_clientdata(client, di); + + config.dev = di->dev; + config.init_data = di->regulator; + config.regmap = regmap; + config.driver_data = di; + config.of_node = np; + + ret = sy8824_regulator_register(di, &config); + if (ret < 0) + dev_err(dev, "Failed to register regulator!\n"); + return ret; +} + +static const struct sy8824_config sy8824c_cfg = { + .vol_reg = 0x00, + .mode_reg = 0x00, + .enable_reg = 0x00, + .vsel_min = 762500, + .vsel_step = 12500, + .vsel_count = 64, +}; + +static const struct sy8824_config sy8824e_cfg = { + .vol_reg = 0x00, + .mode_reg = 0x00, + .enable_reg = 0x00, + .vsel_min = 700000, + .vsel_step = 12500, + .vsel_count = 64, +}; + +static const struct sy8824_config sy20276_cfg = { + .vol_reg = 0x00, + .mode_reg = 0x01, + .enable_reg = 0x01, + .vsel_min = 600000, + .vsel_step = 10000, + .vsel_count = 128, +}; + +static const struct sy8824_config sy20278_cfg = { + .vol_reg = 0x00, + .mode_reg = 0x01, + .enable_reg = 0x01, + .vsel_min = 762500, + .vsel_step = 12500, + .vsel_count = 64, +}; + +static const struct of_device_id sy8824_dt_ids[] = { + { + .compatible = "silergy,sy8824c", + .data = &sy8824c_cfg + }, + { + .compatible = "silergy,sy8824e", + .data = &sy8824e_cfg + }, + { + .compatible = "silergy,sy20276", + .data = &sy20276_cfg + }, + { + .compatible = "silergy,sy20278", + .data = &sy20278_cfg + }, + { } +}; +MODULE_DEVICE_TABLE(of, sy8824_dt_ids); + +static const struct i2c_device_id sy8824_id[] = { + { "sy8824", }, + { }, +}; +MODULE_DEVICE_TABLE(i2c, sy8824_id); + +static struct i2c_driver sy8824_regulator_driver = { + .driver = { + .name = "sy8824-regulator", + .of_match_table = of_match_ptr(sy8824_dt_ids), + }, + .probe = sy8824_i2c_probe, + .id_table = sy8824_id, +}; +module_i2c_driver(sy8824_regulator_driver); + +MODULE_AUTHOR("Jisheng Zhang <jszhang@kernel.org>"); +MODULE_DESCRIPTION("SY8824C/SY8824E regulator driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/tps65132-regulator.c b/drivers/regulator/tps65132-regulator.c index 6e22f5ebba2e..e302bd01a084 100644 --- a/drivers/regulator/tps65132-regulator.c +++ b/drivers/regulator/tps65132-regulator.c @@ -138,7 +138,7 @@ static int tps65132_of_parse_cb(struct device_node *np, rpdata->en_gpiod = devm_fwnode_get_index_gpiod_from_child(tps->dev, "enable", 0, &np->fwnode, 0, "enable"); - if (IS_ERR(rpdata->en_gpiod)) { + if (IS_ERR_OR_NULL(rpdata->en_gpiod)) { ret = PTR_ERR(rpdata->en_gpiod); /* Ignore the error other than probe defer */ @@ -150,7 +150,7 @@ static int tps65132_of_parse_cb(struct device_node *np, rpdata->act_dis_gpiod = devm_fwnode_get_index_gpiod_from_child( tps->dev, "active-discharge", 0, &np->fwnode, 0, "active-discharge"); - if (IS_ERR(rpdata->act_dis_gpiod)) { + if (IS_ERR_OR_NULL(rpdata->act_dis_gpiod)) { ret = PTR_ERR(rpdata->act_dis_gpiod); /* Ignore the error other than probe defer */ diff --git a/drivers/regulator/twl6030-regulator.c b/drivers/regulator/twl6030-regulator.c index 5fe208b381eb..b8100c3cedad 100644 --- a/drivers/regulator/twl6030-regulator.c +++ b/drivers/regulator/twl6030-regulator.c @@ -57,6 +57,9 @@ struct twlreg_info { #define VREG_BC_PROC 3 #define VREG_BC_CLK_RST 4 +/* TWL6030 LDO register values for VREG_VOLTAGE */ +#define TWL6030_VREG_VOLTAGE_WR_S BIT(7) + /* TWL6030 LDO register values for CFG_STATE */ #define TWL6030_CFG_STATE_OFF 0x00 #define TWL6030_CFG_STATE_ON 0x01 @@ -68,9 +71,10 @@ struct twlreg_info { #define TWL6030_CFG_STATE_APP(v) (((v) & TWL6030_CFG_STATE_APP_MASK) >>\ TWL6030_CFG_STATE_APP_SHIFT) -/* Flags for SMPS Voltage reading */ +/* Flags for SMPS Voltage reading and LDO reading*/ #define SMPS_OFFSET_EN BIT(0) #define SMPS_EXTENDED_EN BIT(1) +#define TWL_6030_WARM_RESET BIT(3) /* twl6032 SMPS EPROM values */ #define TWL6030_SMPS_OFFSET 0xB0 @@ -250,6 +254,9 @@ twl6030ldo_set_voltage_sel(struct regulator_dev *rdev, unsigned selector) { struct twlreg_info *info = rdev_get_drvdata(rdev); + if (info->flags & TWL_6030_WARM_RESET) + selector |= TWL6030_VREG_VOLTAGE_WR_S; + return twlreg_write(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE, selector); } @@ -259,6 +266,9 @@ static int twl6030ldo_get_voltage_sel(struct regulator_dev *rdev) struct twlreg_info *info = rdev_get_drvdata(rdev); int vsel = twlreg_read(info, TWL_MODULE_PM_RECEIVER, VREG_VOLTAGE); + if (info->flags & TWL_6030_WARM_RESET) + vsel &= ~TWL6030_VREG_VOLTAGE_WR_S; + return vsel; } @@ -665,14 +675,14 @@ static int twlreg_probe(struct platform_device *pdev) struct regulation_constraints *c; struct regulator_dev *rdev; struct regulator_config config = { }; + struct device_node *np = pdev->dev.of_node; template = of_device_get_match_data(&pdev->dev); if (!template) return -ENODEV; id = template->desc.id; - initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, - &template->desc); + initdata = of_get_regulator_init_data(&pdev->dev, np, &template->desc); if (!initdata) return -EINVAL; @@ -710,10 +720,13 @@ static int twlreg_probe(struct platform_device *pdev) break; } + if (of_get_property(np, "ti,retain-on-reset", NULL)) + info->flags |= TWL_6030_WARM_RESET; + config.dev = &pdev->dev; config.init_data = initdata; config.driver_data = info; - config.of_node = pdev->dev.of_node; + config.of_node = np; rdev = devm_regulator_register(&pdev->dev, &info->desc, &config); if (IS_ERR(rdev)) { diff --git a/drivers/regulator/uniphier-regulator.c b/drivers/regulator/uniphier-regulator.c index 9026d5a3e964..2311924c3103 100644 --- a/drivers/regulator/uniphier-regulator.c +++ b/drivers/regulator/uniphier-regulator.c @@ -186,6 +186,10 @@ static const struct of_device_id uniphier_regulator_match[] = { .data = &uniphier_pro4_usb3_data, }, { + .compatible = "socionext,uniphier-pro5-usb3-regulator", + .data = &uniphier_pro4_usb3_data, + }, + { .compatible = "socionext,uniphier-pxs2-usb3-regulator", .data = &uniphier_pxs2_usb3_data, }, |